Skip to content
Permalink
Browse files
Merge pull request #11326 from Sam-Belliveau/video-common-frame-pacing
VideoCommon: New FrameTime/VBlank Analyzer + Graph
  • Loading branch information
delroth committed Dec 24, 2022
2 parents 2345ba1 + e1d078a commit ea19909
Show file tree
Hide file tree
Showing 26 changed files with 720 additions and 240 deletions.
@@ -175,7 +175,10 @@ 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_FTIMES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowFTimes", false),
GFX_SHOW_VPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowVPS", false),
GFX_SHOW_VTIMES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowVTimes", false),
GFX_SHOW_GRAPHS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowGraphs", 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),
@@ -770,8 +770,14 @@ private void addGraphicsSettings(ArrayList<SettingsItem> sl)
R.string.video_backend, 0, R.array.videoBackendEntries, R.array.videoBackendValues));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_SHOW_FPS, R.string.show_fps,
R.string.show_fps_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_SHOW_FTIMES, R.string.show_ftimes,
R.string.show_ftimes_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_SHOW_VPS, R.string.show_vps,
R.string.show_vps_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_SHOW_VTIMES, R.string.show_vtimes,
R.string.show_vtimes_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_SHOW_GRAPHS, R.string.show_graphs,
R.string.show_graphs_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_SHOW_SPEED, R.string.show_speed,
R.string.show_speed_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_SHOW_SPEED_COLORS,
@@ -245,8 +245,14 @@
<string name="video_backend_description">Select the API used for graphics rendering.</string>
<string name="show_fps">Show FPS</string>
<string name="show_fps_description">Shows the number of distinct frames rendered per second as a measure of visual smoothness.</string>
<string name="show_ftimes">Show Frame Times</string>
<string name="show_ftimes_description">Shows the average time in ms between each distinct rendered frame alongside the standard deviation.</string>
<string name="show_vps">Show VPS</string>
<string name="show_vps_description">Show the number of frames rendered per second as a measure of emulation speed.</string>
<string name="show_vtimes">Show VBlank Times</string>
<string name="show_vtimes_description">Shows the average time in ms between each rendered frame alongside the standard deviation.</string>
<string name="show_graphs">Show Performance Graphs</string>
<string name="show_graphs_description">Shows frametime graph along with statistics as a representation of emulation performance.</string>
<string name="show_speed">Show % Speed</string>
<string name="show_speed_description">Shows the % speed of emulation compared to full speed.</string>
<string name="show_speed_colors">Show Speed Color</string>
@@ -14,6 +14,7 @@
#include "Common/Swap.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "VideoCommon/PerformanceMetrics.h"

static u32 DPL2QualityToFrameBlockSize(AudioCommon::DPL2Quality quality)
{
@@ -160,6 +161,8 @@ unsigned int Mixer::Mix(short* samples, unsigned int num_samples)

memset(samples, 0, num_samples * 2 * sizeof(short));

// TODO: Determine how emulation speed will be used in audio
// const float emulation_speed = std::roundf(g_perf_metrics.GetSpeed()) / 100.f;
const float emulation_speed = m_config_emulation_speed;
const int timing_variance = m_config_timing_variance;
if (m_config_audio_stretch)
@@ -48,9 +48,6 @@ class Mixer final
void StartLogDSPAudio(const std::string& filename);
void StopLogDSPAudio();

float GetCurrentSpeed() const { return m_speed.load(); }
void UpdateSpeed(float val) { m_speed.store(val); }

// 54000000 doesn't work here as it doesn't evenly divide with 32000, but 108000000 does
static constexpr u64 FIXED_SAMPLE_RATE_DIVIDEND = 54000000 * 2;

@@ -117,9 +114,6 @@ class Mixer final
bool m_log_dtk_audio = false;
bool m_log_dsp_audio = false;

// Current rate of emulation (1.0 = 100% speed)
std::atomic<float> m_speed{0.0f};

float m_config_emulation_speed;
int m_config_timing_variance;
bool m_config_audio_stretch;
@@ -7,6 +7,7 @@

#pragma once

#include <chrono>
#include <cstdint>

#ifdef _WIN32
@@ -26,3 +27,10 @@ using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;

using Clock = std::chrono::steady_clock;
using TimePoint = Clock::time_point;
using DT = Clock::duration;
using DT_us = std::chrono::duration<double, std::micro>;
using DT_ms = std::chrono::duration<double, std::milli>;
using DT_s = std::chrono::duration<double, std::ratio<1>>;
@@ -27,7 +27,10 @@ const Info<bool> GFX_CROP{{System::GFX, "Settings", "Crop"}, false};
const Info<int> GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES{
{System::GFX, "Settings", "SafeTextureCacheColorSamples"}, 128};
const Info<bool> GFX_SHOW_FPS{{System::GFX, "Settings", "ShowFPS"}, false};
const Info<bool> GFX_SHOW_FTIMES{{System::GFX, "Settings", "ShowFTimes"}, false};
const Info<bool> GFX_SHOW_VPS{{System::GFX, "Settings", "ShowVPS"}, false};
const Info<bool> GFX_SHOW_VTIMES{{System::GFX, "Settings", "ShowVTimes"}, false};
const Info<bool> GFX_SHOW_GRAPHS{{System::GFX, "Settings", "ShowGraphs"}, false};
const Info<bool> GFX_SHOW_SPEED{{System::GFX, "Settings", "ShowSpeed"}, false};
const Info<bool> GFX_SHOW_SPEED_COLORS{{System::GFX, "Settings", "ShowSpeedColors"}, true};
const Info<int> GFX_PERF_SAMP_WINDOW{{System::GFX, "Settings", "PerfSampWindowMS"}, 1000};
@@ -30,7 +30,10 @@ extern const Info<AspectMode> GFX_SUGGESTED_ASPECT_RATIO;
extern const Info<bool> GFX_CROP;
extern const Info<int> GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES;
extern const Info<bool> GFX_SHOW_FPS;
extern const Info<bool> GFX_SHOW_FTIMES;
extern const Info<bool> GFX_SHOW_VPS;
extern const Info<bool> GFX_SHOW_VTIMES;
extern const Info<bool> GFX_SHOW_GRAPHS;
extern const Info<bool> GFX_SHOW_SPEED;
extern const Info<bool> GFX_SHOW_SPEED_COLORS;
extern const Info<int> GFX_PERF_SAMP_WINDOW;
@@ -86,6 +86,7 @@
#include "VideoCommon/Fifo.h"
#include "VideoCommon/HiresTextures.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PerformanceMetrics.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoBackendBase.h"

@@ -100,8 +101,6 @@ static bool s_wants_determinism;
// Declarations and definitions
static Common::Timer s_timer;
static u64 s_timer_offset;
static std::atomic<u32> s_drawn_frame;
static std::atomic<u32> s_drawn_video;

static bool s_is_stopping = false;
static bool s_hardware_initialized = false;
@@ -347,6 +346,9 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
// This needs to be delayed until after the video backend is ready.
DolphinAnalytics::Instance().ReportGameStart();

// Clear performance data collected from previous threads.
g_perf_metrics.Reset();

#ifdef ANDROID
// For some reason, calling the JNI function AttachCurrentThread from the CPU thread after a
// certain point causes a crash if fastmem is enabled. Let's call it early to avoid that problem.
@@ -843,19 +845,15 @@ void RunOnCPUThread(std::function<void()> function, bool wait_for_completion)
// This should only be called from VI
void VideoThrottle()
{
g_perf_metrics.CountVBlank();

// Update info per second
u64 elapsed_ms = s_timer.ElapsedMs();
if ((elapsed_ms >= 1000 && s_drawn_video.load() > 0) || s_frame_step)
if ((elapsed_ms >= 500) || s_frame_step)
{
s_timer.Start();

UpdateTitle(elapsed_ms);

s_drawn_frame.store(0);
s_drawn_video.store(0);
UpdateTitle();
}

s_drawn_video++;
}

// --- Callbacks for backends / engine ---
@@ -864,9 +862,9 @@ void VideoThrottle()
// frame is presented to the host screen
void Callback_FramePresented(double actual_emulation_speed)
{
s_last_actual_emulation_speed = actual_emulation_speed;
g_perf_metrics.CountFrame();

s_drawn_frame++;
s_last_actual_emulation_speed = actual_emulation_speed;
s_stop_frame_step.store(true);
}

@@ -891,15 +889,11 @@ void Callback_NewField()
}
}

void UpdateTitle(u64 elapsed_ms)
void UpdateTitle()
{
if (elapsed_ms == 0)
elapsed_ms = 1;

float FPS = (float)(s_drawn_frame.load() * 1000.0 / elapsed_ms);
float VPS = (float)(s_drawn_video.load() * 1000.0 / elapsed_ms);
float Speed = (float)(s_drawn_video.load() * (100 * 1000.0) /
(VideoInterface::GetTargetRefreshRate() * elapsed_ms));
float FPS = g_perf_metrics.GetFPS();
float VPS = g_perf_metrics.GetVPS();
float Speed = g_perf_metrics.GetSpeed();

// Settings are shown the same for both extended and summary info
const std::string SSettings = fmt::format(
@@ -956,15 +950,6 @@ void UpdateTitle(u64 elapsed_ms)
message += " | " + title;
}

// Update the audio timestretcher with the current speed
auto& system = Core::System::GetInstance();
SoundStream* sound_stream = system.GetSoundStream();
if (sound_stream)
{
Mixer* mixer = sound_stream->GetMixer();
mixer->UpdateSpeed((float)Speed / 100);
}

Host_UpdateTitle(message);
}

@@ -126,7 +126,7 @@ void OnFrameEnd();

void VideoThrottle();

void UpdateTitle(u64 elapsed_ms);
void UpdateTitle();

// Run a function as the CPU thread.
//
@@ -637,7 +637,6 @@
<ClInclude Include="VideoCommon\DataReader.h" />
<ClInclude Include="VideoCommon\DriverDetails.h" />
<ClInclude Include="VideoCommon\Fifo.h" />
<ClInclude Include="VideoCommon\FPSCounter.h" />
<ClInclude Include="VideoCommon\FramebufferManager.h" />
<ClInclude Include="VideoCommon\FramebufferShaderGen.h" />
<ClInclude Include="VideoCommon\FrameDump.h" />
@@ -672,6 +671,8 @@
<ClInclude Include="VideoCommon\OnScreenDisplay.h" />
<ClInclude Include="VideoCommon\OpcodeDecoding.h" />
<ClInclude Include="VideoCommon\PerfQueryBase.h" />
<ClInclude Include="VideoCommon\PerformanceMetrics.h" />
<ClInclude Include="VideoCommon\PerformanceTracker.h" />
<ClInclude Include="VideoCommon\PixelEngine.h" />
<ClInclude Include="VideoCommon\PixelShaderGen.h" />
<ClInclude Include="VideoCommon\PixelShaderManager.h" />
@@ -1244,7 +1245,6 @@
<ClCompile Include="VideoCommon\CPMemory.cpp" />
<ClCompile Include="VideoCommon\DriverDetails.cpp" />
<ClCompile Include="VideoCommon\Fifo.cpp" />
<ClCompile Include="VideoCommon\FPSCounter.cpp" />
<ClCompile Include="VideoCommon\FramebufferManager.cpp" />
<ClCompile Include="VideoCommon\FramebufferShaderGen.cpp" />
<ClCompile Include="VideoCommon\FrameDump.cpp" />
@@ -1272,6 +1272,8 @@
<ClCompile Include="VideoCommon\OnScreenDisplay.cpp" />
<ClCompile Include="VideoCommon\OpcodeDecoding.cpp" />
<ClCompile Include="VideoCommon\PerfQueryBase.cpp" />
<ClCompile Include="VideoCommon\PerformanceMetrics.cpp" />
<ClCompile Include="VideoCommon\PerformanceTracker.cpp" />
<ClCompile Include="VideoCommon\PixelEngine.cpp" />
<ClCompile Include="VideoCommon\PixelShaderGen.cpp" />
<ClCompile Include="VideoCommon\PixelShaderManager.cpp" />
@@ -377,6 +377,7 @@ PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets
uicommon
imgui
implot
)

if (WIN32)
@@ -51,20 +51,26 @@ void AdvancedWidget::CreateWidgets()
performance_box->setLayout(performance_layout);

m_show_fps = new GraphicsBool(tr("Show FPS"), Config::GFX_SHOW_FPS);
m_show_ftimes = new GraphicsBool(tr("Show Frame Times"), Config::GFX_SHOW_FTIMES);
m_show_vps = new GraphicsBool(tr("Show VPS"), Config::GFX_SHOW_VPS);
m_show_vtimes = new GraphicsBool(tr("Show VBlank Times"), Config::GFX_SHOW_VTIMES);
m_show_graphs = new GraphicsBool(tr("Show Performance Graphs"), Config::GFX_SHOW_GRAPHS);
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_ftimes, 0, 1);
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);
performance_layout->addWidget(m_show_vtimes, 1, 1);
performance_layout->addWidget(m_show_speed, 2, 0);
performance_layout->addWidget(m_show_graphs, 2, 1);
performance_layout->addWidget(new QLabel(tr("Performance Sample Window (ms):")), 3, 0);
performance_layout->addWidget(m_perf_samp_window, 3, 1);
performance_layout->addWidget(m_log_render_time, 4, 0);
performance_layout->addWidget(m_show_speed_colors, 4, 1);

// Debugging
auto* debugging_box = new QGroupBox(tr("Debugging"));
@@ -240,10 +246,22 @@ void AdvancedWidget::AddDescriptions()
QT_TR_NOOP("Shows the number of distinct frames rendered per second as a measure of "
"visual smoothness.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_SHOW_FTIMES_DESCRIPTION[] =
QT_TR_NOOP("Shows the average time in ms between each distinct rendered frame alongside "
"the standard deviation.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_SHOW_VPS_DESCRIPTION[] =
QT_TR_NOOP("Shows the number of frames rendered per second as a measure of "
"emulation speed.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_SHOW_VTIMES_DESCRIPTION[] =
QT_TR_NOOP("Shows the average time in ms between each rendered frame alongside "
"the standard deviation.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_SHOW_GRAPHS_DESCRIPTION[] =
QT_TR_NOOP("Shows frametime graph along with statistics as a representation of "
"emulation performance.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_SHOW_SPEED_DESCRIPTION[] =
QT_TR_NOOP("Shows the % speed of emulation compared to full speed."
"<br><br><dolphin_emphasis>If unsure, leave this "
@@ -380,7 +398,10 @@ void AdvancedWidget::AddDescriptions()
QT_TR_NOOP("<dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");

m_show_fps->SetDescription(tr(TR_SHOW_FPS_DESCRIPTION));
m_show_ftimes->SetDescription(tr(TR_SHOW_FTIMES_DESCRIPTION));
m_show_vps->SetDescription(tr(TR_SHOW_VPS_DESCRIPTION));
m_show_vtimes->SetDescription(tr(TR_SHOW_VTIMES_DESCRIPTION));
m_show_graphs->SetDescription(tr(TR_SHOW_GRAPHS_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));
@@ -36,7 +36,10 @@ class AdvancedWidget final : public GraphicsWidget
GraphicsBool* m_enable_format_overlay;
GraphicsBool* m_enable_api_validation;
GraphicsBool* m_show_fps;
GraphicsBool* m_show_ftimes;
GraphicsBool* m_show_vps;
GraphicsBool* m_show_vtimes;
GraphicsBool* m_show_graphs;
GraphicsBool* m_show_speed;
GraphicsBool* m_show_speed_colors;
GraphicsInteger* m_perf_samp_window;
@@ -425,6 +425,7 @@
<Import Project="$(ExternalsDir)enet\exports.props" />
<Import Project="$(ExternalsDir)fmt\exports.props" />
<Import Project="$(ExternalsDir)imgui\exports.props" />
<Import Project="$(ExternalsDir)implot\exports.props" />
<Import Project="$(ExternalsDir)liblzma\exports.props" />
<Import Project="$(ExternalsDir)mbedtls\exports.props" />
<Import Project="$(ExternalsDir)mGBA\exports.props" />
@@ -27,8 +27,6 @@ add_library(videocommon
DriverDetails.h
Fifo.cpp
Fifo.h
FPSCounter.cpp
FPSCounter.h
FramebufferManager.cpp
FramebufferManager.h
FramebufferShaderGen.cpp
@@ -85,6 +83,10 @@ add_library(videocommon
OpcodeDecoding.h
PerfQueryBase.cpp
PerfQueryBase.h
PerformanceMetrics.cpp
PerformanceMetrics.h
PerformanceTracker.cpp
PerformanceTracker.h
PixelEngine.cpp
PixelEngine.h
PixelShaderGen.cpp
@@ -168,6 +170,7 @@ PRIVATE
spng
xxhash
imgui
implot
glslang
)

0 comments on commit ea19909

Please sign in to comment.