私は、MS Windows で OpenGL を使用してサーバー側のオフスクリーン レンダリングをプログラミングしています。ワークフローは次の手順で構成されます。
クライアントがボリューム レンダリングの要求を送信します。
サーバーはリクエストを受信し、ワーカー スレッドをフォークして、リクエストに含まれるパラメータでレイキャスティングを行います。
サーバーはレンダリングされた画像を取得してクライアントに送信し、ワーカー スレッドを終了します。
最初は問題なく動作します。ただし、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 コンテキストが明示的に削除され、スレッドが終了するため、そのコンテキストに関連付けられているリソースも解放する必要があります。コードまたはドライバーのせいかどうかはわかりません。誰かがこれで私を助けることができますか?