像素数据一般会在 CPU 和 GPU 中进行传输,如果传输过程是从 GPU 到 CPU 一般称为压包(pack),从 CPU 到 GPU 的传输称为解包(unpack)。 glTexImage2D
WINGDIAPI void APIENTRY glTexImage2D (
GLenum target,
GLint level,
GLint internalformat, // OpenGL 内部存储格式
GLsizei width,
GLsizei height,
GLint border,
GLenum format, GLenum type, // 定义了 pixels 内存结构
const GLvoid *pixels
);
类似的,glReadPixels() 函数中也有一个 format 和 type,和上述的 type, format 含义相同, 即按照指定的格式从 OpenGL 显存内部读出到 buffer 中,也就是 pack 操作的格式。
glTexImage2D 中 format internalformat type 参数的含义 GL_RGBA8 & GL_RGBA 的探讨
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)data); 首先是积极的事情。 您使用内部尺寸格式(GL_RGBA8,而不是 GL_RGBA)。 这是非常好的,继续这样做。 您对内部格式(GL_RGBA8)和像素传输格式(GL_RGBA)之间的区别有清楚的了解。 这也很好。
internalformat
The number of color components in the texture. Must be 1, 2, 3, or 4, or one of the following symbolic constants: GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_ALPHA12, GL_ALPHA16, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, GL_LUMINANCE12, GL_LUMINANCE16, GL_LUMINANCE_ALPHA, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12, GL_LUMINANCE16_ALPHA16, GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY12, GL_INTENSITY16, GL_R3_G3_B2, GL_RGB, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12, GL_RGB16, GL_RGBA, GL_RGBA2, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2, GL_RGBA12, or GL_RGBA16.
format
The format of the pixel data. It can assume one of nine symbolic values. GL_COLOR_INDEX GL_RED GL_GREEN GL_BLUE GL_ALPHA GL_RGB GL_RGBA GL_BGR_EXT GL_BGRA_EXT GL_LUMINANCE GL_LUMINANCE_ALPHA
The format (7th argument), together with the type argument, describes the data you pass in as the last argument. So the format/type combination defines the memory layout of the data you pass in.
internalFormat (2nd argument) defines the format that OpenGL should use to store the data internally.
Often times, the two will be very similar. And in fact, it is beneficial to make the two formats directly compatible. Otherwise there will be a conversion while loading the data, which can hurt performance. Full OpenGL allows combinations that require conversions, while OpenGL ES limits the supported combinations so that conversions are not needed in most cases.
The reason GL_RGBA_INTEGER is not legal in this case that there are rules about which conversions between format and internalFormat are supported. In this case, GL_RGBA for the internalFormat specifies a normalized format, while GL_RGBA_INTEGER for format specifies that the input consists of values that should be used as integers. There is no conversion defined between these two.
While GL_RGBA for internalFormat is still supported for backwards compatibility, sized types are generally used for internalFormat in modern versions of OpenGL. For example, if you want to store the data as an 8-bit per component RGBA image, the value for internalFormat is GL_RGBA8.
Frankly, I think there would be cleaner ways of defining these APIs. But this is just the way it works. Partly it evolved this way to maintain backwards compatibility to OpenGL versions where features were much more limited. Newer versions of OpenGL add the glTexStorage*() entry points, which make some of this nicer because it separates the internal data allocation and the specification of the data.
格式(第 7 个参数)与类型参数一起描述了您作为最后一个参数传入的数据。因此,格式 / 类型组合定义了您传入的数据的内存布局。
internalFormat(第二个参数)定义了 OpenGL 内部存储数据时应使用的格式。
通常,两者会非常相似。实际上,使两种格式直接兼容是有益的。否则,在加载数据时会发生转换,这会损害性能。 完整的 OpenGL 允许需要转换的组合,而 OpenGL ES 限制了受支持的组合,因此在大多数情况下不需要转换。
在这种情况下,GL_RGBA_INTEGER 不合法是因为存在关于支持格式和 internalFormat 之间的转换的规则。 在这种情况下,internalFormat 的 GL_RGBA 指定规范化的格式,而 format 的 GL_RGBA_INTEGER 指定输入由应该用作整数的值组成。 两者之间没有定义转换。
虽然仍支持向内部兼容的 GL_RGBA 以实现向后兼容性,但在现代 OpenGL 版本中,大小类型通常用于 internalFormat。 例如,如果要将数据存储为每个组件 RGBA 图像 8 位,则 internalFormat 的值为 GL_RGBA8。
坦白说,我认为会有更干净的方法来定义这些 API。但这只是它的工作方式。它在某种程度上发展了这种方式, 以保持与功能受限得多的 OpenGL 版本的向后兼容性。较新版本的 OpenGL 添加了 glTexStorage*() 入口点,
这些入口点变得更好,因为它将内部数据分配和数据规范分开了。
定义了 format 是 GL_RGB,同时定义 type 是 GL_UNSIGNED_SHORT_5_6_5_REV,那么在解析的时候等同于: 定义 format 是 GL_BGR type 是 GL_UNSIGNED_SHORT_5_6_5。
// ES 2.0 says internalFormat must match pixelFormat (chapter 3.7.1 in Spec).
// Doesn't mention if "match" means "equal" or some other way of matching, but
// some bug on Emscripten and browsing discussions by others lead me to believe
// it means they have to be equal. Note that this was different in OpenGL.
internalFormat = pixelFormat;
OpenGL:
/* PixelFormat */
#define GL_RED 0x1903
#define GL_GREEN 0x1904
#define GL_BLUE 0x1905
#define GL_ALPHA 0x1906
#define GL_RGB 0x1907
#define GL_RGBA 0x1908
/* EXT_bgra pixelFormat */
#define GL_BGR_EXT 0x80E0
#define GL_BGRA_EXT 0x80E1
#define GL_ABGR_EXT 0x8000 // GL_EXT_abgr
#define GL_BGRA8_EXT 0x93A1 // 不常用
/* texture */
#define GL_ALPHA4 0x803B
#define GL_ALPHA8 0x803C
#define GL_ALPHA12 0x803D
#define GL_ALPHA16 0x803E
#define GL_R3_G3_B2 0x2A10
#define GL_RGB4 0x804F
#define GL_RGB5 0x8050
#define GL_RGB8 0x8051
#define GL_RGB10 0x8052
#define GL_RGB12 0x8053
#define GL_RGB16 0x8054
#define GL_RGBA2 0x8055
#define GL_RGBA4 0x8056
#define GL_RGB5_A1 0x8057
#define GL_RGBA8 0x8058
#define GL_RGB10_A2 0x8059
#define GL_RGBA12 0x805A
#define GL_RGBA16 0x805B
像素格式明确了 OpenGL 绘制平面的特性,如象素缓冲区是单缓冲还是双缓冲,数据是 RGBA 方式还是 Color Index 方式等。 每个 OpenGL 显示设备一般用名为 PIXELFORMATDESCRIPTOR 的结构来表示某个的像素格式,这个结构包含 26 个属性信息。 Win32 定义 PIXELFORMATDESCRIPTOR 如下所示:
typedef struct tagPIXELFORMATDESCRIPTOR { // pfd
WORD nSize; // nSize 是象素格式描述子结构的大小,sizeof(PIXELFORMATDESCRIPTOR) 设定其值;
WORD nVersion; // nVersion 是 PIXELFORMATDESCRIPTOR 结构的版本,一般设为 1;
DWORD dwFlags; // dwFlags 是一组表明象素缓冲特性的标志位,如缓冲是否支持 GDI 或 OpenGL 等;
BYTE iPixelType; // iPixelType 说明象素数据类型是 RGBA 还是颜色索引;
BYTE cColorBits; // cColorBits 每个颜色缓冲区中颜色位平面的数目,对颜色索引方式是缓冲区大小;
BYTE cRedBits; // cRedBits 每个 RGBA 颜色缓冲区中红色位平面的数目;
BYTE cRedShift; // cRedShift 每个 RGBA 颜色缓冲区中红色位平面的偏移数;
BYTE cGreenBits; // cGreenBits 每个 RGBA 颜色缓冲区中绿色位平面的数目;
BYTE cGreenShift; // cGreenShift 每个 RGBA 颜色缓冲区中绿色位平面的偏移数;
BYTE cBlueBits; // cBlueBits 每个 RGBA 颜色缓冲区中蓝色位平面的数目;
BYTE cBlueShift; // cBlueShift 每个 RGBA 颜色缓冲区中蓝色位平面的偏移数;
BYTE cAlphaBits; // cAlphaBits 每个 RGBA 颜色缓冲区中 alpha 位平面的数目(保留的,现不支持);
BYTE cAlphaShift; // cAlphaShift 每个 RGBA 颜色缓冲区中 alpha 位平面的偏移数(保留的,现不支持);
BYTE cAccumBits; // cAccumBits 累加缓冲区中全部位平面的数目;
BYTE cAccumRedBits; // cAccumRedBits 累加缓冲区中红色位平面的数目;
BYTE cAccumGreenBits; // cAccumGreenBits 累加缓冲区中绿色位平面的数目;
BYTE cAccumBlueBits; // cAccumBlueBits 累加缓冲区中蓝色位平面的数目;
BYTE cAccumAlphaBits; // cAccumAlphaBits 累加缓冲区中 alpha 位平面的数目;
BYTE cDepthBits; // cDepthBits Z(深度)缓冲区的深度;
BYTE cStencilBits; // cStencilBits 模板缓冲区的深度;
BYTE cAuxBuffers; // cAuxBuffers 轴向缓冲区的数量(一般 1.0 版本不支持);
BYTE iLayerType; // iLayerType 被忽略,为了一致性而包含的;
BYTE bReserved; // bReserved 表层和底层平面的数量::位 0-3 表最多 15 层表层平面,位 4-7 表底层;
DWORD dwLayerMask; // dwLayerMask 被忽略,为了一致性而包含的;
DWORD dwVisibleMask; // dwVisibleMask 是透明色彩的值(RGBA 方式)或是一个底层平面的索引(Index);
DWORD dwDamageMask; // dwDamageMask 被忽略,为了一致性而包含的。
} PIXELFORMATDESCRIPTOR;
Irrlicht: 内存中为:BGRA,文件存储通常 big-endian,为 ARGB。刚好是内存的反转。OpenGLColor RGBA。
//! An enum for the color format of textures used by the Irrlicht Engine.
/** A color format specifies how color information is stored.
NOTE: Byte order in memory is usually flipped (it's probably correct in bitmap files, but flipped on reading).
So for example ECF_A8R8G8B8 is BGRA in memory same as in DX9's D3DFMT_A8R8G8B8 format.
*/
enum ECOLOR_FORMAT {
//! Default 32 bit color format. 8 bits are used for every component: red, green, blue and alpha.
//! Warning: This tends to be BGRA in memory (it's ARGB on file, but with usual big-endian memory it's flipped)
ECF_A8R8G8B8,
};
//! Converts color to OpenGL color format
/** From ARGB to RGBA in 4 byte components for endian aware passing to OpenGL
\param dest: address where the 4x8 bit OpenGL color is stored.
*/
void toOpenGLColor(u8* dest) const
{
*dest = (u8)getRed();
*++dest = (u8)getGreen();
*++dest = (u8)getBlue();
*++dest = (u8)getAlpha();
}
#ifdef __BIG_ENDIAN__
((u32*)out)[x] = c << 24 | c << 16 | c << 8 | 0x000000FF;
#else
((u32*)out)[x] = 0xFF000000 | c << 16 | c << 8 | c;
#endif
If you have GL_RGBA and GL_UNSIGNED_INT_8_8_8_8, that means that pixels are stored in 32-bit integers, and the colors are in the logical order RGBA in such an integer, e.g. the red is in the high-order byte and the alpha is in the low-order byte.
But if the machine is little-endian (as with Intel CPUs), it follows that the actual order in memory is ABGR. Whereas, GL_RGBA with GL_UNSIGNED_BYTE will store the bytes in RGBA order regardless whether the computer is little-endian or big-endian.
GL_BGRA with GL_UNSIGNED_INT_8_8_8_8_REV would store colors in an integer in the logical order ARGB, but then on a little-endian machine, you get BGRA order in memory.
#if OGRE_ENDIAN == ENDIAN_BIG
/// 3 byte pixel format, 1 byte for red, 1 byte for green, 1 byte for blue
PF_BYTE_RGB = PF_R8G8B8,
/// 3 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red
PF_BYTE_BGR = PF_B8G8R8,
/// 4 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red and one byte for alpha
PF_BYTE_BGRA = PF_B8G8R8A8,
#else
/// 3 byte pixel format, 1 byte for red, 1 byte for green, 1 byte for blue
PF_BYTE_RGB = PF_B8G8R8,
/// 3 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red
PF_BYTE_BGR = PF_R8G8B8,
/// 4 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red and one byte for alpha
PF_BYTE_BGRA = PF_A8R8G8B8,
#endif