tor-browser

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

tex-image-and-sub-image-2d-with-webgl-canvas.js (12455B)


      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 "use strict";
      8 
      9 function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
     10    var wtu = WebGLTestUtils;
     11    var tiu = TexImageUtils;
     12    var gl = null;
     13    var successfullyParsed = false;
     14    var redColor = [255, 0, 0, 255];
     15    var greenColor = [0, 255, 0, 255];
     16    var repeatCount;
     17 
     18    function shouldRepeatTestForTextureFormat(internalFormat, pixelFormat, pixelType)
     19    {
     20        // There were bugs in early WebGL 1.0 implementations when repeatedly uploading canvas
     21        // elements into textures. In response, this test was changed into a regression test by
     22        // repeating all of the cases multiple times. Unfortunately, this means that adding a new
     23        // case above significantly increases the run time of the test suite. The problem is made
     24        // even worse by the addition of many more texture formats in WebGL 2.0.
     25        //
     26        // Doing repeated runs with just a couple of WebGL 1.0's supported texture formats acts as a
     27        // sufficient regression test for the old bugs. For this reason the test has been changed to
     28        // only repeat for those texture formats.
     29        return ((internalFormat == 'RGBA' && pixelFormat == 'RGBA' && pixelType == 'UNSIGNED_BYTE') ||
     30                (internalFormat == 'RGB' && pixelFormat == 'RGB' && pixelType == 'UNSIGNED_BYTE'));
     31    }
     32 
     33    async function init()
     34    {
     35        description('Verify texImage2D and texSubImage2D code paths taking webgl canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
     36 
     37        // Set the default context version while still allowing the webglVersion URL query string to override it.
     38        wtu.setDefault3DContextVersion(defaultContextVersion);
     39        gl = wtu.create3DContext("example");
     40 
     41        if (!prologue(gl)) {
     42            return;
     43        }
     44 
     45        repeatCount = (shouldRepeatTestForTextureFormat(internalFormat, pixelFormat, pixelType) ? 4 : 1);
     46 
     47        switch (gl[pixelFormat]) {
     48          case gl.RED:
     49          case gl.RED_INTEGER:
     50            greenColor = [0, 0, 0];
     51            break;
     52          case gl.LUMINANCE:
     53          case gl.LUMINANCE_ALPHA:
     54            redColor = [255, 255, 255];
     55            greenColor = [0, 0, 0];
     56            break;
     57          case gl.ALPHA:
     58            redColor = [0, 0, 0];
     59            greenColor = [0, 0, 0];
     60            break;
     61          default:
     62            break;
     63        }
     64 
     65        gl.clearColor(0,0,0,1);
     66        gl.clearDepth(1);
     67 
     68        await runTest();
     69    }
     70 
     71    function setCanvasToRedGreen(ctx, hasAlpha) {
     72      var width = ctx.canvas.width;
     73      var height = ctx.canvas.height;
     74      var halfHeight = Math.floor(height / 2);
     75 
     76      ctx.viewport(0, 0, width, height);
     77 
     78      ctx.enable(ctx.SCISSOR_TEST);
     79      ctx.scissor(0, 0, width, halfHeight);
     80      if (hasAlpha) {
     81        ctx.clearColor(1.0, 0, 0, 1.0);
     82      } else {
     83        // The WebGL implementation is responsible for making all
     84        // alpha values appear as though they were 1.0.
     85        ctx.clearColor(1.0, 0, 0, 0.0);
     86      }
     87      ctx.clear(ctx.COLOR_BUFFER_BIT);
     88      ctx.scissor(0, halfHeight, width, height - halfHeight);
     89      if (hasAlpha) {
     90        ctx.clearColor(0.0, 1.0, 0, 1.0);
     91      } else {
     92        // The WebGL implementation is responsible for making all
     93        // alpha values appear as though they were 1.0.
     94        ctx.clearColor(0.0, 1.0, 0, 0.0);
     95      }
     96      ctx.clear(ctx.COLOR_BUFFER_BIT);
     97      ctx.disable(ctx.SCISSOR_TEST);
     98    }
     99 
    100    function setCanvasTo257x257(ctx, bindingTarget, hasAlpha) {
    101      ctx.canvas.width = 257;
    102      ctx.canvas.height = 257;
    103      setCanvasToRedGreen(ctx, hasAlpha);
    104    }
    105 
    106    function setCanvasToMin(ctx, bindingTarget, hasAlpha) {
    107      if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
    108        // cube map texture must be square.
    109        ctx.canvas.width = 2;
    110      } else {
    111        ctx.canvas.width = 1;
    112      }
    113      ctx.canvas.height = 2;
    114      setCanvasToRedGreen(ctx, hasAlpha);
    115    }
    116 
    117    function runOneIteration(canvas, useTexSubImage2D, alpha, flipY, program, bindingTarget, opt_texture)
    118    {
    119        var objType = 'canvas';
    120        if (canvas.transferToImageBitmap)
    121            objType = 'OffscreenCanvas';
    122        else if (canvas.parentNode)
    123            objType = 'canvas attached to DOM';
    124        debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') + ' with alpha=' +
    125              alpha + ' flipY=' + flipY + ' source object: ' + objType +
    126              ' bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
    127              ' canvas size: ' + canvas.width + 'x' + canvas.height + ' with red-green');
    128 
    129        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    130        if (!opt_texture) {
    131            var texture = gl.createTexture();
    132            // Bind the texture to texture unit 0
    133            gl.bindTexture(bindingTarget, texture);
    134            // Set up texture parameters
    135            gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    136            gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    137            gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    138            gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    139        } else {
    140            var texture = opt_texture;
    141        }
    142        // Set up pixel store parameters
    143        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors before pixelStorei setup");
    144        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
    145        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_FLIP_Y_WEBGL");
    146        gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
    147        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_PREMULTIPLY_ALPHA_WEBGL");
    148        gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
    149        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_COLORSPACE_CONVERSION_WEBGL");
    150        var targets = [gl.TEXTURE_2D];
    151        if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
    152            targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
    153                       gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
    154                       gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
    155                       gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
    156                       gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
    157                       gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
    158        }
    159        // Upload the image into the texture
    160        for (var tt = 0; tt < targets.length; ++tt) {
    161            // Initialize the texture to black first
    162            if (useTexSubImage2D) {
    163                gl.texImage2D(targets[tt], 0, gl[internalFormat], canvas.width, canvas.height, 0,
    164                              gl[pixelFormat], gl[pixelType], null);
    165                gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], canvas);
    166            } else {
    167                gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], canvas);
    168            }
    169        }
    170 
    171        var width = gl.canvas.width;
    172        var height = gl.canvas.height;
    173        var halfWidth = Math.floor(width / 2);
    174        var halfHeight = Math.floor(height / 2);
    175        var top = flipY ? (height - halfHeight) : 0;
    176        var bottom = flipY ? 0 : (height - halfHeight);
    177 
    178        var loc;
    179        if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
    180            loc = gl.getUniformLocation(program, "face");
    181        }
    182 
    183        for (var tt = 0; tt < targets.length; ++tt) {
    184            if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
    185                gl.uniform1i(loc, targets[tt]);
    186            }
    187            // Draw the triangles
    188            wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
    189 
    190            // Check the top and bottom halves and make sure they have the right color.
    191            debug("Checking " + (flipY ? "top" : "bottom"));
    192            wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, redColor,
    193                    "shouldBe " + redColor);
    194            debug("Checking " + (flipY ? "bottom" : "top"));
    195            wtu.checkCanvasRect(gl, 0, top, width, halfHeight, greenColor,
    196                    "shouldBe " + greenColor);
    197        }
    198 
    199        if (false) {
    200          var ma = wtu.makeImageFromCanvas(canvas);
    201          document.getElementById("console").appendChild(ma);
    202 
    203          var m = wtu.makeImageFromCanvas(gl.canvas);
    204          document.getElementById("console").appendChild(m);
    205          document.getElementById("console").appendChild(document.createElement("hr"));
    206        }
    207 
    208        return texture;
    209    }
    210 
    211    async function runTest()
    212    {
    213        for (let alpha of [ true, false ]) {
    214            let ctx = wtu.create3DContext(null, { alpha:alpha });
    215            let canvas = ctx.canvas;
    216            // Note: We use preserveDrawingBuffer:true to prevent canvas
    217            // visibility from interfering with the tests.
    218            let visibleCtx = wtu.create3DContext(null, { preserveDrawingBuffer:true, alpha:alpha });
    219            if (!visibleCtx) {
    220                testFailed("context does not exist");
    221                return;
    222            }
    223            let visibleCanvas = visibleCtx.canvas;
    224            let descriptionNode = document.getElementById("description");
    225            document.body.insertBefore(visibleCanvas, descriptionNode);
    226 
    227            let cases = [
    228                { sub: false, flipY: true,  ctx: ctx, init: setCanvasToMin },
    229                { sub: false, flipY: false, ctx: ctx },
    230                { sub: true,  flipY: true,  ctx: ctx },
    231                { sub: true,  flipY: false, ctx: ctx },
    232                { sub: false, flipY: true,  ctx: ctx, init: setCanvasTo257x257 },
    233                { sub: false, flipY: false, ctx: ctx },
    234                { sub: true,  flipY: true,  ctx: ctx },
    235                { sub: true,  flipY: false, ctx: ctx },
    236                { sub: false, flipY: true,  ctx: visibleCtx, init: setCanvasToMin },
    237                { sub: false, flipY: false, ctx: visibleCtx },
    238                { sub: true,  flipY: true,  ctx: visibleCtx },
    239                { sub: true,  flipY: false, ctx: visibleCtx },
    240            ];
    241 
    242            if (window.OffscreenCanvas) {
    243                let offscreen = new OffscreenCanvas(1, 1);
    244                let offscreenCtx = wtu.create3DContext(offscreen, { alpha:alpha });
    245                cases = cases.concat([
    246                    { sub: false, flipY: true,  ctx: offscreenCtx, init: setCanvasToMin },
    247                    { sub: false, flipY: false, ctx: offscreenCtx },
    248                    { sub: true,  flipY: true,  ctx: offscreenCtx },
    249                    { sub: true,  flipY: false, ctx: offscreenCtx },
    250                ]);
    251            }
    252 
    253            async function runTexImageTest(bindingTarget) {
    254                let program;
    255                if (bindingTarget == gl.TEXTURE_2D) {
    256                    program = tiu.setupTexturedQuad(gl, internalFormat);
    257                } else {
    258                    program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
    259                }
    260 
    261                let count = repeatCount;
    262                let caseNdx = 0;
    263                let texture = undefined;
    264                while (true) {
    265                    let c = cases[caseNdx];
    266                    if (c.init) {
    267                        c.init(c.ctx, bindingTarget, alpha);
    268                    }
    269                    texture = runOneIteration(c.ctx.canvas, c.sub, alpha, c.flipY, program, bindingTarget, texture);
    270                    // for the first 2 iterations always make a new texture.
    271                    if (count < 2) {
    272                        gl.deleteTexture(texture);
    273                        texture = undefined;
    274                    }
    275                    ++caseNdx;
    276                    if (caseNdx == cases.length) {
    277                        caseNdx = 0;
    278                        --count;
    279                        if (!count)
    280                            return;
    281                    }
    282                    await wtu.dispatchPromise(function() {});
    283                }
    284            }
    285 
    286            await runTexImageTest(gl.TEXTURE_2D);
    287            await runTexImageTest(gl.TEXTURE_CUBE_MAP);
    288        }
    289 
    290        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    291    }
    292 
    293    return function() {
    294        init().then(function(val) {
    295            finishTest();
    296        });
    297    };
    298 }