Keep the stencil when resizing a framebuffer

ResizeFramebufFBO copied color and depth into the new FBO but left its
stencil cleared. Need for Speed Shift grows its framebuffer from 480 to 512
wide just before stencil testing, and the frame came out far too dark on
Android (112k px off the PSP on an Adreno 840, now 4k). MoltenVK happened
to keep it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-14 01:33:33 +02:00
1 parent 3e4458c7b7
commit b9780bc132
1 file changed
+11
+11
View File
@@ -2034,6 +2034,17 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
if (vfb->usageFlags & FB_USAGE_RENDER_DEPTH) {
BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0, RASTER_DEPTH, "BlitDepth_ResizeFramebufFBO");
}
if (!skipCopy && vfb->fb_format != GE_FORMAT_565) {
// Keep the stencil too (Need for Speed Shift stencil tests right after its framebuffer grows from 480 to
// 512 wide). D3D11 has no separate stencil copy, but copies it along with the depth above.
const int stencilW = std::min(old.renderWidth, vfb->renderWidth);
const int stencilH = std::min(old.renderHeight, vfb->renderHeight);
if (draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported) {
draw_->CopyFramebufferImage(old.fbo, 0, 0, 0, 0, vfb->fbo, 0, 0, 0, 0, stencilW, stencilH, 1, Draw::Aspect::STENCIL_BIT, "CopyStencil_ResizeFramebufFBO");
} else if (draw_->GetDeviceCaps().framebufferStencilBlitSupported) {
draw_->BlitFramebuffer(old.fbo, 0, 0, stencilW, stencilH, vfb->fbo, 0, 0, stencilW, stencilH, Draw::Aspect::STENCIL_BIT, Draw::FB_BLIT_NEAREST, "BlitStencil_ResizeFramebufFBO");
}
}
}
fbosToDelete_.push_back(old.fbo);
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO");