如何制作一个可移植的和编译器无关的glBufferData?

How to make a portable & compiler-agnostic glBufferData?

本文关键字:编译器 glBufferData 可移植 何制作 一个      更新时间:2023-10-16

这个问题问是否可以依靠编译器来不弄乱struct的值顺序和填充。

根据这个问题的答案,

OpenGL非常清楚地定义了std140接口块的字节布局。

C++11 定义了一个称为"标准布局类型"的概念。

C++告诉您有关布局的标准布局类型的唯一内容是忽略空基类(只要它仍然是标准布局),并且第一个 NSDM 将位于类的最开头。也就是说,前面永远不会有填充物。

该标准所说的另一件事是,相同访问类的 NSDM 将按顺序分配,较晚的 NSDM 比较早的具有更大的偏移量。

但仅此而已,就C++标准而言。[class.mem]/13 指出,由于各种原因,实现可以在成员之间添加填充。

这种可能但并不总是存在的填充确实会把事情搞砸,最糟糕的部分 - 这取决于编译器。

<小时 />

为了避免错误和噩梦,使用与编译器无关的方法不是更好吗?

例如:

class BufferData
{
private:
    GLfloat data[12];
public:
    GLfloat* getCameraPosition()
    {
        return (GLfloat*) &data[0];
    }
    GLfloat* getLightPosition()
    {
        return (GLfloat*) &data[4];
    }
    GLfloat* getLightDiffuse()
    {
        return (GLfloat*) &data[8];
    }
    GLfloat* getData()
    {
        return data;
    }
};

与天真相反:

struct BufferData
{
    GLfloat camera_position[4];
    GLfloat light_position[4];
    GLfloat light_diffuse[4];
};

还是幼稚的方法足够好?

(让我们假设类/结构不止于此,并且可能会更改)

"编译器不可知"?没有这样的动物。你试图写一个证明了这一点。考虑结构成员定义:

GLfloat data[12];

这需要存在GLfloat类型。但问题是,C++没有定义这种类型。OpenGL做到了。

OpenGL非常清楚地定义了该类型:它是IEEE-754浮点类型,使用BINARY32格式。

问题是,C++并不要求float符合这一点。事实上,C++并不要求其任何类型都符合这一点。如果编译器想要float使用IEEE-754以外的其他东西,那很好。

现在,您可能会说 OpenGL 标头可以将GLfloat定义为大小为 32 位的类类型,它将从编译器的 float 类型转换为 IEEE-754。当然,这可能会发生...除非无法拥有 32 位值。

那里有 9 位字节的系统。或 18 位字节。这些系统有C++编译器。此类系统不能声明大小仅为 32 位的类型。

但是能够传递 32 位值(更不用说 16 位和 8 位)是 OpenGL 的硬性要求。如果没有它,您将无法在缓冲区对象中传递任何数据。然而,C++并不需要它。

说到顶点数据,半现代OpenGL中最基本的功能之一是glVertexAttribPointer。它依赖于你将一个字节偏移量投射到一个void*中,然后它会投射回来。

C++不保证这有效。在C++标准中,没有任何地方要求如果你将一个整数转换为指针,然后将该指针投射回一个整数,你会得到相同的整数(它确实说ptr->int->ptr有效,但这并不意味着相反)。

然而,OpenGL需要它。除非你使用单独的属性缓冲区(如果可用,我强烈建议你这样做),否则你的代码和你调用的 OpenGL 代码依赖于这种未定义的行为。

OpenGL 将GLint定义为有符号、二进制补码、32 位整数。但是C++不需要任何整数类型是 2 的补码。

但OpenGL做到了。

OpenGL 完全无法在类型大小异常的系统上运行。它不能在具有 9 位字节的系统上运行。它不能在使用一个人的补码进行有符号整数数学的系统上运行。我可以继续这样做,但我认为我的观点很清楚。

通过选择使用OpenGL(如果你想知道的话,也可以使用Vulkan),你已经依赖于实现定义的行为。那么,当你已经依赖大量其他实现定义的行为时,为什么要让你的生活更加困难来避免这种特定的实现定义行为呢?

马已经走出谷仓了;现在关上门也无济于事。