PDA

View Full Version : some problems with glReadPixels



peng530
12-26-2008, 05:30 AM
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glu.h>
#include <iostream>
#include "stack.h"

#define FILL_COLOR 100
#define BORDER_COLOR 0

using namespace std;
void DrawRegion();
void myInit(void);
void myDisplay(void);
void RegionFill(void);

int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 150);
glutCreateWindow("my first attempt");

glutDisplayFunc(myDisplay);
//glutReshapeFunc(myReshape);
//glutMouseFunc(myMouse);
//glutKeyboardFunc(myKeyboard);
myInit();
glutMainLoop();

return 0;
}
void myInit(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glPointSize(1.0);//
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
DrawRegion();
RegionFill();
glFlush();
}
void RegionFill(void)
{
GLubyte Pixel;
glReadPixels(50, 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &Pixel);//
int ret = glGetError();
cerr << ret;
Point seed = {300, 180};
Stack stack;
stack.Push(seed);
glColor3ub(100, 0, 0);
while(!stack.IsEmpty())
{
Point point;
stack.Pop(point);
glBegin(GL_POINTS);
glVertex2i(point.x, point.y);
glEnd();
GLint xi = point.x + 1;
GLubyte iPixel = 0;
glReadPixels(50, 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &iPixel);//
while(iPixel != BORDER_COLOR)//向右填充
{
glBegin(GL_POINTS);
glVertex2i(xi, point.y);
glEnd();
xi++;
glReadPixels(xi, point.y, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &iPixel);

}
GLint xRight = xi--;//记录最右点
xi = point.x - 1;
glReadPixels(xi, point.y, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &iPixel);
while(int(iPixel) != BORDER_COLOR)
{
glBegin(GL_POINTS);
glVertex2i(xi, point.y);
glEnd();
xi--;
glReadPixels(xi, point.y, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &iPixel);
}
//GLint xLeft = xi++;//记录最左点
for(int i = -1; i <= 1; i += 2)
{
while(xi <= xRight)
{
glReadPixels(xi, point.y + i, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &iPixel);
while(iPixel != BORDER_COLOR && iPixel != FILL_COLOR && xi <= xRight)
{
xi++;
glReadPixels(xi, point.y + i, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &iPixel);
}
Point tmpPoint = {xi - 1, point.y + i};
stack.Push(tmpPoint);
while((iPixel == BORDER_COLOR || iPixel == FILL_COLOR) && xi <= xRight)
{
xi++;
glReadPixels(xi, point.y + i, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &iPixel);
}
}
}
}
}
void DrawRegion(void)
{
glColor3ub(0, 0, 0);
glBegin(GL_LINE_LOOP);
glVertex2i(50, 50);
glVertex2i(180, 300);
glVertex2i(300, 200);
glVertex2i(450, 320);
glVertex2i(350, 80);
glVertex2i(250, 150);
glVertex2i(150, 150);
glVertex2i(50, 50);
glEnd();
GLubyte Pixel;
glReadPixels(50 , 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &Pixel);
glFlush();
cout << int(Pixel) << " ";
}

This is my program. I run it step by step with gdb. The first glReadPixels in DrawRegion returns a right result of Pixel(0).
But when it returns from the DrawRegion() and get into the RegionFill(), the glReadPixels at the first line of RegionFill returns a wrong result(118).Why the glReadPixels() in two functions executes one after another returns the different results.

I run the program on T23 with ubuntu. Thanks.

James W. Walker
12-26-2008, 09:08 AM
The two glReadPixels calls are separated by glFlush. It is often necessary to call glFlush before glReadPixels, so I have more trust for the glReadPixels call after glFlush, even if the result is not what you expected.

peng530
12-26-2008, 07:23 PM
The two glReadPixels calls are separated by glFlush. It is often necessary to call glFlush before glReadPixels, so I have more trust for the glReadPixels call after glFlush, even if the result is not what you expected.
Thanks for your reply. I call the glReadPixels after glFlush and get the same result. I run the program on my computer always get strange results. I doubt whether it has relation to my computer's environment.
For example, I run the program with gdb step by step and the cout in DrawRegion() puts out 0. But when I run it in terminal, it puts out 255 or other results but not 0.

dletozeun
12-27-2008, 04:18 AM
James W. Walker is right, this is not logic to call glFlush after a glReadPixels command. You should call as James said, glFlush before calling glReadPixels, but IMO, this not sufficient, you need to call glFlush then glFinish and finally, glReadPixels. This way, you are sure that all commands prior to glReadPixels are executed and finished! :)

peng530
12-27-2008, 05:50 AM
For this reason, OpenGL provides the command glFlush(), which forces the client to send the network packet even though it might not be full. Where there is no network and all commands are truly executed immediately on the server, glFlush() might have no effect. However, if you're writing a program that you want to work properly both with and without a network, include a call to glFlush() at the end of each frame or scene. Note that glFlush() doesn't wait for the drawing to complete - it just forces the drawing to begin execution, thereby guaranteeing that all previous commands execute in finite time even if no further rendering commands are executed.

If glFlush() isn't sufficient for you, try glFinish(). This command flushes the network as glFlush() does and then waits for notification from the graphics hardware or network indicating that the drawing is complete in the framebuffer

Thanks for your reply.These paragraphs copy from <OpenGL Programming Guide>.According to it, glFlush and glFinish are only used with network?

I also try to change the program calling glFinish before glReadPixels. But it have no change to the result. I get the same result as before.

eile
12-27-2008, 06:08 AM
Neither glFlush nor glFinish is needed before a glReadPixels. The read will implicitly finish all commands before copying the framebuffer contents.

peng530
12-27-2008, 06:15 AM
I discover a strange case.
I comment the glReadPixels in DrawRegion() as below,
//GLubyte tPixel;
//glReadPixels(50 , 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &tPixel);
//cout << int(Pixel) << " ";

Then, the glReadPixels in RegionFill return right result. It is so strange.

peng530
12-27-2008, 06:22 AM
Neither glFlush nor glFinish is needed before a glReadPixels. The read will implicitly finish all commands before copying the framebuffer contents.

Thanks. Now, I already understand this. But it can not solve my problem. Do you have any suggestions for the problem?

James W. Walker
12-27-2008, 12:07 PM
Neither glFlush nor glFinish is needed before a glReadPixels. The read will implicitly finish all commands before copying the framebuffer contents.

That's the theory, but in practice I have seen cases where glFlush is needed, maybe even glFinish. It may depend on the card and driver.

dletozeun
12-27-2008, 03:42 PM
peng530, that is hard to say, your code is quite complex. Try to write a more simple example and see if the problem still occurs. You can also try to simplify your code commenting then uncommenting parts of the code that you consider correct, checking if opengl throws any error. I could looking to your code when I would have time if you can provide the full code.

Rosario Leonardi
12-27-2008, 07:05 PM
I tried your code.. I made some modified to be able to compile it
-I added windows.h
-used the std:stack instead of your custom stack
-added a basic Point struct
-I commented all the glFlush

I get the correct result
0 0

The program draw a closed line and try to fill it.. but after a while the program fill some space outside the figure and stall. :(

Here the code if somebody else want to try.


#include <windows.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glu.h>
#include <iostream>
#include <stack>

#define FILL_COLOR 100
#define BORDER_COLOR 0

using namespace std;
void DrawRegion();
void myInit(void);
void myDisplay(void);
void RegionFill(void);

struct Point{
float x, y;
};


int main(int argc, char **argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 150);
glutCreateWindow("my first attempt");

glutDisplayFunc(myDisplay);
//glutReshapeFunc(myReshape);
//glutMouseFunc(myMouse);
//glutKeyboardFunc(myKeyboard);
myInit();
glutMainLoop();

return 0;
}

void myInit(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glPointSize(1.0);//
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
DrawRegion();
RegionFill();
// glFlush();
}
void RegionFill(void)
{
GLubyte Pixel;
glReadPixels(50, 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;Pixel);//
int ret = glGetError();
cerr << ret;
Point seed = {300, 180};
stack<Point> s;
s.push(seed);
glColor3ub(100, 0, 0);
while(!s.empty())
{
Point point;
point = s.top();
s.pop();
glBegin(GL_POINTS);
glVertex2i(point.x, point.y);
glEnd();
GLint xi = point.x + 1;
GLubyte iPixel = 0;
glReadPixels(50, 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;iPixel);//
while(iPixel != BORDER_COLOR)//&amp;#21521;&amp;#21491;&amp;#22635;&amp;#20805;
{
glBegin(GL_POINTS);
glVertex2i(xi, point.y);
glEnd();
xi++;
glReadPixels(xi, point.y, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;iPixel);
}
GLint xRight = xi--;//&amp;#35760;&amp;#24405;&amp;#26368;&amp;#21491;&amp;#28857;
xi = point.x - 1;
glReadPixels(xi, point.y, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;iPixel);
while(int(iPixel) != BORDER_COLOR)
{
glBegin(GL_POINTS);
glVertex2i(xi, point.y);
glEnd();
xi--;
glReadPixels(xi, point.y, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;iPixel);
}
//GLint xLeft = xi++;//&amp;#35760;&amp;#24405;&amp;#26368;&amp;#24038;&amp;#28857;
for(int i = -1; i <= 1; i += 2)
{
while(xi <= xRight)
{
glReadPixels(xi, point.y + i, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;iPixel);
while(iPixel != BORDER_COLOR &amp;&amp; iPixel != FILL_COLOR &amp;&amp; xi <= xRight){
xi++;
glReadPixels(xi, point.y + i, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;iPixel);
}
Point tmpPoint = {xi - 1, point.y + i};
s.push(tmpPoint);
while((iPixel == BORDER_COLOR || iPixel == FILL_COLOR) &amp;&amp; xi <= xRight)
{
xi++;
glReadPixels(xi, point.y + i, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;iPixel);
}
}
}
}
}
void DrawRegion(void)
{
glColor3ub(0, 0, 0);
glBegin(GL_LINE_LOOP);
glVertex2i(50, 50);
glVertex2i(180, 300);
glVertex2i(300, 200);
glVertex2i(450, 320);
glVertex2i(350, 80);
glVertex2i(250, 150);
glVertex2i(150, 150);
glVertex2i(50, 50);
glEnd();
GLubyte Pixel;
glReadPixels(50 , 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;Pixel);
// glFlush();
cout << int(Pixel) << " ";
}


by the way.. I'm using windows XP with the latest nVidia driver (181) on a G8800GTS

peng530
12-27-2008, 10:13 PM
peng530, that is hard to say, your code is quite complex. Try to write a more simple example and see if the problem still occurs. You can also try to simplify your code commenting then uncommenting parts of the code that you consider correct, checking if opengl throws any error. I could looking to your code when I would have time if you can provide the full code.

Thanks. The code I provide above is my full code. But It may has lots of problems. Because since I get the problem of glReadPixels, I can not debug the rest code.

Now I comment most code of RegioFill() as below:

#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glu.h>
#include <stdio.h>
#include "stack.h"

#define FILL_COLOR 100
#define BORDER_COLOR 0

void DrawRegion();
void myInit(void);
void myDisplay(void);
void RegionFill(void);

int main(int argc, char **argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 150);
glutCreateWindow("my first attempt");

glutDisplayFunc(myDisplay);
myInit();
glutMainLoop();

return 0;
}
void myInit(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glPointSize(1.0);//&amp;#35774;&amp;#32622;&amp;#28857;&amp;#30340;&amp;#22823;&amp;#23567;&amp;# 20026;&amp;#19968;&amp;#20010;&amp;#20687;&amp;#32032;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
DrawRegion();
RegionFill();
glFlush();
}
void RegionFill(void)
{
GLubyte Pixel;
glReadPixels(50, 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;Pixel);//&amp;#35835;&amp;#21462;&amp;#19968;&amp;#28857;&amp;#30340;&amp;#32418;&amp;# 33394;&amp;#36890;&amp;#36947;&amp;#20540;
printf("%d", Pixel);
}
void DrawRegion(void)
{
glColor3ub(0, 0, 0);
glBegin(GL_LINE_LOOP);
glVertex2i(50, 50);
glVertex2i(180, 300);
glVertex2i(300, 200);
glVertex2i(450, 320);
glVertex2i(350, 80);
glVertex2i(250, 150);
glVertex2i(150, 150);
glVertex2i(50, 50);
glEnd();
glFinish();
GLubyte tPixel;
glReadPixels(50 , 50, 1, 1, GL_RED, GL_UNSIGNED_BYTE, &amp;tPixel);
printf("%d", tPixel);
}

Now, as I run the program step by step with gdb, the two glReadPixels() in DrawRegion() and RegionFill() both put out
right result. I don't know why the code I comment affect the result of glReadPixels().

But there is still a strange case. I run the program step by step with gdb, the result put out is correct. Both the results are 0. But when I run it in terminal or gdb without step by step, the result is wrong. Something like 239 or 255.

peng530
12-27-2008, 10:35 PM
The filling part of the code should still have some problem, because I have not debug it.

Sorry, the second 0 is the result of ret, I think you can add a printf to put out the pixel.
Could you try to run the program step by step, and to see whether the two results of glReadPxiels() give the same result?

Dose the program has relations to the video card? I run the program on t23, and with linux(ubuntu).

dletozeun
12-28-2008, 04:02 AM
I ran your code and get 0 from the two printf running it step by step with gdb or normally from a terminal. I got the same results with the code provided by Rosario Leonardi. I am also working on Ubuntu (Hardy Heron 8.04), with an ATI Radeon X1600 mobility and proprietary drivers.
What hardware are you working on? (What is t23?) Which drivers do you use, mesa ones, proprietary ones?

peng530
12-28-2008, 07:06 AM
T23 stands for IBM ThinkPad T23 which is an old notebook. How can I get the information of drivers my computer use?
I look into the xorg.conf file and get the information like this
Section "Device"
Identifier "S3 Inc. SuperSavage IX/C SDR"
Driver "savage"
BusID "PCI:1:0:0"
EndSection

Also I execute glxinfo command in terminal and get the information as below:
OpenGL vendor string: S3 Graphics Inc.
OpenGL renderer string: Mesa DRI SuperSavage 20061110 AGP 1x x86/MMX/SSE
OpenGL version string: 1.2 Mesa 7.2

Rosario Leonardi
12-28-2008, 08:15 AM
In debug mode I get:
255 255

That's strange. But Maybe it's right.
glRead read the pixel of the framebuffer, but in debug mode your windows could not be active and be hidden behind another one. In this case you are reading random byte.. probably from another window.
I tried to debug the program with the glut windows behind my VC windows and I get 255.
Let's try something different. :)
I change my windows theme so the debug windows have a gray background (192, 192, 192). I run your program again.. and PEM. I get 192. :D
Actually in debug mode you are reading some pixel from the debug windows.
Last try another thing. I put my debug windows in a corner, and I run the program (in debug mode) with the glut windows visible, and I get the correct result. :)

You will get wrong result even if you run the program in release mode and then minimize (or hide) the glut windows.

This is an example of what your framebuffer can appear in debug mode.
http://img355.imageshack.us/img355/7776/framebufferwc8.png (http://imageshack.us)


Dose the program has relations to the video card?
It shouldn't, but it does. :(
This is caused by different driver behaviors or bug. But I'm pretty sure that the nVidia/ATI guys are smarter then us and the bug must be somewhere else. :)

peng530
12-28-2008, 07:19 PM
:D It is helpful.It is so stupid that I never realize the case. I think it can explain why the two glReadPixel() give the different results and why running the program in terminal and gdb get different results.

Now I move my debug window to right so it don't cover the program's window. But I get the result 255 255. Do not they should be 0 0?

dletozeun
12-29-2008, 07:18 AM
hem, this seems to depend on hardware and implementation... I don't get the same result at all. On my machine, in debug mode, it is like, the window is forced to be refreshed when reading pixels with glReadPixels. So each time I call glReadPixels, the current displayed framebuffer is read and not the "window surface" (I mean the window area on screen). I don't understand why your machines behave like reading directly the screen, that is a very dangerous method for the reasons Rosario cited above (another window overlapping the opengl program one, unvisible window) and it would not work at all with fbo which are not necessarly displayed!

Maybe you should use glCopyTexSubImage2D and copy color buffer into a 1x1 texture then use glGetTexImage to retrieve data in your program.

Rosario Leonardi
12-29-2008, 01:03 PM
Also try with double buffer instead of drawing/reading directly on the screen.

Just change this:
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
in this
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

You also have to had a glutSwapBuffers(); at the end of myDisplay();

peng530
12-30-2008, 04:06 AM
Thanks everybody who had helped me especially Rosario Leonardi and dletozeun.

I still have problems according to dletozeun and Rosario Leonardi advised last. So I change my system to windows and there are not any problems. I have the same case Rosario Leonardi published on #250955. Then I changed program according to Rosario Leonardi advised last.Everything is fine.

I doubt why it has so many problems when it runs with linux. Can it be driver's problem or X window's problem. I installed ubuntu with gonme and then I change it to xfce. Maybe this cause some problem to my linux system.