Crash in glIsEnabled with FBO

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.

Can you post the recalcitrant piece of code? Bugs are often where we don’t look…

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.

It is up to you! :slight_smile: Just to be, sure no opengl errors are generated anywhere?

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& 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, &glFrameBufferID );
	CheckOpenGLError();
	glBindFrameBuffer( GL_FRAMEBUFFER_EXT, glFrameBufferID );
	CheckOpenGLError();

	// Create color renderbuffer
	glGenRenderbuffersEXT( 1, &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, &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");
}