tor-browser

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

oes-sample-variables.html (16899B)


      1 <!--
      2 Copyright (c) 2023 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 <title>WebGL OES_sample_variables Conformance Tests</title>
     12 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     13 <script src="../../js/js-test-pre.js"></script>
     14 <script src="../../js/webgl-test-utils.js"></script>
     15 </head>
     16 <body>
     17 <canvas width="32" height="32" id="c"></canvas>
     18 <div id="description"></div>
     19 <div id="console"></div>
     20 <script>
     21 "use strict";
     22 description("This test verifies the functionality of the OES_sample_variables extension, if it is available.");
     23 
     24 debug("");
     25 
     26 var wtu = WebGLTestUtils;
     27 var gl = wtu.create3DContext("c", { antialias: false }, 2);
     28 var ext;
     29 
     30 function runShaderTests(extensionEnabled) {
     31    debug("");
     32    debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
     33 
     34    const macro = `#version 300 es
     35        precision highp float;
     36        out vec4 my_FragColor;
     37        void main() {
     38        #ifdef GL_OES_sample_variables
     39            my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
     40        #else
     41            #error no GL_OES_sample_variables;
     42        #endif
     43        }`;
     44 
     45    // Expect the macro shader to succeed ONLY if enabled
     46    if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, macro])) {
     47        if (extensionEnabled) {
     48            testPassed("Macro defined in shaders when extension is enabled");
     49        } else {
     50            testFailed("Macro defined in shaders when extension is disabled");
     51        }
     52    } else {
     53        if (extensionEnabled) {
     54            testFailed("Macro not defined in shaders when extension is enabled");
     55        } else {
     56            testPassed("Macro not defined in shaders when extension is disabled");
     57        }
     58    }
     59 
     60    const missing = `#version 300 es
     61        precision highp float;
     62        out vec4 my_FragColor;
     63        void main() {
     64            gl_SampleMask[0] = gl_SampleMaskIn[0] & 0x55555555;
     65            my_FragColor = vec4(gl_SamplePosition.yx, float(gl_SampleID), float(gl_MaxSamples + gl_NumSamples));
     66        }`;
     67 
     68    // Always expect the shader missing the #extension pragma to fail (whether enabled or not)
     69    if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, missing])) {
     70        testFailed("Sample variables allowed without #extension pragma");
     71    } else {
     72        testPassed("Sample variables disallowed without #extension pragma");
     73    }
     74 
     75    const valid = `#version 300 es
     76        #extension GL_OES_sample_variables : enable
     77        precision highp float;
     78        out vec4 my_FragColor;
     79        void main() {
     80            gl_SampleMask[0] = gl_SampleMaskIn[0] & 0x55555555;
     81            my_FragColor = vec4(gl_SamplePosition.yx, float(gl_SampleID), float(gl_MaxSamples + gl_NumSamples));
     82        }`;
     83 
     84    // Try to compile a shader using sample variables that should only succeed if enabled
     85    if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, valid])) {
     86        if (extensionEnabled) {
     87            testPassed("Sample variables compiled successfully when extension enabled");
     88        } else {
     89            testFailed("Sample variables compiled successfully when extension disabled");
     90        }
     91    } else {
     92        if (extensionEnabled) {
     93            testFailed("Sample variables failed to compile when extension enabled");
     94        } else {
     95            testPassed("Sample variables failed to compile when extension disabled");
     96        }
     97    }
     98 
     99    debug("");
    100 }
    101 
    102 function runMaxSamplesTest() {
    103    debug("");
    104    debug("Testing gl_MaxSamples");
    105 
    106    const frag = `#version 300 es
    107        #extension GL_OES_sample_variables : require
    108        precision highp float;
    109        out vec4 color;
    110        void main() {
    111            color = vec4(float(gl_MaxSamples * 4) / 255.0, 0.0, 0.0, 1.0);
    112        }`;
    113    gl.useProgram(wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]));
    114 
    115    wtu.setupUnitQuad(gl);
    116    wtu.drawUnitQuad(gl);
    117 
    118    wtu.checkCanvas(gl, [gl.getParameter(gl.MAX_SAMPLES) * 4, 0, 0, 255], "should match MAX_SAMPLES", 1);
    119 }
    120 
    121 function runNumSamplesTest() {
    122    debug("");
    123    debug("Testing gl_NumSamples");
    124 
    125    const rbo = gl.createRenderbuffer();
    126    gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
    127    gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 32, 32);
    128 
    129    const fbo = gl.createFramebuffer();
    130    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    131    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
    132 
    133    wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
    134 
    135    const frag = `#version 300 es
    136        #extension GL_OES_sample_variables : require
    137        precision highp float;
    138        out vec4 color;
    139        void main() {
    140            if (gl_NumSamples == 4) {
    141                color = vec4(0.0, 1.0, 0.0, 1.0);
    142            } else {
    143                color = vec4(1.0, 0.0, 0.0, 1.0);
    144            }
    145        }`;
    146    gl.useProgram(wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]));
    147 
    148    wtu.setupUnitQuad(gl);
    149    wtu.drawUnitQuad(gl);
    150 
    151    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
    152    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
    153    gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    154 
    155    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
    156    wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
    157 }
    158 
    159 function runSampleIDTest() {
    160    debug("");
    161    debug("Testing gl_SampleID");
    162 
    163    const frag = `#version 300 es
    164        #extension GL_OES_sample_variables : require
    165        precision highp float;
    166        out vec4 color;
    167        uniform int id;
    168        void main() {
    169            // Special value when the selected sample is processed, 0.0 otherwise
    170            float r = float(gl_SampleID == id ? (1 << gl_SampleID) : 0) * 32.0 / 255.0;
    171            // Must always be 0.0
    172            float g = float(gl_SampleID < 0 || gl_SampleID >= gl_NumSamples);
    173            color = vec4(r, g, 0.0, 1.0);
    174        }`;
    175    const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
    176    gl.useProgram(program);
    177 
    178    wtu.setupUnitQuad(gl);
    179 
    180    const rbo = gl.createRenderbuffer();
    181    gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
    182    gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 32, 32);
    183 
    184    const fbo = gl.createFramebuffer();
    185    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    186    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
    187 
    188    wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
    189 
    190    for (let sample = 0; sample < 4; sample++) {
    191        debug(`Sample ${sample} is selected`);
    192 
    193        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
    194        gl.uniform1i(gl.getUniformLocation(program, "id"), sample);
    195        wtu.drawUnitQuad(gl);
    196 
    197        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
    198        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
    199        gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    200 
    201        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
    202        wtu.checkCanvas(gl, [(1 << sample) * 8, 0, 0, 255], undefined, 1);
    203    }
    204 }
    205 
    206 function runSampleMaskInTest() {
    207    debug("");
    208    debug("Testing gl_SampleMaskIn");
    209 
    210    const frag = `#version 300 es
    211        #extension GL_OES_sample_variables : require
    212        precision highp float;
    213        out vec4 color;
    214        uint popcount(uint v) {
    215            uint c = 0u;
    216            for (; v != 0u; v >>= 1) c += v & 1u;
    217            return c;
    218        }
    219        void main() {
    220            float r = float(popcount(uint(gl_SampleMaskIn[0])));
    221            color = vec4(r * 4.0 / 255.0, 0, 0, 1);
    222        }`;
    223 
    224    const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
    225    gl.useProgram(program);
    226 
    227    // Use a triangle instead of the WTU's quad
    228    // to avoid artifacts along the diagonal
    229    const vertices = gl.createBuffer();
    230    gl.bindBuffer(gl.ARRAY_BUFFER, vertices);
    231    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    232      -1.0,  1.0,
    233       1.0, -1.0,
    234      -1.0, -1.0]), gl.STATIC_DRAW);
    235    gl.enableVertexAttribArray(0);
    236    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    237 
    238    function test(sampleCount, sampleCoverageEnabled, coverage) {
    239        if (sampleCoverageEnabled) {
    240            gl.enable(gl.SAMPLE_COVERAGE);
    241        } else {
    242            gl.disable(gl.SAMPLE_COVERAGE);
    243        }
    244 
    245        gl.sampleCoverage(coverage, false);
    246 
    247        const rbo = gl.createRenderbuffer();
    248        gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
    249        gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32);
    250 
    251        const fbo = gl.createFramebuffer();
    252        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    253        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
    254 
    255        wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
    256 
    257        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
    258        gl.clear(gl.COLOR_BUFFER_BIT);
    259        gl.drawArrays(gl.TRIANGLES, 0, 3);
    260 
    261        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
    262        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
    263        gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    264 
    265        // Shader scales up the number of input samples to increase precision in unorm8 space.
    266        let expected = Math.max(sampleCount, 1) * 4;
    267 
    268        // Sample coverage must not affect single sampled buffers
    269        if (sampleCoverageEnabled && sampleCount > 0) {
    270            // The number of samples in gl_SampleMaskIn must be affected by the sample
    271            // coverage GL state and then the resolved value must be scaled down again.
    272            expected *= coverage * coverage;
    273        }
    274 
    275        // Check only the red channel
    276        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
    277        const pixel = new Uint8Array(4);
    278        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
    279        const message = `Expected: ${expected}, Actual: ${pixel[0]}, ` +
    280                        `Samples: ${sampleCount}, Sample Coverage: ${sampleCoverageEnabled}, Coverage: ${coverage}`;
    281        if (Math.abs(pixel[0] - expected) > 2) {
    282            testFailed(message);
    283        } else {
    284            testPassed(message);
    285        }
    286    }
    287 
    288    // Include all exposed sample counts and additionally test single-sampled rendering
    289    const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0];
    290 
    291    for (const sampleCount of sampleCounts) {
    292        if (sampleCount > 32) {
    293            // This test will not work with more than 32 samples.
    294            continue;
    295        }
    296 
    297        for (const sampleCoverageEnabled of [false, true]) {
    298            for (const coverage of [0.0, 0.5, 1.0]) {
    299                if (sampleCount == 1 && coverage != 0.0 && coverage != 1.0) {
    300                    continue;
    301                }
    302                test(sampleCount, sampleCoverageEnabled, coverage);
    303            }
    304        }
    305    }
    306 }
    307 
    308 function runSampleMaskInPerSampleTest() {
    309    debug("");
    310    debug("Testing gl_SampleMaskIn with per-sample shading");
    311 
    312    const frag = `#version 300 es
    313        #extension GL_OES_sample_variables : require
    314        precision highp float;
    315        out vec4 color;
    316        void main() {
    317            float r = float(gl_SampleMaskIn[0] == (1 << gl_SampleID));
    318            color = vec4(r, 0, 0, 1);
    319        }`;
    320    const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
    321    gl.useProgram(program);
    322 
    323    wtu.setupUnitQuad(gl);
    324 
    325    // Include all exposed sample counts and additionally test single-sampled rendering
    326    const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0];
    327    for (const sampleCount of sampleCounts) {
    328        if (sampleCount > 32) {
    329            // This test will not work with more than 32 samples.
    330            continue;
    331        }
    332 
    333        const rbo = gl.createRenderbuffer();
    334        gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
    335        gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32);
    336 
    337        const fbo = gl.createFramebuffer();
    338        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    339        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
    340 
    341        wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
    342 
    343        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
    344        wtu.drawUnitQuad(gl);
    345 
    346        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
    347        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
    348        gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    349 
    350        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
    351        wtu.checkCanvas(gl, [255, 0, 0, 255], `Samples: ${sampleCount}`, 1);
    352    }
    353 }
    354 
    355 function runSampleMaskTest() {
    356    debug("");
    357    debug("Testing gl_SampleMask");
    358 
    359    const frag = `#version 300 es
    360        #extension GL_OES_sample_variables : require
    361        precision highp float;
    362        uniform highp int sampleMask;
    363        out vec4 color;
    364        void main() {
    365            gl_SampleMask[0] = sampleMask;
    366            color = vec4(1, 0, 0, 1);
    367        }`;
    368    const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
    369    gl.useProgram(program);
    370 
    371    // Use a triangle instead of the WTU's quad
    372    // to avoid artifacts along the diagonal
    373    const vertices = gl.createBuffer();
    374    gl.bindBuffer(gl.ARRAY_BUFFER, vertices);
    375    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    376      -1.0,  1.0,
    377       1.0, -1.0,
    378      -1.0, -1.0]), gl.STATIC_DRAW);
    379    gl.enableVertexAttribArray(0);
    380    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    381 
    382    function test(sampleCount, sampleMask) {
    383        const rbo = gl.createRenderbuffer();
    384        gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
    385        gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32);
    386 
    387        const fbo = gl.createFramebuffer();
    388        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    389        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
    390 
    391        wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
    392 
    393        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
    394        gl.clear(gl.COLOR_BUFFER_BIT);
    395        gl.uniform1i(gl.getUniformLocation(program, "sampleMask"), sampleMask);
    396        gl.drawArrays(gl.TRIANGLES, 0, 3);
    397 
    398        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
    399        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
    400        gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    401 
    402        let expected = 1.0;
    403        if (sampleCount > 0) {
    404            let mask = sampleMask & ((1 << Math.max(sampleCount, 1)) - 1);
    405            let bits = 0;
    406            for (; mask != 0; mask >>= 1) bits += mask & 1;
    407            expected = bits / Math.max(sampleCount, 1);
    408        }
    409        expected *= 255;
    410 
    411        // Check only the red channel
    412        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
    413        const pixel = new Uint8Array(4);
    414        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
    415        const message = `Samples: ${sampleCount}, `
    416                        + `gl_SampleMask[0]: 0x${sampleMask.toString(16).padStart(8, "0").toUpperCase()}, `
    417                        + `Actual: ${pixel[0]}, Expected: ${expected}`;
    418        if (Math.abs(pixel[0] - expected) > 2) {
    419            testFailed(message);
    420        } else {
    421            testPassed(message);
    422        }
    423    }
    424 
    425    // Include all exposed sample counts and additionally test single-sampled rendering
    426    const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0];
    427 
    428    for (const sampleCount of sampleCounts) {
    429        if (sampleCount > 31) {
    430            // This test will not work with more than 31 samples.
    431            continue;
    432        }
    433 
    434        for (const sampleMask of [0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x00000000]) {
    435            test(sampleCount, sampleMask);
    436        }
    437    }
    438 }
    439 
    440 function runTest() {
    441    if (!gl) {
    442        testFailed("WebGL context does not exist");
    443        return;
    444    }
    445    testPassed("WebGL context exists");
    446 
    447    runShaderTests(false);
    448 
    449    ext = gl.getExtension("OES_sample_variables");
    450    wtu.runExtensionSupportedTest(gl, "OES_sample_variables", ext !== null);
    451 
    452    if (!ext) {
    453        testPassed("No OES_sample_variables support -- this is legal");
    454    } else {
    455        testPassed("Successfully enabled OES_sample_variables extension");
    456        runShaderTests(true);
    457 
    458        debug("Testing sample variables");
    459        runMaxSamplesTest();
    460        runNumSamplesTest();
    461        runSampleIDTest();
    462        runSampleMaskInTest();
    463        runSampleMaskInPerSampleTest();
    464        runSampleMaskTest();
    465    }
    466 }
    467 
    468 runTest();
    469 
    470 var successfullyParsed = true;
    471 </script>
    472 <script src="../../js/js-test-post.js"></script>
    473 </body>
    474 </html>