PDA

View Full Version : nested FBO render to texture? RT1(RT2(), RT2())?



Zarniwoop
07-03-2010, 11:48 AM
I'm a newb to GL and am trying to create a spiffy GL app. My app uses render to texture via FBOs, and I have a C++ object to encapsulate a GL texture, with startRenderTo() and endRenderTo() methods. I do this because it seems there are about 8000 different ways to do RTT in GL, depending on whether it's multisampled or not, is a format you can render to (e.g. 4 components) or one you can't directly (e.g. 1 component), needs 6 renders for a cubemap, and so forth. I don't care about the minutia of the setup, so I just want to say:

tx->startRenderTo();
do_renderings();
tx->endRenderTo();

I have built this, and it works great as long as I don't nest them. I can RTT and get exactly the result I want no matter if it's MSAA, cube, or a single component. GLSL shaders are applied and work great. Whee!

But here is my problem: sometimes when rendering to a texture, that in turn needs *another* RTT so I can use it to render the first. I don't know this in advance, so I want the following. I can't easily do the inner ones in a non-nested way since it's really part of a more complex custom scene graph:


tx0->startRenderTo();
tx1->startRenderTo();
tx1->endRenderTo();
tx2->startRenderTo();
tx2->endRenderTo();
tx3->startRenderTo();
tx3->endRenderTo();
tx4->startRenderTo();
tx4->endRenderTo();
tx0->endRenderTo();


Now I have a problem. In the above sequence, the first several inner RTT's work OK, but when I get to tx3, the NV driver hangs in glDrawElements(). I'm about 99% sure I'm not doing any of the usual glDrawElement mistakes such as enabling arrays I'm not using or rending more data than I have. I've checked this very closely. For debugging I glDisableClientState all but the GL_VERTEX_ARRAY, *and* I have used the very same vertex array ID for lots of rendering before this such as tx1 and tx2, and I haven't touched it. Nowhere else in my app enables any draw elements client state - just a single function. I'm pretty sure I'm not overflowing something. Also if I *do* overflow something on purpose, I see an app segfault, which I don't here - it just hangs in the NV driver, and takes kill -9 to terminate the app.

I'm actually suspecting something is going wrong in my startRenderTo/endRenderTo methods, although I have no idea what. At the beginning of startRenderTo(), I do this so that I can restore the buffer bindings later:



for (uint32 x=0; x<maxDrawBuffer; ++x) {
GLDBG(glGetIntegerv(GL_DRAW_BUFFER0 + x, (GLint*)(oldDrawBuffer+x)));
// For some reason, GL gives us GL_BACK here but doesn't
// like it when set again in glDrawBuffers
if (oldDrawBuffer[x] == GL_BACK)
oldDrawBuffer[x] = 0;
}

GLDBG(glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, (GLint*)&amp;oldFBId));
GLDBG(glGetIntegerv(GL_RENDERBUFFER_BINDING, (GLint*) &amp;oldRenderBuffer));


Then at the end of endRenderTo():


GLDBG(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, oldFBId));
GLDBG(glDrawBuffers(maxDrawBuffer, oldDrawBuffer));
GLDBG(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, oldRenderBuffer));


Is there some fundamental reason I can't stop in mid-stream when rendering to some framebuffer, start rendering to a second one, then later bind the first one again and carry on?

Funny thing is that it works for several of the inner RTT's. Alas I have no indication whatsoever of what might be wrong :-(. I've made a lot of mistakes in my use of GL so far but I've always been able to figure them out. This one has had me stuck for days now. I don't even know how to debug it. This is a hobby project so I cannot afford gDebugger. I'm using Ubuntu 64 10.04.

Any ideas would be awesomely appreciated and I'd buy you a beverage of your choice if you were ever in the area if you can think of something I'm overlooking.

I *could* post the whole of my start/end render to methods, but they're kind of big by necessity to handle all the different RTT cases.

*EDIT* There are no glGetError codes set, ever - I check them at every single gl call, which is what my GLDBG macro above does.

Zarniwoop
07-03-2010, 07:59 PM
Hmm: I don't know if this is related, but I wrote a function to dump all the GL state I can get to via the glGet*v functions (not including "deep" state of various objects). I am doing "glPushAttrib(GL_ALL_ATTRIB_BITS)" at the start of my startRenderTo method, and the same pop at the end of endRenderTo. I would think this would fully restore my state, and it *almost* does, but I see two state diffs. After the pop:

GL_CURRENT_PROGRAM = { 0x5 }
0: GL_TEXTURE_BINDING_CUBE_MAP = { 0x0 }

The GL_CURRENT_PROGRAM is 5 where I expect 0, and the GL_TEXTURE_BINDING_CUBE_MAP is 0 where I expect 6.

Should the glPush/PopAttrib of GL_ALL_ATTRIB_BITS not save and restore these?

Again I'm not sure it's causing my hang, it just seems odd. But then I'm pretty new to all this so maybe I misunderstand something...

GL Starter
07-03-2010, 08:05 PM
Im doing multiple render targets in the below method.

// Start pre processing.
tx1->startRenderTo();
tx1->endRenderTo();
tx2->startRenderTo();
tx2->endRenderTo();
tx3->startRenderTo();
tx3->endRenderTo();
tx4->startRenderTo();
tx4->endRenderTo();
// After preprocessing do final rendering.
tx0->startRenderTo();
tx0->endRenderTo();

In my startRenderTo() I just binds my texture id to FBOs COLOR_ATTACHMENT_0.

In my endRenderTo() function I just reset COLOR_ATTACHMENT_0
to 0, for rendering to backbuffer.

Im suspecting any problem in your tricky code defined in startRenderTo() and endRenderTo() functions.

Alfonse Reinheart
07-03-2010, 08:30 PM
Should the glPush/PopAttrib of GL_ALL_ATTRIB_BITS not save and restore these?

No. No, it should not. The OpenGL specification's table list (section 6.2) has an "attribute" column. This defines what bit for Push/PopAttrib will save this value. The value for CURRENT_PROGRAM has no attribute, so no pushing and popping will preserve it.

Also, some attributes are considered "client state" and are pushed/poped with glPush/PopClientAttrib.

As to what happened to your cubemap binding, I can't say, as this binding is server state. You may want to try GL Intercept; it's a good tool for watching to see what changes your GL state.

Zarniwoop
07-03-2010, 10:03 PM
> The value for CURRENT_PROGRAM has no attribute, so no pushing and popping will preserve it.

Ok, thanks Alfonse! I changed to save CURRENT_PROGRAM with a glGetIntegerv and restore it. Same for the cubemap binding, although I still don't know why the push/pop didn't restore that one. (I know where I'm changing it, I just don't know why it isn't restored with the pop).

After this, all the state I'm dumping is 100% identical after a startRenderTo/endRenderTo pair, but it hasn't fixed my hang :-(.

I am dumping the core and extensions state for the exts I'm using, which makes me think the problem may be in some "deep" state that I can only get to with other kinds of query methods. That or it's something totally unrelated. I wish I had some way to know *why* the glDrawElements is hanging - just a wee clue! Without that, I'm kind of flying blind.

Zarniwoop
07-03-2010, 10:10 PM
> Im doing multiple render targets in the below method.

Hi GL Starter. If I could do that it would work fine with my current functions, which are OK for non-nested case. But unfortunately the RTT involves a complicated custom scene graph, so the code doing the RTT for tx0 has no idea what that scene graph will need to do. And it's a dynamic situation, not static, so it may not need tx1..4 at all depending on runtime data, or it may need some other ones.

Zarniwoop
07-04-2010, 12:35 PM
Well this is unpleasant. I added the ability to dump glGetFramebufferAttachmentParameteriv and glGetRenderbufferParameteriv state for RB/FB objects, and I did two dumps right before the hanging glDrawArrays: one where the glDrawElements hangs and one where it doesn't.

The renderbuffer and framebuffer state looks just fine to me even in the hanging case. In the nested (hang) case there's one more framebuffer and renderbuffer (#2), but it's set up identically to the single FB/RB (#1) in the working case, and it's the one bound in GL_DRAW/READ_FRAMEBUFFER_BINDING_EXT. The same arrays for glDrawArrays are enabled, and they are bound to the same objects!

This leaves me at wit's end. I'm stuck, unless anyone knows of a way to figure out what is making the driver so unhappy. Everything I know how to check looks OK.

Alfonse Reinheart
07-04-2010, 12:57 PM
Stop relying on GL Gets and start using GL Intercept.

Zarniwoop
07-04-2010, 01:08 PM
I will check it out, Alfonse, although the latest version I see is old (2005). Does it support modern GL extensions? It looks like I'll have to compile it from source on Linux - hopefully that will work. Sometimes with old code there are troubles due to it wanting out of date libraries, but I'll give it a shot.