summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/PerformanceMetrics.cpp
diff options
context:
space:
mode:
authorSam Belliveau <sam.belliveau@gmail.com>2022-12-23 19:52:53 -0500
committerSam Belliveau <sam.belliveau@gmail.com>2022-12-23 19:52:53 -0500
commit673f81c18a7ec5af6d243d5ac4e90b5778c69385 (patch)
treec6dce088a5b6485f855e913ae0b035afd04ad022 /Source/Core/VideoCommon/PerformanceMetrics.cpp
parent2345ba178d91b172319472add4232d2c97bb180c (diff)
New FrameTime/VBlank Analyzer + Graph
Diffstat (limited to 'Source/Core/VideoCommon/PerformanceMetrics.cpp')
-rw-r--r--Source/Core/VideoCommon/PerformanceMetrics.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/Source/Core/VideoCommon/PerformanceMetrics.cpp b/Source/Core/VideoCommon/PerformanceMetrics.cpp
new file mode 100644
index 0000000000..3b9cc81791
--- /dev/null
+++ b/Source/Core/VideoCommon/PerformanceMetrics.cpp
@@ -0,0 +1,221 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "VideoCommon/PerformanceMetrics.h"
+
+#include <imgui.h>
+#include <implot.h>
+
+#include "Core/HW/VideoInterface.h"
+#include "VideoCommon/VideoConfig.h"
+
+PerformanceMetrics g_perf_metrics;
+
+void PerformanceMetrics::Reset()
+{
+ m_fps_counter.Reset();
+ m_vps_counter.Reset();
+ m_speed_counter.Reset();
+}
+
+void PerformanceMetrics::CountFrame()
+{
+ m_fps_counter.Count();
+}
+
+void PerformanceMetrics::CountVBlank()
+{
+ m_vps_counter.Count();
+ m_speed_counter.Count();
+}
+
+double PerformanceMetrics::GetFPS() const
+{
+ return m_fps_counter.GetHzAvg();
+}
+
+double PerformanceMetrics::GetVPS() const
+{
+ return m_vps_counter.GetHzAvg();
+}
+
+double PerformanceMetrics::GetSpeed() const
+{
+ return 100.0 * m_speed_counter.GetHzAvg() / VideoInterface::GetTargetRefreshRate();
+}
+
+double PerformanceMetrics::GetLastSpeedDenominator() const
+{
+ return DT_s(m_speed_counter.GetLastRawDt()).count() * VideoInterface::GetTargetRefreshRate();
+}
+
+void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) const
+{
+ const float bg_alpha = 0.7f;
+ const auto imgui_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
+ ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
+ ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
+ ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing;
+
+ const double fps = GetFPS();
+ const double vps = GetVPS();
+ const double speed = GetSpeed();
+
+ // 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;
+ }
+
+ const float window_padding = 8.f * backbuffer_scale;
+ const float window_width = 93.f * backbuffer_scale;
+ float window_y = window_padding;
+ float window_x = ImGui::GetIO().DisplaySize.x - window_padding;
+
+ const float graph_width = 50.f * backbuffer_scale + 3.f * window_width + 2.f * window_padding;
+ const float graph_height =
+ std::min(200.f * backbuffer_scale, ImGui::GetIO().DisplaySize.y - 85.f * backbuffer_scale);
+
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.f);
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 14.f * backbuffer_scale);
+ if (g_ActiveConfig.bShowGraphs)
+ {
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 4.f * backbuffer_scale));
+
+ // Position in the top-right corner of the screen.
+ ImGui::SetNextWindowPos(ImVec2(window_x, window_y), ImGuiCond_Always, ImVec2(1.0f, 0.0f));
+ ImGui::SetNextWindowSize(ImVec2(graph_width, graph_height));
+ ImGui::SetNextWindowBgAlpha(bg_alpha);
+ window_y += graph_height + window_padding;
+
+ if (ImGui::Begin("PerformanceGraphs", nullptr, imgui_flags))
+ {
+ const static int num_ticks = 17;
+ const static double tick_marks[num_ticks] = {0.0,
+ 1000.0 / 360.0,
+ 1000.0 / 240.0,
+ 1000.0 / 180.0,
+ 1000.0 / 120.0,
+ 1000.0 / 90.00,
+ 1000.0 / 59.94,
+ 1000.0 / 40.00,
+ 1000.0 / 29.97,
+ 1000.0 / 24.00,
+ 1000.0 / 20.00,
+ 1000.0 / 15.00,
+ 1000.0 / 10.00,
+ 1000.0 / 5.000,
+ 1000.0 / 2.000,
+ 1000.0,
+ 2000.0};
+
+ const DT vblank_time = m_vps_counter.GetDtAvg() + m_vps_counter.GetDtStd();
+ const DT frame_time = m_fps_counter.GetDtAvg() + m_fps_counter.GetDtStd();
+ const double target_max_time = DT_ms(vblank_time + frame_time).count();
+ const double a =
+ std::max(0.0, 1.0 - std::exp(-4000.0 * m_vps_counter.GetLastRawDt().count() /
+ DT_ms(m_vps_counter.GetSampleWindow()).count()));
+
+ static double max_time = 0.0;
+ if (std::isfinite(max_time))
+ max_time += a * (target_max_time - max_time);
+ else
+ max_time = target_max_time;
+
+ const double total_frame_time = std::max(DT_ms(m_fps_counter.GetSampleWindow()).count(),
+ DT_ms(m_vps_counter.GetSampleWindow()).count());
+
+ if (ImPlot::BeginPlot("PerformanceGraphs", ImVec2(-1.0, -1.0),
+ ImPlotFlags_NoFrame | ImPlotFlags_NoTitle | ImPlotFlags_NoMenus))
+ {
+ ImPlot::PushStyleColor(ImPlotCol_PlotBg, {0, 0, 0, 0});
+ ImPlot::PushStyleColor(ImPlotCol_LegendBg, {0, 0, 0, 0.2f});
+ ImPlot::PushStyleVar(ImPlotStyleVar_FitPadding, ImVec2(0.f, 0.f));
+ ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 3.f);
+ ImPlot::SetupAxes(nullptr, nullptr,
+ ImPlotAxisFlags_Lock | ImPlotAxisFlags_Invert |
+ ImPlotAxisFlags_NoDecorations | ImPlotAxisFlags_NoHighlight,
+ ImPlotAxisFlags_Lock | ImPlotAxisFlags_Invert | ImPlotAxisFlags_NoLabel |
+ ImPlotAxisFlags_NoHighlight);
+ ImPlot::SetupAxisFormat(ImAxis_Y1, "%.1f");
+ ImPlot::SetupAxisTicks(ImAxis_Y1, tick_marks, num_ticks);
+ ImPlot::SetupAxesLimits(0, total_frame_time, 0, max_time, ImGuiCond_Always);
+ ImPlot::SetupLegend(ImPlotLocation_SouthEast, ImPlotLegendFlags_None);
+ m_vps_counter.ImPlotPlotLines("V-Blank (ms)");
+ m_fps_counter.ImPlotPlotLines("Frame (ms)");
+ ImPlot::EndPlot();
+ ImPlot::PopStyleVar(2);
+ ImPlot::PopStyleColor(2);
+ }
+ ImGui::PopStyleVar();
+ ImGui::End();
+ }
+ }
+
+ if (g_ActiveConfig.bShowFPS || g_ActiveConfig.bShowFTimes)
+ {
+ // Position in the top-right corner of the screen.
+ int count = g_ActiveConfig.bShowFPS + 2 * g_ActiveConfig.bShowFTimes;
+ ImGui::SetNextWindowPos(ImVec2(window_x, window_y), ImGuiCond_Always, ImVec2(1.0f, 0.0f));
+ ImGui::SetNextWindowSize(ImVec2(window_width, (12.f + 17.f * count) * backbuffer_scale));
+ ImGui::SetNextWindowBgAlpha(bg_alpha);
+ window_x -= window_width + window_padding;
+
+ if (ImGui::Begin("FPSStats", nullptr, imgui_flags))
+ {
+ if (g_ActiveConfig.bShowFPS)
+ ImGui::TextColored(ImVec4(r, g, b, 1.0f), "FPS:%7.2lf", fps);
+ if (g_ActiveConfig.bShowFTimes)
+ {
+ ImGui::TextColored(ImVec4(r, g, b, 1.0f), "dt:%6.2lfms",
+ DT_ms(m_fps_counter.GetDtAvg()).count());
+ ImGui::TextColored(ImVec4(r, g, b, 1.0f), " ±:%6.2lfms",
+ DT_ms(m_fps_counter.GetDtStd()).count());
+ }
+ ImGui::End();
+ }
+ }
+
+ if (g_ActiveConfig.bShowVPS || g_ActiveConfig.bShowVTimes)
+ {
+ // Position in the top-right corner of the screen.
+ int count = g_ActiveConfig.bShowVPS + 2 * g_ActiveConfig.bShowVTimes;
+ ImGui::SetNextWindowPos(ImVec2(window_x, window_y), ImGuiCond_Always, ImVec2(1.0f, 0.0f));
+ ImGui::SetNextWindowSize(ImVec2(window_width, (12.f + 17.f * count) * backbuffer_scale));
+ ImGui::SetNextWindowBgAlpha(bg_alpha);
+ window_x -= window_width + window_padding;
+
+ if (ImGui::Begin("VPSStats", nullptr, imgui_flags))
+ {
+ if (g_ActiveConfig.bShowVPS)
+ ImGui::TextColored(ImVec4(r, g, b, 1.0f), "VPS:%7.2lf", vps);
+ if (g_ActiveConfig.bShowVTimes)
+ {
+ ImGui::TextColored(ImVec4(r, g, b, 1.0f), "dt:%6.2lfms",
+ DT_ms(m_vps_counter.GetDtAvg()).count());
+ ImGui::TextColored(ImVec4(r, g, b, 1.0f), " ±:%6.2lfms",
+ DT_ms(m_vps_counter.GetDtStd()).count());
+ }
+ ImGui::End();
+ }
+ }
+
+ if (g_ActiveConfig.bShowSpeed)
+ {
+ // Position in the top-right corner of the screen.
+ ImGui::SetNextWindowPos(ImVec2(window_x, window_y), ImGuiCond_Always, ImVec2(1.0f, 0.0f));
+ ImGui::SetNextWindowSize(ImVec2(window_width, 29.f * backbuffer_scale));
+ ImGui::SetNextWindowBgAlpha(bg_alpha);
+
+ if (ImGui::Begin("SpeedStats", nullptr, imgui_flags))
+ {
+ ImGui::TextColored(ImVec4(r, g, b, 1.0f), "Speed:%4.0lf%%", speed);
+ ImGui::End();
+ }
+ }
+
+ ImGui::PopStyleVar(2);
+}