【问题标题】:Uniform buffered array elements are incorrect统一缓冲数组元素不正确
【发布时间】:2016-06-20 23:06:41
【问题描述】:

我一直在使用 GL3.3 编写一些东西,它采用统一缓冲区,并使用其中的信息在片段着色器中选择精灵图块。它在我的台式机上运行,​​配备 Nvidia GTX780,但我的基于 AMD 的笔记本电脑 (A6-4455M) 存在一些问题。两者都在最新(或最近)的驱动程序上。

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

前两个 uint 没问题。我还在着色器中得到了一些可读的数组,只有一个问题;数据乘以四!目前数组只是一些测试数据,初始化为其索引,所以 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());

片段着色器:

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 数组的方式的错误?

【问题讨论】:

    标签: c++ opengl buffer


    【解决方案1】:

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

    因为那是你要求的:

    layout (shared) uniform SpriteMatchData
    

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

    虽然您确实查询了值的偏移量,但您确实没有查询数组步幅:数组中从元素到元素的字节偏移量。规范中没有任何内容要求 shared 布局紧密封装数组。

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

    【讨论】:

    • 谢谢,稍后我会检查一下数组步幅,我忘记了这些,并自动假设它们是正确的。看来这可能是问题所在。
    • 刚刚做了一个快速测试,是的,步幅不同。 4 在台式机上和 16 在笔记本电脑上,这将适合我得到的。我猜默认数组步幅是为 vec4s 数组设置的,而不是为 uints 设置的。我之前没有使用 std140,因为我遇到了一些问题,但我现在再试一次,我知道它可能与数组步幅或没有为其额外的填充分配足够的空间有关。
    猜你喜欢
    • 1970-01-01
    • 2020-09-05
    • 2021-05-03
    • 2012-02-16
    • 1970-01-01
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    相关资源
    最近更新 更多