多次调用GLClear不交换缓冲区致内存泄漏(Windows MSVC)
Windows MSVC环境下OpenGL
glClear无缓冲区交换时的内存泄漏问题 在Windows MSVC环境中,调用glClear但不执行缓冲区交换操作时,程序出现内存泄漏。无法确定这是显卡驱动问题还是代码实现错误,恳请帮忙测试该问题,或提供相关排查思路。
代码概述(完整代码见下文)
static bool CloseFlag = false; LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static PAINTSTRUCT ps; switch(uMsg) { case WM_SIZE: glViewport(0, 0, LOWORD(lParam), HIWORD(lParam)); PostMessage(hWnd, WM_PAINT, 0, 0); return 0; case WM_CHAR: //Handle input.... return 0; case WM_CLOSE: CloseFlag = true; return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } HWND CreateOpenGLWindow(char* title, int x, int y, int width, int height, BYTE type, DWORD flags) { //Create window (with double buffer) and register it... } int main () { hWnd = CreateOpenGLWindow("minimal", 0, 0, 256, 256, PFD_TYPE_RGBA, 0); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); gladLoadWGL(hDC); gladLoadGL(); ShowWindow(hWnd, SW_SHOW); while(!CloseFlag) { //Handles input while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } glClear(GL_COLOR_BUFFER_BIT); } wglMakeCurrent(NULL, NULL); ReleaseDC(hWnd, hDC); wglDeleteContext(hRC); DestroyWindow(hWnd); return 0; }
可复现问题的最简Win32代码
#ifndef UNICODE #define UNICODE #define _UNICODE #endif #include <windows.h> /* must include this before GL/gl.h */ #include "glad/glad.h" #include "glad/glad_wgl.h" #include "wglext.h" #include <string> static bool CloseFlag = false; void display(HDC hDC) { /* rotate a triangle around */ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2i(0, 1); glColor3f(0.0f, 1.0f, 0.0f); glVertex2i(-1, -1); glColor3f(0.0f, 0.0f, 1.0f); glVertex2i(1, -1); glEnd(); glFlush(); SwapBuffers(hDC); } void JustClear() { glClear(GL_COLOR_BUFFER_BIT); } LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static PAINTSTRUCT ps; switch(uMsg) { case WM_SIZE: glViewport(0, 0, LOWORD(lParam), HIWORD(lParam)); PostMessage(hWnd, WM_PAINT, 0, 0); return 0; case WM_CHAR: switch (wParam) { case 27: /* ESC key */ //PostQuitMessage(0); CloseFlag = true; break; } return 0; case WM_CLOSE: CloseFlag = true; //PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } HWND CreateOpenGLWindow(char* title, int x, int y, int width, int height, BYTE type, DWORD flags) { int pf; HDC hDC; HWND hWnd; WNDCLASS wc; PIXELFORMATDESCRIPTOR pfd; static HINSTANCE hInstance = 0; /* only register the window class once - use hInstance as a flag. */ if (!hInstance) { hInstance = GetModuleHandle(NULL); wc.style = CS_OWNDC; wc.lpfnWndProc = (WNDPROC)WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = L"OpenGL"; if (!RegisterClass(&wc)) { return NULL; } } std::wstring className = L"OpenGL"; hWnd = CreateWindow(className.c_str(), className.c_str(), WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, x, y, width, height, NULL, NULL, hInstance, NULL); if (hWnd == NULL) { return NULL; } hDC = GetDC(hWnd); /* there is no guarantee that the contents of the stack that become the pfd are zeroed, therefore _make sure_ to clear these bits. */ memset(&pfd, 0, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | flags; pfd.iPixelType = type; pfd.cColorBits = 32; pf = ChoosePixelFormat(hDC, &pfd); if (pf == 0) { return 0; } if (SetPixelFormat(hDC, pf, &pfd) == FALSE) { return 0; } DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); ReleaseDC(hWnd, hDC); return hWnd; } int main () { HDC hDC; /* device context */ HGLRC hRC; /* opengl context */ HWND hWnd; /* window */ MSG msg; /* message */ hWnd = CreateOpenGLWindow("minimal", 0, 0, 256, 256, PFD_TYPE_RGBA, 0); if (hWnd == NULL) exit(1); hDC = GetDC(hWnd); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); if(!gladLoadWGL(hDC)) { return -1; } if (!gladLoadGL()) //Load Glad { return -1; } ShowWindow(hWnd, SW_SHOW); while(!CloseFlag) { //Handles input while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } //Render //display(hDC); JustClear(); } wglMakeCurrent(NULL, NULL); ReleaseDC(hWnd, hDC); wglDeleteContext(hRC); DestroyWindow(hWnd); return 0; }
注:wglext.h取自Khronos OpenGL注册表
OpenGL Glad配置信息
/* OpenGL loader generated by glad 0.1.36 on Fri Oct 28 11:12:34 2022. Language/Generator: C/C++ Specification: gl APIs: gl=3.3 Profile: compatibility Extensions: Loader: True Local files: False Omit khrplatform: False Reproducible: False Commandline: --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="" */
同时使用了包含所有扩展的Glad wgl 1.0版本。
使用的CMake配置
cmake_minimum_required(VERSION 3.14) set (CMAKE_CXX_STANDARD 11) # For Clang to do parsing set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # set the project name project(Example) add_executable(EXAMPLE_EXE ${CMAKE_CURRENT_LIST_DIR}/Src/main.cpp) add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/External/glad_v0.1.36") find_package(OpenGL REQUIRED) target_include_directories(EXAMPLE_EXE PUBLIC "${CMAKE_CURRENT_LIST_DIR}/External/wglExt") target_link_libraries(EXAMPLE_EXE PUBLIC OpenGL::GL glad)
内容的提问来源于stack exchange,提问作者Eds
相关产品推荐
相关产品推荐

