【问题标题】:Make a shader storage buffer in different shader programs accessible使不同着色器程序中的着色器存储缓冲区可访问
【发布时间】:2019-03-14 17:57:06
【问题描述】:

我必须做哪些布局和绑定才能使(工作的)着色器存储缓冲区在第二个着色器程序中可读? 我设置并填充了一个成功绑定并在几何着色器中使用的 SSBO。该着色器读取和写入该 SSBO - 到目前为止没有问题。那里没有进行渲染。
在下一步中,我的渲染通道(第二个着色器程序)应该可以访问这些数据。这个想法是拥有一个大数据集,而第二个程序的顶点着色器在每次渲染调用时只使用一些索引来选择该 SSBO 的某些值。

我是否遗漏了一些特定的绑定命令,或者我将它们放置在错误的位置?
两个程序的布局是否一致?我把实例搞砸了吗?
我只是找不到在两个程序中使用的 SSBO 的任何示例..

创建、填充和绑定:

float data[48000];
data[0] = -1.0;
data[1] = 1.0;

data[2] = -1.0;
data[3] = -1.0;

data[4] = 1.0;
data[5] = -1.0;

data[6] = 1.0;
data[7] = 1.0;

data[16000] = 0.0;
data[16001] = 1.0;

data[16002] = 0.0;
data[16003] = 0.0;

data[16004] = 1.0;
data[16005] = 0.0;

data[16006] = 1.0;
data[16007] = 1.0;


GLuint ssbo;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);  

几何着色器中的实例化

layout(std140, binding = 1) buffer mesh
{
    vec2 points[8000];
    vec2 texs[8000];
    vec4 colors_and_errors[8000];
} mesh_data;  

另一个程序的顶点着色器中的第二个实例

layout(std140, binding = 1) buffer mesh
{
    vec2 points[8000];
    vec2 texs[8000];
    vec4 colors_and_errors[8000];
} mesh_data;  

这些实例是否相互对抗? 现在我没有在渲染循环中发布我的绑定,因为我不确定我在那里做什么。我尝试在更改使用的程序之前/之后进行绑定;没有成功。
有人有想法吗?

编辑:我是否还必须将 SSBO 绑定到渲染循环之外的第二个程序?以不同于第一次绑定的方式?

编辑:虽然我没有解决这个特殊问题,但我找到了一种可能更接近 opengl 的解决方法。
我在第二个程序中使用了第一个程序的 SSBO 作为顶点属性。这和opengl的索引渲染功能解决了这个问题。

(是否应该将其标记为已解决?)

【问题讨论】:

    标签: opengl glsl shader shader-storage-buffer


    【解决方案1】:

    您似乎已经完成了大部分工作,但您应该注意一些事项。

    两个程序的布局是否一致? layout(std140, binding = 1) 缓冲网格

    您需要小心这种布局。 std140 将四舍五入对齐到 vec4,因此将不再与您从 C 代码提供的数据对齐。在这种情况下,std430 应该适合你。

    我是否还必须将 SSBO 绑定到渲染循环之外的第二个程序?与第一次绑定的方式不同?

    一旦您绑定了 SSBO,假设两个程序都使用相同的绑定点(在您的示例中,它们是),那么您应该没问题。在程序之间共享数据很好,但需要同步。您可以通过内存屏障强制执行此操作。

    您没有提及 VAO,但您只能在绑定 VAO(不是默认的 VAO)后才能使用 SSBO。

    我认为这最好用一个例子来解释。

    第一个程序的顶点着色器。它使用缓冲区数据作为其位置和纹理坐标,然后翻转 Y 中的位置。

    layout(std430, binding = 1) buffer mesh {
        vec4 points[3];
        vec2 texs[3];
    } mesh_data;
    out highp vec2 coords;
    void main() {
        coords = mesh_data.texs[gl_VertexID];
        gl_Position = mesh_data.points[gl_VertexID];
        mesh_data.points[gl_VertexID] = vec4(gl_Position.x, -gl_Position.y, gl_Position.zw);
    }
    

    第二个程序的垂直着色器。它只使用数据但不修改它。

    layout(std430, binding = 1) buffer mesh {
        vec4 points[3];
        vec2 texs[3];
    } mesh_data;
    out highp vec2 coords;
    void main() {
        coords = mesh_data.texs[gl_VertexID];
        gl_Position = mesh_data.points[gl_VertexID];
    }
    

    在应用中,需要绑定一个VAO。

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    

    然后设置您的 SSBO。

    float const data[] = {
        -0.5f, -0.5f, 0.0f, 1.0,
        0.0f,  0.5f,  0.0f, 1.0,
        0.5f,  -0.5f, 0.0f, 1.0,
    
        0.0f, 0.0f,
        0.5f, 1.0f,
        1.0f, 0.0f
    };
    glGenBuffers(1, &ssbo);
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
    glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_DYNAMIC_COPY);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);
    

    使用第一个程序进行绘图调用。

    glUseProgram(first_program);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    

    插入内存屏障以确保在下一个绘图调用尝试从缓冲区读取之前完成前一个绘图调用的写入。

    glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
    

    使用第二个程序进行绘图调用。

    glUseProgram(second_program);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    

    我希望澄清一些事情!如果您有任何其他问题,请告诉我。

    【讨论】:

    • 感谢您的回答!我尝试了三种布局:std140、std430 和共享。我也已经使用了 glMemoryBarrier 和一个单独的 VAO。还是行不通。不过,我找到了解决方法,请参阅第二次编辑。
    • 很抱歉听到这对您不起作用。它在本地对我有用,所以虽然我很高兴你找到了解决方法,但我认为这个问题不应该被标记为已解决,因为原始问题尚未解决。我认为 glGetError 正在返回 GL_NO_ERROR?
    • 是的,到目前为止没有错误。只有一些关于使用存储缓冲区的使用提示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多