tor-browser

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

webgl-depth-texture.html (15077B)


      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 <!DOCTYPE html>
      7 <html>
      8 <head>
      9 <meta charset="utf-8">
     10 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     11 <script src="../../js/js-test-pre.js"></script>
     12 <script src="../../js/webgl-test-utils.js"></script>
     13 <title>WebGL WEBGL_depth_texture Conformance Tests</title>
     14 </head>
     15 <body>
     16 <script id="vshader" type="x-shader/x-vertex">
     17 attribute vec4 a_position;
     18 void main()
     19 {
     20    gl_Position = a_position;
     21 }
     22 </script>
     23 
     24 <script id="fshader" type="x-shader/x-fragment">
     25 precision mediump float;
     26 uniform sampler2D u_texture;
     27 uniform vec2 u_resolution;
     28 void main()
     29 {
     30    vec2 texcoord = (gl_FragCoord.xy - vec2(0.5)) / (u_resolution - vec2(1.0));
     31    gl_FragColor = texture2D(u_texture, texcoord);
     32 }
     33 </script>
     34 <div id="description"></div>
     35 <div id="console"></div>
     36 <canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
     37 <script>
     38 "use strict";
     39 description("This test verifies the functionality of the WEBGL_depth_texture extension, if it is available.");
     40 
     41 debug("");
     42 
     43 var wtu = WebGLTestUtils;
     44 var canvas = document.getElementById("canvas");
     45 var gl = wtu.create3DContext(canvas, {antialias: false});
     46 var program = wtu.setupTexturedQuad(gl);
     47 var ext = null;
     48 var vao = null;
     49 var tex;
     50 var name;
     51 var supportedFormats;
     52 var canvas2;
     53 
     54 if (!gl) {
     55    testFailed("WebGL context does not exist");
     56 } else {
     57    testPassed("WebGL context exists");
     58 
     59    // Run tests with extension disabled
     60    runTestDisabled();
     61 
     62    // Query the extension and store globally so shouldBe can access it
     63    ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
     64    if (!ext) {
     65        testPassed("No WEBGL_depth_texture support -- this is legal");
     66        runSupportedTest(false);
     67    } else {
     68        testPassed("Successfully enabled WEBGL_depth_texture extension");
     69 
     70        runSupportedTest(true);
     71        runTestExtension(true);
     72        runTestExtension(false);
     73    }
     74 }
     75 
     76 function runSupportedTest(extensionEnabled) {
     77    var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
     78    if (name !== undefined) {
     79        if (extensionEnabled) {
     80            testPassed("WEBGL_depth_texture listed as supported and getExtension succeeded");
     81        } else {
     82            testFailed("WEBGL_depth_texture listed as supported but getExtension failed");
     83        }
     84    } else {
     85        if (extensionEnabled) {
     86            testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded");
     87        } else {
     88            testPassed("WEBGL_depth_texture not listed as supported and getExtension failed -- this is legal");
     89        }
     90    }
     91 }
     92 
     93 
     94 function runTestDisabled() {
     95    debug("Testing binding enum with extension disabled");
     96 
     97    var tex = gl.createTexture();
     98    gl.bindTexture(gl.TEXTURE_2D, tex);
     99    wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE],
    100                              'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)');
    101    wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE],
    102                              'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)');
    103 }
    104 
    105 
    106 function dumpIt(gl, res, msg) {
    107  return;  // comment out to debug
    108  debug(msg);
    109  var actualPixels = new Uint8Array(res * res * 4);
    110  gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
    111 
    112  for (var yy = 0; yy < res; ++yy) {
    113    var strs = [];
    114    for (var xx = 0; xx < res; ++xx) {
    115      var actual = (yy * res + xx) * 4;
    116      strs.push("(" + actualPixels[actual] + "," + actualPixels[actual+1] + "," + actualPixels[actual + 2] + "," + actualPixels[actual + 3] + ")");
    117    }
    118    debug(strs.join(" "));
    119  }
    120 }
    121 function runTestExtension(unpackFlipY) {
    122    debug("Testing WEBGL_depth_texture. UNPACK_FLIP_Y_WEBGL: " + unpackFlipY);
    123 
    124    const res = 2;
    125    const destRes = 4;
    126 
    127    // make canvas for testing.
    128    canvas2 = document.createElement("canvas");
    129    canvas2.width = res;
    130    canvas2.height = res;
    131    var ctx = canvas2.getContext("2d");
    132    ctx.fillStyle = "blue";
    133    ctx.fillRect(0, 0, canvas2.width, canvas2.height);
    134 
    135    var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']);
    136    gl.useProgram(program);
    137    gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), destRes, destRes);
    138 
    139    var buffer = gl.createBuffer();
    140    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    141    gl.bufferData(
    142        gl.ARRAY_BUFFER,
    143        new Float32Array(
    144            [   1,  1,  1,
    145               -1,  1,  0,
    146               -1, -1, -1,
    147                1,  1,  1,
    148               -1, -1, -1,
    149                1, -1,  0,
    150            ]),
    151        gl.STATIC_DRAW);
    152    gl.enableVertexAttribArray(0);
    153    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
    154 
    155    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, unpackFlipY);
    156 
    157    var types = [
    158        {obj: 'gl',  attachment: 'DEPTH_ATTACHMENT',         format: 'DEPTH_COMPONENT', type: 'UNSIGNED_SHORT',          data: 'new Uint16Array(1)', depthBits: "16"},
    159        {obj: 'gl',  attachment: 'DEPTH_ATTACHMENT',         format: 'DEPTH_COMPONENT', type: 'UNSIGNED_INT',            data: 'new Uint32Array(1)', depthBits: "16"},
    160        {obj: 'ext', attachment: 'DEPTH_STENCIL_ATTACHMENT', format: 'DEPTH_STENCIL',   type: 'UNSIGNED_INT_24_8_WEBGL', data: 'new Uint32Array(1)', depthBits: "24", stencilBits: "8"}
    161    ];
    162 
    163    for (var ii = 0; ii < types.length; ++ii) {
    164        var typeInfo = types[ii];
    165        var type = typeInfo.type;
    166        var typeStr = typeInfo.obj + '.' + type;
    167 
    168        debug("");
    169        debug("testing: " + type);
    170 
    171        // check that cubemaps are not allowed.
    172        var cubeTex = gl.createTexture();
    173        gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTex);
    174        var targets = [
    175          'TEXTURE_CUBE_MAP_POSITIVE_X',
    176          'TEXTURE_CUBE_MAP_NEGATIVE_X',
    177          'TEXTURE_CUBE_MAP_POSITIVE_Y',
    178          'TEXTURE_CUBE_MAP_NEGATIVE_Y',
    179          'TEXTURE_CUBE_MAP_POSITIVE_Z',
    180          'TEXTURE_CUBE_MAP_NEGATIVE_Z'
    181        ];
    182        for (var tt = 0; tt < targets.length; ++tt) {
    183            wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.' + targets[ii] + ', 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
    184        }
    185 
    186        // The WebGL_depth_texture extension supports both NEAREST and
    187        // LINEAR filtering for depth textures, even though LINEAR
    188        // doesn't have much meaning, and isn't supported in WebGL
    189        // 2.0. Still, test both.
    190        var filterModes = [
    191          'LINEAR',
    192          'NEAREST'
    193        ];
    194 
    195        for (var jj = 0; jj < filterModes.length; ++jj) {
    196            debug('');
    197            debug('testing ' + filterModes[jj] + ' filtering');
    198            var filterMode = gl[filterModes[jj]];
    199 
    200            // check 2d textures.
    201            tex = gl.createTexture();
    202            gl.bindTexture(gl.TEXTURE_2D, tex);
    203            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    204            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    205            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterMode);
    206            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterMode);
    207 
    208            // test level > 0
    209            wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
    210 
    211            // test with data
    212            wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')');
    213 
    214            // test with canvas
    215            wtu.shouldGenerateGLError(gl, [gl.INVALID_VALUE, gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', gl.' + typeInfo.format + ', ' + typeStr  + ', canvas2)');
    216 
    217            // test copyTexImage2D
    218            wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 0, 0, 1, 1, 0)');
    219 
    220            // test real thing
    221            wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', ' + res + ', ' + res + ', 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
    222 
    223            // test texSubImage2D
    224            wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.' + typeInfo.format + ', ' + typeStr  + ', ' + typeInfo.data + ')');
    225 
    226            // test copyTexSubImage2D
    227            wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1)');
    228 
    229            // test generateMipmap
    230            wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.generateMipmap(gl.TEXTURE_2D)');
    231 
    232            var fbo = gl.createFramebuffer();
    233            gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    234            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, tex, 0);
    235 
    236            // Ensure DEPTH_BITS returns >= 16 bits for UNSIGNED_SHORT and UNSIGNED_INT, >= 24 UNSIGNED_INT_24_8_WEBGL.
    237            // If there is stencil, ensure STENCIL_BITS reports >= 8 for UNSIGNED_INT_24_8_WEBGL.
    238            shouldBeGreaterThanOrEqual('gl.getParameter(gl.DEPTH_BITS)', typeInfo.depthBits);
    239            if (typeInfo.stencilBits === undefined) {
    240                shouldBe('gl.getParameter(gl.STENCIL_BITS)', '0');
    241            } else {
    242                shouldBeGreaterThanOrEqual('gl.getParameter(gl.STENCIL_BITS)', typeInfo.stencilBits);
    243            }
    244 
    245            // TODO: remove this check if the spec is updated to require these combinations to work.
    246            if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
    247            {
    248                // try adding a color buffer.
    249                var colorTex = gl.createTexture();
    250                gl.bindTexture(gl.TEXTURE_2D, colorTex);
    251                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    252                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    253                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    254                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    255                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, res, res, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    256                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);
    257            }
    258 
    259            shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
    260 
    261            // use the default texture to render with while we return to the depth texture.
    262            gl.bindTexture(gl.TEXTURE_2D, null);
    263 
    264            /* Setup 2x2 depth texture:
    265             * 1 0.6 0.8
    266             * |
    267             * 0 0.2 0.4
    268             *    0---1
    269             */
    270            const d00 = 0.2;
    271            const d01 = 0.4;
    272            const d10 = 0.6;
    273            const d11 = 0.8;
    274 
    275            gl.enable(gl.SCISSOR_TEST);
    276 
    277            gl.scissor(0, 0, 1, 1);
    278            gl.clearDepth(d00);
    279            gl.clear(gl.DEPTH_BUFFER_BIT);
    280 
    281            gl.scissor(1, 0, 1, 1);
    282            gl.clearDepth(d10);
    283            gl.clear(gl.DEPTH_BUFFER_BIT);
    284 
    285            gl.scissor(0, 1, 1, 1);
    286            gl.clearDepth(d01);
    287            gl.clear(gl.DEPTH_BUFFER_BIT);
    288 
    289            gl.scissor(1, 1, 1, 1);
    290            gl.clearDepth(d11);
    291            gl.clear(gl.DEPTH_BUFFER_BIT);
    292 
    293            gl.disable(gl.SCISSOR_TEST);
    294 
    295            // render the depth texture.
    296            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    297            gl.canvas.width = destRes;
    298            gl.canvas.height = destRes;
    299            gl.viewport(0, 0, destRes, destRes);
    300            gl.bindTexture(gl.TEXTURE_2D, tex);
    301 
    302            gl.disable(gl.DITHER);
    303            gl.enable(gl.DEPTH_TEST);
    304            gl.clearColor(1, 0, 0, 1);
    305            gl.clearDepth(1.0);
    306            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    307            gl.drawArrays(gl.TRIANGLES, 0, 6);
    308 
    309            dumpIt(gl, res, "--depth--");
    310 
    311            var actualPixels = new Uint8Array(destRes * destRes * 4);
    312            gl.readPixels(0, 0, destRes, destRes, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
    313 
    314            const eps = 0.002;
    315 
    316            let expectedMin;
    317            let expectedMax;
    318            if (filterMode == gl.NEAREST) {
    319                expectedMin = [
    320                    d00, d00, d10, d10,
    321                    d00, d00, d10, d10,
    322                    d01, d01, d11, d11,
    323                    d01, d01, d11, d11
    324                ];
    325                expectedMax = expectedMin.slice();
    326 
    327                expectedMin = expectedMin.map(x => x - eps);
    328                expectedMax = expectedMax.map(x => x + eps);
    329            } else {
    330                expectedMin = [
    331                    d00-eps, d00, d00, d10-eps,
    332                    d00, d00, d00, d10,
    333                    d00, d00, d00, d10,
    334                    d01-eps, d01, d01, d11-eps,
    335                ];
    336                expectedMax = [
    337                    d00+eps, d10, d10, d10+eps,
    338                    d01, d11, d11, d11,
    339                    d01, d11, d11, d11,
    340                    d01+eps, d11, d11, d11+eps,
    341                ];
    342            }
    343 
    344            for (var yy = 0; yy < destRes; ++yy) {
    345                for (var xx = 0; xx < destRes; ++xx) {
    346                    const t = xx + destRes*yy;
    347                    const was = actualPixels[4*t] / 255.0; // 4bpp
    348                    const eMin = expectedMin[t];
    349                    const eMax = expectedMax[t];
    350                    let func = testPassed;
    351                    const text = `At ${xx},${yy}, expected within [${eMin},${eMax}], was ${was.toFixed(3)}`
    352                    if (was <= eMin || was >= eMax) {
    353                        func = testFailed;
    354                    }
    355                    func(text);
    356                }
    357            }
    358 
    359            // check limitations
    360            gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    361            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, null, 0);
    362            var badAttachment = typeInfo.attachment == 'DEPTH_ATTACHMENT' ? 'DEPTH_STENCIL_ATTACHMENT' : 'DEPTH_ATTACHMENT';
    363            wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.' + badAttachment + ', gl.TEXTURE_2D, tex, 0)');
    364            shouldNotBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
    365            wtu.shouldGenerateGLError(gl, gl.INVALID_FRAMEBUFFER_OPERATION, 'gl.clear(gl.DEPTH_BUFFER_BIT)');
    366            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    367            shouldBe('gl.getError()', 'gl.NO_ERROR');
    368        }
    369    }
    370 }
    371 
    372 debug("");
    373 var successfullyParsed = true;
    374 </script>
    375 <script src="../../js/js-test-post.js"></script>
    376 </body>
    377 </html>