使着色器存储缓冲区可在不同的着色器程序中访问

时间:2019-03-14 17:57:06

标签: opengl glsl shader shader-storage-buffer

我必须做什么布局和绑定才能使(工作的)着色器存储缓冲区在第二个着色器程序中可读? 我设置并填充了一个我成功绑定并用于几何着色器的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的索引渲染功能解决了这个问题。

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

1 个答案:

答案 0 :(得分:0)

似乎您已经走了很多路,但是您需要注意一些事项。

  

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

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

  

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

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

您没有提及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);

我希望这可以澄清一切!如果您还有其他问题,请告诉我。