3

私は、MS Windows で OpenGL を使用してサーバー側のオフスクリーン レンダリングをプログラミングしています。ワークフローは次の手順で構成されます。

  1. クライアントがボリューム レンダリングの要求を送信します。

  2. サーバーはリクエストを受信し、ワーカー スレッドをフォークして、リクエストに含まれるパラメータでレイキャスティングを行います。

  3. サーバーはレンダリングされた画像を取得してクライアントに送信し、ワーカー スレッドを終了します。

最初は問題なく動作します。ただし、10,000 回のリクエストの後、wglMakeCurrent() は失敗し、重大なメモリ リークが検出される可能性があります。そこで、OpenGL コンテキストの作成と削除のみを含む簡易テスト プログラムを作成します。以下に示します。wglMakeCurrent() は、約 10,000 回のループ後に常に失敗します。コードに何か問題があるかどうか誰か教えてもらえますか? Nvidia Quadro GPU を使用しており、ドライバーのバージョンは 307.45、OS は 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() では解放されません。ワーカーが終了した後も存在するため、メモリ リークが発生します。Windows ではプロセスごとのユーザー オブジェクトに制限があるため、プログラムは最終的に失敗します。

コンテキストの作成/削除のコードがメイン スレッドに移動されると、wglMakeCurrent() は最初の呼び出しの後に新しいユーザー オブジェクトを作成しません。したがって、 wglMakeCurrent() は新しいスレッドでのみ新しいユーザー オブジェクトを作成するようです。ただし、OpenGL コンテキストが明示的に削除され、スレッドが終了するため、そのコンテキストに関連付けられているリソースも解放する必要があります。コードまたはドライバーのせいかどうかはわかりません。誰かがこれで私を助けることができますか?

4

0 に答える 0