首先,OpenGL中有8种类型的缓冲区对象:
- GL_ARRAY_BUFFER
- GL_ELEMENT_ARRAY_BUFFER
- GL_COPY_READ_BUFFER
它们是枚举,或者更具体地说是GLenum。其中GLenum是一个无符号的32位整数,可以说其值高达4743222432。
缓冲区对象的大多数用途都涉及将它们绑定到某个特定目标,例如
glBindBuffer(GL_ARRAY_BUFFER,Buffers[size]);
[void glBindBuffer(GLenum目标,GLuint缓冲区)]文档
我的问题是,如果它是一个枚举,那么它的唯一值必须分别为0、1、2、3、4……7,那么如果它只有7以内的值,为什么要一直把它变成32位整数呢?请原谅我对CS和OpenGL的了解,这似乎是不道德的。
枚举不仅用于缓冲区,而且在任何地方都需要符号常量。目前,分配了几千个枚举值(看看你的GL.h和最新的glext.h。注意,供应商会被分配他们的官方枚举范围,这样他们就可以在不干扰其他人的情况下实现供应商特定的扩展-所以32位枚举空间不是一个坏主意。此外,在现代CPU架构中,使用小于32位的枚举空间不会更有效率,所以这在性能方面不是问题。
更新:正如Andon M.Coleman所指出的,目前只有16位枚举范围被分配。链接OpenGL枚举分配策略可能很有用,该策略也有以下注释:
历史上,一些单个供应商扩展的枚举值以1000为块进行分配,从块[1002000102999]开始,向上递增。此范围内的值不能表示为16位无符号整数。这会给某些实现带来显著且不必要的性能损失。已经分配给供应商的这些块将继续分配,除非供应商自愿释放整个块,但不会分配该范围内的其他块。
大多数似乎都被删除了,取而代之的是16位值,但32位值一直在使用。在当前的glext.h中,仍然可以找到一些0xffff以上的(过时的)枚举,比如
#ifndef GL_PGI_misc_hints
#define GL_PGI_misc_hints 1
#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8
#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD
#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE
...
为什么要使用short?在什么情况下,通过为枚举和常量声明使用GLuint的short或uint8_t istead,您甚至可以节省超过8k ram(如果近千个GLenum的报告是正确的)?考虑到潜在的硬件不兼容和潜在的跨平台错误,即使在最初的2mb Voodoo3d图形硬件的背景下,尝试保存类似8k ram的东西也有点奇怪,更不用说OpenGL是为SGL超级计算机场创建的了。
此外,现代x86和GPU硬件一次对齐32或64位,您实际上会暂停CPU/GPU的操作,因为寄存器的24或56位必须归零,然后读取/写入,而它可以在复制后立即对标准int进行操作。从OpenGL开始,计算资源往往比内存更有价值,而在程序的生命周期中,你可能会进行数十亿次状态更改,如果你用uint8_t替换每个32位的GLuint枚举,你将节省大约10kb(千字节)的内存。我现在正努力不显得格外愤世嫉俗,呵呵。
例如,uint18_t等的一个有效原因是数据适合该比特深度的大数据缓冲区/算法。堆栈上的1024个int与1024个uint8_t变量是8k,我们要拆分8k以上的头发吗?现在考虑一个4000*2500*32位的4k原始位图图像,我们说的是几百兆,如果我们使用64位RGBA缓冲区来代替标准的8位RGBA8缓冲区,它的大小将是原来的8倍,或者如果我们使用32位RGBA编码,它的大度将增加四倍。将其乘以打开的纹理数或保存的图片数,用一点cpu操作来交换所有额外的内存是有意义的,尤其是在这种类型的工作中。
这就是使用非标准整数类型的意义所在。除非你在64k机器或其他系统上(比如老式的蜂鸣器,祝你好运,在上面运行OpenGL),否则如果你试图在const声明或引用计数器上节省一些内存,你只是在浪费每个人的时间。