123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- /* eslint-disable @typescript-eslint/naming-convention */
- /* eslint-disable babylonjs/available */
- /* eslint-disable jsdoc/require-jsdoc */
- import * as WebGPUConstants from "./webgpuConstants.js";
- import { VertexBuffer } from "../../Buffers/buffer.js";
- import { WebGPUShaderProcessor } from "./webgpuShaderProcessor.js";
- import { WebGPUTextureHelper } from "./webgpuTextureHelper.js";
- import { renderableTextureFormatToIndex } from "./webgpuTextureManager.js";
- var StatePosition;
- (function (StatePosition) {
- StatePosition[StatePosition["StencilReadMask"] = 0] = "StencilReadMask";
- StatePosition[StatePosition["StencilWriteMask"] = 1] = "StencilWriteMask";
- //DepthBiasClamp = 1, // not used, so remove it to improve perf
- StatePosition[StatePosition["DepthBias"] = 2] = "DepthBias";
- StatePosition[StatePosition["DepthBiasSlopeScale"] = 3] = "DepthBiasSlopeScale";
- StatePosition[StatePosition["DepthStencilState"] = 4] = "DepthStencilState";
- StatePosition[StatePosition["MRTAttachments1"] = 5] = "MRTAttachments1";
- StatePosition[StatePosition["MRTAttachments2"] = 6] = "MRTAttachments2";
- StatePosition[StatePosition["RasterizationState"] = 7] = "RasterizationState";
- StatePosition[StatePosition["ColorStates"] = 8] = "ColorStates";
- StatePosition[StatePosition["ShaderStage"] = 9] = "ShaderStage";
- StatePosition[StatePosition["TextureStage"] = 10] = "TextureStage";
- StatePosition[StatePosition["VertexState"] = 11] = "VertexState";
- StatePosition[StatePosition["NumStates"] = 12] = "NumStates";
- })(StatePosition || (StatePosition = {}));
- const alphaBlendFactorToIndex = {
- 0: 1,
- 1: 2,
- 0x0300: 3,
- 0x0301: 4,
- 0x0302: 5,
- 0x0303: 6,
- 0x0304: 7,
- 0x0305: 8,
- 0x0306: 9,
- 0x0307: 10,
- 0x0308: 11,
- 0x8001: 12,
- 0x8002: 13,
- 0x8003: 12,
- 0x8004: 13, // OneMinusBlendColor (alpha)
- };
- const stencilOpToIndex = {
- 0x0000: 0,
- 0x1e00: 1,
- 0x1e01: 2,
- 0x1e02: 3,
- 0x1e03: 4,
- 0x150a: 5,
- 0x8507: 6,
- 0x8508: 7, // DECR_WRAP
- };
- const vertexBufferKindForNonFloatProcessing = {
- [VertexBuffer.PositionKind]: true,
- [VertexBuffer.NormalKind]: true,
- [VertexBuffer.TangentKind]: true,
- [VertexBuffer.UVKind]: true,
- [VertexBuffer.UV2Kind]: true,
- [VertexBuffer.UV3Kind]: true,
- [VertexBuffer.UV4Kind]: true,
- [VertexBuffer.UV5Kind]: true,
- [VertexBuffer.UV6Kind]: true,
- [VertexBuffer.ColorKind]: true,
- [VertexBuffer.ColorInstanceKind]: true,
- [VertexBuffer.MatricesIndicesKind]: true,
- [VertexBuffer.MatricesWeightsKind]: true,
- [VertexBuffer.MatricesIndicesExtraKind]: true,
- [VertexBuffer.MatricesWeightsExtraKind]: true,
- };
- /** @internal */
- export class WebGPUCacheRenderPipeline {
- static _IsSignedType(type) {
- switch (type) {
- case VertexBuffer.BYTE:
- case VertexBuffer.SHORT:
- case VertexBuffer.INT:
- case VertexBuffer.FLOAT:
- return true;
- case VertexBuffer.UNSIGNED_BYTE:
- case VertexBuffer.UNSIGNED_SHORT:
- case VertexBuffer.UNSIGNED_INT:
- return false;
- default:
- throw new Error(`Invalid type '${type}'`);
- }
- }
- constructor(device, emptyVertexBuffer) {
- this.mrtTextureCount = 0;
- this._device = device;
- this._useTextureStage = true; // we force usage because we must handle depth textures with "float" filtering, which can't be fixed by a caps (like "textureFloatLinearFiltering" can for float textures)
- this._states = new Array(30); // pre-allocate enough room so that no new allocation will take place afterwards
- this._statesLength = 0;
- this._stateDirtyLowestIndex = 0;
- this._emptyVertexBuffer = emptyVertexBuffer;
- this._mrtFormats = [];
- this._parameter = { token: undefined, pipeline: null };
- this.disabled = false;
- this.vertexBuffers = [];
- this._kMaxVertexBufferStride = device.limits.maxVertexBufferArrayStride || 2048;
- this.reset();
- }
- reset() {
- this._isDirty = true;
- this.vertexBuffers.length = 0;
- this.setAlphaToCoverage(false);
- this.resetDepthCullingState();
- this.setClampDepth(false);
- this.setDepthBias(0);
- //this.setDepthBiasClamp(0);
- this._webgpuColorFormat = [WebGPUConstants.TextureFormat.BGRA8Unorm];
- this.setColorFormat(WebGPUConstants.TextureFormat.BGRA8Unorm);
- this.setMRT([]);
- 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, null);
- this._setTextureState(0);
- }
- get colorFormats() {
- return this._mrtAttachments1 > 0 ? this._mrtFormats : this._webgpuColorFormat;
- }
- getRenderPipeline(fillMode, effect, sampleCount, textureState = 0) {
- sampleCount = WebGPUTextureHelper.GetSample(sampleCount);
- if (this.disabled) {
- const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
- this._setVertexState(effect); // to fill this.vertexBuffers with correct data
- this._setTextureState(textureState);
- this._parameter.pipeline = this._createRenderPipeline(effect, topology, sampleCount);
- WebGPUCacheRenderPipeline.NumCacheMiss++;
- WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
- return this._parameter.pipeline;
- }
- this._setShaderStage(effect.uniqueId);
- this._setRasterizationState(fillMode, sampleCount);
- this._setColorStates();
- this._setDepthStencilState();
- this._setVertexState(effect);
- this._setTextureState(textureState);
- this.lastStateDirtyLowestIndex = this._stateDirtyLowestIndex;
- if (!this._isDirty && this._parameter.pipeline) {
- this._stateDirtyLowestIndex = this._statesLength;
- WebGPUCacheRenderPipeline.NumCacheHitWithoutHash++;
- return this._parameter.pipeline;
- }
- this._getRenderPipeline(this._parameter);
- this._isDirty = false;
- this._stateDirtyLowestIndex = this._statesLength;
- if (this._parameter.pipeline) {
- WebGPUCacheRenderPipeline.NumCacheHitWithHash++;
- return this._parameter.pipeline;
- }
- const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
- this._parameter.pipeline = this._createRenderPipeline(effect, topology, sampleCount);
- this._setRenderPipeline(this._parameter);
- WebGPUCacheRenderPipeline.NumCacheMiss++;
- WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
- return this._parameter.pipeline;
- }
- endFrame() {
- WebGPUCacheRenderPipeline.NumPipelineCreationLastFrame = WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame;
- WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame = 0;
- }
- setAlphaToCoverage(enabled) {
- this._alphaToCoverageEnabled = enabled;
- }
- setFrontFace(frontFace) {
- this._frontFace = frontFace;
- }
- setCullEnabled(enabled) {
- this._cullEnabled = enabled;
- }
- setCullFace(cullFace) {
- this._cullFace = cullFace;
- }
- setClampDepth(clampDepth) {
- this._clampDepth = clampDepth;
- }
- resetDepthCullingState() {
- this.setDepthCullingState(false, 2, 1, 0, 0, true, true, 519);
- }
- setDepthCullingState(cullEnabled, frontFace, cullFace, zOffset, zOffsetUnits, depthTestEnabled, depthWriteEnabled, depthCompare) {
- this._depthWriteEnabled = depthWriteEnabled;
- this._depthTestEnabled = depthTestEnabled;
- this._depthCompare = (depthCompare ?? 519) - 0x0200;
- this._cullFace = cullFace;
- this._cullEnabled = cullEnabled;
- this._frontFace = frontFace;
- this.setDepthBiasSlopeScale(zOffset);
- this.setDepthBias(zOffsetUnits);
- }
- setDepthBias(depthBias) {
- if (this._depthBias !== depthBias) {
- this._depthBias = depthBias;
- this._states[StatePosition.DepthBias] = depthBias;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.DepthBias);
- }
- }
- /*public setDepthBiasClamp(depthBiasClamp: number): void {
- if (this._depthBiasClamp !== depthBiasClamp) {
- this._depthBiasClamp = depthBiasClamp;
- this._states[StatePosition.DepthBiasClamp] = depthBiasClamp.toString();
- this._isDirty = true;
- }
- }*/
- setDepthBiasSlopeScale(depthBiasSlopeScale) {
- if (this._depthBiasSlopeScale !== depthBiasSlopeScale) {
- this._depthBiasSlopeScale = depthBiasSlopeScale;
- this._states[StatePosition.DepthBiasSlopeScale] = depthBiasSlopeScale;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.DepthBiasSlopeScale);
- }
- }
- setColorFormat(format) {
- this._webgpuColorFormat[0] = format;
- this._colorFormat = renderableTextureFormatToIndex[format ?? ""];
- }
- setMRTAttachments(attachments) {
- this.mrtAttachments = attachments;
- let mask = 0;
- for (let i = 0; i < attachments.length; ++i) {
- if (attachments[i] !== 0) {
- mask += 1 << i;
- }
- }
- if (this._mrtEnabledMask !== mask) {
- this._mrtEnabledMask = mask;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.MRTAttachments1);
- }
- }
- setMRT(textureArray, textureCount) {
- textureCount = textureCount ?? textureArray.length;
- if (textureCount > 10) {
- // If we want more than 10 attachments we need to change this method (and the StatePosition enum) but 10 seems plenty: note that WebGPU only supports 8 at the time (2021/12/13)!
- // As we need ~39 different values we are using 6 bits to encode a texture format, meaning we can encode 5 texture formats in 32 bits
- // We are using 2x32 bit values to handle 10 textures
- // eslint-disable-next-line no-throw-literal
- throw "Can't handle more than 10 attachments for a MRT in cache render pipeline!";
- }
- this.mrtTextureArray = textureArray;
- this.mrtTextureCount = textureCount;
- this._mrtEnabledMask = 0xffff; // all textures are enabled at start (meaning we can write to them). Calls to setMRTAttachments may disable some
- const bits = [0, 0];
- let indexBits = 0, mask = 0, numRT = 0;
- for (let i = 0; i < textureCount; ++i) {
- const texture = textureArray[i];
- const gpuWrapper = texture?._hardwareTexture;
- this._mrtFormats[numRT] = gpuWrapper?.format ?? this._webgpuColorFormat[0];
- bits[indexBits] += renderableTextureFormatToIndex[this._mrtFormats[numRT] ?? ""] << mask;
- mask += 6;
- numRT++;
- if (mask >= 32) {
- mask = 0;
- indexBits++;
- }
- }
- this._mrtFormats.length = numRT;
- if (this._mrtAttachments1 !== bits[0] || this._mrtAttachments2 !== bits[1]) {
- this._mrtAttachments1 = bits[0];
- this._mrtAttachments2 = bits[1];
- this._states[StatePosition.MRTAttachments1] = bits[0];
- this._states[StatePosition.MRTAttachments2] = bits[1];
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.MRTAttachments1);
- }
- }
- setAlphaBlendEnabled(enabled) {
- this._alphaBlendEnabled = enabled;
- }
- setAlphaBlendFactors(factors, operations) {
- this._alphaBlendFuncParams = factors;
- this._alphaBlendEqParams = operations;
- }
- setWriteMask(mask) {
- this._writeMask = mask;
- }
- setDepthStencilFormat(format) {
- this._webgpuDepthStencilFormat = format;
- this._depthStencilFormat = format === undefined ? 0 : renderableTextureFormatToIndex[format];
- }
- setDepthTestEnabled(enabled) {
- this._depthTestEnabled = enabled;
- }
- setDepthWriteEnabled(enabled) {
- this._depthWriteEnabled = enabled;
- }
- setDepthCompare(func) {
- this._depthCompare = (func ?? 519) - 0x0200;
- }
- setStencilEnabled(enabled) {
- this._stencilEnabled = enabled;
- }
- setStencilCompare(func) {
- this._stencilFrontCompare = (func ?? 519) - 0x0200;
- }
- setStencilDepthFailOp(op) {
- this._stencilFrontDepthFailOp = op === null ? 1 /* KEEP */ : stencilOpToIndex[op];
- }
- setStencilPassOp(op) {
- this._stencilFrontPassOp = op === null ? 2 /* REPLACE */ : stencilOpToIndex[op];
- }
- setStencilFailOp(op) {
- this._stencilFrontFailOp = op === null ? 1 /* KEEP */ : stencilOpToIndex[op];
- }
- setStencilReadMask(mask) {
- if (this._stencilReadMask !== mask) {
- this._stencilReadMask = mask;
- this._states[StatePosition.StencilReadMask] = mask;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.StencilReadMask);
- }
- }
- setStencilWriteMask(mask) {
- if (this._stencilWriteMask !== mask) {
- this._stencilWriteMask = mask;
- this._states[StatePosition.StencilWriteMask] = mask;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.StencilWriteMask);
- }
- }
- resetStencilState() {
- this.setStencilState(false, 519, 7680, 7681, 7680, 0xff, 0xff);
- }
- setStencilState(stencilEnabled, compare, depthFailOp, passOp, failOp, readMask, writeMask) {
- this._stencilEnabled = stencilEnabled;
- this._stencilFrontCompare = (compare ?? 519) - 0x0200;
- this._stencilFrontDepthFailOp = depthFailOp === null ? 1 /* KEEP */ : stencilOpToIndex[depthFailOp];
- this._stencilFrontPassOp = passOp === null ? 2 /* REPLACE */ : stencilOpToIndex[passOp];
- this._stencilFrontFailOp = failOp === null ? 1 /* KEEP */ : stencilOpToIndex[failOp];
- this.setStencilReadMask(readMask);
- this.setStencilWriteMask(writeMask);
- }
- setBuffers(vertexBuffers, indexBuffer, overrideVertexBuffers) {
- this._vertexBuffers = vertexBuffers;
- this._overrideVertexBuffers = overrideVertexBuffers;
- this._indexBuffer = indexBuffer;
- }
- static _GetTopology(fillMode) {
- switch (fillMode) {
- // Triangle views
- case 0:
- return WebGPUConstants.PrimitiveTopology.TriangleList;
- case 2:
- return WebGPUConstants.PrimitiveTopology.PointList;
- case 1:
- return WebGPUConstants.PrimitiveTopology.LineList;
- // Draw modes
- case 3:
- return WebGPUConstants.PrimitiveTopology.PointList;
- case 4:
- return WebGPUConstants.PrimitiveTopology.LineList;
- case 5:
- // return this._gl.LINE_LOOP;
- // TODO WEBGPU. Line Loop Mode Fallback at buffer load time.
- // eslint-disable-next-line no-throw-literal
- throw "LineLoop is an unsupported fillmode in WebGPU";
- case 6:
- return WebGPUConstants.PrimitiveTopology.LineStrip;
- case 7:
- return WebGPUConstants.PrimitiveTopology.TriangleStrip;
- case 8:
- // return this._gl.TRIANGLE_FAN;
- // TODO WEBGPU. Triangle Fan Mode Fallback at buffer load time.
- // eslint-disable-next-line no-throw-literal
- throw "TriangleFan is an unsupported fillmode in WebGPU";
- default:
- return WebGPUConstants.PrimitiveTopology.TriangleList;
- }
- }
- static _GetAphaBlendOperation(operation) {
- switch (operation) {
- case 32774:
- return WebGPUConstants.BlendOperation.Add;
- case 32778:
- return WebGPUConstants.BlendOperation.Subtract;
- case 32779:
- return WebGPUConstants.BlendOperation.ReverseSubtract;
- case 32775:
- return WebGPUConstants.BlendOperation.Min;
- case 32776:
- return WebGPUConstants.BlendOperation.Max;
- default:
- return WebGPUConstants.BlendOperation.Add;
- }
- }
- static _GetAphaBlendFactor(factor) {
- switch (factor) {
- case 0:
- return WebGPUConstants.BlendFactor.Zero;
- case 1:
- return WebGPUConstants.BlendFactor.One;
- case 768:
- return WebGPUConstants.BlendFactor.Src;
- case 769:
- return WebGPUConstants.BlendFactor.OneMinusSrc;
- case 770:
- return WebGPUConstants.BlendFactor.SrcAlpha;
- case 771:
- return WebGPUConstants.BlendFactor.OneMinusSrcAlpha;
- case 772:
- return WebGPUConstants.BlendFactor.DstAlpha;
- case 773:
- return WebGPUConstants.BlendFactor.OneMinusDstAlpha;
- case 774:
- return WebGPUConstants.BlendFactor.Dst;
- case 775:
- return WebGPUConstants.BlendFactor.OneMinusDst;
- case 776:
- return WebGPUConstants.BlendFactor.SrcAlphaSaturated;
- case 32769:
- return WebGPUConstants.BlendFactor.Constant;
- case 32770:
- return WebGPUConstants.BlendFactor.OneMinusConstant;
- case 32771:
- return WebGPUConstants.BlendFactor.Constant;
- case 32772:
- return WebGPUConstants.BlendFactor.OneMinusConstant;
- default:
- return WebGPUConstants.BlendFactor.One;
- }
- }
- static _GetCompareFunction(compareFunction) {
- 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;
- }
- static _GetStencilOpFunction(operation) {
- 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;
- }
- static _GetVertexInputDescriptorFormat(vertexBuffer) {
- 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.Snorm8x2 : WebGPUConstants.VertexFormat.Sint8x2;
- case 3:
- case 4:
- return normalized ? WebGPUConstants.VertexFormat.Snorm8x4 : WebGPUConstants.VertexFormat.Sint8x4;
- }
- break;
- case VertexBuffer.UNSIGNED_BYTE:
- switch (size) {
- case 1:
- case 2:
- return normalized ? WebGPUConstants.VertexFormat.Unorm8x2 : WebGPUConstants.VertexFormat.Uint8x2;
- case 3:
- case 4:
- return normalized ? WebGPUConstants.VertexFormat.Unorm8x4 : WebGPUConstants.VertexFormat.Uint8x4;
- }
- break;
- case VertexBuffer.SHORT:
- switch (size) {
- case 1:
- case 2:
- return normalized ? WebGPUConstants.VertexFormat.Snorm16x2 : WebGPUConstants.VertexFormat.Sint16x2;
- case 3:
- case 4:
- return normalized ? WebGPUConstants.VertexFormat.Snorm16x4 : WebGPUConstants.VertexFormat.Sint16x4;
- }
- break;
- case VertexBuffer.UNSIGNED_SHORT:
- switch (size) {
- case 1:
- case 2:
- return normalized ? WebGPUConstants.VertexFormat.Unorm16x2 : WebGPUConstants.VertexFormat.Uint16x2;
- case 3:
- case 4:
- return normalized ? WebGPUConstants.VertexFormat.Unorm16x4 : WebGPUConstants.VertexFormat.Uint16x4;
- }
- break;
- case VertexBuffer.INT:
- switch (size) {
- case 1:
- return WebGPUConstants.VertexFormat.Sint32;
- case 2:
- return WebGPUConstants.VertexFormat.Sint32x2;
- case 3:
- return WebGPUConstants.VertexFormat.Sint32x3;
- case 4:
- return WebGPUConstants.VertexFormat.Sint32x4;
- }
- break;
- case VertexBuffer.UNSIGNED_INT:
- switch (size) {
- case 1:
- return WebGPUConstants.VertexFormat.Uint32;
- case 2:
- return WebGPUConstants.VertexFormat.Uint32x2;
- case 3:
- return WebGPUConstants.VertexFormat.Uint32x3;
- case 4:
- return WebGPUConstants.VertexFormat.Uint32x4;
- }
- break;
- case VertexBuffer.FLOAT:
- switch (size) {
- case 1:
- return WebGPUConstants.VertexFormat.Float32;
- case 2:
- return WebGPUConstants.VertexFormat.Float32x2;
- case 3:
- return WebGPUConstants.VertexFormat.Float32x3;
- case 4:
- return WebGPUConstants.VertexFormat.Float32x4;
- }
- break;
- }
- throw new Error(`Invalid Format '${vertexBuffer.getKind()}' - type=${type}, normalized=${normalized}, size=${size}`);
- }
- _getAphaBlendState() {
- if (!this._alphaBlendEnabled) {
- return null;
- }
- return {
- srcFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[2]),
- dstFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[3]),
- operation: WebGPUCacheRenderPipeline._GetAphaBlendOperation(this._alphaBlendEqParams[1]),
- };
- }
- _getColorBlendState() {
- if (!this._alphaBlendEnabled) {
- return null;
- }
- return {
- srcFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[0]),
- dstFactor: WebGPUCacheRenderPipeline._GetAphaBlendFactor(this._alphaBlendFuncParams[1]),
- operation: WebGPUCacheRenderPipeline._GetAphaBlendOperation(this._alphaBlendEqParams[0]),
- };
- }
- _setShaderStage(id) {
- if (this._shaderId !== id) {
- this._shaderId = id;
- this._states[StatePosition.ShaderStage] = id;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.ShaderStage);
- }
- }
- _setRasterizationState(topology, sampleCount) {
- 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;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.RasterizationState);
- }
- }
- _setColorStates() {
- let colorStates = ((this._writeMask ? 1 : 0) << 22) + (this._colorFormat << 23) + ((this._depthWriteEnabled ? 1 : 0) << 29); // this state has been moved from depthStencilState here because alpha and depth are related (generally when alpha is on, depth write is off and the other way around)
- 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;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.ColorStates);
- }
- }
- _setDepthStencilState() {
- const stencilState = !this._stencilEnabled
- ? 7 /* ALWAYS */ + (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._depthTestEnabled ? this._depthCompare : 7) /* ALWAYS */ << 6) + (stencilState << 10); // stencil front - stencil back is the same
- if (this._depthStencilState !== depthStencilState) {
- this._depthStencilState = depthStencilState;
- this._states[StatePosition.DepthStencilState] = this._depthStencilState;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.DepthStencilState);
- }
- }
- _setVertexState(effect) {
- const currStateLen = this._statesLength;
- let newNumStates = StatePosition.VertexState;
- const webgpuPipelineContext = effect._pipelineContext;
- const attributes = webgpuPipelineContext.shaderProcessingContext.attributeNamesFromEffect;
- const locations = webgpuPipelineContext.shaderProcessingContext.attributeLocationsFromEffect;
- let currentGPUBuffer;
- let numVertexBuffers = 0;
- for (let index = 0; index < attributes.length; index++) {
- const location = locations[index];
- let vertexBuffer = (this._overrideVertexBuffers && this._overrideVertexBuffers[attributes[index]]) ?? 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 buffer = vertexBuffer.effectiveBuffer?.underlyingResource;
- // We optimize usage of GPUVertexBufferLayout: we will create a single GPUVertexBufferLayout for all the attributes which follow each other and which use the same GPU buffer
- // However, there are some constraints in the attribute.offset value range, so we must check for them before being able to reuse the same GPUVertexBufferLayout
- // See _getVertexInputDescriptor() below
- if (vertexBuffer._validOffsetRange === undefined) {
- const offset = vertexBuffer.effectiveByteOffset;
- const formatSize = vertexBuffer.getSize(true);
- const byteStride = vertexBuffer.effectiveByteStride;
- vertexBuffer._validOffsetRange =
- (offset + formatSize <= this._kMaxVertexBufferStride && byteStride === 0) || (byteStride !== 0 && offset + formatSize <= byteStride);
- }
- if (!(currentGPUBuffer && currentGPUBuffer === buffer && vertexBuffer._validOffsetRange)) {
- // we can't combine the previous vertexBuffer with the current one
- this.vertexBuffers[numVertexBuffers++] = vertexBuffer;
- currentGPUBuffer = vertexBuffer._validOffsetRange ? buffer : null;
- }
- const vid = vertexBuffer.hashCode + (location << 7);
- this._isDirty = this._isDirty || this._states[newNumStates] !== vid;
- this._states[newNumStates++] = vid;
- }
- this.vertexBuffers.length = numVertexBuffers;
- this._statesLength = newNumStates;
- this._isDirty = this._isDirty || newNumStates !== currStateLen;
- if (this._isDirty) {
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.VertexState);
- }
- }
- _setTextureState(textureState) {
- if (this._textureState !== textureState) {
- this._textureState = textureState;
- this._states[StatePosition.TextureStage] = this._textureState;
- this._isDirty = true;
- this._stateDirtyLowestIndex = Math.min(this._stateDirtyLowestIndex, StatePosition.TextureStage);
- }
- }
- _createPipelineLayout(webgpuPipelineContext) {
- if (this._useTextureStage) {
- return this._createPipelineLayoutWithTextureStage(webgpuPipelineContext);
- }
- const bindGroupLayouts = [];
- const bindGroupLayoutEntries = webgpuPipelineContext.shaderProcessingContext.bindGroupLayoutEntries;
- for (let i = 0; i < bindGroupLayoutEntries.length; i++) {
- const setDefinition = bindGroupLayoutEntries[i];
- bindGroupLayouts[i] = this._device.createBindGroupLayout({
- entries: setDefinition,
- });
- }
- webgpuPipelineContext.bindGroupLayouts[0] = bindGroupLayouts;
- return this._device.createPipelineLayout({ bindGroupLayouts });
- }
- _createPipelineLayoutWithTextureStage(webgpuPipelineContext) {
- const shaderProcessingContext = webgpuPipelineContext.shaderProcessingContext;
- const bindGroupLayoutEntries = shaderProcessingContext.bindGroupLayoutEntries;
- let bitVal = 1;
- for (let i = 0; i < bindGroupLayoutEntries.length; i++) {
- const setDefinition = bindGroupLayoutEntries[i];
- for (let j = 0; j < setDefinition.length; j++) {
- const entry = bindGroupLayoutEntries[i][j];
- if (entry.texture) {
- const name = shaderProcessingContext.bindGroupLayoutEntryInfo[i][entry.binding].name;
- const textureInfo = shaderProcessingContext.availableTextures[name];
- const samplerInfo = textureInfo.autoBindSampler ? shaderProcessingContext.availableSamplers[name + WebGPUShaderProcessor.AutoSamplerSuffix] : null;
- let sampleType = textureInfo.sampleType;
- let samplerType = samplerInfo?.type ?? WebGPUConstants.SamplerBindingType.Filtering;
- if (this._textureState & bitVal && sampleType !== WebGPUConstants.TextureSampleType.Depth) {
- // The texture is a 32 bits float texture but the system does not support linear filtering for them OR the texture is a depth texture with "float" filtering:
- // we set the sampler to "non-filtering" and the texture sample type to "unfilterable-float"
- if (textureInfo.autoBindSampler) {
- samplerType = WebGPUConstants.SamplerBindingType.NonFiltering;
- }
- sampleType = WebGPUConstants.TextureSampleType.UnfilterableFloat;
- }
- entry.texture.sampleType = sampleType;
- if (samplerInfo) {
- const binding = shaderProcessingContext.bindGroupLayoutEntryInfo[samplerInfo.binding.groupIndex][samplerInfo.binding.bindingIndex].index;
- bindGroupLayoutEntries[samplerInfo.binding.groupIndex][binding].sampler.type = samplerType;
- }
- bitVal = bitVal << 1;
- }
- }
- }
- const bindGroupLayouts = [];
- for (let i = 0; i < bindGroupLayoutEntries.length; ++i) {
- bindGroupLayouts[i] = this._device.createBindGroupLayout({
- entries: bindGroupLayoutEntries[i],
- });
- }
- webgpuPipelineContext.bindGroupLayouts[this._textureState] = bindGroupLayouts;
- return this._device.createPipelineLayout({ bindGroupLayouts });
- }
- _getVertexInputDescriptor(effect) {
- const descriptors = [];
- const webgpuPipelineContext = effect._pipelineContext;
- const attributes = webgpuPipelineContext.shaderProcessingContext.attributeNamesFromEffect;
- const locations = webgpuPipelineContext.shaderProcessingContext.attributeLocationsFromEffect;
- let currentGPUBuffer;
- let currentGPUAttributes;
- for (let index = 0; index < attributes.length; index++) {
- const location = locations[index];
- let vertexBuffer = (this._overrideVertexBuffers && this._overrideVertexBuffers[attributes[index]]) ?? 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;
- }
- let buffer = vertexBuffer.effectiveBuffer?.underlyingResource;
- // We reuse the same GPUVertexBufferLayout for all attributes that use the same underlying GPU buffer (and for attributes that follow each other in the attributes array)
- let offset = vertexBuffer.effectiveByteOffset;
- const invalidOffsetRange = !vertexBuffer._validOffsetRange;
- if (!(currentGPUBuffer && currentGPUAttributes && currentGPUBuffer === buffer) || invalidOffsetRange) {
- const vertexBufferDescriptor = {
- arrayStride: vertexBuffer.effectiveByteStride,
- stepMode: vertexBuffer.getIsInstanced() ? WebGPUConstants.VertexStepMode.Instance : WebGPUConstants.VertexStepMode.Vertex,
- attributes: [],
- };
- descriptors.push(vertexBufferDescriptor);
- currentGPUAttributes = vertexBufferDescriptor.attributes;
- if (invalidOffsetRange) {
- offset = 0; // the offset will be set directly in the setVertexBuffer call
- buffer = null; // buffer can't be reused
- }
- }
- currentGPUAttributes.push({
- shaderLocation: location,
- offset,
- format: WebGPUCacheRenderPipeline._GetVertexInputDescriptorFormat(vertexBuffer),
- });
- currentGPUBuffer = buffer;
- }
- return descriptors;
- }
- _processNonFloatVertexBuffers(webgpuPipelineContext, effect) {
- const webgpuShaderProcessor = webgpuPipelineContext.engine._getShaderProcessor(webgpuPipelineContext.shaderProcessingContext.shaderLanguage);
- let reprocessShaders = false;
- for (const kind in this._vertexBuffers) {
- const currentVertexBuffer = this._vertexBuffers[kind];
- if (!currentVertexBuffer || !vertexBufferKindForNonFloatProcessing[kind]) {
- continue;
- }
- const currentVertexBufferType = currentVertexBuffer.normalized ? VertexBuffer.FLOAT : currentVertexBuffer.type;
- const vertexBufferType = webgpuPipelineContext.vertexBufferKindToType[kind];
- if ((currentVertexBufferType !== VertexBuffer.FLOAT && vertexBufferType === undefined) ||
- (vertexBufferType !== undefined && vertexBufferType !== currentVertexBufferType)) {
- reprocessShaders = true;
- webgpuPipelineContext.vertexBufferKindToType[kind] = currentVertexBufferType;
- if (currentVertexBufferType !== VertexBuffer.FLOAT) {
- webgpuShaderProcessor.vertexBufferKindToNumberOfComponents[kind] = VertexBuffer.DeduceStride(kind);
- if (WebGPUCacheRenderPipeline._IsSignedType(currentVertexBufferType)) {
- webgpuShaderProcessor.vertexBufferKindToNumberOfComponents[kind] *= -1;
- }
- }
- }
- }
- if (reprocessShaders) {
- effect._processShaderCode(webgpuShaderProcessor, true);
- }
- }
- _createRenderPipeline(effect, topology, sampleCount) {
- const webgpuPipelineContext = effect._pipelineContext;
- const inputStateDescriptor = this._getVertexInputDescriptor(effect);
- const pipelineLayout = this._createPipelineLayout(webgpuPipelineContext);
- const colorStates = [];
- const alphaBlend = this._getAphaBlendState();
- const colorBlend = this._getColorBlendState();
- this._processNonFloatVertexBuffers(webgpuPipelineContext, effect);
- if (this._mrtAttachments1 > 0) {
- for (let i = 0; i < this._mrtFormats.length; ++i) {
- const format = this._mrtFormats[i];
- if (format) {
- const descr = {
- format,
- writeMask: (this._mrtEnabledMask & (1 << i)) !== 0 ? this._writeMask : 0,
- };
- if (alphaBlend && colorBlend) {
- descr.blend = {
- alpha: alphaBlend,
- color: colorBlend,
- };
- }
- colorStates.push(descr);
- }
- else {
- colorStates.push(null);
- }
- }
- }
- else {
- if (this._webgpuColorFormat[0]) {
- const descr = {
- format: this._webgpuColorFormat[0],
- writeMask: this._writeMask,
- };
- if (alphaBlend && colorBlend) {
- descr.blend = {
- alpha: alphaBlend,
- color: colorBlend,
- };
- }
- colorStates.push(descr);
- }
- else {
- colorStates.push(null);
- }
- }
- const stencilFrontBack = {
- compare: WebGPUCacheRenderPipeline._GetCompareFunction(this._stencilEnabled ? this._stencilFrontCompare : 7 /* ALWAYS */),
- depthFailOp: WebGPUCacheRenderPipeline._GetStencilOpFunction(this._stencilEnabled ? this._stencilFrontDepthFailOp : 1 /* KEEP */),
- failOp: WebGPUCacheRenderPipeline._GetStencilOpFunction(this._stencilEnabled ? this._stencilFrontFailOp : 1 /* KEEP */),
- passOp: WebGPUCacheRenderPipeline._GetStencilOpFunction(this._stencilEnabled ? this._stencilFrontPassOp : 1 /* KEEP */),
- };
- let stripIndexFormat = undefined;
- if (topology === WebGPUConstants.PrimitiveTopology.LineStrip || topology === WebGPUConstants.PrimitiveTopology.TriangleStrip) {
- stripIndexFormat = !this._indexBuffer || this._indexBuffer.is32Bits ? WebGPUConstants.IndexFormat.Uint32 : WebGPUConstants.IndexFormat.Uint16;
- }
- const depthStencilFormatHasStencil = this._webgpuDepthStencilFormat ? WebGPUTextureHelper.HasStencilAspect(this._webgpuDepthStencilFormat) : false;
- return this._device.createRenderPipeline({
- label: `RenderPipeline_${colorStates[0]?.format ?? "nooutput"}_${this._webgpuDepthStencilFormat ?? "nodepth"}_samples${sampleCount}_textureState${this._textureState}`,
- layout: pipelineLayout,
- vertex: {
- module: webgpuPipelineContext.stages.vertexStage.module,
- entryPoint: webgpuPipelineContext.stages.vertexStage.entryPoint,
- buffers: inputStateDescriptor,
- },
- primitive: {
- topology,
- stripIndexFormat,
- frontFace: this._frontFace === 1 ? WebGPUConstants.FrontFace.CCW : WebGPUConstants.FrontFace.CW,
- cullMode: !this._cullEnabled ? WebGPUConstants.CullMode.None : this._cullFace === 2 ? WebGPUConstants.CullMode.Front : WebGPUConstants.CullMode.Back,
- },
- fragment: !webgpuPipelineContext.stages.fragmentStage
- ? undefined
- : {
- module: webgpuPipelineContext.stages.fragmentStage.module,
- entryPoint: webgpuPipelineContext.stages.fragmentStage.entryPoint,
- targets: colorStates,
- },
- multisample: {
- count: sampleCount,
- /*mask,
- alphaToCoverageEnabled,*/
- },
- depthStencil: this._webgpuDepthStencilFormat === undefined
- ? undefined
- : {
- depthWriteEnabled: this._depthWriteEnabled,
- depthCompare: this._depthTestEnabled ? WebGPUCacheRenderPipeline._GetCompareFunction(this._depthCompare) : WebGPUConstants.CompareFunction.Always,
- format: this._webgpuDepthStencilFormat,
- stencilFront: this._stencilEnabled && depthStencilFormatHasStencil ? stencilFrontBack : undefined,
- stencilBack: this._stencilEnabled && depthStencilFormatHasStencil ? stencilFrontBack : undefined,
- stencilReadMask: this._stencilEnabled && depthStencilFormatHasStencil ? this._stencilReadMask : undefined,
- stencilWriteMask: this._stencilEnabled && depthStencilFormatHasStencil ? this._stencilWriteMask : undefined,
- depthBias: this._depthBias,
- depthBiasClamp: this._depthBiasClamp,
- depthBiasSlopeScale: this._depthBiasSlopeScale,
- },
- });
- }
- }
- WebGPUCacheRenderPipeline.NumCacheHitWithoutHash = 0;
- WebGPUCacheRenderPipeline.NumCacheHitWithHash = 0;
- WebGPUCacheRenderPipeline.NumCacheMiss = 0;
- WebGPUCacheRenderPipeline.NumPipelineCreationLastFrame = 0;
- WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame = 0;
- //# sourceMappingURL=webgpuCacheRenderPipeline.js.map
|