Metal: Fail backbuffer readbacks until something draws to it

Headless renders to an offscreen backbuffer that nothing ever draws to,
so the GE debugger's screenshot read uninitialized memory. Fail the
readback instead, like headless Vulkan (which has no backbuffer), so the
debugger falls back to the displayed PSP framebuffer.

All the GE debugger buffers (screenshot, render color/depth/stencil,
texture, CLUT) now read back the same as Vulkan's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-19 12:02:22 +02:00
1 parent b2e6113f21
commit 987a904cff
3 files changed
+6 -1

No files matched your search

+3
View File
@@ -360,6 +360,8 @@ public:
MTLPixelFormat BackbufferFormat() const { return MTLPixelFormatBGRA8Unorm; }
// The offscreen backbuffer, or nil when rendering to the layer.
id<MTLTexture> OffscreenBackbuffer() const { return offscreenBackbuffer_; }
// False until something renders to the backbuffer (headless never does).
bool BackbufferDrawn() const { return backbufferDrawn_; }
// Render passes. The pass is started lazily, see above.
void BindRenderPass(const MetalRenderPassDesc &desc);
@@ -480,6 +482,7 @@ private:
// Recording state (emu thread).
MetalCommandChunk *chunk_ = nullptr;
id<MTLTexture> offscreenBackbuffer_;
bool backbufferDrawn_ = false;
id<MTLTexture> bbDepth_;
int bbWidth_ = 0;
int bbHeight_ = 0;
+1
View File
@@ -494,6 +494,7 @@ void MetalRenderManager::BindBackbufferPass(MTLLoadAction colorLoad, MTLClearCol
// Already rendering to it.
return;
}
backbufferDrawn_ = true;
EndRenderPass();
MetalRenderPassDesc desc{};
desc.colorLoad = colorLoad;
+2 -1
View File
@@ -1039,7 +1039,8 @@ bool MetalDrawContext::CopyFramebufferToMemory(Framebuffer *srcfb, Aspect aspect
texW = (int)srcTex.width;
texH = (int)srcTex.height;
srcFormat = srcTex.pixelFormat;
} else if (aspect != Aspect::COLOR_BIT) {
} else if (aspect != Aspect::COLOR_BIT || !rm_->BackbufferDrawn()) {
// Like headless Vulkan, which has no backbuffer. The GE debugger shows the PSP's framebuffer instead.
return false;
} else if (rm_->OffscreenBackbuffer()) {
srcTex = rm_->OffscreenBackbuffer();