11
\$\begingroup\$

For example, how detect if my videocard doesn’t support "bgr8" and convert it to another format, such as "rgba8" in software mode.

UPDATE: Sorry for the confusion. This question more about situation when I set internalFormat in glTexImage2D to something like "bgra8" but videodriver internally convert data to another format, like "rgba8".

\$\endgroup\$

2 Answers 2

12
\$\begingroup\$

Your question seems to confuse certain concepts, so let's take things from the top. This is the definition of the function glTexImage2D:

void glTexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data );

There are two things that you might call "texture formats". The first is the internalformat parameter. This is the real format of the image as OpenGL stores it. The format parameter describes part of the format of the pixel data you are providing with the data parameter.

To put it another way, format and type define what your data looks like. internalformat is how you're telling OpenGL to store your data. Let us call format and type the "pixel transfer format", while internalformat will be the "image format".

The image format of a texture can never be "bgr8". There is no GL_BGR8 image format enumerator. There is a GL_BGR enum, but that is for the pixel transfer format, not the image format.

Or to put it another way, your pixel data that you give OpenGL can be stored in BGR order. But the OpenGL implementation decides on its own how to actually store that pixel data. Maybe it stores it in little-endian order. Maybe it stores it big-endian. Maybe it just arbitrarily rearranges the bytes. You don't know, and OpenGL does not provide a way to find out.

There is no way to tell if a particular set of pixel transfer format parameters matches how the OpenGL implementation will store them given the image format.

There is a way to tell now. And by "now", I mean in OpenGL 4.3 and/or ARB_internalformat_query2. Coming to a graphics card near you:

GLenum format, type;
glGetInternalformativ(texture_target, GL_RGBA8, GL_TEXTURE_IMAGE_FORMAT, 1, &format);
glGetInternalformativ(texture_target, GL_RGBA8, GL_TEXTURE_IMAGE_TYPE, 1, &type);

format and type now have the implementation's preferred format and type for using glTex(Sub)Image calls to GL_RGBA8 images. There are separate format and type queries for glReadPixels downloads.

There are other queries you can make.

If you don't have access to these, you can use some general rules of thumb that most hardware will adhere to:

  • will store pixel data for 8-bit-per-channel data in BGRA order. So if you want to match the format with your pixel data, so as to more quickly upload texture data, you want to use GL_BGRA for the format, and GL_UNSIGNED_INT_8888 or GL_UNSIGNED_BYTE for the type.
  • will not actually store 24-bit colors as 24-bits. It will always pad them out to 32-bits; the alpha will just be ignored when it reads the data. So if you want to match formats, always use GL_BGRA format with GL_RGB8 image formats, even if you have to put dummy data in the alpha component.
\$\endgroup\$
2
  • 4
    \$\begingroup\$ I found also better use format GL_BGRA with internalFormat GL_RGBA http.download.nvidia.com/developer/Papers/2005/… \$\endgroup\$
    – KindDragon
    Commented Sep 22, 2011 at 21:43
  • \$\begingroup\$ I would refrain from rebranding the internalFormat parameter as "image format", because it's equally confusing. Perhaps it makes sense to think of "internalFormat" as the "texture pixel format". The "format" and "type" parameter combination are the "source pixel format" (which is often an image, hence my comment). And then of course there is the GPU format, which is BGRA for integer type formats. \$\endgroup\$
    – StarShine
    Commented Mar 2, 2017 at 14:13
7
\$\begingroup\$

Generally most hardware doesn't suport 3-component texture formats so in this specific example you can make a reasonably safe assumption that it's converted. A 3-component OpenGL texture is actually 4-component in hardware but with the alpha component ignored/set to 255/whatever.

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads (That "common mistakes" page is a goldmine - bookmark it now!)

For a more general case, glTexSubImage2D performance can give you a good indication of whether or not the upload must go through a software conversion path. You'd go about this during program startup - just create an empty texture (via glTexImage2D with NULL data), then issue a bunch of glTexSubImage2D calls, each followed by a glFinish to ensure it completes. Ignore the first one because caches/states/etc are being setup for it, and time the rest of them. Repeat this for a few different formats and pick the fastest.

Another alternative - seeing as you've tagged this question "Windows" - is to create a D3D device at startup (just after you've created your window but before you init OpenGL) then use D3D to check for format support. While OpenGL allows for software conversion to a valid internal format, D3D doesn't - if it's not supported by the hardware you can't do it. Then destroy D3D and bring up OpenGL. (This technique can also be used for querying other stuff that OpenGL doesn't let you query directly).

It's actually a useful rule of thumb to cross-check what you're doing in OpenGL with the D3D documentation. If D3D can't do something then it can be a good indication that the something in question is not supported in hardware. Not always true, but a useful starting place.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .