From 36c9c1232ef8ad3906dee01a7c4e60bd90e64f4b Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 2 Nov 2022 04:13:02 -0400 Subject: [PATCH] Use sleep-based frame limiting instead of vsync since it's unreliable on buggy graphics drivers. --- src/window/Window.cpp | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/window/Window.cpp b/src/window/Window.cpp index 986f5e7f..0065927c 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -91,8 +91,8 @@ struct Window::Internal { bool ignoreNextMouseDelta = false; double monitorRefreshRate = 0.0; int frameSwapInterval = -1; - double frameTime = 0.0; - double lastFrameDuration = 0.0; + double frameTime = NAN; + double lastFrameDuration = NAN; math::Vec lastMousePos; @@ -298,6 +298,7 @@ Window::Window() { glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); glfwMakeContextCurrent(win); + glfwSwapInterval(0); const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); if (monitorMode->refreshRate > 0) { internal->monitorRefreshRate = monitorMode->refreshRate; @@ -412,11 +413,11 @@ void Window::run() { void Window::step() { double frameTime = system::getTime(); - double lastFrameTime = internal->frameTime; + if (std::isfinite(internal->frameTime)) { + internal->lastFrameDuration = frameTime - internal->frameTime; + } internal->frameTime = frameTime; - internal->lastFrameDuration = frameTime - lastFrameTime; internal->fbCount = 0; - // DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); // double t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0; // Make event handlers and step() have a clean NanoVG context @@ -433,17 +434,6 @@ void Window::step() { // In case glfwPollEvents() sets another OpenGL context glfwMakeContextCurrent(win); - // Set swap interval - int frameSwapInterval = 0; - if (settings::frameRateLimit > 0.f) { - frameSwapInterval = std::ceil(internal->monitorRefreshRate / settings::frameRateLimit); - } - - if (frameSwapInterval != internal->frameSwapInterval) { - glfwSwapInterval(frameSwapInterval); - internal->frameSwapInterval = frameSwapInterval; - } - // Call cursorPosCallback every frame, not just when the mouse moves { double xpos, ypos; @@ -514,25 +504,26 @@ void Window::step() { glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); nvgEndFrame(vg); - // t4 = system::getTime(); } + // t4 = system::getTime(); } glfwSwapBuffers(win); - // On some platforms, glfwSwapBuffers() doesn't wait on monitor refresh, so we have to sleep as a fallback. - double frameDurationRemaining = getFrameDurationRemaining(); - if (frameDurationRemaining > 0.0) { - std::this_thread::sleep_for(std::chrono::duration(frameDurationRemaining)); + // Limit frame rate + if (settings::frameRateLimit > 0) { + double remaining = getFrameDurationRemaining(); + if (remaining > 0.0) { + system::sleep(remaining); + } } // t5 = system::getTime(); - // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", // (t1 - frameTime) * 1e3f, // (t2 - t1) * 1e3f, // (t3 - t2) * 1e3f, - // (t4 - t2) * 1e3f, + // (t4 - t3) * 1e3f, // (t5 - t4) * 1e3f, // (t5 - frameTime) * 1e3f // ); @@ -717,8 +708,8 @@ double Window::getLastFrameDuration() { double Window::getFrameDurationRemaining() { - double frameDurationDesired = 1.f / settings::frameRateLimit; - return frameDurationDesired - (system::getTime() - internal->frameTime); + double frameDuration = 1.f / settings::frameRateLimit; + return frameDuration - (system::getTime() - internal->frameTime); }