fix(presenter): depth of field and scene changes at render resolution on Metal and Vulkan
What
Above 480p on macOS and Linux (the SDL_GPU Metal/Vulkan presenter), three full-screen effects looked much coarser than the models around them:
- Depth of field and the soft-focus overlay in the real-time demo. The game copies the frame into a 256x256 target, blurs it and stretches it back over the scene. The presenter point-sampled that copy from the upscaled frame, so it was jagged and streaky, and magnified the depth-of-field blur with plain bilinear, so its texels showed.
- Scene changes. The game copies the frame into a 512x512 target and holds that picture for a moment when it cuts to the next scene. The copy stayed 512x512, so the held picture was visibly blocky.
Changes
Both commits touch only recomp-runtime/d3d_presenter_sdl_gpu.cpp and only act when RECOMP_D3D_SCALE is above 1. D3D11 is untouched.
- Downsamples read a mipped copy of the frame, as the D3D11 presenter has done since 307daf0. The depth-of-field composite (the alpha-masked draw of a render target onto the main target) samples its blur target with a cubic B-spline in four bilinear taps. The blur target stays 256x256, so the blur is as strong as before.
- A depthless target of 512x512 or more that takes a pretransformed copy of the frame is sized like the main target. Guest coordinates and normalised UVs address it as before. A target that later binds depth returns to guest size. Target creation moves into one
acquireRenderTargethelper shared by clear and draw.
Verification
- Headless Metal runs of the real-time demo at 1920x1080, 4x MSAA, before and after, captured at the same swaps. Screenshots to follow in a comment.
ctest: 28 run, 27 passed, 1 skipped (custom-music), with local generated code and in a public-only configure.tools/public_export.py verify --require-public-treepasses.- Played on macOS by the author at 1080p for the first commit.
Not tested: Vulkan/Linux (the GLSL shader mirrors the Metal one but was not run), 4K, and the tools Python tests (my local Python is too old for them; CI runs them).
Known limit: at 4K two held-frame targets do not both fit in the 64 MB offscreen budget, so the second falls back to guest size.
Summary by cubic
Fixes depth of field and scene-change frames appearing blocky or streaky above 480p on the Metal and Vulkan (SDL_GPU) presenters.
- Depth-of-field and soft-focus blur targets are now sampled from a mipped copy of the upscaled frame, and the composite stretches the blur back with a cubic B-spline, applied only when the blur target is narrower than the frame.
- Held frames from scene changes (depthless front-buffer copies into 512x512-or-larger targets) are sized at render resolution. Only new targets grow, and targets bound to custom depth return to guest size, so existing targets no longer resize on every frame.
- Both fixes apply only when
RECOMP_D3D_SCALEis above 1; D3D11 is unchanged. Target creation is consolidated into a sharedacquireRenderTargethelper that matches depth attachments to the host color size.
Known limit: at 4K, two held-frame targets don't both fit in the 64 MB offscreen budget, so the second falls back to guest size.