Skip to content

impr: Optimize radiance cascade execution - #2914

Open
reczkok wants to merge 1 commit into
impr/better-rcfrom
impr/radiance-cascades-execution
Open

impr: Optimize radiance cascade execution#2914
reczkok wants to merge 1 commit into
impr/better-rcfrom
impr/radiance-cascades-execution

Conversation

@reczkok

@reczkok reczkok commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Built on top of #2617.

  • shares ray directions through workgroup memory when the cascade layout allows it
  • prebuilds jump-flood pipelines instead of updating the offset uniform between dispatches
  • records the entire jump-flood run into one compute pass
  • allows jump flooding to participate in a caller-owned command encoder

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

pkg.pr.new

packages
Ready to be installed by your favorite package manager ⬇️

https://pkg.pr.new/software-mansion/TypeGPU/typegpu@7d1de3cc7c89e345d305a679cf06c7d2bf4ef351
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/radiance-cascades@7d1de3cc7c89e345d305a679cf06c7d2bf4ef351
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/sdf@7d1de3cc7c89e345d305a679cf06c7d2bf4ef351

benchmark
view benchmark

commit
view commit

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

Resolution Time Benchmark

---
config:
  themeVariables:
    xyChart:
      plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
  title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
  x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
  y-axis "time (ms)"
  line [0.70, 1.41, 3.19, 4.40, 5.54, 8.16, 16.37, 16.03]
  line [0.73, 1.37, 2.82, 4.36, 5.42, 6.94, 15.77, 18.24]
  line [0.68, 1.40, 2.81, 4.64, 5.52, 7.61, 17.23, 18.79]
Loading
---
config:
  themeVariables:
    xyChart:
      plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
  title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
  x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
  y-axis "time (ms)"
  line [0.26, 0.40, 0.54, 0.59, 0.78, 0.85, 1.03, 1.14]
  line [0.24, 0.39, 0.49, 0.60, 0.81, 0.88, 1.03, 1.14]
  line [0.24, 0.40, 0.51, 0.61, 0.81, 0.88, 1.00, 1.10]
Loading
---
config:
  themeVariables:
    xyChart:
      plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
  title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
  x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
  y-axis "time (ms)"
  line [0.67, 1.53, 2.47, 4.97, 8.73, 17.95, 39.07, 79.87]
  line [0.70, 1.64, 2.46, 4.71, 8.46, 18.01, 39.21, 78.43]
  line [0.56, 1.49, 2.27, 4.70, 8.25, 17.94, 39.62, 79.89]
Loading

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

Bundle size comparison (import * as ... in PR vs import * as ... in target):

🟢 Decreased ➖ Unchanged 🔴 Increased ❔ Unknown
0 325 0 0

import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):

Test tsdown
tgpu_init.ts 263.09 kB ($${\color{green}-3.5\%}$$)
tgpu_initFromDevice.ts 262.55 kB ($${\color{green}-3.7\%}$$)
tgpu_resolve.ts 161.75 kB ($${\color{green}-40.7\%}$$)
tgpu_resolveWithContext.ts 161.68 kB ($${\color{green}-40.7\%}$$)
tgpu_bindGroupLayout.ts 62.32 kB ($${\color{green}-77.1\%}$$)
tgpu_mutableAccessor.ts 57.04 kB ($${\color{green}-79.1\%}$$)
tgpu_accessor.ts 57.04 kB ($${\color{green}-79.1\%}$$)
tgpu_privateVar.ts 55.73 kB ($${\color{green}-79.6\%}$$)
tgpu_workgroupVar.ts 55.73 kB ($${\color{green}-79.6\%}$$)
tgpu_const.ts 55.15 kB ($${\color{green}-79.8\%}$$)
tgpu_lazy.ts 54.95 kB ($${\color{green}-79.8\%}$$)
tgpu_fragmentFn.ts 39.68 kB ($${\color{green}-85.4\%}$$)
tgpu_fn.ts 39.62 kB ($${\color{green}-85.5\%}$$)
tgpu_vertexFn.ts 39.50 kB ($${\color{green}-85.5\%}$$)
tgpu_computeFn.ts 39.20 kB ($${\color{green}-85.6\%}$$)
tgpu_vertexLayout.ts 28.33 kB ($${\color{green}-89.6\%}$$)
tgpu_comptime.ts 15.93 kB ($${\color{green}-94.2\%}$$)
tgpu_unroll.ts 1.75 kB ($${\color{green}-99.4\%}$$)
tgpu_slot.ts 1.70 kB ($${\color{green}-99.4\%}$$)

If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ Solid optimization, two verification gaps worth closing.

Reviewed changes

  • Shared ray directions through workgroup memory (cascades.ts): when the cascade layout allows it, the PREAVERAGE_RAY_COUNT directions are computed once per workgroup and broadcast via a workgroupVar + workgroupBarrier(); the OOB early-return was correctly moved after the barrier.
  • Per-layer gating + pipeline caching (runner.ts): useSharedRayDirections is allowed only when workgroup 8×8 blocks align inside probe cells (probes divisible by 8), and cascade pipelines are now cached keyed by hasUpperCascade:useSharedRayDirections. I verified the shared path is arithmetically identical to the per-invocation fallback (thread localIndex 0..3 covers the same 4 directions the loop iterates), and that out-of-bounds workgroups still source the shared writes from valid threads.
  • Prebuilt jump-flood pipelines + single compute pass (jumpFlood.ts): builds one pipeline per offset (offset uniform frozen) rather than mutating a shared uniform, and records the whole init + flood + finalize run into one caller-owned compute pass. I checked the ping-pong buffer parity for the prebuilt flood passes and the finalizeReadBG selection against the old sourceIdx alternation — both are equivalent for power-of-two offset sequences.
  • Tests (cascades.test.ts): snapshots updated for shared-dir emission, memoization extended, plus a new snapshot pinning the useSharedRayDirections: false fallback.

ℹ️ Single-pass ordering is the load-bearing assumption

The whole jump-flood run is now written into one encoder.beginComputePass()/end(), whereas previously each flood pass got its own encoder + submit, forcing the driver to flush each pass (including its storage writes) before the next dispatch. Without a real-GPU test, this depends on the WebGPU command buffer surfacing the write→read dependency between successive dispatchWorkgroups commands inside a single compute pass. Worth confirming on the backend/driver — the codegen/docs tests won't catch a pickle-write artifact.

Technical details
# Single-pass batching vs storage write/read ordering

## Affected sites
- packages/typegpu-sdf/src/jumpFlood.ts:426 (`run`) — copies init + every flood pass + finalize into one compute pass, one submit.

## Required outcome
- Confirm that a storage-texture written by flood pass *i* is observable to flood pass *i+1* when both are recorded into the same `computePass`/submission. Previously each pass was a separate submit which forced serialization.

## Suggested approach
- A functional test (or run on a real GPU and inspect the SDF output) that asserts batched `run()` output matches the non-batched reference. If the driver does not synchronize in-pass dispatches, split the passes (or insert explicit synchronization).

ℹ️ No functional-equivalence test for the new paths

The added tests assert WGSL emission only. Nothing asserts that useSharedRayDirections: true produces identical output to the false fallback, and nothing compares the batched jump-flood result against the previous per-dispatch behavior. The shared-dir indexing and the batch ordering are exactly where an indexing or visibility slip would live, so a runtime A/B test is cheap insurance.

ℹ️ Nitpicks

  • cascades.ts:517 builds the cache key with string interpolation; fine, but the three boolean/mergeMode components now read a bit tersely — consider a structured key if the specialization grows again.
  • The runner gate runner.ts:336 hardcodes CASCADE_WORKGROUP_DIM through the constant, which is good; no change needed.

Pullfrog  | Fix it ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Copilot AI lite review requested due to automatic review settings August 26, 2026 16:29
@reczkok
reczkok force-pushed the impr/radiance-cascades-execution branch from 2eacea7 to 7d1de3c Compare August 26, 2026 16:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes radiance cascade and jump-flood execution by reducing per-dispatch overhead (pipeline/bindgroup churn and repeated direction computation) and by enabling whole runs to be recorded into a single compute pass, optionally into a caller-owned command encoder.

Changes:

  • Add an optional caller-owned TgpuCommandEncoder path for jump-flood execution and record the full algorithm into one compute pass.
  • Introduce an optional “shared ray directions” cascade specialization using workgroup memory, and cache cascade pipelines by specialization.
  • Centralize cascade workgroup sizing via CASCADE_WORKGROUP_DIM and update shader snapshots/tests to cover the new specialization + fallback.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/typegpu-sdf/src/jumpFlood.ts Prebuild per-offset pipelines and record the entire jump-flood run into a single compute pass with optional external encoder support.
packages/typegpu-radiance-cascades/src/cascades.ts Add CASCADE_WORKGROUP_DIM and a new useSharedRayDirections specialization that can use workgroup memory for ray directions.
packages/typegpu-radiance-cascades/src/runner.ts Use the new workgroup dimension constant, compute when shared-ray-direction specialization is valid per layer, and cache pipelines by specialization.
packages/typegpu-radiance-cascades/tests/cascades.test.ts Update shader-resolution snapshots for shared-ray-direction variants and add coverage for the fallback specialization.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +385 to +388
const offsets: number[] = [];
for (let offset = maxRange; offset >= 1; offset = Math.floor(offset / 2)) {
offsets.push(offset);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants