소스 검색

Added a temporary webgpu "cache" engine for testing purpose

Popov72 4 년 전
부모
커밋
80da46b4bd
5개의 변경된 파일5073개의 추가작업 그리고 93개의 파일을 삭제
  1. 664 90
      src/Engines/WebGPU/webgpuCacheRenderPipeline.ts
  2. 1 0
      src/Engines/WebGPU/webgpuPipelineContext.ts
  3. 2 0
      src/Engines/index.ts
  4. 1 3
      src/Engines/webgpuEngine.ts
  5. 4405 0
      src/Engines/webgpuEngineCache.ts

+ 664 - 90
src/Engines/WebGPU/webgpuCacheRenderPipeline.ts

@@ -1,26 +1,27 @@
-//import { Constants } from "../constants";
-//import * as WebGPUConstants from './webgpuConstants';
+import { Constants } from "../constants";
+import * as WebGPUConstants from './webgpuConstants';
 import { Effect } from "../../Materials/effect";
 import { Effect } from "../../Materials/effect";
 import { InternalTexture } from "../../Materials/Textures/internalTexture";
 import { InternalTexture } from "../../Materials/Textures/internalTexture";
 import { VertexBuffer } from "../../Meshes/buffer";
 import { VertexBuffer } from "../../Meshes/buffer";
 import { DataBuffer } from "../../Meshes/dataBuffer";
 import { DataBuffer } from "../../Meshes/dataBuffer";
 import { Nullable } from "../../types";
 import { Nullable } from "../../types";
 import { WebGPUHardwareTexture } from "./webgpuHardwareTexture";
 import { WebGPUHardwareTexture } from "./webgpuHardwareTexture";
-//import { WebGPUPipelineContext } from "./webgpuPipelineContext";
+import { WebGPUPipelineContext } from "./webgpuPipelineContext";
 
 
 enum StatePosition {
 enum StatePosition {
     ShaderStage = 0,
     ShaderStage = 0,
-    PrimitiveTopology = 1,
-    FrontFace = 2,
-    CullMode = 3,
-    DepthBias=  4,
-    DepthBiasClamp = 5,
-    DepthBiasSlopeScale = 6,
-    ColorFormat = 7,
-    MRTAttachments = 8,
-    AlphaBlendFactors = 9,
-
-    NumStates = 10
+    RasterizationState = 1,
+    DepthBias = 2,
+    DepthBiasClamp = 3,
+    DepthBiasSlopeScale = 4,
+    MRTAttachments = 5,
+    ColorStates = 6,
+    DepthStencilState = 7,
+    StencilReadMask = 8,
+    StencilWriteMask = 9,
+    VertexState = 10,
+
+    NumStates = 11
 }
 }
 
 
 const textureFormatToIndex: { [name: string]: number } = {
 const textureFormatToIndex: { [name: string]: number } = {
@@ -84,6 +85,35 @@ const textureFormatToIndex: { [name: string]: number } = {
     "depth32float-stencil8": 57,
     "depth32float-stencil8": 57,
 };
 };
 
 
+const alphaBlendFactorToIndex: { [name: number]: number } = {
+    0: 1, // Zero
+    1: 2, // One
+    0x0300: 3, // SrcColor
+    0x0301: 4, // OneMinusSrcColor
+    0x0302: 5, // SrcAlpha
+    0x0303: 6, // OneMinusSrcAlpha
+    0x0304: 7, // DstAlpha
+    0x0305: 8, // OneMinusDstAlpha
+    0x0306: 9, // DstColor
+    0x0307: 10, // OneMinusDstColor
+    0x0308: 11, // SrcAlphaSaturated
+    0x8001: 12, // BlendColor
+    0x8002: 13, // OneMinusBlendColor
+    0x8003: 12, // BlendColor (alpha)
+    0x8004: 13, // OneMinusBlendColor (alpha)
+};
+
+const stencilOpToIndex: { [name: number]: number } = {
+    0x0000: 0, // ZERO
+    0x1E00: 1, // KEEP
+    0x1E01: 2, // REPLACE
+    0x1E02: 3, // INCR
+    0x1E03: 4, // DECR
+    0x150A: 5, // INVERT
+    0x8507: 6, // INCR_WRAP
+    0x8508: 7, // DECR_WRAP
+};
+
 /** @hidden */
 /** @hidden */
 export class WebGPUCacheRenderPipeline {
 export class WebGPUCacheRenderPipeline {
 
 
@@ -95,47 +125,88 @@ export class WebGPUCacheRenderPipeline {
     private static _Cache: { [hash: string]: GPURenderPipeline } = {};
     private static _Cache: { [hash: string]: GPURenderPipeline } = {};
     private static _NumPipelineCreationCurrentFrame = 0;
     private static _NumPipelineCreationCurrentFrame = 0;
 
 
-    //private _device: GPUDevice;
+    private _device: GPUDevice;
     private _states: string[];
     private _states: string[];
     private _isDirty: boolean;
     private _isDirty: boolean;
     private _currentRenderPipeline: GPURenderPipeline;
     private _currentRenderPipeline: GPURenderPipeline;
+    private _emptyVertexBuffer: VertexBuffer;
 
 
     private _shaderId: number;
     private _shaderId: number;
-    private _topology: number;
+    private _alphaToCoverageEnabled: boolean;
     private _frontFace: number;
     private _frontFace: number;
     private _cullEnabled: boolean;
     private _cullEnabled: boolean;
     private _cullFace: number;
     private _cullFace: number;
-    private _cullMode: number;
+    private _clampDepth: boolean;
+    private _rasterizationState: number;
     private _depthBias: number;
     private _depthBias: number;
     private _depthBiasClamp: number;
     private _depthBiasClamp: number;
     private _depthBiasSlopeScale: number;
     private _depthBiasSlopeScale: number;
-    private _colorFormat: GPUTextureFormat;
+    private _colorFormat: number;
+    private _webgpuColorFormat: GPUTextureFormat;
     private _mrtAttachments: number;
     private _mrtAttachments: number;
+    private _mrtFormats: GPUTextureFormat[];
     private _alphaBlendEnabled: boolean;
     private _alphaBlendEnabled: boolean;
-    private _alphaBlendFuncParams: number[];
-    private _alphaBlendEqParams: number[];
-    private _alphaBlend: number;
-
-    constructor(device: GPUDevice) {
-        //this._device = device;
+    private _alphaBlendFuncParams: Array<Nullable<number>>;
+    private _alphaBlendEqParams: Array<Nullable<number>>;
+    private _writeMask: number;
+    private _colorStates: number;
+    private _depthStencilFormat: number;
+    private _webgpuDepthStencilFormat: GPUTextureFormat | undefined;
+    private _depthTestEnabled: boolean;
+    private _depthWriteEnabled: boolean;
+    private _depthCompare: number;
+    private _stencilEnabled: boolean;
+    private _stencilFrontCompare: number;
+    private _stencilFrontDepthFailOp: number;
+    private _stencilFrontPassOp: number;
+    private _stencilFrontFailOp: number;
+    private _stencilReadMask: number;
+    private _stencilWriteMask: number;
+    private _depthStencilState: number;
+    private _vertexBuffers: Nullable<{ [key: string]: Nullable<VertexBuffer> }>;
+    private _indexBuffer: Nullable<DataBuffer>;
+    private _vertexState: string;
+
+    constructor(device: GPUDevice, emptyVertexBuffer: VertexBuffer) {
+        this._device = device;
         this._states = [];
         this._states = [];
         this._states.length = StatePosition.NumStates;
         this._states.length = StatePosition.NumStates;
+        this._emptyVertexBuffer = emptyVertexBuffer;
+        this._mrtFormats = [];
+        this.reset();
+    }
+
+    public reset(): void {
         this._isDirty = true;
         this._isDirty = true;
-        this._alphaBlendFuncParams.length = 4;
-        this._alphaBlendEqParams.length = 2;
+        this.setAlphaToCoverage(false);
+        this.resetDepthCullingState(); //
+        this.setClampDepth(false);
+        this.setDepthBias(0);
+        this.setDepthBiasClamp(0);
+        this.setColorFormat(WebGPUConstants.TextureFormat.BGRA8Unorm); //
+        this.setMRTAttachments([], []); //
+        this.setAlphaBlendEnabled(false); //
+        this.setAlphaBlendFactors([null, null, null, null], [null, null]); //
+        this.setWriteMask(0xF); //
+        this.setDepthStencilFormat(WebGPUConstants.TextureFormat.Depth24PlusStencil8); //
+        this.setStencilEnabled(false); //
+        this.resetStencilState(); //
+        this.setBuffers(null, null); //
     }
     }
 
 
     public getRenderPipeline(fillMode: number, effect: Effect, sampleCount: number): GPURenderPipeline {
     public getRenderPipeline(fillMode: number, effect: Effect, sampleCount: number): GPURenderPipeline {
         this._setShaderStage(effect.uniqueId);
         this._setShaderStage(effect.uniqueId);
-        this._setTopology(fillMode);
-        this._applyCullMode();
+        this._setRasterizationState(fillMode, sampleCount);
+        this._setColorStates();
+        this._setDepthStencilState();
+        this._setVertexState(effect);
 
 
         if (!this._isDirty && this._currentRenderPipeline) {
         if (!this._isDirty && this._currentRenderPipeline) {
             WebGPUCacheRenderPipeline.NumCacheHitWithoutHash++;
             WebGPUCacheRenderPipeline.NumCacheHitWithoutHash++;
             return this._currentRenderPipeline;
             return this._currentRenderPipeline;
         }
         }
 
 
-        let hash = this._states.join("_");
+        let hash = this._states.join();
         let pipeline = WebGPUCacheRenderPipeline._Cache[hash];
         let pipeline = WebGPUCacheRenderPipeline._Cache[hash];
 
 
         if (pipeline) {
         if (pipeline) {
@@ -144,9 +215,10 @@ export class WebGPUCacheRenderPipeline {
             return pipeline;
             return pipeline;
         }
         }
 
 
-        //const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
+        const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
 
 
-        //this._currentRenderPipeline = WebGPUCacheRenderPipeline._Cache[hash] = this._createRenderPipeline(effect._pipelineContext as WebGPUPipelineContext, topology, sampleCount);
+        this._currentRenderPipeline = this._createRenderPipeline(effect, topology, sampleCount);
+        WebGPUCacheRenderPipeline._Cache[hash] = this._currentRenderPipeline;
 
 
         WebGPUCacheRenderPipeline.NumCacheMiss++;
         WebGPUCacheRenderPipeline.NumCacheMiss++;
         WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
         WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
@@ -159,12 +231,18 @@ export class WebGPUCacheRenderPipeline {
         WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame = 0;
         WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame = 0;
     }
     }
 
 
+    public setAlphaToCoverage(enabled: boolean): void {
+        this._alphaToCoverageEnabled = enabled;
+    }
+
+    public setState(cullEnabled: boolean, frontFace: number, cullFace: number): void {
+        this._cullEnabled = cullEnabled;
+        this._frontFace = frontFace;
+        this._cullFace = cullFace;
+    }
+
     public setFrontFace(frontFace: number): void {
     public setFrontFace(frontFace: number): void {
-        if (this._frontFace !== frontFace) {
-            this._frontFace = frontFace;
-            this._states[StatePosition.FrontFace] = frontFace.toString();
-            this._isDirty = true;
-        }
+        this._frontFace = frontFace;
     }
     }
 
 
     public setCullEnabled(enabled: boolean): void {
     public setCullEnabled(enabled: boolean): void {
@@ -175,18 +253,18 @@ export class WebGPUCacheRenderPipeline {
         this._cullFace = cullFace;
         this._cullFace = cullFace;
     }
     }
 
 
-    private _applyCullMode(): void {
-        if (!this._cullEnabled) {
-            if (this._cullMode !== 0) {
-                this._cullMode = 0;
-                this._states[StatePosition.CullMode] = "0";
-                this._isDirty = true;
-            }
-        } else if (this._cullMode !== this._cullFace) {
-            this._cullMode = this._cullFace;
-            this._states[StatePosition.CullMode] = this._cullMode.toString();
-            this._isDirty = true;
-        }
+    public setClampDepth(clampDepth: boolean): void {
+        this._clampDepth = clampDepth;
+    }
+
+    public resetDepthCullingState(): void {
+        this._depthWriteEnabled = true;
+        this._depthTestEnabled = true;
+        this._depthCompare = Constants.LEQUAL - 0x0200;
+        this._cullFace = 1;
+        this._cullEnabled = false;
+        this._frontFace = 2;
+        this.setDepthBiasSlopeScale(0);
     }
     }
 
 
     public setDepthBias(depthBias: number): void {
     public setDepthBias(depthBias: number): void {
@@ -214,11 +292,8 @@ export class WebGPUCacheRenderPipeline {
     }
     }
 
 
     public setColorFormat(format: GPUTextureFormat): void {
     public setColorFormat(format: GPUTextureFormat): void {
-        if (this._colorFormat !== format) {
-            this._colorFormat = format;
-            this._states[StatePosition.ColorFormat] = format;
-            this._isDirty = true;
-        }
+        this._webgpuColorFormat = format;
+        this._colorFormat = textureFormatToIndex[format];
     }
     }
 
 
     public setMRTAttachments(attachments: number[], textureArray: InternalTexture[]): void {
     public setMRTAttachments(attachments: number[], textureArray: InternalTexture[]): void {
@@ -230,15 +305,16 @@ export class WebGPUCacheRenderPipeline {
             throw "Can't handle more than 10 attachments for a MRT in cache render pipeline!";
             throw "Can't handle more than 10 attachments for a MRT in cache render pipeline!";
         }
         }
         let bits = 0, mask = 0;
         let bits = 0, mask = 0;
+        this._mrtFormats.length = attachments.length;
         for (let i = 0; i < attachments.length; ++i) {
         for (let i = 0; i < attachments.length; ++i) {
             const index = attachments[i];
             const index = attachments[i];
-            if (index > 0) {
-                const texture = textureArray[index - 1];
-                const gpuWrapper = texture?._hardwareTexture as Nullable<WebGPUHardwareTexture>;
-                const gpuTexture = gpuWrapper?.underlyingResource as Nullable<WebGPUHardwareTexture>;
+            const texture = textureArray[index - 1];
+            const gpuWrapper = texture?._hardwareTexture as Nullable<WebGPUHardwareTexture>;
+            const gpuTexture = gpuWrapper?.underlyingResource as Nullable<WebGPUHardwareTexture>;
 
 
-                bits += textureFormatToIndex[gpuTexture?.format ?? ""] << mask;
-            }
+            this._mrtFormats[i] = gpuTexture?.format ?? WebGPUConstants.TextureFormat.BGRA8Unorm;
+
+            bits += textureFormatToIndex[this._mrtFormats[i]] << mask;
             mask += 6;
             mask += 6;
         }
         }
         if (this._mrtAttachments !== bits) {
         if (this._mrtAttachments !== bits) {
@@ -252,29 +328,83 @@ export class WebGPUCacheRenderPipeline {
         this._alphaBlendEnabled = enabled;
         this._alphaBlendEnabled = enabled;
     }
     }
 
 
-    public setAlphaBlendFactors(factors: number[], operations: number[]): void {
+    public setAlphaBlendFactors(factors: Array<Nullable<number>>, operations: Array<Nullable<number>>): void {
+        this._alphaBlendFuncParams = factors;
+        this._alphaBlendEqParams = operations;
+    }
 
 
+    public setWriteMask(mask: number): void {
+        this._writeMask = mask;
     }
     }
 
 
-    private _applyAlphaBlend(): void {
-        if (!this._alphaBlendEnabled) {
-            if (this._alphaBlend !== 0) {
-                this._alphaBlend = 0;
-                this._states[StatePosition.AlphaBlendFactors] = "0";
-                this._isDirty = true;
-            }
-        } else {
-            this._cullMode = this._cullFace;
-            this._states[StatePosition.AlphaBlendFactors] = this._alphaBlend.toString();
+    public setDepthStencilFormat(format: GPUTextureFormat | undefined): void {
+        this._webgpuDepthStencilFormat = format;
+        this._depthStencilFormat = format === undefined ? 0 : textureFormatToIndex[format];
+    }
+
+    public setDepthTestEnabled(enabled: boolean): void {
+        this._depthTestEnabled = enabled;
+    }
+
+    public setDepthWriteEnabled(enabled: boolean): void {
+        this._depthWriteEnabled = enabled;
+    }
+
+    public setDepthCompare(func: Nullable<number>): void {
+        this._depthCompare = (func ?? Constants.LEQUAL) - 0x0200;
+    }
+
+    public setStencilEnabled(enabled: boolean): void {
+        this._stencilEnabled = enabled;
+    }
+
+    public setStencilCompare(func: Nullable<number>): void {
+        this._stencilFrontCompare = (func ?? Constants.LEQUAL) - 0x0200;
+    }
+
+    public setStencilDepthFailOp(op: Nullable<number>): void {
+        this._stencilFrontDepthFailOp = op === null ? 1 /* KEEP */ : stencilOpToIndex[op];
+    }
+
+    public setStencilPassOp(op: Nullable<number>): void {
+        this._stencilFrontPassOp = op === null ? 2 /* REPLACE */ : stencilOpToIndex[op];
+    }
+
+    public setStencilFailOp(op: Nullable<number>): void {
+        this._stencilFrontFailOp = op === null ? 1 /* KEEP */ : stencilOpToIndex[op];
+    }
+
+    public setStencilReadMask(mask: number): void {
+        if (this._stencilReadMask !== mask) {
+            this._stencilReadMask = mask;
+            this._states[StatePosition.StencilReadMask] = mask.toString();
             this._isDirty = true;
             this._isDirty = true;
         }
         }
     }
     }
 
 
-    public setBuffers(vertexBuffers: Nullable<{ [key: string]: Nullable<VertexBuffer> }>, indexBuffer: Nullable<DataBuffer>): void {
+    public setStencilWriteMask(mask: number): void {
+        if (this._stencilWriteMask !== mask) {
+            this._stencilWriteMask = mask;
+            this._states[StatePosition.StencilWriteMask] = mask.toString();
+            this._isDirty = true;
+        }
+    }
 
 
+    public resetStencilState(): void {
+        this._stencilFrontCompare = Constants.ALWAYS - 0x0200;
+        this._stencilFrontDepthFailOp = stencilOpToIndex[Constants.KEEP];
+        this._stencilFrontPassOp = stencilOpToIndex[Constants.REPLACE];
+        this._stencilFrontFailOp = stencilOpToIndex[Constants.KEEP];
+        this.setStencilReadMask(0xFF);
+        this.setStencilWriteMask(0xFF);
     }
     }
 
 
-    /*private static _GetTopology(fillMode: number): GPUPrimitiveTopology {
+    public setBuffers(vertexBuffers: Nullable<{ [key: string]: Nullable<VertexBuffer> }>, indexBuffer: Nullable<DataBuffer>): void {
+        this._vertexBuffers = vertexBuffers;
+        this._indexBuffer = indexBuffer;
+    }
+
+    private static _GetTopology(fillMode: number): GPUPrimitiveTopology {
         switch (fillMode) {
         switch (fillMode) {
             // Triangle views
             // Triangle views
             case Constants.MATERIAL_TriangleFillMode:
             case Constants.MATERIAL_TriangleFillMode:
@@ -303,14 +433,215 @@ export class WebGPUCacheRenderPipeline {
             default:
             default:
                 return WebGPUConstants.PrimitiveTopology.TriangleList;
                 return WebGPUConstants.PrimitiveTopology.TriangleList;
         }
         }
-    }*/
+    }
 
 
-    private _setTopology(topology: number): void {
-        if (this._topology !== topology) {
-            this._topology = topology;
-            this._states[StatePosition.PrimitiveTopology] = topology.toString();
-            this._isDirty = true;
+    private static _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 static _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 static _GetCompareFunction(compareFunction: number): GPUCompareFunction {
+        switch (compareFunction) {
+            case 0: // NEVER
+                return WebGPUConstants.CompareFunction.Never;
+            case 1: // LESS
+                return WebGPUConstants.CompareFunction.Less;
+            case 2: // EQUAL
+                return WebGPUConstants.CompareFunction.Equal;
+            case 3: // LEQUAL
+                return WebGPUConstants.CompareFunction.LessEqual;
+            case 4: // GREATER
+                return WebGPUConstants.CompareFunction.Greater;
+            case 5: // NOTEQUAL
+                return WebGPUConstants.CompareFunction.NotEqual;
+            case 6: // GEQUAL
+                return WebGPUConstants.CompareFunction.GreaterEqual;
+            case 7: // ALWAYS
+                return WebGPUConstants.CompareFunction.Always;
+        }
+        return WebGPUConstants.CompareFunction.Never;
+    }
+
+    private static _GetStencilOpFunction(operation: number): GPUStencilOperation {
+        switch (operation) {
+            case 0:
+                return WebGPUConstants.StencilOperation.Zero;
+            case 1:
+                return WebGPUConstants.StencilOperation.Keep;
+            case 2:
+                return WebGPUConstants.StencilOperation.Replace;
+            case 3:
+                return WebGPUConstants.StencilOperation.IncrementClamp;
+            case 4:
+                return WebGPUConstants.StencilOperation.DecrementClamp;
+            case 5:
+                return WebGPUConstants.StencilOperation.Invert;
+            case 6:
+                return WebGPUConstants.StencilOperation.IncrementWrap;
+            case 7:
+                return WebGPUConstants.StencilOperation.DecrementWrap;
         }
         }
+        return WebGPUConstants.StencilOperation.Keep;
+    }
+
+    private static _GetVertexInputDescriptorFormat(vertexBuffer: VertexBuffer): GPUVertexFormat {
+        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 '${vertexBuffer.getKind()}' - type=${type}, normalized=${normalized}, size=${size}`);
+    }
+
+    private _getAphaBlendState(): GPUBlendDescriptor {
+        if (!this._alphaBlendEnabled) {
+            return { };
+        }
+
+        return {
+            srcFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[2]),
+            dstFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[3]),
+            operation: WebGPUCacheRenderPipeline._GetAphaBlendOperation(this._alphaBlendEqParams[1]),
+        };
+    }
+
+    private _getColorBlendState(): GPUBlendDescriptor {
+        if (!this._alphaBlendEnabled) {
+            return { };
+        }
+
+        return {
+            srcFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[0]),
+            dstFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[1]),
+            operation: WebGPUCacheRenderPipeline._GetAphaBlendOperation(this._alphaBlendEqParams[0]),
+        };
     }
     }
 
 
     private _setShaderStage(id: number): void {
     private _setShaderStage(id: number): void {
@@ -321,11 +652,248 @@ export class WebGPUCacheRenderPipeline {
         }
         }
     }
     }
 
 
-    /*private _createRenderPipeline(webgpuPipelineContext: WebGPUPipelineContext, topology: GPUPrimitiveTopology, sampleCount: number, createLayout = true): GPURenderPipeline {
-        const depthStateDescriptor = this._getDepthStencilStateDescriptor();
-        const colorStateDescriptors = this._getColorStateDescriptors();
-        const inputStateDescriptor = this._getVertexInputDescriptor(topology);
-        const pipelineLayout = createLayout ? this._getPipelineLayout() : undefined;
+    private _setRasterizationState(topology: number, sampleCount: number): void {
+        const frontFace = this._frontFace;
+        const cullMode = this._cullEnabled ? this._cullFace : 0;
+        const clampDepth = this._clampDepth ? 1 : 0;
+        const alphaToCoverage = this._alphaToCoverageEnabled ? 1 : 0;
+        const rasterizationState =
+            (frontFace - 1) +
+            (cullMode << 1) +
+            (clampDepth << 3) +
+            (alphaToCoverage << 4) +
+            (topology << 5) +
+            (sampleCount << 8);
+
+        if (this._rasterizationState !== rasterizationState) {
+            this._rasterizationState = rasterizationState;
+            this._states[StatePosition.RasterizationState] = this._rasterizationState.toString();
+            this._isDirty = true;
+        }
+    }
+
+    private _setColorStates(): void {
+        let colorStates = ((this._writeMask ? 1 : 0) << 22) + (this._colorFormat << 23);
+
+        if (this._alphaBlendEnabled) {
+            colorStates +=
+                ((this._alphaBlendFuncParams[0] === null ? 2 : alphaBlendFactorToIndex[this._alphaBlendFuncParams[0]]) << 0) +
+                ((this._alphaBlendFuncParams[1] === null ? 2 : alphaBlendFactorToIndex[this._alphaBlendFuncParams[1]]) << 4) +
+                ((this._alphaBlendFuncParams[2] === null ? 2 : alphaBlendFactorToIndex[this._alphaBlendFuncParams[2]]) << 8) +
+                ((this._alphaBlendFuncParams[3] === null ? 2 : alphaBlendFactorToIndex[this._alphaBlendFuncParams[3]]) << 12) +
+                ((this._alphaBlendEqParams[0] === null ? 1 : this._alphaBlendEqParams[0] - 0x8005) << 16) +
+                ((this._alphaBlendEqParams[1] === null ? 1 : this._alphaBlendEqParams[1] - 0x8005) << 19);
+        }
+
+        if (colorStates !== this._colorStates) {
+            this._colorStates = colorStates;
+            this._states[StatePosition.ColorStates] = this._colorStates.toString();
+            this._isDirty = true;
+        }
+    }
+
+    private _setDepthStencilState(): void {
+        let stencilState = !this._stencilEnabled ?
+            0 /* NEVER */ + (1 /* KEEP */ << 3) + (1 /* KEEP */ << 6) + (1 /* KEEP */ << 9) :
+            this._stencilFrontCompare + (this._stencilFrontDepthFailOp << 3) + (this._stencilFrontPassOp << 6) + (this._stencilFrontFailOp << 9);
+
+        const depthStencilState =
+                this._depthStencilFormat +
+                ((this._depthWriteEnabled ? 1 : 0) << 6) +
+                ((this._depthTestEnabled ? this._depthCompare : 7 /* ALWAYS */) << 7) +
+                (stencilState << 10); // stencil front - stencil back is the same
+
+        if (this._depthStencilState !== depthStencilState) {
+            this._depthStencilState = depthStencilState;
+            this._states[StatePosition.DepthStencilState] = this._depthStencilState.toString();
+            this._isDirty = true;
+        }
+    }
+
+    private _setVertexState(effect: Effect): void {
+        let vertexState = "";
+
+        const attributes = effect.getAttributesNames();
+        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);
+
+                vertexState += vid + "_";
+            }
+        }
+
+        if (vertexState !== this._vertexState) {
+            this._vertexState = vertexState;
+            this._states[StatePosition.VertexState] = this._vertexState;
+            this._isDirty = true;
+        }
+    }
+
+    private _createPipelineLayout(webgpuPipelineContext: WebGPUPipelineContext): GPUPipelineLayout {
+        const bindGroupLayouts: GPUBindGroupLayout[] = [];
+
+        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;
+            }
+
+            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 _getVertexInputDescriptor(effect: Effect, topology: GPUPrimitiveTopology): GPUVertexStateDescriptor {
+        const descriptors: GPUVertexBufferLayoutDescriptor[] = [];
+        const attributes = effect.getAttributesNames();
+        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 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]
+                };
+
+               descriptors.push(vertexBufferDescriptor);
+            }
+        }
+
+        const inputStateDescriptor: GPUVertexStateDescriptor = {
+            vertexBuffers: descriptors
+        };
+
+        if (topology === WebGPUConstants.PrimitiveTopology.LineStrip || topology === WebGPUConstants.PrimitiveTopology.TriangleStrip) {
+            inputStateDescriptor.indexFormat = !this._indexBuffer || this._indexBuffer.is32Bits ? WebGPUConstants.IndexFormat.Uint32 : WebGPUConstants.IndexFormat.Uint16;
+        }
+
+        return inputStateDescriptor;
+    }
+
+    private _createRenderPipeline(effect: Effect, topology: GPUPrimitiveTopology, sampleCount: number, createLayout = true): GPURenderPipeline {
+        const webgpuPipelineContext = effect._pipelineContext as WebGPUPipelineContext;
+        const inputStateDescriptor = this._getVertexInputDescriptor(effect, topology);
+        const pipelineLayout = createLayout ? this._createPipelineLayout(webgpuPipelineContext) : undefined;
+
+        const colorStates: Array<GPUColorStateDescriptor> = [];
+        const alphaBlend = this._getAphaBlendState();
+        const colorBlend = this._getColorBlendState();
+
+        if (this._mrtAttachments > 0) {
+            for (let i = 0; i < this._mrtFormats.length; ++i) {
+                colorStates.push({
+                    format: this._mrtFormats[i],
+                    alphaBlend,
+                    colorBlend,
+                    writeMask: this._writeMask,
+                });
+            }
+        } else {
+            colorStates.push({
+                format: this._webgpuColorFormat,
+                alphaBlend,
+                colorBlend,
+                writeMask: this._writeMask,
+            });
+        }
+
+        const stencilFrontBack: GPUStencilStateFaceDescriptor = {
+            compare: WebGPUCacheRenderPipeline._GetCompareFunction(this._stencilFrontCompare),
+            depthFailOp: WebGPUCacheRenderPipeline._GetStencilOpFunction(this._stencilFrontDepthFailOp),
+            failOp: WebGPUCacheRenderPipeline._GetStencilOpFunction(this._stencilFrontFailOp),
+            passOp: WebGPUCacheRenderPipeline._GetStencilOpFunction(this._stencilFrontPassOp)
+        };
 
 
         return this._device.createRenderPipeline({
         return this._device.createRenderPipeline({
             layout: pipelineLayout,
             layout: pipelineLayout,
@@ -333,20 +901,26 @@ export class WebGPUCacheRenderPipeline {
             primitiveTopology: topology,
             primitiveTopology: topology,
             rasterizationState: {
             rasterizationState: {
                 frontFace: this._frontFace === 1 ? WebGPUConstants.FrontFace.CCW : WebGPUConstants.FrontFace.CW,
                 frontFace: this._frontFace === 1 ? WebGPUConstants.FrontFace.CCW : WebGPUConstants.FrontFace.CW,
-                cullMode: !this._cullEnabled ? WebGPUConstants.CullMode.None : this._cullMode === 2 ? WebGPUConstants.CullMode.Front : WebGPUConstants.CullMode.Back,
+                cullMode: !this._cullEnabled ? WebGPUConstants.CullMode.None : this._cullFace === 2 ? WebGPUConstants.CullMode.Front : WebGPUConstants.CullMode.Back,
                 depthBias: this._depthBias,
                 depthBias: this._depthBias,
                 depthBiasClamp: this._depthBiasClamp,
                 depthBiasClamp: this._depthBiasClamp,
                 depthBiasSlopeScale: this._depthBiasSlopeScale,
                 depthBiasSlopeScale: this._depthBiasSlopeScale,
             },
             },
-            colorStates: {
-
-            },
+            colorStates,
 
 
             sampleCount,
             sampleCount,
-            depthStencilState: depthStateDescriptor,
+            depthStencilState: this._webgpuDepthStencilFormat === undefined ? undefined : {
+                depthWriteEnabled: this._depthWriteEnabled,
+                depthCompare: WebGPUCacheRenderPipeline._GetCompareFunction(this._depthCompare),
+                format: this._webgpuDepthStencilFormat,
+                stencilFront: stencilFrontBack,
+                stencilBack: stencilFrontBack,
+                stencilReadMask: this._stencilReadMask,
+                stencilWriteMask: this._stencilWriteMask,
+            },
 
 
             vertexState: inputStateDescriptor,
             vertexState: inputStateDescriptor,
         });
         });
-    }*/
+    }
 
 
-}
+}

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

@@ -99,6 +99,7 @@ export class WebGPUPipelineContext implements IPipelineContext {
         this._name = "unnamed";
         this._name = "unnamed";
         this.shaderProcessingContext = shaderProcessingContext;
         this.shaderProcessingContext = shaderProcessingContext;
         this.leftOverUniformsByName = {};
         this.leftOverUniformsByName = {};
+        this.engine = engine;
     }
     }
 
 
     public _handlesSpectorRebuildCallback(onCompiled: (program: any) => void): void {
     public _handlesSpectorRebuildCallback(onCompiled: (program: any) => void): void {

+ 2 - 0
src/Engines/index.ts

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

+ 1 - 3
src/Engines/webgpuEngine.ts

@@ -1185,9 +1185,7 @@ export class WebGPUEngine extends Engine {
      * @returns the new pipeline
      * @returns the new pipeline
      */
      */
     public createPipelineContext(shaderProcessingContext: Nullable<ShaderProcessingContext>): IPipelineContext {
     public createPipelineContext(shaderProcessingContext: Nullable<ShaderProcessingContext>): IPipelineContext {
-        var pipelineContext = new WebGPUPipelineContext(shaderProcessingContext! as WebGPUShaderProcessingContext, this);
-        pipelineContext.engine = this;
-        return pipelineContext;
+        return new WebGPUPipelineContext(shaderProcessingContext! as WebGPUShaderProcessingContext, this);
     }
     }
 
 
     /** @hidden */
     /** @hidden */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 4405 - 0
src/Engines/webgpuEngineCache.ts