mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #4282 from zhaowenlan1779/frame-advance
core, citra_qt: add frame advancing to framelimiter
This commit is contained in:
		
						commit
						0df32275a7
					
				
					 4 changed files with 90 additions and 0 deletions
				
			
		|  | @ -352,6 +352,10 @@ void GMainWindow::InitializeHotkeys() { | ||||||
|                                    Qt::ApplicationShortcut); |                                    Qt::ApplicationShortcut); | ||||||
|     hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"), |     hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"), | ||||||
|                                    Qt::ApplicationShortcut); |                                    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(); |     hotkey_registry.LoadHotkeys(); | ||||||
| 
 | 
 | ||||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, |     connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, | ||||||
|  | @ -409,6 +413,10 @@ void GMainWindow::InitializeHotkeys() { | ||||||
|                     UpdateStatusBar(); |                     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() { | void GMainWindow::ShowUpdaterWidgets() { | ||||||
|  | @ -540,6 +548,20 @@ void GMainWindow::ConnectMenuEvents() { | ||||||
|     connect(ui.action_Play_Movie, &QAction::triggered, this, &GMainWindow::OnPlayMovie); |     connect(ui.action_Play_Movie, &QAction::triggered, this, &GMainWindow::OnPlayMovie); | ||||||
|     connect(ui.action_Stop_Recording_Playback, &QAction::triggered, this, |     connect(ui.action_Stop_Recording_Playback, &QAction::triggered, this, | ||||||
|             &GMainWindow::OnStopRecordingPlayback); |             &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
 |     // Help
 | ||||||
|     connect(ui.action_FAQ, &QAction::triggered, |     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
 |     // TODO(bunnei): This function is not thread safe, but it's being used as if it were
 | ||||||
|     Pica::g_debug_context->ClearBreakpoints(); |     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(); |     emit EmulationStopping(); | ||||||
| 
 | 
 | ||||||
|     // Wait for emulation thread to complete and delete it
 |     // Wait for emulation thread to complete and delete it
 | ||||||
|  | @ -823,6 +848,9 @@ void GMainWindow::ShutdownGame() { | ||||||
|     ui.action_Stop->setEnabled(false); |     ui.action_Stop->setEnabled(false); | ||||||
|     ui.action_Restart->setEnabled(false); |     ui.action_Restart->setEnabled(false); | ||||||
|     ui.action_Report_Compatibility->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(); |     render_window->hide(); | ||||||
|     if (game_list->isEmpty()) |     if (game_list->isEmpty()) | ||||||
|         game_list_placeholder->show(); |         game_list_placeholder->show(); | ||||||
|  | @ -1110,6 +1138,7 @@ void GMainWindow::OnStartGame() { | ||||||
|     ui.action_Stop->setEnabled(true); |     ui.action_Stop->setEnabled(true); | ||||||
|     ui.action_Restart->setEnabled(true); |     ui.action_Restart->setEnabled(true); | ||||||
|     ui.action_Report_Compatibility->setEnabled(true); |     ui.action_Report_Compatibility->setEnabled(true); | ||||||
|  |     ui.action_Enable_Frame_Advancing->setEnabled(true); | ||||||
| 
 | 
 | ||||||
|     discord_rpc->Update(); |     discord_rpc->Update(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -114,6 +114,9 @@ | ||||||
|     <addaction name="action_Record_Movie"/> |     <addaction name="action_Record_Movie"/> | ||||||
|     <addaction name="action_Play_Movie"/> |     <addaction name="action_Play_Movie"/> | ||||||
|     <addaction name="action_Stop_Recording_Playback"/> |     <addaction name="action_Stop_Recording_Playback"/> | ||||||
|  |     <addaction name="separator"/> | ||||||
|  |     <addaction name="action_Enable_Frame_Advancing"/> | ||||||
|  |     <addaction name="action_Advance_Frame"/> | ||||||
|    </widget> |    </widget> | ||||||
|    <widget class="QMenu" name="menu_Multiplayer"> |    <widget class="QMenu" name="menu_Multiplayer"> | ||||||
|     <property name="enabled"> |     <property name="enabled"> | ||||||
|  | @ -276,6 +279,25 @@ | ||||||
|     <string>Stop Recording / Playback</string> |     <string>Stop Recording / Playback</string> | ||||||
|    </property> |    </property> | ||||||
|   </action> |   </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"> |   <action name="action_View_Lobby"> | ||||||
|    <property name="enabled"> |    <property name="enabled"> | ||||||
|     <bool>true</bool> |     <bool>true</bool> | ||||||
|  |  | ||||||
|  | @ -74,6 +74,13 @@ double PerfStats::GetLastFrameTimeScale() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) { | 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) { |     if (!Settings::values.use_frame_limit) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -104,4 +111,20 @@ void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) { | ||||||
|     previous_walltime = now; |     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
 | } // namespace Core
 | ||||||
|  |  | ||||||
|  | @ -4,9 +4,11 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <atomic> | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <mutex> | #include <mutex> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "common/thread.h" | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
| 
 | 
 | ||||||
|  | @ -70,6 +72,14 @@ public: | ||||||
| 
 | 
 | ||||||
|     void DoFrameLimiting(std::chrono::microseconds current_system_time_us); |     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: | private: | ||||||
|     /// Emulated system time (in microseconds) at the last limiter invocation
 |     /// Emulated system time (in microseconds) at the last limiter invocation
 | ||||||
|     std::chrono::microseconds previous_system_time_us{0}; |     std::chrono::microseconds previous_system_time_us{0}; | ||||||
|  | @ -78,6 +88,12 @@ private: | ||||||
| 
 | 
 | ||||||
|     /// Accumulated difference between walltime and emulated time
 |     /// Accumulated difference between walltime and emulated time
 | ||||||
|     std::chrono::microseconds frame_limiting_delta_err{0}; |     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
 | } // namespace Core
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue