浏览代码

Recreate the render pipeline if some of its settings change

Popov72 4 年之前
父节点
当前提交
f2eb9f0a50
共有 1 个文件被更改,包括 167 次插入6 次删除
  1. 167 6
      src/Engines/webgpuEngine.ts

+ 167 - 6
src/Engines/webgpuEngine.ts

@@ -43,11 +43,22 @@ function assert(condition: any, msg?: string): asserts condition {
 const dbgShowShaderCode = false;
 const dbgSanityChecks = true;
 const dbgGenerateLogs = true;
-const dbgVerboseLogsForFirstFrames = false;
+const dbgVerboseLogsForFirstFrames = true;
 const dbgVerboseLogsNumFrames = 20;
 const dbgShowWarningsNotImplemented = true;
 export const dbgShowDebugInliningProcess = false;
 
+const enum RenderPipelineDirtyFlags {
+    rasterizationState = 1,
+    colorStates = 2,
+    depthStencilState = 4,
+    vertexState = 8,
+    sampleCount = 16,
+    sampleMask = 32,
+    alphaToCoverageEnabled = 64,
+    all = 0xFFFF
+}
+
 /**
  * Options to load the associated Glslang library
  */
@@ -162,6 +173,12 @@ export class WebGPUEngine extends Engine {
     private _bufferManager: WebGPUBufferManager;
     private _deferredReleaseTextures: Array<[InternalTexture, Nullable<HardwareTextureWrapper>, Nullable<BaseTexture>, Nullable<InternalTexture>]> = [];
     private _deferredReleaseBuffers: Array<GPUBuffer> = [];
+    private _renderPipelineDirtyFlags = 0;
+    private _counters: {
+        numPipelineDescriptorCreation: number;
+    } = {
+        numPipelineDescriptorCreation: 0
+    };
 
     // Some of the internal state might change during the render pass.
     // This happens mainly during clear for the state
@@ -523,6 +540,7 @@ export class WebGPUEngine extends Engine {
         this._resetCachedViewport();
         this._currentIndexBuffer = null;
         this._currentVertexBuffers = null;
+        this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.all);
 
         if (bruteForce) {
             this._currentProgram = null;
@@ -537,7 +555,6 @@ export class WebGPUEngine extends Engine {
             this._alphaEquation = Constants.ALPHA_DISABLE;
 
             this.__colorWrite = true;
-            this._colorWriteChanged = true;
         }
 
         this._cachedVertexBuffers = null;
@@ -547,6 +564,7 @@ export class WebGPUEngine extends Engine {
 
     public setColorWrite(enable: boolean): void {
         this.__colorWrite = enable;
+        this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.colorStates);
     }
 
     public getColorWrite(): boolean {
@@ -749,6 +767,7 @@ export class WebGPUEngine extends Engine {
     public bindBuffers(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, indexBuffer: Nullable<DataBuffer>, effect: Effect): void {
         this._currentIndexBuffer = indexBuffer;
         this._currentVertexBuffers = vertexBuffers;
+        this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.vertexState);
     }
 
     /** @hidden */
@@ -2023,6 +2042,8 @@ export class WebGPUEngine extends Engine {
      * Begin a new frame
      */
     public beginFrame(): void {
+        this._counters.numPipelineDescriptorCreation = 0;
+
         if (dbgVerboseLogsForFirstFrames) {
             if (!(this as any)._count || (this as any)._count < dbgVerboseLogsNumFrames) {
                 if (!(this as any)._count) {
@@ -2301,6 +2322,131 @@ export class WebGPUEngine extends Engine {
     //                              Render
     //------------------------------------------------------------------------------
 
+    private _renderPipelineSetDirtyFlags(flags: number): void {
+        this._renderPipelineDirtyFlags |= flags;
+    }
+
+    // TODO WEBGPU make sure all state changes are handled
+    public setZOffset(value: number): void {
+        if (value !== this._depthCullingState.zOffset) {
+            this._depthCullingState.zOffset = value;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.rasterizationState);
+        }
+    }
+
+    public setDepthBuffer(enable: boolean): void {
+        if (this._depthCullingState.depthTest !== enable) {
+            this._depthCullingState.depthTest = enable;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setDepthWrite(enable: boolean): void {
+        if (this._depthCullingState.depthMask !== enable) {
+            this._depthCullingState.depthMask = enable;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilBuffer(enable: boolean): void {
+        if (this._stencilState.stencilTest !== enable) {
+            this._stencilState.stencilTest = enable;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilMask(mask: number): void {
+        if (this._stencilState.stencilMask !== mask) {
+            this._stencilState.stencilMask = mask;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilFunction(stencilFunc: number) {
+        if (this._stencilState.stencilFunc !== stencilFunc) {
+            this._stencilState.stencilFunc = stencilFunc;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilFunctionReference(reference: number) {
+        if (this._stencilState.stencilFuncRef !== reference) {
+            this._stencilState.stencilFuncRef = reference;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilFunctionMask(mask: number) {
+        if (this._stencilState.stencilFuncMask !== mask) {
+            this._stencilState.stencilFuncMask = mask;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilOperationFail(operation: number): void {
+        if (this._stencilState.stencilOpStencilFail !== operation) {
+            this._stencilState.stencilOpStencilFail = operation;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilOperationDepthFail(operation: number): void {
+        if (this._stencilState.stencilOpDepthFail !== operation) {
+            this._stencilState.stencilOpDepthFail = operation;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setStencilOperationPass(operation: number): void {
+        if (this._stencilState.stencilOpStencilDepthPass !== operation) {
+            this._stencilState.stencilOpStencilDepthPass = operation;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setDitheringState(value: boolean): void {
+        // Does not exist in WebGPU
+    }
+
+    public setRasterizerState(value: boolean): void {
+        // Does not exist in WebGPU
+    }
+
+    public setDepthFunction(depthFunc: number) {
+        if (this._depthCullingState.depthFunc !== depthFunc) {
+            this._depthCullingState.depthFunc = depthFunc;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setDepthFunctionToGreater(): void {
+        if (this._depthCullingState.depthFunc !== Constants.GREATER) {
+            this._depthCullingState.depthFunc = Constants.GREATER;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setDepthFunctionToGreaterOrEqual(): void {
+        if (this._depthCullingState.depthFunc !== Constants.GEQUAL) {
+            this._depthCullingState.depthFunc = Constants.GEQUAL;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setDepthFunctionToLess(): void {
+        if (this._depthCullingState.depthFunc !== Constants.LESS) {
+            this._depthCullingState.depthFunc = Constants.LESS;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
+    public setDepthFunctionToLessOrEqual(): void {
+        if (this._depthCullingState.depthFunc !== Constants.LEQUAL) {
+            this._depthCullingState.depthFunc = Constants.LEQUAL;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.depthStencilState);
+        }
+    }
+
     private _indexFormatInRenderPass(topology: GPUPrimitiveTopology): boolean {
         return  topology === WebGPUConstants.PrimitiveTopology.PointList ||
                 topology === WebGPUConstants.PrimitiveTopology.LineList ||
@@ -2420,6 +2566,7 @@ export class WebGPUEngine extends Engine {
         // Culling
         if (this._depthCullingState.cull !== culling || force) {
             this._depthCullingState.cull = culling;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.rasterizationState);
         }
 
         // Cull face
@@ -2427,6 +2574,7 @@ export class WebGPUEngine extends Engine {
         var cullFace = this.cullBackFaces ? 1 : 2;
         if (this._depthCullingState.cullFace !== cullFace || force) {
             this._depthCullingState.cullFace = cullFace;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.rasterizationState);
         }
 
         // Z offset
@@ -2437,6 +2585,7 @@ export class WebGPUEngine extends Engine {
         var frontFace = reverseSide ? 1 : 2;
         if (this._depthCullingState.frontFace !== frontFace || force) {
             this._depthCullingState.frontFace = frontFace;
+            this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.rasterizationState);
         }
     }
 
@@ -2549,6 +2698,7 @@ export class WebGPUEngine extends Engine {
             this.setDepthWrite(mode === Engine.ALPHA_DISABLE);
         }
         this._alphaMode = mode;
+        this._renderPipelineSetDirtyFlags(RenderPipelineDirtyFlags.colorStates);
     }
 
     private _getAphaBlendOperation(operation: Nullable<number>): GPUBlendOperation {
@@ -2829,6 +2979,8 @@ export class WebGPUEngine extends Engine {
             return webgpuPipelineContext.renderPipeline;
         }
 
+        this._counters.numPipelineDescriptorCreation++;
+
         // Unsupported at the moment but needs to be extracted from the MSAA param.
         const rasterizationStateDescriptor = this._getRasterizationStateDescriptor();
         const depthStateDescriptor = this._getDepthStencilStateDescriptor();
@@ -3050,6 +3202,8 @@ export class WebGPUEngine extends Engine {
     }
 
     private _setRenderPipeline(fillMode: number): void {
+        this.applyStates();
+
         const renderPass = this._bundleEncoder || this._getCurrentRenderPass();
 
         const topology = this._getTopology(fillMode);
@@ -3217,13 +3371,20 @@ export class WebGPUEngine extends Engine {
 
     public _unpackFlipY(value: boolean) { }
 
-    // TODO WEBGPU. All of the below should go once engine split with baseEngine.
-
     public applyStates() {
-        // Apply States dynamically.
-        // This is done at the pipeline creation level for the moment...
+        if (!this._currentEffect || !this._renderPipelineDirtyFlags) {
+            return;
+        }
+
+        // We can't update only a part of the pipeline descriptor, we must recreate the whole pipeline if any setting changes
+        const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
+        webgpuPipelineContext.renderPipeline = null as any;
+
+        this._renderPipelineDirtyFlags = 0;
     }
 
+    // TODO WEBGPU. All of the below should go once engine split with baseEngine.
+
     /** @hidden */
     public _getSamplingParameters(samplingMode: number, generateMipMaps: boolean): { min: number; mag: number } {
         throw "_getSamplingParameters is not available in WebGPU";