@@ -67,7 +67,8 @@ extern bool tooltips; | |||||
extern bool cpuMeter; | extern bool cpuMeter; | ||||
extern bool lockModules; | extern bool lockModules; | ||||
extern bool squeezeModules; | extern bool squeezeModules; | ||||
extern int frameSwapInterval; | |||||
/** Maximum screen redraw frequency in Hz, or 0 for unlimited. */ | |||||
extern float frameRateLimit; | |||||
extern float autosaveInterval; | extern float autosaveInterval; | ||||
extern bool skipLoadOnLaunch; | extern bool skipLoadOnLaunch; | ||||
extern std::list<std::string> recentPatchPaths; | extern std::list<std::string> recentPatchPaths; | ||||
@@ -409,13 +409,12 @@ struct ViewButton : MenuButton { | |||||
APP->window->setFullScreen(!fullscreen); | 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++) { | for (int i = 1; i <= 6; i++) { | ||||
double frameRate = APP->window->getMonitorRefreshRate() / i; | double frameRate = APP->window->getMonitorRefreshRate() / i; | ||||
menu->addChild(createCheckMenuItem(string::f("%.0f Hz", frameRate), "", | 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 lockModules = false; | ||||
bool squeezeModules = true; | bool squeezeModules = true; | ||||
#if defined ARCH_MAC | #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 | #else | ||||
int frameSwapInterval = 1; | |||||
float frameRateLimit = 60.f; | |||||
#endif | #endif | ||||
float autosaveInterval = 15.0; | float autosaveInterval = 15.0; | ||||
bool skipLoadOnLaunch = false; | bool skipLoadOnLaunch = false; | ||||
@@ -158,7 +158,7 @@ json_t* toJson() { | |||||
json_object_set_new(rootJ, "squeezeModules", json_boolean(squeezeModules)); | 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)); | json_object_set_new(rootJ, "autosaveInterval", json_real(autosaveInterval)); | ||||
@@ -347,9 +347,20 @@ void fromJson(json_t* rootJ) { | |||||
if (squeezeModulesJ) | if (squeezeModulesJ) | ||||
squeezeModules = json_boolean_value(squeezeModulesJ); | squeezeModules = json_boolean_value(squeezeModulesJ); | ||||
// Legacy setting in Rack <2.2 | |||||
json_t* frameSwapIntervalJ = json_object_get(rootJ, "frameSwapInterval"); | 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"); | json_t* autosaveIntervalJ = json_object_get(rootJ, "autosaveInterval"); | ||||
if (autosaveIntervalJ) | if (autosaveIntervalJ) | ||||
@@ -89,8 +89,8 @@ struct Window::Internal { | |||||
int frame = 0; | int frame = 0; | ||||
bool ignoreNextMouseDelta = false; | bool ignoreNextMouseDelta = false; | ||||
int frameSwapInterval = -1; | |||||
double monitorRefreshRate = 0.0; | double monitorRefreshRate = 0.0; | ||||
int frameSwapInterval = -1; | |||||
double frameTime = 0.0; | double frameTime = 0.0; | ||||
double lastFrameDuration = 0.0; | double lastFrameDuration = 0.0; | ||||
@@ -298,7 +298,6 @@ Window::Window() { | |||||
glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); | glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); | ||||
glfwMakeContextCurrent(win); | glfwMakeContextCurrent(win); | ||||
glfwSwapInterval(1); | |||||
const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); | const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); | ||||
if (monitorMode->refreshRate > 0) { | if (monitorMode->refreshRate > 0) { | ||||
internal->monitorRefreshRate = monitorMode->refreshRate; | internal->monitorRefreshRate = monitorMode->refreshRate; | ||||
@@ -433,9 +432,16 @@ void Window::step() { | |||||
// In case glfwPollEvents() sets another OpenGL context | // In case glfwPollEvents() sets another OpenGL context | ||||
glfwMakeContextCurrent(win); | 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 | // Call cursorPosCallback every frame, not just when the mouse moves | ||||
@@ -711,7 +717,7 @@ double Window::getLastFrameDuration() { | |||||
double Window::getFrameDurationRemaining() { | double Window::getFrameDurationRemaining() { | ||||
double frameDurationDesired = internal->frameSwapInterval / internal->monitorRefreshRate; | |||||
double frameDurationDesired = 1.f / settings::frameRateLimit; | |||||
return frameDurationDesired - (system::getTime() - internal->frameTime); | return frameDurationDesired - (system::getTime() - internal->frameTime); | ||||
} | } | ||||