3
votes

I'm trying to retrieve the pixel information for an alpha-only texture via glGetTexImage.

The problem is, the glGetTexImage-Call seems to read more data than it should, leading to memory corruption and a crash at the delete[]-Call. Here's my code:

int format;
glGetTexLevelParameteriv(target,0,GL_TEXTURE_INTERNAL_FORMAT,&format);
int w;
int h;
glGetTexLevelParameteriv(target,0,GL_TEXTURE_WIDTH,&w);
glGetTexLevelParameteriv(target,0,GL_TEXTURE_HEIGHT,&h);
if(w == 0 || h == 0)
    return false;
if(format != GL_ALPHA)
    return false;
unsigned int size = w *h *sizeof(unsigned char);
unsigned char *pixels = new unsigned char[size];
glGetTexImage(target,level,format,GL_UNSIGNED_BYTE,&pixels[0]);
delete[] pixels;

glGetError reports no errors, and without the glGetTexImage-Call it doesn't crash.

'target' is GL_TEXTURE_2D (The texture is valid and bound before the shown code), 'w' is 19, 'h' is 24, 'level' is 0.

If I increase the array size to (w *h *100) it doesn't crash either. I know for a fact that GL_UNSIGNED_BYTE has the same size as an unsigned char on my system, so I don't understand what's going on here.

Where's the additional data coming from and how can I make sure that my array is large enough?

1
Each row written to by OpenGL pixel operations like glGetTexImage are aligned to a 4-byte boundary by default, which may add some padding. Look up GL_[UN]PACK_ALIGNMENTColonel Thirty Two
So, can I just set GL_UNPACK_ALIGNMENT to 1, or does it depend on what GL_PACK_ALIGNMENT had been set to when the texture was created? I tried setting GL_UNPACK_ALIGNMENT to 1 right before the glGetTexImage-Call, but that didn't seem to help.Silverlan
Pack and unpack only affect pixel transfer. That is to say, when you upload it the unpack alignment is used for GL to interpret the data it's going to store it a native format of its choosing and then it really does not matter anymore. Likewise, when you download the image you can have GL pack the image it returns according to some rules that might differ from what it uses internally. But in both cases, one really does not affect the other.Andon M. Coleman
To that end, setting the unpack alignment before downloading a texture image isn't going to do anything. You need to set the pack alignment. You've basically got the two things confused.Andon M. Coleman
Thanks, it makes sense now. Changing the pack alignment did the trick.Silverlan

1 Answers

9
votes

Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4-byte boundary by default, which may add some padding.

To modify the alignment, use glPixelStorei with the GL_[UN]PACK_ALIGNMENT setting. GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.) while GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)

The alignment can be any of 1 (tightly packed with no padding), 2, 4 (the default), or 8.

So in your case, run glPixelStorei(GL_PACK_ALIGNMENT, 1); before running glGetImage2D.