| @@ -67,7 +67,8 @@ extern bool tooltips; | |||
| extern bool cpuMeter; | |||
| extern bool lockModules; | |||
| extern bool squeezeModules; | |||
| extern int frameSwapInterval; | |||
| /** Maximum screen redraw frequency in Hz, or 0 for unlimited. */ | |||
| extern float frameRateLimit; | |||
| extern float autosaveInterval; | |||
| extern bool skipLoadOnLaunch; | |||
| extern std::list<std::string> recentPatchPaths; | |||
| @@ -409,13 +409,12 @@ struct ViewButton : MenuButton { | |||
| APP->window->setFullScreen(!fullscreen); | |||
| })); | |||
| double frameRate = APP->window->getMonitorRefreshRate() / settings::frameSwapInterval; | |||
| menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", frameRate), [=](ui::Menu* menu) { | |||
| menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", settings::frameRateLimit), [=](ui::Menu* menu) { | |||
| for (int i = 1; i <= 6; i++) { | |||
| double frameRate = APP->window->getMonitorRefreshRate() / i; | |||
| menu->addChild(createCheckMenuItem(string::f("%.0f Hz", frameRate), "", | |||
| [=]() {return settings::frameSwapInterval == i;}, | |||
| [=]() {settings::frameSwapInterval = i;} | |||
| [=]() {return settings::frameRateLimit == frameRate;}, | |||
| [=]() {settings::frameRateLimit = frameRate;} | |||
| )); | |||
| } | |||
| })); | |||
| @@ -42,10 +42,10 @@ bool cpuMeter = false; | |||
| bool lockModules = false; | |||
| bool squeezeModules = true; | |||
| #if defined ARCH_MAC | |||
| // Most Mac GPUs can't handle rendering the screen every frame, so use ~30 Hz by default. | |||
| int frameSwapInterval = 2; | |||
| // Most Mac GPUs can't handle rendering the screen every frame, so use 30 Hz by default. | |||
| float frameRateLimit = 30.f; | |||
| #else | |||
| int frameSwapInterval = 1; | |||
| float frameRateLimit = 60.f; | |||
| #endif | |||
| float autosaveInterval = 15.0; | |||
| bool skipLoadOnLaunch = false; | |||
| @@ -158,7 +158,7 @@ json_t* toJson() { | |||
| json_object_set_new(rootJ, "squeezeModules", json_boolean(squeezeModules)); | |||
| json_object_set_new(rootJ, "frameSwapInterval", json_integer(frameSwapInterval)); | |||
| json_object_set_new(rootJ, "frameRateLimit", json_real(frameRateLimit)); | |||
| json_object_set_new(rootJ, "autosaveInterval", json_real(autosaveInterval)); | |||
| @@ -347,9 +347,20 @@ void fromJson(json_t* rootJ) { | |||
| if (squeezeModulesJ) | |||
| squeezeModules = json_boolean_value(squeezeModulesJ); | |||
| // Legacy setting in Rack <2.2 | |||
| json_t* frameSwapIntervalJ = json_object_get(rootJ, "frameSwapInterval"); | |||
| if (frameSwapIntervalJ) | |||
| frameSwapInterval = json_integer_value(frameSwapIntervalJ); | |||
| if (frameSwapIntervalJ) { | |||
| // Assume 60 Hz monitor refresh rate. | |||
| int frameSwapInterval = json_integer_value(frameSwapIntervalJ); | |||
| if (frameSwapInterval > 0) | |||
| frameRateLimit = 60.f / frameSwapInterval; | |||
| else | |||
| frameRateLimit = 0.f; | |||
| } | |||
| json_t* frameRateLimitJ = json_object_get(rootJ, "frameRateLimit"); | |||
| if (frameRateLimitJ) | |||
| frameRateLimit = json_number_value(frameRateLimitJ); | |||
| json_t* autosaveIntervalJ = json_object_get(rootJ, "autosaveInterval"); | |||
| if (autosaveIntervalJ) | |||
| @@ -89,8 +89,8 @@ struct Window::Internal { | |||
| int frame = 0; | |||
| bool ignoreNextMouseDelta = false; | |||
| int frameSwapInterval = -1; | |||
| double monitorRefreshRate = 0.0; | |||
| int frameSwapInterval = -1; | |||
| double frameTime = 0.0; | |||
| double lastFrameDuration = 0.0; | |||
| @@ -298,7 +298,6 @@ Window::Window() { | |||
| glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); | |||
| glfwMakeContextCurrent(win); | |||
| glfwSwapInterval(1); | |||
| const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); | |||
| if (monitorMode->refreshRate > 0) { | |||
| internal->monitorRefreshRate = monitorMode->refreshRate; | |||
| @@ -433,9 +432,16 @@ void Window::step() { | |||
| // In case glfwPollEvents() sets another OpenGL context | |||
| glfwMakeContextCurrent(win); | |||
| if (settings::frameSwapInterval != internal->frameSwapInterval) { | |||
| glfwSwapInterval(settings::frameSwapInterval); | |||
| internal->frameSwapInterval = settings::frameSwapInterval; | |||
| // 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 | |||
| @@ -711,7 +717,7 @@ double Window::getLastFrameDuration() { | |||
| double Window::getFrameDurationRemaining() { | |||
| double frameDurationDesired = internal->frameSwapInterval / internal->monitorRefreshRate; | |||
| double frameDurationDesired = 1.f / settings::frameRateLimit; | |||
| return frameDurationDesired - (system::getTime() - internal->frameTime); | |||
| } | |||