Jump to content
  • Advertisement
Sign in to follow this  
haegarr

FBO, BlitFramebuffer / CopyPixels and GL_FRONT

This topic is 2986 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi. Yesterday I hit a poblem during programming an intro animation: The purpose is to make a screenshot of the desktop a.t.m. of starting the game, and to play a little 3D animation with the desktop image in the background. The technique I've intended to use is as follows: (1) making a double buffered full-screen context (works fine) (2) making an FBO with a solely render buffer attachment, matching the display (works fine) (3) copying the front buffer to the FBO's color attachment 0 (doesn't work) (4) copying the FBO's color attachment 0 to the back buffer (works fine) (5) rendering the animation into the back buffer (works fine) (6) swapping back to front (works fine) (7) loop back to (4) With my possibilities, I can use glBlitFramebufferEXT (on Mac OS X 10.5.8 w/ ATI X1900XT) or glCopyPixels (same as before, and also on Mac OS X 10.5.2 w/ NVIDIA 8800); the way using a texture is possible, too, but not part of the questions I have. The code looks as follows. I've segmented it to make reading easier. Listing 1: To initialize the back buffer just as first operation after context is made current:
::glClearColor(0.5f, 0.6f, 0.8f, 1);
::glClear(GL_COLOR_BUFFER_BIT);
// [#1] ::glReadBuffer(GL_FRONT);
// [#1] ::glDrawBuffer(GL_BACK);
// [#1] ::glRasterPos2f(-1, -1);
// [#1] ::glCopyPixels(0, 0, 1920, 1200, GL_COLOR);
The color set-up here is just used as an indicator later. The lines marked with [#1] will play a role later; they are not neccessary for the original purpose. Listing 2: Allocating of the FBO and RB:
::GLuint fbo;
::glGenFramebuffersEXT(1, &fbo);
::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
// allocating render buffer on card
::GLuint framebuffer;
::glGenRenderbuffersEXT(1, &framebuffer);
::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, framebuffer);
::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, 1920, 1200);
::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, framebuffer);
Each function invocations returns "no error", and the FBO tells "complete" if asked for its status. Listing 3: Copying desktop image to FBO:
::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
::glReadBuffer(GL_FRONT);
::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo);
::glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
// [#2] ::glRasterPos2f(-1, -1);
// [#2] ::glCopyPixels(0, 0, 1920, 1200, GL_COLOR);
::glBlitFramebufferEXT(0, 0, 1920, 1200, 0, 0, 1920, 1200, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// [#3] ::glClearColor(0, 0, 0, 1);
// [#3] ::glClear(GL_COLOR_BUFFER_BIT);
AFAIS, here I set the context's front buffer as read target, and the FBO's color attachment 0 as draw target. Each function invocations returns "no error". The lines marked with [#3] show a clearing of the render buffer just for test purposes. (The lines marked with [#2] show the alternative using glCopyPixels instead of BlitFramebuffer.) Listing 4: Copying FBO to back buffer (should fill the back buffer with the desktop image):
::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo);
::glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
::glDrawBuffer(GL_BACK);
// [#2] ::glRasterPos2f(-1, -1);
// [#2] ::glCopyPixels(0, 0, 1920, 1200, GL_COLOR);
::glBlitFramebufferEXT(0, 0, 1920, 1200, 0, 0, 1920, 1200, GL_COLOR_BUFFER_BIT, GL_NEAREST);
AFAIS, here I set the context's back buffer as draw target, and the FBO's color attachment 0 as read target. Each function invocations returns "no error". (The lines marked with [#2] show the alternative using glCopyPixels instead of BlitFramebuffer.) Listing 5: Rendering a dummy object and swapping buffers:
::glColor3f(1.0f, 1.0f, 1.0f);
::glBegin(GL_TRIANGLES);
::glVertex3f( 0.0f, +0.5f, 0.0f);
::glVertex3f(+0.25f, -0.5f, 0.0f);
::glVertex3f(-0.5f, -0.5f, 0.0f);
::glEnd();
// swapping back and front buffers
target->postRender();
Now, executing the program shown above renders a white triangle above blueish background! I would expect to see a white triangle above the desktop image, of course. Activating the lines marked with [#3] shows a white triangle above black background. That means IMO that the copying from the FBO to the back buffer works as expected, but copying from the front buffer to the FBO does not; it copies the back buffer instead. Just to verify this, if the lines marked with [#1] are not commented, the white triangle appears above the desktop image (notice that the blit is still invoked with the front buffer as rerad target)! That is because [#1] makes a front to back buffer copy, of course. Can someone please enlighten me what's wrong? For those that are still interested in (;)), here comes the 2nd approach: Instead of BlitFramebuffer, the lines marked with [#2] can be enabled to use glCopyPixels. Doing so seems to work fine but only until a second rendering is done. E.g adding ... ... Listing 6: Rendering a 2nd dummy object and swapping buffers:
::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo);
::glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
::glDrawBuffer(GL_BACK);
::glRasterPos2f(-1, -1); ::glCopyPixels(0, 0, 1680, 1050, GL_COLOR);
// ::glBlitFramebufferEXT(0, 0, 1920, 1200, 0, 0, 1920, 1200, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// rendering object
::glColor3f(0.5f, 0.5f, 0.5f);
::glBegin(GL_TRIANGLES);
::glVertex3f( 0.0f, +0.25f, 0.0f);
::glVertex3f(+0.125f, -0.25f, 0.0f);
::glVertex3f(-0.25f, -0.25f, 0.0f);
::glEnd();
// swapping back and front buffers
target->postRender();
finally shows a grey triangle above a white triangle above the desktop background. The fact that the white triangle is still visible means IMO that the glReadBuffer command addresses the front buffer but not the specified color attachment of the FBO. Maybe I misunderstand something w.r.t. FBOs and glReadBuffer, or I miss some necessary settings. There is a mysterious "pixel ownership" issue, but I have the impression that it isn't the problem here?! Thank you for reading. Awaiting for answers ... :) [Edited by - haegarr on April 12, 2010 2:01:03 PM]

Share this post


Link to post
Share on other sites
Advertisement
I can only guess but maybe it is just not possible to access the
active front buffer for copyingpurpose.
But swapping the buffer should be a valid work-around, shouldn't it?

Share this post


Link to post
Share on other sites
I second the idea of buffer swapping.
I once had a similar situation (at east I think so before going to bed: I wanted the desktop to fade into the game), and that solved it. (but that wasn't with FBO-s, just simple glCopyTexSubImage2D, but I guess that doesn't matter)

The swapping produced a flash of a black screen (I guess the other "page" of the double buffer is zeroed), but it was acceptable.

Share this post


Link to post
Share on other sites
Thanks for answering.

Quote:
Original post by Spynacker
I can only guess but maybe it is just not possible to access the
active front buffer for copyingpurpose.
But swapping the buffer should be a valid work-around, shouldn't it?

Accessing the front is possible in principle, at least for Macs. E.g. it works fine if the render target is made a single buffer target (i.e. without back-buffering at all) and using glReadPixels. (This can be used for a work-around, of course, but is obviously less efficient.) The fact that the (IMHO) misbehaving code actually does a copy of the front buffer also shows that an access is possible, although it may be "undefined behaviour". And buffer swapping introduces a black flash.

Quote:
Original post by HuntsMan
Why are you trying to read from the front buffer?

Its for a game intro, showing animated geometry in interaction with a screen snapshot of the desktop.

Quote:
Original post by szecs
I second the idea of buffer swapping.
I once had a similar situation (at east I think so before going to bed: I wanted the desktop to fade into the game), and that solved it. (but that wasn't with FBO-s, just simple glCopyTexSubImage2D, but I guess that doesn't matter)

The swapping produced a flash of a black screen (I guess the other "page" of the double buffer is zeroed), but it was acceptable.

I know of the possibility with the swapping, of course. But I'm also curious of why the shown code doesn't work as expected. Is it a bug or is my expectation wrong?

However, your application then ("I wanted the desktop to fade into the game") is actually similar to mine :) And belonging to the black flash: Going the "copy front to back buffer first" way (see lines marked with [#1]) avoids it.

Share this post


Link to post
Share on other sites
I experienced a strange behavior with my program:
I skipped the fading screen stuff, and replaced it with a progress type "load-screen": a text line is printed, when something loaded successfully. Without buffer swapping, just print to front buffer then glFinish.

This produced a very strange phenomena: when I pressed printscreen in the game at any time, sometimes the loadscreen was copied to the clipboard. I have no idea why. I swap buffers. I would notice, if it wasn't working (and shouldn't be able record the game with FRAPS).

So where the hell the loadscreen comes from? The driver's control panel says triple buffering is off. (If I turn it on my program simply crashes BTW).

So, maybe that was the reason I had to swap the buffers (I tried setting the FRONT as read-target of course without success).

So I say give it a shot (swapping).

And do not clear the buffers (I'm telling just in case...)

Or maybe you could make a single buffered context first, copy stuff, then make it double buffered. (Or would that destroy your textures/FBO-s?)

I guess you have already tried the old glTexSubImage-to-a-standard-texture stuff. The desktop is not as beautiful when the context is made, as you see it before launching your program. (some desktop icons disappear randomly for example)

Share this post


Link to post
Share on other sites
Quote:
Original post by szecs
...
So I say give it a shot (swapping).

And do not clear the buffers (I'm telling just in case...)

Or maybe you could make a single buffered context first, copy stuff, then make it double buffered. (Or would that destroy your textures/FBO-s?)

I guess you have already tried the old glTexSubImage-to-a-standard-texture stuff. The desktop is not as beautiful when the context is made, as you see it before launching your program. (some desktop icons disappear randomly for example)
Thanks for showing up alternatives, but you misunderstand my intention. I already have working solutions, but I'm curious why the method mentioned in the OP doesn't work. I simply want to have the knowledge what's going wrong because it allows me to do a better job.

Solutions that work are:
(a) Making a double buffer context, copying front buffer to back buffer, copying back buffer to FBO,
(b) making a single buffer context, copying front buffer, making a double buffer context,
and
(c) making a double buffer context, doing a swap (although this method is avoided because of its black flash).

And for completeness: Solutions that I haven't tried are (besides others):
(d) Copying to texture.


For (b) you have to deal with either system memory as temporary buffer, or else share the context between the 2 render targets (necessary in case using an FBO), so there will be no problem with "Or would that destroy your textures/FBO-s".

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!