Skip to content
1 change: 1 addition & 0 deletions packages/dev/core/src/Engines/Native/nativeInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface INativeEngine {
updateDynamicVertexBuffer(vertexBuffer: NativeData, bytes: ArrayBuffer, byteOffset: number, byteLength: number): void;

createProgram(vertexShader: string, fragmentShader: string): NativeProgram;
createProgramAsync(vertexShader: string, fragmentShader: string, onSuccess: () => void, onError: (error: Error) => void): NativeProgram;
getUniforms(shaderProgram: NativeProgram, uniformsNames: string[]): WebGLUniformLocation[];
getAttributes(shaderProgram: NativeProgram, attributeNames: string[]): number[];

Expand Down
20 changes: 17 additions & 3 deletions packages/dev/core/src/Engines/Native/nativePipelineContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,23 @@ import type { IPipelineContext } from "../IPipelineContext";
import type { NativeEngine } from "../nativeEngine";

export class NativePipelineContext implements IPipelineContext {
// TODO: async should be true?
public isAsync = false;
public isReady = false;
public isParallelCompiled: boolean = true;
public isCompiled: boolean = false;
public compilationError?: Error;

public get isAsync(): boolean {
return this.isParallelCompiled;
}

public get isReady(): boolean {
if (this.compilationError) {
const message = this.compilationError.message;
throw new Error("SHADER ERROR" + (typeof message === "string" ? "\n" + message : ""));
}
return this.isCompiled;
}

public onCompiled?: () => void;

public _getVertexShaderCode(): string | null {
return null;
Expand Down
58 changes: 46 additions & 12 deletions packages/dev/core/src/Engines/nativeEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,27 +646,44 @@ export class NativeEngine extends Engine {
}
}

/**
* @internal
*/
public _isRenderingStateCompiled(pipelineContext: IPipelineContext): boolean {
// TODO: support async shader compilcation
return true;
public isAsync(pipelineContext: IPipelineContext): boolean {
return !!(pipelineContext.isAsync && this._engine.createProgramAsync);
}

/**
* @internal
*/
public _executeWhenRenderingStateIsCompiled(pipelineContext: IPipelineContext, action: () => void) {
// TODO: support async shader compilcation
action();
const nativePipelineContext = pipelineContext as NativePipelineContext;

if (!this.isAsync(pipelineContext)) {
action();
return;
}

const oldHandler = nativePipelineContext.onCompiled;

if (oldHandler) {
nativePipelineContext.onCompiled = () => {
oldHandler!();
action();
};
} else {
nativePipelineContext.onCompiled = action;
}
}

public createRawShaderProgram(): WebGLProgram {
throw new Error("Not Supported");
}

public createShaderProgram(_pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>): WebGLProgram {
public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>): WebGLProgram {
const nativePipelineContext = pipelineContext as NativePipelineContext;

if (nativePipelineContext.nativeProgram) {
throw new Error("Tried to create a second program in the same NativePipelineContext");
}

this.onBeforeShaderCompilationObservable.notifyObservers(this);

const vertexInliner = new ShaderCodeInliner(vertexCode);
Expand All @@ -680,9 +697,26 @@ export class NativeEngine extends Engine {
vertexCode = ThinEngine._ConcatenateShader(vertexCode, defines);
fragmentCode = ThinEngine._ConcatenateShader(fragmentCode, defines);

const program = this._engine.createProgram(vertexCode, fragmentCode);
this.onAfterShaderCompilationObservable.notifyObservers(this);
return program as WebGLProgram;
const onSuccess = () => {
nativePipelineContext.isCompiled = true;
nativePipelineContext.onCompiled?.();
this.onAfterShaderCompilationObservable.notifyObservers(this);
};

if (this.isAsync(pipelineContext)) {
return this._engine.createProgramAsync(vertexCode, fragmentCode, onSuccess, (error: Error) => {
nativePipelineContext.compilationError = error;
}) as WebGLProgram;
} else {
try {
const program = (nativePipelineContext.nativeProgram = this._engine.createProgram(vertexCode, fragmentCode));
onSuccess();
return program as WebGLProgram;
} catch (e: any) {
const message = e?.message;
throw new Error("SHADER ERROR" + (typeof message === "string" ? "\n" + message : ""));
}
}
}

/**
Expand Down