我正在浏览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 ++标准中是否有一个强有力的保证,即不会插入更多的填充,或者这是一个"实际上是便携式的"处理?
答案 0 :(得分:7)
OpenGL非常清楚地定义了std140
接口块的字节布局。您在C ++方面所要做的就是提供符合该布局的数据。如果您可以定义编译器将与std140
匹配的结构,那么您就可以了。你是怎么做到的?
您必须知道编译器用于布局类型的规则。
C ++ 11定义了一个名为" standard layout types"的概念。如果您遵循某些规则,您的类型是标准布局。现在,对于确切知道它们在内存中的布局方式来说,这并不是很有意义。 C ++告诉你关于布局的标准布局类型的唯一内容是忽略空基类(只要它保持标准布局)并且第一个NSDM将在类的最开始。也就是说,前面永远不会有填充物。
标准所说的另一件事是,相同访问类的NSDM将按顺序分配,后者的偏移量比之前的偏移量大。由于您不允许在标准布局类型中使用不同访问类别的不同NSDM,因此您可以依赖它们按指定顺序布局。
但就C ++标准而言,就是这样。 [class.mem] / 13声明实现可以出于各种原因在成员之间添加填充。
然而,非正式地,"标准布局类型的规则"给你一个很好的指导,以了解何时添加赢得这样的填充。遵循标准布局规则,对于大多数系统,您可以假设您的班级布局与所使用类型的大小和对齐方式一样紧密。
实施必须发挥作用吗?不,但我们没有理由认为他们不会赢。最糟糕的是,你总是可以检查实现是如何形成类型的。