2

A game uses software rendering to draw a full-screen paletted (8-bit) image in memory.

What's the fastest way to put that image on the screen, using OpenGL?

Things I've tried:

  • glDrawPixels with glPixelMap to specify the palette, and letting OpenGL do the palette mapping. Performance was horrendous (~5 FPS).
  • Doing palette mapping (indexed -> BGRX) in software, then drawing that using glDrawPixels. Performance was better, but CPU usage is still much higher than using 32-bit DirectDraw with the same software palette mapping.

Should I be using some kind of texture instead?

Vladimir Panteleev
  • 24,651
  • 6
  • 70
  • 114
  • Definitely. Load the image as a texture object, then draw a quad (or two triangles) textured with that image. – Ben Zotto Sep 21 '12 at 05:40
  • Even though the image will change every frame? – Vladimir Panteleev Sep 21 '12 at 05:44
  • 2
    @CyberShadow: Well, what else are you going to do? Your image data is in client memory, not on the GPU. Before the GPU can render it, it needs to *get* to the GPU. Such as by putting it in a texture. – Nicol Bolas Sep 21 '12 at 05:46
  • Thanks. I guess it's just counter-intuitive to me that creating a texture (with all its overhead) would be faster than simply calling a function specifically meant for this task. – Vladimir Panteleev Sep 21 '12 at 05:56
  • And still you can speed up texture upload using Async DMA transfer with PBOs ping-pong.Google for it.Here is one of the resources:http://www.songho.ca/opengl/gl_pbo.html .You can gain x10 -x16 load time( your texture should be read from the memory ,not from IO ) – Michael IV Sep 21 '12 at 08:08
  • 1
    @CyberShadow You don't create a texture every frame (which indeed brings some additional overhead). You merely update its image using `glTexSubImage2D` (and the `Sub` in there is important). And of course *Michael* is right about using PBOs to your advantage. But `glDrawPixels` is by far the slowest thing you could do. – Christian Rau Sep 21 '12 at 08:28

1 Answers1

6
  • glDrawPixels with glPixelMap to specify the palette, and letting OpenGL do the palette mapping. Performance was horrendous (~5 FPS).

That's not a surprise. glDrawPixels is not very fast to begin with and glPixelMap will do the index/palette → RGB conversion on the CPU in a surely not very optimized codepath.

  • Doing palette mapping (indexed -> BGRX) in software, then drawing that using glDrawPixels.

glDrawPixels is about one of the slowest functions in OpenGL there is. This has two main reasons: First it's a codepatch not very much optimized, second it writes directly into the target framebuffer, hence forcing the pipeline into synchronization every time it's called. Also on most GPU it isn't backed by any cache.

What I suggest is you place your indexed image into single channel texture, e.g. GL_R8 (for OpenGL-3 or later) or GL_LUMINANCE8, and your palette into a 1D RGB texture, so that the index used as texture coordinate does look up the color. Using a texture as a LUT is perfectly normal. With this combination you use a fragment shader for in-situ palette index to color conversion.

The fragment shader would look like this

#version 330

uniform sampler2D image;
uniform sampler1D palette;

in vec2 texcoord;

void main()
{
    float index = tex2D(image, texcoord).r * 255.f; // 255 for a 8 bit palette
    gl_FragColor = texelFetch(palette, index, 0);
}
datenwolf
  • 159,371
  • 13
  • 185
  • 298