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(); }