Uniform buffers,glGetActiveUniformBlockiv报告的大小

3
我看到一个问题,即我获取GLSL统一块的错误大小。
这是着色器中的块:
uniform MaterialInfo {
    vec3 Ka;
    vec3 Ks;    
    vec3 Kd;
};

接下来是准备我的统一缓冲区对象的代码:

blockIndex = glGetUniformBlockIndex(program, "MaterialInfo");
 if (blockIndex == -1) {
   fprintf(stderr, "Could not bind uniform block\n");
}

printf("Found blockindex materialinfo: %d\n", blockIndex);

 glGetActiveUniformBlockiv(program, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
 blockBuffer = (GLubyte *) malloc(blockSize);
 cout << "GLSL blocksize: " << blockSize << endl;
 cout << "sizeof glm::vec3 type: " << sizeof(mesh->Ka) << endl;
 cout << "sizeof 3 x glm::vec3 type: " << 3 * sizeof(mesh->Ka) << endl;

以下是报告内容:
GLSL blocksize: 48
sizeof glm::vec3 type: 12
sizeof 3 x glm::vec3 type: 36

总的来说,我原本预期GLSL块大小应该是36,而不是48。GLSL中的vec3应该像我的glm :: vec3类型一样是一个float。
还请注意,我正在使用HD4000 beta驱动程序:OpenGL 4.0.0 Build 9.17.10.2792。我没有机会在另一台计算机上进行测试。 这是我误解了什么吗?
回复后跟进:
所以,在这种情况下,提交我的glm :: vec3浮点数的正确方法是以下方式吗?
glGetUniformIndices(program, 3, namesMaterial, indices);
glGetActiveUniformsiv(program, 3, indices, GL_UNIFORM_OFFSET, offset);

memcpy(blockBuffer + offset[0], glm::value_ptr(mesh->Ka), 4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[1], glm::value_ptr(mesh->Ks), 4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[2], glm::value_ptr(mesh->Kd), 4 * sizeof(GLfloat));

对齐?我敢打赌那些vec3被填充成了vec4。 - genpfault
2个回答

3

许多GPU将每个uniform填充为vec4的大小:

请参考OpenGL维基百科的实现说明(强调是我的):

实现注意事项:OpenGL实现允许出于实现相关原因拒绝着色器。所以,即使根据您的计算得到较少的活动uniform部件,仍可能由于uniform限制而无法链接。这通常发生在本质上是矢量硬件的硬件上。GeForce 8xxx之前的硬件和所有ATi硬件都是这样的。在这种情况下,您应该假设每个单独的uniform占用4个部件,就像在D3D中一样。这意味着"uniform float"是4个部分,mat2x4是16个部分(每行4个部分),但mat4x2是8个部分。


3
总之,我原本期望GLSL块大小为36,而不是48。GLSL中的vec3应该像我的glm :: vec3类型一样是float。
为什么?OpenGL规范中没有保证块大小是多少。
或者至少,不是用那个统一块的定义。
如果不提供适当的内存布局限定符,则默认使用共享。这允许实现在元素之间放置任何它感觉舒适的填充。因此,您不能仅仅假设3个vec3将占用12个连续的float大小。每个vec3将是3个连续的float,但不能保证不会有填充。
如果要获得固定、已知且一致的统一块布局,则需要使用std140布局。否则,您将得到实现所给出的内容。OpenGL规范详细说明了std140元素布局的规则。
当然,使用std140布局,此块的大小也将为48,因为它将所有vec3元素填充到vec4中。
在这种情况下,正确的提交glm::vec3浮点数的方式是什么?
假设以下内容是正确的: 1. memoryBlock是映射缓冲对象指针或使用glBufferSubData上传的内容。 2. 您将其上传到缓冲区的前面或适当的偏移量(uniform块的glBindBufferRange偏移必须对GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT进行对齐)。 3. mesh->Ka及其类别实际上包含4个浮点数。否则,您将从未分配的内存中复制。
再次强烈建议您停止查询此类信息并使用std140布局。这样做时,您不必查询偏移量或任何其他内容;您可以设计与GLSL定义在所有硬件上完全兼容的结构体。

谢谢回复。我更新了我的问题,并提出了如何创建blockBuffer的后续问题。这是正确的方法吗?我问的原因是,当只有一个统一块时,它可以工作,但是一旦我添加第二个统一块,就会崩溃。 - toeplitz
@toeplitz: Stack Overflow 不会很快用完数据库空间。如果您想要关于另一个(即使有些相关)问题的后续问题,请再次按“提问”按钮。不过,我更新了我的答案,以评论您的问题。如果您想要解决崩溃问题,请提出一个新问题,其中包含您的代码。 - Nicol Bolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接