PDA

View Full Version : Render to texture with Uint8



RogerBennett
02-22-2016, 06:11 AM
Hi.
I coded myself in circles trying to get some render to texture code working in an eight bit environment. And I'd like some sanity checking.

Iím trying to slot in to an existing project that has an 8-bit blitter. So I want to render to the same surface that the current blitter does - looks like a simple RTT using a GL_RED and UNIT8 pixelformat with Nearest Neighbour filtering. I think I can do this with a fixed function pipeline.
Because this is SDL 1.2.15 I need to use the frame buffer EXT methods.

Before posting up a long description of the problem and two pages of code, I'm doing this to generate a colour buffer to render to. The SDL surface object, "image" has an allocated buffer of (width*height) size.

glGenTextures(1, &_colourBuffer);
glBindTexture(GL_TEXTURE_2D, _colourBuffer);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image->w, image->h, 0, GL_RED, GL_UNSIGNED_BYTE, image->pixels);

Then this is attached to GL_COLOR_ATTACHMENT0_EXT and I'm relying on the fixed function and GL_NEAREST to do all of the work.

Is this a terrible plan?
Am I going to face a world of hurt trying to draw to an eight bit surface?

I didn't want to post up a longer description and pages of code until I was sure that GL_RED, GL_UNSIGNED_BYTE was legal and the problem was with my implementation not my thought process.

GClements
02-22-2016, 03:23 PM
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image->w, image->h, 0, GL_RED, GL_UNSIGNED_BYTE, image->pixels);

If you want an 8-bit unsigned integer texture, this should be:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, image->w, image->h, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, image->pixels);

An internalformat parameter of GL_RED simply requests a single-channel normalised (fixed-point) format with unspecified precision. The format and type parameters indicate the format of the data used to initialise the texture; they have no effect upon the texture's internal format.

Note that the fixed-function pipeline can only render to such a texture when in colour-index mode, not in RGBA mode. But texturing is only available in RGBA mode. So you'd need to use shaders to render textures onto an integer framebuffer texture.

If you actually want an 8-bit normalised format, use:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, image->w, image->h, 0, GL_RED, GL_UNSIGNED_BYTE, image->pixels);

This can be rendered with the fixed-function pipeline; you'll only get the red channel.

If you're trying to emulate a system with 8-bit indexed-colour graphics, using a normalised texture is probably the simplest approach. Provided that you disable anything which will modify the colours (linear filtering, alpha-blending, modulation, etc), texture colours should be passed through without modification.

RogerBennett
02-22-2016, 04:08 PM
OK Thanks.
GL_R8UI isn't in the GL.h the project is using. Everything looks very old and dusty.

Its an SDL app that actually is an 8-bit indexed palette. I wanted to draw quads instead of using the 2D blit method so I can do scale, rotate etc..
I thought I might be able to create a texture from the SDL surface, attach it to GL_COLOR_ATTACHMENT0_EXT, and as long as I pretended everything was eight bit it'd still work.

OK.
I have some questions then. Normally I'd do something like this to sample from a texture in my fragment shader.
uniform sampler2D TextureAtlas;

vec3 colour = texture2D(TextureAtlas,gl_TexCoord[0].st).rgb;

If I was writing the same thing to read and write indicies, how do I pass the indexed image in and read it? using texture2D or some other method that returns a uint8?

And lastly though.. if GL_R8UI isn't available to me, am I in trouble?

GClements
02-22-2016, 07:55 PM
I have some questions then. Normally I'd do something like this to sample from a texture in my fragment shader.
uniform sampler2D TextureAtlas;

vec3 colour = texture2D(TextureAtlas,gl_TexCoord[0].st).rgb;

If I was writing the same thing to read and write indicies, how do I pass the indexed image in and read it? using texture2D or some other method that returns a uint8?

The methods are the same regardless of format. However, a R8UI texture would be accessed via a usampler2D uniform rather than sampler2D, and texture2D() would return a uvec4 rather than a vec4.


And lastly though.. if GL_R8UI isn't available to me, am I in trouble?
No. You can use GL_R8 instead. But reading from the texture will return a vec4 (so selecting the red component will return a float). Multiplying by 255, rounding and converting to uint should produce exactly the same result as using GL_R8UI.

When dealing with 32-bit integers, you have to bear in mind that converting to and from float will introduce rounding errors which mean that the original value isn't preserved exactly. But this isn't an issue for 8-bit or 16-bit values.