mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Add performance statistics to status bar
This commit is contained in:
		
							parent
							
								
									21f4f49c7a
								
							
						
					
					
						commit
						c75ae6c585
					
				
					 11 changed files with 159 additions and 3 deletions
				
			
		|  | @ -253,6 +253,8 @@ void GMainWindow::ConnectWidgetEvents() { | |||
|     connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, | ||||
|             SLOT(OnEmulationStarting(EmuThread*))); | ||||
|     connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); | ||||
| 
 | ||||
|     connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::ConnectMenuEvents() { | ||||
|  | @ -401,6 +403,8 @@ void GMainWindow::BootGame(const QString& filename) { | |||
|     if (ui.action_Single_Window_Mode->isChecked()) { | ||||
|         game_list->hide(); | ||||
|     } | ||||
|     status_bar_update_timer.start(1000); | ||||
| 
 | ||||
|     render_window->show(); | ||||
|     render_window->setFocus(); | ||||
| 
 | ||||
|  | @ -435,6 +439,12 @@ void GMainWindow::ShutdownGame() { | |||
|     render_window->hide(); | ||||
|     game_list->show(); | ||||
| 
 | ||||
|     // Disable status bar updates
 | ||||
|     status_bar_update_timer.stop(); | ||||
|     emu_speed_label->setVisible(false); | ||||
|     game_fps_label->setVisible(false); | ||||
|     emu_frametime_label->setVisible(false); | ||||
| 
 | ||||
|     emulation_running = false; | ||||
| } | ||||
| 
 | ||||
|  | @ -614,6 +624,23 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() { | |||
|     graphicsSurfaceViewerWidget->show(); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::UpdateStatusBar() { | ||||
|     if (emu_thread == nullptr) { | ||||
|         status_bar_update_timer.stop(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto results = Core::System::GetInstance().GetAndResetPerfStats(); | ||||
| 
 | ||||
|     emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 2)); | ||||
|     game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 1)); | ||||
|     emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); | ||||
| 
 | ||||
|     emu_speed_label->setVisible(true); | ||||
|     game_fps_label->setVisible(true); | ||||
|     emu_frametime_label->setVisible(true); | ||||
| } | ||||
| 
 | ||||
| bool GMainWindow::ConfirmClose() { | ||||
|     if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) | ||||
|         return true; | ||||
|  |  | |||
|  | @ -127,6 +127,8 @@ private slots: | |||
|     void OnCreateGraphicsSurfaceViewer(); | ||||
| 
 | ||||
| private: | ||||
|     void UpdateStatusBar(); | ||||
| 
 | ||||
|     Ui::MainWindow ui; | ||||
| 
 | ||||
|     GRenderWindow* render_window; | ||||
|  | @ -136,6 +138,7 @@ private: | |||
|     QLabel* emu_speed_label = nullptr; | ||||
|     QLabel* game_fps_label = nullptr; | ||||
|     QLabel* emu_frametime_label = nullptr; | ||||
|     QTimer status_bar_update_timer; | ||||
| 
 | ||||
|     std::unique_ptr<Config> config; | ||||
| 
 | ||||
|  |  | |||
|  | @ -170,6 +170,7 @@ set(SRCS | |||
|             loader/smdh.cpp | ||||
|             tracer/recorder.cpp | ||||
|             memory.cpp | ||||
|             perf_stats.cpp | ||||
|             settings.cpp | ||||
|             ) | ||||
| 
 | ||||
|  | @ -357,6 +358,7 @@ set(HEADERS | |||
|             memory.h | ||||
|             memory_setup.h | ||||
|             mmio.h | ||||
|             perf_stats.h | ||||
|             settings.h | ||||
|             ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -109,6 +109,11 @@ void System::PrepareReschedule() { | |||
|     reschedule_pending = true; | ||||
| } | ||||
| 
 | ||||
| PerfStats::Results System::GetAndResetPerfStats() { | ||||
|     auto perf_stats = this->perf_stats.Lock(); | ||||
|     return perf_stats->GetAndResetStats(CoreTiming::GetGlobalTimeUs()); | ||||
| } | ||||
| 
 | ||||
| void System::Reschedule() { | ||||
|     if (!reschedule_pending) { | ||||
|         return; | ||||
|  | @ -140,6 +145,10 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | |||
| 
 | ||||
|     LOG_DEBUG(Core, "Initialized OK"); | ||||
| 
 | ||||
|     // Reset counters and set time origin to current frame
 | ||||
|     GetAndResetPerfStats(); | ||||
|     perf_stats.Lock()->BeginSystemFrame(); | ||||
| 
 | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,9 +6,10 @@ | |||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "common/synchronized_wrapper.h" | ||||
| #include "core/memory.h" | ||||
| #include "core/perf_stats.h" | ||||
| 
 | ||||
| class EmuWindow; | ||||
| class ARM_Interface; | ||||
|  | @ -83,6 +84,8 @@ public: | |||
|     /// Prepare the core emulation for a reschedule
 | ||||
|     void PrepareReschedule(); | ||||
| 
 | ||||
|     PerfStats::Results GetAndResetPerfStats(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets a reference to the emulated CPU. | ||||
|      * @returns A reference to the emulated CPU. | ||||
|  | @ -91,6 +94,8 @@ public: | |||
|         return *cpu_core; | ||||
|     } | ||||
| 
 | ||||
|     Common::SynchronizedWrapper<PerfStats> perf_stats; | ||||
| 
 | ||||
| private: | ||||
|     /**
 | ||||
|      * Initialize the emulated system. | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| 
 | ||||
| #include "common/bit_field.h" | ||||
| #include "common/microprofile.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/kernel/shared_memory.h" | ||||
| #include "core/hle/result.h" | ||||
|  | @ -280,6 +281,8 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { | |||
| 
 | ||||
|     if (screen_id == 0) { | ||||
|         MicroProfileFlip(); | ||||
|         auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||||
|         perf_stats->EndGameFrame(); | ||||
|     } | ||||
| 
 | ||||
|     return RESULT_SUCCESS; | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ namespace GPU { | |||
| Regs g_regs; | ||||
| 
 | ||||
| /// 268MHz CPU clocks / 60Hz frames per second
 | ||||
| const u64 frame_ticks = BASE_CLOCK_RATE_ARM11 / 60; | ||||
| const u64 frame_ticks = BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE; | ||||
| /// Event id for CoreTiming
 | ||||
| static int vblank_event; | ||||
| /// Total number of frames drawn
 | ||||
|  | @ -41,7 +41,7 @@ static u64 frame_count; | |||
| static u32 time_point; | ||||
| /// Total delay caused by slow frames
 | ||||
| static float time_delay; | ||||
| constexpr float FIXED_FRAME_TIME = 1000.0f / 60; | ||||
| constexpr float FIXED_FRAME_TIME = 1000.0f / SCREEN_REFRESH_RATE; | ||||
| // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher
 | ||||
| // values increases time needed to limit frame rate after spikes
 | ||||
| constexpr float MAX_LAG_TIME = 18; | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ | |||
| 
 | ||||
| namespace GPU { | ||||
| 
 | ||||
| constexpr float SCREEN_REFRESH_RATE = 60; | ||||
| 
 | ||||
| // Returns index corresponding to the Regs member labeled by field_name
 | ||||
| // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
 | ||||
| //       when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])).
 | ||||
|  |  | |||
							
								
								
									
										53
									
								
								src/core/perf_stats.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/core/perf_stats.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| // Copyright 2017 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include "core/hw/gpu.h" | ||||
| #include "core/perf_stats.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| 
 | ||||
| void PerfStats::BeginSystemFrame() { | ||||
|     frame_begin = Clock::now(); | ||||
| } | ||||
| 
 | ||||
| void PerfStats::EndSystemFrame() { | ||||
|     auto frame_end = Clock::now(); | ||||
|     accumulated_frametime += frame_end - frame_begin; | ||||
|     system_frames += 1; | ||||
| } | ||||
| 
 | ||||
| void PerfStats::EndGameFrame() { | ||||
|     game_frames += 1; | ||||
| } | ||||
| 
 | ||||
| PerfStats::Results PerfStats::GetAndResetStats(u64 current_system_time_us) { | ||||
|     using DoubleSecs = std::chrono::duration<double, std::chrono::seconds::period>; | ||||
|     using std::chrono::duration_cast; | ||||
| 
 | ||||
|     auto now = Clock::now(); | ||||
|     // Walltime elapsed since stats were reset
 | ||||
|     auto interval = duration_cast<DoubleSecs>(now - reset_point).count(); | ||||
| 
 | ||||
|     auto system_us_per_second = | ||||
|         static_cast<double>(current_system_time_us - reset_point_system_us) / interval; | ||||
| 
 | ||||
|     Results results{}; | ||||
|     results.system_fps = static_cast<double>(system_frames) / interval; | ||||
|     results.game_fps = static_cast<double>(game_frames) / interval; | ||||
|     results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / | ||||
|                         static_cast<double>(system_frames); | ||||
|     results.emulation_speed = system_us_per_second / 1'000'000.0; | ||||
| 
 | ||||
|     // Reset counters
 | ||||
|     reset_point = now; | ||||
|     reset_point_system_us = current_system_time_us; | ||||
|     accumulated_frametime = Clock::duration::zero(); | ||||
|     system_frames = 0; | ||||
|     game_frames = 0; | ||||
| 
 | ||||
|     return results; | ||||
| } | ||||
| 
 | ||||
| } // namespace Core
 | ||||
							
								
								
									
										43
									
								
								src/core/perf_stats.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/core/perf_stats.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| // Copyright 2017 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| 
 | ||||
| class PerfStats { | ||||
| public: | ||||
|     using Clock = std::chrono::high_resolution_clock; | ||||
| 
 | ||||
|     struct Results { | ||||
|         /// System FPS (LCD VBlanks) in Hz
 | ||||
|         double system_fps; | ||||
|         /// Game FPS (GSP frame submissions) in Hz
 | ||||
|         double game_fps; | ||||
|         /// Walltime per system frame, in seconds, excluding any waits
 | ||||
|         double frametime; | ||||
|         /// Ratio of walltime / emulated time elapsed
 | ||||
|         double emulation_speed; | ||||
|     }; | ||||
| 
 | ||||
|     void BeginSystemFrame(); | ||||
|     void EndSystemFrame(); | ||||
|     void EndGameFrame(); | ||||
| 
 | ||||
|     Results GetAndResetStats(u64 current_system_time_us); | ||||
| 
 | ||||
| private: | ||||
|     Clock::time_point reset_point = Clock::now(); | ||||
| 
 | ||||
|     Clock::time_point frame_begin; | ||||
|     Clock::duration accumulated_frametime = Clock::duration::zero(); | ||||
|     u64 reset_point_system_us = 0; | ||||
|     u32 system_frames = 0; | ||||
|     u32 game_frames = 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Core
 | ||||
|  | @ -12,6 +12,7 @@ | |||
| #include "common/logging/log.h" | ||||
| #include "common/profiler_reporting.h" | ||||
| #include "common/synchronized_wrapper.h" | ||||
| #include "core/core.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "core/hw/gpu.h" | ||||
| #include "core/hw/hw.h" | ||||
|  | @ -151,6 +152,10 @@ void RendererOpenGL::SwapBuffers() { | |||
|         auto aggregator = Common::Profiling::GetTimingResultsAggregator(); | ||||
|         aggregator->AddFrame(profiler.GetPreviousFrameResults()); | ||||
|     } | ||||
|     { | ||||
|         auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||||
|         perf_stats->EndSystemFrame(); | ||||
|     } | ||||
| 
 | ||||
|     // Swap buffers
 | ||||
|     render_window->PollEvents(); | ||||
|  | @ -159,6 +164,10 @@ void RendererOpenGL::SwapBuffers() { | |||
|     prev_state.Apply(); | ||||
| 
 | ||||
|     profiler.BeginFrame(); | ||||
|     { | ||||
|         auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||||
|         perf_stats->BeginSystemFrame(); | ||||
|     } | ||||
| 
 | ||||
|     RefreshRasterizerSetting(); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue