OpenGL片段着色器不会写入SSBO

时间:2016-11-04 19:05:10

标签: opengl

我编写了一个小的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。任何人都可以帮我找到问题吗?

2 个答案:

答案 0 :(得分:2)

为什么要将binding_point(为0)传递给memcpy函数?这样就可以复制0字节的数据。

memcpy(&(this->number_of_lines),mapped_ssbo,this->binding_point);

答案 1 :(得分:0)

我假设至少有一条......线条是你忽略显示的记忆障碍?

您需要在并行调用之间进行某种形式的同步以确保一致性,这在使用SSBO,图像加载/存储等时不是自动的。您可能会读取未定义的值而没有障碍,因为每个执行单元都有相同记忆的不同(孤立)视图。

确保您对SSBO所做的更改对其他着色器调用可见,在执行读取之前,需要在GLSL代码中设置一个屏障。其他类型的非相干操作可能需要GL命令流中的障碍,但前提是相同的;命令命令和读/写内存,以便后面的操作使用先前的结果。