Hi all,
I’ve just modified my renderer to use FBOs instead of pbuffers for doing my multipass rendering. Its basically drawing into a float16 framebuffer, generating a glow texture in another framebuffer, blurs that, adds it back to the float16, then does some refraction post processing, and draws it into the windowsystem framebuffer. This worked fine with pbuffers, and now with fbo’s however in my test scenes that have had consistant 15FPS in certain views with pbuffers, now run at 9FPS! It seems everything has slowed down with FBO’s, including drawing lighting & stencil passes into the float16 FBO (went from about 0.04sec to 0.05sec for all my lighting to draw!)
I havent had time to test it out thoroughly yet, but it seems that its definitly got to do with the FBO code, I can change a #define and go back to the pbuffer version, that still runs at the same framerates as before!
I was doing something silly and reallocating the FBO’s on resizes, causing about 6 reallocations/frame, now its keeping it at the largest size (was doing this with pbuffers too), so I expected it to hop back to the same speed as pbuffers, but its not.
So, anyone else seen something similar? Heres my FBO initing code:
bool FramebufferObject::CreateFBO()
{
CHECK_GL_ERRORS("FramebufferObject::CreateFBO: start");
// if(m_iFBO)
// Destroy(false);
if(!m_iFBO)
glGenFramebuffersEXT(1, &m_iFBO);
if(!m_iDepthRB)
glGenRenderbuffersEXT(1, &m_iDepthRB);
if(!m_iStencilRB)
glGenRenderbuffersEXT(1, &m_iStencilRB);
if(!m_iDepthStencilRB)
glGenRenderbuffersEXT(1, &m_iDepthStencilRB);
CHECK_GL_ERRORS("FramebufferObject::CreateFBO: before binding FBO");
// Enable render-to-texture
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_iFBO);
// Set up color_tex and depth_rb for render-to-texture
CreateTextureObject();
CHECK_GL_ERRORS("FramebufferObject::CreateFBO: after creating texture");
// attach positive X for now
if(m_iTexTarget == GL_TEXTURE_CUBE_MAP)
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X, m_iTextureID, 0);
else
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_iTexTarget, m_iTextureID, 0);
CHECK_GL_ERRORS("FramebufferObject::CreateFBO: after color attachment");
// if we're using 24bit depth and 8bit stencil, we can use an interleaved buffer for both stencil & depth data
// otherwise we can only use the one buffer for each separately (lone stencil not currently supported on any hardware!)
if(m_iDepthBits > 0 && m_iStencilBits > 0)
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_iDepthStencilRB);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_NV, m_iWidth, m_iHeight);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_iDepthStencilRB);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_iDepthStencilRB);
}
else
{
// initialize separate depth renderbuffer
if(m_iDepthBits > 0)
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_iDepthRB);
int depth = GL_DEPTH_COMPONENT32;
if(m_iDepthBits < 32)
depth = GL_DEPTH_COMPONENT24;
if(m_iDepthBits < 24)
depth = GL_DEPTH_COMPONENT16;
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depth, m_iWidth, m_iHeight);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_iDepthRB);
}
CHECK_GL_ERRORS("FramebufferObject::CreateFBO: after depth attachment");
// and the separate stencil renderbuffer
if(m_iStencilBits > 0)
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_iStencilRB);
int stencil = GL_STENCIL_INDEX8_EXT;
if(m_iStencilBits < 8)
stencil = GL_STENCIL_INDEX4_EXT;
if(m_iStencilBits < 4)
stencil = GL_STENCIL_INDEX1_EXT;
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, stencil, m_iWidth, m_iHeight);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_iStencilRB);
}
CHECK_GL_ERRORS("FramebufferObject::CreateFBO: after stencil attachment");
}
// Check framebuffer completeness at the end of initialization.
CheckFBOStatus();
// Re-enable rendering to the window
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// remember our new actual size
m_iActualWidth = m_iWidth;
m_iActualHeight = m_iHeight;
CHECK_GL_ERRORS("FramebufferObject::CreateFBO: end");
return true;
}
void FramebufferObject::CreateTextureObject()
{
CHECK_GL_ERRORS("FramebufferObject::CreateTextureObject: start");
if(!m_iTextureID)
glGenTextures(1, &m_iTextureID);
glBindTexture(m_iTexTarget, m_iTextureID);
if(m_iTexTarget == GL_TEXTURE_CUBE_MAP)
{
glTexParameterf(m_iTexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, m_iWidth, m_iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, m_iWidth, m_iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, m_iWidth, m_iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, m_iWidth, m_iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, m_iWidth, m_iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, m_iWidth, m_iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
else
{
int type = GL_UNSIGNED_BYTE;
int internalformat = GL_RGBA8;
if(m_bFloatBuffer)
{
if(m_iColourBits > 64)
{
type = GL_FLOAT; // shouldnt matter
internalformat = GL_RGBA32F_ARB;
}
else
{
type = GL_FLOAT; // shouldnt matter
internalformat = GL_RGBA16F_ARB;
}
}
glTexImage2D(m_iTexTarget, 0, internalformat, m_iWidth, m_iHeight, 0, GL_RGBA, type, NULL);
}
CHECK_GL_ERRORS("FramebufferObject::CreateTextureObject: end");
}