PDA

View Full Version : FBO Corruption on ATi/Mac



OrangyTang
05-10-2009, 06:19 AM
I have an game which uses FBOs to do 2d rendering to compose multiple layers. This works fine on the windows machines I've tested it on (all nVidia cards) but on a friends laptop it produces corrupt output. It's a Mac with an ATi Radeon 9600 XT.

I've distilled this down to a minimum reproduction case, which does something like:

- Create single FBO
- Create two empty textures to use with FBO
- Render:
-- Bind FBO
-- Attach texture 1 to FBO
-- Draw into texture 1
-- Attach texture 2 into FBO
-- Draw into texture 2
-- Detach FBO
-- Draw texture 1 to screen
-- Draw texture 2 to screen

Code:


public FboTest5() throws Exception
{
final boolean fboCapable = GLContext.getCapabilities().GL_EXT_framebuffer_obj ect;
if (!fboCapable)
throw new RuntimeException("FBOs not supported\n");

sprite = new Sprite("Textures/Tails.png");

x = 200;
y = 200;

// Gen FBO
IntBuffer buffer = BufferUtils.createIntBuffer(1);
EXTFramebufferObject.glGenFramebuffersEXT(buffer);
fboId = buffer.get();
if (fboId == 0)
throw new RuntimeException("Couldn't create FBO");

// Gen textures
shadowTex = createBlankTexture(256, 256);
fullbrightTex = createBlankTexture(256, 256);

Util.checkGLError();
}


public void render()
{
Util.checkGLError();

setDefaultState();

// Shadow RTT

// Bind fbo
EXTFramebufferObject.glBindFramebufferEXT(EXTFrame bufferObject.GL_FRAMEBUFFER_EXT, fboId);

// Attach our target texture
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
EXTFramebufferObject.glFramebufferTexture2DEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
GL11.GL_TEXTURE_2D, shadowTex, 0);
checkCompleteness(fboId);
{
GL11.glViewport(0, 0, 256, 256);
setOrtho(Testbed.SCREEN_WIDTH, Testbed.SCREEN_HEIGHT);

GL11.glClearColor(1f, 1f, 1f, 0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

GL11.glColor4f(0f, 0f, 0f, 1f);

sprite.draw(x-20, y+40);
sprite.draw(x+20, y+40);
}

// Fullbright RTT

// Attach our target texture
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
EXTFramebufferObject.glFramebufferTexture2DEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
GL11.GL_TEXTURE_2D, fullbrightTex, 0);
checkCompleteness(fboId);
{
GL11.glViewport(0, 0, Testbed.SCREEN_WIDTH, Testbed.SCREEN_HEIGHT);
setOrtho(Testbed.SCREEN_WIDTH, Testbed.SCREEN_HEIGHT);

GL11.glClearColor(0.4f, 0.4f, 0.8f, 0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);


// Normal, full colour sprite
GL11.glColor4f(1f, 1f, 1f, 1f);
sprite.draw(x, y);
sprite.draw(x-20, y);
sprite.draw(x+20, y);
}
// Release fbo
EXTFramebufferObject.glBindFramebufferEXT(EXTFrame bufferObject.GL_FRAMEBUFFER_EXT, 0);


// Final framebuffer render

GL11.glViewport(0, 0, Testbed.SCREEN_WIDTH, Testbed.SCREEN_HEIGHT);

GL11.glClearColor(0.4f, 0.4f, 0.8f, 0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
{
setOrtho(Testbed.SCREEN_WIDTH, Testbed.SCREEN_HEIGHT);

// Fullbright RTT
// draw RTT result as whole screen quad
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, fullbrightTex);

float width = Testbed.SCREEN_WIDTH;
float height = Testbed.SCREEN_HEIGHT;

GL11.glBegin(GL11.GL_QUADS);
{
GL11.glColor4f(1, 1, 1, 0.5f);
GL11.glTexCoord2f(0f, 0f);
GL11.glVertex2f(0, 0);

GL11.glTexCoord2f(1, 0f);
GL11.glVertex2f(width, 0);

GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(width, height);

GL11.glTexCoord2f(0f, 1);
GL11.glVertex2f(0, height);
}
GL11.glEnd();
}

// Shadow RTT
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, shadowTex);

float width = Testbed.SCREEN_WIDTH;
float height = Testbed.SCREEN_HEIGHT;

GL11.glBegin(GL11.GL_QUADS);
{
GL11.glColor4f(1, 1, 1, 0.5f);
GL11.glTexCoord2f(0f, 0f);
GL11.glVertex2f(0, 0);

GL11.glTexCoord2f(1, 0f);
GL11.glVertex2f(width, 0);

GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(width, height);

GL11.glTexCoord2f(0f, 1);
GL11.glVertex2f(0, height);
}
GL11.glEnd();
}
}
}


The full code is here: http://www.triangularpixels.com/Junk/FboTest5.java

I'm a bit of a n00b with FBOs but as far as I can tell this is correct usage of an fbo. My only hint so far is that it seems to be related to having two render-to-texture passes - if I have only a single pass (and a single target texture) then it works as expected.

Any hints would be greatly appreciated, thanks.

OrangyTang
05-11-2009, 02:06 AM
Some further tinkering shows that if I unbind and then rebind the FBO before changing the attached texture then it works on ATi. To me that doesn't make much sense - does anyone know if that is correct behaviour or an ATi quirk?

dletozeun
05-11-2009, 04:23 AM
Looks like a driver bug... Are the latest ATI drivers installed on the testing machine?

scratt
05-11-2009, 07:11 PM
If it's on a Mac then don't hold your breath for the drivers to be "latest". ;)

Although right now there is a good chance that either with the next point release of the current OS, or with the release of Snow Leopard that OpenGL drivers will have a minor / major make over on OS X.

So, it is worth filing a bug report with Apple for this, especially right now.