c – 如何使可移植和编译器无关的glBufferData?

This question询问是否可以依赖编译器来处理结构值的顺序和填充.

根据这个问题的答案,

OpenGL defines, very clearly, what the byte layout of a std140 interface block is.

C++11 defines a concept called 07001.

The only things C++ tells you about standard layout types with regard to layout is that empty base classes are ignored (so long as it remains standard layout) and that the first NSDM will be at the very beginning of the class. That is, there will never be padding at the front.

The other thing the standard says is that NSDMs of the same access class will be allocated in order, with later ones having larger offsets than earlier ones.

But that’s it, as far as the C++ standard is concerned. [class.mem]/13 states that implementations can add padding between members for various reasons.

那可能但不总是存在填充可能真的搞砸了,最糟糕的部分 – 它取决于编译器.

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

例如:

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];
};

或者天真的方法是否足够好?

(假设类/结构不仅仅是那个,而且可能会改变)

最佳答案 “编译器无关”?没有这样的动物.你试图写一个证明了它.考虑您的struct成员定义:

GLfloat data[12];

这需要存在GLfloat类型.但问题是,C没有定义那种类型. OpenGL呢.

OpenGL非常清楚地定义了这种类型:它是一个IEEE-754 floating-point type, using the BINARY32 format.

问题是,C不要求浮点符合那个.实际上,C并不要求任何类型符合这一点.如果编译器希望浮点数使用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需要它.除非您使用单独的属性缓冲区(和I strongly suggest you do if it’s available),否则您的代码和您调用的OpenGL代码将依赖于此未定义的行为.

OpenGL将GLint定义为带符号,二进制补码,32位整数.但是C不需要任何整数类型作为二进制补码.

但OpenGL确实如此.

OpenGL flat out无法在类型不同的系统上运行.它不能在具有9位字节的系统上运行.它不能在使用有符号整数数学补码的系统上运行.我可以坚持下去,但我认为我的观点很明确.

通过选择使用OpenGL(Vulkan,如果你想知道),你已经依赖于实现定义的行为.那么,当您已经依赖于大量其他实现定义的行为时,为什么还要让您的生活更难以避免这些特定的实现定义行为?

这匹马离开了谷仓;现在关门没有帮助.

点赞