// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkNew.h" #include "vtkOpenGLBufferObject.h" #include "vtkOpenGLRenderWindow.h" #include "vtkOpenGLShaderCache.h" #include "vtkShader.h" #include "vtkShaderProgram.h" #include "vtk_glad.h" #include namespace { // number of threads per group // same as local_size_x in the shader constexpr unsigned int LocalSize = 64; // number of groups constexpr unsigned int GroupSize = 1024; // total number of elements constexpr unsigned int TotalSize = LocalSize * GroupSize; } int TestComputeShader(int vtkNotUsed(argc), char* vtkNotUsed(argv)[]) { #ifdef GL_COMPUTE_SHADER std::string shaderCode = R"==( #version 430 layout(local_size_x = 64) in; layout(std430, binding = 0) writeonly buffer ValuesBuffer { uint values[]; }; void main() { uint i = gl_GlobalInvocationID.x; values[i] = i; } )=="; // we need an OpenGL context vtkNew renWin; renWin->OffScreenRenderingOn(); renWin->Start(); if (!vtkShader::IsComputeShaderSupported()) { std::cerr << "Compute shaders are not supported on this system, skipping the test.\n"; return EXIT_SUCCESS; } vtkNew shader; shader->SetSource(shaderCode); shader->SetType(vtkShader::Compute); vtkNew program; program->SetComputeShader(shader); vtkOpenGLRenderWindow* oglRenWin = vtkOpenGLRenderWindow::SafeDownCast(renWin); if (!oglRenWin) { std::cerr << "Cannot create an OpenGL window" << std::endl; return EXIT_FAILURE; } vtkOpenGLShaderCache* shaderCache = oglRenWin->GetShaderCache(); shaderCache->ReadyShaderProgram(program); std::array values; // allocate the same size on the GPU vtkNew buffer; buffer->Allocate(::TotalSize * sizeof(unsigned int), vtkOpenGLBufferObject::ArrayBuffer, vtkOpenGLBufferObject::DynamicCopy); buffer->BindShaderStorage(0); // fill the buffer on the GPU using the compute shader glDispatchCompute(::GroupSize, 1, 1); glMemoryBarrier(GL_ALL_BARRIER_BITS); // download from the GPU buffer->Download(values.data(), ::TotalSize); // check values for (unsigned int i = 0; i < ::TotalSize; i++) { if (values[i] != i) { std::cerr << "Value at index " << i << " is " << values[i] << std::endl; return EXIT_FAILURE; } } #else (void)TotalSize; #endif return EXIT_SUCCESS; }