summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance/extensions
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt46
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays-out-of-bounds.html56
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays.html723
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-blend-minmax.html225
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-color-buffer-half-float.html27
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html312
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-float-blend.html98
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-frag-depth.html289
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html468
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-shader-texture-lod.html341
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-bptc.html159
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html162
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-filter-anisotropic.html26
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/get-extension.html99
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html220
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-element-index-uint.html428
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-fbo-render-mipmap.html92
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-standard-derivatives.html444
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-linear.html42
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-canvas.html34
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image-data.html35
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image.html34
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html39
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html426
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-linear.html46
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-canvas.html39
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image-data.html40
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image.html39
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html44
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float.html474
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object-bufferData.html194
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html780
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/s3tc-and-rgtc.html1066
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-astc.html2524
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc.html126
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc1.html74
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-pvrtc.html371
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc-srgb.html912
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-size-limit.html35
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-renderer-info.html104
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-shaders.html144
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html377
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-broadcast-return.html138
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-framebuffer-unsupported.html126
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-max-draw-buffers.html118
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers.html812
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-multi-draw.html1064
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-webcodecs-video-frame.html211
48 files changed, 14683 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt
new file mode 100644
index 0000000000..9a72b67ef0
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt
@@ -0,0 +1,46 @@
+--min-version 1.0.3 --max-version 1.9.9 angle-instanced-arrays.html
+--min-version 1.0.3 --max-version 1.9.9 angle-instanced-arrays-out-of-bounds.html
+--min-version 1.0.3 --max-version 1.9.9 ext-blend-minmax.html
+--min-version 1.0.4 ext-color-buffer-half-float.html
+--min-version 1.0.4 ext-float-blend.html
+--min-version 1.0.4 ext-texture-compression-bptc.html
+--min-version 1.0.4 ext-texture-compression-rgtc.html
+--min-version 1.0.4 ext-disjoint-timer-query.html
+--min-version 1.0.3 --max-version 1.9.9 ext-frag-depth.html
+--min-version 1.0.3 --max-version 1.9.9 ext-shader-texture-lod.html
+--min-version 1.0.3 --max-version 1.9.9 ext-sRGB.html
+--min-version 1.0.2 ext-texture-filter-anisotropic.html
+--min-version 1.0.2 get-extension.html
+--min-version 1.0.4 khr-parallel-shader-compile.html
+--max-version 1.9.9 oes-standard-derivatives.html
+--max-version 1.9.9 oes-texture-float-with-canvas.html
+--max-version 1.9.9 oes-texture-float-with-image-data.html
+--max-version 1.9.9 oes-texture-float-with-image.html
+--max-version 1.9.9 oes-texture-float-with-video.html
+--max-version 1.9.9 oes-texture-float.html
+--max-version 1.9.9 oes-vertex-array-object.html
+--min-version 1.0.3 --max-version 1.9.9 oes-vertex-array-object-bufferData.html
+--min-version 1.0.3 --max-version 1.9.9 oes-texture-half-float.html
+--min-version 1.0.3 oes-texture-float-linear.html
+--min-version 1.0.3 --max-version 1.9.9 oes-texture-half-float-linear.html
+--min-version 1.0.3 --max-version 1.9.9 oes-texture-half-float-with-canvas.html
+--min-version 1.0.3 --max-version 1.9.9 oes-texture-half-float-with-image-data.html
+--min-version 1.0.3 --max-version 1.9.9 oes-texture-half-float-with-image.html
+--min-version 1.0.3 --max-version 1.9.9 oes-texture-half-float-with-video.html
+--min-version 1.0.2 --max-version 1.9.9 oes-element-index-uint.html
+--min-version 1.0.4 --max-version 1.9.9 oes-fbo-render-mipmap.html
+webgl-debug-renderer-info.html
+webgl-debug-shaders.html
+--min-version 1.0.4 webgl-compressed-texture-astc.html
+--min-version 1.0.4 webgl-compressed-texture-etc.html
+--min-version 1.0.4 webgl-compressed-texture-etc1.html
+--min-version 1.0.3 webgl-compressed-texture-pvrtc.html
+--min-version 1.0.4 s3tc-and-rgtc.html
+--min-version 1.0.4 webgl-compressed-texture-s3tc-srgb.html
+--min-version 1.0.3 webgl-compressed-texture-size-limit.html
+--min-version 1.0.2 --max-version 1.9.9 webgl-depth-texture.html
+--min-version 1.0.3 --max-version 1.9.9 webgl-draw-buffers.html
+--min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-broadcast-return.html
+--min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-framebuffer-unsupported.html
+--min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-max-draw-buffers.html
+--min-version 1.0.4 webgl-multi-draw.html
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays-out-of-bounds.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays-out-of-bounds.html
new file mode 100644
index 0000000000..64a063854e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays-out-of-bounds.html
@@ -0,0 +1,56 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/out-of-bounds-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("Test of drawArraysInstancedANGLE and drawElementsInstancedANGLE with out-of-bounds parameters");
+
+var wtu = WebGLTestUtils;
+
+var gl = wtu.create3DContext();
+var ext = wtu.getExtensionWithKnownPrefixes(gl, "ANGLE_instanced_arrays");
+if (!ext) {
+ testPassed("No ANGLE_instanced_arrays support -- this is legal");
+} else {
+ testPassed("Successfully enabled ANGLE_instanced_arrays extension");
+ debug("");
+ debug("Test with 1 instance without instanced attributes");
+ debug("");
+ OutOfBoundsTest.runDrawArraysTest("ext.drawArraysInstancedANGLE(gl.TRIANGLES, $(offset), $(count), 1)", gl, wtu, ext);
+ debug("");
+ OutOfBoundsTest.runDrawElementsTest("ext.drawElementsInstancedANGLE(gl.TRIANGLES, $(count), $(type), $(offset), 1)", gl, wtu, ext);
+ debug("");
+ debug("Test with 2 instances without instanced attributes");
+ debug("");
+ OutOfBoundsTest.runDrawArraysTest("ext.drawArraysInstancedANGLE(gl.TRIANGLES, $(offset), $(count), 2)", gl, wtu, ext);
+ debug("");
+ OutOfBoundsTest.runDrawElementsTest("ext.drawElementsInstancedANGLE(gl.TRIANGLES, $(count), $(type), $(offset), 2)", gl, wtu, ext);
+ debug("");
+ OutOfBoundsTest.runDrawArraysInstancedTest("ext.drawArraysInstancedANGLE(gl.TRIANGLES, $(offset), $(count), $(primcount))", gl, wtu, ext);
+ debug("");
+ OutOfBoundsTest.runDrawElementsInstancedTest("ext.drawElementsInstancedANGLE(gl.TRIANGLES, $(count), $(type), $(offset), $(primcount))", gl, wtu, ext);
+ debug("");
+}
+
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays.html
new file mode 100644
index 0000000000..f96c732bb2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/angle-instanced-arrays.html
@@ -0,0 +1,723 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL ANGLE_instanced_arrays Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/desktop-gl-constants.js"></script>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compositing-test.js"></script>
+<script src="../../js/tests/invalid-vertex-attrib-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing instanced draws -->
+<script id="outputVertexShader" type="x-shader/x-vertex">
+attribute vec4 aPosition;
+attribute vec2 aOffset;
+attribute vec4 aColor;
+varying vec4 vColor;
+void main() {
+ vColor = aColor;
+ gl_Position = aPosition + vec4(aOffset, 0.0, 0.0);
+}
+</script>
+
+<script id="outputFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+varying vec4 vColor;
+void main() {
+ gl_FragColor = vColor;
+}
+</script>
+
+<script id="drawArraysTestVertexShader" type="x-shader/x-vertex">
+attribute vec3 aPosition;
+attribute vec3 aInstancePos;
+uniform vec3 uOffset;
+void main() {
+ gl_Position = vec4(aPosition.xyz + aInstancePos.xyz + uOffset, 1.0);
+}
+</script>
+
+<script id="drawArraysTestFragmentShader" type="x-shader/x-fragment">
+void main() {
+ gl_FragColor = vec4(1.0, 0, 0, 1.0);
+}
+</script>
+
+<script>
+"use strict";
+description("This test verifies the functionality of the ANGLE_instanced_arrays extension, if it is available.");
+
+debug("");
+
+const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+var vaoext = null;
+
+var positionLoc = 0;
+var offsetLoc = 2;
+var colorLoc = 3;
+var program;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+ finishTest();
+} else {
+ testPassed("WebGL context exists");
+
+ runDivisorTestDisabled();
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "ANGLE_instanced_arrays");
+ if (!ext) {
+ testPassed("No ANGLE_instanced_arrays support -- this is legal");
+
+ runSupportedTest(false);
+ finishTest();
+ } else {
+ testPassed("Successfully enabled ANGLE_instanced_arrays extension");
+
+ (async function() {
+ runSupportedTest(true);
+
+ runDivisorTestEnabled();
+ runUniqueObjectTest();
+
+ setupCanvas();
+ runOutputTests();
+ runDrawArraysWithOffsetTest();
+ runVAOInstancingInteractionTest();
+ await runANGLECorruptionTest();
+ await runInvalidAttribTests(gl);
+ await runCompositingTests();
+ finishTest();
+ }());
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("ANGLE_instanced_arrays") >= 0) {
+ if (extensionEnabled) {
+ testPassed("ANGLE_instanced_arrays listed as supported and getExtension succeeded");
+ } else {
+ testFailed("ANGLE_instanced_arrays listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("ANGLE_instanced_arrays not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("ANGLE_instanced_arrays not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runDivisorTestDisabled() {
+ debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension disabled");
+
+ var VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+
+ gl.getVertexAttrib(0, VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should not be queryable if extension is disabled");
+}
+
+function runDivisorTestEnabled() {
+ debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension enabled");
+
+ shouldBe("ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", "0x88FE");
+
+ var max_vertex_attribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+
+ for (var i = 0; i < max_vertex_attribs; ++i) {
+ var queried_value = gl.getVertexAttrib(i, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
+ if(queried_value == 0){
+ testPassed("Vertex attribute " + i + " must has a default divisor of 0");
+ }
+ else{
+ testFailed("Default divisor of vertex attribute " + i + " should be: 0, returned value was: " + queried_value);
+ }
+ }
+
+ ext.vertexAttribDivisorANGLE(max_vertex_attribs, 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "vertexAttribDivisorANGLE index set greater than or equal to MAX_VERTEX_ATTRIBS should be an invalid value");
+
+ ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertexAttribDivisorANGLE index set less than MAX_VERTEX_ATTRIBS should succeed");
+
+ var queried_value = gl.getVertexAttrib(max_vertex_attribs-1, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
+ if(queried_value == 2){
+ testPassed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE matches expecation");
+ }
+ else{
+ testFailed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should be: 2, returned value was: " + queried_value);
+ }
+
+ // Reset vertex attrib divisors so they cannot affect following subtests.
+ ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 0);
+}
+
+function setupCanvas() {
+ canvas.width = 50; canvas.height = 50;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+ gl.clearColor(0, 0, 0, 0);
+
+ program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['aPosition', 'aOffset', 'aColor'], [positionLoc, offsetLoc, colorLoc]);
+ ext = gl.getExtension("ANGLE_instanced_arrays");
+}
+
+function runOutputTests() {
+ var instanceCount = 4;
+
+ debug("Testing various draws for valid built-in function behavior");
+
+ var offsets = new Float32Array([
+ -1.0, 1.0,
+ 1.0, 1.0,
+ -1.0, -1.0,
+ 1.0, -1.0,
+ ]);
+ var offsetBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(offsetLoc);
+ gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0);
+ ext.vertexAttribDivisorANGLE(offsetLoc, 1);
+
+ var colors = new Float32Array([
+ 1.0, 0.0, 0.0, 1.0, // Red
+ 0.0, 1.0, 0.0, 1.0, // Green
+ 0.0, 0.0, 1.0, 1.0, // Blue
+ 1.0, 1.0, 0.0, 1.0, // Yellow
+ // extra data when colorLoc divisor is set back to 0
+ 1.0, 1.0, 0.0, 1.0, // Yellow
+ 1.0, 1.0, 0.0, 1.0, // Yellow
+ ]);
+ var colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(colorLoc);
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
+ ext.vertexAttribDivisorANGLE(colorLoc, 1);
+
+ wtu.setupUnitQuad(gl, 0);
+
+ // Draw 1: Regular drawArrays
+ debug("");
+ debug("Testing drawArrays with non-zero divisor");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertex attrib divisor should affect regular drawArrays when the extension is enabled");
+ wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
+
+ // Draw 2: Draw Non-indexed instances
+ debug("");
+ debug("Testing drawArraysInstancedANGLE");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ // Test drawArraysInstancedANGLE error conditions
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
+ wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]);
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]);
+ wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
+
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, -1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a primcount less than 0");
+
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, -1, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a count less than 0");
+
+ ext.vertexAttribDivisorANGLE(positionLoc, 1);
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawArraysInstancedANGLE");
+ ext.vertexAttribDivisorANGLE(positionLoc, 0);
+
+ ext.drawArraysInstancedANGLE(gl.POINTS, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with POINTS should succeed");
+ ext.drawArraysInstancedANGLE(gl.LINES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINES should succeed");
+ ext.drawArraysInstancedANGLE(gl.LINE_LIST, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINE_LIST should return succeed");
+ ext.drawArraysInstancedANGLE(gl.TRIANGLE_LIST, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with TRIANGLE_LIST should succeed");
+
+ ext.drawArraysInstancedANGLE(desktopGL['QUAD_STRIP'], 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUAD_STRIP should return INVALID_ENUM");
+ ext.drawArraysInstancedANGLE(desktopGL['QUADS'], 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUADS should return INVALID_ENUM");
+ ext.drawArraysInstancedANGLE(desktopGL['POLYGON'], 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with POLYGON should return INVALID_ENUM");
+
+ debug("");
+ debug("Testing drawArraysInstancedANGLE with param 'first' > 0");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.setupQuad(gl, {
+ positionLocation: 0,
+ scale: 0.5
+ });
+ var offsetsHalf = new Float32Array([
+ -0.5, 0.5,
+ 0.5, 0.5,
+ -0.5, -0.5,
+ 0.5, -0.5
+ ]);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, offsetsHalf, gl.STATIC_DRAW);
+
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 3, 3, instanceCount);
+ var w = Math.floor(0.25*canvas.width),
+ h = Math.floor(0.25*canvas.height);
+ wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 0, 0, 255]);
+ wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [0, 255, 0, 255]);
+ wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [0, 0, 255, 255]);
+ wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
+
+ debug("");
+ debug("Testing drawArraysInstancedANGLE with attributes 'divisor' reset to 0");
+ debug("Correct rendering output: 4 yellow triangles");
+ debug("Possible incorrect rendering output: missing triangles, or triangles with different color at each vertex");
+ ext.vertexAttribDivisorANGLE(colorLoc, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 3, 3, instanceCount);
+ wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
+ wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
+ wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [255, 255, 0, 255]);
+ wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
+ ext.vertexAttribDivisorANGLE(colorLoc, 1);
+
+ wtu.setupUnitQuad(gl, 0);
+ wtu.setupIndexedQuad(gl, 1, 0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
+
+ // Draw 3: Regular drawElements
+ debug("");
+ debug("Testing drawElements with non-zero divisor");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ // Point to another location in the buffer so that the draw would overflow without the divisor
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 48);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertex attrib divisor should affect regular drawElements when the extension is enabled");
+ wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
+ // Restore the vertex attrib pointer
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
+
+ // Draw 4: Draw indexed instances
+ debug("");
+ debug("Testing drawElementsInstancedANGLE");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
+ wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]);
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]);
+ wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
+
+ // Test drawElementsInstancedANGLE error conditions
+ ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, -1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a primcount less than 0");
+
+ ext.drawElementsInstancedANGLE(gl.TRIANGLES, -1, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a count less than 0");
+
+ ext.vertexAttribDivisorANGLE(positionLoc, 1);
+ ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawElementsInstancedANGLE");
+ ext.vertexAttribDivisorANGLE(positionLoc, 0);
+
+ ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with UNSIGNED_BYTE should succeed");
+
+ ext.drawElementsInstancedANGLE(gl.POINTS, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with POINTS should succeed");
+ ext.drawElementsInstancedANGLE(gl.LINES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINES should succeed");
+ ext.drawElementsInstancedANGLE(gl.LINE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINE_LIST should return succeed");
+ ext.drawElementsInstancedANGLE(gl.TRIANGLE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with TRIANGLE_LIST should succeed");
+
+ ext.drawElementsInstancedANGLE(desktopGL['QUAD_STRIP'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUAD_STRIP should return INVALID_ENUM");
+ ext.drawElementsInstancedANGLE(desktopGL['QUADS'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUADS should return INVALID_ENUM");
+ ext.drawElementsInstancedANGLE(desktopGL['POLYGON'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with POLYGON should return INVALID_ENUM");
+
+ // Reset vertex attrib divisors so they cannot affect following subtests.
+ ext.vertexAttribDivisorANGLE(colorLoc, 0);
+ ext.vertexAttribDivisorANGLE(offsetLoc, 0);
+}
+
+function runDrawArraysTest(program, first, count, instanceCount, offset)
+{
+ // Get the attribute and uniform locations
+ var positionLoc = gl.getAttribLocation(program, "aPosition");
+ var instancePosLoc = gl.getAttribLocation(program, "aInstancePos");
+ var uniformLoc = gl.getUniformLocation(program, "uOffset");
+
+ // Load the vertex positions
+ var positions = new Float32Array([
+ -1, -1,
+ -1, 0,
+ 0, 0,
+
+ 0, 0,
+ 0, -1,
+ -1, -1,
+
+ 1, -1,
+ 1, 0,
+ 0, 0,
+
+ 0, 0,
+ 0, -1,
+ 1, -1,
+ ]);
+ var positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(positionLoc);
+ gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
+
+ // Load the instance positions
+ var instancePositions = new Float32Array([
+ 0, 0,
+ 1, 0
+ ]);
+ var instancePositionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, instancePositionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, instancePositions, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(instancePosLoc);
+ gl.vertexAttribPointer(instancePosLoc, 2, gl.FLOAT, false, 0, 0);
+
+ // Enable instancing
+ ext.vertexAttribDivisorANGLE(instancePosLoc, 1);
+
+ // Offset
+ gl.uniform3fv(uniformLoc, offset);
+
+ // Do the instanced draw
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, first, count, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE should succeed");
+
+ // Reset vertex attrib divisors so they cannot affect following subtests.
+ ext.vertexAttribDivisorANGLE(instancePosLoc, 0);
+}
+
+function runDrawArraysWithOffsetTest()
+{
+ debug("");
+ debug("Testing that the 'first' parameter to drawArraysInstancedANGLE is only an offset into the non-instanced vertex attributes.");
+ // See: http://crbug.com/457269 and http://crbug.com/447140
+
+ var drawArraysProgram = wtu.setupProgram(gl, ["drawArraysTestVertexShader", "drawArraysTestFragmentShader"]);
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ runDrawArraysTest(drawArraysProgram, 0, 6, 2, [0, 0, 0]);
+
+ runDrawArraysTest(drawArraysProgram, 6, 6, 2, [-1, 1, 0]);
+
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
+}
+
+function runUniqueObjectTest()
+{
+ debug("");
+ debug("Testing that getExtension() returns the same object each time");
+ ext = null;
+ gl.getExtension("ANGLE_instanced_arrays").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("ANGLE_instanced_arrays").myProperty', '2');
+}
+
+function runVAOInstancingInteractionTest()
+{
+ debug("")
+ debug("Testing that ANGLE_instanced_arrays interacts correctly with OES_vertex_array_object if present");
+ // See: https://github.com/KhronosGroup/WebGL/issues/1228
+
+ // Query the extension and store globally so shouldBe can access it
+ vaoext = gl.getExtension("OES_vertex_array_object");
+ if (!vaoext) {
+ testPassed("No OES_vertex_array_object support -- this is legal");
+ return;
+ }
+
+ testPassed("Successfully enabled OES_vertex_array_object extension");
+
+ gl.useProgram(program);
+
+ var positions = new Float32Array([
+ 0.0, 1.0, // Left quad
+ -1.0, 1.0,
+ -1.0, -1.0,
+ 0.0, 1.0,
+ -1.0, -1.0,
+ 0.0, -1.0,
+
+ 1.0, 1.0, // Right quad
+ 0.0, 1.0,
+ 0.0, -1.0,
+ 1.0, 1.0,
+ 0.0, -1.0,
+ 1.0, -1.0
+ ]);
+ var positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
+
+ var colors = new Float32Array([
+ 1.0, 0.0, 0.0, 1.0, // Red
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+
+ 0.0, 0.0, 1.0, 1.0, // Blue
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ ]);
+ var colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+
+ // Reset the divisor of the default VAO to 0
+ ext.vertexAttribDivisorANGLE(colorLoc, 0);
+
+ // Set up VAO with an attrib divisor
+ var vao1 = vaoext.createVertexArrayOES();
+ vaoext.bindVertexArrayOES(vao1);
+ {
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.enableVertexAttribArray(positionLoc);
+ gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.enableVertexAttribArray(colorLoc);
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
+ ext.vertexAttribDivisorANGLE(colorLoc, 1);
+
+ gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]);
+ }
+ vaoext.bindVertexArrayOES(null);
+
+ // Set up VAO with no attrib divisor
+ var vao2 = vaoext.createVertexArrayOES();
+ vaoext.bindVertexArrayOES(vao2);
+ {
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.enableVertexAttribArray(positionLoc);
+ gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.enableVertexAttribArray(colorLoc);
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
+ // Note that no divisor is set here, which implies that it's 0
+
+ gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]);
+ }
+ vaoext.bindVertexArrayOES(null);
+
+ debug("");
+ debug("Ensure that Vertex Array Objects retain attrib divisors");
+
+ vaoext.bindVertexArrayOES(vao1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 12);
+ // If the divisor is properly managed by the VAO a single red quad will be drawn
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "entire canvas should be red");
+
+ vaoext.bindVertexArrayOES(vao2);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 12);
+ // If the divisor is properly managed by the VAO a red and blue quad will be drawn.
+ wtu.checkCanvasRects(gl, [
+ wtu.makeCheckRect(0, 0, canvas.width * 0.5, canvas.height, [255, 0, 0, 255], "left half of canvas should be red", 1),
+ wtu.makeCheckRect(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height, [0, 0, 255, 255], "right half of canvas should be blue", 1)
+ ]);
+
+ vaoext.bindVertexArrayOES(null);
+}
+
+async function runANGLECorruptionTest()
+{
+ debug("")
+ debug("Testing to ensure that rendering isn't corrupt due to an ANGLE bug");
+ // See: https://code.google.com/p/angleproject/issues/detail?id=467
+
+ setupCanvas();
+
+ var tolerance = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
+ var instanceCount = 10; // Must be higher than 6
+
+ var offsets = new Float32Array([
+ 0.0, 0.0,
+ 0.2, 0.0,
+ 0.4, 0.0,
+ 0.6, 0.0,
+ 0.8, 0.0,
+ 1.0, 0.0,
+ 1.2, 0.0,
+ 1.4, 0.0,
+ 1.6, 0.0,
+ 1.8, 0.0,
+ ]);
+ var offsetBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, offsets.byteLength * 2, gl.STATIC_DRAW);
+ gl.bufferSubData(gl.ARRAY_BUFFER, 0, offsets);
+ gl.enableVertexAttribArray(offsetLoc);
+ gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0);
+ ext.vertexAttribDivisorANGLE(offsetLoc, 1);
+
+ var colors = new Float32Array([
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ 1.0, 0.0, 1.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 1.0, 1.0,
+ ]);
+ var colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors.byteLength * 2, gl.STATIC_DRAW);
+ gl.bufferSubData(gl.ARRAY_BUFFER, 0, colors);
+ gl.enableVertexAttribArray(colorLoc);
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
+ ext.vertexAttribDivisorANGLE(colorLoc, 1);
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.setupUnitQuad(gl, 0);
+
+ const totalIterations = 10;
+ for (let iteration = 0; iteration < totalIterations; ++iteration)
+ {
+ // Update the instanced data buffers outside the accessed range.
+ // This, plus rendering more instances than vertices, triggers the bug.
+ var nullData = new Float32Array(offsets.length);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
+ gl.bufferSubData(gl.ARRAY_BUFFER, offsets.byteLength, nullData);
+
+ nullData = new Float32Array(colors.length);
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferSubData(gl.ARRAY_BUFFER, colors.byteLength, nullData);
+
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
+
+ // Make sure each color was drawn correctly
+ var i;
+ var passed = true;
+ for (i = 0; i < instanceCount; ++i) {
+ var w = canvas.width / instanceCount;
+ var x = w * i;
+ var color = [colors[(i*4)] * 255, colors[(i*4)+1] * 255, colors[(i*4)+2] * 255, 255]
+
+ wtu.checkCanvasRectColor(
+ gl, x, 0, w, canvas.height, color, tolerance,
+ function() {},
+ function() {
+ passed = false;
+ }, debug);
+ }
+
+ if (passed) {
+ testPassed("Passed test " + iteration + " of " + totalIterations);
+ } else {
+ testFailed("Failed test " + iteration + " of " + totalIterations);
+ break;
+ }
+ await wait();
+ }
+ ext.vertexAttribDivisorANGLE(offsetLoc, 0);
+ ext.vertexAttribDivisorANGLE(colorLoc, 0);
+}
+
+async function runDrawTests(testFn) {
+ function drawArrays(gl) {
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ }
+
+ function drawElements(gl) {
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
+ }
+
+ function drawArraysInstancedANGLE(gl) {
+ const ext = gl.getExtension('ANGLE_instanced_arrays');
+ if (!ext) {
+ return true;
+ }
+
+ ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, 1);
+ }
+
+ function drawElementsInstancedANGLE(gl) {
+ const ext = gl.getExtension('ANGLE_instanced_arrays');
+ if (!ext) {
+ return true;
+ }
+
+ ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, 1);
+ }
+
+ await testFn(drawArrays); // sanity check
+ await testFn(drawElements); // sanity check
+
+ await testFn(drawArraysInstancedANGLE);
+ await testFn(drawElementsInstancedANGLE);
+}
+
+async function runCompositingTests() {
+ const compositingTestFn = createCompositingTestFn({
+ webglVersion: 1,
+ shadersFn(gl) {
+ const vs = `\
+ attribute vec4 position;
+ void main() {
+ gl_Position = position;
+ }
+ `;
+ const fs = `\
+ precision mediump float;
+ void main() {
+ gl_FragColor = vec4(1, 0, 0, 1);
+ }
+ `;
+ return [vs, fs];
+ },
+ });
+ await runDrawTests(compositingTestFn);
+}
+
+async function runInvalidAttribTests(gl) {
+ const invalidAttribTestFn = createInvalidAttribTestFn(gl);
+ await runDrawTests(invalidAttribTestFn);
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-blend-minmax.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-blend-minmax.html
new file mode 100644
index 0000000000..445dcb92d4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-blend-minmax.html
@@ -0,0 +1,225 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_blend_minmax Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders to test output -->
+<script id="outputVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+void main() {
+ gl_Position = vPosition;
+}
+</script>
+<script id="outputFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+uniform vec4 uColor;
+void main() {
+ gl_FragColor = uColor;
+}
+</script>
+
+<script>
+"use strict";
+description("This test verifies the functionality of the EXT_blend_minmax extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+
+// Use the constant directly when we don't have the extension
+var MIN_EXT = 0x8007;
+var MAX_EXT = 0x8008;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ runBlendTestDisabled();
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "EXT_blend_minmax");
+ if (!ext) {
+ testPassed("No EXT_blend_minmax support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ debug("");
+ testPassed("Successfully enabled EXT_blend_minmax extension");
+
+ runSupportedTest(true);
+
+ runBlendTestEnabled();
+ runOutputTests();
+ runUniqueObjectTest();
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("EXT_blend_minmax") >= 0) {
+ if (extensionEnabled) {
+ testPassed("EXT_blend_minmax listed as supported and getExtension succeeded");
+ } else {
+ testFailed("EXT_blend_minmax listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("EXT_blend_minmax not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("EXT_blend_minmax not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runBlendTestDisabled() {
+ debug("");
+ debug("Testing blending enums with extension disabled");
+
+ // Set the blend equation to a known-good enum first
+ gl.blendEquation(gl.FUNC_ADD);
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.blendEquation(MIN_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION)", "gl.FUNC_ADD");
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.blendEquation(MAX_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION)", "gl.FUNC_ADD");
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.blendEquationSeparate(MIN_EXT, gl.FUNC_ADD)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_RGB)", "gl.FUNC_ADD");
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.blendEquationSeparate(gl.FUNC_ADD, MIN_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_ALPHA)", "gl.FUNC_ADD");
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.blendEquationSeparate(MAX_EXT, gl.FUNC_ADD)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_RGB)", "gl.FUNC_ADD");
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.blendEquationSeparate(gl.FUNC_ADD, MAX_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_ALPHA)", "gl.FUNC_ADD");
+}
+
+function runBlendTestEnabled() {
+ debug("");
+ debug("Testing blending enums with extension enabled");
+
+ shouldBe("ext.MIN_EXT", "0x8007");
+ shouldBe("ext.MAX_EXT", "0x8008");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendEquation(ext.MIN_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION)", "ext.MIN_EXT");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendEquation(ext.MAX_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION)", "ext.MAX_EXT");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendEquationSeparate(ext.MIN_EXT, gl.FUNC_ADD)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_RGB)", "ext.MIN_EXT");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_ALPHA)", "gl.FUNC_ADD");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendEquationSeparate(gl.FUNC_ADD, ext.MIN_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_RGB)", "gl.FUNC_ADD");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_ALPHA)", "ext.MIN_EXT");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendEquationSeparate(ext.MAX_EXT, gl.FUNC_ADD)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_RGB)", "ext.MAX_EXT");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_ALPHA)", "gl.FUNC_ADD");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendEquationSeparate(gl.FUNC_ADD, ext.MAX_EXT)");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_RGB)", "gl.FUNC_ADD");
+ shouldBe("gl.getParameter(gl.BLEND_EQUATION_ALPHA)", "ext.MAX_EXT");
+}
+
+function runOutputTests() {
+ var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
+
+ debug("");
+ debug("Testing various draws for valid blending behavior");
+
+ canvas.width = 50; canvas.height = 50;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.ONE, gl.ONE);
+
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['vPosition'], [0]);
+ var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
+ var colorUniform = gl.getUniformLocation(program, "uColor");
+
+
+ // Draw 1
+ gl.blendEquation(ext.MIN_EXT);
+
+ gl.clearColor(0.2, 0.4, 0.6, 0.8);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.uniform4f(colorUniform, 0.8, 0.6, 0.4, 0.2);
+ wtu.drawUnitQuad(gl);
+
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [51, 102, 102, 51]);
+
+ // Draw 2:
+ gl.blendEquation(ext.MAX_EXT);
+
+ gl.clearColor(0.2, 0.4, 0.6, 0.8);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.uniform4f(colorUniform, 0.8, 0.6, 0.4, 0.2);
+ wtu.drawUnitQuad(gl);
+
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [204, 153, 153, 204]);
+
+ // Draw 3
+ gl.blendEquationSeparate(ext.MIN_EXT, ext.MAX_EXT);
+
+ gl.clearColor(0.2, 0.4, 0.6, 0.8);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.uniform4f(colorUniform, 0.8, 0.6, 0.4, 0.2);
+ wtu.drawUnitQuad(gl);
+
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [51, 102, 102, 204]);
+
+ // Draw 4
+ gl.blendEquationSeparate(ext.MAX_EXT, ext.MIN_EXT);
+
+ gl.clearColor(0.2, 0.4, 0.6, 0.8);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.uniform4f(colorUniform, 0.8, 0.6, 0.4, 0.2);
+ wtu.drawUnitQuad(gl);
+
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [204, 153, 153, 51]);
+}
+
+function runUniqueObjectTest()
+{
+ debug("");
+ debug("Testing that getExtension() returns the same object each time");
+ ext = null;
+ gl.getExtension("EXT_blend_minmax").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("EXT_blend_minmax").myProperty', '2');
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-color-buffer-half-float.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-color-buffer-half-float.html
new file mode 100644
index 0000000000..752fe98e45
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-color-buffer-half-float.html
@@ -0,0 +1,27 @@
+<!--
+Copyright (c) 2020 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_color_buffer_half_float Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head> 
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<script>
+var version = 1;
+</script>
+<script src="../../js/tests/ext-color-buffer-half-float.js"></script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html
new file mode 100644
index 0000000000..1fc29cc445
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html
@@ -0,0 +1,312 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_disjoint_timer_query Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("This test verifies the functionality of the EXT_disjoint_timer_query extension, if it is available.");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+var query = null;
+var query2 = null;
+var elapsed_query = null;
+var timestamp_query1 = null;
+var timestamp_query2 = null;
+var availability_retry = 500;
+var timestamp_counter_bits = 0;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+ finishTest();
+} else {
+ testPassed("WebGL context exists");
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "EXT_disjoint_timer_query");
+ if (!ext) {
+ testPassed("No EXT_disjoint_timer_query support -- this is legal");
+ finishTest();
+ } else {
+ if (wtu.getDefault3DContextVersion() > 1) {
+ testFailed("EXT_disjoint_timer_query must not be advertised on WebGL 2.0 contexts");
+ finishTest();
+ } else {
+ runSanityTests();
+
+ // Clear disjoint value.
+ gl.getParameter(ext.GPU_DISJOINT_EXT);
+
+ runElapsedTimeTest();
+ timestamp_counter_bits = ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT);
+ if (timestamp_counter_bits > 0) {
+ runTimeStampTest();
+ }
+ verifyQueryResultsNotAvailable();
+
+ window.requestAnimationFrame(checkQueryResults);
+ }
+ }
+}
+
+function runSanityTests() {
+ debug("");
+ debug("Testing timer query expectations");
+
+ shouldBe("ext.QUERY_COUNTER_BITS_EXT", "0x8864");
+ shouldBe("ext.CURRENT_QUERY_EXT", "0x8865");
+ shouldBe("ext.QUERY_RESULT_EXT", "0x8866");
+ shouldBe("ext.QUERY_RESULT_AVAILABLE_EXT", "0x8867");
+ shouldBe("ext.TIME_ELAPSED_EXT", "0x88BF");
+ shouldBe("ext.TIMESTAMP_EXT", "0x8E28");
+ shouldBe("ext.GPU_DISJOINT_EXT", "0x8FBB");
+
+ shouldBe("ext.isQueryEXT(null)", "false");
+
+ shouldBeTrue("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT) === null");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBeTrue("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ shouldBeTrue("ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.CURRENT_QUERY_EXT) === null");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ // Certain drivers set timestamp counter bits to 0 as they don't support timestamps
+ shouldBeTrue("ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30 || " +
+ "ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) === 0");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Testing time elapsed query lifecycle");
+ query = ext.createQueryEXT();
+ shouldBe("ext.isQueryEXT(query)", "false");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query creation must succeed.");
+ shouldThrow("ext.beginQueryEXT(ext.TIMESTAMP_EXT, null)");
+ ext.beginQueryEXT(ext.TIMESTAMP_EXT, query);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Beginning a timestamp query should fail.");
+ ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);
+ shouldBe("ext.isQueryEXT(query)", "true");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Beginning an inactive time elapsed query should succeed.");
+ ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Attempting to begin an active query should fail.");
+ ext.getQueryObjectEXT(query, ext.QUERY_RESULT_AVAILABLE_EXT);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Fetching query result availability of an active query should fail.");
+ ext.getQueryObjectEXT(query, ext.QUERY_RESULT_EXT);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Fetching query result of an active query should fail.");
+ shouldBe("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT)", "query");
+ ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Ending an active time elapsed query should succeed.");
+ shouldThrow("ext.getQueryObjectEXT(null, ext.QUERY_RESULT_AVAILABLE_EXT)");
+ ext.getQueryObjectEXT(query, ext.QUERY_RESULT_AVAILABLE_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Fetching query result availability after query end should succeed.");
+ ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Attempting to end an inactive query should fail.");
+ ext.queryCounterEXT(query, ext.TIMESTAMP_EXT);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Should not be able to use time elapsed query to store a timestamp.");
+ ext.deleteQueryEXT(query);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query deletion must succeed.");
+ ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Beginning a deleted query must fail.");
+ ext.getQueryObjectEXT(query, ext.QUERY_RESULT_AVAILABLE_EXT);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Fetching query result availability after query deletion should fail.");
+ shouldBe("ext.isQueryEXT(query)", "false");
+
+ debug("");
+ debug("Testing timestamp counter");
+ query = ext.createQueryEXT();
+ shouldThrow("ext.queryCounterEXT(null, ext.TIMESTAMP_EXT)");
+ ext.queryCounterEXT(query, ext.TIMESTAMP_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Timestamp counter queries should work.");
+ ext.deleteQueryEXT(query);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Performing parameter sanity checks");
+ gl.getParameter(ext.TIMESTAMP_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getParameter timestamp calls should work.");
+ gl.getParameter(ext.GPU_DISJOINT_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getParameter disjoint calls should work.");
+
+ debug("");
+ debug("Testing current query conditions");
+ query = ext.createQueryEXT();
+ query2 = ext.createQueryEXT();
+ shouldBe("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT)", "null");
+ ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);
+ shouldBe("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT)", "query");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Testing failed begin query should not change the current query.");
+ ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Beginning an elapsed query without ending should fail.");
+ shouldBe("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT)", "query");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Testing beginning a timestamp query is invalid and should not change the elapsed query.");
+ ext.beginQueryEXT(ext.TIMESTAMP_EXT, query2)
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM);
+ shouldBe("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT)", "query");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Testing timestamp queries end immediately so are never current.");
+ ext.queryCounterEXT(query2, ext.TIMESTAMP_EXT);
+ shouldBe("ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.CURRENT_QUERY_EXT)", "null");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Testing ending the query should clear the current query.");
+ ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
+ shouldBe("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT)", "null");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Testing beginning a elapsed query using a timestamp query should fail and not affect current query.")
+ ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Switching query targets should fail.");
+ shouldBe("ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT)", "null");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ ext.deleteQueryEXT(query);
+ ext.deleteQueryEXT(query2);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors at end of sanity tests");
+}
+
+function runElapsedTimeTest() {
+ debug("");
+ debug("Testing elapsed time query");
+
+ elapsed_query = ext.createQueryEXT();
+ ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, elapsed_query);
+ gl.clearColor(0, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Time elapsed query should have no errors");
+}
+
+function runTimeStampTest() {
+ debug("");
+ debug("Testing timestamp query");
+
+ timestamp_query1 = ext.createQueryEXT();
+ timestamp_query2 = ext.createQueryEXT();
+ ext.queryCounterEXT(timestamp_query1, ext.TIMESTAMP_EXT);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ ext.queryCounterEXT(timestamp_query2, ext.TIMESTAMP_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Timestamp queries should have no errors");
+}
+
+function verifyQueryResultsNotAvailable() {
+ debug("");
+ debug("Verifying queries' results don't become available too early");
+
+ // Verify as best as possible that the implementation doesn't
+ // allow a query's result to become available the same frame, by
+ // spin-looping for some time and ensuring that none of the
+ // queries' results become available.
+ var startTime = Date.now();
+ while (Date.now() - startTime < 2000) {
+ gl.finish();
+ if (ext.getQueryObjectEXT(elapsed_query, ext.QUERY_RESULT_AVAILABLE_EXT)) {
+ testFailed("One of the queries' results became available too early");
+ return;
+ }
+ if (timestamp_counter_bits > 0) {
+ if (ext.getQueryObjectEXT(timestamp_query1, ext.QUERY_RESULT_AVAILABLE_EXT) ||
+ ext.getQueryObjectEXT(timestamp_query2, ext.QUERY_RESULT_AVAILABLE_EXT)) {
+ testFailed("One of the queries' results became available too early");
+ return;
+ }
+ }
+ }
+
+ testPassed("Queries' results didn't become available in a spin loop");
+}
+
+function checkQueryResults() {
+ if (availability_retry > 0) {
+ // Make a reasonable attempt to wait for the queries' results to become available.
+ if (!ext.getQueryObjectEXT(elapsed_query, ext.QUERY_RESULT_AVAILABLE_EXT) ||
+ (timestamp_counter_bits > 0 && !ext.getQueryObjectEXT(timestamp_query2, ext.QUERY_RESULT_AVAILABLE_EXT))) {
+ var error = gl.getError();
+ if (error != gl.NO_ERROR) {
+ testFailed("getQueryObjectEXT should have no errors: " + wtu.glEnumToString(gl, error));
+ debug("");
+ finishTest();
+ return;
+ }
+ availability_retry--;
+ window.requestAnimationFrame(checkQueryResults);
+ return;
+ }
+ }
+
+ debug("");
+ debug("Testing query results");
+
+ // Make sure queries are available.
+ shouldBe("ext.getQueryObjectEXT(elapsed_query, ext.QUERY_RESULT_AVAILABLE_EXT)", "true");
+ if (timestamp_counter_bits > 0) {
+ shouldBe("ext.getQueryObjectEXT(timestamp_query1, ext.QUERY_RESULT_AVAILABLE_EXT)", "true");
+ shouldBe("ext.getQueryObjectEXT(timestamp_query2, ext.QUERY_RESULT_AVAILABLE_EXT)", "true");
+ }
+
+ var disjoint_value = gl.getParameter(ext.GPU_DISJOINT_EXT);
+ if (disjoint_value) {
+ // Cannot validate results make sense, but this is okay.
+ testPassed("Disjoint triggered.");
+ } else {
+ var elapsed_result = ext.getQueryObjectEXT(elapsed_query, ext.QUERY_RESULT_EXT);
+ if (timestamp_counter_bits > 0) {
+ var timestamp_result1 = ext.getQueryObjectEXT(timestamp_query1, ext.QUERY_RESULT_EXT);
+ var timestamp_result2 = ext.getQueryObjectEXT(timestamp_query2, ext.QUERY_RESULT_EXT);
+ }
+ // Do some basic validity checking of the elapsed time query. There's no way it should
+ // take more than about half a second for a no-op query.
+ var halfSecondInNanos = 0.5 * 1000 * 1000 * 1000;
+ if (elapsed_result < 0 || elapsed_result > halfSecondInNanos) {
+ testFailed("Time elapsed query returned invalid data: " + elapsed_result);
+ } else {
+ testPassed("Time elapsed query results were valid.");
+ }
+
+ if (timestamp_counter_bits > 0) {
+ if (timestamp_result1 <= 0 ||
+ timestamp_result2 <= 0 ||
+ timestamp_result2 <= timestamp_result1) {
+ testFailed("Timestamp queries returned invalid data: timestamp_result1 = " +
+ timestamp_result1 + ", timestamp_result2 = " + timestamp_result2);
+ } else {
+ testPassed("Timestamp query results were valid.");
+ }
+ }
+ }
+
+ debug("");
+ finishTest();
+}
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-float-blend.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-float-blend.html
new file mode 100644
index 0000000000..a825d78bef
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-float-blend.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_float_blend Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/ext-float-blend.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the EXT_float_blend extension, if it is available.");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+
+function extFloatBlendTests(version, config) {
+ debug("");
+ debug("Testing float32 blending without EXT_float_blend");
+ testExtFloatBlend(config.internalFormat);
+ testExtFloatBlendMRT(version, config.drawBuffers);
+ testExtFloatBlendNonFloat32Type(version, config.oesTextureHalfFloat);
+
+ const floatBlend = gl.getExtension("EXT_float_blend");
+ if (!floatBlend) {
+ testPassed("EXT_float_blend is allowed to be missing.");
+ return;
+ }
+
+ debug("");
+ debug("Testing that float32 blending is allowed with EXT_float_blend");
+ testExtFloatBlend(config.internalFormat);
+ testExtFloatBlendMRT(version, config.drawBuffers);
+ testExtFloatBlendNonFloat32Type(version, config.oesTextureHalfFloat);
+}
+
+(function(){
+ if (wtu.getDefault3DContextVersion() < 2) {
+ const oesTextureFloat = gl.getExtension("OES_texture_float");
+ if (!oesTextureFloat) {
+ testPassed("OES_texture_float is allowed to be missing.");
+ return;
+ }
+
+ const colorBufferFloat = gl.getExtension("WEBGL_color_buffer_float");
+ if (!colorBufferFloat) {
+ testPassed("WEBGL_color_buffer_float is allowed to be missing.");
+ return;
+ }
+
+ const drawBuffers = gl.getExtension("WEBGL_draw_buffers");
+ if (!drawBuffers) {
+ debug("WEBGL_draw_buffers is allowed to be missing. MRT tests will be skipped.");
+ }
+
+ const oesTextureHalfFloat = gl.getExtension("OES_texture_half_float");
+ const extColorBufferHalfFloat = gl.getExtension("EXT_color_buffer_half_float");
+ const testHalfFloat = !(!oesTextureHalfFloat || !extColorBufferHalfFloat);
+ if (!testHalfFloat) {
+ debug("OES_texture_half_float or EXT_color_buffer_half_float is allowed to be missing. NonFloat32Type tests will be skipped.");
+ }
+
+ const internalFormat = gl.RGBA;
+ extFloatBlendTests(1, {
+ internalFormat, drawBuffers, oesTextureHalfFloat
+ });
+ } else {
+ const colorBufferFloat = gl.getExtension("EXT_color_buffer_float");
+ if (!colorBufferFloat) {
+ testPassed("EXT_color_buffer_float is allowed to be missing.");
+ return;
+ }
+
+ const internalFormat = gl.RGBA32F;
+ extFloatBlendTests(2, {
+ internalFormat
+ });
+ }
+})();
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-frag-depth.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-frag-depth.html
new file mode 100644
index 0000000000..ee2a6df0cd
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-frag-depth.html
@@ -0,0 +1,289 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_frag_depth Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing fragment depth writing -->
+
+<!-- Shader omitting the required #extension pragma -->
+<script id="missingPragmaFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+void main() {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ gl_FragDepthEXT = 1.0;
+}
+</script>
+
+<!-- Shader to test macro definition -->
+<script id="macroFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+void main() {
+#ifdef GL_EXT_frag_depth
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+#else
+ // Error expected
+ #error no GL_EXT_frag_depth;
+#endif
+}
+</script>
+
+<!-- Shader with required #extension pragma -->
+<script id="testFragmentShader" type="x-shader/x-fragment">
+#extension GL_EXT_frag_depth : enable
+precision mediump float;
+void main() {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ gl_FragDepthEXT = 1.0;
+}
+</script>
+<!-- Shaders to link with test fragment shaders -->
+<script id="goodVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+void main() {
+ gl_Position = vPosition;
+}
+</script>
+<!-- Shaders to test output -->
+<script id="outputVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+void main() {
+ gl_Position = vPosition;
+}
+</script>
+<script id="outputFragmentShader" type="x-shader/x-fragment">
+#extension GL_EXT_frag_depth : enable
+precision mediump float;
+uniform float uDepth;
+void main() {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ gl_FragDepthEXT = uDepth;
+}
+</script>
+
+<script>
+"use strict";
+description("This test verifies the functionality of the EXT_frag_depth extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+
+// Run all tests once.
+runAllTests();
+
+// Run all tests against with a new context to test for any cache issues.
+debug("");
+debug("Testing new context to catch cache errors");
+gl = wtu.create3DContext();
+ext = null;
+runAllTests();
+
+function runAllTests() {
+ if (!gl) {
+ testFailed("WebGL context does not exist");
+ } else {
+ testPassed("WebGL context exists");
+
+ runShaderTests(false);
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "EXT_frag_depth");
+ if (!ext) {
+ testPassed("No EXT_frag_depth support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled EXT_frag_depth extension");
+
+ runSupportedTest(true);
+
+ runShaderTests(true);
+ runOutputTests();
+ runUniqueObjectTest();
+
+ // Run deferred link tests.
+ runDeferredLinkTests();
+ }
+ }
+
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("EXT_frag_depth") >= 0) {
+ if (extensionEnabled) {
+ testPassed("EXT_frag_depth listed as supported and getExtension succeeded");
+ } else {
+ testFailed("EXT_frag_depth listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("EXT_frag_depth not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("EXT_frag_depth not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runShaderTests(extensionEnabled) {
+ debug("");
+ debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
+
+ // Expect the macro shader to succeed ONLY if enabled
+ var macroFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "macroFragmentShader");
+ if (extensionEnabled) {
+ if (macroFragmentProgram) {
+ // Expected result
+ testPassed("GL_EXT_frag_depth defined in shaders when extension is enabled");
+ } else {
+ testFailed("GL_EXT_frag_depth not defined in shaders when extension is enabled");
+ }
+ } else {
+ if (macroFragmentProgram) {
+ testFailed("GL_EXT_frag_depth defined in shaders when extension is disabled");
+ } else {
+ testPassed("GL_EXT_frag_depth not defined in shaders when extension disabled");
+ }
+ }
+
+ // Always expect the shader missing the #pragma to fail (whether enabled or not)
+ var missingPragmaFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "missingPragmaFragmentShader");
+ if (missingPragmaFragmentProgram) {
+ testFailed("Shader built-ins allowed without #extension pragma");
+ } else {
+ testPassed("Shader built-ins disallowed without #extension pragma");
+ }
+
+ // Try to compile a shader using the built-ins that should only succeed if enabled
+ var testFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShader");
+ if (extensionEnabled) {
+ if (testFragmentProgram) {
+ testPassed("Shader built-ins compiled successfully when extension enabled");
+ } else {
+ testFailed("Shader built-ins failed to compile when extension enabled");
+ }
+ } else {
+ if (testFragmentProgram) {
+ testFailed("Shader built-ins compiled successfully when extension disabled");
+ } else {
+ testPassed("Shader built-ins failed to compile when extension disabled");
+ }
+ }
+}
+
+function runOutputTests() {
+ var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
+
+ debug("Testing various draws for valid built-in function behavior");
+
+ canvas.width = 50; canvas.height = 50;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ // Enable depth testing with a clearDepth of 0.5
+ // This makes it so that fragments are only rendered when
+ // gl_fragDepthEXT is < 0.5
+ gl.clearDepth(0.5);
+ gl.enable(gl.DEPTH_TEST);
+
+ var positionLoc = 0;
+ var texcoordLoc = 1;
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['vPosition'], [0]);
+ var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
+ var depthUniform = gl.getUniformLocation(program, "uDepth");
+
+ // Draw 1: Greater than clear depth
+ gl.uniform1f(depthUniform, 1.0);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 255, 255, 255]);
+
+ // Draw 2: Less than clear depth
+ gl.uniform1f(depthUniform, 0.0);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
+}
+
+function runUniqueObjectTest()
+{
+ debug("Testing that getExtension() returns the same object each time");
+ ext = null;
+ gl.getExtension("EXT_frag_depth").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("EXT_frag_depth").myProperty', '2');
+}
+
+function runDeferredLinkTests() {
+ debug("");
+ debug("Testing deferred shader compilation tests.");
+
+ // Test for compilation failures that are caused by missing extensions
+ // do not succeed if extensions are enabled during linking. This would
+ // only happen for deferred shader compilations.
+
+ // First test if link succeeds with extension enabled.
+ var glEnabled = wtu.create3DContext();
+ var extEnabled = glEnabled.getExtension("EXT_frag_depth");
+ if (!extEnabled) {
+ testFailed("Deferred link test expects the extension to be supported");
+ }
+
+ var vertexShader = wtu.loadShaderFromScript(glEnabled, "goodVertexShader");
+ var fragmentShader = wtu.loadShaderFromScript(glEnabled, "macroFragmentShader");
+
+ if (!vertexShader || !fragmentShader) {
+ testFailed("Could not create good shaders.");
+ return;
+ }
+
+ var program = wtu.setupProgram(glEnabled, [vertexShader, fragmentShader]);
+
+ if (!program) {
+ testFailed("Compilation with extension enabled failed.");
+ return;
+ }
+
+ // Create new context to test link failure without extension enabled.
+ var glDeferred = wtu.create3DContext();
+
+ var vertexShader = wtu.loadShaderFromScript(glDeferred, "goodVertexShader", glDeferred.VERTEX_SHADER, undefined, undefined, true);
+ var fragmentShader = wtu.loadShaderFromScript(glDeferred, "macroFragmentShader", glDeferred.FRAGMENT_SHADER, undefined, undefined, true);
+
+ if (vertexShader == null || fragmentShader == null) {
+ testFailed("Could not create shaders.");
+ return;
+ }
+
+ // Shader compilations should have failed due to extensions not enabled.
+ glDeferred.getExtension("EXT_frag_depth");
+ var program = wtu.setupProgram(glDeferred, [vertexShader, fragmentShader]);
+ if (program) {
+ testFailed("Compilation with extension disabled then linking with extension enabled should have failed.");
+ return;
+ }
+
+ testPassed("Compilation with extension disabled then linking with extension enabled.");
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html
new file mode 100644
index 0000000000..7e8353f7f2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html
@@ -0,0 +1,468 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="16" height="16" style="width: 50px; height: 50px; border: 1px solid black;"></canvas>
+
+<!-- Shaders to test output -->
+<script id="vertexShader" type="x-shader/x-vertex">
+attribute vec4 aPosition;
+void main() {
+ gl_Position = aPosition;
+}
+</script>
+
+<script id="fragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+uniform float uColor;
+void main() {
+ gl_FragColor = vec4(uColor, uColor, uColor, 1);
+}
+</script>
+
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec2 texCoord0;
+varying vec2 texCoord;
+void main()
+{
+ gl_Position = vPosition;
+ texCoord = texCoord0;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D tex;
+varying vec2 texCoord;
+void main()
+{
+ gl_FragColor = texture2D(tex, texCoord);
+}
+</script>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+var canvas;
+var gl;
+var ext = null;
+
+var extConstants = {
+ "SRGB_EXT": 0x8C40,
+ "SRGB_ALPHA_EXT": 0x8C42,
+ "SRGB8_ALPHA8_EXT": 0x8C43,
+ "FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT": 0x8210
+};
+
+function getExtension() {
+ ext = gl.getExtension("EXT_sRGB");
+}
+
+function listsExtension() {
+ var supported = gl.getSupportedExtensions();
+ return (supported.indexOf("EXT_sRGB") >= 0);
+}
+
+function toVec3String(val) {
+ if (typeof(val) == 'number') {
+ return toVec3String([val, val, val]);
+ }
+ return '[' + val[0] + ', ' + val[1] + ', ' + val[2] + ']';
+}
+
+var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
+
+function expectResult(target) {
+ wtu.checkCanvasRect(gl,
+ Math.floor(gl.drawingBufferWidth / 2),
+ Math.floor(gl.drawingBufferHeight / 2),
+ 1,
+ 1,
+ [target, target, target, 255],
+ undefined,
+ e);
+}
+
+function createGreysRGBTexture(gl, color, format) {
+ var numPixels = gl.drawingBufferWidth * gl.drawingBufferHeight;
+ var elements;
+ switch (format) {
+ case ext.SRGB_EXT: elements = 3; break;
+ case ext.SRGB_ALPHA_EXT: elements = 4; break;
+ default: return null;
+ }
+
+ var size = numPixels * elements;
+ var buf = new Uint8Array(size);
+ for (var ii = 0; ii < numPixels; ++ii) {
+ var off = ii * elements;
+ buf[off + 0] = color;
+ buf[off + 1] = color;
+ buf[off + 2] = color;
+ if (format == ext.SRGB_ALPHA_EXT) {
+ buf[off + 3] = 255;
+ }
+ }
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D,
+ 0,
+ format,
+ gl.drawingBufferWidth,
+ gl.drawingBufferHeight,
+ 0,
+ format,
+ gl.UNSIGNED_BYTE,
+ buf);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ return tex;
+}
+
+function testValidFormat(fn, internalFormat, formatName, enabled) {
+ if (enabled) {
+ fn(internalFormat);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "was able to create type " + formatName);
+ } else {
+ testInvalidFormat(fn, internalFormat, formatName, enabled);
+ }
+}
+
+function testInvalidFormat(fn, internalFormat, formatName, enabled) {
+ fn(internalFormat);
+ var err = gl.getError();
+ if (err == gl.NO_ERROR) {
+ testFailed("should NOT be able to create type " + formatName);
+ } else if (err == gl.INVALID_ENUM || err == gl.INVALID_VALUE) {
+ testPassed("not able to create invalid format: " + formatName);
+ }
+}
+
+var textureFormatFixture = {
+ desc: "Checking texture formats",
+ create: function(format) {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D,
+ 0, // level
+ format, // internalFormat
+ gl.drawingBufferWidth, // width
+ gl.drawingBufferHeight, // height
+ 0, // border
+ format, // format
+ gl.UNSIGNED_BYTE, // type
+ null); // data
+ },
+ tests: [
+ {
+ desc: "Checking valid formats",
+ fn: testValidFormat,
+ formats: [ 'SRGB_EXT', 'SRGB_ALPHA_EXT' ]
+ },
+ {
+ desc: "Checking invalid formats",
+ fn: testInvalidFormat,
+ formats: [ 'SRGB8_ALPHA8_EXT' ]
+ }
+ ]
+};
+
+var renderbufferFormatFixture = {
+ desc: "Checking renderbuffer formats",
+ create: function(format) {
+ var rbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER,
+ format,
+ gl.drawingBufferWidth,
+ gl.drawingBufferHeight);
+ },
+ tests: [
+ {
+ desc: "Checking valid formats",
+ fn: testValidFormat,
+ formats: [ 'SRGB8_ALPHA8_EXT' ]
+ },
+ {
+ desc: "Checking invalid formats",
+ fn: testInvalidFormat,
+ formats: [ 'SRGB_EXT', 'SRGB_ALPHA_EXT' ]
+ }
+ ]
+};
+
+
+description("Test sRGB texture support");
+
+debug("");
+debug("Canvas.getContext");
+
+canvas = document.getElementById("canvas");
+gl = wtu.create3DContext(canvas);
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ debug("");
+ debug("Checking sRGB texture support with extension disabled");
+
+ runFormatTest(textureFormatFixture, false);
+ runFormatTest(renderbufferFormatFixture, false);
+
+ debug("");
+ debug("Checking sRGB texture support");
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("EXT_sRGB");
+
+ if (!ext) {
+ testPassed("No EXT_sRGB support -- this is legal");
+
+ runSupportedTest(false);
+ finishTest();
+ } else {
+ testPassed("Successfully enabled EXT_sRGB extension");
+
+ runSupportedTest(true);
+
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+
+ runConstantsTest();
+ runFormatTest(textureFormatFixture, true);
+ runFormatTest(renderbufferFormatFixture, true);
+ runTextureReadConversionTest();
+ runFramebufferTextureConversionTest(ext.SRGB_EXT);
+ runFramebufferTextureConversionTest(ext.SRGB_ALPHA_EXT);
+ runFramebufferRenderbufferConversionTest();
+ runGenerateMipmapTest();
+ runLoadFromImageTest(function() {
+ finishTest();
+ });
+ }
+}
+
+function runConstantsTest() {
+ debug("");
+ debug("Checking extension constants values");
+
+ for (var constant in extConstants) {
+ if (constant in ext) {
+ if (extConstants[constant] != ext[constant]) {
+ testFailed("Value of " + constant + " should be: " + extConstants[constant] + ", was: " + ext[constant]);
+ } else {
+ testPassed("Value of " + constant + " was expected value: " + extConstants[constant]);
+ }
+ } else {
+ testFailed(constant + " not found in extension object");
+ }
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ if (listsExtension()) {
+ if (extensionEnabled) {
+ testPassed("EXT_sRGB listed as supported and getExtension succeeded");
+ } else {
+ testFailed("EXT_sRGB listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("EXT_sRGB not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("EXT_sRGB not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runFormatTest(fixture, enabled) {
+ debug("");
+ debug(fixture.desc);
+
+ for (var tt = 0; tt < fixture.tests.length; ++tt) {
+ var test = fixture.tests[tt];
+ debug(test.desc);
+
+ for (var ii = 0; ii < test.formats.length; ++ii) {
+ var formatName = test.formats[ii];
+ test.fn(fixture.create, extConstants[formatName], "ext." + formatName, enabled);
+ }
+
+ if (tt != fixture.tests.length - 1)
+ debug("");
+ }
+}
+
+function runTextureReadConversionTest() {
+ debug("");
+ debug("Test the conversion of colors from sRGB to linear on texture read");
+
+ // Draw
+ var conversions = [
+ [ 0, 0 ],
+ [ 63, 13 ],
+ [ 127, 54 ],
+ [ 191, 133 ],
+ [ 255, 255 ]
+ ];
+
+ var program = wtu.setupTexturedQuad(gl);
+ gl.uniform1i(gl.getUniformLocation(program, "tex"), 0);
+
+ for (var ii = 0; ii < conversions.length; ii++) {
+ var tex = createGreysRGBTexture(gl, conversions[ii][0], ext.SRGB_EXT);
+ wtu.drawUnitQuad(gl);
+ expectResult(conversions[ii][1]);
+ }
+}
+
+function runFramebufferTextureConversionTest(format) {
+ var formatString;
+ var validFormat;
+ switch (format) {
+ case ext.SRGB_EXT: formatString = "sRGB"; validFormat = false; break;
+ case ext.SRGB_ALPHA_EXT: formatString = "sRGB_ALPHA"; validFormat = true; break;
+ default: return null;
+ }
+ debug("");
+ debug("Test " + formatString + " framebuffer attachments." + (validFormat ? "" : " (Invalid)"));
+
+ var program = wtu.setupProgram(gl, ['vertexShader', 'fragmentShader'], ['aPosition'], [0]);
+ var tex = createGreysRGBTexture(gl, 0, format);
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)', 'ext.SRGB_EXT');
+
+ if (validFormat) {
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ debug("");
+ debug("Test the conversion of colors from linear to " + formatString + " on framebuffer (texture) write");
+
+ // Draw
+ var conversions = [
+ [ 0, 0 ],
+ [ 13, 63 ],
+ [ 54, 127 ],
+ [ 133, 191 ],
+ [ 255, 255 ]
+ ];
+
+ wtu.setupUnitQuad(gl, 0);
+
+ for (var ii = 0; ii < conversions.length; ii++) {
+ gl.uniform1f(gl.getUniformLocation(program, "uColor"), conversions[ii][0]/255.0);
+ wtu.drawUnitQuad(gl, [0, 0, 0, 0]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ expectResult(conversions[ii][1]);
+ }
+ } else {
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+
+ wtu.setupUnitQuad(gl, 0);
+ gl.uniform1f(gl.getUniformLocation(program, "uColor"), 0.5);
+ wtu.drawUnitQuad(gl, [0, 0, 0, 0]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+}
+
+function runFramebufferRenderbufferConversionTest() {
+ debug("");
+ debug("Test the conversion of colors from linear to sRGB on framebuffer (renderbuffer) write");
+
+ function createsRGBFramebuffer(gl, width, height) {
+ var rbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER, ext.SRGB8_ALPHA8_EXT, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
+ gl.RENDERBUFFER, rbo);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)', 'ext.SRGB_EXT');
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ return fbo;
+ }
+
+ // Draw
+ var conversions = [
+ [ 0, 0 ],
+ [ 13, 63 ],
+ [ 54, 127 ],
+ [ 133, 191 ],
+ [ 255, 255 ]
+ ];
+
+ var program = wtu.setupProgram(gl, ['vertexShader', 'fragmentShader'], ['aPosition'], [0]);
+ wtu.setupUnitQuad(gl, 0);
+ var fbo = createsRGBFramebuffer(gl, gl.drawingBufferWidth, gl.drawingBufferHeight);
+
+ for (var ii = 0; ii < conversions.length; ii++) {
+ gl.uniform1f(gl.getUniformLocation(program, "uColor"), conversions[ii][0]/255.0);
+ wtu.drawUnitQuad(gl, [0, 0, 0, 0]);
+ expectResult(conversions[ii][1]);
+ }
+}
+
+function runLoadFromImageTest(callback) {
+ debug("");
+ debug("Tests to ensure that SRGB textures can successfully use image elements as their source");
+
+ var img = wtu.makeImage("../../resources/gray-1024x1024.jpg", function() {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.SRGB_EXT, ext.SRGB_EXT, gl.UNSIGNED_BYTE, img);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.SRGB_ALPHA_EXT, ext.SRGB_ALPHA_EXT, gl.UNSIGNED_BYTE, img);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ callback();
+ }, function() {
+ testFailed("Image could not be loaded");
+ callback();
+ });
+}
+
+function runGenerateMipmapTest()
+{
+ debug("");
+ debug("GenerateMipmaps for sRGB textures is forbidden");
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.SRGB_ALPHA_EXT, 2, 2, 0, ext.SRGB_ALPHA_EXT,
+ gl.UNSIGNED_BYTE, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.generateMipmap(gl.TEXTURE_2D);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
+
+ gl.deleteTexture(tex);
+}
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-shader-texture-lod.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-shader-texture-lod.html
new file mode 100644
index 0000000000..30176bd590
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-shader-texture-lod.html
@@ -0,0 +1,341 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_shader_texture_lod Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/desktop-gl-constants.js"></script>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 256px; height: 256px;"> </canvas>
+<canvas id="canvas2" style="width: 256px; height: 256px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing texture LOD functions -->
+
+<!-- Shader omitting the required #extension pragma -->
+<script id="missingPragmaFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+varying vec2 texCoord0v;
+uniform float lod;
+uniform sampler2D tex;
+void main() {
+ vec4 color = texture2DLodEXT(tex, texCoord0v, lod);
+ gl_FragColor = color;
+}
+</script>
+
+<!-- Shader to test macro definition -->
+<script id="macroFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+void main() {
+#ifdef GL_EXT_shader_texture_lod
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
+#else
+ // Error expected
+ #error no GL_EXT_shader_texture_lod;
+#endif
+}
+</script>
+
+<!-- Shader with required #extension pragma -->
+<script id="testFragmentShader" type="x-shader/x-fragment">
+#extension GL_EXT_shader_texture_lod : enable
+precision mediump float;
+varying vec2 texCoord0v;
+uniform float lod;
+uniform sampler2D tex;
+void main() {
+ vec4 color = texture2DLodEXT(tex, texCoord0v, lod);
+ gl_FragColor = color;
+}
+</script>
+
+<!-- Shaders to link with test fragment shaders -->
+<script id="goodVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec2 texCoord0;
+varying vec2 texCoord0v;
+void main() {
+ texCoord0v = texCoord0;
+ gl_Position = vPosition;
+}
+</script>
+
+<!-- Shaders to test output -->
+<script id="outputVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec2 texCoord0;
+varying vec2 texCoord0v;
+void main() {
+ texCoord0v = texCoord0;
+ gl_Position = vPosition;
+}
+</script>
+<script id="outputFragmentShader" type="x-shader/x-fragment">
+#extension GL_EXT_shader_texture_lod : require
+precision mediump float;
+varying vec2 texCoord0v;
+uniform float lod;
+uniform sampler2D tex;
+void main() {
+ vec4 color = texture2DLodEXT(tex, texCoord0v, lod);
+ gl_FragColor = color;
+}
+</script>
+
+<script>
+description("This test verifies the functionality of the EXT_shader_texture_lod extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+
+// Run all tests once.
+runAllTests();
+
+// Run all tests against with a new context to test for any cache issues.
+debug("");
+debug("Testing new context to catch cache errors");
+var canvas2 = document.getElementById("canvas2");
+gl = wtu.create3DContext(canvas2);
+ext = null;
+runAllTests();
+
+function runAllTests() {
+ if (!gl) {
+ testFailed("WebGL context does not exist");
+ } else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runShaderTests(false);
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("EXT_shader_texture_lod");
+ if (!ext) {
+ testPassed("No EXT_shader_texture_lod support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled EXT_shader_texture_lod extension");
+
+ runSupportedTest(true);
+
+ runShaderTests(true);
+ runOutputTests();
+ runUniqueObjectTest();
+ runReferenceCycleTest();
+
+ // Run deferred link tests.
+ runDeferredLinkTests();
+ }
+ }
+
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("EXT_shader_texture_lod") >= 0) {
+ if (extensionEnabled) {
+ testPassed("EXT_shader_texture_lod listed as supported and getExtension succeeded");
+ } else {
+ testFailed("EXT_shader_texture_lod listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("EXT_shader_texture_lod not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("EXT_shader_texture_lod not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runShaderTests(extensionEnabled) {
+ debug("");
+ debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
+
+ // Expect the macro shader to succeed ONLY if enabled
+ var macroFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "macroFragmentShader");
+ if (extensionEnabled) {
+ if (macroFragmentProgram) {
+ // Expected result
+ testPassed("GL_EXT_shader_texture_lod defined in shaders when extension is enabled");
+ } else {
+ testFailed("GL_EXT_shader_texture_lod not defined in shaders when extension is enabled");
+ }
+ } else {
+ if (macroFragmentProgram) {
+ testFailed("GL_EXT_shader_texture_lod defined in shaders when extension is disabled");
+ } else {
+ testPassed("GL_EXT_shader_texture_lod not defined in shaders when extension disabled");
+ }
+ }
+
+ // Always expect the shader missing the #pragma to fail (whether enabled or not)
+ var missingPragmaFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "missingPragmaFragmentShader");
+ if (missingPragmaFragmentProgram) {
+ testFailed("Shader built-ins allowed without #extension pragma");
+ } else {
+ testPassed("Shader built-ins disallowed without #extension pragma");
+ }
+
+ // Try to compile a shader using the built-ins that should only succeed if enabled
+ var testFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShader");
+ if (extensionEnabled) {
+ if (testFragmentProgram) {
+ testPassed("Shader built-ins compiled successfully when extension enabled");
+ } else {
+ testFailed("Shader built-ins failed to compile when extension enabled");
+ }
+ } else {
+ if (testFragmentProgram) {
+ testFailed("Shader built-ins compiled successfully when extension disabled");
+ } else {
+ testPassed("Shader built-ins failed to compile when extension disabled");
+ }
+ }
+}
+
+function runOutputTests() {
+ debug("");
+ debug("Testing various draws for valid built-in function behavior");
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['vPosition', 'texCoord0'], [0, 1]);
+ var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
+
+ var colors = [
+ {name: 'red', color:[255, 0, 0, 255]},
+ {name: 'green', color:[0, 255, 0, 255]},
+ {name: 'blue', color:[0, 0, 255, 255]},
+ {name: 'yellow', color:[255, 255, 0, 255]},
+ {name: 'magenta', color:[255, 0, 255, 255]},
+ {name: 'cyan', color:[0, 255, 255, 255]},
+ {name: 'pink', color:[255, 128, 128, 255]},
+ {name: 'gray', color:[128, 128, 128, 255]},
+ {name: 'light green', color:[128, 255, 128, 255]},
+ ];
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
+
+ for (var ii = 0; ii < colors.length; ++ii) {
+ var color = colors[ii];
+ var size = Math.pow(2, colors.length - ii - 1);
+ wtu.fillTexture(gl, tex, size, size, color.color, ii);
+ }
+
+ var loc = gl.getUniformLocation(program, "lod");
+
+ for (var ii = 0; ii < colors.length; ++ii) {
+ gl.uniform1f(loc, ii);
+ var color = colors[ii];
+ wtu.drawUnitQuad(gl);
+ wtu.checkCanvas(
+ gl, color.color,
+ "256x256 texture drawn to 256x256 dest with lod = " + ii +
+ " should be " + color.name);
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+}
+
+function runUniqueObjectTest()
+{
+ debug("");
+ debug("Testing that getExtension() returns the same object each time");
+ ext = null;
+ gl.getExtension("EXT_shader_texture_lod").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("EXT_shader_texture_lod").myProperty', '2');
+}
+
+function runReferenceCycleTest()
+{
+ // create some reference cycles. The goal is to see if they cause leaks. The point is that
+ // some browser test runners have instrumentation to detect leaked refcounted objects.
+ debug("");
+ debug("Testing reference cycles between context and extension objects");
+ var ext = gl.getExtension("EXT_shader_texture_lod");
+
+ // create cycle between extension and context, since the context has to hold a reference to the extension
+ ext.context = gl;
+
+ // create a self-cycle on the extension object
+ ext.ext = ext;
+}
+
+function runDeferredLinkTests() {
+ debug("");
+ debug("Testing deferred shader compilation tests.");
+
+ // Test for compilation failures that are caused by missing extensions
+ // do not succeed if extensions are enabled during linking. This would
+ // only happen for deferred shader compilations.
+
+ // First test if link succeeds with extension enabled.
+ var glEnabled = wtu.create3DContext();
+ var extEnabled = glEnabled.getExtension("EXT_shader_texture_lod");
+ if (!extEnabled) {
+ testFailed("Deferred link test expects the extension to be supported");
+ }
+
+ var vertexShader = wtu.loadShaderFromScript(glEnabled, "goodVertexShader");
+ var fragmentShader = wtu.loadShaderFromScript(glEnabled, "macroFragmentShader");
+
+ if (!vertexShader || !fragmentShader) {
+ testFailed("Could not create good shaders.");
+ return;
+ }
+
+ var program = wtu.setupProgram(glEnabled, [vertexShader, fragmentShader]);
+
+ if (!program) {
+ testFailed("Compilation with extension enabled failed.");
+ return;
+ }
+
+ // Create new context to test link failure without extension enabled.
+ var glDeferred = wtu.create3DContext();
+
+ var vertexShader = wtu.loadShaderFromScript(glDeferred, "goodVertexShader", glDeferred.VERTEX_SHADER, undefined, undefined, true);
+ var fragmentShader = wtu.loadShaderFromScript(glDeferred, "macroFragmentShader", glDeferred.FRAGMENT_SHADER, undefined, undefined, true);
+
+ if (vertexShader == null || fragmentShader == null) {
+ testFailed("Could not create shaders.");
+ return;
+ }
+
+ // Shader compilations should have failed due to extensions not enabled.
+ glDeferred.getExtension("EXT_shader_texture_lod");
+ var program = wtu.setupProgram(glDeferred, [vertexShader, fragmentShader]);
+ if (program) {
+ testFailed("Compilation with extension disabled then linking with extension enabled should have failed.");
+ return;
+ }
+
+ testPassed("Compilation with extension disabled then linking with extension enabled.");
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-bptc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-bptc.html
new file mode 100644
index 0000000000..5b6c10f044
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-bptc.html
@@ -0,0 +1,159 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_texture_compression_bptc Conformance Tests</title>
+<LINK rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compressed-texture-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the EXT_texture_compression_bptc extension, if it is available.");
+
+debug("");
+
+var validFormats = {
+ COMPRESSED_RGBA_BPTC_UNORM_EXT: 0x8E8C,
+ COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT: 0x8E8D,
+ COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT: 0x8E8E,
+ COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT: 0x8E8F
+};
+
+function expectedByteLength(width, height, format) {
+ return Math.ceil(width / 4) * Math.ceil(height / 4) * 16;
+}
+
+function getBlockDimensions(format) {
+ return {width: 4, height: 4};
+}
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var gl = wtu.create3DContext();
+var ext;
+
+var formats = null;
+
+function runTestExtension() {
+ // Test that enum values are listed correctly in supported formats and in the extension object.
+ ctu.testCompressedFormatsListed(gl, validFormats);
+ ctu.testCorrectEnumValuesInExt(ext, validFormats);
+ // Test that texture upload buffer size is validated correctly.
+ ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+ // Test TexSubImage validation on dimensions
+ // CompressedTexSubImage* will result in an
+ // INVALID_OPERATION error only if one of the following conditions occurs:
+ // * <width> is not a multiple of four, and <width> plus <xoffset> is not
+ // equal to TEXTURE_WIDTH;
+ // * <height> is not a multiple of four, and <height> plus <yoffset> is
+ // not equal to TEXTURE_HEIGHT; or
+ // * <xoffset> or <yoffset> is not a multiple of four.
+ ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ 16, 16, [
+ { xoffset: 0, yoffset: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
+ { xoffset: 0, yoffset: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
+ { xoffset: 1, yoffset: 0, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
+ { xoffset: 0, yoffset: 1, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
+ { xoffset: 12, yoffset: 12, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ ]);
+
+ // Test TexImage validation on level dimensions combinations.
+ // When level equals 0, width and height must be a multiple of 4.
+ // When level is larger than 0, this constraint doesn't apply.
+
+ let npotExpectation, npotMessage;
+ if (contextVersion >= 2) {
+ npotExpectation = gl.NO_ERROR;
+ npotMessage = "valid";
+ } else {
+ npotExpectation = gl.INVALID_VALUE;
+ npotMessage = "invalid";
+ }
+
+ ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { level: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "level is 0, height is not a multiple of 4" },
+ { level: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
+ { level: 0, width: 2, height: 2,
+ expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
+ { level: 0, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ { level: 1, width: 1, height: 1,
+ expectation: gl.INVALID_OPERATION, message: "implied base mip 2x2 is invalid" },
+ { level: 1, width: 1, height: 2,
+ expectation: gl.INVALID_OPERATION, message: "implied base mip 2x4 is invalid" },
+ { level: 1, width: 2, height: 1,
+ expectation: gl.INVALID_OPERATION, message: "implied base mip 4x2 is invalid" },
+ { level: 1, width: 2, height: 2,
+ expectation: gl.NO_ERROR, message: "implied base mip 4x4 is valid" },
+ { level: 2, width: 1, height: 3,
+ expectation: npotExpectation, message: "implied base mip 4x12 is " + npotMessage },
+ ]);
+
+ // Test that BPTC enums are not accepted by texImage2D
+ {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_RGBA_BPTC_UNORM_EXT fails with texImage2D");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT fails with texImage2D");
+
+ if (contextVersion >= 2) {
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, 4, 4, 0, gl.RGB, gl.FLOAT, null);
+ wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT fails with texImage2D");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, 4, 4, 0, gl.RGB, gl.FLOAT, null);
+ wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT fails with texImage2D");
+ }
+
+ gl.deleteTexture(tex);
+ }
+};
+
+function runTest() {
+ if (!gl) {
+ testFailed("context does not exist");
+ } else {
+ testPassed("context exists");
+
+ ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+ ext = gl.getExtension("EXT_texture_compression_bptc");
+
+ wtu.runExtensionSupportedTest(gl, "EXT_texture_compression_bptc", ext !== null);
+
+ if (ext !== null) {
+ runTestExtension();
+ }
+ }
+}
+
+runTest();
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html
new file mode 100644
index 0000000000..70dcf9ba7b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html
@@ -0,0 +1,162 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_texture_compression_rgtc Conformance Tests</title>
+<LINK rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compressed-texture-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the EXT_texture_compression_rgtc extension, if it is available.");
+
+debug("");
+
+var validFormats = {
+ COMPRESSED_RED_RGTC1_EXT: 0x8DBB,
+ COMPRESSED_SIGNED_RED_RGTC1_EXT: 0x8DBC,
+ COMPRESSED_RED_GREEN_RGTC2_EXT: 0x8DBD,
+ COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: 0x8DBE
+};
+
+function expectedByteLength(width, height, format) {
+ if (format == validFormats.COMPRESSED_RED_RGTC1_EXT || format == validFormats.COMPRESSED_SIGNED_RED_RGTC1_EXT) {
+ return Math.ceil(width / 4) * Math.ceil(height / 4) * 8;
+ }
+ else {
+ return Math.ceil(width / 4) * Math.ceil(height / 4) * 16;
+ }
+}
+
+function getBlockDimensions(format) {
+ return {width: 4, height: 4};
+}
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var gl = wtu.create3DContext();
+var ext;
+
+var formats = null;
+
+function runTestExtension() {
+ // Test that enum values are listed correctly in supported formats and in the extension object.
+ ctu.testCompressedFormatsListed(gl, validFormats);
+ ctu.testCorrectEnumValuesInExt(ext, validFormats);
+ // Test that texture upload buffer size is validated correctly.
+ ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+ // Test TexSubImage validation on dimensions
+ // CompressedTexSubImage* will result in an
+ // INVALID_OPERATION error only if one of the following conditions occurs:
+ // * <width> is not a multiple of four, and <width> plus <xoffset> is not
+ // equal to TEXTURE_WIDTH;
+ // * <height> is not a multiple of four, and <height> plus <yoffset> is
+ // not equal to TEXTURE_HEIGHT; or
+ // * <xoffset> or <yoffset> is not a multiple of four.
+ ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ 16, 16, [
+ { xoffset: 0, yoffset: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
+ { xoffset: 0, yoffset: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
+ { xoffset: 1, yoffset: 0, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
+ { xoffset: 0, yoffset: 1, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
+ { xoffset: 12, yoffset: 12, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ ]);
+
+ // Test TexImage validation on level dimensions combinations.
+ // When level equals 0, width and height must be a multiple of 4.
+ // When level is larger than 0, this constraint doesn't apply.
+
+ let npotExpectation, npotMessage;
+ if (contextVersion >= 2) {
+ npotExpectation = gl.NO_ERROR;
+ npotMessage = "valid";
+ } else {
+ npotExpectation = gl.INVALID_VALUE;
+ npotMessage = "invalid";
+ }
+
+ ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { level: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "level is 0, height is not a multiple of 4" },
+ { level: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
+ { level: 0, width: 2, height: 2,
+ expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
+ { level: 0, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ { level: 1, width: 1, height: 1,
+ expectation: gl.INVALID_OPERATION, message: "implied base mip 2x2 is invalid" },
+ { level: 1, width: 1, height: 2,
+ expectation: gl.INVALID_OPERATION, message: "implied base mip 2x4 is invalid" },
+ { level: 1, width: 2, height: 1,
+ expectation: gl.INVALID_OPERATION, message: "implied base mip 4x2 is invalid" },
+ { level: 1, width: 2, height: 2,
+ expectation: gl.NO_ERROR, message: "implied base mip 4x4 is valid" },
+ { level: 2, width: 1, height: 3,
+ expectation: npotExpectation, message: "implied base mip 4x12 is " + npotMessage },
+ ]);
+
+ // Test that RGTC enums are not accepted by texImage2D
+ if (contextVersion >= 2) {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.UNSIGNED_BYTE, null);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_RGTC1_EXT fails with texImage2D");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.BYTE, null);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_RGTC1_EXT fails with texImage2D");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.UNSIGNED_BYTE, null);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_GREEN_RGTC2_EXT fails with texImage2D");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.BYTE, null);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT fails with texImage2D");
+
+ gl.deleteTexture(tex);
+ }
+};
+
+function runTest() {
+ if (!gl) {
+ testFailed("context does not exist");
+ } else {
+ testPassed("context exists");
+
+ ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+ ext = gl.getExtension("EXT_texture_compression_rgtc");
+
+ wtu.runExtensionSupportedTest(gl, "EXT_texture_compression_rgtc", ext !== null);
+
+ if (ext !== null) {
+ runTestExtension();
+ }
+ }
+}
+
+runTest();
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-filter-anisotropic.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-filter-anisotropic.html
new file mode 100644
index 0000000000..1376d3e402
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-filter-anisotropic.html
@@ -0,0 +1,26 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_texture_filter_anisotropic Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<script>
+var contextVersion = 1;
+</script>
+<script src="../../js/tests/ext-texture-filter-anisotropic.js"></script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/get-extension.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/get-extension.html
new file mode 100644
index 0000000000..8d9a9bc6de
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/get-extension.html
@@ -0,0 +1,99 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Extension Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<script>
+"use strict";
+
+var pseudoRandom = (function() {
+ var seed = 3;
+ return function() {
+ seed = (seed * 11 + 17) % 25;
+ return seed / 25;
+ };
+})();
+
+var randomizeCase = function(str) {
+ var newChars = [];
+ for (var ii = 0; ii < str.length; ++ii) {
+ var c = str.substr(ii, 1);
+ var m = (pseudoRandom() > 0.5) ? c.toLowerCase() : c.toUpperCase();
+ newChars.push(m);
+ }
+ return newChars.join("");
+};
+
+description();
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+
+var ii;
+
+debug("check every extension advertised can be enabled");
+debug("");
+var extensionNames = gl.getSupportedExtensions();
+var extensionNamesLower = [];
+for (ii = 0; ii < extensionNames.length; ++ii) {
+ extensionNamesLower.push(extensionNames[ii].toLowerCase());
+}
+
+for (ii = 0; ii < extensionNames.length; ++ii) {
+ var originalName = extensionNames[ii];
+ var mixedName = randomizeCase(originalName);
+ var extension = gl.getExtension(mixedName);
+ assertMsg(extension, "able to get " + originalName + " as " + mixedName);
+ if (extension) {
+ var kTestString = "this is a test";
+ var kTestNumber = 123;
+ var kTestFunction = function() { };
+ var kTestObject = { };
+ extension.testStringProperty = kTestString;
+ extension.testNumberProperty = kTestNumber;
+ extension.testFunctionProperty = kTestFunction;
+ extension.testObjectProperty = kTestObject;
+ webglHarnessCollectGarbage();
+ var extension2 = gl.getExtension(originalName);
+ assertMsg(
+ extension === extension2,
+ "calling getExtension twice for the same extension returns the same object");
+ assertMsg(
+ extension2.testStringProperty === kTestString &&
+ extension2.testFunctionProperty === kTestFunction &&
+ extension2.testObjectProperty === kTestObject &&
+ extension2.testNumberProperty === kTestNumber,
+ "object returned by 2nd call to getExtension has same properties");
+
+ var prefixedVariants = wtu.getExtensionPrefixedNames(originalName);
+ for (var jj = 0; jj < prefixedVariants.length; ++jj) {
+ assertMsg(
+ gl.getExtension(prefixedVariants[jj]) === null ||
+ extensionNamesLower.indexOf(prefixedVariants[jj].toLowerCase()) !== -1,
+ "getExtension('" + prefixedVariants[jj] + "') returns an object only if the name is returned by getSupportedExtensions");
+ }
+ }
+ debug("");
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html
new file mode 100644
index 0000000000..2915a2d2de
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html
@@ -0,0 +1,220 @@
+<!--
+Copyright (c) 2020 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<style>
+.spinner {
+ width: 100px;
+ height: 100px;
+ border: 20px solid transparent;
+ border-top: 20px solid black;
+ border-radius: 100%;
+ text-align: center;
+ padding: 10px;
+}
+@keyframes rotation {
+ from { transorm: rotate(0); }
+ to { transform: rotate(360deg); }
+}
+</style>
+</head>
+<body>
+<div id="description"></div>
+<button onclick='compileShaders()'>The spinners below should not stutter when you click this button.</button>
+<div class="spinner" style="animation: rotation 2s infinite linear;">CSS</div>
+<div class="spinner" id=spinner>JS</div>
+<div id="console"></div>
+<canvas id=canvas></canvas>
+<script>
+"use strict";
+description("Test KHR_parallel_shader_compile");
+
+function spinSpinner() {
+ let degrees = (performance.now() / 1000 / 2 % 1.) * 360;
+ spinner.style.transform = `rotate(${degrees}deg)`;
+ requestAnimationFrame(spinSpinner);
+}
+spinSpinner();
+
+const wtu = WebGLTestUtils;
+
+const gl = wtu.create3DContext();
+const loseContext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_lose_context");
+
+let counter = 0;
+const vertexSource = (extra) => `
+void main() {
+ vec4 result = vec4(0.${counter++});
+${extra || ''}
+ gl_Position = result;
+}`;
+const fragmentSource = (extra) => `
+precision highp float;
+void main() {
+ vec4 result = vec4(0.${counter++});
+${extra || ''}
+ gl_FragColor = result;
+}`;
+
+let vs = gl.createShader(gl.VERTEX_SHADER);
+let fs = gl.createShader(gl.FRAGMENT_SHADER);
+let program = gl.createProgram();
+gl.attachShader(program, vs);
+gl.attachShader(program, fs);
+
+const COMPLETION_STATUS_KHR = 0x91B1;
+
+gl.shaderSource(vs, vertexSource());
+gl.compileShader(vs);
+let status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
+if (status !== null) testFailed('Extension disabled, status should be null');
+wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "extension disabled");
+
+gl.shaderSource(fs, fragmentSource());
+gl.compileShader(fs);
+
+gl.linkProgram(program);
+status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
+if (status !== null) testFailed('Extension disabled, status should be null');
+wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "extension disabled");
+
+const ext = wtu.getExtensionWithKnownPrefixes(gl, "KHR_parallel_shader_compile");
+
+let successfullyParsed = false;
+
+let extraCode = '';
+
+(async () => {
+
+ if (!ext) {
+ testPassed("No KHR_parallel_shader_compile support -- this is legal");
+ } else {
+ testPassed("Successfully enabled KHR_parallel_shader_compile extension");
+
+ shouldBe("ext.COMPLETION_STATUS_KHR", "0x91B1");
+
+ debug("Checking that status is a boolean.");
+ gl.shaderSource(vs, vertexSource());
+ gl.compileShader(vs);
+ let status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
+ if (status !== true && status !== false) testFailed("status should be a boolean");
+
+ gl.linkProgram(program);
+ status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
+ if (status !== true && status !== false) testFailed("status should be a boolean");
+
+ const minimumShaderCompileDurationMs = 500;
+ debug(`Constructing shader that takes > ${minimumShaderCompileDurationMs} ms to compile.`);
+ let measuredCompileDuration = 0;
+ extraCode = '\n if (true) { result += vec4(0.0000001); }';
+ for (let i = 0; measuredCompileDuration < minimumShaderCompileDurationMs; i++) {
+ extraCode += extraCode;
+ extraCode += extraCode;
+ if (i < 4) continue;
+ gl.shaderSource(vs, vertexSource(extraCode));
+ gl.shaderSource(fs, fragmentSource(extraCode));
+ gl.compileShader(vs);
+ gl.compileShader(fs);
+ gl.linkProgram(program);
+ const start = performance.now();
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ testFailed(`Shaders failed to compile.
+ program: ${gl.getProgramInfoLog(program)}
+ vs: ${gl.getShaderInfoLog(vs)}
+ fs: ${gl.getShaderInfoLog(fs)}`);
+ break;
+ }
+ measuredCompileDuration = performance.now() - start;
+ }
+
+ debug('');
+ gl.shaderSource(vs, vertexSource(extraCode));
+ gl.shaderSource(fs, fragmentSource(extraCode));
+ gl.compileShader(vs);
+ gl.compileShader(fs);
+ gl.linkProgram(program);
+
+ let start = performance.now();
+ gl.getShaderParameter(fs, COMPLETION_STATUS_KHR);
+ gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
+ let duration = performance.now() - start;
+ if (duration > 100)
+ testFailed(`Querying shader status should not wait for compilation. Took ${duration} ms`);
+
+ let frames = 0;
+ const maximumTimeToWait = measuredCompileDuration * 4;
+ while (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)
+ && performance.now() - start < maximumTimeToWait) {
+ frames++;
+ await new Promise(requestAnimationFrame);
+ }
+ duration = performance.now() - start;
+ if (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)) {
+ testFailed(`Program took longer than ${maximumTimeToWait} ms to compile. Expected: ${measuredCompileDuration} ms, actual: ${duration} ms`);
+ } else if (!gl.getShaderParameter(vs, COMPLETION_STATUS_KHR) || !gl.getShaderParameter(fs, COMPLETION_STATUS_KHR)) {
+ testFailed('Program linked before shaders finished compiling.');
+ } else if (frames <= 6) {
+ testFailed(`Program should have taken many more than 6 frames to compile. Actual value: ${frames} frames, duration ${performance.now() - start} ms.`);
+ } else {
+ console.log(`COMPLETION_STATUS_KHR sucessfully transitioned from false to true in ${frames} frames and ${duration} ms.`);
+ testPassed(`COMPLETION_STATUS_KHR sucessfully transitioned from false to true`);
+ }
+
+
+ debug("Checking that status is true when context is lost.");
+ if (loseContext) {
+ gl.shaderSource(vs, vertexSource(extraCode));
+ gl.shaderSource(fs, fragmentSource(extraCode));
+ gl.compileShader(vs);
+ gl.compileShader(fs);
+ gl.linkProgram(program);
+ loseContext.loseContext();
+ status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
+ if (status !== true) testFailed("shader status should be true when context is lost");
+ status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
+ if (status !== true) testFailed("program status should be true when context is lost");
+ loseContext.restoreContext();
+ vs = gl.createShader(gl.VERTEX_SHADER);
+ fs = gl.createShader(gl.FRAGMENT_SHADER);
+ program = gl.createProgram();
+ }
+ }
+ finishTest();
+})();
+
+async function compileShaders() {
+ console.log('Compiling shaders');
+ const gl = canvas.getContext('webgl');
+ const vs = gl.createShader(gl.VERTEX_SHADER);
+ const fs = gl.createShader(gl.FRAGMENT_SHADER);
+ const program = gl.createProgram();
+ gl.getExtension(wtu.getExtensionWithKnownPrefixes(gl, "KHR_parallel_shader_compile"));
+ gl.attachShader(program, vs);
+ gl.attachShader(program, fs);
+ gl.shaderSource(vs, vertexSource(extraCode));
+ gl.shaderSource(fs, fragmentSource(extraCode));
+ gl.compileShader(vs);
+ gl.compileShader(fs);
+ gl.linkProgram(program);
+ while (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)) {
+ gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
+ gl.getShaderParameter(fs, COMPLETION_STATUS_KHR);
+ await new Promise(requestAnimationFrame);
+ }
+ gl.getProgramParameter(program, gl.LINK_STATUS);
+ console.log('Compilation finished.');
+}
+
+</script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-element-index-uint.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-element-index-uint.html
new file mode 100644
index 0000000000..f30acaba28
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-element-index-uint.html
@@ -0,0 +1,428 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL OES_element_index_uint Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+
+<script id="vs" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec4 vColor;
+varying vec4 color;
+void main() {
+ gl_Position = vPosition;
+ color = vColor;
+}
+</script>
+<script id="fs" type="x-shader/x-fragment">
+precision mediump float;
+varying vec4 color;
+void main() {
+ gl_FragColor = color;
+}
+</script>
+
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the OES_element_index_uint extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var gl = null;
+var ext = null;
+var canvas = null;
+
+// Test both STATIC_DRAW and DYNAMIC_DRAW as a regression test
+// for a bug in ANGLE which has since been fixed.
+for (var ii = 0; ii < 2; ++ii) {
+ canvas = document.createElement("canvas");
+ canvas.width = 50;
+ canvas.height = 50;
+
+ gl = wtu.create3DContext(canvas);
+
+ if (!gl) {
+ testFailed("WebGL context does not exist");
+ } else {
+ testPassed("WebGL context exists");
+
+ var drawType = (ii == 0) ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW;
+ debug("Testing " + ((ii == 0) ? "STATIC_DRAW" : "DYNAMIC_DRAW"));
+
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("OES_element_index_uint");
+ if (!ext) {
+ testPassed("No OES_element_index_uint support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled OES_element_index_uint extension");
+
+ runSupportedTest(true);
+
+ runDrawTests(drawType);
+
+ // These tests are tweaked duplicates of the buffers/index-validation* tests
+ // using unsigned int indices to ensure that behavior remains consistent
+ runIndexValidationTests(drawType);
+ runCopiesIndicesTests(drawType);
+ runResizedBufferTests(drawType);
+ runVerifiesTooManyIndicesTests(drawType);
+ runCrashWithBufferSubDataTests(drawType);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+ }
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("OES_element_index_uint") >= 0) {
+ if (extensionEnabled) {
+ testPassed("OES_element_index_uint listed as supported and getExtension succeeded");
+ } else {
+ testFailed("OES_element_index_uint listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("OES_element_index_uint not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("OES_element_index_uint not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runDrawTests(drawType) {
+ debug("Test that draws with unsigned integer indices produce the expected results");
+
+ canvas.width = 50; canvas.height = 50;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var program = wtu.setupSimpleColorProgram(gl);
+
+ function setupDraw(s) {
+ // Create a vertex buffer that cannot be fully indexed via shorts
+ var quadArrayLen = 65537 * 3;
+ var quadArray = new Float32Array(quadArrayLen);
+
+ // Leave all but the last 4 values zero-ed out
+ var idx = quadArrayLen - 12;
+
+ // Initialized the last 4 values to a quad
+ quadArray[idx++] = 1.0 * s;
+ quadArray[idx++] = 1.0 * s;
+ quadArray[idx++] = 0.0;
+
+ quadArray[idx++] = -1.0 * s;
+ quadArray[idx++] = 1.0 * s;
+ quadArray[idx++] = 0.0;
+
+ quadArray[idx++] = -1.0 * s;
+ quadArray[idx++] = -1.0 * s;
+ quadArray[idx++] = 0.0;
+
+ quadArray[idx++] = 1.0 * s;
+ quadArray[idx++] = -1.0 * s;
+ quadArray[idx++] = 0.0;
+
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, quadArray, drawType);
+
+ // Create an unsigned int index buffer that indexes the last 4 vertices
+ var baseIndex = (quadArrayLen / 3) - 4;
+
+ var indexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([
+ baseIndex + 0,
+ baseIndex + 1,
+ baseIndex + 2,
+ baseIndex + 2,
+ baseIndex + 3,
+ baseIndex + 0]), drawType);
+
+ var opt_positionLocation = 0;
+ gl.enableVertexAttribArray(opt_positionLocation);
+ gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0);
+ };
+ function testPixel(blockList, allowList) {
+ function testList(list, expected) {
+ for (var n = 0; n < list.length; n++) {
+ var l = list[n];
+ var x = -Math.floor(l * canvas.width / 2) + canvas.width / 2;
+ var y = -Math.floor(l * canvas.height / 2) + canvas.height / 2;
+ wtu.checkCanvasRect(gl, x, y, 1, 1, [expected, expected, expected],
+ "Draw should pass", 2);
+ }
+ }
+ testList(blockList, 0);
+ testList(allowList, 255);
+ };
+ function verifyDraw(s) {
+ gl.clearColor(1.0, 1.0, 1.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ wtu.setFloatDrawColor(gl, [0.0, 0.0, 0.0, 1.0]);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
+
+ var blockList = [];
+ var allowList = [];
+ var points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
+ for (var n = 0; n < points.length; n++) {
+ if (points[n] <= s) {
+ blockList.push(points[n]);
+ } else {
+ allowList.push(points[n]);
+ }
+ }
+ testPixel(blockList, allowList);
+ };
+
+ setupDraw(0.5);
+ verifyDraw(0.5);
+}
+
+function runIndexValidationTests(drawType) {
+ description("Tests that index validation verifies the correct number of indices");
+
+ function sizeInBytes(type) {
+ switch (type) {
+ case gl.BYTE:
+ case gl.UNSIGNED_BYTE:
+ return 1;
+ case gl.SHORT:
+ case gl.UNSIGNED_SHORT:
+ return 2;
+ case gl.INT:
+ case gl.UNSIGNED_INT:
+ case gl.FLOAT:
+ return 4;
+ default:
+ throw "unknown type";
+ }
+ }
+
+ var program = wtu.loadStandardProgram(gl);
+
+ // 3 vertices => 1 triangle, interleaved data
+ var dataComplete = new Float32Array([0, 0, 0, 1,
+ 0, 0, 1,
+ 1, 0, 0, 1,
+ 0, 0, 1,
+ 1, 1, 1, 1,
+ 0, 0, 1]);
+ var dataIncomplete = new Float32Array([0, 0, 0, 1,
+ 0, 0, 1,
+ 1, 0, 0, 1,
+ 0, 0, 1,
+ 1, 1, 1, 1]);
+ var indices = new Uint32Array([0, 1, 2]);
+
+ debug("Testing with valid indices");
+
+ var bufferComplete = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, bufferComplete);
+ gl.bufferData(gl.ARRAY_BUFFER, dataComplete, drawType);
+ var elements = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
+ gl.useProgram(program);
+ var vertexLoc = gl.getAttribLocation(program, "a_vertex");
+ var normalLoc = gl.getAttribLocation(program, "a_normal");
+ gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0);
+ gl.enableVertexAttribArray(vertexLoc);
+ gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
+ gl.enableVertexAttribArray(normalLoc);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Testing with out-of-range indices");
+
+ var bufferIncomplete = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, bufferIncomplete);
+ gl.bufferData(gl.ARRAY_BUFFER, dataIncomplete, drawType);
+ gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0);
+ gl.enableVertexAttribArray(vertexLoc);
+ gl.disableVertexAttribArray(normalLoc);
+ debug("Enable vertices, valid");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ debug("Enable normals, out-of-range");
+ gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
+ gl.enableVertexAttribArray(normalLoc);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ wtu.shouldGenerateGLError(gl, [gl.INVALID_OPERATION, gl.NO_ERROR],
+ 'gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
+
+ debug("Test with enabled attribute that does not belong to current program");
+
+ gl.disableVertexAttribArray(normalLoc);
+ var extraLoc = Math.max(vertexLoc, normalLoc) + 1;
+ gl.enableVertexAttribArray(extraLoc);
+ debug("Enable an extra attribute with null");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
+ debug("Enable an extra attribute with insufficient data buffer");
+ gl.vertexAttribPointer(extraLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
+ debug("Pass large negative index to vertexAttribPointer");
+ gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), -2000000000 * sizeInBytes(gl.FLOAT));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
+}
+
+function runCopiesIndicesTests(drawType) {
+ debug("Test that client data is always copied during bufferData and bufferSubData calls");
+
+ var program = wtu.loadStandardProgram(gl);
+
+ gl.useProgram(program);
+ var vertexObject = gl.createBuffer();
+ gl.enableVertexAttribArray(0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ // 4 vertices -> 2 triangles
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+ var indexObject = gl.createBuffer();
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
+ var indices = new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
+ var indexValidationError = wtu.shouldGenerateGLError(gl, [gl.INVALID_OPERATION, gl.NO_ERROR],
+ "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
+ wtu.shouldGenerateGLError(gl, indexValidationError, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
+ indices[0] = 2;
+ indices[5] = 1;
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
+ wtu.shouldGenerateGLError(gl, indexValidationError, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
+ wtu.shouldGenerateGLError(gl, indexValidationError, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
+}
+
+function runResizedBufferTests(drawType) {
+ debug("Test that updating the size of a vertex buffer is properly noticed by the WebGL implementation.");
+
+ var program = wtu.setupProgram(gl, ["vs", "fs"], ["vPosition", "vColor"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after initialization");
+
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
+ [-1,1,0, 1,1,0, -1,-1,0,
+ -1,-1,0, 1,1,0, 1,-1,0]), drawType);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex setup");
+
+ var texCoordObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
+ [0,0, 1,0, 0,1,
+ 0,1, 1,0, 1,1]), drawType);
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coord setup");
+
+ // Now resize these buffers because we want to change what we're drawing.
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -1,1,0, 1,1,0, -1,-1,0, 1,-1,0,
+ -1,1,0, 1,1,0, -1,-1,0, 1,-1,0]), drawType);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex redefinition");
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([
+ 255, 0, 0, 255,
+ 255, 0, 0, 255,
+ 255, 0, 0, 255,
+ 255, 0, 0, 255,
+ 0, 255, 0, 255,
+ 0, 255, 0, 255,
+ 0, 255, 0, 255,
+ 0, 255, 0, 255]), drawType);
+ gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, false, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coordinate / color redefinition");
+
+ var numQuads = 2;
+ var indices = new Uint32Array(numQuads * 6);
+ for (var ii = 0; ii < numQuads; ++ii) {
+ var offset = ii * 6;
+ var quad = (ii == (numQuads - 1)) ? 4 : 0;
+ indices[offset + 0] = quad + 0;
+ indices[offset + 1] = quad + 1;
+ indices[offset + 2] = quad + 2;
+ indices[offset + 3] = quad + 2;
+ indices[offset + 4] = quad + 1;
+ indices[offset + 5] = quad + 3;
+ }
+ var indexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting up indices");
+ gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_INT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing");
+}
+
+function runVerifiesTooManyIndicesTests(drawType) {
+ description("Tests that index validation for drawElements does not examine too many indices");
+
+ var program = wtu.loadStandardProgram(gl);
+
+ gl.useProgram(program);
+ var vertexObject = gl.createBuffer();
+ gl.enableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ // 4 vertices -> 2 triangles
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+ var indexObject = gl.createBuffer();
+
+ debug("Test out of range indices")
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]), drawType);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
+ var indexValidationError = wtu.shouldGenerateGLError(gl, [gl.INVALID_OPERATION, gl.NO_ERROR],
+ "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
+ wtu.shouldGenerateGLError(gl, indexValidationError, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
+}
+
+function runCrashWithBufferSubDataTests(drawType) {
+ debug('Verifies that the index validation code which is within bufferSubData does not crash.')
+
+ var elementBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 256, drawType);
+ var data = new Uint32Array(127);
+ gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 64, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "after attempting to update a buffer outside of the allocated bounds");
+ testPassed("bufferSubData, when buffer object was initialized with null, did not crash");
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-fbo-render-mipmap.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-fbo-render-mipmap.html
new file mode 100644
index 0000000000..b560a4c89a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-fbo-render-mipmap.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL OES_fbo_render_mipmap Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="128" height="128"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the OES_fbo_render_mipmap extension, if it is available.");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+
+(function(){
+
+ const oesFboRenderMipmap = gl.getExtension("OES_fbo_render_mipmap");
+ if (!oesFboRenderMipmap) {
+ testPassed("OES_fbo_render_mipmap is allowed to be missing.");
+ return;
+ }
+
+ let texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
+
+ let colors = [
+ [255, 0, 0, 255],
+ [255, 127, 0, 255],
+ [255, 255, 0, 255],
+ [0, 255, 0, 255],
+ [0, 255, 255, 255],
+ [0, 127, 255, 255],
+ [0, 0, 255, 255],
+ [255, 0, 255, 255],
+ ];
+
+ let fbos = [];
+ let maxLevel = 7;
+ for (let level = 0; level <= maxLevel; level++) {
+ let size = Math.pow(2, maxLevel - level);
+ gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ let fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, level);
+ fbos.push(fbo);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Any level of a texture can be attached to a framebuffer object.");
+ }
+
+ for (let level = 0; level <= maxLevel; level++) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbos[level]);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ gl.clearColor(colors[level][0] / 255, colors[level][1] / 255, colors[level][2] / 255, colors[level][3] / 255);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ let program = wtu.setupTexturedQuad(gl);
+
+ for (let level = 0; level <= maxLevel; level++) {
+ let size = Math.pow(2, maxLevel - level);
+ // We use differrent viewport sizes to affect which miplevel is fetched from the texture.
+ gl.viewport(0, 0, size, size);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.checkCanvasRect(gl, 0, 0, 1, 1, colors[level]);
+ }
+
+})();
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-standard-derivatives.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-standard-derivatives.html
new file mode 100644
index 0000000000..f6f4de0243
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-standard-derivatives.html
@@ -0,0 +1,444 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL OES_standard_derivatives Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing standard derivatives -->
+
+<!-- Shader omitting the required #extension pragma -->
+<script id="missingPragmaFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+varying vec2 texCoord;
+void main() {
+ float dx = dFdx(texCoord.x);
+ float dy = dFdy(texCoord.y);
+ float w = fwidth(texCoord.x);
+ gl_FragColor = vec4(dx, dy, w, 1.0);
+}
+</script>
+
+<!-- Shader to test macro definition -->
+<script id="macroFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+void main() {
+#ifdef GL_OES_standard_derivatives
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
+#else
+ // Error expected
+ #error no GL_OES_standard_derivatives;
+#endif
+}
+</script>
+
+<!-- Shader with required #extension pragma -->
+<script id="testFragmentShader" type="x-shader/x-fragment">
+#extension GL_OES_standard_derivatives : enable
+precision mediump float;
+varying vec2 texCoord;
+void main() {
+ float dx = dFdx(texCoord.x);
+ float dy = dFdy(texCoord.y);
+ float w = fwidth(texCoord.x);
+ gl_FragColor = vec4(dx, dy, w, 1.0);
+}
+</script>
+<!-- Shader with #extension after other code -->
+<script id="testFragmentShaderWithExtensionNotAtTop" type="x-shader/x-fragment">
+precision mediump float;
+varying vec2 texCoord;
+void main() {
+#extension GL_OES_standard_derivatives : enable
+ float dx = dFdx(texCoord.x);
+ float dy = dFdy(texCoord.y);
+ float w = fwidth(texCoord.x);
+ gl_FragColor = vec4(dx, dy, w, 1.0);
+}
+</script>
+<!-- Shaders to link with test fragment shaders -->
+<script id="goodVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+varying vec2 texCoord;
+void main() {
+ texCoord = vPosition.xy;
+ gl_Position = vPosition;
+}
+</script>
+<!-- Shaders to test output -->
+<script id="outputVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+varying vec4 position;
+void main() {
+ position = vPosition;
+ gl_Position = vPosition;
+}
+</script>
+<script id="outputFragmentShader" type="x-shader/x-fragment">
+#extension GL_OES_standard_derivatives : enable
+precision mediump float;
+varying vec4 position;
+void main() {
+ float dzdx = dFdx(position.z);
+ float dzdy = dFdy(position.z);
+ float fw = fwidth(position.z);
+ gl_FragColor = vec4(abs(dzdx) * 40.0, abs(dzdy) * 40.0, fw * 40.0, 1.0);
+}
+</script>
+
+<script>
+"use strict";
+description("This test verifies the functionality of the OES_standard_derivatives extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+
+// Run all tests once.
+runAllTests();
+
+// Run all tests against with a new context to test for any cache issues.
+debug("");
+debug("Testing new context to catch cache errors");
+gl = wtu.create3DContext();
+ext = null;
+runAllTests();
+
+function runAllTests() {
+ if (!gl) {
+ testFailed("WebGL context does not exist");
+ } else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runHintTestDisabled();
+ runShaderTests(false);
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("OES_standard_derivatives");
+ if (!ext) {
+ testPassed("No OES_standard_derivatives support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled OES_standard_derivatives extension");
+
+ runSupportedTest(true);
+
+ runHintTestEnabled();
+ runShaderTests(true);
+ runOutputTests();
+ runUniqueObjectTest();
+
+ // Run deferred link tests.
+ runDeferredLinkTests();
+ }
+ }
+
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("OES_standard_derivatives") >= 0) {
+ if (extensionEnabled) {
+ testPassed("OES_standard_derivatives listed as supported and getExtension succeeded");
+ } else {
+ testFailed("OES_standard_derivatives listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("OES_standard_derivatives not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("OES_standard_derivatives not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runHintTestDisabled() {
+ debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension disabled");
+
+ // Use the constant directly as we don't have the extension
+ var FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
+
+ gl.getParameter(FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES should not be queryable if extension is disabled");
+
+ gl.hint(FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "hint should not accept FRAGMENT_SHADER_DERIVATIVE_HINT_OES if extension is disabled");
+}
+
+function runHintTestEnabled() {
+ debug("Testing FRAGMENT_SHADER_DERIVATIVE_HINT_OES with extension enabled");
+
+ shouldBe("ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES", "0x8B8B");
+
+ gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "FRAGMENT_SHADER_DERIVATIVE_HINT_OES query should succeed if extension is enabled");
+
+ // Default value is DONT_CARE
+ if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) == gl.DONT_CARE) {
+ testPassed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is DONT_CARE");
+ } else {
+ testFailed("Default value of FRAGMENT_SHADER_DERIVATIVE_HINT_OES is not DONT_CARE");
+ }
+
+ // Ensure that we can set the target
+ gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.DONT_CARE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "hint should accept FRAGMENT_SHADER_DERIVATIVE_HINT_OES");
+
+ // Test all the hint modes
+ var validModes = ["FASTEST", "NICEST", "DONT_CARE"];
+ var anyFailed = false;
+ for (var n = 0; n < validModes.length; n++) {
+ var mode = validModes[n];
+ gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl[mode]);
+ if (gl.getParameter(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES) != gl[mode]) {
+ testFailed("Round-trip of hint()/getParameter() failed on mode " + mode);
+ anyFailed = true;
+ }
+ }
+ if (!anyFailed) {
+ testPassed("Round-trip of hint()/getParameter() with all supported modes");
+ }
+}
+
+function runShaderTests(extensionEnabled) {
+ debug("");
+ debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
+
+ // Expect the macro shader to succeed ONLY if enabled
+ {
+ const macroFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "macroFragmentShader");
+ if (extensionEnabled) {
+ if (macroFragmentProgram) {
+ // Expected result
+ testPassed("GL_OES_standard_derivatives defined in shaders when extension is enabled");
+ } else {
+ testFailed("GL_OES_standard_derivatives not defined in shaders when extension is enabled");
+ }
+ } else {
+ if (macroFragmentProgram) {
+ testFailed("GL_OES_standard_derivatives defined in shaders when extension is disabled");
+ } else {
+ testPassed("GL_OES_standard_derivatives not defined in shaders when extension disabled");
+ }
+ }
+ }
+
+ // Always expect the shader missing the #pragma to fail (whether enabled or not)
+ {
+ const missingPragmaFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "missingPragmaFragmentShader");
+ if (missingPragmaFragmentProgram) {
+ testFailed("Shader built-ins allowed without #extension pragma");
+ } else {
+ testPassed("Shader built-ins disallowed without #extension pragma");
+ }
+ }
+
+ // Try to compile a shader using the built-ins that should only succeed if enabled
+ {
+ const testFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShader");
+ if (extensionEnabled) {
+ if (testFragmentProgram) {
+ testPassed("Shader built-ins compiled successfully when extension enabled");
+ } else {
+ testFailed("Shader built-ins failed to compile when extension enabled");
+ }
+ } else {
+ if (testFragmentProgram) {
+ testFailed("Shader built-ins compiled successfully when extension disabled");
+ } else {
+ testPassed("Shader built-ins failed to compile when extension disabled");
+ }
+ }
+ }
+
+ // This tests specifically that #extension directives after other code are
+ // valid, per spec (6.35 GLSL ES #extension directive location).
+ //
+ // This test actually has nothing to do with OES_standard_derivatives, but
+ // is inserted here because this extension is ubiquitous.
+ //
+ // This test is not as strict as the spec - it doesn't require that "the
+ // scope ... is always the whole shader", because implementations (ANGLE
+ // shader translator) do not actually implement this correctly. The test
+ // coverage is intentionally left incomplete - in practice, all WebGL
+ // shaders already work with the current implementation, so there's no
+ // practical reason to update them to match the spec. Conversely, the
+ // currently implemented rules are too complex to formalize in spec.
+ //
+ // Regression test for https://crbug.com/971660 .
+ {
+ const testFragmentProgramWithExtensionNotAtTop = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShaderWithExtensionNotAtTop");
+ if (extensionEnabled) {
+ if (testFragmentProgramWithExtensionNotAtTop) {
+ testPassed("Shader with #extension after non-preprocessor code: compiled successfully when extension enabled");
+ } else {
+ testFailed("Shader with #extension after non-preprocessor code: failed to compile when extension enabled");
+ }
+ }
+ }
+}
+
+function runOutputTests() {
+ // This tests does several draws with various values of z.
+ // The output of the fragment shader is:
+ // [dFdx(z), dFdy(z), fwidth(z), 1.0]
+ // The expected math: (note the conversion to uint8)
+ // canvas.width = canvas.height = 50
+ // dFdx = totalChange.x / canvas.width = 0.5 / 50.0 = 0.01
+ // dFdy = totalChange.y / canvas.height = 0.5 / 50.0 = 0.01
+ // fw = abs(dFdx + dFdy) = 0.01 + 0.01 = 0.02
+ // r = floor(dFdx * 40.0 * 255) = 102
+ // g = floor(dFdy * 40.0 * 255) = 102
+ // b = floor(fw * 40.0 * 255) = 204
+
+ var e = 5; // Amount of variance to allow in result pixels - may need to be tweaked higher
+
+ debug("Testing various draws for valid built-in function behavior");
+
+ canvas.width = 50; canvas.height = 50;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+ gl.hint(ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.NICEST);
+
+ var positionLoc = 0;
+ var texcoordLoc = 1;
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['vPosition', 'texCoord0'], [0, 1]);
+ var quadParameters = wtu.setupUnitQuad(gl, positionLoc, texcoordLoc);
+
+ function expectResult(target, message) {
+ var locations = [
+ [ 0.1, 0.1 ],
+ [ 0.9, 0.1 ],
+ [ 0.1, 0.9 ],
+ [ 0.9, 0.9 ],
+ [ 0.5, 0.5 ]
+ ];
+ for (var n = 0; n < locations.length; n++) {
+ var loc = locations[n];
+ var px = Math.floor(loc[0] * canvas.width);
+ var py = Math.floor(loc[1] * canvas.height);
+ wtu.checkCanvasRect(gl, px, py, 1, 1, target, message, 4);
+ }
+ };
+
+ function setupBuffers(tl, tr, bl, br) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, quadParameters[0]);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 1.0, 1.0, tr,
+ -1.0, 1.0, tl,
+ -1.0, -1.0, bl,
+ 1.0, 1.0, tr,
+ -1.0, -1.0, bl,
+ 1.0, -1.0, br]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
+ };
+
+ // Draw 1: (no variation)
+ setupBuffers(0.0, 0.0, 0.0, 0.0);
+ wtu.clearAndDrawUnitQuad(gl);
+ expectResult([0, 0, 0, 255],
+ "Draw 1 (no variation) should pass");
+
+ // Draw 2: (variation in x)
+ setupBuffers(1.0, 0.0, 1.0, 0.0);
+ wtu.clearAndDrawUnitQuad(gl);
+ expectResult([204, 0, 204, 255],
+ "Draw 2 (variation in x) should pass");
+
+ // Draw 3: (variation in y)
+ setupBuffers(1.0, 1.0, 0.0, 0.0);
+ wtu.clearAndDrawUnitQuad(gl);
+ expectResult([0, 204, 204, 255],
+ "Draw 3 (variation in y) should pass");
+
+ // Draw 4: (variation in x & y)
+ setupBuffers(1.0, 0.5, 0.5, 0.0);
+ wtu.clearAndDrawUnitQuad(gl);
+ expectResult([102, 102, 204, 255],
+ "Draw 4 (variation in x & y) should pass");
+}
+
+function runUniqueObjectTest()
+{
+ debug("Testing that getExtension() returns the same object each time");
+ ext = null;
+ gl.getExtension("OES_standard_derivatives").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("OES_standard_derivatives").myProperty', '2');
+}
+
+function runDeferredLinkTests() {
+ debug("");
+ debug("Testing deferred shader compilation tests.");
+
+ // Test for compilation failures that are caused by missing extensions
+ // do not succeed if extensions are enabled during linking. This would
+ // only happen for deferred shader compilations.
+
+ // First test if link succeeds with extension enabled.
+ var glEnabled = wtu.create3DContext();
+ var extEnabled = glEnabled.getExtension("OES_standard_derivatives");
+ if (!extEnabled) {
+ testFailed("Deferred link test expects the extension to be supported");
+ }
+
+ var vertexShader = wtu.loadShaderFromScript(glEnabled, "goodVertexShader");
+ var fragmentShader = wtu.loadShaderFromScript(glEnabled, "macroFragmentShader");
+
+ if (!vertexShader || !fragmentShader) {
+ testFailed("Could not create good shaders.");
+ return;
+ }
+
+ var program = wtu.setupProgram(glEnabled, [vertexShader, fragmentShader]);
+
+ if (!program) {
+ testFailed("Compilation with extension enabled failed.");
+ return;
+ }
+
+ // Create new context to test link failure without extension enabled.
+ var glDeferred = wtu.create3DContext();
+
+ var vertexShader = wtu.loadShaderFromScript(glDeferred, "goodVertexShader", glDeferred.VERTEX_SHADER, undefined, undefined, true);
+ var fragmentShader = wtu.loadShaderFromScript(glDeferred, "macroFragmentShader", glDeferred.FRAGMENT_SHADER, undefined, undefined, true);
+
+ if (vertexShader == null || fragmentShader == null) {
+ testFailed("Could not create shaders.");
+ return;
+ }
+
+ // Shader compilations should have failed due to extensions not enabled.
+ glDeferred.getExtension("OES_standard_derivatives");
+ var program = wtu.setupProgram(glDeferred, [vertexShader, fragmentShader]);
+ if (program) {
+ testFailed("Compilation with extension disabled then linking with extension enabled should have failed.");
+ return;
+ }
+
+ testPassed("Compilation with extension disabled then linking with extension enabled.");
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-linear.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-linear.html
new file mode 100644
index 0000000000..2c8f194e82
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-linear.html
@@ -0,0 +1,42 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/oes-texture-float-and-half-float-linear.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+
+description("Test OES_texture_float_linear, if available.");
+
+const wtu = WebGLTestUtils;
+const gl = wtu.create3DContext();
+
+(function() {
+ if (!wtu.isWebGL2(gl)) {
+ if (!gl.getExtension("OES_texture_float")) {
+ testPassed("No OES_texture_float support -- this is legal");
+ return;
+ }
+ }
+ testTexLinear(gl, "OES_texture_float_linear", "RGBA32F", "FLOAT");
+})();
+
+debug("");
+const successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-canvas.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-canvas.html
new file mode 100644
index 0000000000..b681083899
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-canvas.html
@@ -0,0 +1,34 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-canvas.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ if (!gl.getExtension("OES_texture_float")) {
+ testPassed("No OES_texture_float support -- this is legal");
+ return false;
+ }
+
+ testPassed("Successfully enabled OES_texture_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "FLOAT", testPrologue, "../../resources/")()'>
+<canvas id="example" width="32" height="32"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image-data.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image-data.html
new file mode 100644
index 0000000000..74ad8d27db
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image-data.html
@@ -0,0 +1,35 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-image-data.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ if (!gl.getExtension("OES_texture_float")) {
+ testPassed("No OES_texture_float support -- this is legal");
+ return false;
+ }
+
+ testPassed("Successfully enabled OES_texture_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "FLOAT", testPrologue, "../../resources/")()'>
+<canvas id="texcanvas" width="2" height="2"></canvas>
+<canvas id="example" width="2" height="2"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image.html
new file mode 100644
index 0000000000..cff19e5d51
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-image.html
@@ -0,0 +1,34 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-image.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ if (!gl.getExtension("OES_texture_float")) {
+ testPassed("No OES_texture_float support -- this is legal");
+ return false;
+ }
+
+ testPassed("Successfully enabled OES_texture_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "FLOAT", testPrologue, "../../resources/")()'>
+<canvas id="example" width="32" height="32"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html
new file mode 100644
index 0000000000..3ccbd50f15
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html
@@ -0,0 +1,39 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-video.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ if (!gl.getExtension("OES_texture_float")) {
+ testPassed("No OES_texture_float support -- this is legal");
+ return false;
+ }
+
+ testPassed("Successfully enabled OES_texture_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "FLOAT", testPrologue, "../../resources/")()'>
+<canvas id="example" width="32" height="32"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<video width="640" height="228" id="vid" controls muted>
+ <source src="../../resources/red-green.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
+ <source src="../../resources/red-green.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' />
+ <source src="../../resources/red-green.theora.ogv" type='video/ogg; codecs="theora, vorbis"' />
+</video>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html
new file mode 100644
index 0000000000..a757cb22ec
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html
@@ -0,0 +1,426 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>OES_texture_float/WEBGL_color_buffer_float</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/ext-float-blend.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing floating-point textures -->
+<script id="testFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D tex;
+uniform vec4 subtractor;
+varying vec2 texCoord;
+void main()
+{
+ vec4 color = texture2D(tex, texCoord);
+ if (abs(color.r - subtractor.r) +
+ abs(color.g - subtractor.g) +
+ abs(color.b - subtractor.b) +
+ abs(color.a - subtractor.a) < 8.0) {
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+}
+</script>
+<!-- Shaders for testing floating-point render targets -->
+<script id="positionVertexShader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+void main()
+{
+ gl_Position = vPosition;
+}
+</script>
+<script id="floatingPointFragmentShader" type="x-shader/x-fragment">
+void main()
+{
+ gl_FragColor = vec4(10000.0, 10000.0, 10000.0, 10000.0);
+}
+</script>
+<script>
+"use strict";
+description("This test verifies the functionality of the OES_texture_float and WEBGL_color_buffer_float extensions, if available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ var texturedShaders = [
+ wtu.simpleTextureVertexShader,
+ "testFragmentShader"
+ ];
+ var testProgram =
+ wtu.setupProgram(gl,
+ texturedShaders,
+ ['vPosition', 'texCoord0'],
+ [0, 1]);
+ var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
+
+ // First verify that allocation of floating-point textures fails if
+ // the extension has not been enabled yet.
+ runTextureCreationTest(testProgram, false);
+
+ if (!gl.getExtension("OES_texture_float")) {
+ testPassed("No OES_texture_float support -- this is legal");
+ } else {
+ testPassed("Successfully enabled OES_texture_float extension");
+ // If alpha value is missing from a texture it gets filled to 1 when sampling according to GLES2.0 table 3.12
+ runTextureCreationTest(testProgram, true, gl.RGBA, 4, [10000, 10000, 10000, 10000]);
+ runTextureCreationTest(testProgram, true, gl.RGB, 3, [10000, 10000, 10000, 1]);
+ runTextureCreationTest(testProgram, true, gl.LUMINANCE, 1, [10000, 10000, 10000, 1]);
+ runTextureCreationTest(testProgram, true, gl.ALPHA, 1, [0, 0, 0, 10000]);
+ runTextureCreationTest(testProgram, true, gl.LUMINANCE_ALPHA, 2, [10000, 10000, 10000, 10000]);
+
+ (function() {
+ debug("");
+ var renderable = isRenderable(gl);
+ var renderableExtName = "WEBGL_color_buffer_float";
+ var supported = gl.getSupportedExtensions().includes(renderableExtName);
+ if (renderable && !supported) {
+ testFailed("RGBA/FLOAT is color renderable but " + renderableExtName + " not exposed");
+ } else if (supported && !renderable) {
+ testFailed(renderableExtName + " is exposed but RGBA/FLOAT is not color renderable");
+ }
+ if (supported) {
+ runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 0, true);
+ runRenderTargetAndReadbackTest(testProgram, gl.RGB, 3, [10000, 10000, 10000, 1], 0, false);
+ runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 1, true);
+ runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 0.5, true);
+ runFramebufferTest();
+
+ debug("");
+ debug("Test float32 blending without EXT_float_blend.");
+ testExtFloatBlend(gl.RGBA);
+
+ debug("");
+ debug("Testing that float32 blending succeeds with EXT_float_blend.");
+ if (!gl.getExtension("EXT_float_blend")) {
+ testPassed("No EXT_float_blend support -- this is legal");
+ return;
+ }
+ testExtFloatBlend(gl.RGBA);
+ }
+ })();
+
+ runUniqueObjectTest();
+ }
+}
+
+function isRenderable(gl) {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ var fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+
+ var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+
+ return status == gl.FRAMEBUFFER_COMPLETE;
+}
+
+function allocateTexture()
+{
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed");
+ return texture;
+}
+
+function checkRenderingResults()
+{
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+}
+
+function runTextureCreationTest(testProgram, extensionEnabled, opt_format, opt_numChannels, opt_subtractor)
+{
+ var format = opt_format || gl.RGBA;
+ var numberOfChannels = opt_numChannels || 4;
+ var expectFailure = !extensionEnabled;
+ var subtractor = opt_subtractor || [10000, 10000, 10000, 10000];
+
+ debug("");
+ debug("testing format: " + wtu.glEnumToString(gl, format) +
+ " expect:" + (extensionEnabled ? "success" : "failure"));
+
+ var texture = allocateTexture();
+ // Generate data.
+ var width = 2;
+ var height = 2;
+ var data = new Float32Array(width * height * numberOfChannels);
+ for (var ii = 0; ii < data.length; ++ii) {
+ data[ii] = 10000;
+ }
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, gl.FLOAT, data);
+ if (expectFailure) {
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "floating-point texture allocation must be disallowed if OES_texture_float isn't enabled");
+ return;
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed if OES_texture_float is enabled");
+ }
+ // Verify that the texture actually works for sampling and contains the expected data.
+ gl.uniform4fv(gl.getUniformLocation(testProgram, "subtractor"), subtractor);
+ wtu.clearAndDrawUnitQuad(gl);
+ checkRenderingResults();
+
+ // Check that linear fails.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
+}
+
+function arrayToString(arr, size) {
+ var mySize;
+ if (!size)
+ mySize = arr.length;
+ else
+ mySize = size;
+ var out = "[";
+ for (var ii = 0; ii < mySize; ++ii) {
+ if (ii > 0) {
+ out += ", ";
+ }
+ out += arr[ii];
+ }
+ return out + "]";
+}
+
+function runRenderTargetAndReadbackTest(testProgram, format, numberOfChannels, subtractor, texSubImageCover, requireRenderable)
+{
+ var formatString = wtu.glEnumToString(gl, format);
+ debug("");
+ debug("testing floating-point " + formatString + " render target" + (texSubImageCover > 0 ? " after calling texSubImage" : ""));
+
+ var texture = allocateTexture();
+ var width = 2;
+ var height = 2;
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, gl.FLOAT, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed if OES_texture_float is enabled");
+
+ // Try to use this texture as a render target.
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ // It is legal for a WebGL implementation exposing the OES_texture_float extension to
+ // support floating-point textures but not as attachments to framebuffer objects.
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ if (requireRenderable)
+ testFailed("floating-point " + formatString + " render target not supported");
+ else
+ debug("floating-point " + formatString + " render target not supported -- this is legal");
+ return;
+ }
+
+ if (texSubImageCover > 0) {
+ // Ensure that replacing the whole texture or a part of it with texSubImage2D doesn't affect renderability
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ var data = new Float32Array(width * height * numberOfChannels * texSubImageCover);
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height * texSubImageCover, format, gl.FLOAT, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texSubImage2D should succeed if OES_texture_float is enabled");
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("render target support changed after calling texSubImage2D");
+ return;
+ }
+ }
+
+ var renderProgram =
+ wtu.setupProgram(gl,
+ ["positionVertexShader", "floatingPointFragmentShader"],
+ ['vPosition'],
+ [0]);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering to floating-point texture should succeed");
+
+ // Now sample from the floating-point texture and verify we got the correct values.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.useProgram(testProgram);
+ gl.uniform1i(gl.getUniformLocation(testProgram, "tex"), 0);
+ gl.uniform4fv(gl.getUniformLocation(testProgram, "subtractor"), subtractor);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering from floating-point texture should succeed");
+ checkRenderingResults();
+
+ // Finally, if the implementation supports floating-point readback, verify it.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+ var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getParameter of IMPLEMENTATION_COLOR_READ_{FORMAT|TYPE} should succeed");
+ if ((implFormat == gl.RGBA || implFormat == gl.RGB) && implType == gl.FLOAT) {
+ debug("Checking readback of floating-point values");
+ var arraySize = (implFormat == gl.RGBA) ? 4 : 3
+ var buf = new Float32Array(arraySize);
+ gl.readPixels(0, 0, 1, 1, implFormat, implType , buf);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels from floating-point renderbuffer should succeed");
+ var ok = true;
+ var tolerance = 8.0; // TODO: factor this out from both this test and the subtractor shader above.
+ for (var ii = 0; ii < buf.length; ++ii) {
+ if (Math.abs(buf[ii] - subtractor[ii]) > tolerance) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ testPassed("readPixels of float-type data from floating-point renderbuffer succeeded");
+ } else {
+ testFailed("readPixels of float-type data from floating-point renderbuffer failed: expected "
+ + arrayToString(subtractor, arraySize) + ", got " + arrayToString(buf));
+ }
+ }
+}
+
+function runUniqueObjectTest()
+{
+ debug("");
+ debug("Testing that getExtension() returns the same object each time");
+ gl.getExtension("OES_texture_float").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("OES_texture_float").myProperty', '2');
+}
+
+// Make sure we can call readPixels with the passed in arrayBufferConstructor and that the color
+// channels are the ones we expect. If there is a mismatch between the glType and arrayBuffer type,
+// fail the test.
+function verifyReadPixelsColors(red, green, blue, alpha, alphaRGB, glFormat, glType, arrayBufferConstructor) {
+ var typeName = wtu.glEnumToString(gl, glType);
+
+ debug(wtu.glEnumToString(gl, glFormat) + " framebuffer with " + typeName + " readback.");
+
+ var arrayBuffer = new arrayBufferConstructor(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should return NO_ERROR when reading " + typeName + " data.");
+
+ assertMsg(arrayBuffer[0] === red, "Red channel should be " + red + " for " + typeName + " readPixels. Received: " + arrayBuffer[0]);
+ assertMsg(arrayBuffer[1] === green, "Green channel should be " + green + " for " + typeName + " readPixels. Received: " + arrayBuffer[1]);
+ assertMsg(arrayBuffer[2] === blue, "Blue channel should be " + blue + " for " + typeName + " readPixels. Received: " + arrayBuffer[2]);
+ if (glFormat === gl.RGBA) {
+ assertMsg(arrayBuffer[3] === alpha, "Alpha channel should be " + alpha + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
+ } else if (glFormat === gl.RGB) {
+ assertMsg(arrayBuffer[3] === alphaRGB, "Alpha channel should be " + alphaRGB + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
+ }
+
+ // Make sure any arrayBuffer types that are not equal to arrayBufferConstructor fail readPixels.
+ if (arrayBufferConstructor !== Uint8Array) {
+ arrayBuffer = new Uint8Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint8Array.toString());
+ }
+ if (arrayBufferConstructor !== Float32Array) {
+ arrayBuffer = new Float32Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Float32Array.toString());
+ }
+ if (arrayBufferConstructor !== Uint16Array) {
+ arrayBuffer = new Uint16Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint16Array.toString());
+ }
+}
+
+// Verify that float textures attached to frame buffers function correctly with regard to framebuffer
+// completness, IMPLEMENTATION_COLOR_READ_FORMAT/TYPE and readPixels
+function runFramebufferTest() {
+ debug("");
+ debug("Framebuffer Tests");
+
+ var texture = allocateTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+
+ debug("Ensure non-color-renderable formats [LUMINANCE, LUMINANCE_ALPHA, ALPHA] fail.");
+ var arrayBufferFloatOutput = new Float32Array(4); // 4 color channels
+ [gl.LUMINANCE, gl.LUMINANCE_ALPHA, gl.ALPHA].forEach(function(badFormat) {
+ debug(wtu.glEnumToString(gl, badFormat) + " framebuffer");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, badFormat, 1, 1, 0, badFormat, gl.FLOAT, null);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+
+ shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.");
+
+ shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_TYPE should fail for incomplete framebuffers.");
+
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, arrayBufferFloatOutput);
+ wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION , "readPixels should fail on incomplete framebuffers.");
+ debug("");
+ });
+
+ debug("Ensure color renderable formats [RGBA, RGB] succeed.");
+ var arrayBufferFloatInput = new Float32Array(4); // 4 color channels
+ arrayBufferFloatInput[0] = 0;
+ arrayBufferFloatInput[1] = .25;
+ arrayBufferFloatInput[2] = .50;
+ arrayBufferFloatInput[3] = .75;
+
+ [gl.RGBA, gl.RGB].forEach(function(goodFormat) {
+ debug("");
+ debug(wtu.glEnumToString(gl, goodFormat) + " framebuffer tests");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, goodFormat, 1, 1, 0, goodFormat, gl.FLOAT, arrayBufferFloatInput);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testPassed("Format is not renderable. This is allowed.");
+ return;
+ }
+ verifyReadPixelsColors(
+ 0.00, // red
+ 0.25, // green
+ 0.50, // blue
+ 0.75, // alpha
+ 1.0, // alphaRGB
+ goodFormat,
+ gl.FLOAT,
+ Float32Array);
+
+ var implementationColorReadFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+ assertMsg(implementationColorReadFormat === gl.RGBA || implementationColorReadFormat === gl.RGB,
+ "IMPLEMENTATION_COLOR_READ_FORMAT should be color renderable: RGBA or RGB. Received: " + wtu.glEnumToString(gl, implementationColorReadFormat));
+
+ var implementationColorReadType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+ assertMsg(implementationColorReadType === gl.UNSIGNED_BYTE ||
+ implementationColorReadType === gl.FLOAT ||
+ "IMPLEMENTATION_COLOR_READ_TYPE must be one of UNSIGNED_BYTE or FLOAT " +
+ "Received: " + wtu.glEnumToString(gl, implementationColorReadType));
+ });
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-linear.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-linear.html
new file mode 100644
index 0000000000..459346857e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-linear.html
@@ -0,0 +1,46 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/oes-texture-float-and-half-float-linear.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+
+description("Test OES_texture_half_float_linear, if available.");
+
+const wtu = WebGLTestUtils;
+const gl = wtu.create3DContext();
+
+(function() {
+ if (wtu.isWebGL2(gl))
+ throw new Error("OES_texture_half_float_linear is core in WebGL 2.");
+
+ const ext = gl.getExtension("OES_texture_half_float");
+ if (!ext) {
+ testPassed("No OES_texture_half_float support -- this is legal");
+ return;
+ }
+ // Required by the test harness.
+ gl.HALF_FLOAT_OES = ext.HALF_FLOAT_OES;
+ testTexLinear(gl, "OES_texture_half_float_linear", undefined, "HALF_FLOAT_OES");
+})();
+
+debug("");
+const successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-canvas.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-canvas.html
new file mode 100644
index 0000000000..b991c58b19
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-canvas.html
@@ -0,0 +1,39 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-canvas.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ var ext = null;
+
+ if (!(ext = gl.getExtension("OES_texture_half_float"))) {
+ testPassed("No OES_texture_half_float support -- this is legal");
+ return false;
+ }
+
+ // Required by the test harness.
+ gl.HALF_FLOAT_OES = ext.HALF_FLOAT_OES;
+
+ testPassed("Successfully enabled OES_texture_half_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "HALF_FLOAT_OES", testPrologue, "../../resources/")()'>
+<canvas id="example" width="32" height="32"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image-data.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image-data.html
new file mode 100644
index 0000000000..91f3f97b08
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image-data.html
@@ -0,0 +1,40 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-image-data.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ var ext = null;
+
+ if (!(ext = gl.getExtension("OES_texture_half_float"))) {
+ testPassed("No OES_texture_half_float support -- this is legal");
+ return false;
+ }
+
+ // Required by the test harness.
+ gl.HALF_FLOAT_OES = ext.HALF_FLOAT_OES;
+
+ testPassed("Successfully enabled OES_texture_half_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "HALF_FLOAT_OES", testPrologue, "../../resources/")()'>
+<canvas id="texcanvas" width="2" height="2"></canvas>
+<canvas id="example" width="2" height="2"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image.html
new file mode 100644
index 0000000000..3f486eac0e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-image.html
@@ -0,0 +1,39 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-image.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ var ext = null;
+
+ if (!(ext = gl.getExtension("OES_texture_half_float"))) {
+ testPassed("No OES_texture_half_float support -- this is legal");
+ return false;
+ }
+
+ // Required by the test harness.
+ gl.HALF_FLOAT_OES = ext.HALF_FLOAT_OES;
+
+ testPassed("Successfully enabled OES_texture_half_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "HALF_FLOAT_OES", testPrologue, "../../resources/")()'>
+<canvas id="example" width="32" height="32"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html
new file mode 100644
index 0000000000..719b332113
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html
@@ -0,0 +1,44 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-utils.js"></script>
+<script src="../../js/tests/tex-image-and-sub-image-2d-with-video.js"></script>
+<script>
+"use strict";
+function testPrologue(gl) {
+ var ext = null;
+
+ if (!(ext = gl.getExtension("OES_texture_half_float"))) {
+ testPassed("No OES_texture_half_float support -- this is legal");
+ return false;
+ }
+
+ // Required by the test harness.
+ gl.HALF_FLOAT_OES = ext.HALF_FLOAT_OES;
+
+ testPassed("Successfully enabled OES_texture_half_float extension");
+ return true;
+}
+</script>
+</head>
+<body onload='generateTest("RGBA", "RGBA", "HALF_FLOAT_OES", testPrologue, "../../resources/")()'>
+<canvas id="example" width="32" height="32"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<video width="640" height="228" id="vid" controls muted>
+ <source src="../../resources/red-green.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
+ <source src="../../resources/red-green.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' />
+ <source src="../../resources/red-green.theora.ogv" type='video/ogg; codecs="theora, vorbis"' />
+</video>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float.html
new file mode 100644
index 0000000000..4d5d81608a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float.html
@@ -0,0 +1,474 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL OES_texture_half_float Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<canvas id="canvas2d" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<script id="testFragmentShader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D tex;
+uniform vec4 subtractor;
+varying vec2 texCoord;
+void main()
+{
+ vec4 color = texture2D(tex, texCoord);
+ if (abs(color.r - subtractor.r) +
+ abs(color.g - subtractor.g) +
+ abs(color.b - subtractor.b) +
+ abs(color.a - subtractor.a) < 8.0) {
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+}
+</script>
+<!-- Shaders for testing half-floating-point render targets -->
+<script id="floatingPointFragmentShader" type="x-shader/x-fragment">
+void main()
+{
+ gl_FragColor = vec4(10000.0, 10000.0, 10000.0, 10000.0);
+}
+</script>
+<script>
+"use strict"
+description("This test verifies the functionality of OES_texture_half_float with null/non-null ArrayBufferView");
+
+debug("");
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var colorCanvas = document.getElementById("canvas2d");
+colorCanvas.width = 2;
+colorCanvas.height = 2;
+var ctx = colorCanvas.getContext("2d");
+ctx.fillStyle = "rgb(255,0,0)";
+ctx.fillRect(0, 0, 2, 2);
+var gl = wtu.create3DContext(canvas);
+// This constant must be defined in order to run the texture creation test without the extension enabled.
+var halfFloatOESEnum = 0x8D61;
+var ext = null;
+
+
+if (!gl) {
+ testFailed("WebGL context does not exists");
+} else {
+ testPassed("WebGL context exists");
+
+ // Verify that allocation of texture fails if extension is not enabled
+ runTextureCreationTest(false);
+ ext = gl.getExtension("OES_texture_half_float")
+ if (!ext) {
+ testPassed("No OES_texture_half_float support. This is legal");
+ } else {
+ testPassed("Successfully enabled OES_texture_half_float extension");
+
+ var program = wtu.setupTexturedQuad(gl);
+
+ // Check if creation of texture succeed's with various formats and null ArrayBufferView
+ var formats = [
+ { format: gl.RGBA, expected: [255, 0, 0, 255], },
+ { format: gl.RGB, expected: [255, 0, 0, 255], },
+ { format: gl.LUMINANCE, expected: [255, 255, 255, 255], },
+ { format: gl.ALPHA, expected: [ 0, 0, 0, 255], },
+ { format: gl.LUMINANCE_ALPHA, expected: [255, 255, 255, 255], },
+ ];
+ formats.forEach(function(f) {
+ runTextureCreationTest(true, f.format, null, f.expected);
+ });
+
+ // Texture creation should fail when passed with non-null, non-Uint16 ArrayBufferView
+ formats.forEach(function(f) {
+ var width = 2;
+ var height = 2;
+ var format = f.format;
+
+ // Float32Array
+ var float32Data = new Float32Array(width * height * getNumberOfChannels(format));
+ for (var ii = 0; ii < float32Data.length; ii++) {
+ float32Data[ii] = 1000;
+ }
+ runTextureCreationTest(true, format, float32Data, null);
+
+ // Int16Array
+ var int16Data = new Int16Array(width * height * getNumberOfChannels(format));
+ for (var ii = 0; ii < int16Data.length; ii++) {
+ int16Data[ii] = 1000;
+ }
+ runTextureCreationTest(true, format, int16Data, null);
+ });
+
+ // Test that Uint16 encoded half float values can be used as texture data.
+
+ // First test that values in the 0-1 range can be written and read.
+ var halfFloatOneThird = 0x3555; // Half float 1/3
+ var uint16Formats = [
+ { format: gl.RGBA, expected: [85, 85, 85, 85], },
+ { format: gl.RGB, expected: [85, 85, 85, 255], },
+ { format: gl.LUMINANCE, expected: [85, 85, 85, 255], },
+ { format: gl.ALPHA, expected: [ 0, 0, 0, 85], },
+ { format: gl.LUMINANCE_ALPHA, expected: [85, 85, 85, 85], },
+ ];
+
+ uint16Formats.forEach(function(f) {
+ var width = 2;
+ var height = 2;
+ var format = f.format;
+
+ var uint16Data = new Uint16Array(width * height * getNumberOfChannels(format));
+ for (var ii = 0; ii < uint16Data.length; ii++) {
+ uint16Data[ii] = halfFloatOneThird;
+ }
+ runTextureCreationTest(true, format, uint16Data, f.expected);
+ });
+
+ // Next check that values outside the 0-1 range can be written.
+ var halfFloatTenK = 0x70E2; // Half float 10000
+ var uint16Formats2 = [
+ { format: gl.RGBA, subtractor: [10000, 10000, 10000, 10000], requireRenderable: true},
+ { format: gl.RGB, subtractor: [10000, 10000, 10000, 1], requireRenderable: false},
+ ];
+
+ uint16Formats2.forEach(function(f) {
+ var width = 2;
+ var height = 2;
+ var format = f.format;
+
+ var uint16Data = new Uint16Array(width * height * getNumberOfChannels(format));
+ for (var ii = 0; ii < uint16Data.length; ii++) {
+ uint16Data[ii] = halfFloatTenK;
+ }
+ runRenderTest(format, f.subtractor, uint16Data, f.requireRenderable);
+ });
+
+ (function() {
+ debug("");
+ var renderable = isRenderable(gl, ext);
+ var renderableExtName = "EXT_color_buffer_half_float";
+ var supported = gl.getSupportedExtensions().includes(renderableExtName);
+ if (renderable && !supported) {
+ testFailed("RGBA/HALF_FLOAT_OES is color renderable but " + renderableExtName + " not exposed");
+ } else if (supported && !renderable) {
+ testFailed(renderableExtName + " is exposed but RGBA/HALF_FLOAT_OES is not color renderable");
+ }
+ if (supported) {
+ runRenderTest(gl.RGBA, [10000, 10000, 10000, 10000], null, true);
+ runRenderTest(gl.RGB, [10000, 10000, 10000, 1], null, false);
+ runFramebufferTest();
+ }
+ })();
+
+ // Check of getExtension() returns same object
+ runUniqueObjectTest();
+ }
+}
+
+function isRenderable(gl, ext) {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, ext.HALF_FLOAT_OES, null);
+
+ var fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+
+ var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+
+ return status == gl.FRAMEBUFFER_COMPLETE;
+}
+
+function getNumberOfChannels(format)
+{
+ if (format == gl.RGBA)
+ return 4;
+ else if (format == gl.RGB)
+ return 3;
+ else if (format == gl.LUMINANCE || format == gl.ALPHA)
+ return 1;
+ else if (format == gl.LUMINANCE_ALPHA)
+ return 2;
+}
+
+function allocateTexture()
+{
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed");
+ return texture;
+}
+
+function runTextureCreationTest(extensionEnabled, opt_format, opt_data, opt_expected)
+{
+ var format = opt_format || gl.RGBA;
+ var data = opt_data || null;
+ var expectSuccess = true;
+
+ if (!extensionEnabled || !opt_expected)
+ expectSuccess = false;
+ debug("Testing texture creation with extension " + (extensionEnabled ? "enabled" : "disabled") +
+ ", format " + wtu.glEnumToString(gl, format) + ", and data " + (data ? "non-null" : "null") +
+ ". Expect " + (expectSuccess ? "Success" : "Failure"));
+
+ var texture = allocateTexture();
+ var width = 2;
+ var height = 2;
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, halfFloatOESEnum, data);
+ if(!extensionEnabled) {
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Half floating point texture must be disallowed if OES_texture_half_float isn't enabled");
+ return;
+ } else if (!opt_expected) {
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Half floating point texture allocation must be disallowed when ArrayBufferView is not-null and not-Uint16");
+ return;
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Half floating point texture allocation should succeed if OES_texture_half_float is enabled");
+
+ if (!data) {
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, format, halfFloatOESEnum, colorCanvas);
+ }
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, opt_expected);
+ // Check that linear fails.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 0, 0, 255], "should be black");
+ }
+
+}
+
+function checkRenderingResults()
+{
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+}
+
+function runRenderTest(format, subtractor, data, requireRenderable)
+{
+ var formatString = wtu.glEnumToString(gl, format);
+
+ debug("");
+
+ if (!data) {
+ debug("Testing half floating point " + formatString + " render target");
+ } else {
+ debug("Testing half floating point " + formatString + " from a Uint16Array");
+ }
+
+ var texture = allocateTexture();
+ var width = 2;
+ var height = 2;
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, ext.HALF_FLOAT_OES, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Half floating point texture allocation should succeed if OES_texture_half_float is enabled");
+
+ if (!data) {
+ // Try to use this texture as render target
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ // It is legal for a WebGL implementation exposing the OES_texture_half_float extension to
+ // support half floating point textures but not as attachments to framebuffer objects.
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ if (requireRenderable) {
+ testFailed(formatString + " render targets not supported.");
+ } else {
+ debug(formatString + " render targets not supported -- this is legal");
+ }
+ return;
+ }
+
+ var renderProgram =
+ wtu.setupProgram(gl,
+ [wtu.simpleVertexShader, "floatingPointFragmentShader"],
+ ['vPosition'],
+ [0]);
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Rendering to half floating point texture should succeed");
+ }
+
+ // Now sample from the half floating-point texture and verify we got the correct values.
+ var texturedShaders = [
+ wtu.simpleTextureVertexShader,
+ "testFragmentShader"
+ ];
+ var testProgram =
+ wtu.setupProgram(gl,
+ [wtu.simpleTextureVertexShader, "testFragmentShader"],
+ ['vPosition', 'texCoord0'],
+ [0, 1]);
+ var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.useProgram(testProgram);
+ gl.uniform4fv(gl.getUniformLocation(testProgram, "subtractor"), subtractor);
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering from half floating point texture should succeed");
+ checkRenderingResults();
+}
+
+function runUniqueObjectTest()
+{
+ debug("");
+ debug("Testing that getExtension() returns the same object each time");
+ ext = null;
+ gl.getExtension("OES_texture_half_float").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("OES_texture_half_float").myProperty', '2');
+}
+
+// Make sure we can call readPixels with the passed in arrayBufferConstructor and that the color
+// channels are the ones we expect. If there is a mismatch between the glType and arrayBuffer type,
+// fail the test.
+function verifyReadPixelsColors(red, green, blue, alpha, alphaRGB, glFormat, glType, arrayBufferConstructor) {
+ var typeName = wtu.glEnumToString(gl, glType);
+
+ debug(wtu.glEnumToString(gl, glFormat) + " framebuffer with " + typeName + " readback.");
+
+ var arrayBuffer = new arrayBufferConstructor(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should return NO_ERROR when reading " + typeName + " data.");
+
+ assertMsg(arrayBuffer[0] === red, "Red channel should be " + red + " for " + typeName + " readPixels. Received: " + arrayBuffer[0]);
+ assertMsg(arrayBuffer[1] === green, "Green channel should be " + green + " for " + typeName + " readPixels. Received: " + arrayBuffer[1]);
+ assertMsg(arrayBuffer[2] === blue, "Blue channel should be " + blue + " for " + typeName + " readPixels. Received: " + arrayBuffer[2]);
+ if (glFormat === gl.RGBA) {
+ assertMsg(arrayBuffer[3] === alpha, "Alpha channel should be " + alpha + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
+ } else if (glFormat === gl.RGB) {
+ assertMsg(arrayBuffer[3] === alphaRGB, "Alpha channel should be " + alphaRGB + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
+ }
+
+ // Make sure any arrayBuffer types that are not equal to arrayBufferConstructor fail readPixels.
+ if (arrayBufferConstructor !== Uint8Array) {
+ arrayBuffer = new Uint8Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint8Array.toString());
+ }
+ if (arrayBufferConstructor !== Float32Array) {
+ arrayBuffer = new Float32Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Float32Array.toString());
+ }
+ if (arrayBufferConstructor !== Uint16Array) {
+ arrayBuffer = new Uint16Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint16Array.toString());
+ }
+}
+
+// Verify that half float textures attached to frame buffers function correctly with regard to framebuffer
+// completness, IMPLEMENTATION_COLOR_READ_FORMAT/TYPE and readPixels
+function runFramebufferTest() {
+ debug("");
+ debug("Framebuffer Tests");
+
+ var texture = allocateTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+
+ debug("Ensure non-color-renderable formats [LUMINANCE, LUMINANCE_ALPHA, ALPHA] fail.");
+ var arrayBufferFloatOutput = new Float32Array(4); // 4 color channels
+ [gl.LUMINANCE, gl.LUMINANCE_ALPHA, gl.ALPHA].forEach(function(badFormat) {
+ debug(wtu.glEnumToString(gl, badFormat) + " framebuffer");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, badFormat, 1, 1, 0, badFormat, ext.HALF_FLOAT_OES, null);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+
+ shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.");
+
+ shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_TYPE should fail for incomplete framebuffers.");
+
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, arrayBufferFloatOutput);
+ wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION , "readPixels should fail on incomplete framebuffers.");
+ debug("");
+ });
+
+ debug("Ensure color renderable formats [RGBA, RGB] succeed.");
+ var arrayBufferHalfFloatInput = new Uint16Array(4); // 4 color channels
+ arrayBufferHalfFloatInput[0] = 0; // 0 in half float
+ arrayBufferHalfFloatInput[1] = 0x3400; // 0.25 in half float
+ arrayBufferHalfFloatInput[2] = 0x3800; // 0.50 in half float
+ arrayBufferHalfFloatInput[3] = 0x3A00; // 0.75 in half float
+
+ [gl.RGBA, gl.RGB].forEach(function(goodFormat) {
+ debug(wtu.glEnumToString(gl, goodFormat) + " framebuffer tests");
+ debug("");
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, goodFormat, 1, 1, 0, goodFormat, ext.HALF_FLOAT_OES, arrayBufferHalfFloatInput);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ // Per the OES_color_buffer_half_float, RGBA/FLOAT should always succeed for readPixels
+ verifyReadPixelsColors(
+ 0.00, // red
+ 0.25, // green
+ 0.50, // blue
+ 0.75, // alpha
+ 1.0, // alphaRGB
+ goodFormat,
+ gl.FLOAT,
+ Float32Array);
+
+ var implementationColorReadFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+ assertMsg(implementationColorReadFormat === gl.RGBA || implementationColorReadFormat === gl.RGB,
+ "IMPLEMENTATION_COLOR_READ_FORMAT should be color renderable: RGBA or RGB. Received: " + wtu.glEnumToString(gl, implementationColorReadFormat));
+
+ var implementationColorReadType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+
+ // There is nothing in the specifications that keeps the
+ // implementation color read format and type from being the
+ // same as the implicitly supported one. For this reason, keep
+ // gl.FLOAT as one of the valid options.
+ assertMsg(implementationColorReadType === gl.UNSIGNED_BYTE ||
+ implementationColorReadType === gl.FLOAT ||
+ implementationColorReadType === ext.HALF_FLOAT_OES ||
+ implementationColorReadType === gl.UNSIGNED_SHORT_4_4_4_4 ||
+ implementationColorReadType === gl.UNSIGNED_SHORT_5_5_5_1 ||
+ implementationColorReadType === gl.UNSIGNED_SHORT_5_6_5,
+ "IMPLEMENTATION_COLOR_READ_TYPE must be one of UNSIGNED_BYTE, UNSIGNED_SHORT_4_4_4_4, UNSIGNED_SHORT_5_5_5_1, UNSIGNED_SHORT_5_6_5, FLOAT, or HALF_FLOAT_OES. " +
+ "Received: " + wtu.glEnumToString(gl, implementationColorReadType));
+
+ // Test the RGBA/HALF_FLOAT_OES combination
+ if (implementationColorReadFormat === gl.RGBA && implementationColorReadType === ext.HALF_FLOAT_OES) {
+ verifyReadPixelsColors(
+ 0, // red
+ 0x3400, // green
+ 0x3800, // blue
+ 0x3A00, // alpha
+ 0x3C00, // alphaRGB
+ goodFormat,
+ ext.HALF_FLOAT_OES,
+ Uint16Array);
+ }
+ }
+ debug("");
+ });
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object-bufferData.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object-bufferData.html
new file mode 100644
index 0000000000..d89e9bcc1b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object-bufferData.html
@@ -0,0 +1,194 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL OES_vertex_array_object_bufferData Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<!-- comment in the script tag below to test through JS emualation of the extension. -->
+<!--
+<script src="../../../demos/google/resources/OESVertexArrayObject.js"></script>
+-->
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 a_position;
+attribute vec4 a_color;
+varying vec4 v_color;
+void main(void) {
+ gl_Position = a_position;
+ v_color = a_color;
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+varying vec4 v_color;
+void main(void) {
+ gl_FragColor = v_color;
+}
+</script>
+<script>
+"use strict";
+description("This test verifies drawing results when using gl.bufferData with the OES_vertex_array_object extension.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+var vao = null;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Setup emulated OESVertexArrayObject if it has been included.
+ if (window.setupVertexArrayObject) {
+ debug("using emuated OES_vertex_array_object");
+ setupVertexArrayObject(gl);
+ }
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("OES_vertex_array_object");
+ if (!ext) {
+ testPassed("No OES_vertex_array_object support -- this is legal");
+
+ } else {
+ testPassed("Successfully enabled OES_vertex_array_object extension");
+
+ runBufferDataTest();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+ }
+}
+
+/**
+ * The OES_vertex_array_object extension seems to work incorrectly on some handheld devices,
+ * namely the Nexus 5, and Nexus 7 (in 2014/01) when using bufferData before binding the VAO.
+ * The tested OS was Android KitKat 4.4.2, the effects were the same in all tested browsers
+ * (Chrome, Chrome Beta, Firefox, Firefox Beta), so it is likely a driver bug.
+ * These devices have the similar Adreno 320 and Adreno 330 GPUs respectively.
+ *
+ * The issuse resulted from this sequence of actions in a requestAnimationFrame loop:
+ * 1. upload some vertex buffers with gl.bufferData (eg. colors)
+ * 2. bind the VAO
+ * 3. clear the canvas
+ * 4. draw (some triangles) to the canvas
+ * 5. unbind the VAO
+ *
+ * This caused the drawn triangles to be drawn with black (0) for most of the frames, with some
+ * rare frames presenting the correct render results. Interestingly on both devices exactly every
+ * 64th frame passed (starting with the very first one), the others failed.
+ * (Because of this, we test multiple frames.)
+ * When positions were uploaded, seemingly nothing was drawn, that's likely because the
+ * position buffer was also all 0s.
+ *
+ * The issue did not occur:
+ * - if step 1. and 2. were swapped
+ * - or if step5 was ommited (probably because that makes step 2 a no-op since the VAO is bound)
+ */
+function runBufferDataTest() {
+ debug("Testing draws with bufferData");
+
+ canvas.width = 50; canvas.height = 50;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var testColor = [0, 255, 0, 255];
+ var clearColor = [255, 0, 0, 255];
+
+ // Where the issue occures, this is the sequence of success/failure every time:
+ // result: success fail fail fail fail ... success fail fail ...
+ // currentTestCount: 0 1 2 3 4 ... 64 65 66 ...
+ // So with just 1 test it passes, but 2 tests are enough. Here we use 3.
+ var numberOfTests = 3;
+ var currentTestCount = 0;
+
+ var positionLoc = 0;
+ var colorLoc = 1;
+ var gridRes = 1;
+
+ var program = wtu.setupSimpleVertexColorProgram(gl, positionLoc, colorLoc);
+
+ var vao0 = ext.createVertexArrayOES();
+ ext.bindVertexArrayOES(vao0);
+
+ var buffers = wtu.setupIndexedQuadWithOptions(gl,
+ { gridRes: gridRes,
+ positionLocation: positionLoc
+ });
+
+ var colorTypedArray = createColorTypedArray();
+
+ var colorBuffer = gl.createBuffer(gl.ARRAY_BUFFER);
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.enableVertexAttribArray(colorLoc);
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
+
+ ext.bindVertexArrayOES(null);
+
+ testDrawing();
+
+ function testDrawing() {
+ // this order works fine:
+ // ext.bindVertexArrayOES(vao0);
+ // uploadColor();
+
+ // this order doesn't:
+ uploadColor();
+ ext.bindVertexArrayOES(vao0);
+
+ wtu.clearAndDrawIndexedQuad(gl, 1, clearColor);
+
+ ext.bindVertexArrayOES(null);
+
+ //debug("<span>"+currentTestCount+"</span");
+ wtu.checkCanvas(gl, testColor, "should be green")
+
+ if (++currentTestCount < numberOfTests) {
+ testDrawing();
+ // wtu.requestAnimFrame(testDrawing);
+ } else {
+ // clean up
+ ext.deleteVertexArrayOES(vao0);
+ }
+ }
+
+ function uploadColor() {
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colorTypedArray, gl.STREAM_DRAW);
+ }
+
+ function createColorTypedArray() {
+ var colors = [];
+ var pOffset = 0;
+ for (var yy = 0; yy <= gridRes; ++yy) {
+ for (var xx = 0; xx <= gridRes; ++xx) {
+ colors[pOffset + 0] = testColor[0];
+ colors[pOffset + 1] = testColor[1];
+ colors[pOffset + 2] = testColor[2];
+ colors[pOffset + 3] = testColor[3];
+ pOffset += 4;
+ }
+ }
+ return new Float32Array(colors);
+ }
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
new file mode 100644
index 0000000000..4d544aeade
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
@@ -0,0 +1,780 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL OES_vertex_array_object Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<!-- comment in the script tag below to test through JS emulation of the extension. -->
+<!--
+<script src="../../../demos/google/resources/OESVertexArrayObject.js"></script>
+-->
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 a_position;
+attribute vec4 a_color;
+varying vec4 v_color;
+void main(void) {
+ gl_Position = a_position;
+ v_color = a_color;
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+varying vec4 v_color;
+void main(void) {
+ gl_FragColor = v_color;
+}
+</script>
+<script>
+"use strict";
+description("This test verifies the functionality of the OES_vertex_array_object extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+var vao = null;
+
+var contextA;
+var contextB;
+var extA;
+var extB;
+var vertexArrayA;
+var vertexArrayB;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Setup emulated OESVertexArrayObject if it has been included.
+ if (window.setupVertexArrayObject) {
+ debug("using emulated OES_vertex_array_object");
+ setupVertexArrayObject(gl);
+ }
+
+ // Run tests with extension disabled
+ runBindingTestDisabled();
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("OES_vertex_array_object");
+ if (!ext) {
+ testPassed("No OES_vertex_array_object support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled OES_vertex_array_object extension");
+
+ runSupportedTest(true);
+ runBindingTestEnabled();
+ runObjectTest();
+ runAttributeTests();
+ runAttributeValueTests();
+ runDrawTests();
+ runUnboundDeleteTests();
+ runBoundDeleteTests();
+ runArrayBufferBindTests();
+ runInvalidContextTests();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("OES_vertex_array_object") >= 0) {
+ if (extensionEnabled) {
+ testPassed("OES_vertex_array_object listed as supported and getExtension succeeded");
+ } else {
+ testFailed("OES_vertex_array_object listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("OES_vertex_array_object not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("OES_vertex_array_object not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runBindingTestDisabled() {
+ debug("");
+ debug("Testing binding enum with extension disabled");
+
+ // Use the constant directly as we don't have the extension
+ var VERTEX_ARRAY_BINDING_OES = 0x85B5;
+
+ gl.getParameter(VERTEX_ARRAY_BINDING_OES);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "VERTEX_ARRAY_BINDING_OES should not be queryable if extension is disabled");
+}
+
+function runBindingTestEnabled() {
+ debug("");
+ debug("Testing binding enum with extension enabled");
+
+ shouldBe("ext.VERTEX_ARRAY_BINDING_OES", "0x85B5");
+
+ gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "VERTEX_ARRAY_BINDING_OES query should succeed if extension is enabled");
+
+ // Default value is null
+ if (gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) === null) {
+ testPassed("Default value of VERTEX_ARRAY_BINDING_OES is null");
+ } else {
+ testFailed("Default value of VERTEX_ARRAY_BINDING_OES is not null");
+ }
+
+ debug("");
+ debug("Testing binding a VAO");
+ var vao0 = ext.createVertexArrayOES();
+ var vao1 = ext.createVertexArrayOES();
+ shouldBeNull("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)");
+ ext.bindVertexArrayOES(vao0);
+ if (gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) == vao0) {
+ testPassed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is expected VAO");
+ } else {
+ testFailed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is not expected VAO")
+ }
+ ext.bindVertexArrayOES(vao1);
+ if (gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) == vao1) {
+ testPassed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is expected VAO");
+ } else {
+ testFailed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is not expected VAO")
+ }
+ ext.deleteVertexArrayOES(vao1);
+ shouldBeNull("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)");
+ ext.bindVertexArrayOES(vao1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "binding a deleted vertex array object");
+ ext.bindVertexArrayOES(null);
+ shouldBeNull("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)");
+ ext.deleteVertexArrayOES(vao1);
+}
+
+function runObjectTest() {
+ debug("");
+ debug("Testing object creation");
+
+ vao = ext.createVertexArrayOES();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "createVertexArrayOES should not set an error");
+ shouldBeNonNull("vao");
+
+ // Expect false if never bound
+ shouldBeFalse("ext.isVertexArrayOES(vao)");
+ ext.bindVertexArrayOES(vao);
+ shouldBeTrue("ext.isVertexArrayOES(vao)");
+ ext.bindVertexArrayOES(null);
+ shouldBeTrue("ext.isVertexArrayOES(vao)");
+
+ shouldBeFalse("ext.isVertexArrayOES(null)");
+
+ ext.deleteVertexArrayOES(vao);
+ vao = null;
+}
+
+function runAttributeTests() {
+ debug("");
+ debug("Testing attributes work across bindings");
+
+ var states = [];
+
+ var attrCount = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ for (var n = 0; n < attrCount; n++) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+
+ var state = {};
+ states.push(state);
+
+ var vao = state.vao = ext.createVertexArrayOES();
+ ext.bindVertexArrayOES(vao);
+
+ var enableArray = (n % 2 == 0);
+ if (enableArray) {
+ gl.enableVertexAttribArray(n);
+ } else {
+ gl.disableVertexAttribArray(n);
+ }
+
+ if (enableArray) {
+ var buffer = state.buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, 1024, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(n, 1 + n % 4, gl.FLOAT, true, n * 4, n * 4);
+ }
+
+ if (enableArray) {
+ var elbuffer = state.elbuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elbuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 1024, gl.STATIC_DRAW);
+ }
+
+ ext.bindVertexArrayOES(null);
+ }
+
+ var anyMismatch = false;
+ for (var n = 0; n < attrCount; n++) {
+ var state = states[n];
+
+ ext.bindVertexArrayOES(state.vao);
+
+ var shouldBeEnabled = (n % 2 == 0);
+ var isEnabled = gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_ENABLED);
+ if (shouldBeEnabled != isEnabled) {
+ testFailed("VERTEX_ATTRIB_ARRAY_ENABLED not preserved");
+ anyMismatch = true;
+ }
+
+ var buffer = gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
+ if (shouldBeEnabled) {
+ if (buffer == state.buffer) {
+ // Matched
+ if ((gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_SIZE) == 1 + n % 4) &&
+ (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_TYPE) == gl.FLOAT) &&
+ (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED) == true) &&
+ (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_STRIDE) == n * 4) &&
+ (gl.getVertexAttribOffset(n, gl.VERTEX_ATTRIB_ARRAY_POINTER) == n * 4)) {
+ // Matched
+ } else {
+ testFailed("VERTEX_ATTRIB_ARRAY_* not preserved");
+ anyMismatch = true;
+ }
+ } else {
+ testFailed("VERTEX_ATTRIB_ARRAY_BUFFER_BINDING not preserved");
+ anyMismatch = true;
+ }
+ } else {
+ // GL_CURRENT_VERTEX_ATTRIB is not preserved
+ if (buffer) {
+ testFailed("VERTEX_ATTRIB_ARRAY_BUFFER_BINDING not preserved");
+ anyMismatch = true;
+ }
+ }
+
+ var elbuffer = gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING);
+ if (shouldBeEnabled) {
+ if (elbuffer == state.elbuffer) {
+ // Matched
+ } else {
+ testFailed("ELEMENT_ARRAY_BUFFER_BINDING not preserved");
+ anyMismatch = true;
+ }
+ } else {
+ if (elbuffer == null) {
+ // Matched
+ } else {
+ testFailed("ELEMENT_ARRAY_BUFFER_BINDING not preserved");
+ anyMismatch = true;
+ }
+ }
+ }
+ ext.bindVertexArrayOES(null);
+ if (!anyMismatch) {
+ testPassed("All attributes preserved across bindings");
+ }
+
+ for (var n = 0; n < attrCount; n++) {
+ var state = states[n];
+ ext.deleteVertexArrayOES(state.vao);
+ }
+}
+
+function runAttributeValueTests() {
+ debug("");
+ debug("Testing that attribute values are not attached to bindings");
+
+ var v;
+ var vao0 = ext.createVertexArrayOES();
+ var anyFailed = false;
+
+ ext.bindVertexArrayOES(null);
+ gl.vertexAttrib4f(0, 0, 1, 2, 3);
+
+ v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
+ if (!(v[0] == 0 && v[1] == 1 && v[2] == 2 && v[3] == 3)) {
+ testFailed("Vertex attrib value not round-tripped?");
+ anyFailed = true;
+ }
+
+ ext.bindVertexArrayOES(vao0);
+
+ v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
+ if (!(v[0] == 0 && v[1] == 1 && v[2] == 2 && v[3] == 3)) {
+ testFailed("Vertex attrib value reset across bindings");
+ anyFailed = true;
+ }
+
+ gl.vertexAttrib4f(0, 4, 5, 6, 7);
+ ext.bindVertexArrayOES(null);
+
+ v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
+ if (!(v[0] == 4 && v[1] == 5 && v[2] == 6 && v[3] == 7)) {
+ testFailed("Vertex attrib value bound to buffer");
+ anyFailed = true;
+ }
+
+ if (!anyFailed) {
+ testPassed("Vertex attribute values are not attached to bindings")
+ }
+
+ ext.bindVertexArrayOES(null);
+ ext.deleteVertexArrayOES(vao0);
+}
+
+function runDrawTests() {
+ debug("");
+ debug("Testing draws with various VAO bindings");
+
+ canvas.width = 50; canvas.height = 50;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var vao0 = ext.createVertexArrayOES();
+ var vao1 = ext.createVertexArrayOES();
+ var vao2 = ext.createVertexArrayOES();
+
+ var positionLocation = 0;
+ var colorLocation = 1;
+
+ var program = wtu.setupSimpleVertexColorProgram(gl, positionLocation, colorLocation);
+
+ function setupQuad(s, colorsInArray) {
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 1.0 * s, 1.0 * s, 0.0,
+ -1.0 * s, 1.0 * s, 0.0,
+ -1.0 * s, -1.0 * s, 0.0,
+ 1.0 * s, 1.0 * s, 0.0,
+ -1.0 * s, -1.0 * s, 0.0,
+ 1.0 * s, -1.0 * s, 0.0]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(positionLocation);
+ gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
+
+ // Test switching between VAOs that have different number of enabled arrays
+ if (colorsInArray) {
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0.0, 0.0, 0.0, 1.0,
+ 0.0, 0.0, 0.0, 1.0,
+ 0.0, 0.0, 0.0, 1.0,
+ 0.0, 0.0, 0.0, 1.0,
+ 0.0, 0.0, 0.0, 1.0,
+ 0.0, 0.0, 0.0, 1.0]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(colorLocation);
+ gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);
+ } else {
+ gl.disableVertexAttribArray(colorLocation);
+ }
+ };
+
+ function verifyDiagonalPixels(s, expectedInside, drawDescription) {
+ // Tests pixels along a diagonal running from the center of the canvas to the (0, 0) corner.
+ // Values on the points list indicate relative position along this diagonal.
+ var points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
+ for (var n = 0; n < points.length; n++) {
+ var expected = points[n] <= s ? expectedInside : 255;
+ var x = Math.round((1 - points[n]) * canvas.width / 2);
+ var y = Math.round((1 - points[n]) * canvas.height / 2);
+ wtu.checkCanvasRect(gl, x, y, 1, 1, [expected, expected, expected, 255],
+ "Drawing " + drawDescription + " should pass", 2);
+ }
+ };
+ function verifyDraw(drawDescription, s, colorsInArray) {
+ wtu.clearAndDrawUnitQuad(gl);
+ var expectedInside = colorsInArray ? 0 : 128;
+ verifyDiagonalPixels(s, expectedInside, drawDescription);
+ };
+
+ // Setup all bindings
+ setupQuad(1, true);
+ ext.bindVertexArrayOES(vao0);
+ setupQuad(0.5, true);
+ ext.bindVertexArrayOES(vao1);
+ setupQuad(0.25, true);
+ ext.bindVertexArrayOES(vao2);
+ setupQuad(0.75, false);
+
+ gl.vertexAttrib4f(colorLocation, 0.5, 0.5, 0.5, 1);
+
+ // Verify drawing
+ ext.bindVertexArrayOES(null);
+ verifyDraw("with the default VAO", 1, true);
+ ext.bindVertexArrayOES(vao0);
+ verifyDraw("with VAO #0", 0.5, true);
+ ext.bindVertexArrayOES(vao1);
+ verifyDraw("with VAO #1", 0.25, true);
+ ext.bindVertexArrayOES(vao2);
+ verifyDraw("with VAO that has the color array disabled", 0.75, false);
+
+ // Verify bound VAO after delete
+ ext.bindVertexArrayOES(vao1);
+ ext.deleteVertexArrayOES(vao0);
+ verifyDraw("after deleting another VAO", 0.25, true);
+ ext.deleteVertexArrayOES(vao1);
+ verifyDraw("after deleting the VAO that was bound", 1, true);
+
+ // Disable global vertex attrib array
+ gl.disableVertexAttribArray(positionLocation);
+ gl.disableVertexAttribArray(colorLocation);
+
+ // Check that constant values are treated correctly as not being part of VAO state.
+ var positionLoc = 0;
+ var colorLoc = 1;
+ var gridRes = 1;
+ wtu.setupIndexedQuad(gl, gridRes, positionLoc);
+ // Set the vertex color to red.
+ gl.vertexAttrib4f(colorLoc, 1, 0, 0, 1);
+
+ var vao0 = ext.createVertexArrayOES();
+ ext.bindVertexArrayOES(vao0);
+ var program = wtu.setupSimpleVertexColorProgram(gl, positionLoc, colorLoc);
+ wtu.setupIndexedQuad(gl, gridRes, positionLoc);
+ // Set the vertex color to green.
+ gl.vertexAttrib4f(colorLoc, 0, 1, 0, 1);
+ wtu.clearAndDrawIndexedQuad(gl, gridRes);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+ ext.deleteVertexArrayOES(vao0);
+ wtu.clearAndDrawIndexedQuad(gl, gridRes);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+}
+
+function runUnboundDeleteTests() {
+ debug("");
+ debug("Testing using buffers that are deleted when attached to unbound VAOs");
+
+ var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["a_position", "a_color"]);
+ gl.useProgram(program);
+
+ var positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ new Float32Array([
+ 1.0, 1.0,
+ -1.0, 1.0,
+ -1.0, -1.0,
+ 1.0, -1.0]),
+ gl.STATIC_DRAW);
+
+ var colors = [
+ [255, 0, 0, 255],
+ [ 0, 255, 0, 255],
+ [ 0, 0, 255, 255],
+ [ 0, 255, 255, 255]
+ ];
+ var colorBuffers = [];
+ var elementBuffers = [];
+ var vaos = [];
+ for (var ii = 0; ii < colors.length; ++ii) {
+ var vao = ext.createVertexArrayOES();
+ vaos.push(vao);
+ ext.bindVertexArrayOES(vao);
+ // Set the position buffer
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+
+ var elementBuffer = gl.createBuffer();
+ elementBuffers.push(elementBuffer);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
+ gl.bufferData(
+ gl.ELEMENT_ARRAY_BUFFER,
+ new Uint8Array([0, 1, 2, 0, 2, 3]),
+ gl.STATIC_DRAW);
+
+ // Setup the color attrib
+ var color = colors[ii];
+ if (ii < 3) {
+ var colorBuffer = gl.createBuffer();
+ colorBuffers.push(colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
+ [ color[0], color[1], color[2], color[3],
+ color[0], color[1], color[2], color[3],
+ color[0], color[1], color[2], color[3],
+ color[0], color[1], color[2], color[3]
+ ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, 0);
+ } else {
+ gl.vertexAttrib4f(1, color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255);
+ }
+ }
+
+ // delete the color buffers AND the position buffer.
+ ext.bindVertexArrayOES(null);
+ for (var ii = 0; ii < colorBuffers.length; ++ii) {
+ gl.deleteBuffer(colorBuffers[ii]);
+ gl.deleteBuffer(elementBuffers[ii]);
+ ext.bindVertexArrayOES(vaos[ii]);
+ var boundBuffer = gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
+ // The buffers should still be valid at this point, since it was attached to the VAO
+ if(boundBuffer != colorBuffers[ii]) {
+ testFailed("buffer removed even though it is still attached to a VAO");
+ }
+ }
+
+ ext.bindVertexArrayOES(null);
+ gl.deleteBuffer(positionBuffer);
+
+ // Render with the deleted buffers. As they are referenced by VAOs they
+ // must still be around.
+ for (var ii = 0; ii < colors.length; ++ii) {
+ var color = colors[ii];
+ ext.bindVertexArrayOES(vaos[ii]);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
+ wtu.checkCanvas(gl, color, "should be " + color);
+ }
+
+ // Clean up.
+ for (var ii = 0; ii < colorBuffers.length; ++ii) {
+ ext.deleteVertexArrayOES(vaos[ii]);
+ }
+
+ for (var ii = 0; ii < colorBuffers.length; ++ii) {
+ // The buffers should no longer be valid now that the VAOs are deleted
+ if(gl.isBuffer(colorBuffers[ii])) {
+ testFailed("buffer not properly cleaned up after VAO deletion");
+ }
+ }
+}
+
+function runBoundDeleteTests() {
+ debug("Testing using buffers that are deleted when attached to bound VAOs");
+
+ var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["a_position", "a_color"]);
+ gl.useProgram(program);
+
+ var positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ new Float32Array([
+ 1.0, 1.0,
+ -1.0, 1.0,
+ -1.0, -1.0,
+ 1.0, -1.0]),
+ gl.STATIC_DRAW);
+
+ // Setup the color attrib
+ var colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
+ [ 255, 0, 0, 255,
+ 0, 255, 0, 255,
+ 0, 0, 255, 255,
+ 0, 255, 255, 255
+ ]), gl.STATIC_DRAW);
+
+ var vaos = [];
+ var elementBuffers = [];
+ for (var ii = 0; ii < 4; ++ii) {
+ var vao = ext.createVertexArrayOES();
+ vaos.push(vao);
+ ext.bindVertexArrayOES(vao);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+
+ var elementBuffer = gl.createBuffer();
+ elementBuffers.push(elementBuffer);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
+ gl.bufferData(
+ gl.ELEMENT_ARRAY_BUFFER,
+ new Uint8Array([0, 1, 2, 0, 2, 3]),
+ gl.STATIC_DRAW);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, 0);
+ }
+
+ // delete the color buffers AND the position buffer, that are bound to the current VAO
+ for (var ii = 0; ii < vaos.length; ++ii) {
+ ext.bindVertexArrayOES(vaos[ii]);
+
+ gl.deleteBuffer(colorBuffer);
+ gl.deleteBuffer(positionBuffer);
+
+ // After the first iteration, deleteBuffer will be a no-op, and will not unbind its matching
+ // bind points on the now-bound VAO like it did on the first iteration.
+ var expectRetained = (ii != 0);
+ var shouldBeStr = (expectRetained ? "retained" : "cleared");
+
+ var boundPositionBuffer = gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
+ if (expectRetained != (boundPositionBuffer == positionBuffer)) {
+ testFailed("Position attrib stored buffer should be " + shouldBeStr + ".");
+ }
+
+ var boundColorBuffer = gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
+ if (expectRetained != (boundColorBuffer == colorBuffer)) {
+ testFailed("Color attrib stored buffer should be " + shouldBeStr + ".");
+ }
+
+ // If retained, everything should still work. If cleared, drawing should now fail.
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
+ var expectedError = (expectRetained ? gl.NO_ERROR : gl.INVALID_OPERATION);
+ wtu.glErrorShouldBe(gl, expectedError,
+ "Draw call should " + (expectRetained ? "not " : "") + "fail.");
+
+ if (gl.isBuffer(positionBuffer)) {
+ testFailed("References from unbound VAOs don't keep Position buffer alive.");
+ }
+ if (gl.isBuffer(colorBuffer)) {
+ testFailed("References from unbound VAOs don't keep Color buffer alive");
+ }
+ }
+}
+
+function runArrayBufferBindTests() {
+ debug("");
+ debug("Testing that buffer bindings on VAOs don't affect default VAO ARRAY_BUFFER binding.");
+
+ ext.bindVertexArrayOES(null);
+
+ var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["a_color", "a_position"]);
+ gl.useProgram(program);
+
+ // create shared element buffer
+ var elementBuffer = gl.createBuffer();
+ // bind to default
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
+ gl.bufferData(
+ gl.ELEMENT_ARRAY_BUFFER,
+ new Uint8Array([0, 1, 2, 0, 2, 3]),
+ gl.STATIC_DRAW);
+
+ // first create the buffers for no VAO draw.
+ var nonVAOColorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, nonVAOColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
+ [ 0, 255, 0, 255,
+ 0, 255, 0, 255,
+ 0, 255, 0, 255,
+ 0, 255, 0, 255,
+ ]), gl.STATIC_DRAW);
+
+ // shared position buffer.
+ var positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ new Float32Array([
+ 1.0, 1.0,
+ -1.0, 1.0,
+ -1.0, -1.0,
+ 1.0, -1.0]),
+ gl.STATIC_DRAW);
+
+ // attach position buffer to default
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
+
+ // now create VAO
+ var vao = ext.createVertexArrayOES();
+ ext.bindVertexArrayOES(vao);
+
+ // attach the position buffer VAO
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
+
+ var vaoColorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vaoColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
+ [ 255, 0, 0, 255,
+ 255, 0, 0, 255,
+ 255, 0, 0, 255,
+ 255, 0, 0, 255,
+ ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 4, gl.UNSIGNED_BYTE, true, 0, 0);
+
+ // now set the buffer back to the nonVAOColorBuffer
+ gl.bindBuffer(gl.ARRAY_BUFFER, nonVAOColorBuffer);
+
+ // bind to VAO
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
+
+ // unbind VAO
+ ext.bindVertexArrayOES(null);
+
+ // At this point the nonVAOColorBuffer should be still be bound.
+ // If the WebGL impl is emulating VAOs it must make sure
+ // it correctly restores this binding.
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 4, gl.UNSIGNED_BYTE, true, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+}
+
+function runInvalidContextTests() {
+ contextA = wtu.create3DContext(undefined, undefined, 1);
+ contextB = wtu.create3DContext(undefined, undefined, 1);
+ extA = contextA.getExtension("OES_vertex_array_object");
+ extB = contextB.getExtension("OES_vertex_array_object");
+ vertexArrayA = extA.createVertexArrayOES();
+ vertexArrayB = extB.createVertexArrayOES();
+
+ wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "extA.bindVertexArrayOES(vertexArrayA)");
+ wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "extA.bindVertexArrayOES(null)");
+ wtu.shouldGenerateGLError(contextB, contextB.NO_ERROR, "extB.bindVertexArrayOES(vertexArrayB)");
+ wtu.shouldGenerateGLError(contextB, contextB.NO_ERROR, "extB.bindVertexArrayOES(null)");
+
+ debug("")
+ debug("State queries validate context");
+ shouldBeFalse("extA.isVertexArrayOES(vertexArrayB)");
+ wtu.glErrorShouldBe(contextA, gl.NO_ERROR, "there should be no errors from invalid request");
+ shouldBeFalse("extB.isVertexArrayOES(vertexArrayA)");
+ wtu.glErrorShouldBe(contextB, gl.NO_ERROR, "there should be no errors from invalid request");
+ shouldBeTrue("extA.isVertexArrayOES(vertexArrayA)");
+ wtu.glErrorShouldBe(contextA, gl.NO_ERROR, "there should be no errors from valid request");
+ shouldBeTrue("extB.isVertexArrayOES(vertexArrayB)");
+ wtu.glErrorShouldBe(contextB, gl.NO_ERROR, "there should be no errors from valid request");
+
+ debug("")
+ debug("Deleting an object from another context generates an error");
+ wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "extA.deleteVertexArrayOES(vertexArrayB)");
+ wtu.shouldGenerateGLError(contextB, contextB.INVALID_OPERATION, "extB.deleteVertexArrayOES(vertexArrayA)");
+
+ debug("")
+ debug("Invalid delete operations do not delete");
+ shouldBeTrue("extA.isVertexArrayOES(vertexArrayA)");
+ shouldBeTrue("extB.isVertexArrayOES(vertexArrayB)");
+
+ debug("")
+ debug("Cannot bind VAOs from other contexts");
+ wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "extA.bindVertexArrayOES(vertexArrayB)");
+ wtu.shouldGenerateGLError(contextB, contextB.INVALID_OPERATION, "extB.bindVertexArrayOES(vertexArrayA)");
+
+ debug("")
+ debug("Context checks happen even for deleted objects");
+ wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "extA.deleteVertexArrayOES(vertexArrayA)");
+ wtu.shouldGenerateGLError(contextB, contextB.NO_ERROR, "extB.deleteVertexArrayOES(vertexArrayB)");
+ wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "extA.deleteVertexArrayOES(vertexArrayB)");
+ wtu.shouldGenerateGLError(contextB, contextB.INVALID_OPERATION, "extB.deleteVertexArrayOES(vertexArrayA)");
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/s3tc-and-rgtc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/s3tc-and-rgtc.html
new file mode 100644
index 0000000000..3b725ffe22
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/s3tc-and-rgtc.html
@@ -0,0 +1,1066 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compressed-texture-utils.js"></script>
+<title>WebGL WEBGL_compressed_texture_s3tc and EXT_texture_compression_rgtc Conformance Tests</title>
+<style>
+img {
+ border: 1px solid black;
+ margin-right: 1em;
+}
+
+.testimages br {
+ clear: both;
+}
+
+.testimages > div {
+ float: left;
+ margin: 1em;
+}
+</style>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_compressed_texture_s3tc extension, if it is available. It also tests the related formats from the EXT_texture_compression_rgtc extension.");
+
+debug("");
+
+// Acceptable interpolation error depends on endpoints:
+// 1.0 / 255.0 + 0.03 * max(abs(endpoint0 - endpoint1), abs(endpoint0_p - endpoint1_p))
+// For simplicity, assume the worst case (e0 is 0.0, e1 is 1.0). After conversion to unorm8, it is 9.
+const DEFAULT_COLOR_ERROR = 9;
+
+/*
+BC1 (DXT1) block
+e0 = [ 0, 255, 0]
+e1 = [255, 0, 0]
+e0 < e1, so it uses 3-color mode
+
+local palette
+ 0: [ 0, 255, 0, 255]
+ 1: [255, 0, 0, 255]
+ 2: [128, 128, 0, 255]
+ 3: [ 0, 0, 0, 255] // for BC1 RGB
+ 3: [ 0, 0, 0, 0] // for BC1 RGBA
+selectors
+ 3 2 1 0
+ 2 2 1 0
+ 1 1 1 0
+ 0 0 0 0
+
+Extending this block with opaque alpha and uploading as BC2 or BC3
+will generate wrong colors because BC2 and BC3 do not have 3-color mode.
+*/
+var img_4x4_rgba_dxt1 = new Uint8Array([
+ 0xE0, 0x07, 0x00, 0xF8, 0x1B, 0x1A, 0x15, 0x00
+]);
+
+/*
+BC2 (DXT3) block
+
+Quantized alpha values
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 A B
+ C D E F
+
+RGB block
+e0 = [255, 0, 0]
+e1 = [ 0, 255, 0]
+BC2 has only 4-color mode
+
+local palette
+ 0: [255, 0, 0]
+ 1: [ 0, 255, 0]
+ 2: [170, 85, 0]
+ 3: [ 85, 170, 0]
+selectors
+ 0 1 2 3
+ 1 1 2 3
+ 2 2 2 3
+ 3 3 3 3
+*/
+var img_4x4_rgba_dxt3 = new Uint8Array([
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ 0x00, 0xF8, 0xE0, 0x07, 0xE4, 0xE5, 0xEA, 0xFF
+]);
+
+/*
+BC3 (DXT5) block
+
+Alpha block (aka DXT5A)
+e0 = 255
+e1 = 0
+e0 > e1, so using 6 intermediate points
+local palette
+ 255, 0, 219, 182, 146, 109, 73, 36
+selectors
+ 0 1 2 3
+ 1 2 3 4
+ 2 3 4 5
+ 3 4 5 6
+
+RGB block
+e0 = [255, 0, 0]
+e1 = [ 0, 255, 0]
+BC3 has only 4-color mode
+
+local palette
+ 0: [255, 0, 0]
+ 1: [ 0, 255, 0]
+ 2: [170, 85, 0]
+ 3: [ 85, 170, 0]
+selectors
+ 3 2 1 0
+ 3 2 1 1
+ 3 2 2 2
+ 3 3 3 3
+*/
+var img_4x4_rgba_dxt5 = new Uint8Array([
+ 0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x00, 0xF8, 0xE0, 0x07, 0x1B, 0x5B, 0xAB, 0xFF
+]);
+
+// BC4 - just the alpha block from BC3 above, interpreted as the red channel.
+// See http://www.reedbeta.com/blog/understanding-bcn-texture-compression-formats/#bc4
+// for format details.
+var img_4x4_r_bc4 = new Uint8Array([
+ 0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+// BC5 - Two BC3 alpha blocks, interpreted as the red and green channels.
+var img_4x4_rg_bc5 = new Uint8Array([
+ 0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x00, 0xFF, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+// Signed BC4 - change endpoints to use full -1 to 1 range.
+var img_4x4_signed_r_bc4 = new Uint8Array([
+ 0x7F, 0x80, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+// Signed BC5 - Two BC3 alpha blocks, interpreted as the red and green channels.
+var img_4x4_signed_rg_bc5 = new Uint8Array([
+ 0x7F, 0x80, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x80, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+
+/*
+8x8 block endpoints use half-intensity values (appear darker than 4x4)
+*/
+var img_8x8_rgba_dxt1 = new Uint8Array([
+ 0xe0,0x03,0x00,0x78,0x13,0x10,0x15,0x00,
+ 0x0f,0x00,0xe0,0x7b,0x11,0x10,0x15,0x00,
+ 0xe0,0x03,0x0f,0x78,0x44,0x45,0x40,0x55,
+ 0x0f,0x00,0xef,0x03,0x44,0x45,0x40,0x55
+]);
+var img_8x8_rgba_dxt3 = new Uint8Array([
+ 0xf6,0xff,0xf6,0xff,0xff,0xff,0xff,0xff,0x00,0x78,0xe0,0x03,0x44,0x45,0x40,0x55,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x7b,0x0f,0x00,0x44,0x45,0x40,0x55,
+ 0xff,0xff,0xff,0xff,0xf6,0xff,0xf6,0xff,0x0f,0x78,0xe0,0x03,0x11,0x10,0x15,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x03,0x0f,0x00,0x11,0x10,0x15,0x00
+]);
+var img_8x8_rgba_dxt5 = new Uint8Array([
+ 0xff,0x69,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x78,0xe0,0x03,0x44,0x45,0x40,0x55,
+ 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x7b,0x0f,0x00,0x44,0x45,0x40,0x55,
+ 0xff,0x69,0x00,0x00,0x00,0x01,0x10,0x00,0x0f,0x78,0xe0,0x03,0x11,0x10,0x15,0x00,
+ 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x03,0xef,0x00,0x11,0x10,0x15,0x00
+]);
+var img_8x8_r_bc4 = new Uint8Array([
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+var img_8x8_rg_bc5 = new Uint8Array([
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var ext = null;
+var ext_rgtc = {};
+var vao = null;
+var validFormats = {
+ COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0,
+ COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1,
+ COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2,
+ COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3,
+};
+var name;
+var supportedFormats;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_s3tc");
+ if (!ext) {
+ testPassed("No WEBGL_compressed_texture_s3tc support -- this is legal");
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_s3tc", false);
+ } else {
+ testPassed("Successfully enabled WEBGL_compressed_texture_s3tc extension");
+
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_s3tc", true);
+ runTestExtension();
+ }
+ ext_rgtc = wtu.getExtensionWithKnownPrefixes(gl, "EXT_texture_compression_rgtc");
+ if (ext_rgtc) {
+ ext = ext || {};
+ // Make ctu.formatToString work for rgtc enums.
+ for (const name in ext_rgtc)
+ ext[name] = ext_rgtc[name];
+ runTestRGTC();
+ }
+}
+
+function expectedByteLength(width, height, format) {
+ if (format == validFormats.COMPRESSED_RGBA_S3TC_DXT3_EXT || format == validFormats.COMPRESSED_RGBA_S3TC_DXT5_EXT) {
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16;
+ }
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;
+}
+
+function getBlockDimensions(format) {
+ return {width: 4, height: 4};
+}
+
+function runTestExtension() {
+ debug("");
+ debug("Testing WEBGL_compressed_texture_s3tc");
+
+ // Test that enum values are listed correctly in supported formats and in the extension object.
+ ctu.testCompressedFormatsListed(gl, validFormats);
+ ctu.testCorrectEnumValuesInExt(ext, validFormats);
+ // Test that texture upload buffer size is validated correctly.
+ ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+
+ // Test each format
+ testDXT1_RGB();
+ testDXT1_RGBA();
+ testDXT3_RGBA();
+ testDXT5_RGBA();
+
+ // Test compressed PBOs with a single format
+ if (contextVersion >= 2) {
+ testDXT5_RGBA_PBO();
+ }
+
+ // Test TexImage validation on level dimensions combinations.
+ debug("");
+ debug("When level equals 0, width and height must be a multiple of 4.");
+ debug("When level is larger than 0, this constraint doesn't apply.");
+ ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { level: 0, width: 4, height: 3, expectation: gl.INVALID_OPERATION, message: "0: 4x3" },
+ { level: 0, width: 3, height: 4, expectation: gl.INVALID_OPERATION, message: "0: 3x4" },
+ { level: 0, width: 2, height: 2, expectation: gl.INVALID_OPERATION, message: "0: 2x2" },
+ { level: 0, width: 4, height: 4, expectation: gl.NO_ERROR, message: "0: 4x4" },
+ { level: 1, width: 2, height: 2, expectation: gl.NO_ERROR, message: "1: 2x2" },
+ { level: 2, width: 1, height: 1, expectation: gl.NO_ERROR, message: "2: 1x1" },
+ ]);
+
+ ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 16, 16,
+ [
+ { xoffset: 0, yoffset: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
+ { xoffset: 0, yoffset: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
+ { xoffset: 1, yoffset: 0, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
+ { xoffset: 0, yoffset: 1, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
+ { xoffset: 12, yoffset: 12, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ ]);
+
+ if (contextVersion >= 2) {
+ debug("");
+ debug("Testing NPOT textures");
+ ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { level: 0, width: 0, height: 0, expectation: gl.NO_ERROR, message: "0: 0x0 is valid" },
+ { level: 0, width: 1, height: 1, expectation: gl.INVALID_OPERATION, message: "0: 1x1 is invalid" },
+ { level: 0, width: 2, height: 2, expectation: gl.INVALID_OPERATION, message: "0: 2x2 is invalid" },
+ { level: 0, width: 3, height: 3, expectation: gl.INVALID_OPERATION, message: "0: 3x3 is invalid" },
+ { level: 0, width: 10, height: 10, expectation: gl.INVALID_OPERATION, message: "0: 10x10 is invalid" },
+ { level: 0, width: 11, height: 11, expectation: gl.INVALID_OPERATION, message: "0: 11x11 is invalid" },
+ { level: 0, width: 11, height: 12, expectation: gl.INVALID_OPERATION, message: "0: 11x12 is invalid" },
+ { level: 0, width: 12, height: 11, expectation: gl.INVALID_OPERATION, message: "0: 12x11 is invalid" },
+ { level: 0, width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
+ { level: 1, width: 0, height: 0, expectation: gl.NO_ERROR, message: "1: 0x0, is valid" },
+ { level: 1, width: 3, height: 3, expectation: gl.INVALID_OPERATION, message: "1: 3x3, is invalid" },
+ { level: 1, width: 5, height: 5, expectation: gl.INVALID_OPERATION, message: "1: 5x5, is invalid" },
+ { level: 1, width: 5, height: 6, expectation: gl.INVALID_OPERATION, message: "1: 5x6, is invalid" },
+ { level: 1, width: 6, height: 5, expectation: gl.INVALID_OPERATION, message: "1: 6x5, is invalid" },
+ { level: 1, width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
+ { level: 2, width: 0, height: 0, expectation: gl.NO_ERROR, message: "2: 0x0, is valid" },
+ { level: 2, width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
+ { level: 3, width: 1, height: 3, expectation: gl.NO_ERROR, message: "3: 1x3, is valid" },
+ { level: 3, width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
+ ]);
+
+ debug("");
+ debug("Testing partial updates");
+ ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 12, 12,
+ [
+ { xoffset: 0, yoffset: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
+ { xoffset: 0, yoffset: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
+ { xoffset: 1, yoffset: 0, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
+ { xoffset: 0, yoffset: 1, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
+ { xoffset: 8, yoffset: 8, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ ]);
+
+ debug("");
+ debug("Testing immutable NPOT textures");
+ ctu.testTexStorageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
+ { width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
+ { width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
+ { width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
+ ]);
+ }
+}
+
+function runTestRGTC() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 1,
+ data: img_4x4_r_bc4,
+ format: ext_rgtc.COMPRESSED_RED_RGTC1_EXT,
+ hasAlpha: false,
+ },
+ { width: 4,
+ height: 4,
+ channels: 1,
+ data: img_4x4_signed_r_bc4,
+ format: ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT,
+ hasAlpha: false,
+ },
+ { width: 4,
+ height: 4,
+ channels: 2,
+ data: img_4x4_rg_bc5,
+ format: ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT,
+ hasAlpha: false,
+ },
+ { width: 4,
+ height: 4,
+ channels: 2,
+ data: img_4x4_signed_rg_bc5,
+ format: ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT,
+ hasAlpha: false,
+ error: 18, // Signed, so twice the normal error.
+ // Experimentally needed by e.g. RTX 3070.
+ },
+ { width: 8,
+ height: 8,
+ channels: 2,
+ data: img_8x8_r_bc4,
+ format: ext_rgtc.COMPRESSED_RED_RGTC1_EXT,
+ hasAlpha: false,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_r_bc4,
+ },
+ { width: 8,
+ height: 8,
+ channels: 2,
+ data: img_8x8_rg_bc5,
+ format: ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT,
+ hasAlpha: false,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_rg_bc5,
+ },
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXT1_RGB() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 3,
+ data: img_4x4_rgba_dxt1,
+ format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT,
+ hasAlpha: false,
+ },
+ { width: 8,
+ height: 8,
+ channels: 3,
+ data: img_8x8_rgba_dxt1,
+ format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT,
+ hasAlpha: false,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_rgba_dxt1
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXT1_RGBA() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: img_4x4_rgba_dxt1,
+ format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT,
+ // This is a special case -- the texture is still opaque
+ // though it's RGBA.
+ hasAlpha: false,
+ },
+ { width: 8,
+ height: 8,
+ channels: 4,
+ data: img_8x8_rgba_dxt1,
+ format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT,
+ // This is a special case -- the texture is still opaque
+ // though it's RGBA.
+ hasAlpha: false,
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXT3_RGBA() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: img_4x4_rgba_dxt3,
+ format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT,
+ hasAlpha: true,
+ },
+ { width: 8,
+ height: 8,
+ channels: 4,
+ data: img_8x8_rgba_dxt3,
+ format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT,
+ hasAlpha: true,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_rgba_dxt3
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXT5_RGBA() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: img_4x4_rgba_dxt5,
+ format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT,
+ hasAlpha: true,
+ },
+ { width: 8,
+ height: 8,
+ channels: 4,
+ data: img_8x8_rgba_dxt5,
+ format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT,
+ hasAlpha: true,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_rgba_dxt5
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXTTextures(tests) {
+ debug("<hr/>");
+ for (var ii = 0; ii < tests.length; ++ii) {
+ testDXTTexture(tests[ii], false);
+ if (contextVersion >= 2) {
+ debug("<br/>");
+ testDXTTexture(tests[ii], true);
+ }
+ }
+}
+
+function uncompressDXTBlock(
+ destBuffer, destX, destY, destWidth, src, srcOffset, format) {
+ // Decoding routines follow D3D11 functional spec wrt
+ // endpoints unquantization and interpolation.
+ // Some hardware may produce slightly different values - it's normal.
+
+ function make565(src, offset) {
+ return src[offset + 0] + (src[offset + 1] << 8);
+ }
+ function make8888From565(c) {
+ // These values exactly match hw decoder when selectors are 0 or 1.
+ function replicateBits(v, w) {
+ return (v << (8 - w)) | (v >> (w + w - 8));
+ }
+ return [
+ replicateBits((c >> 11) & 0x1F, 5),
+ replicateBits((c >> 5) & 0x3F, 6),
+ replicateBits((c >> 0) & 0x1F, 5),
+ 255
+ ];
+ }
+ function mix(mult, c0, c1, div) {
+ var r = [];
+ for (var ii = 0; ii < c0.length; ++ii) {
+ // For green channel (6 bits), this interpolation exactly matches hw decoders
+
+ // For red and blue channels (5 bits), this interpolation exactly
+ // matches only some hw decoders and stays within acceptable range for others.
+ r[ii] = Math.floor((c0[ii] * mult + c1[ii]) / div + 0.5);
+ }
+ return r;
+ }
+ var isBC45 = ext_rgtc &&
+ (format == ext_rgtc.COMPRESSED_RED_RGTC1_EXT ||
+ format == ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT ||
+ format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT ||
+ format == ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
+ let colorOffset = srcOffset;
+ if (!isBC45) {
+ var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ if (!isDXT1) {
+ colorOffset += 8;
+ }
+ var color0 = make565(src, colorOffset + 0);
+ var color1 = make565(src, colorOffset + 2);
+ var c0gtc1 = color0 > color1 || !isDXT1;
+ var rgba0 = make8888From565(color0);
+ var rgba1 = make8888From565(color1);
+ var colors = [
+ rgba0,
+ rgba1,
+ c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2),
+ c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255]
+ ];
+ }
+ const isSigned = ext_rgtc && (format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT || format == ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
+ const signedSrc = new Int8Array(src);
+
+ // yea I know there is a lot of math in this inner loop.
+ // so sue me.
+ for (var yy = 0; yy < 4; ++yy) {
+ var pixels = src[colorOffset + 4 + yy];
+ for (var xx = 0; xx < 4; ++xx) {
+ var dstOff = ((destY + yy) * destWidth + destX + xx) * 4;
+ if (!isBC45) {
+ var code = (pixels >> (xx * 2)) & 0x3;
+ var srcColor = colors[code];
+ }
+ var alpha;
+ var rgChannel2 = 0;
+ let decodeAlpha = (offset) => {
+ let alpha;
+ var alpha0 = (isSigned ? signedSrc : src)[offset + 0];
+ var alpha1 = (isSigned ? signedSrc : src)[offset + 1];
+ var alphaOff = (yy >> 1) * 3 + 2;
+ var alphaBits =
+ src[offset + alphaOff + 0] +
+ src[offset + alphaOff + 1] * 256 +
+ src[offset + alphaOff + 2] * 65536;
+ var alphaShift = (yy % 2) * 12 + xx * 3;
+ var alphaCode = (alphaBits >> alphaShift) & 0x7;
+ if (alpha0 > alpha1) {
+ switch (alphaCode) {
+ case 0:
+ alpha = alpha0;
+ break;
+ case 1:
+ alpha = alpha1;
+ break;
+ default:
+ alpha = Math.floor(((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7.0 + 0.5);
+ break;
+ }
+ } else {
+ switch (alphaCode) {
+ case 0:
+ alpha = alpha0;
+ break;
+ case 1:
+ alpha = alpha1;
+ break;
+ case 6:
+ alpha = 0;
+ break;
+ case 7:
+ alpha = 255;
+ break;
+ default:
+ alpha = Math.floor(((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5.0 + 0.5);
+ break;
+ }
+ }
+ return alpha;
+ }
+
+ switch (format) {
+ case ext.COMPRESSED_RGB_S3TC_DXT1_EXT:
+ alpha = 255;
+ break;
+ case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ alpha = (code == 3 && !c0gtc1) ? 0 : 255;
+ break;
+ case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ {
+ var alpha0 = src[srcOffset + yy * 2 + (xx >> 1)];
+ var alpha1 = (alpha0 >> ((xx % 2) * 4)) & 0xF;
+ alpha = alpha1 | (alpha1 << 4);
+ }
+ break;
+ case ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT:
+ case ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
+ rgChannel2 = decodeAlpha(srcOffset + 8);
+ // FALLTHROUGH
+ case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ case ext_rgtc.COMPRESSED_RED_RGTC1_EXT:
+ case ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT:
+ alpha = decodeAlpha(srcOffset);
+ break;
+ default:
+ throw "bad format";
+ }
+ if (isBC45) {
+ destBuffer[dstOff + 0] = alpha;
+ destBuffer[dstOff + 1] = rgChannel2;
+ destBuffer[dstOff + 2] = 0;
+ destBuffer[dstOff + 3] = 255;
+ if (isSigned) {
+ destBuffer[dstOff + 0] = Math.max(0, alpha) * 2;
+ destBuffer[dstOff + 1] = Math.max(0, rgChannel2) * 2;
+ }
+ } else {
+ destBuffer[dstOff + 0] = srcColor[0];
+ destBuffer[dstOff + 1] = srcColor[1];
+ destBuffer[dstOff + 2] = srcColor[2];
+ destBuffer[dstOff + 3] = alpha;
+ }
+ }
+ }
+}
+
+function getBlockSize(format) {
+ var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ var isBC4 = ext_rgtc && (format == ext_rgtc.COMPRESSED_RED_RGTC1_EXT || format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT);
+ return isDXT1 || isBC4 ? 8 : 16;
+}
+
+function uncompressDXT(width, height, data, format) {
+ if (width % 4 || height % 4) throw "bad width or height";
+
+ var dest = new Uint8Array(width * height * 4);
+ var blocksAcross = width / 4;
+ var blocksDown = height / 4;
+ var blockSize = getBlockSize(format);
+ for (var yy = 0; yy < blocksDown; ++yy) {
+ for (var xx = 0; xx < blocksAcross; ++xx) {
+ uncompressDXTBlock(
+ dest, xx * 4, yy * 4, width, data,
+ (yy * blocksAcross + xx) * blockSize, format);
+ }
+ }
+ return dest;
+}
+
+function uncompressDXTIntoSubRegion(width, height, subX0, subY0, subWidth, subHeight, data, format)
+{
+ if (width % 4 || height % 4 || subX0 % 4 || subY0 % 4 || subWidth % 4 || subHeight % 4)
+ throw "bad dimension";
+
+ var dest = new Uint8Array(width * height * 4);
+ // Zero-filled DXT1 or BC4/5 texture represents [0, 0, 0, 255]
+ if (format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT ||
+ format == ext.COMPRESSED_RED_RGTC1_EXT || format == ext.COMPRESSED_SIGNED_RED_RGTC1_EXT ||
+ format == ext.COMPRESSED_RED_GREEN_RGTC2_EXT || format == ext.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT) {
+ for (var i = 3; i < dest.length; i += 4) dest[i] = 255;
+ }
+ var blocksAcross = subWidth / 4;
+ var blocksDown = subHeight / 4;
+ var blockSize = getBlockSize(format);
+ for (var yy = 0; yy < blocksDown; ++yy) {
+ for (var xx = 0; xx < blocksAcross; ++xx) {
+ uncompressDXTBlock(
+ dest, subX0 + xx * 4, subY0 + yy * 4, width, data,
+ (yy * blocksAcross + xx) * blockSize, format);
+ }
+ }
+ return dest;
+}
+
+function copyRect(data, srcX, srcY, dstX, dstY, width, height, stride) {
+ var bytesPerLine = width * 4;
+ var srcOffset = srcX * 4 + srcY * stride;
+ var dstOffset = dstX * 4 + dstY * stride;
+ for (; height > 0; --height) {
+ for (var ii = 0; ii < bytesPerLine; ++ii) {
+ data[dstOffset + ii] = data[srcOffset + ii];
+ }
+ srcOffset += stride;
+ dstOffset += stride;
+ }
+}
+
+function testDXTTexture(test, useTexStorage) {
+ test.error = test.error || DEFAULT_COLOR_ERROR;
+
+ var data = new Uint8Array(test.data);
+ var width = test.width;
+ var height = test.height;
+ var format = test.format;
+
+ var uncompressedData = uncompressDXT(width, height, data, format);
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, width, height);
+ debug("testing " + ctu.formatToString(ext, format) + " " + width + "x" + height +
+ (useTexStorage ? " via texStorage2D" : " via compressedTexImage2D"));
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ if (useTexStorage) {
+ if (test.subData) {
+ var uncompressedDataSub = uncompressDXTIntoSubRegion(
+ width, height, test.subX0, test.subY0, test.subWidth, test.subHeight, test.subData, format);
+ var tex1 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
+ gl.compressedTexSubImage2D(
+ gl.TEXTURE_2D, 0, test.subX0, test.subY0, test.subWidth, test.subHeight, format, test.subData);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D");
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1");
+ compareRect(width, height, test.channels, uncompressedDataSub, "NEAREST", test.error);
+
+ // Clean up and recover
+ gl.deleteTexture(tex1);
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ }
+
+ gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ var clearColor = (test.hasAlpha ? [0, 0, 0, 0] : [0, 0, 0, 255]);
+ wtu.checkCanvas(gl, clearColor, "texture should be initialized to black");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D");
+ } else {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
+ }
+ gl.generateMipmap(gl.TEXTURE_2D);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after clearing generateMipmap error");
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1");
+ compareRect(width, height, test.channels, uncompressedData, "NEAREST", test.error);
+ // Test again with linear filtering.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 2");
+ compareRect(width, height, test.channels, uncompressedData, "LINEAR", test.error);
+
+ if (!useTexStorage) {
+ // It's not allowed to redefine textures defined via texStorage2D.
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+
+ if (width == 4) {
+ // The width/height of the implied base level must be a multiple of the block size.
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+ }
+ if (height == 4) {
+ // The width/height of the implied base level must be a multiple of the block size.
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+ }
+ }
+
+ // pick a wrong format that uses the same amount of data.
+ var wrongFormat;
+ switch (format) {
+ case ext.COMPRESSED_RGB_S3TC_DXT1_EXT:
+ wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ break;
+ case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ wrongFormat = ext.COMPRESSED_RGB_S3TC_DXT1_EXT;
+ break;
+ case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ break;
+ case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ break;
+ case ext_rgtc.COMPRESSED_RED_RGTC1_EXT:
+ case ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT:
+ wrongFormat = ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT;
+ break;
+ case ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT:
+ case ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
+ wrongFormat = ext_rgtc.COMPRESSED_RED_RGTC1_EXT;
+ break;
+ }
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "format does not match");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 4, 0, width, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 4, width, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width + 4, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height + 4, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 4, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 4, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 1, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 1, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+
+ var subData = new Uint8Array(data.buffer, 0, getBlockSize(format));
+
+ if (width == 8 && height == 8) {
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 1, 0, 4, 4, format, subData);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 1, 4, 4, format, subData);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
+ }
+
+ var stride = width * 4;
+ for (var yoff = 0; yoff < height; yoff += 4) {
+ for (var xoff = 0; xoff < width; xoff += 4) {
+ copyRect(uncompressedData, 0, 0, xoff, yoff, 4, 4, stride);
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, xoff, yoff, 4, 4, format, subData);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
+ // First test NEAREST filtering.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ wtu.clearAndDrawUnitQuad(gl);
+ compareRect(width, height, test.channels, uncompressedData, "NEAREST", test.error);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ // Next test LINEAR filtering.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ compareRect(width, height, test.channels, uncompressedData, "LINEAR", test.error);
+ }
+ }
+}
+
+function testDXT5_RGBA_PBO() {
+ debug("");
+ debug("testing PBO uploads");
+ var width = 8;
+ var height = 8;
+ var channels = 4;
+ var data = img_8x8_rgba_dxt5;
+ var format = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ var uncompressedData = uncompressDXT(width, height, data, format);
+
+ var tex = gl.createTexture();
+
+ // First, PBO size = image size
+ var pbo1 = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo1);
+ gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data, gl.STATIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO");
+
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO");
+
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ compareRect(width, height, channels, uncompressedData, "NEAREST", DEFAULT_COLOR_ERROR);
+
+ // Clear the texture before the next test
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, new Uint8Array(data.length));
+
+ // Second, image is just a subrange of the PBO
+ var pbo2 = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo2);
+ gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data.length*3, gl.STATIC_DRAW);
+ gl.bufferSubData(gl.PIXEL_UNPACK_BUFFER, data.length, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO subrange");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, data.length);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO subrange");
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ compareRect(width, height, channels, uncompressedData, "NEAREST", DEFAULT_COLOR_ERROR);
+}
+
+function compareRect(width, height, channels, expectedData, filteringMode, colorError) {
+ var actual = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, actual);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "reading back pixels");
+
+ var div = document.createElement("div");
+ div.className = "testimages";
+ ctu.insertCaptionedImg(div, "expected", ctu.makeScaledImage(width, height, width, expectedData, true));
+ ctu.insertCaptionedImg(div, "actual", ctu.makeScaledImage(width, height, width, actual, true));
+ div.appendChild(document.createElement('br'));
+ document.getElementById("console").appendChild(div);
+
+ var failed = false;
+ for (var yy = 0; yy < height; ++yy) {
+ for (var xx = 0; xx < width; ++xx) {
+ var offset = (yy * width + xx) * 4;
+ var expected = expectedData.slice(offset, offset + 4);
+ const was = actual.slice(offset, offset + 4);
+
+ // Compare RGB values
+ for (var jj = 0; jj < 3; ++jj) {
+ if (Math.abs(was[jj] - expected[jj]) > colorError) {
+ failed = true;
+ testFailed(`RGB at (${xx}, ${yy}) expected: ${expected}` +
+ ` +/- ${colorError}, was ${was}`);
+ break;
+ }
+ }
+
+ if (channels == 3) {
+ // BC1 RGB is allowed to be mapped to BC1 RGBA.
+ // In such a case, 3-color mode black value can be transparent:
+ // [0, 0, 0, 0] instead of [0, 0, 0, 255].
+
+ if (actual[offset + 3] != expected[3]) {
+ // Got non-opaque value for opaque format
+
+ // Check RGB values. Notice, that the condition here
+ // is more permissive than needed since we don't have
+ // compressed data at this point.
+ if (was[0] == 0 &&
+ was[1] == 0 &&
+ was[2] == 0 &&
+ was[3] == 0) {
+ debug("<b>DXT1 RGB is mapped to DXT1 RGBA</b>");
+ } else {
+ failed = true;
+ testFailed('Alpha at (' + xx + ', ' + yy +
+ ') expected: ' + expected[3] + ' was ' + was);
+ }
+ }
+ } else {
+ // Compare Alpha values
+ // Acceptable interpolation error depends on endpoints:
+ // 1.0 / 65535.0 + 0.03 * max(abs(endpoint0 - endpoint1), abs(endpoint0_p - endpoint1_p))
+ // For simplicity, assume the worst case (e0 is 0.0, e1 is 1.0). After conversion to unorm8, it is 8.
+ if (Math.abs(was[3] - expected[3]) > 8) {
+ failed = true;
+ testFailed('Alpha at (' + xx + ', ' + yy +
+ ') expected: ' + expected + ' +/- 8 was ' + was);
+ }
+ }
+ }
+ }
+ if (!failed) {
+ testPassed("texture rendered correctly with " + filteringMode + " filtering");
+ }
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-astc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-astc.html
new file mode 100644
index 0000000000..d737c3f2a4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-astc.html
@@ -0,0 +1,2524 @@
+<!--
+Copyright (c) 2020 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compressed-texture-utils.js"></script>
+<title>WebGL WEBGL_compressed_texture_astc Conformance Tests</title>
+<style>
+img {
+ border: 1px solid black;
+ margin-right: 1em;
+}
+
+.testimages br {
+ clear: both;
+}
+
+.testimages > div {
+ float: left;
+ margin: 1em;
+}
+</style>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_compressed_texture_astc extension, if it is available.");
+
+debug("");
+
+// Compressed textures generated with ARM's ASTC encoder
+// https://github.com/ARM-software/astc-encoder
+
+// The data below is printed directly from the astc file,
+// and the header has been left for clarity reasons.
+
+// LDR encoded with the following command line:
+// 'astcenc -c source.png result.astc {blockSize} -medium'
+
+// The image used for LDR compression can be found
+// at sdk/tests/resources/red-green-hard.png
+
+var astc_4x4_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x4, 0x4, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x42, 0x2, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x42, 0x2, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x42, 0x2, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x42, 0x2, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x42, 0x2, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x42, 0x2, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+]);
+var astc_5x4_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x5, 0x4, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xc1, 0x2, 0x1, 0x2, 0x1, 0x0, 0x0, 0x80, 0x48, 0x22, 0x89, 0x24, 0x92, 0x48, 0x22, 0x9,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xc1, 0x2, 0x1, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x20, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xc1, 0x2, 0x1, 0x2, 0x1, 0x0, 0x0, 0x80, 0x48, 0x22, 0x89, 0x24, 0x0, 0x40, 0x0, 0x80,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xc1, 0x2, 0x1, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89,
+]);
+var astc_5x5_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x5, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xf3, 0x0, 0x81, 0xff, 0x7, 0x0, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xf3, 0x0, 0x7f, 0x0, 0xf8, 0x1, 0xe0, 0xff, 0xf1, 0xff, 0xf8, 0x7f, 0x0, 0x0, 0x0, 0x0,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff,
+]);
+var astc_6x5_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x6, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x63, 0x1, 0x81, 0x10, 0x0, 0x0, 0x48, 0x49, 0x29, 0x29, 0x25, 0xa5, 0xa4, 0x94, 0x94, 0x12,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x63, 0x1, 0x81, 0x10, 0x0, 0x0, 0x48, 0x0, 0x28, 0x0, 0x24, 0x0, 0xa4, 0x94, 0x94, 0x92,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x63, 0x1, 0x81, 0x10, 0x0, 0x0, 0x0, 0x48, 0x1, 0x28, 0x1, 0xa4, 0x0, 0x94, 0x0, 0x92,
+]);
+var astc_6x6_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x6, 0x6, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x4, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x4, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xc3, 0x30, 0xfc,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x4, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xe3, 0xf8, 0xff, 0xff,
+]);
+var astc_8x5_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x8, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x66, 0x0, 0xc1, 0xff, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x66, 0x0, 0xc1, 0xff, 0x0, 0x0, 0xf0, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x66, 0x0, 0xc1, 0xff, 0x0, 0x0, 0xff, 0xf, 0xff, 0xf, 0xff, 0xf, 0xff, 0xff, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x66, 0x0, 0x3f, 0x0, 0x1f, 0x0, 0x3, 0x0, 0x3, 0x0, 0x3, 0x0, 0x3, 0x0, 0x3, 0x0,
+]);
+var astc_8x6_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x8, 0x6, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x70, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x3f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x70, 0x7f, 0x7f, 0xf8, 0x7f, 0x56, 0x3f, 0x72, 0x7f, 0x7f,
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x70, 0x7f, 0x7f, 0x7f, 0x3f, 0x72, 0x78, 0x7f, 0x70, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x50, 0x7f, 0x72, 0xfe, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+]);
+var astc_8x8_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x8, 0x8, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x44, 0x5, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0x44, 0x5, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x44, 0x5, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc,
+ 0x44, 0x5, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f,
+]);
+var astc_10x5_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x65, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0x0, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x65, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0x0, 0x0, 0xfc, 0xf0, 0xc3, 0xff, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x65, 0x1, 0xff, 0x1, 0x0, 0xfe, 0x1, 0x0, 0x0, 0xc0, 0x7, 0x1f, 0x7c, 0xf0, 0xc1, 0x7,
+]);
+var astc_10x6_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0x6, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xa4, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xa4, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xf0, 0xc3, 0xf, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xa4, 0x1, 0x1, 0xfe, 0xff, 0x1, 0x0, 0x0, 0x0, 0x3e, 0xf8, 0xe0, 0xff, 0xff, 0xff, 0xff,
+]);
+var astc_10x8_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0x8, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x65, 0x9, 0x69, 0x35, 0x0, 0x8, 0x10, 0x2, 0x0, 0x0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x6, 0x11, 0x69, 0x2d, 0x80, 0x40, 0x2, 0x80, 0x4, 0x0, 0x8, 0x0, 0xff, 0xf, 0xf0, 0xff,
+ 0x44, 0x5, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+]);
+var astc_10x10_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0xa, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xa4, 0xc9, 0xc, 0x3, 0x22, 0x0, 0x8, 0x40, 0x8, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x45, 0x89, 0x7, 0x35, 0x0, 0x40, 0x10, 0x0, 0x20, 0x0, 0x0, 0x1f, 0x7c, 0xf0, 0xc1, 0xff,
+]);
+var astc_12x10_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xc, 0xa, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x64, 0x8, 0x11, 0x3, 0x22, 0x0, 0x8, 0x40, 0x38, 0xfc, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xe5, 0x10, 0x4a, 0x4d, 0x46, 0x7f, 0x0, 0xc0, 0xf, 0x40, 0xf8, 0x1, 0x39, 0xf1, 0x7, 0x0,
+]);
+var astc_12x12_argb_ldr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xc, 0xc, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x64, 0xa8, 0x21, 0x3, 0x22, 0x0, 0x8, 0x40, 0x38, 0xfc, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x84, 0xd8, 0xe9, 0x2e, 0x0, 0x0, 0x1, 0x0, 0x80, 0xc0, 0x80, 0x28, 0x2a, 0xab, 0x2a, 0xff,
+]);
+
+// HDR encoded with the following command line:
+// 'astcenc -c source.hdr result.astc {blockSize} -medium'
+
+// The image used for HDR compression can be found
+// at sdk/tests/resources/red-green-hard.hdr
+
+var astc_4x4_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x4, 0x4, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x42, 0x2, 0x1, 0x82, 0x82, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x42, 0x2, 0x81, 0x3, 0x82, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x42, 0x2, 0x81, 0x3, 0x82, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x42, 0x2, 0x83, 0x0, 0x0, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0,
+ 0x42, 0x2, 0x83, 0x0, 0x0, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x42, 0x2, 0x1, 0x82, 0x82, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+]);
+var astc_5x4_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x5, 0x4, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xc1, 0x2, 0x1, 0x42, 0x21, 0x0, 0x0, 0x80, 0x48, 0x22, 0x89, 0x24, 0x92, 0x48, 0x22, 0x9,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xc1, 0x2, 0x1, 0x42, 0x21, 0x0, 0x0, 0x0, 0x0, 0x20, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xc1, 0x2, 0x1, 0x42, 0x21, 0x0, 0x0, 0x80, 0x48, 0x22, 0x89, 0x24, 0x0, 0x40, 0x0, 0x80,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xc1, 0x2, 0x1, 0x42, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89,
+]);
+var astc_5x5_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x5, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xf3, 0x0, 0x81, 0xff, 0x7, 0x0, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xf3, 0x0, 0x81, 0xff, 0x7, 0x0, 0x0, 0x0, 0xe, 0x0, 0x7, 0x80, 0xff, 0xff, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff,
+]);
+var astc_6x5_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x6, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x63, 0x1, 0x81, 0x10, 0x0, 0x0, 0x48, 0x49, 0x29, 0x29, 0x25, 0xa5, 0xa4, 0x94, 0x94, 0x12,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x63, 0x1, 0x81, 0x10, 0x0, 0x0, 0x48, 0x0, 0x28, 0x0, 0x24, 0x0, 0xa4, 0x94, 0x94, 0x92,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x63, 0x1, 0x81, 0x10, 0x0, 0x0, 0x0, 0x48, 0x1, 0x28, 0x1, 0xa4, 0x0, 0x94, 0x0, 0x92,
+]);
+var astc_6x6_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x6, 0x6, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x4, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x4, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xc3, 0x30, 0xfc,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x4, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xe3, 0xf8, 0xff, 0xff,
+]);
+var astc_8x5_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x8, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x66, 0x0, 0xc1, 0xff, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x66, 0x0, 0xc1, 0xff, 0x0, 0x0, 0xf0, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x66, 0x0, 0xc1, 0xff, 0x0, 0x0, 0xff, 0xf, 0xff, 0xf, 0xff, 0xf, 0xff, 0xff, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x66, 0x0, 0xc1, 0xff, 0x0, 0x0, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff,
+]);
+var astc_8x6_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x8, 0x6, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x70, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x3f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x70, 0x7f, 0x7f, 0xf8, 0x7f, 0x56, 0x3f, 0x72, 0x7f, 0x7f,
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x70, 0x7f, 0x7f, 0x7f, 0x3f, 0x72, 0x78, 0x7f, 0x70, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x54, 0x1, 0x81, 0x20, 0x0, 0x0, 0x50, 0x7f, 0x72, 0xfe, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+]);
+var astc_8x8_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0x8, 0x8, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x44, 0x5, 0x81, 0x3, 0x82, 0x0, 0x0, 0x0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0x44, 0x5, 0x81, 0x3, 0x82, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x44, 0x5, 0x1, 0x82, 0x82, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc,
+ 0x44, 0x5, 0x1, 0x82, 0x82, 0x0, 0x0, 0x0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f,
+]);
+var astc_10x5_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0x5, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x65, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0x0, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x65, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0x0, 0x0, 0xfc, 0xf0, 0xc3, 0xff, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x65, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0x0, 0x0, 0xf8, 0xe0, 0x83, 0xf, 0x3e, 0xf8,
+]);
+var astc_10x6_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0x6, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xa4, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xa4, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xf0, 0xc3, 0xf, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xa4, 0x1, 0x1, 0xfc, 0xfd, 0x1, 0x0, 0x0, 0x0, 0x3e, 0xf8, 0xe0, 0xff, 0xff, 0xff, 0xff,
+]);
+var astc_10x8_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0x8, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x65, 0x9, 0x69, 0x35, 0x0, 0x8, 0x10, 0x2, 0x0, 0x0, 0xfc, 0xe0, 0x3, 0x0, 0x0, 0x0,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x15, 0x11, 0x69, 0x25, 0x0, 0x84, 0x0, 0x10, 0x0, 0x2, 0x40, 0x88, 0x3f, 0x0, 0x3f, 0x0,
+ 0x44, 0x5, 0x1, 0x2, 0x2, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+]);
+var astc_10x10_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xa, 0xa, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0xa4, 0xc9, 0xc, 0x3, 0x22, 0x0, 0x8, 0x40, 0x8, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x45, 0x89, 0x7, 0x35, 0x0, 0x40, 0x0, 0x82, 0x0, 0x0, 0x0, 0xe0, 0x83, 0xf, 0x3e, 0x0,
+]);
+var astc_12x10_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xc, 0xa, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x64, 0x8, 0x11, 0x3, 0x22, 0x0, 0x8, 0x40, 0x38, 0xfc, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x44, 0x10, 0x4a, 0x49, 0x46, 0xf, 0x1c, 0x3f, 0x0, 0x28, 0xff, 0x1, 0xc0, 0x3f, 0xc, 0x0,
+]);
+var astc_12x12_argb_hdr = new Uint8Array([
+ //0x13, 0xab, 0xa1, 0x5c, 0xc, 0xc, 0x1, 0x10, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0, 0x0, HEADER
+ 0x64, 0xa8, 0x21, 0x3, 0x22, 0x0, 0x8, 0x40, 0x38, 0xfc, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
+ 0x4, 0xd8, 0xe9, 0x2e, 0x0, 0x8, 0x1, 0x40, 0x80, 0xc0, 0x81, 0x28, 0x2a, 0x0, 0x0, 0x0,
+]);
+
+// Decoded ASTC textures generated with ARM's ASTC encoder
+// https://github.com/ARM-software/astc-encoder
+
+// As the original image is quite simple to compress,
+// several decoded images share the same data
+
+// LDR decoded with the following command line:
+// 'astcenc -d source.astc result.tga'
+var decoded_4x4To10x6_argb_ldr = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+var decoded_10x8_argb_ldr = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xdf, 0x20, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+var decoded_10x10_argb_ldr = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff,
+ 0x20, 0xdf, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x8f, 0x70, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+var decoded_12x10_argb_ldr = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xdf, 0x20, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x70, 0x8f, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+var decoded_12x12_argb_ldr = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x10, 0xef, 0x0, 0xff, 0x10, 0xef, 0x0, 0xff,
+ 0x10, 0xef, 0x0, 0xff, 0x10, 0xef, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x70, 0x8f, 0x0, 0xff, 0x70, 0x8f, 0x0, 0xff,
+ 0x70, 0x8f, 0x0, 0xff, 0x70, 0x8f, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xcf, 0x30, 0x0, 0xff, 0xcf, 0x30, 0x0, 0xff,
+ 0xcf, 0x30, 0x0, 0xff, 0xcf, 0x30, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xbf, 0x40, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x60, 0x9f, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+
+var decoded_10x8_argb_ldr_srgb = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xbc, 0x4, 0x0, 0xff, 0x4, 0xbc, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+var decoded_10x10_argb_ldr_srgb = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x4, 0xbc, 0x0, 0xff, 0x4, 0xbc, 0x0, 0xff,
+ 0x4, 0xbc, 0x0, 0xff, 0x4, 0xbc, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x46, 0x29, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+var decoded_12x10_argb_ldr_srgb = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xbc, 0x4, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x29, 0x46, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+var decoded_12x12_argb_ldr_srgb = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x1, 0xdc, 0x0, 0xff, 0x1, 0xdc, 0x0, 0xff,
+ 0x1, 0xdc, 0x0, 0xff, 0x1, 0xdc, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x29, 0x46, 0x0, 0xff, 0x29, 0x46, 0x0, 0xff,
+ 0x29, 0x46, 0x0, 0xff, 0x29, 0x46, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x9f, 0x8, 0x0, 0xff, 0x9f, 0x8, 0x0, 0xff,
+ 0x9f, 0x8, 0x0, 0xff, 0x9f, 0x8, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x85, 0xd, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x1e, 0x58, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+]);
+
+// HDR decoded with the following command line:
+// 'astcenc -d source.astc result.tga'
+
+var decoded_4x4_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfd, 0x0, 0xff, 0x0, 0xfd, 0x0, 0xff,
+ 0x0, 0xfd, 0x0, 0xff, 0x0, 0xfd, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_5x4_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_5x5_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_6x5_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_6x6_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_8x5_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_8x6_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_8x8_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfd, 0x0, 0xff, 0x0, 0xfd, 0x0, 0xff,
+ 0x0, 0xfd, 0x0, 0xff, 0x0, 0xfd, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xfd, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+
+var decoded_10x5To10x6_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xfe, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+
+var decoded_10x8_argb_hdr = new Uint8Array([
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xdf, 0x20, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_10x10_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff,
+ 0x20, 0xdf, 0x0, 0xff, 0x20, 0xdf, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x8f, 0x70, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_12x10_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xdf, 0x20, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x70, 0x8f, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+var decoded_12x12_argb_hdr = new Uint8Array([
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0x0, 0xfe, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x10, 0xef, 0x0, 0xff, 0x10, 0xef, 0x0, 0xff,
+ 0x10, 0xef, 0x0, 0xff, 0x10, 0xef, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0x70, 0x8f, 0x0, 0xff, 0x70, 0x8f, 0x0, 0xff,
+ 0x70, 0x8f, 0x0, 0xff, 0x70, 0x8f, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xcf, 0x30, 0x0, 0xff, 0xcf, 0x30, 0x0, 0xff,
+ 0xcf, 0x30, 0x0, 0xff, 0xcf, 0x30, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0xbf, 0x40, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x60, 0x9f, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+ 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
+ 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0xff,
+]);
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var nanToMagentaProgram2D, nanToMagentaProgram2DArray, nanToMagentaProgram3D;
+var program2DArray, program3D;
+
+gl.useProgram(program);
+
+var extFlag = "WEBGL_compressed_texture_astc";
+var ext = null;
+var vao = null;
+var validFormats = {
+
+ COMPRESSED_RGBA_ASTC_4x4_KHR : 0x93B0,
+ COMPRESSED_RGBA_ASTC_5x4_KHR : 0x93B1,
+ COMPRESSED_RGBA_ASTC_5x5_KHR : 0x93B2,
+ COMPRESSED_RGBA_ASTC_6x5_KHR : 0x93B3,
+ COMPRESSED_RGBA_ASTC_6x6_KHR : 0x93B4,
+ COMPRESSED_RGBA_ASTC_8x5_KHR : 0x93B5,
+ COMPRESSED_RGBA_ASTC_8x6_KHR : 0x93B6,
+ COMPRESSED_RGBA_ASTC_8x8_KHR : 0x93B7,
+ COMPRESSED_RGBA_ASTC_10x5_KHR : 0x93B8,
+ COMPRESSED_RGBA_ASTC_10x6_KHR : 0x93B9,
+ COMPRESSED_RGBA_ASTC_10x8_KHR : 0x93BA,
+ COMPRESSED_RGBA_ASTC_10x10_KHR : 0x93BB,
+ COMPRESSED_RGBA_ASTC_12x10_KHR : 0x93BC,
+ COMPRESSED_RGBA_ASTC_12x12_KHR : 0x93BD,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : 0x93D0,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : 0x93D1,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : 0x93D2,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : 0x93D3,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : 0x93D4,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : 0x93D5,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : 0x93D6,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : 0x93D7,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : 0x93D8,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : 0x93D9,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : 0x93DA,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : 0x93DB,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : 0x93DC,
+ COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : 0x93DD
+
+};
+var name;
+
+const errorColor = [255, 0, 255, 255];
+let hasHdr = false;
+
+var check2DTarget = 1;
+var check2DArrayTarget = 1;
+var check3DTarget = 1;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // The texture size 3 * 5 * 8 below is divisible by all the different block sizes supported by the extension.
+ ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 3 * 5 * 8);
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, extFlag);
+ if (!ext) {
+ testPassed("No WEBGL_compressed_texture_astc support -- this is legal");
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_astc", false);
+ } else {
+ testPassed("Successfully enabled WEBGL_compressed_texture_astc extension");
+
+ debug("");
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_astc", true);
+ runTestExtension();
+ }
+}
+
+function runTestExtension() {
+ debug("");
+ debug("Testing " + extFlag);
+
+ // Test that enum values are listed correctly in supported formats and in the extension object.
+ ctu.testCompressedFormatsListed(gl, validFormats);
+ ctu.testCorrectEnumValuesInExt(ext, validFormats);
+ // Test that texture upload buffer size is validated correctly.
+ ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+
+ if (contextVersion >= 2) {
+ // For LDR and non-sRGB formats, the error color is magenta *or* all NaNs. To
+ // make sure we accept this we create a program that transforms an all NaN
+ // sampling result to magenta.
+
+ nanToMagentaProgram2D = wtu.setupSimpleTextureProgramESSL300(gl, undefined, undefined,
+ `#version 300 es
+ precision mediump float;
+ uniform sampler2D tex;
+ in vec2 texCoord;
+ out vec4 out_color;
+ void main() {
+ vec4 c = texture(tex, texCoord);
+ if (all(isnan(c))) {
+ out_color = vec4(1, 0, 1, 1);
+ } else {
+ out_color = c;
+ }
+ }`
+ );
+
+ nanToMagentaProgram2DArray = wtu.setupSimpleTextureProgramESSL300(gl, undefined, undefined,
+ `#version 300 es
+ precision mediump float;
+ uniform mediump sampler2DArray tex;
+ in vec2 texCoord;
+ out vec4 out_color;
+ void main() {
+ vec4 c = texture(tex, vec3(texCoord, 0));
+ if (all(isnan(c))) {
+ out_color = vec4(1, 0, 1, 1);
+ } else {
+ out_color = c;
+ }
+ }`
+ );
+
+ nanToMagentaProgram3D = wtu.setupSimpleTextureProgramESSL300(gl, undefined, undefined,
+ `#version 300 es
+ precision mediump float;
+ uniform mediump sampler3D tex;
+ in vec2 texCoord;
+ out vec4 out_color;
+ void main() {
+ vec4 c = texture(tex, vec3(texCoord, 0));
+ if (all(isnan(c))) {
+ out_color = vec4(1, 0, 1, 1);
+ } else {
+ out_color = c;
+ }
+ }`
+ );
+
+ program2DArray = wtu.setupSimpleTextureProgramESSL300(gl, undefined, undefined,
+ `#version 300 es
+ precision mediump float;
+ uniform mediump sampler2DArray tex;
+ in vec2 texCoord;
+ out vec4 out_color;
+ void main() {
+ out_color = texture(tex, vec3(texCoord, 0));
+ }`
+ );
+
+ program3D = wtu.setupSimpleTextureProgramESSL300(gl, undefined, undefined,
+ `#version 300 es
+ precision mediump float;
+ uniform mediump sampler3D tex;
+ in vec2 texCoord;
+ out vec4 out_color;
+ void main() {
+ out_color = texture(tex, vec3(texCoord, 0));
+ }`
+ );
+ }
+
+ // Query supported profiles and test ASTC texture with appropriate formats
+ var profiles = ext.getSupportedProfiles();
+ // Check for HDR support first, since it affects sliced 3D support for LDR
+ if (profiles.indexOf("hdr") != -1) {
+ hasHdr = true;
+ testHDRTextures();
+ } else {
+ testPassed("HDR profile is not supported.");
+ }
+
+ if (profiles.indexOf("ldr") != -1) {
+ testLDRTextures();
+ } else {
+ testFailed('LDR profile must be supported.');
+ }
+}
+
+function testLDRTextures() {
+ debug("");
+ debug("Testing every LDR texture format compression");
+
+ var data = [];
+ var formats = [];
+ var sRGBformats = [];
+ var raws = [];
+ var sRGBraws = [];
+
+ data.push(astc_4x4_argb_ldr, astc_5x4_argb_ldr, astc_5x5_argb_ldr,
+ astc_6x5_argb_ldr, astc_6x6_argb_ldr, astc_8x5_argb_ldr,
+ astc_8x6_argb_ldr, astc_8x8_argb_ldr, astc_10x5_argb_ldr,
+ astc_10x6_argb_ldr, astc_10x8_argb_ldr, astc_10x10_argb_ldr,
+ astc_12x10_argb_ldr, astc_12x12_argb_ldr);
+
+ formats.push(ext.COMPRESSED_RGBA_ASTC_4x4_KHR, ext.COMPRESSED_RGBA_ASTC_5x4_KHR,
+ ext.COMPRESSED_RGBA_ASTC_5x5_KHR, ext.COMPRESSED_RGBA_ASTC_6x5_KHR,
+ ext.COMPRESSED_RGBA_ASTC_6x6_KHR, ext.COMPRESSED_RGBA_ASTC_8x5_KHR,
+ ext.COMPRESSED_RGBA_ASTC_8x6_KHR, ext.COMPRESSED_RGBA_ASTC_8x8_KHR,
+ ext.COMPRESSED_RGBA_ASTC_10x5_KHR, ext.COMPRESSED_RGBA_ASTC_10x6_KHR,
+ ext.COMPRESSED_RGBA_ASTC_10x8_KHR, ext.COMPRESSED_RGBA_ASTC_10x10_KHR,
+ ext.COMPRESSED_RGBA_ASTC_12x10_KHR, ext.COMPRESSED_RGBA_ASTC_12x12_KHR);
+
+ sRGBformats.push(ext.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
+ ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
+ ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
+ ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
+ ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
+ ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
+ ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR);
+
+ // adds decoded image to use in the compare function
+ // certain block size share the same decoded data
+ // due to the fact that the test image is quite simple
+ for (var i = 0; i < 10; ++i)
+ raws.push(decoded_4x4To10x6_argb_ldr);
+ raws.push(decoded_10x8_argb_ldr, decoded_10x10_argb_ldr, decoded_12x10_argb_ldr, decoded_12x12_argb_ldr);
+
+ // Given that test images mostly use 0 and 255, sRGB decoding is the same as linear for 4x4 - 10x6 images
+ for (var i = 0; i < 10; ++i)
+ sRGBraws.push(decoded_4x4To10x6_argb_ldr);
+ sRGBraws.push(decoded_10x8_argb_ldr_srgb, decoded_10x10_argb_ldr_srgb, decoded_12x10_argb_ldr_srgb, decoded_12x12_argb_ldr_srgb);
+
+ testASTCTextures(buildTests(data, formats, raws, 'LDR'));
+ testASTCTextures(buildTests(data, sRGBformats, sRGBraws, 'LDR-sRGB'));
+}
+
+function testHDRTextures() {
+ debug("");
+ debug("Testing every HDR texture format compression");
+
+
+ var data = [];
+ var formats = [];
+ var raws = [];
+
+ data.push(astc_4x4_argb_hdr, astc_5x4_argb_hdr, astc_5x5_argb_hdr,
+ astc_6x5_argb_hdr, astc_6x6_argb_hdr, astc_8x5_argb_hdr,
+ astc_8x6_argb_hdr, astc_8x8_argb_hdr, astc_10x5_argb_hdr,
+ astc_10x6_argb_hdr, astc_10x8_argb_hdr, astc_10x10_argb_hdr,
+ astc_12x10_argb_hdr, astc_12x12_argb_hdr);
+
+ formats.push(ext.COMPRESSED_RGBA_ASTC_4x4_KHR, ext.COMPRESSED_RGBA_ASTC_5x4_KHR,
+ ext.COMPRESSED_RGBA_ASTC_5x5_KHR, ext.COMPRESSED_RGBA_ASTC_6x5_KHR,
+ ext.COMPRESSED_RGBA_ASTC_6x6_KHR, ext.COMPRESSED_RGBA_ASTC_8x5_KHR,
+ ext.COMPRESSED_RGBA_ASTC_8x6_KHR, ext.COMPRESSED_RGBA_ASTC_8x8_KHR,
+ ext.COMPRESSED_RGBA_ASTC_10x5_KHR, ext.COMPRESSED_RGBA_ASTC_10x6_KHR,
+ ext.COMPRESSED_RGBA_ASTC_10x8_KHR, ext.COMPRESSED_RGBA_ASTC_10x10_KHR,
+ ext.COMPRESSED_RGBA_ASTC_12x10_KHR, ext.COMPRESSED_RGBA_ASTC_12x12_KHR);
+
+ // adds decoded image to use in the compare function
+ // certain block size share the same decoded data
+ // due to the fact that the test image is quite simple
+ raws.push(decoded_4x4_argb_hdr, decoded_5x4_argb_hdr, decoded_5x5_argb_hdr, decoded_6x5_argb_hdr,
+ decoded_6x6_argb_hdr, decoded_8x5_argb_hdr, decoded_8x6_argb_hdr, decoded_8x8_argb_hdr,
+ decoded_10x5To10x6_argb_hdr, decoded_10x5To10x6_argb_hdr, decoded_10x8_argb_hdr,
+ decoded_10x10_argb_hdr, decoded_12x10_argb_hdr, decoded_12x12_argb_hdr);
+
+ testASTCTextures(buildTests(data, formats, raws, 'HDR'));
+}
+
+function testASTCTextures(tests) {
+ debug("<hr/>");
+ for (var i = 0; i < tests.length; ++i) {
+ testASTCTexture(tests[i], contextVersion >= 2);
+ }
+}
+
+function testASTCTexture(test, useES3) {
+ var data = test.data;
+ var width = test.width;
+ var height = test.height;
+ var format = test.format;
+ var raw = test.raw;
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, width, height);
+ debug("");
+ debug("testing " + ctu.formatToString(ext, format) + " " + width + "x" + height + " (" + test.mode + ")" +
+ (useES3 ? " via ES 3.0 entrypoints" : " via compressedTexImage2D"));
+ debug("");
+
+ function errorColorMaybeNaN() {
+ return format >= ext.COMPRESSED_RGBA_ASTC_4x4_KHR && format <= ext.COMPRESSED_RGBA_ASTC_12x12_KHR;
+ }
+
+ function ensureParameters(target) {
+ gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ }
+
+ function setupEmptyTexture(target, useStorage) {
+ var tex = gl.createTexture();
+ gl.bindTexture(target, tex);
+ ensureParameters(target);
+
+ if (target == gl.TEXTURE_2D) {
+ if (useStorage) {
+ gl.texStorage2D(target, 1, format, width, height);
+ } else {
+ gl.compressedTexImage2D(target, 0, format, width, height, 0, new Uint8Array(data.length));
+ }
+ } else if (target == gl.TEXTURE_2D_ARRAY || target == gl.TEXTURE_3D) {
+ if (useStorage) {
+ gl.texStorage3D(target, 1, format, width, height, 1);
+ } else {
+ gl.compressedTexImage3D(target, 0, format, width, height, 1, 0, new Uint8Array(data.length));
+ }
+ }
+
+ return tex; // Keep reference to the texture so it could be deleted
+ }
+
+ function uploadSubData(target) {
+ function checkResult(target, expectations, dim) {
+ switch (target) {
+ case gl.TEXTURE_2D:
+ wtu.glErrorShouldBe(gl, expectations[0], "uploading compressed 2D texture data via compressedTexSubImage" + dim);
+ break;
+ case gl.TEXTURE_2D_ARRAY:
+ wtu.glErrorShouldBe(gl, expectations[1], "uploading compressed 2D array texture data via compressedTexSubImage" + dim);
+ break;
+ case gl.TEXTURE_3D:
+ wtu.glErrorShouldBe(gl, expectations[2], "uploading compressed 3D texture data via compressedTexSubImage" + dim);
+ break;
+ }
+ }
+
+ gl.compressedTexSubImage2D(target, 0, 0, 0, width, height, format, data);
+ checkResult(target, [gl.NO_ERROR, gl.INVALID_ENUM, gl.INVALID_ENUM ], "2D");
+
+ if (useES3) {
+ gl.compressedTexSubImage3D(target, 0, 0, 0, 0, width, height, 1, format, data);
+ checkResult(target, [gl.INVALID_ENUM, gl.NO_ERROR, gl.NO_ERROR], "3D");
+ }
+ }
+
+ function setupFilledTexture(target) {
+ var tex = gl.createTexture();
+ gl.bindTexture(target, tex);
+ ensureParameters(target);
+
+ if (target == gl.TEXTURE_2D) {
+ gl.compressedTexImage2D(target, 0, format, width, height, 1, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
+
+ gl.compressedTexImage2D(target, 0, format, width, height, 0, data);
+ } else if (target == gl.TEXTURE_2D_ARRAY || target == gl.TEXTURE_3D) {
+ gl.compressedTexImage3D(target, 0, format, width, height, 1, 0, data);
+ }
+
+ return tex; // Keep reference to the texture so it could be deleted
+ }
+
+ function switchProgram(target) {
+ // For LDR non-sRGB and HDR formats, we accept all NaNs as a valid result.
+ // This program transforms all NaNs to the normal error color, magenta.
+
+ // There's no 100% reliable way to check NaN values on ESSL 1.0,
+ // so error color is verified only on ESSL 3.0.
+
+ if (errorColorMaybeNaN()) {
+ if (target == gl.TEXTURE_2D) {
+ gl.useProgram(nanToMagentaProgram2D);
+ } else if (target == gl.TEXTURE_2D_ARRAY) {
+ gl.useProgram(nanToMagentaProgram2DArray);
+ } else if (target == gl.TEXTURE_3D) {
+ gl.useProgram(nanToMagentaProgram3D);
+ }
+ } else {
+ if (target == gl.TEXTURE_2D) {
+ gl.useProgram(program);
+ } else if (target == gl.TEXTURE_2D_ARRAY) {
+ gl.useProgram(program2DArray);
+ } else if (target == gl.TEXTURE_3D) {
+ gl.useProgram(program3D);
+ }
+ }
+ }
+
+ function checkErrorColor() {
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad from empty texture");
+ wtu.checkCanvas(gl, errorColor, "texture should be initialized to error color");
+ }
+
+ function checkSampling(target) {
+ // Check that the decoded image is consistent with NEAREST filtering
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing quad with NEAREST filtering");
+ compareRect(width, height, test.channels, width, height, raw, data, format, undefined, "NEAREST");
+
+ // Check that the decoded image is consistent with LINEAR filtering
+ gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing quad with LINEAR filtering");
+ compareRect(width, height, test.channels, width, height, raw, data, format, undefined, "LINEAR");
+
+ debug("");
+ // Mipmaps handling
+ gl.generateMipmap(target);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
+ }
+
+ var tex;
+
+ if (useES3) {
+ // 2D texture
+ if (check2DTarget) {
+ switchProgram(gl.TEXTURE_2D);
+
+ // immutable
+ tex = setupEmptyTexture(gl.TEXTURE_2D, true);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
+ checkErrorColor();
+ uploadSubData(gl.TEXTURE_2D);
+ checkSampling(gl.TEXTURE_2D)
+ gl.deleteTexture(tex);
+
+ // mutable empty
+ tex = setupEmptyTexture(gl.TEXTURE_2D, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating empty compressed texture via compressedTexImage2D");
+ checkErrorColor();
+ uploadSubData(gl.TEXTURE_2D);
+ checkSampling(gl.TEXTURE_2D)
+ gl.deleteTexture(tex);
+
+ // mutable filled
+ tex = setupFilledTexture(gl.TEXTURE_2D);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating filled compressed texture via compressedTexImage2D");
+ checkSampling(gl.TEXTURE_2D)
+ gl.deleteTexture(tex);
+ }
+
+ // 2D array
+ if (check2DArrayTarget) {
+ switchProgram(gl.TEXTURE_2D_ARRAY);
+
+ // immutable
+ tex = setupEmptyTexture(gl.TEXTURE_2D_ARRAY, true);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture array via texStorage3D");
+ checkErrorColor();
+ uploadSubData(gl.TEXTURE_2D_ARRAY);
+ checkSampling(gl.TEXTURE_2D_ARRAY)
+ gl.deleteTexture(tex);
+
+ // mutable empty
+ tex = setupEmptyTexture(gl.TEXTURE_2D_ARRAY, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating empty compressed texture array via compressedTexImage3D");
+ checkErrorColor();
+ uploadSubData(gl.TEXTURE_2D_ARRAY);
+ checkSampling(gl.TEXTURE_2D_ARRAY)
+ gl.deleteTexture(tex);
+
+ // mutable filled
+ tex = setupFilledTexture(gl.TEXTURE_2D_ARRAY);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating filled compressed texture array via compressedTexImage3D");
+ checkSampling(gl.TEXTURE_2D_ARRAY)
+ gl.deleteTexture(tex);
+ }
+
+ // 3D texture
+ if (check3DTarget) {
+ switchProgram(gl.TEXTURE_3D);
+ // immutable
+ tex = setupEmptyTexture(gl.TEXTURE_3D, true);
+ if (hasHdr) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed sliced 3D texture via texStorage3D");
+ checkErrorColor();
+ uploadSubData(gl.TEXTURE_3D);
+ checkSampling(gl.TEXTURE_3D)
+ } else {
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "allocating compressed sliced 3D texture via texStorage3D");
+ }
+ gl.deleteTexture(tex);
+
+ // mutable empty
+ tex = setupEmptyTexture(gl.TEXTURE_3D, false);
+ if (hasHdr) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating empty compressed sliced 3D texture via compressedTexImage3D");
+ checkErrorColor();
+ uploadSubData(gl.TEXTURE_3D);
+ checkSampling(gl.TEXTURE_3D)
+ } else {
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "allocating empty compressed sliced 3D texture via compressedTexImage3D");
+ }
+ gl.deleteTexture(tex);
+
+ // mutable filled
+ tex = setupFilledTexture(gl.TEXTURE_3D);
+ if (hasHdr) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating filled compressed sliced 3D texture via compressedTexImage3D");
+ checkSampling(gl.TEXTURE_3D)
+ } else {
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "allocating filled compressed sliced 3D texture via compressedTexImage3D");
+ }
+ gl.deleteTexture(tex);
+ }
+ } else {
+ // 2D texture
+ if (check2DTarget) {
+ // mutable empty
+ tex = setupEmptyTexture(gl.TEXTURE_2D, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating empty compressed texture via compressedTexImage2D");
+
+ // Skip error color check on HDR and non-sRGB formats on WebGL 1.0
+ if (!errorColorMaybeNaN()) checkErrorColor();
+ uploadSubData(gl.TEXTURE_2D);
+ checkSampling(gl.TEXTURE_2D)
+ gl.deleteTexture(tex);
+
+ // mutable filled
+ tex = setupFilledTexture(gl.TEXTURE_2D);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating filled compressed texture via compressedTexImage2D");
+ checkSampling(gl.TEXTURE_2D)
+ gl.deleteTexture(tex);
+ }
+ }
+}
+
+function compareRect(
+ actualWidth, actualHeight, actualChannels,
+ dataWidth, dataHeight, expectedData,
+ testData, testFormat, tolerance, filteringMode) {
+
+ if(typeof(tolerance) == 'undefined') { tolerance = 5; }
+ var actual = new Uint8Array(actualWidth * actualHeight * 4);
+ gl.readPixels(0, 0, actualWidth, actualHeight, gl.RGBA, gl.UNSIGNED_BYTE, actual);
+ flipImage(actual, actualWidth, actualHeight);
+
+ var div = document.createElement("div");
+ div.className = "testimages";
+ ctu.insertCaptionedImg(div, "expected", ctu.makeScaledImage(
+ actualWidth, actualHeight, dataWidth, expectedData,
+ actualChannels == 4));
+ ctu.insertCaptionedImg(div, "actual", ctu.makeScaledImage(
+ actualWidth, actualHeight, actualWidth, actual,
+ actualChannels == 4));
+ div.appendChild(document.createElement('br'));
+ document.getElementById("console").appendChild(div);
+
+ var failed = false;
+ for (var yy = 0; yy < actualHeight; ++yy) {
+ for (var xx = 0; xx < actualWidth; ++xx) {
+ var actualOffset = (yy * actualWidth + xx) * 4;
+ var expectedOffset = (yy * dataWidth + xx) * 4;
+ var expected = [
+ expectedData[expectedOffset + 0],
+ expectedData[expectedOffset + 1],
+ expectedData[expectedOffset + 2],
+ (actualChannels == 3 ? 255 : expectedData[expectedOffset + 3])
+ ];
+ for (var jj = 0; jj < 4; ++jj) {
+ if (Math.abs(actual[actualOffset + jj] - expected[jj]) > tolerance) {
+ failed = true;
+ var was = actual[actualOffset + 0].toString();
+ for (var j = 1; j < 4; ++j) {
+ was += "," + actual[actualOffset + j];
+ }
+ testFailed('at (' + xx + ', ' + yy +
+ ') expected: ' + expected + ' was ' + was);
+ }
+ }
+ }
+ }
+ if (!failed) {
+ testPassed("texture rendered correctly with " + filteringMode + " filtering");
+ }
+}
+
+// Builds several tests from two arrays
+// data gives each Uint8Array encoded data to use
+// formats the associate format to decode the data
+// raws gives each decoded Uint8Array data for texture comparison
+// mode 'LDR', 'LDR-sRGB', or 'HDR'
+function buildTests(data, formats, raws, mode) {
+
+ var tests = [];
+ for (var i = 0; i < data.length; ++i) {
+ var test = {
+ width: 16,
+ height: 16,
+ channels: 4,
+ data: data[i],
+ format: formats[i],
+ raw: raws[i],
+ mode: mode
+ };
+ tests.push(test);
+ }
+
+ return tests;
+}
+
+function expectedByteLength(w, h, format) {
+
+ if (format == validFormats.COMPRESSED_RGBA_ASTC_4x4_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR)
+ return Math.floor((w + 3) / 4) * Math.floor((h + 3) / 4) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_5x4_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR)
+ return Math.floor((w + 4) / 5) * Math.floor((h + 3) / 4) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_5x5_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR)
+ return Math.floor((w + 4) / 5) * Math.floor((h + 4) / 5) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_6x5_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR)
+ return Math.floor((w + 5) / 6) * Math.floor((h + 4) / 5) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_6x6_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR)
+ return Math.floor((w + 5) / 6) * Math.floor((h + 5) / 6) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_8x5_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR)
+ return Math.floor((w + 7) / 8) * Math.floor((h + 4) / 5) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_8x6_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR)
+ return Math.floor((w + 7) / 8) * Math.floor((h + 5) / 6) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_8x8_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR)
+ return Math.floor((w + 7) / 8) * Math.floor((h + 7) / 8) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_10x5_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR)
+ return Math.floor((w + 9) / 10) * Math.floor((h + 4) / 5) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_10x6_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR)
+ return Math.floor((w + 9) / 10) * Math.floor((h + 5) / 6) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_10x8_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR)
+ return Math.floor((w + 9) / 10) * Math.floor((h + 7) / 8) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_10x10_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR)
+ return Math.floor((w + 9) / 10) * Math.floor((h + 9) / 10) * 16;
+ else if (format == validFormats.COMPRESSED_RGBA_ASTC_12x10_KHR || format == validFormats.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR)
+ return Math.floor((w + 11) / 12) * Math.floor((h + 9) / 10) * 16;
+
+ return Math.floor((w + 11) / 12) * Math.floor((h + 11) / 12) * 16;
+}
+
+function getBlockDimensions(format) {
+ var re = /.*_(\d+)x(\d+)_KHR/;
+ for (name in validFormats) {
+ if (validFormats[name] === format) {
+ var match = name.match(re);
+ return {
+ width: parseInt(match[1], 10),
+ height: parseInt(match[2], 10)
+ };
+ }
+ }
+ testFailed('Could not find block dimensions for format ' + ctu.formatToString(ext, format));
+ return {width: 4, height: 4};
+}
+
+// Swaps two cells in an arraybuffer.
+// this function is used in the image flipping function
+function swapCell(array, i, j) {
+ var a = array[i];
+ array[i] = array[j];
+ array[j] = a;
+}
+
+function flipImage(imgBuffer, w, h) {
+ var halfHeight = h / 2;
+
+ for (var j = 0; j < halfHeight; j++) {
+ for (var i = 0; i < w; i++) {
+ var beginByte = (j * w + i) * 4;
+ var endByte = ((h - j - 1) * w + i) * 4;
+
+ swapCell(imgBuffer, beginByte, endByte);
+ swapCell(imgBuffer, beginByte + 1, endByte + 1);
+ swapCell(imgBuffer, beginByte + 2, endByte + 2);
+ swapCell(imgBuffer, beginByte + 3, endByte + 3);
+ }
+ }
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc.html
new file mode 100644
index 0000000000..8a85239ff9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc.html
@@ -0,0 +1,126 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WEBGL_compressed_texture_etc Conformance Tests</title>
+<LINK rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compressed-texture-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_compressed_texture_etc extension, if it is available.");
+
+debug("");
+
+var validFormats = {
+ COMPRESSED_R11_EAC : 0x9270,
+ COMPRESSED_SIGNED_R11_EAC : 0x9271,
+ COMPRESSED_RG11_EAC : 0x9272,
+ COMPRESSED_SIGNED_RG11_EAC : 0x9273,
+ COMPRESSED_RGB8_ETC2 : 0x9274,
+ COMPRESSED_SRGB8_ETC2 : 0x9275,
+ COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9276,
+ COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9277,
+ COMPRESSED_RGBA8_ETC2_EAC : 0x9278,
+ COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : 0x9279
+};
+
+function expectedByteLength(width, height, format) {
+ var blockSizeInBytes = 8;
+
+ var largerBlockFormats = [
+ validFormats.COMPRESSED_RG11_EAC,
+ validFormats.COMPRESSED_SIGNED_RG11_EAC,
+ validFormats.COMPRESSED_RGBA8_ETC2_EAC,
+ validFormats.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC];
+
+ if (largerBlockFormats.indexOf(format) >= 0) {
+ blockSizeInBytes = 16;
+ }
+
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * blockSizeInBytes;
+}
+
+function getBlockDimensions(format) {
+ return {width: 4, height: 4};
+}
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var gl = wtu.create3DContext();
+var WEBGL_compressed_texture_etc;
+
+var formats = null;
+
+function runTest() {
+ if (!gl) {
+ testFailed("context does not exist");
+ } else {
+ testPassed("context exists");
+
+ ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+ WEBGL_compressed_texture_etc = gl.getExtension("WEBGL_compressed_texture_etc");
+
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_etc", WEBGL_compressed_texture_etc !== null);
+
+ var isPositive = WEBGL_compressed_texture_etc !== null;
+
+ if (isPositive) {
+ // Test that enum values are listed correctly in supported formats and in the extension object.
+ ctu.testCompressedFormatsListed(gl, validFormats);
+ ctu.testCorrectEnumValuesInExt(WEBGL_compressed_texture_etc, validFormats);
+ // Test that texture upload buffer size is validated correctly.
+ ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ for (var name in validFormats) {
+ if (validFormats.hasOwnProperty(name)) {
+ var format = validFormats[name];
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, " + format + ", 4, 4, 0, new Uint8Array(" + expectedByteLength(4, 4, format) + "))");
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, " + format + ", new Uint8Array(" + expectedByteLength(4, 4, format) + "))");
+ }
+ }
+ }
+
+ var tex2 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex2);
+
+ debug("");
+ if (contextVersion >= 2) {
+ var expectedError = isPositive ? gl.INVALID_OPERATION: [gl.INVALID_ENUM, gl.INVALID_OPERATION];
+ // `null` coerces into `0` for the PBO entrypoint, yielding INVALID_OP due to no PBO bound.
+ wtu.shouldGenerateGLError(gl, expectedError, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, validFormats.COMPRESSED_R11_EAC, 4, 4, 0, 0, null)");
+ wtu.shouldGenerateGLError(gl, expectedError, "gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, validFormats.COMPRESSED_R11_EAC, 0, null)");
+ wtu.shouldGenerateGLError(gl, expectedError, "gl.compressedTexImage3D(gl.TEXTURE_2D_ARRAY, 0, validFormats.COMPRESSED_R11_EAC, 4, 4, 4, 0, 0, null)");
+ wtu.shouldGenerateGLError(gl, expectedError, "gl.compressedTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, 0, 0, 0, validFormats.COMPRESSED_R11_EAC, 0, null)");
+ } else {
+ shouldThrow("gl.compressedTexImage2D(gl.TEXTURE_2D, 0, validFormats.COMPRESSED_R11_EAC, 4, 4, 0, null)");
+ shouldThrow("gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, validFormats.COMPRESSED_R11_EAC, null)");
+ shouldThrow("gl.compressedTexImage3D(gl.TEXTURE_2D_ARRAY, 0, validFormats.COMPRESSED_R11_EAC, 4, 4, 4, 0, null)");
+ shouldThrow("gl.compressedTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, 0, 0, 0, validFormats.COMPRESSED_R11_EAC, null)");
+ }
+ }
+}
+
+runTest();
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc1.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc1.html
new file mode 100644
index 0000000000..09a6ed0642
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-etc1.html
@@ -0,0 +1,74 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WEBGL_compressed_texture_etc1 Conformance Tests</title>
+<LINK rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compressed-texture-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_compressed_texture_etc1 extension, if it is available.");
+
+debug("");
+
+var validFormats = {
+ COMPRESSED_RGB_ETC1_WEBGL: 0x8D64,
+};
+
+function expectedByteLength(width, height, format) {
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;
+}
+
+function getBlockDimensions(format) {
+ return {width: 4, height: 4};
+}
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var gl = wtu.create3DContext();
+var WEBGL_compressed_texture_etc1;
+
+var formats = null;
+
+function runTest() {
+ if (!gl) {
+ testFailed("context does not exist");
+ } else {
+ testPassed("context exists");
+
+ ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+ WEBGL_compressed_texture_etc1 = gl.getExtension("WEBGL_compressed_texture_etc1");
+
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_etc1", WEBGL_compressed_texture_etc1 !== null);
+
+ if (WEBGL_compressed_texture_etc1 !== null) {
+ // Test that enum values are listed correctly in supported formats and in the extension object.
+ ctu.testCompressedFormatsListed(gl, validFormats);
+ ctu.testCorrectEnumValuesInExt(WEBGL_compressed_texture_etc1, validFormats);
+ // Test that texture upload buffer size is validated correctly.
+ ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+ }
+ }
+}
+
+runTest();
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-pvrtc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-pvrtc.html
new file mode 100644
index 0000000000..465f44a9cd
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-pvrtc.html
@@ -0,0 +1,371 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<title>WebGL WEBGL_compressed_texture_pvrtc Conformance Tests</title>
+<style>
+img {
+ border: 1px solid black;
+ margin-right: 1em;
+}
+.testimages {
+}
+
+.testimages br {
+ clear: both;
+}
+
+.testimages > div {
+ float: left;
+ margin: 1em;
+}
+</style>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_compressed_texture_pvrtc extension, if it is available.");
+
+debug("");
+
+var pvrtc_4x4_2bpp = new Uint8Array([
+ 0x77, 0x22, 0x77, 0x22, 0xbb, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+]);
+
+var pvrtc_4x4_4bpp = new Uint8Array([
+ 0x1b, 0x1b, 0x1b, 0x1b, 0xba, 0x2b, 0x00, 0x80, 0x1b, 0x1b, 0x1b, 0x1b, 0xba, 0x2b, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+]);
+
+var pvrtc_4x4_rgba_decoded = new Uint8Array([
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xba, 0x44,
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xb5, 0x44,
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xb5, 0x44,
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xb7, 0x44,
+]);
+
+var pvrtc_4x4_rgb_decoded = new Uint8Array([
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xba, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xb5, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xb5, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xb7, 0xff,
+]);
+
+var wtu = WebGLTestUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var ext = null;
+var vao = null;
+var validFormats = {
+ COMPRESSED_RGB_PVRTC_4BPPV1_IMG : 0x8C00,
+ COMPRESSED_RGB_PVRTC_2BPPV1_IMG : 0x8C01,
+ COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : 0x8C02,
+ COMPRESSED_RGBA_PVRTC_2BPPV1_IMG : 0x8C03,
+};
+var name;
+var supportedFormats;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runTestDisabled();
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_pvrtc");
+ if (!ext) {
+ testPassed("No WEBGL_compressed_texture_pvrtc support -- this is legal");
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled WEBGL_compressed_texture_pvrtc extension");
+
+ runSupportedTest(true);
+ runTestExtension();
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_pvrtc");
+ if (name !== undefined) {
+ if (extensionEnabled) {
+ testPassed("WEBGL_compressed_texture_pvrtc listed as supported and getExtension succeeded");
+ } else {
+ testFailed("WEBGL_compressed_texture_pvrtc listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("WEBGL_compressed_texture_pvrtc not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("WEBGL_compressed_texture_pvrtc not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+
+function runTestDisabled() {
+ debug("Testing binding enum with extension disabled");
+
+ supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
+ shouldBe("supportedFormats", "[]");
+}
+
+function formatExists(format, supportedFormats) {
+ for (var ii = 0; ii < supportedFormats.length; ++ii) {
+ if (format == supportedFormats[ii]) {
+ testPassed("supported format " + formatToString(format) + " is exists");
+ return;
+ }
+ }
+ testFailed("supported format " + formatToString(format) + " does not exist");
+}
+
+function formatToString(format) {
+ for (var p in ext) {
+ if (ext[p] == format) {
+ return p;
+ }
+ }
+ return "0x" + format.toString(16);
+}
+
+function runTestExtension() {
+ debug("Testing WEBGL_compressed_texture_pvrtc");
+
+ // check that all format enums exist.
+ for (name in validFormats) {
+ var expected = "0x" + validFormats[name].toString(16);
+ var actual = "ext['" + name + "']";
+ shouldBe(actual, expected);
+ }
+
+ supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
+ // There should be exactly 4 formats for both WebGL 1.0 and WebGL 2.0.
+ shouldBe("supportedFormats.length", "4");
+
+ // check that all 4 formats exist
+ for (var name in validFormats.length) {
+ formatExists(validFormats[name], supportedFormats);
+ }
+
+ // Test each format
+ testPVRTC_RGBA_2BPP();
+ testPVRTC_RGB_2BPP();
+ testPVRTC_RGBA_4BPP();
+ testPVRTC_RGB_4BPP();
+}
+
+function testPVRTC_RGBA_2BPP() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: pvrtc_4x4_2bpp,
+ raw: pvrtc_4x4_rgba_decoded,
+ format: ext.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
+ }
+ ];
+ testPVRTCTextures(tests);
+}
+
+function testPVRTC_RGB_2BPP() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: pvrtc_4x4_2bpp,
+ raw: pvrtc_4x4_rgb_decoded,
+ format: ext.COMPRESSED_RGB_PVRTC_2BPPV1_IMG
+ }
+ ];
+ testPVRTCTextures(tests);
+}
+
+function testPVRTC_RGBA_4BPP() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: pvrtc_4x4_4bpp,
+ raw: pvrtc_4x4_rgba_decoded,
+ format: ext.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
+ }
+ ];
+ testPVRTCTextures(tests);
+}
+
+function testPVRTC_RGB_4BPP() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: pvrtc_4x4_4bpp,
+ raw: pvrtc_4x4_rgb_decoded,
+ format: ext.COMPRESSED_RGB_PVRTC_4BPPV1_IMG
+ }
+ ];
+ testPVRTCTextures(tests);
+}
+
+function testPVRTCTextures(tests) {
+ debug("<hr/>");
+ for (var ii = 0; ii < tests.length; ++ii) {
+ testPVRTCTexture(tests[ii]);
+ }
+}
+
+function testPVRTCTexture(test) {
+ var data = new Uint8Array(test.data);
+ var width = test.width;
+ var height = test.height;
+ var format = test.format;
+ var uncompressedData = test.raw;
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, width, height);
+ debug("testing " + formatToString(format) + " " + width + "x" + height);
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
+ gl.generateMipmap(gl.TEXTURE_2D);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
+ wtu.clearAndDrawUnitQuad(gl);
+ compareRect(width, height, test.channels, width, height, uncompressedData, data, format, undefined, "NEAREST");
+ // Test again with linear filtering.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ compareRect(width, height, test.channels, width, height, uncompressedData, data, format, undefined, "LINEAR");
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "compressedTexSubImage2D allowed for reloading of complete textures");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "compressedTexSubImage2D not allowed for partial texture updates");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "compressedTexSubImage2D not allowed for partial texture updates");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 2, 0, width - 2, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "compressedTexSubImage2D not allowed for partial texture updates");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 2, width, height - 2, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "compressedTexSubImage2D not allowed for partial texture updates");
+}
+
+function insertImg(element, caption, img) {
+ var div = document.createElement("div");
+ div.appendChild(img);
+ var label = document.createElement("div");
+ label.appendChild(document.createTextNode(caption));
+ div.appendChild(label);
+ element.appendChild(div);
+}
+
+function makeImage(imageWidth, imageHeight, dataWidth, data, alpha) {
+ var scale = 8;
+ var c = document.createElement("canvas");
+ c.width = imageWidth * scale;
+ c.height = imageHeight * scale;
+ var ctx = c.getContext("2d");
+ for (var yy = 0; yy < imageHeight; ++yy) {
+ for (var xx = 0; xx < imageWidth; ++xx) {
+ var offset = (yy * dataWidth + xx) * 4;
+ ctx.fillStyle = "rgba(" +
+ data[offset + 0] + "," +
+ data[offset + 1] + "," +
+ data[offset + 2] + "," +
+ (alpha ? data[offset + 3] / 255 : 1) + ")";
+ ctx.fillRect(xx * scale, yy * scale, scale, scale);
+ }
+ }
+ return wtu.makeImageFromCanvas(c);
+}
+function compareRect(
+ actualWidth, actualHeight, actualChannels,
+ dataWidth, dataHeight, expectedData,
+ testData, testFormat, tolerance, filteringMode) {
+ if(typeof(tolerance) == 'undefined') { tolerance = 5; }
+ var actual = new Uint8Array(actualWidth * actualHeight * 4);
+ gl.readPixels(
+ 0, 0, actualWidth, actualHeight, gl.RGBA, gl.UNSIGNED_BYTE, actual);
+
+ var div = document.createElement("div");
+ div.className = "testimages";
+ insertImg(div, "expected", makeImage(
+ actualWidth, actualHeight, dataWidth, expectedData,
+ actualChannels == 4));
+ insertImg(div, "actual", makeImage(
+ actualWidth, actualHeight, actualWidth, actual,
+ actualChannels == 4));
+ div.appendChild(document.createElement('br'));
+ document.getElementById("console").appendChild(div);
+
+ var failed = false;
+ for (var yy = 0; yy < actualHeight; ++yy) {
+ for (var xx = 0; xx < actualWidth; ++xx) {
+ var actualOffset = (yy * actualWidth + xx) * 4;
+ var expectedOffset = (yy * dataWidth + xx) * 4;
+ var expected = [
+ expectedData[expectedOffset + 0],
+ expectedData[expectedOffset + 1],
+ expectedData[expectedOffset + 2],
+ (actualChannels == 3 ? 255 : expectedData[expectedOffset + 3])
+ ];
+ for (var jj = 0; jj < 4; ++jj) {
+ if (Math.abs(actual[actualOffset + jj] - expected[jj]) > tolerance) {
+ failed = true;
+ var was = actual[actualOffset + 0].toString();
+ for (var j = 1; j < 4; ++j) {
+ was += "," + actual[actualOffset + j];
+ }
+ testFailed('at (' + xx + ', ' + yy +
+ ') expected: ' + expected + ' was ' + was);
+ }
+ }
+ }
+ }
+ if (!failed) {
+ testPassed("texture rendered correctly with " + filteringMode + " filtering");
+ }
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc-srgb.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc-srgb.html
new file mode 100644
index 0000000000..91fc3f0b1c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc-srgb.html
@@ -0,0 +1,912 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compressed-texture-utils.js"></script>
+<title>WebGL WEBGL_compressed_texture_s3tc_srgb Conformance Tests</title>
+<style>
+img {
+ border: 1px solid black;
+ margin-right: 1em;
+}
+
+.testimages br {
+ clear: both;
+}
+
+.testimages > div {
+ float: left;
+ margin: 1em;
+}
+</style>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_compressed_texture_s3tc_srgb extension, if it is available.");
+
+debug("");
+
+/*
+These tests use the same payloads as a non-sRGB version. When running side-by-side,
+images from these tests must appear much darker than linear counterparts.
+*/
+
+/*
+BC1 (DXT1) block
+e0 = [ 0, 255, 0]
+e1 = [255, 0, 0]
+e0 < e1, so it uses 3-color mode
+
+local palette
+ 0: [ 0, 255, 0, 255]
+ 1: [255, 0, 0, 255]
+ 2: [128, 128, 0, 255]
+ 3: [ 0, 0, 0, 255] // for BC1 RGB
+ 3: [ 0, 0, 0, 0] // for BC1 RGBA
+selectors
+ 3 2 1 0
+ 2 2 1 0
+ 1 1 1 0
+ 0 0 0 0
+
+Extending this block with opaque alpha and uploading as BC2 or BC3
+will generate wrong colors because BC2 and BC3 do not have 3-color mode.
+*/
+var img_4x4_rgba_dxt1 = new Uint8Array([
+ 0xE0, 0x07, 0x00, 0xF8, 0x1B, 0x1A, 0x15, 0x00
+]);
+
+/*
+BC2 (DXT3) block
+
+Quantized alpha values
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 A B
+ C D E F
+
+RGB block
+e0 = [255, 0, 0]
+e1 = [ 0, 255, 0]
+BC2 has only 4-color mode
+
+local palette
+ 0: [255, 0, 0]
+ 1: [ 0, 255, 0]
+ 2: [170, 85, 0]
+ 3: [ 85, 170, 0]
+selectors
+ 0 1 2 3
+ 1 1 2 3
+ 2 2 2 3
+ 3 3 3 3
+*/
+var img_4x4_rgba_dxt3 = new Uint8Array([
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ 0x00, 0xF8, 0xE0, 0x07, 0xE4, 0xE5, 0xEA, 0xFF
+]);
+
+/*
+BC3 (DXT5) block
+
+Alpha block (aka DXT5A)
+e0 = 255
+e1 = 0
+e0 > e1, so using 6 intermediate points
+local palette
+ 255, 0, 219, 182, 146, 109, 73, 36
+selectors
+ 0 1 2 3
+ 1 2 3 4
+ 2 3 4 5
+ 3 4 5 6
+
+RGB block
+e0 = [255, 0, 0]
+e1 = [ 0, 255, 0]
+BC3 has only 4-color mode
+
+local palette
+ 0: [255, 0, 0]
+ 1: [ 0, 255, 0]
+ 2: [170, 85, 0]
+ 3: [ 85, 170, 0]
+selectors
+ 3 2 1 0
+ 3 2 1 1
+ 3 2 2 2
+ 3 3 3 3
+*/
+var img_4x4_rgba_dxt5 = new Uint8Array([
+ 0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+ 0x00, 0xF8, 0xE0, 0x07, 0x1B, 0x5B, 0xAB, 0xFF
+]);
+
+/*
+8x8 block endpoints use half-intensity values (appear darker than 4x4)
+*/
+var img_8x8_rgba_dxt1 = new Uint8Array([
+ 0xe0,0x03,0x00,0x78,0x13,0x10,0x15,0x00,
+ 0x0f,0x00,0xe0,0x7b,0x11,0x10,0x15,0x00,
+ 0xe0,0x03,0x0f,0x78,0x44,0x45,0x40,0x55,
+ 0x0f,0x00,0xef,0x03,0x44,0x45,0x40,0x55
+]);
+var img_8x8_rgba_dxt3 = new Uint8Array([
+ 0xf6,0xff,0xf6,0xff,0xff,0xff,0xff,0xff,0x00,0x78,0xe0,0x03,0x44,0x45,0x40,0x55,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x7b,0x0f,0x00,0x44,0x45,0x40,0x55,
+ 0xff,0xff,0xff,0xff,0xf6,0xff,0xf6,0xff,0x0f,0x78,0xe0,0x03,0x11,0x10,0x15,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x03,0x0f,0x00,0x11,0x10,0x15,0x00
+]);
+var img_8x8_rgba_dxt5 = new Uint8Array([
+0xff,0x69,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x78,0xe0,0x03,0x44,0x45,0x40,0x55,
+ 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x7b,0x0f,0x00,0x44,0x45,0x40,0x55,
+ 0xff,0x69,0x00,0x00,0x00,0x01,0x10,0x00,0x0f,0x78,0xe0,0x03,0x11,0x10,0x15,0x00,
+ 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x03,0xef,0x00,0x11,0x10,0x15,0x00
+]);
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var ext = null;
+var vao = null;
+var validFormats = {
+ COMPRESSED_SRGB_S3TC_DXT1_EXT : 0x8C4C,
+ COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : 0x8C4D,
+ COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : 0x8C4E,
+ COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : 0x8C4F,
+};
+var name;
+var supportedFormats;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_s3tc_srgb");
+ if (!ext) {
+ testPassed("No WEBGL_compressed_texture_s3tc_srgb support -- this is legal");
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_s3tc_srgb", false);
+ } else {
+ testPassed("Successfully enabled WEBGL_compressed_texture_s3tc_srgb extension");
+
+ wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_s3tc_srgb", true);
+ runTestExtension();
+ }
+}
+
+function expectedByteLength(width, height, format) {
+ if (format == validFormats.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT || format == validFormats.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16;
+ }
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;
+}
+
+function getBlockDimensions(format) {
+ return {width: 4, height: 4};
+}
+
+function runTestExtension() {
+ debug("");
+ debug("Testing WEBGL_compressed_texture_s3tc_srgb");
+
+ // Test that enum values are listed correctly in supported formats and in the extension object.
+ ctu.testCompressedFormatsListed(gl, validFormats);
+ ctu.testCorrectEnumValuesInExt(ext, validFormats);
+ // Test that texture upload buffer size is validated correctly.
+ ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+
+ // Test each format
+ testDXT1_SRGB();
+ testDXT1_SRGB_ALPHA();
+ testDXT3_SRGB_ALPHA();
+ testDXT5_SRGB_ALPHA();
+
+ // Test compressed PBOs with a single format
+ if (contextVersion >= 2) {
+ testDXT5_SRGB_ALPHA_PBO();
+ }
+
+ // Test TexImage validation on level dimensions combinations.
+ debug("");
+ debug("When level equals 0, width and height must be a multiple of 4.");
+ debug("When level is larger than 0, this constraint doesn't apply.");
+ ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { level: 0, width: 4, height: 3, expectation: gl.INVALID_OPERATION, message: "0: 4x3" },
+ { level: 0, width: 3, height: 4, expectation: gl.INVALID_OPERATION, message: "0: 3x4" },
+ { level: 0, width: 2, height: 2, expectation: gl.INVALID_OPERATION, message: "0: 2x2" },
+ { level: 0, width: 4, height: 4, expectation: gl.NO_ERROR, message: "0: 4x4" },
+ { level: 1, width: 2, height: 2, expectation: gl.NO_ERROR, message: "1: 2x2" },
+ { level: 2, width: 1, height: 1, expectation: gl.NO_ERROR, message: "2: 1x1" },
+ ]);
+
+ ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 16, 16,
+ [
+ { xoffset: 0, yoffset: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
+ { xoffset: 0, yoffset: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
+ { xoffset: 1, yoffset: 0, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
+ { xoffset: 0, yoffset: 1, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
+ { xoffset: 12, yoffset: 12, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ ]);
+
+ if (contextVersion >= 2) {
+ debug("");
+ debug("Testing NPOT textures");
+ ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { level: 0, width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
+ { level: 1, width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
+ { level: 2, width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
+ { level: 3, width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
+ ]);
+
+ debug("");
+ debug("Testing partial updates");
+ ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 12, 12,
+ [
+ { xoffset: 0, yoffset: 0, width: 4, height: 3,
+ expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
+ { xoffset: 0, yoffset: 0, width: 3, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
+ { xoffset: 1, yoffset: 0, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
+ { xoffset: 0, yoffset: 1, width: 4, height: 4,
+ expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
+ { xoffset: 8, yoffset: 8, width: 4, height: 4,
+ expectation: gl.NO_ERROR, message: "is valid" },
+ ]);
+
+ debug("");
+ debug("Testing immutable NPOT textures");
+ ctu.testTexStorageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
+ [
+ { width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
+ { width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
+ { width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
+ { width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
+ ]);
+ }
+}
+
+function testDXT1_SRGB() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 3,
+ data: img_4x4_rgba_dxt1,
+ format: ext.COMPRESSED_SRGB_S3TC_DXT1_EXT,
+ hasAlpha: false,
+ },
+ { width: 8,
+ height: 8,
+ channels: 3,
+ data: img_8x8_rgba_dxt1,
+ format: ext.COMPRESSED_SRGB_S3TC_DXT1_EXT,
+ hasAlpha: false,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_rgba_dxt1
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXT1_SRGB_ALPHA() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: img_4x4_rgba_dxt1,
+ format: ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
+ // This is a special case -- the texture is still opaque
+ // though it's RGBA.
+ hasAlpha: false,
+ },
+ { width: 8,
+ height: 8,
+ channels: 4,
+ data: img_8x8_rgba_dxt1,
+ format: ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
+ // This is a special case -- the texture is still opaque
+ // though it's RGBA.
+ hasAlpha: false,
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXT3_SRGB_ALPHA() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: img_4x4_rgba_dxt3,
+ format: ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
+ hasAlpha: true,
+ },
+ { width: 8,
+ height: 8,
+ channels: 4,
+ data: img_8x8_rgba_dxt3,
+ format: ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
+ hasAlpha: true,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_rgba_dxt3
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXT5_SRGB_ALPHA() {
+ var tests = [
+ { width: 4,
+ height: 4,
+ channels: 4,
+ data: img_4x4_rgba_dxt5,
+ format: ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
+ hasAlpha: true,
+ },
+ { width: 8,
+ height: 8,
+ channels: 4,
+ data: img_8x8_rgba_dxt5,
+ format: ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
+ hasAlpha: true,
+ subX0: 0,
+ subY0: 0,
+ subWidth: 4,
+ subHeight: 4,
+ subData: img_4x4_rgba_dxt5
+ }
+ ];
+ testDXTTextures(tests);
+}
+
+function testDXTTextures(tests) {
+ debug("<hr/>");
+ for (var ii = 0; ii < tests.length; ++ii) {
+ testDXTTexture(tests[ii], false);
+ if (contextVersion >= 2) {
+ debug("<br/>");
+ testDXTTexture(tests[ii], true);
+ }
+ }
+}
+
+function uncompressDXTBlockSRGB(
+ destBuffer, destX, destY, destWidth, src, srcOffset, format) {
+ // Decoding routines follow D3D11 functional spec wrt
+ // endpoints unquantization and interpolation.
+ // Some hardware may produce slightly different values - it's normal.
+
+ function make565(src, offset) {
+ return src[offset + 0] + (src[offset + 1] << 8);
+ }
+ function make8888From565(c) {
+ // These values exactly match hw decoder when selectors are 0 or 1.
+ function replicateBits(v, w) {
+ return (v << (8 - w)) | (v >> (w + w - 8));
+ }
+ return [
+ replicateBits((c >> 11) & 0x1F, 5),
+ replicateBits((c >> 5) & 0x3F, 6),
+ replicateBits((c >> 0) & 0x1F, 5),
+ 255
+ ];
+ }
+ function mix(mult, c0, c1, div) {
+ var r = [];
+ for (var ii = 0; ii < c0.length; ++ii) {
+ // For green channel (6 bits), this interpolation exactly matches hw decoders
+
+ // For red and blue channels (5 bits), this interpolation exactly
+ // matches only some hw decoders and stays within acceptable range for others.
+ r[ii] = Math.floor((c0[ii] * mult + c1[ii]) / div + 0.5);
+ }
+ return r;
+ }
+ var isDXT1 = format == ext.COMPRESSED_SRGB_S3TC_DXT1_EXT ||
+ format == ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
+ var colorOffset = srcOffset + (isDXT1 ? 0 : 8);
+ var color0 = make565(src, colorOffset + 0);
+ var color1 = make565(src, colorOffset + 2);
+ var c0gtc1 = color0 > color1 || !isDXT1;
+ var rgba0 = make8888From565(color0);
+ var rgba1 = make8888From565(color1);
+ var colors = [
+ rgba0,
+ rgba1,
+ c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2),
+ c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255]
+ ];
+
+ // yea I know there is a lot of math in this inner loop.
+ // so sue me.
+ for (var yy = 0; yy < 4; ++yy) {
+ var pixels = src[colorOffset + 4 + yy];
+ for (var xx = 0; xx < 4; ++xx) {
+ var dstOff = ((destY + yy) * destWidth + destX + xx) * 4;
+ var code = (pixels >> (xx * 2)) & 0x3;
+ var srcColor = colors[code];
+ var alpha;
+ switch (format) {
+ case ext.COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ alpha = 255;
+ break;
+ case ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ alpha = (code == 3 && !c0gtc1) ? 0 : 255;
+ break;
+ case ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ {
+ var alpha0 = src[srcOffset + yy * 2 + (xx >> 1)];
+ var alpha1 = (alpha0 >> ((xx % 2) * 4)) & 0xF;
+ alpha = alpha1 | (alpha1 << 4);
+ }
+ break;
+ case ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ {
+ var alpha0 = src[srcOffset + 0];
+ var alpha1 = src[srcOffset + 1];
+ var alphaOff = (yy >> 1) * 3 + 2;
+ var alphaBits =
+ src[srcOffset + alphaOff + 0] +
+ src[srcOffset + alphaOff + 1] * 256 +
+ src[srcOffset + alphaOff + 2] * 65536;
+ var alphaShift = (yy % 2) * 12 + xx * 3;
+ var alphaCode = (alphaBits >> alphaShift) & 0x7;
+ if (alpha0 > alpha1) {
+ switch (alphaCode) {
+ case 0:
+ alpha = alpha0;
+ break;
+ case 1:
+ alpha = alpha1;
+ break;
+ default:
+ alpha = Math.floor(((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7.0 + 0.5);
+ break;
+ }
+ } else {
+ switch (alphaCode) {
+ case 0:
+ alpha = alpha0;
+ break;
+ case 1:
+ alpha = alpha1;
+ break;
+ case 6:
+ alpha = 0;
+ break;
+ case 7:
+ alpha = 255;
+ break;
+ default:
+ alpha = Math.floor(((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5.0 + 0.5);
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ throw "bad format";
+ }
+ destBuffer[dstOff + 0] = sRGBChannelToLinear(srcColor[0]);
+ destBuffer[dstOff + 1] = sRGBChannelToLinear(srcColor[1]);
+ destBuffer[dstOff + 2] = sRGBChannelToLinear(srcColor[2]);
+ destBuffer[dstOff + 3] = alpha;
+ }
+ }
+}
+
+function getBlockSize(format) {
+ var isDXT1 = format == ext.COMPRESSED_SRGB_S3TC_DXT1_EXT ||
+ format == ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
+ return isDXT1 ? 8 : 16;
+}
+
+function uncompressDXTSRGB(width, height, data, format) {
+ if (width % 4 || height % 4) throw "bad width or height";
+
+ var dest = new Uint8Array(width * height * 4);
+ var blocksAcross = width / 4;
+ var blocksDown = height / 4;
+ var blockSize = getBlockSize(format);
+ for (var yy = 0; yy < blocksDown; ++yy) {
+ for (var xx = 0; xx < blocksAcross; ++xx) {
+ uncompressDXTBlockSRGB(
+ dest, xx * 4, yy * 4, width, data,
+ (yy * blocksAcross + xx) * blockSize, format);
+ }
+ }
+ return dest;
+}
+
+function uncompressDXTIntoSubRegionSRGB(width, height, subX0, subY0, subWidth, subHeight, data, format)
+{
+ if (width % 4 || height % 4 || subX0 % 4 || subY0 % 4 || subWidth % 4 || subHeight % 4)
+ throw "bad dimension";
+
+ var dest = new Uint8Array(width * height * 4);
+ // Zero-filled DXT1 texture represents [0, 0, 0, 255]
+ if (format == ext.COMPRESSED_SRGB_S3TC_DXT1_EXT || format == ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
+ for (var i = 3; i < dest.length; i += 4) dest[i] = 255;
+ }
+ var blocksAcross = subWidth / 4;
+ var blocksDown = subHeight / 4;
+ var blockSize = getBlockSize(format);
+ for (var yy = 0; yy < blocksDown; ++yy) {
+ for (var xx = 0; xx < blocksAcross; ++xx) {
+ uncompressDXTBlockSRGB(
+ dest, subX0 + xx * 4, subY0 + yy * 4, width, data,
+ (yy * blocksAcross + xx) * blockSize, format);
+ }
+ }
+ return dest;
+}
+
+function copyRect(data, srcX, srcY, dstX, dstY, width, height, stride) {
+ var bytesPerLine = width * 4;
+ var srcOffset = srcX * 4 + srcY * stride;
+ var dstOffset = dstX * 4 + dstY * stride;
+ for (; height > 0; --height) {
+ for (var ii = 0; ii < bytesPerLine; ++ii) {
+ data[dstOffset + ii] = data[srcOffset + ii];
+ }
+ srcOffset += stride;
+ dstOffset += stride;
+ }
+}
+
+function testDXTTexture(test, useTexStorage) {
+ var data = new Uint8Array(test.data);
+ var width = test.width;
+ var height = test.height;
+ var format = test.format;
+
+ var uncompressedData = uncompressDXTSRGB(width, height, data, format);
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, width, height);
+ debug("testing " + ctu.formatToString(ext, format) + " " + width + "x" + height +
+ (useTexStorage ? " via texStorage2D" : " via compressedTexImage2D"));
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ if (useTexStorage) {
+ if (test.subData) {
+ var uncompressedDataSub = uncompressDXTIntoSubRegionSRGB(
+ width, height, test.subX0, test.subY0, test.subWidth, test.subHeight, test.subData, format);
+ var tex1 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
+ gl.compressedTexSubImage2D(
+ gl.TEXTURE_2D, 0, test.subX0, test.subY0, test.subWidth, test.subHeight, format, test.subData);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D");
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1");
+ compareRect(width, height, test.channels, uncompressedDataSub, "NEAREST");
+
+ // Clean up and recover
+ gl.deleteTexture(tex1);
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ }
+
+ gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ var clearColor = (test.hasAlpha ? [0, 0, 0, 0] : [0, 0, 0, 255]);
+ wtu.checkCanvas(gl, clearColor, "texture should be initialized to black");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D");
+ } else {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
+ }
+ gl.generateMipmap(gl.TEXTURE_2D);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after clearing generateMipmap error");
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1");
+ compareRect(width, height, test.channels, uncompressedData, "NEAREST");
+ // Test again with linear filtering.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 2");
+ compareRect(width, height, test.channels, uncompressedData, "LINEAR");
+
+ if (!useTexStorage) {
+ // It's not allowed to redefine textures defined via texStorage2D.
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+
+ if (width == 4) {
+ // The width/height of the implied base level must be a multiple of the block size.
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+ }
+ if (height == 4) {
+ // The width/height of the implied base level must be a multiple of the block size.
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+ }
+ }
+
+ // pick a wrong format that uses the same amount of data.
+ var wrongFormat;
+ switch (format) {
+ case ext.COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ wrongFormat = ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
+ break;
+ case ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ wrongFormat = ext.COMPRESSED_SRGB_S3TC_DXT1_EXT;
+ break;
+ case ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ wrongFormat = ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
+ break;
+ case ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ wrongFormat = ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
+ break;
+ }
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "format does not match");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 4, 0, width, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 4, width, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width + 4, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height + 4, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 4, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 4, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 1, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 1, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+
+ var subData = new Uint8Array(data.buffer, 0, getBlockSize(format));
+
+ if (width == 8 && height == 8) {
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 1, 0, 4, 4, format, subData);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 1, 4, 4, format, subData);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
+ }
+
+ var stride = width * 4;
+ for (var yoff = 0; yoff < height; yoff += 4) {
+ for (var xoff = 0; xoff < width; xoff += 4) {
+ copyRect(uncompressedData, 0, 0, xoff, yoff, 4, 4, stride);
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, xoff, yoff, 4, 4, format, subData);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
+ // First test NEAREST filtering.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ wtu.clearAndDrawUnitQuad(gl);
+ compareRect(width, height, test.channels, uncompressedData, "NEAREST");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ // Next test LINEAR filtering.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ compareRect(width, height, test.channels, uncompressedData, "LINEAR");
+ }
+ }
+}
+
+function testDXT5_SRGB_ALPHA_PBO() {
+ debug("");
+ debug("testing PBO uploads");
+ var width = 8;
+ var height = 8;
+ var channels = 4;
+ var data = img_8x8_rgba_dxt5;
+ var format = ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
+ var uncompressedData = uncompressDXTSRGB(width, height, data, format);
+
+ var tex = gl.createTexture();
+
+ // First, PBO size = image size
+ var pbo1 = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo1);
+ gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data, gl.STATIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO");
+
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO");
+
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ compareRect(width, height, channels, uncompressedData, "NEAREST");
+
+ // Clear the texture before the next test
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, new Uint8Array(data.length));
+
+ // Second, image is just a subrange of the PBO
+ var pbo2 = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo2);
+ gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data.length*3, gl.STATIC_DRAW);
+ gl.bufferSubData(gl.PIXEL_UNPACK_BUFFER, data.length, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO subrange");
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, data.length);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO subrange");
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+ compareRect(width, height, channels, uncompressedData, "NEAREST");
+}
+
+// See EXT_texture_sRGB, Section 3.8.x, sRGB Texture Color Conversion.
+function sRGBChannelToLinear(value) {
+ value = value / 255;
+ if (value <= 0.04045) {
+ value = value / 12.92;
+ } else {
+ value = Math.pow((value + 0.055) / 1.055, 2.4);
+ }
+ return Math.trunc(value * 255 + 0.5);
+}
+
+function compareRect(width, height, channels, expectedData, filteringMode) {
+ var actual = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, actual);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "reading back pixels");
+
+ var div = document.createElement("div");
+ div.className = "testimages";
+ ctu.insertCaptionedImg(div, "expected", ctu.makeScaledImage(width, height, width, expectedData, true));
+ ctu.insertCaptionedImg(div, "actual", ctu.makeScaledImage(width, height, width, actual, true));
+ div.appendChild(document.createElement('br'));
+ document.getElementById("console").appendChild(div);
+
+ var failed = false;
+ for (var yy = 0; yy < height; ++yy) {
+ for (var xx = 0; xx < width; ++xx) {
+ var offset = (yy * width + xx) * 4;
+ var expected = expectedData.slice(offset, offset + 4);
+ // Compare RGB values
+ for (var jj = 0; jj < 3; ++jj) {
+ // Acceptable interpolation error depends on endpoints:
+ // 1.0 / 255.0 + 0.03 * max(abs(endpoint0 - endpoint1), abs(endpoint0_p - endpoint1_p))
+ // For simplicity, assume the worst case (e0 is 0.0, e1 is 1.0). After conversion to unorm8, it is 9.
+ if (Math.abs(actual[offset + jj] - expected[jj]) > 9) {
+ var was = actual[offset + 0].toString();
+ for (var j = 1; j < 3; ++j) {
+ was += "," + actual[offset + j];
+ }
+ failed = true;
+ testFailed('RGB at (' + xx + ', ' + yy +
+ ') expected: ' + expected + ' ± 9 was ' + was);
+ }
+ }
+
+ if (channels == 3) {
+ // BC1 RGB is allowed to be mapped to BC1 RGBA.
+ // In such a case, 3-color mode black value can be transparent:
+ // [0, 0, 0, 0] instead of [0, 0, 0, 255].
+
+ if (actual[offset + 3] != expected[3]) {
+ // Got non-opaque value for opaque format
+
+ // Check RGB values. Notice, that the condition here
+ // is more permissive than needed since we don't have
+ // compressed data at this point.
+ if (actual[offset] == 0 &&
+ actual[offset + 1] == 0 &&
+ actual[offset + 2] == 0 &&
+ actual[offset + 3] == 0) {
+ debug("<b>DXT1 SRGB is mapped to DXT1 SRGB ALPHA</b>");
+ } else {
+ failed = true;
+ testFailed('Alpha at (' + xx + ', ' + yy +
+ ') expected: ' + expected[3] + ' was ' + actual[offset + 3]);
+ }
+ }
+ } else {
+ // Compare Alpha values
+ // Acceptable interpolation error depends on endpoints:
+ // 1.0 / 65535.0 + 0.03 * max(abs(endpoint0 - endpoint1), abs(endpoint0_p - endpoint1_p))
+ // For simplicity, assume the worst case (e0 is 0.0, e1 is 1.0). After conversion to unorm8, it is 8.
+ if (Math.abs(actual[offset + 3] - expected[3]) > 8) {
+ var was = actual[offset + 3].toString();
+ failed = true;
+ testFailed('Alpha at (' + xx + ', ' + yy +
+ ') expected: ' + expected + ' ± 8 was ' + was);
+ }
+ }
+ }
+ }
+ if (!failed) {
+ testPassed("texture rendered correctly with " + filteringMode + " filtering");
+ }
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-size-limit.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-size-limit.html
new file mode 100644
index 0000000000..ab50e64d07
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-size-limit.html
@@ -0,0 +1,35 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL compressed texture size limit conformance test</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/webgl-compressed-texture-size-limit.js"></script>
+</head>
+<body>
+<canvas id="example" width="32" height="32" style="width: 40px; height: 40px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+enableJSTestPreVerboseLogging();
+description("Checks size limit of the webgl compressed textures")
+
+// ArrayBuffers can be at most 4GB (minus 1 byte), but any allocations larger than 1 GB are unreliable in practice. So limit allocations to 1 GB.
+// Textures that are wide in just one dimension can still be used to test max TEXTURE_2D size limit even if we can't allocate space for huge square textures.
+// Use a fairly conservative limit for positive test cube map size so OOM is avoided.
+runCompressedTextureSizeLimitTest(Math.pow(2, 30), 2048);
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
+
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-renderer-info.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-renderer-info.html
new file mode 100644
index 0000000000..7901225db7
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-renderer-info.html
@@ -0,0 +1,104 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WebGL_debug_renderer_info Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 1px; height: 1px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing standard derivatives -->
+
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_debug_renderer_info extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas");
+var ext = null;
+var vao = null;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runTestDisabled();
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("WEBGL_debug_renderer_info");
+ if (!ext) {
+ testPassed("No WEBGL_debug_renderer_info support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled WEBGL_debug_renderer_info extension");
+
+ runSupportedTest(true);
+ runTestEnabled();
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("WEBGL_debug_renderer_info") >= 0) {
+ if (extensionEnabled) {
+ testPassed("WEBGL_debug_renderer_info listed as supported and getExtension succeeded");
+ } else {
+ testFailed("WEBGL_debug_renderer_info listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("WEBGL_debug_renderer_info not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("WEBGL_debug_renderer_info not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runTestDisabled() {
+ debug("Testing enums with extension disabled");
+
+ // Use the constants directly as we don't have the extension
+
+ var UNMASKED_VENDOR_WEBGL = 0x9245;
+ gl.getParameter(UNMASKED_VENDOR_WEBGL);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "UNMASKED_VENDOR_WEBGL should not be queryable if extension is disabled");
+
+ var UNMASKED_RENDERER_WEBGL = 0x9246;
+ gl.getParameter(UNMASKED_RENDERER_WEBGL);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "UNMASKED_RENDERER_WEBGL should not be queryable if extension is disabled");
+}
+
+function runTestEnabled() {
+ debug("Testing enums with extension enabled");
+
+ shouldBe("ext.UNMASKED_VENDOR_WEBGL", "0x9245");
+ gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "UNMASKED_VENDOR_WEBGL query should succeed if extension is enable");
+
+ shouldBe("ext.UNMASKED_RENDERER_WEBGL", "0x9246");
+ gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "UNMASKED_RENDERER_WEBGL query should succeed if extension is enable");
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-shaders.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-shaders.html
new file mode 100644
index 0000000000..9a95736a86
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-debug-shaders.html
@@ -0,0 +1,144 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WebGL_debug_shaders Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 1px; height: 1px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing standard derivatives -->
+
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_debug_shaders extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas");
+var ext = null;
+var shader = null;
+var program = null;
+var info = null;
+var translatedSource;
+var newTranslatedSource;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("WEBGL_debug_shaders");
+ if (!ext) {
+ testPassed("No WEBGL_debug_shaders support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled WEBGL_debug_shaders extension");
+
+ runSupportedTest(true);
+ runTestEnabled();
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("WEBGL_debug_shaders") >= 0) {
+ if (extensionEnabled) {
+ testPassed("WEBGL_debug_shaders listed as supported and getExtension succeeded");
+ } else {
+ testFailed("WEBGL_debug_shaders listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("WEBGL_debug_shaders not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("WEBGL_debug_shaders not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runTestEnabled() {
+ debug("Testing function with extension enabled");
+
+ var shaderInfos = [
+ {
+ source: "void main() { gl_Position = vec4(1.0, 0.0, 0.0, 1.0); }",
+ type: gl.VERTEX_SHADER
+ },
+ {
+ source: "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }",
+ type: gl.FRAGMENT_SHADER
+ }
+ ];
+
+ // Do this twice to test for caching issues.
+ for (var jj = 0; jj < 2; ++jj) {
+ debug("pass:" + (jj + 1));
+ program = gl.createProgram();
+ for (var ii = 0; ii < shaderInfos.length; ++ii) {
+ info = shaderInfos[ii];
+
+ shader = gl.createShader(info.type);
+
+ // if no source has been defined or compileShader() has not been called,
+ // getTranslatedShaderSource() should return an empty string.
+ shouldBe("ext.getTranslatedShaderSource(shader)", '""');
+ gl.shaderSource(shader, info.source);
+ shouldBe("ext.getTranslatedShaderSource(shader)", '""');
+ gl.compileShader(shader);
+ shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)");
+ translatedSource = ext.getTranslatedShaderSource(shader);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No gl error should occur");
+ if (translatedSource && translatedSource.length > 0) {
+ testPassed("Successfully called getTranslatedShaderSource()");
+ } else {
+ testFailed("Calling getTranslatedShaderSource() failed");
+ }
+ gl.attachShader(program, shader);
+ }
+ gl.linkProgram(program);
+ shouldBeTrue("gl.getProgramParameter(program, gl.LINK_STATUS)");
+ }
+
+ // Test changing the source. Make sure we get the correct source each time.
+ debug("test changing source");
+ shader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(shader, "void main() { gl_FragColor = vec4(gl_FragCoord.x, 0.0, 0.0, 1.0); }");
+ gl.compileShader(shader);
+ shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)");
+ shouldThrow("ext.getTranslatedShaderSource(null)");
+ translatedSource = ext.getTranslatedShaderSource(shader);
+ shouldBeTrue('translatedSource && translatedSource.indexOf("gl_FragCoord") >= 0');
+ // change the source but don't compile.
+ gl.shaderSource(shader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
+ // the source should NOT change. It should be the same as the old source.
+ newTranslatedSource = ext.getTranslatedShaderSource(shader);
+ shouldBe('newTranslatedSource', 'translatedSource');
+ // now compile.
+ gl.compileShader(shader);
+ shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)");
+ // the source should have change.
+ newTranslatedSource = ext.getTranslatedShaderSource(shader);
+ shouldNotBe('newTranslatedSource', 'translatedSource');
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html
new file mode 100644
index 0000000000..f2318cc1d3
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html
@@ -0,0 +1,377 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<title>WebGL WEBGL_depth_texture Conformance Tests</title>
+</head>
+<body>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 a_position;
+void main()
+{
+ gl_Position = a_position;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D u_texture;
+uniform vec2 u_resolution;
+void main()
+{
+ vec2 texcoord = (gl_FragCoord.xy - vec2(0.5)) / (u_resolution - vec2(1.0));
+ gl_FragColor = texture2D(u_texture, texcoord);
+}
+</script>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_depth_texture extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var ext = null;
+var vao = null;
+var tex;
+var name;
+var supportedFormats;
+var canvas2;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runTestDisabled();
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
+ if (!ext) {
+ testPassed("No WEBGL_depth_texture support -- this is legal");
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled WEBGL_depth_texture extension");
+
+ runSupportedTest(true);
+ runTestExtension(true);
+ runTestExtension(false);
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
+ if (name !== undefined) {
+ if (extensionEnabled) {
+ testPassed("WEBGL_depth_texture listed as supported and getExtension succeeded");
+ } else {
+ testFailed("WEBGL_depth_texture listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("WEBGL_depth_texture not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+
+function runTestDisabled() {
+ debug("Testing binding enum with extension disabled");
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE],
+ 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)');
+ wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE],
+ 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)');
+}
+
+
+function dumpIt(gl, res, msg) {
+ return; // comment out to debug
+ debug(msg);
+ var actualPixels = new Uint8Array(res * res * 4);
+ gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
+
+ for (var yy = 0; yy < res; ++yy) {
+ var strs = [];
+ for (var xx = 0; xx < res; ++xx) {
+ var actual = (yy * res + xx) * 4;
+ strs.push("(" + actualPixels[actual] + "," + actualPixels[actual+1] + "," + actualPixels[actual + 2] + "," + actualPixels[actual + 3] + ")");
+ }
+ debug(strs.join(" "));
+ }
+}
+function runTestExtension(unpackFlipY) {
+ debug("Testing WEBGL_depth_texture. UNPACK_FLIP_Y_WEBGL: " + unpackFlipY);
+
+ const res = 2;
+ const destRes = 4;
+
+ // make canvas for testing.
+ canvas2 = document.createElement("canvas");
+ canvas2.width = res;
+ canvas2.height = res;
+ var ctx = canvas2.getContext("2d");
+ ctx.fillStyle = "blue";
+ ctx.fillRect(0, 0, canvas2.width, canvas2.height);
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']);
+ gl.useProgram(program);
+ gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), destRes, destRes);
+
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ new Float32Array(
+ [ 1, 1, 1,
+ -1, 1, 0,
+ -1, -1, -1,
+ 1, 1, 1,
+ -1, -1, -1,
+ 1, -1, 0,
+ ]),
+ gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, unpackFlipY);
+
+ var types = [
+ {obj: 'gl', attachment: 'DEPTH_ATTACHMENT', format: 'DEPTH_COMPONENT', type: 'UNSIGNED_SHORT', data: 'new Uint16Array(1)', depthBits: "16"},
+ {obj: 'gl', attachment: 'DEPTH_ATTACHMENT', format: 'DEPTH_COMPONENT', type: 'UNSIGNED_INT', data: 'new Uint32Array(1)', depthBits: "16"},
+ {obj: 'ext', attachment: 'DEPTH_STENCIL_ATTACHMENT', format: 'DEPTH_STENCIL', type: 'UNSIGNED_INT_24_8_WEBGL', data: 'new Uint32Array(1)', depthBits: "24", stencilBits: "8"}
+ ];
+
+ for (var ii = 0; ii < types.length; ++ii) {
+ var typeInfo = types[ii];
+ var type = typeInfo.type;
+ var typeStr = typeInfo.obj + '.' + type;
+
+ debug("");
+ debug("testing: " + type);
+
+ // check that cubemaps are not allowed.
+ var cubeTex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTex);
+ var targets = [
+ 'TEXTURE_CUBE_MAP_POSITIVE_X',
+ 'TEXTURE_CUBE_MAP_NEGATIVE_X',
+ 'TEXTURE_CUBE_MAP_POSITIVE_Y',
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Y',
+ 'TEXTURE_CUBE_MAP_POSITIVE_Z',
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Z'
+ ];
+ for (var tt = 0; tt < targets.length; ++tt) {
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.' + targets[ii] + ', 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+ }
+
+ // The WebGL_depth_texture extension supports both NEAREST and
+ // LINEAR filtering for depth textures, even though LINEAR
+ // doesn't have much meaning, and isn't supported in WebGL
+ // 2.0. Still, test both.
+ var filterModes = [
+ 'LINEAR',
+ 'NEAREST'
+ ];
+
+ for (var jj = 0; jj < filterModes.length; ++jj) {
+ debug('');
+ debug('testing ' + filterModes[jj] + ' filtering');
+ var filterMode = gl[filterModes[jj]];
+
+ // check 2d textures.
+ tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterMode);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterMode);
+
+ // test level > 0
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+
+ // test with data
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')');
+
+ // test with canvas
+ 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)');
+
+ // test copyTexImage2D
+ wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 0, 0, 1, 1, 0)');
+
+ // test real thing
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', ' + res + ', ' + res + ', 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+
+ // test texSubImage2D
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')');
+
+ // test copyTexSubImage2D
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1)');
+
+ // test generateMipmap
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.generateMipmap(gl.TEXTURE_2D)');
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, tex, 0);
+
+ // Ensure DEPTH_BITS returns >= 16 bits for UNSIGNED_SHORT and UNSIGNED_INT, >= 24 UNSIGNED_INT_24_8_WEBGL.
+ // If there is stencil, ensure STENCIL_BITS reports >= 8 for UNSIGNED_INT_24_8_WEBGL.
+ shouldBeGreaterThanOrEqual('gl.getParameter(gl.DEPTH_BITS)', typeInfo.depthBits);
+ if (typeInfo.stencilBits === undefined) {
+ shouldBe('gl.getParameter(gl.STENCIL_BITS)', '0');
+ } else {
+ shouldBeGreaterThanOrEqual('gl.getParameter(gl.STENCIL_BITS)', typeInfo.stencilBits);
+ }
+
+ // TODO: remove this check if the spec is updated to require these combinations to work.
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
+ {
+ // try adding a color buffer.
+ var colorTex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, colorTex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, res, res, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);
+ }
+
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ // use the default texture to render with while we return to the depth texture.
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ /* Setup 2x2 depth texture:
+ * 1 0.6 0.8
+ * |
+ * 0 0.2 0.4
+ * 0---1
+ */
+ const d00 = 0.2;
+ const d01 = 0.4;
+ const d10 = 0.6;
+ const d11 = 0.8;
+
+ gl.enable(gl.SCISSOR_TEST);
+
+ gl.scissor(0, 0, 1, 1);
+ gl.clearDepth(d00);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+
+ gl.scissor(1, 0, 1, 1);
+ gl.clearDepth(d10);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+
+ gl.scissor(0, 1, 1, 1);
+ gl.clearDepth(d01);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+
+ gl.scissor(1, 1, 1, 1);
+ gl.clearDepth(d11);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+
+ gl.disable(gl.SCISSOR_TEST);
+
+ // render the depth texture.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.canvas.width = destRes;
+ gl.canvas.height = destRes;
+ gl.viewport(0, 0, destRes, destRes);
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ gl.disable(gl.DITHER);
+ gl.enable(gl.DEPTH_TEST);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ dumpIt(gl, res, "--depth--");
+
+ var actualPixels = new Uint8Array(destRes * destRes * 4);
+ gl.readPixels(0, 0, destRes, destRes, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
+
+ const eps = 0.002;
+
+ let expectedMin;
+ let expectedMax;
+ if (filterMode == gl.NEAREST) {
+ expectedMin = [
+ d00, d00, d10, d10,
+ d00, d00, d10, d10,
+ d01, d01, d11, d11,
+ d01, d01, d11, d11
+ ];
+ expectedMax = expectedMin.slice();
+
+ expectedMin = expectedMin.map(x => x - eps);
+ expectedMax = expectedMax.map(x => x + eps);
+ } else {
+ expectedMin = [
+ d00-eps, d00, d00, d10-eps,
+ d00, d00, d00, d10,
+ d00, d00, d00, d10,
+ d01-eps, d01, d01, d11-eps,
+ ];
+ expectedMax = [
+ d00+eps, d10, d10, d10+eps,
+ d01, d11, d11, d11,
+ d01, d11, d11, d11,
+ d01+eps, d11, d11, d11+eps,
+ ];
+ }
+
+ for (var yy = 0; yy < destRes; ++yy) {
+ for (var xx = 0; xx < destRes; ++xx) {
+ const t = xx + destRes*yy;
+ const was = actualPixels[4*t] / 255.0; // 4bpp
+ const eMin = expectedMin[t];
+ const eMax = expectedMax[t];
+ let func = testPassed;
+ const text = `At ${xx},${yy}, expected within [${eMin},${eMax}], was ${was.toFixed(3)}`
+ if (was <= eMin || was >= eMax) {
+ func = testFailed;
+ }
+ func(text);
+ }
+ }
+
+ // check limitations
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, null, 0);
+ var badAttachment = typeInfo.attachment == 'DEPTH_ATTACHMENT' ? 'DEPTH_STENCIL_ATTACHMENT' : 'DEPTH_ATTACHMENT';
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.' + badAttachment + ', gl.TEXTURE_2D, tex, 0)');
+ shouldNotBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_FRAMEBUFFER_OPERATION, 'gl.clear(gl.DEPTH_BUFFER_BIT)');
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ shouldBe('gl.getError()', 'gl.NO_ERROR');
+ }
+ }
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-broadcast-return.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-broadcast-return.html
new file mode 100644
index 0000000000..d773ae8621
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-broadcast-return.html
@@ -0,0 +1,138 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WEBGL_draw_buffers Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/webgl-draw-buffers-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="64" height="64"> </canvas>
+<div id="console"></div>
+<script id="fshaderRedWithReturn" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+uniform float u_zero;
+void main() {
+ gl_FragColor = vec4(1,0,0,1);
+ if (u_zero < 1.0) {
+ return;
+ }
+ gl_FragColor = vec4(0,0,1,1);
+}
+</script>
+<script id="fshaderWithDiscard" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+uniform float u_zero;
+void main() {
+ gl_FragColor = vec4(1,0,0,1);
+ if (u_zero < 1.0) {
+ discard;
+ }
+ gl_FragColor = vec4(0,0,1,1);
+}
+</script>
+<script>
+"use strict";
+description("This test verifies gl_FragColor being broadcasted when using WEBGL_draw_buffers extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+var drawBuffersUtils;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("WEBGL_draw_buffers");
+ if (!ext) {
+ testPassed("No WEBGL_draw_buffers support -- this is legal");
+ } else {
+ testPassed("Successfully enabled WEBGL_draw_buffers extension");
+ drawBuffersUtils = WebGLDrawBuffersUtils(gl, ext);
+ runDrawTests();
+ }
+}
+
+function runDrawTests() {
+ debug("");
+ var fb = gl.createFramebuffer();
+
+ var maxUsable = drawBuffersUtils.getMaxUsableColorAttachments();
+ var bufs = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
+
+ var width = 64;
+ var height = 64;
+ var attachments = [];
+ for (var ii = 0; ii < maxUsable; ++ii) {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
+ attachments.push({
+ texture: tex
+ });
+ }
+
+ debug("test that gl_FragColor broadcasts if extension is enabled in fragment shader and fragment shader main returns in the middle");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ var redProgramWithReturn = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderRedWithReturn"], ["vPosition"], undefined, true);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.useProgram(redProgramWithReturn);
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after draw");
+
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
+
+ debug("test that none of the attachments are written in case the fragment shader discards");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ var programWithDiscard = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderWithDiscard"], ["vPosition"], undefined, true);
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.useProgram(programWithDiscard);
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after draw");
+
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 0, 0, 0]);
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fb);
+ attachments.forEach(function(attachment) {
+ gl.deleteTexture(attachment.texture);
+ });
+ gl.deleteProgram(redProgramWithReturn);
+ gl.deleteProgram(programWithDiscard);
+}
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-framebuffer-unsupported.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-framebuffer-unsupported.html
new file mode 100644
index 0000000000..5866a3c38b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-framebuffer-unsupported.html
@@ -0,0 +1,126 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WEBGL_draw_buffers FRAMEBUFFER_UNSUPPORTED Test</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+var gl;
+var canvas = document.getElementById("canvas");
+var fb1 = null;
+var fb2 = null;
+
+function checkFramebuffer(expected) {
+ var actual = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (expected.indexOf(actual) < 0) {
+ var msg = "checkFramebufferStatus expects [";
+ for (var index = 0; index < expected.length; ++index) {
+ msg += wtu.glEnumToString(gl, expected[index]);
+ if (index + 1 < expected.length)
+ msg += ", ";
+ }
+ msg += "], was " + wtu.glEnumToString(gl, actual);
+ testFailed(msg);
+ } else {
+ var msg = "checkFramebufferStatus got " + wtu.glEnumToString(gl, actual) +
+ " as expected";
+ testPassed(msg);
+ }
+}
+
+function testImageAttachedTwoPoints() {
+ debug("");
+ debug("Checking an image is attached to more than one color attachment in a framebuffer.");
+
+ var tex1 = gl.createTexture();
+ var tex2 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
+ gl.texImage2D(gl.TEXTURE_2D,
+ 0, // level
+ gl.RGBA, // internalFormat
+ 1, // width
+ 1, // height
+ 0, // border
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ new Uint8Array(4)); // data
+ gl.bindTexture(gl.TEXTURE_2D, tex2);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Texture creation should succeed.");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_2D, tex1, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, tex2, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT2_WEBGL, gl.TEXTURE_2D, tex1, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ var texCube = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCube);
+ for (var target = gl.TEXTURE_CUBE_MAP_POSITIVE_X; target < gl.TEXTURE_CUBE_MAP_POSITIVE_X + 6; target++) {
+ gl.texImage2D(target, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
+ }
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_CUBE_MAP_POSITIVE_X, texCube, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, texCube, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT2_WEBGL, gl.TEXTURE_CUBE_MAP_POSITIVE_X, texCube, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]);
+
+ // Clean up
+ gl.deleteTexture(tex1);
+ gl.deleteTexture(tex2);
+ gl.deleteTexture(texCube);
+}
+
+description("This tests FRAMEBUFFER_UNSUPPORTED.");
+
+shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, 1)");
+fb1 = gl.createFramebuffer();
+fb2 = gl.createFramebuffer();
+
+var ext = gl.getExtension("WEBGL_draw_buffers");
+if (!ext) {
+ testPassed("No WEBGL_draw_buffers support -- this is legal");
+} else {
+ var bufs = [ext.COLOR_ATTACHMENT0_WEBGL, ext.COLOR_ATTACHMENT1_WEBGL, ext.COLOR_ATTACHMENT2_WEBGL];
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb1);
+ ext.drawBuffersWEBGL(bufs);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL successfully");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ ext.drawBuffersWEBGL(bufs);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL successfully");
+
+ testPassed("Successfully enabled WEBGL_draw_buffers extension");
+ testImageAttachedTwoPoints();
+
+ gl.deleteFramebuffer(fb1);
+ gl.deleteFramebuffer(fb2);
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-max-draw-buffers.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-max-draw-buffers.html
new file mode 100644
index 0000000000..8181a6a587
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-max-draw-buffers.html
@@ -0,0 +1,118 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WEBGL_draw_buffers gl_FragData[gl_MaxDrawBuffers] Conformance Test</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="64" height="64"> </canvas>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 a_position;
+void main() {
+ gl_Position = a_position;
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+void main() {
+ gl_FragData[gl_MaxDrawBuffers] = vec4(0.0);
+}
+</script>
+<script id="fshaderConstantIndex" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+void main() {
+ gl_FragData[$(gl_MaxDrawBuffers)] = vec4(0.0);
+}
+</script>
+<script id="fshaderTestMaxDrawBuffersValue" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+void main() {
+ gl_FragColor = ($(gl_MaxDrawBuffers) == gl_MaxDrawBuffers) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
+}
+</script>
+<script>
+"use strict";
+description("This test verifies that compiling the same shader using GL_EXT_draw_buffers twice will have similar results on both rounds.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+var maxDrawBuffers;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ ext = gl.getExtension("WEBGL_draw_buffers");
+ if (!ext) {
+ testPassed("No WEBGL_draw_buffers support -- this is legal");
+ finishTest();
+ } else {
+ testPassed("Successfully enabled WEBGL_draw_buffers extension");
+ maxDrawBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
+ runShadersTest();
+ finishTest();
+ }
+}
+
+function testValueOfMaxDrawBuffers() {
+ debug("Test the value of gl_MaxDrawBuffers in a shader");
+ var fshader = wtu.replaceParams(wtu.getScript("fshaderTestMaxDrawBuffersValue"), {"gl_MaxDrawBuffers": maxDrawBuffers});
+ var program = wtu.setupProgram(gl, ["vshader", fshader], ["a_position"], undefined, true);
+ expectTrue(program != null, "Test program should compile");
+ wtu.setupUnitQuad(gl);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green to indicate that gl_MaxDrawBuffers had the right value");
+ gl.deleteProgram(program);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runSingleTest(shaders, indexMsg) {
+ var program = wtu.setupProgram(gl, shaders, ["a_position"], undefined, true);
+ var programLinkedSuccessfully = (program != null);
+ expectTrue(!programLinkedSuccessfully, "Program where gl_FragData is indexed by " + indexMsg + " should fail compilation.");
+ gl.deleteProgram(program);
+}
+
+function runShadersTest() {
+ debug("MAX_DRAW_BUFFERS_WEBGL is: " + maxDrawBuffers);
+
+ // For reference, use a constant out-of-range parameter to test:
+ debug("Test indexing gl_FragData with value of MAX_DRAW_BUFFERS_WEBGL");
+ var fshader = wtu.replaceParams(wtu.getScript("fshaderConstantIndex"), {"gl_MaxDrawBuffers": maxDrawBuffers});
+ runSingleTest(["vshader", fshader], maxDrawBuffers + " (value of MAX_DRAW_BUFFERS_WEBGL)");
+
+ debug("");
+
+ debug("Test indexing gl_FragData with gl_MaxDrawBuffers");
+ debug("Repeat this test twice as that has revealed a bug.");
+ for (var i = 0; i < 2; ++i) {
+ runSingleTest(["vshader", "fshader"], "gl_MaxDrawBuffers");
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ debug("");
+
+ testValueOfMaxDrawBuffers();
+}
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers.html
new file mode 100644
index 0000000000..a33844f6b4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers.html
@@ -0,0 +1,812 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WEBGL_draw_buffers Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/webgl-draw-buffers-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="64" height="64"> </canvas>
+<div id="console"></div>
+<script id="fshader" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+uniform vec4 u_colors[$(numDrawingBuffers)];
+void main() {
+ for (int i = 0; i < $(numDrawingBuffers); ++i) {
+ gl_FragData[i] = u_colors[i];
+ }
+}
+</script>
+<script id="fshaderNoWrite" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+void main() {
+}
+</script>
+<script id="fshaderRed" type="x-shader/x-fragment">
+precision mediump float;
+void main() {
+ gl_FragColor = vec4(1,0,0,1);
+}
+</script>
+<script id="fshaderRedWithExtension" type="x-shader/x-fragment">
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+void main() {
+ gl_FragColor = vec4(1,0,0,1);
+}
+</script>
+<script id="fshaderMacroDisabled" type="x-shader/x-fragment">
+#ifdef GL_EXT_draw_buffers
+ bad code here
+#endif
+precision mediump float;
+void main() {
+ gl_FragColor = vec4(0,0,0,0);
+}
+</script>
+<script id="fshaderMacroEnabled" type="x-shader/x-fragment">
+#ifdef GL_EXT_draw_buffers
+ #if GL_EXT_draw_buffers == 1
+ #define CODE
+ #else
+ #define CODE this_code_is_bad_it_should_have_compiled
+ #endif
+#else
+ #define CODE this_code_is_bad_it_should_have_compiled
+#endif
+CODE
+precision mediump float;
+void main() {
+ gl_FragColor = vec4(0,0,0,0);
+}
+</script>
+<script id="fshaderBuiltInConstEnabled" type="x-shader/x-fragment">
+precision mediump float;
+void main() {
+ gl_FragColor = (gl_MaxDrawBuffers == $(numDrawingBuffers)) ? vec4(0,1,0,1) : vec4(1,0,0,1);
+}
+</script>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_draw_buffers extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas);
+var ext = null;
+var programWithMaxDrawBuffersEqualOne = null;
+var drawBuffersUtils;
+let fb;
+
+var extensionConstants = [
+ { name: "MAX_COLOR_ATTACHMENTS_WEBGL", enum: 0x8CDF, expectedFn: function(v) { return v >= 4; }, passMsg: " should be >= 4"},
+ { name: "MAX_DRAW_BUFFERS_WEBGL", enum: 0x8824, expectedFn: function(v) { return v > 0; }, passMsg: " should be > 0"},
+
+ { name: "COLOR_ATTACHMENT0_WEBGL", enum: 0x8CE0, },
+ { name: "COLOR_ATTACHMENT1_WEBGL", enum: 0x8CE1, },
+ { name: "COLOR_ATTACHMENT2_WEBGL", enum: 0x8CE2, },
+ { name: "COLOR_ATTACHMENT3_WEBGL", enum: 0x8CE3, },
+ { name: "COLOR_ATTACHMENT4_WEBGL", enum: 0x8CE4, },
+ { name: "COLOR_ATTACHMENT5_WEBGL", enum: 0x8CE5, },
+ { name: "COLOR_ATTACHMENT6_WEBGL", enum: 0x8CE6, },
+ { name: "COLOR_ATTACHMENT7_WEBGL", enum: 0x8CE7, },
+ { name: "COLOR_ATTACHMENT8_WEBGL", enum: 0x8CE8, },
+ { name: "COLOR_ATTACHMENT9_WEBGL", enum: 0x8CE9, },
+ { name: "COLOR_ATTACHMENT10_WEBGL", enum: 0x8CEA, },
+ { name: "COLOR_ATTACHMENT11_WEBGL", enum: 0x8CEB, },
+ { name: "COLOR_ATTACHMENT12_WEBGL", enum: 0x8CEC, },
+ { name: "COLOR_ATTACHMENT13_WEBGL", enum: 0x8CED, },
+ { name: "COLOR_ATTACHMENT14_WEBGL", enum: 0x8CEE, },
+ { name: "COLOR_ATTACHMENT15_WEBGL", enum: 0x8CEF, },
+
+ { name: "DRAW_BUFFER0_WEBGL", enum: 0x8825, },
+ { name: "DRAW_BUFFER1_WEBGL", enum: 0x8826, },
+ { name: "DRAW_BUFFER2_WEBGL", enum: 0x8827, },
+ { name: "DRAW_BUFFER3_WEBGL", enum: 0x8828, },
+ { name: "DRAW_BUFFER4_WEBGL", enum: 0x8829, },
+ { name: "DRAW_BUFFER5_WEBGL", enum: 0x882A, },
+ { name: "DRAW_BUFFER6_WEBGL", enum: 0x882B, },
+ { name: "DRAW_BUFFER7_WEBGL", enum: 0x882C, },
+ { name: "DRAW_BUFFER8_WEBGL", enum: 0x882D, },
+ { name: "DRAW_BUFFER9_WEBGL", enum: 0x882E, },
+ { name: "DRAW_BUFFER10_WEBGL", enum: 0x882F, },
+ { name: "DRAW_BUFFER11_WEBGL", enum: 0x8830, },
+ { name: "DRAW_BUFFER12_WEBGL", enum: 0x8831, },
+ { name: "DRAW_BUFFER13_WEBGL", enum: 0x8832, },
+ { name: "DRAW_BUFFER14_WEBGL", enum: 0x8833, },
+ { name: "DRAW_BUFFER15_WEBGL", enum: 0x8834, },
+];
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runEnumTestDisabled();
+ runShadersTestDisabled();
+ runAttachmentTestDisabled();
+
+ debug("");
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = gl.getExtension("WEBGL_draw_buffers");
+ if (!ext) {
+ testPassed("No WEBGL_draw_buffers support -- this is legal");
+
+ runSupportedTest(false);
+ finishTest();
+ } else {
+ testPassed("Successfully enabled WEBGL_draw_buffers extension");
+
+ drawBuffersUtils = WebGLDrawBuffersUtils(gl, ext);
+ runSupportedTest(true);
+ runEnumTestEnabled();
+ runShadersTestEnabled();
+ runAttachmentTestEnabled();
+ runDrawTests();
+ runPreserveTests();
+ }
+}
+
+function createExtDrawBuffersProgram(scriptId, sub) {
+ var fsource = wtu.getScript(scriptId);
+ fsource = wtu.replaceParams(fsource, sub);
+ return wtu.setupProgram(gl, [wtu.simpleVertexShader, fsource], ["vPosition"], undefined, true);
+}
+
+function runSupportedTest(extensionEnabled) {
+ var supported = gl.getSupportedExtensions();
+ if (supported.indexOf("WEBGL_draw_buffers") >= 0) {
+ if (extensionEnabled) {
+ testPassed("WEBGL_draw_buffers listed as supported and getExtension succeeded");
+ } else {
+ testFailed("WEBGL_draw_buffers listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("WEBGL_draw_buffers not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("WEBGL_draw_buffers not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runEnumTestDisabled() {
+ debug("");
+ debug("Testing binding enum with extension disabled");
+
+ // Use the constant directly as we don't have the extension
+ extensionConstants.forEach(function(c) {
+ if (c.expectedFn) {
+ shouldBeNull(`gl.getParameter(${c.enum})`);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, c.name + " should not be queryable if extension is disabled");
+ }
+ });
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runEnumTestEnabled() {
+ debug("");
+ debug("Testing enums with extension enabled");
+
+ extensionConstants.forEach(function(c) {
+ shouldBe("ext." + c.name, "0x" + c.enum.toString(16));
+ if (c.expectedFn) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "before getParameter");
+ debug(c.name + ": 0x" + ext[c.name].toString(16));
+ expectTrue(c.expectedFn(gl.getParameter(ext[c.name])), "gl.getParameter(ext." + c.name + ")" + c.passMsg);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, c.name + " query should succeed if extension is enabled");
+ }
+ });
+
+ shouldBeTrue("gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL) >= gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL)");
+
+ debug("Testing drawBuffersWEBGL with default drawing buffer");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "ext.drawBuffersWEBGL([])");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "ext.drawBuffersWEBGL([gl.NONE, gl.NONE])");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "ext.drawBuffersWEBGL([ext.COLOR_ATTACHMENT0_WEBGL])");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.NONE])");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.NONE");
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.BACK])");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ debug("Testing drawBuffers and getParameter with bindFramebuffer, without drawing.");
+ fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.COLOR_ATTACHMENT0");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL+1)", "gl.NONE");
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.NONE])");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.NONE");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.NONE,gl.COLOR_ATTACHMENT0+1])");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.NONE");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL+1)", "gl.COLOR_ATTACHMENT0+1");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.COLOR_ATTACHMENT0,gl.COLOR_ATTACHMENT0+1])");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.COLOR_ATTACHMENT0");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL+1)", "gl.COLOR_ATTACHMENT0+1");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fb)");
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
+}
+
+function testShaders(tests, sub) {
+ tests.forEach(function(test) {
+ var shaders = [wtu.simpleVertexShader, wtu.replaceParams(wtu.getScript(test.fragmentShaderTemplate), sub)];
+ var program = wtu.setupProgram(gl, shaders, ["vPosition"], undefined, true);
+ var programLinkedSuccessfully = (program != null);
+ var expectedProgramToLinkSuccessfully = (test.expectFailure == true);
+ expectTrue(programLinkedSuccessfully != expectedProgramToLinkSuccessfully, test.msg);
+ gl.deleteProgram(program);
+ });
+}
+
+function runShadersTestDisabled() {
+ debug("");
+ debug("test shaders disabled");
+
+ var sub = {numDrawingBuffers: 1};
+ testShaders([
+ { fragmentShaderTemplate: "fshaderMacroDisabled",
+ msg: "GL_EXT_draw_buffers should not be defined in GLSL",
+ },
+ { fragmentShaderTemplate: "fshader",
+ msg: "#extension GL_EXT_draw_buffers should not be allowed in GLSL",
+ expectFailure: true,
+ },
+ ], sub);
+
+ programWithMaxDrawBuffersEqualOne = createExtDrawBuffersProgram("fshaderBuiltInConstEnabled", sub);
+ wtu.setupUnitQuad(gl);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runShadersTestEnabled() {
+ debug("");
+ debug("test shaders enabled");
+
+ var sub = {numDrawingBuffers: gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL)};
+ testShaders([
+ { fragmentShaderTemplate: "fshaderMacroEnabled",
+ msg: "GL_EXT_draw_buffers should be defined as 1 in GLSL",
+ },
+ { fragmentShaderTemplate: "fshader",
+ msg: "fragment shader containing the #extension directive should compile",
+ },
+ ], sub);
+
+ var program = createExtDrawBuffersProgram("fshaderBuiltInConstEnabled", sub);
+ wtu.setupUnitQuad(gl);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+ gl.deleteProgram(program);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ debug("");
+ debug("test that gl_MaxDrawBuffers is frozen at link time and enabling the extension won't change it.");
+ gl.useProgram(programWithMaxDrawBuffersEqualOne);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+ gl.deleteProgram(programWithMaxDrawBuffersEqualOne);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runAttachmentTestDisabled() {
+ debug("");
+ debug("test attachment disabled");
+ var tex = gl.createTexture();
+ var fb = gl.createFramebuffer();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + 1, gl.TEXTURE_2D, tex, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach to gl.COLOR_ATTACHMENT1");
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function makeArray(size, value) {
+ var array = []
+ for (var ii = 0; ii < size; ++ii) {
+ array.push(value);
+ }
+ return array;
+}
+
+function runAttachmentTestEnabled() {
+ debug("");
+ debug("test attachment enabled");
+
+ var maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
+ var maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL);
+
+ var tex = gl.createTexture();
+ var fb = gl.createFramebuffer();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments, gl.TEXTURE_2D, tex, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach pass the max attachment point: gl.COLOR_ATTACHMENT0 + " + maxColorAttachments);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments - 1, gl.TEXTURE_2D, tex, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to attach to the max attachment point: gl.COLOR_ATTACHMENT0 + " + (maxColorAttachments - 1));
+ ext.drawBuffersWEBGL(makeArray(maxDrawingBuffers, gl.NONE));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with array NONE of size " + maxColorAttachments);
+ var bufs = drawBuffersUtils.makeColorAttachmentArray(maxDrawingBuffers);
+ ext.drawBuffersWEBGL(bufs);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with array attachments of size " + maxColorAttachments);
+ bufs[0] = gl.NONE;
+ ext.drawBuffersWEBGL(bufs);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with mixed array attachments of size " + maxColorAttachments);
+ if (maxDrawingBuffers > 1) {
+ bufs[0] = ext.COLOR_ATTACHMENT1_WEBGL;
+ bufs[1] = ext.COLOR_ATTACHMENT0_WEBGL;
+ ext.drawBuffersWEBGL(bufs);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be able to call drawBuffersWEBGL with out of order attachments of size " + maxColorAttachments);
+ var bufs = drawBuffersUtils.makeColorAttachmentArray(Math.floor(maxDrawingBuffers / 2));
+ ext.drawBuffersWEBGL(bufs);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with short array of attachments of size " + bufs.length);
+ }
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function makeColorByIndex(index) {
+ var low = (index - 1) % 15 + 1;
+ var high = (index - 1) / 15;
+
+ var zeroOrOne = function(v) {
+ return v ? 1 : 0;
+ };
+
+ var oneOrTwo = function(v) {
+ return v ? 2 : 1;
+ }
+
+ var makeComponent = function(b0, b1, b2) {
+ return Math.floor(255 * zeroOrOne(b0) / oneOrTwo(b1) / oneOrTwo(b2));
+ };
+ return [
+ makeComponent(low & (1 << 0), high & (1 << 0), high & (1 << 4)),
+ makeComponent(low & (1 << 1), high & (1 << 1), high & (1 << 5)),
+ makeComponent(low & (1 << 2), high & (1 << 2), high & (1 << 6)),
+ makeComponent(low & (1 << 3), high & (1 << 3), high & (1 << 7)),
+ ];
+}
+
+function runDrawTests() {
+ debug("");
+ debug("--------- draw tests -----------");
+ var fb = gl.createFramebuffer();
+ var fb2 = gl.createFramebuffer();
+ var halfFB1 = gl.createFramebuffer();
+ var halfFB2 = gl.createFramebuffer();
+ var endsFB = gl.createFramebuffer();
+ var middleFB = gl.createFramebuffer();
+
+ var maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
+ var maxUsable = drawBuffersUtils.getMaxUsableColorAttachments();
+ var half = Math.floor(maxUsable / 2);
+ var bufs = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
+ var nones = makeArray(maxUsable, gl.NONE);
+
+ [fb, fb2, halfFB1, halfFB2, endsFB, middleFB].forEach(function(fbo) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ });
+
+ var checkProgram = wtu.setupTexturedQuad(gl);
+ var redProgram = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderRed"], ["vPosition"]);
+ var redProgramWithExtension = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderRedWithExtension"], ["vPosition"]);
+ var drawProgram = createExtDrawBuffersProgram("fshader", {numDrawingBuffers: maxDrawingBuffers});
+ var width = 64;
+ var height = 64;
+ var attachments = [];
+ // Makes 6 framebuffers.
+ // fb and fb2 have all the attachments.
+ // halfFB1 has the first half of the attachments
+ // halfFB2 has the second half of the attachments
+ // endsFB has the first and last attachments
+ // middleFB has all but the first and last attachments
+ for (var ii = 0; ii < maxUsable; ++ii) {
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, ii < half ? halfFB1 : halfFB2);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, (ii == 0 || ii == (maxUsable - 1)) ? endsFB : middleFB);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
+ var location = gl.getUniformLocation(drawProgram, "u_colors[" + ii + "]");
+ var color = makeColorByIndex(ii + 1);
+ var floatColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
+ gl.uniform4fv(location, floatColor);
+ attachments.push({
+ texture: tex,
+ color: color
+ });
+ }
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ var drawAndCheckAttachments = function(testFB, msg, testFn) {
+ debug("test clearing " + msg);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
+
+ attachments.forEach(function(attachment, index) {
+ debug("attachment: " + index + " = " + wtu.glEnumToString(gl, gl.getParameter(ext.DRAW_BUFFER0_WEBGL + index)) +
+ ", " + wtu.glEnumToString(gl, gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + index, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)));
+ });
+
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ debug("framebuffer not complete");
+ debug("");
+ return;
+ }
+
+ // Clear all the attachments
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ //drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ // return [0, 0, 0, 0];
+ //});
+ //debug("--");
+
+ // Clear some attachments using testFB
+ gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
+
+ gl.clearColor(0, 1, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return testFn(attachment, index) ? [0, 255, 0, 255] : [0, 0, 0, 0];
+ });
+
+ debug("test drawing to " + msg);
+
+ // Draw to some attachments using testFB
+ gl.useProgram(drawProgram);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
+ wtu.drawUnitQuad(gl);
+
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return testFn(attachment, index) ? attachment.color : [0, 0, 0, 0];
+ });
+ };
+
+ gl.useProgram(drawProgram);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ ext.drawBuffersWEBGL(bufs);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+
+ wtu.drawUnitQuad(gl);
+
+ debug("test that each texture got the correct color.");
+
+ drawBuffersUtils.checkAttachmentsForColor(attachments);
+
+ debug("test clearing clears all the textures");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.clearColor(0, 1, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
+
+ debug("test a fragment shader writing to neither gl_FragColor nor gl_FragData does not touch attachments");
+ var noWriteProgram = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderNoWrite"], ["vPosition"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no GL error setting up the program");
+ if (!noWriteProgram) {
+ testFailed("Setup a program where fragment shader writes nothing failed");
+ } else {
+ gl.useProgram(noWriteProgram);
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
+ gl.deleteProgram(noWriteProgram);
+ }
+
+ debug("test that NONE draws nothing");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(nones);
+ gl.useProgram(redProgram);
+ wtu.clearAndDrawUnitQuad(gl);
+
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
+
+ debug("test that gl_FragColor does not broadcast unless extension is enabled in fragment shader");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ gl.useProgram(redProgram);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
+ gl.colorMask(false, false, false, false);
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors when all 4 channels of color mask are disabled.");
+ gl.colorMask(false, true, false, false);
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "partially diabled color mask shall have no impact.");
+ gl.colorMask(true, true, true, true);
+
+ debug("test that gl_FragColor broadcasts if extension is enabled in fragment shader");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ gl.useProgram(redProgramWithExtension);
+ wtu.drawUnitQuad(gl);
+
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
+
+ if (maxUsable > 1) {
+ // First half of color buffers disable.
+ var bufs1 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
+ // Second half of color buffers disable.
+ var bufs2 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
+ // Color buffers with even indices disabled.
+ var bufs3 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
+ // Color buffers with odd indices disabled.
+ var bufs4 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
+ for (var ii = 0; ii < maxUsable; ++ii) {
+ if (ii < half) {
+ bufs1[ii] = gl.NONE;
+ } else {
+ bufs2[ii] = gl.NONE;
+ }
+ if (ii % 2) {
+ bufs3[ii] = gl.NONE;
+ } else {
+ bufs4[ii] = gl.NONE;
+ }
+ }
+
+ debug("test setting first half to NONE and clearing");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ // We should clear all buffers rather than depending on the previous
+ // gl_FragColor broadcasts test to succeed and setting the colors.
+ ext.drawBuffersWEBGL(bufs);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ ext.drawBuffersWEBGL(bufs1);
+ gl.clearColor(0, 1, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return index < half ? [255, 0, 0, 255] : [0, 255, 0, 255];
+ });
+
+ debug("test setting first half to NONE and drawing");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.useProgram(drawProgram);
+ wtu.drawUnitQuad(gl);
+
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return index < half ? [255, 0, 0, 255] : attachment.color;
+ });
+
+ debug("test setting second half to NONE and clearing");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ ext.drawBuffersWEBGL(bufs2);
+ gl.clearColor(0, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return index < half ? [0, 0, 255, 255] : [255, 0, 0, 255];
+ });
+
+ debug("test setting second half to NONE and drawing");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.useProgram(drawProgram);
+ wtu.drawUnitQuad(gl);
+
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return index < half ? attachment.color : [255, 0, 0, 255];
+ });
+
+ debug("test setting buffers with even indices to NONE and clearing");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ ext.drawBuffersWEBGL(bufs3);
+ gl.clearColor(1, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return (index % 2) ? [255, 0, 0, 255] : [255, 0, 255, 255];
+ });
+
+ debug("test setting buffers with odd indices to NONE and drawing");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.useProgram(drawProgram);
+ ext.drawBuffersWEBGL(bufs4);
+ wtu.drawUnitQuad(gl);
+
+ drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return (index % 2 == 0) ? [0, 0, 0, 255] : attachment.color;
+ });
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB1);
+ ext.drawBuffersWEBGL(bufs);
+ drawAndCheckAttachments(
+ halfFB1, "framebuffer that only has first half of attachments",
+ function(attachment, index) {
+ return index < half;
+ });
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB2);
+ ext.drawBuffersWEBGL(bufs);
+ drawAndCheckAttachments(
+ halfFB2, "framebuffer that only has second half of attachments",
+ function(attachment, index) {
+ return index >= half;
+ });
+
+ if (maxUsable > 2) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, endsFB);
+ ext.drawBuffersWEBGL(bufs);
+ drawAndCheckAttachments(
+ endsFB, "framebuffer that only has first and last attachments",
+ function(attachment, index) {
+ return index == 0 || index == (maxUsable - 1);
+ });
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, middleFB);
+ ext.drawBuffersWEBGL(bufs);
+ drawAndCheckAttachments(
+ middleFB,
+ "framebuffer that has all but the first and last attachments",
+ function(attachment, index) {
+ return index != 0 && index != (maxUsable - 1);
+ });
+ }
+ }
+
+ debug("test switching between fbos does not affect any color attachment contents");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ ext.drawBuffersWEBGL(nones);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ ext.drawBuffersWEBGL(bufs);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
+
+ // fb2 still has the NONE draw buffers from before, so this draw should be a no-op.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ gl.useProgram(drawProgram);
+ wtu.drawUnitQuad(gl);
+ drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.useProgram(drawProgram);
+ wtu.drawUnitQuad(gl);
+ drawBuffersUtils.checkAttachmentsForColor(attachments);
+
+ debug("test queries");
+ debug("check framebuffer with all attachments on");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ for (var ii = 0; ii < maxUsable; ++ii) {
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL + " + ii + ")", "gl.COLOR_ATTACHMENT0 + " + ii);
+ }
+
+ debug("check framebuffer with all attachments off");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ for (var ii = 0; ii < maxUsable; ++ii) {
+ shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL + " + ii + ")", "gl.NONE");
+ }
+
+ debug("test attachment size mis-match");
+ gl.bindTexture(gl.TEXTURE_2D, attachments[0].texture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width * 2, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteFramebuffer(fb2);
+ gl.deleteFramebuffer(halfFB1);
+ gl.deleteFramebuffer(halfFB2);
+ attachments.forEach(function(attachment) {
+ gl.deleteTexture(attachment.texture);
+ });
+ gl.deleteProgram(checkProgram);
+ gl.deleteProgram(redProgram);
+ gl.deleteProgram(redProgramWithExtension);
+ gl.deleteProgram(drawProgram);
+}
+
+function runPreserveTests() {
+ debug("");
+ debug("--------- preserve tests -----------");
+
+ debug("Testing that frame buffer is cleared after compositing");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ gl.clearColor(1, 1, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.checkCanvas(gl, [255, 255, 0, 255], "should be yellow");
+
+ // set the draw buffer to NONE
+ ext.drawBuffersWEBGL([gl.NONE]);
+ gl.clearColor(1, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ // make sure the canvas is still clear
+ wtu.checkCanvas(gl, [255, 255, 0, 255], "should be yellow");
+
+ wtu.waitForComposite(function() {
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.checkCanvas(gl, [0, 0, 0, 0], "should be clear");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ runEndTests();
+ });
+}
+
+function runEndTests() {
+ // Create new context and verify shader tests with no extension still succeeds.
+ debug("");
+ debug("Testing new context with no extension");
+ gl = wtu.create3DContext();
+ if (!gl) {
+ testFailed("New WebGL context does not exist");
+ } else {
+ testPassed("New WebGL context exists");
+ runEnumTestDisabled();
+ runShadersTestDisabled();
+ runAttachmentTestDisabled();
+ }
+
+ finishTest();
+}
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-multi-draw.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-multi-draw.html
new file mode 100644
index 0000000000..ae4bbc1af0
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-multi-draw.html
@@ -0,0 +1,1064 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL ANGLE_multi_draw Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/desktop-gl-constants.js"></script>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compositing-test.js"></script>
+<script src="../../js/tests/invalid-vertex-attrib-test.js"></script>
+</head>
+<body>
+<script id="vshaderIllegalDrawID" type="x-shader/x-vertex">
+attribute vec2 vPosition;
+varying vec4 color;
+void main()
+{
+ color = vec4(1.0, 0.0, 0.0, 1.0);
+ gl_Position = vec4(vPosition * 2.0 - 1.0, gl_DrawID, 1);
+}
+</script>
+<script id="vshaderDrawIDZero" type="x-shader/x-vertex">
+#extension GL_ANGLE_multi_draw : require
+attribute vec2 vPosition;
+varying vec4 color;
+void main()
+{
+ if (gl_DrawID == 0) {
+ color = vec4(0, 1, 0, 1);
+ } else {
+ color = vec4(1, 0, 0, 1);
+ }
+ gl_Position = vec4(vPosition * 2.0 - 1.0, 0, 1);
+}
+</script>
+<!-- The behavior of the shaders below is described in runPixelTests() -->
+<script id="vshaderWithDrawID" type="x-shader/x-vertex">
+#extension GL_ANGLE_multi_draw : require
+attribute vec2 vPosition;
+attribute float vInstance;
+varying vec4 color;
+void main()
+{
+ // color_id = (gl_DrawID / 2) % 3
+ float quad_id = float(gl_DrawID / 2);
+ float color_id = quad_id - (3.0 * floor(quad_id / 3.0));
+ if (color_id < 0.5) {
+ color = vec4(1, 0, 0, 1);
+ } else if (color_id < 1.5) {
+ color = vec4(0, 1, 0, 1);
+ } else {
+ color = vec4(0, 0, 1, 1);
+ }
+ mat3 transform = mat3(1.0);
+ // vInstance starts at 1.0 on instanced calls
+ if (vInstance >= 1.0) {
+ transform[0][0] = 0.5;
+ transform[1][1] = 0.5;
+ }
+ if (vInstance == 1.0) {
+ } else if (vInstance == 2.0) {
+ transform[2][0] = 0.5;
+ } else if (vInstance == 3.0) {
+ transform[2][1] = 0.5;
+ } else if (vInstance == 4.0) {
+ transform[2][0] = 0.5;
+ transform[2][1] = 0.5;
+ }
+ gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
+}
+</script>
+<script id="vshaderEmulatedDrawID" type="x-shader/x-vertex">
+uniform int drawID;
+attribute vec2 vPosition;
+attribute float vInstance;
+varying vec4 color;
+void main()
+{
+ float quad_id = float(drawID / 2);
+ float color_id = quad_id - (3.0 * floor(quad_id / 3.0));
+ if (color_id == 0.0) {
+ color = vec4(1, 0, 0, 1);
+ } else if (color_id == 1.0) {
+ color = vec4(0, 1, 0, 1);
+ } else {
+ color = vec4(0, 0, 1, 1);
+ }
+ mat3 transform = mat3(1.0);
+ // vInstance starts at 1.0 on instanced calls
+ if (vInstance >= 1.0) {
+ transform[0][0] = 0.5;
+ transform[1][1] = 0.5;
+ }
+ if (vInstance == 1.0) {
+ } else if (vInstance == 2.0) {
+ transform[2][0] = 0.5;
+ } else if (vInstance == 3.0) {
+ transform[2][1] = 0.5;
+ } else if (vInstance == 4.0) {
+ transform[2][0] = 0.5;
+ transform[2][1] = 0.5;
+ }
+ gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
+}
+</script>
+<script id="vshaderNoDrawID" type="x-shader/x-vertex">
+attribute vec2 vPosition;
+attribute float vInstance;
+varying vec4 color;
+void main()
+{
+ color = vec4(1.0, 0.0, 0.0, 1.0);
+ mat3 transform = mat3(1.0);
+ // vInstance starts at 1.0 on instanced calls
+ if (vInstance >= 1.0) {
+ transform[0][0] = 0.5;
+ transform[1][1] = 0.5;
+ }
+ if (vInstance == 1.0) {
+ } else if (vInstance == 2.0) {
+ transform[2][0] = 0.5;
+ } else if (vInstance == 3.0) {
+ transform[2][1] = 0.5;
+ } else if (vInstance == 4.0) {
+ transform[2][0] = 0.5;
+ transform[2][1] = 0.5;
+ }
+ gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+varying vec4 color;
+void main() {
+ gl_FragColor = color;
+}
+</script>
+<div id="description"></div>
+<canvas id="canvas" width="128" height="128"> </canvas>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("This test verifies the functionality of the ANGLE_multi_draw extension, if it is available.");
+
+const wtu = WebGLTestUtils;
+const canvas = document.getElementById("canvas");
+const gl = wtu.create3DContext(canvas);
+const instancedExt = gl && gl.getExtension('ANGLE_instanced_arrays');
+const bufferUsageSet = [ gl.STATIC_DRAW, gl.DYNAMIC_DRAW ];
+
+// Check if the extension is either both enabled and supported or
+// not enabled and not supported.
+function runSupportedTest(extensionName, extensionEnabled) {
+ const supported = gl.getSupportedExtensions();
+ if (supported.indexOf(extensionName) >= 0) {
+ if (extensionEnabled) {
+ testPassed(extensionName + ' listed as supported and getExtension succeeded');
+ return true;
+ } else {
+ testFailed(extensionName + ' listed as supported but getExtension failed');
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed(extensionName + ' not listed as supported but getExtension succeeded');
+ } else {
+ testPassed(extensionName + ' not listed as supported and getExtension failed -- this is legal');
+ }
+ }
+ return false;
+}
+
+function runTest() {
+ if (!gl) {
+ return function() {
+ testFailed('WebGL context does not exist');
+ }
+ }
+
+ const extensionName = 'WEBGL_multi_draw';
+ const ext = gl.getExtension(extensionName);
+ if (!runSupportedTest(extensionName, ext)) {
+ return;
+ }
+
+ doTest(ext, false);
+ doTest(ext, true);
+}
+
+function doTest(ext, instanced) {
+
+ function runValidationTests(bufferUsage) {
+ const vertexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.2,0.2, 0.8,0.2, 0.5,0.8 ]), bufferUsage);
+
+ const indexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2, 0]), bufferUsage);
+
+ const instanceBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 1, 2, 3 ]), bufferUsage);
+
+ const program = wtu.setupProgram(gl, ["vshaderNoDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+ expectTrue(program != null, "can compile simple program");
+
+ function setupDrawArrays() {
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ }
+
+ function setupDrawElements() {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ }
+
+ function setupInstanced() {
+ gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
+ if (wtu.getDefault3DContextVersion() < 2) {
+ instancedExt.vertexAttribDivisorANGLE(1, 1);
+ } else {
+ gl.vertexAttribDivisor(1, 1);
+ }
+ }
+
+ function setupDrawArraysInstanced() {
+ setupDrawArrays();
+ setupInstanced();
+ }
+
+ function setupDrawElementsInstanced() {
+ setupDrawElements();
+ setupInstanced();
+ }
+
+ // Wrap a draw call in a function to setup the draw call, execute,
+ // and check errors.
+ // The `drawFunc` is one of the extension entrypoints being tested. It may
+ // be undefined if that entrypoint is not supported on the context
+ function makeDrawCheck(drawFunc, setup) {
+ if (!drawFunc) {
+ return function() {};
+ }
+ return function(f_args, expect, msg) {
+ setup();
+ drawFunc.apply(ext, f_args);
+ wtu.glErrorShouldBe(gl, expect, drawFunc.name + " " + msg);
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ }
+ }
+
+ const checkMultiDrawArrays = makeDrawCheck(
+ ext.multiDrawArraysWEBGL, setupDrawArrays);
+ const checkMultiDrawElements = makeDrawCheck(
+ ext.multiDrawElementsWEBGL, setupDrawElements);
+ const checkMultiDrawArraysInstanced = makeDrawCheck(
+ ext.multiDrawArraysInstancedWEBGL, setupDrawArraysInstanced);
+ const checkMultiDrawElementsInstanced = makeDrawCheck(
+ ext.multiDrawElementsInstancedWEBGL, setupDrawElementsInstanced);
+
+ gl.useProgram(program);
+
+ // Check that drawing a single triangle works
+ if (!instanced) {
+ checkMultiDrawArrays(
+ [gl.TRIANGLES, [0], 0, [3], 0, 1],
+ gl.NO_ERROR, "with gl.TRIANGLES");
+ checkMultiDrawElements(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, 1],
+ gl.NO_ERROR, "with gl.TRIANGLES");
+ } else {
+ checkMultiDrawElementsInstanced(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 0, 1],
+ gl.NO_ERROR, "with gl.TRIANGLES");
+ checkMultiDrawArraysInstanced(
+ [gl.TRIANGLES, [0], 0, [3], 0, [1], 0, 1],
+ gl.NO_ERROR, "with gl.TRIANGLES");
+ }
+
+ // Zero drawcount permitted
+ if (!instanced) {
+ checkMultiDrawArrays(
+ [gl.TRIANGLES, [0], 0, [3], 0, 0],
+ gl.NO_ERROR, "with drawcount == 0");
+ checkMultiDrawElements(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, 0],
+ gl.NO_ERROR, "with drawcount == 0");
+ } else {
+ checkMultiDrawElementsInstanced(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 0, 0],
+ gl.NO_ERROR, "with drawcount == 0");
+ checkMultiDrawArraysInstanced(
+ [gl.TRIANGLES, [0], 0, [3], 0, [1], 0, 0],
+ gl.NO_ERROR, "with drawcount == 0");
+ }
+
+ // Check negative drawcount
+ if (!instanced) {
+ checkMultiDrawArrays(
+ [gl.TRIANGLES, [0], 0, [3], 0, -1],
+ gl.INVALID_VALUE, "with drawcount < 0");
+ checkMultiDrawElements(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, -1],
+ gl.INVALID_VALUE, "with drawcount < 0");
+ } else {
+ checkMultiDrawElementsInstanced(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 0, -1],
+ gl.INVALID_VALUE, "with drawcount < 0");
+ checkMultiDrawArraysInstanced(
+ [gl.TRIANGLES, [0], 0, [3], 0, [1], 0, -1],
+ gl.INVALID_VALUE, "with drawcount < 0");
+ }
+
+ // Check offsets greater than array length
+ if (!instanced) {
+ checkMultiDrawArrays(
+ [gl.TRIANGLES, [0], 1, [3], 0, 1],
+ gl.INVALID_OPERATION, "with firstsStart >= firstsList.length");
+ checkMultiDrawArrays(
+ [gl.TRIANGLES, [0], 0, [3], 1, 1],
+ gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+
+ checkMultiDrawElements(
+ [gl.TRIANGLES, [3], 1, gl.UNSIGNED_BYTE, [0], 0, 1],
+ gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+ checkMultiDrawElements(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 1, 1],
+ gl.INVALID_OPERATION, "with offsetsStart >= offsetsList.length");
+ } else {
+ checkMultiDrawArraysInstanced(
+ [gl.TRIANGLES, [0], 1, [3], 0, [1], 0, 1],
+ gl.INVALID_OPERATION, "with firstsStart >= firstsList.length");
+ checkMultiDrawArraysInstanced(
+ [gl.TRIANGLES, [0], 0, [3], 1, [1], 0, 1],
+ gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+ checkMultiDrawArraysInstanced(
+ [gl.TRIANGLES, [0], 0, [3], 0, [1], 1, 1],
+ gl.INVALID_OPERATION, "with instanceCountsStart >= instanceCountsList.length");
+
+ checkMultiDrawElementsInstanced(
+ [gl.TRIANGLES, [3], 1, gl.UNSIGNED_BYTE, [0], 0, [1], 0, 1],
+ gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+ checkMultiDrawElementsInstanced(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 1, [1], 0, 1],
+ gl.INVALID_OPERATION, "with offsetsStart >= offsetsList.length");
+ checkMultiDrawElementsInstanced(
+ [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 1, 1],
+ gl.INVALID_OPERATION, "with instanceCountsStart >= instanceCountsList.length");
+ }
+ }
+
+ function runShaderTests(bufferUsage) {
+ const illegalProgram = wtu.setupProgram(gl, ["vshaderIllegalDrawID", "fshader"], ["vPosition"], [0]);
+ expectTrue(illegalProgram == null, "cannot compile program with gl_DrawID but no extension directive");
+
+ const drawIDProgram = wtu.setupProgram(gl, ["vshaderDrawIDZero", "fshader"], ["vPosition"], [0]);
+ wtu.setupProgram(gl, ["vshaderDrawIDZero", "fshader"], ["vPosition"], [0]);
+ expectTrue(drawIDProgram !== null, "can compile program with gl_DrawID");
+ gl.useProgram(drawIDProgram);
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0,1, 0,1, 1,0, 1,1 ]), bufferUsage);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "gl_DrawID is 0 for non-Multi* draw calls", 0);
+ }
+
+ function runPixelTests(bufferUsage, useSharedArrayBuffer) {
+ // An array of quads is tiled across the screen.
+ // gl_DrawID is checked by using it to select the color of the draw.
+ // Instanced entrypoints are tested here scaling and then instancing the
+ // array of quads over four quadrants on the screen.
+
+ // These tests also include "manyDraw" tests which emulate a multiDraw with
+ // a Javascript for-loop and gl_DrawID with a uniform constiable. They are
+ // included to ensure the test is written correctly.
+
+ const width = gl.canvas.width;
+ const height = gl.canvas.height;
+ const x_count = 8;
+ const y_count = 8;
+ const quad_count = x_count * y_count;
+ const tri_count = quad_count * 2;
+ const tileSize = [ 1/x_count, 1/y_count ];
+ const tilePixelSize = [ Math.floor(width / x_count), Math.floor(height / y_count) ];
+ const quadRadius = [ 0.25 * tileSize[0], 0.25 * tileSize[1] ];
+ const pixelCheckSize = [ Math.floor(quadRadius[0] * width), Math.floor(quadRadius[1] * height) ];
+
+ function getTileCenter(x, y) {
+ return [ tileSize[0] * (0.5 + x), tileSize[1] * (0.5 + y) ];
+ }
+
+ function getQuadVertices(x, y) {
+ const center = getTileCenter(x, y);
+ return [
+ [center[0] - quadRadius[0], center[1] - quadRadius[1], 0],
+ [center[0] + quadRadius[0], center[1] - quadRadius[1], 0],
+ [center[0] + quadRadius[0], center[1] + quadRadius[1], 0],
+ [center[0] - quadRadius[0], center[1] + quadRadius[1], 0],
+ ]
+ }
+
+ const indicesData = [];
+ const verticesData = [];
+ const nonIndexedVerticesData = [];
+ {
+ const is = new Uint16Array([0, 1, 2, 0, 2, 3]);
+ for (let y = 0; y < y_count; ++y) {
+ for (let x = 0; x < x_count; ++x) {
+ const quadIndex = y * x_count + x;
+ const starting_index = 4 * quadIndex;
+ const vs = getQuadVertices(x, y);
+ for (let i = 0; i < is.length; ++i) {
+ indicesData.push(starting_index + is[i]);
+ }
+ for (let i = 0; i < vs.length; ++i) {
+ for (let v = 0; v < vs[i].length; ++v) verticesData.push(vs[i][v]);
+ }
+ for (let i = 0; i < is.length; ++i) {
+ for (let v = 0; v < vs[is[i]].length; ++v) nonIndexedVerticesData.push(vs[is[i]][v]);
+ }
+ }
+ }
+ }
+
+ const indices = new Uint16Array(indicesData);
+ const vertices = new Float32Array(verticesData);
+ const nonIndexedVertices = new Float32Array(nonIndexedVerticesData);
+
+ const indexBuffer = gl.createBuffer();
+ const vertexBuffer = gl.createBuffer();
+ const nonIndexedVertexBuffer = gl.createBuffer();
+ const instanceBuffer = gl.createBuffer();
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, nonIndexedVertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, nonIndexedVertices, bufferUsage);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, bufferUsage);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, bufferUsage);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), bufferUsage);
+
+ function checkResult(config, msg) {
+ const rects = [];
+ const expected = [
+ [255, 0, 0, 255],
+ [0, 255, 0, 255],
+ [0, 0, 255, 255],
+ ];
+ for (let y = 0; y < y_count; ++y) {
+ for (let x = 0; x < x_count; ++x) {
+ const center_x = x * tilePixelSize[0] + Math.floor(tilePixelSize[0] / 2);
+ const center_y = y * tilePixelSize[1] + Math.floor(tilePixelSize[1] / 2);
+ const quadID = y * x_count + x;
+ const colorID = config.drawID ? quadID % 3 : 0;
+ if (config.instanced) {
+ rects.push(wtu.makeCheckRect(
+ center_x / 2 - Math.floor(pixelCheckSize[0] / 4),
+ center_y / 2 - Math.floor(pixelCheckSize[1] / 4),
+ pixelCheckSize[0] / 2,
+ pixelCheckSize[1] / 2,
+ expected[colorID],
+ msg + " (" + x + "," + y + ")", 0));
+ rects.push(wtu.makeCheckRect(
+ center_x / 2 - Math.floor(pixelCheckSize[0] / 4) + width / 2,
+ center_y / 2 - Math.floor(pixelCheckSize[1] / 4),
+ pixelCheckSize[0] / 2,
+ pixelCheckSize[1] / 2,
+ expected[colorID],
+ msg + " (" + x + "," + y + ")", 0));
+ rects.push(wtu.makeCheckRect(
+ center_x / 2 - Math.floor(pixelCheckSize[0] / 4),
+ center_y / 2 - Math.floor(pixelCheckSize[1] / 4) + height / 2,
+ pixelCheckSize[0] / 2,
+ pixelCheckSize[1] / 2,
+ expected[colorID],
+ msg + " (" + x + "," + y + ")", 0));
+ rects.push(wtu.makeCheckRect(
+ center_x / 2 - Math.floor(pixelCheckSize[0] / 4) + width / 2,
+ center_y / 2 - Math.floor(pixelCheckSize[1] / 4) + height / 2,
+ pixelCheckSize[0] / 2,
+ pixelCheckSize[1] / 2,
+ expected[colorID],
+ msg + " (" + x + "," + y + ")", 0));
+ } else {
+ rects.push(wtu.makeCheckRect(
+ center_x - Math.floor(pixelCheckSize[0] / 2),
+ center_y - Math.floor(pixelCheckSize[1] / 2),
+ pixelCheckSize[0],
+ pixelCheckSize[1],
+ expected[colorID],
+ msg + " (" + x + "," + y + ")", 0));
+ }
+ }
+ }
+ wtu.checkCanvasRects(gl, rects);
+ }
+
+ function newIntArray(count) {
+ if (!useSharedArrayBuffer) {
+ return new Int32Array(count);
+ }
+ let sab = new SharedArrayBuffer(count * Int32Array.BYTES_PER_ELEMENT);
+ return new Int32Array(sab);
+ }
+
+ const firsts = newIntArray(tri_count);
+ const counts = newIntArray(tri_count);
+ const offsets = newIntArray(tri_count);
+ const instances = newIntArray(tri_count);
+
+ for (let i = 0; i < firsts.length; ++i) firsts[i] = i * 3;
+ counts.fill(3);
+ for (let i = 0; i < offsets.length; ++i) offsets[i] = i * 3 * 2;
+ instances.fill(4);
+
+ const firstsOffset = 47;
+ const countsOffset = firstsOffset + firsts.length;
+ const offsetsOffset = countsOffset + counts.length;
+ const instancesOffset = offsetsOffset + instances.length;
+
+ const buffer = newIntArray(firstsOffset + firsts.length + counts.length + offsets.length + instances.length);
+ buffer.set(firsts, firstsOffset);
+ buffer.set(counts, countsOffset);
+ buffer.set(offsets, offsetsOffset);
+ buffer.set(instances, instancesOffset);
+
+ let drawIDLocation;
+
+ const multiDrawArrays = function() {
+ ext.multiDrawArraysWEBGL(gl.TRIANGLES, firsts, 0, counts, 0, tri_count);
+ }
+
+ const multiDrawArraysWithNonzeroOffsets = function() {
+ ext.multiDrawArraysWEBGL(gl.TRIANGLES, buffer, firstsOffset, buffer, countsOffset, tri_count);
+ }
+
+ const multiDrawElements = function() {
+ ext.multiDrawElementsWEBGL(gl.TRIANGLES, counts, 0, gl.UNSIGNED_SHORT, offsets, 0, tri_count);
+ }
+
+ const multiDrawElementsWithNonzeroOffsets = function() {
+ ext.multiDrawElementsWEBGL(gl.TRIANGLES, buffer, countsOffset, gl.UNSIGNED_SHORT, buffer, offsetsOffset, tri_count);
+ }
+
+ const multiDrawArraysInstanced = function() {
+ ext.multiDrawArraysInstancedWEBGL(gl.TRIANGLES, firsts, 0, counts, 0, instances, 0, tri_count);
+ }
+
+ const multiDrawArraysInstancedWithNonzeroOffsets = function() {
+ ext.multiDrawArraysInstancedWEBGL(gl.TRIANGLES, buffer, firstsOffset, buffer, countsOffset, buffer, instancesOffset, tri_count);
+ }
+
+ const multiDrawElementsInstanced = function() {
+ ext.multiDrawElementsInstancedWEBGL(gl.TRIANGLES, counts, 0, gl.UNSIGNED_SHORT, offsets, 0, instances, 0, tri_count);
+ }
+
+ const multiDrawElementsInstancedWithNonzeroOffsets = function() {
+ ext.multiDrawElementsInstancedWEBGL(gl.TRIANGLES, buffer, countsOffset, gl.UNSIGNED_SHORT, buffer, offsetsOffset, buffer, instancesOffset, tri_count);
+ }
+
+ const manyDrawArrays = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ gl.drawArrays(gl.TRIANGLES, firsts[i], counts[i]);
+ }
+ }
+
+ const manyDrawElements = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ gl.drawElements(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i]);
+ }
+ }
+
+ const manyDrawArraysEmulateDrawID = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ gl.uniform1i(drawIDLocation, i);
+ gl.drawArrays(gl.TRIANGLES, firsts[i], counts[i]);
+ }
+ }
+
+ const manyDrawElementsEmulateDrawID = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ gl.uniform1i(drawIDLocation, i);
+ gl.drawElements(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i]);
+ }
+ }
+
+ function drawArraysInstanced() {
+ if (wtu.getDefault3DContextVersion() < 2) {
+ instancedExt.drawArraysInstancedANGLE.apply(instancedExt, arguments);
+ } else {
+ gl.drawArraysInstanced.apply(gl, arguments);
+ }
+ }
+
+ function drawElementsInstanced() {
+ if (wtu.getDefault3DContextVersion() < 2) {
+ instancedExt.drawElementsInstancedANGLE.apply(instancedExt, arguments);
+ } else {
+ gl.drawElementsInstanced.apply(gl, arguments);
+ }
+ }
+
+ function vertexAttribDivisor(attrib, divisor) {
+ if (wtu.getDefault3DContextVersion() < 2) {
+ instancedExt.vertexAttribDivisorANGLE(attrib, divisor);
+ } else {
+ gl.vertexAttribDivisor(attrib, divisor);
+ }
+ }
+
+ const manyDrawArraysInstanced = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ drawArraysInstanced(gl.TRIANGLES, firsts[i], counts[i], 4);
+ }
+ }
+
+ const manyDrawElementsInstanced = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ drawElementsInstanced(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i], 4);
+ }
+ }
+
+ const manyDrawArraysInstancedEmulateDrawID = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ gl.uniform1i(drawIDLocation, i);
+ drawArraysInstanced(gl.TRIANGLES, firsts[i], counts[i], 4);
+ }
+ }
+
+ const manyDrawElementsInstancedEmulateDrawID = function() {
+ for (let i = 0; i < tri_count; ++i) {
+ gl.uniform1i(drawIDLocation, i);
+ drawElementsInstanced(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i], 4);
+ }
+ }
+
+ function checkDraw(config) {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ if (config.indexed) {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ } else {
+ gl.bindBuffer(gl.ARRAY_BUFFER, nonIndexedVertexBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ }
+
+ if (config.instanced) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
+ vertexAttribDivisor(1, 1);
+ }
+
+ config.drawFunc();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+ checkResult(config, config.drawFunc.name + (
+ config.instanced ? ' instanced' : ''
+ ) + (
+ config.drawID ? ' with gl_DrawID' : ''
+ ) + (
+ useSharedArrayBuffer ? ' and SharedArrayBuffer' : ''
+ ));
+
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ }
+
+ const noDrawIDProgram = wtu.setupProgram(gl, ["vshaderNoDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+ expectTrue(noDrawIDProgram != null, "can compile simple program");
+ if (noDrawIDProgram) {
+ gl.useProgram(noDrawIDProgram);
+
+ if (!instanced) {
+ checkDraw({
+ drawFunc: multiDrawArrays,
+ drawID: false,
+ });
+ checkDraw({
+ drawFunc: multiDrawArraysWithNonzeroOffsets,
+ drawID: false,
+ });
+ checkDraw({
+ drawFunc: multiDrawElements,
+ indexed: true,
+ drawID: false,
+ });
+ checkDraw({
+ drawFunc: multiDrawElementsWithNonzeroOffsets,
+ indexed: true,
+ drawID: false,
+ });
+ checkDraw({
+ drawFunc: manyDrawArrays,
+ drawID: false,
+ });
+ checkDraw({
+ drawFunc: manyDrawElements,
+ indexed: true,
+ drawID: false,
+ });
+ } else {
+ checkDraw({
+ drawFunc: multiDrawArraysInstanced,
+ drawID: false,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawArraysInstancedWithNonzeroOffsets,
+ drawID: false,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawElementsInstanced,
+ indexed: true,
+ drawID: false,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawElementsInstancedWithNonzeroOffsets,
+ indexed: true,
+ drawID: false,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: manyDrawArraysInstanced,
+ drawID: false,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: manyDrawElementsInstanced,
+ indexed: true,
+ drawID: false,
+ instanced: true,
+ });
+ }
+ }
+
+ const withDrawIDProgram = wtu.setupProgram(gl, ["vshaderWithDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+ expectTrue(withDrawIDProgram != null, "can compile program with ANGLE_multi_draw");
+ if (withDrawIDProgram) {
+ gl.useProgram(withDrawIDProgram);
+
+ if (!instanced) {
+ checkDraw({
+ drawFunc: multiDrawArrays,
+ drawID: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawArraysWithNonzeroOffsets,
+ drawID: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawElements,
+ indexed: true,
+ drawID: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawElementsWithNonzeroOffsets,
+ indexed: true,
+ drawID: true,
+ });
+ } else {
+ checkDraw({
+ drawFunc: multiDrawArraysInstanced,
+ drawID: true,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawArraysInstancedWithNonzeroOffsets,
+ drawID: true,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawElementsInstanced,
+ indexed: true,
+ drawID: true,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: multiDrawElementsInstancedWithNonzeroOffsets,
+ indexed: true,
+ drawID: true,
+ instanced: true,
+ });
+ }
+ }
+
+ const emulatedDrawIDProgram = wtu.setupProgram(gl, ["vshaderEmulatedDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+ expectTrue(emulatedDrawIDProgram != null, "can compile program to emulate gl_DrawID");
+ drawIDLocation = gl.getUniformLocation(emulatedDrawIDProgram, "drawID");
+ if (emulatedDrawIDProgram) {
+ gl.useProgram(emulatedDrawIDProgram);
+
+ if (!instanced) {
+ checkDraw({
+ drawFunc: manyDrawArraysEmulateDrawID,
+ drawID: true,
+ });
+ checkDraw({
+ drawFunc: manyDrawElementsEmulateDrawID,
+ indexed: true,
+ drawID: true,
+ });
+ } else {
+ checkDraw({
+ drawFunc: manyDrawArraysInstancedEmulateDrawID,
+ drawID: true,
+ instanced: true,
+ });
+ checkDraw({
+ drawFunc: manyDrawElementsInstancedEmulateDrawID,
+ indexed: true,
+ drawID: true,
+ instanced: true,
+ });
+ }
+ }
+ }
+
+ for (let i = 0; i < bufferUsageSet.length; i++) {
+ let bufferUsage = bufferUsageSet[i];
+ debug("Testing with BufferUsage = " + bufferUsage);
+ runValidationTests(bufferUsage);
+ runShaderTests(bufferUsage);
+ runPixelTests(bufferUsage, false);
+ }
+
+ // Run a subset of the pixel tests with SharedArrayBuffer if supported.
+ if (window.SharedArrayBuffer) {
+ runPixelTests(bufferUsageSet[0], true);
+ }
+}
+
+function waitForComposite() {
+ debug('wait for composite');
+ return new Promise(resolve => wtu.waitForComposite(resolve));
+}
+
+async function testPreserveDrawingBufferFalse(gl, drawFn) {
+ debug('');
+ debug('test preserveDrawingBuffer: false');
+
+ if (drawFn(gl)) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvasRect(gl, 0, 0, 20, 20, [255, 0, 0, 255],
+ "canvas should be red");
+
+ // enable scissor here, before compositing, to make sure it's correctly
+ // ignored and restored
+ gl.scissor(0, 10, 10, 10);
+ gl.enable(gl.SCISSOR_TEST);
+
+ await waitForComposite();
+
+ // scissor was set earlier
+ gl.clearColor(0, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ wtu.checkCanvasRect(gl, 0, 10, 10, 10, [0, 0, 255, 255],
+ "cleared corner should be blue, stencil should be preserved");
+ wtu.checkCanvasRect(gl, 0, 0, 10, 10, [0, 0, 0, 0],
+ "remainder of buffer should be cleared");
+
+ gl.disable(gl.SCISSOR_TEST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+async function testPreserveDrawingBufferTrue(gl, drawFn) {
+ debug('');
+ debug('test preserveDrawingBuffer: true');
+ if (drawFn(gl)) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvasRect(gl, 0, 0, 20, 20, [255, 0, 0, 255],
+ "canvas should be red");
+
+ await waitForComposite();
+
+ wtu.checkCanvasRect(gl, 0, 0, 20, 20, [255, 0, 0, 255],
+ "canvas should be red");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+async function doCompositingTests([glPreserveDrawingBufferFalse, glPreserveDrawingBufferTrue], drawFn) {
+ debug('');
+ debug(drawFn.name);
+
+ await testPreserveDrawingBufferFalse(glPreserveDrawingBufferFalse, drawFn);
+ await testPreserveDrawingBufferTrue(glPreserveDrawingBufferTrue, drawFn);
+}
+
+async function runDrawTests(testFn) {
+ function drawArrays(gl) {
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ }
+
+ function drawElements(gl) {
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
+ }
+
+ function drawArraysInstanced(gl) {
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, 1);
+ }
+
+ function drawElementsInstanced(gl) {
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, 1);
+ }
+
+ function multiDrawArraysWEBGL(gl) {
+ const ext = gl.getExtension('WEBGL_multi_draw');
+ if (!ext) {
+ throw 'Should not have run this test without WEBGL_multi_draw';
+ }
+
+ ext.multiDrawArraysWEBGL(
+ gl.TRIANGLES,
+ [0], 0, // firsts
+ [6], 0, // counts
+ 1, // drawCount
+ );
+ }
+
+ function multiDrawElementsWEBGL(gl) {
+ const ext = gl.getExtension('WEBGL_multi_draw');
+ if (!ext) {
+ throw 'Should not have run this test without WEBGL_multi_draw';
+ }
+
+ ext.multiDrawElementsWEBGL(
+ gl.TRIANGLES,
+ [6], 0, // counts
+ gl.UNSIGNED_BYTE,
+ [0], 0, // offsets
+ 1, // drawCount
+ );
+ }
+
+ function multiDrawArraysInstancedWEBGL(gl) {
+ const ext = gl.getExtension('WEBGL_multi_draw');
+ if (!ext) {
+ throw 'Should not have run this test without WEBGL_multi_draw';
+ }
+ ext.multiDrawArraysInstancedWEBGL(
+ gl.TRIANGLES,
+ [0], 0, // firsts
+ [6], 0, // counts
+ [1], 0, // instances
+ 1, // drawCount
+ );
+ }
+
+ function multiDrawElementsInstancedWEBGL(gl) {
+ const ext = gl.getExtension('WEBGL_multi_draw');
+ if (!ext) {
+ throw 'Should not have run this test without WEBGL_multi_draw';
+ }
+ ext.multiDrawElementsInstancedWEBGL(
+ gl.TRIANGLES,
+ [6], 0, // counts
+ gl.UNSIGNED_BYTE,
+ [0], 0, // offsets
+ [1], 0, // instances
+ 1, // drawCount
+ );
+ }
+
+ await testFn(drawArrays); // sanity check
+ await testFn(drawElements); // sanity check
+
+ // It's only legal to call testFn if the extension is supported,
+ // since the invalid vertex attrib tests, in particular, expect the
+ // draw function to have an effect.
+ if (gl.getExtension('WEBGL_multi_draw')) {
+ await testFn(multiDrawArraysWEBGL);
+ await testFn(multiDrawElementsWEBGL);
+ await testFn(multiDrawArraysInstancedWEBGL);
+ await testFn(multiDrawElementsInstancedWEBGL);
+ }
+}
+
+async function runCompositingTests() {
+ const compositingTestFn = createCompositingTestFn({
+ webglVersion: 1,
+ shadersFn(gl) {
+ const vs = `\
+ //#extension GL_ANGLE_multi_draw : enable
+ attribute vec4 position;
+ void main() {
+ gl_Position = position;
+ }
+ `;
+ const fs = `\
+ precision mediump float;
+ void main() {
+ gl_FragColor = vec4(1, 0, 0, 1);
+ }
+ `;
+ return [vs, fs];
+ },
+ });
+ await runDrawTests(compositingTestFn);
+}
+
+async function runInvalidAttribTests(gl) {
+ const invalidAttribTestFn = createInvalidAttribTestFn(gl);
+ await runDrawTests(invalidAttribTestFn);
+}
+
+function testSideEffects() {
+ debug("")
+ debug("Testing that ANGLE_instanced_arrays is implicitly enabled")
+ const canvas = document.createElement("canvas");
+ const gl = wtu.create3DContext(canvas, undefined, 1);
+ if (!gl) {
+ testFailed('WebGL context creation failed');
+ return;
+ }
+ gl.enableVertexAttribArray(0);
+ const VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+ gl.getVertexAttrib(0, VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "divisor enum unknown");
+ const ext = gl.getExtension("WEBGL_multi_draw");
+ if (ext) {
+ debug("WEBGL_multi_draw enabled");
+ gl.getVertexAttrib(0, VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "divisor enum known");
+ }
+}
+
+async function main() {
+ runTest();
+ testSideEffects();
+ await runInvalidAttribTests(gl);
+ await runCompositingTests();
+ finishTest();
+}
+main();
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-webcodecs-video-frame.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-webcodecs-video-frame.html
new file mode 100644
index 0000000000..f0e413e2f6
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-webcodecs-video-frame.html
@@ -0,0 +1,211 @@
+<!--
+Copyright (c) 2021 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="UTF-8">
+ <link rel="stylesheet" href="../../resources/js-test-style.css" />
+ <script src="../../js/js-test-pre.js"></script>
+ <script src="../../js/webgl-test-utils.js"></script>
+ <script src="../../js/tests/out-of-bounds-test.js"></script>
+ <script src="../../../../extensions/proposals/WEBGL_webcodecs_video_frame/webgl_webcodecs_video_frame.js"></script>
+ <style>
+ canvas {
+ padding: 10px;
+ background: gold;
+ }
+
+ button {
+ background-color: #555555;
+ border: none;
+ color: white;
+ padding: 15px 32px;
+ width: 150px;
+ text-align: center;
+ display: block;
+ font-size: 16px;
+ }
+ </style>
+</head>
+
+<body>
+ <canvas id="src" width="640" height="480"></canvas>
+ <canvas id="dst" width="640" height="480"></canvas>
+ <p id="info"></p>
+ <div id="description"></div>
+ <div id="console"></div>
+ <script>
+ "use strict";
+ description("Test of importing Videoframe from Webcodecs to Webgl");
+
+ const kIsRunningTest = true;
+ const kMaxFrame = 10;
+ const kTestPixel = [255, 128, 0, 255];
+ // Sum of pixel difference of R/G/B channel. Use to decide whether a
+ // pixel is matched with another.
+ const codec_string = "vp09.00.51.08.00";
+
+ let wtu = WebGLTestUtils;
+ let cnv = document.getElementById("src");
+ let src_width = cnv.width;
+ let src_height = cnv.height;
+ let src_color = "rgba(" + kTestPixel[0].toString() + "," + kTestPixel[1].toString() + ","
+ + kTestPixel[2].toString() + "," + kTestPixel[3].toString() + ")";
+ let frame_counter = 0;
+ let pixelCompareTolerance = 5;
+
+ function getQueryVariable(variable) {
+ var query = window.location.search.substring(1);
+ var vars = query.split("&");
+ for (var i = 0; i < vars.length; i++) {
+ var pair = vars[i].split("=");
+ if (pair[0] == variable) { return pair[1]; }
+ }
+ return false;
+ }
+
+ let th = parseInt(getQueryVariable('threshold'));
+ if (!isNaN(th))
+ pixelCompareTolerance = th;
+
+ async function startDrawing() {
+ let cnv = document.getElementById("src");
+ var ctx = cnv.getContext('2d', { alpha: false });
+
+ ctx.fillStyle = src_color;
+ let drawOneFrame = function (time) {
+ ctx.fillStyle = src_color;
+ ctx.fillRect(0, 0, src_width, src_height);
+ window.requestAnimationFrame(drawOneFrame);
+ }
+ window.requestAnimationFrame(drawOneFrame);
+ }
+
+ function captureAndEncode(processChunk) {
+ let cnv = document.getElementById("src");
+ let fps = 60;
+ let pending_outputs = 0;
+ let stream = cnv.captureStream(fps);
+ let processor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]);
+
+ const init = {
+ output: (chunk) => {
+ testPassed("Encode frame successfully.");
+ pending_outputs--;
+ processChunk(chunk);
+ },
+ error: (e) => {
+ testFailed("Failed to encode frame.");
+ finishTest();
+ vtr.stop();
+ }
+ };
+
+ const config = {
+ codec: codec_string,
+ width: cnv.width,
+ height: cnv.height,
+ bitrate: 10e6,
+ framerate: fps,
+ };
+
+ let encoder = new VideoEncoder(init);
+ encoder.configure(config);
+
+ const frame_reader = processor.readable.getReader();
+ frame_reader.read().then(function processFrame({done, value}) {
+ if (done)
+ return;
+
+ if (pending_outputs > 30) {
+ console.log("drop this frame");
+ // Too many frames in flight, encoder is overwhelmed
+ // let's drop this frame.
+ value.close();
+ frame_reader.read().then(processFrame);
+ return;
+ }
+
+ if(frame_counter == kMaxFrame) {
+ frame_reader.releaseLock();
+ processor.readable.cancel();
+ value.close();
+ return;
+ }
+
+ frame_counter++;
+ pending_outputs++;
+ const insert_keyframe = (frame_counter % 150) == 0;
+ encoder.encode(value, { keyFrame: insert_keyframe });
+
+ frame_reader.read().then(processFrame);
+ });
+ }
+
+ function startDecodingAndRendering(cnv, handleFrame) {
+ const init = {
+ output: handleFrame,
+ error: (e) => {
+ testFailed("Failed to decode frame.");
+ finishTest();
+ }
+ };
+
+ const config = {
+ codec: codec_string,
+ codedWidth: cnv.width,
+ codedHeight: cnv.height,
+ acceleration: "deny",
+
+ };
+
+ let decoder = new VideoDecoder(init);
+ decoder.configure(config);
+ return decoder;
+ }
+
+ function isFramePixelMatched(gl, th_per_pixel = pixelCompareTolerance) {
+ WebGLTestUtils.checkCanvasRect(gl, 0, 0, src_width, src_width, kTestPixel, "should be orange", pixelCompareTolerance)
+ }
+
+ function main() {
+ if (!("VideoEncoder" in window)) {
+ testPassed("WebCodecs API is not supported.");
+ finishTest();
+ return;
+ }
+ let cnv = document.getElementById("dst");
+
+ let webgl_webcodecs_test_context = {
+ maxFrameTested: kMaxFrame,
+ displayed_frame: 0,
+ isFramePixelMatched: isFramePixelMatched,
+ testFailed: testFailed,
+ testPassed: testPassed,
+ finishTest: finishTest
+ };
+ setTestMode(webgl_webcodecs_test_context);
+ let handleFrame = requestWebGLVideoFrameHandler(cnv);
+ if (handleFrame === null) {
+ finishTest();
+ return;
+ }
+
+ startDrawing();
+ let decoder = startDecodingAndRendering(cnv, handleFrame);
+ captureAndEncode((chunk) => {
+ decoder.decode(chunk);
+ });
+ }
+
+ document.body.onload = main;
+ </script>
+
+</body>
+
+</html> \ No newline at end of file