summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/reading
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/reading/00_test_list.txt5
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/reading/format-r11f-g11f-b10f.html266
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-fbo-test.html642
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-rgb8-into-pbo-bug.html85
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-into-pixel-pack-buffer.html152
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-pack-parameters.html353
6 files changed, 1503 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/reading/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/00_test_list.txt
new file mode 100644
index 0000000000..d5fe8b664e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/00_test_list.txt
@@ -0,0 +1,5 @@
+--min-version 2.0.1 format-r11f-g11f-b10f.html
+read-pixels-from-fbo-test.html
+--min-version 2.0.1 read-pixels-from-rgb8-into-pbo-bug.html
+read-pixels-into-pixel-pack-buffer.html
+read-pixels-pack-parameters.html
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/reading/format-r11f-g11f-b10f.html b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/format-r11f-g11f-b10f.html
new file mode 100644
index 0000000000..5534a6884f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/format-r11f-g11f-b10f.html
@@ -0,0 +1,266 @@
+<!--
+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>Test Format R11F_G11F_B10F</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="20" height="20"> </canvas>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec2 pos;
+attribute vec2 texCoord0;
+varying vec2 texCoord;
+
+void main() {
+ gl_Position = vec4(pos, 0.0, 1.0);
+ texCoord = texCoord0;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform vec3 u_color;
+uniform vec3 u_tol;
+uniform sampler2D u_tex;
+varying vec2 texCoord;
+
+void main() {
+ vec4 sample = texture2D(u_tex, texCoord);
+ vec3 rgb = sample.xyz;
+ if (abs(rgb[0] - u_color[0]) > u_tol[0] ||
+ abs(rgb[1] - u_color[1]) > u_tol[1] ||
+ abs(rgb[2] - u_color[2]) > u_tol[2]) {
+ gl_FragColor = vec4(1, 0, 0, 1);
+ } else {
+ gl_FragColor = vec4(0, 1, 0, 1);
+ }
+}
+</script>
+<script>
+"use strict";
+description("This tests format R11F_G11F_B10F works as expected");
+debug("MacOSX driver bug. See https://github.com/KhronosGroup/WebGL/issues/1832");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, undefined, 2);
+
+var testValues = [100, 1000, 2047, 2500, 4095, 5000,
+ 8191, 8192, 10000, 16383, 16384];
+
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+ if (gl.getExtension("EXT_color_buffer_float")) {
+ testPassed("Extension EXT_color_buffer_float is available");
+
+ testRenderbufferReadback(4, 4);
+ testTextureReadback(4, 4);
+ testTextureSampling(4, 4);
+ } else {
+ testPassed("Extension EXT_color_buffer_float is unavailable - this is legal");
+ }
+}
+
+function setupColor(testR, testG, testB, value) {
+ var data = new Float32Array(4);
+ data[0] = testR ? value : 0;
+ data[1] = testG ? value : 0;
+ data[2] = testB ? value : 0;
+ data[3] = 1; // Doesn't really matter for RGB formats.
+ return data;
+}
+
+// The definition of <Unsinged 11-Bit Floating-Point Number> in GLES 3.0.4:
+// https://www.khronos.org/registry/gles/specs/3.0/es_spec_3.0.4.pdf#nameddest=section-2.1.3
+// The definition of <Unsinged 10-Bit Floating-Point Number> in GLES 3.0.4:
+// https://www.khronos.org/registry/gles/specs/3.0/es_spec_3.0.4.pdf#nameddest=section-2.1.4
+function setTolerance (testR, testG, testB, value) {
+ var tol = new Float32Array(3);
+ var exponent;
+ if (value < Math.pow(2, -14)) {
+ exponent = -14;
+ } else {
+ exponent = Math.floor(Math.log(value) / Math.LN2);
+ }
+ var tol11F = Math.pow(2, exponent) / 64;
+ var tol10F = Math.pow(2, exponent) / 32;
+ tol[0] = testR ? tol11F : 0;
+ tol[1] = testG ? tol11F : 0;
+ tol[2] = testB ? tol10F : 0;
+ return tol;
+}
+
+function clearAndVerifyColor(width, height, testR, testG, testB, value) {
+ var data = setupColor(testR, testG, testB, value);
+ var tol = setTolerance(testR, testG, testB, value);
+ gl.clearBufferfv(gl.COLOR, 0, data);
+ var buffer = new Float32Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.FLOAT, buffer);
+ for (var ii = 0; ii < width * height; ++ii) {
+ var pixel = [buffer[ii * 4], buffer[ii * 4 + 1], buffer[ii * 4 + 2], buffer[ii * 4 + 3]];
+ if (isNaN(pixel[0]) || isNaN(pixel[1]) || isNaN(pixel[2]) ||
+ Math.abs(pixel[0] - data[0]) > tol[0] ||
+ Math.abs(pixel[1] - data[1]) > tol[1] ||
+ Math.abs(pixel[2] - data[2]) > tol[2]) {
+ testFailed("ReadPixels " + ii + " : got [" + pixel + "], expected [" + data + "], tol [" + tol + "]");
+ return;
+ }
+ }
+ testPassed("ReadPixels success : [" + data + "]");
+}
+
+function clearDrawAndVerifyColor(fbo, program, testR, testG, testB, value) {
+ var data = setupColor(testR, testG, testB, value);
+ var tol = setTolerance(testR, testG, testB, value);
+ debug("Testing : [" + data + "] with tolerance = [" + tol + "]");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.clearBufferfv(gl.COLOR, 0, data);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.clearColor(0, 0, 0,1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.uniform3fv(program.colorPos, data.slice(0, 3));
+ gl.uniform3fv(program.tolPos, tol);
+
+ wtu.drawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "Should pass (green color instead of red)");
+}
+
+
+function testReadPixelsFromColorChannelsWithVariousValues(width, height) {
+ debug("Testing R channel");
+ for (var ii = 0; ii < testValues.length; ++ii) {
+ clearAndVerifyColor(width, height, true, false, false, testValues[ii]);
+ }
+ debug("Testing G channel");
+ for (var ii = 0; ii < testValues.length; ++ii) {
+ clearAndVerifyColor(width, height, false, true, false, testValues[ii]);
+ }
+ debug("Testing B channel");
+ for (var ii = 0; ii < testValues.length; ++ii) {
+ clearAndVerifyColor(width, height, false, false, true, testValues[ii]);
+ }
+}
+
+function testSampleTextureFromColorChannelsWithVariousValues(fbo, program) {
+ debug("Testing R channel");
+ for (var ii = 0; ii < testValues.length; ++ii) {
+ clearDrawAndVerifyColor(fbo, program, true, false, false, testValues[ii]);
+ }
+ debug("Testing G channel");
+ for (var ii = 0; ii < testValues.length; ++ii) {
+ clearDrawAndVerifyColor(fbo, program, false, true, false, testValues[ii]);
+ }
+ debug("Testing B channel");
+ for (var ii = 0; ii < testValues.length; ++ii) {
+ clearDrawAndVerifyColor(fbo, program, false, false, true, testValues[ii]);
+ }
+}
+
+function testRenderbufferReadback(width, height) {
+ debug("");
+ debug("Checking clearing and readback of a color image of renderbuffer with R11F_G11F_B10F format.");
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ var renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.R11F_G11F_B10F, width, height);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer);
+ shouldBe("gl.FRAMEBUFFER_COMPLETE", "gl.checkFramebufferStatus(gl.FRAMEBUFFER)");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup framebuffer with renderbuffer should succeed.");
+
+ testReadPixelsFromColorChannelsWithVariousValues(width, height);
+
+ gl.deleteFramebuffer(fbo);
+ gl.deleteRenderbuffer(renderbuffer);
+}
+
+function testTextureReadback(width, height) {
+ debug("");
+ debug("Checking clearing and readback of a color image of texture with R11F_G11F_B10F format.");
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R11F_G11F_B10F, width, height, 0, gl.RGB, gl.FLOAT, null);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ shouldBe("gl.FRAMEBUFFER_COMPLETE", "gl.checkFramebufferStatus(gl.FRAMEBUFFER)");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup framebuffer with texture should succeed.");
+
+ testReadPixelsFromColorChannelsWithVariousValues(width, height);
+
+ gl.deleteFramebuffer(fbo);
+ gl.deleteTexture(tex);
+}
+
+function setupProgram() {
+ var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["pos", "texCoord0"]);
+ if (!program)
+ return null;
+ program.colorPos = gl.getUniformLocation(program, "u_color");
+ program.tolPos = gl.getUniformLocation(program, "u_tol");
+ var texPos = gl.getUniformLocation(program, "u_tex");
+ program.buffers = wtu.setupUnitQuad(gl, 0, 1);
+ if (!program.colorPos || !program.tolPos || !texPos || program.buffers.length == 0) {
+ gl.deleteProgram(program);
+ return null;
+ }
+ gl.useProgram(program);
+ gl.uniform1i(texPos, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup program should succeed.");
+ return program;
+}
+
+function testTextureSampling(width, height) {
+ debug("");
+ debug("Checking sampling of a texture with R11_G11F_B10F format");
+
+ var program = setupProgram();
+ if (!program) {
+ testFailed("Failed to setup program");
+ return;
+ }
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R11F_G11F_B10F, width, height, 0, gl.RGB, gl.FLOAT, null);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ shouldBe("gl.FRAMEBUFFER_COMPLETE", "gl.checkFramebufferStatus(gl.FRAMEBUFFER)");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup framebuffer with texture should succeed.");
+
+ testSampleTextureFromColorChannelsWithVariousValues(fbo, program);
+
+ gl.deleteTexture(tex);
+ gl.deleteFramebuffer(fbo);
+ gl.deleteProgram(program);
+}
+
+debug("");
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error from tests.");
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-fbo-test.html b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-fbo-test.html
new file mode 100644
index 0000000000..c06e9988ed
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-fbo-test.html
@@ -0,0 +1,642 @@
+<!--
+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 2 ReadPixels 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>
+<script>
+"use strict";
+description("Checks that ReadPixels from a fbo works as expected.");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext(undefined, undefined, 2);
+gl.pixelStorei(gl.PACK_ALIGNMENT, 1);
+
+function getChannelCount(format) {
+ switch (format) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ case gl.ALPHA:
+ case gl.LUMINANCE:
+ return 1;
+ case gl.RB:
+ case gl.RB_INTEGER:
+ case gl.LUMINANCE_ALPHA:
+ return 2;
+ case gl.RGB:
+ case gl.RGB_INTEGER:
+ return 3;
+ case gl.RGBA:
+ case gl.RGBA_INTEGER:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+function getUnpackInfo(type) {
+ switch (type) {
+ case gl.UNSIGNED_SHORT_5_6_5:
+ return {bitsCount: [5, 6, 5], isReverse: false};
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ return {bitsCount: [4, 4, 4, 4], isReverse: false};
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ return {bitsCount: [5, 5, 5, 1], isReverse: false};
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ return {bitsCount: [2, 10, 10, 10], isReverse: true};
+ case gl.UNSIGNED_INT_10F_11F_11F_REV:
+ return {bitsCount: [10, 11, 11], isReverse: true};
+ case gl.UNSIGNED_INT_5_9_9_9_REV:
+ return {bitsCount: [5, 9, 9, 9], isReverse: true};
+ default:
+ return null;
+ }
+}
+
+// bitsCount is an array contains bit count for each component.
+function unpack(value, channelCount, bitsCount, isReverse) {
+ var result = new Array(channelCount);
+
+ var accumBitsCount = 0;
+ for (var i = channelCount - 1; i >= 0; --i) {
+ var currentChannel = isReverse ? (channelCount - i - 1) : i;
+ var mask = 0xFFFFFFFF >>> (32 - bitsCount[i]);
+ result[currentChannel] = ((value >> accumBitsCount) & mask);
+ accumBitsCount += bitsCount[i];
+ }
+
+ return result;
+}
+
+function getColor(buf, index, readFormat, readType) {
+ var channelCount = getChannelCount(readFormat);
+ var result = new Array(channelCount);
+
+ var unpackInfo = getUnpackInfo(readType);
+ if (unpackInfo) {
+ result = unpack(buf[index], channelCount, unpackInfo.bitsCount, unpackInfo.isReverse);
+ } else {
+ for (var i = 0; i < channelCount; ++i) {
+ result[i] = buf[index + i];
+ }
+ }
+
+ return result;
+}
+
+function convertToSRGB(val) {
+ if (val <= 0) {
+ return 0;
+ } else if (val < 0.0031308) {
+ return 12.92 * val;
+ } else if (val < 1) {
+ return 1.055 * Math.pow(val, 0.41666) - 0.055;
+ } else {
+ return 1;
+ }
+}
+
+function denormalizeColor(srcInternalFormat, destType, color) {
+ var result = color.slice();
+ var tol = 0;
+
+ var srcIsNormalized = false;
+
+ switch (srcInternalFormat) {
+ case gl.R8:
+ case gl.RG8:
+ case gl.RGB8:
+ case gl.RGBA8:
+ case gl.RGB5_A1:
+ case gl.SRGB8_ALPHA8:
+ case gl.RGB10_A2:
+ srcIsNormalized = true;
+ tol = 6;
+ break;
+ case gl.RGB565:
+ // RGB565 needs slightly extra tolerance, at least on Google Pixel. crbug.com/682753
+ srcIsNormalized = true;
+ tol = 7;
+ break;
+ case gl.RGBA4:
+ srcIsNormalized = true;
+ tol = 10;
+ break;
+ }
+
+ if (!srcIsNormalized) {
+ return { color: result, tol: tol };
+ }
+
+ if (srcInternalFormat == gl.SRGB8_ALPHA8) {
+ for (var i = 0; i < 3; ++i) {
+ result[i] = convertToSRGB(result[i]);
+ }
+ }
+
+ switch (destType) {
+ case gl.UNSIGNED_BYTE:
+ result = result.map(val => { return val * 0xFF});
+ break;
+ case gl.UNSIGNED_SHORT:
+ // On Linux NVIDIA, tol of 33 is necessary to pass the test.
+ tol = 40;
+ result = result.map(val => { return val * 0xFFFF});
+ break;
+ case gl.UNSIGNED_INT:
+ tol = 40;
+ result = result.map(val => { return val * 0xFFFFFFFF});
+ break;
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ result = result.map(val => { return val * 0xF});
+ break;
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ result[0] = result[0] * 0x1F;
+ result[1] = result[1] * 0x1F;
+ result[2] = result[2] * 0x1F;
+ result[3] = result[3] * 0x1;
+ break;
+ case gl.UNSIGNED_SHORT_5_6_5:
+ result[0] = result[0] * 0x1F;
+ result[1] = result[1] * 0x3F;
+ result[2] = result[2] * 0x1F;
+ break;
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ tol = 25;
+ result[0] = result[0] * 0x3FF;
+ result[1] = result[1] * 0x3FF;
+ result[2] = result[2] * 0x3FF;
+ result[3] = result[3] * 0x3;
+ break;
+ case gl.UNSIGNED_INT_5_9_9_9_REV:
+ result[0] = result[0] * 0x1FF;
+ result[1] = result[1] * 0x1FF;
+ result[2] = result[2] * 0x1FF;
+ result[3] = result[3] * 0x1F;
+ break;
+ }
+
+ return { color: result, tol: tol };
+}
+
+function compareColor(buf, index, expectedColor, srcInternalFormat,
+ srcFormat, srcType, readFormat, readType) {
+ var srcChannelCount = getChannelCount(srcFormat);
+ var readChannelCount = getChannelCount(readFormat);
+
+ var color = getColor(buf, index, readFormat, readType);
+ expectedColor = denormalizeColor(srcInternalFormat, readType, expectedColor);
+
+ var minChannel = Math.min(srcChannelCount, readChannelCount);
+ for (var i = 0; i < minChannel; ++i) {
+ if (Math.abs(expectedColor.color[i] - color[i]) > expectedColor.tol) {
+ testFailed("Expected color = " + expectedColor.color + ", was = " + color);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+var textureTestCases = [
+ {
+ texInternalFormat: 'R8', texFormat: 'RED', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0.0, 0.0, 0],
+ },
+ {
+ texInternalFormat: 'R8UI', texFormat: 'RED_INTEGER', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [250, 0, 0, 0],
+ },
+ {
+ texInternalFormat: 'R8I', texFormat: 'RED_INTEGER', texType: 'BYTE',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [-126, 0, 0, 0],
+ },
+ {
+ texInternalFormat: 'R16UI', texFormat: 'RED_INTEGER', texType: 'UNSIGNED_SHORT',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [30001, 0, 0, 0],
+ },
+ {
+ texInternalFormat: 'R16I', texFormat: 'RED_INTEGER', texType: 'SHORT',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [-14189, 0, 0, 0],
+ },
+ {
+ texInternalFormat: 'R32UI', texFormat: 'RED_INTEGER', texType: 'UNSIGNED_INT',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [126726, 0, 0, 0],
+ },
+ {
+ texInternalFormat: 'R32I', texFormat: 'RED_INTEGER', texType: 'INT',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [-126726, 0, 0, 0],
+ },
+
+ {
+ texInternalFormat: 'RG8', texFormat: 'RG', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0.7, 0.0, 0],
+ },
+ {
+ texInternalFormat: 'RG8UI', texFormat: 'RG_INTEGER', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [250, 124, 0, 0],
+ },
+ {
+ texInternalFormat: 'RG8I', texFormat: 'RG_INTEGER', texType: 'BYTE',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [-55, 124, 0, 0],
+ },
+ {
+ texInternalFormat: 'RG16UI', texFormat: 'RG_INTEGER', texType: 'UNSIGNED_SHORT',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [30001, 18, 0, 0],
+ },
+ {
+ texInternalFormat: 'RG16I', texFormat: 'RG_INTEGER', texType: 'SHORT',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [-14189, 6735, 0, 0],
+ },
+ {
+ texInternalFormat: 'RG32UI', texFormat: 'RG_INTEGER', texType: 'UNSIGNED_INT',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [126726, 1976, 0, 0],
+ },
+ {
+ texInternalFormat: 'RG32I', texFormat: 'RG_INTEGER', texType: 'INT',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [-126726, 126726, 0, 0],
+ },
+
+ {
+ texInternalFormat: 'RGB8', texFormat: 'RGB', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 1, 0, 0],
+ },
+ {
+ texInternalFormat: 'RGB565', texFormat: 'RGB', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0.7, 0.2, 0],
+ },
+ {
+ texInternalFormat: 'RGB565', texFormat: 'RGB', texType: 'UNSIGNED_SHORT_5_6_5',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0.7, 0.2, 0],
+ },
+
+ {
+ texInternalFormat: 'RGBA8', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0, 1, 0.7],
+ },
+ {
+ texInternalFormat: 'SRGB8_ALPHA8', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0, 1, 0.7],
+ },
+ {
+ texInternalFormat: 'RGB5_A1', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0, 0.7, 1],
+ },
+ {
+ texInternalFormat: 'RGB5_A1', texFormat: 'RGBA', texType: 'UNSIGNED_SHORT_5_5_5_1',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0.7, 1, 0],
+ },
+ {
+ texInternalFormat: 'RGB5_A1', texFormat: 'RGBA', texType: 'UNSIGNED_INT_2_10_10_10_REV',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0.7, 0, 1],
+ },
+ {
+ texInternalFormat: 'RGBA4', texFormat: 'RGBA', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.5, 0.7, 1, 0],
+ },
+ {
+ texInternalFormat: 'RGBA4', texFormat: 'RGBA', texType: 'UNSIGNED_SHORT_4_4_4_4',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [1, 0, 0.5, 0.7],
+ },
+ {
+ texInternalFormat: 'RGBA8UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_BYTE',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [127, 0, 255, 178],
+ },
+ {
+ texInternalFormat: 'RGBA8I', texFormat: 'RGBA_INTEGER', texType: 'BYTE',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [-55, 56, 80, 127],
+ },
+ {
+ texInternalFormat: 'RGB10_A2UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_INT_2_10_10_10_REV',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [178, 0, 127, 3],
+ },
+ {
+ texInternalFormat: 'RGBA16UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_SHORT',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [14189, 6735, 0, 19],
+ },
+ {
+ texInternalFormat: 'RGBA16I', texFormat: 'RGBA_INTEGER', texType: 'SHORT',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [14189, -6735, 0, 19],
+ },
+ {
+ texInternalFormat: 'RGBA32UI', texFormat: 'RGBA_INTEGER', texType: 'UNSIGNED_INT',
+ readFormat: 'RGBA_INTEGER', readType: 'UNSIGNED_INT',
+ clearColor: [126726, 6726, 98765, 2015],
+ },
+ {
+ texInternalFormat: 'RGBA32I', texFormat: 'RGBA_INTEGER', texType: 'INT',
+ readFormat: 'RGBA_INTEGER', readType: 'INT',
+ clearColor: [126726, -6726, -98765, 2015],
+ },
+
+ {
+ texInternalFormat: 'RGB10_A2', texFormat: 'RGBA', texType: 'UNSIGNED_INT_2_10_10_10_REV',
+ readFormat: 'RGBA', readType: 'UNSIGNED_BYTE',
+ clearColor: [0.7, 0, 0.5, 1],
+ },
+
+ // TODO(zmo): add float/half_float test cases with extension supports.
+];
+
+function getArrayTypeFromReadPixelsType(gl, type) {
+ switch (type) {
+ case gl.UNSIGNED_BYTE:
+ return Uint8Array;
+ case gl.BYTE:
+ return Int8Array;
+ case gl.UNSIGNED_SHORT:
+ case gl.UNSIGNED_SHORT_5_6_5:
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ return Uint16Array;
+ case gl.SHORT:
+ return Int16Array;
+ case gl.UNSIGNED_INT:
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ case gl.UNSIGNED_INT_10F_11F_11F_REV:
+ case gl.UNSIGNED_INT_5_9_9_9_REV:
+ return Uint32Array;
+ case gl.INT:
+ return Int32Array;
+ case gl.HALF_FLOAT:
+ return Uint16Array;
+ case gl.FLOAT:
+ return Float32Array;
+ default:
+ return null;
+ }
+}
+
+function getFormatString(gl, format) {
+ switch (format) {
+ case gl.RED:
+ return 'RED';
+ case gl.RED_INTEGER:
+ return 'RED_INTEGER';
+ case gl.RG:
+ return 'RG';
+ case gl.RG_INTEGER:
+ return 'RG_INTEGER';
+ case gl.RGB:
+ return 'RGB';
+ case gl.RGB_INTEGER:
+ return 'RGB_INTEGER';
+ case gl.RGBA:
+ return 'RGBA';
+ case gl.RGBA_INTEGER:
+ return 'RGBA_INTEGER';
+ case gl.LUMINANCE:
+ return 'LUMINANCE';
+ case gl.LUMINANCE_ALPHA:
+ return 'LUMINANCE_ALPHA';
+ case gl.ALPHA:
+ return 'ALPHA';
+ default:
+ return '';
+ };
+}
+
+function getTypeString(gl, type) {
+ switch (type) {
+ case gl.UNSIGNED_BYTE:
+ return 'UNSIGNED_BYTE';
+ case gl.BYTE:
+ return 'BYTE';
+ case gl.UNSIGNED_SHORT:
+ return 'UNSIGNED_SHORT';
+ case gl.SHORT:
+ return 'SHORT';
+ case gl.UNSIGNED_INT:
+ return 'UNSIGNED_INT';
+ case gl.INT:
+ return 'INT';
+ case gl.UNSIGNED_SHORT_5_6_5:
+ return 'UNSIGNED_SHORT_5_6_5';
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ return 'UNSIGNED_SHORT_5_5_5_1';
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ return 'UNSIGNED_INT_2_10_10_10_REV';
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ return 'UNSIGNED_SHORT_4_4_4_4';
+ case gl.UNSIGNED_INT_10F_11F_11F_REV:
+ return 'UNSIGNED_INT_10F_11F_11F_REV';
+ case gl.UNSIGNED_INT_5_9_9_9_REV:
+ return 'UNSIGNED_INT_5_9_9_9_REV';
+ default:
+ return '';
+ };
+}
+
+function elementCountPerPixel(gl, readFormat, readType) {
+ switch (readFormat) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ case gl.ALPHA:
+ case gl.LUMINANCE:
+ return 1;
+ case gl.RG:
+ case gl.RG_INTEGER:
+ case gl.LUMINANCE_ALPHA:
+ return 2;
+ case gl.RGB:
+ case gl.RGB_INTEGER:
+ switch (readType) {
+ case gl.UNSIGNED_SHORT_5_6_5:
+ return 1;
+ default:
+ return 3;
+ }
+ case gl.RGBA:
+ case gl.RGBA_INTEGER:
+ switch (readType) {
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ case gl.UNSIGNED_INT_10F_11F_11F_REV:
+ case gl.UNSIGNED_INT_5_9_9_9_REV:
+ return 1;
+ default:
+ return 4;
+ }
+ default:
+ testFailed("Unexpected read format/type = " + readFormat + "/" + readType);
+ return 0;
+ }
+}
+
+function testReadPixels(gl, srcInternalFormat, srcFormat, srcType,
+ readFormat, readType, expectedColor) {
+ var arrayType = getArrayTypeFromReadPixelsType(gl, readType);
+ var buf = new arrayType(width * height * 4);
+ gl.readPixels(0, 0, width, height, readFormat, readType, buf);
+ wtu.glErrorShouldBe(
+ gl, gl.NO_ERROR, "readPixels should generate no error");
+ var diffFound = false;
+ for (var ii = 0; ii < width * height; ++ii) {
+ var offset = ii * elementCountPerPixel(gl, readFormat, readType);
+ if (!compareColor(buf, offset, expectedColor, srcInternalFormat, srcFormat, srcType,
+ readFormat, readType)) {
+ diffFound = true;
+ break;
+ }
+ }
+ if (!diffFound) {
+ testPassed("Color read back as expected");
+ }
+}
+
+function clearBuffer(gl, texInternalFormat, clearColor) {
+ var value;
+ switch (texInternalFormat) {
+ case gl.R8UI:
+ case gl.R16UI:
+ case gl.R32UI:
+ case gl.RG8UI:
+ case gl.RG16UI:
+ case gl.RG32UI:
+ case gl.RGBA8UI:
+ case gl.RGBA16UI:
+ case gl.RGBA32UI:
+ case gl.RGB10_A2UI:
+ value = new Uint32Array(4);
+ for (var ii = 0; ii < 4; ++ii)
+ value[ii] = clearColor[ii];
+ gl.clearBufferuiv(gl.COLOR, 0, value);
+ break;
+ case gl.R8I:
+ case gl.R16I:
+ case gl.R32I:
+ case gl.RG8I:
+ case gl.RG16I:
+ case gl.RG32I:
+ case gl.RGBA8I:
+ case gl.RGBA16I:
+ case gl.RGBA32I:
+ value = new Int32Array(4);
+ for (var ii = 0; ii < 4; ++ii)
+ value[ii] = clearColor[ii];
+ gl.clearBufferiv(gl.COLOR, 0, value);
+ break;
+ default:
+ gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ break;
+ }
+}
+
+for (var tt = 0; tt < textureTestCases.length; ++tt) {
+ var test = textureTestCases[tt];
+ debug("");
+ debug("ReadPixels from fbo with texture = (" + test.texInternalFormat +
+ ", " + test.texFormat + ", " + test.texType +
+ "), format = " + test.readFormat + ", type = " + test.readType);
+ var width = 2;
+ var height = 2;
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ var colorImage = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, colorImage);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl[test.texInternalFormat], width, height, 0,
+ gl[test.texFormat], gl[test.texType], null);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
+ gl.TEXTURE_2D, colorImage, 0);
+ wtu.glErrorShouldBe(
+ gl, gl.NO_ERROR, "Setting up fbo should generate no error");
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ debug("fbo is not complete, skip");
+ continue;
+ }
+ clearBuffer(gl, gl[test.texInternalFormat], test.clearColor);
+ wtu.glErrorShouldBe(
+ gl, gl.NO_ERROR, "Clear color should generate no error");
+
+ var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+ var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+ var implFormatString = getFormatString(gl, implFormat);
+ var implTypeString = getTypeString(gl, implType);
+
+ if (gl[test.texInternalFormat] == gl.RGB10_A2) {
+ // This is a special case where three read format/type are supported.
+ var readTypes = [gl.UNSIGNED_BYTE, gl.UNSIGNED_INT_2_10_10_10_REV];
+ var readTypeStrings = ['UNSIGNED_BYTE', 'UNSIGNED_INT_2_10_10_10_REV'];
+ if (implFormat == gl.RGBA && implTypeString != '') {
+ readTypes.push(implType);
+ readTypeStrings.push(implTypeString);
+ } else {
+ testFailed("Unimplemented Implementation dependent color read format/type = " +
+ implFormat + "/" + implType);
+ }
+ for (var rr = 0; rr < readTypes.length; ++rr) {
+ debug("Special case RGB10_A2, format = RGBA, type = " + readTypeStrings[rr]);
+ testReadPixels(gl, gl[test.texInternalFormat], gl[test.texFormat], gl[test.texType],
+ gl.RGBA, readTypes[rr], test.clearColor);
+ }
+ } else {
+ testReadPixels(gl, gl[test.texInternalFormat], gl[test.texFormat], gl[test.texType],
+ gl[test.readFormat], gl[test.readType], test.clearColor);
+
+ debug("Testing implementation dependent color read format = " + implFormatString +
+ ", type = " + implTypeString);
+ if (implFormatString == '') {
+ testFailed("Invalid IMPLEMENTATION_COLOR_READ_FORMAT = " + implFormat);
+ continue;
+ }
+ if (implTypeString == '') {
+ testFailed("Invalid IMPLEMENTATION_COLOR_READ_TYPE = " + implType);
+ continue;
+ }
+ testReadPixels(gl, gl[test.texInternalFormat], gl[test.texFormat], gl[test.texType],
+ implFormat, implType, test.clearColor);
+
+ gl.deleteTexture(colorImage);
+ gl.deleteFramebuffer(fbo);
+ }
+}
+
+debug("")
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-rgb8-into-pbo-bug.html b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-rgb8-into-pbo-bug.html
new file mode 100644
index 0000000000..b4f91f1d3c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-from-rgb8-into-pbo-bug.html
@@ -0,0 +1,85 @@
+<!--
+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 2 Conformance Test: readPixels from RGB8 Buffer Into Pixel Pack Buffer.</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="example" width="4" height="4"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+
+debug("");
+description("Verifies readPixels from RGB8 buffer into PIXEL_PACK buffer works");
+
+debug("On MacOSX with AMD GPUs, the alpha channel is readback as 0 instead of 255");
+
+var wtu = WebGLTestUtils;
+var pixel = [0, 0, 0, 0];
+var expectedColor = [255, 102, 0, 255];
+
+var canvas = document.getElementById("example");
+var gl = wtu.create3DContext(canvas, undefined, 2);
+
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ var width = 4;
+ var height = 4;
+
+ var renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB8, width, height);
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer);
+
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("framebuffer with RGB8 color buffer is incomplete");
+ } else {
+ gl.clearColor(1.0, 0.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var pbo = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo);
+ gl.bufferData(gl.PIXEL_PACK_BUFFER, width * height * 4, gl.STATIC_COPY);
+
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+
+ var data = new Uint8Array(width * height * 4);
+ gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
+
+ for (var ii = 0; ii < width * height; ++ii) {
+ if (data[ii * 4] != 255 ||
+ data[ii * 4 + 1] != 0 ||
+ data[ii * 4 + 2] != 0 ||
+ data[ii * 4 + 3] != 255) {
+ testFailed("Expected in pixel " + ii + ": [255,0,0,255], got: " +
+ [data[ii * 4], data[ii * 4 + 1], data[ii * 4 + 2], data[ii * 4 + 3]]);
+ break;
+ }
+ }
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Tests should complete without gl errors");
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-into-pixel-pack-buffer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-into-pixel-pack-buffer.html
new file mode 100644
index 0000000000..7d646a6ecd
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-into-pixel-pack-buffer.html
@@ -0,0 +1,152 @@
+<!--
+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 2 Conformance Test: ReadPixels Into Pixel Pack Buffer.</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="example" width="4" height="4"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+
+function checkFormatAndType()
+{
+ debug("");
+ debug("check format / type");
+ var invalidFormat = [gl.DEPTH_COMPONENT, gl.DEPTH_STENCIL, gl.R8, gl.RGBA4, gl.LUMINANCE, gl.LUMINANCE_ALPHA];
+ var invalidType = [gl.UNSIGNED_INT_24_8];
+ for (var ff = 0; ff < invalidFormat.length; ++ff) {
+ var format = invalidFormat[ff];
+ gl.readPixels(0, 0, 1, 1, format, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Format should not be able to read as " + wtu.glEnumToString(gl, format));
+ }
+ for (var tt = 0; tt < invalidType.length; ++tt) {
+ var type = invalidType[tt];
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, type, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Type should not be able to read as " + wtu.glEnumToString(gl, type));
+ }
+
+ debug("");
+ debug("check combinations of format and type");
+ var combinations = [
+ {format: gl.RGBA, type: gl.UNSIGNED_BYTE},
+ {format: gl.RGB, type: gl.UNSIGNED_BYTE},
+ {format: gl.RGB, type: gl.UNSIGNED_SHORT_5_6_5},
+ {format: gl.RGBA, type: gl.UNSIGNED_SHORT_5_5_5_1},
+ {format: gl.RGBA, type: gl.UNSIGNED_SHORT_4_4_4_4},
+ {format: gl.ALPHA, type: gl.UNSIGNED_BYTE},
+ {format: gl.RED, type: gl.UNSIGNED_BYTE},
+ {format: gl.RGBA_INTEGER, type: gl.UNSIGNED_INT},
+ {format: gl.RGBA_INTEGER, type: gl.INT}
+ ];
+
+ var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+ var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+ for (var tt = 0; tt < combinations.length; ++ tt) {
+ var info = combinations[tt];
+ var format = info.format;
+ var type = info.type;
+ gl.readPixels(0, 0, 1, 1, format, type, 0);
+ // Only two format/type parameter pairs are accepted. GL_RGBA/GL_UNSIGNED_BYTE is always
+ // accepted on default readbuffer. The other acceptable pair can be discovered by querying
+ // GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
+ if ((format == gl.RGBA && type == gl.UNSIGNED_BYTE) || (format == implFormat && type == implType)) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "The combination of format/type should be able to read as " +
+ wtu.glEnumToString(gl, format) + " / " + wtu.glEnumToString(gl, type));
+ } else {
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "The combination of format/type should not be able to read as " +
+ wtu.glEnumToString(gl, format) + " / " + wtu.glEnumToString(gl, type));
+ }
+ }
+}
+
+function validatePixelPackBufferAndParameters(canvasWidth, canvasHeight)
+{
+ debug("");
+ debug("Validate PIXEL_PACK buffer and readPixels' parameters");
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.pixelStorei(gl.PACK_ALIGNMENT, 1);
+
+ var size = canvasWidth * canvasHeight * 4;
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer);
+ gl.bufferData(gl.PIXEL_PACK_BUFFER, size, gl.STATIC_DRAW);
+ var array = new Uint8Array(size);
+
+ debug("");
+ debug("PIXEL_PACK buffer is bound");
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, array);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should generate INVALID_OPERATION if pixel pack buffer is bound");
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Validate the offset of PIXEL_PACK buffer and buffer size");
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, -1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "offset < 0");
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, size);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "offset > buffer size");
+ gl.readPixels(0, 0, canvasWidth + 1, canvasHeight, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "pixel pack buffer is not large enough");
+
+ debug("");
+ debug("Validate the reading area of framebuffer");
+ gl.readPixels(-1, -2, canvasWidth, canvasHeight, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "reading pixels outside of the framebuffer should succeed.");
+ gl.readPixels(2, 1, canvasWidth, canvasHeight, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "reading pixels outside of the framebuffer should succeed.");
+ gl.readPixels(2, 1, -1, -1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
+ "reading pixels with negative width / height should generate INVALID_VALUE.");
+
+ checkFormatAndType();
+
+ debug("");
+ debug("no PIXEL_PACK buffer bound");
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, array);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "no pixel pack buffer bound");
+
+ gl.deleteBuffer(buffer);
+}
+
+debug("");
+debug("Canvas.getContext");
+
+var wtu = WebGLTestUtils;
+var pixel = [0, 0, 0, 0];
+var expectedColor = [255, 102, 0, 255];
+
+var canvas = document.getElementById("example");
+var gl = wtu.create3DContext(canvas, undefined, 2);
+
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ debug("");
+ description('ReadPixels into PIXEL_PACK buffer');
+ validatePixelPackBufferAndParameters(4, 4);
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-pack-parameters.html b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-pack-parameters.html
new file mode 100644
index 0000000000..8d4559fb93
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/reading/read-pixels-pack-parameters.html
@@ -0,0 +1,353 @@
+<!--
+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>
+</head>
+<body>
+<canvas id="example" width="4" height="4"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict"
+
+var wtu = WebGLTestUtils;
+var initialColor = [1, 2, 3, 4];
+var expectedColor = [[249, 102, 0, 255],
+ [2, 200, 102, 255],
+ [134, 87, 234, 255],
+ [99, 5, 76, 255]];
+
+function calculatePaddingBytes(bytesPerPixel, packAlignment, width)
+{
+ var padding = 0;
+ switch (packAlignment) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ padding = (bytesPerPixel * width) % packAlignment;
+ if (padding > 0)
+ padding = packAlignment - padding;
+ return padding;
+ default:
+ testFailed("should not reach here");
+ return;
+ }
+}
+
+function paintWebGLCanvas(gl)
+{
+ var program = wtu.setupTexturedQuad(gl);
+ gl.disable(gl.DEPTH_TEST);
+ gl.disable(gl.BLEND);
+
+ var data = new Uint8Array(4 * 4);
+ for (var ii = 0; ii < 4; ++ii) {
+ data[ii * 4] = expectedColor[ii][0];
+ data[ii * 4 + 1] = expectedColor[ii][1];
+ data[ii * 4 + 2] = expectedColor[ii][2];
+ data[ii * 4 + 3] = expectedColor[ii][3];
+ }
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
+
+ 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);
+
+ var loc = gl.getUniformLocation(program, "tex");
+ gl.uniform1i(loc, 0);
+
+ wtu.clearAndDrawUnitQuad(gl);
+}
+
+function samePixel(array, index, refPixel, row, pixelTag)
+{
+ for (var ii = 0; ii < refPixel.length; ++ii) {
+ if (array[index] == refPixel[ii][0] &&
+ array[index + 1] == refPixel[ii][1] &&
+ array[index + 2] == refPixel[ii][2] &&
+ array[index + 3] == refPixel[ii][3]) {
+ return true;
+ }
+ }
+ var refPixelText = "";
+ for (var ii = 0; ii < refPixel.length; ++ii) {
+ if (ii > 0)
+ refPixelText += " or ";
+ refPixelText += "[" + refPixel[ii] + "]";
+ }
+ testFailed(pixelTag + " pixel of row " + row + ": expected " + refPixelText + ", got [" +
+ [array[index], array[index + 1], array[index + 2], array[index + 3]] + "]");
+ return false;
+}
+
+function runTestIteration(xoffset, yoffset, width, height, packParams, usePixelPackBuffer, packParamsValid)
+{
+ if (!("alignment" in packParams))
+ packParams.alignment = 4;
+ if (!("rowLength" in packParams))
+ packParams.rowLength = 0;
+ if (!("skipPixels" in packParams))
+ packParams.skipPixels = 0;
+ if (!("skipRows" in packParams))
+ packParams.skipRows = 0;
+ debug("Testing xoffset = " + xoffset + ", yoffset " + yoffset +
+ ", width = " + width + ", height = " + height +
+ ", PACK_ALIGNMENT = " + packParams.alignment + ", PACK_ROW_LENGTH = " + packParams.rowLength +
+ ", PACK_SKIP_PIXELS = " + packParams.skipPixels + " , PACK_SKIP_ROWS = " + packParams.skipRows);
+ gl.pixelStorei(gl.PACK_ALIGNMENT, packParams.alignment);
+ gl.pixelStorei(gl.PACK_ROW_LENGTH, packParams.rowLength);
+ gl.pixelStorei(gl.PACK_SKIP_PIXELS, packParams.skipPixels);
+ gl.pixelStorei(gl.PACK_SKIP_ROWS, packParams.skipRows);
+
+ var actualWidth = packParams.rowLength > 0 ? packParams.rowLength : width;
+
+ var bytesPerPixel = 4; // see readPixels' parameters below, the format is gl.RGBA, type is gl.UNSIGNED_BYTE
+ var padding = calculatePaddingBytes(bytesPerPixel, packParams.alignment, actualWidth);
+ var bytesPerRow = actualWidth * bytesPerPixel + padding;
+
+ var size = bytesPerRow * (height - 1) + bytesPerPixel * width;
+ var skipSize = packParams.skipPixels * bytesPerPixel + packParams.skipRows * bytesPerRow;
+ var array = new Uint8Array(skipSize + size);
+ for (var ii = 0; ii < skipSize + size; ++ii) {
+ array[ii] = initialColor[ii % bytesPerPixel];
+ }
+ var arrayWrongSize = null;
+ if (size > 0)
+ arrayWrongSize = new Uint8Array(skipSize + size - 1);
+ if (usePixelPackBuffer) {
+ var offset = 0;
+
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer);
+ if (size > 0) {
+ gl.bufferData(gl.PIXEL_PACK_BUFFER, arrayWrongSize, gl.STATIC_DRAW);
+ gl.readPixels(xoffset, yoffset, width, height, gl.RGBA, gl.UNSIGNED_BYTE, offset);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "buffer too small");
+ }
+ gl.bufferData(gl.PIXEL_PACK_BUFFER, array, gl.STATIC_DRAW);
+ gl.readPixels(xoffset, yoffset, width, height, gl.RGBA, gl.UNSIGNED_BYTE, offset);
+ } else {
+ if (size > 0) {
+ gl.readPixels(xoffset, yoffset, width, height, gl.RGBA, gl.UNSIGNED_BYTE, arrayWrongSize);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "buffer too small");
+ }
+ gl.readPixels(xoffset, yoffset, width, height, gl.RGBA, gl.UNSIGNED_BYTE, array);
+ }
+ if (packParamsValid) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should succeed");
+ } else {
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Invalid pack params combination");
+ return;
+ }
+
+ if (size == 0)
+ return;
+
+ if (usePixelPackBuffer) {
+ array = new Uint8Array(skipSize + size);
+ gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, array);
+ }
+
+ // Check skipped bytes are unchanged.
+ for (var ii = 0; ii < skipSize; ++ii) {
+ if (array[ii] != initialColor[ii % bytesPerPixel]) {
+ testFailed("skipped bytes changed at index " + ii + ": expected " +
+ initialColor[ii % bytesPerPixel] + " got " + array[ii]);
+ break;
+ }
+ }
+ // Check the first and last pixels of each row.
+ var canvasWidth = 4;
+ var canvasHeight = 4;
+ for (var row = 0; row < height; ++row) {
+ var refColor;
+ var yIndex = yoffset + row;
+ var xIndex;
+
+ // First pixel
+ var pos = skipSize + bytesPerRow * row;
+ xIndex = xoffset;
+ if (xIndex < 0 || xIndex >= canvasWidth || yIndex < 0 || yIndex >= canvasHeight) {
+ if (row > 0 && usePixelPackBuffer && packParams.rowLength > 0 && packParams.rowLength < width)
+ refColor = [initialColor, expectedColor[yIndex - 1]];
+ else
+ refColor = [initialColor];
+ } else {
+ refColor = [expectedColor[yIndex]];
+ }
+ samePixel(array, pos, refColor, row, "first");
+
+ // Last pixel
+ var xSpan;
+ if (row + 1 == height || packParams.rowLength > width)
+ xSpan = width;
+ else
+ xSpan = actualWidth;
+ xIndex = xoffset + xSpan - 1;
+ pos += (xSpan - 1) * bytesPerPixel;
+ if (xIndex < 0 || xIndex >= canvasWidth || yIndex < 0 || yIndex >= canvasHeight) {
+ if (row > 0 && usePixelPackBuffer && packParams.rowLength > 0 && packParams.rowLength < width)
+ refColor = [initialColor, expectedColor[yIndex - 1]];
+ else
+ refColor = [initialColor];
+ } else {
+ refColor = [expectedColor[yIndex]];
+ }
+ samePixel(array, pos, refColor, row, "last");
+
+ // Check padding bytes are unchanged and bytes beyond rowLength set correctly.
+ pos += bytesPerPixel;
+ if (row + 1 < height) {
+ // Beyond bytes filled for PACK_ROW_LENGTH, the row could have extra bytes due to
+ // padding. These extra bytes could be either filled with pixel data if
+ // PACK_ROW_LENGTH is set to be less than width, or they could be left unchanged
+ // if they are beyond |width| pixels.
+ if (packParams.rowLength > 0 && packParams.rowLength < width) {
+ var trailingBytes = Math.min((width - packParams.rowLength) * bytesPerPixel,
+ bytesPerRow - packParams.rowLength * bytesPerPixel);
+ for (var ii = 0; ii < trailingBytes; ++ii) {
+ if (array[pos + ii] != refColor[0][ii % bytesPerPixel]) {
+ testFailed("Trailing byte " + ii + " after rowLength of row " + row + " : expected " +
+ refColor[0][ii % bytesPerPixel] + ", got " + array[pos + ii]);
+ break;
+ }
+ }
+ pos += trailingBytes;
+ }
+ var paddingBytes = skipSize + bytesPerRow * (row + 1) - pos;
+ for (var ii = 0; ii < paddingBytes; ++ii) {
+ if (array[pos + ii] != initialColor[ii % bytesPerPixel]) {
+ testFailed("Padding byte " + ii + " of row " + row + " changed: expected " +
+ initialColor[ii % bytesPerPixel] + ", got " + array[pos + ii]);
+ break;
+ }
+ }
+ }
+ }
+}
+
+function testPackParameters(usePixelPackBuffer)
+{
+ debug("");
+ var destText = usePixelPackBuffer ? "PIXEL_PACK buffer" : "array buffer";
+ debug("Verify that reading pixels to " + destText + " works fine with various pack alignments.");
+ runTestIteration(0, 0, 1, 3, {alignment:1}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 1, 3, {alignment:2}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 1, 3, {alignment:4}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 1, 3, {alignment:8}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 2, 3, {alignment:4}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 2, 3, {alignment:8}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 3, 3, {alignment:4}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 3, 3, {alignment:8}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 0, 0, {alignment:1}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 1, 3, {alignment:4}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 1, 3, {alignment:8}, usePixelPackBuffer, true);
+
+ debug("");
+ debug("Verify that reading pixels to " + destText + " is disallowed when PACK_ROW_LENGTH < width.");
+ runTestIteration(0, 0, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(-1, 0, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(0, -1, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(-1, -1, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(-5, 0, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(0, -5, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(2, 0, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(0, 2, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(2, 2, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(5, 0, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(0, 5, 3, 3, {alignment:8, rowLength:2}, usePixelPackBuffer, false);
+ runTestIteration(0, 0, 3, 3, {alignment:8, rowLength:1}, usePixelPackBuffer, false);
+
+ debug("");
+ debug("Verify that reading pixels to " + destText + " works fine with PACK_ROW_LENGTH == width.");
+ runTestIteration(0, 0, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(-1, 0, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(0, -1, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(-1, -1, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(-5, 0, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(0, -5, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(2, 0, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(0, 2, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(2, 2, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(5, 0, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+ runTestIteration(0, 5, 3, 3, {alignment:8, rowLength:3}, usePixelPackBuffer, true);
+
+ debug("");
+ debug("Verify that reading pixels to " + destText + " works fine with PACK_ROW_LENGTH > width and with no padding");
+ runTestIteration(0, 0, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(-1, 0, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(0, -1, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(-1, -1, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(-5, 0, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(0, -5, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(2, 0, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(0, 2, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(2, 2, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(5, 0, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+ runTestIteration(0, 5, 3, 3, {alignment:8, rowLength:4}, usePixelPackBuffer, true);
+
+ debug("");
+ debug("Verify that reading pixels to " + destText + " works fine with PACK_ROW_LENGTH > width and with padding");
+ runTestIteration(0, 0, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(-1, 0, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(0, -1, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(-1, -1, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(-5, 0, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(0, -5, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(2, 0, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(0, 2, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(2, 2, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(5, 0, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+ runTestIteration(0, 5, 3, 3, {alignment:8, rowLength:5}, usePixelPackBuffer, true);
+
+ debug("");
+ debug("Verify that reading pixels to " + destText + " works fine with pack skip parameters.");
+ runTestIteration(0, 0, 3, 3, {alignment:8, skipPixels:2}, usePixelPackBuffer, false);
+ runTestIteration(0, 0, 3, 3, {alignment:8, skipPixels:1, skipRows:3}, usePixelPackBuffer, false);
+ runTestIteration(0, 0, 3, 3, {alignment:8, skipRows:3}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 2, 3, {alignment:8, skipPixels:2}, usePixelPackBuffer, false);
+ runTestIteration(0, 0, 2, 3, {alignment:8, skipPixels:1, skipRows:3}, usePixelPackBuffer, false);
+ runTestIteration(0, 0, 2, 3, {alignment:8, skipRows:3}, usePixelPackBuffer, true);
+ runTestIteration(0, 0, 2, 3, {skipPixels:1, rowLength:4}, usePixelPackBuffer, true);
+}
+
+debug("");
+debug("Canvas.getContext");
+
+var canvas = document.getElementById("example");
+var gl = wtu.create3DContext(canvas, undefined, 2);
+
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ debug("");
+ description('ReadPixels into array buffer');
+ paintWebGLCanvas(gl);
+ var usePixelPackBuffer = false;
+ testPackParameters(usePixelPackBuffer);
+ usePixelPackBuffer = true;
+ testPackParameters(usePixelPackBuffer);
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>