我编写了一个小的OpenGL引擎,我想使用SSBO来允许着色器编写我可以写出的调试日志。我的日志类看起来像这样:
#define SHADER_LOG_LINE_LENGTH 128
#define SHADER_LOG_MAX_LINES 512
#define SHADER_LOG_DATA_OFFSET sizeof(int32_t) * 3
#define SHADER_LOG_DATA_SIZE SHADER_LOG_LINE_LENGTH * SHADER_LOG_MAX_LINES * sizeof(int32_t)
#define SHADER_LOG_TOTAL_SIZE SHADER_LOG_DATA_OFFSET + SHADER_LOG_DATA_SIZE
class ShaderLog
{
protected:
GLuint ssbo;
GLuint binding_point;
int32_t number_of_lines;
int32_t max_lines;
int32_t line_length;
int32_t data[SHADER_LOG_DATA_SIZE];
public:
ShaderLog()
{
glGenBuffers(1,&(this->ssbo));
this->number_of_lines = 0;
this->max_lines = SHADER_LOG_MAX_LINES;
this->line_length = SHADER_LOG_LINE_LENGTH;
this->binding_point = 0;
glBindBuffer(GL_SHADER_STORAGE_BUFFER,this->ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER,SHADER_LOG_TOTAL_SIZE,&(this->number_of_lines),GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER,this->binding_point,this->ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER,0);
};
void connect_to_shader(Shader *shader, string shader_variable_name)
{
GLuint block_index = 0;
block_index = glGetProgramResourceIndex(shader->get_shader_program_number(),GL_SHADER_STORAGE_BLOCK,shader_variable_name.c_str());
if (block_index == GL_INVALID_INDEX)
ErrorWriter::write_error("Shader log could not be connected to the shader.");
glBindBufferBase(GL_SHADER_STORAGE_BUFFER,block_index,this->binding_point);
glShaderStorageBlockBinding(shader->get_shader_program_number(),block_index,this->binding_point);
}
virtual void load_from_gpu()
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER,this->ssbo);
GLvoid* mapped_ssbo = glMapBuffer(GL_SHADER_STORAGE_BUFFER,GL_READ_ONLY);
if (mapped_ssbo == NULL)
ErrorWriter::write_error("Could not map shader log into client's memory space for reading.");
else
memcpy(&(this->number_of_lines),mapped_ssbo,SHADER_LOG_DATA_SIZE);
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
int get_number_of_lines()
{
return this->number_of_lines;
}
...
};
在我的片段着色器中,我做了:
#version 430
layout (std430, binding=0) buffer shader_log_data
{
int number_of_lines;
int max_lines;
int line_length;
int data[];
} shader_log;
...
void main()
{
shader_log.number_of_lines = 20; // just to test
shader_log.data[0] = 10000;
...
}
主程序看起来像这样:
void render()
{
... // rendering
shader_log->load_from_gpu();
cout << "lines: " << shader_log->get_number_of_lines() << endl;
glutSwapBuffers();
}
...
int main(int argc, char** argv)
{
...
shader_log = new ShaderLog();
...
shader_log->connect_to_shader(shader,"shader_log_data");
shader_log->update_gpu();
...
// rendering loop
...
}
现在写出的行数仍为0,即使着色器应将其设置为20。我尝试在glBufferData(...)之后从GPU加载数据并且它们在那里,问题似乎在缓冲区和着色器之间的连接中。我也尝试在着色器中读取数据并将它们输出到屏幕,它们总是为0,这支持了我的假设。基本上我似乎能够从CPU写入/读取SSBO,而不是从着色器读取/读取SSBO。任何人都可以帮我找到问题吗?
答案 0 :(得分:2)
为什么要将binding_point(为0)传递给memcpy函数?这样就可以复制0字节的数据。
memcpy(&(this->number_of_lines),mapped_ssbo,this->binding_point);
答案 1 :(得分:0)
我假设至少有一条......线条是你忽略显示的记忆障碍?
您需要在并行调用之间进行某种形式的同步以确保一致性,这在使用SSBO,图像加载/存储等时不是自动的。您可能会读取未定义的值而没有障碍,因为每个执行单元都有相同记忆的不同(孤立)视图。
确保您对SSBO所做的更改对其他着色器调用可见,在执行读取之前,需要在GLSL代码中设置一个屏障。其他类型的非相干操作可能需要GL命令流中的障碍,但前提是相同的;命令命令和读/写内存,以便后面的操作使用先前的结果。