Repository navigation
Rendering: DoF spiral turned per texel, one draw-count rule, far world text without shimmer (#881, #882, #892) - #975
Merged
Merged
Conversation
The gather read the same 32 places on a golden-angle spiral at every texel, so the blur of a wide disc showed the spiral itself. It now turns the spiral by an interleaved-gradient noise of the texel (the occlusion's dither, counted from the same corner on both renderers) and takes 48 taps; the radii stay where they were, so a texel in focus still takes nothing. test_gpu_dof gains an edge under the widest disc: its rows must differ and average to an even disc's blur within 0.015. Turned: 0.0077. Main's gather (32, unturned) is 0.029 out and fails; 48 unturned is 0.026 and fails. M6, against main: frames_against 81 frames, only the four depth of field frames differ (the change), the rest byte-identical (clouds, city within #793/#794). Parity GL vs Vulkan: 1x 0 of 147,456 channels on both focuses (as main), 4x 2,115 / 1,969 (main 1,991 / 1,989). Cost at the widest disc, zombie_city 1280x720: Vulkan 0.27 ms (main 0.12), OpenGL 0.35 ms (main 0.18); off by default, no budget pins it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er (#882) The two renderers counted different screen passes: OpenGL the reflections' pass, the temporal pass and the HUD; Vulkan the depth's resolve and the occlusion's pass (drawn inside the scene, before its count is read). So the counts disagreed by whichever passes were on: test_backend_parity's scene, 7 with nothing on, was GL 7 / VK 9 with the occlusion, 8 / 8 with TAA, 8 / 8 with SSR, 7 / 8 with DoF, 9 / 9 with all four. zombie_street's 88 on both was two different 88s. The rule vkframe already stated, applied to all: a quoted pass (vkframe.draw_quoted_with) no longer counts, and the counted/restore guards around it go (dead for the post chain); OpenGL's SSR, TAA and HUD draws no longer count. docs/rendering.md says what the count is. test_backend_parity: each of SSAO, TAA, SSR, DoF on and all four on holds the count with none (7) on both renderers, and the renderers to each other; the old renderers fail 5 of those checks. Budgets, draw_calls only (M6, 320x180, as ci_scenes runs them): zombie_street 88 -> 87 on both; zombie_city shadow-map budgets (12 m and 28 m near bands) 696 -> 694. The RTX 4070 Ti ray-traced city budgets (285) need recording again on that card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…892) A far, small label sized in the world's units read its glyph field at one point a pixel, many atlas texels apart, so it found a stroke one frame and the gap beside it the next and shimmered as the camera moved. Where a pixel spans more than a texel (dFdx/dFdy of the atlas place), the shader now covers it by the mean of a grid of reads over its footprint, up to 4 by 4, faded in from one texel a pixel to two. No mips, as #892 (Nic 876-3) has it: the two APIs' mip filters would part the frames. The grid is symmetric about the pixel's centre, so GL's y-up turns it into itself; neither atlas changed (#894 untouched). test_world_text moves the camera past a label 5 and one 9 px to the em for 24 frames and holds each frame's coverage (read in the scene's light) within 2% of its mean and of the frame before, both renderers, and their frames to each other. Main: 4.2% / 6.7% (far) and 1.9% / 3.6% (4 checks fail); now 1.3% / 1.5% and 0.74% / 0.76% at 4x and 1x, the renderers 0 channels apart; the suite's other GL/VK comparisons are main's (108, 51 channels). frames_against: no parity frame moved by it (the four DoF frames of #881 only). bench_world_text: 500 labels within noise of main. 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.
Three rendering fixes, one commit each, each with a
changes/2026-11-05-*.mdentry. No motion code is touched.#881 Depth of field
dof_gatherread the same 32 spiral taps at every texel, so the spiral's own pattern showed in the blur. The spiral is now turned at each texel by interleaved-gradient noise (the occlusion'sdither, counted from the same corner on both back ends), 48 taps; radii unchanged, so an in-focus texel still takes nothing. New CPU check intest_gpu_dof: a hard edge under the widest disc, rows along the edge must differ and their mean must match an even disc's blur within 0.015 (new code 0.0077 off; main's gather 0.029 off and fails; 48 taps without the turn 0.026 off and fails).frames_againstmain: only the four DoF frames differ, the other 77 byte-identical. GL/Vulkan parity at 1x: 0 channels (as main). Cost at disc 100, zombie_city 1280x720: Vulkan 0.27 ms (main 0.12), OpenGL 0.35 ms (0.18); DoF is off by default, no budget pins it.#882 Draw counts
The back ends counted different full-screen passes (OpenGL: SSR, TAA, HUD; Vulkan: depth resolve, SSAO). The rule
vkframealready stated now applies everywhere: a screen pass is never a draw.draw_quoted_withno longer counts (six save/restore guards removed); OpenGL's SSR/TAA/HUD increments removed.docs/rendering.mdgains "What a frame's draw count is".test_backend_parityturns on SSAO, TAA, SSR, DoF one at a time and together: every case must equal the no-post count of 7 on both back ends and match across them (5 checks fail on main). Budgets: zombie_streetdraw_calls88 → 87 both back ends; zombie_city shadow-map 696 → 694 (measured on the M6 at 320x180 asci_scenesdoes). Not done: the RTX 4070 Ti ray-tracedzombie_city*.vulkan.budget.json(285) should now read 284 (283 with ray-traced occlusion off) and need re-recording on that card withae3d_bench --record; noted inci_scenes.shand the changes entry.#892 World text shimmer
Per the issue (no mips, keep GL and Vulkan identical), the fix is in the shader only: where a pixel spans more than one atlas texel, the pixel is covered by the mean of a grid of field reads over its footprint (up to 4x4), faded in between one and two texels per pixel; symmetric about the pixel centre so OpenGL's upward y maps onto itself. Neither atlas changed; #894 untouched.
test_world_textslides the camera past a 5 px/em and a 9 px/em label for 24 frames: coverage within 2% of its mean and of the previous frame on both back ends, back ends agreeing. Main: 4.2%/6.7% and 1.9%/3.6% (4 checks fail); branch 1.3%/1.5% and 0.74%/0.76% at 4x and 1x; moving frames 0 channels apart on the M6, 9 on Intel.bench_world_textwithin noise.Verification
generate_shaders --checkcurrent (glslang 16.6.0);msl_check60 files;test_quoted_hashes,test_vk_msl,test_gpu_msl,test_gpu_letteringpass; GLSL fixtures regenerated.validate.shwith DoF at its widest: 0 for zombie_city and street_life../ci.sh: all pass except 4 "exported fixtures stale" checks (tests/fixtures/exported,resources/blender/{showcase,zombie_street,car}), whose only difference is the Blender version string (5.2.2 committed, 5.2.3 installed here); main fails the same way on this Mac. A re-export is a separate commit, not in this PR. 8 hardware skips (DLSS, ray queries, one leak report).🤖 Generated with Claude Code