Parcourir la source

Remove the WebGPUEngineCache class

Popov72 il y a 4 ans
Parent
commit
214c6efd73

+ 0 - 1
src/Engines/index.ts

@@ -10,7 +10,6 @@ export * from "./IPipelineContext";
 export * from "./WebGL/webGLPipelineContext";
 export * from "./WebGPU/webgpuConstants";
 export * from "./webgpuEngine";
-export * from "./webgpuEngineCache";
 export * from "./WebGPU/webgpuCacheRenderPipeline";
 export * from "./WebGL/webGL2ShaderProcessors";
 export * from "./nativeEngine";

+ 119 - 577
src/Engines/webgpuEngine.ts

@@ -11,7 +11,7 @@ import { _TimeToken } from "../Instrumentation/timeToken";
 import { Constants } from "./constants";
 import * as WebGPUConstants from './WebGPU/webgpuConstants';
 import { VertexBuffer } from "../Meshes/buffer";
-import { WebGPUPipelineContext, IWebGPUPipelineContextVertexInputsCache, IWebGPURenderPipelineStageDescriptor } from './WebGPU/webgpuPipelineContext';
+import { WebGPUPipelineContext, IWebGPURenderPipelineStageDescriptor } from './WebGPU/webgpuPipelineContext';
 import { IPipelineContext } from './IPipelineContext';
 import { DataBuffer } from '../Meshes/dataBuffer';
 import { WebGPUDataBuffer } from '../Meshes/WebGPU/webgpuDataBuffer';
@@ -35,6 +35,7 @@ import { WebGPURenderPassWrapper } from './WebGPU/webgpuRenderPassWrapper';
 import { IMultiRenderTargetOptions } from '../Materials/Textures/multiRenderTarget';
 import { WebGPUCacheSampler } from "./WebGPU/webgpuCacheSampler";
 import { WebGPUShaderManager } from "./WebGPU/webgpuShaderManager";
+import { WebGPUCacheRenderPipeline } from "./WebGPU/webgpuCacheRenderPipeline";
 
 import "../Shaders/clearQuad.vertex";
 import "../Shaders/clearQuad.fragment";
@@ -173,19 +174,16 @@ export class WebGPUEngine extends Engine {
     private _bufferManager: WebGPUBufferManager;
     private _shaderManager: WebGPUShaderManager;
     private _cacheSampler: WebGPUCacheSampler;
+    private _cacheRenderPipeline: WebGPUCacheRenderPipeline;
     private _emptyVertexBuffer: VertexBuffer;
     private _lastCachedWrapU: number;
     private _lastCachedWrapV: number;
     private _lastCachedWrapR: number;
     private _mrtAttachments: number[];
     private _counters: {
-        numPipelineDescriptorCreation: number;
         numBindGroupsCreation: number;
-        numVertexInputCacheCreation: number;
     } = {
-        numPipelineDescriptorCreation: 0,
         numBindGroupsCreation: 0,
-        numVertexInputCacheCreation: 0,
     };
 
     // Some of the internal state might change during the render pass.
@@ -234,6 +232,32 @@ export class WebGPUEngine extends Engine {
     public dbgShowWarningsNotImplemented = false;
 
     /**
+     * Sets this to true to disable the cache for the samplers. You should do it only for testing purpose!
+     */
+    public get disableCacheSamplers(): boolean {
+        return this._cacheSampler ? this._cacheSampler.disabled : false;
+    }
+
+    public set disableCacheSamplers(disable: boolean) {
+        if (this._cacheSampler) {
+            this._cacheSampler.disabled = disable;
+        }
+    }
+
+    /**
+     * Sets this to true to disable the cache for the render pipelines. You should do it only for testing purpose!
+     */
+    public get disableCacheRenderPipelines(): boolean {
+        return this._cacheRenderPipeline ? this._cacheRenderPipeline.disabled : false;
+    }
+
+    public set disableCacheRenderPipelines(disable: boolean) {
+        if (this._cacheRenderPipeline) {
+            this._cacheRenderPipeline.disabled = disable;
+        }
+    }
+
+    /**
      * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
      * @returns true if the engine can be created
      */
@@ -269,7 +293,7 @@ export class WebGPUEngine extends Engine {
      * Returns a string describing the current engine
      */
     public get description(): string {
-        let description = this.name + this.version;
+        let description = this.name + this.version + " (cache)";
 
         return description;
     }
@@ -309,7 +333,7 @@ export class WebGPUEngine extends Engine {
         options.stencil = options.stencil ?? true;
         options.enableGPUDebugMarkers = options.enableGPUDebugMarkers ?? false;
 
-        Logger.Log(`Babylon.js v${Engine.Version} - WebGPU engine`);
+        Logger.Log(`Babylon.js v${Engine.Version} - ${this.description} engine`);
         if (!navigator.gpu) {
             Logger.Error("WebGPU is not supported by your browser.");
             return;
@@ -416,10 +440,15 @@ export class WebGPUEngine extends Engine {
                 this._renderEncoder = this._device.createCommandEncoder(this._renderEncoderDescriptor);
                 this._renderTargetEncoder = this._device.createCommandEncoder(this._renderTargetEncoderDescriptor);
 
-                this._textureHelper.setCommandEncoder(this._uploadEncoder);
-
                 this._emptyVertexBuffer = new VertexBuffer(this, [0], "", false, false, 1, false, 0, 1);
 
+                this._cacheRenderPipeline = new WebGPUCacheRenderPipeline(this._device, this._emptyVertexBuffer);
+
+                this._cacheRenderPipeline.setDepthCompare(this._depthCullingState.depthFunc);
+                //this._cacheRenderPipeline.disabled = true;
+
+                this._textureHelper.setCommandEncoder(this._uploadEncoder);
+
                 this._initializeLimits();
                 this._initializeContextAndSwapChain();
                 this._initializeMainAttachments();
@@ -672,20 +701,26 @@ export class WebGPUEngine extends Engine {
         this._forceEnableEffect = true;
         this._currentIndexBuffer = null;
         this._currentVertexBuffers = null;
+        this._cacheRenderPipeline.setBuffers(null, null);
 
         if (bruteForce) {
             this._currentProgram = null;
 
             this._stencilState.reset();
+            this._cacheRenderPipeline.resetStencilState();
 
             this._depthCullingState.reset();
             this._depthCullingState.depthFunc = Constants.LEQUAL;
+            this._cacheRenderPipeline.resetDepthCullingState();
+            this._cacheRenderPipeline.setDepthCompare(Constants.LEQUAL);
 
             this._alphaState.reset();
             this._alphaMode = Constants.ALPHA_ADD;
             this._alphaEquation = Constants.ALPHA_DISABLE;
+            this._cacheRenderPipeline.setAlphaBlendFactors(this._alphaState._blendFunctionParameters, this._alphaState._blendEquationParameters);
+            this._cacheRenderPipeline.setAlphaBlendEnabled(false);
 
-            this.__colorWrite = true;
+            this.setColorWrite(true);
         }
 
         this._cachedVertexBuffers = null;
@@ -699,6 +734,7 @@ export class WebGPUEngine extends Engine {
      */
     public setColorWrite(enable: boolean): void {
         this.__colorWrite = enable;
+        this._cacheRenderPipeline.setWriteMask(enable ? 0xF : 0);
     }
 
     /**
@@ -1029,6 +1065,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._cacheRenderPipeline.setBuffers(vertexBuffers, indexBuffer);
     }
 
     /** @hidden */
@@ -1758,8 +1795,7 @@ export class WebGPUEngine extends Engine {
 
             if (webgpuPipelineContext.textures[name]) {
                 if (webgpuPipelineContext.textures[name]!.texture !== internalTexture) {
-                    // TODO WEBGPU when the bindGroups has a caching mechanism set up, clear this cache
-                    //webgpuPipelineContext.bindGroups = null as any; // the bind groups need to be rebuilt (at least the bind group owning this texture, but it's easier to just have them all rebuilt)
+                    webgpuPipelineContext.bindGroupsCache = {}; // the bind groups need to be rebuilt (at least the bind group owning this texture, but it's easier to just have them all rebuilt)
                 }
                 webgpuPipelineContext.textures[name]!.texture = internalTexture!;
             }
@@ -1813,8 +1849,7 @@ export class WebGPUEngine extends Engine {
             const webgpuPipelineContext = this._currentEffect._pipelineContext as WebGPUPipelineContext;
             if (!texture) {
                 if (webgpuPipelineContext.textures[name] && webgpuPipelineContext.textures[name]!.texture) {
-                    // TODO WEBGPU when the bindGroups has a caching mechanism set up, clear this cache
-                    //webgpuPipelineContext.bindGroups = null as any; // the bind groups need to be rebuilt (at least the bind group owning this texture, but it's easier to just have them all rebuilt)
+                    webgpuPipelineContext.bindGroupsCache = {}; // the bind groups need to be rebuilt (at least the bind group owning this texture, but it's easier to just have them all rebuilt)
                 }
                 webgpuPipelineContext.textures[name] = null;
                 return false;
@@ -2639,8 +2674,7 @@ export class WebGPUEngine extends Engine {
         if (this.dbgVerboseLogsForFirstFrames) {
             if ((this as any)._count === undefined) { (this as any)._count = 0; }
             if (!(this as any)._count || (this as any)._count < this.dbgVerboseLogsNumFrames) {
-                console.log("frame #" + (this as any)._count + " - counters - numPipelineDescriptorCreation=", this._counters.numPipelineDescriptorCreation, ", numBindGroupsCreation=", this._counters.numBindGroupsCreation,
-                    ", numVertexInputCacheCreation=", this._counters.numVertexInputCacheCreation);
+                console.log("frame #" + (this as any)._count + " - counters - numBindGroupsCreation=", this._counters.numBindGroupsCreation);
             }
         }
 
@@ -2661,9 +2695,8 @@ export class WebGPUEngine extends Engine {
             UniformBuffer._updatedUbosInFrame = {};
         }
 
-        this._counters.numPipelineDescriptorCreation = 0;
         this._counters.numBindGroupsCreation = 0;
-        this._counters.numVertexInputCacheCreation = 0;
+        this._cacheRenderPipeline.endFrame();
 
         this._pendingDebugCommands.length = 0;
 
@@ -2765,6 +2798,7 @@ export class WebGPUEngine extends Engine {
                 }
             }
             this._mrtAttachments = internalTexture._attachments;
+            this._cacheRenderPipeline.setMRTAttachments(this._mrtAttachments, internalTexture._textureArray);
         } else {
             // single render target
             const gpuMSAATexture = gpuWrapper.msaaTexture;
@@ -2836,10 +2870,6 @@ export class WebGPUEngine extends Engine {
         return this._currentRenderPass!;
     }
 
-    private _currentRenderPassIsMRT(): boolean {
-        return !!this._currentRenderTarget?._attachments ?? false;
-    }
-
     private _startMainRenderPass(setClearStates: boolean, clearColor?: Nullable<IColor4Like>, clearDepth?: boolean, clearStencil?: boolean): void {
         if (this._mainRenderPassWrapper.renderPass) {
             this._endMainRenderPass();
@@ -3113,6 +3143,7 @@ export class WebGPUEngine extends Engine {
         this._currentRenderTarget = null;
 
         this._mrtAttachments = [];
+        this._cacheRenderPipeline.setMRTAttachments(this._mrtAttachments, []);
         this._currentRenderPass = this._mainRenderPassWrapper.renderPass;
         this._setDepthTextureFormat(this._mainRenderPassWrapper);
         this._setColorFormat(this._mainRenderPassWrapper);
@@ -3145,6 +3176,8 @@ export class WebGPUEngine extends Engine {
 
         this._currentRenderTarget = null;
 
+        this._mrtAttachments = [];
+        this._cacheRenderPipeline.setMRTAttachments(this._mrtAttachments, []);
         this._currentRenderPass = this._mainRenderPassWrapper.renderPass;
         this._setDepthTextureFormat(this._mainRenderPassWrapper);
         this._setColorFormat(this._mainRenderPassWrapper);
@@ -3182,6 +3215,7 @@ export class WebGPUEngine extends Engine {
 
     private _setColorFormat(wrapper: WebGPURenderPassWrapper): void {
         const format = wrapper.colorAttachmentGPUTextures[0].format;
+        this._cacheRenderPipeline.setColorFormat(format);
         if (this._colorFormat === format) {
             return;
         }
@@ -3189,6 +3223,7 @@ export class WebGPUEngine extends Engine {
     }
 
     private _setDepthTextureFormat(wrapper: WebGPURenderPassWrapper): void {
+        this._cacheRenderPipeline.setDepthStencilFormat(wrapper.depthTextureFormat);
         if (this._depthTextureFormat === wrapper.depthTextureFormat) {
             return;
         }
@@ -3293,89 +3328,6 @@ export class WebGPUEngine extends Engine {
         }
     }
 
-    private _indexFormatInRenderPass(topology: GPUPrimitiveTopology): boolean {
-        return  topology === WebGPUConstants.PrimitiveTopology.PointList ||
-                topology === WebGPUConstants.PrimitiveTopology.LineList ||
-                topology === WebGPUConstants.PrimitiveTopology.TriangleList;
-    }
-
-    private _getTopology(fillMode: number): GPUPrimitiveTopology {
-        switch (fillMode) {
-            // Triangle views
-            case Constants.MATERIAL_TriangleFillMode:
-                return WebGPUConstants.PrimitiveTopology.TriangleList;
-            case Constants.MATERIAL_PointFillMode:
-                return WebGPUConstants.PrimitiveTopology.PointList;
-            case Constants.MATERIAL_WireFrameFillMode:
-                return WebGPUConstants.PrimitiveTopology.LineList;
-            // Draw modes
-            case Constants.MATERIAL_PointListDrawMode:
-                return WebGPUConstants.PrimitiveTopology.PointList;
-            case Constants.MATERIAL_LineListDrawMode:
-                return WebGPUConstants.PrimitiveTopology.LineList;
-            case Constants.MATERIAL_LineLoopDrawMode:
-                // return this._gl.LINE_LOOP;
-                // TODO WEBGPU. Line Loop Mode Fallback at buffer load time.
-                throw "LineLoop is an unsupported fillmode in WebGPU";
-            case Constants.MATERIAL_LineStripDrawMode:
-                return WebGPUConstants.PrimitiveTopology.LineStrip;
-            case Constants.MATERIAL_TriangleStripDrawMode:
-                return WebGPUConstants.PrimitiveTopology.TriangleStrip;
-            case Constants.MATERIAL_TriangleFanDrawMode:
-                // return this._gl.TRIANGLE_FAN;
-                // TODO WEBGPU. Triangle Fan Mode Fallback at buffer load time.
-                throw "TriangleFan is an unsupported fillmode in WebGPU";
-            default:
-                return WebGPUConstants.PrimitiveTopology.TriangleList;
-        }
-    }
-
-    private _getOpFunction(operation: Nullable<number>, defaultOp: GPUStencilOperation): GPUStencilOperation {
-        switch (operation) {
-            case Constants.KEEP:
-                return WebGPUConstants.StencilOperation.Keep;
-            case Constants.ZERO:
-                return WebGPUConstants.StencilOperation.Zero;
-            case Constants.REPLACE:
-                return WebGPUConstants.StencilOperation.Replace;
-            case Constants.INVERT:
-                return WebGPUConstants.StencilOperation.Invert;
-            case Constants.INCR:
-                return WebGPUConstants.StencilOperation.IncrementClamp;
-            case Constants.DECR:
-                return WebGPUConstants.StencilOperation.DecrementClamp;
-            case Constants.INCR_WRAP:
-                return WebGPUConstants.StencilOperation.IncrementWrap;
-            case Constants.DECR_WRAP:
-                return WebGPUConstants.StencilOperation.DecrementWrap;
-            default:
-                return defaultOp;
-        }
-    }
-
-    private _getDepthStencilStateDescriptor(): GPUDepthStencilStateDescriptor | undefined {
-        if (this._depthTextureFormat === undefined) {
-            return undefined;
-        }
-
-        const stencilFrontBack: GPUStencilStateFaceDescriptor = {
-            compare: WebGPUTextureHelper.GetCompareFunction(this._stencilState.stencilFunc),
-            depthFailOp: this._getOpFunction(this._stencilState.stencilOpDepthFail, WebGPUConstants.StencilOperation.Keep),
-            failOp: this._getOpFunction(this._stencilState.stencilOpStencilFail, WebGPUConstants.StencilOperation.Keep),
-            passOp: this._getOpFunction(this._stencilState.stencilOpStencilDepthPass, WebGPUConstants.StencilOperation.Replace)
-        };
-
-        return {
-            depthWriteEnabled: this.getDepthWrite(),
-            depthCompare: this.getDepthBuffer() ? WebGPUTextureHelper.GetCompareFunction(this.getDepthFunction()) : WebGPUConstants.CompareFunction.Always,
-            format: this._depthTextureFormat,
-            stencilFront: stencilFrontBack,
-            stencilBack: stencilFrontBack,
-            stencilReadMask: this._stencilState.stencilFuncMask,
-            stencilWriteMask: this._stencilState.stencilMask,
-        };
-    }
-
     /**
      * Set various states to the context
      * @param culling defines backface culling state
@@ -3407,45 +3359,6 @@ export class WebGPUEngine extends Engine {
         }
     }
 
-    private _getFrontFace(): GPUFrontFace {
-        switch (this._depthCullingState.frontFace) {
-            case 1:
-                return WebGPUConstants.FrontFace.CCW;
-            default:
-                return WebGPUConstants.FrontFace.CW;
-        }
-    }
-
-    private _getCullMode(): GPUCullMode {
-        if (this._depthCullingState.cull === false) {
-            return WebGPUConstants.CullMode.None;
-        }
-
-        if (this._depthCullingState.cullFace === 2) {
-            return WebGPUConstants.CullMode.Front;
-        }
-        else {
-            return WebGPUConstants.CullMode.Back;
-        }
-    }
-
-    private _getRasterizationStateDescriptor(): GPURasterizationStateDescriptor {
-        return {
-            frontFace: this._getFrontFace(),
-            cullMode: this._getCullMode(),
-            depthBias: 0,
-            depthBiasClamp: 0,
-            depthBiasSlopeScale: this._depthCullingState.zOffset,
-        };
-    }
-
-    private _getWriteMask(): number {
-        if (this.__colorWrite) {
-            return WebGPUConstants.ColorWrite.All;
-        }
-        return 0;
-    }
-
     /**
      * Sets the current alpha mode
      * @param mode defines the mode to use (one of the Engine.ALPHA_XXX)
@@ -3514,8 +3427,11 @@ export class WebGPUEngine extends Engine {
         }
         if (!noDepthWriteChange) {
             this.setDepthWrite(mode === Engine.ALPHA_DISABLE);
+            this._cacheRenderPipeline.setDepthWriteEnabled(mode === Engine.ALPHA_DISABLE);
         }
         this._alphaMode = mode;
+        this._cacheRenderPipeline.setAlphaBlendEnabled(this._alphaState.alphaBlend);
+        this._cacheRenderPipeline.setAlphaBlendFactors(this._alphaState._blendFunctionParameters, this._alphaState._blendEquationParameters);
     }
 
     /**
@@ -3523,441 +3439,38 @@ export class WebGPUEngine extends Engine {
      * @param equation defines the equation to use (one of the Engine.ALPHA_EQUATION_XXX)
      */
     public setAlphaEquation(equation: number): void {
-        if (this._alphaEquation === equation) {
-            return;
-        }
+        super.setAlphaEquation(equation);
 
-        switch (equation) {
-            case Constants.ALPHA_EQUATION_ADD:
-                this._alphaState.setAlphaEquationParameters(this._gl.FUNC_ADD, this._gl.FUNC_ADD);
-                break;
-            case Constants.ALPHA_EQUATION_SUBSTRACT:
-                this._alphaState.setAlphaEquationParameters(this._gl.FUNC_SUBTRACT, this._gl.FUNC_SUBTRACT);
-                break;
-            case Constants.ALPHA_EQUATION_REVERSE_SUBTRACT:
-                this._alphaState.setAlphaEquationParameters(this._gl.FUNC_REVERSE_SUBTRACT, this._gl.FUNC_REVERSE_SUBTRACT);
-                break;
-            case Constants.ALPHA_EQUATION_MAX:
-                this._alphaState.setAlphaEquationParameters(this._gl.MAX, this._gl.MAX);
-                break;
-            case Constants.ALPHA_EQUATION_MIN:
-                this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.MIN);
-                break;
-            case Constants.ALPHA_EQUATION_DARKEN:
-                this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.FUNC_ADD);
-                break;
-        }
-        this._alphaEquation = equation;
-    }
-
-    private _getAphaBlendOperation(operation: Nullable<number>): GPUBlendOperation {
-        switch (operation) {
-            case 0x8006:
-                return WebGPUConstants.BlendOperation.Add;
-            case 0x800A:
-                return WebGPUConstants.BlendOperation.Subtract;
-            case 0x800B:
-                return WebGPUConstants.BlendOperation.ReverseSubtract;
-            case 0x8007:
-                return WebGPUConstants.BlendOperation.Min;
-            case 0x8008:
-                return WebGPUConstants.BlendOperation.Max;
-            default:
-                return WebGPUConstants.BlendOperation.Add;
-        }
-    }
-
-    private _getAphaBlendFactor(factor: Nullable<number>): GPUBlendFactor {
-        switch (factor) {
-            case 0:
-                return WebGPUConstants.BlendFactor.Zero;
-            case 1:
-                return WebGPUConstants.BlendFactor.One;
-            case 0x0300:
-                return WebGPUConstants.BlendFactor.SrcColor;
-            case 0x0301:
-                return WebGPUConstants.BlendFactor.OneMinusSrcColor;
-            case 0x0302:
-                return WebGPUConstants.BlendFactor.SrcAlpha;
-            case 0x0303:
-                return WebGPUConstants.BlendFactor.OneMinusSrcAlpha;
-            case 0x0304:
-                return WebGPUConstants.BlendFactor.DstAlpha;
-            case 0x0305:
-                return WebGPUConstants.BlendFactor.OneMinusDstAlpha;
-            case 0x0306:
-                return WebGPUConstants.BlendFactor.DstColor;
-            case 0x0307:
-                return WebGPUConstants.BlendFactor.OneMinusDstColor;
-            case 0x0308:
-                return WebGPUConstants.BlendFactor.SrcAlphaSaturated;
-            case 0x8001:
-                return WebGPUConstants.BlendFactor.BlendColor;
-            case 0x8002:
-                return WebGPUConstants.BlendFactor.OneMinusBlendColor;
-            case 0x8003:
-                return WebGPUConstants.BlendFactor.BlendColor;
-            case 0x8004:
-                return WebGPUConstants.BlendFactor.OneMinusBlendColor;
-            default:
-                return WebGPUConstants.BlendFactor.One;
-        }
-    }
-
-    private _getAphaBlendState(): GPUBlendDescriptor {
-        if (!this._alphaState.alphaBlend) {
-            return { };
-        }
-
-        return {
-            srcFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[2]),
-            dstFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[3]),
-            operation: this._getAphaBlendOperation(this._alphaState._blendEquationParameters[1]),
-        };
+        this._cacheRenderPipeline.setAlphaBlendFactors(this._alphaState._blendFunctionParameters, this._alphaState._blendEquationParameters);
     }
 
-    private _getColorBlendState(): GPUBlendDescriptor {
-        if (!this._alphaState.alphaBlend) {
-            return { };
-        }
-
-        return {
-            srcFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[0]),
-            dstFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[1]),
-            operation: this._getAphaBlendOperation(this._alphaState._blendEquationParameters[0]),
-        };
-    }
-
-    private _getColorStateDescriptors(): GPUColorStateDescriptor[] {
-        const descriptors: GPUColorStateDescriptor[] = [];
-
-        const alphaBlend = this._getAphaBlendState();
-        const colorBlend = this._getColorBlendState();
-        const writeMask = this._getWriteMask();
-
-        if (this._currentRenderPassIsMRT()) {
-            const textureArray = this._currentRenderTarget!._textureArray!;
-            for (let i = 0; i < this._mrtAttachments.length; ++i) {
-                const index = this._mrtAttachments[i];
-                if (index > 0) {
-                    const mrtTexture = textureArray[index - 1];
-                    const gpuMRTWrapper = mrtTexture?._hardwareTexture as Nullable<WebGPUHardwareTexture>;
-                    descriptors.push({
-                        format: gpuMRTWrapper?.format ?? this._colorFormat,
-                        alphaBlend,
-                        colorBlend,
-                        writeMask,
-                    });
-                } else {
-                    descriptors.push(undefined as any); // TODO WEBGPU what to do when this._mrtAttachments[i] === 0? The corresponding texture should be bound as an "empty" texture
-                }
-            }
-        } else {
-            descriptors.push({
-                format: this._colorFormat,
-                alphaBlend,
-                colorBlend,
-                writeMask,
-            });
-        }
-
-        return descriptors;
-    }
-
-    private _getStages(): IWebGPURenderPipelineStageDescriptor {
+    private _getBindGroupsToRender(): GPUBindGroup[] {
         const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
-        return webgpuPipelineContext.stages!;
-    }
-
-    private _getVertexInputDescriptorFormat(vertexBuffer: VertexBuffer): GPUVertexFormat {
-        const kind = vertexBuffer.getKind();
-        const type = vertexBuffer.type;
-        const normalized = vertexBuffer.normalized;
-        const size = vertexBuffer.getSize();
-
-        switch (type) {
-            case VertexBuffer.BYTE:
-                switch (size) {
-                    case 1:
-                    case 2:
-                        return normalized ? WebGPUConstants.VertexFormat.Char2Norm : WebGPUConstants.VertexFormat.Char2;
-                    case 3:
-                    case 4:
-                        return normalized ? WebGPUConstants.VertexFormat.Char4Norm : WebGPUConstants.VertexFormat.Char4;
-                }
-                break;
-            case VertexBuffer.UNSIGNED_BYTE:
-                switch (size) {
-                    case 1:
-                    case 2:
-                        return normalized ? WebGPUConstants.VertexFormat.Uchar2Norm : WebGPUConstants.VertexFormat.Uchar2;
-                    case 3:
-                    case 4:
-                        return normalized ? WebGPUConstants.VertexFormat.Uchar4Norm : WebGPUConstants.VertexFormat.Uchar4;
-                }
-                break;
-            case VertexBuffer.SHORT:
-                switch (size) {
-                    case 1:
-                    case 2:
-                        return normalized ? WebGPUConstants.VertexFormat.Short2Norm : WebGPUConstants.VertexFormat.Short2;
-                    case 3:
-                    case 4:
-                        return normalized ? WebGPUConstants.VertexFormat.Short4Norm : WebGPUConstants.VertexFormat.Short4;
-                }
-                break;
-            case VertexBuffer.UNSIGNED_SHORT:
-                switch (size) {
-                    case 1:
-                    case 2:
-                        return normalized ? WebGPUConstants.VertexFormat.Ushort2Norm : WebGPUConstants.VertexFormat.Ushort2;
-                    case 3:
-                    case 4:
-                        return normalized ? WebGPUConstants.VertexFormat.Ushort4Norm : WebGPUConstants.VertexFormat.Ushort4;
-                }
-                break;
-            case VertexBuffer.INT:
-                switch (size) {
-                    case 1:
-                        return WebGPUConstants.VertexFormat.Int;
-                    case 2:
-                        return WebGPUConstants.VertexFormat.Int2;
-                    case 3:
-                        return WebGPUConstants.VertexFormat.Int3;
-                    case 4:
-                        return WebGPUConstants.VertexFormat.Int4;
-                }
-                break;
-            case VertexBuffer.UNSIGNED_INT:
-                switch (size) {
-                    case 1:
-                        return WebGPUConstants.VertexFormat.Uint;
-                    case 2:
-                        return WebGPUConstants.VertexFormat.Uint2;
-                    case 3:
-                        return WebGPUConstants.VertexFormat.Uint3;
-                    case 4:
-                        return WebGPUConstants.VertexFormat.Uint4;
-                }
-                break;
-            case VertexBuffer.FLOAT:
-                switch (size) {
-                    case 1:
-                        return WebGPUConstants.VertexFormat.Float;
-                    case 2:
-                        return WebGPUConstants.VertexFormat.Float2;
-                    case 3:
-                        return WebGPUConstants.VertexFormat.Float3;
-                    case 4:
-                        return WebGPUConstants.VertexFormat.Float4;
-                }
-                break;
-        }
-
-        throw new Error(`Invalid Format '${kind}' - type=${type}, normalized=${normalized}, size=${size}`);
-    }
-
-    private _getVertexInputDescriptor(topology: GPUPrimitiveTopology): GPUVertexStateDescriptor {
-        const descriptors: GPUVertexBufferLayoutDescriptor[] = [];
-        const effect = this._currentEffect!;
-        const attributes = effect.getAttributesNames();
-        for (var index = 0; index < attributes.length; index++) {
-            const location = effect.getAttributeLocation(index);
-
-            if (location >= 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;
-                }
-
-                const positionAttributeDescriptor: GPUVertexAttributeDescriptor = {
-                    shaderLocation: location,
-                    offset: 0, // not available in WebGL
-                    format: this._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: [positionAttributeDescriptor]
-                };
 
-               descriptors.push(vertexBufferDescriptor);
-            }
-        }
-
-        if (!this._currentIndexBuffer) {
-            return {
-                indexFormat: !this._indexFormatInRenderPass(topology) ? WebGPUConstants.IndexFormat.Uint32 : undefined,
-                vertexBuffers: descriptors
-            };
-        }
-
-        const inputStateDescriptor: GPUVertexStateDescriptor = {
-            vertexBuffers: descriptors
-        };
-
-        if (!this._indexFormatInRenderPass(topology)) {
-            inputStateDescriptor.indexFormat = this._currentIndexBuffer!.is32Bits ? WebGPUConstants.IndexFormat.Uint32 : WebGPUConstants.IndexFormat.Uint16;
+        if (webgpuPipelineContext.uniformBuffer) {
+            this.bindUniformBufferBase(webgpuPipelineContext.uniformBuffer.getBuffer()!, 0, "LeftOver");
+            webgpuPipelineContext.uniformBuffer.update();
         }
 
-        return inputStateDescriptor;
-    }
-
-    private _getPipelineLayout(): GPUPipelineLayout {
-        const bindGroupLayouts: GPUBindGroupLayout[] = [];
-        const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
-
-        for (let i = 0; i < webgpuPipelineContext.shaderProcessingContext.orderedUBOsAndSamplers.length; i++) {
-            const setDefinition = webgpuPipelineContext.shaderProcessingContext.orderedUBOsAndSamplers[i];
-            if (setDefinition === undefined) {
-                const entries: GPUBindGroupLayoutEntry[] = [];
-                const uniformsBindGroupLayout = this._device.createBindGroupLayout({
-                    entries,
-                });
-                bindGroupLayouts[i] = uniformsBindGroupLayout;
-                continue;
+        let bufferKey = "";
+        for (let i = 0; i < webgpuPipelineContext.shaderProcessingContext.uniformBufferNames.length; ++i) {
+            const bufferName = webgpuPipelineContext.shaderProcessingContext.uniformBufferNames[i];
+            const dataBuffer = this._uniformsBuffers[bufferName];
+            if (dataBuffer) {
+                bufferKey += dataBuffer.uniqueId + "_";
             }
-
-            const entries: GPUBindGroupLayoutEntry[] = [];
-            for (let j = 0; j < setDefinition.length; j++) {
-                const bindingDefinition = webgpuPipelineContext.shaderProcessingContext.orderedUBOsAndSamplers[i][j];
-                if (bindingDefinition === undefined) {
-                    continue;
-                }
-
-                let visibility = 0;
-                if (bindingDefinition.usedInVertex) {
-                    visibility = visibility | WebGPUConstants.ShaderStage.Vertex;
-                }
-                if (bindingDefinition.usedInFragment) {
-                    visibility = visibility | WebGPUConstants.ShaderStage.Fragment;
-                }
-
-                if (bindingDefinition.isSampler) {
-                    entries.push({
-                        binding: j,
-                        visibility,
-                        type: bindingDefinition.isComparisonSampler ? WebGPUConstants.BindingType.ComparisonSampler : WebGPUConstants.BindingType.Sampler
-                    });
-                } else if (bindingDefinition.isTexture) {
-                    entries.push({
-                        binding: j,
-                        visibility,
-                        type: WebGPUConstants.BindingType.SampledTexture,
-                        viewDimension: bindingDefinition.textureDimension,
-                        textureComponentType: bindingDefinition.componentType,
-                        // TODO WEBGPU.
-                        // hasDynamicOffset?: boolean;
-                        // storageTextureFormat?: GPUTextureFormat;
-                        // minBufferBindingSize?: number;
-                    });
-                } else {
-                    entries.push({
-                        binding: j,
-                        visibility,
-                        type: WebGPUConstants.BindingType.UniformBuffer,
-                    });
-                }
-            }
-
-            if (entries.length > 0) {
-                const uniformsBindGroupLayout = this._device.createBindGroupLayout({
-                    entries,
-                });
-                bindGroupLayouts[i] = uniformsBindGroupLayout;
-            }
-        }
-
-        webgpuPipelineContext.bindGroupLayouts = bindGroupLayouts;
-        return this._device.createPipelineLayout({ bindGroupLayouts });
-    }
-
-    private _getRenderPipeline(topology: GPUPrimitiveTopology, createLayout = true): GPURenderPipeline {
-        this._counters.numPipelineDescriptorCreation++;
-
-        // Unsupported at the moment but needs to be extracted from the MSAA param.
-        const rasterizationStateDescriptor = this._getRasterizationStateDescriptor();
-        const depthStateDescriptor = this._getDepthStencilStateDescriptor();
-        const colorStateDescriptors = this._getColorStateDescriptors();
-        const stages = this._getStages();
-        const inputStateDescriptor = this._getVertexInputDescriptor(topology);
-        const pipelineLayout = createLayout ? this._getPipelineLayout() : undefined;
-
-        return this._device.createRenderPipeline({
-            sampleCount: this._currentRenderTarget ? this._currentRenderTarget.samples : this._mainPassSampleCount,
-            primitiveTopology: topology,
-            rasterizationState: rasterizationStateDescriptor,
-            depthStencilState: depthStateDescriptor,
-            colorStates: colorStateDescriptors,
-
-            ...stages,
-            vertexState: inputStateDescriptor,
-            layout: pipelineLayout,
-        });
-    }
-
-    private _getVertexInputsToRender(): IWebGPUPipelineContextVertexInputsCache {
-        const effect = this._currentEffect!;
-
-        this._counters.numVertexInputCacheCreation++;
-
-        let vertexInputs: IWebGPUPipelineContextVertexInputsCache = {
-            indexBuffer: null,
-            indexOffset: 0,
-
-            vertexStartSlot: 0,
-            vertexBuffers: [],
-            vertexOffsets: [],
-        };
-
-        if (this._currentIndexBuffer) {
-            // TODO WEBGPU. Check if cache would be worth it.
-            vertexInputs.indexBuffer = this._currentIndexBuffer.underlyingResource;
-            vertexInputs.indexOffset = 0;
-        }
-        else {
-            vertexInputs.indexBuffer = null;
         }
 
-        const attributes = effect.getAttributesNames();
-        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;
-                }
-
-                var buffer = vertexBuffer.getBuffer();
-                if (buffer) {
-                    vertexInputs.vertexBuffers.push(buffer.underlyingResource);
-                    vertexInputs.vertexOffsets.push(vertexBuffer.byteOffset);
-                }
-            }
+        let bindGroups: GPUBindGroup[] = webgpuPipelineContext.bindGroupsCache[bufferKey];
+        if (bindGroups) {
+            return bindGroups;
         }
 
-        // TODO WEBGPU. Optimize buffer reusability and types as more are now allowed.
-        return vertexInputs;
-    }
-
-    private _getBindGroupsToRender(): GPUBindGroup[] {
-        const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
-        let bindGroups: GPUBindGroup[] = [];
+        bindGroups = [];
 
+        webgpuPipelineContext.bindGroupsCache[bufferKey] = bindGroups;
         this._counters.numBindGroupsCreation++;
 
-        if (webgpuPipelineContext.uniformBuffer) {
-            this.bindUniformBufferBase(webgpuPipelineContext.uniformBuffer.getBuffer()!, 0, "LeftOver");
-            webgpuPipelineContext.uniformBuffer.update();
-        }
-
         const bindGroupLayouts = webgpuPipelineContext.bindGroupLayouts;
 
         for (let i = 0; i < webgpuPipelineContext.shaderProcessingContext.orderedUBOsAndSamplers.length; i++) {
@@ -4044,19 +3557,31 @@ export class WebGPUEngine extends Engine {
         return bindGroups;
     }
 
-    private _bindVertexInputs(vertexInputs: IWebGPUPipelineContextVertexInputsCache): void {
+    private _bindVertexInputs(): void {
         const renderPass = this._bundleEncoder || this._getCurrentRenderPass();
 
-        if (vertexInputs.indexBuffer) {
-            // TODO WEBGPU. Check if cache would be worth it.
-            renderPass.setIndexBuffer(vertexInputs.indexBuffer, this._currentIndexBuffer!.is32Bits ? WebGPUConstants.IndexFormat.Uint32 : WebGPUConstants.IndexFormat.Uint16, vertexInputs.indexOffset);
+        if (this._currentIndexBuffer) {
+            renderPass.setIndexBuffer(this._currentIndexBuffer.underlyingResource, this._currentIndexBuffer!.is32Bits ? WebGPUConstants.IndexFormat.Uint32 : WebGPUConstants.IndexFormat.Uint16, 0);
         }
 
-        // TODO WEBGPU. Optimize buffer reusability and types as more are now allowed.
-        for (let i = 0; i < vertexInputs.vertexBuffers.length; i++) {
-            const buf = vertexInputs.vertexBuffers[i];
-            if (buf) {
-                renderPass.setVertexBuffer(vertexInputs.vertexStartSlot + i, buf, vertexInputs.vertexOffsets[i]);
+        const effect = this._currentEffect!;
+        const attributes = effect.getAttributesNames();
+        let bufferIdx = 0;
+        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;
+                }
+
+                const buffer = vertexBuffer.getBuffer();
+                if (buffer) {
+                    renderPass.setVertexBuffer(bufferIdx++, buffer.underlyingResource, vertexBuffer.byteOffset);
+                }
             }
         }
     }
@@ -4072,13 +3597,30 @@ export class WebGPUEngine extends Engine {
     private _setRenderPipeline(fillMode: number): void {
         const renderPass = this._bundleEncoder || this._getCurrentRenderPass();
 
-        const topology = this._getTopology(fillMode);
+        this._cacheRenderPipeline.setDepthCullingState(
+            !!this._depthCullingState.cull,
+            this._depthCullingState.frontFace ?? 2,
+            this._depthCullingState.cullFace ?? 1,
+            this._depthCullingState.zOffset,
+            this._depthCullingState.depthTest,
+            this._depthCullingState.depthMask,
+            this._depthCullingState.depthFunc
+        );
+
+        this._cacheRenderPipeline.setStencilState(
+            this._stencilState.stencilTest,
+            this._stencilState.stencilFunc,
+            this._stencilState.stencilOpDepthFail,
+            this._stencilState.stencilOpStencilDepthPass,
+            this._stencilState.stencilOpStencilFail,
+            this._stencilState.stencilFuncMask,
+            this._stencilState.stencilMask
+        );
 
-        const pipeline = this._getRenderPipeline(topology);
+        const pipeline = this._cacheRenderPipeline.getRenderPipeline(fillMode, this._currentEffect!, this._currentRenderTarget ? this._currentRenderTarget.samples : this._mainPassSampleCount);
         renderPass.setPipeline(pipeline);
 
-        const vertexInputs = this._getVertexInputsToRender();
-        this._bindVertexInputs(vertexInputs);
+        this._bindVertexInputs();
 
         const bindGroups = this._getBindGroupsToRender();
         this._setRenderBindGroups(bindGroups);

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 3927
src/Engines/webgpuEngineCache.ts


+ 6 - 6
tests/validation/config.json

@@ -455,7 +455,7 @@
             "playgroundId": "#DS8AA7#18",
             "replace": "__folder__, Animation_Skin, __page__, 0",
             "referenceImage": "gltfAnimationSkin0.png",
-            "excludedEngines": ["webgpu","webgpucache"]
+            "excludedEngines": ["webgpu"]
         },
         {
             "title": "GLTF Animation Skin (1)",
@@ -463,14 +463,14 @@
             "playgroundId": "#DS8AA7#18",
             "replace": "__folder__, Animation_Skin, __page__, 1",
             "referenceImage": "gltfAnimationSkin1.png",
-            "excludedEngines": ["webgpu","webgpucache"]
+            "excludedEngines": ["webgpu"]
         },
         {
             "title": "GLTF Animation Skin Type",
             "playgroundId": "#DS8AA7#18",
             "replace": "__folder__, Animation_SkinType, __page__, 0",
             "referenceImage": "gltfAnimationSkinType.png",
-            "excludedEngines": ["webgpu","webgpucache"]
+            "excludedEngines": ["webgpu"]
         },
         {
             "title": "GLTF Buffer Interleaved",
@@ -549,14 +549,14 @@
             "playgroundId": "#DS8AA7#18",
             "replace": "__folder__, Mesh_PrimitiveMode, __page__, 0",
             "referenceImage": "gltfMeshPrimitiveMode0.png",
-            "excludedEngines": ["webgpu","webgpucache"]
+            "excludedEngines": ["webgpu"]
         },
         {
             "title": "GLTF Mesh Primitive Mode (1)",
             "playgroundId": "#DS8AA7#18",
             "replace": "__folder__, Mesh_PrimitiveMode, __page__, 1",
             "referenceImage": "gltfMeshPrimitiveMode1.png",
-            "excludedEngines": ["webgpu","webgpucache"]
+            "excludedEngines": ["webgpu"]
         },
         {
             "title": "GLTF Mesh Primitive Vertex Color",
@@ -985,7 +985,7 @@
             "playgroundId": "#PIZ1GK#173",
             "referenceImage": "geometrybufferrenderer.png",
             "renderCount": 10,
-            "excludedEngines": ["webgl1", "webgpu","webgpucache"],
+            "excludedEngines": ["webgl1", "webgpu"],
             "excludeFromAutomaticTesting": true
         },
         {

+ 2 - 2
tests/validation/validation.js

@@ -456,7 +456,7 @@ function init(_engineName) {
     canvas = document.createElement("canvas");
     canvas.className = "renderCanvas";
     document.body.appendChild(canvas);
-    if (engineName === "webgpu" || engineName === "webgpucache") {
+    if (engineName === "webgpu") {
         const glslangOptions = { 
             jsPath: "../../dist/preview%20release/glslang/glslang.js",
             wasmPath: "../../dist/preview%20release/glslang/glslang.wasm"
@@ -476,7 +476,7 @@ function init(_engineName) {
             antialiasing: false,
         };
 
-        engine = engineName === "webgpucache" ? new BABYLON.WebGPUEngineCache(canvas, options) : new BABYLON.WebGPUEngine(canvas, options);
+        engine = new BABYLON.WebGPUEngine(canvas, options);
         engine.enableOfflineSupport = false;
         return new Promise((resolve) => {
             engine.initAsync(glslangOptions).then(() => resolve());