tor-browser

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

test_webgl_compressed_texture_es3.html (25461B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4 <meta charset="utf-8">
      5 <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6 <link rel="stylesheet" href="/tests/SimpleTest/test.css">
      7 <script src="webgl-util.js"></script>
      8 <script src="es3-data.js"></script>
      9 <title>WebGL test: test WEBGL_compressed_texture_etc extension</title>
     10 <style>
     11 img {
     12 border: 1px solid black;
     13 margin-right: 1em;
     14 }
     15 .testimages {
     16 }
     17 
     18 .testimages br {
     19  clear: both;
     20 }
     21 
     22 .testimages > div {
     23  float: left;
     24  margin: 1em;
     25 }
     26 </style>
     27 </head>
     28 <body>
     29 <div id="description"></div>
     30 <canvas id="canvas" width="8" height="8"></canvas>
     31 <div id="console"></div>
     32 <script id="vshader" type="x-shader/x-vertex">
     33    attribute vec4 vPosition;
     34    attribute vec2 texCoord0;
     35    varying vec2 texCoord;
     36    void main() {
     37        gl_Position = vPosition;
     38        texCoord = texCoord0;
     39    }
     40 </script>
     41 <script id="fshader" type="x-shader/x-fragment">
     42    precision mediump float;
     43    uniform sampler2D tex;
     44    varying vec2 texCoord;
     45    void main() {
     46        gl_FragData[0] = texture2D(tex, texCoord);
     47    }
     48 </script>
     49 <script id="fshader-r" type="x-shader/x-fragment">
     50    precision mediump float;
     51    uniform sampler2D tex;
     52    varying vec2 texCoord;
     53    void main() {
     54        vec4 pixel = (texture2D(tex, texCoord));
     55        pixel.r = (pixel.r + 1.0) / 2.0;
     56        gl_FragData[0] = pixel;
     57    }
     58 </script>
     59 <script id="fshader-rg" type="x-shader/x-fragment">
     60    precision mediump float;
     61    uniform sampler2D tex;
     62    varying vec2 texCoord;
     63    void main() {
     64        vec4 pixel = (texture2D(tex, texCoord));
     65        pixel.rg = (pixel.rg + 1.0) / 2.0;
     66        gl_FragData[0] = pixel;
     67    }
     68 </script>
     69 <script>
     70 "use strict";
     71 var ext = null;
     72 var vao = null;
     73 var gl = null;
     74 var validFormats = {
     75    COMPRESSED_R11_EAC                        : 0x9270,
     76    COMPRESSED_SIGNED_R11_EAC                 : 0x9271,
     77    COMPRESSED_RG11_EAC                       : 0x9272,
     78    COMPRESSED_SIGNED_RG11_EAC                : 0x9273,
     79    COMPRESSED_RGB8_ETC2                      : 0x9274,
     80    COMPRESSED_SRGB8_ETC2                     : 0x9275,
     81    COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2  : 0x9276,
     82    COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9277,
     83    COMPRESSED_RGBA8_ETC2_EAC                 : 0x9278,
     84    COMPRESSED_SRGB8_ALPHA8_ETC2_EAC          : 0x9279,
     85 };
     86 
     87 function setupUnitQuad() {
     88    var vertexObject = gl.createBuffer();
     89    gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
     90    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
     91         1.0,  1.0, 0.0,
     92        -1.0,  1.0, 0.0,
     93        -1.0, -1.0, 0.0,
     94         1.0,  1.0, 0.0,
     95        -1.0, -1.0, 0.0,
     96         1.0, -1.0, 0.0]), gl.STATIC_DRAW);
     97    gl.enableVertexAttribArray(0);
     98    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
     99 
    100    var vertexObject = gl.createBuffer();
    101    gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
    102    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    103        1.0, 1.0,
    104        0.0, 1.0,
    105        0.0, 0.0,
    106        1.0, 1.0,
    107        0.0, 0.0,
    108        1.0, 0.0]), gl.STATIC_DRAW);
    109    gl.enableVertexAttribArray(1);
    110    gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
    111 }
    112 
    113 function runTest() {
    114    gl = canvas.getContext('webgl', {antialias: false});
    115    if (!gl) {
    116        ok(false, "WebGL context does not exist");
    117    } else {
    118        ok(true, "WebGL context exists");
    119        setupUnitQuad();
    120 
    121        // Run tests with extension disabled
    122        runTestDisabled();
    123 
    124        // Query the extension and store globally so shouldBe can access it
    125        ext = gl.getExtension("WEBGL_compressed_texture_etc");
    126        if (!ext) {
    127            ok(true, "No WEBGL_compressed_texture_etc support -- this is legal");
    128            runSupportedTest(false);
    129        } else {
    130            ok(true, "Successfully enabled WEBGL_compressed_texture_etc extension");
    131 
    132            runSupportedTest(true);
    133            runTestExtension();
    134        }
    135    }
    136    SimpleTest.finish();
    137 }
    138 
    139 function runSupportedTest(extensionEnabled) {
    140    var supported = gl.getSupportedExtensions();
    141    if (supported.includes("WEBGL_compressed_texture_etc")) {
    142        if (extensionEnabled) {
    143            ok(true, "WEBGL_compressed_texture_etc listed as supported and getExtension succeeded");
    144        } else {
    145            ok(false, "WEBGL_compressed_texture_etc listed as supported but getExtension failed");
    146        }
    147    } else {
    148        if (extensionEnabled) {
    149            ok(false, "WEBGL_compressed_texture_etc not listed as supported but getExtension succeeded");
    150        } else {
    151            ok(true, "WEBGL_compressed_texture_etc not listed as supported and getExtension failed -- this is legal");
    152        }
    153    }
    154 }
    155 
    156 function runTestDisabled() {
    157    is(gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS).length, 0,
    158       "Should be no compressed texture formats");
    159 }
    160 
    161 function formatExists(format, supportedFormats) {
    162    for (var ii = 0; ii < supportedFormats.length; ++ii) {
    163        if (format == supportedFormats[ii]) {
    164            ok(true, "supported format " + formatToString(format) + " is exists");
    165            return;
    166        }
    167    }
    168    ok(false, "supported format " + formatToString(format) + " does not exist");
    169 }
    170 
    171 function formatToString(format) {
    172    for (var p in ext) {
    173        if (ext[p] == format) {
    174            return p;
    175        }
    176    }
    177    return "0x" + format.toString(16);
    178 }
    179 
    180 function runTestExtension() {
    181    // check that all format enums exist.
    182    for (let name in validFormats) {
    183        is(ext[name], validFormats[name], "format is match");
    184    }
    185 
    186    let supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
    187    // There should be exactly 10 formats
    188    is(supportedFormats.length, 10, "Should be exactly 10 formats");
    189 
    190    // check that all 10 formats exist
    191    for (let name in validFormats.length) {
    192        formatExists(validFormats[name], supportedFormats);
    193    }
    194 
    195    // Test each format
    196    testETC2_RGB();
    197 }
    198 
    199 function testETC2_RGB() {
    200    var tests = [
    201        {
    202            width: 4,
    203            height: 4,
    204            channels: 1,
    205            data: img_4x4_r11_eac,
    206            format: ext.COMPRESSED_R11_EAC
    207        },
    208        {
    209            width: 4,
    210            height: 4,
    211            channels: 1,
    212            data: img_4x4_signed_r11_eac,
    213            format: ext.COMPRESSED_SIGNED_R11_EAC
    214        },
    215        {
    216            width: 4,
    217            height: 4,
    218            channels: 2,
    219            data: img_4x4_rg11_eac,
    220            format: ext.COMPRESSED_RG11_EAC
    221        },
    222        {
    223            width: 4,
    224            height: 4,
    225            channels: 2,
    226            data: img_4x4_signed_rg11_eac,
    227            format: ext.COMPRESSED_SIGNED_RG11_EAC
    228        },
    229        {
    230            width: 4,
    231            height: 4,
    232            channels: 3,
    233            data: img_4x4_rgb_etc2,
    234            format: ext.COMPRESSED_RGB8_ETC2
    235        },
    236        {
    237            width: 4,
    238            height: 4,
    239            channels: 3,
    240            data: img_4x4_rgb_etc2,
    241            format: ext.COMPRESSED_SRGB8_ETC2
    242        },
    243        {
    244            width: 4,
    245            height: 4,
    246            channels: 4,
    247            data: img_4x4_rgb_punchthrough_etc2,
    248            format: ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
    249        },
    250        {
    251            width: 4,
    252            height: 4,
    253            channels: 4,
    254            data: img_4x4_rgb_punchthrough_etc2,
    255            format: ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
    256        },
    257        {
    258            width: 4,
    259            height: 4,
    260            channels: 4,
    261            data: img_4x4_rgba_etc2,
    262            format: ext.COMPRESSED_RGBA8_ETC2_EAC
    263        },
    264        {
    265            width: 4,
    266            height: 4,
    267            channels: 4,
    268            data: img_4x4_rgba_etc2,
    269            format: ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
    270        },
    271        {
    272            width: 8,
    273            height: 8,
    274            channels: 1,
    275            data: img_8x8_r11_eac,
    276            format: ext.COMPRESSED_R11_EAC
    277        },
    278        {
    279            width: 8,
    280            height: 8,
    281            channels: 1,
    282            data: img_8x8_signed_r11_eac,
    283            format: ext.COMPRESSED_SIGNED_R11_EAC
    284        },
    285        {
    286            width: 8,
    287            height: 8,
    288            channels: 2,
    289            data: img_8x8_rg11_eac,
    290            format: ext.COMPRESSED_RG11_EAC
    291        },
    292        {
    293            width: 8,
    294            height: 8,
    295            channels: 2,
    296            data: img_8x8_signed_rg11_eac,
    297            format: ext.COMPRESSED_SIGNED_RG11_EAC
    298        },
    299        {
    300            width: 8,
    301            height: 8,
    302            channels: 3,
    303            data: img_8x8_rgb_etc2,
    304            format: ext.COMPRESSED_RGB8_ETC2
    305        },
    306        {
    307            width: 8,
    308            height: 8,
    309            channels: 3,
    310            data: img_8x8_rgb_etc2,
    311            format: ext.COMPRESSED_SRGB8_ETC2
    312        },
    313        {
    314            width: 8,
    315            height: 8,
    316            channels: 4,
    317            data: img_8x8_rgb_punchthrough_etc2,
    318            format: ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
    319        },
    320        {
    321            width: 8,
    322            height: 8,
    323            channels: 4,
    324            data: img_8x8_rgb_punchthrough_etc2,
    325            format: ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
    326        },
    327        {
    328            width: 8,
    329            height: 8,
    330            channels: 4,
    331            data: img_8x8_rgba_etc2,
    332            format: ext.COMPRESSED_RGBA8_ETC2_EAC
    333        },
    334        {
    335            width: 8,
    336            height: 8,
    337            channels: 4,
    338            data: img_8x8_rgba_etc2,
    339            format: ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
    340        },
    341        {
    342            width: 32,
    343            height: 32,
    344            channels: 1,
    345            data: img_32x32_r11_eac,
    346            format: ext.COMPRESSED_R11_EAC
    347        },
    348        {
    349            width: 32,
    350            height: 32,
    351            channels: 1,
    352            data: img_32x32_signed_r11_eac,
    353            format: ext.COMPRESSED_SIGNED_R11_EAC
    354        },
    355        {
    356            width: 32,
    357            height: 32,
    358            channels: 2,
    359            data: img_32x32_rg11_eac,
    360            format: ext.COMPRESSED_RG11_EAC
    361        },
    362        {
    363            width: 32,
    364            height: 32,
    365            channels: 2,
    366            data: img_32x32_signed_rg11_eac,
    367            format: ext.COMPRESSED_SIGNED_RG11_EAC
    368        },
    369        {
    370            width: 32,
    371            height: 32,
    372            channels: 3,
    373            data: img_32x32_rgb_etc2,
    374            format: ext.COMPRESSED_RGB8_ETC2
    375        },
    376        {
    377            width: 32,
    378            height: 32,
    379            channels: 3,
    380            data: img_32x32_rgb_etc2,
    381            format: ext.COMPRESSED_SRGB8_ETC2
    382        },
    383        {
    384            width: 32,
    385            height: 32,
    386            channels: 4,
    387            data: img_32x32_rgb_punchthrough_etc2,
    388            format: ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
    389        },
    390        {
    391            width: 32,
    392            height: 32,
    393            channels: 4,
    394            data: img_32x32_rgb_punchthrough_etc2,
    395            format: ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
    396        },
    397        {
    398            width: 32,
    399            height: 32,
    400            channels: 4,
    401            data: img_32x32_rgba_etc2,
    402            format: ext.COMPRESSED_RGBA8_ETC2_EAC
    403        },
    404        {
    405            width: 32,
    406            height: 32,
    407            channels: 4,
    408            data: img_32x32_rgba_etc2,
    409            format: ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
    410        },
    411    ];
    412    testETCTextures(tests);
    413 }
    414 
    415 function testETCTextures(tests) {
    416    for (var ii = 0; ii < tests.length; ++ii) {
    417        testETCTexture(tests[ii]);
    418    }
    419 }
    420 
    421 /* Return the size of block in bytes */
    422 function getBlockSize(format) {
    423    switch (format) {
    424    case ext.COMPRESSED_R11_EAC:
    425    case ext.COMPRESSED_SIGNED_R11_EAC:
    426    case ext.COMPRESSED_RGB8_ETC2:
    427    case ext.COMPRESSED_SRGB8_ETC2:
    428    case ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
    429    case ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
    430        return 8;
    431    case ext.COMPRESSED_RG11_EAC:
    432    case ext.COMPRESSED_SIGNED_RG11_EAC:
    433    case ext.COMPRESSED_RGBA8_ETC2_EAC:
    434    case ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
    435        return 16
    436    }
    437    throw new Error(`Unexpected format ${format}`);
    438 }
    439 
    440 function copyRect(data, srcX, srcY, dstX, dstY, width, height, stride) {
    441  var bytesPerLine = width * 4;
    442  var srcOffset = srcX * 4 + srcY * stride;
    443  var dstOffset = dstX * 4 + dstY * stride;
    444  for (var jj = height; jj > 0; --jj) {
    445    for (var ii = 0; ii < bytesPerLine; ++ii) {
    446      data[dstOffset + ii] = data[srcOffset + ii];
    447    }
    448    srcOffset += stride;
    449    dstOffset += stride;
    450  }
    451 }
    452 
    453 function testETCTexture(test) {
    454    var data = new Uint8Array(test.data.compressed);
    455    var width = test.width;
    456    var height = test.height;
    457    var format = test.format;
    458 
    459    var uncompressedData = new Uint8Array(test.data.decompressed);
    460    var glErrorShouldBe = (glInner, glError, msg) => {
    461        msg = msg || "";
    462        var err = glInner.getError();
    463        var getGLErrorAsString = error => {
    464            if (error === glInner.NO_ERROR) {
    465                return "NO_ERROR";
    466            }
    467            for (let name in glInner) {
    468                if (glInner[name] === error) {
    469                    return name;
    470                }
    471            }
    472            return error.toString();
    473        }
    474 
    475        if (err != glError) {
    476            ok(false, "getError expected: " + getGLErrorAsString(glError) +
    477                      ". Was " + getGLErrorAsString(err) + " : " + msg);
    478        } else {
    479            ok(true, "getError was expected value: " +
    480                     getGLErrorAsString(glError) + " : " + msg);
    481        }
    482    };
    483 
    484    canvas.width = width;
    485    canvas.height = height;
    486    gl.viewport(0, 0, width, height);
    487 
    488    var tex = gl.createTexture();
    489    gl.bindTexture(gl.TEXTURE_2D, tex);
    490    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    491    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    492    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    493    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    494    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
    495    glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
    496    gl.generateMipmap(gl.TEXTURE_2D);
    497    glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
    498    if (format == ext.COMPRESSED_SIGNED_R11_EAC) {
    499      var program = WebGLUtil.createProgramByIds(gl, 'vshader', 'fshader-r');
    500    } else if (format == ext.COMPRESSED_SIGNED_RG11_EAC) {
    501      var program = WebGLUtil.createProgramByIds(gl, 'vshader', 'fshader-rg');
    502    } else {
    503      var program = WebGLUtil.createProgramByIds(gl, 'vshader', 'fshader');
    504    }
    505    gl.bindAttribLocation(program, 0, 'vPosition');
    506    gl.bindAttribLocation(program, 1, 'texCoord0');
    507    gl.useProgram(program);
    508 
    509    gl.clearColor(1.0, 1.0, 1.0, 1.0);
    510    gl.clear(gl.COLOR_BUFFER_BIT);
    511    gl.drawArrays(gl.TRIANGLES, 0, 6);
    512    compareRect(width, height, test.channels, width, height, uncompressedData, data, format);
    513 
    514    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data);
    515    glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
    516 
    517    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data);
    518    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    519    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data);
    520    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    521    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data);
    522    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    523    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data);
    524    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    525 
    526    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
    527    glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
    528    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
    529    glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
    530    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
    531    glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
    532    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
    533    glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
    534 
    535    if (width == 4) {
    536        gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
    537        glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
    538        gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
    539        glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
    540    }
    541    if (height == 4) {
    542        gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
    543        glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
    544        gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
    545        glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
    546    }
    547 
    548    // pick a wrong format that uses the same amount of data.
    549    var wrongFormat;
    550    switch (format) {
    551    case ext.COMPRESSED_R11_EAC:
    552        wrongFormat = ext.COMPRESSED_SIGNED_R11_EAC;
    553        break;
    554    case ext.COMPRESSED_SIGNED_R11_EAC:
    555        wrongFormat = ext.COMPRESSED_R11_EAC;
    556        break;
    557    case ext.COMPRESSED_RG11_EAC:
    558        wrongFormat = ext.COMPRESSED_SIGNED_RG11_EAC;
    559        break;
    560    case ext.COMPRESSED_SIGNED_RG11_EAC:
    561        wrongFormat = ext.COMPRESSED_RG11_EAC;
    562        break;
    563    case ext.COMPRESSED_RGB8_ETC2:
    564        wrongFormat = ext.COMPRESSED_SRGB8_ETC2;
    565        break;
    566    case ext.COMPRESSED_SRGB8_ETC2:
    567        wrongFormat = ext.COMPRESSED_RGB8_ETC2;
    568        break;
    569    case ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
    570        wrongFormat = ext.COMPRESSED_RGB8_ETC2;
    571        break;
    572    case ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
    573        wrongFormat = ext.COMPRESSED_RGB8_ETC2;
    574        break;
    575    case ext.COMPRESSED_RGBA8_ETC2_EAC:
    576        wrongFormat = ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
    577        break;
    578    case ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
    579        wrongFormat = ext.COMPRESSED_RGBA8_ETC2_EAC;
    580        break;
    581    }
    582 
    583    // Restore original texture.
    584    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
    585    glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
    586 
    587    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data);
    588    glErrorShouldBe(gl, gl.INVALID_OPERATION, "format does not match");
    589 
    590    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width + 4, height, format, data);
    591    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    592    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height + 4, format, data);
    593    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    594    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 4, height, format, data);
    595    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    596    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 4, format, data);
    597    glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
    598 
    599    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
    600    glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
    601    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 1, height, format, data);
    602    glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
    603    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data);
    604    glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
    605    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 1, format, data);
    606    glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
    607    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data);
    608    glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
    609 
    610    var subData = new Uint8Array(data.buffer, 0, getBlockSize(format));
    611 
    612    if (width == 8 && height == 8) {
    613        gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 1, 0, 4, 4, format, subData);
    614        glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
    615        gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 1, 4, 4, format, subData);
    616        glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
    617    }
    618 
    619    if (width < 32 && height < 32) {
    620        var stride = width * 4;
    621        for (var yoff = 0; yoff < height; yoff += 4) {
    622            for (var xoff = 0; xoff < width; xoff += 4) {
    623                copyRect(uncompressedData, 0, 0, xoff, yoff, 4, 4, stride);
    624                gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, xoff, yoff, 4, 4, format, subData);
    625                glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
    626                gl.clearColor(1.0, 1.0, 1.0, 1.0);
    627                gl.clear(gl.COLOR_BUFFER_BIT);
    628                gl.drawArrays(gl.TRIANGLES, 0, 6);
    629                compareRect(width, height, test.channels, width, height, uncompressedData, data, format);
    630            }
    631        }
    632    }
    633 }
    634 
    635 function insertImg(element, caption, img) {
    636    var div = document.createElement("div");
    637    div.appendChild(img);
    638    var label = document.createElement("div");
    639    label.appendChild(document.createTextNode(caption));
    640    div.appendChild(label);
    641    element.appendChild(div);
    642 }
    643 
    644 function convertToSRGB(val) {
    645    var norm = val / 255.0;
    646    var res = 0;
    647    if (norm <= 0.04045) {
    648        res = norm / 12.92;
    649    } else {
    650        res = Math.pow(((norm + 0.055)/1.055), 2.4);
    651    }
    652 
    653    return res * 255.0;
    654 }
    655 
    656 function makeImage(imageWidth, imageHeight, dataWidth, data, alpha) {
    657    var scale = 8;
    658    var c = document.createElement("canvas");
    659    c.width = imageWidth * scale;
    660    c.height = imageHeight * scale;
    661    var ctx = c.getContext("2d");
    662    for (var yy = 0; yy < imageHeight; ++yy) {
    663        for (var xx = 0; xx < imageWidth; ++xx) {
    664            var offset = (yy * dataWidth + xx) * 4;
    665            ctx.fillStyle = "rgba(" +
    666                    data[offset + 0] + "," +
    667                    data[offset + 1] + "," +
    668                    data[offset + 2] + "," +
    669                    (alpha ? data[offset + 3] / 255 : 1) + ")";
    670            ctx.fillRect(xx * scale, yy * scale, scale, scale);
    671        }
    672    }
    673    var img = document.createElement("img");
    674    img.src = c.toDataURL();
    675    return img;
    676 }
    677 
    678 function compareRect(actualWidth, actualHeight, actualChannels,
    679                     dataWidth, dataHeight, expectedData,
    680                     testData, testFormat)
    681 {
    682    var actual = new Uint8Array(actualWidth * actualHeight * 4);
    683    gl.readPixels(
    684            0, 0, actualWidth, actualHeight, gl.RGBA, gl.UNSIGNED_BYTE, actual);
    685 
    686    var div = document.createElement("div");
    687    div.className = "testimages";
    688    var hasAlpha = actualChannels == 4;
    689    var imgExpected = makeImage(actualWidth, actualHeight, dataWidth, expectedData, hasAlpha);
    690    var imgActual = makeImage(actualWidth, actualHeight, actualWidth, actual, hasAlpha);
    691    insertImg(div, "expected", imgExpected);
    692    insertImg(div, "actual", imgActual);
    693    div.appendChild(document.createElement('br'));
    694    document.getElementById("console").appendChild(div);
    695 
    696    var failed = false;
    697    for (var yy = 0; yy < actualHeight; ++yy) {
    698        for (var xx = 0; xx < actualWidth; ++xx) {
    699            var actualOffset = (yy * actualWidth + xx) * 4;
    700            var expectedOffset = (yy * dataWidth + xx) * 4;
    701            var expected = expectedData.slice(expectedOffset, expectedOffset + 4);
    702 
    703            var maxDiffPixel = 0;
    704            switch (testFormat) {
    705              case ext.COMPRESSED_SRGB8_ETC2:
    706              case ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
    707              case ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
    708 
    709                  // Alpha shouldn't do conversion.
    710                  for (var i = 0; i < 3; ++i) {
    711                      expected[i] = convertToSRGB(expected[i]);
    712                  }
    713                  //fallthrough
    714              case ext.COMPRESSED_R11_EAC:
    715              case ext.COMPRESSED_RG11_EAC:
    716              case ext.COMPRESSED_SIGNED_R11_EAC:
    717              case ext.COMPRESSED_SIGNED_RG11_EAC:
    718                  // Due to floating round error, we need fuzzy test here.
    719                  var maxDiffPixel = 1;
    720                  break;
    721              default:
    722                  var maxDiffPixel = 0;
    723                  break;
    724            }
    725 
    726            for (var channel = 0; channel < actualChannels; ++channel) {
    727                var diff = Math.abs(expected[channel] - actual[actualOffset + channel]);
    728 
    729                if (diff > maxDiffPixel) {
    730                    failed = true;
    731                    var was = actual.slice(actualOffset, actualOffset + 4).join();
    732                    ok(false, 'at (' + xx + ', ' + yy +
    733                              ') expected: ' + expected.join() + ' was ' + was);
    734                    break;
    735                }
    736            }
    737        }
    738    }
    739    if (!failed) {
    740        ok(true, "texture rendered correctly");
    741    }
    742 }
    743 
    744 var prefArrArr = [
    745  ['webgl.enable-draft-extensions', true],
    746 ];
    747 var prefEnv = {'set': prefArrArr};
    748 SimpleTest.waitForExplicitFinish();
    749 SpecialPowers.pushPrefEnv(prefEnv, runTest);
    750 </script>
    751 </body>
    752 </html>