PDA

View Full Version : Snapshots of the Screen



J. Ryan
01-23-2006, 09:19 AM
Hi all,

I'm a newbie at OpenGl and am learning as I go. For my latest project, I need to get essentially a continuous (or near) stream of "snapshots" (tiff or jpg images) from the screen. This I will display with another program so someone who doesn't have OpenGL on their system can still observe in near real time what the others are doing.

Now, right now I am taking snapshots every second or so by using an implementation of glReadPixels and ultimately saving the data as a tiff image. This works, however it creates a small pause during every snapshot action. While this might be ok once in a while, when doing a snapshot every frame, the whole ball of wax slows down way too much. I realized that part of the problem was that I am doing the bulk of the work in the main graphics thread of the program, thus anything which slows it down slows down the presentation to the user. But when I tried accessing the pixel data from another thread, the timing was off so I got nothing but black pixels.

I'm not very familiar with how this all works, my beginner books don't even mention this stuff. Any help or reference you can offer will be much appreciated!!

-Jess

shelll
01-23-2006, 11:11 AM
your slowdown is caused by HDD. do you need to save it? if you just send it, then performance should be ok.

andras
01-23-2006, 05:47 PM
You could do it asynchronously, but it's not trivial, definitely not a beginner task. But if you want to give it a try, then use PBOs (Pixel Buffer Object), but first, you should learn about VBO (Vertex Buffer Object), which is almost the same, but have more tutorials and samples on it.
Once you figure out how it works, you can create two PBOs (for double buffering), and then read data into it using glReadPixels. This will happen asynchronously. Of course, you don't know when it's finished, but when you get to the next frame, and ready to call glReadPixels again (this time with the other PBO), by that time the transfer is probably done, so you can "Map" the buffer (this will make sure that the copy is done, and return a pointer). While a buffer is mapped, you can access the contents from another thread, so you can dump it to disk.
Also, I'd recommend not using compression, because it will slow you down, I usually dump the screenshots into uncompressed bmp files..

J. Ryan
01-26-2006, 11:17 AM
Alright, thanks guys! I will procede trying both these ways. Thanks for helping.

-Jess

jide
01-26-2006, 11:22 AM
Why using PBO and such ? Simply not put all the data file at once. Do it in several frames, sending parts of it each time.
Also I advise not to snap all the images, but only 1 over 2 or 3 or so.

andras
01-26-2006, 11:53 AM
You want to use PBOs, because otherwise glReadPixels stalls program execution until it's done reading.
Saving out only every nth frame certainly helps, but I don't know what are the requirements. If they need all the frames, then it's not an option.
Also, what's wrong with using threads? :)

J. Ryan
01-26-2006, 04:48 PM
Well, I initially tried threads. But the data I was getting was all black pixels. I learned that this was because the new thread that I spawned wasn't in sync with the graphics thread and so it didn't read the pixels at the correct time. Someone at work told me that I could only read the pixels either before or after the buffer had been swapped, not just anytime the thread wanted... Which is too bad because that would've solved my problems from the start. Do you know how to syncronize the threads so they won't have this problem?

-Jess

andras
01-26-2006, 08:44 PM
The PBO's Map and Unmap methods are used for synchronization. When you call glReadPixels with a PBO, it will return immediately. Then, when you Map the buffer, it will wait, if necessary, until the buffer is full. Then, while the buffer is mapped, you can read it from any thread, and it will have the right data. Once you are done, you unmap it, so you can read into it again. Of course, this would still not buy you anything. The trick is to use two PBOs, and write data into one, while reading from the other. Again, it might be a little tough to implement this, if you don't have much experience with PBOs and threads..