Jump to content

  • Log In with Google      Sign In   
  • Create Account

Does wglMakeCurrent() leak memory in a worker thread?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 Humblest   Members   -  Reputation: 102

Like
0Likes
Like

Posted 08 January 2013 - 03:04 AM

Hi, all:

I've been programming server-side offscreen rendering with OpenGL under MS Windows. The workflow consists of the following steps:
1. A client sends a request for volume rendering.
2. Server receives the request, forks a worker thread to do some ray-casting with parameters contained in the request.
3. Server retrieves the rendered image, sends it to the client and terminates the worker thread.

It works fine at first. However, after 10,000 requests, wglMakeCurrent() will fail and significant memory leak can be detected. So I make a simplified test program which contains only OpenGL context creation and deletion. It's shown below. wglMakeCurrent() always fails after about 10,000 loops. Can somebody tell me if there's anything wrong with the code? I'm using Nvidia Quadro GPU, the driver version is 307.45, OS is Windows 7 64-bit.

 

 

#include <cstdio>
#include <windows.h>
#include <tchar.h>
#include <process.h>

LRESULT CALLBACK WndProc_GL(HWND handle, UINT message, WPARAM w_param, LPARAM l_param)
{
  return DefWindowProc(handle, message, w_param, l_param);
}//-------------------------------------------------------

unsigned int __stdcall OpenglThreadProc(void *ptr_input)
{
  HINSTANCE inst_handle = GetModuleHandle(NULL);
  WNDCLASS wnd_class = {CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
    (WNDPROC)WndProc_GL,
    0, 0, inst_handle, NULL, NULL, NULL, NULL,
    _T("OpenGL Hidden Window Class")
  };
  if (!RegisterClass(&wnd_class)) return 0;
  HWND window_handle = CreateWindow(_T("OpenGL Hidden Window Class"),
    _T("Window For OpenGL"),
    WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS|WS_CLIPCHILDRE N, 0, 0, 256, 256,
    NULL, NULL, inst_handle, NULL);
  if (!window_handle) return 0;
  HDC dc_handle = GetDC(window_handle);
  PIXELFORMATDESCRIPTOR ogl_pfd = {sizeof(PIXELFORMATDESCRIPTOR), 1,
    PFD_SUPPORT_OPENGL,
    PFD_TYPE_RGBA, 32,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    24, 8, 0,
    PFD_MAIN_PLANE,
    0, 0, 0, 0
  };
  int pixel_format = ChoosePixelFormat(dc_handle, &ogl_pfd);
  if (!SetPixelFormat(dc_handle, pixel_format, &ogl_pfd)) return 0;
    HGLRC rc_handle = wglCreateContext(dc_handle);
  if (!rc_handle || !wglMakeCurrent(dc_handle, rc_handle)) return 0;

  _tprintf_s(_T("Executing Thread %d.\n"), *(reinterpret_cast<int*>(ptr_input)) + 1);

  // Deletes OpenGL context and destroys window.
  wglMakeCurrent(NULL, NULL);
  wglDeleteContext(rc_handle);
  ReleaseDC(window_handle, dc_handle);
  DestroyWindow(window_handle);
  UnregisterClass(_T("OpenGL Hidden Window Class"), GetModuleHandle(NULL));
  return 1;
}//--------

int main (const int argc, TCHAR *argv[])
{
  int i = 0;
  for (; i < 20000; i++) {
    HANDLE running_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
      OpenglThreadProc, &i, 0, NULL));
    WaitForSingleObject(running_thread, INFINITE);
    CloseHandle(running_thread);
  }
  return 1;
}//---------

 

 

I found something confusing with this test program. wglMakeCurrent() creates a Windows user object every time it's called, but this object is not released in wglDeleteContext(). It still exists even after the worker is terminated, causing a memory leak. There is a per-process limit of user objects under Windows, so the program will eventually fail.

When the code of context creation/deletion is moved to the main thread, wglMakeCurrent() doesn't create new user object after the first invocation. So it seems that wglMakeCurrent() only create new user object in new threads. But since the OpenGL context is explicitly deleted and the thread is terminated, resources associated with that context should be released as well. I'm not sure it's the fault with my code or the driver. Can somebody help me with this?



Sponsor:

#2 samoth   Crossbones+   -  Reputation: 5038

Like
1Likes
Like

Posted 08 January 2013 - 06:58 AM

I can't tell whether wglMakeCurrent really leaks or whether there is a different reason for what you see, but if you need to call wglMakeCurrent more than 2-3 times in a program, you're very likely doing something wrong.

Usually you will have one render thread (for most people that is the main thread, too). Often you have worker threads to fill buffers (given a pointer to a mapping), too.
Sometimes you have shared contexts and two threads (one for rendering, one for uploading data), but this is rarely done both for added overhead and complexity.

You really never want to have a hundred or a thousand threads with a hundred/thousand contexts. You also really do not want to call wglMakeCurrent in the middle of your program, because it kills the pipeline.

What you want to do is create one (or at most two or three) threads that will deal with OpenGL, and one (or at most two or three) contexts. Then you want to make exactly one context current in one thread. And then you never want to change that again.

Edited by samoth, 08 January 2013 - 06:59 AM.


#3 Humblest   Members   -  Reputation: 102

Like
0Likes
Like

Posted 09 January 2013 - 01:09 AM

I can't tell whether wglMakeCurrent really leaks or whether there is a different reason for what you see, but if you need to call wglMakeCurrent more than 2-3 times in a program, you're very likely doing something wrong.

Usually you will have one render thread (for most people that is the main thread, too). Often you have worker threads to fill buffers (given a pointer to a mapping), too.
Sometimes you have shared contexts and two threads (one for rendering, one for uploading data), but this is rarely done both for added overhead and complexity.

You really never want to have a hundred or a thousand threads with a hundred/thousand contexts. You also really do not want to call wglMakeCurrent in the middle of your program, because it kills the pipeline.

What you want to do is create one (or at most two or three) threads that will deal with OpenGL, and one (or at most two or three) contexts. Then you want to make exactly one context current in one thread. And then you never want to change that again.

For each thread, there's one dedicated OpenGL context and only one wglMakeCurrent(). This is a server rendering program rather than a desktop application, each thread is responding to one client request and doing its own job. No OpenGL context is shared among them. The maximum number of concurrency won't be high, but concurrency is required.



#4 samoth   Crossbones+   -  Reputation: 5038

Like
0Likes
Like

Posted 09 January 2013 - 02:03 AM

What you describe should actually be a legitimate way of using OpenGL, and should cause no problems (both in regards of errors and performance). Did you try if you actually need wglMakeCurrent at all? If you create a context in the worker thread, it should already be current in that one. Since you don't really want it to be current anywhere else, why not just leave it that way?

 

This still doesn't answer the question whether wglMakeCurrent leaks, but it might just solve your problem (or, it might shift your problem to wglCreateContext eventually failing -- I hope not).






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS