Pārlūkot izejas kodu

Render pipeline cache optimization

Popov72 4 gadi atpakaļ
vecāks
revīzija
61ca2cdd7a

+ 48 - 50
src/Engines/WebGPU/webgpuCacheRenderPipeline.ts

@@ -740,35 +740,34 @@ export class WebGPUCacheRenderPipeline {
         const currStateLen = this._states.length;
         let newNumStates = StatePosition.VertexState;
 
-        const attributes = effect.getAttributesNames();
+        const webgpuPipelineContext = effect._pipelineContext as WebGPUPipelineContext;
+        const attributes = webgpuPipelineContext.shaderProcessingContext.attributeNamesFromEffect;
+        const locations = webgpuPipelineContext.shaderProcessingContext.attributeLocationsFromEffect;
         for (var index = 0; index < attributes.length; index++) {
-            const location = effect.getAttributeLocation(index);
-
-            if (location >= 0) {
-                let  vertexBuffer = this._vertexBuffers![attributes[index]];
-                if (!vertexBuffer) {
-                    // In WebGL it's valid to not bind a vertex buffer to an attribute, but it's not valid in WebGPU
-                    // So we must bind a dummy buffer when we are not given one for a specific attribute
-                    vertexBuffer = this._emptyVertexBuffer;
-                }
-
-                const type = vertexBuffer.type - 5120;
-                const normalized = vertexBuffer.normalized ? 1 : 0;
-                const size = vertexBuffer.getSize();
-                const stepMode = vertexBuffer.getIsInstanced() ? 1 : 0;
-                const stride = vertexBuffer.byteStride;
-
-                const vid =
-                    ((type << 0) +
-                    (normalized << 3) +
-                    (size << 4) +
-                    (stepMode << 6) +
-                    (location << 7) +
-                    (stride << 12)).toString();
-
-                this._isDirty = this._isDirty || this._states[newNumStates] !== vid;
-                this._states[newNumStates++] = vid;
+            const location = locations[index];
+            let  vertexBuffer = this._vertexBuffers![attributes[index]];
+            if (!vertexBuffer) {
+                // In WebGL it's valid to not bind a vertex buffer to an attribute, but it's not valid in WebGPU
+                // So we must bind a dummy buffer when we are not given one for a specific attribute
+                vertexBuffer = this._emptyVertexBuffer;
             }
+
+            const type = vertexBuffer.type - 5120;
+            const normalized = vertexBuffer.normalized ? 1 : 0;
+            const size = vertexBuffer.getSize();
+            const stepMode = vertexBuffer.getIsInstanced() ? 1 : 0;
+            const stride = vertexBuffer.byteStride;
+
+            const vid =
+                ((type << 0) +
+                (normalized << 3) +
+                (size << 4) +
+                (stepMode << 6) +
+                (location << 7) +
+                (stride << 12)).toString();
+
+            this._isDirty = this._isDirty || this._states[newNumStates] !== vid;
+            this._states[newNumStates++] = vid;
         }
 
         this._states.length = newNumStates;
@@ -846,33 +845,32 @@ export class WebGPUCacheRenderPipeline {
 
     private _getVertexInputDescriptor(effect: Effect, topology: GPUPrimitiveTopology): GPUVertexStateDescriptor {
         const descriptors: GPUVertexBufferLayoutDescriptor[] = [];
-        const attributes = effect.getAttributesNames();
+        const webgpuPipelineContext = effect._pipelineContext as WebGPUPipelineContext;
+        const attributes = webgpuPipelineContext.shaderProcessingContext.attributeNamesFromEffect;
+        const locations = webgpuPipelineContext.shaderProcessingContext.attributeLocationsFromEffect;
         for (var index = 0; index < attributes.length; index++) {
-            const location = effect.getAttributeLocation(index);
-
-            if (location >= 0) {
-                let  vertexBuffer = this._vertexBuffers![attributes[index]];
-                if (!vertexBuffer) {
-                    // In WebGL it's valid to not bind a vertex buffer to an attribute, but it's not valid in WebGPU
-                    // So we must bind a dummy buffer when we are not given one for a specific attribute
-                    vertexBuffer = this._emptyVertexBuffer;
-                }
+            const location = locations[index];
+            let  vertexBuffer = this._vertexBuffers![attributes[index]];
+            if (!vertexBuffer) {
+                // In WebGL it's valid to not bind a vertex buffer to an attribute, but it's not valid in WebGPU
+                // So we must bind a dummy buffer when we are not given one for a specific attribute
+                vertexBuffer = this._emptyVertexBuffer;
+            }
 
-                const attributeDescriptor: GPUVertexAttributeDescriptor = {
-                    shaderLocation: location,
-                    offset: 0, // not available in WebGL
-                    format: WebGPUCacheRenderPipeline._GetVertexInputDescriptorFormat(vertexBuffer),
-                };
+            const attributeDescriptor: GPUVertexAttributeDescriptor = {
+                shaderLocation: location,
+                offset: 0, // not available in WebGL
+                format: WebGPUCacheRenderPipeline._GetVertexInputDescriptorFormat(vertexBuffer),
+            };
 
-                // TODO WEBGPU. Factorize the one with the same underlying buffer.
-                const vertexBufferDescriptor: GPUVertexBufferLayoutDescriptor = {
-                    arrayStride: vertexBuffer.byteStride,
-                    stepMode: vertexBuffer.getIsInstanced() ? WebGPUConstants.InputStepMode.Instance : WebGPUConstants.InputStepMode.Vertex,
-                    attributes: [attributeDescriptor]
-                };
+            // TODO WEBGPU. Factorize the one with the same underlying buffer.
+            const vertexBufferDescriptor: GPUVertexBufferLayoutDescriptor = {
+                arrayStride: vertexBuffer.byteStride,
+                stepMode: vertexBuffer.getIsInstanced() ? WebGPUConstants.InputStepMode.Instance : WebGPUConstants.InputStepMode.Vertex,
+                attributes: [attributeDescriptor]
+            };
 
-               descriptors.push(vertexBufferDescriptor);
-            }
+            descriptors.push(vertexBufferDescriptor);
         }
 
         const inputStateDescriptor: GPUVertexStateDescriptor = {

+ 12 - 0
src/Engines/WebGPU/webgpuPipelineContext.ts

@@ -144,6 +144,18 @@ export class WebGPUPipelineContext implements IPipelineContext {
 
         // Build the uniform layout for the left over uniforms.
         this.buildUniformLayout();
+
+        let attributeNamesFromEffect: string[] = [];
+        let attributeLocationsFromEffect: number[] = [];
+        for (index = 0; index < attributesNames.length; index++) {
+            const location = attributes[index];
+            if (location >= 0) {
+                attributeNamesFromEffect.push(attributesNames[index]);
+                attributeLocationsFromEffect.push(location);
+            }
+        }
+        this.shaderProcessingContext.attributeNamesFromEffect = attributeNamesFromEffect;
+        this.shaderProcessingContext.attributeLocationsFromEffect = attributeLocationsFromEffect;
     }
 
     /** @hidden */

+ 2 - 0
src/Engines/WebGPU/webgpuShaderProcessingContext.ts

@@ -57,6 +57,8 @@ export class WebGPUShaderProcessingContext implements ShaderProcessingContext {
     public orderedAttributes: string[];
     public orderedUBOsAndSamplers: WebGPUBindingDescription[][];
     public uniformBufferNames: string[];
+    public attributeNamesFromEffect: string[];
+    public attributeLocationsFromEffect: number[];
 
     private _attributeNextLocation: number;
     private _varyingNextLocation: number;

+ 12 - 16
src/Engines/webgpuEngine.ts

@@ -3455,6 +3455,7 @@ export class WebGPUEngine extends Engine {
             webgpuPipelineContext.uniformBuffer.update();
         }
 
+        // TODO WEBGPU try to optimize this loop / lookup in bindGroupsCache
         let bufferKey = "";
         for (let i = 0; i < webgpuPipelineContext.shaderProcessingContext.uniformBufferNames.length; ++i) {
             const bufferName = webgpuPipelineContext.shaderProcessingContext.uniformBufferNames[i];
@@ -3567,24 +3568,19 @@ export class WebGPUEngine extends Engine {
             renderPass.setIndexBuffer(this._currentIndexBuffer.underlyingResource, this._currentIndexBuffer!.is32Bits ? WebGPUConstants.IndexFormat.Uint32 : WebGPUConstants.IndexFormat.Uint16, 0);
         }
 
-        const effect = this._currentEffect!;
-        const attributes = effect.getAttributesNames();
-        let bufferIdx = 0;
+        const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
+        const attributes = webgpuPipelineContext.shaderProcessingContext.attributeNamesFromEffect;
         for (var index = 0; index < attributes.length; index++) {
-            const order = effect.getAttributeLocation(index);
-
-            if (order >= 0) {
-                let vertexBuffer = this._currentVertexBuffers![attributes[index]];
-                if (!vertexBuffer) {
-                    // In WebGL it's valid to not bind a vertex buffer to an attribute, but it's not valid in WebGPU
-                    // So we must bind a dummy buffer when we are not given one for a specific attribute
-                    vertexBuffer = this._emptyVertexBuffer;
-                }
+            let vertexBuffer = this._currentVertexBuffers![attributes[index]];
+            if (!vertexBuffer) {
+                // In WebGL it's valid to not bind a vertex buffer to an attribute, but it's not valid in WebGPU
+                // So we must bind a dummy buffer when we are not given one for a specific attribute
+                vertexBuffer = this._emptyVertexBuffer;
+            }
 
-                const buffer = vertexBuffer.getBuffer();
-                if (buffer) {
-                    renderPass.setVertexBuffer(bufferIdx++, buffer.underlyingResource, vertexBuffer.byteOffset);
-                }
+            const buffer = vertexBuffer.getBuffer();
+            if (buffer) {
+                renderPass.setVertexBuffer(index, buffer.underlyingResource, vertexBuffer.byteOffset);
             }
         }
     }