glReadPixels Weirdness

Hi there

I have some code to take a screenshot. I use glReadPixels to get the data.

However, i use that piece of code for over 2 years now and used several drivers, etc. and since the first day there is one weird thing about it:

The data is randomly flipped about the horizontal or vertical axis!

Sometimes i need to flip the screenshot around the x-axis, sometimes around the y-axis, sometimes i need to rotate the image 180°. It seems to be completely non-deterministic. I don’t change ANYTHING of the code, it seems to be decided at program-startup, how the driver flips the data around.

I use an ATI Radeon 9700.

So, i assume it is some setting, which i don’t set, which affects how the data is transfered. Any ideas?


Strange. Did you ensure all the ReadPixels have been fully processed before doing anything else ? (like calling glFinish).

Hm, i put a glFinish right before and after glReadPixels and now it seems to always work as expected. Although i can’t say for sure now, because this “bug” has a will of his own.

I will test it further and if it comes up again, i’ll tell you. However, it seems as if this solved it.


this is my source for reading one pixel of the screen, but i am read the whole screen for it.

Maybe you can use it:

int Thervl :: getColorAt ( int x , int y ) {


int size = ( mwin ->getWidth () ) * ( mwin ->getHeight () );

glReadPixels (0,0,mwin ->getWidth (),mwin ->getHeight (),GL_RED,GL_UNSIGNED_BYTE,pixels);

return( int ) ( pixels [x + mwin ->getWidth () * ( mwin ->getHeight () - y )] );

return 0;


congratulations for living for 2 years with the pain :wink:

can you show some code?

I only “lived with the pain” because it didn’t bother me very much :slight_smile:
I simply had to rotate/flip some screenshots. And now i wanted to sort things out.

But well, if you want my code for taking a screenshot, here it is:

unsigned int uiViewPort[4];
glGetIntegerv (GL_VIEWPORT, (GLint*) uiViewPort);

uiViewPort[2] = GetResolutionX ();
uiViewPort[3] = GetResolutionY ();

int Width = uiViewPort[2];
int Height = uiViewPort[3];

unsigned char* Data = new unsigned char[Width * Height * 3];

glFinish ();   // new!
glReadPixels (0, 0, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, (void*) Data);
glFinish ();   // also new!

FILESYSTEM* Fs = gp_FileSystem;
char path[256];
strcpy (path, Fs->GetProgramPath ().c_str ());

char filename[256] = "$SCREENSHOTS$/Screenshot0.tga";

int i = 1;
while (Fs->DoesFileExist (filename))
sprintf (filename, "$SCREENSHOTS$/Screenshot%d.tga", i);

gp_LogSystem->Log ("Saving Screenshot to: \"%s\".

", filename);

File = Fs->Open (filename, WRITE, 4096);

TGAHeader Header;
fastmemcpy (&Header, uTGAcompare, sizeof (TGAHeader));
Fs->Write (File, &Header, sizeof (TGAHeader));

TGA tga;
tga.header[1] = Width / 256;
tga.header[0] = Width % 256;
tga.header[3] = Height / 256;
tga.header[2] = Height % 256;
tga.header[4] = 24;

Fs->Write (File, &tga.header, sizeof (tga.header));

for (int y=0; y<Height; y++)
	for (int x=0; x<Width; x++)			
		Fs->Write (File, &Data[y*Width*3+x*3 + 2], sizeof (char));
		Fs->Write (File, &Data[y*Width*3+x*3 + 1], sizeof (char));
		Fs->Write (File, &Data[y*Width*3+x*3 + 0], sizeof (char));

Fs->Close (File);
delete[] Data;

Have fun with it :smiley:


pretty complicated :stuck_out_tongue:

the beginning looks a bit strange: first, you use glGetInteger to get the viewport size. then you modify the viewport variable with GetResolution*, although it already contains the viewport size.

btw, it’s not necessary to create the file byte by byte if you use GL_BGR in glReadPixels, like in the following example

void ScreenToTGA(int W, int H) {
 FILE           *out = fopen("screenshot.tga", "w");
 short          TGAhead[] = {0, 2, 0, 0, 0, 0, W, H, 24};
 char           pixel_data[3*W*H];

 fwrite(&TGAhead, sizeof(TGAhead), 1, out);
 glReadPixels(0, 0, W, H, GL_BGR, GL_UNSIGNED_BYTE, pixel_data);
 fwrite(pixel_data, 3*W*H, 1, out);
 fclose(out); }

Uh, got me there! :smiley:
Seems i first did it this way and then, after i had some new and shiny code, changed it to another way, but forgot to remove the redundancy.

Well, i admit, your code is shorter. And nicer. But mine got more love in it! :stuck_out_tongue:

But maybe i use yours from now on.

I wish i had the time to do all the programming i like, right now :frowning:
If you are so good, would you also like to write my medicine test for me?


i’m not a doctor, but i think the correct answer to every question is: “take 2 aspirin and call me tomorrow”