|
|
@@ -1491,205 +1491,211 @@ class WebGPUBackend extends Backend {
|
|
|
|
|
|
}
|
|
|
|
|
|
- // render object
|
|
|
-
|
|
|
/**
|
|
|
- * Executes a draw command for the given render object.
|
|
|
+ * Internal draw function that performs the draw with the given pass encoder.
|
|
|
*
|
|
|
- * @param {RenderObject} renderObject - The render object to draw.
|
|
|
+ * @private
|
|
|
+ * @param {RenderObject} renderObject - The render object.
|
|
|
* @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process.
|
|
|
+ * @param {Object} renderContextData - The render context data object, holding current pass state and occlusion query tracking.
|
|
|
+ * @param {GPURenderPipeline} pipelineGPU - The GPU render pipeline.
|
|
|
+ * @param {Array<BufferAttribute>} vertexBuffers - The vertex buffers.
|
|
|
+ * @param {{vertexCount: number, firstVertex: number, instanceCount: number, firstInstance: number}} drawParams - The draw parameters.
|
|
|
+ * @param {GPURenderPassEncoder|GPURenderBundleEncoder} passEncoderGPU - The GPU pass encoder used for recording draw commands.
|
|
|
+ * @param {Object} currentSets - Tracking object for currently set pipeline, attributes, bind groups, and index state.
|
|
|
*/
|
|
|
- draw( renderObject, info ) {
|
|
|
+ _draw( renderObject, info, renderContextData, pipelineGPU, vertexBuffers, drawParams, passEncoderGPU, currentSets ) {
|
|
|
|
|
|
- const { object, material, context, pipeline } = renderObject;
|
|
|
- const bindings = renderObject.getBindings();
|
|
|
- const renderContextData = this.get( context );
|
|
|
- const pipelineData = this.get( pipeline );
|
|
|
- const pipelineGPU = pipelineData.pipeline;
|
|
|
+ const { object, material, context } = renderObject;
|
|
|
|
|
|
- // Skip if pipeline has error
|
|
|
- if ( pipelineData.error === true ) return;
|
|
|
+ const bindings = renderObject.getBindings();
|
|
|
|
|
|
const index = renderObject.getIndex();
|
|
|
const hasIndex = ( index !== null );
|
|
|
|
|
|
-
|
|
|
- const drawParams = renderObject.getDrawParameters();
|
|
|
- if ( drawParams === null ) return;
|
|
|
-
|
|
|
// pipeline
|
|
|
+ this.pipelineUtils.setPipeline( passEncoderGPU, pipelineGPU );
|
|
|
+ currentSets.pipeline = pipelineGPU;
|
|
|
|
|
|
- const setPipelineAndBindings = ( passEncoderGPU, currentSets ) => {
|
|
|
+ // bind groups
|
|
|
+ const currentBindingGroups = currentSets.bindingGroups;
|
|
|
+ for ( let i = 0, l = bindings.length; i < l; i ++ ) {
|
|
|
|
|
|
- // pipeline
|
|
|
- this.pipelineUtils.setPipeline( passEncoderGPU, pipelineGPU );
|
|
|
- currentSets.pipeline = pipelineGPU;
|
|
|
+ const bindGroup = bindings[ i ];
|
|
|
+ const bindingsData = this.get( bindGroup );
|
|
|
+ if ( currentBindingGroups[ bindGroup.index ] !== bindGroup.id ) {
|
|
|
|
|
|
- // bind groups
|
|
|
- const currentBindingGroups = currentSets.bindingGroups;
|
|
|
- for ( let i = 0, l = bindings.length; i < l; i ++ ) {
|
|
|
+ passEncoderGPU.setBindGroup( bindGroup.index, bindingsData.group );
|
|
|
+ currentBindingGroups[ bindGroup.index ] = bindGroup.id;
|
|
|
|
|
|
- const bindGroup = bindings[ i ];
|
|
|
- const bindingsData = this.get( bindGroup );
|
|
|
- if ( currentBindingGroups[ bindGroup.index ] !== bindGroup.id ) {
|
|
|
+ }
|
|
|
|
|
|
- passEncoderGPU.setBindGroup( bindGroup.index, bindingsData.group );
|
|
|
- currentBindingGroups[ bindGroup.index ] = bindGroup.id;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ // attributes
|
|
|
|
|
|
- }
|
|
|
+ // index
|
|
|
|
|
|
- // attributes
|
|
|
+ if ( hasIndex === true ) {
|
|
|
|
|
|
- // index
|
|
|
+ if ( currentSets.index !== index ) {
|
|
|
|
|
|
- if ( hasIndex === true ) {
|
|
|
+ const buffer = this.get( index ).buffer;
|
|
|
+ const indexFormat = ( index.array instanceof Uint16Array ) ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32;
|
|
|
|
|
|
- if ( currentSets.index !== index ) {
|
|
|
+ passEncoderGPU.setIndexBuffer( buffer, indexFormat );
|
|
|
|
|
|
- const buffer = this.get( index ).buffer;
|
|
|
- const indexFormat = ( index.array instanceof Uint16Array ) ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32;
|
|
|
+ currentSets.index = index;
|
|
|
|
|
|
- passEncoderGPU.setIndexBuffer( buffer, indexFormat );
|
|
|
+ }
|
|
|
|
|
|
- currentSets.index = index;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ for ( let i = 0, l = vertexBuffers.length; i < l; i ++ ) {
|
|
|
|
|
|
- }
|
|
|
- // vertex buffers
|
|
|
+ const vertexBuffer = vertexBuffers[ i ];
|
|
|
|
|
|
- const vertexBuffers = renderObject.getVertexBuffers();
|
|
|
+ if ( currentSets.attributes[ i ] !== vertexBuffer ) {
|
|
|
|
|
|
- for ( let i = 0, l = vertexBuffers.length; i < l; i ++ ) {
|
|
|
+ const buffer = this.get( vertexBuffer ).buffer;
|
|
|
+ passEncoderGPU.setVertexBuffer( i, buffer );
|
|
|
|
|
|
- const vertexBuffer = vertexBuffers[ i ];
|
|
|
+ currentSets.attributes[ i ] = vertexBuffer;
|
|
|
|
|
|
- if ( currentSets.attributes[ i ] !== vertexBuffer ) {
|
|
|
+ }
|
|
|
|
|
|
- const buffer = this.get( vertexBuffer ).buffer;
|
|
|
- passEncoderGPU.setVertexBuffer( i, buffer );
|
|
|
+ }
|
|
|
+ // stencil
|
|
|
|
|
|
- currentSets.attributes[ i ] = vertexBuffer;
|
|
|
+ if ( context.stencil === true && material.stencilWrite === true && renderContextData.currentStencilRef !== material.stencilRef ) {
|
|
|
|
|
|
- }
|
|
|
+ passEncoderGPU.setStencilReference( material.stencilRef );
|
|
|
+ renderContextData.currentStencilRef = material.stencilRef;
|
|
|
|
|
|
- }
|
|
|
- // stencil
|
|
|
+ }
|
|
|
|
|
|
- if ( context.stencil === true && material.stencilWrite === true && renderContextData.currentStencilRef !== material.stencilRef ) {
|
|
|
+ if ( object.isBatchedMesh === true ) {
|
|
|
|
|
|
- passEncoderGPU.setStencilReference( material.stencilRef );
|
|
|
- renderContextData.currentStencilRef = material.stencilRef;
|
|
|
+ const starts = object._multiDrawStarts;
|
|
|
+ const counts = object._multiDrawCounts;
|
|
|
+ const drawCount = object._multiDrawCount;
|
|
|
+ const drawInstances = object._multiDrawInstances;
|
|
|
|
|
|
- }
|
|
|
+ if ( drawInstances !== null ) {
|
|
|
|
|
|
+ // @deprecated, r174
|
|
|
+ warnOnce( 'WebGPUBackend: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection.' );
|
|
|
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
- // Define draw function
|
|
|
- const draw = ( passEncoderGPU, currentSets ) => {
|
|
|
+ let bytesPerElement = ( hasIndex === true ) ? index.array.BYTES_PER_ELEMENT : 1;
|
|
|
|
|
|
- setPipelineAndBindings( passEncoderGPU, currentSets );
|
|
|
+ if ( material.wireframe ) {
|
|
|
|
|
|
- if ( object.isBatchedMesh === true ) {
|
|
|
+ bytesPerElement = object.geometry.attributes.position.count > 65535 ? 4 : 2;
|
|
|
|
|
|
- const starts = object._multiDrawStarts;
|
|
|
- const counts = object._multiDrawCounts;
|
|
|
- const drawCount = object._multiDrawCount;
|
|
|
- const drawInstances = object._multiDrawInstances;
|
|
|
+ }
|
|
|
|
|
|
- if ( drawInstances !== null ) {
|
|
|
+ for ( let i = 0; i < drawCount; i ++ ) {
|
|
|
|
|
|
- // @deprecated, r174
|
|
|
- warnOnce( 'WebGPUBackend: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection.' );
|
|
|
+ const count = drawInstances ? drawInstances[ i ] : 1;
|
|
|
+ const firstInstance = count > 1 ? 0 : i;
|
|
|
|
|
|
- }
|
|
|
+ if ( hasIndex === true ) {
|
|
|
|
|
|
- let bytesPerElement = ( hasIndex === true ) ? index.array.BYTES_PER_ELEMENT : 1;
|
|
|
+ passEncoderGPU.drawIndexed( counts[ i ], count, starts[ i ] / bytesPerElement, 0, firstInstance );
|
|
|
|
|
|
- if ( material.wireframe ) {
|
|
|
+ } else {
|
|
|
|
|
|
- bytesPerElement = object.geometry.attributes.position.count > 65535 ? 4 : 2;
|
|
|
+ passEncoderGPU.draw( counts[ i ], count, starts[ i ], firstInstance );
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( let i = 0; i < drawCount; i ++ ) {
|
|
|
+ info.update( object, counts[ i ], count );
|
|
|
|
|
|
- const count = drawInstances ? drawInstances[ i ] : 1;
|
|
|
- const firstInstance = count > 1 ? 0 : i;
|
|
|
+ }
|
|
|
|
|
|
- if ( hasIndex === true ) {
|
|
|
+ } else if ( hasIndex === true ) {
|
|
|
|
|
|
- passEncoderGPU.drawIndexed( counts[ i ], count, starts[ i ] / bytesPerElement, 0, firstInstance );
|
|
|
+ const { vertexCount: indexCount, instanceCount, firstVertex: firstIndex } = drawParams;
|
|
|
|
|
|
- } else {
|
|
|
+ const indirect = renderObject.getIndirect();
|
|
|
|
|
|
- passEncoderGPU.draw( counts[ i ], count, starts[ i ], firstInstance );
|
|
|
+ if ( indirect !== null ) {
|
|
|
|
|
|
- }
|
|
|
+ const buffer = this.get( indirect ).buffer;
|
|
|
+ const indirectOffset = renderObject.getIndirectOffset();
|
|
|
+ const indirectOffsets = Array.isArray( indirectOffset ) ? indirectOffset : [ indirectOffset ];
|
|
|
+
|
|
|
+ for ( let i = 0; i < indirectOffsets.length; i ++ ) {
|
|
|
|
|
|
- info.update( object, counts[ i ], count );
|
|
|
+ passEncoderGPU.drawIndexedIndirect( buffer, indirectOffsets[ i ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- } else if ( hasIndex === true ) {
|
|
|
+ } else {
|
|
|
|
|
|
- const { vertexCount: indexCount, instanceCount, firstVertex: firstIndex } = drawParams;
|
|
|
+ passEncoderGPU.drawIndexed( indexCount, instanceCount, firstIndex, 0, 0 );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- const indirect = renderObject.getIndirect();
|
|
|
+ info.update( object, indexCount, instanceCount );
|
|
|
|
|
|
- if ( indirect !== null ) {
|
|
|
+ } else {
|
|
|
|
|
|
- const buffer = this.get( indirect ).buffer;
|
|
|
- const indirectOffset = renderObject.getIndirectOffset();
|
|
|
- const indirectOffsets = Array.isArray( indirectOffset ) ? indirectOffset : [ indirectOffset ];
|
|
|
+ const { vertexCount, instanceCount, firstVertex } = drawParams;
|
|
|
|
|
|
- for ( let i = 0; i < indirectOffsets.length; i ++ ) {
|
|
|
+ const indirect = renderObject.getIndirect();
|
|
|
|
|
|
- passEncoderGPU.drawIndexedIndirect( buffer, indirectOffsets[ i ] );
|
|
|
+ if ( indirect !== null ) {
|
|
|
|
|
|
- }
|
|
|
+ const buffer = this.get( indirect ).buffer;
|
|
|
+ const indirectOffset = renderObject.getIndirectOffset();
|
|
|
+ const indirectOffsets = Array.isArray( indirectOffset ) ? indirectOffset : [ indirectOffset ];
|
|
|
|
|
|
- } else {
|
|
|
+ for ( let i = 0; i < indirectOffsets.length; i ++ ) {
|
|
|
|
|
|
- passEncoderGPU.drawIndexed( indexCount, instanceCount, firstIndex, 0, 0 );
|
|
|
+ passEncoderGPU.drawIndirect( buffer, indirectOffsets[ i ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- info.update( object, indexCount, instanceCount );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- const { vertexCount, instanceCount, firstVertex } = drawParams;
|
|
|
-
|
|
|
- const indirect = renderObject.getIndirect();
|
|
|
-
|
|
|
- if ( indirect !== null ) {
|
|
|
+ passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 );
|
|
|
|
|
|
- const buffer = this.get( indirect ).buffer;
|
|
|
- const indirectOffset = renderObject.getIndirectOffset();
|
|
|
- const indirectOffsets = Array.isArray( indirectOffset ) ? indirectOffset : [ indirectOffset ];
|
|
|
+ }
|
|
|
|
|
|
- for ( let i = 0; i < indirectOffsets.length; i ++ ) {
|
|
|
+ info.update( object, vertexCount, instanceCount );
|
|
|
|
|
|
- passEncoderGPU.drawIndirect( buffer, indirectOffsets[ i ] );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
+ // render object
|
|
|
|
|
|
- } else {
|
|
|
+ /**
|
|
|
+ * Executes a draw command for the given render object.
|
|
|
+ *
|
|
|
+ * @param {RenderObject} renderObject - The render object to draw.
|
|
|
+ * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process.
|
|
|
+ */
|
|
|
+ draw( renderObject, info ) {
|
|
|
|
|
|
- passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 );
|
|
|
+ const { object, context, pipeline } = renderObject;
|
|
|
+ const renderContextData = this.get( context );
|
|
|
+ const pipelineData = this.get( pipeline );
|
|
|
+ const pipelineGPU = pipelineData.pipeline;
|
|
|
|
|
|
- }
|
|
|
+ // Skip if pipeline has error
|
|
|
+ if ( pipelineData.error === true ) return;
|
|
|
|
|
|
- info.update( object, vertexCount, instanceCount );
|
|
|
+ const drawParams = renderObject.getDrawParameters();
|
|
|
+ if ( drawParams === null ) return;
|
|
|
|
|
|
- }
|
|
|
+ // vertex buffers
|
|
|
|
|
|
- };
|
|
|
+ const vertexBuffers = renderObject.getVertexBuffers();
|
|
|
|
|
|
if ( renderObject.camera.isArrayCamera && renderObject.camera.cameras.length > 0 ) {
|
|
|
|
|
|
@@ -1767,8 +1773,7 @@ class WebGPUBackend extends Backend {
|
|
|
|
|
|
}
|
|
|
|
|
|
- draw( pass, sets );
|
|
|
-
|
|
|
+ this._draw( renderObject, info, renderContextData, pipelineGPU, vertexBuffers, drawParams, pass, sets );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -1805,7 +1810,7 @@ class WebGPUBackend extends Backend {
|
|
|
|
|
|
}
|
|
|
|
|
|
- draw( renderContextData.currentPass, renderContextData.currentSets );
|
|
|
+ this._draw( renderObject, info, renderContextData, pipelineGPU, vertexBuffers, drawParams, renderContextData.currentPass, renderContextData.currentSets );
|
|
|
|
|
|
}
|
|
|
|