Skip to content

Fix black renders after engine 2.19 upgrade by constructing ComputeRadixSort in indirect mode#259

Merged
slimbuck merged 1 commit into
playcanvas:mainfrom
slimbuck:rastersize-dev
Jun 12, 2026
Merged

Fix black renders after engine 2.19 upgrade by constructing ComputeRadixSort in indirect mode#259
slimbuck merged 1 commit into
playcanvas:mainfrom
slimbuck:rastersize-dev

Conversation

@slimbuck

Copy link
Copy Markdown
Member

Problem

Since the dependency update in #252 (PlayCanvas 2.18.2 → 2.19.2), the GPU rasterizer produces uniform black/background-only images, and rendering got slower. All three render-golden tests fail with 46–82 byte WebP outputs.

Cause

PlayCanvas 2.19 refactored ComputeRadixSort (adding the OneSweep backend) and changed how indirect mode is enabled:

  • 2.18.2: indirect mode was per-call — sortIndirect() recreated the shaders/bind groups for indirect dispatch on the fly.
  • 2.19.2: indirect mode is a constructor option (new ComputeRadixSort(device, { indirect: true })), and the execute path only checks that flag.

The rasterizer constructed the sort without the flag, so its sortIndirect() call silently fell back to a direct dispatch sized by maxElementCount — the full pair-buffer capacity (chunkCap × maxCoveragePerSplat) — instead of reading the GPU-side totalPairs count:

  • The uninitialized buffer tail beyond totalPairs sorted as zero keys to the front, so findBoundaries saw all-zero sorted tile keys and left every tile slice empty except tile 0 — nothing composited, and finalize wrote pure background.
  • Sorting the full capacity (hundreds of millions of elements at large chunk caps) instead of the actual pair count caused the slowdown.

No validation errors fired because every API call was valid, just semantically wrong.

Fix

Construct the sort in indirect mode:

this.radixSort = new ComputeRadixSort(device, { indirect: true });

This is the only ComputeRadixSort site in the repo. The hand-written prepare-indirect shader (1 slot, 2048 elements/workgroup) still matches the portable multipass backend's granularity, which is unchanged in 2.19.

Verification

  • All 3 render-golden tests pass byte-exact again, confirming output is identical to the pre-update renderer.
  • shoe.ply renders 59.2 KB of real image content (was 82 B black); rasterization time dropped 0.138 s → 0.042 s.

@slimbuck slimbuck requested a review from Copilot June 12, 2026 10:49
@slimbuck slimbuck self-assigned this Jun 12, 2026
@slimbuck slimbuck added the bug Something isn't working label Jun 12, 2026

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

Updates the GPU splat rasterizer to restore correct output and performance after the PlayCanvas 2.19 engine upgrade by ensuring the radix sort is constructed in indirect mode (as required by the updated ComputeRadixSort API).

Changes:

  • Construct ComputeRadixSort with { indirect: true } so sortIndirect() performs an indirect dispatch based on GPU totalPairs.
  • Add an explanatory comment documenting the PlayCanvas 2.19 API change and the failure mode when indirect mode is not enabled.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@slimbuck slimbuck marked this pull request as ready for review June 12, 2026 11:19
@slimbuck slimbuck requested a review from a team June 12, 2026 11:20
@slimbuck slimbuck merged commit c290f9b into playcanvas:main Jun 12, 2026
3 checks passed
@slimbuck slimbuck deleted the rastersize-dev branch June 12, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants