Вот очень простая тестовая программа. Когда vsync отключен, эта программа работает на скорости 100FPS и использует практически 0% процессорного времени. Когда я включаю vsync, я получаю 60FPS и 25% (100% одного ядра в 4-х ядерной системе) загрузку процессора. Это использует графический процессор Nvidia. Поиск в Интернете привел меня к предложению отключить «многопоточную оптимизацию» внутри панели управления Nvidia. Это уменьшает загрузку процессора, но только до 10%. Кроме того, если я удаляю вызов в сон после SwapBuffers, я снова получаю 25% использования даже при отключенной многопоточной оптимизации. Может кто-нибудь пролить некоторый свет на это? Я делаю что-то неправильно? Является ли реализация Nvidia OpenGL просто безнадежно ошибочной?
#include <GLFW/glfw3.h>
#include <thread>
#include <cstdlib>
#include <cstdio>
int main(int argc, char *argv[])
{
if(!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Vsync Test", nullptr, nullptr);
if(!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
#ifdef USE_VSYNC
glfwSwapInterval(1);
#else
glfwSwapInterval(0);
#endif
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
double lastTime = glfwGetTime();
double nbFrames = 0;
while(!glfwWindowShouldClose(window))
{
double currentTime = glfwGetTime();
nbFrames++;
if (currentTime - lastTime >= 1.0)
{
char cbuffer[50];
snprintf(cbuffer, sizeof(cbuffer), "OpenGL Vsync Test [%.1f fps, %.3f ms]", nbFrames, 1000.0 / nbFrames);
glfwSetWindowTitle(window, cbuffer);
nbFrames = 0;
lastTime++;
}
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
//limit to 100FPS for when vsync is disabled
std::chrono::milliseconds dura(10);
std::this_thread::sleep_for(dura);
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
Я не решаюсь дать это как ответ, так как я действительно не знаю «ответа», но, надеюсь, я смогу пролить свет на это.
У меня также есть графический процессор nVidia, и я заметил то же самое. Я предполагаю, что драйвер, по сути, ждет вращения:
while(NotTimeToSwapYet()){}
(или как там выглядит модная версия драйвера).
С помощью процесс хакер чтобы отобрать некоторые следы стека из nvoglv32.dll
Это тема, которая находится в верхней части списка в 99% случаев.
KeAcquireSpinLockAtDpcLevel()
который обычно ниже по течению от таких вещей, как
KiCheckForKernelApcDelivery()
а также EngUnlockDirectDrawSurface()
Я недостаточно хорошо разбираюсь в программировании драйверов Windows, чтобы назвать это убедительным, но это, конечно, не говорит мне, что я тоже не прав.
И не похоже, что вы делаете что-то явно не так. По моему опыту, время подкачки в неисключительных приложениях Windows просто очень болезненно: в нем много проб и ошибок, а также много различий между различными системами. Насколько я знаю, нет «правильного» способа сделать это, который будет работать хорошо все время (пожалуйста, кто-то скажет мне, что я неправ!).
В прошлом я мог полагаться на vsync, чтобы поддерживать низкую загрузку ЦП (даже если это делало вещи менее отзывчивыми), но, похоже, это уже не так. Я перешел с DirectX на OpenGL относительно недавно, поэтому не могу сказать вам, является ли это недавним изменением драйвера nVidia, или они просто по-разному относятся к DX и OpenGL по сравнению с vsync.
Других решений пока нет …