Add texture cache stats to ImDebugger

This commit is contained in:
Henrik Rydgård 2024-12-01 13:57:07 +01:00
parent 61ae6d6c90
commit b195061a45
7 changed files with 117 additions and 23 deletions

View File

@ -58,6 +58,7 @@ enum class ReplacementState : uint32_t {
NOT_FOUND, // Also used on error loading the images.
ACTIVE,
CANCEL_INIT,
COUNT, // Not a valid state
};
const char *StateString(ReplacementState state);
@ -168,6 +169,10 @@ public:
return fmt;
}
const ReplacementDesc &Desc() const {
return desc_;
}
u8 AlphaStatus() const {
return (u8)alphaStatus_;
}

View File

@ -3068,12 +3068,23 @@ void TextureCacheCommon::DrawImGuiDebug(uint64_t &selectedTextureId) const {
ImGui::BeginChild("left", ImVec2(140.0f, 0.0f), ImGuiChildFlags_ResizeX);
float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
// Global texture stats
int replacementStateCounts[(int)ReplacementState::COUNT]{};
if (!secondCache_.empty()) {
ImGui::Text("Primary Cache");
}
for (auto &iter : cache_) {
u64 id = iter.first;
const TexCacheEntry *entry = iter.second.get();
void *nativeView = GetNativeTextureView(iter.second.get(), true);
int w = 128;
int h = 128;
if (entry->replacedTexture) {
replacementStateCounts[(int)entry->replacedTexture->State()]++;
}
ImTextureID texId = ImGui_ImplThin3d_AddNativeTextureTemp(nativeView);
float last_button_x2 = ImGui::GetItemRectMax().x;
float next_button_x2 = last_button_x2 + style.ItemSpacing.x + w; // Expected position if next button was on same line
@ -3084,39 +3095,90 @@ void TextureCacheCommon::DrawImGuiDebug(uint64_t &selectedTextureId) const {
if (ImGui::Selectable(("##Image" + std::to_string(id)).c_str(), selectedTextureId == id, 0, ImVec2(w, h))) {
selectedTextureId = id; // Update the selected index if clicked
}
ImGui::SameLine();
ImGui::SetCursorPosX(x + 2.0f);
ImGui::Image(texId, ImVec2(128, 128));
}
if (!secondCache_.size()) {
ImGui::Text("Secondary Cache (%d): TODO", (int)secondCache_.size());
// TODO
}
ImGui::EndChild();
ImGui::SameLine();
ImGui::BeginChild("right", ImVec2(0.f, 0.0f));
if (selectedTextureId) {
auto iter = cache_.find(selectedTextureId);
if (iter != cache_.end()) {
void *nativeView = GetNativeTextureView(iter->second.get(), true);
ImTextureID texId = ImGui_ImplThin3d_AddNativeTextureTemp(nativeView);
const TexCacheEntry *entry = iter->second.get();
int dim = entry->dim;
int w = dimWidth(dim);
int h = dimHeight(dim);
ImGui::Image(texId, ImVec2(w, h));
ImGui::Text("%08x: %dx%d, %d mips, %s", (uint32_t)(selectedTextureId & 0xFFFFFFFF), w, h, entry->maxLevel + 1, GeTextureFormatToString((GETextureFormat)entry->format));
ImGui::Text("Stride: %d", entry->bufw);
ImGui::Text("Status: %08x", entry->status); // TODO: Show the flags
ImGui::Text("Hash: %08x", entry->fullhash);
ImGui::Text("CLUT Hash: %08x", entry->cluthash);
ImGui::Text("Minihash: %08x", entry->minihash);
ImGui::Text("MaxSeenV: %08x", entry->maxSeenV);
ImGui::Text("Replaced: %s", entry->replacedTexture ? "true" : "false");
ImGui::Text("Frames until next full hash: %08x", entry->framesUntilNextFullHash); // TODO: Show the flags
if (ImGui::CollapsingHeader("Texture", ImGuiTreeNodeFlags_DefaultOpen)) {
if (selectedTextureId) {
auto iter = cache_.find(selectedTextureId);
if (iter != cache_.end()) {
void *nativeView = GetNativeTextureView(iter->second.get(), true);
ImTextureID texId = ImGui_ImplThin3d_AddNativeTextureTemp(nativeView);
const TexCacheEntry *entry = iter->second.get();
int dim = entry->dim;
int w = dimWidth(dim);
int h = dimHeight(dim);
ImGui::Image(texId, ImVec2(w, h));
ImGui::Text("%08x: %dx%d, %d mips, %s", (uint32_t)(selectedTextureId & 0xFFFFFFFF), w, h, entry->maxLevel + 1, GeTextureFormatToString((GETextureFormat)entry->format));
ImGui::Text("Stride: %d", entry->bufw);
ImGui::Text("Status: %08x", entry->status); // TODO: Show the flags
ImGui::Text("Hash: %08x", entry->fullhash);
ImGui::Text("CLUT Hash: %08x", entry->cluthash);
ImGui::Text("Minihash: %08x", entry->minihash);
ImGui::Text("MaxSeenV: %08x", entry->maxSeenV);
if (entry->replacedTexture) {
if (ImGui::CollapsingHeader("Replacement", ImGuiTreeNodeFlags_DefaultOpen)) {
const auto &desc = entry->replacedTexture->Desc();
ImGui::Text("State: %s", StateString(entry->replacedTexture->State()));
// ImGui::Text("Original: %dx%d (%dx%d)", desc.w, desc.h, desc.newW, desc.newH);
if (entry->replacedTexture->State() == ReplacementState::ACTIVE) {
int w, h;
entry->replacedTexture->GetSize(0, &w, &h);
int numLevels = entry->replacedTexture->NumLevels();
ImGui::Text("Replaced: %dx%d, %d mip levels", w, h, numLevels);
ImGui::Text("Level 0 size: %d bytes, format: %s", entry->replacedTexture->GetLevelDataSizeAfterCopy(0), Draw::DataFormatToString(entry->replacedTexture->Format()));
}
ImGui::Text("Key: %08x_%08x", (u32)(desc.cachekey >> 32), (u32)desc.cachekey);
ImGui::Text("Hashfiles: %s", desc.hashfiles.c_str());
ImGui::Text("Base: %s", desc.basePath.c_str());
ImGui::Text("Alpha status: %02x", entry->replacedTexture->AlphaStatus());
}
} else {
ImGui::Text("Not replaced");
}
ImGui::Text("Frames until next full hash: %08x", entry->framesUntilNextFullHash); // TODO: Show the flags
} else {
selectedTextureId = 0;
}
} else {
selectedTextureId = 0;
ImGui::Text("(no texture selected)");
}
}
if (ImGui::CollapsingHeader("Texture Cache State"), ImGuiTreeNodeFlags_DefaultOpen) {
ImGui::Text("Cache: %d textures, size est %d", (int)cache_.size(), cacheSizeEstimate_);
ImGui::Text("Second: %d textures, size est %d", (int)secondCache_.size(), secondCacheSizeEstimate_);
ImGui::Text("Low memory mode: %d", (int)lowMemoryMode_);
ImGui::Text("Standard/shader scale factor: %d/%d", standardScaleFactor_, shaderScaleFactor_);
ImGui::Text("Texels scaled this frame: %d", texelsScaledThisFrame_);
if (ImGui::CollapsingHeader("Texture Replacement", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Text("Frame time/budget: %0.3f/%0.3f ms", replacementTimeThisFrame_, replacementFrameBudget_);
ImGui::Text("UNLOADED: %d PENDING: %d NOT_FOUND: %d ACTIVE: %d CANCEL_INIT: %d",
replacementStateCounts[(int)ReplacementState::UNLOADED],
replacementStateCounts[(int)ReplacementState::PENDING],
replacementStateCounts[(int)ReplacementState::NOT_FOUND],
replacementStateCounts[(int)ReplacementState::ACTIVE],
replacementStateCounts[(int)ReplacementState::CANCEL_INIT]);
}
if (videos_.size()) {
if (ImGui::CollapsingHeader("Tracked video playback memory")) {
for (auto &video : videos_) {
ImGui::Text("%08x: %d flips, size = %d", video.addr, video.flips, video.size);
}
}
}
} else {
ImGui::Text("(no texture selected)");
}
ImGui::EndChild();
}

View File

@ -515,6 +515,12 @@ u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, bool swizzled
const u32 totalPixels = bufw * h + (w - bufw);
const u32 sizeInRAM = (textureBitsPerPixel[fmt] * totalPixels) / 8 * reduceHashSize;
// Sanity check: Ignore textures that are at the end of RAM.
if (Memory::MaxSizeAtAddress(addr) < sizeInRAM) {
ERROR_LOG(Log::G3D, "Can't hash a %d bytes textures at %08x - end point is outside memory", sizeInRAM, addr);
return 0;
}
switch (hash_) {
case ReplacedTextureHash::QUICK:
return StableQuickTexHash(checkp, sizeInRAM);

View File

@ -833,6 +833,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Debug stats", nullptr, &cfg_.debugStatsOpen);
ImGui::MenuItem("Struct viewer", nullptr, &cfg_.structViewerOpen);
ImGui::EndMenu();
}
@ -911,6 +912,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
DrawDisplayWindow(cfg_, gpuDebug->GetFramebufferManagerCommon());
}
if (cfg_.debugStatsOpen) {
DrawDebugStatsWindow(cfg_);
}
if (cfg_.structViewerOpen) {
structViewer_.Draw(mipsDebug, &cfg_.structViewerOpen);
}
@ -1121,6 +1126,7 @@ void ImConfig::SyncConfig(IniFile *ini, bool save) {
sync.Sync("kernelObjectsOpen", &kernelObjectsOpen, false);
sync.Sync("audioChannelsOpen", &audioChannelsOpen, false);
sync.Sync("texturesOpen", &texturesOpen, false);
sync.Sync("debugStatsOpen", &debugStatsOpen, false);
sync.SetSection(ini->GetOrCreateSection("Settings"));
sync.Sync("displayLatched", &displayLatched, false);

View File

@ -77,6 +77,7 @@ struct ImConfig {
bool filesystemBrowserOpen;
bool kernelObjectsOpen;
bool audioChannelsOpen;
bool debugStatsOpen;
// HLE explorer settings
// bool filterByUsed = true;

View File

@ -6,6 +6,7 @@
#include "GPU/Common/TextureCacheCommon.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HW/Display.h"
void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager) {
if (!ImGui::Begin("Framebuffers", &cfg.framebuffersOpen)) {
@ -55,3 +56,15 @@ void DrawDisplayWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManag
ImGui::End();
}
// Note: This is not exclusively graphics.
void DrawDebugStatsWindow(ImConfig &cfg) {
if (!ImGui::Begin("Debug Stats", &cfg.debugStatsOpen)) {
ImGui::End();
return;
}
char statbuf[4096];
__DisplayGetDebugStats(statbuf, sizeof(statbuf));
ImGui::TextUnformatted(statbuf);
ImGui::End();
}

View File

@ -10,6 +10,7 @@ class TextureCacheCommon;
void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager);
void DrawTexturesWindow(ImConfig &cfg, TextureCacheCommon *textureCache);
void DrawDisplayWindow(ImConfig &cfg, FramebufferManagerCommon *framebufferManager);
void DrawDebugStatsWindow(ImConfig &cfg);
class ImGeDebugger {
public: