glReadPixels, glDrawPixels and glRasterPos

I want to save a rectangular portion of rendered pixel data using glReadPixels() and paste the data at the same position later using glDrawPixels(). I’d like to know how to specify the point of the pasting (the identical point of the data extraction.)
I tried to use glRasterPos(). But, it does not work as expected. I am still using OpenGL ver. 1.2, which does not support glWindowPos().
I will appreciate very much if anyone gives me a tip…

The coordinates passed to glRasterPos are transformed in the same manner as for glVertex: model-view matrix, projection matrix, viewport transformation.

If you want to set the position in window coordinates, set the model-view matrix to an identity matrix and the projection matrix with glOrtho. You can use glPushMatrix and glPopMatrix (along with glMatrixMode) to preserve the existing matrices.

E.g.

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
// the window width/height should have been stored from the last resize event
glOrtho(0, win_width, 0, win_height);
glRasterPos2i(x, y);
glDrawPixels(w, h, format, type, data);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

Does performance matter here?

If so, don’t read the pixels back from the GPU to a CPU memory buffer, and then re-upload those pixels from the CPU to the GPU (potentially multiple times) per draw. This is the default behavior with glReadPixels() / glDrawPixels(). This can stall the CPU → GPU pipeline, result in CPU dispatch thread frame time hangs (pipeline bubbles), thwart driver queue-ahead, and lower your frame rate.

Instead, keep those pixels you’ve saved off in a GPU-side buffer and then just redraw them from there. This avoids CPU dispatch thread frame queuing stalls, works well with driver queue-ahead, and will give you a higher frame rate.

How?

There are a number of ways to do this. Here are two. Instead of reading back to a CPU memory buffer (aka “client-side memory”) and uploading from there, instead…:

  • Read back to a PBO and then upload from there (as before withglReadPixels() / glDrawPixels(), but with a special buffer object bound for both). OR…
  • Copy your screen texels to a 2D texture and then just redraw that 2D texture onto the screen as needed (see glCopyTexSubImage2D())

Both of those should stay on the GPU, or at least operate in the GPU’s timeline, avoiding stalls.

1 Like

Thank you very much for your kind reply. I understand that you advised to disable the coordinate transformation. So, I tried as you suggested. But, I could not get the result as expected.
I am trying to capture a small portion of image before changing the portion, and recover the previously captured image before doing the same process with another rectangular area.
I attached my code. I don’t know what I did wrong.

void _OGLSwitchCapturePixel(MWrect theRect)
{
	long pixelLength;
	MWrect nullRect={-1000,-1000,-1000,-1000};
	static MWrect lastRect;
	static GLint  width,height,cx,cy;
	static GLfloat *pixelValue=NULL;
	if(lastRect.left>=0) {
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glLoadIdentity();
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glLoadIdentity();    
//		glOrtho((GLdouble)0, (GLdouble)oglWidth, (GLdouble)0, (GLdouble)oglHeight,-20000.0,30000.0);
		glRasterPos2i(cx,cy);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();
		glDrawPixels(width,height,GL_RGB,GL_FLOAT,(GLvoid *)pixelValue);
		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();
	}
	if(theRect.left<0) {
		lastRect=nullRect;
		return;	
	}
	cx=theRect.left;
	cy=oglHeight-theRect.top;
	width=theRect.right-theRect.left;
	height=theRect.bottom-theRect.top;
	pixelLength=(width+1)*(height+1)*3;
	pixelValue=(GLfloat *)_ResizePtrSize((Ptr)pixelValue,pixelLength,sizeof(GLfloat));
	glReadPixels(cx,cy,width,height,GL_RGB,GL_FLOAT,(GLvoid *)pixelValue);
	lastRect=theRect;
}

Thank you very much. It is not a matter of performance. I am trying to mark the graphic object under screen cursor with specific color. The marking changes as the screen cursor hovers over one object to another. Instead of changing the whole screen, I want to modify the small portion of the object each time as follows.

  1. Capturing the image of the portion before marking.
  2. Recover the portion of the image using the captured image to remove the marking.
  3. Repeat the process for each marking of the object under screen cursor.
    I tried with glReadPixels and glDrawPixels, but was not successful.
    I am thinking of another method using XOR raster operation. Is any parameter of glBlendFunc available for XOR operation.

This approach is very unlikely to be performant. Just redraw the whole screen. The first generation of OpenGL games from 1996/1997 redrew the whole screen each frame and had no problems. You’re only going to make your program more complex for a very dubious gain (or no gain at all, or even a loss) based on something you think but haven’t benchmarked.

1 Like

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.