Skip to content

Commit a11661c

Browse files
mvaligurskyMartin Valigursky
andauthored
Skip pcNodeIndex work buffer stream when GPU sorting is active (#8492)
The GPU sort + culling path uses interval-based compaction which reads node visibility directly from intervals, never accessing pcNodeIndex from the work buffer. Only the CPU sort + culling path needs it. Convert gpuSorting to a getter/setter and unify the pcNodeIndex stream decision into _syncNodeIndexStream(), which adds/removes the stream based on both culling and gpuSorting state. Made-with: Cursor Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
1 parent 78d557c commit a11661c

File tree

1 file changed

+44
-11
lines changed

1 file changed

+44
-11
lines changed

src/scene/gsplat-unified/gsplat-params.js

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,34 @@ class GSplatParams {
124124
*/
125125
radialSorting = false;
126126

127+
/**
128+
* @type {boolean}
129+
* @private
130+
*/
131+
_gpuSorting = false;
132+
127133
/**
128134
* Enables GPU-based sorting using compute shaders. WebGPU only.
129135
*
130136
* @type {boolean}
131137
* @ignore
132138
*/
133-
gpuSorting = false;
139+
set gpuSorting(value) {
140+
if (value !== this._gpuSorting) {
141+
this._gpuSorting = value;
142+
this._syncNodeIndexStream();
143+
}
144+
}
145+
146+
/**
147+
* Gets the GPU sorting enabled state.
148+
*
149+
* @type {boolean}
150+
* @ignore
151+
*/
152+
get gpuSorting() {
153+
return this._gpuSorting;
154+
}
134155

135156
/**
136157
* Enables debug rendering of AABBs for GSplat octree nodes. Defaults to false.
@@ -226,16 +247,9 @@ class GSplatParams {
226247
* @ignore
227248
*/
228249
set culling(value) {
229-
if (value && !this._culling) {
230-
this._culling = true;
231-
if (!this._format.getStream('pcNodeIndex')) {
232-
this._format.addExtraStreams([
233-
{ name: 'pcNodeIndex', format: PIXELFORMAT_R32U }
234-
]);
235-
}
236-
} else if (!value && this._culling) {
237-
this._culling = false;
238-
this._format.removeExtraStreams(['pcNodeIndex']);
250+
if (value !== this._culling) {
251+
this._culling = value;
252+
this._syncNodeIndexStream();
239253
}
240254
}
241255

@@ -249,6 +263,25 @@ class GSplatParams {
249263
return this._culling;
250264
}
251265

266+
/**
267+
* Adds or removes the pcNodeIndex extra stream based on current culling and gpuSorting state.
268+
* Only the CPU sort + culling path needs per-splat node index in the work buffer; the GPU sort
269+
* path uses interval-based compaction which reads node visibility directly from intervals.
270+
*
271+
* @private
272+
*/
273+
_syncNodeIndexStream() {
274+
const needsNodeIndex = this._culling && !(this._gpuSorting && this._device.isWebGPU);
275+
const hasNodeIndex = !!this._format.getStream('pcNodeIndex');
276+
if (needsNodeIndex && !hasNodeIndex) {
277+
this._format.addExtraStreams([
278+
{ name: 'pcNodeIndex', format: PIXELFORMAT_R32U }
279+
]);
280+
} else if (!needsNodeIndex && hasNodeIndex) {
281+
this._format.removeExtraStreams(['pcNodeIndex']);
282+
}
283+
}
284+
252285
/**
253286
* Distance threshold in world units to trigger LOD updates for camera and gsplat instances.
254287
* Defaults to 1.

0 commit comments

Comments
 (0)