tor-browser

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

immutable-tex-render-feedback.html (7505B)


      1 <!--
      2 Copyright (c) 2019 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>Ensure sampling-feedback detection can allow certain immutable texture uses</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 <div id="description"></div>
     18 <div id="console"></div>
     19 <script>
     20 "use strict";
     21 
     22 const wtu = WebGLTestUtils;
     23 description();
     24 
     25 const gl = wtu.create3DContext(undefined, undefined, 2);
     26 
     27 function* range(a, b) {
     28    a.required;
     29    if (b === undefined) {
     30        b = a;
     31        a = 0;
     32    }
     33    for (let i = a; i < b; i += 1) {
     34        yield i;
     35    }
     36 }
     37 
     38 const VS = `\
     39 void main() {
     40    gl_PointSize = 1.0;
     41 }
     42 `;
     43 
     44 const FS = `\
     45 uniform sampler2D u_tex0;
     46 void main() {
     47    gl_FragColor = texture2D(u_tex0, vec2(0));
     48 }
     49 `;
     50 
     51 const prog = wtu.loadProgram(gl, VS, FS);
     52 gl.useProgram(prog);
     53 
     54 (() => {
     55    const MIPS = 3;
     56    const SIZE = 10;
     57 
     58    const immutTex = gl.createTexture();
     59    immutTex.name = "immutTex";
     60    immutTex.immutable = true;
     61    gl.bindTexture(gl.TEXTURE_2D, immutTex);
     62    gl.texStorage2D(gl.TEXTURE_2D, MIPS, gl.RGBA8, SIZE, SIZE);
     63 
     64    const mutTex = gl.createTexture();
     65    mutTex.name = "mutTex";
     66    mutTex.immutable = false;
     67    gl.bindTexture(gl.TEXTURE_2D, mutTex);
     68    for (const mip of range(MIPS)) {
     69        const size = SIZE >> mip;
     70        gl.texImage2D(gl.TEXTURE_2D, mip, gl.RGBA8, size, size, 0,
     71                      gl.RGBA, gl.UNSIGNED_BYTE, null);
     72    }
     73 
     74    const MAG_FILTERS = [
     75        'LINEAR',
     76        'NEAREST',
     77    ];
     78    const MIN_FILTERS = [
     79        ['LINEAR',false],
     80        ['LINEAR_MIPMAP_LINEAR',true],
     81        ['LINEAR_MIPMAP_NEAREST',true],
     82        ['NEAREST',false],
     83        ['NEAREST_MIPMAP_LINEAR',true],
     84        ['NEAREST_MIPMAP_NEAREST',true],
     85    ];
     86 
     87    const fb = gl.createFramebuffer();
     88    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
     89 
     90    debug(`
     91        mips: ${MIPS}: [0,${MIPS-1}] (inclusive)
     92        size: ${SIZE}`);
     93    const texs = [
     94        immutTex,
     95        mutTex,
     96    ];
     97    for (const tex of texs) {
     98        debug(`\
     99 
    100            immutable: ${tex.immutable}`);
    101        gl.bindTexture(gl.TEXTURE_2D, tex);
    102 
    103        for (const level_prime_base of range(MIPS+1)) { // `level_base` in GLES
    104            // ES 3.0.6 p150
    105            let _level_base = level_prime_base;
    106            if (tex.immutable) {
    107                _level_base = Math.min(_level_base, MIPS-1);
    108            }
    109            const level_base = _level_base;
    110 
    111            for (let _level_prime_max of range(level_prime_base-1, MIPS+2)) { // `q` in GLES
    112                if (_level_prime_max < 0) continue;
    113                if (_level_prime_max == MIPS+1) {
    114                    _level_prime_max = 10000; // This is the default, after all!
    115                }
    116                const level_prime_max = _level_prime_max;
    117 
    118                // ES 3.0.6 p150
    119                let _level_max = level_prime_max;
    120                if (tex.immutable) {
    121                    _level_max = Math.min(Math.max(level_base, level_prime_max), MIPS-1);
    122                }
    123                const level_max = _level_max;
    124 
    125                const p = Math.floor(Math.log2(SIZE)) + level_base;
    126                const q = Math.min(p, level_max);
    127 
    128                debug(`\
    129 
    130                    level_prime_base/max: [${level_prime_base}, ${level_prime_max}] (inclusive)
    131                    level_base/max: [${level_base}, ${level_max}] (inclusive)
    132                    q: ${q}`);
    133                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL,
    134                                 level_prime_base);
    135                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL,
    136                                 level_prime_max);
    137 
    138                const mipComplete = (q <= MIPS-1);
    139 
    140                for (const [minFilter,useMips] of MIN_FILTERS) {
    141                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
    142                                     gl[minFilter]);
    143 
    144                    // ES3.0 p211
    145                    const srcMaxSampledMip = (useMips ? q : level_base);
    146 
    147                    // ES3.0 p160-161
    148                    const textureComplete = (srcMaxSampledMip <= MIPS-1) &&
    149                                            (level_base <= level_max);
    150 
    151                    for (const magFilter of MAG_FILTERS) {
    152                        debug(`\
    153 
    154                            min: ${minFilter}, mag: ${magFilter}`);
    155                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,
    156                                         gl[magFilter]);
    157 
    158                        for (const dstMip of range(0,MIPS+1)) {
    159                            debug(`
    160                                mip: ${dstMip}`);
    161                            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
    162                                                    gl.TEXTURE_2D, tex, dstMip);
    163 
    164                            // -
    165 
    166                            // ES3.0 p213-214
    167                            let fbComplete = true;
    168 
    169                            // * "The width and height of `image` are non-zero"
    170                            fbComplete &= (0 <= dstMip && dstMip <= MIPS-1);
    171 
    172                            if (!tex.immutable) { // "...does not name an immutable-format texture..."
    173                                // * "...the value of [level] must be in the range `[level_base, q]`"
    174                                fbComplete &= (level_base <= dstMip && dstMip <= q);
    175 
    176                                // * "...the value of [level] is not `level_base`, then the texture must be mipmap complete"
    177                                if (dstMip != level_base) {
    178                                    fbComplete &= mipComplete;
    179                                }
    180                            }
    181 
    182                            // -
    183 
    184                            let expectError = 0;
    185                            let expectStatus = gl.FRAMEBUFFER_COMPLETE;
    186 
    187                            // ES3.0 p211
    188                            let samplingFeedback = (level_base <= dstMip && dstMip <= srcMaxSampledMip);
    189                            if (!textureComplete) {
    190                                // Incomplete textures are safe
    191                                samplingFeedback = false;
    192                            }
    193                            if (samplingFeedback) {
    194                                expectError = gl.INVALID_OPERATION;
    195                            }
    196                            if (!fbComplete) {
    197                                expectStatus = gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    198                                expectError = gl.INVALID_FRAMEBUFFER_OPERATION;
    199                            }
    200 
    201                            // -
    202 
    203                            wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER,
    204                              expectStatus, `{immutable: ${tex.immutable}, level_prime_base/max: [${level_prime_base}, ${level_prime_max}], minFilter: ${minFilter}, dest: ${dstMip}}`);
    205 
    206                            gl.drawArrays(gl.POINTS, 0, 1);
    207                            wtu.glErrorShouldBe(gl, expectError, "after draw with texture");
    208                        }
    209                    }
    210                }
    211            }
    212        }
    213    }
    214 })();
    215 
    216 var successfullyParsed = true;
    217 </script>
    218 <script src="../../../js/js-test-post.js"></script>
    219 
    220 </body>
    221 </html>