我正在尝试使用 OpenGL、GLFW、GLEW 和 GLM 在 GLSL 中编写计算着色器。问题在于计算着色器未运行或未修改任何缓冲区。我有最新的 NVIDIA 4060 Ti 驱动程序,并且正在使用 Mesa 在 Windows 上开发 WSL。
代码(这个和glew.c(我知道,hacky)进入src目录,glm应该进入include):
#include <iostream>
#include <cstring>
#include <GLFW/glfw3.h>
#include "glm.hpp"
#include <GL/gl.h>
int main(int argc, char **argv) {
//Window width and height
int window_w = 640, window_h = 480;
printf("Startup\n");
//Init and create window
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, false);
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true);
std::cout << "Trying to create window" << std::endl;
GLFWwindow* window = glfwCreateWindow(window_w, window_h, "Marching Cubes", nullptr, nullptr);
std::cout << "Just tried to create window\n" << std::endl;
if (window == nullptr)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
else {
std::cerr << "Succeeded at creating window" << std::endl;
}
//More init
glfwMakeContextCurrent(window);
printf("Made the window the current context\n");
glEnable ( GL_DEBUG_OUTPUT );
glewInit();
// The buffer for use in the compute shader
uint32_t buffer_vertices;
uint32_t buffer_size = 10;
glCreateBuffers(1, &buffer_vertices);
glNamedBufferStorage(buffer_vertices, buffer_size, nullptr, GL_DYNAMIC_STORAGE_BIT);
printf("Buffers have been created\n");
// Create the VAO for drawing the resulting triangles
uint32_t vao_draw;
glCreateVertexArrays(1, &vao_draw);
glEnableVertexArrayAttrib(vao_draw, 0);
glEnableVertexArrayAttrib(vao_draw, 1);
glVertexArrayVertexBuffer(vao_draw, 0, buffer_vertices, 0, sizeof(glm::vec4));
glVertexArrayAttribFormat(vao_draw, 0, 4, GL_FLOAT, false, 0);
glVertexArrayAttribFormat(vao_draw, 1, 4, GL_FLOAT, false, 0);
glVertexArrayAttribBinding(vao_draw, 0, 0);
glVertexArrayAttribBinding(vao_draw, 1, 1);
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
glClearColor(1.0, 1.0, 1.0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
// The compute shader
char* smcsource = "\n\
#version 430\n\
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n\
layout(std430, binding = 0) buffer u_buffer_vertices\n\
{\n\
vec4 output_vertices[];\n\
};\n\
\n\
void main() {\n\
for (float i = 0.0; i < 10.0; i++) output_vertices[int(i)] = vec4(i,i,i,i);\n\
}\n\
";
//Compile the shader
GLint length = strlen(smcsource);
GLuint compute_shader = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(compute_shader, 1, &smcsource, &length);
glCompileShader(compute_shader);
GLint smcsuccess = 0;
glGetShaderiv(compute_shader, GL_COMPILE_STATUS, &smcsuccess);
GLuint smcprogram;
if (smcsuccess) {
printf("Successfully compiled\n");
smcprogram = glCreateProgram();
glAttachShader(smcprogram, compute_shader);
glLinkProgram(smcprogram);
GLint TotalLength = 0;
glGetShaderiv(compute_shader, GL_INFO_LOG_LENGTH, &TotalLength);
std::string logs;
logs.resize(TotalLength);
glGetShaderInfoLog(compute_shader, TotalLength, NULL, &logs[0]);
std::cout << "Shader output log:\n" << logs << std::endl;
}
else {
printf("Failed compile\n");
GLint TotalLength = 0;
glGetShaderiv(compute_shader, GL_INFO_LOG_LENGTH, &TotalLength);
std::string logs;
logs.resize(TotalLength);
glGetShaderInfoLog(compute_shader, TotalLength, NULL, &logs[0]);
std::cout << "Shader output log:\n" << logs << std::endl;
}
//Select shader
glUseProgram(smcprogram);
//Bind buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer_vertices);
printf("Buffer binded\n");
//Run shader. Problem happens here: nothing happens to the buffer when I run this
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
//Test and print the buffer data
//If this is working as intended, it should count up in groups of four, something like:
//0.0 0.0 0.0 0.0 | 1.0 1.0 1.0 1.0 | 2.0 2.0 2.0 2.0 | 3.0 3.0 3.0 3.0 | etc.
glm::vec4 vertices[16];
glGetBufferSubData(buffer_vertices, 0, 16, &vertices);
printf("Vertex data after: ");
for (int i = 0; i < 10; i++)
printf("%f %f %f %f | ", vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3]);
printf("\n");
glEnd();
glfwSwapBuffers(window);
return 0;
}
可以编译:
g++ src/main.cpp src/glew.c -Iinclude -lGLEW -lglut -lglfw -lGL -lX11 -lc -o shader-compiler-bug
就像评论所说,基于计算着色器,它应该(连同调试消息)打印:
0.0 0.0 0.0 0.0 | 1.0 1.0 1.0 1.0 | 2.0 2.0 2.0 2.0 | 3.0 3.0 3.0 3.0 | [etc. to 10]
相反,这部分打印:
-11653242706460672.000000 0.000000 0.000000 0.000000 | -496068722688.000000 0.000000 -496183017472.000000 0.000000 | -496015245312.000000 0.000000 -496055091200.000000 0.000000 | -496050896896.000000 0.000000 -496059285504.000000 0.000000 | -496066625536.000000 0.000000 -447767117824.000000 0.000000 | 0.000000 0.000000 0.000000 -0.000000 | 0.000000 0.000000 0.000000 0.000000 | 0.000000 0.000000 0.000000 0.000000 | 0.000000 0.000000 0.000000 0.000000 | -496055091200.000000 0.000000 -496025731072.000000 0.000000 |
(虽然每次都不同,有些尝试全是零或输出中有 NaN)
几个问题:
glBegin()
/glEnd()
在核心环境中不起作用;删除它们。
size
的glNamedBufferStorage()
参数以字节为单位,而不是元素。 因此,您不仅需要 buffer_size
,还需要 buffer_size * sizeof(glm::vec4)
:
glNamedBufferStorage(buffer_vertices, buffer_size * sizeof(glm::vec4), nullptr, GL_DYNAMIC_STORAGE_BIT);
glGetBufferSubData()
调用的参数使您看起来像是打算使用glNamedBufferStorage()
;它还受到以前的字节与元素问题的困扰。 更正:
glGetNamedBufferSubData(buffer_vertices, 0, buffer_size * sizeof(glm::vec4), &vertices);
一起(对GLAD转换表示歉意,这是我手头的东西):
#include <glad/glad.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vector>
#include <iostream>
void CheckStatus( GLuint obj, bool isShader )
{
GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
std::cerr << (GLchar*)log << "\n";
std::exit( EXIT_FAILURE );
}
void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader, true );
glAttachShader( program, shader );
glDeleteShader( shader );
}
const char* const comp = R"GLSL(
#version 430
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(std430, binding = 0) buffer u_buffer_vertices
{
vec4 output_vertices[];
};
void main() {
for (float i = 0.0; i < 10.0; i++) {
output_vertices[int(i)] = vec4(i,i,i,i);
}
}
)GLSL";
int main( int, char** )
{
glfwSetErrorCallback( []( int, const char* desc ) { std::cerr << desc << "\n"; std::exit( EXIT_FAILURE ); } );
glfwInit();
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 4 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 6 );
glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
glfwMakeContextCurrent( window );
gladLoadGLLoader( (GLADloadproc)glfwGetProcAddress );
GLuint prog = glCreateProgram();
AttachShader( prog, GL_COMPUTE_SHADER, comp );
glLinkProgram( prog );
CheckStatus( prog, false );
glUseProgram( prog );
// The buffer for use in the compute shader
uint32_t buffer_vertices;
uint32_t buffer_size = 10;
glCreateBuffers(1, &buffer_vertices);
glNamedBufferStorage(buffer_vertices, buffer_size * sizeof(glm::vec4), nullptr, GL_DYNAMIC_STORAGE_BIT);
//Bind buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer_vertices);
//Run shader.
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glm::vec4 vertices[10];
glGetNamedBufferSubData(buffer_vertices, 0, buffer_size * sizeof(glm::vec4), &vertices);
printf("Vertex data after: \n");
for (int i = 0; i < 10; i++)
printf("%f %f %f %f \n", vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3]);
printf("\n");
glfwTerminate();
return 0;
}
输出:
Vertex data after:
0.000000 0.000000 0.000000 0.000000
1.000000 1.000000 1.000000 1.000000
2.000000 2.000000 2.000000 2.000000
3.000000 3.000000 3.000000 3.000000
4.000000 4.000000 4.000000 4.000000
5.000000 5.000000 5.000000 5.000000
6.000000 6.000000 6.000000 6.000000
7.000000 7.000000 7.000000 7.000000
8.000000 8.000000 8.000000 8.000000
9.000000 9.000000 9.000000 9.000000