WIP: feat(vk): ray-traced ambient occlusion, sun shadows, global illumination and reflections #727

Draft
winterelfeas wants to merge 20 commits from winterelfeas/Longshot:feat/ray-tracing into main
First-time contributor

Type: feat · Risk: medium · Tested on: Windows 11, RTX 5090 · Needs: AMD (RDNA 2+), Intel Arc, an older NVIDIA RTX card, Linux

Why

The game lights its world with tricks made for a handheld: a screen-space ambient occlusion that only sees what is on screen, sun shadows from low-resolution cascades that fade out in the distance, light baked once per object that never bounces off what is near it, and reflections that show a fixed environment picture instead of the scene. On a PC with a ray tracing GPU, all four can be traced against the real scene instead. This PR adds that, as four options in the Graphics tab, all off by default, so nothing changes for anyone who doesn't turn them on.

No issue asks for it (searched the tracker for ray tracing, reflections, AO and shadows: #601 and #603 are about the game's own character shadows, which this leaves as they are).

What changed

Ray tracing over the game's own frame. The renderer keeps the scene's geometry as Vulkan acceleration structures, built from the game's own vertex and index buffers, and each effect goes in where the game computes the same thing: AO and sun shadows into the game's screen-space light mask, the bounce light and the reflections inside the game's own lighting programs, by a SPIR-V patch of their fragment modules when they are made. The game's renderer is otherwise left as it is; with every row off nothing here runs (rt::mode() is one load). docs/ray-tracing.md describes each part, what it found in the game's frame, the requirements, the cost and the switches.

  • Interface: gpu/vk/vk_rt.h. The parts are told of each draw before and after it is recorded (vk_draw.cpp), of each dispatch, and of each present (vk_replay.cpp).
  • Scene (vk_rt_scene.cpp, vk_rt_omm.h, shaders/rt_scene_*): bottom levels from the depth pre-pass's draws, skinned characters (re-skinned in a compute pass), terrain patches, and the mesh-shader foliage (in the default native mode by running the compute fallback for capture only, every 4th frame per draw; RX_VK_RT_NATIVE_MESH=0 turns that off), and the cascade draws placed by their own vertex stage (the Lost Woods' falling leaves) captured by transform feedback where the device has VK_EXT_transform_feedback (RX_VK_RT_XFB=0 turns that off), and static models the camera has drawn kept as casters while out of view, so interiors keep their roofs (RX_VK_RT_REMEMBER=0 turns that off); a top level a frame with instance masks by kind (opaque, cutout, skinned, foliage, out-of-view casters, cascade-only blockers). Alpha-tested cards are cut by opacity micromaps from the game's own alpha where the device has VK_EXT_opacity_micromap; hit normals by position fetch. The game's pools become build inputs only with ray tracing on (pool_usage() in vk_memory.cpp). Device extensions and features are asked for only when a row or RX_VK_RT is on (vk_main.cpp).
  • AO and sun shadows (vk_rt_mask.cpp, shaders/rt_ao_*): after the game's combine writes its light mask (found by what it does, since it is another program in each kind of place), a trace, a temporal pass and a filter write the mask's AO and sun channels. The traced sun shadow takes the place of the game's (RX_VK_RT_SUN_KEEP=1 adds it to the game's instead, for debugging), and a gate keeps the game's own where the rays would take away sunlight the game shows. Every caster's sun shadow is traced, in both mesh modes: the world, the characters and the plants; past 60 m the traced shadow hands over to the game's (fully by 120 m). The gate is a safety net for a broken structure only.
  • Global illumination (vk_rt_gi.cpp, rt_gi_spirv.h, shaders/rt_gi_*): one diffuse bounce at half resolution, one ray a pixel, from the previous frame's lit colour, accumulated and filtered, added in the lit programs' ambient term.
  • Reflections (vk_rt_refl.cpp, rt_refl_spirv.h, shaders/rt_refl_*): the lit programs' specular environment lookup replaced by a traced reflection along the same vector, on water first, and on smooth metal and glass by their roughness; a march against the previous frame's colour, then the structure for what is off screen.
  • Program cache (vk_progcache.cpp, vk_shader.h): the GI and reflection patches are applied when a module is made, so the cache's records are the game's own, unchanged, and its stamp does not move.
  • Replay: par_threads() turns parallel replay off while ray tracing is on: its parts record in the stream's order (the frame's captures, the structure's builds), and the log says so.
  • Menu (vk_menu.cpp, vk_menu.h): a Ray tracing section at the end of the Graphics tab, four Off/On rows, read once at the start (restart rows, outside the quality presets). RX_VK_RT=<bits> goes over them.
  • Checks: tests/test_menu_sections.py and the README's table know the rows; tests/test_recorder_sync.py knows the structure builds (with a control case); the program cache, import and fallback pipeline fixtures stand in for the new hooks; gpu/vk/tests/rt_*_spirv_test.cpp patch modules for spirv-val.

Measurements

Verdict: pending. The in-game A/B (main against this PR with the rows off and with all four on, two interleaved runs each after a warm-up) will be run once on the PC below when the four parts are done; its numbers, log lines and screenshots will follow in a comment and here. Until then this PR stays WIP.

Hardware: Windows 11 Home (26200), RTX 5090 32 GB, driver 621.01, Ryzen 7 9800X3D, 64 GB
Scene: Kokiri Forest by day, child Link standing at the save's spot; headless (longshot_ctl.py launch, offscreen presents at 1920x1080), sound off, the test profile's settings, below normal priority
Method: the log's vk: N presents, X fps lines, 90 s after 30 s standing, each run's median; two interleaved runs per side after a warm-up run (RX_VK_LOAD=create, RX_VK_PRECOMPILE=0); the median of the runs
Baseline: main @ e090cc4, this PR's base before its rebase onto 5274fb7, and the PR's renderer at 49260a6 (the same ray tracing code as the rebased branch; main's 4 new commits change none of it): measured before the rebase.
How to reproduce: python -I scripts/longshot_ctl.py launch <game> --profile test --save <a save in Kokiri Forest> --env RX_VK_RT=0 (then =15), and read the fps lines

Before: main @ e090cc4 After, RX_VK_RT=0: this PR @ 49260a6 After, RX_VK_RT=15: this PR @ 49260a6
fps, median of the runs pending pending pending

GPU time of each part, from docs/ray-tracing.md (RTX 5090, 4K scene with DLAA, RX_VK_PASS_TIMING=1), measured on the parts' branches before they were joined here:

Part GPU time a frame Where
The structure 0.4-0.6 ms Kokiri Forest
AO and sun shadows 1.2-1.4 ms (about 2 ms with RX_VK_MESH_SHADERS=compute) Kokiri Forest
GI 0.94 ms of passes (1 ray, 3 x 3 filter; was 1.4 ms with 2 rays and 5 x 5) Kokiri Forest
Reflections +1.6-1.8 ms; +0.8-1.0 ms Lake Hylia; Kakariko Village and the Market
RX_VK_MESH_SHADERS=compute itself (for leaf and grass shadows) +1.3 ms Kokiri Forest

Quality, on those branches: the structure agrees with the game's depth on 90-99% of the screen across eight areas; with the sun gate the rays keep 98-100% of the game's sunlit screen in Kokiri Forest and 92-96% in the gorge; GI adds 11% to Kokiri Forest's picture and 17-30% inside the Deku Tree, never darkening; at night (22:00) the traced shadows follow the moon's cascades and GI adds 12-22% with nothing darker; reflections reach ten water surfaces, the armour and the Market's shop windows.

Flags and settings

Four new menu rows (ini keys from their names) and the RX_VK_RT switch family; all off as shipped.

Flag What it is Before this PR After this PR Effect Helps / doesn't help / untested Recommendation
Ray-traced ambient occlusion (Graphics row) AO traced in place of the game's SSAO - Off contact and corner shading from the scene, not the screen helps on RTX 5090; untested elsewhere off by default until other GPUs are tested
Ray-traced sun shadows (Graphics row) sun shadows traced into the light mask, the cascades kept where the rays would lose light - Off sharp, far-reaching sun shadows helps on RTX 5090; leaf shadows need RX_VK_MESH_SHADERS=compute off by default
Ray-traced global illumination (Graphics row) one diffuse bounce added to the baked ambient - Off coloured light in the shade helps on RTX 5090; untested elsewhere off by default
Ray-traced reflections (Graphics row) traced reflections in place of the environment lookup - Off water and smooth surfaces reflect the scene helps on RTX 5090; some water (Kakariko's pond, the moat, the river) not reached yet off by default
RX_VK_RT=<bits> the four for one run: 1 AO, 2 sun shadows, 4 GI, 8 reflections - unset (the rows) over the rows testing for testing and A/B runs
RX_VK_RT_*: RX_VK_RT_AO_FALLOFF, RX_VK_RT_AO_FAR, RX_VK_RT_AO_MARCH_RADIUS, RX_VK_RT_AO_MARCH_WEIGHT, RX_VK_RT_AO_MASK, RX_VK_RT_AO_POWER, RX_VK_RT_AO_QUARTER, RX_VK_RT_AO_RADIUS, RX_VK_RT_AO_RAYS, RX_VK_RT_AO_STEPS, RX_VK_RT_AO_STRENGTH, RX_VK_RT_AO_THICKNESS, RX_VK_RT_ARENA_MB, RX_VK_RT_BACK, RX_VK_RT_BIAS, RX_VK_RT_BLAS_MB, RX_VK_RT_BUILD_TRIS, RX_VK_RT_CASCADES, RX_VK_RT_CASCADE_MESH, RX_VK_RT_CHANNELS, RX_VK_RT_CLAMP, RX_VK_RT_CONTACT, RX_VK_RT_CONTACT_STEPS, RX_VK_RT_CONTACT_THICKNESS, RX_VK_RT_CUT, RX_VK_RT_CUTOUT, RX_VK_RT_CUTOUT_COVER, RX_VK_RT_CUT_LEVEL, RX_VK_RT_DEBUG, RX_VK_RT_DEBUG_FILE, RX_VK_RT_DEBUG_GAIN, RX_VK_RT_DEBUG_MASK, RX_VK_RT_DEBUG_POINT, RX_VK_RT_DEBUG_VIEW, RX_VK_RT_FETCH, RX_VK_RT_FILTER, RX_VK_RT_FORCE, RX_VK_RT_GI_ADD, RX_VK_RT_GI_AREA, RX_VK_RT_GI_CACHE, RX_VK_RT_GI_CLAMP, RX_VK_RT_GI_CTL, RX_VK_RT_GI_FALLBACK, RX_VK_RT_GI_FILTER, RX_VK_RT_GI_FORGET, RX_VK_RT_GI_HISTORY, RX_VK_RT_GI_LENGTH, RX_VK_RT_GI_NEAR, RX_VK_RT_GI_OCCLUDE, RX_VK_RT_GI_PROBE, RX_VK_RT_GI_RAYS, RX_VK_RT_GI_REGION, RX_VK_RT_GI_REPLACE, RX_VK_RT_GI_STEPS, RX_VK_RT_GI_STRENGTH, RX_VK_RT_GI_THICKNESS, RX_VK_RT_GI_TRACE, RX_VK_RT_GI_WAY, RX_VK_RT_GROUND_MATERIAL, RX_VK_RT_HISTORY, RX_VK_RT_HISTORY_TOL, RX_VK_RT_HOLES, RX_VK_RT_HYBRID, RX_VK_RT_KEEP, RX_VK_RT_LEAF_MIN, RX_VK_RT_LEAF_MIN_FAR, RX_VK_RT_LIFT, RX_VK_RT_MARCH, RX_VK_RT_MESH, RX_VK_RT_MESH_EVERY, RX_VK_RT_MESH_MB, RX_VK_RT_MESH_TEST, RX_VK_RT_OMM, RX_VK_RT_OMM_ALPHA, RX_VK_RT_OMM_LEVEL, RX_VK_RT_PALETTE_COPY, RX_VK_RT_PROBE, RX_VK_RT_REFL_AMBIENT, RX_VK_RT_REFL_CLAMP, RX_VK_RT_REFL_CONE, RX_VK_RT_REFL_CTL, RX_VK_RT_REFL_DITHER, RX_VK_RT_REFL_LENGTH, RX_VK_RT_REFL_MARCH_ALL, RX_VK_RT_REFL_MASK, RX_VK_RT_REFL_METAL_RAYS, RX_VK_RT_REFL_METAL_ROUGH, RX_VK_RT_REFL_PROBE, RX_VK_RT_REFL_RAYS, RX_VK_RT_REFL_RES, RX_VK_RT_REFL_ROUGH, RX_VK_RT_REFL_STEPS, RX_VK_RT_REFL_STRENGTH, RX_VK_RT_REFL_STRIDE, RX_VK_RT_REFL_SUN, RX_VK_RT_REFL_THICKNESS, RX_VK_RT_SCENE_EARLY, RX_VK_RT_SCENE_LOG, RX_VK_RT_SCENE_SPV, RX_VK_RT_SCRATCH_MB, RX_VK_RT_SHADOW_BIAS, RX_VK_RT_SHADOW_DIST, RX_VK_RT_SHADOW_MASK, RX_VK_RT_SHADOW_RAYS, RX_VK_RT_SHADOW_SLOPE, RX_VK_RT_SUN_CUTOUT, RX_VK_RT_SUN_GATE, RX_VK_RT_SUN_GATE_FAR, RX_VK_RT_SUN_LOG, RX_VK_RT_SUN_SOFT, RX_VK_RT_TERRAIN_MASK, RX_VK_RT_TUNE each part's tuning, memory budgets and debug pictures (docs/ray-tracing.md; the head of each part's .cpp file) - unset - (unset: the defaults the rows use) testing only leave unset

Documented in docs/ray-tracing.md, in docs/development.md ("The GPU") and in the README's option table.

Screenshots

The same spot and frame, the feature off (left) and on (right), 4K on an RTX 5090, one part on at a time, from the parts' development builds (this PR's code; the sun shadow ones also carry the static shadow map's casters, still in testing). AO and reflections follow.

Sun shadows (RX_VK_RT=2 against 0): each clover leaf, grass blade and fence slat casts its own cut shadow where the game's maps give soft patches.

Sun shadows, Kakariko's gate: off left, on right

Sun shadows, Kakariko's fence: off left, on right

GI (RX_VK_RT=4 against 0): light bounced from lamps, doorways and lava into what the game leaves near black.

GI, a Kakariko house: off left, on right

GI, Link's house: off left, on right

GI, Dodongo's Cavern: off left, on right

Testing

Tested:

  • python -I -B tests/run_all.py on Windows, on this branch rebased onto main aa95d35 (after v3.0.0-rc.4) (llvm-mingw and the Vulkan SDK on PATH): 540 passed, 18 failed, 35 skipped. The same 18 fail on main aa95d35 on this PC (540 passed, 18 failed): test_appimage_player_build, test_cpm_discovery, test_cpp_preflight, test_crash_dialog, test_env_on, test_lift_cleanup_error, test_linux_preflight, test_make_game_cache, test_make_game_prepare, test_missing_nup, test_oot_state_tap, test_readback_late, test_tested_configurations, test_vk_pgo, test_vram_budget_row, test_walk_key, test_fpx_sticky, test_spawn_emit (missing tools here, Linux-only paths and CRLF output). test_dev_packs and test_finish_output failed once each under load on both sides and pass alone.
  • In the game, this PR's full build (make_game.py, before the rebase onto 5274fb7) on Windows 11, RTX 5090, 621.01: Kokiri Forest with the rows off and with all four on loads and plays, no device lost; the A/B comes at the end (Measurements).
  • On the parts' branches, over a night of runs on the v3.0.0-rc.3 base: Kokiri Forest, Lost Woods, Hyrule Field, Lake Hylia, Kakariko Village, the Market, Death Mountain Trail, the gorge and inside the Deku Tree, in both mesh shader modes.
  • scripts/check_guide_screenshots.py --review-sources: settings-graphics.png now also names vk_menu.cpp and vk_menu.h (main already names four other files for it). The new section is at the end of the Graphics tab, below Anisotropic filtering, far below what the image shows, so the image still matches; the review record is left for the documentation maintainer with main's four.

Not tested:

  • Any GPU other than an RTX 5090: AMD, Intel, older NVIDIA cards, and a GPU with ray queries but without VK_EXT_opacity_micromap (every part has a path without micromaps; none of them ran).
  • Linux: no Linux PC here; the renderer is meant to build there as it is (no Windows-only code added), not tried.
  • Frame generation and the other upscalers with the rows on (DLAA and the game's own upscaler only).
  • Areas past the first few hours of the game.

Must be tested:

  • linux (Test Farm): build, then the same as below, expecting the same (Test Farm: @Beanstalk build and ray tracing rows on, Linux)
  • linux, amd, radv (Test Farm): turn on the four Ray tracing rows, restart, play a few minutes in Kokiri Forest and at Lake Hylia, expecting no device lost and the log's vk: rt: lines saying the scene is kept as acceleration structures (Test Farm: @Beanstalk ray tracing rows on, Kokiri Forest and Lake Hylia, RDNA 2 or newer)
  • windows, intel arc (Test Farm): the same, expecting the same (Test Farm: @Beanstalk ray tracing rows on, Intel Arc)
  • windows, NVIDIA RTX 20 or 30 series (by hand or Test Farm): the same, and the frame rate with the rows on against off, expecting the cost to scale with the GPU
  • A GPU without ray tracing (any): the rows on, expecting the game to run as with them off, apart from AO and sun shadows marched against the depth buffer and GI against the depth buffer alone (by hand: the log's vk: rt: lines and the picture)

Risks

What could break: with the rows on: a device lost or a hang on a driver this was not run on; wrong shading where the patched lighting programs meet a program the patch did not expect (it only patches programs it recognises, and leaves the rest as they are); memory (about 365 MB of images for AO and sun shadows at 4K, plus the structures). With the rows off: nothing should change; the hooks are behind rt::on(), one load. Parallel replay is off while ray tracing is on, which costs CPU time on PCs that use it.

Turning it off: the four rows (off by default), or RX_VK_RT=0 for a run.

Compatibility: saves unchanged. longshot_options.ini gains four keys, written only when the menu saves. The shader and program caches are unchanged (the patch is applied when a module is made, after the cache); with GI or reflections on, the driver's pipeline cache builds the lit programs again on the first run. The vk ABI (MKWVK_API_VERSION) is unchanged. The builder's tools are unchanged.

Checklist

Everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description) of the status line's type.
  • Why gives the reason plainly and links the issues that fit (the tracker searched).
  • Measurements has a verdict, or one line saying why there is nothing to measure. (pending: measured once at the end, when the parts work)
  • Testing names what was tested, what wasn't, and what must still be tested, where and how.
  • Rebased on current main.
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named).
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

When it applies

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (pending)
  • Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value.
  • Screenshots of the same spot, captioned like the Measurements columns, for a change that shows on screen. (sun shadows and GI in Screenshots; AO and reflections to follow)
  • A file in docs/tested/ for each new measured run (format in docs/tested-configurations.md). (pending: with the measurements at the end)
  • The SPIR-V headers regenerated with glslang (a shader changed).
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows only: no Linux here; Test Farm asked under Must be tested)
  • Docs updated.

🤖 Generated with Claude Code

**Type:** feat · **Risk:** medium · **Tested on:** Windows 11, RTX 5090 · **Needs:** AMD (RDNA 2+), Intel Arc, an older NVIDIA RTX card, Linux ## Why The game lights its world with tricks made for a handheld: a screen-space ambient occlusion that only sees what is on screen, sun shadows from low-resolution cascades that fade out in the distance, light baked once per object that never bounces off what is near it, and reflections that show a fixed environment picture instead of the scene. On a PC with a ray tracing GPU, all four can be traced against the real scene instead. This PR adds that, as four options in the Graphics tab, all off by default, so nothing changes for anyone who doesn't turn them on. No issue asks for it (searched the tracker for ray tracing, reflections, AO and shadows: #601 and #603 are about the game's own character shadows, which this leaves as they are). ## What changed Ray tracing over the game's own frame. The renderer keeps the scene's geometry as Vulkan acceleration structures, built from the game's own vertex and index buffers, and each effect goes in where the game computes the same thing: AO and sun shadows into the game's screen-space light mask, the bounce light and the reflections inside the game's own lighting programs, by a SPIR-V patch of their fragment modules when they are made. The game's renderer is otherwise left as it is; with every row off nothing here runs (`rt::mode()` is one load). `docs/ray-tracing.md` describes each part, what it found in the game's frame, the requirements, the cost and the switches. - **Interface:** `gpu/vk/vk_rt.h`. The parts are told of each draw before and after it is recorded (`vk_draw.cpp`), of each dispatch, and of each present (`vk_replay.cpp`). - **Scene** (`vk_rt_scene.cpp`, `vk_rt_omm.h`, `shaders/rt_scene_*`): bottom levels from the depth pre-pass's draws, skinned characters (re-skinned in a compute pass), terrain patches, and the mesh-shader foliage (in the default native mode by running the compute fallback for capture only, every 4th frame per draw; `RX_VK_RT_NATIVE_MESH=0` turns that off), and the cascade draws placed by their own vertex stage (the Lost Woods' falling leaves) captured by transform feedback where the device has `VK_EXT_transform_feedback` (`RX_VK_RT_XFB=0` turns that off), and static models the camera has drawn kept as casters while out of view, so interiors keep their roofs (`RX_VK_RT_REMEMBER=0` turns that off); a top level a frame with instance masks by kind (opaque, cutout, skinned, foliage, out-of-view casters, cascade-only blockers). Alpha-tested cards are cut by opacity micromaps from the game's own alpha where the device has `VK_EXT_opacity_micromap`; hit normals by position fetch. The game's pools become build inputs only with ray tracing on (`pool_usage()` in `vk_memory.cpp`). Device extensions and features are asked for only when a row or `RX_VK_RT` is on (`vk_main.cpp`). - **AO and sun shadows** (`vk_rt_mask.cpp`, `shaders/rt_ao_*`): after the game's combine writes its light mask (found by what it does, since it is another program in each kind of place), a trace, a temporal pass and a filter write the mask's AO and sun channels. The traced sun shadow takes the place of the game's (`RX_VK_RT_SUN_KEEP=1` adds it to the game's instead, for debugging), and a gate keeps the game's own where the rays would take away sunlight the game shows. Every caster's sun shadow is traced, in both mesh modes: the world, the characters and the plants; past 60 m the traced shadow hands over to the game's (fully by 120 m). The gate is a safety net for a broken structure only. - **Global illumination** (`vk_rt_gi.cpp`, `rt_gi_spirv.h`, `shaders/rt_gi_*`): one diffuse bounce at half resolution, one ray a pixel, from the previous frame's lit colour, accumulated and filtered, added in the lit programs' ambient term. - **Reflections** (`vk_rt_refl.cpp`, `rt_refl_spirv.h`, `shaders/rt_refl_*`): the lit programs' specular environment lookup replaced by a traced reflection along the same vector, on water first, and on smooth metal and glass by their roughness; a march against the previous frame's colour, then the structure for what is off screen. - **Program cache** (`vk_progcache.cpp`, `vk_shader.h`): the GI and reflection patches are applied when a module is made, so the cache's records are the game's own, unchanged, and its stamp does not move. - **Replay:** `par_threads()` turns parallel replay off while ray tracing is on: its parts record in the stream's order (the frame's captures, the structure's builds), and the log says so. - **Menu** (`vk_menu.cpp`, `vk_menu.h`): a Ray tracing section at the end of the Graphics tab, four Off/On rows, read once at the start (restart rows, outside the quality presets). `RX_VK_RT=<bits>` goes over them. - **Checks:** `tests/test_menu_sections.py` and the README's table know the rows; `tests/test_recorder_sync.py` knows the structure builds (with a control case); the program cache, import and fallback pipeline fixtures stand in for the new hooks; `gpu/vk/tests/rt_*_spirv_test.cpp` patch modules for `spirv-val`. ## Measurements **Verdict:** pending. The in-game A/B (main against this PR with the rows off and with all four on, two interleaved runs each after a warm-up) will be run once on the PC below when the four parts are done; its numbers, log lines and screenshots will follow in a comment and here. Until then this PR stays WIP. Hardware: Windows 11 Home (26200), RTX 5090 32 GB, driver 621.01, Ryzen 7 9800X3D, 64 GB Scene: Kokiri Forest by day, child Link standing at the save's spot; headless (`longshot_ctl.py launch`, offscreen presents at 1920x1080), sound off, the test profile's settings, below normal priority Method: the log's `vk: N presents, X fps` lines, 90 s after 30 s standing, each run's median; two interleaved runs per side after a warm-up run (`RX_VK_LOAD=create`, `RX_VK_PRECOMPILE=0`); the median of the runs Baseline: main @ e090cc4, this PR's base before its rebase onto 5274fb7, and the PR's renderer at 49260a6 (the same ray tracing code as the rebased branch; main's 4 new commits change none of it): measured before the rebase. How to reproduce: `python -I scripts/longshot_ctl.py launch <game> --profile test --save <a save in Kokiri Forest> --env RX_VK_RT=0` (then `=15`), and read the fps lines | | Before: main @ e090cc4 | After, RX_VK_RT=0: this PR @ 49260a6 | After, RX_VK_RT=15: this PR @ 49260a6 | |---|---|---|---| | fps, median of the runs | pending | pending | pending | GPU time of each part, from `docs/ray-tracing.md` (RTX 5090, 4K scene with DLAA, `RX_VK_PASS_TIMING=1`), measured on the parts' branches before they were joined here: | Part | GPU time a frame | Where | |---|---|---| | The structure | 0.4-0.6 ms | Kokiri Forest | | AO and sun shadows | 1.2-1.4 ms (about 2 ms with `RX_VK_MESH_SHADERS=compute`) | Kokiri Forest | | GI | 0.94 ms of passes (1 ray, 3 x 3 filter; was 1.4 ms with 2 rays and 5 x 5) | Kokiri Forest | | Reflections | +1.6-1.8 ms; +0.8-1.0 ms | Lake Hylia; Kakariko Village and the Market | | `RX_VK_MESH_SHADERS=compute` itself (for leaf and grass shadows) | +1.3 ms | Kokiri Forest | Quality, on those branches: the structure agrees with the game's depth on 90-99% of the screen across eight areas; with the sun gate the rays keep 98-100% of the game's sunlit screen in Kokiri Forest and 92-96% in the gorge; GI adds 11% to Kokiri Forest's picture and 17-30% inside the Deku Tree, never darkening; at night (22:00) the traced shadows follow the moon's cascades and GI adds 12-22% with nothing darker; reflections reach ten water surfaces, the armour and the Market's shop windows. ### Flags and settings Four new menu rows (ini keys from their names) and the `RX_VK_RT` switch family; all off as shipped. | Flag | What it is | Before this PR | After this PR | Effect | Helps / doesn't help / untested | Recommendation | |---|---|---|---|---|---|---| | Ray-traced ambient occlusion (Graphics row) | AO traced in place of the game's SSAO | - | Off | contact and corner shading from the scene, not the screen | helps on RTX 5090; untested elsewhere | off by default until other GPUs are tested | | Ray-traced sun shadows (Graphics row) | sun shadows traced into the light mask, the cascades kept where the rays would lose light | - | Off | sharp, far-reaching sun shadows | helps on RTX 5090; leaf shadows need `RX_VK_MESH_SHADERS=compute` | off by default | | Ray-traced global illumination (Graphics row) | one diffuse bounce added to the baked ambient | - | Off | coloured light in the shade | helps on RTX 5090; untested elsewhere | off by default | | Ray-traced reflections (Graphics row) | traced reflections in place of the environment lookup | - | Off | water and smooth surfaces reflect the scene | helps on RTX 5090; some water (Kakariko's pond, the moat, the river) not reached yet | off by default | | `RX_VK_RT=<bits>` | the four for one run: 1 AO, 2 sun shadows, 4 GI, 8 reflections | - | unset (the rows) | over the rows | testing | for testing and A/B runs | | `RX_VK_RT_*`: `RX_VK_RT_AO_FALLOFF`, `RX_VK_RT_AO_FAR`, `RX_VK_RT_AO_MARCH_RADIUS`, `RX_VK_RT_AO_MARCH_WEIGHT`, `RX_VK_RT_AO_MASK`, `RX_VK_RT_AO_POWER`, `RX_VK_RT_AO_QUARTER`, `RX_VK_RT_AO_RADIUS`, `RX_VK_RT_AO_RAYS`, `RX_VK_RT_AO_STEPS`, `RX_VK_RT_AO_STRENGTH`, `RX_VK_RT_AO_THICKNESS`, `RX_VK_RT_ARENA_MB`, `RX_VK_RT_BACK`, `RX_VK_RT_BIAS`, `RX_VK_RT_BLAS_MB`, `RX_VK_RT_BUILD_TRIS`, `RX_VK_RT_CASCADES`, `RX_VK_RT_CASCADE_MESH`, `RX_VK_RT_CHANNELS`, `RX_VK_RT_CLAMP`, `RX_VK_RT_CONTACT`, `RX_VK_RT_CONTACT_STEPS`, `RX_VK_RT_CONTACT_THICKNESS`, `RX_VK_RT_CUT`, `RX_VK_RT_CUTOUT`, `RX_VK_RT_CUTOUT_COVER`, `RX_VK_RT_CUT_LEVEL`, `RX_VK_RT_DEBUG`, `RX_VK_RT_DEBUG_FILE`, `RX_VK_RT_DEBUG_GAIN`, `RX_VK_RT_DEBUG_MASK`, `RX_VK_RT_DEBUG_POINT`, `RX_VK_RT_DEBUG_VIEW`, `RX_VK_RT_FETCH`, `RX_VK_RT_FILTER`, `RX_VK_RT_FORCE`, `RX_VK_RT_GI_ADD`, `RX_VK_RT_GI_AREA`, `RX_VK_RT_GI_CACHE`, `RX_VK_RT_GI_CLAMP`, `RX_VK_RT_GI_CTL`, `RX_VK_RT_GI_FALLBACK`, `RX_VK_RT_GI_FILTER`, `RX_VK_RT_GI_FORGET`, `RX_VK_RT_GI_HISTORY`, `RX_VK_RT_GI_LENGTH`, `RX_VK_RT_GI_NEAR`, `RX_VK_RT_GI_OCCLUDE`, `RX_VK_RT_GI_PROBE`, `RX_VK_RT_GI_RAYS`, `RX_VK_RT_GI_REGION`, `RX_VK_RT_GI_REPLACE`, `RX_VK_RT_GI_STEPS`, `RX_VK_RT_GI_STRENGTH`, `RX_VK_RT_GI_THICKNESS`, `RX_VK_RT_GI_TRACE`, `RX_VK_RT_GI_WAY`, `RX_VK_RT_GROUND_MATERIAL`, `RX_VK_RT_HISTORY`, `RX_VK_RT_HISTORY_TOL`, `RX_VK_RT_HOLES`, `RX_VK_RT_HYBRID`, `RX_VK_RT_KEEP`, `RX_VK_RT_LEAF_MIN`, `RX_VK_RT_LEAF_MIN_FAR`, `RX_VK_RT_LIFT`, `RX_VK_RT_MARCH`, `RX_VK_RT_MESH`, `RX_VK_RT_MESH_EVERY`, `RX_VK_RT_MESH_MB`, `RX_VK_RT_MESH_TEST`, `RX_VK_RT_OMM`, `RX_VK_RT_OMM_ALPHA`, `RX_VK_RT_OMM_LEVEL`, `RX_VK_RT_PALETTE_COPY`, `RX_VK_RT_PROBE`, `RX_VK_RT_REFL_AMBIENT`, `RX_VK_RT_REFL_CLAMP`, `RX_VK_RT_REFL_CONE`, `RX_VK_RT_REFL_CTL`, `RX_VK_RT_REFL_DITHER`, `RX_VK_RT_REFL_LENGTH`, `RX_VK_RT_REFL_MARCH_ALL`, `RX_VK_RT_REFL_MASK`, `RX_VK_RT_REFL_METAL_RAYS`, `RX_VK_RT_REFL_METAL_ROUGH`, `RX_VK_RT_REFL_PROBE`, `RX_VK_RT_REFL_RAYS`, `RX_VK_RT_REFL_RES`, `RX_VK_RT_REFL_ROUGH`, `RX_VK_RT_REFL_STEPS`, `RX_VK_RT_REFL_STRENGTH`, `RX_VK_RT_REFL_STRIDE`, `RX_VK_RT_REFL_SUN`, `RX_VK_RT_REFL_THICKNESS`, `RX_VK_RT_SCENE_EARLY`, `RX_VK_RT_SCENE_LOG`, `RX_VK_RT_SCENE_SPV`, `RX_VK_RT_SCRATCH_MB`, `RX_VK_RT_SHADOW_BIAS`, `RX_VK_RT_SHADOW_DIST`, `RX_VK_RT_SHADOW_MASK`, `RX_VK_RT_SHADOW_RAYS`, `RX_VK_RT_SHADOW_SLOPE`, `RX_VK_RT_SUN_CUTOUT`, `RX_VK_RT_SUN_GATE`, `RX_VK_RT_SUN_GATE_FAR`, `RX_VK_RT_SUN_LOG`, `RX_VK_RT_SUN_SOFT`, `RX_VK_RT_TERRAIN_MASK`, `RX_VK_RT_TUNE` | each part's tuning, memory budgets and debug pictures (`docs/ray-tracing.md`; the head of each part's `.cpp` file) | - | unset | - (unset: the defaults the rows use) | testing only | leave unset | Documented in `docs/ray-tracing.md`, in `docs/development.md` ("The GPU") and in the README's option table. ## Screenshots The same spot and frame, the feature off (left) and on (right), 4K on an RTX 5090, one part on at a time, from the parts' development builds (this PR's code; the sun shadow ones also carry the static shadow map's casters, still in testing). AO and reflections follow. **Sun shadows** (`RX_VK_RT=2` against 0): each clover leaf, grass blade and fence slat casts its own cut shadow where the game's maps give soft patches. ![Sun shadows, Kakariko's gate: off left, on right](https://git.magicbean.dev/attachments/df1860c1-0485-4337-8d43-0f0632241b11) ![Sun shadows, Kakariko's fence: off left, on right](https://git.magicbean.dev/attachments/9376dd86-34d3-417c-89cf-dc850181d063) **GI** (`RX_VK_RT=4` against 0): light bounced from lamps, doorways and lava into what the game leaves near black. ![GI, a Kakariko house: off left, on right](https://git.magicbean.dev/attachments/4d697f53-ecab-4dfa-81ed-4fed83a7e2a4) ![GI, Link's house: off left, on right](https://git.magicbean.dev/attachments/5ef7dee5-51b7-4f95-80a7-4af325efccf3) ![GI, Dodongo's Cavern: off left, on right](https://git.magicbean.dev/attachments/fbbc8221-5675-47c9-bb21-57b42a412ea4) ## Testing **Tested:** - `python -I -B tests/run_all.py` on Windows, on this branch rebased onto main aa95d35 (after v3.0.0-rc.4) (llvm-mingw and the Vulkan SDK on PATH): 540 passed, 18 failed, 35 skipped. The same 18 fail on main aa95d35 on this PC (540 passed, 18 failed): test_appimage_player_build, test_cpm_discovery, test_cpp_preflight, test_crash_dialog, test_env_on, test_lift_cleanup_error, test_linux_preflight, test_make_game_cache, test_make_game_prepare, test_missing_nup, test_oot_state_tap, test_readback_late, test_tested_configurations, test_vk_pgo, test_vram_budget_row, test_walk_key, test_fpx_sticky, test_spawn_emit (missing tools here, Linux-only paths and CRLF output). test_dev_packs and test_finish_output failed once each under load on both sides and pass alone. - In the game, this PR's full build (`make_game.py`, before the rebase onto 5274fb7) on Windows 11, RTX 5090, 621.01: Kokiri Forest with the rows off and with all four on loads and plays, no device lost; the A/B comes at the end (Measurements). - On the parts' branches, over a night of runs on the v3.0.0-rc.3 base: Kokiri Forest, Lost Woods, Hyrule Field, Lake Hylia, Kakariko Village, the Market, Death Mountain Trail, the gorge and inside the Deku Tree, in both mesh shader modes. - `scripts/check_guide_screenshots.py --review-sources`: `settings-graphics.png` now also names `vk_menu.cpp` and `vk_menu.h` (main already names four other files for it). The new section is at the end of the Graphics tab, below Anisotropic filtering, far below what the image shows, so the image still matches; the review record is left for the documentation maintainer with main's four. **Not tested:** - Any GPU other than an RTX 5090: AMD, Intel, older NVIDIA cards, and a GPU with ray queries but without `VK_EXT_opacity_micromap` (every part has a path without micromaps; none of them ran). - Linux: no Linux PC here; the renderer is meant to build there as it is (no Windows-only code added), not tried. - Frame generation and the other upscalers with the rows on (DLAA and the game's own upscaler only). - Areas past the first few hours of the game. **Must be tested:** - linux (Test Farm): build, then the same as below, expecting the same (Test Farm: @Beanstalk build and ray tracing rows on, Linux) - linux, amd, radv (Test Farm): turn on the four Ray tracing rows, restart, play a few minutes in Kokiri Forest and at Lake Hylia, expecting no device lost and the log's `vk: rt:` lines saying the scene is kept as acceleration structures (Test Farm: @Beanstalk ray tracing rows on, Kokiri Forest and Lake Hylia, RDNA 2 or newer) - windows, intel arc (Test Farm): the same, expecting the same (Test Farm: @Beanstalk ray tracing rows on, Intel Arc) - windows, NVIDIA RTX 20 or 30 series (by hand or Test Farm): the same, and the frame rate with the rows on against off, expecting the cost to scale with the GPU - A GPU without ray tracing (any): the rows on, expecting the game to run as with them off, apart from AO and sun shadows marched against the depth buffer and GI against the depth buffer alone (by hand: the log's `vk: rt:` lines and the picture) ## Risks **What could break:** with the rows on: a device lost or a hang on a driver this was not run on; wrong shading where the patched lighting programs meet a program the patch did not expect (it only patches programs it recognises, and leaves the rest as they are); memory (about 365 MB of images for AO and sun shadows at 4K, plus the structures). With the rows off: nothing should change; the hooks are behind `rt::on()`, one load. Parallel replay is off while ray tracing is on, which costs CPU time on PCs that use it. **Turning it off:** the four rows (off by default), or `RX_VK_RT=0` for a run. **Compatibility:** saves unchanged. `longshot_options.ini` gains four keys, written only when the menu saves. The shader and program caches are unchanged (the patch is applied when a module is made, after the cache); with GI or reflections on, the driver's pipeline cache builds the lit programs again on the first run. The vk ABI (`MKWVK_API_VERSION`) is unchanged. The builder's tools are unchanged. ## Checklist ### Everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`) of the status line's type. - [x] Why gives the reason plainly and links the issues that fit (the tracker searched). - [ ] Measurements has a verdict, or one line saying why there is nothing to measure. (pending: measured once at the end, when the parts work) - [x] Testing names what was tested, what wasn't, and what must still be tested, where and how. - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### When it applies - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [ ] Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (pending) - [x] Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value. - [ ] Screenshots of the same spot, captioned like the Measurements columns, for a change that shows on screen. (sun shadows and GI in Screenshots; AO and reflections to follow) - [ ] A file in `docs/tested/` for each new measured run (format in `docs/tested-configurations.md`). (pending: with the measurements at the end) - [x] The SPIR-V headers regenerated with glslang (a shader changed). - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows only: no Linux here; Test Farm asked under Must be tested) - [x] Docs updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Ported from the work on v3.0.0-rc.3 (rt-all 2ad17d6) onto main e090cc4.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Fable 5.2 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The checks test_drawn_page_map and test_recorder_sync now know the RT passes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The mask part's ray query trace declared VK_EXT_opacity_micromap's capability on every device: a second build without it
(rt_ao_trace_rq_plain) where the scene cuts no cards. docs/ray-tracing.md describes the four parts, their requirements,
cost and switches, and the comments point to it; docs/development.md's switch table names RX_VK_RT.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
fix(vk): the sun's coverage-weighted cards are RX_VK_RT_SUN_CUTOUT, no longer sharing RX_VK_RT_CUTOUT with the scene's cutout rule
Some checks failed
PR description / Description follows the template (pull_request_target) Has been cancelled
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
f7abe7e73a
Co-Authored-By: Claude Opus 5.5 <[email protected]>
feat(vk): the traced sun shadow is added to the game's instead of replacing it (RX_VK_RT_SUN_KEEP, default 1)
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 5s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
1ffa9e4b79
The rays alone miss casters the game's cascades and static map have: with native mesh shaders every plant (a mesh stage's output cannot be captured), 15 % of the Kokiri spawn's picture is game shadow the rays leave lit; with RX_VK_MESH_SHADERS=compute 5.8 %. The static map's channel now takes min(game, traced) under the sun gate, the cascades stay the game's in both modes. Same-frame 4K dumps, share of the picture, lost shadow / lost sun: native Kokiri 1.7 -> 0 % / 1.9 %; compute Kokiri 5.8 -> 0 % / 7.3 -> 7.7 %; gorge 1.1 -> 0 % (compute); Lake Hylia 0 % / 8.9 % (past the cascades' reach). RX_VK_RT_SUN_KEEP=0: as before. docs/ray-tracing.md describes it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

New commit 1ffa9e4: the traced sun shadow is now added to the game's instead of replacing it (RX_VK_RT_SUN_KEEP=1, the default; =0 is the previous behaviour).

Why: the rays alone miss casters the game's shadow maps have. With native mesh shaders the plants can't be captured into the acceleration structure, so 15 % of the Kokiri spawn's picture was game shadow the rays left lit (5.8 % with RX_VK_MESH_SHADERS=compute). The static map's channel now takes the darker of the game's value and the traced one under the sun gate; the cascades' channel stays the game's.

Measured on the same frames (4K dumps, RTX 5090), share of the picture, lost shadow / lost sun, before -> after: native Kokiri 1.7 -> 0 % / 1.9 %; compute Kokiri 5.8 -> 0 % / 7.3 -> 7.7 %; compute gorge exit 1.1 -> 0 % / 1.8 -> 2.1 %; native gorge 0 % / 0.9 % and Lake Hylia 0 % / 8.9 % unchanged (the far cliffs past the cascades' reach: being worked on). Also checked: RX_VK_RT_OMM=0 runs the plain (no micromap) ray-query shader with no errors.

Checks after the commit: tests/run_all.py 540 passed, 18 failed, the same 18 as main on this PC. docs/ray-tracing.md updated.

New commit 1ffa9e4: the traced sun shadow is now added to the game's instead of replacing it (`RX_VK_RT_SUN_KEEP=1`, the default; `=0` is the previous behaviour). Why: the rays alone miss casters the game's shadow maps have. With native mesh shaders the plants can't be captured into the acceleration structure, so 15 % of the Kokiri spawn's picture was game shadow the rays left lit (5.8 % with `RX_VK_MESH_SHADERS=compute`). The static map's channel now takes the darker of the game's value and the traced one under the sun gate; the cascades' channel stays the game's. Measured on the same frames (4K dumps, RTX 5090), share of the picture, lost shadow / lost sun, before -> after: native Kokiri 1.7 -> 0 % / 1.9 %; compute Kokiri 5.8 -> 0 % / 7.3 -> 7.7 %; compute gorge exit 1.1 -> 0 % / 1.8 -> 2.1 %; native gorge 0 % / 0.9 % and Lake Hylia 0 % / 8.9 % unchanged (the far cliffs past the cascades' reach: being worked on). Also checked: `RX_VK_RT_OMM=0` runs the plain (no micromap) ray-query shader with no errors. Checks after the commit: `tests/run_all.py` 540 passed, 18 failed, the same 18 as main on this PC. `docs/ray-tracing.md` updated.
feat(vk): the traced sun shadow takes the game's place by default; RX_VK_RT_SUN_KEEP=1 (added to the game's) is a debug switch
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
801b951e27
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

New commit 801b951: the traced sun shadow takes the place of the game's by default again. Adding it on top of the game's (RX_VK_RT_SUN_KEEP=1) is now only a debug switch, to see what the rays miss.

The goal is ray-traced sun shadows for every caster. What's missing for that in the default (native) mesh mode is the plants: their geometry comes from mesh shaders and isn't captured into the acceleration structure yet, so their shadows still come from the game's cascades (with RX_VK_MESH_SHADERS=compute they are traced). Capturing them in the native mode is what's being worked on next.

New commit 801b951: the traced sun shadow takes the place of the game's by default again. Adding it on top of the game's (`RX_VK_RT_SUN_KEEP=1`) is now only a debug switch, to see what the rays miss. The goal is ray-traced sun shadows for every caster. What's missing for that in the default (native) mesh mode is the plants: their geometry comes from mesh shaders and isn't captured into the acceleration structure yet, so their shadows still come from the game's cascades (with `RX_VK_MESH_SHADERS=compute` they are traced). Capturing them in the native mode is what's being worked on next.
Author
First-time contributor

New commit 6228330: the mesh-shader plants (grass, ferns, flowers, tree leaves) are now in the ray tracing structure in the default native mesh mode, not only with RX_VK_MESH_SHADERS=compute.

How: after a native task/mesh draw of the depth pre-pass or a sun cascade whose bottom level is due (every 4th frame per draw, RX_VK_RT_MESH_EVERY), draw() runs once more with the program's compute fallback variant, for capture only: its task and mesh stages write the records the bottom level is built from, nothing is drawn, and the cards are cut by opacity micromaps as in compute mode. RX_VK_RT_NATIVE_MESH=0 turns it off. The capture helpers sit before writes_memory() in vk_draw.cpp, and tests/test_draw_side_effects.py stubs the two calls the readiness block makes.

Kokiri Forest, native, RTX 5090: leaves and grass in the structure, 23 mesh draws a frame, about a quarter captured each frame, none left out; no device lost, no validation line. A first uncapped sample with the capture: median 320 fps, 1.8 ms GPU; the comparison against native without capture and compute mode is running. The first native run in an area compiles the fallback variants (a slow first minute).

Next: the sun shadow pass uses the captured plants in the native mode too, so every sun shadow is traced. Checks after the commit: tests/run_all.py 540 passed, 18 failed, the same 18 as main on this PC.

New commit 6228330: the mesh-shader plants (grass, ferns, flowers, tree leaves) are now in the ray tracing structure in the default native mesh mode, not only with `RX_VK_MESH_SHADERS=compute`. How: after a native task/mesh draw of the depth pre-pass or a sun cascade whose bottom level is due (every 4th frame per draw, `RX_VK_RT_MESH_EVERY`), `draw()` runs once more with the program's compute fallback variant, for capture only: its task and mesh stages write the records the bottom level is built from, nothing is drawn, and the cards are cut by opacity micromaps as in compute mode. `RX_VK_RT_NATIVE_MESH=0` turns it off. The capture helpers sit before `writes_memory()` in `vk_draw.cpp`, and `tests/test_draw_side_effects.py` stubs the two calls the readiness block makes. Kokiri Forest, native, RTX 5090: leaves and grass in the structure, 23 mesh draws a frame, about a quarter captured each frame, none left out; no device lost, no validation line. A first uncapped sample with the capture: median 320 fps, 1.8 ms GPU; the comparison against native without capture and compute mode is running. The first native run in an area compiles the fallback variants (a slow first minute). Next: the sun shadow pass uses the captured plants in the native mode too, so every sun shadow is traced. Checks after the commit: `tests/run_all.py` 540 passed, 18 failed, the same 18 as main on this PC.
feat(vk): mesh-shader foliage in the ray tracing structure with native mesh shaders
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 13s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
6228330faa
After each native task/mesh draw of the pre-pass or a sun cascade whose bottom level is due (RX_VK_RT_MESH_EVERY), draw() runs again for capture only with the program's compute fallback variant: its task and mesh stages write the records, nothing is drawn, and the cards are cut by micromaps as in compute mode. Kokiri Forest, native: leaves and grass in the structure, 23 mesh draws a frame, about a quarter captured each frame, none left out; no device loss or validation line. RX_VK_RT_NATIVE_MESH=0 turns it off. The first native run in an area compiles the fallback variants.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
perf(vk): rt gi: the passes under 1 ms at 4K (1 ray, a 3 x 3 filter by default); a stability measure and two history switches
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 17s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
3f68dfd1bf
GI's passes cost 0.94 ms at 4K on an RTX 5090 (were 1.4): one ray a half-size pixel and a 3 x 3 a-trous filter by default (RX_VK_RT_GI_RAYS, RX_VK_RT_GI_KERNEL=5 for the old taps), and the hit's own sun ray only where neither the screen nor the cache knows the hit. RX_VK_RT_GI_STABLE=1 logs how much the light changes a frame where the same surface is seen (about 6 % still, 10-12 % turning, below the game's own lit colour's 10-16 %); RX_VK_RT_GI_HOLD and RX_VK_RT_GI_FEEDBACK are the history's clamp and feedback, for testing. The head comment says what the energy rule is now (the scale held between 1 and 2.5, ADD 2).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

New commit 3f68dfd: GI's passes cost 0.94 ms at 4K on the RTX 5090 (were 1.4 ms), with no visible loss in the irradiance pictures compared.

What changed: one ray a half-size pixel and a 3 x 3 a-trous filter by default (RX_VK_RT_GI_RAYS=2 and RX_VK_RT_GI_KERNEL=5 give the old settings), and a hit's own sun ray is traced only where neither the screen nor the world-space cache knows the hit. Timing from the pass report: filter 0.39 -> 0.16 ms, rays 1.0 -> 0.51 ms.

Stability was measured too (RX_VK_RT_GI_STABLE=1 logs it): the GI term changes about 6 % a frame with the camera still and 10-12 % while turning, which is below the game's own lit colour (10-16 %, partly its TAA jitter). More rays, a longer history or more filter steps barely moved it, so it is not ray noise; RX_VK_RT_GI_HOLD and RX_VK_RT_GI_FEEDBACK are history switches for testing that.

Checks after the commit: tests/run_all.py 540 passed, 18 failed, the same 18 as main on this PC. docs/ray-tracing.md updated.

New commit 3f68dfd: GI's passes cost 0.94 ms at 4K on the RTX 5090 (were 1.4 ms), with no visible loss in the irradiance pictures compared. What changed: one ray a half-size pixel and a 3 x 3 a-trous filter by default (`RX_VK_RT_GI_RAYS=2` and `RX_VK_RT_GI_KERNEL=5` give the old settings), and a hit's own sun ray is traced only where neither the screen nor the world-space cache knows the hit. Timing from the pass report: filter 0.39 -> 0.16 ms, rays 1.0 -> 0.51 ms. Stability was measured too (`RX_VK_RT_GI_STABLE=1` logs it): the GI term changes about 6 % a frame with the camera still and 10-12 % while turning, which is below the game's own lit colour (10-16 %, partly its TAA jitter). More rays, a longer history or more filter steps barely moved it, so it is not ray noise; `RX_VK_RT_GI_HOLD` and `RX_VK_RT_GI_FEEDBACK` are history switches for testing that. Checks after the commit: `tests/run_all.py` 540 passed, 18 failed, the same 18 as main on this PC. `docs/ray-tracing.md` updated.
Author
First-time contributor

New commit 0b32254, two small ones: GI gets an area row for Death Mountain Trail (its light-mask program is its own), and a place with no row now takes the switches' values instead of the previous area's; the scene's status line counts the sun cascades' draws left out of the structure, by reason, and names their programs once. GI was also checked at Death Mountain Trail, Zora's Domain and the Market.

Checks after the commit: tests/run_all.py 540 passed, 18 failed, the same 18 as main on this PC.

New commit 0b32254, two small ones: GI gets an area row for Death Mountain Trail (its light-mask program is its own), and a place with no row now takes the switches' values instead of the previous area's; the scene's status line counts the sun cascades' draws left out of the structure, by reason, and names their programs once. GI was also checked at Death Mountain Trail, Zora's Domain and the Market. Checks after the commit: `tests/run_all.py` 540 passed, 18 failed, the same 18 as main on this PC.
feat(vk): rt gi: Death Mountain Trail's area row; the scene's status line counts the sun cascades' draws left out
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 6s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
0b32254dd7
GI: Death Mountain Trail gets its own area row (its light-mask program is its own), and a place with no row takes the switches' values instead of the last area's. Scene: the status line counts the sun cascades' draws left out of the structure, by reason, and names their programs once.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

Rebased onto current main (aa95d35, after v3.0.0-rc.4); force-pushed. One conflict: tests/test_menu_sections.py, where #735 removed the VRAM budget row next to the new Ray tracing rows; resolved by keeping both changes. The renderer builds, and tests/run_all.py gives 540 passed, 18 failed on both main aa95d35 and this branch, the same 18.

Rebased onto current main (aa95d35, after v3.0.0-rc.4); force-pushed. One conflict: `tests/test_menu_sections.py`, where #735 removed the VRAM budget row next to the new Ray tracing rows; resolved by keeping both changes. The renderer builds, and `tests/run_all.py` gives 540 passed, 18 failed on both main aa95d35 and this branch, the same 18.
winterelfeas force-pushed feat/ray-tracing from 0b32254dd7
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 6s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
to b4e2584ed3
Some checks failed
Website / Website on Cloudflare (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Has been cancelled
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
2026-11-15 11:27:43 +00:00
Compare
feat(vk): rt reflections: rough metal smoothed by rays shared over the quad; no cut classes without micromaps
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
aa8853afef
Neighbouring pixels share their reflection rays through quad subgroup swaps (RX_VK_RT_REFL_SHARE, default 2): for the material-F0 class (armour, water) each pixel traces 2 rays and the 2 x 2 quad averages them, so rough plate armour is smooth and as steady frame to frame as the game's own (Kakariko's guard); a single-ray pixel takes the quad leader's answer when it is on the same surface. A device without quad operations in fragment shaders gets no reflections, logged. Without opacity micromaps the rays leave the cut classes out (mask 0x85 in place of 0x97), as GI does. The kept picture is half size, and nothing is captured while reflections are off. The Castle moat shows the scene (a ninth water surface). The SPIR-V linker check passes: 20 modules, 0 invalid.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

New commit aa8853a, reflections:

  • Rough metal: neighbouring pixels share their reflection rays through quad subgroup swaps (RX_VK_RT_REFL_SHARE, default 2). For the material-F0 class each pixel traces 2 rays and the 2 x 2 quad averages them, so rough plate armour (Kakariko's guard) is smooth and as steady frame to frame as the game's own, where 1 ray a pixel left blotches. A device without quad operations in fragment shaders gets no reflections, and the log says so.
  • Without opacity micromaps the reflection rays leave the cut classes out (mask 0x85 in place of 0x97), as GI already does, so cards are never traced as whole triangles.
  • The Castle moat now reflects the scene: nine water surfaces in all.
  • The kept picture is half size, and nothing is captured while reflections are off.

The SPIR-V linker check passes (20 modules, 0 invalid). Checks after the commit: tests/run_all.py 540 passed, 18 failed, the same 18 as main aa95d35 on this PC. docs/ray-tracing.md updated.

New commit aa8853a, reflections: - Rough metal: neighbouring pixels share their reflection rays through quad subgroup swaps (`RX_VK_RT_REFL_SHARE`, default 2). For the material-F0 class each pixel traces 2 rays and the 2 x 2 quad averages them, so rough plate armour (Kakariko's guard) is smooth and as steady frame to frame as the game's own, where 1 ray a pixel left blotches. A device without quad operations in fragment shaders gets no reflections, and the log says so. - Without opacity micromaps the reflection rays leave the cut classes out (mask 0x85 in place of 0x97), as GI already does, so cards are never traced as whole triangles. - The Castle moat now reflects the scene: nine water surfaces in all. - The kept picture is half size, and nothing is captured while reflections are off. The SPIR-V linker check passes (20 modules, 0 invalid). Checks after the commit: `tests/run_all.py` 540 passed, 18 failed, the same 18 as main aa95d35 on this PC. `docs/ray-tracing.md` updated.
feat(vk): rt sun shadows replace the game's for every caster: plants in the native mode, characters, a far hand-over, the gate as a safety net
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
fb962659b7
The traced sun shadow takes the game's place in all three channels the sun goes through: the cascades', the static map's and the characters' (Link and the people are in the structure), so nothing is shadowed twice. The plants count as traced with the scene's native capture as in compute mode (foliage_traced()). Past 60 m the traced shadow hands over to the game's value, fully by 120 m (RX_VK_RT_SUN_FADE). The sun gate only catches a broken structure: the game's shadow comes back under 25 % of its sunlight kept (back over 40 %), or over 125 % (back under 115 %), and its log names its sums. Debug views sun_cmp and sun_cmp2 put the game's sun, the traced and the depth in one frame.

Native mode, one frame per view at 4K, share of the picture, lost shadow / shadow the game lacks: Kokiri spawn 4.3 % (15.0 % before the native foliage capture) / 4.9 %; Hyrule Field tunnel 0.1 / 1.0 %; gorge exit 0.9 / 1.7 %; Lost Woods 2.4 / 15.6 % (real canopy and blade-on-blade shadow); Lake Hylia 5.4 / 1.4 % (the game's blurred map past the traced edge). The gate fired in none. The menu help, README and docs no longer say leaf shadows need the compute mesh mode.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

New commit fb96265: the traced sun shadow now replaces the game's for every caster, in the default native mesh mode too.

  • It takes the game's place in all three channels the sun goes through: the cascades', the static map's and the characters' (Link and the people are skinned in the structure), so nothing is shadowed twice.
  • The plants count as traced with the scene's native capture (6228330), as in compute mode, so leaf and grass shadows are traced by default.
  • Past 60 m the traced shadow hands over to the game's value, fully by 120 m (RX_VK_RT_SUN_FADE).
  • The sun gate is only a safety net for a broken structure: the game's shadow comes back under 25 % of its sunlight kept, or over 125 %.

Native mode, one frame per view at 4K, share of the picture (lost shadow: the game shadows, the rays don't / shadow the game lacks):

View Lost shadow Shadow the game lacks
Kokiri Forest spawn 4.3 % (15.0 % before the native foliage capture) 4.9 %
Hyrule Field, the tunnel 0.1 % 1.0 %
Hyrule Field, the gorge exit 0.9 % 1.7 %
Lost Woods 2.4 % 15.6 % (canopy and blade-on-blade shadow the cascades lack)
Lake Hylia 5.4 % 1.4 %

The gate fired in none of the five. What is left is not a missing caster: scattered bits at Kokiri (leaf surfaces drawn at another level of detail, thin edges), and at Lake Hylia a band along shadow edges where the game's blurred static map reaches further than the traced edge. The Graphics menu's help, the README and docs/ray-tracing.md no longer say leaf shadows need the compute mesh mode. Not checked yet: the night (moon) and held items.

Checks after the commit: the renderer builds, tests/run_all.py 540 passed, 18 failed, the same 18 as main aa95d35 on this PC.

New commit fb96265: the traced sun shadow now replaces the game's for every caster, in the default native mesh mode too. - It takes the game's place in all three channels the sun goes through: the cascades', the static map's and the characters' (Link and the people are skinned in the structure), so nothing is shadowed twice. - The plants count as traced with the scene's native capture (6228330), as in compute mode, so leaf and grass shadows are traced by default. - Past 60 m the traced shadow hands over to the game's value, fully by 120 m (`RX_VK_RT_SUN_FADE`). - The sun gate is only a safety net for a broken structure: the game's shadow comes back under 25 % of its sunlight kept, or over 125 %. Native mode, one frame per view at 4K, share of the picture (lost shadow: the game shadows, the rays don't / shadow the game lacks): | View | Lost shadow | Shadow the game lacks | |---|---|---| | Kokiri Forest spawn | 4.3 % (15.0 % before the native foliage capture) | 4.9 % | | Hyrule Field, the tunnel | 0.1 % | 1.0 % | | Hyrule Field, the gorge exit | 0.9 % | 1.7 % | | Lost Woods | 2.4 % | 15.6 % (canopy and blade-on-blade shadow the cascades lack) | | Lake Hylia | 5.4 % | 1.4 % | The gate fired in none of the five. What is left is not a missing caster: scattered bits at Kokiri (leaf surfaces drawn at another level of detail, thin edges), and at Lake Hylia a band along shadow edges where the game's blurred static map reaches further than the traced edge. The Graphics menu's help, the README and docs/ray-tracing.md no longer say leaf shadows need the compute mesh mode. Not checked yet: the night (moon) and held items. Checks after the commit: the renderer builds, `tests/run_all.py` 540 passed, 18 failed, the same 18 as main aa95d35 on this PC.
A cascade draw whose vertex stage places its triangles by a rule the scene cannot read (the Lost Woods' falling leaves,
from particle storage buffers) is recorded again with its own vertex stage, the rasterizer off, and its clip positions
captured by VK_EXT_transform_feedback; rt_scene_mesh.comp turns them into world triangles (kCaster). RX_VK_RT_XFB=0 turns
it off. Also: a logged frame writes the SPIR-V of the cascades' left-out programs, the sun gate's log line names the sun's
direction, and the GI and reflection control files take clock=<hour> (menu_ask_cheat_action) for night tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
test(vk): fallback pipeline state: the fixture declares rt_xfb_vertex, which build_graphics now reads
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 5s
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
34cfe3f0fb
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

Pushed 34cfe3f: every caster the game's sun cascades draw is now in the ray tracing structure in the areas checked (Kokiri Forest, the Hyrule Field gorge, Lake Hylia, the Lost Woods, inside the Deku Tree).

  • The Lost Woods' falling leaves are particles placed by their vertex stage from storage buffers. Their cascade draws are now recorded once more with their own vertex stage, the rasterizer off, and the positions captured by VK_EXT_transform_feedback, then turned into world triangles every 4th frame. The status line's count of cascade draws left out there went from 5.5 a frame to none; the same particle captured from two cascades lands at the same world position. RX_VK_RT_XFB=0 turns it off, and a device without the extension goes on without it.
  • The GI and reflection control files take clock=<hour> (a test aid for night runs, through the Cheats page's clock action). At 22:00 the traced sun shadows follow the moon's cascades and GI brightens by 12-22% with nothing darker.
  • Reflections: Hyrule Field's river and the Market's shop windows added to what has been seen.
  • tests/test_fallback_pipeline_state.py's fixture declares the new variable build_graphics reads.

Checks: tests/run_all.py on Windows, the same failures as main aa95d35 (machine-specific) plus the two that fail under load here (test_dev_packs, test_finish_output); the renderer builds with 0 failures. Still WIP: the measurements are taken once at the end.

Pushed 34cfe3f: every caster the game's sun cascades draw is now in the ray tracing structure in the areas checked (Kokiri Forest, the Hyrule Field gorge, Lake Hylia, the Lost Woods, inside the Deku Tree). - The Lost Woods' falling leaves are particles placed by their vertex stage from storage buffers. Their cascade draws are now recorded once more with their own vertex stage, the rasterizer off, and the positions captured by `VK_EXT_transform_feedback`, then turned into world triangles every 4th frame. The status line's count of cascade draws left out there went from 5.5 a frame to none; the same particle captured from two cascades lands at the same world position. `RX_VK_RT_XFB=0` turns it off, and a device without the extension goes on without it. - The GI and reflection control files take `clock=<hour>` (a test aid for night runs, through the Cheats page's clock action). At 22:00 the traced sun shadows follow the moon's cascades and GI brightens by 12-22% with nothing darker. - Reflections: Hyrule Field's river and the Market's shop windows added to what has been seen. - `tests/test_fallback_pipeline_state.py`'s fixture declares the new variable `build_graphics` reads. Checks: `tests/run_all.py` on Windows, the same failures as main aa95d35 (machine-specific) plus the two that fail under load here (`test_dev_packs`, `test_finish_output`); the renderer builds with 0 failures. Still WIP: the measurements are taken once at the end.
fix(vk): rt sun: the gate keeps the game's shadow where the game shows no sunlight and the rays would light the picture
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
51e66ed9da
Inside the Temple of Time the game's mask keeps the sun out wholly and the structure has no roof over the hall: the
traced shadow left 40-42 % of the picture lit and the floor burnt white, since the gate took no reading under 5 % sunlit.
Now the traced sunlight over a twentieth of the picture more than the game's reads as 150 % and the game's values stay.
A Kakariko house, Link's house and the Bombchu Bowling Alley are as with the rays off. Also test switches for the sun's
direction (RX_VK_RT_SUN_TILT, RX_VK_RT_SUN_TURN; RX_VK_RT_LIFT may be negative), and the docs' gate defaults corrected.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

Pushed 51e66ed: a fix to the sun gate for interiors.

  • Inside the Temple of Time the game's light mask keeps the sun out wholly, but the structure has no roof over the hall yet: the traced shadow left 40-42% of the picture lit and the floor burnt white. The gate took no reading where under 5% of the game's picture is sunlit, so the traced value was written. Now, there, traced sunlight over a twentieth of the picture more than the game's reads as 150% and the game's own values stay. Checked in the game: the temple with the rays on is the game's picture again; Link's house, a Kakariko house and the Bombchu Bowling Alley look as with the rays off. The hall's shell in the structure is the real fix and is being looked at.
  • Test switches for the sun's direction (RX_VK_RT_SUN_TILT, RX_VK_RT_SUN_TURN), used to show that the remaining band at Lake Hylia is the game's cascade edge, not a wrong direction.
  • docs/ray-tracing.md: the gate's interior rule, and the gate's default thresholds in the switch table corrected (0.25, 0.4, 1.15, 1.25).

Checks: the same as the last push (main's failures plus the two that fail under load here); the renderer builds with 0 failures.

Pushed 51e66ed: a fix to the sun gate for interiors. - Inside the Temple of Time the game's light mask keeps the sun out wholly, but the structure has no roof over the hall yet: the traced shadow left 40-42% of the picture lit and the floor burnt white. The gate took no reading where under 5% of the game's picture is sunlit, so the traced value was written. Now, there, traced sunlight over a twentieth of the picture more than the game's reads as 150% and the game's own values stay. Checked in the game: the temple with the rays on is the game's picture again; Link's house, a Kakariko house and the Bombchu Bowling Alley look as with the rays off. The hall's shell in the structure is the real fix and is being looked at. - Test switches for the sun's direction (`RX_VK_RT_SUN_TILT`, `RX_VK_RT_SUN_TURN`), used to show that the remaining band at Lake Hylia is the game's cascade edge, not a wrong direction. - docs/ray-tracing.md: the gate's interior rule, and the gate's default thresholds in the switch table corrected (0.25, 0.4, 1.15, 1.25). Checks: the same as the last push (main's failures plus the two that fail under load here); the renderer builds with 0 failures.
feat(vk): rt scene: static models the camera has drawn stay as casters out of view (interior roofs); a capture that did not run is counted
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Guide screenshots / Guide images and local UI source review (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 5s
da8301011b
Indoors no sun cascade draws the walls and roof, so the Temple of Time's vault left the structure whenever the camera
looked level and the sun's rays reached the floor (40 % of the picture open to the sun, 0.2 % now). A static model the
pre-pass has drawn at one place for eight frames stays in the top level as a caster when it is not drawn; it is let go
when its memory is rewritten, its bottom level is freed, a loading screen passes or the camera jumps 30 m.
RX_VK_RT_REMEMBER=0 turns it off. Also: a transform feedback capture that could not run (its program not in the cache
yet, on the first visit) is counted among the cascades' left-out draws with the reason, and retried every 180 frames.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

Pushed da83010: interiors keep their roofs in the structure, and the caster count is honest on a first visit.

  • Indoors no sun cascade draws the walls and roof, and the camera's pass draws them only while in view, so the Temple of Time's vault left the structure whenever the camera looked level: 40% of the picture was open to the sun. A static model the camera's pass has drawn at one place for eight frames now stays in the top level as a caster on the frames it is not drawn. It is let go when its memory is rewritten, its bottom level is freed, a loading screen passes or the camera jumps 30 m (so the previous area's models, at the same coordinates, are not kept). Inside the hall the open share is 0.2%, agreement with the game's depth 99.98%; Kokiri Forest is unchanged. RX_VK_RT_REMEMBER=0 turns it off. The gate fix of the last push stays as the safety net.
  • A transform feedback capture that cannot run (on the first visit to an area its program is not in the program cache yet, as with the Market's particles) is now counted among the cascades' left-out draws, with the reason, and retried every 180 frames.
  • docs/ray-tracing.md: both, and the coverage sweep: over 17 areas in the native mode no sun cascade draw is left out after the first visit, and the structure agrees with the game's depth on 88% to 99.9% of the screen.

Checks: as before (main's failures plus the two that fail under load here); the renderer builds with 0 failures.

Pushed da83010: interiors keep their roofs in the structure, and the caster count is honest on a first visit. - Indoors no sun cascade draws the walls and roof, and the camera's pass draws them only while in view, so the Temple of Time's vault left the structure whenever the camera looked level: 40% of the picture was open to the sun. A static model the camera's pass has drawn at one place for eight frames now stays in the top level as a caster on the frames it is not drawn. It is let go when its memory is rewritten, its bottom level is freed, a loading screen passes or the camera jumps 30 m (so the previous area's models, at the same coordinates, are not kept). Inside the hall the open share is 0.2%, agreement with the game's depth 99.98%; Kokiri Forest is unchanged. `RX_VK_RT_REMEMBER=0` turns it off. The gate fix of the last push stays as the safety net. - A transform feedback capture that cannot run (on the first visit to an area its program is not in the program cache yet, as with the Market's particles) is now counted among the cascades' left-out draws, with the reason, and retried every 180 frames. - docs/ray-tracing.md: both, and the coverage sweep: over 17 areas in the native mode no sun cascade draw is left out after the first visit, and the structure agrees with the game's depth on 88% to 99.9% of the screen. Checks: as before (main's failures plus the two that fail under load here); the renderer builds with 0 failures.
program_cache_save hands each translated program's SPIR-V to rt::scene_program_translated, which keeps the vertex
stages of the programs transform feedback would capture (at most 512) and makes the capturing module at the program's
first capture. Programs loaded from the cache file still go through the background scan. Lost Woods with
RX_VK_NO_PROGRAM_CACHE=1: 4 of 4 capturing stages made from memory, no cascade draw left out.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
test(vk): program cache fixtures stub rt::on and rt::scene_program_translated, which program_cache_save now calls
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 5s
2a46f56f52
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

Pushed dd2361b and 1d7f2ce: the particles cast on an area's first visit.

  • The transform feedback capture's vertex stage was made only from the program cache file, so on an area's first visit (the Market's particles) it waited until the cache had saved the program. program_cache_save now hands each translated program's SPIR-V to rt::scene_program_translated, which keeps the vertex stages of the programs that would be captured (at most 512) and makes the capturing module at the first capture. Lost Woods with RX_VK_NO_PROGRAM_CACHE=1 (every program translated in the run): 4 of 4 stages made from memory, no cascade draw left out.
  • The program cache checks' fixtures stub the two new calls.

Known open, being worked on: static-map shadows whose casters are out of the camera's view (a mound by Link's house in Kokiri, a cliff over Kakariko's terraces) are lost with the traced shadow in the static map's place; the fix is capturing the static shadow map's casters into the structure.

Checks: as before (main's failures plus the two that fail under load here); the renderer builds with 0 failures.

Pushed dd2361b and 1d7f2ce: the particles cast on an area's first visit. - The transform feedback capture's vertex stage was made only from the program cache file, so on an area's first visit (the Market's particles) it waited until the cache had saved the program. `program_cache_save` now hands each translated program's SPIR-V to `rt::scene_program_translated`, which keeps the vertex stages of the programs that would be captured (at most 512) and makes the capturing module at the first capture. Lost Woods with `RX_VK_NO_PROGRAM_CACHE=1` (every program translated in the run): 4 of 4 stages made from memory, no cascade draw left out. - The program cache checks' fixtures stub the two new calls. Known open, being worked on: static-map shadows whose casters are out of the camera's view (a mound by Link's house in Kokiri, a cliff over Kakariko's terraces) are lost with the traced shadow in the static map's place; the fix is capturing the static shadow map's casters into the structure. Checks: as before (main's failures plus the two that fail under load here); the renderer builds with 0 failures.
Author
First-time contributor

Screenshots, same spot and frame, the feature off (left) and on (right), 4K on an RTX 5090, one part on at a time, from the parts' development builds (this PR's code; the sun shadow ones also carry the static shadow map's casters, still in testing). AO and reflections follow.

Sun shadows (RX_VK_RT=2 against 0): each clover leaf, grass blade and fence slat casts its own cut shadow where the game's maps give soft patches.

Sun shadows, Kakariko's gate: off left, on right

Sun shadows, Kakariko's fence: off left, on right

GI (RX_VK_RT=4 against 0): light bounced from lamps, doorways and lava into what the game leaves near black.

GI, a Kakariko house: off left, on right

GI, Link's house: off left, on right

GI, Dodongo's Cavern: off left, on right

Screenshots, same spot and frame, the feature off (left) and on (right), 4K on an RTX 5090, one part on at a time, from the parts' development builds (this PR's code; the sun shadow ones also carry the static shadow map's casters, still in testing). AO and reflections follow. **Sun shadows** (`RX_VK_RT=2` against 0): each clover leaf, grass blade and fence slat casts its own cut shadow where the game's maps give soft patches. ![Sun shadows, Kakariko's gate: off left, on right](https://git.magicbean.dev/attachments/df1860c1-0485-4337-8d43-0f0632241b11) ![Sun shadows, Kakariko's fence: off left, on right](https://git.magicbean.dev/attachments/9376dd86-34d3-417c-89cf-dc850181d063) **GI** (`RX_VK_RT=4` against 0): light bounced from lamps, doorways and lava into what the game leaves near black. ![GI, a Kakariko house: off left, on right](https://git.magicbean.dev/attachments/4d697f53-ecab-4dfa-81ed-4fed83a7e2a4) ![GI, Link's house: off left, on right](https://git.magicbean.dev/attachments/5ef7dee5-51b7-4f95-80a7-4af325efccf3) ![GI, Dodongo's Cavern: off left, on right](https://git.magicbean.dev/attachments/fbbc8221-5675-47c9-bb21-57b42a412ea4)
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 5s
This pull request is marked as a work in progress.
Some workflows are waiting to be reviewed.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'feat/ray-tracing:winterelfeas-feat/ray-tracing'
git switch 'winterelfeas-feat/ray-tracing'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!727
No description provided.