Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to WebGL shader compilation and linking #4964

Merged
merged 3 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/platform/graphics/webgl/webgl-graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -2714,7 +2714,7 @@ class WebglGraphicsDevice extends GraphicsDevice {
if (shader !== this.shader) {
if (shader.failed) {
return false;
} else if (!shader.ready && !shader.impl.postLink(this, shader)) {
} else if (!shader.ready && !shader.impl.finalize(this, shader)) {
shader.failed = true;
return false;
}
Expand Down
61 changes: 37 additions & 24 deletions src/platform/graphics/webgl/webgl-shader.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ class WebglShader {

constructor(shader) {
this.init();
this.compileAndLink(shader.device, shader);

// kick off vertex and fragment shader compilation, but not linking here, as that would
// make it blocking.
this.compile(shader.device, shader);

shader.device.shaders.push(shader);
}

Expand Down Expand Up @@ -87,33 +91,44 @@ class WebglShader {
* @param {import('../shader.js').Shader} shader - The shader to restore.
*/
restoreContext(device, shader) {
this.compileAndLink(device, shader);
this.compile(device, shader);
}

/**
* Compile shader programs.
*
* @param {import('./webgl-graphics-device.js').WebglGraphicsDevice} device - The graphics device.
* @param {import('../shader.js').Shader} shader - The shader to compile.
*/
compile(device, shader) {

const definition = shader.definition;
this.glVertexShader = this._compileShaderSource(device, definition.vshader, true);
this.glFragmentShader = this._compileShaderSource(device, definition.fshader, false);
}

/**
* Compile and link a shader program.
* Link shader programs. This is called at a later stage, to allow many shaders to compile in parallel.
*
* @param {import('./webgl-graphics-device.js').WebglGraphicsDevice} device - The graphics device.
* @param {import('../shader.js').Shader} shader - The shader to compile.
*/
compileAndLink(device, shader) {
link(device, shader) {

let startTime = 0;
Debug.call(() => {
this.compileDuration = 0;
startTime = now();
});

const definition = shader.definition;
const glVertexShader = this._compileShaderSource(device, definition.vshader, true);
const glFragmentShader = this._compileShaderSource(device, definition.fshader, false);

const gl = device.gl;
const glProgram = gl.createProgram();
this.glProgram = glProgram;

gl.attachShader(glProgram, glVertexShader);
gl.attachShader(glProgram, glFragmentShader);
gl.attachShader(glProgram, this.glVertexShader);
gl.attachShader(glProgram, this.glFragmentShader);

const definition = shader.definition;
const attrs = definition.attributes;
if (device.webgl2 && definition.useTransformFeedback) {
// Collect all "out_" attributes and use them for output
Expand Down Expand Up @@ -141,11 +156,6 @@ class WebglShader {

gl.linkProgram(glProgram);

// Cache the WebGL objects on the shader
this.glVertexShader = glVertexShader;
this.glFragmentShader = glFragmentShader;
this.glProgram = glProgram;

Debug.call(() => {
this.compileDuration = now() - startTime;
});
Expand Down Expand Up @@ -216,15 +226,18 @@ class WebglShader {
}

/**
* Extract attribute and uniform information from a successfully linked shader.
* Link the shader, and extract its attributes and uniform information.
*
* @param {import('./webgl-graphics-device.js').WebglGraphicsDevice} device - The graphics device.
* @param {import('../shader.js').Shader} shader - The shader to query.
* @returns {boolean} True if the shader was successfully queried and false otherwise.
*/
postLink(device, shader) {
const gl = device.gl;
finalize(device, shader) {

// finish linking at this point, giving system more time to compile shaders by now
this.link(device, shader);

const gl = device.gl;
const glProgram = this.glProgram;
const definition = shader.definition;

Expand All @@ -241,14 +254,14 @@ class WebglShader {
linkStartTime = now();
});

// Check for compilation errors
if (!this._isCompiled(device, shader, this.glVertexShader, definition.vshader, "vertex"))
return false;
if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {

if (!this._isCompiled(device, shader, this.glFragmentShader, definition.fshader, "fragment"))
return false;
// Check for compilation errors
if (!this._isCompiled(device, shader, this.glVertexShader, definition.vshader, "vertex"))
return false;

if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
if (!this._isCompiled(device, shader, this.glFragmentShader, definition.fshader, "fragment"))
return false;

const message = "Failed to link shader program. Error: " + gl.getProgramInfoLog(glProgram);

Expand Down