From 0f18f054abc35e9576f2e84e82f224907cbb99cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 22 Apr 2025 20:19:43 +0200 Subject: [PATCH] Make the frame-time budget for uploading replacement textures take framerate into account --- Core/HW/Display.cpp | 12 +++++++++--- GPU/Common/ReplacedTexture.cpp | 2 +- GPU/Common/TextureCacheCommon.cpp | 20 ++++++++++++++------ GPU/Common/TextureCacheCommon.h | 4 ++-- UI/EmuScreen.cpp | 3 +-- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/Core/HW/Display.cpp b/Core/HW/Display.cpp index 182769eabf..573297f37f 100644 --- a/Core/HW/Display.cpp +++ b/Core/HW/Display.cpp @@ -105,9 +105,15 @@ static void CalculateFPS() { // TODO: Also average actualFps void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps) { - *out_vps = (float)fps; - *out_fps = flips; - *out_actual_fps = actualFps; + if (out_vps) { + *out_vps = (float)fps; + } + if (out_fps) { + *out_fps = flips; + } + if (out_actual_fps) { + *out_actual_fps = actualFps; + } } void __DisplayGetVPS(float *out_vps) { diff --git a/GPU/Common/ReplacedTexture.cpp b/GPU/Common/ReplacedTexture.cpp index ba6bb34b2a..8221c4c72f 100644 --- a/GPU/Common/ReplacedTexture.cpp +++ b/GPU/Common/ReplacedTexture.cpp @@ -176,7 +176,7 @@ bool ReplacedTexture::Poll(double budget) { lastUsed_ = now; // Let's not even start a new texture if we're already behind. - if (budget < 0.0) + if (budget <= 0.0) return false; _assert_(!threadWaitable_); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 5eccb78e49..93a140fbfd 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -34,6 +34,7 @@ #include "Core/Config.h" #include "Core/Debugger/MemBlockInfo.h" #include "Core/System.h" +#include "Core/HW/Display.h" #include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Common/TextureDecoder.h" @@ -127,6 +128,14 @@ void TextureCacheCommon::StartFrame() { timesInvalidatedAllThisFrame_ = 0; replacementTimeThisFrame_ = 0.0; + float fps; + __DisplayGetFPS(nullptr, &fps, nullptr); + if (fps <= 5.0f) { + fps = 60.0f; + } + // Allow spending half a frame on uploading textures. + replacementFrameBudgetSeconds_ = 0.5f / fps; + if ((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS) { gpuStats.numReplacerTrackedTex = replacer_.GetNumTrackedTextures(); gpuStats.numCachedReplacedTextures = replacer_.GetNumCachedReplacedTextures(); @@ -530,7 +539,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { } } - if (match && (entry->status & TexCacheEntry::STATUS_TO_REPLACE) && replacementTimeThisFrame_ < replacementFrameBudget_) { + if (match && (entry->status & TexCacheEntry::STATUS_TO_REPLACE) && replacementTimeThisFrame_ < replacementFrameBudgetSeconds_) { int w0 = gstate.getTextureWidth(0); int h0 = gstate.getTextureHeight(0); int d0 = 1; @@ -1572,10 +1581,9 @@ ReplacedTexture *TextureCacheCommon::FindReplacement(TexCacheEntry *entry, int * } void TextureCacheCommon::PollReplacement(TexCacheEntry *entry, int *w, int *h, int *d) { - // Allow some delay to reduce pop-in. - constexpr double MAX_BUDGET_PER_TEX = 0.25 / 60.0; - - double budget = std::min(MAX_BUDGET_PER_TEX, replacementFrameBudget_ - replacementTimeThisFrame_); + double budget = replacementFrameBudgetSeconds_ - replacementTimeThisFrame_; + // Note: Don't avoid the Poll call if budget is 0, we do meaningful things there. + // Poll also handles negative budgets. double replaceStart = time_now_d(); if (entry->replacedTexture->Poll(budget)) { @@ -3157,7 +3165,7 @@ void TextureCacheCommon::DrawImGuiDebug(uint64_t &selectedTextureId) const { ImGui::Text("Texels scaled this frame: %d", texelsScaledThisFrame_); ImGui::Text("Low memory mode: %d", (int)lowMemoryMode_); if (ImGui::CollapsingHeader("Texture Replacement", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Text("Frame time/budget: %0.3f/%0.3f ms", replacementTimeThisFrame_ * 1000.0f, replacementFrameBudget_ * 1000.0f); + ImGui::Text("Frame time/budget: %0.3f/%0.3f ms", replacementTimeThisFrame_ * 1000.0f, replacementFrameBudgetSeconds_ * 1000.0f); ImGui::Text("UNLOADED: %d PENDING: %d NOT_FOUND: %d ACTIVE: %d CANCEL_INIT: %d", replacementStateCounts[(int)ReplacementState::UNLOADED], replacementStateCounts[(int)ReplacementState::PENDING], diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 2283b2eef4..597cecfa79 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -496,8 +496,8 @@ protected: int texelsScaledThisFrame_ = 0; int timesInvalidatedAllThisFrame_ = 0; double replacementTimeThisFrame_ = 0; - // TODO: Maybe vary by FPS... - double replacementFrameBudget_ = 0.5 / 60.0; + // Recomputed once per frame. Depends FPS and soon also config. + double replacementFrameBudgetSeconds_ = 0.5 / 60.0; TexCache cache_; u32 cacheSizeEstimate_ = 0; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index d2c6ddaa33..f3987613d4 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1768,8 +1768,6 @@ void EmuScreen::runImDebugger() { if (g_Config.bShowImDebugger) { Draw::DrawContext *draw = screenManager()->getDrawContext(); if (!imguiInited_) { - imguiInited_ = true; - // TODO: Do this only on demand. IMGUI_CHECKVERSION(); ctx_ = ImGui::CreateContext(); @@ -1783,6 +1781,7 @@ void EmuScreen::runImDebugger() { // This call works even if fontData is nullptr, in which case the font just won't get loaded. // This takes ownership of the font array. ImGui_ImplThin3d_Init(draw, fontData, size); + imguiInited_ = true; } if (PSP_IsInited()) {