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) <noreply@anthropic.com>
This commit is contained in:
Henrik Rydgård
2026-09-12 12:53:13 -06:00
co-authored by Claude Opus 5
parent ad7cfefd49
commit 9dfce3ec2f
3 changed files with 80 additions and 0 deletions
+18
View File
@@ -280,6 +280,24 @@ static bool PublishFrameBuffers(VideocodecCtx &vctx, u32 structAddr, int width,
return true;
}
void VideocodecGetCtxInfo(std::vector<VideocodecCtxInfo> *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;
+28
View File
@@ -17,6 +17,8 @@
#pragma once
#include <vector>
#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<VideocodecCtxInfo> *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]);
+34
View File
@@ -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<VideocodecCtxInfo> 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();
}