Skip to content

Commit

Permalink
Nme webgpu2 (#15003)
Browse files Browse the repository at this point in the history
* Very initial webGPU compilation

* several blocks AND beginning of TextureBlock

* textureblock step 2

* textureBlock and ConditionalBlock

* FresnelBLock

* More nodes

* More nodes!

* moar!!

* introducing BabylonSL ;)

* Address comments

* oupsie

* Cloud block

* merge conflict

* WorleyNoise3DBlock

* Moar!

* fix  imports

* Fix build

* LightBlock step 1

* mat4x4f{X}

* LightBlock step 2

* Thanks Alexis!

* shadows part 2

* more shadow work!

* Continue...

* making slow progress

* First working shadow!!

* Shadow PCF works!

* PCSS are in!

* CSM step 0!

* deploy #define

* CSM step 2

* turn off UA diag for csm

* csm + PCSS step 1

* Fix weird array access

* Error if WGSL but not webgpu

* Fog!

* fragdepth and discard

* triplanar + imagesource

* BiPlanarBlock

* matrixbuilder

* fragCoord

* instanceBLock

* clipPlaneBLock

* const input

* fix build

* Address comments

* More fixes!

* .

* Fix ES6

* Fix test

* fix es6

* Fix spotlight
  • Loading branch information
deltakosh committed May 14, 2024
1 parent f2599a5 commit 6185211
Show file tree
Hide file tree
Showing 46 changed files with 1,890 additions and 280 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface IShaderProcessor {
textureProcessor?: (texture: string, isFragment: boolean, preProcessors: { [key: string]: string }, processingContext: Nullable<ShaderProcessingContext>) => string;
endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
lineProcessor?: (line: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
preProcessor?: (code: string, defines: string[], isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
preProcessor?: (code: string, defines: string[], preProcessors: { [key: string]: string }, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
postProcessor?: (
code: string,
defines: string[],
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/core/src/Engines/Processors/shaderProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ function _ProcessShaderConversion(sourceCode: string, options: ProcessingOptions

// General pre processing
if (options.processor.preProcessor) {
preparedSourceCode = options.processor.preProcessor(preparedSourceCode, defines, options.isFragment, options.processingContext);
preparedSourceCode = options.processor.preProcessor(preparedSourceCode, defines, preprocessors, options.isFragment, options.processingContext);
}

preparedSourceCode = _EvaluatePreProcessors(preparedSourceCode, preprocessors, options);
Expand Down Expand Up @@ -367,7 +367,7 @@ function _ApplyPreProcessing(sourceCode: string, options: ProcessingOptions, eng

// General pre processing
if (options.processor?.preProcessor) {
preparedSourceCode = options.processor.preProcessor(preparedSourceCode, defines, options.isFragment, options.processingContext);
preparedSourceCode = options.processor.preProcessor(preparedSourceCode, defines, preprocessors, options.isFragment, options.processingContext);
}

preparedSourceCode = _EvaluatePreProcessors(preparedSourceCode, preprocessors, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { DataBuffer } from "../../Buffers/dataBuffer";
import type { Nullable } from "../../types";
import type { WebGPUHardwareTexture } from "./webgpuHardwareTexture";
import type { WebGPUPipelineContext } from "./webgpuPipelineContext";
import { WebGPUShaderProcessor } from "./webgpuShaderProcessor";
import type { WebGPUShaderProcessor } from "./webgpuShaderProcessor";
import { WebGPUTextureHelper } from "./webgpuTextureHelper";
import { renderableTextureFormatToIndex } from "./webgpuTextureManager";

Expand Down Expand Up @@ -898,7 +898,7 @@ export abstract class WebGPUCacheRenderPipeline {
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;
const samplerInfo = textureInfo.autoBindSampler ? shaderProcessingContext.availableSamplers[name + Constants.AUTOSAMPLERSUFFIX] : null;

let sampleType = textureInfo.sampleType;
let samplerType = samplerInfo?.type ?? WebGPUConstants.SamplerBindingType.Filtering;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type { WebGPUSamplerDescription, WebGPUShaderProcessingContext, WebGPUTex

/** @internal */
export abstract class WebGPUShaderProcessor implements IShaderProcessor {
public static readonly AutoSamplerSuffix = "Sampler";
public static readonly LeftOvertUBOName = "LeftOver";
public static readonly InternalsUBOName = "Internals";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as WebGPUConstants from "./webgpuConstants";
import { Logger } from "../../Misc/logger";
import { WebGPUShaderProcessor } from "./webgpuShaderProcessor";
import { ShaderLanguage } from "../../Materials/shaderLanguage";
import { Constants } from "../constants";

/** @internal */
export class WebGPUShaderProcessorGLSL extends WebGPUShaderProcessor {
Expand Down Expand Up @@ -174,7 +175,7 @@ export class WebGPUShaderProcessorGLSL extends WebGPUShaderProcessor {
const samplerType = WebGPUShaderProcessor._SamplerTypeByWebGLSamplerType[uniformType] ?? "sampler";
const isComparisonSampler = !!WebGPUShaderProcessor._IsComparisonSamplerByWebGPUSamplerType[samplerType];
const samplerBindingType = isComparisonSampler ? WebGPUConstants.SamplerBindingType.Comparison : WebGPUConstants.SamplerBindingType.Filtering;
const samplerName = name + WebGPUShaderProcessor.AutoSamplerSuffix;
const samplerName = name + Constants.AUTOSAMPLERSUFFIX;

let samplerInfo = this._webgpuProcessingContext.availableSamplers[samplerName];
if (!samplerInfo) {
Expand Down
62 changes: 47 additions & 15 deletions packages/dev/core/src/Engines/WebGPU/webgpuShaderProcessorsWGSL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ import "../../ShadersWGSL/ShadersInclude/morphTargetsVertexDeclaration";
import "../../ShadersWGSL/ShadersInclude/morphTargetsVertexGlobal";
import "../../ShadersWGSL/ShadersInclude/morphTargetsVertexGlobalDeclaration";
import "../../ShadersWGSL/ShadersInclude/sceneUboDeclaration";
import "../../ShadersWGSL/ShadersInclude/lightsFragmentFunctions";
import "../../ShadersWGSL/ShadersInclude/lightFragment";
import "../../ShadersWGSL/ShadersInclude/lightUboDeclaration";
import "../../ShadersWGSL/ShadersInclude/lightVxUboDeclaration";
import "../../ShadersWGSL/ShadersInclude/shadowsFragmentFunctions";
import "../../ShadersWGSL/ShadersInclude/shadowsVertex";
import "../../ShadersWGSL/ShadersInclude/fogFragmentDeclaration";
import { ShaderLanguage } from "../../Materials/shaderLanguage";
import { Constants } from "../constants";

const builtInName_frag_depth = "fragmentOutputs.fragDepth";

Expand Down Expand Up @@ -70,6 +78,21 @@ export class WebGPUShaderProcessorWGSL extends WebGPUShaderProcessor {
public textureRegexp = /var\s+(\w+)\s*:\s*((array<\s*)?(texture_\w+)\s*(<\s*(.+)\s*>)?\s*(,\s*\w+\s*>\s*)?);/;
public noPrecision = true;

public preProcessor(code: string, defines: string[], preProcessors: { [key: string]: string }, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) {
// Convert defines into const
for (const key in preProcessors) {
if (key === "__VERSION__") {
continue;
}
const value = preProcessors[key];
if (!isNaN(parseInt(value)) || !isNaN(parseFloat(value))) {
code = `const ${key} = ${value};\n` + code;
}
}

return code;
}

protected _getArraySize(name: string, uniformType: string, preProcessors: { [key: string]: string }): [string, string, number] {
let length = 0;

Expand Down Expand Up @@ -251,16 +274,17 @@ export class WebGPUShaderProcessorWGSL extends WebGPUShaderProcessor {
return texture;
}

public postProcessor(code: string, defines: string[]) {
const defineToValue: { [key: string]: string } = {};
for (const define of defines) {
const parts = define.split(/ +/);
defineToValue[parts[1]] = parts.length > 2 ? parts[2] : "";
}
return code.replace(/\$(\w+)\$/g, (_, p1) => {
return defineToValue[p1] ?? p1;
});
}
// Ignore for now as we inject const for numeric defines
// public postProcessor(code: string, defines: string[]) {
// const defineToValue: { [key: string]: string } = {};
// for (const define of defines) {
// const parts = define.split(/ +/);
// defineToValue[parts[1]] = parts.length > 2 ? parts[2] : "";
// }
// return code.replace(/\$(\w+)\$/g, (_, p1) => {
// return defineToValue[p1] ?? p1;
// });
// }

public finalizeShaders(vertexCode: string, fragmentCode: string): { vertexCode: string; fragmentCode: string } {
const fragCoordCode =
Expand All @@ -287,6 +311,7 @@ export class WebGPUShaderProcessorWGSL extends WebGPUShaderProcessor {
fragmentCode = leftOverUBO + fragmentCode;

// Vertex code
vertexCode = vertexCode.replace(/#define (\w+)\s+(\d+\.?\d*)/g, "const $1 = $2;");
vertexCode = vertexCode.replace(/#define /g, "//#define ");
vertexCode = this._processStridedUniformArrays(vertexCode);

Expand Down Expand Up @@ -316,10 +341,14 @@ export class WebGPUShaderProcessorWGSL extends WebGPUShaderProcessor {
vertexMainStartingCode += "\n";
}
const vertexMainEndingCode = ` vertexOutputs.position.y = vertexOutputs.position.y * internals.yFactor_;\n return vertexOutputs;`;
let needDiagnosticOff = vertexCode.indexOf(Constants.DISABLEUA) !== -1;

vertexCode = this._injectStartingAndEndingCode(vertexCode, "fn main", vertexMainStartingCode, vertexMainEndingCode);
vertexCode =
(needDiagnosticOff ? "diagnostic(off, derivative_uniformity);\n" : "") +
this._injectStartingAndEndingCode(vertexCode, "fn main", vertexMainStartingCode, vertexMainEndingCode);

// fragment code
fragmentCode = fragmentCode.replace(/#define (\w+)\s+(\d+\.?\d*)/g, "const $1 = $2;");
fragmentCode = fragmentCode.replace(/#define /g, "//#define ");
fragmentCode = this._processStridedUniformArrays(fragmentCode);
fragmentCode = fragmentCode.replace(/dpdy/g, "(-internals.yFactor_)*dpdy"); // will also handle dpdyCoarse and dpdyFine
Expand Down Expand Up @@ -361,8 +390,11 @@ export class WebGPUShaderProcessorWGSL extends WebGPUShaderProcessor {

const fragmentStartingCode = " fragmentInputs = input;\n " + fragCoordCode;
const fragmentEndingCode = " return fragmentOutputs;";
needDiagnosticOff = fragmentCode.indexOf(Constants.DISABLEUA) !== -1;

fragmentCode = this._injectStartingAndEndingCode(fragmentCode, "fn main", fragmentStartingCode, fragmentEndingCode);
fragmentCode =
(needDiagnosticOff ? "diagnostic(off, derivative_uniformity);\n" : "") +
this._injectStartingAndEndingCode(fragmentCode, "fn main", fragmentStartingCode, fragmentEndingCode);

this._collectBindingNames();
this._preCreateBindGroupEntries();
Expand Down Expand Up @@ -416,8 +448,8 @@ export class WebGPUShaderProcessorWGSL extends WebGPUShaderProcessor {
const name = match[1]; // name of the variable
const samplerType = match[2]; // sampler or sampler_comparison
const textureName =
name.indexOf(WebGPUShaderProcessor.AutoSamplerSuffix) === name.length - WebGPUShaderProcessor.AutoSamplerSuffix.length
? name.substring(0, name.indexOf(WebGPUShaderProcessor.AutoSamplerSuffix))
name.indexOf(Constants.AUTOSAMPLERSUFFIX) === name.length - Constants.AUTOSAMPLERSUFFIX.length
? name.substring(0, name.indexOf(Constants.AUTOSAMPLERSUFFIX))
: null;
const samplerBindingType = samplerType === "sampler_comparison" ? WebGPUConstants.SamplerBindingType.Comparison : WebGPUConstants.SamplerBindingType.Filtering;

Expand Down Expand Up @@ -516,7 +548,7 @@ export class WebGPUShaderProcessorWGSL extends WebGPUShaderProcessor {

private _processStridedUniformArrays(code: string): string {
for (const uniformArrayName of this._stridedUniformArrays) {
code = code.replace(new RegExp(`${uniformArrayName}\\s*\\[(.*)\\]`, "g"), `${uniformArrayName}[$1].el`);
code = code.replace(new RegExp(`${uniformArrayName}\\s*\\[(.*?)\\]`, "g"), `${uniformArrayName}[$1].el`);
}
return code;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/core/src/Engines/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
/* eslint-disable @typescript-eslint/naming-convention */
/** Defines the cross module used constants to avoid circular dependencies */
export class Constants {
/** Sampler suffix when associated with a texture name */
public static readonly AUTOSAMPLERSUFFIX = "Sampler";
/** Flag used to disable diagnostics for WebGPU */
public static readonly DISABLEUA = "#define DIAGNOSTIC_OFF";
/** Defines that alpha blending is disabled */
public static readonly ALPHA_DISABLE = 0;
/** Defines that alpha blending is SRC ALPHA * SRC + DEST */
Expand Down
17 changes: 5 additions & 12 deletions packages/dev/core/src/Engines/webgpuEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ const viewDescriptorSwapChain: GPUTextureViewDescriptor = {
mipLevelCount: 1,
arrayLayerCount: 1,
};

const disableUniformityAnalysisMarker = "/* disable_uniformity_analysis */";

const tempColor4 = new Color4();

/** @internal */
Expand Down Expand Up @@ -1216,10 +1213,6 @@ export class WebGPUEngine extends AbstractEngine {
* @param name The texture name
*/
public setDepthStencilTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<RenderTargetTexture>, name?: string): void {
if (channel === undefined) {
return;
}

if (!texture || !texture.depthStencilTexture) {
this._setTexture(channel, null, undefined, undefined, name);
} else {
Expand Down Expand Up @@ -2058,8 +2051,8 @@ export class WebGPUEngine extends AbstractEngine {
}

private _compileRawPipelineStageDescriptor(vertexCode: string, fragmentCode: string, shaderLanguage: ShaderLanguage): IWebGPURenderPipelineStageDescriptor {
const disableUniformityAnalysisInVertex = vertexCode.indexOf(disableUniformityAnalysisMarker) >= 0;
const disableUniformityAnalysisInFragment = fragmentCode.indexOf(disableUniformityAnalysisMarker) >= 0;
const disableUniformityAnalysisInVertex = vertexCode.indexOf(Constants.DISABLEUA) >= 0;
const disableUniformityAnalysisInFragment = fragmentCode.indexOf(Constants.DISABLEUA) >= 0;

const vertexShader = shaderLanguage === ShaderLanguage.GLSL ? this._compileRawShaderToSpirV(vertexCode, "vertex") : vertexCode;
const fragmentShader = shaderLanguage === ShaderLanguage.GLSL ? this._compileRawShaderToSpirV(fragmentCode, "fragment") : fragmentCode;
Expand All @@ -2075,8 +2068,8 @@ export class WebGPUEngine extends AbstractEngine {
): IWebGPURenderPipelineStageDescriptor {
this.onBeforeShaderCompilationObservable.notifyObservers(this);

const disableUniformityAnalysisInVertex = vertexCode.indexOf(disableUniformityAnalysisMarker) >= 0;
const disableUniformityAnalysisInFragment = fragmentCode.indexOf(disableUniformityAnalysisMarker) >= 0;
const disableUniformityAnalysisInVertex = vertexCode.indexOf(Constants.DISABLEUA) >= 0;
const disableUniformityAnalysisInFragment = fragmentCode.indexOf(Constants.DISABLEUA) >= 0;

const shaderVersion = "#version 450\n";
const vertexShader =
Expand Down Expand Up @@ -2653,7 +2646,7 @@ export class WebGPUEngine extends AbstractEngine {
this._currentMaterialContext.setTexture(name, texture);

if (availableTexture && availableTexture.autoBindSampler) {
const samplerName = baseName + WebGPUShaderProcessor.AutoSamplerSuffix;
const samplerName = baseName + Constants.AUTOSAMPLERSUFFIX;
this._currentMaterialContext.setSampler(samplerName, texture as InternalTexture); // we can safely cast to InternalTexture because ExternalTexture always has autoBindSampler = false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ export class CascadedShadowGenerator extends ShadowGenerator {

// Only PCF uses depth stencil texture.
if (this._filter === ShadowGenerator.FILTER_PCF) {
effect.setDepthStencilTexture("shadowSampler" + lightIndex, shadowMap);
effect.setDepthStencilTexture("shadowTexture" + lightIndex, shadowMap);
light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), width, 1 / width, this.frustumEdgeFalloff, lightIndex);
} else if (this._filter === ShadowGenerator.FILTER_PCSS) {
for (let cascadeIndex = 0; cascadeIndex < this._numCascades; ++cascadeIndex) {
Expand All @@ -989,14 +989,15 @@ export class CascadedShadowGenerator extends ShadowGenerator {
? 1
: (this._cascadeMaxExtents[cascadeIndex].z - this._cascadeMinExtents[cascadeIndex].z) / (this._cascadeMaxExtents[0].z - this._cascadeMinExtents[0].z);
}
effect.setDepthStencilTexture("shadowSampler" + lightIndex, shadowMap);
effect.setTexture("depthSampler" + lightIndex, shadowMap);
effect.setDepthStencilTexture("shadowTexture" + lightIndex, shadowMap);
effect.setTexture("depthTexture" + lightIndex, shadowMap);

effect.setArray2("lightSizeUVCorrection" + lightIndex, this._lightSizeUVCorrection);
effect.setArray("depthCorrection" + lightIndex, this._depthCorrection);
effect.setFloat("penumbraDarkness" + lightIndex, this.penumbraDarkness);
light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), 1 / width, this._contactHardeningLightSizeUVRatio * width, this.frustumEdgeFalloff, lightIndex);
} else {
effect.setTexture("shadowSampler" + lightIndex, shadowMap);
effect.setTexture("shadowTexture" + lightIndex, shadowMap);
light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), width, 1 / width, this.frustumEdgeFalloff, lightIndex);
}

Expand Down
9 changes: 5 additions & 4 deletions packages/dev/core/src/Lights/Shadows/shadowGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1783,12 +1783,13 @@ export class ShadowGenerator implements IShadowGenerator {
}

// Only PCF uses depth stencil texture.
const shadowMapForRendering = this.getShadowMapForRendering();
if (this._filter === ShadowGenerator.FILTER_PCF) {
effect.setDepthStencilTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
effect.setDepthStencilTexture("shadowTexture" + lightIndex, shadowMapForRendering);
light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), shadowMap.getSize().width, 1 / shadowMap.getSize().width, this.frustumEdgeFalloff, lightIndex);
} else if (this._filter === ShadowGenerator.FILTER_PCSS) {
effect.setDepthStencilTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
effect.setTexture("depthSampler" + lightIndex, this.getShadowMapForRendering());
effect.setDepthStencilTexture("shadowTexture" + lightIndex, shadowMapForRendering);
effect.setTexture("depthTexture" + lightIndex, shadowMapForRendering);
light._uniformBuffer.updateFloat4(
"shadowsInfo",
this.getDarkness(),
Expand All @@ -1798,7 +1799,7 @@ export class ShadowGenerator implements IShadowGenerator {
lightIndex
);
} else {
effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
effect.setTexture("shadowTexture" + lightIndex, shadowMapForRendering);
light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), this.blurScale / shadowMap.getSize().width, this.depthScale, this.frustumEdgeFalloff, lightIndex);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/dev/core/src/Lights/spotLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ export class SpotLight extends ShadowLight {
this._computeProjectionTextureMatrix();
}
effect.setMatrix("textureProjectionMatrix" + lightIndex, this._projectionTextureMatrix);
effect.setTexture("projectionLightSampler" + lightIndex, this.projectionTexture);
effect.setTexture("projectionLightTexture" + lightIndex, this.projectionTexture);
}
return this;
}
Expand Down

0 comments on commit 6185211

Please sign in to comment.