OSD: Eliminate performance overlay flickering via caching

This commit is contained in:
TheTechnician27 2025-11-10 13:38:49 -06:00 committed by lightningterror
parent 080858b97c
commit e5d94e255b
4 changed files with 297 additions and 209 deletions

View File

@ -106,6 +106,11 @@ namespace Common
Reset(); Reset();
} }
Timer::Timer(Value start_value)
{
m_tvStartValue = start_value;
}
void Timer::Reset() void Timer::Reset()
{ {
m_tvStartValue = GetCurrentValue(); m_tvStartValue = GetCurrentValue();

View File

@ -12,6 +12,7 @@ namespace Common
using Value = std::uint64_t; using Value = std::uint64_t;
Timer(); Timer();
Timer (Value start_value);
static Value GetCurrentValue(); static Value GetCurrentValue();
static double ConvertValueToSeconds(Value value); static double ConvertValueToSeconds(Value value);

View File

@ -664,36 +664,32 @@ void GSgetStats(SmallStringBase& info)
if (pps >= 170000000) if (pps >= 170000000)
{ {
pps /= 1073741824; // Gpps pps /= _1gb; // Gpps
prefix = 'G'; prefix = 'G';
} }
else if (pps >= 35000000) else if (pps >= 35000000)
{ {
pps /= 1048576; // Mpps pps /= _1mb; // Mpps
prefix = 'M'; prefix = 'M';
} }
else if (pps >= 1024) else if (pps >= _1kb)
{ {
pps /= 1024; pps /= _1kb; // Kpps
prefix = 'K'; prefix = 'K';
} }
else
{
prefix = '\0';
}
info.format("{} SW | {} SP | {} P | {} D | {:.2f} S | {:.2f} U | {:.2f} {}pps", info.format("{} SW | {} SP | {} P | {} D | {:.2f} S | {:.2f} U | {:.2f} {}pps",
api_name, api_name,
(int)pm.Get(GSPerfMon::SyncPoint), (int)pm.Get(GSPerfMon::SyncPoint),
(int)pm.Get(GSPerfMon::Prim), (int)pm.Get(GSPerfMon::Prim),
(int)pm.Get(GSPerfMon::Draw), (int)pm.Get(GSPerfMon::Draw),
pm.Get(GSPerfMon::Swizzle) / 1024, pm.Get(GSPerfMon::Swizzle) / _1kb,
pm.Get(GSPerfMon::Unswizzle) / 1024, pm.Get(GSPerfMon::Unswizzle) / _1kb,
pps, prefix); pps, prefix);
} }
else if (GSCurrentRenderer == GSRendererType::Null) else if (GSCurrentRenderer == GSRendererType::Null)
{ {
fmt::format_to(std::back_inserter(info), "{} Null", api_name); info.format("{} Null", api_name);
} }
else else
{ {
@ -713,30 +709,45 @@ void GSgetStats(SmallStringBase& info)
void GSgetMemoryStats(SmallStringBase& info) void GSgetMemoryStats(SmallStringBase& info)
{ {
if (!g_texture_cache) if (!g_texture_cache)
{
info.assign("");
return; return;
}
const u64 targets = g_texture_cache->GetTargetMemoryUsage(); // Get megabyte values. Round negligible values to 0.1 MB to avoid swamping.
const u64 sources = g_texture_cache->GetSourceMemoryUsage(); const auto get_MB = [](const double bytes) {
const u64 hashcache = g_texture_cache->GetHashCacheMemoryUsage(); return (bytes <= 0.0 ? bytes : std::max(0.1, bytes / static_cast<double>(_1mb)));
const u64 pool = g_gs_device->GetPoolMemoryUsage(); };
const u64 total = targets + sources + hashcache + pool;
const auto format_precision = [](const double megabytes) -> std::string {
return (megabytes < 10.0 ?
fmt::format("{:.1f}", megabytes) :
fmt::format("{:.0f}", std::round(megabytes)));
};
const double targets_MB = get_MB(static_cast<double>(g_texture_cache->GetTargetMemoryUsage()));
const double sources_MB = get_MB(static_cast<double>(g_texture_cache->GetSourceMemoryUsage()));
const double pool_MB = get_MB(static_cast<double>(g_gs_device->GetPoolMemoryUsage()));
if (GSConfig.TexturePreloading == TexturePreloadingLevel::Full) if (GSConfig.TexturePreloading == TexturePreloadingLevel::Full)
{ {
fmt::format_to(std::back_inserter(info), "VRAM: {} MB | T: {} MB | S: {} MB | H: {} MB | P: {} MB", const double hashcache_MB = get_MB(static_cast<double>(g_texture_cache->GetHashCacheMemoryUsage()));
(int)std::ceil(total / 1048576.0f), const double total_MB = targets_MB + sources_MB + hashcache_MB + pool_MB;
(int)std::ceil(targets / 1048576.0f), info.format("VRAM: {} MB | T: {} MB | S: {} MB | H: {} MB | P: {} MB",
(int)std::ceil(sources / 1048576.0f), format_precision(total_MB),
(int)std::ceil(hashcache / 1048576.0f), format_precision(targets_MB),
(int)std::ceil(pool / 1048576.0f)); format_precision(sources_MB),
format_precision(hashcache_MB),
format_precision(pool_MB));
} }
else else
{ {
fmt::format_to(std::back_inserter(info), "VRAM: {} MB | T: {} MB | S: {} MB | P: {} MB", const double total_MB = targets_MB + sources_MB + pool_MB;
(int)std::ceil(total / 1048576.0f), info.format("VRAM: {} MB | T: {} MB | S: {} MB | P: {} MB",
(int)std::ceil(targets / 1048576.0f), format_precision(total_MB),
(int)std::ceil(sources / 1048576.0f), format_precision(targets_MB),
(int)std::ceil(pool / 1048576.0f)); format_precision(sources_MB),
format_precision(pool_MB));
} }
} }

View File

@ -49,6 +49,31 @@
InputRecordingUI::InputRecordingData g_InputRecordingData; InputRecordingUI::InputRecordingData g_InputRecordingData;
// Start timers at 0 so we immediately get lines to cache.
static constexpr double ONE_BILLION = 1000000000;
static constexpr double UPDATE_INTERVAL = 0.1 * ONE_BILLION;
static constexpr double UPDATE_INTERVAL_CPU_INFO = 5.0 * ONE_BILLION;
Common::Timer s_last_update_timer = Common::Timer(0.0);
Common::Timer s_last_update_timer_cpu_info = Common::Timer(0.0);
ImU32 s_speed_line_color;
SmallString s_speed_line;
SmallString s_gs_stats_line;
SmallString s_gs_memory_stats_line;
SmallString s_gs_frame_times_line;
SmallString s_resolution_line;
SmallString s_hardware_info_cpu_line;
SmallString s_hardware_info_gpu_line;
SmallString s_cpu_usage_ee_line;
SmallString s_cpu_usage_gs_line;
SmallString s_cpu_usage_vu_line;
std::vector<SmallString> s_software_thread_lines;
SmallString s_capture_line;
SmallString s_gpu_usage_line;
SmallString s_speed_icon;
constexpr ImU32 white_color = IM_COL32(255, 255, 255, 255);
// OSD positioning funcs // OSD positioning funcs
ImVec2 CalculateOSDPosition(OsdOverlayPos position, float margin, const ImVec2& text_size, float window_width, float window_height) ImVec2 CalculateOSDPosition(OsdOverlayPos position, float margin, const ImVec2& text_size, float window_width, float window_height)
{ {
@ -170,7 +195,6 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
const float font_size = ImGuiManager::GetFontSizeStandard(); const float font_size = ImGuiManager::GetFontSizeStandard();
ImDrawList* dl = ImGui::GetBackgroundDrawList(); ImDrawList* dl = ImGui::GetBackgroundDrawList();
SmallString text;
ImVec2 text_size; ImVec2 text_size;
// Adjust initial Y position based on vertical alignment // Adjust initial Y position based on vertical alignment
@ -208,166 +232,159 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
position_y += text_size.y + spacing; \ position_y += text_size.y + spacing; \
} while (0) } while (0)
const bool paused = (VMManager::GetState() == VMState::Paused); if (VMManager::GetState() != VMState::Paused)
const bool fsui_active = FullscreenUI::HasActiveWindow();
if (!paused)
{ {
bool first = true; if (s_last_update_timer.GetTimeNanoseconds() >= UPDATE_INTERVAL)
{
s_last_update_timer.Reset();
const float speed = PerformanceMetrics::GetSpeed(); const float speed = PerformanceMetrics::GetSpeed();
s_speed_line.clear();
if (GSConfig.OsdShowFPS) if (GSConfig.OsdShowFPS)
{ {
switch (PerformanceMetrics::GetInternalFPSMethod()) switch (PerformanceMetrics::GetInternalFPSMethod())
{ {
case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister: case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister:
text.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS()); s_speed_line.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS());
break; break;
case PerformanceMetrics::InternalFPSMethod::DISPFBBlit: case PerformanceMetrics::InternalFPSMethod::DISPFBBlit:
text.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS()); s_speed_line.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS());
break; break;
case PerformanceMetrics::InternalFPSMethod::None: case PerformanceMetrics::InternalFPSMethod::None:
default: default:
text.append("FPS: N/A"); s_speed_line.append("FPS: N/A");
break; break;
} }
first = false;
} }
if (GSConfig.OsdShowVPS) if (GSConfig.OsdShowVPS)
{ s_speed_line.append_format("{}VPS: {:.2f}", s_speed_line.empty() ? "" : " | ", PerformanceMetrics::GetFPS());
text.append_format("{}VPS: {:.2f}", first ? "" : " | ", PerformanceMetrics::GetFPS(),
PerformanceMetrics::GetFPS());
first = false;
}
if (GSConfig.OsdShowSpeed) if (GSConfig.OsdShowSpeed)
{ {
text.append_format("{}Speed: {}%", first ? "" : " | ", static_cast<u32>(std::round(speed))); s_speed_line.append_format("{}Speed: {}%", s_speed_line.empty() ? "" : " | ", static_cast<u32>(std::round(speed)));
const float target_speed = VMManager::GetTargetSpeed(); const float target_speed = VMManager::GetTargetSpeed();
if (target_speed == 0.0f) if (target_speed == 0.0f)
text.append(" (T: Max)"); s_speed_line.append(" (T: Max)");
else else
text.append_format(" (T: {:.0f}%)", target_speed * 100.0f); s_speed_line.append_format(" (T: {:.0f}%)", target_speed * 100.0f);
first = false;
} }
if (GSConfig.OsdShowVersion) if (GSConfig.OsdShowVersion)
{ s_speed_line.append_format("{}PCSX2 {}", s_speed_line.empty() ? "" : " | ", BuildVersion::GitRev);
text.append_format("{}PCSX2 {}", first ? "" : " | ", BuildVersion::GitRev);
}
if (!text.empty()) if (!s_speed_line.empty())
{ {
ImU32 color;
if (speed < 95.0f) if (speed < 95.0f)
color = IM_COL32(255, 100, 100, 255); s_speed_line_color = IM_COL32(255, 100, 100, 255); // red
else if (speed > 105.0f) else if (speed > 105.0f)
color = IM_COL32(100, 255, 100, 255); s_speed_line_color = IM_COL32(100, 255, 100, 255); // green
else else
color = IM_COL32(255, 255, 255, 255); s_speed_line_color = white_color;
DRAW_LINE(fixed_font, font_size, text.c_str(), color); DRAW_LINE(fixed_font, font_size, s_speed_line.c_str(), s_speed_line_color);
} }
if (GSConfig.OsdShowGSStats) if (GSConfig.OsdShowGSStats)
{ {
text.clear(); GSgetStats(s_gs_stats_line);
GSgetStats(text); GSgetMemoryStats(s_gs_memory_stats_line);
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); s_gs_frame_times_line.format("{} QF | Min: {:.2f}ms | Avg: {:.2f}ms | Max: {:.2f}ms",
MTGS::GetCurrentVsyncQueueSize() - 1, // subtract one for the current frame
text.clear();
GSgetMemoryStats(text);
if (!text.empty())
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255));
text.clear();
text.append_format("{} QF | Min: {:.2f}ms | Avg: {:.2f}ms | Max: {:.2f}ms",
MTGS::GetCurrentVsyncQueueSize() - 1, // we subtract one for the current frame
PerformanceMetrics::GetMinimumFrameTime(), PerformanceMetrics::GetMinimumFrameTime(),
PerformanceMetrics::GetAverageFrameTime(), PerformanceMetrics::GetAverageFrameTime(),
PerformanceMetrics::GetMaximumFrameTime()); PerformanceMetrics::GetMaximumFrameTime());
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255));
if (!s_gs_stats_line.empty())
DRAW_LINE(fixed_font, font_size, s_gs_stats_line.c_str(), white_color);
if (!s_gs_memory_stats_line.empty())
DRAW_LINE(fixed_font, font_size, s_gs_memory_stats_line.c_str(), white_color);
DRAW_LINE(fixed_font, font_size, s_gs_frame_times_line.c_str(), white_color);
} }
if (GSConfig.OsdShowResolution) if (GSConfig.OsdShowResolution)
{ {
int width, height; int iwidth, iheight;
GSgetInternalResolution(&width, &height); GSgetInternalResolution(&iwidth, &iheight);
text.clear(); s_resolution_line.format("{}x{} {} {}", iwidth, iheight, ReportVideoMode(), ReportInterlaceMode());
text.append_format("{}x{} {} {}", width, height, ReportVideoMode(), ReportInterlaceMode()); DRAW_LINE(fixed_font, font_size, s_resolution_line.c_str(), white_color);
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255));
} }
if (GSConfig.OsdShowHardwareInfo) if (GSConfig.OsdShowHardwareInfo)
{ {
// GPU can change on the fly with settings, but CPU change of any kind is a rare edge case.
if (s_last_update_timer_cpu_info.GetTimeNanoseconds() >= UPDATE_INTERVAL_CPU_INFO)
{
s_last_update_timer_cpu_info.Reset();
// CPU // CPU
text.clear();
const CPUInfo& info = GetCPUInfo(); const CPUInfo& info = GetCPUInfo();
bool has_small = info.num_small_cores > 0; const bool has_small = info.num_small_cores > 0;
bool has_ht = info.num_threads != info.num_big_cores + info.num_small_cores; const bool has_smt = info.num_threads != info.num_big_cores + info.num_small_cores;
text.append_format("CPU: {}", info.name); s_hardware_info_cpu_line.format("CPU: {}", info.name);
if (has_ht & has_small) if (has_smt && has_small)
text.append_format(" ({}P/{}E/{}T)", info.num_big_cores, info.num_small_cores, info.num_threads); s_hardware_info_cpu_line.append_format(" ({}P/{}E/{}T)", info.num_big_cores, info.num_small_cores, info.num_threads);
else if (has_small) else if (has_small)
text.append_format(" ({}P/{}E)", info.num_big_cores, info.num_small_cores); s_hardware_info_cpu_line.append_format(" ({}P/{}E)", info.num_big_cores, info.num_small_cores);
else else
text.append_format(" ({}C/{}T)", info.num_big_cores, info.num_threads); s_hardware_info_cpu_line.append_format(" ({}C/{}T)", info.num_big_cores, info.num_threads);
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); }
DRAW_LINE(fixed_font, font_size, s_hardware_info_cpu_line.c_str(), white_color);
// GPU // GPU
text.clear(); s_hardware_info_gpu_line.format("GPU: {}{}", g_gs_device->GetName(), GSConfig.UseDebugDevice ? " (Debug)" : "");
text.append_format("GPU: {}{}", g_gs_device->GetName(), GSConfig.UseDebugDevice ? " (Debug)" : ""); DRAW_LINE(fixed_font, font_size, s_hardware_info_gpu_line.c_str(), white_color);
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255));
} }
if (GSConfig.OsdShowCPU) if (GSConfig.OsdShowCPU)
{ {
text.clear();
if (EmuConfig.Speedhacks.EECycleRate != 0 || EmuConfig.Speedhacks.EECycleSkip != 0) if (EmuConfig.Speedhacks.EECycleRate != 0 || EmuConfig.Speedhacks.EECycleSkip != 0)
text.append_format("EE[{}/{}]: ", EmuConfig.Speedhacks.EECycleRate, EmuConfig.Speedhacks.EECycleSkip); s_cpu_usage_ee_line.format("EE[{}/{}]: ", EmuConfig.Speedhacks.EECycleRate, EmuConfig.Speedhacks.EECycleSkip);
else else
text = "EE: "; s_cpu_usage_ee_line.assign("EE: ");
FormatProcessorStat(text, PerformanceMetrics::GetCPUThreadUsage(), PerformanceMetrics::GetCPUThreadAverageTime()); FormatProcessorStat(s_cpu_usage_ee_line, PerformanceMetrics::GetCPUThreadUsage(), PerformanceMetrics::GetCPUThreadAverageTime());
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, font_size, s_cpu_usage_ee_line.c_str(), white_color);
text = "GS: "; s_cpu_usage_gs_line.assign("GS: ");
FormatProcessorStat(text, PerformanceMetrics::GetGSThreadUsage(), PerformanceMetrics::GetGSThreadAverageTime()); FormatProcessorStat(s_cpu_usage_gs_line, PerformanceMetrics::GetGSThreadUsage(), PerformanceMetrics::GetGSThreadAverageTime());
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, font_size, s_cpu_usage_gs_line.c_str(), white_color);
if (THREAD_VU1) if (THREAD_VU1)
{ {
text = "VU: "; s_cpu_usage_vu_line.assign("VU: ");
FormatProcessorStat(text, PerformanceMetrics::GetVUThreadUsage(), PerformanceMetrics::GetVUThreadAverageTime()); FormatProcessorStat(s_cpu_usage_vu_line, PerformanceMetrics::GetVUThreadUsage(), PerformanceMetrics::GetVUThreadAverageTime());
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, font_size, s_cpu_usage_vu_line.c_str(), white_color);
} }
const u32 gs_sw_threads = PerformanceMetrics::GetGSSWThreadCount(); const u32 gs_sw_threads = PerformanceMetrics::GetGSSWThreadCount();
for (u32 i = 0; i < gs_sw_threads; i++) for (u32 thread = 0; thread < gs_sw_threads; thread++)
{ {
text.clear(); if (thread < s_software_thread_lines.size())
text.append_format("SW-{}: ", i); s_software_thread_lines[thread].format("SW-{}: ", thread);
FormatProcessorStat(text, PerformanceMetrics::GetGSSWThreadUsage(i), PerformanceMetrics::GetGSSWThreadAverageTime(i)); else
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); s_software_thread_lines.push_back(SmallString("SW-{}: ", thread));
FormatProcessorStat(s_software_thread_lines[thread], PerformanceMetrics::GetGSSWThreadUsage(thread), PerformanceMetrics::GetGSSWThreadAverageTime(thread));
DRAW_LINE(fixed_font, font_size, s_software_thread_lines[thread].c_str(), white_color);
} }
if (GSCapture::IsCapturing()) if (GSCapture::IsCapturing())
{ {
text = "CAP: "; s_capture_line.assign("CAP: ");
FormatProcessorStat(text, PerformanceMetrics::GetCaptureThreadUsage(), PerformanceMetrics::GetCaptureThreadAverageTime()); FormatProcessorStat(s_capture_line, PerformanceMetrics::GetCaptureThreadUsage(), PerformanceMetrics::GetCaptureThreadAverageTime());
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, font_size, s_capture_line.c_str(), white_color);
} }
} }
if (GSConfig.OsdShowGPU) if (GSConfig.OsdShowGPU)
{ {
text = "GPU: "; s_gpu_usage_line.assign("GPU: ");
FormatProcessorStat(text, PerformanceMetrics::GetGPUUsage(), PerformanceMetrics::GetGPUAverageTime()); FormatProcessorStat(s_gpu_usage_line, PerformanceMetrics::GetGPUUsage(), PerformanceMetrics::GetGPUAverageTime());
DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, font_size, s_gpu_usage_line.c_str(), white_color);
} }
if (GSConfig.OsdShowIndicators) if (GSConfig.OsdShowIndicators)
@ -378,14 +395,70 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
if (!is_normal_speed) if (!is_normal_speed)
{ {
if (target_speed == EmuConfig.EmulationSpeed.SlomoScalar) // Slow-Motion if (target_speed == EmuConfig.EmulationSpeed.SlomoScalar) // Slow-Motion
DRAW_LINE(standard_font, font_size, ICON_PF_SLOW_MOTION, IM_COL32(255, 255, 255, 255)); s_speed_icon = ICON_PF_SLOW_MOTION;
else if (target_speed == EmuConfig.EmulationSpeed.TurboScalar) // Turbo else if (target_speed == EmuConfig.EmulationSpeed.TurboScalar) // Turbo
DRAW_LINE(standard_font, font_size, ICON_FA_FORWARD_FAST, IM_COL32(255, 255, 255, 255)); s_speed_icon = ICON_FA_FORWARD_FAST;
else // Unlimited else // Unlimited
DRAW_LINE(standard_font, font_size, ICON_FA_FORWARD, IM_COL32(255, 255, 255, 255)); s_speed_icon = ICON_FA_FORWARD;
DRAW_LINE(standard_font, font_size, s_speed_icon, white_color);
}
}
}
// No refresh yet. Display cached lines.
else
{
if (GSConfig.OsdShowFPS || GSConfig.OsdShowVPS || GSConfig.OsdShowSpeed || GSConfig.OsdShowVersion)
DRAW_LINE(fixed_font, font_size, s_speed_line.c_str(), s_speed_line_color);
if (GSConfig.OsdShowGSStats)
{
if (!s_gs_stats_line.empty())
DRAW_LINE(fixed_font, font_size, s_gs_stats_line.c_str(), white_color);
if (!s_gs_memory_stats_line.empty())
DRAW_LINE(fixed_font, font_size, s_gs_memory_stats_line.c_str(), white_color);
DRAW_LINE(fixed_font, font_size, s_gs_frame_times_line.c_str(), white_color);
}
if (GSConfig.OsdShowResolution)
DRAW_LINE(fixed_font, font_size, s_resolution_line.c_str(), white_color);
if (GSConfig.OsdShowHardwareInfo)
{
DRAW_LINE(fixed_font, font_size, s_hardware_info_cpu_line.c_str(), white_color);
DRAW_LINE(fixed_font, font_size, s_hardware_info_gpu_line.c_str(), white_color);
}
if (GSConfig.OsdShowCPU)
{
DRAW_LINE(fixed_font, font_size, s_cpu_usage_ee_line.c_str(), white_color);
DRAW_LINE(fixed_font, font_size, s_cpu_usage_gs_line.c_str(), white_color);
if (THREAD_VU1)
DRAW_LINE(fixed_font, font_size, s_cpu_usage_vu_line.c_str(), white_color);
const u32 thread_count = std::min(
PerformanceMetrics::GetGSSWThreadCount(),
static_cast<u32>(s_software_thread_lines.size()));
for (u32 thread = 0; thread < thread_count; thread++)
DRAW_LINE(fixed_font, font_size, s_software_thread_lines[thread].c_str(), white_color);
if (GSCapture::IsCapturing())
DRAW_LINE(fixed_font, font_size, s_capture_line.c_str(), white_color);
}
if (GSConfig.OsdShowGPU)
DRAW_LINE(fixed_font, font_size, s_gpu_usage_line.c_str(), white_color);
if (GSConfig.OsdShowIndicators)
{
const bool is_normal_speed = (VMManager::GetTargetSpeed() == EmuConfig.EmulationSpeed.NominalScalar ||
VMManager::IsTargetSpeedAdjustedToHost());
if (!is_normal_speed)
DRAW_LINE(standard_font, font_size, s_speed_icon, white_color);
} }
} }
// Check every OSD frame because this is an animation.
if (GSConfig.OsdShowFrameTimes) if (GSConfig.OsdShowFrameTimes)
{ {
const ImVec2 history_size(200.0f * scale, 50.0f * scale); const ImVec2 history_size(200.0f * scale, 50.0f * scale);
@ -426,9 +499,9 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
ImDrawList* win_dl = ImGui::GetCurrentWindow()->DrawList; ImDrawList* win_dl = ImGui::GetCurrentWindow()->DrawList;
const ImVec2 wpos(ImGui::GetCurrentWindow()->Pos); const ImVec2 wpos(ImGui::GetCurrentWindow()->Pos);
text.clear(); SmallString frame_times_text;
text.append_format("Max: {:.1f} ms", max); frame_times_text.format("Max: {:.1f} ms", max);
text_size = fixed_font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text.c_str(), text.c_str() + text.length()); text_size = fixed_font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, frame_times_text.c_str(), frame_times_text.c_str() + frame_times_text.length());
float text_x; float text_x;
switch (GSConfig.OsdPerformancePos) switch (GSConfig.OsdPerformancePos)
@ -451,13 +524,12 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
break; break;
} }
win_dl->AddText(ImVec2(text_x + shadow_offset, wpos.y + shadow_offset), win_dl->AddText(ImVec2(text_x + shadow_offset, wpos.y + shadow_offset),
IM_COL32(0, 0, 0, 100), text.c_str(), text.c_str() + text.length()); IM_COL32(0, 0, 0, 100), frame_times_text.c_str(), frame_times_text.c_str() + frame_times_text.length());
win_dl->AddText(ImVec2(text_x, wpos.y), win_dl->AddText(ImVec2(text_x, wpos.y),
IM_COL32(255, 255, 255, 255), text.c_str(), text.c_str() + text.length()); white_color, frame_times_text.c_str(), frame_times_text.c_str() + frame_times_text.length());
text.clear(); frame_times_text.format("Min: {:.1f} ms", min);
text.append_format("Min: {:.1f} ms", min); text_size = fixed_font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, frame_times_text.c_str(), frame_times_text.c_str() + frame_times_text.length());
text_size = fixed_font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text.c_str(), text.c_str() + text.length());
float min_text_x; float min_text_x;
switch (GSConfig.OsdPerformancePos) switch (GSConfig.OsdPerformancePos)
@ -480,9 +552,9 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
break; break;
} }
win_dl->AddText(ImVec2(min_text_x + shadow_offset, wpos.y + history_size.y - font_size + shadow_offset), win_dl->AddText(ImVec2(min_text_x + shadow_offset, wpos.y + history_size.y - font_size + shadow_offset),
IM_COL32(0, 0, 0, 100), text.c_str(), text.c_str() + text.length()); IM_COL32(0, 0, 0, 100), frame_times_text.c_str(), frame_times_text.c_str() + frame_times_text.length());
win_dl->AddText(ImVec2(min_text_x, wpos.y + history_size.y - font_size), win_dl->AddText(ImVec2(min_text_x, wpos.y + history_size.y - font_size),
IM_COL32(255, 255, 255, 255), text.c_str(), text.c_str() + text.length()); white_color, frame_times_text.c_str(), frame_times_text.c_str() + frame_times_text.length());
} }
ImGui::End(); ImGui::End();
ImGui::PopFont(); ImGui::PopFont();
@ -490,16 +562,15 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
ImGui::PopStyleColor(3); ImGui::PopStyleColor(3);
} }
} }
else if (!fsui_active) else if (!FullscreenUI::HasActiveWindow())
{ {
if (GSConfig.OsdShowIndicators) if (GSConfig.OsdShowIndicators)
{ {
// We should put the Pause icon in the top right regardless of performance overlay position // We should put the Pause icon in the top right regardless of performance overlay position
text = ICON_FA_PAUSE; text_size = standard_font->CalcTextSizeA(font_size, std::numeric_limits<float>::max(), -1.0f, ICON_FA_PAUSE, nullptr, nullptr);
text_size = standard_font->CalcTextSizeA(font_size, std::numeric_limits<float>::max(), -1.0f, text.c_str(), nullptr, nullptr);
const ImVec2 pause_pos(GetWindowWidth() - margin - text_size.x, margin); const ImVec2 pause_pos(GetWindowWidth() - margin - text_size.x, margin);
dl->AddText(standard_font, font_size, ImVec2(pause_pos.x + shadow_offset, pause_pos.y + shadow_offset), IM_COL32(0, 0, 0, 100), text.c_str()); dl->AddText(standard_font, font_size, ImVec2(pause_pos.x + shadow_offset, pause_pos.y + shadow_offset), IM_COL32(0, 0, 0, 100), ICON_FA_PAUSE);
dl->AddText(standard_font, font_size, pause_pos, IM_COL32(255, 255, 255, 255), text.c_str()); dl->AddText(standard_font, font_size, pause_pos, white_color, ICON_FA_PAUSE);
} }
} }
@ -640,7 +711,7 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa
dl->AddText(font, font_size, dl->AddText(font, font_size,
ImVec2(GetWindowWidth() - margin - text_size.x + shadow_offset, position_y + shadow_offset), IM_COL32(0, 0, 0, 100), ImVec2(GetWindowWidth() - margin - text_size.x + shadow_offset, position_y + shadow_offset), IM_COL32(0, 0, 0, 100),
text.c_str(), text.c_str() + text.length()); text.c_str(), text.c_str() + text.length());
dl->AddText(font, font_size, ImVec2(GetWindowWidth() - margin - text_size.x, position_y), IM_COL32(255, 255, 255, 255), dl->AddText(font, font_size, ImVec2(GetWindowWidth() - margin - text_size.x, position_y), white_color,
text.c_str(), text.c_str() + text.length()); text.c_str(), text.c_str() + text.length());
} }
@ -868,7 +939,7 @@ __ri void ImGuiManager::DrawVideoCaptureOverlay(float& position_y, float scale,
dl->AddText(standard_font, font_size, dl->AddText(standard_font, font_size,
ImVec2(GetWindowWidth() - margin - text_size.x - icon_size.x, position_y), IM_COL32(255, 0, 0, 255), ICON); ImVec2(GetWindowWidth() - margin - text_size.x - icon_size.x, position_y), IM_COL32(255, 0, 0, 255), ICON);
dl->AddText(standard_font, font_size, dl->AddText(standard_font, font_size,
ImVec2(GetWindowWidth() - margin - text_size.x, position_y), IM_COL32(255, 255, 255, 255), text_msg.c_str(), ImVec2(GetWindowWidth() - margin - text_size.x, position_y), white_color, text_msg.c_str(),
text_msg.end_ptr()); text_msg.end_ptr());
position_y += std::max(icon_size.y, text_size.y) + spacing; position_y += std::max(icon_size.y, text_size.y) + spacing;