Repository navigation
Conversation
The game's AO stayed at 480x270 at every render scale (#356), so on a large frame it was soft and flickered at the edges of objects. A new Video setting, Ambient occlusion (Switch / High), draws it at the size of the depth level it is made from: 2x the render scale, between the Switch's size and twice it (960x540 at 1x and up). Scaling the targets alone broke the AO's 4x4 sample-rotation pattern (#356). Two signature-checked shader patches give it the real pixel grid: the AO pass's rotation index is scaled by the target's scale, and the two blurs of the AO itself (the Gaussian shader the bloom also uses, flagged per draw through rscale[65].y) divide their tap offsets by the AO's scale. At the Switch's size both are unchanged. Metal and Vulkan. LARECOMP_AO_SCALE (fixed scale), LARECOMP_AO_NO_GRID (A/B for the patches); LARECOMP_AO_SCALED keeps the pre-#356 path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For #602: the game's ambient occlusion is soft and flickers around objects at high resolutions.
What changed
Since #356 the AO stays at the Switch's size (480x270, blurred, plus a 240x135 level) at every render scale, so on a large frame it is the Switch's AO stretched up.
A new Video setting, Ambient occlusion: Default / High (default Default, the Switch's AO; ini
ambient_occlusion = switch | high). High draws the AO at the size of the depth it is built from: 2x the render scale, clamped between the Switch's size and twice it. That is 960x540 at 1x and above, the Switch's size below 0.5x. The cost is 4x the AO pass at most, still a quarter of 1080p.Scaling the targets alone is what broke #356. The AO shader takes its 4x4 sample-rotation index from
uv / texel sizewith the game's texel size, and the blur's tap offsets are in uv of the Switch's size. Two shader patches inmaxwell/translate.c(ao_grid_fix, checked against the original instruction words likelight_tiles_fix) give both the real pixel grid:rscale[0]).rscale[65].y= AO scale, 0 for every other draw). Their tap offsets around the centre tap are divided by it, which is the Switch's blur in pixels.At the Switch's size both patches change nothing. The 240x135 level keeps the game's offsets.
Textures: the AO targets and their quarter-size depth-stencil are scalable again, with a scale of their own (
tex_ao,tex_alloc_x/y) on both Metal (metal.m) and Vulkan (vulkan/textures.c). They reallocate when the setting changes. Dynamic resolution goes by the allocation scale, so its steps don't reallocate them.Test switches (docs/debug-hooks.md):
LARECOMP_AO_SCALE=<n>(fixed scale),LARECOMP_AO_NO_GRID=1(A/B for the patches),LARECOMP_AO_SCALED=1(the pre-#356 path, unchanged).Not done: an edge-aware upsample from the AO to the frame. The game's composite multiplies the AO in with a plain bilinear fetch, and its own blur isn't depth-aware either. At 2x the bleed past edges is half as wide, and I didn't see halos in the comparisons below, so I left the game's composite alone.
Testing
Metal (Apple Silicon, macOS), hidden window, scratch saves. Field_11C (flat grass, fences, the house, trees) and Bow-wow's house (furniture), at render scales 0.25, 1 and 2:
LARECOMP_AO_SCALE=4, same setup): no visible difference from High. The mean pixel difference to High is a third of High's difference to Switch. The AO samples depth snapped to a 960x540 grid, so High already uses all the detail there is. That's why the setting stops at High.Vulkan (Linux aarch64 VM, lavapipe): builds clean. The two patched shaders also pass glslc and spirv-val offline (plain and structured). In game, at the reporter's spot (render scale 1, Bilinear, SMAA, Remove Blur): Default shows the same speckled fringe at the wall bases as Metal, High is smooth, and there's no crosshatch, so the grid fix works on Vulkan too. No validation errors or device loss in the logs.
Comparison images: to be attached (AO buffer at 1x and 2x in the Field, the house; frames at 0.25x, 1x, 2x; the reporter's setup, Default / High / 4x; Vulkan Default / High).
🤖 Generated with Claude Code