如何使用Shader Storage Buffer和std430建立glBindBufferRange()偏移量?

时间:2019-06-03 14:38:48

标签: c++ opengl

我想在ssbo数据之间切换以使用不同的设置绘制事物。为此,我需要使用glBindBufferRange()及其适当的偏移量。 我已经读过,对于ubo,偏移量必须是GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT的倍数,但是由于使用std430而不是std140,所以ssbo可能会改变某些情况。

我尝试过最简单的方法

struct Color
{
    float r, g, b, a;
};
struct V2
{
   float x, y;
};
struct Uniform
{
    Color c1;
    Color c2;
    V2 v2;
    float r;
    float f;
    int t;
};

GLuint ssbo = 0;
std::vector<Uniform> uniform;

int main()
{
    //create window, context etc.

    glCreateBuffers(1, &ssbo);
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);

    Uniform u;
    u.c1 = {255, 0, 255, 255 };
    u.c2 = {255, 0, 255, 255 };
    u.v2 = { 0.0f, 0.0f };
    u.r = 0.0f;
    u.f = 100.0f;
    u.t = 0;
    uniform.push_back(u);

    u.c1 = {255, 255, 0, 255 };
    u.c2 = {255, 255, 0, 255 };
    u.v2 = { 0.0f, 0.0f };
    u.r = 100.0f;
    u.f = 100.0f;
    u.t = 1;
    uniform.push_back(u);

    u.c1 = {255, 0, 0, 255 };
    u.c2 = {255, 0, 0, 255 };
    u.v2 = { 0.0f, 0.0f };
    u.r = 100.0f;
    u.f = 0.0f;
    u.t = 0;
    uniform.push_back(u);

    glNamedBufferData(ssbo, sizeof(Uniform) * uniform.size(), uniform.data(), GL_STREAM_DRAW);

    for(int i = 0; i < uniform.size(); ++i) {
        glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, ssbo, sizeof(Uniform) * i, sizeof(Uniform));

        glDrawArrays(...);
    }

    //swap buffer etc.

    return 0;
}
#version 460 core

layout(location = 0) out vec4 f_color;

layout(std430, binding = 1) buffer Unif
{
    vec4 c1; 
    vec4 c2; 
    vec2 v2;   
    float r;  
    float f; 
    int t;      
};

void main()
{       
    f_color = vec4(t, 0, 0, 1);
}

当然有vao,vbo,顶点结构等,但它们不会影响ssbo。

不过,我遇到了GL_INVALID_VALUE glBindBufferRange()错误。而且这必须来自偏移量,因为我的下一次尝试将传输数据,但是顺序错误。

我的下一个态度是使用GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 还有我在互联网上找到的公式

    int align = 4;
    glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &align);
    int ssboSize = sizeof(Uniform) + align - sizeof(Uniform) % align;

所以只需更改glNamedBufferDataglBindBufferRange就像这样

 glNamedBufferData(ssbo, ssboSize * uniform.size(), uniform.data(), GL_STREAM_DRAW);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, ssbo, ssboSize * i, sizeof(Uniform));

这样,它几乎起作用了。如您所见,t

0;
1;
0;

所以opengl应该用颜色绘制3种形状-

vec4(0, 0, 0, 1); 
vec4(1, 0, 0, 1); 
vec4(0, 0, 0, 1); 

它会给他们错误的顺序

vec4(1, 0, 0, 1); 
vec4(0, 0, 0, 1); 
vec4(0, 0, 0, 1);

如何使它正确传输数据?

2 个答案:

答案 0 :(得分:1)

OpenGL spec (Version 4.6)在“ 6.1.1将缓冲区对象绑定到已索引的目标点”一节中声明了以下内容,以补充glBindBufferRange的错误条件:

  
      
  • 如果INVALID_VALUEBindBufferRange,则会产生buffer错误   非零offsetsize分别不满足为指定目标的那些参数描述的约束,如第6.7.1节所述。
  •   

SSBO的第6.7.1节“索引缓冲区对象限制和绑定查询”状态:

  
      
  • 起始偏移量:SHADER_STORAGE_BUFFER_START
  •   
  • 偏移量限制:SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT的值的倍数
  •   
  • 绑定大小SHADER_STORAGE_BUFFER_SIZE
  •   

根据表23.64“依赖于实现的总体明暗器限制”:

  

256 [带有以下脚注]:SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT的值是允许的最大值,而不是最小值。

因此,如果偏移量不是256的倍数(不是)的倍数,则根本无法保证该代码完全起作用。您可以通过运行的实现查询实际的限制,并相应地调整缓冲区内容,但是必须准备好它高达256个字节。

答案 1 :(得分:0)

我最终使用了struct alignas(128) Uniform。我想我的下一个目标是不使用硬编码对齐。