diff --git a/common/Timer.cpp b/common/Timer.cpp index 3e2a9e1166..261e12af97 100644 --- a/common/Timer.cpp +++ b/common/Timer.cpp @@ -106,6 +106,11 @@ namespace Common Reset(); } + Timer::Timer(Value start_value) + { + m_tvStartValue = start_value; + } + void Timer::Reset() { m_tvStartValue = GetCurrentValue(); diff --git a/common/Timer.h b/common/Timer.h index 74242a43fa..69419937f1 100644 --- a/common/Timer.h +++ b/common/Timer.h @@ -12,6 +12,7 @@ namespace Common using Value = std::uint64_t; Timer(); + Timer (Value start_value); static Value GetCurrentValue(); static double ConvertValueToSeconds(Value value); diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 582991b182..4b58c41c6f 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -664,36 +664,32 @@ void GSgetStats(SmallStringBase& info) if (pps >= 170000000) { - pps /= 1073741824; // Gpps + pps /= _1gb; // Gpps prefix = 'G'; } else if (pps >= 35000000) { - pps /= 1048576; // Mpps + pps /= _1mb; // Mpps prefix = 'M'; } - else if (pps >= 1024) + else if (pps >= _1kb) { - pps /= 1024; + pps /= _1kb; // Kpps prefix = 'K'; } - else - { - prefix = '\0'; - } info.format("{} SW | {} SP | {} P | {} D | {:.2f} S | {:.2f} U | {:.2f} {}pps", api_name, (int)pm.Get(GSPerfMon::SyncPoint), (int)pm.Get(GSPerfMon::Prim), (int)pm.Get(GSPerfMon::Draw), - pm.Get(GSPerfMon::Swizzle) / 1024, - pm.Get(GSPerfMon::Unswizzle) / 1024, + pm.Get(GSPerfMon::Swizzle) / _1kb, + pm.Get(GSPerfMon::Unswizzle) / _1kb, pps, prefix); } else if (GSCurrentRenderer == GSRendererType::Null) { - fmt::format_to(std::back_inserter(info), "{} Null", api_name); + info.format("{} Null", api_name); } else { @@ -713,30 +709,45 @@ void GSgetStats(SmallStringBase& info) void GSgetMemoryStats(SmallStringBase& info) { if (!g_texture_cache) + { + info.assign(""); return; + } - const u64 targets = g_texture_cache->GetTargetMemoryUsage(); - const u64 sources = g_texture_cache->GetSourceMemoryUsage(); - const u64 hashcache = g_texture_cache->GetHashCacheMemoryUsage(); - const u64 pool = g_gs_device->GetPoolMemoryUsage(); - const u64 total = targets + sources + hashcache + pool; + // Get megabyte values. Round negligible values to 0.1 MB to avoid swamping. + const auto get_MB = [](const double bytes) { + return (bytes <= 0.0 ? bytes : std::max(0.1, bytes / static_cast(_1mb))); + }; + + 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(g_texture_cache->GetTargetMemoryUsage())); + const double sources_MB = get_MB(static_cast(g_texture_cache->GetSourceMemoryUsage())); + const double pool_MB = get_MB(static_cast(g_gs_device->GetPoolMemoryUsage())); if (GSConfig.TexturePreloading == TexturePreloadingLevel::Full) { - fmt::format_to(std::back_inserter(info), "VRAM: {} MB | T: {} MB | S: {} MB | H: {} MB | P: {} MB", - (int)std::ceil(total / 1048576.0f), - (int)std::ceil(targets / 1048576.0f), - (int)std::ceil(sources / 1048576.0f), - (int)std::ceil(hashcache / 1048576.0f), - (int)std::ceil(pool / 1048576.0f)); + const double hashcache_MB = get_MB(static_cast(g_texture_cache->GetHashCacheMemoryUsage())); + const double total_MB = targets_MB + sources_MB + hashcache_MB + pool_MB; + info.format("VRAM: {} MB | T: {} MB | S: {} MB | H: {} MB | P: {} MB", + format_precision(total_MB), + format_precision(targets_MB), + format_precision(sources_MB), + format_precision(hashcache_MB), + format_precision(pool_MB)); } else { - fmt::format_to(std::back_inserter(info), "VRAM: {} MB | T: {} MB | S: {} MB | P: {} MB", - (int)std::ceil(total / 1048576.0f), - (int)std::ceil(targets / 1048576.0f), - (int)std::ceil(sources / 1048576.0f), - (int)std::ceil(pool / 1048576.0f)); + const double total_MB = targets_MB + sources_MB + pool_MB; + info.format("VRAM: {} MB | T: {} MB | S: {} MB | P: {} MB", + format_precision(total_MB), + format_precision(targets_MB), + format_precision(sources_MB), + format_precision(pool_MB)); } } diff --git a/pcsx2/ImGui/ImGuiOverlays.cpp b/pcsx2/ImGui/ImGuiOverlays.cpp index 0f8f19722e..a9fac9d652 100644 --- a/pcsx2/ImGui/ImGuiOverlays.cpp +++ b/pcsx2/ImGui/ImGuiOverlays.cpp @@ -49,6 +49,31 @@ 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 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 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(); ImDrawList* dl = ImGui::GetBackgroundDrawList(); - SmallString text; ImVec2 text_size; // Adjust initial Y position based on vertical alignment @@ -208,184 +232,233 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f position_y += text_size.y + spacing; \ } while (0) - const bool paused = (VMManager::GetState() == VMState::Paused); - const bool fsui_active = FullscreenUI::HasActiveWindow(); - - if (!paused) + if (VMManager::GetState() != VMState::Paused) { - bool first = true; - const float speed = PerformanceMetrics::GetSpeed(); - - if (GSConfig.OsdShowFPS) + if (s_last_update_timer.GetTimeNanoseconds() >= UPDATE_INTERVAL) { - switch (PerformanceMetrics::GetInternalFPSMethod()) + s_last_update_timer.Reset(); + const float speed = PerformanceMetrics::GetSpeed(); + + s_speed_line.clear(); + if (GSConfig.OsdShowFPS) { - case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister: - text.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS()); - break; + switch (PerformanceMetrics::GetInternalFPSMethod()) + { + case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister: + s_speed_line.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS()); + break; - case PerformanceMetrics::InternalFPSMethod::DISPFBBlit: - text.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS()); - break; + case PerformanceMetrics::InternalFPSMethod::DISPFBBlit: + s_speed_line.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS()); + break; - case PerformanceMetrics::InternalFPSMethod::None: - default: - text.append("FPS: N/A"); - break; - } - first = false; - } - - if (GSConfig.OsdShowVPS) - { - text.append_format("{}VPS: {:.2f}", first ? "" : " | ", PerformanceMetrics::GetFPS(), - PerformanceMetrics::GetFPS()); - first = false; - } - - if (GSConfig.OsdShowSpeed) - { - text.append_format("{}Speed: {}%", first ? "" : " | ", static_cast(std::round(speed))); - - const float target_speed = VMManager::GetTargetSpeed(); - if (target_speed == 0.0f) - text.append(" (T: Max)"); - else - text.append_format(" (T: {:.0f}%)", target_speed * 100.0f); - first = false; - } - - if (GSConfig.OsdShowVersion) - { - text.append_format("{}PCSX2 {}", first ? "" : " | ", BuildVersion::GitRev); - } - - if (!text.empty()) - { - ImU32 color; - if (speed < 95.0f) - color = IM_COL32(255, 100, 100, 255); - else if (speed > 105.0f) - color = IM_COL32(100, 255, 100, 255); - else - color = IM_COL32(255, 255, 255, 255); - - DRAW_LINE(fixed_font, font_size, text.c_str(), color); - } - - if (GSConfig.OsdShowGSStats) - { - text.clear(); - GSgetStats(text); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - - 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::GetAverageFrameTime(), - PerformanceMetrics::GetMaximumFrameTime()); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - } - - if (GSConfig.OsdShowResolution) - { - int width, height; - GSgetInternalResolution(&width, &height); - - text.clear(); - text.append_format("{}x{} {} {}", width, height, ReportVideoMode(), ReportInterlaceMode()); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - } - - if (GSConfig.OsdShowHardwareInfo) - { - // CPU - text.clear(); - const CPUInfo& info = GetCPUInfo(); - bool has_small = info.num_small_cores > 0; - bool has_ht = info.num_threads != info.num_big_cores + info.num_small_cores; - text.append_format("CPU: {}", info.name); - if (has_ht & has_small) - text.append_format(" ({}P/{}E/{}T)", info.num_big_cores, info.num_small_cores, info.num_threads); - else if (has_small) - text.append_format(" ({}P/{}E)", info.num_big_cores, info.num_small_cores); - else - text.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)); - - // GPU - text.clear(); - text.append_format("GPU: {}{}", g_gs_device->GetName(), GSConfig.UseDebugDevice ? " (Debug)" : ""); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - } - - if (GSConfig.OsdShowCPU) - { - text.clear(); - if (EmuConfig.Speedhacks.EECycleRate != 0 || EmuConfig.Speedhacks.EECycleSkip != 0) - text.append_format("EE[{}/{}]: ", EmuConfig.Speedhacks.EECycleRate, EmuConfig.Speedhacks.EECycleSkip); - else - text = "EE: "; - FormatProcessorStat(text, PerformanceMetrics::GetCPUThreadUsage(), PerformanceMetrics::GetCPUThreadAverageTime()); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - - text = "GS: "; - FormatProcessorStat(text, PerformanceMetrics::GetGSThreadUsage(), PerformanceMetrics::GetGSThreadAverageTime()); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - - if (THREAD_VU1) - { - text = "VU: "; - FormatProcessorStat(text, PerformanceMetrics::GetVUThreadUsage(), PerformanceMetrics::GetVUThreadAverageTime()); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); + case PerformanceMetrics::InternalFPSMethod::None: + default: + s_speed_line.append("FPS: N/A"); + break; + } } - const u32 gs_sw_threads = PerformanceMetrics::GetGSSWThreadCount(); - for (u32 i = 0; i < gs_sw_threads; i++) + if (GSConfig.OsdShowVPS) + s_speed_line.append_format("{}VPS: {:.2f}", s_speed_line.empty() ? "" : " | ", PerformanceMetrics::GetFPS()); + + if (GSConfig.OsdShowSpeed) { - text.clear(); - text.append_format("SW-{}: ", i); - FormatProcessorStat(text, PerformanceMetrics::GetGSSWThreadUsage(i), PerformanceMetrics::GetGSSWThreadAverageTime(i)); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); + s_speed_line.append_format("{}Speed: {}%", s_speed_line.empty() ? "" : " | ", static_cast(std::round(speed))); + + const float target_speed = VMManager::GetTargetSpeed(); + if (target_speed == 0.0f) + s_speed_line.append(" (T: Max)"); + else + s_speed_line.append_format(" (T: {:.0f}%)", target_speed * 100.0f); } - if (GSCapture::IsCapturing()) + if (GSConfig.OsdShowVersion) + s_speed_line.append_format("{}PCSX2 {}", s_speed_line.empty() ? "" : " | ", BuildVersion::GitRev); + + if (!s_speed_line.empty()) { - text = "CAP: "; - FormatProcessorStat(text, PerformanceMetrics::GetCaptureThreadUsage(), PerformanceMetrics::GetCaptureThreadAverageTime()); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - } - } - - if (GSConfig.OsdShowGPU) - { - text = "GPU: "; - FormatProcessorStat(text, PerformanceMetrics::GetGPUUsage(), PerformanceMetrics::GetGPUAverageTime()); - DRAW_LINE(fixed_font, font_size, text.c_str(), IM_COL32(255, 255, 255, 255)); - } - - if (GSConfig.OsdShowIndicators) - { - const float target_speed = VMManager::GetTargetSpeed(); - const bool is_normal_speed = (target_speed == EmuConfig.EmulationSpeed.NominalScalar || - VMManager::IsTargetSpeedAdjustedToHost()); - if (!is_normal_speed) - { - if (target_speed == EmuConfig.EmulationSpeed.SlomoScalar) // Slow-Motion - DRAW_LINE(standard_font, font_size, ICON_PF_SLOW_MOTION, IM_COL32(255, 255, 255, 255)); - else if (target_speed == EmuConfig.EmulationSpeed.TurboScalar) // Turbo - DRAW_LINE(standard_font, font_size, ICON_FA_FORWARD_FAST, IM_COL32(255, 255, 255, 255)); - else // Unlimited - DRAW_LINE(standard_font, font_size, ICON_FA_FORWARD, IM_COL32(255, 255, 255, 255)); + if (speed < 95.0f) + s_speed_line_color = IM_COL32(255, 100, 100, 255); // red + else if (speed > 105.0f) + s_speed_line_color = IM_COL32(100, 255, 100, 255); // green + else + s_speed_line_color = white_color; + + DRAW_LINE(fixed_font, font_size, s_speed_line.c_str(), s_speed_line_color); + } + + if (GSConfig.OsdShowGSStats) + { + GSgetStats(s_gs_stats_line); + GSgetMemoryStats(s_gs_memory_stats_line); + 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 + PerformanceMetrics::GetMinimumFrameTime(), + PerformanceMetrics::GetAverageFrameTime(), + PerformanceMetrics::GetMaximumFrameTime()); + + 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) + { + int iwidth, iheight; + GSgetInternalResolution(&iwidth, &iheight); + + s_resolution_line.format("{}x{} {} {}", iwidth, iheight, ReportVideoMode(), ReportInterlaceMode()); + DRAW_LINE(fixed_font, font_size, s_resolution_line.c_str(), white_color); + } + + 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 + const CPUInfo& info = GetCPUInfo(); + const bool has_small = info.num_small_cores > 0; + const bool has_smt = info.num_threads != info.num_big_cores + info.num_small_cores; + s_hardware_info_cpu_line.format("CPU: {}", info.name); + if (has_smt && has_small) + 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) + s_hardware_info_cpu_line.append_format(" ({}P/{}E)", info.num_big_cores, info.num_small_cores); + else + s_hardware_info_cpu_line.append_format(" ({}C/{}T)", info.num_big_cores, info.num_threads); + } + + DRAW_LINE(fixed_font, font_size, s_hardware_info_cpu_line.c_str(), white_color); + + // GPU + s_hardware_info_gpu_line.format("GPU: {}{}", g_gs_device->GetName(), GSConfig.UseDebugDevice ? " (Debug)" : ""); + DRAW_LINE(fixed_font, font_size, s_hardware_info_gpu_line.c_str(), white_color); + } + + if (GSConfig.OsdShowCPU) + { + if (EmuConfig.Speedhacks.EECycleRate != 0 || EmuConfig.Speedhacks.EECycleSkip != 0) + s_cpu_usage_ee_line.format("EE[{}/{}]: ", EmuConfig.Speedhacks.EECycleRate, EmuConfig.Speedhacks.EECycleSkip); + else + s_cpu_usage_ee_line.assign("EE: "); + FormatProcessorStat(s_cpu_usage_ee_line, PerformanceMetrics::GetCPUThreadUsage(), PerformanceMetrics::GetCPUThreadAverageTime()); + DRAW_LINE(fixed_font, font_size, s_cpu_usage_ee_line.c_str(), white_color); + + s_cpu_usage_gs_line.assign("GS: "); + FormatProcessorStat(s_cpu_usage_gs_line, PerformanceMetrics::GetGSThreadUsage(), PerformanceMetrics::GetGSThreadAverageTime()); + DRAW_LINE(fixed_font, font_size, s_cpu_usage_gs_line.c_str(), white_color); + + if (THREAD_VU1) + { + s_cpu_usage_vu_line.assign("VU: "); + FormatProcessorStat(s_cpu_usage_vu_line, PerformanceMetrics::GetVUThreadUsage(), PerformanceMetrics::GetVUThreadAverageTime()); + DRAW_LINE(fixed_font, font_size, s_cpu_usage_vu_line.c_str(), white_color); + } + + const u32 gs_sw_threads = PerformanceMetrics::GetGSSWThreadCount(); + for (u32 thread = 0; thread < gs_sw_threads; thread++) + { + if (thread < s_software_thread_lines.size()) + s_software_thread_lines[thread].format("SW-{}: ", thread); + else + 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()) + { + s_capture_line.assign("CAP: "); + FormatProcessorStat(s_capture_line, PerformanceMetrics::GetCaptureThreadUsage(), PerformanceMetrics::GetCaptureThreadAverageTime()); + DRAW_LINE(fixed_font, font_size, s_capture_line.c_str(), white_color); + } + } + + if (GSConfig.OsdShowGPU) + { + s_gpu_usage_line.assign("GPU: "); + FormatProcessorStat(s_gpu_usage_line, PerformanceMetrics::GetGPUUsage(), PerformanceMetrics::GetGPUAverageTime()); + DRAW_LINE(fixed_font, font_size, s_gpu_usage_line.c_str(), white_color); + } + + if (GSConfig.OsdShowIndicators) + { + const float target_speed = VMManager::GetTargetSpeed(); + const bool is_normal_speed = (target_speed == EmuConfig.EmulationSpeed.NominalScalar || + VMManager::IsTargetSpeedAdjustedToHost()); + if (!is_normal_speed) + { + if (target_speed == EmuConfig.EmulationSpeed.SlomoScalar) // Slow-Motion + s_speed_icon = ICON_PF_SLOW_MOTION; + else if (target_speed == EmuConfig.EmulationSpeed.TurboScalar) // Turbo + s_speed_icon = ICON_FA_FORWARD_FAST; + else // Unlimited + 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(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) { 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; const ImVec2 wpos(ImGui::GetCurrentWindow()->Pos); - text.clear(); - text.append_format("Max: {:.1f} ms", max); - text_size = fixed_font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text.c_str(), text.c_str() + text.length()); + SmallString frame_times_text; + frame_times_text.format("Max: {:.1f} ms", max); + 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; switch (GSConfig.OsdPerformancePos) @@ -451,13 +524,12 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f break; } 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), - 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(); - text.append_format("Min: {:.1f} ms", min); - text_size = fixed_font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text.c_str(), text.c_str() + text.length()); + frame_times_text.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()); float min_text_x; switch (GSConfig.OsdPerformancePos) @@ -480,9 +552,9 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f break; } 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), - 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::PopFont(); @@ -490,16 +562,15 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f ImGui::PopStyleColor(3); } } - else if (!fsui_active) + else if (!FullscreenUI::HasActiveWindow()) { if (GSConfig.OsdShowIndicators) { // 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::max(), -1.0f, text.c_str(), nullptr, nullptr); + text_size = standard_font->CalcTextSizeA(font_size, std::numeric_limits::max(), -1.0f, ICON_FA_PAUSE, nullptr, nullptr); 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, pause_pos, IM_COL32(255, 255, 255, 255), 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, white_color, ICON_FA_PAUSE); } } @@ -640,7 +711,7 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa dl->AddText(font, font_size, 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()); - 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()); } @@ -868,7 +939,7 @@ __ri void ImGuiManager::DrawVideoCaptureOverlay(float& position_y, float scale, dl->AddText(standard_font, font_size, ImVec2(GetWindowWidth() - margin - text_size.x - icon_size.x, position_y), IM_COL32(255, 0, 0, 255), ICON); 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()); position_y += std::max(icon_size.y, text_size.y) + spacing;