Juce::OpenGLContext HDC leak


#1

Hi !

I think have found a complex bug and its fix in OpenGLContext
Tested and reproduced on Window 7 64 Pro Sp1 US.
Nvidia GTX, 295, 480, 580 and 680.
Nvidia Driver version 301.42 to 310.90.

If we create a loop creating and deleting an OpenGL component attached to a juce::OpenGLContext with setComponentPaintingEnabled(true),
at each iteration, nvoglv64.dll performs an HDC leak.
(visible in Processes panel of the Window Task Manager column “GDI Objects”)
In my case, all OpenGL context are shared, and OpenGL drawing performance decreases proportionately to the leak count.

When component painting is enabled, juce::OpenGLContext::CachedImage uses an internal juce::OpenGLFrameBuffer (cachedImageFrameBuffer).
OpenGLFrameBuffer::Pimpl destructor do not calls glDeleteFramebuffers because when CachedImage destructor is called, OpenGLHelpers::isContextActive() return false.

To fix this issue, I modify the following OpenGLContext::CachedImage’s method:

[code] void shutdownOnThread()
{
if (context.renderer != nullptr)
context.renderer->openGLContextClosing();

    nativeContext->shutdownOnRenderThread();

    associatedObjectNames.clear();
    associatedObjects.clear();
}[/code]

by adding a call to cachedImageFrameBuffer.release(); before nativeContext->shutdownOnRenderThread() call, like this:

[code] void shutdownOnThread()
{
if (context.renderer != nullptr)
context.renderer->openGLContextClosing();

    cachedImageFrameBuffer.release();
    nativeContext->shutdownOnRenderThread();

    associatedObjectNames.clear();
    associatedObjects.clear();
[/code]}

I hope this can help !

For the little story, nvoglv64.dll seems to manage off screen rendering by using hidden Win32 windows (NVOpenGLPBuffer registered class name).
Ugly !
When an application create a frame buffer, nvoglv64.dll calls GetDC on this window.
If this frame buffer is not explicitly destroyed before the OpenGL context destruction, nvoglv64.dll forgot to call ReleaseDC. That’s why I think it’s a Nvidia bug.

By the way, in case of shared context, OpenGLFrameBuffer::release() must be called to destroy attached render buffers.

Thanks to Microsoft Spy++, Rohitab Batra Api Monitor, Nir Sofer GDIView and ADM gDEBugger, helping me found the origin of this issue in all this mess.


#2

Ah, good find! Thanks very much, I’ll get that sorted out…


#3

You are welcome.

thanks for having taken care about this issue.