|
@@ -9,17 +9,17 @@ import { WebGPUHardwareTexture } from "./webgpuHardwareTexture";
|
|
import { WebGPUPipelineContext } from "./webgpuPipelineContext";
|
|
import { WebGPUPipelineContext } from "./webgpuPipelineContext";
|
|
|
|
|
|
enum StatePosition {
|
|
enum StatePosition {
|
|
- ShaderStage = 0,
|
|
|
|
- RasterizationState = 1,
|
|
|
|
- //DepthBias = 2, // not used, so remove it to improve perf
|
|
|
|
- //DepthBiasClamp = 3, // not used, so remove it to improve perf
|
|
|
|
|
|
+ //DepthBias = 0, // not used, so remove it to improve perf
|
|
|
|
+ //DepthBiasClamp = 1, // not used, so remove it to improve perf
|
|
|
|
+ StencilReadMask = 0,
|
|
|
|
+ StencilWriteMask = 1,
|
|
DepthBiasSlopeScale = 2,
|
|
DepthBiasSlopeScale = 2,
|
|
MRTAttachments1 = 3,
|
|
MRTAttachments1 = 3,
|
|
MRTAttachments2 = 4,
|
|
MRTAttachments2 = 4,
|
|
- ColorStates = 5,
|
|
|
|
- DepthStencilState = 6,
|
|
|
|
- StencilReadMask = 7,
|
|
|
|
- StencilWriteMask = 8,
|
|
|
|
|
|
+ DepthStencilState = 5,
|
|
|
|
+ RasterizationState = 6,
|
|
|
|
+ ColorStates = 7,
|
|
|
|
+ ShaderStage = 8,
|
|
VertexState = 9, // vertex state will consume positions 9, 10, ... depending on the number of vertex inputs
|
|
VertexState = 9, // vertex state will consume positions 9, 10, ... depending on the number of vertex inputs
|
|
|
|
|
|
NumStates = 10
|
|
NumStates = 10
|
|
@@ -116,7 +116,7 @@ const stencilOpToIndex: { [name: number]: number } = {
|
|
};
|
|
};
|
|
|
|
|
|
/** @hidden */
|
|
/** @hidden */
|
|
-export class WebGPUCacheRenderPipeline {
|
|
|
|
|
|
+export abstract class WebGPUCacheRenderPipeline {
|
|
|
|
|
|
public static NumCacheHitWithoutHash = 0;
|
|
public static NumCacheHitWithoutHash = 0;
|
|
public static NumCacheHitWithHash = 0;
|
|
public static NumCacheHitWithHash = 0;
|
|
@@ -125,14 +125,14 @@ export class WebGPUCacheRenderPipeline {
|
|
|
|
|
|
public disabled: boolean;
|
|
public disabled: boolean;
|
|
|
|
|
|
- private static _Cache: { [hash: string]: GPURenderPipeline } = {};
|
|
|
|
private static _NumPipelineCreationCurrentFrame = 0;
|
|
private static _NumPipelineCreationCurrentFrame = 0;
|
|
|
|
|
|
|
|
+ protected _states: number[];
|
|
|
|
+
|
|
private _device: GPUDevice;
|
|
private _device: GPUDevice;
|
|
- private _states: string[];
|
|
|
|
private _isDirty: boolean;
|
|
private _isDirty: boolean;
|
|
- private _currentRenderPipeline: GPURenderPipeline;
|
|
|
|
private _emptyVertexBuffer: VertexBuffer;
|
|
private _emptyVertexBuffer: VertexBuffer;
|
|
|
|
+ private _parameter: { token: any, pipeline: Nullable<GPURenderPipeline> };
|
|
|
|
|
|
private _shaderId: number;
|
|
private _shaderId: number;
|
|
private _alphaToCoverageEnabled: boolean;
|
|
private _alphaToCoverageEnabled: boolean;
|
|
@@ -176,6 +176,7 @@ export class WebGPUCacheRenderPipeline {
|
|
this._states.length = StatePosition.NumStates;
|
|
this._states.length = StatePosition.NumStates;
|
|
this._emptyVertexBuffer = emptyVertexBuffer;
|
|
this._emptyVertexBuffer = emptyVertexBuffer;
|
|
this._mrtFormats = [];
|
|
this._mrtFormats = [];
|
|
|
|
+ this._parameter = { token: undefined, pipeline: null };
|
|
this.disabled = false;
|
|
this.disabled = false;
|
|
this.reset();
|
|
this.reset();
|
|
}
|
|
}
|
|
@@ -198,16 +199,19 @@ export class WebGPUCacheRenderPipeline {
|
|
this.setBuffers(null, null);
|
|
this.setBuffers(null, null);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ protected abstract _getRenderPipeline(param: { token: any, pipeline: Nullable<GPURenderPipeline> }): void;
|
|
|
|
+ protected abstract _setRenderPipeline(param: { token: any, pipeline: Nullable<GPURenderPipeline> }): void;
|
|
|
|
+
|
|
public getRenderPipeline(fillMode: number, effect: Effect, sampleCount: number): GPURenderPipeline {
|
|
public getRenderPipeline(fillMode: number, effect: Effect, sampleCount: number): GPURenderPipeline {
|
|
if (this.disabled) {
|
|
if (this.disabled) {
|
|
const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
|
|
const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
|
|
|
|
|
|
- this._currentRenderPipeline = this._createRenderPipeline(effect, topology, sampleCount);
|
|
|
|
|
|
+ this._parameter.pipeline = this._createRenderPipeline(effect, topology, sampleCount);
|
|
|
|
|
|
WebGPUCacheRenderPipeline.NumCacheMiss++;
|
|
WebGPUCacheRenderPipeline.NumCacheMiss++;
|
|
WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
|
|
WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
|
|
|
|
|
|
- return this._currentRenderPipeline;
|
|
|
|
|
|
+ return this._parameter.pipeline;
|
|
}
|
|
}
|
|
|
|
|
|
this._setShaderStage(effect.uniqueId);
|
|
this._setShaderStage(effect.uniqueId);
|
|
@@ -216,31 +220,29 @@ export class WebGPUCacheRenderPipeline {
|
|
this._setDepthStencilState();
|
|
this._setDepthStencilState();
|
|
this._setVertexState(effect);
|
|
this._setVertexState(effect);
|
|
|
|
|
|
- if (!this._isDirty && this._currentRenderPipeline) {
|
|
|
|
|
|
+ if (!this._isDirty && this._parameter.pipeline) {
|
|
WebGPUCacheRenderPipeline.NumCacheHitWithoutHash++;
|
|
WebGPUCacheRenderPipeline.NumCacheHitWithoutHash++;
|
|
- return this._currentRenderPipeline;
|
|
|
|
|
|
+ return this._parameter.pipeline;
|
|
}
|
|
}
|
|
|
|
|
|
this._isDirty = false;
|
|
this._isDirty = false;
|
|
|
|
|
|
- let hash = this._states.join();
|
|
|
|
- let pipeline = WebGPUCacheRenderPipeline._Cache[hash];
|
|
|
|
|
|
+ this._getRenderPipeline(this._parameter);
|
|
|
|
|
|
- if (pipeline) {
|
|
|
|
- this._currentRenderPipeline = pipeline;
|
|
|
|
|
|
+ if (this._parameter.pipeline) {
|
|
WebGPUCacheRenderPipeline.NumCacheHitWithHash++;
|
|
WebGPUCacheRenderPipeline.NumCacheHitWithHash++;
|
|
- return pipeline;
|
|
|
|
|
|
+ return this._parameter.pipeline;
|
|
}
|
|
}
|
|
|
|
|
|
const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
|
|
const topology = WebGPUCacheRenderPipeline._GetTopology(fillMode);
|
|
|
|
|
|
- this._currentRenderPipeline = this._createRenderPipeline(effect, topology, sampleCount);
|
|
|
|
- WebGPUCacheRenderPipeline._Cache[hash] = this._currentRenderPipeline;
|
|
|
|
|
|
+ this._parameter.pipeline = this._createRenderPipeline(effect, topology, sampleCount);
|
|
|
|
+ this._setRenderPipeline(this._parameter);
|
|
|
|
|
|
WebGPUCacheRenderPipeline.NumCacheMiss++;
|
|
WebGPUCacheRenderPipeline.NumCacheMiss++;
|
|
WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
|
|
WebGPUCacheRenderPipeline._NumPipelineCreationCurrentFrame++;
|
|
|
|
|
|
- return this._currentRenderPipeline;
|
|
|
|
|
|
+ return this._parameter.pipeline;
|
|
}
|
|
}
|
|
|
|
|
|
public endFrame(): void {
|
|
public endFrame(): void {
|
|
@@ -301,7 +303,7 @@ export class WebGPUCacheRenderPipeline {
|
|
public setDepthBiasSlopeScale(depthBiasSlopeScale: number): void {
|
|
public setDepthBiasSlopeScale(depthBiasSlopeScale: number): void {
|
|
if (this._depthBiasSlopeScale !== depthBiasSlopeScale) {
|
|
if (this._depthBiasSlopeScale !== depthBiasSlopeScale) {
|
|
this._depthBiasSlopeScale = depthBiasSlopeScale;
|
|
this._depthBiasSlopeScale = depthBiasSlopeScale;
|
|
- this._states[StatePosition.DepthBiasSlopeScale] = depthBiasSlopeScale.toString();
|
|
|
|
|
|
+ this._states[StatePosition.DepthBiasSlopeScale] = depthBiasSlopeScale;
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -339,8 +341,8 @@ export class WebGPUCacheRenderPipeline {
|
|
if (this._mrtAttachments1 !== bits[0] || this._mrtAttachments2 !== bits[1]) {
|
|
if (this._mrtAttachments1 !== bits[0] || this._mrtAttachments2 !== bits[1]) {
|
|
this._mrtAttachments1 = bits[0];
|
|
this._mrtAttachments1 = bits[0];
|
|
this._mrtAttachments2 = bits[1];
|
|
this._mrtAttachments2 = bits[1];
|
|
- this._states[StatePosition.MRTAttachments1] = bits[0].toString();
|
|
|
|
- this._states[StatePosition.MRTAttachments2] = bits[1].toString();
|
|
|
|
|
|
+ this._states[StatePosition.MRTAttachments1] = bits[0];
|
|
|
|
+ this._states[StatePosition.MRTAttachments2] = bits[1];
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -398,7 +400,7 @@ export class WebGPUCacheRenderPipeline {
|
|
public setStencilReadMask(mask: number): void {
|
|
public setStencilReadMask(mask: number): void {
|
|
if (this._stencilReadMask !== mask) {
|
|
if (this._stencilReadMask !== mask) {
|
|
this._stencilReadMask = mask;
|
|
this._stencilReadMask = mask;
|
|
- this._states[StatePosition.StencilReadMask] = mask.toString();
|
|
|
|
|
|
+ this._states[StatePosition.StencilReadMask] = mask;
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -406,7 +408,7 @@ export class WebGPUCacheRenderPipeline {
|
|
public setStencilWriteMask(mask: number): void {
|
|
public setStencilWriteMask(mask: number): void {
|
|
if (this._stencilWriteMask !== mask) {
|
|
if (this._stencilWriteMask !== mask) {
|
|
this._stencilWriteMask = mask;
|
|
this._stencilWriteMask = mask;
|
|
- this._states[StatePosition.StencilWriteMask] = mask.toString();
|
|
|
|
|
|
+ this._states[StatePosition.StencilWriteMask] = mask;
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -673,7 +675,7 @@ export class WebGPUCacheRenderPipeline {
|
|
private _setShaderStage(id: number): void {
|
|
private _setShaderStage(id: number): void {
|
|
if (this._shaderId !== id) {
|
|
if (this._shaderId !== id) {
|
|
this._shaderId = id;
|
|
this._shaderId = id;
|
|
- this._states[StatePosition.ShaderStage] = id.toString();
|
|
|
|
|
|
+ this._states[StatePosition.ShaderStage] = id;
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -693,13 +695,15 @@ export class WebGPUCacheRenderPipeline {
|
|
|
|
|
|
if (this._rasterizationState !== rasterizationState) {
|
|
if (this._rasterizationState !== rasterizationState) {
|
|
this._rasterizationState = rasterizationState;
|
|
this._rasterizationState = rasterizationState;
|
|
- this._states[StatePosition.RasterizationState] = this._rasterizationState.toString();
|
|
|
|
|
|
+ this._states[StatePosition.RasterizationState] = this._rasterizationState;
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private _setColorStates(): void {
|
|
private _setColorStates(): void {
|
|
- let colorStates = ((this._writeMask ? 1 : 0) << 22) + (this._colorFormat << 23);
|
|
|
|
|
|
+ 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) {
|
|
if (this._alphaBlendEnabled) {
|
|
colorStates +=
|
|
colorStates +=
|
|
@@ -713,7 +717,7 @@ export class WebGPUCacheRenderPipeline {
|
|
|
|
|
|
if (colorStates !== this._colorStates) {
|
|
if (colorStates !== this._colorStates) {
|
|
this._colorStates = colorStates;
|
|
this._colorStates = colorStates;
|
|
- this._states[StatePosition.ColorStates] = this._colorStates.toString();
|
|
|
|
|
|
+ this._states[StatePosition.ColorStates] = this._colorStates;
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -725,13 +729,12 @@ export class WebGPUCacheRenderPipeline {
|
|
|
|
|
|
const depthStencilState =
|
|
const depthStencilState =
|
|
this._depthStencilFormat +
|
|
this._depthStencilFormat +
|
|
- ((this._depthWriteEnabled ? 1 : 0) << 6) +
|
|
|
|
- ((this._depthTestEnabled ? this._depthCompare : 7 /* ALWAYS */) << 7) +
|
|
|
|
|
|
+ ((this._depthTestEnabled ? this._depthCompare : 7 /* ALWAYS */) << 6) +
|
|
(stencilState << 10); // stencil front - stencil back is the same
|
|
(stencilState << 10); // stencil front - stencil back is the same
|
|
|
|
|
|
if (this._depthStencilState !== depthStencilState) {
|
|
if (this._depthStencilState !== depthStencilState) {
|
|
this._depthStencilState = depthStencilState;
|
|
this._depthStencilState = depthStencilState;
|
|
- this._states[StatePosition.DepthStencilState] = this._depthStencilState.toString();
|
|
|
|
|
|
+ this._states[StatePosition.DepthStencilState] = this._depthStencilState;
|
|
this._isDirty = true;
|
|
this._isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -752,19 +755,7 @@ export class WebGPUCacheRenderPipeline {
|
|
vertexBuffer = this._emptyVertexBuffer;
|
|
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)).toString();
|
|
|
|
|
|
+ const vid = vertexBuffer.hashCode + (location << 7);
|
|
|
|
|
|
this._isDirty = this._isDirty || this._states[newNumStates] !== vid;
|
|
this._isDirty = this._isDirty || this._states[newNumStates] !== vid;
|
|
this._states[newNumStates++] = vid;
|
|
this._states[newNumStates++] = vid;
|