Merge pull request #4282 from zhaowenlan1779/frame-advance
core, citra_qt: add frame advancing to framelimiter
This commit is contained in:
		| @@ -352,6 +352,10 @@ void GMainWindow::InitializeHotkeys() { | ||||
|                                    Qt::ApplicationShortcut); | ||||
|     hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"), | ||||
|                                    Qt::ApplicationShortcut); | ||||
|     hotkey_registry.RegisterHotkey("Main Window", "Toggle Frame Advancing", QKeySequence("CTRL+A"), | ||||
|                                    Qt::ApplicationShortcut); | ||||
|     hotkey_registry.RegisterHotkey("Main Window", "Advance Frame", QKeySequence(Qt::Key_Backslash), | ||||
|                                    Qt::ApplicationShortcut); | ||||
|     hotkey_registry.LoadHotkeys(); | ||||
|  | ||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, | ||||
| @@ -409,6 +413,10 @@ void GMainWindow::InitializeHotkeys() { | ||||
|                     UpdateStatusBar(); | ||||
|                 } | ||||
|             }); | ||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Toggle Frame Advancing", this), | ||||
|             &QShortcut::activated, ui.action_Enable_Frame_Advancing, &QAction::trigger); | ||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Advance Frame", this), &QShortcut::activated, | ||||
|             ui.action_Advance_Frame, &QAction::trigger); | ||||
| } | ||||
|  | ||||
| void GMainWindow::ShowUpdaterWidgets() { | ||||
| @@ -540,6 +548,20 @@ void GMainWindow::ConnectMenuEvents() { | ||||
|     connect(ui.action_Play_Movie, &QAction::triggered, this, &GMainWindow::OnPlayMovie); | ||||
|     connect(ui.action_Stop_Recording_Playback, &QAction::triggered, this, | ||||
|             &GMainWindow::OnStopRecordingPlayback); | ||||
|     connect(ui.action_Enable_Frame_Advancing, &QAction::triggered, this, [this] { | ||||
|         if (emulation_running) { | ||||
|             Core::System::GetInstance().frame_limiter.SetFrameAdvancing( | ||||
|                 ui.action_Enable_Frame_Advancing->isChecked()); | ||||
|             ui.action_Advance_Frame->setEnabled(ui.action_Enable_Frame_Advancing->isChecked()); | ||||
|         } | ||||
|     }); | ||||
|     connect(ui.action_Advance_Frame, &QAction::triggered, this, [this] { | ||||
|         if (emulation_running) { | ||||
|             ui.action_Enable_Frame_Advancing->setChecked(true); | ||||
|             ui.action_Advance_Frame->setEnabled(true); | ||||
|             Core::System::GetInstance().frame_limiter.AdvanceFrame(); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     // Help | ||||
|     connect(ui.action_FAQ, &QAction::triggered, | ||||
| @@ -803,6 +825,9 @@ void GMainWindow::ShutdownGame() { | ||||
|     // TODO(bunnei): This function is not thread safe, but it's being used as if it were | ||||
|     Pica::g_debug_context->ClearBreakpoints(); | ||||
|  | ||||
|     // Frame advancing must be cancelled in order to release the emu thread from waiting | ||||
|     Core::System::GetInstance().frame_limiter.SetFrameAdvancing(false); | ||||
|  | ||||
|     emit EmulationStopping(); | ||||
|  | ||||
|     // Wait for emulation thread to complete and delete it | ||||
| @@ -823,6 +848,9 @@ void GMainWindow::ShutdownGame() { | ||||
|     ui.action_Stop->setEnabled(false); | ||||
|     ui.action_Restart->setEnabled(false); | ||||
|     ui.action_Report_Compatibility->setEnabled(false); | ||||
|     ui.action_Enable_Frame_Advancing->setEnabled(false); | ||||
|     ui.action_Enable_Frame_Advancing->setChecked(false); | ||||
|     ui.action_Advance_Frame->setEnabled(false); | ||||
|     render_window->hide(); | ||||
|     if (game_list->isEmpty()) | ||||
|         game_list_placeholder->show(); | ||||
| @@ -1110,6 +1138,7 @@ void GMainWindow::OnStartGame() { | ||||
|     ui.action_Stop->setEnabled(true); | ||||
|     ui.action_Restart->setEnabled(true); | ||||
|     ui.action_Report_Compatibility->setEnabled(true); | ||||
|     ui.action_Enable_Frame_Advancing->setEnabled(true); | ||||
|  | ||||
|     discord_rpc->Update(); | ||||
| } | ||||
|   | ||||
| @@ -114,6 +114,9 @@ | ||||
|     <addaction name="action_Record_Movie"/> | ||||
|     <addaction name="action_Play_Movie"/> | ||||
|     <addaction name="action_Stop_Recording_Playback"/> | ||||
|     <addaction name="separator"/> | ||||
|     <addaction name="action_Enable_Frame_Advancing"/> | ||||
|     <addaction name="action_Advance_Frame"/> | ||||
|    </widget> | ||||
|    <widget class="QMenu" name="menu_Multiplayer"> | ||||
|     <property name="enabled"> | ||||
| @@ -276,6 +279,25 @@ | ||||
|     <string>Stop Recording / Playback</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="action_Enable_Frame_Advancing"> | ||||
|    <property name="checkable"> | ||||
|     <bool>true</bool> | ||||
|    </property> | ||||
|    <property name="enabled"> | ||||
|     <bool>false</bool> | ||||
|    </property> | ||||
|    <property name="text"> | ||||
|     <string>Enable Frame Advancing</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="action_Advance_Frame"> | ||||
|    <property name="enabled"> | ||||
|     <bool>false</bool> | ||||
|    </property> | ||||
|    <property name="text"> | ||||
|     <string>Advance Frame</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="action_View_Lobby"> | ||||
|    <property name="enabled"> | ||||
|     <bool>true</bool> | ||||
|   | ||||
| @@ -74,6 +74,13 @@ double PerfStats::GetLastFrameTimeScale() { | ||||
| } | ||||
|  | ||||
| void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) { | ||||
|     if (frame_advancing_enabled) { | ||||
|         // Frame advancing is enabled: wait on event instead of doing framelimiting | ||||
|         frame_advance_event.Wait(); | ||||
|         frame_advance_event.Reset(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!Settings::values.use_frame_limit) { | ||||
|         return; | ||||
|     } | ||||
| @@ -104,4 +111,20 @@ void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) { | ||||
|     previous_walltime = now; | ||||
| } | ||||
|  | ||||
| void FrameLimiter::SetFrameAdvancing(bool value) { | ||||
|     const bool was_enabled = frame_advancing_enabled.exchange(value); | ||||
|     if (was_enabled && !value) { | ||||
|         // Set the event to let emulation continue | ||||
|         frame_advance_event.Set(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void FrameLimiter::AdvanceFrame() { | ||||
|     if (!frame_advancing_enabled) { | ||||
|         // Start frame advancing | ||||
|         frame_advancing_enabled = true; | ||||
|     } | ||||
|     frame_advance_event.Set(); | ||||
| } | ||||
|  | ||||
| } // namespace Core | ||||
|   | ||||
| @@ -4,9 +4,11 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <mutex> | ||||
| #include "common/common_types.h" | ||||
| #include "common/thread.h" | ||||
|  | ||||
| namespace Core { | ||||
|  | ||||
| @@ -70,6 +72,14 @@ public: | ||||
|  | ||||
|     void DoFrameLimiting(std::chrono::microseconds current_system_time_us); | ||||
|  | ||||
|     /** | ||||
|      * Sets whether frame advancing is enabled or not. | ||||
|      * Note: The frontend must cancel frame advancing before shutting down in order | ||||
|      *       to resume the emu_thread. | ||||
|      */ | ||||
|     void SetFrameAdvancing(bool value); | ||||
|     void AdvanceFrame(); | ||||
|  | ||||
| private: | ||||
|     /// Emulated system time (in microseconds) at the last limiter invocation | ||||
|     std::chrono::microseconds previous_system_time_us{0}; | ||||
| @@ -78,6 +88,12 @@ private: | ||||
|  | ||||
|     /// Accumulated difference between walltime and emulated time | ||||
|     std::chrono::microseconds frame_limiting_delta_err{0}; | ||||
|  | ||||
|     /// Whether to use frame advancing (i.e. frame by frame) | ||||
|     std::atomic_bool frame_advancing_enabled; | ||||
|  | ||||
|     /// Event to advance the frame when frame advancing is enabled | ||||
|     Common::Event frame_advance_event; | ||||
| }; | ||||
|  | ||||
| } // namespace Core | ||||
|   | ||||
		Reference in New Issue
	
	Block a user