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-canvas-sub-rectangle.js (12381B)


      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 function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
      8    var wtu = WebGLTestUtils;
      9    var tiu = TexImageUtils;
     10    var gl = null;
     11    var successfullyParsed = false;
     12    var realRedColor = [255, 0, 0];
     13    var realGreenColor = [0, 255, 0];
     14    var realBlueColor = [0, 0, 255];
     15    var realCyanColor = [0, 255, 255];
     16    var redColor = realRedColor;
     17    var greenColor = realGreenColor;
     18    var blueColor = realBlueColor;
     19    var cyanColor = realCyanColor;
     20 
     21    function init()
     22    {
     23        description('Verify texImage2D and texSubImage2D code paths taking a sub-rectangle of a canvas (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
     24 
     25        // Set the default context version while still allowing the webglVersion URL query string to override it.
     26        wtu.setDefault3DContextVersion(defaultContextVersion);
     27 
     28        // The sub-rectangle tests only apply to WebGL 2.0 for the
     29        // time being, though the tests for the WebGL 1.0
     30        // format/internal format/type combinations are generated into
     31        // conformance/textures/.
     32        if (wtu.getDefault3DContextVersion() < 2) {
     33            debug('Test only applies to WebGL 2.0');
     34            finishTest();
     35            return;
     36        }
     37 
     38        gl = wtu.create3DContext("example", { preserveDrawingBuffer: true });
     39 
     40        if (!prologue(gl)) {
     41            finishTest();
     42            return;
     43        }
     44 
     45        switch (gl[pixelFormat]) {
     46        case gl.RED:
     47        case gl.RED_INTEGER:
     48          greenColor = [0, 0, 0];
     49          blueColor = [0, 0, 0];
     50          cyanColor = [0, 0, 0];
     51          break;
     52 
     53        case gl.RG:
     54        case gl.RG_INTEGER:
     55          blueColor = [0, 0, 0];
     56          cyanColor = [0, 255, 0];
     57          break;
     58 
     59        case gl.LUMINANCE:
     60        case gl.LUMINANCE_ALPHA:
     61          redColor = [255, 255, 255];
     62          greenColor = [0, 0, 0];
     63          blueColor = [0, 0, 0];
     64          cyanColor = [0, 0, 0];
     65          break;
     66 
     67        case gl.ALPHA:
     68          redColor = [0, 0, 0];
     69          greenColor = [0, 0, 0];
     70          blueColor = [0, 0, 0];
     71          cyanColor = [0, 0, 0];
     72          break;
     73 
     74        default:
     75          break;
     76        }
     77 
     78        gl.clearColor(0,0,0,1);
     79        gl.clearDepth(1);
     80        gl.disable(gl.BLEND);
     81 
     82        var canvas2d = document.createElement('canvas');
     83        runTest(canvas2d, setupSourceCanvas2D, '2D-rendered canvas');
     84 
     85        var canvasWebGL = document.createElement('canvas');
     86        runTest(canvasWebGL, setupSourceCanvasWebGL, 'WebGL-rendered canvas');
     87 
     88        finishTest();
     89    }
     90 
     91    function fillStyle2D(ctx, color) {
     92        ctx.fillStyle = 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')';
     93    }
     94 
     95    function setupSourceCanvas2D(canvas) {
     96        var width = canvas.width;
     97        var height = canvas.height;
     98        var halfWidth = Math.floor(width / 2);
     99        var halfHeight = Math.floor(height / 2);
    100 
    101        var ctx = canvas.getContext('2d');
    102        // Always use the same pattern for this test: four quadrants:
    103        //   red    green
    104        //   blue   cyan
    105        // Handle odd-sized canvases
    106        fillStyle2D(ctx, realRedColor);
    107        ctx.fillRect(0, 0, halfWidth, halfHeight);
    108        fillStyle2D(ctx, realGreenColor);
    109        ctx.fillRect(halfWidth, 0, width - halfWidth, halfHeight);
    110        fillStyle2D(ctx, realBlueColor);
    111        ctx.fillRect(0, halfHeight, halfWidth, height - halfHeight);
    112        fillStyle2D(ctx, realCyanColor);
    113        ctx.fillRect(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
    114    }
    115 
    116    function clearColorWebGL(ctx, color) {
    117        ctx.clearColor(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0);
    118        ctx.clear(ctx.COLOR_BUFFER_BIT);
    119    }
    120 
    121    function setupSourceCanvasWebGL(canvas) {
    122        var width = canvas.width;
    123        var height = canvas.height;
    124        var halfWidth = Math.floor(width / 2);
    125        var halfHeight = Math.floor(height / 2);
    126 
    127        var ctx = canvas.getContext('webgl');
    128        // Always use the same pattern for this test: four quadrants:
    129        //   red    green
    130        //   blue   cyan
    131        // Handle odd-sized canvases
    132 
    133        ctx.viewport(0, 0, width, height);
    134        ctx.enable(ctx.SCISSOR_TEST);
    135        // OpenGL origin is lower-left
    136        ctx.scissor(0, 0, halfWidth, halfHeight);
    137        clearColorWebGL(ctx, realBlueColor);
    138        ctx.scissor(halfWidth, 0, width - halfWidth, halfHeight);
    139        clearColorWebGL(ctx, realCyanColor);
    140        ctx.scissor(0, halfHeight, halfWidth, height - halfHeight);
    141        clearColorWebGL(ctx, realRedColor);
    142        ctx.scissor(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
    143        clearColorWebGL(ctx, realGreenColor);
    144    }
    145 
    146    function runOneIteration(sourceDescription, useTexSubImage2D, flipY,
    147                             canvas, canvasSize, canvasSetupFunction,
    148                             sourceSubRectangle, expected,
    149                             bindingTarget, program)
    150    {
    151        sourceSubRectangleString = '';
    152        if (sourceSubRectangle) {
    153            sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle;
    154        }
    155        debug('');
    156        debug('Testing ' + sourceDescription + ' with ' +
    157              (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
    158              ', flipY=' + flipY +
    159              ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
    160              sourceSubRectangleString);
    161 
    162        var loc;
    163        if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
    164            loc = gl.getUniformLocation(program, "face");
    165        }
    166 
    167        // Initialize the contents of the source canvas.
    168        var width = canvasSize[0];
    169        var height = canvasSize[1];
    170        var halfWidth = Math.floor(width / 2);
    171        var halfHeight = Math.floor(height / 2);
    172        canvas.width = width;
    173        canvas.height = height;
    174        canvasSetupFunction(canvas);
    175 
    176        // Upload the source canvas to the texture and draw it to a quad.
    177        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    178        // Enable writes to the RGBA channels
    179        gl.colorMask(1, 1, 1, 0);
    180        var texture = gl.createTexture();
    181        // Bind the texture to texture unit 0
    182        gl.bindTexture(bindingTarget, texture);
    183        // Set up texture parameters
    184        gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    185        gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    186        // Set up pixel store parameters
    187        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
    188        gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
    189        wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
    190        var targets = [gl.TEXTURE_2D];
    191        if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
    192            targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
    193                       gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
    194                       gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
    195                       gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
    196                       gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
    197                       gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
    198        }
    199        // In this test, this is always specified. It's currently WebGL 2.0-specific.
    200        gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
    201        gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
    202        // Upload the image into the texture
    203        var uploadWidth = sourceSubRectangle[2];
    204        var uploadHeight = sourceSubRectangle[3];
    205        for (var tt = 0; tt < targets.length; ++tt) {
    206            if (useTexSubImage2D) {
    207                // Initialize the texture to black first
    208                gl.texImage2D(targets[tt], 0, gl[internalFormat],
    209                              uploadWidth, uploadHeight, 0,
    210                              gl[pixelFormat], gl[pixelType], null);
    211                gl.texSubImage2D(targets[tt], 0, 0, 0,
    212                                 uploadWidth, uploadHeight,
    213                                 gl[pixelFormat], gl[pixelType], canvas);
    214            } else {
    215                gl.texImage2D(targets[tt], 0, gl[internalFormat],
    216                              uploadWidth, uploadHeight, 0,
    217                              gl[pixelFormat], gl[pixelType], canvas);
    218            }
    219        }
    220 
    221        gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
    222        gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
    223 
    224        // The tests are constructed to upload a single solid color
    225        // out of the canvas.
    226        var outputCanvasWidth = gl.drawingBufferWidth;
    227        var outputCanvasHeight = gl.drawingBufferHeight;
    228 
    229        for (var tt = 0; tt < targets.length; ++tt) {
    230            if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
    231                gl.uniform1i(loc, targets[tt]);
    232            }
    233            // Draw the triangles
    234            wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
    235 
    236            var msg = 'should be ' + expected;
    237            wtu.checkCanvasRect(gl, 0, 0, outputCanvasWidth, outputCanvasHeight, expected, msg);
    238        }
    239    }
    240 
    241    function runTest(canvas, canvasSetupFunction, sourceDescription)
    242    {
    243        var program = tiu.setupTexturedQuad(gl, internalFormat);
    244        runTestOnBindingTarget(gl.TEXTURE_2D, program, canvas, canvasSetupFunction, sourceDescription);
    245        program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
    246        runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program, canvas, canvasSetupFunction, sourceDescription);
    247 
    248        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
    249    }
    250 
    251    function runTestOnBindingTarget(bindingTarget, program, canvas, canvasSetupFunction, sourceDescription) {
    252        var cases = [
    253            // Small canvas cases. Expected that these won't be
    254            // GPU-accelerated in most browsers' implementations.
    255            { expected: redColor,   flipY: false, size: [2, 2], subRect: [0, 0, 1, 1] },
    256            { expected: greenColor, flipY: false, size: [2, 2], subRect: [1, 0, 1, 1] },
    257            { expected: blueColor,  flipY: false, size: [2, 2], subRect: [0, 1, 1, 1] },
    258            { expected: cyanColor,  flipY: false, size: [2, 2], subRect: [1, 1, 1, 1] },
    259            { expected: redColor,   flipY: true,  size: [2, 2], subRect: [0, 1, 1, 1] },
    260            { expected: greenColor, flipY: true,  size: [2, 2], subRect: [1, 1, 1, 1] },
    261            { expected: blueColor,  flipY: true,  size: [2, 2], subRect: [0, 0, 1, 1] },
    262            { expected: cyanColor,  flipY: true,  size: [2, 2], subRect: [1, 0, 1, 1] },
    263 
    264            // Larger canvas cases. Expected that these will be
    265            // GPU-accelerated in most browsers' implementations.
    266            // Changes will be gladly accepted to trigger more
    267            // browsers' heuristics to accelerate these canvases.
    268            { expected: redColor,   flipY: false, size: [384, 384], subRect: [  0,   0, 192, 192] },
    269            { expected: greenColor, flipY: false, size: [384, 384], subRect: [192,   0, 192, 192] },
    270            { expected: blueColor,  flipY: false, size: [384, 384], subRect: [  0, 192, 192, 192] },
    271            { expected: cyanColor,  flipY: false, size: [384, 384], subRect: [192, 192, 192, 192] },
    272            { expected: blueColor,  flipY: true,  size: [384, 384], subRect: [  0,   0, 192, 192] },
    273            { expected: cyanColor,  flipY: true,  size: [384, 384], subRect: [192,   0, 192, 192] },
    274            { expected: redColor,   flipY: true,  size: [384, 384], subRect: [  0, 192, 192, 192] },
    275            { expected: greenColor, flipY: true,  size: [384, 384], subRect: [192, 192, 192, 192] },
    276 
    277        ];
    278 
    279        for (var i in cases) {
    280            runOneIteration(sourceDescription, false, cases[i].flipY,
    281                            canvas, cases[i].size, canvasSetupFunction,
    282                            cases[i].subRect,
    283                            cases[i].expected, bindingTarget, program);
    284            runOneIteration(sourceDescription, true, cases[i].flipY,
    285                            canvas, cases[i].size, canvasSetupFunction,
    286                            cases[i].subRect,
    287                            cases[i].expected, bindingTarget, program);
    288        }
    289    }
    290 
    291    return init;
    292 }