diff --git a/README.md b/README.md index 1ca56bc15..8119c7443 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2238. +This is the source code for early-access 2239. ## Legal Notice diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 3bcaa072f..6964a8273 100755 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -183,6 +183,7 @@ void RestoreGlobalState(bool is_powered_on) { values.max_anisotropy.SetGlobal(true); values.use_speed_limit.SetGlobal(true); values.speed_limit.SetGlobal(true); + values.fps_cap.SetGlobal(true); values.use_disk_shader_cache.SetGlobal(true); values.gpu_accuracy.SetGlobal(true); values.use_asynchronous_gpu_emulation.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index d805b176f..79b2e7e8b 100755 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -524,7 +524,7 @@ struct Values { Setting nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; Setting accelerate_astc{true, "accelerate_astc"}; Setting use_vsync{true, "use_vsync"}; - BasicRangedSetting fps_cap{1000, 1, 1000, "fps_cap"}; + RangedSetting fps_cap{1000, 1, 1000, "fps_cap"}; BasicSetting disable_fps_limit{false, "disable_fps_limit"}; RangedSetting shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL, ShaderBackend::SPIRV, "shader_backend"}; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 54c1a2324..54d4ed93d 100755 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -723,7 +723,7 @@ void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std: bool is_charging = false; bool is_powered = false; - BatteryLevel battery_level = 0; + NpadBatteryLevel battery_level = 0; switch (controller.battery_values[index]) { case Common::Input::BatteryLevel::Charging: is_charging = true; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 3cbe16260..acf54e233 100755 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -346,15 +346,15 @@ struct NpadGcTriggerState { static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); // This is nn::hid::system::NpadBatteryLevel -using BatteryLevel = u32; -static_assert(sizeof(BatteryLevel) == 0x4, "BatteryLevel is an invalid size"); +using NpadBatteryLevel = u32; +static_assert(sizeof(NpadBatteryLevel) == 0x4, "NpadBatteryLevel is an invalid size"); // This is nn::hid::system::NpadPowerInfo struct NpadPowerInfo { bool is_powered; bool is_charging; INSERT_PADDING_BYTES(0x6); - BatteryLevel battery_level; + NpadBatteryLevel battery_level; }; static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index ea7e8f18f..f0f3105dc 100755 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -24,34 +24,25 @@ void Controller_ConsoleSixAxis::OnRelease() {} void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - seven_six_axis.header.timestamp = core_timing.GetCPUTicks(); - seven_six_axis.header.total_entry_count = 17; - if (!IsControllerActivated() || !is_transfer_memory_set) { - seven_six_axis.header.entry_count = 0; - seven_six_axis.header.last_entry_index = 0; + seven_sixaxis_lifo.buffer_count = 0; + seven_sixaxis_lifo.buffer_tail = 0; return; } - seven_six_axis.header.entry_count = 16; - const auto& last_entry = - seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - seven_six_axis.header.last_entry_index = (seven_six_axis.header.last_entry_index + 1) % 17; - auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state; + next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1; // Try to read sixaxis sensor states const auto motion_status = console->GetMotion(); console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - cur_entry.accel = motion_status.accel; + next_seven_sixaxis_state.accel = motion_status.accel; // Zero gyro values as they just mess up with the camera // Note: Probably a correct sensivity setting must be set - cur_entry.gyro = {}; - cur_entry.quaternion = { + next_seven_sixaxis_state.gyro = {}; + next_seven_sixaxis_state.quaternion = { { motion_status.quaternion.xyz.y, motion_status.quaternion.xyz.x, @@ -68,7 +59,8 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti // Update console six axis shared memory std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); // Update seven six axis transfer memory - std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis)); + seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); + std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); } void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { @@ -77,8 +69,7 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { } void Controller_ConsoleSixAxis::ResetTimestamp() { - auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; - cur_entry.sampling_number = 0; - cur_entry.sampling_number2 = 0; + seven_sixaxis_lifo.buffer_count = 0; + seven_sixaxis_lifo.buffer_tail = 0; } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index 7c92413e8..279241858 100755 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -10,6 +10,7 @@ #include "common/quaternion.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" namespace Core::HID { class EmulatedConsole; @@ -40,50 +41,30 @@ private: struct SevenSixAxisState { INSERT_PADDING_WORDS(4); // unused s64 sampling_number{}; - s64 sampling_number2{}; u64 unknown{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Quaternion quaternion{}; }; - static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); - - struct CommonHeader { - s64 timestamp; - s64 total_entry_count; - s64 last_entry_index; - s64 entry_count; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - - // TODO(german77): SevenSixAxisMemory doesn't follow the standard lifo. Investigate - struct SevenSixAxisMemory { - CommonHeader header{}; - std::array sevensixaxis_states{}; - }; - static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size"); + static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size"); // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat struct ConsoleSharedMemory { u64 sampling_number{}; bool is_seven_six_axis_sensor_at_rest{}; + INSERT_PADDING_BYTES(4); // padding f32 verticalization_error{}; Common::Vec3f gyro_bias{}; }; static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); - struct MotionDevice { - Common::Vec3f accel; - Common::Vec3f gyro; - Common::Vec3f rotation; - std::array orientation; - Common::Quaternion quaternion; - }; + Lifo seven_sixaxis_lifo{}; + static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); Core::HID::EmulatedConsole* console; u8* transfer_memory = nullptr; bool is_transfer_memory_set = false; ConsoleSharedMemory console_six_axis{}; - SevenSixAxisMemory seven_six_axis{}; + SevenSixAxisState next_seven_sixaxis_state{}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 8125bbc84..7450eb20a 100755 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -41,6 +41,8 @@ public: bool IsControllerActivated() const; + static const std::size_t hid_entry_count = 17; + protected: bool is_activated{false}; diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 15b3afb7a..afe374fc2 100755 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -54,7 +54,7 @@ private: static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); // This is nn::hid::detail::DebugPadLifo - Lifo debug_pad_lifo{}; + Lifo debug_pad_lifo{}; static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); DebugPadState next_state{}; diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index f924464e0..0936a3fa3 100755 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -136,7 +136,7 @@ private: GestureProperties GetGestureProperties(); // This is nn::hid::detail::GestureLifo - Lifo gesture_lifo{}; + Lifo gesture_lifo{}; static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); GestureState next_state{}; diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 0d61cb470..cf62d3896 100755 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -44,7 +44,7 @@ private: static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); // This is nn::hid::detail::KeyboardLifo - Lifo keyboard_lifo{}; + Lifo keyboard_lifo{}; static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); KeyboardState next_state{}; diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 1ac69aa6f..7559fc78d 100755 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -34,7 +34,7 @@ public: private: // This is nn::hid::detail::MouseLifo - Lifo mouse_lifo{}; + Lifo mouse_lifo{}; static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); Core::HID::MouseState next_state{}; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 4b23230e1..dd4d954aa 100755 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -157,6 +157,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); + shared_memory.system_properties.use_directional_buttons.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; @@ -167,6 +168,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory.system_properties.is_vertical.Assign(1); shared_memory.system_properties.use_plus.Assign(1); shared_memory.system_properties.use_minus.Assign(1); + shared_memory.system_properties.use_directional_buttons.Assign(1); shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; break; diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 3798c037f..9fa113bb6 100755 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -339,26 +339,6 @@ private: static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, "NfcXcdDeviceHandleStateImpl is an invalid size"); - // nn::hid::detail::NfcXcdDeviceHandleStateImplAtomicStorage - struct NfcXcdDeviceHandleStateImplAtomicStorage { - u64 sampling_number; - NfcXcdDeviceHandleStateImpl nfc_xcd_device_handle_state; - }; - static_assert(sizeof(NfcXcdDeviceHandleStateImplAtomicStorage) == 0x20, - "NfcXcdDeviceHandleStateImplAtomicStorage is an invalid size"); - - // This is nn::hid::detail::NfcXcdDeviceHandleState - struct NfcXcdDeviceHandleState { - // TODO(german77): Make this struct a ring lifo object - INSERT_PADDING_BYTES(0x8); // Unused - s64 total_buffer_count = max_buffer_size; - s64 buffer_tail{}; - s64 buffer_count{}; - std::array nfc_xcd_device_handle_storage; - }; - static_assert(sizeof(NfcXcdDeviceHandleState) == 0x60, - "NfcXcdDeviceHandleState is an invalid size"); - // This is nn::hid::system::AppletFooterUiAttributesSet struct AppletFooterUiAttributes { INSERT_PADDING_BYTES(0x4); @@ -433,32 +413,32 @@ private: NpadJoyAssignmentMode assignment_mode; NpadFullKeyColorState fullkey_color; NpadJoyColorState joycon_color; - Lifo fullkey_lifo; - Lifo handheld_lifo; - Lifo joy_dual_lifo; - Lifo joy_left_lifo; - Lifo joy_right_lifo; - Lifo palma_lifo; - Lifo system_ext_lifo; - Lifo sixaxis_fullkey_lifo; - Lifo sixaxis_handheld_lifo; - Lifo sixaxis_dual_left_lifo; - Lifo sixaxis_dual_right_lifo; - Lifo sixaxis_left_lifo; - Lifo sixaxis_right_lifo; + Lifo fullkey_lifo; + Lifo handheld_lifo; + Lifo joy_dual_lifo; + Lifo joy_left_lifo; + Lifo joy_right_lifo; + Lifo palma_lifo; + Lifo system_ext_lifo; + Lifo sixaxis_fullkey_lifo; + Lifo sixaxis_handheld_lifo; + Lifo sixaxis_dual_left_lifo; + Lifo sixaxis_dual_right_lifo; + Lifo sixaxis_left_lifo; + Lifo sixaxis_right_lifo; DeviceType device_type; INSERT_PADDING_BYTES(0x4); // Reserved NPadSystemProperties system_properties; NpadSystemButtonProperties button_properties; - Core::HID::BatteryLevel battery_level_dual; - Core::HID::BatteryLevel battery_level_left; - Core::HID::BatteryLevel battery_level_right; + Core::HID::NpadBatteryLevel battery_level_dual; + Core::HID::NpadBatteryLevel battery_level_left; + Core::HID::NpadBatteryLevel battery_level_right; union { - NfcXcdDeviceHandleState nfc_xcd_device_handle; + Lifo nfc_xcd_device_lifo{}; AppletFooterUi applet_footer; }; INSERT_PADDING_BYTES(0x20); // Unknown - Lifo gc_trigger_lifo; + Lifo gc_trigger_lifo; NpadLarkType lark_type_l_and_main; NpadLarkType lark_type_r; NpadLuciaType lucia_type; diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 135c2bf13..708dde4f0 100755 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -61,7 +61,7 @@ private: static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); // This is nn::hid::detail::TouchScreenLifo - Lifo touch_screen_lifo{}; + Lifo touch_screen_lifo{}; static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); TouchScreenState next_state{}; diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index 54dae0be1..ba8db8d9d 100755 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -102,7 +102,7 @@ private: static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); // This is nn::hid::detail::BasicXpadLifo - Lifo basic_xpad_lifo{}; + Lifo basic_xpad_lifo{}; static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); BasicXpadState next_state{}; }; diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index f0e0bab7f..44c20d967 100755 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -9,7 +9,6 @@ #include "common/common_types.h" namespace Service::HID { -constexpr std::size_t max_buffer_size = 17; template struct AtomicStorage { @@ -17,7 +16,7 @@ struct AtomicStorage { State state; }; -template +template struct Lifo { s64 timestamp{}; s64 total_buffer_count = static_cast(max_buffer_size); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 9bd61e132..ae1684dd4 100755 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -645,6 +645,7 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.max_anisotropy); ReadGlobalSetting(Settings::values.use_speed_limit); ReadGlobalSetting(Settings::values.speed_limit); + ReadGlobalSetting(Settings::values.fps_cap); ReadGlobalSetting(Settings::values.use_disk_shader_cache); ReadGlobalSetting(Settings::values.gpu_accuracy); ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); @@ -659,7 +660,6 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.bg_blue); if (global) { - ReadBasicSetting(Settings::values.fps_cap); ReadBasicSetting(Settings::values.renderer_debug); ReadBasicSetting(Settings::values.renderer_shader_feedback); ReadBasicSetting(Settings::values.enable_nsight_aftermath); @@ -1185,6 +1185,7 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.max_anisotropy); WriteGlobalSetting(Settings::values.use_speed_limit); WriteGlobalSetting(Settings::values.speed_limit); + WriteGlobalSetting(Settings::values.fps_cap); WriteGlobalSetting(Settings::values.use_disk_shader_cache); WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()), static_cast(Settings::values.gpu_accuracy.GetValue(global)), @@ -1208,7 +1209,6 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.bg_blue); if (global) { - WriteBasicSetting(Settings::values.fps_cap); WriteBasicSetting(Settings::values.renderer_debug); WriteBasicSetting(Settings::values.renderer_shader_feedback); WriteBasicSetting(Settings::values.enable_nsight_aftermath); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 7af3ea97e..566879317 100755 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -30,6 +30,9 @@ ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent) connect(ui->button_reset_defaults, &QPushButton::clicked, this, &ConfigureGeneral::ResetDefaults); + + ui->fps_cap_label->setVisible(Settings::IsConfiguringGlobal()); + ui->fps_cap_combobox->setVisible(!Settings::IsConfiguringGlobal()); } ConfigureGeneral::~ConfigureGeneral() = default; @@ -57,6 +60,11 @@ void ConfigureGeneral::SetConfiguration() { } else { ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && use_speed_limit != ConfigurationShared::CheckState::Global); + + ui->fps_cap_combobox->setCurrentIndex(Settings::values.fps_cap.UsingGlobal() ? 0 : 1); + ui->fps_cap->setEnabled(!Settings::values.fps_cap.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->fps_cap_layout, + !Settings::values.fps_cap.UsingGlobal()); } } @@ -106,6 +114,13 @@ void ConfigureGeneral::ApplyConfiguration() { Qt::Checked); Settings::values.speed_limit.SetValue(ui->speed_limit->value()); } + + if (ui->fps_cap_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { + Settings::values.fps_cap.SetGlobal(true); + } else { + Settings::values.fps_cap.SetGlobal(false); + Settings::values.fps_cap.SetValue(ui->fps_cap->value()); + } } } @@ -148,4 +163,9 @@ void ConfigureGeneral::SetupPerGameUI() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && (use_speed_limit != ConfigurationShared::CheckState::Global)); }); + + connect(ui->fps_cap_combobox, qOverload(&QComboBox::activated), this, [this](int index) { + ui->fps_cap->setEnabled(index == 1); + ConfigurationShared::SetHighlight(ui->fps_cap_layout, index == 1); + }); } diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index f9f0e3ebf..112dc72b3 100755 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -6,8 +6,8 @@ 0 0 - 329 - 407 + 744 + 568 @@ -28,34 +28,85 @@ - - - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Use global framerate cap + + + 0 + + - Framerate Cap + Use global framerate cap - - Requires the use of the FPS Limiter Toggle hotkey to take effect. + + + + Set framerate cap: + - - - - - x - - - 1 - - - 1000 - - - 500 - + + + + + Requires the use of the FPS Limiter Toggle hotkey to take effect. + + + Framerate Cap + - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + x + + + 1 + + + 1000 + + + 500 + + + +