1

我正在使用计算着色器来处理输入缓冲区数据并使用 imagestore() 将其存储为输出纹理。

执行计算着色器后,我依次进行了 3 次渲染调用。

计算着色器代码:

#version 310 es
precision mediump image2D;
layout(std430) buffer; // Sets the default layout for SSBOs 
layout(local_size_x = 256) in; // 256 threads per work group
layout(binding = 0) readonly buffer InputBuf 
{
    uint input_buff[];
} inputbuff;
layout (rgba32f, binding = 1 ) uniform writeonly image2D out_teximg;
void main()
{
    int idx = int(gl_GlobalInvocationID.x);
    int idy = int(gl_GlobalInvocationID.y);
    unsigned int inputpix = inputbuff[1024 * idy + idx];
    // some calculation on inputpix and output is rcolor, bcolor, gcolor
    imageStore(out_teximg, ivec2(idx , idy), vec4(rcolor, bcolor, gcolor, 1.0)); 
    barrier();
};

代码:

void initCompute()
{
    glGenTextures(1, &computeOutTex);
    glGenBuffers(1, &inSSBOId);
}

uint inputBuffData = { .... }; // input buffer data
void execute_compute()
{
    // compute shader code starts...
    glUseProgram(computePgmId);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, computeOutTex);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, width, height);

    glBindImageTexture(1, computeOutTex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); // binding is 1 
    glUniform1i( glGetUniformLocation(computePgmId, "out_teximg"), 0);
    
    uint inputBuffSize = 1024 * 512 * 3;
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, inSSBOId);
    glBufferData(GL_SHADER_STORAGE_BUFFER, inputBuffSize, inputBuffData, GL_STATIC_DRAW);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER,  0 , inSSBOId); // binding is 0

    glDispatchCompute(width / 256, height, 1);
    glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
    // glFinish();
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
    glBindImageTexture(1, 0, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);  // binding is 1 
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);// binding is 0
}

int draw()
{
    glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId); // Offscreen Rendering
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(compute_pgm); 
    execute_compute();

    glUseProgram(render_pgm1);
    glViewport(0,0,w,h);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, computeOutTex);
    glDrawElements(); // Render the texture data

  // 2nd draw call 
    glUseProgram(render_pgm2);
    ....
    ....
    glDrawElements();

  // 3rd draw call
    glUseProgram(render_pgm3);
    ....
    ....
    glDrawElements(); 
    
    glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind FBO
}

在这里,唯一的第二次绘制调用在使用计算着色器后需要更多时间。

如果在 glMemoryBarrier() 之后调用 glFinish(),那么只有 execute_compute() 调用会减慢。为什么计算着色器会减慢后续的绘制调用?glFinish() 真的需要吗?

4

1 回答 1

2

计算着色器不会减慢后续的绘制调用。但是,计算着色器本身需要一些时间来执行。由于您正在设置内存屏障,因此后续的绘制必须等待。
OpenGL 命令被缓存并且在调用时不会立即执行。GPU 和 CPU 并行工作。CPU 向 GPU 发送指令,GPU 尽快处理它们。
glFinish准备好一切,直到所有先前调用的命令都完成后才返回。glFinish本身并不“昂贵”。在测量 CPU 上的时间时,它似乎“代价高昂”,因为它测量完成之前调用的 OpenGL 命令所需的时间。
反正glFinish这里不需要。您所需要的只是内存屏障。使用内存屏障时,以下依赖于此屏障的 OpenGL 命令似乎需要更长的时间才能完成。但是他们不再需要,他们只需要等待屏障指示的条件得到满足。

在您的情况下,您需要使用GL_ALL_BARRIER_BITSor GL_TEXTURE_FETCH_BARRIER_BIT,它反映了在障碍之前的不连贯内存写入(例如:图像存储),以在障碍之后获取纹理。

于 2022-01-04T07:23:29.720 回答