- 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);
}