PDA

View Full Version : Crash in glIsEnabled with FBO



James W. Walker
07-31-2008, 06:36 PM
I've been getting some crashes (access violations in the video driver) when using FBOs. So far it has only happened on Windows PCs with Nvidia graphics, but we haven't tested much with other configurations. After much labor, we got it narrowed down to a situation where we start rendering with an FBO, then go into a tight loop that calls glIsEnabled( GL_LIGHT6 ), and after some tens of thousands of iterations, it crashes.

I realize that for performance reasons it is recommended that one minimize glGet... and glIs... calls. I'm sure I could reduce such calls substantially, but I'd rather have no crashes than rarer crashes.

Are there any FBO gotchas I should look for? If not, I guess I'll keep trying to reproduce the bug in simpler and simpler code.

dletozeun
08-01-2008, 12:40 AM
Can you post the recalcitrant piece of code? Bugs are often where we don't look...

James W. Walker
08-01-2008, 10:27 AM
Can you post the recalcitrant piece of code?

I was afraid someone would say that. Currently the code is spread through an application and two DLLs, so I will need to do much simplification before I can post anything.

dletozeun
08-01-2008, 11:23 AM
It is up to you! :) Just to be, sure no opengl errors are generated anywhere?

James W. Walker
08-01-2008, 02:57 PM
I was surprised to find that I was able to make a self-contained example without too much effort.

First, here's the setup for the main OpenGL context:


static int ChooseWindowPixelFormat()
{
PIXELFORMATDESCRIPTOR pixelFormatDesc;

std::memset( &pixelFormatDesc, 0, sizeof(pixelFormatDesc) );

pixelFormatDesc.nSize = sizeof(pixelFormatDesc);
pixelFormatDesc.nVersion = 1;
pixelFormatDesc.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;
pixelFormatDesc.cColorBits = 0;
pixelFormatDesc.cDepthBits = 24;
pixelFormatDesc.cStencilBits = 8;
pixelFormatDesc.iPixelType = PFD_TYPE_RGBA;

int pixelFormat = ChoosePixelFormat( gDC, &pixelFormatDesc );
SetPixelFormat( gDC, pixelFormat, &pixelFormatDesc );

return pixelFormat;
}

void InitOpenGLWindowContext()
{
RECT windowRect;
GetClientRect( gWindow, &windowRect );
gWindowWidth = windowRect.right - windowRect.left;
gWindowHeight = windowRect.bottom - windowRect.top;
int pixelFormat = ChooseWindowPixelFormat();
if (pixelFormat == 0)
{
OutputDebugString("Failed to get pixel format");
throw std::exception();
}
PIXELFORMATDESCRIPTOR pixelFormatDesc;
DescribePixelFormat( gDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pixelFormatDesc );

glContext = wglCreateContext( gDC );
wglMakeCurrent( gDC, glContext );

glBindFrameBuffer = (glBindFramebufferEXTProcPtr) wglGetProcAddress( "glBindFramebufferEXT" );
if (glBindFrameBuffer == NULL)
{
OutputDebugString("No FBO support here");
}
else
{
OutputDebugString("FBO supported here");
InitFBO();
}

glViewport( 0, 0, gWindowWidth, gWindowHeight );
}


Next, we have the initialization of the FBO, which is called from within the main initialization function above. I have lots of glGetError tests here, none of which detected any error.


static void CheckOpenGLError()
{
GLenum theError = glGetError();
if (theError != GL_NO_ERROR)
{
char msg[300];
std::sprintf( msg, "OpenGL error %d", theError );
OutputDebugString(msg);
}
}

template <typename T>
inline void GLGetProcAddress( T&amp; outFuncPtr, const char* inName1 )
{
outFuncPtr = (T) wglGetProcAddress( inName1 );
}


void InitFBO()
{
// Get FBO function pointers
GLGetProcAddress( glGenFramebuffersEXT, "glGenFramebuffersEXT" );
GLGetProcAddress( glDeleteFramebuffersEXT, "glDeleteFramebuffersEXT" );
GLGetProcAddress( glGenRenderbuffersEXT, "glGenRenderbuffersEXT" );
GLGetProcAddress( glDeleteRenderbuffersEXT, "glDeleteRenderbuffersEXT" );
GLGetProcAddress( glBindRenderbufferEXT, "glBindRenderbufferEXT" );
GLGetProcAddress( glRenderbufferStorageEXT, "glRenderbufferStorageEXT" );
GLGetProcAddress( glFramebufferRenderbufferEXT, "glFramebufferRenderbufferEXT" );
GLGetProcAddress( glCheckFramebufferStatusEXT, "glCheckFramebufferStatusEXT" );
GLGetProcAddress( glFramebufferTexture2DEXT, "glFramebufferTexture2DEXT" );

// Create and bind a framebuffer object
glGenFramebuffersEXT( 1, &amp;glFrameBufferID );
CheckOpenGLError();
glBindFrameBuffer( GL_FRAMEBUFFER_EXT, glFrameBufferID );
CheckOpenGLError();

// Create color renderbuffer
glGenRenderbuffersEXT( 1, &amp;glColorRenderBufferID );
CheckOpenGLError();
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT,
glColorRenderBufferID );
CheckOpenGLError();
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_RGB,
kFBO_width, kFBO_height );
CheckOpenGLError();
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT,
glColorRenderBufferID );
CheckOpenGLError();

// Create a depth buffer...
glGenRenderbuffersEXT( 1, &amp;glDepthRenderBufferID );
CheckOpenGLError();
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT,
glDepthRenderBufferID );
CheckOpenGLError();

// Make a packed depth-stencil buffer
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT,
GL_DEPTH24_STENCIL8_EXT, kFBO_width, kFBO_height );
CheckOpenGLError();
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT,
glDepthRenderBufferID );
CheckOpenGLError();
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT,
GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT,
glDepthRenderBufferID );
CheckOpenGLError();

// Check whether FBO is OK
GLenum result = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
if (result == GL_FRAMEBUFFER_COMPLETE_EXT)
{
// Set the viewport
glViewport( 0, 0, kFBO_width, kFBO_height );
}
else
{
OutputDebugString("FBO failed status check");
glBindFrameBuffer( GL_FRAMEBUFFER_EXT, 0 );
glBindFrameBuffer = NULL;
}
}


Finally, the FBO rendering function. There is an access violation in the video driver after 9000000 calls to glIsEnabled.


void RenderFBO()
{
OutputDebugString("RenderFBO 1");

// Make the FBO the current context
wglMakeCurrent( gDC, glContext );
glBindFrameBuffer( GL_FRAMEBUFFER_EXT, glFrameBufferID );
CheckOpenGLError();

OutputDebugString("RenderFBO 2");

int count = 1;
while (count)
{
glIsEnabled( GL_LIGHT6 );
++count;

if ((count % 100000) == 0)
{
char msg[300];
std::sprintf( msg, "RenderFBO %d iterations", count );
OutputDebugString(msg);
}
}
OutputDebugString("RenderFBO end");
}