From 9dfce3ec2f7f86d10788de4754e8f358a71c2c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 12 Sep 2026 11:49:06 -0600 Subject: [PATCH] ImDebugger: list the sceVideocodec contexts alongside sceAudiocodec Same shape as the audio table: one row per open context, with its EDRAM block and frame buffer allocation. Both are in ME memory, so the addresses shown are in that space, not in PSP RAM. Co-Authored-By: Claude Opus 5 (1M context) --- Core/HLE/sceVideocodec.cpp | 18 ++++++++++++++++++ Core/HLE/sceVideocodec.h | 28 ++++++++++++++++++++++++++++ UI/ImDebugger/ImDebugger.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/Core/HLE/sceVideocodec.cpp b/Core/HLE/sceVideocodec.cpp index 15c83f5e08..48482d1905 100644 --- a/Core/HLE/sceVideocodec.cpp +++ b/Core/HLE/sceVideocodec.cpp @@ -280,6 +280,24 @@ static bool PublishFrameBuffers(VideocodecCtx &vctx, u32 structAddr, int width, return true; } +void VideocodecGetCtxInfo(std::vector *infos) { + infos->clear(); + for (const auto &[addr, ctx] : g_videocodecCtxs) { + VideocodecCtxInfo info; + info.ctxAddr = addr; + info.type = ctx.type; + info.hasDecoder = ctx.decoder != nullptr; + info.frameCount = ctx.frameCount; + info.edramToken = ctx.edram; + info.edramSize = ctx.edram ? g_meAlloc.GetBlockSizeFromAddress(ctx.edram) : 0; + info.frameBuffers = ctx.frameBuffers; + info.frameBuffersSize = ctx.frameBuffersSize; + info.width = ctx.frameBufferWidth; + info.height = ctx.frameBufferHeight; + infos->push_back(info); + } +} + bool VideocodecGetFrameBuffers(u32 firstBuffer, u32 buffers[8]) { // sceMpegbase only has the first of the eight addresses, so find whose allocation it is. const VideocodecCtx *found = nullptr; diff --git a/Core/HLE/sceVideocodec.h b/Core/HLE/sceVideocodec.h index 37486744b7..0bb19e3216 100644 --- a/Core/HLE/sceVideocodec.h +++ b/Core/HLE/sceVideocodec.h @@ -17,6 +17,8 @@ #pragma once +#include + #include "Common/CommonTypes.h" class PointerWrap; @@ -27,11 +29,37 @@ void __VideocodecDoState(PointerWrap &p); void Register_sceVideocodec(); +// The state of each open decoder, for the debugger. A game can have several - Silent Hill Origins +// runs one context for the EDRAM and another for the decoding. +struct VideocodecCtxInfo { + u32 ctxAddr; + int type; + bool hasDecoder; + int frameCount; + // The token sceVideocodecGetEDRAM handed back, and how much it stands for. Not an address - + // the block is ours, not the game's, the way the Media Engine's memory is on hardware. + u32 edramToken; + u32 edramSize; + u32 frameBuffers; + u32 frameBuffersSize; + int width; + int height; +}; +void VideocodecGetCtxInfo(std::vector *infos); + // A host pointer into the Media Engine's memory, or null if the range isn't in it. The frame // buffers and the EDRAM block both live there, so anything reading them goes through this rather // than through Memory:: - the ME's memory is not part of PSP RAM. u8 *VideocodecMEPointer(u32 addr, u32 size); + // mpeg.prx copies only the four luma buffers into the descriptor it hands sceMpegBaseCscAvc. // Both ends of that are ours, so the conversion can recover the other four from the allocation // they came from. Returns false if `firstBuffer` isn't one we handed out. bool VideocodecGetFrameBuffers(u32 firstBuffer, u32 buffers[8]); + +// How the eight buffers a frame is delivered in are sized and laid out, in the order the +// descriptor lists them: four luma (left/right half of a 32-pixel band, even/odd rows) then four +// chroma. Everything that writes, reads or allocates them has to agree, so it lives in one place. +// `offsets` is each buffer's start within a single allocation, 64-byte aligned; either array may +// be null. Returns the total allocation size. +u32 VideocodecFrameBufferLayout(int width, int height, int sizes[8], u32 offsets[8]); diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index d0e2850da7..634d521db1 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -47,6 +47,7 @@ #include "Core/HLE/sceAtrac.h" #include "Core/HLE/sceAudio.h" #include "Core/HLE/sceAudiocodec.h" +#include "Core/HLE/sceVideocodec.h" #include "Core/HLE/sceMp3.h" #include "Core/HLE/AtracCtx.h" #include "Core/HLE/sceSas.h" @@ -1577,6 +1578,39 @@ void DrawMediaDecodersView(ImConfig &cfg, ImControl &control) { } } + std::vector videoCtxs; + VideocodecGetCtxInfo(&videoCtxs); + if (ImGui::CollapsingHeaderWithCount("sceVideocodec", (int)videoCtxs.size(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::BeginTable("videocodecs", 7, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) { + ImGui::TableSetupColumn("CtxAddr", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Frames", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Decoder", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("EDRAM", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Frame buffers", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableHeadersRow(); + for (const VideocodecCtxInfo &ctx : videoCtxs) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%08x", ctx.ctxAddr); + ImGui::TableNextColumn(); + ImGui::Text("H.264 (%d)", ctx.type); + ImGui::TableNextColumn(); + ImGui::Text("%dx%d", ctx.width, ctx.height); + ImGui::TableNextColumn(); + ImGui::Text("%d", ctx.frameCount); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(ctx.hasDecoder ? "open" : "-"); + ImGui::TableNextColumn(); + ImGui::Text("%08x (%d)", ctx.edramToken, ctx.edramSize); + ImGui::TableNextColumn(); + ImGui::Text("%08x (%d)", ctx.frameBuffers, ctx.frameBuffersSize); + } + ImGui::EndTable(); + } + } + ImGui::End(); }