summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/citra_qt/main.cpp27
-rw-r--r--src/citra_qt/main.h3
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp9
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/hle/service/gsp_gpu.cpp3
-rw-r--r--src/core/hw/gpu.cpp4
-rw-r--r--src/core/hw/gpu.h2
-rw-r--r--src/core/perf_stats.cpp53
-rw-r--r--src/core/perf_stats.h43
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp9
11 files changed, 159 insertions, 3 deletions
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 43530b275..41356a6ca 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -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;
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 3cbf4ea99..ec841eaa5 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -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;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 5332e35a3..1adc78d8d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -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
)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index c9c9b7615..ca2c28ce4 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -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;
}
diff --git a/src/core/core.h b/src/core/core.h
index 17572a74f..3efc20c3d 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -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.
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 1457518d4..67bab38da 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -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;
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index fa8c13d36..7cf081aad 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -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;
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index d53381216..bdd997b2a 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -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])).
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
new file mode 100644
index 000000000..6d9e603e4
--- /dev/null
+++ b/src/core/perf_stats.cpp
@@ -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
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
new file mode 100644
index 000000000..566a1419a
--- /dev/null
+++ b/src/core/perf_stats.h
@@ -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
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 2aa90e5c1..0b90dcb3d 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -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();