|
@@ -84,7 +84,6 @@ export class WebGPUEngineCache extends Engine {
|
|
|
private _shaderManager: WebGPUShaderManager;
|
|
|
private _cacheSampler: WebGPUCacheSampler;
|
|
|
private _cacheRenderPipeline: WebGPUCacheRenderPipeline;
|
|
|
- private _cacheRenderPipelineClear: WebGPUCacheRenderPipeline;
|
|
|
private _emptyVertexBuffer: VertexBuffer;
|
|
|
private _lastCachedWrapU: number;
|
|
|
private _lastCachedWrapV: number;
|
|
@@ -146,6 +145,32 @@ export class WebGPUEngineCache extends Engine {
|
|
|
public dbgShowWarningsNotImplemented = false;
|
|
|
|
|
|
/**
|
|
|
+ * Sets this to true to disable the cache for the samplers. You should do it only for testing purpose!
|
|
|
+ */
|
|
|
+ public get disableCacheSamplers(): boolean {
|
|
|
+ return this._cacheSampler ? this._cacheSampler.disabled : false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public set disableCacheSamplers(disable: boolean) {
|
|
|
+ if (this._cacheSampler) {
|
|
|
+ this._cacheSampler.disabled = disable;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets this to true to disable the cache for the render pipelines. You should do it only for testing purpose!
|
|
|
+ */
|
|
|
+ public get disableCacheRenderPipelines(): boolean {
|
|
|
+ return this._cacheRenderPipeline ? this._cacheRenderPipeline.disabled : false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public set disableCacheRenderPipelines(disable: boolean) {
|
|
|
+ if (this._cacheRenderPipeline) {
|
|
|
+ this._cacheRenderPipeline.disabled = disable;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
|
|
|
* @returns true if the engine can be created
|
|
|
*/
|
|
@@ -331,7 +356,9 @@ export class WebGPUEngineCache extends Engine {
|
|
|
this._emptyVertexBuffer = new VertexBuffer(this, [0], "", false, false, 1, false, 0, 1);
|
|
|
|
|
|
this._cacheRenderPipeline = new WebGPUCacheRenderPipeline(this._device, this._emptyVertexBuffer);
|
|
|
- this._cacheRenderPipelineClear = new WebGPUCacheRenderPipeline(this._device, this._emptyVertexBuffer);
|
|
|
+
|
|
|
+ this._cacheRenderPipeline.setDepthCompare(this._depthCullingState.depthFunc);
|
|
|
+ //this._cacheRenderPipeline.disabled = true;
|
|
|
|
|
|
this._textureHelper.setCommandEncoder(this._uploadEncoder);
|
|
|
|
|
@@ -598,6 +625,7 @@ export class WebGPUEngineCache extends Engine {
|
|
|
this._depthCullingState.reset();
|
|
|
this._depthCullingState.depthFunc = Constants.LEQUAL;
|
|
|
this._cacheRenderPipeline.resetDepthCullingState();
|
|
|
+ this._cacheRenderPipeline.setDepthCompare(Constants.LEQUAL);
|
|
|
|
|
|
this._alphaState.reset();
|
|
|
this._alphaMode = Constants.ALPHA_ADD;
|
|
@@ -2760,10 +2788,6 @@ export class WebGPUEngineCache extends Engine {
|
|
|
return this._currentRenderPass!;
|
|
|
}
|
|
|
|
|
|
- private _currentRenderPassIsMRT(): boolean {
|
|
|
- return !!this._currentRenderTarget?._attachments ?? false;
|
|
|
- }
|
|
|
-
|
|
|
private _startMainRenderPass(setClearStates: boolean, clearColor?: Nullable<IColor4Like>, clearDepth?: boolean, clearStencil?: boolean): void {
|
|
|
if (this._mainRenderPassWrapper.renderPass) {
|
|
|
this._endMainRenderPass();
|
|
@@ -3102,7 +3126,6 @@ export class WebGPUEngineCache extends Engine {
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
public setZOffset(value: number): void {
|
|
|
- this._cacheRenderPipeline.setDepthBiasSlopeScale(value);
|
|
|
if (value !== this._depthCullingState.zOffset) {
|
|
|
this._depthCullingState.zOffset = value;
|
|
|
}
|
|
@@ -3126,35 +3149,30 @@ export class WebGPUEngineCache extends Engine {
|
|
|
}
|
|
|
|
|
|
public setDepthBuffer(enable: boolean): void {
|
|
|
- this._cacheRenderPipeline.setDepthTestEnabled(enable);
|
|
|
if (this._depthCullingState.depthTest !== enable) {
|
|
|
this._depthCullingState.depthTest = enable;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setDepthWrite(enable: boolean): void {
|
|
|
- this._cacheRenderPipeline.setDepthWriteEnabled(enable);
|
|
|
if (this._depthCullingState.depthMask !== enable) {
|
|
|
this._depthCullingState.depthMask = enable;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setStencilBuffer(enable: boolean): void {
|
|
|
- this._cacheRenderPipeline.setStencilEnabled(enable);
|
|
|
if (this._stencilState.stencilTest !== enable) {
|
|
|
this._stencilState.stencilTest = enable;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setStencilMask(mask: number): void {
|
|
|
- this._cacheRenderPipeline.setStencilWriteMask(mask);
|
|
|
if (this._stencilState.stencilMask !== mask) {
|
|
|
this._stencilState.stencilMask = mask;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setStencilFunction(stencilFunc: number) {
|
|
|
- this._cacheRenderPipeline.setStencilCompare(stencilFunc);
|
|
|
if (this._stencilState.stencilFunc !== stencilFunc) {
|
|
|
this._stencilState.stencilFunc = stencilFunc;
|
|
|
}
|
|
@@ -3167,28 +3185,24 @@ export class WebGPUEngineCache extends Engine {
|
|
|
}
|
|
|
|
|
|
public setStencilFunctionMask(mask: number) {
|
|
|
- this._cacheRenderPipeline.setStencilReadMask(mask);
|
|
|
if (this._stencilState.stencilFuncMask !== mask) {
|
|
|
this._stencilState.stencilFuncMask = mask;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setStencilOperationFail(operation: number): void {
|
|
|
- this._cacheRenderPipeline.setStencilFailOp(operation);
|
|
|
if (this._stencilState.stencilOpStencilFail !== operation) {
|
|
|
this._stencilState.stencilOpStencilFail = operation;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setStencilOperationDepthFail(operation: number): void {
|
|
|
- this._cacheRenderPipeline.setStencilDepthFailOp(operation);
|
|
|
if (this._stencilState.stencilOpDepthFail !== operation) {
|
|
|
this._stencilState.stencilOpDepthFail = operation;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setStencilOperationPass(operation: number): void {
|
|
|
- this._cacheRenderPipeline.setStencilPassOp(operation);
|
|
|
if (this._stencilState.stencilOpStencilDepthPass !== operation) {
|
|
|
this._stencilState.stencilOpStencilDepthPass = operation;
|
|
|
}
|
|
@@ -3203,123 +3217,35 @@ export class WebGPUEngineCache extends Engine {
|
|
|
}
|
|
|
|
|
|
public setDepthFunction(depthFunc: number) {
|
|
|
- this._cacheRenderPipeline.setDepthCompare(depthFunc);
|
|
|
if (this._depthCullingState.depthFunc !== depthFunc) {
|
|
|
this._depthCullingState.depthFunc = depthFunc;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setDepthFunctionToGreater(): void {
|
|
|
- this._cacheRenderPipeline.setDepthCompare(Constants.GREATER);
|
|
|
if (this._depthCullingState.depthFunc !== Constants.GREATER) {
|
|
|
this._depthCullingState.depthFunc = Constants.GREATER;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setDepthFunctionToGreaterOrEqual(): void {
|
|
|
- this._cacheRenderPipeline.setDepthCompare(Constants.GEQUAL);
|
|
|
if (this._depthCullingState.depthFunc !== Constants.GEQUAL) {
|
|
|
this._depthCullingState.depthFunc = Constants.GEQUAL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setDepthFunctionToLess(): void {
|
|
|
- this._cacheRenderPipeline.setDepthCompare(Constants.LESS);
|
|
|
if (this._depthCullingState.depthFunc !== Constants.LESS) {
|
|
|
this._depthCullingState.depthFunc = Constants.LESS;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public setDepthFunctionToLessOrEqual(): void {
|
|
|
- this._cacheRenderPipeline.setDepthCompare(Constants.LEQUAL);
|
|
|
if (this._depthCullingState.depthFunc !== Constants.LEQUAL) {
|
|
|
this._depthCullingState.depthFunc = Constants.LEQUAL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private _indexFormatInRenderPass(topology: GPUPrimitiveTopology): boolean {
|
|
|
- return topology === WebGPUConstants.PrimitiveTopology.PointList ||
|
|
|
- topology === WebGPUConstants.PrimitiveTopology.LineList ||
|
|
|
- topology === WebGPUConstants.PrimitiveTopology.TriangleList;
|
|
|
- }
|
|
|
-
|
|
|
- private _getTopology(fillMode: number): GPUPrimitiveTopology {
|
|
|
- switch (fillMode) {
|
|
|
- // Triangle views
|
|
|
- case Constants.MATERIAL_TriangleFillMode:
|
|
|
- return WebGPUConstants.PrimitiveTopology.TriangleList;
|
|
|
- case Constants.MATERIAL_PointFillMode:
|
|
|
- return WebGPUConstants.PrimitiveTopology.PointList;
|
|
|
- case Constants.MATERIAL_WireFrameFillMode:
|
|
|
- return WebGPUConstants.PrimitiveTopology.LineList;
|
|
|
- // Draw modes
|
|
|
- case Constants.MATERIAL_PointListDrawMode:
|
|
|
- return WebGPUConstants.PrimitiveTopology.PointList;
|
|
|
- case Constants.MATERIAL_LineListDrawMode:
|
|
|
- return WebGPUConstants.PrimitiveTopology.LineList;
|
|
|
- case Constants.MATERIAL_LineLoopDrawMode:
|
|
|
- // return this._gl.LINE_LOOP;
|
|
|
- // TODO WEBGPU. Line Loop Mode Fallback at buffer load time.
|
|
|
- throw "LineLoop is an unsupported fillmode in WebGPU";
|
|
|
- case Constants.MATERIAL_LineStripDrawMode:
|
|
|
- return WebGPUConstants.PrimitiveTopology.LineStrip;
|
|
|
- case Constants.MATERIAL_TriangleStripDrawMode:
|
|
|
- return WebGPUConstants.PrimitiveTopology.TriangleStrip;
|
|
|
- case Constants.MATERIAL_TriangleFanDrawMode:
|
|
|
- // return this._gl.TRIANGLE_FAN;
|
|
|
- // TODO WEBGPU. Triangle Fan Mode Fallback at buffer load time.
|
|
|
- throw "TriangleFan is an unsupported fillmode in WebGPU";
|
|
|
- default:
|
|
|
- return WebGPUConstants.PrimitiveTopology.TriangleList;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private _getOpFunction(operation: Nullable<number>, defaultOp: GPUStencilOperation): GPUStencilOperation {
|
|
|
- switch (operation) {
|
|
|
- case Constants.KEEP:
|
|
|
- return WebGPUConstants.StencilOperation.Keep;
|
|
|
- case Constants.ZERO:
|
|
|
- return WebGPUConstants.StencilOperation.Zero;
|
|
|
- case Constants.REPLACE:
|
|
|
- return WebGPUConstants.StencilOperation.Replace;
|
|
|
- case Constants.INVERT:
|
|
|
- return WebGPUConstants.StencilOperation.Invert;
|
|
|
- case Constants.INCR:
|
|
|
- return WebGPUConstants.StencilOperation.IncrementClamp;
|
|
|
- case Constants.DECR:
|
|
|
- return WebGPUConstants.StencilOperation.DecrementClamp;
|
|
|
- case Constants.INCR_WRAP:
|
|
|
- return WebGPUConstants.StencilOperation.IncrementWrap;
|
|
|
- case Constants.DECR_WRAP:
|
|
|
- return WebGPUConstants.StencilOperation.DecrementWrap;
|
|
|
- default:
|
|
|
- return defaultOp;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private _getDepthStencilStateDescriptor(): GPUDepthStencilStateDescriptor | undefined {
|
|
|
- if (this._depthTextureFormat === undefined) {
|
|
|
- return undefined;
|
|
|
- }
|
|
|
-
|
|
|
- const stencilFrontBack: GPUStencilStateFaceDescriptor = {
|
|
|
- compare: WebGPUTextureHelper.GetCompareFunction(this._stencilState.stencilFunc),
|
|
|
- depthFailOp: this._getOpFunction(this._stencilState.stencilOpDepthFail, WebGPUConstants.StencilOperation.Keep),
|
|
|
- failOp: this._getOpFunction(this._stencilState.stencilOpStencilFail, WebGPUConstants.StencilOperation.Keep),
|
|
|
- passOp: this._getOpFunction(this._stencilState.stencilOpStencilDepthPass, WebGPUConstants.StencilOperation.Replace)
|
|
|
- };
|
|
|
-
|
|
|
- return {
|
|
|
- depthWriteEnabled: this.getDepthWrite(),
|
|
|
- depthCompare: this.getDepthBuffer() ? WebGPUTextureHelper.GetCompareFunction(this.getDepthFunction()) : WebGPUConstants.CompareFunction.Always,
|
|
|
- format: this._depthTextureFormat,
|
|
|
- stencilFront: stencilFrontBack,
|
|
|
- stencilBack: stencilFrontBack,
|
|
|
- stencilReadMask: this._stencilState.stencilFuncMask,
|
|
|
- stencilWriteMask: this._stencilState.stencilMask,
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Set various states to the context
|
|
|
* @param culling defines backface culling state
|
|
@@ -3349,48 +3275,6 @@ export class WebGPUEngineCache extends Engine {
|
|
|
if (this._depthCullingState.frontFace !== frontFace || force) {
|
|
|
this._depthCullingState.frontFace = frontFace;
|
|
|
}
|
|
|
-
|
|
|
- this._cacheRenderPipeline.setState(culling, frontFace, cullFace);
|
|
|
- this._cacheRenderPipeline.setDepthBiasSlopeScale(zOffset);
|
|
|
- }
|
|
|
-
|
|
|
- private _getFrontFace(): GPUFrontFace {
|
|
|
- switch (this._depthCullingState.frontFace) {
|
|
|
- case 1:
|
|
|
- return WebGPUConstants.FrontFace.CCW;
|
|
|
- default:
|
|
|
- return WebGPUConstants.FrontFace.CW;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private _getCullMode(): GPUCullMode {
|
|
|
- if (this._depthCullingState.cull === false) {
|
|
|
- return WebGPUConstants.CullMode.None;
|
|
|
- }
|
|
|
-
|
|
|
- if (this._depthCullingState.cullFace === 2) {
|
|
|
- return WebGPUConstants.CullMode.Front;
|
|
|
- }
|
|
|
- else {
|
|
|
- return WebGPUConstants.CullMode.Back;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private _getRasterizationStateDescriptor(): GPURasterizationStateDescriptor {
|
|
|
- return {
|
|
|
- frontFace: this._getFrontFace(),
|
|
|
- cullMode: this._getCullMode(),
|
|
|
- depthBias: 0,
|
|
|
- depthBiasClamp: 0,
|
|
|
- depthBiasSlopeScale: this._depthCullingState.zOffset,
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- private _getWriteMask(): number {
|
|
|
- if (this.__colorWrite) {
|
|
|
- return WebGPUConstants.ColorWrite.All;
|
|
|
- }
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -3478,356 +3362,6 @@ export class WebGPUEngineCache extends Engine {
|
|
|
this._cacheRenderPipeline.setAlphaBlendFactors(this._alphaState._blendFunctionParameters, this._alphaState._blendEquationParameters);
|
|
|
}
|
|
|
|
|
|
- private _getAphaBlendOperation(operation: Nullable<number>): GPUBlendOperation {
|
|
|
- switch (operation) {
|
|
|
- case 0x8006:
|
|
|
- return WebGPUConstants.BlendOperation.Add;
|
|
|
- case 0x800A:
|
|
|
- return WebGPUConstants.BlendOperation.Subtract;
|
|
|
- case 0x800B:
|
|
|
- return WebGPUConstants.BlendOperation.ReverseSubtract;
|
|
|
- case 0x8007:
|
|
|
- return WebGPUConstants.BlendOperation.Min;
|
|
|
- case 0x8008:
|
|
|
- return WebGPUConstants.BlendOperation.Max;
|
|
|
- default:
|
|
|
- return WebGPUConstants.BlendOperation.Add;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private _getAphaBlendFactor(factor: Nullable<number>): GPUBlendFactor {
|
|
|
- switch (factor) {
|
|
|
- case 0:
|
|
|
- return WebGPUConstants.BlendFactor.Zero;
|
|
|
- case 1:
|
|
|
- return WebGPUConstants.BlendFactor.One;
|
|
|
- case 0x0300:
|
|
|
- return WebGPUConstants.BlendFactor.SrcColor;
|
|
|
- case 0x0301:
|
|
|
- return WebGPUConstants.BlendFactor.OneMinusSrcColor;
|
|
|
- case 0x0302:
|
|
|
- return WebGPUConstants.BlendFactor.SrcAlpha;
|
|
|
- case 0x0303:
|
|
|
- return WebGPUConstants.BlendFactor.OneMinusSrcAlpha;
|
|
|
- case 0x0304:
|
|
|
- return WebGPUConstants.BlendFactor.DstAlpha;
|
|
|
- case 0x0305:
|
|
|
- return WebGPUConstants.BlendFactor.OneMinusDstAlpha;
|
|
|
- case 0x0306:
|
|
|
- return WebGPUConstants.BlendFactor.DstColor;
|
|
|
- case 0x0307:
|
|
|
- return WebGPUConstants.BlendFactor.OneMinusDstColor;
|
|
|
- case 0x0308:
|
|
|
- return WebGPUConstants.BlendFactor.SrcAlphaSaturated;
|
|
|
- case 0x8001:
|
|
|
- return WebGPUConstants.BlendFactor.BlendColor;
|
|
|
- case 0x8002:
|
|
|
- return WebGPUConstants.BlendFactor.OneMinusBlendColor;
|
|
|
- case 0x8003:
|
|
|
- return WebGPUConstants.BlendFactor.BlendColor;
|
|
|
- case 0x8004:
|
|
|
- return WebGPUConstants.BlendFactor.OneMinusBlendColor;
|
|
|
- default:
|
|
|
- return WebGPUConstants.BlendFactor.One;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private _getAphaBlendState(): GPUBlendDescriptor {
|
|
|
- if (!this._alphaState.alphaBlend) {
|
|
|
- return { };
|
|
|
- }
|
|
|
-
|
|
|
- return {
|
|
|
- srcFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[2]),
|
|
|
- dstFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[3]),
|
|
|
- operation: this._getAphaBlendOperation(this._alphaState._blendEquationParameters[1]),
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- private _getColorBlendState(): GPUBlendDescriptor {
|
|
|
- if (!this._alphaState.alphaBlend) {
|
|
|
- return { };
|
|
|
- }
|
|
|
-
|
|
|
- return {
|
|
|
- srcFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[0]),
|
|
|
- dstFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[1]),
|
|
|
- operation: this._getAphaBlendOperation(this._alphaState._blendEquationParameters[0]),
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- private _getColorStateDescriptors(): GPUColorStateDescriptor[] {
|
|
|
- const descriptors: GPUColorStateDescriptor[] = [];
|
|
|
-
|
|
|
- const alphaBlend = this._getAphaBlendState();
|
|
|
- const colorBlend = this._getColorBlendState();
|
|
|
- const writeMask = this._getWriteMask();
|
|
|
-
|
|
|
- if (this._currentRenderPassIsMRT()) {
|
|
|
- const textureArray = this._currentRenderTarget!._textureArray!;
|
|
|
- for (let i = 0; i < this._mrtAttachments.length; ++i) {
|
|
|
- const index = this._mrtAttachments[i];
|
|
|
- if (index > 0) {
|
|
|
- const mrtTexture = textureArray[index - 1];
|
|
|
- const gpuMRTWrapper = mrtTexture?._hardwareTexture as Nullable<WebGPUHardwareTexture>;
|
|
|
- descriptors.push({
|
|
|
- format: gpuMRTWrapper?.format ?? this._colorFormat,
|
|
|
- alphaBlend,
|
|
|
- colorBlend,
|
|
|
- writeMask,
|
|
|
- });
|
|
|
- } else {
|
|
|
- descriptors.push(undefined as any); // TODO WEBGPU what to do when this._mrtAttachments[i] === 0? The corresponding texture should be bound as an "empty" texture
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- descriptors.push({
|
|
|
- format: this._colorFormat,
|
|
|
- alphaBlend,
|
|
|
- colorBlend,
|
|
|
- writeMask,
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- return descriptors;
|
|
|
- }
|
|
|
-
|
|
|
- private _getStages(): IWebGPURenderPipelineStageDescriptor {
|
|
|
- const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
|
|
|
- return webgpuPipelineContext.stages!;
|
|
|
- }
|
|
|
-
|
|
|
- private _getVertexInputDescriptorFormat(vertexBuffer: VertexBuffer): GPUVertexFormat {
|
|
|
- const kind = vertexBuffer.getKind();
|
|
|
- const type = vertexBuffer.type;
|
|
|
- const normalized = vertexBuffer.normalized;
|
|
|
- const size = vertexBuffer.getSize();
|
|
|
-
|
|
|
- switch (type) {
|
|
|
- case VertexBuffer.BYTE:
|
|
|
- switch (size) {
|
|
|
- case 1:
|
|
|
- case 2:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Char2Norm : WebGPUConstants.VertexFormat.Char2;
|
|
|
- case 3:
|
|
|
- case 4:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Char4Norm : WebGPUConstants.VertexFormat.Char4;
|
|
|
- }
|
|
|
- break;
|
|
|
- case VertexBuffer.UNSIGNED_BYTE:
|
|
|
- switch (size) {
|
|
|
- case 1:
|
|
|
- case 2:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Uchar2Norm : WebGPUConstants.VertexFormat.Uchar2;
|
|
|
- case 3:
|
|
|
- case 4:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Uchar4Norm : WebGPUConstants.VertexFormat.Uchar4;
|
|
|
- }
|
|
|
- break;
|
|
|
- case VertexBuffer.SHORT:
|
|
|
- switch (size) {
|
|
|
- case 1:
|
|
|
- case 2:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Short2Norm : WebGPUConstants.VertexFormat.Short2;
|
|
|
- case 3:
|
|
|
- case 4:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Short4Norm : WebGPUConstants.VertexFormat.Short4;
|
|
|
- }
|
|
|
- break;
|
|
|
- case VertexBuffer.UNSIGNED_SHORT:
|
|
|
- switch (size) {
|
|
|
- case 1:
|
|
|
- case 2:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Ushort2Norm : WebGPUConstants.VertexFormat.Ushort2;
|
|
|
- case 3:
|
|
|
- case 4:
|
|
|
- return normalized ? WebGPUConstants.VertexFormat.Ushort4Norm : WebGPUConstants.VertexFormat.Ushort4;
|
|
|
- }
|
|
|
- break;
|
|
|
- case VertexBuffer.INT:
|
|
|
- switch (size) {
|
|
|
- case 1:
|
|
|
- return WebGPUConstants.VertexFormat.Int;
|
|
|
- case 2:
|
|
|
- return WebGPUConstants.VertexFormat.Int2;
|
|
|
- case 3:
|
|
|
- return WebGPUConstants.VertexFormat.Int3;
|
|
|
- case 4:
|
|
|
- return WebGPUConstants.VertexFormat.Int4;
|
|
|
- }
|
|
|
- break;
|
|
|
- case VertexBuffer.UNSIGNED_INT:
|
|
|
- switch (size) {
|
|
|
- case 1:
|
|
|
- return WebGPUConstants.VertexFormat.Uint;
|
|
|
- case 2:
|
|
|
- return WebGPUConstants.VertexFormat.Uint2;
|
|
|
- case 3:
|
|
|
- return WebGPUConstants.VertexFormat.Uint3;
|
|
|
- case 4:
|
|
|
- return WebGPUConstants.VertexFormat.Uint4;
|
|
|
- }
|
|
|
- break;
|
|
|
- case VertexBuffer.FLOAT:
|
|
|
- switch (size) {
|
|
|
- case 1:
|
|
|
- return WebGPUConstants.VertexFormat.Float;
|
|
|
- case 2:
|
|
|
- return WebGPUConstants.VertexFormat.Float2;
|
|
|
- case 3:
|
|
|
- return WebGPUConstants.VertexFormat.Float3;
|
|
|
- case 4:
|
|
|
- return WebGPUConstants.VertexFormat.Float4;
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- throw new Error(`Invalid Format '${kind}' - type=${type}, normalized=${normalized}, size=${size}`);
|
|
|
- }
|
|
|
-
|
|
|
- private _getVertexInputDescriptor(topology: GPUPrimitiveTopology): GPUVertexStateDescriptor {
|
|
|
- const descriptors: GPUVertexBufferLayoutDescriptor[] = [];
|
|
|
- const effect = this._currentEffect!;
|
|
|
- const attributes = effect.getAttributesNames();
|
|
|
- for (var index = 0; index < attributes.length; index++) {
|
|
|
- const location = effect.getAttributeLocation(index);
|
|
|
-
|
|
|
- if (location >= 0) {
|
|
|
- let vertexBuffer = this._currentVertexBuffers![attributes[index]];
|
|
|
- if (!vertexBuffer) {
|
|
|
- // In WebGL it's valid to not bind a vertex buffer to an attribute, but it's not valid in WebGPU
|
|
|
- // So we must bind a dummy buffer when we are not given one for a specific attribute
|
|
|
- vertexBuffer = this._emptyVertexBuffer;
|
|
|
- }
|
|
|
-
|
|
|
- const positionAttributeDescriptor: GPUVertexAttributeDescriptor = {
|
|
|
- shaderLocation: location,
|
|
|
- offset: 0, // not available in WebGL
|
|
|
- format: this._getVertexInputDescriptorFormat(vertexBuffer),
|
|
|
- };
|
|
|
-
|
|
|
- // TODO WEBGPU. Factorize the one with the same underlying buffer.
|
|
|
- const vertexBufferDescriptor: GPUVertexBufferLayoutDescriptor = {
|
|
|
- arrayStride: vertexBuffer.byteStride,
|
|
|
- stepMode: vertexBuffer.getIsInstanced() ? WebGPUConstants.InputStepMode.Instance : WebGPUConstants.InputStepMode.Vertex,
|
|
|
- attributes: [positionAttributeDescriptor]
|
|
|
- };
|
|
|
-
|
|
|
- descriptors.push(vertexBufferDescriptor);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!this._currentIndexBuffer) {
|
|
|
- return {
|
|
|
- indexFormat: !this._indexFormatInRenderPass(topology) ? WebGPUConstants.IndexFormat.Uint32 : undefined,
|
|
|
- vertexBuffers: descriptors
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- const inputStateDescriptor: GPUVertexStateDescriptor = {
|
|
|
- vertexBuffers: descriptors
|
|
|
- };
|
|
|
-
|
|
|
- if (!this._indexFormatInRenderPass(topology)) {
|
|
|
- inputStateDescriptor.indexFormat = this._currentIndexBuffer!.is32Bits ? WebGPUConstants.IndexFormat.Uint32 : WebGPUConstants.IndexFormat.Uint16;
|
|
|
- }
|
|
|
-
|
|
|
- return inputStateDescriptor;
|
|
|
- }
|
|
|
-
|
|
|
- private _getPipelineLayout(): GPUPipelineLayout {
|
|
|
- const bindGroupLayouts: GPUBindGroupLayout[] = [];
|
|
|
- const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
|
|
|
-
|
|
|
- for (let i = 0; i < webgpuPipelineContext.shaderProcessingContext.orderedUBOsAndSamplers.length; i++) {
|
|
|
- const setDefinition = webgpuPipelineContext.shaderProcessingContext.orderedUBOsAndSamplers[i];
|
|
|
- if (setDefinition === undefined) {
|
|
|
- const entries: GPUBindGroupLayoutEntry[] = [];
|
|
|
- const uniformsBindGroupLayout = this._device.createBindGroupLayout({
|
|
|
- entries,
|
|
|
- });
|
|
|
- bindGroupLayouts[i] = uniformsBindGroupLayout;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- const entries: GPUBindGroupLayoutEntry[] = [];
|
|
|
- for (let j = 0; j < setDefinition.length; j++) {
|
|
|
- const bindingDefinition = webgpuPipelineContext.shaderProcessingContext.orderedUBOsAndSamplers[i][j];
|
|
|
- if (bindingDefinition === undefined) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- let visibility = 0;
|
|
|
- if (bindingDefinition.usedInVertex) {
|
|
|
- visibility = visibility | WebGPUConstants.ShaderStage.Vertex;
|
|
|
- }
|
|
|
- if (bindingDefinition.usedInFragment) {
|
|
|
- visibility = visibility | WebGPUConstants.ShaderStage.Fragment;
|
|
|
- }
|
|
|
-
|
|
|
- if (bindingDefinition.isSampler) {
|
|
|
- entries.push({
|
|
|
- binding: j,
|
|
|
- visibility,
|
|
|
- type: bindingDefinition.isComparisonSampler ? WebGPUConstants.BindingType.ComparisonSampler : WebGPUConstants.BindingType.Sampler
|
|
|
- });
|
|
|
- } else if (bindingDefinition.isTexture) {
|
|
|
- entries.push({
|
|
|
- binding: j,
|
|
|
- visibility,
|
|
|
- type: WebGPUConstants.BindingType.SampledTexture,
|
|
|
- viewDimension: bindingDefinition.textureDimension,
|
|
|
- textureComponentType: bindingDefinition.componentType,
|
|
|
- // TODO WEBGPU.
|
|
|
- // hasDynamicOffset?: boolean;
|
|
|
- // storageTextureFormat?: GPUTextureFormat;
|
|
|
- // minBufferBindingSize?: number;
|
|
|
- });
|
|
|
- } else {
|
|
|
- entries.push({
|
|
|
- binding: j,
|
|
|
- visibility,
|
|
|
- type: WebGPUConstants.BindingType.UniformBuffer,
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (entries.length > 0) {
|
|
|
- const uniformsBindGroupLayout = this._device.createBindGroupLayout({
|
|
|
- entries,
|
|
|
- });
|
|
|
- bindGroupLayouts[i] = uniformsBindGroupLayout;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- webgpuPipelineContext.bindGroupLayouts = bindGroupLayouts;
|
|
|
- return this._device.createPipelineLayout({ bindGroupLayouts });
|
|
|
- }
|
|
|
-
|
|
|
- private _getRenderPipeline(topology: GPUPrimitiveTopology, createLayout = true): GPURenderPipeline {
|
|
|
- this._counters.numPipelineDescriptorCreation++;
|
|
|
-
|
|
|
- // Unsupported at the moment but needs to be extracted from the MSAA param.
|
|
|
- const rasterizationStateDescriptor = this._getRasterizationStateDescriptor();
|
|
|
- const depthStateDescriptor = this._getDepthStencilStateDescriptor();
|
|
|
- const colorStateDescriptors = this._getColorStateDescriptors();
|
|
|
- const stages = this._getStages();
|
|
|
- const inputStateDescriptor = this._getVertexInputDescriptor(topology);
|
|
|
- const pipelineLayout = createLayout ? this._getPipelineLayout() : undefined;
|
|
|
-
|
|
|
- return this._device.createRenderPipeline({
|
|
|
- sampleCount: this._currentRenderTarget ? this._currentRenderTarget.samples : this._mainPassSampleCount,
|
|
|
- primitiveTopology: topology,
|
|
|
- rasterizationState: rasterizationStateDescriptor,
|
|
|
- depthStencilState: depthStateDescriptor,
|
|
|
- colorStates: colorStateDescriptors,
|
|
|
-
|
|
|
- ...stages,
|
|
|
- vertexState: inputStateDescriptor,
|
|
|
- layout: pipelineLayout,
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
private _getVertexInputsToRender(): IWebGPUPipelineContextVertexInputsCache {
|
|
|
const effect = this._currentEffect!;
|
|
|
|
|
@@ -4000,9 +3534,26 @@ export class WebGPUEngineCache extends Engine {
|
|
|
private _setRenderPipeline(fillMode: number): void {
|
|
|
const renderPass = this._bundleEncoder || this._getCurrentRenderPass();
|
|
|
|
|
|
- //const topology = this._getTopology(fillMode);
|
|
|
+ this._cacheRenderPipeline.setDepthCullingState(
|
|
|
+ !!this._depthCullingState.cull,
|
|
|
+ this._depthCullingState.frontFace ?? 2,
|
|
|
+ this._depthCullingState.cullFace ?? 1,
|
|
|
+ this._depthCullingState.zOffset,
|
|
|
+ this._depthCullingState.depthTest,
|
|
|
+ this._depthCullingState.depthMask,
|
|
|
+ this._depthCullingState.depthFunc
|
|
|
+ );
|
|
|
+
|
|
|
+ this._cacheRenderPipeline.setStencilState(
|
|
|
+ this._stencilState.stencilTest,
|
|
|
+ this._stencilState.stencilFunc,
|
|
|
+ this._stencilState.stencilOpDepthFail,
|
|
|
+ this._stencilState.stencilOpStencilDepthPass,
|
|
|
+ this._stencilState.stencilOpStencilFail,
|
|
|
+ this._stencilState.stencilFuncMask,
|
|
|
+ this._stencilState.stencilMask
|
|
|
+ );
|
|
|
|
|
|
- //const pipeline = this._getRenderPipeline(topology);
|
|
|
const pipeline = this._cacheRenderPipeline.getRenderPipeline(fillMode, this._currentEffect!, this._currentRenderTarget ? this._currentRenderTarget.samples : this._mainPassSampleCount);
|
|
|
renderPass.setPipeline(pipeline);
|
|
|
|