Skip to content

feat: support dynamic work buffer formats in compute GSplat renderers#8547

Merged
mvaligursky merged 3 commits intomainfrom
mv-compute-dynamic-format
Mar 24, 2026
Merged

feat: support dynamic work buffer formats in compute GSplat renderers#8547
mvaligursky merged 3 commits intomainfrom
mv-compute-dynamic-format

Conversation

@mvaligursky
Copy link
Copy Markdown
Contributor

@mvaligursky mvaligursky commented Mar 23, 2026

Compute tiled GSplat renderers now dynamically support different work buffer formats (compact and large) instead of hardcoding the compact format's texture bindings and decode logic.

Changes:

  • Add getComputeInputDeclarations() and getComputeBindFormats() to GSplatFormat for generating compute shader bindings and declarations from format metadata (including extra streams like pcId, pcNodeIndex)
  • Replace hardcoded texture bindings and decode functions in compute tile-count shaders with format-generated #include directives (gsplatComputeSplatCS, gsplatFormatDeclCS, gsplatFormatReadCS)
  • Remove compact-specific decodeRotation(), decodeScale(), decodeColor() from compute-gsplat-common.js — format read chunks now handle all decoding
  • Derive formatStartBinding from fixed bindings array length instead of hardcoding magic numbers
  • Recreate compute shaders when work buffer format changes at runtime (tracked via format hash), with consolidated recreation to avoid redundant double-recreation per frame
  • Set GSPLAT_COLOR_FLOAT define for non-RGBA16U color formats to use the correct float reading path
  • Clamp negative color values before gamma decoding to prevent NaN from pow() on negative inputs, matching the quad renderer

Compact format repack:

  • Co-locate alpha with center position in dataTransformA (scale.xyz 3×8-bit + alpha 8-bit), move rotation to dataTransformB
  • Enables single-texture opacity early-out in compute shaders — culled splats skip dataColor and dataTransformB loads entirely

Work buffer getOpacity()/getColor() API:

  • Add getOpacity() to both work buffer format readers for early culling before loading color data
  • Change getColor() to return vec3 (RGB only) for both work buffer formats; opacity handled separately via getOpacity()
  • Large format: getOpacity() unconditionally loads and caches color (no conditional branch); getColor() returns cached RGB
  • Compact format: getOpacity() reads alpha from cachedTransformA (no extra texture load); getColor() returns decoded RGB
  • Quad VS uses GSPLAT_SEPARATE_OPACITY define to call getOpacity() before getColor() when rendering from work buffer
  • Strict call order: getCenter()getOpacity()getColor() for all work buffer consumers (compute shaders and quad VS)

Performance:

  • Fixed bindings precede format-specific bindings so format textures are always last, keeping binding indices stable
  • Early opacity culling in compute tile-count shaders avoids unnecessary texture loads for transparent splats

Compute tiled renderers now dynamically support different work buffer
formats instead of hardcoding the compact format's bindings and decode
logic. Format-specific shader code is generated from GSplatFormat
metadata, with shader recreation on format changes at runtime.

Made-with: Cursor
@mvaligursky mvaligursky self-assigned this Mar 23, 2026
@mvaligursky mvaligursky requested a review from Copilot March 23, 2026 17:27
@mvaligursky mvaligursky added enhancement Request for a new feature area: graphics Graphics related issue labels Mar 23, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 updates the unified compute-based GSplat renderers to work with multiple work-buffer layouts (compact vs large/packed) by generating compute shader bindings/declarations and read/decode logic from GSplatFormat metadata instead of hardcoding compact-only streams and decoders.

Changes:

  • Add compute-specific stream declaration/bind-format generation on GSplatFormat, and new WGSL helper chunks for compute splat indexing + explicit bindings.
  • Refactor compute tile-count shaders to use format-provided declarations/read code and clamp negative color before gamma conversion.
  • Recreate compute shaders when the work-buffer format (hash) or tonemap/gamma changes, consolidating recreation triggers.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatComputeStreamDecl.js New WGSL template to declare compute-bound stream textures with explicit @binding and load helpers.
src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatComputeSplat.js New WGSL chunk providing a compute-compatible Splat struct and setSplat() helper.
src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-tile-count.js Switch to format-generated declarations/read code and remove compact-specific decode paths; clamp color before gamma.
src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-local-tile-count.js Same as global tile-count, updated for the local/compacted-ID path.
src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-common.js Remove compact-only decode helpers now replaced by format read chunks.
src/scene/gsplat/gsplat-format.js Add getComputeInputDeclarations() and getComputeBindFormats() to generate compute bindings from format metadata.
src/scene/gsplat-unified/gsplat-compute-local-renderer.js Bind all format streams dynamically and recreate count compute when format hash/tonemap/gamma changes.
src/scene/gsplat-unified/gsplat-compute-global-renderer.js Same dynamic binding + recreation logic for the global compute renderer.

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

Comment thread src/scene/gsplat-unified/gsplat-compute-local-renderer.js
Comment thread src/scene/gsplat-unified/gsplat-compute-global-renderer.js
Comment thread src/scene/gsplat-unified/gsplat-compute-local-renderer.js
Comment thread src/scene/gsplat-unified/gsplat-compute-global-renderer.js
Comment thread src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-tile-count.js Outdated
Comment thread src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-local-tile-count.js Outdated
Comment thread src/scene/gsplat/gsplat-format.js Outdated
…ity(), repack compact format, getColor() returns vec3

- Derive formatStartBinding from fixed bindings array length instead of hardcoding
- Include extra streams (pcId, pcNodeIndex) in compute bind formats, declarations, and dispatch loops
- Add getOpacity() to work buffer format readers for early opacity culling before loading color
- Repack compact format: co-locate alpha with center in dataTransformA, move rotation to dataTransformB
- Change getColor() to return vec3 (RGB only) for both work buffer formats; opacity handled separately
- Remove conditional colorLoaded branch in packed format reader; getOpacity() unconditionally caches color
- Add GSPLAT_SEPARATE_OPACITY define for quad VS to call getOpacity() before getColor()
- Consolidate shader recreation to avoid redundant double-recreation per frame

Made-with: Cursor
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.


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

@mvaligursky mvaligursky merged commit c5f98ca into main Mar 24, 2026
8 checks passed
@mvaligursky mvaligursky deleted the mv-compute-dynamic-format branch March 24, 2026 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: graphics Graphics related issue enhancement Request for a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants