我已经写了一个小的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(...)之后从图形处理器加载数据。它们在那里,问题似乎出在缓冲区和着色器之间的连接上。我还尝试读取着色器中的数据并将其输出到屏幕,它们始终为0,这支持我的假设。基本上,我似乎能够从CPU写入/读取SSBO,但不能从着色器读取。有人能帮我找出问题所在吗?
发布于 2016-11-05 16:17:14
为什么要将binding_point ( 0)传递给memcpy函数?通过这种方式,您可以复制0字节的数据。
memcpy(&(this->number_of_lines),mapped_ssbo,this->binding_point);发布于 2016-11-06 15:00:06
我假设其中至少有一个...线条是你忽视的记忆障碍吗?
您需要跨并行调用的某种形式的同步来确保一致性,当使用SSBO、映像加载/存储等时,这不是自动的。您可能会在没有屏障的情况下读取未定义的值,因为每个执行单元都有相同内存的不同(隔离)视图。
确保对SSBO所做的更改对其他着色器调用可见,在执行读取之前需要在GLSL代码中设置障碍。其他类型的非相干操作可能需要GL命令流中的屏障,但前提是相同的;对命令和读/写内存进行排序,以便后续操作使用前一个操作的结果。
https://stackoverflow.com/questions/40430105
复制相似问题