统一缓冲的数组元素不正确

时间:2016-06-20 14:53:40

标签: c++ opengl buffer

我一直在使用GL3.3编写一些内容,它采用统一缓冲区,并使用其中的信息在frag着色器中选择精灵图块。它在我的桌面上使用Nvidia GTX780,但我的基于AMD的笔记本电脑(A6-4455M)有一些问题。两者都是最新的(或最近的)司机。

回到代码,它首先设置一个统一缓冲区,它由两个uint和一个uint数组组成。然后它们被填充,并在着色器中访问。起初我在笔记本电脑上遇到GL错误,因为我没有足够的分配,但考虑填充的临时更改已经排除了,现在数据实际上正在被缓冲。

前两个优点没问题。我在渲染器中也有一些可读的数组,只有一个问题;数据乘以4!目前,数组只是一些测试数据,初始化为其索引,因此spriteArr [1] == 1,spriteArr [34] == 34等。但是,在着色器中访问它,spriteArr [10]给出40。这一直到spriteArr [143] == 572。除此之外,还有别的东西。我不知道为什么会这样,但它似乎是一个不正确的偏移。

我正在使用共享的统一布局,并从GL本身获得统一的偏移,因此它们应该是正确的。我注意到AMD卡上的偏移量要大得多,就好像它增加了更多的填充。它们在桌面上总是为0,4,8,而在笔记本电脑上为0,16,32。

如果它有任何区别,还有另一个UBO(绑定点0),用于视图和投影矩阵。这些按预期工作。但是它不会在片段着色器中使用。它也是在这个UBO之前创建的。

UBO初始化代码:

GLuint spriteUBO;
glGenBuffers(1, &spriteUBO);
glBindBuffer(GL_UNIFORM_BUFFER, spriteUBO);
unsigned maxsize = (2 + 576 + 24) * sizeof(GLuint);
/*Bad I know, but temporary. AMD's driver adds 24 bytes of padding. Nvidias has none.
 Not the cause of this problem. At least ensures we have enough allocated. */

glBufferData(GL_UNIFORM_BUFFER, maxsize, NULL, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
//Set binding point
GLuint spriteUBOIndex = glGetUniformBlockIndex(programID, "SpriteMatchData");
glUniformBlockBinding(programID, spriteUBOIndex, 1);


static const GLchar *unames[] = 
{
    "width", "height", 
    //"size", 
    "spriteArr"
};

GLuint uindices[3];
GLint offsets[3];
glGetUniformIndices(programID,3,unames,uindices);
glGetActiveUniformsiv(programID, 3, uindices, GL_UNIFORM_OFFSET, offsets);

//buffer stuff
glBindBufferBase(GL_UNIFORM_BUFFER, 1, spriteUBO);
glBufferSubData(GL_UNIFORM_BUFFER,offsets[0], sizeof(GLuint), tm.getWidth());
glBufferSubData(GL_UNIFORM_BUFFER, offsets[1], sizeof(GLuint), tm.getHeight());
glBufferSubData(GL_UNIFORM_BUFFER, offsets[2], tm.getTileCount() * sizeof(GLuint), tm.getSpriteArray());

Fragment Shader:

layout (shared) uniform SpriteMatchData{
uint width, height;
uint spriteArr[576];};

然后我在实验中使用类似的东西进行实验:

if(spriteArr[10] == uint(40))
{
debug_colour = vec4(0.0,1.0,0.0,0.0);//green
}
else
{
debug_colour = vec4(1.0,0.0,0.0,0.0); //red
}

在此实例中,debug_colour变为绿色。

有没有办法用适合两个系统的东西来解决这个问题?为什么AMD驱动程序处理方式如此不同?它处理统一的uint数组的方式可能是一个错误吗?

1 个答案:

答案 0 :(得分:1)

  

为什么AMD驱动程序的处理方式如此不同?

因为那是你要求的:

layout (shared) uniform SpriteMatchData

您明确要求shared布局。该布局是实现定义。因此,允许两种不同的实现为您提供两种不同的布局。因此,如果您想以独立于平台的方式使用SpriteMatchData,则必须在链接后从程序中查询其布局。

当您确实查询了值的偏移量时,您确实查询数组步长:数组中元素与元素之间的字节偏移量。规范中没有任何内容要求shared布局紧密打包数组。

实际上,我们几乎没有理由不使用std140布局。您可以避免所有这些对偏移的查询,只需设计可以由GLSL直接使用的C ++结构。