From edb2c90b38f6b32cf6f687ed0d00b272fc5a5793 Mon Sep 17 00:00:00 2001 From: Sam Belliveau Date: Wed, 26 Oct 2022 15:17:15 -0400 Subject: [PATCH] Improve FPS/VPS Counting and Revamp Appearance --- .../settings/model/BooleanSetting.java | 3 + .../ui/SettingsFragmentPresenter.java | 7 +++ .../app/src/main/res/values/strings.xml | 9 ++- Source/Core/Core/Config/GraphicsSettings.cpp | 4 ++ Source/Core/Core/Config/GraphicsSettings.h | 4 ++ .../Config/Graphics/AdvancedWidget.cpp | 55 ++++++++++++++++ .../Config/Graphics/AdvancedWidget.h | 6 ++ .../Config/Graphics/GeneralWidget.cpp | 26 ++------ .../DolphinQt/Config/Graphics/GeneralWidget.h | 2 - Source/Core/VideoCommon/FPSCounter.cpp | 63 ++++++++++++------- Source/Core/VideoCommon/FPSCounter.h | 29 +++++---- Source/Core/VideoCommon/RenderBase.cpp | 49 +++++++++++---- Source/Core/VideoCommon/RenderBase.h | 3 +- Source/Core/VideoCommon/VideoConfig.cpp | 4 ++ Source/Core/VideoCommon/VideoConfig.h | 4 ++ 15 files changed, 196 insertions(+), 72 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java index 21812df053..9c6e2ce476 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java @@ -173,6 +173,9 @@ public enum BooleanSetting implements AbstractBooleanSetting GFX_WIDESCREEN_HACK(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "wideScreenHack", false), GFX_CROP(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "Crop", false), GFX_SHOW_FPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowFPS", false), + GFX_SHOW_VPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowVPS", false), + GFX_SHOW_SPEED(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowSpeed", false), + GFX_SHOW_SPEED_COLORS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowSpeedColors", true), GFX_OVERLAY_STATS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "OverlayStats", false), GFX_DUMP_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpTextures", false), GFX_DUMP_MIP_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpMipTextures", false), diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java index cb4fcc38fb..1f073ace20 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java @@ -690,6 +690,13 @@ public final class SettingsFragmentPresenter R.string.video_backend, 0, R.array.videoBackendEntries, R.array.videoBackendValues)); sl.add(new CheckBoxSetting(mContext, BooleanSetting.GFX_SHOW_FPS, R.string.show_fps, R.string.show_fps_description)); + sl.add(new CheckBoxSetting(mContext, BooleanSetting.GFX_SHOW_VPS, R.string.show_vps, + R.string.show_vps_description)); + sl.add(new CheckBoxSetting(mContext, BooleanSetting.GFX_SHOW_SPEED, R.string.show_speed, + R.string.show_speed_description)); + sl.add(new CheckBoxSetting(mContext, BooleanSetting.GFX_SHOW_SPEED_COLORS, + R.string.show_speed_colors, + R.string.show_speed_colors_description)); sl.add(new SingleChoiceSettingDynamicDescriptions(mContext, IntSetting.GFX_SHADER_COMPILATION_MODE, R.string.shader_compilation_mode, 0, R.array.shaderCompilationModeEntries, R.array.shaderCompilationModeValues, diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index bef6431747..f35b5adb60 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -246,8 +246,13 @@ Video Backend Select the API used for graphics rendering. Show FPS - Show the number of frames rendered per second as a measure of emulation speed. - + Shows the number of distinct frames rendered per second as a measure of visual smoothness. + Show VPS + Show the number of frames rendered per second as a measure of emulation speed. + Show % Speed + Shows the % speed of emulation compared to full speed. + Show Speed Color + Changes the color of the FPS counter depending on emulation speed. Enhancements Internal Resolution Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain games. diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index 5a9f7b0954..3d99d06be4 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -27,6 +27,10 @@ const Info GFX_CROP{{System::GFX, "Settings", "Crop"}, false}; const Info GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES{ {System::GFX, "Settings", "SafeTextureCacheColorSamples"}, 128}; const Info GFX_SHOW_FPS{{System::GFX, "Settings", "ShowFPS"}, false}; +const Info GFX_SHOW_VPS{{System::GFX, "Settings", "ShowVPS"}, false}; +const Info GFX_SHOW_SPEED{{System::GFX, "Settings", "ShowSpeed"}, false}; +const Info GFX_SHOW_SPEED_COLORS{{System::GFX, "Settings", "ShowSpeedColors"}, true}; +const Info GFX_PERF_SAMP_WINDOW{{System::GFX, "Settings", "PerfSampWindowMS"}, 1000}; const Info GFX_SHOW_NETPLAY_PING{{System::GFX, "Settings", "ShowNetPlayPing"}, false}; const Info GFX_SHOW_NETPLAY_MESSAGES{{System::GFX, "Settings", "ShowNetPlayMessages"}, false}; const Info GFX_LOG_RENDER_TIME_TO_FILE{{System::GFX, "Settings", "LogRenderTimeToFile"}, diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index 5e3dbb46ae..cd75b068a4 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -29,6 +29,10 @@ extern const Info GFX_SUGGESTED_ASPECT_RATIO; extern const Info GFX_CROP; extern const Info GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES; extern const Info GFX_SHOW_FPS; +extern const Info GFX_SHOW_VPS; +extern const Info GFX_SHOW_SPEED; +extern const Info GFX_SHOW_SPEED_COLORS; +extern const Info GFX_PERF_SAMP_WINDOW; extern const Info GFX_SHOW_NETPLAY_PING; extern const Info GFX_SHOW_NETPLAY_MESSAGES; extern const Info GFX_LOG_RENDER_TIME_TO_FILE; diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp index 4a25976a1c..bd51c9e372 100644 --- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp @@ -45,6 +45,27 @@ void AdvancedWidget::CreateWidgets() { auto* main_layout = new QVBoxLayout; + // Performance + auto* performance_box = new QGroupBox(tr("Performance Statistics")); + auto* performance_layout = new QGridLayout(); + performance_box->setLayout(performance_layout); + + m_show_fps = new GraphicsBool(tr("Show FPS"), Config::GFX_SHOW_FPS); + m_show_vps = new GraphicsBool(tr("Show VPS"), Config::GFX_SHOW_VPS); + m_show_speed = new GraphicsBool(tr("Show % Speed"), Config::GFX_SHOW_SPEED); + m_show_speed_colors = new GraphicsBool(tr("Show Speed Colors"), Config::GFX_SHOW_SPEED_COLORS); + m_perf_samp_window = new GraphicsInteger(0, 10000, Config::GFX_PERF_SAMP_WINDOW, 100); + m_log_render_time = + new GraphicsBool(tr("Log Render Time to File"), Config::GFX_LOG_RENDER_TIME_TO_FILE); + + performance_layout->addWidget(m_show_fps, 0, 0); + performance_layout->addWidget(m_show_vps, 1, 0); + performance_layout->addWidget(m_show_speed, 0, 1); + performance_layout->addWidget(new QLabel(tr("Performance Sample Window (ms):")), 2, 0); + performance_layout->addWidget(m_perf_samp_window, 2, 1); + performance_layout->addWidget(m_log_render_time, 3, 0); + performance_layout->addWidget(m_show_speed_colors, 3, 1); + // Debugging auto* debugging_box = new QGroupBox(tr("Debugging")); auto* debugging_layout = new QGridLayout(); @@ -155,6 +176,7 @@ void AdvancedWidget::CreateWidgets() experimental_layout->addWidget(m_defer_efb_access_invalidation, 0, 0); experimental_layout->addWidget(m_manual_texture_sampling, 0, 1); + main_layout->addWidget(performance_box); main_layout->addWidget(debugging_box); main_layout->addWidget(utility_box); main_layout->addWidget(texture_dump_box); @@ -214,6 +236,32 @@ void AdvancedWidget::OnEmulationStateChanged(bool running) void AdvancedWidget::AddDescriptions() { + static const char TR_SHOW_FPS_DESCRIPTION[] = + QT_TR_NOOP("Shows the number of distinct frames rendered per second as a measure of " + "visual smoothness.

If unsure, leave this " + "unchecked."); + static const char TR_SHOW_VPS_DESCRIPTION[] = + QT_TR_NOOP("Shows the number of frames rendered per second as a measure of " + "emulation speed.

If unsure, leave this " + "unchecked."); + static const char TR_SHOW_SPEED_DESCRIPTION[] = + QT_TR_NOOP("Shows the % speed of emulation compared to full speed." + "

If unsure, leave this " + "unchecked."); + static const char TR_SHOW_SPEED_COLORS_DESCRIPTION[] = + QT_TR_NOOP("Changes the color of the FPS counter depending on emulation speed." + "

If unsure, leave this " + "checked."); + static const char TR_PERF_SAMP_WINDOW_DESCRIPTION[] = + QT_TR_NOOP("The amount of time the FPS and VPS counters will sample over." + "

The higher the value, the more stable the FPS/VPS counter will be, " + "but the slower it will be slower to update." + "

If unsure, leave this " + "at 1000ms."); + static const char TR_LOG_RENDERTIME_DESCRIPTION[] = QT_TR_NOOP( + "Logs the render time of every frame to User/Logs/render_time.txt.

Use this " + "feature to measure Dolphin's performance.

If " + "unsure, leave this unchecked."); static const char TR_WIREFRAME_DESCRIPTION[] = QT_TR_NOOP("Renders the scene as a wireframe.

If unsure, leave " "this unchecked."); @@ -331,10 +379,17 @@ void AdvancedWidget::AddDescriptions() static const char IF_UNSURE_UNCHECKED[] = QT_TR_NOOP("If unsure, leave this unchecked."); + m_show_fps->SetDescription(tr(TR_SHOW_FPS_DESCRIPTION)); + m_show_vps->SetDescription(tr(TR_SHOW_VPS_DESCRIPTION)); + m_show_speed->SetDescription(tr(TR_SHOW_SPEED_DESCRIPTION)); + m_log_render_time->SetDescription(tr(TR_LOG_RENDERTIME_DESCRIPTION)); + m_show_speed_colors->SetDescription(tr(TR_SHOW_SPEED_COLORS_DESCRIPTION)); + m_enable_wireframe->SetDescription(tr(TR_WIREFRAME_DESCRIPTION)); m_show_statistics->SetDescription(tr(TR_SHOW_STATS_DESCRIPTION)); m_enable_format_overlay->SetDescription(tr(TR_TEXTURE_FORMAT_DESCRIPTION)); m_enable_api_validation->SetDescription(tr(TR_VALIDATION_LAYER_DESCRIPTION)); + m_perf_samp_window->SetDescription(tr(TR_PERF_SAMP_WINDOW_DESCRIPTION)); m_dump_textures->SetDescription(tr(TR_DUMP_TEXTURE_DESCRIPTION)); m_dump_mip_textures->SetDescription(tr(TR_DUMP_MIP_TEXTURE_DESCRIPTION)); m_dump_base_textures->SetDescription(tr(TR_DUMP_BASE_TEXTURE_DESCRIPTION)); diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h index 8188fcb010..58b7107cbb 100644 --- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h @@ -35,6 +35,12 @@ private: GraphicsBool* m_show_statistics; GraphicsBool* m_enable_format_overlay; GraphicsBool* m_enable_api_validation; + GraphicsBool* m_show_fps; + GraphicsBool* m_show_vps; + GraphicsBool* m_show_speed; + GraphicsBool* m_show_speed_colors; + GraphicsInteger* m_perf_samp_window; + GraphicsBool* m_log_render_time; // Utility GraphicsBool* m_prefetch_custom_textures; diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp index 733da068c9..27a2c16e56 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp @@ -87,10 +87,7 @@ void GeneralWidget::CreateWidgets() auto* m_options_box = new QGroupBox(tr("Other")); auto* m_options_layout = new QGridLayout(); - m_show_fps = new GraphicsBool(tr("Show FPS"), Config::GFX_SHOW_FPS); m_show_ping = new GraphicsBool(tr("Show NetPlay Ping"), Config::GFX_SHOW_NETPLAY_PING); - m_log_render_time = - new GraphicsBool(tr("Log Render Time to File"), Config::GFX_LOG_RENDER_TIME_TO_FILE); m_autoadjust_window_size = new GraphicsBool(tr("Auto-Adjust Window Size"), Config::MAIN_RENDER_WINDOW_AUTOSIZE); m_show_messages = @@ -99,14 +96,11 @@ void GeneralWidget::CreateWidgets() m_options_box->setLayout(m_options_layout); - m_options_layout->addWidget(m_show_fps, 0, 0); - m_options_layout->addWidget(m_log_render_time, 0, 1); + m_options_layout->addWidget(m_render_main_window, 0, 0); + m_options_layout->addWidget(m_autoadjust_window_size, 1, 0); - m_options_layout->addWidget(m_render_main_window, 1, 0); - m_options_layout->addWidget(m_autoadjust_window_size, 1, 1); - - m_options_layout->addWidget(m_show_messages, 2, 0); - m_options_layout->addWidget(m_show_ping, 2, 1); + m_options_layout->addWidget(m_show_messages, 0, 1); + m_options_layout->addWidget(m_show_ping, 1, 1); // Other auto* shader_compilation_box = new QGroupBox(tr("Shader Compilation")); @@ -226,17 +220,9 @@ void GeneralWidget::AddDescriptions() "if emulation speed is below 100%.

If unsure, leave " "this " "unchecked."); - static const char TR_SHOW_FPS_DESCRIPTION[] = - QT_TR_NOOP("Shows the number of frames rendered per second as a measure of " - "emulation speed.

If unsure, leave this " - "unchecked."); static const char TR_SHOW_NETPLAY_PING_DESCRIPTION[] = QT_TR_NOOP( "Shows the player's maximum ping while playing on " "NetPlay.

If unsure, leave this unchecked."); - static const char TR_LOG_RENDERTIME_DESCRIPTION[] = QT_TR_NOOP( - "Logs the render time of every frame to User/Logs/render_time.txt.

Use this " - "feature to measure Dolphin's performance.

If " - "unsure, leave this unchecked."); static const char TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION[] = QT_TR_NOOP("Shows chat messages, buffer changes, and desync alerts " "while playing NetPlay.

If unsure, leave " @@ -281,12 +267,8 @@ void GeneralWidget::AddDescriptions() m_enable_fullscreen->SetDescription(tr(TR_FULLSCREEN_DESCRIPTION)); - m_show_fps->SetDescription(tr(TR_SHOW_FPS_DESCRIPTION)); - m_show_ping->SetDescription(tr(TR_SHOW_NETPLAY_PING_DESCRIPTION)); - m_log_render_time->SetDescription(tr(TR_LOG_RENDERTIME_DESCRIPTION)); - m_autoadjust_window_size->SetDescription(tr(TR_AUTOSIZE_DESCRIPTION)); m_show_messages->SetDescription(tr(TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION)); diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h index f561c1728d..7b8fa2622e 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h @@ -49,9 +49,7 @@ private: GraphicsBool* m_enable_fullscreen; // Options - GraphicsBool* m_show_fps; GraphicsBool* m_show_ping; - GraphicsBool* m_log_render_time; GraphicsBool* m_autoadjust_window_size; GraphicsBool* m_show_messages; GraphicsBool* m_render_main_window; diff --git a/Source/Core/VideoCommon/FPSCounter.cpp b/Source/Core/VideoCommon/FPSCounter.cpp index e38305eb7f..e5f396a094 100644 --- a/Source/Core/VideoCommon/FPSCounter.cpp +++ b/Source/Core/VideoCommon/FPSCounter.cpp @@ -3,7 +3,7 @@ #include "VideoCommon/FPSCounter.h" -#include +#include #include #include "Common/CommonTypes.h" @@ -12,11 +12,15 @@ #include "Core/Core.h" #include "VideoCommon/VideoConfig.h" -static constexpr u64 FPS_REFRESH_INTERVAL_US = 250000; +static constexpr double US_TO_MS = 1000.0; +static constexpr double US_TO_S = 1000000.0; -FPSCounter::FPSCounter() +static constexpr double FPS_SAMPLE_RC_RATIO = 0.25; + +FPSCounter::FPSCounter(const char* log_name) { m_last_time = Common::Timer::NowUs(); + m_log_name = log_name; m_on_state_changed_handle = Core::AddOnStateChangedCallback([this](Core::State state) { if (state == Core::State::Paused) @@ -31,47 +35,64 @@ FPSCounter::~FPSCounter() Core::RemoveOnStateChangedCallback(&m_on_state_changed_handle); } -void FPSCounter::LogRenderTimeToFile(u64 val) +void FPSCounter::LogRenderTimeToFile(s64 val) { if (!m_bench_file.is_open()) { - File::OpenFStream(m_bench_file, File::GetUserPath(D_LOGS_IDX) + "render_time.txt", - std::ios_base::out); + File::OpenFStream(m_bench_file, File::GetUserPath(D_LOGS_IDX) + m_log_name, std::ios_base::out); } - m_bench_file << std::fixed << std::setprecision(8) << (val / 1000.0) << std::endl; + m_bench_file << std::fixed << std::setprecision(8) << (val / US_TO_MS) << std::endl; } void FPSCounter::Update() { - const u64 time = Common::Timer::NowUs(); - const u64 diff = time - m_last_time; - m_time_diff_secs = static_cast(diff / 1000000.0); - if (g_ActiveConfig.bLogRenderTimeToFile) - LogRenderTimeToFile(diff); + if (m_paused) + return; - m_frame_counter++; - m_time_since_update += diff; + const s64 time = Common::Timer::NowUs(); + const s64 diff = std::max(0, time - m_last_time); + const s64 window = std::max(1, g_ActiveConfig.iPerfSampleUSec); + + m_raw_dt = diff / US_TO_S; m_last_time = time; - if (m_time_since_update >= FPS_REFRESH_INTERVAL_US) + m_dt_total += diff; + m_dt_queue.push_back(diff); + + while (window <= m_dt_total - m_dt_queue.front()) { - m_fps = m_frame_counter / (m_time_since_update / 1000000.0); - m_frame_counter = 0; - m_time_since_update = 0; + m_dt_total -= m_dt_queue.front(); + m_dt_queue.pop_front(); } + + // This frame count takes into account frames that are partially in the sample window + const double fps = (m_dt_queue.size() * US_TO_S) / m_dt_total; + const double rc = FPS_SAMPLE_RC_RATIO * std::min(window, m_dt_total) / US_TO_S; + const double a = std::max(0.0, 1.0 - std::exp(-m_raw_dt / rc)); + + // Sometimes euler averages can break when the average is inf/nan + // This small check makes sure that if it does break, it gets fixed + if (std::isfinite(m_avg_fps)) + m_avg_fps += a * (fps - m_avg_fps); + else + m_avg_fps = fps; + + if (g_ActiveConfig.bLogRenderTimeToFile) + LogRenderTimeToFile(diff); } void FPSCounter::SetPaused(bool paused) { - if (paused) + m_paused = paused; + if (m_paused) { m_last_time_pause = Common::Timer::NowUs(); } else { - const u64 time = Common::Timer::NowUs(); - const u64 diff = time - m_last_time_pause; + const s64 time = Common::Timer::NowUs(); + const s64 diff = time - m_last_time_pause; m_last_time += diff; } } diff --git a/Source/Core/VideoCommon/FPSCounter.h b/Source/Core/VideoCommon/FPSCounter.h index 8cd559a1de..852c39fd3b 100644 --- a/Source/Core/VideoCommon/FPSCounter.h +++ b/Source/Core/VideoCommon/FPSCounter.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include "Common/CommonTypes.h" @@ -10,7 +11,7 @@ class FPSCounter { public: - FPSCounter(); + explicit FPSCounter(const char* log_name = "log.txt"); ~FPSCounter(); FPSCounter(const FPSCounter&) = delete; FPSCounter& operator=(const FPSCounter&) = delete; @@ -20,20 +21,26 @@ public: // Called when a frame is rendered (updated every second). void Update(); - float GetFPS() const { return m_fps; } - double GetDeltaTime() const { return m_time_diff_secs; } + double GetFPS() const { return m_avg_fps; } + + double GetDeltaTime() const { return m_raw_dt; } private: + void LogRenderTimeToFile(s64 val); void SetPaused(bool paused); - u64 m_last_time = 0; - u64 m_time_since_update = 0; - u64 m_last_time_pause = 0; - u32 m_frame_counter = 0; - int m_on_state_changed_handle = -1; - float m_fps = 0.f; + const char* m_log_name; std::ofstream m_bench_file; - double m_time_diff_secs = 0.0; - void LogRenderTimeToFile(u64 val); + bool m_paused = false; + s64 m_last_time = 0; + + double m_avg_fps = 0.0; + double m_raw_dt = 0.0; + + s64 m_dt_total = 0; + std::deque m_dt_queue; + + int m_on_state_changed_handle = -1; + s64 m_last_time_pause = 0; }; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index c2fdcbaa3d..792160f195 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -590,21 +590,42 @@ void Renderer::CheckForConfigChanges() // Create On-Screen-Messages void Renderer::DrawDebugText() { - if (g_ActiveConfig.bShowFPS) + if (g_ActiveConfig.bShowFPS || g_ActiveConfig.bShowVPS || g_ActiveConfig.bShowSpeed) { // Position in the top-right corner of the screen. ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (10.0f * m_backbuffer_scale), - 10.0f * m_backbuffer_scale), + 10.f * m_backbuffer_scale), ImGuiCond_Always, ImVec2(1.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(100.0f * m_backbuffer_scale, 30.0f * m_backbuffer_scale)); - if (ImGui::Begin("FPS", nullptr, + int count = g_ActiveConfig.bShowFPS + g_ActiveConfig.bShowVPS + g_ActiveConfig.bShowSpeed; + ImGui::SetNextWindowSize( + ImVec2(94.f * m_backbuffer_scale, (12.f + 17.f * count) * m_backbuffer_scale)); + + if (ImGui::Begin("Performance", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) { - ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "FPS: %.2f", m_fps_counter.GetFPS()); + const double fps = m_fps_counter.GetFPS(); + const double vps = m_vps_counter.GetFPS(); + const double speed = 100.0 * vps / VideoInterface::GetTargetRefreshRate(); + + // Change Color based on % Speed + float r = 0.0f, g = 1.0f, b = 1.0f; + if (g_ActiveConfig.bShowSpeedColors) + { + r = 1.0 - (speed - 80.0) / 20.0; + g = speed / 80.0; + b = (speed - 90.0) / 10.0; + } + + if (g_ActiveConfig.bShowFPS) + ImGui::TextColored(ImVec4(r, g, b, 1.0f), "FPS:%7.2lf", fps); + if (g_ActiveConfig.bShowVPS) + ImGui::TextColored(ImVec4(r, g, b, 1.0f), "VPS:%7.2lf", vps); + if (g_ActiveConfig.bShowSpeed) + ImGui::TextColored(ImVec4(r, g, b, 1.0f), "Speed:%4.0lf%%", speed); } ImGui::End(); } @@ -616,9 +637,9 @@ void Renderer::DrawDebugText() if (show_movie_window) { // Position under the FPS display. - ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (10.0f * m_backbuffer_scale), - 50.0f * m_backbuffer_scale), - ImGuiCond_FirstUseEver, ImVec2(1.0f, 0.0f)); + ImGui::SetNextWindowPos( + ImVec2(ImGui::GetIO().DisplaySize.x - 10.f * m_backbuffer_scale, 80.f * m_backbuffer_scale), + ImGuiCond_FirstUseEver, ImVec2(1.0f, 0.0f)); ImGui::SetNextWindowSizeConstraints( ImVec2(150.0f * m_backbuffer_scale, 20.0f * m_backbuffer_scale), ImGui::GetIO().DisplaySize); @@ -1363,10 +1384,14 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6 MathUtil::Rectangle xfb_rect; const auto* xfb_entry = g_texture_cache->GetXFBTexture(xfb_addr, fb_width, fb_height, fb_stride, &xfb_rect); - if (xfb_entry && - (!g_ActiveConfig.bSkipPresentingDuplicateXFBs || xfb_entry->id != m_last_xfb_id)) + const bool is_duplicate_frame = xfb_entry->id == m_last_xfb_id; + + m_vps_counter.Update(); + if (!is_duplicate_frame) + m_fps_counter.Update(); + + if (xfb_entry && (!g_ActiveConfig.bSkipPresentingDuplicateXFBs || !is_duplicate_frame)) { - const bool is_duplicate_frame = xfb_entry->id == m_last_xfb_id; m_last_xfb_id = xfb_entry->id; // Since we use the common pipelines here and draw vertices if a batch is currently being @@ -1416,8 +1441,6 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6 if (!is_duplicate_frame) { - m_fps_counter.Update(); - DolphinAnalytics::PerformanceSample perf_sample; perf_sample.speed_ratio = SystemTimers::GetEstimatedEmulationPerformance(); perf_sample.num_prims = g_stats.this_frame.num_prims + g_stats.this_frame.num_dl_prims; diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 0553d59f73..c44e2ebabe 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -338,7 +338,8 @@ protected: MathUtil::Rectangle m_target_rectangle = {}; int m_frame_count = 0; - FPSCounter m_fps_counter; + FPSCounter m_fps_counter = FPSCounter("render_times.txt"); + FPSCounter m_vps_counter = FPSCounter("v_blank_times.txt"); std::unique_ptr m_post_processor; diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 40d5841714..4e66c9d822 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -64,6 +64,10 @@ void VideoConfig::Refresh() bCrop = Config::Get(Config::GFX_CROP); iSafeTextureCache_ColorSamples = Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES); bShowFPS = Config::Get(Config::GFX_SHOW_FPS); + bShowVPS = Config::Get(Config::GFX_SHOW_VPS); + bShowSpeed = Config::Get(Config::GFX_SHOW_SPEED); + bShowSpeedColors = Config::Get(Config::GFX_SHOW_SPEED_COLORS); + iPerfSampleUSec = Config::Get(Config::GFX_PERF_SAMP_WINDOW) * 1000; bShowNetPlayPing = Config::Get(Config::GFX_SHOW_NETPLAY_PING); bShowNetPlayMessages = Config::Get(Config::GFX_SHOW_NETPLAY_MESSAGES); bLogRenderTimeToFile = Config::Get(Config::GFX_LOG_RENDER_TIME_TO_FILE); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 05d86a18f4..2bdf4b2835 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -82,6 +82,10 @@ struct VideoConfig final // Information bool bShowFPS = false; + bool bShowVPS = false; + bool bShowSpeed = false; + bool bShowSpeedColors = false; + int iPerfSampleUSec = 0; bool bShowNetPlayPing = false; bool bShowNetPlayMessages = false; bool bOverlayStats = false;