mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +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); | ||||
|     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
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue