tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

khr-parallel-shader-compile.html (9219B)


      1 <!--
      2 Copyright (c) 2020 The Khronos Group Inc.
      3 Use of this source code is governed by an MIT-style license that can be
      4 found in the LICENSE.txt file.
      5 -->
      6 
      7 <!DOCTYPE html>
      8 <html>
      9 <head>
     10 <meta charset="utf-8">
     11 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     12 <script src="../../js/js-test-pre.js"></script>
     13 <script src="../../js/webgl-test-utils.js"></script>
     14 <style>
     15 .spinner {
     16    width: 100px;
     17    height: 100px;
     18    border: 20px solid transparent;
     19    border-top: 20px solid black;
     20    border-radius: 100%;
     21    text-align: center;
     22    padding: 10px;
     23 }
     24 @keyframes rotation {
     25    from { transorm: rotate(0); }
     26    to { transform: rotate(360deg); }
     27 }
     28 </style>
     29 </head>
     30 <body>
     31 <div id="description"></div>
     32 <button onclick='compileShaders()'>The spinners below should not stutter when you click this button.</button>
     33 <div class="spinner" style="animation: rotation 2s infinite linear;">CSS</div>
     34 <div class="spinner" id=spinner>JS</div>
     35 <div id="console"></div>
     36 <canvas id=canvas></canvas>
     37 <script>
     38 "use strict";
     39 description("Test KHR_parallel_shader_compile");
     40 
     41 function spinSpinner() {
     42    let degrees = (performance.now() / 1000 / 2 % 1.) * 360;
     43    spinner.style.transform = `rotate(${degrees}deg)`;
     44    requestAnimationFrame(spinSpinner);
     45 }
     46 spinSpinner();
     47 
     48 const wtu = WebGLTestUtils;
     49 
     50 const gl = wtu.create3DContext();
     51 const loseContext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_lose_context");
     52 
     53 let counter = 0;
     54 const vertexSource = (extra) => `
     55 void main() {
     56    vec4 result = vec4(0.${counter++});
     57 ${extra || ''}
     58    gl_Position = result;
     59 }`;
     60 const fragmentSource = (extra) => `
     61 precision highp float;
     62 void main() {
     63    vec4 result = vec4(0.${counter++});
     64 ${extra || ''}
     65    gl_FragColor = result;
     66 }`;
     67 
     68 let vs = gl.createShader(gl.VERTEX_SHADER);
     69 let fs = gl.createShader(gl.FRAGMENT_SHADER);
     70 let program = gl.createProgram();
     71 gl.attachShader(program, vs);
     72 gl.attachShader(program, fs);
     73 
     74 const COMPLETION_STATUS_KHR = 0x91B1;
     75 
     76 gl.shaderSource(vs, vertexSource());
     77 gl.compileShader(vs);
     78 let status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
     79 if (status !== null) testFailed('Extension disabled, status should be null');
     80 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "extension disabled");
     81 
     82 gl.shaderSource(fs, fragmentSource());
     83 gl.compileShader(fs);
     84 
     85 gl.linkProgram(program);
     86 status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
     87 if (status !== null) testFailed('Extension disabled, status should be null');
     88 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "extension disabled");
     89 
     90 const ext = wtu.getExtensionWithKnownPrefixes(gl, "KHR_parallel_shader_compile");
     91 
     92 let successfullyParsed = false;
     93 
     94 let extraCode = '';
     95 
     96 (async () => {
     97 
     98    if (!ext) {
     99        testPassed("No KHR_parallel_shader_compile support -- this is legal");
    100    } else {
    101        testPassed("Successfully enabled KHR_parallel_shader_compile extension");
    102 
    103        shouldBe("ext.COMPLETION_STATUS_KHR", "0x91B1");
    104 
    105        debug("Checking that status is a boolean.");
    106        gl.shaderSource(vs, vertexSource());
    107        gl.compileShader(vs);
    108        let status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
    109        if (status !== true && status !== false) testFailed("status should be a boolean");
    110 
    111        gl.linkProgram(program);
    112        status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
    113        if (status !== true && status !== false) testFailed("status should be a boolean");
    114 
    115        const minimumShaderCompileDurationMs = 500;
    116        debug(`Constructing shader that takes > ${minimumShaderCompileDurationMs} ms to compile.`);
    117        let measuredCompileDuration = 0;
    118        extraCode = '\n    if (true) { result += vec4(0.0000001); }';
    119        for (let i = 0; measuredCompileDuration < minimumShaderCompileDurationMs; i++) {
    120            extraCode += extraCode;
    121            extraCode += extraCode;
    122            if (i < 4) continue;
    123            gl.shaderSource(vs, vertexSource(extraCode));
    124            gl.shaderSource(fs, fragmentSource(extraCode));
    125            gl.compileShader(vs);
    126            gl.compileShader(fs);
    127            gl.linkProgram(program);
    128            const start = performance.now();
    129            if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    130                testFailed(`Shaders failed to compile.
    131                            program: ${gl.getProgramInfoLog(program)}
    132                            vs: ${gl.getShaderInfoLog(vs)}
    133                            fs: ${gl.getShaderInfoLog(fs)}`);
    134                break;
    135            }
    136            measuredCompileDuration = performance.now() - start;
    137        }
    138 
    139        debug('');
    140        gl.shaderSource(vs, vertexSource(extraCode));
    141        gl.shaderSource(fs, fragmentSource(extraCode));
    142        gl.compileShader(vs);
    143        gl.compileShader(fs);
    144        gl.linkProgram(program);
    145 
    146        let start = performance.now();
    147        gl.getShaderParameter(fs, COMPLETION_STATUS_KHR);
    148        gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
    149        let duration = performance.now() - start;
    150        if (duration > 100)
    151            testFailed(`Querying shader status should not wait for compilation. Took ${duration} ms`);
    152 
    153        let frames = 0;
    154        const maximumTimeToWait = measuredCompileDuration * 4;
    155        while (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)
    156            && performance.now() - start < maximumTimeToWait) {
    157            frames++;
    158            await new Promise(requestAnimationFrame);
    159        }
    160        duration = performance.now() - start;
    161        if (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)) {
    162            testFailed(`Program took longer than ${maximumTimeToWait} ms to compile. Expected: ${measuredCompileDuration} ms, actual: ${duration} ms`);
    163        } else if (!gl.getShaderParameter(vs, COMPLETION_STATUS_KHR) || !gl.getShaderParameter(fs, COMPLETION_STATUS_KHR)) {
    164            testFailed('Program linked before shaders finished compiling.');
    165        } else if (frames <= 6) {
    166            testFailed(`Program should have taken many more than 6 frames to compile. Actual value: ${frames} frames, duration ${performance.now() - start} ms.`);
    167        } else {
    168            console.log(`COMPLETION_STATUS_KHR sucessfully transitioned from false to true in ${frames} frames and ${duration} ms.`);
    169            testPassed(`COMPLETION_STATUS_KHR sucessfully transitioned from false to true`);
    170        }
    171 
    172        debug("Checking that compiling lots of programs in parallel eventually completes.");
    173        let programs = [];
    174        for (let i = 0; i < 256; ++i) {
    175            gl.shaderSource(vs, vertexSource());
    176            gl.shaderSource(fs, fragmentSource());
    177            gl.compileShader(vs);
    178            gl.compileShader(fs);
    179            let program = gl.createProgram();
    180            gl.attachShader(program, vs);
    181            gl.attachShader(program, fs);
    182            gl.linkProgram(program);
    183            programs.push(program);
    184        }
    185        let allDone = false;
    186        while (!allDone) {
    187            allDone = true;
    188            for (let i = 0; i < programs.length; ++i) {
    189                if (!gl.getProgramParameter(programs[i], COMPLETION_STATUS_KHR)) {
    190                    allDone = false;
    191                    break;
    192                }
    193            }
    194            if (!allDone) {
    195                await new Promise(requestAnimationFrame);
    196            }
    197        }
    198 
    199        debug("Checking that status is true when context is lost.");
    200        if (loseContext) {
    201            gl.shaderSource(vs, vertexSource(extraCode));
    202            gl.shaderSource(fs, fragmentSource(extraCode));
    203            gl.compileShader(vs);
    204            gl.compileShader(fs);
    205            gl.linkProgram(program);
    206            loseContext.loseContext();
    207            status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
    208            if (status !== true) testFailed("shader status should be true when context is lost");
    209            status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
    210            if (status !== true) testFailed("program status should be true when context is lost");
    211            loseContext.restoreContext();
    212            vs = gl.createShader(gl.VERTEX_SHADER);
    213            fs = gl.createShader(gl.FRAGMENT_SHADER);
    214            program = gl.createProgram();
    215        }
    216    }
    217    finishTest();
    218 })();
    219 
    220 async function compileShaders() {
    221    console.log('Compiling shaders');
    222    const gl = canvas.getContext('webgl');
    223    const vs = gl.createShader(gl.VERTEX_SHADER);
    224    const fs = gl.createShader(gl.FRAGMENT_SHADER);
    225    const program = gl.createProgram();
    226    gl.getExtension(wtu.getExtensionWithKnownPrefixes(gl, "KHR_parallel_shader_compile"));
    227    gl.attachShader(program, vs);
    228    gl.attachShader(program, fs);
    229    gl.shaderSource(vs, vertexSource(extraCode));
    230    gl.shaderSource(fs, fragmentSource(extraCode));
    231    gl.compileShader(vs);
    232    gl.compileShader(fs);
    233    gl.linkProgram(program);
    234    while (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)) {
    235        gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
    236        gl.getShaderParameter(fs, COMPLETION_STATUS_KHR);
    237        await new Promise(requestAnimationFrame);
    238    }
    239    gl.getProgramParameter(program, gl.LINK_STATUS);
    240    console.log('Compilation finished.');
    241 }
    242 
    243 </script>
    244 
    245 </body>
    246 </html>