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

Tre*_*ngs 3 c++ opengl struct

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

struct shader_data_t
{
    float camera_position[4];
    float light_position[4];
    float light_diffuse[4];
} shader_data;
Run Code Online (Sandbox Code Playgroud)

使用缓冲区缓冲到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);
Run Code Online (Sandbox Code Playgroud)

并在着色器中使用

...
layout (std140) uniform shader_data
{ 
  vec4 camera_position;
  vec4 light_position;
  vec4 light_diffuse;
};
...
Run Code Online (Sandbox Code Playgroud)

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

Nic*_*las 7

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

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

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

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

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

但是,非正式地,"标准布局类型"的规则为您提供了一个很好的指导,以便知道何时添加这种填充.遵循标准布局规则,对于大多数系统,您可以假设您的类的布局将与所使用类型的大小和对齐允许一样紧密.

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

  • @IvanRubinson非静态数据成员 (2认同)