Skip to content

refactor: Switch gsplat work buffer from row-aligned to pixel-offset layout#8484

Merged
mvaligursky merged 2 commits intomainfrom
mv-gsplat-offset-allocation
Feb 26, 2026
Merged

refactor: Switch gsplat work buffer from row-aligned to pixel-offset layout#8484
mvaligursky merged 2 commits intomainfrom
mv-gsplat-offset-allocation

Conversation

@mvaligursky
Copy link
Copy Markdown
Contributor

@mvaligursky mvaligursky commented Feb 26, 2026

Summary

  • Replaces row-based lineStart/lineCount work buffer allocation with contiguous pixel-offset packing, eliminating up to textureSize - 1 pixels of padding waste per splat
  • Simplifies texture sizing from binary search (estimateTextureSize) to Math.ceil(Math.sqrt(totalPixels))
  • Cleans up shader uniforms: removes dead uStartLine, combines uLineCount + uTextureWidth into a single ivec2 uTextureSize (future-proof for non-square textures)
  • Removes per-splat viewport from render pass (full render target used instead)

…layout

Replace row-based lineStart/lineCount allocation with contiguous
pixel-offset packing, eliminating row padding waste. Simplify texture
sizing from binary search to Math.ceil(Math.sqrt(totalPixels)), and
clean up shader uniforms (remove uStartLine, combine uLineCount +
uTextureWidth into ivec2 uTextureSize).

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

This PR refactors GSplat work-buffer addressing from row-aligned allocation to contiguous pixel-offset packing, updating both CPU/GPU metadata flow and the copy-to-workbuffer shaders to match the new layout.

Changes:

  • Replace per-splat row allocation (lineStart/lineCount/viewport) with contiguous pixelOffset packing across splats.
  • Simplify work-buffer sizing to ceil(sqrt(totalActiveSplats)) and propagate new layout metadata through sorting/compaction.
  • Update GLSL/WGSL copy shaders and render pass uniforms (remove uStartLine, replace uLineCount/uTextureWidth with uTextureSize).

Reviewed changes

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

Show a summary per file
File Description
src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatCopyInstancedQuad.js Switch vertex uniform inputs to uTextureSize for NDC mapping.
src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplatCopyToWorkbuffer.js Remove uStartLine and compute local row directly from absolute rowStart.
src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatCopyInstancedQuad.js Switch vertex uniform inputs to uTextureSize for NDC mapping.
src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplatCopyToWorkbuffer.js Remove uStartLine and compute local row directly from absolute rowStart.
src/scene/gsplat-unified/gsplat-world-state.js Compute textureSize from total pixels and assign contiguous pixel offsets.
src/scene/gsplat-unified/gsplat-work-buffer-render-pass.js Remove per-splat viewport/start-line; set uTextureSize and render full RT.
src/scene/gsplat-unified/gsplat-unified-sort-worker.js Build index map using pixelOffsets rather than lineStarts * textureSize.
src/scene/gsplat-unified/gsplat-manager.js Use totalActiveSplats consistently; send pixelOffsets in intervals payload.
src/scene/gsplat-unified/gsplat-interval-compaction.js Use pixelOffset as the work-buffer base index for interval metadata.
src/scene/gsplat-unified/gsplat-info.js Introduce pixelOffset + setLayout; build sub-draws from absolute target offset.
Comments suppressed due to low confidence (1)

src/scene/gsplat-unified/gsplat-info.js:224

  • setLayout will call updateSubDraws even when activeSplats is 0. In that case the synthesized interval is [0, 0), subDrawCount stays 0, and TextureUtils.calcTextureSize(0, ...) returns invalid dimensions (width 0 / height NaN), which will break texture creation. Add an early return for activeSplats === 0 (and ensure subDrawTexture/subDrawCount are cleared) or make updateSubDraws handle subDrawCount === 0 safely.
    setLayout(pixelOffset, textureSize, activeSplats) {
        this.pixelOffset = pixelOffset;

        // Synthesize a full-range interval when none exist, so all paths use sub-draws
        if (this.intervals.length === 0) {
            this.intervals[0] = 0;
            this.intervals[1] = activeSplats;
        }

        this.updateSubDraws(textureSize);
    }

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

Comment thread src/scene/gsplat-unified/gsplat-world-state.js
@mvaligursky mvaligursky merged commit 5421804 into main Feb 26, 2026
8 checks passed
@mvaligursky mvaligursky deleted the mv-gsplat-offset-allocation branch February 26, 2026 13:55
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