OpenGL Mistakes - GL_RGB

Discuss programming topics that involve the OpenGL API.
Post Reply
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

OpenGL Mistakes - GL_RGB

Post by mh »

It's common to see use of the GL_RGB format when specifying textures, and I assume that the author's intention is to save memory by not using a fourth component if the texture only needs 3.

But OpenGL doesn't actually work that way.

Let's look at the documentation so that we know what's going on (novel concept, that ;) )

http://www.opengl.org/sdk/docs/man/xhtm ... mage2D.xml
Each element is an RGB triple. The GL converts it to floating point and assembles it into an RGBA element by attaching 1 for alpha.
and
The last three arguments describe how the image is represented in memory; they are identical to the pixel formats used for glDrawPixels.
And glDrawPixels says: http://www.opengl.org/sdk/docs/man/xhtm ... quote]Each pixel is a three-component group: red first, followed by green, followed by blue; for GL_BGR, the first component is blue, followed by green and then red. Each component is converted to the internal floating-point format in the same way the red, green, and blue components of an RGBA pixel are. The color triple is converted to an RGBA pixel with alpha set to 1. After this conversion, the pixel is treated as if it had been read as an RGBA pixel.[/quote]
So the end result of the noble attempt to save memory not only doesn't save memory at all, but actually slows the program down by forcing OpenGL to expand 3 component textures to 4 components before it can use them.

In other words, GL_RGB (or any other 3 component format, for that matter) is evil. Don't do it.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
andrewj
Posts: 133
Joined: Mon Aug 30, 2010 3:29 pm
Location: Australia

Post by andrewj »

It seems unlikely to me that 3D cards are going to waste precious texture memory on color channels which are not needed.

Do you have any benchmarks which show that using GL_RGB is actually slower than using GL_RGBA?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

32bit rgba is bus aligned, rgb is not. that means that if that particular texture is stored in system ram instead of video ram, its much faster to access. keeping things aligned is not only faster, but its also cheaper and more reliable too.
There were benchmarks elsewhere on this site mostly centered on lightmaps.

Actually, its BGRA (by byte) which is fastest. RGBA still requires a conversion.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

andrewj wrote:It seems unlikely to me that 3D cards are going to waste precious texture memory on color channels which are not needed.

Do you have any benchmarks which show that using GL_RGB is actually slower than using GL_RGBA?
Depends on how you define "waste" - I prefer the word "use" in this kind of scenario. ;)

Even worse to waste precious cycles converting from an unaligned format to an aligned one, isn't it?

Benchmark:

Code: Select all

void R_CheckTexMode (void)
{
	int i;
	GLuint texnums[16];

	glGenTextures (16, texnums);

	glFinish ();
	Uint32 start = SDL_GetTicks ();

	for (i = 0; i < 16; i++)
	{
		glBindTexture (GL_TEXTURE_2D, texnums[i]);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, TEX_WIDTH, TEX_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, sibuffer);
	}

	glFinish ();
	Uint32 end = SDL_GetTicks ();
	printf ("GL_RGB: %i ms\n", (end - start));

	glDeleteTextures (16, texnums);
	glGenTextures (16, texnums);

	glFinish ();
	start = SDL_GetTicks ();

	for (i = 0; i < 16; i++)
	{
		glBindTexture (GL_TEXTURE_2D, texnums[i]);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, TEX_WIDTH, TEX_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, sibuffer);
	}

	glFinish ();
	end = SDL_GetTicks ();
	printf ("GL_RGBA: %i ms\n", (end - start));

	glDeleteTextures (16, texnums);
	glGenTextures (16, texnums);

	glFinish ();
	start = SDL_GetTicks ();

	for (i = 0; i < 16; i++)
	{
		glBindTexture (GL_TEXTURE_2D, texnums[i]);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, TEX_WIDTH, TEX_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, sibuffer);
	}

	glFinish ();
	end = SDL_GetTicks ();
	printf ("GL_BGRA: %i ms\n", (end - start));

	glDeleteTextures (16, texnums);
}
GL_RGBA is between 1.5 and 2.5 times faster than GL_RGB, GL_BGRA is between 5 and 8 times faster than GL_RGB.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Post by leileilol »

What about paletted textures?
i should not be here
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

leileilol wrote:What about paletted textures?
Unlikely to be supported in hardware: http://www.opengl.org/registry/specs/EX ... exture.txt
Intel 810/815.

Mesa.

Microsoft software OpenGL implementation.

Selected NVIDIA GPUs: NV1x (GeForce 256, GeForce2, GeForce4 MX,
GeForce4 Go, Quadro, Quadro2), NV2x (GeForce3, GeForce4 Ti,
Quadro DCC, Quadro4 XGL), and NV3x (GeForce FX 5xxxx, Quadro FX
1000/2000/3000). NV3 (Riva 128) and NV4 (TNT, TNT2) GPUs and NV4x
GPUs do NOT support this functionality (no hardware support).
Future NVIDIA GPU designs will no longer support paletted textures.

S3 ProSavage, Savage 2000.

3Dfx Voodoo3, Voodoo5.

3Dlabs GLINT.
(My emphasis).

They're a completely different case anyway, as is any other 1-component texture (GL_LUMINANCE, etc). I haven't benchmarked them.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Post by leileilol »

mh wrote:
leileilol wrote:What about paletted textures?
Unlikely to be supported in hardware
Fortunately, Nvidia hardware isn't everything. They probably GL_RGBA anything indexed on-load anyhow
i should not be here
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

leileilol wrote:Fortunately, Nvidia hardware isn't everything. They probably GL_RGBA anything indexed on-load anyhow
Nor is a Savage 3D running in a P 90 (with 16 MB RAM). ;)

So try this for size then: http://www.opengl.org/wiki/Common_Mista ... d_textures
Do not use the GL_EXT_paletted_texture extension. Support for it has been dropped by the major GL vendors.
So not supported on either NVIDIA or ATI, which does mean that on the majority of 3D cards that the majority of people have they're not supported.

Of course it's not "everything" still, but at the same time it's close enough to "everything" to be a workable rule of thumb for most practical purposes.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
andrewj
Posts: 133
Joined: Mon Aug 30, 2010 3:29 pm
Location: Australia

Post by andrewj »

mh wrote:Even worse to waste precious cycles converting from an unaligned format to an aligned one, isn't it?
Why do you assume a conversion? I don't know anything about how 3D hardware works under the hood, but it seems possible that RGB data could be used directly from texture memory, or the conversion could be done without cost while uploading the image data to the card.
GL_RGBA is between 1.5 and 2.5 times faster than GL_RGB, GL_BGRA is between 5 and 8 times faster than GL_RGB.
Wow that's..... surprising.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

andrewj wrote:
mh wrote:Even worse to waste precious cycles converting from an unaligned format to an aligned one, isn't it?
Why do you assume a conversion?
Because the spec and the documentation says so.

Check the links in my first post for the documentation. The spec for all of the glTexImage functions says:
The selected groups are processed exactly as for DrawPixels, stopping just before final conversion. Each R, G, B, A, or depth value so generated is clamped to [0, 1].
And:
Each group is converted to a group of 4 elements as follows: if a group does not contain an A element, then A is added and set to 1.0. If any of R, G, or B is missing from the group, each missing element is added and assigned a value of 0.0.
andrewj wrote:...the conversion could be done without cost while uploading the image data to the card.
This is pretty much what I mean. There's no runtime impact here for most standard textures, but be aware that the conversion is done and that you're not saving memory at all. It's not without cost though; the trade-off is much slower texture loading, and therefore much slower map loading.

There is however runtime impact if you're subsequently modifying a texture as the conversion will need to be done at runtime too.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Entar
Posts: 439
Joined: Fri Nov 05, 2004 7:27 pm
Location: At my computer
Contact:

Post by Entar »

I hope there will be more in this "OpenGL Mistakes" series :)
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Post by frag.machine »

Entar wrote:I hope there will be more in this "OpenGL Mistakes" series :)
I'd call it "best practices" than "mistakes" :)
But nonetheless, good stuff mh. Bring on it!
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

Pretty amazing stuff mh.

The inner workings of openGL and how you can extract fps from them.
Post Reply