当c ++没有指定struct layout时,为什么glBufferData缓冲区可以用于UBO和SSBO

时间:2016-07-18 04:37:17

标签: c++ opengl struct

我正在浏览Android docs页面,了解如何在openGL中使用统一缓冲区对象,并看到以下结构:

struct shader_data_t
{
    float camera_position[4];
    float light_position[4];
    float light_diffuse[4];
} shader_data;

使用

缓冲到openGL Uniform Buffer Object中
GLuint ubo = 0;
glGenBuffers(1, &ubo);
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
glBufferData(GL_UNIFORM_BUFFER, sizeof(shader_data), &shader_data, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);

并在着色器中用作

...
layout (std140) uniform shader_data
{ 
  vec4 camera_position;
  vec4 light_position;
  vec4 light_diffuse;
};
...

但是,当glBufferData转换结构指针和void指针时,我不明白openGl如何知道如何将结构中的数据映射到制服,这应该使openGL不知道结构的内存布局。 c ++ struct layout是实现定义的,虽然UBO的作者和其他用户用虚拟变量手动填充c ++结构以匹配着色器中的标准化std140布局,但是什么阻止c ++编译器添加更多填充并破坏布局?在c ++标准中是否有一个强有力的保证,即不会插入更多的填充,或者这是一个"实际上是便携式的"处理?

1 个答案:

答案 0 :(得分:7)

OpenGL非常清楚地定义了std140接口块的字节布局。您在C ++方面所要做的就是提供符合该布局的数据。如果您可以定义编译器将与std140匹配的结构,那么您就可以了。你是怎么做到的?

您必须知道编译器用于布局类型的规则。

C ++ 11定义了一个名为" standard layout types"的概念。如果您遵循某些规则,您的类型是标准布局。现在,对于确切知道它们在内存中的布局方式来说,这并不是很有意义。 C ++告诉你关于布局的标准布局类型的唯一内容是忽略空基类(只要它保持标准布局)并且第一个NSDM将在类的最开始。也就是说,前面永远不会有填充物。

标准所说的另一件事是,相同访问类的NSDM将按顺序分配,后者的偏移量比之前的偏移量大。由于您不允许在标准布局类型中使用不同访问类别的不同NSDM,因此您可以依赖它们按指定顺序布局。

但就C ++标准而言,就是这样。 [class.mem] / 13声明实现可以出于各种原因在成员之间添加填充。

然而,非正式地,"标准布局类型的规则"给你一个很好的指导,以了解何时添加赢得这样的填充。遵循标准布局规则,对于大多数系统,您可以假设您的班级布局与所使用类型的大小和对齐方式一样紧密。

实施必须发挥作用吗?不,但我们没有理由认为他们不会赢。最糟糕的是,你总是可以检查实现是如何形成类型的。