【问题标题】:Compute shader not writing to SSBO计算着色器不写入 SSBO
【发布时间】:2016-06-28 19:00:38
【问题描述】:

我正在编写一个简单的测试计算着色器,它将值 5.0 写入缓冲区中的每个元素。缓冲区的值被初始化为-1,这样我就知道创建缓冲区和读取缓冲区是否有问题。

class ComputeShaderWindow : public QOpenGLWindow {
  public:
    void initializeGL() {
        // Create the opengl functions object
        gl = context()->versionFunctions<QOpenGLFunctions_4_3_Core>();
        m_compute_program = new QOpenGLShaderProgram(this);
        auto compute_shader_s = fs::readFile(
                                    "test_assets/example_compute_shader.comp");
        // Adds the compute shader, then links and binds it
        m_compute_program->addShaderFromSourceCode(QOpenGLShader::Compute,
                compute_shader_s);
        m_compute_program->link();
        m_compute_program->bind();

        // Fills the buffer with -1, so we know whether the problem
        // is the compute shader not being invoked or not reading
        // the buffer correctly afterwards.
        GLfloat* default_values = new GLfloat[NUM_INVOCATIONS];
        std::fill(default_values, default_values + NUM_INVOCATIONS, -1.0);
        GLuint ssbo;
        gl->glGenBuffers(1, &ssbo);
        gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
        gl->glBufferData(GL_SHADER_STORAGE_BUFFER,
                         NUM_INVOCATIONS,
                         default_values,
                         GL_DYNAMIC_DRAW);
        gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
        gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
        gl->glDispatchCompute(NUM_INVOCATIONS / WORKGROUP_SIZE, 1, 1);
        gl->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
        gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
        gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);

        // Now map the buffer so that we can check its values
        GLfloat* read_data = (GLfloat*) gl->glMapBuffer(GL_SHADER_STORAGE_BUFFER,
                            GL_READ_ONLY);
        std::vector<GLfloat> buffer_data(NUM_INVOCATIONS);

        for (int i = 0; i < NUM_INVOCATIONS; i++) {
            buffer_data[i] = read_data[i];
        }

        gl->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);

        for (int i = 0; i < NUM_INVOCATIONS; i++) {
            DEBUG(buffer_data[i]);
        }
        assert(gl->glGetError() == GL_NO_ERROR);
    }

    void resizeGL(int width, int height) {

    }

    void paintGL() {

    }

    void teardownGL() {

    }

  private:
    QOpenGLFunctions_4_3_Core* gl;
    QOpenGLShaderProgram* m_compute_program;
    static constexpr int NUM_INVOCATIONS = 9000;
    static constexpr int WORKGROUP_SIZE = 128;
};

我的计算着色器相当简单:

#version 430 core

layout(std430, binding = 0) writeonly buffer SSBO {
    float data[];
};

layout(local_size_x = 128) in;

void main() {
    uint ident = gl_GlobalInvocationID.x;
    data[ident] = 5.0f;
}

当我读取缓冲区时,大多数是 -1,但一些数据由随机浮点值(-nan、0 等)组成。这是怎么回事?

编辑:将内存屏障更改为GL_BUFFER_UPDATE_BARRIER_BIT(甚至GL_ALL_BARRIER_BITS)并不能解决问题;我不明白这个问题是如何重复的。

【问题讨论】:

    标签: opengl buffer qt5 gpgpu compute-shader


    【解决方案1】:

    这个小问题我花了很长时间才弄明白。这里有几个错误。

    这一行

    gl->glBufferData(GL_SHADER_STORAGE_BUFFER,
                         NUM_INVOCATIONS,
                         default_values,
                         GL_DYNAMIC_DRAW);
    

    应该是

    gl->glBufferData(GL_SHADER_STORAGE_BUFFER,
                         NUM_INVOCATIONS * sizeof(float),
                         default_values,
                         GL_DYNAMIC_DRAW);
    

    以便我们复制正确数量的字节。而这个块应该是

    gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
    gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
    gl->glDispatchCompute(NUM_INVOCATIONS / WORKGROUP_SIZE, 1, 1);
    gl->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
    gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
    gl->glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
    

    应该是

    gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
    gl->glDispatchCompute(NUM_INVOCATIONS / WORKGROUP_SIZE, 1, 1);
    gl->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
    gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
    

    glBindBufferBase 调用将 ssbo 对象作为第三个参数。不知道为什么我最初给它0。此外 glBindBuffer 调用是不必要的(为了计算着色器的目的,我们只需要绑定到索引缓冲区目标)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-22
      • 1970-01-01
      • 1970-01-01
      • 2015-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多