|
@@ -13,7 +13,7 @@ import { _TimeToken } from "../Instrumentation/timeToken";
|
|
import { Constants } from "./constants";
|
|
import { Constants } from "./constants";
|
|
import { WebGPUConstants } from "./WebGPU/webgpuConstants";
|
|
import { WebGPUConstants } from "./WebGPU/webgpuConstants";
|
|
import { VertexBuffer } from "../Meshes/buffer";
|
|
import { VertexBuffer } from "../Meshes/buffer";
|
|
-import { WebGPUPipelineContext, IWebGPUPipelineContextVertexInputsCache } from './WebGPU/webgpuPipelineContext';
|
|
|
|
|
|
+import { WebGPUPipelineContext, IWebGPUPipelineContextVertexInputsCache, IWebGPURenderPipelineStageDescriptor } from './WebGPU/webgpuPipelineContext';
|
|
import { IPipelineContext } from './IPipelineContext';
|
|
import { IPipelineContext } from './IPipelineContext';
|
|
import { DataBuffer } from '../Meshes/dataBuffer';
|
|
import { DataBuffer } from '../Meshes/dataBuffer';
|
|
import { WebGPUDataBuffer } from '../Meshes/WebGPU/webgpuDataBuffer';
|
|
import { WebGPUDataBuffer } from '../Meshes/WebGPU/webgpuDataBuffer';
|
|
@@ -153,7 +153,7 @@ export class WebGPUEngine extends Engine {
|
|
|
|
|
|
// Caches
|
|
// Caches
|
|
private _compiledShaders: { [key: string]: {
|
|
private _compiledShaders: { [key: string]: {
|
|
- stages: GPURenderPipelineStageDescriptor,
|
|
|
|
|
|
+ stages: IWebGPURenderPipelineStageDescriptor,
|
|
availableAttributes: { [key: string]: number },
|
|
availableAttributes: { [key: string]: number },
|
|
availableUBOs: { [key: string]: { setIndex: number, bindingIndex: number} },
|
|
availableUBOs: { [key: string]: { setIndex: number, bindingIndex: number} },
|
|
availableSamplers: { [key: string]: { setIndex: number, bindingIndex: number} },
|
|
availableSamplers: { [key: string]: { setIndex: number, bindingIndex: number} },
|
|
@@ -253,11 +253,11 @@ export class WebGPUEngine extends Engine {
|
|
this._glslang = glslang;
|
|
this._glslang = glslang;
|
|
return navigator.gpu!.requestAdapter(this._options);
|
|
return navigator.gpu!.requestAdapter(this._options);
|
|
})
|
|
})
|
|
- .then((adapter: GPUAdapter) => {
|
|
|
|
- this._adapter = adapter;
|
|
|
|
|
|
+ .then((adapter: GPUAdapter | null) => {
|
|
|
|
+ this._adapter = adapter!;
|
|
return this._adapter.requestDevice(this._options.deviceDescriptor);
|
|
return this._adapter.requestDevice(this._options.deviceDescriptor);
|
|
})
|
|
})
|
|
- .then((device: GPUDevice) => this._device = device)
|
|
|
|
|
|
+ .then((device: GPUDevice | null) => this._device = device!)
|
|
.then(() => {
|
|
.then(() => {
|
|
this._initializeLimits();
|
|
this._initializeLimits();
|
|
this._initializeContextAndSwapChain();
|
|
this._initializeContextAndSwapChain();
|
|
@@ -781,7 +781,7 @@ export class WebGPUEngine extends Engine {
|
|
return this._compileRawShaderToSpirV(shaderVersion + (defines ? defines + "\n" : "") + source, type);
|
|
return this._compileRawShaderToSpirV(shaderVersion + (defines ? defines + "\n" : "") + source, type);
|
|
}
|
|
}
|
|
|
|
|
|
- private _createPipelineStageDescriptor(vertexShader: Uint32Array, fragmentShader: Uint32Array): GPURenderPipelineStageDescriptor {
|
|
|
|
|
|
+ private _createPipelineStageDescriptor(vertexShader: Uint32Array, fragmentShader: Uint32Array): IWebGPURenderPipelineStageDescriptor {
|
|
return {
|
|
return {
|
|
vertexStage: {
|
|
vertexStage: {
|
|
module: this._device.createShaderModule({
|
|
module: this._device.createShaderModule({
|
|
@@ -798,14 +798,14 @@ export class WebGPUEngine extends Engine {
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
- private _compileRawPipelineStageDescriptor(vertexCode: string, fragmentCode: string): GPURenderPipelineStageDescriptor {
|
|
|
|
|
|
+ private _compileRawPipelineStageDescriptor(vertexCode: string, fragmentCode: string): IWebGPURenderPipelineStageDescriptor {
|
|
var vertexShader = this._compileRawShaderToSpirV(vertexCode, "vertex");
|
|
var vertexShader = this._compileRawShaderToSpirV(vertexCode, "vertex");
|
|
var fragmentShader = this._compileRawShaderToSpirV(fragmentCode, "fragment");
|
|
var fragmentShader = this._compileRawShaderToSpirV(fragmentCode, "fragment");
|
|
|
|
|
|
return this._createPipelineStageDescriptor(vertexShader, fragmentShader);
|
|
return this._createPipelineStageDescriptor(vertexShader, fragmentShader);
|
|
}
|
|
}
|
|
|
|
|
|
- private _compilePipelineStageDescriptor(vertexCode: string, fragmentCode: string, defines: Nullable<string>): GPURenderPipelineStageDescriptor {
|
|
|
|
|
|
+ private _compilePipelineStageDescriptor(vertexCode: string, fragmentCode: string, defines: Nullable<string>): IWebGPURenderPipelineStageDescriptor {
|
|
this.onBeforeShaderCompilationObservable.notifyObservers(this);
|
|
this.onBeforeShaderCompilationObservable.notifyObservers(this);
|
|
|
|
|
|
var shaderVersion = "#version 450\n";
|
|
var shaderVersion = "#version 450\n";
|
|
@@ -1495,6 +1495,12 @@ export class WebGPUEngine extends Engine {
|
|
// Render
|
|
// Render
|
|
//------------------------------------------------------------------------------
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
+ private _indexFormatInRenderPass(topology: GPUPrimitiveTopology): boolean {
|
|
|
|
+ return topology === WebGPUConstants.GPUPrimitiveTopology_pointList ||
|
|
|
|
+ topology === WebGPUConstants.GPUPrimitiveTopology_lineList ||
|
|
|
|
+ topology === WebGPUConstants.GPUPrimitiveTopology_triangleList;
|
|
|
|
+ }
|
|
|
|
+
|
|
private _getTopology(fillMode: number): GPUPrimitiveTopology {
|
|
private _getTopology(fillMode: number): GPUPrimitiveTopology {
|
|
switch (fillMode) {
|
|
switch (fillMode) {
|
|
// Triangle views
|
|
// Triangle views
|
|
@@ -1819,7 +1825,7 @@ export class WebGPUEngine extends Engine {
|
|
}];
|
|
}];
|
|
}
|
|
}
|
|
|
|
|
|
- private _getStages(): GPURenderPipelineStageDescriptor {
|
|
|
|
|
|
+ private _getStages(): IWebGPURenderPipelineStageDescriptor {
|
|
const gpuPipeline = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
|
|
const gpuPipeline = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
|
|
return gpuPipeline.stages!;
|
|
return gpuPipeline.stages!;
|
|
}
|
|
}
|
|
@@ -1897,7 +1903,7 @@ export class WebGPUEngine extends Engine {
|
|
throw new Error("Invalid Format '" + kind + "'");
|
|
throw new Error("Invalid Format '" + kind + "'");
|
|
}
|
|
}
|
|
|
|
|
|
- private _getVertexInputDescriptor(): GPUVertexStateDescriptor {
|
|
|
|
|
|
+ private _getVertexInputDescriptor(topology: GPUPrimitiveTopology): GPUVertexStateDescriptor {
|
|
const descriptors: GPUVertexBufferLayoutDescriptor[] = [];
|
|
const descriptors: GPUVertexBufferLayoutDescriptor[] = [];
|
|
const effect = this._currentEffect!;
|
|
const effect = this._currentEffect!;
|
|
const attributes = effect.getAttributesNames();
|
|
const attributes = effect.getAttributesNames();
|
|
@@ -1935,9 +1941,13 @@ export class WebGPUEngine extends Engine {
|
|
}
|
|
}
|
|
|
|
|
|
const inputStateDescriptor: GPUVertexStateDescriptor = {
|
|
const inputStateDescriptor: GPUVertexStateDescriptor = {
|
|
- indexFormat: this._currentIndexBuffer!.is32Bits ? WebGPUConstants.GPUIndexFormat_uint32 : WebGPUConstants.GPUIndexFormat_uint16,
|
|
|
|
vertexBuffers: descriptors
|
|
vertexBuffers: descriptors
|
|
};
|
|
};
|
|
|
|
+
|
|
|
|
+ if (!this._indexFormatInRenderPass(topology)) {
|
|
|
|
+ inputStateDescriptor.indexFormat = this._currentIndexBuffer!.is32Bits ? WebGPUConstants.GPUIndexFormat_uint32 : WebGPUConstants.GPUIndexFormat_uint16;
|
|
|
|
+ }
|
|
|
|
+
|
|
return inputStateDescriptor;
|
|
return inputStateDescriptor;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2003,7 +2013,7 @@ export class WebGPUEngine extends Engine {
|
|
return this._device.createPipelineLayout({ bindGroupLayouts });
|
|
return this._device.createPipelineLayout({ bindGroupLayouts });
|
|
}
|
|
}
|
|
|
|
|
|
- private _getRenderPipeline(fillMode: number): GPURenderPipeline {
|
|
|
|
|
|
+ private _getRenderPipeline(topology: GPUPrimitiveTopology): GPURenderPipeline {
|
|
// This is wrong to cache this way but workarounds the need of cache in the simple demo context.
|
|
// This is wrong to cache this way but workarounds the need of cache in the simple demo context.
|
|
const gpuPipeline = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
|
|
const gpuPipeline = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
|
|
if (gpuPipeline.renderPipeline) {
|
|
if (gpuPipeline.renderPipeline) {
|
|
@@ -2011,12 +2021,11 @@ export class WebGPUEngine extends Engine {
|
|
}
|
|
}
|
|
|
|
|
|
// Unsupported at the moment but needs to be extracted from the MSAA param.
|
|
// Unsupported at the moment but needs to be extracted from the MSAA param.
|
|
- const topology = this._getTopology(fillMode);
|
|
|
|
const rasterizationStateDescriptor = this._getRasterizationStateDescriptor();
|
|
const rasterizationStateDescriptor = this._getRasterizationStateDescriptor();
|
|
const depthStateDescriptor = this._getDepthStencilStateDescriptor();
|
|
const depthStateDescriptor = this._getDepthStencilStateDescriptor();
|
|
const colorStateDescriptors = this._getColorStateDescriptors();
|
|
const colorStateDescriptors = this._getColorStateDescriptors();
|
|
const stages = this._getStages();
|
|
const stages = this._getStages();
|
|
- const inputStateDescriptor = this._getVertexInputDescriptor();
|
|
|
|
|
|
+ const inputStateDescriptor = this._getVertexInputDescriptor(topology);
|
|
const pipelineLayout = this._getPipelineLayout();
|
|
const pipelineLayout = this._getPipelineLayout();
|
|
|
|
|
|
gpuPipeline.renderPipeline = this._device.createRenderPipeline({
|
|
gpuPipeline.renderPipeline = this._device.createRenderPipeline({
|
|
@@ -2186,12 +2195,16 @@ export class WebGPUEngine extends Engine {
|
|
return bindGroups;
|
|
return bindGroups;
|
|
}
|
|
}
|
|
|
|
|
|
- private _bindVertexInputs(vertexInputs: IWebGPUPipelineContextVertexInputsCache): void {
|
|
|
|
|
|
+ private _bindVertexInputs(vertexInputs: IWebGPUPipelineContextVertexInputsCache, setIndexFormat: boolean): void {
|
|
const renderPass = this._bundleEncoder || this._currentRenderPass!;
|
|
const renderPass = this._bundleEncoder || this._currentRenderPass!;
|
|
|
|
|
|
if (vertexInputs.indexBuffer) {
|
|
if (vertexInputs.indexBuffer) {
|
|
// TODO WEBGPU. Check if cache would be worth it.
|
|
// TODO WEBGPU. Check if cache would be worth it.
|
|
- renderPass.setIndexBuffer(vertexInputs.indexBuffer, vertexInputs.indexOffset);
|
|
|
|
|
|
+ if (setIndexFormat) {
|
|
|
|
+ renderPass.setIndexBuffer(vertexInputs.indexBuffer, this._currentIndexBuffer!.is32Bits ? WebGPUConstants.GPUIndexFormat_uint32 : WebGPUConstants.GPUIndexFormat_uint16, vertexInputs.indexOffset);
|
|
|
|
+ } else {
|
|
|
|
+ renderPass.setIndexBuffer(vertexInputs.indexBuffer, vertexInputs.indexOffset);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// TODO WEBGPU. Optimize buffer reusability and types as more are now allowed.
|
|
// TODO WEBGPU. Optimize buffer reusability and types as more are now allowed.
|
|
@@ -2214,11 +2227,14 @@ export class WebGPUEngine extends Engine {
|
|
private _setRenderPipeline(fillMode: number): void {
|
|
private _setRenderPipeline(fillMode: number): void {
|
|
const renderPass = this._bundleEncoder || this._currentRenderPass!;
|
|
const renderPass = this._bundleEncoder || this._currentRenderPass!;
|
|
|
|
|
|
- const pipeline = this._getRenderPipeline(fillMode);
|
|
|
|
|
|
+ const topology = this._getTopology(fillMode);
|
|
|
|
+ const setIndexFormatInRenderPass = this._indexFormatInRenderPass(topology);
|
|
|
|
+
|
|
|
|
+ const pipeline = this._getRenderPipeline(topology);
|
|
renderPass.setPipeline(pipeline);
|
|
renderPass.setPipeline(pipeline);
|
|
|
|
|
|
const vertexInputs = this._getVertexInputsToRender();
|
|
const vertexInputs = this._getVertexInputsToRender();
|
|
- this._bindVertexInputs(vertexInputs);
|
|
|
|
|
|
+ this._bindVertexInputs(vertexInputs, setIndexFormatInRenderPass);
|
|
|
|
|
|
const bindGroups = this._getBindGroupsToRender();
|
|
const bindGroups = this._getBindGroupsToRender();
|
|
this._setRenderBindGroups(bindGroups);
|
|
this._setRenderBindGroups(bindGroups);
|