WebGL
Khronos
 

WebGL KHR_parallel_shader_compile Extension Specification

Name

KHR_parallel_shader_compile

Contact

WebGL working group (public_webgl 'at' khronos.org)

Contributors

Jie Chen, (jie.a.chen 'at' intel.com)

Geoff Lang, (geofflang 'at' google.com)

Members of the WebGL working group

Version

Last modified date: November 24, 2020
Revision: 6

Number

WebGL extension #37

Dependencies

Written against the WebGL API 1.0 specification.

Overview

This extension exposes the KHR_parallel_shader_compile functionality to WebGL.

The following WebGL-specific behavioral changes apply:

Consult the above extension for documentation, issues and new functions and enumerants.

When this extension is enabled:

Notes:

IDL

    [Exposed=(Window,Worker), LegacyNoInterfaceObject]
    interface KHR_parallel_shader_compile {
      const GLenum COMPLETION_STATUS_KHR                = 0x91B1;
    };
  

Sample Code

    var canvas = document.createElement("canvas");
    var gl = canvas.getContext("webgl");
    var ext = gl.getExtension('KHR_parallel_shader_compile');

    var vSource = "attribute vec2 position; void main() { gl_Position = vec4(position, 0, 1); }";
    var fSource = "precision mediump float; void main() { gl_FragColor = vec4(1,0,0,1); }";

    var vShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vShader, vSource);
    gl.compileShader(vShader);

    var fShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fShader, fSource);
    gl.compileShader(fShader);

    var program = gl.createProgram();
    gl.attachShader(program, vShader);
    gl.attachShader(program, fShader);
    gl.linkProgram(program);

    function checkToUseProgram() {
      if (gl.getProgramParameter(program, gl.LINK_STATUS) == true) {
        gl.useProgram(program);
      } else {
        // error check.
      }
    }

    if (ext) {
      function checkCompletion() {
        if (gl.getProgramParameter(program, ext.COMPLETION_STATUS_KHR) == true) {
          checkToUseProgram();
        } else {
          requestAnimationFrame(checkCompletion);
        }
      }
      requestAnimationFrame(checkCompletion);
    } else {
      checkToUseProgram();
    }
    
In general, best practice with or without the extension is:
// Assuming lists of `shaders` and `programs`:
    for (const x of shaders)
      gl.compileShader(x); // Never check compile status unless subsequent linking fails.
    for (const x of programs)
      gl.linkProgram(x);
With the extension, apps would be able to poll whether programs have linked without janking, but these are likely to take the same total wall time to link:
// Generator yielding a progress ratio [0.0, 1.0].
    // Without the extension, this will jank and only check one program per generation.
    function* linkingProgress(programs) {
      const ext = gl.getExtension('KHR_parallel_shader_compile');
      let todo = programs.slice();
      while (todo.length) {
        if (ext) {
          todo = todo.filter(x => !gl.getProgramParameter(x, ext.COMPLETION_STATUS_KHR));
        } else {
          const x = todo.pop();
          gl.getProgramParameter(x, gl.LINK_STATUS);
        }
        if (!todo.length)
          return;
        yield 1.0 - (todo.length / programs.length);
      }
    }

Revision History

Revision 1, 2018/08/07

Revision 2, 2018/09/14

Revision 3, 2019/01/30

Revision 4, 2019/04/23

Revision 5, 2019/05/10

Revision 6, 2020/11/24