tor-browser

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

compressed-texture-utils.js (11746B)


      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 let CompressedTextureUtils = (function() {
     10 
     11 let formatToString = function(ext, format) {
     12    for (let p in ext) {
     13        if (ext[p] == format) {
     14            return p;
     15        }
     16    }
     17    return "0x" + format.toString(16);
     18 };
     19 
     20 /**
     21 * Make an image element from Uint8Array bitmap data.
     22 * @param {number} imageHeight Height of the data in pixels.
     23 * @param {number} imageWidth Width of the data in pixels.
     24 * @param {number} dataWidth Width of each row in the data buffer, in pixels.
     25 * @param {Uint8Array} data Image data buffer to display. Each pixel takes up 4 bytes in the array regardless of the alpha parameter.
     26 * @param {boolean} alpha True if alpha data should be taken from data. Otherwise alpha channel is set to 255.
     27 * @return {HTMLImageElement} The image element.
     28 */
     29 let makeScaledImage = function(imageWidth, imageHeight, dataWidth, data, alpha, opt_scale) {
     30    let scale = opt_scale ? opt_scale : 8;
     31    let c = document.createElement("canvas");
     32    c.width = imageWidth * scale;
     33    c.height = imageHeight * scale;
     34    let ctx = c.getContext("2d");
     35    for (let yy = 0; yy < imageHeight; ++yy) {
     36        for (let xx = 0; xx < imageWidth; ++xx) {
     37            let offset = (yy * dataWidth + xx) * 4;
     38            ctx.fillStyle = "rgba(" +
     39                    data[offset + 0] + "," +
     40                    data[offset + 1] + "," +
     41                    data[offset + 2] + "," +
     42                    (alpha ? data[offset + 3] / 255 : 1) + ")";
     43            ctx.fillRect(xx * scale, yy * scale, scale, scale);
     44        }
     45    }
     46    return wtu.makeImageFromCanvas(c);
     47 };
     48 
     49 let insertCaptionedImg = function(parent, caption, img) {
     50    let div = document.createElement("div");
     51    div.appendChild(img);
     52    let label = document.createElement("div");
     53    label.appendChild(document.createTextNode(caption));
     54    div.appendChild(label);
     55    parent.appendChild(div);
     56 };
     57 
     58 /**
     59 * @param {WebGLRenderingContextBase} gl
     60 * @param {Object} compressedFormats Mapping from format names to format enum values.
     61 * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
     62 */
     63 let testCompressedFormatsUnavailableWhenExtensionDisabled = function(gl, compressedFormats, expectedByteLength, testSize) {
     64    let tex = gl.createTexture();
     65    gl.bindTexture(gl.TEXTURE_2D, tex);
     66    for (let name in compressedFormats) {
     67        if (compressedFormats.hasOwnProperty(name)) {
     68            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, compressedFormats[name], testSize, testSize, 0, new Uint8Array(expectedByteLength(testSize, testSize, compressedFormats[name])));
     69            wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with extension disabled.");
     70            if (gl.texStorage2D) {
     71                gl.texStorage2D(gl.TEXTURE_2D, 1, compressedFormats[name], testSize, testSize);
     72                wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with texStorage2D with extension disabled.");
     73            }
     74        }
     75    }
     76    gl.bindTexture(gl.TEXTURE_2D, null);
     77    gl.deleteTexture(tex);
     78 };
     79 
     80 /**
     81 * @param {WebGLRenderingContextBase} gl
     82 * @param {Object} expectedFormats Mapping from format names to format enum values.
     83 */
     84 let testCompressedFormatsListed = function(gl, expectedFormats) {
     85    debug("");
     86    debug("Testing that every format is listed by the compressed texture formats query");
     87 
     88    let supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
     89 
     90    let failed;
     91    let count = 0;
     92    for (let name in expectedFormats) {
     93        if (expectedFormats.hasOwnProperty(name)) {
     94            ++count;
     95            let format = expectedFormats[name];
     96            failed = true;
     97            for (let ii = 0; ii < supportedFormats.length; ++ii) {
     98                if (format == supportedFormats[ii]) {
     99                    testPassed("supported format " + name + " exists");
    100                    failed = false;
    101                    break;
    102                }
    103            }
    104            if (failed) {
    105                testFailed("supported format " + name + " does not exist");
    106            }
    107        }
    108    }
    109    if (supportedFormats.length != count) {
    110        testFailed("Incorrect number of supported formats, was " + supportedFormats.length + " should be " + count);
    111    }
    112 };
    113 
    114 /**
    115 * @param {Object} ext Compressed texture extension object.
    116 * @param {Object} expectedFormats Mapping from format names to format enum values.
    117 */
    118 let testCorrectEnumValuesInExt = function(ext, expectedFormats) {
    119    debug("");
    120    debug("Testing that format enum values in the extension object are correct");
    121 
    122    for (name in expectedFormats) {
    123        if (expectedFormats.hasOwnProperty(name)) {
    124            if (isResultCorrect(ext[name], expectedFormats[name])) {
    125                testPassed("Enum value for " + name + " matches 0x" + ext[name].toString(16));
    126            } else {
    127                testFailed("Enum value for " + name + " mismatch: 0x" + ext[name].toString(16) + " should be 0x" + expectedFormats[name].toString(16));
    128            }
    129        }
    130    }
    131 };
    132 
    133 /**
    134 * @param {WebGLRenderingContextBase} gl
    135 * @param {Object} validFormats Mapping from format names to format enum values.
    136 * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
    137 * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
    138 */
    139 let testFormatRestrictionsOnBufferSize = function(gl, validFormats, expectedByteLength, getBlockDimensions) {
    140    debug("");
    141    debug("Testing format restrictions on texture upload buffer size");
    142 
    143    let tex = gl.createTexture();
    144    gl.bindTexture(gl.TEXTURE_2D, tex);
    145    for (let formatId in validFormats) {
    146        if (validFormats.hasOwnProperty(formatId)) {
    147            let format = validFormats[formatId];
    148            let blockSize = getBlockDimensions(format);
    149            let expectedSize = expectedByteLength(blockSize.width * 4, blockSize.height * 4, format);
    150            let data = new Uint8Array(expectedSize);
    151            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 3, blockSize.height * 4, 0, data);
    152            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small width)");
    153            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 5, blockSize.height * 4, 0, data);
    154            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large width)");
    155            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 3, 0, data);
    156            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small height)");
    157            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 5, 0, data);
    158            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large height)");
    159        }
    160    }
    161 };
    162 
    163 /**
    164 * @param {WebGLRenderingContextBase} gl
    165 * @param {Object} validFormats Mapping from format names to format enum values.
    166 * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
    167 * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
    168 * @param {number} width Width of the image in pixels.
    169 * @param {number} height Height of the image in pixels.
    170 * @param {Object} subImageConfigs configs for compressedTexSubImage calls
    171 */
    172 let testTexSubImageDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, width, height, subImageConfigs) {
    173    let tex = gl.createTexture();
    174    gl.bindTexture(gl.TEXTURE_2D, tex);
    175 
    176    for (let formatId in validFormats) {
    177        if (validFormats.hasOwnProperty(formatId)) {
    178            let format = validFormats[formatId];
    179            let blockSize = getBlockDimensions(format);
    180            debug("testing " + ctu.formatToString(ext, format));
    181            let expectedSize = expectedByteLength(width, height, format);
    182            let data = new Uint8Array(expectedSize);
    183 
    184            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
    185            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setting up compressed texture");
    186 
    187            for (let i = 0, len = subImageConfigs.length; i < len; ++i) {
    188                let c = subImageConfigs[i];
    189                let subData = new Uint8Array(expectedByteLength(c.width, c.height, format));
    190                gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, c.xoffset, c.yoffset, c.width, c.height, format, subData);
    191                wtu.glErrorShouldBe(gl, c.expectation, c.message);
    192            }
    193        }
    194    }
    195 
    196    gl.bindTexture(gl.TEXTURE_2D, null);
    197    gl.deleteTexture(tex);
    198 };
    199 
    200 let testTexImageLevelDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, imageConfigs) {
    201    let tex = gl.createTexture();
    202    gl.bindTexture(gl.TEXTURE_2D, tex);
    203 
    204    for (let formatId in validFormats) {
    205        if (validFormats.hasOwnProperty(formatId)) {
    206            let format = validFormats[formatId];
    207            let blockSize = getBlockDimensions(format);
    208            debug("testing " + ctu.formatToString(ext, format));
    209 
    210            for (let i = 0, len = imageConfigs.length; i < len; ++i) {
    211                let c = imageConfigs[i];
    212                let data = new Uint8Array(expectedByteLength(c.width, c.height, format));
    213                gl.compressedTexImage2D(gl.TEXTURE_2D, c.level, format, c.width, c.height, 0, data);
    214                wtu.glErrorShouldBe(gl, c.expectation, c.message);
    215            }
    216        }
    217    }
    218 
    219    gl.bindTexture(gl.TEXTURE_2D, null);
    220    gl.deleteTexture(tex);
    221 }
    222 
    223 let testTexStorageLevelDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, imageConfigs) {
    224    for (let formatId in validFormats) {
    225        let tex = gl.createTexture();
    226        gl.bindTexture(gl.TEXTURE_2D, tex);
    227 
    228        if (validFormats.hasOwnProperty(formatId)) {
    229            let format = validFormats[formatId];
    230            let blockSize = getBlockDimensions(format);
    231            debug("testing " + ctu.formatToString(ext, format));
    232 
    233            for (let i = 0, len = imageConfigs.length; i < len; ++i) {
    234                let c = imageConfigs[i];
    235                let data = new Uint8Array(expectedByteLength(c.width, c.height, format));
    236                if (i == 0) {
    237                    gl.texStorage2D(gl.TEXTURE_2D, imageConfigs.length, format, c.width, c.height);
    238                    wtu.glErrorShouldBe(gl, c.expectation, c.message);
    239                }
    240                gl.compressedTexSubImage2D(gl.TEXTURE_2D, i, 0, 0, c.width, c.height, format, data);
    241                wtu.glErrorShouldBe(gl, c.expectation, c.message);
    242            }
    243        }
    244        gl.bindTexture(gl.TEXTURE_2D, null);
    245        gl.deleteTexture(tex);
    246    }
    247 }
    248 
    249 return {
    250    formatToString: formatToString,
    251    insertCaptionedImg: insertCaptionedImg,
    252    makeScaledImage: makeScaledImage,
    253    testCompressedFormatsListed: testCompressedFormatsListed,
    254    testCompressedFormatsUnavailableWhenExtensionDisabled: testCompressedFormatsUnavailableWhenExtensionDisabled,
    255    testCorrectEnumValuesInExt: testCorrectEnumValuesInExt,
    256    testFormatRestrictionsOnBufferSize: testFormatRestrictionsOnBufferSize,
    257    testTexSubImageDimensions: testTexSubImageDimensions,
    258    testTexImageLevelDimensions: testTexImageLevelDimensions,
    259    testTexStorageLevelDimensions: testTexStorageLevelDimensions,
    260 };
    261 
    262 })();