3

我一直在 MS Windows 下使用 OpenGL 编写服务器端离屏渲染。工作流程包括以下步骤:

  1. 客户端发送体绘制请求。

  2. 服务器接收到请求,派生一个工作线程以使用请求中包含的参数进行一些光线投射。

  3. 服务器检索渲染图像,将其发送到客户端并终止工作线程。

一开始它工作得很好。但是,在 10,000 个请求之后,wglMakeCurrent() 将失败并且可以检测到显着的内存泄漏。所以我做了一个简化的测试程序,它只包含 OpenGL 上下文的创建和删除。如下图所示。wglMakeCurrent() 在大约 10,000 次循环后总是失败。有人可以告诉我代码是否有问题吗?我使用的是 Nvidia Quadro GPU,驱动版本是 307.45,操作系统是 Windows 7 64 位。

 #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;
}//---------

我发现这个测试程序有些令人困惑。wglMakeCurrent() 每次被调用时都会创建一个 Windows 用户对象,但是这个对象并没有在 wglDeleteContext() 中释放。即使在worker终止后它仍然存在,导致内存泄漏。在 Windows 下存在每个进程的用户对象限制,因此程序最终会失败。

当上下文创建/删除的代码移动到主线程时,wglMakeCurrent() 在第一次调用后不会创建新的用户对象。所以看起来 wglMakeCurrent() 只在新线程中创建新的用户对象。但是由于 OpenGL 上下文被显式删除并且线程被终止,与该上下文相关的资源也应该被释放。我不确定这是我的代码或驱动程序的问题。有人可以帮我吗?

4

0 回答 0