所以我偶然发现了一些相当奇怪的东西(在完成一个项目并修复内存泄漏之后,一旦关闭程序,内存泄漏就会导致 100% CPU 峰值),这似乎也会导致令人难以置信的短暂 100% GPU 使用峰值,一旦你关闭程序。
这是我为实现此目的而运行的最少代码:
#undef UNICODE
#include <Windows.h>
#define GLEW_STATIC
#include "include/GL/glew.h"
#include <string>
#include <chrono>
#include <thread>
//
// window
//
HWND window_hwnd = { };
WNDCLASS window_wndclass = { };
std::string wndclass_name = "class";
std::string window_name = "class";
LRESULT CALLBACK WindowProc(
_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (
uMsg
)
{
default:
return DefWindowProc(
hWnd,
uMsg,
wParam,
lParam
);
}
return 0;
}
void window_create_class()
{
window_wndclass = { };
window_wndclass.lpfnWndProc = WindowProc;
window_wndclass.lpszClassName = wndclass_name.c_str();
window_wndclass.cbClsExtra = 0;
window_wndclass.cbWndExtra = 0;
window_wndclass.hInstance = 0;
RegisterClass(
&window_wndclass
);
}
void window_create()
{
window_create_class();
window_hwnd = CreateWindow(
wndclass_name.c_str(),
window_name.c_str(),
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
0,
0
);
}
int window_loop()
{
MSG msg;
BOOL get_message;
while (
(
get_message = GetMessage(
&msg,
window_hwnd,
0,
0
) > 0
) != 0
)
{
if (
get_message == -1
)
{
// error handling
break;
}
else
{
TranslateMessage(
&msg
);
DispatchMessage(
&msg
);
}
}
return get_message;
}
//
// opengl
//
HDC gl_hdc = { };
HGLRC gl_hglrc = { };
PIXELFORMATDESCRIPTOR gl_pixel_format_descriptor = {
sizeof(
PIXELFORMATDESCRIPTOR
),
1,
// Flags
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
// The kind of framebuffer. RGBA or palette.
PFD_TYPE_RGBA,
// Colordepth of the framebuffer.
32,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
// Number of bits for the depthbuffer
24,
// Number of bits for the stencilbuffer
8,
// Number of Aux buffers in the framebuffer.
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int gl_pixel_format = -1;
void gl_pixel_format_configure()
{
gl_pixel_format = ChoosePixelFormat(
gl_hdc,
&gl_pixel_format_descriptor
);
SetPixelFormat(
gl_hdc,
gl_pixel_format,
&gl_pixel_format_descriptor
);
}
void gl_create()
{
gl_pixel_format_configure();
gl_hglrc = wglCreateContext(
gl_hdc
);
wglMakeCurrent(
gl_hdc,
gl_hglrc
);
GLenum state = glewInit();
if (
state != GLEW_OK
)
{
throw;
}
}
void gl_draw()
{
RECT client_rect = { };
GetClientRect(
window_hwnd,
&client_rect
);
int window_width = client_rect.right - client_rect.left;
int window_height = client_rect.bottom - client_rect.top;
glViewport(
0,
0,
window_width,
window_height
);
glClearColor(
0.0f,
0.0f,
0.0f,
1.0f
);
glClear(
GL_COLOR_BUFFER_BIT
);
wglSwapLayerBuffers(
gl_hdc,
WGL_SWAP_MAIN_PLANE
);
}
int main()
{
window_create();
gl_hdc = GetDC(
window_hwnd
);
gl_create();
ShowWindow(
window_hwnd,
SW_SHOW
);
// simulate drawing frames
auto now = std::chrono::steady_clock::now();
auto interval = std::chrono::duration<
double,
std::chrono::seconds::period
>(
1.0 / 60.0
);
auto next = now + interval;
for (
int i = 0;
i < 400;
i++
)
{
gl_draw();
std::this_thread::sleep_until(
next
);
next += interval;
}
return window_loop();
}
在 Windows 上,使用 GLEW 库。使用Visual Studio的编译器编译,经过Release优化。我也在我的笔记本电脑上测试了它,它具有完全不同的 GPU(实际上是英特尔集成显卡),具有相同的效果。
当未调用
wglSwapLayerBuffers
时,不会发生这种情况。
注意它甚至没有绘制任何东西,甚至没有创建任何 OpenGL 对象,也没有在任何地方使用指针。这让我想知道,我使用 Windows 的 OpenGL 上下文是否错误?或者这是 GLEW 的一些特点? (顺便说一句,我假设 400 个绘制帧的影响(这不是导致这种情况的确切数量,我没有费心去精确地确定它,但例如,300 个绘制帧就不会发生这种情况)可能虽然将其设置为 1000+ 肯定是可行的;但对于这个问题来说,这并不是一个不切实际的数字)。
说实话,这不完全是一个问题(毕竟,它发生在main
返回之后),但它仍然很奇怪,我想避免它。那么为什么会发生这种情况,或者至少我该如何解决它?
如官方 OpenGL Wiki 上所述,而不是我提供的示例中的简单上下文,但没有成功。
好奇心也战胜了我,这让我浏览了我的 Steam 库,启动了大约十几个游戏,在主菜单中等待了几秒钟,让它们绘制了几百帧,甚至几千帧。一旦退出游戏,大多数游戏都会出现相同的 100% GPU 峰值。但值得注意的是,一些 AAA 游戏(即《DOOM Eternal》和《GTA V》)并未表现出这种行为。
我想,一方面,这进一步说明了这一点:这并不是真正值得担心的事情。但这也证明这是可以避免的,尽管我仍然不知道如何实现这一目标。
我认为运行这些 AAA 游戏的引擎有自己的 OpenGL 包装器,甚至可能有自己的较低级别的 OpenGL-OS 接口,从而避免使用 WGL,而问题似乎完全源于此。
但这只是猜测,我肯定还没有找到具体的答案。
至于为什么你的程序与其他 win32 程序相比会发生这种情况,我很确定这只是因为你使用的是 GLEW (不过我可能是错的)。