瀏覽代碼

Render pipeline cache

Popov72 4 年之前
父節點
當前提交
6cbd765f30
共有 1 個文件被更改,包括 352 次插入0 次删除
  1. 352 0
      src/Engines/WebGPU/webgpuCacheRenderPipeline.ts

+ 352 - 0
src/Engines/WebGPU/webgpuCacheRenderPipeline.ts

@@ -0,0 +1,352 @@
+//import { Constants } from "../constants";
+//import * as WebGPUConstants from './webgpuConstants';
+import { Effect } from "../../Materials/effect";
+import { InternalTexture } from "../../Materials/Textures/internalTexture";
+import { VertexBuffer } from "../../Meshes/buffer";
+import { DataBuffer } from "../../Meshes/dataBuffer";
+import { Nullable } from "../../types";
+import { WebGPUHardwareTexture } from "./webgpuHardwareTexture";
+//import { WebGPUPipelineContext } from "./webgpuPipelineContext";
+
+enum StatePosition {
+    ShaderStage = 0,
+    PrimitiveTopology = 1,
+    FrontFace = 2,
+    CullMode = 3,
+    DepthBias=  4,
+    DepthBiasClamp = 5,
+    DepthBiasSlopeScale = 6,
+    ColorFormat = 7,
+    MRTAttachments = 8,
+    AlphaBlendFactors = 9,
+
+    NumStates = 10
+}
+
+const textureFormatToIndex: { [name: string]: number } = {
+    "" : 0,
+    "r8unorm": 1,
+    "r8snorm": 2,
+    "r8uint": 3,
+    "r8sint": 4,
+    "r16uint": 5,
+    "r16sint": 6,
+    "r16float": 7,
+    "rg8unorm": 8,
+    "rg8snorm": 9,
+    "rg8uint": 10,
+    "rg8sint": 11,
+    "r32uint": 12,
+    "r32sint": 13,
+    "r32float": 14,
+    "rg16uint": 15,
+    "rg16sint": 16,
+    "rg16float": 17,
+    "rgba8unorm": 18,
+    "rgba8unorm-srgb": 19,
+    "rgba8snorm": 20,
+    "rgba8uint": 21,
+    "rgba8sint": 22,
+    "bgra8unorm": 23,
+    "bgra8unorm-srgb": 24,
+    "rgb9e5ufloat": 25,
+    "rgb10a2unorm": 26,
+    "rg11b10ufloat": 27,
+    "rg32uint": 28,
+    "rg32sint": 29,
+    "rg32float": 30,
+    "rgba16uint": 31,
+    "rgba16sint": 32,
+    "rgba16float": 33,
+    "rgba32uint": 34,
+    "rgba32sint": 35,
+    "rgba32float": 36,
+    "stencil8": 37,
+    "depth16unorm": 38,
+    "depth24plus": 39,
+    "depth24plus-stencil8": 40,
+    "depth32float": 41,
+    "bc1-rgba-unorm": 42,
+    "bc1-rgba-unorm-srgb": 43,
+    "bc2-rgba-unorm": 44,
+    "bc2-rgba-unorm-srgb": 45,
+    "bc3-rgba-unorm": 46,
+    "bc3-rgba-unorm-srgb": 47,
+    "bc4-r-unorm": 48,
+    "bc4-r-snorm": 49,
+    "bc5-rg-unorm": 50,
+    "bc5-rg-snorm": 51,
+    "bc6h-rgb-ufloat": 52,
+    "bc6h-rgb-float": 53,
+    "bc7-rgba-unorm": 54,
+    "bc7-rgba-unorm-srgb": 55,
+    "depth24unorm-stencil8": 56,
+    "depth32float-stencil8": 57,
+};
+
+/** @hidden */
+export class WebGPUCacheRenderPipeline {
+
+    public static NumCacheHitWithoutHash = 0;
+    public static NumCacheHitWithHash = 0;
+    public static NumCacheMiss = 0;
+    public static NumPipelineCreationLastFrame = 0;
+
+    private static _Cache: { [hash: string]: GPURenderPipeline } = {};
+    private static _NumPipelineCreationCurrentFrame = 0;
+
+    //private _device: GPUDevice;
+    private _states: string[];
+    private _isDirty: boolean;
+    private _currentRenderPipeline: GPURenderPipeline;
+
+    private _shaderId: number;
+    private _topology: number;
+    private _frontFace: number;
+    private _cullEnabled: boolean;
+    private _cullFace: number;
+    private _cullMode: number;
+    private _depthBias: number;
+    private _depthBiasClamp: number;
+    private _depthBiasSlopeScale: number;
+    private _colorFormat: GPUTextureFormat;
+    private _mrtAttachments: number;
+    private _alphaBlendEnabled: boolean;
+    private _alphaBlendFuncParams: number[];
+    private _alphaBlendEqParams: number[];
+    private _alphaBlend: number;
+
+    constructor(device: GPUDevice) {
+        //this._device = device;
+        this._states = [];
+        this._states.length = StatePosition.NumStates;
+        this._isDirty = true;
+        this._alphaBlendFuncParams.length = 4;
+        this._alphaBlendEqParams.length = 2;
+    }
+
+    public getRenderPipeline(fillMode: number, effect: Effect, sampleCount: number): GPURenderPipeline {
+        this._setShaderStage(effect.uniqueId);
+        this._setTopology(fillMode);
+        this._applyCullMode();
+
+        if (!this._isDirty && this._currentRenderPipeline) {
+            WebGPUCacheRenderPipeline.NumCacheHitWithoutHash++;
+            return this._currentRenderPipeline;
+        }
+
+        let hash = this._states.join("_");
+        let pipeline = WebGPUCacheRenderPipeline._Cache[hash];
+
+        if (pipeline) {
+            this._currentRenderPipeline = pipeline;
+            WebGPUCacheRenderPipeline.NumCacheHitWithHash++;
+            return pipeline;
+        }
+
+        //const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
+
+        //this._currentRenderPipeline = WebGPUCacheRenderPipeline._Cache[hash] = this._createRenderPipeline(effect._pipelineContext as WebGPUPipelineContext, topology, sampleCount);
+
+        WebGPUCacheRenderPipeline.NumCacheMiss++;
+        WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
+
+        return this._currentRenderPipeline;
+    }
+
+    public endFrame(): void {
+        WebGPUCacheRenderPipeline.NumPipelineCreationLastFrame = WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame;
+        WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame = 0;
+    }
+
+    public setFrontFace(frontFace: number): void {
+        if (this._frontFace !== frontFace) {
+            this._frontFace = frontFace;
+            this._states[StatePosition.FrontFace] = frontFace.toString();
+            this._isDirty = true;
+        }
+    }
+
+    public setCullEnabled(enabled: boolean): void {
+        this._cullEnabled = enabled;
+    }
+
+    public setCullFace(cullFace: number): void {
+        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 setDepthBias(depthBias: number): void {
+        if (this._depthBias !== depthBias) {
+            this._depthBias = depthBias;
+            this._states[StatePosition.DepthBias] = depthBias.toString();
+            this._isDirty = true;
+        }
+    }
+
+    public setDepthBiasClamp(depthBiasClamp: number): void {
+        if (this._depthBiasClamp !== depthBiasClamp) {
+            this._depthBiasClamp = depthBiasClamp;
+            this._states[StatePosition.DepthBiasClamp] = depthBiasClamp.toString();
+            this._isDirty = true;
+        }
+    }
+
+    public setDepthBiasSlopeScale(depthBiasSlopeScale: number): void {
+        if (this._depthBiasSlopeScale !== depthBiasSlopeScale) {
+            this._depthBiasSlopeScale = depthBiasSlopeScale;
+            this._states[StatePosition.DepthBiasSlopeScale] = depthBiasSlopeScale.toString();
+            this._isDirty = true;
+        }
+    }
+
+    public setColorFormat(format: GPUTextureFormat): void {
+        if (this._colorFormat !== format) {
+            this._colorFormat = format;
+            this._states[StatePosition.ColorFormat] = format;
+            this._isDirty = true;
+        }
+    }
+
+    public setMRTAttachments(attachments: number[], textureArray: InternalTexture[]): void {
+        if (attachments.length > 10) {
+            // If we want more than 10 attachments we need to change this method but 10 seems plenty and it allows to use some bit shifting for faster operations
+            // Note we can do better without changing this method if only dealing with texture formats that can be used as output attachments
+            // It could allow to use 5 bits (or even less) to code a texture format. For the time being, we use 6 bits as we need 58 different values (2^6=64)
+            // so we can encode 10 texture formats in 64 bits
+            throw "Can't handle more than 10 attachments for a MRT in cache render pipeline!";
+        }
+        let bits = 0, mask = 0;
+        for (let i = 0; i < attachments.length; ++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>;
+
+                bits += textureFormatToIndex[gpuTexture?.format ?? ""] << mask;
+            }
+            mask += 6;
+        }
+        if (this._mrtAttachments !== bits) {
+            this._mrtAttachments = bits;
+            this._states[StatePosition.MRTAttachments] = bits.toString();
+            this._isDirty = true;
+        }
+    }
+
+    public setAlphaBlendEnabled(enabled: boolean): void {
+        this._alphaBlendEnabled = enabled;
+    }
+
+    public setAlphaBlendFactors(factors: number[], operations: number[]): void {
+
+    }
+
+    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();
+            this._isDirty = true;
+        }
+    }
+
+    public setBuffers(vertexBuffers: Nullable<{ [key: string]: Nullable<VertexBuffer> }>, indexBuffer: Nullable<DataBuffer>): void {
+
+    }
+
+    /*private static _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 _setTopology(topology: number): void {
+        if (this._topology !== topology) {
+            this._topology = topology;
+            this._states[StatePosition.PrimitiveTopology] = topology.toString();
+            this._isDirty = true;
+        }
+    }
+
+    private _setShaderStage(id: number): void {
+        if (this._shaderId !== id) {
+            this._shaderId = id;
+            this._states[StatePosition.ShaderStage] = id.toString();
+            this._isDirty = true;
+        }
+    }
+
+    /*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;
+
+        return this._device.createRenderPipeline({
+            layout: pipelineLayout,
+            ...webgpuPipelineContext.stages!,
+            primitiveTopology: topology,
+            rasterizationState: {
+                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,
+                depthBias: this._depthBias,
+                depthBiasClamp: this._depthBiasClamp,
+                depthBiasSlopeScale: this._depthBiasSlopeScale,
+            },
+            colorStates: {
+
+            },
+
+            sampleCount,
+            depthStencilState: depthStateDescriptor,
+
+            vertexState: inputStateDescriptor,
+        });
+    }*/
+
+}