summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance2/rendering')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt25
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/attrib-type-match.html582
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-outofbounds.html199
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-srgb.html183
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html134
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-outside-readbuffer.html289
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-scissor-enabled.html182
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-size-overflow.html98
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html229
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-stencil-only.html192
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-test.html342
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html130
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-func-buffer-type-match.html166
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-srgb-color-buffer.html109
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clipping-wide-points.html47
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html581
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/element-index-uint.html426
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-completeness-unaffected.html113
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-unsupported.html155
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html190
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-arrays.html242
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-rendering-bug.html275
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/out-of-bounds-index-buffers-after-copying.html207
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html148
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rgb-format-support.html132
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/rendering/uniform-block-buffer-size.html249
26 files changed, 5625 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt
new file mode 100644
index 000000000..7aed37329
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt
@@ -0,0 +1,25 @@
+attrib-type-match.html
+blitframebuffer-filter-outofbounds.html
+blitframebuffer-filter-srgb.html
+blitframebuffer-multisampled-readbuffer.html
+--min-version 2.0.1 blitframebuffer-outside-readbuffer.html
+blitframebuffer-scissor-enabled.html
+blitframebuffer-size-overflow.html
+--min-version 2.0.1 blitframebuffer-srgb-and-linear-drawbuffers.html
+--min-version 2.0.1 blitframebuffer-stencil-only.html
+blitframebuffer-test.html
+canvas-resizing-with-pbo-bound.html
+clear-func-buffer-type-match.html
+--min-version 2.0.1 clear-srgb-color-buffer.html
+--min-version 2.0.1 clipping-wide-points.html
+draw-buffers.html
+element-index-uint.html
+framebuffer-completeness-unaffected.html
+framebuffer-unsupported.html
+--min-version 2.0.1 fs-color-type-mismatch-color-buffer-type.html
+instanced-arrays.html
+--min-version 2.0.1 instanced-rendering-bug.html
+out-of-bounds-index-buffers-after-copying.html
+--min-version 2.0.1 rendering-sampling-feedback-loop.html
+rgb-format-support.html
+uniform-block-buffer-size.html
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/attrib-type-match.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/attrib-type-match.html
new file mode 100644
index 000000000..5d810187f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/attrib-type-match.html
@@ -0,0 +1,582 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Conformance Tests: Vertex Attribute Type Match</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: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<!-- Shaders for testing instanced draws -->
+<script id="outputVertexShader" type="x-shader/x-vertex">#version 300 es
+in vec4 aPosition;
+in ivec2 aOffsetI;
+in uvec2 aOffsetU;
+in vec4 aColor;
+out vec4 vColor;
+void main() {
+ vColor = aColor;
+ vec2 offset = vec2(float(aOffsetI.x) + float(aOffsetU.x),
+ float(aOffsetI.y) + float(aOffsetU.y));
+ gl_Position = aPosition + vec4(offset, 0.0, 0.0);
+}
+</script>
+
+<script id="outputFragmentShader" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+in vec4 vColor;
+out vec4 fragColor;
+void main() {
+ fragColor = vColor;
+}
+</script>
+
+<script id='vshader_inactive_attrib' type='x-shader/x-vertex'>#version 300 es
+in ivec4 p;
+in ivec4 a;
+void main()
+{
+ gl_Position = vec4(p);
+}
+</script>
+<script id='vshader_active_attrib_int' type='x-shader/x-vertex'>#version 300 es
+in ivec4 p;
+in ivec4 a;
+in uvec4 b;
+void main()
+{
+ gl_Position = vec4(p) + vec4(a) + vec4(b);
+}
+</script>
+<script id='vshader_active_attrib_float' type='x-shader/x-vertex'>#version 300 es
+in vec4 p;
+in vec4 a;
+in vec4 c;
+void main()
+{
+ gl_Position = vec4(p) + vec4(a) + vec4(c);
+}
+</script>
+<script id='fshader' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+void main()
+{
+ oColor = vec4(1.0, 0.0, 0.0, 1.0);
+}
+</script>
+
+
+<script>
+"use strict";
+description("This test verifies an active vertex attribute's base type has to match the verexAttrib function type.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, 2);
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ testGenericAttribs();
+ runTests();
+}
+
+function testGenericAttribs() {
+ debug("");
+ debug("Test Generic Vertex Attributes for some corner cases");
+
+ var pIndex = 2;
+ var aIndex = 3;
+ var bIndex = 4;
+ var cIndex = 5;
+ var program0 = wtu.setupProgram(gl, ["vshader_inactive_attrib", "fshader"],
+ ['p', 'a'], [pIndex, aIndex]);
+ var program1 = wtu.setupProgram(gl, ["vshader_active_attrib_int", "fshader"],
+ ['p', 'a', 'b'], [pIndex, aIndex, bIndex]);
+ var program2 = wtu.setupProgram(gl, ["vshader_active_attrib_float", "fshader"],
+ ['p', 'a', 'c'], [pIndex, aIndex, cIndex]);
+ if (!program0 || !program1 || !program2) {
+ testFailed("Set up program failed");
+ return;
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error from set up");
+
+ wtu.setupUnitQuad(gl, 0);
+
+ debug("Inactive input in vertex shader");
+ gl.useProgram(program0);
+ gl.vertexAttribI4i(pIndex, 1, 0, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds: type in shader mismatch default vertex type is valid for inactive attrib");
+
+ gl.vertexAttrib4f(aIndex, 0.0, 1.0, 0.0, 0.0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds: type in shader mismatch vertexAttrib type is valid for inactive attrib");
+
+ debug("active int/uint inputs in vertex shader");
+ gl.useProgram(program1);
+ gl.vertexAttribI4i(pIndex, 1, 0, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Type mismatch: type in shader mismatch the default type for a vertex attrib");
+ gl.vertexAttribI4i(aIndex, 0, 1, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Type mismatch: type in shader mismatch the default type for a vertex attrib");
+ gl.vertexAttribI4ui(bIndex, 0, 0, 1, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds");
+
+ debug("active float input in vertex shader");
+ gl.useProgram(program2);
+ gl.vertexAttrib4f(pIndex, 1.0, 0.0, 0.0, 0.0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Type mismatch: generic attrib is valid per context. 'a' is set to int type by previous test case");
+ gl.vertexAttrib4f(aIndex, 0.0, 1.0, 0.0, 0.0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds: default type of generic attrib is float");
+}
+
+function setupAttribValues(offsetILoc, offsetULoc, colorLoc) {
+ gl.vertexAttribI4i(offsetILoc, -1, -2, 0, 0);
+ gl.vertexAttribI4ui(offsetULoc, 1, 2, 0, 0);
+ gl.vertexAttrib4f(colorLoc, 1.0, 0, 0, 1.0);
+}
+
+function setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer);
+ gl.vertexAttribIPointer(offsetILoc, 2, gl.INT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer);
+ gl.vertexAttribIPointer(offsetULoc, 2, gl.UNSIGNED_INT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
+}
+
+function runTests() {
+ debug("");
+ debug("Test vertexAttrib with drawArrays and drawArraysInstanced");
+
+ var instanceCount = 4;
+
+ var positionLoc = 0;
+ var offsetILoc = 2;
+ var offsetULoc = 3;
+ var colorLoc = 4;
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"],
+ ['aPosition', 'aOffsetI', 'aOffsetU','aColor'],
+ [positionLoc, offsetILoc, offsetULoc, colorLoc]);
+ if (!program) {
+ testFailed("Set up program failed");
+ return;
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error from set up");
+
+ wtu.setupUnitQuad(gl, 0);
+
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
+
+ debug("int type function on uint type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4i(offsetULoc, 1, 2, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("float type function on uint type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttrib4f(offsetULoc, 1.0, 2.0, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("uint type function on int type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4ui(offsetILoc, 1, 2, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("float type function on int type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttrib4f(offsetILoc, 1.0, 2.0, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("int type function on float type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4i(colorLoc, 1, 0, 0, 1);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("uint type function on float type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4ui(colorLoc, 1, 0, 0, 1);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("");
+ debug("Test vertexAttrib with drawElements, drawRangeElements, and drawElementsInstanced");
+ wtu.setupIndexedQuad(gl, 1, 0);
+
+ debug("Correct setup");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawRangeElements succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
+
+ debug("int type function on uint type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4i(offsetULoc, 1, 2, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("float type function on uint type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttrib4f(offsetULoc, 1.0, 2.0, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("uint type function on int type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4ui(offsetILoc, 1, 2, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("float type function on int type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttrib4f(offsetILoc, 1.0, 2.0, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("int type function on float type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4i(colorLoc, 1, 0, 0, 1);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("uint type function on float type attrib");
+ setupAttribValues(offsetILoc, offsetULoc, colorLoc);
+ gl.vertexAttribI4ui(colorLoc, 1, 0, 0, 1);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+
+ var offsetIBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer);
+ var offsetI = new Int32Array([-1, -2,
+ -1, -2,
+ -1, -2,
+ -1, -2,
+ -1, -2,
+ -1, -2]);
+ gl.bufferData(gl.ARRAY_BUFFER, offsetI, gl.STATIC_DRAW);
+
+ var offsetUBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer);
+ var offsetU = new Uint32Array([1, 2,
+ 1, 2,
+ 1, 2,
+ 1, 2,
+ 1, 2,
+ 1, 2]);
+ gl.bufferData(gl.ARRAY_BUFFER, offsetU, gl.STATIC_DRAW);
+
+ var offsetFBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer);
+ var offsetF = new Float32Array([1.0, 2.0,
+ 1.0, 2.0,
+ 1.0, 2.0,
+ 1.0, 2.0,
+ 1.0, 2.0,
+ 1.0, 2.0]);
+ gl.bufferData(gl.ARRAY_BUFFER, offsetF, gl.STATIC_DRAW);
+
+ var colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ var colors = new Float32Array([0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0]);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+
+ var colorUBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer);
+ var colorsU = new Uint32Array([0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1,
+ 0, 1, 0, 1]);
+ gl.bufferData(gl.ARRAY_BUFFER, colorsU, gl.STATIC_DRAW);
+
+ gl.enableVertexAttribArray(offsetILoc);
+ gl.enableVertexAttribArray(offsetULoc);
+ gl.enableVertexAttribArray(colorLoc);
+
+ debug("");
+ debug("Test vertexAttrib{I}Pointer with drawArrays and drawArraysInstanced");
+ wtu.setupUnitQuad(gl, 0);
+
+ debug("Correct setup");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]);
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]);
+
+ debug("vertexAttribIPointer with int type on uint type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer);
+ gl.vertexAttribIPointer(offsetULoc, 2, gl.INT, false, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribPointer on uint type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer);
+ gl.vertexAttribPointer(offsetULoc, 2, gl.FLOAT, false, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("VertexAttribIPointer with uint type on int type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer);
+ gl.vertexAttribIPointer(offsetILoc, 2, gl.UNSIGNED_INT, false, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribPointer on int type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer);
+ gl.vertexAttribPointer(offsetILoc, 2, gl.FLOAT, false, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribIPointer with uint type on float type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer);
+ gl.vertexAttribIPointer(colorLoc, 4, gl.UNSIGNED_INT, false, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribIPointer with int type on float type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer);
+ gl.vertexAttribIPointer(colorLoc, 4, gl.INT, false, 0, 0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("");
+ debug("Test vertexAttrib{I}Pointer with drawElements, drawRangeElements, and drawElementsInstanced");
+ wtu.setupIndexedQuad(gl, 1, 0);
+
+ debug("Correct setup");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setting up succeeds");
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]);
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawRangeElements succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]);
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced succeeds");
+ wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [0, 255, 0, 255]);
+
+ debug("vertexAttribIPointer with int type on uint type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetIBuffer);
+ gl.vertexAttribIPointer(offsetULoc, 2, gl.INT, false, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribPointer on uint type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer);
+ gl.vertexAttribPointer(offsetULoc, 2, gl.FLOAT, false, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("VertexAttribIPointer with uint type on int type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetUBuffer);
+ gl.vertexAttribIPointer(offsetILoc, 2, gl.UNSIGNED_INT, false, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribPointer on int type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetFBuffer);
+ gl.vertexAttribPointer(offsetILoc, 2, gl.FLOAT, false, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribIPointer with uint type on float type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer);
+ gl.vertexAttribIPointer(colorLoc, 4, gl.UNSIGNED_INT, false, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+
+ debug("vertexAttribIPointer with int type on float type attrib");
+ setupAttribPointers(offsetILoc, offsetULoc, colorLoc,
+ offsetIBuffer, offsetUBuffer, colorBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorUBuffer);
+ gl.vertexAttribIPointer(colorLoc, 4, gl.INT, false, 0, 0);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "type mismatch");
+}
+
+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/rendering/blitframebuffer-filter-outofbounds.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-outofbounds.html
new file mode 100644
index 000000000..358465214
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-outofbounds.html
@@ -0,0 +1,199 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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/glsl-conformance-test.js"></script>
+</head>
+<body>
+<canvas id="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of blitFramebuffer when src/dst region are out-of-bounds.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+function checkPixel(color, expectedColor) {
+ var tolerance = 3;
+ return (Math.abs(color[0] - expectedColor[0]) <= tolerance &&
+ Math.abs(color[1] - expectedColor[1]) <= tolerance &&
+ Math.abs(color[2] - expectedColor[2]) <= tolerance &&
+ Math.abs(color[3] - expectedColor[3]) <= tolerance);
+}
+
+function blitframebuffer_filter_outofbounds(readbufferFormat, drawbufferFormat, filter) {
+ debug("");
+ debug("blitting pixels out-of-bounds, read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat) + ", filter is: " + wtu.glEnumToString(gl, filter));
+
+ // Initiate data to read framebuffer
+ var size = 8;
+ var uint_read = new Uint8Array(size * size * 4);
+ var color = 0x20;
+ for (var ii = 0; ii < size * size * 4; ii += 4) {
+ for (var jj = 0; jj < 3; ++jj) {
+ uint_read[ii + jj] = color;
+ }
+ uint_read[ii + 3] = 0xff;
+ }
+
+ // Create read framebuffer and feed data to read buffer
+ // Read buffer may have srgb image
+ var tex_read = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex_read);
+ gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_read);
+
+ var fbo_read = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0);
+
+ // Create draw framebuffer. Color in draw buffer is initialized to 0.
+ // Draw buffer may have srgb image
+ var tex_draw = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex_draw);
+ gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ var fbo_draw = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0);
+
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ // Blit read framebuffer to the image in draw framebuffer.
+ var test = [
+ // [srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1]
+ [-2, -2, 4, 4, 1, 1, 4, 4], // only src region is out-of-bounds, dst region has different width/height as src region.
+ [-2, -2, 4, 4, 1, 1, 7, 7], // only src region is out-of-bounds, dst region has the same width/height as src region.
+ [0, 0, 6, 6, 7, 7, 10, 10], // only dst region is out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer.
+ [0, 0, 6, 6, 4, 4, 10, 10], // only dst region is out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer.
+ [-2, -2, 4, 4, 7, 7, 10, 10], // both src and dst region are out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer.
+ [-2, -2, 4, 4, 4, 4, 10, 10], // both src and dst region are out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer.
+ [-2, -2, 4, 4, 2, 2, 10, 10], // both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 8] , and x or y equals to 4) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area.
+ [-2, -2, 4, 4, 3, 3, 10, 10], // both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 7] , and x or y equals to 5) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area.
+ [-2, -2, 4, 4, 10, 10, 2, 2], // both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [2, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area.
+ [-2, -2, 4, 4, 10, 10, 3, 3], // both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [3, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the read sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area.
+ ];
+
+ var realBlittedDstRegion = [
+ [2, 2, 4, 4],
+ [3, 3, 7, 7],
+ [7, 7, 8, 8],
+ [4, 4, 8, 8],
+ [8, 8, 8, 8],
+ [6, 6, 8, 8],
+ [5, 5, 8, 8],
+ [5, 5, 8, 8],
+ [2, 2, 7, 7],
+ [3, 3, 8, 8],
+ ]
+ var readbufferHasSRGBImage = (readbufferFormat == gl.SRGB8_ALPHA8);
+ var drawbufferHasSRGBImage = (drawbufferFormat == gl.SRGB8_ALPHA8);
+
+ for (var i = 0; i < test.length; ++i) {
+ debug("");
+ debug("both the read framebuffer and draw framebuffer bounds are [0, 0, 8, 8]");
+ debug("blitting from src region [" + test[i][0] + ", " + test[i][1] + ", " + test[i][2] + ", " + test[i][3] + "] to dst region [" + test[i][4] + ", " + test[i][5] + ", " + test[i][6] + ", " + test[i][7] + "]");
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+ gl.bindTexture(gl.TEXTURE_2D, tex_draw);
+ gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.blitFramebuffer(test[i][0], test[i][1], test[i][2], test[i][3], test[i][4], test[i][5], test[i][6], test[i][7], gl.COLOR_BUFFER_BIT, filter);
+
+ // Read pixels and check the correctness.
+ var pixels = new Uint8Array(size * size * 4);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw);
+ gl.readPixels(0, 0, size, size, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+
+ for (var ii = 0; ii < size; ++ii) {
+ for (var jj = 0; jj < size; ++jj) {
+ var loc = ii * size + jj;
+ var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]];
+
+ var expectedColor = [0, 0, 0, 0];
+ if (ii >= realBlittedDstRegion[i][0] && ii < realBlittedDstRegion[i][2] && jj >= realBlittedDstRegion[i][1] && jj < realBlittedDstRegion[i][3]) {
+ expectedColor = [0x20, 0x20, 0x20, 0xff];
+
+ // We may need to covert the color space for pixels in blit region
+ if (readbufferHasSRGBImage ^ drawbufferHasSRGBImage) {
+ if (drawbufferHasSRGBImage) {
+ expectedColor = wtu.linearToSRGB(expectedColor);
+ } else {
+ expectedColor = wtu.sRGBToLinear(expectedColor);
+ }
+ }
+ }
+
+ if (checkPixel(color, expectedColor) == true) {
+ testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!");
+ } else {
+ testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")");
+ }
+ }
+ }
+ }
+ } else {
+ testFailed("framebuffer not complete");
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fbo_read);
+ gl.deleteFramebuffer(fbo_draw);
+ gl.deleteTexture(tex_read);
+ gl.deleteTexture(tex_draw);
+};
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+ var filters = [gl.LINEAR, gl.NEAREST];
+ for (var ii = 0; ii < filters.length; ++ii) {
+ blitframebuffer_filter_outofbounds(gl.RGBA8, gl.RGBA8, filters[ii]);
+ blitframebuffer_filter_outofbounds(gl.RGBA8, gl.SRGB8_ALPHA8, filters[ii]);
+ blitframebuffer_filter_outofbounds(gl.SRGB8_ALPHA8, gl.RGBA8, filters[ii]);
+ blitframebuffer_filter_outofbounds(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii]);
+ }
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-srgb.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-srgb.html
new file mode 100644
index 000000000..7cce19513
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-filter-srgb.html
@@ -0,0 +1,183 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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/glsl-conformance-test.js"></script>
+</head>
+<body>
+<canvas id="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of blitFramebuffer with sRGB framebuffers.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+function checkPixel(color, expectedColor) {
+ var tolerance = 7;
+ return (Math.abs(color[0] - expectedColor[0]) <= tolerance &&
+ Math.abs(color[1] - expectedColor[1]) <= tolerance &&
+ Math.abs(color[2] - expectedColor[2]) <= tolerance &&
+ Math.abs(color[3] - expectedColor[3]) <= tolerance);
+}
+
+var tex_read = gl.createTexture();
+var tex_draw = gl.createTexture();
+var fbo_read = gl.createFramebuffer();
+var fbo_draw = gl.createFramebuffer();
+var size_read = 4;
+var size_draw = 0;
+
+function blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter, data) {
+ // Create read framebuffer and feed data to read buffer
+ gl.bindTexture(gl.TEXTURE_2D, tex_read);
+ gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size_read, size_read, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0);
+
+ // Create draw framebuffer and feed 0 to draw buffer
+ gl.bindTexture(gl.TEXTURE_2D, tex_draw);
+ gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size_draw, size_draw, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0);
+
+ gl.blitFramebuffer(0, 0, size_read, size_read, 0, 0, size_draw, size_draw, gl.COLOR_BUFFER_BIT, filter);
+
+ // Read pixels for comparision
+ var pixels = new Uint8Array(size_draw * size_draw * 4);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw);
+ gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+ return pixels;
+}
+
+function blitframebuffer_filter_srgb(readbufferFormat, drawbufferFormat, filter, minified) {
+ debug("");
+ debug("Test srgb filtering for blitFramebuffer, the current filter is: " + wtu.glEnumToString(gl, filter));
+ var min_mag = minified ? "minified to half the size." : "magnified to double the size.";
+ debug("read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat) + ", minify/magnify: " + min_mag);
+
+ // Initiate data to read framebuffer
+ var src_buffer = new Uint8Array(size_read * size_read * 4);
+ var start = 0;
+ for (var ii = 0; ii < size_read * size_read * 4; ii += 4) {
+ for (var jj = 0; jj < 3; ++jj) {
+ src_buffer[ii + jj] = start;
+ }
+ src_buffer[ii + 3] = 0xff;
+ start += 0x10;
+ }
+
+ // We may need to decode srgb to linear for reference data
+ var ref_buffer = new Uint8Array(size_read * size_read * 4);
+ for (var ii = 0; ii < size_read * size_read * 4; ii += 4) {
+ var color = [src_buffer[ii], src_buffer[ii + 1], src_buffer[ii + 2], src_buffer[ii + 3]];
+ var ref_color;
+ if (readbufferFormat == gl.SRGB8_ALPHA8) {
+ ref_color = wtu.sRGBToLinear(color);
+ } else {
+ ref_color = color;
+ }
+ for (var jj = 0; jj < 4; ++jj) {
+ ref_buffer[ii + jj] = ref_color[jj];
+ }
+ }
+
+ // Blit framebuffer to filter srgb image, but the reference data is always retrieved by blitFramebuffer against linear image
+ size_draw = minified ? size_read / 2 : size_read * 2;
+ var pixels = blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter, src_buffer);
+ var temp = blitframebuffer_helper(gl.RGBA, gl.RGBA, filter, ref_buffer);
+
+ // We may need to encode linear to srgb for reference data
+ var ref_pixels = new Uint8Array(size_draw * size_draw * 4);
+ for (var ii = 0; ii < size_draw * size_draw * 4; ii += 4) {
+ var color = [temp[ii], temp[ii + 1], temp[ii + 2], temp[ii + 3]];
+ var ref_color;
+ if (drawbufferFormat == gl.SRGB8_ALPHA8) {
+ ref_color = wtu.linearToSRGB(color);
+ } else {
+ ref_color = color;
+ }
+ for (var jj = 0; jj < 4; ++jj) {
+ ref_pixels[ii + jj] = ref_color[jj];
+ }
+ }
+
+ // Compare
+ for (var ii = 0; ii < size_draw; ++ii) {
+ for (var jj = 0; jj < size_draw; ++jj) {
+ var index = ii * size_draw * 4 + jj;
+ var color = [pixels[index], pixels[index + 1], pixels[index + 2], pixels[index + 3]];
+ var expectedColor = [ref_pixels[index], ref_pixels[index + 1], ref_pixels[index + 2], ref_pixels[index + 3]];
+ if (checkPixel(color, expectedColor) == true) {
+ testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!");
+ } else {
+ testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")");
+ }
+ }
+ }
+}
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+ var filters = [gl.LINEAR, gl.NEAREST];
+ for (var ii = 0; ii < filters.length; ++ii) {
+ blitframebuffer_filter_srgb(gl.RGBA8, gl.SRGB8_ALPHA8, filters[ii], true);
+ blitframebuffer_filter_srgb(gl.RGBA8, gl.SRGB8_ALPHA8, filters[ii], false);
+ blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.RGBA8, filters[ii], true);
+ blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.RGBA8, filters[ii], false);
+ blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii], true);
+ blitframebuffer_filter_srgb(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii], false);
+ }
+}
+
+gl.bindTexture(gl.TEXTURE_2D, null);
+gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+gl.deleteFramebuffer(fbo_read);
+gl.deleteFramebuffer(fbo_draw);
+gl.deleteTexture(tex_read);
+gl.deleteTexture(tex_draw);
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html
new file mode 100644
index 000000000..568442a01
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-multisampled-readbuffer.html
@@ -0,0 +1,134 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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/glsl-conformance-test.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of blitFramebuffer with multisampled sRGB color buffer.");
+
+var gl = wtu.create3DContext("canvas", undefined, 2);
+
+var tex_blit = gl.createTexture();
+var fb0 = gl.createFramebuffer();
+var rb0 = gl.createRenderbuffer();
+var fbo_blit = gl.createFramebuffer();
+var size = 32;
+var program;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ init();
+
+ var filters = [gl.LINEAR, gl.NEAREST];
+ for (var ii = 0; ii < filters.length; ++ii) {
+ blitframebuffer_multisampled_readbuffer(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii]);
+ }
+}
+
+function init() {
+ program = wtu.setupColorQuad(gl);
+ gl.viewport(0, 0, size, size);
+}
+
+function blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter) {
+ // Create draw framebuffer and feed 0 to draw buffer
+ gl.bindTexture(gl.TEXTURE_2D, tex_blit);
+ gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_blit);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_blit, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup draw framebuffer should succeed");
+
+ gl.blitFramebuffer(0, 0, size, size, 0, 0, size, size, gl.COLOR_BUFFER_BIT, filter);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitframebuffer should succeed");
+}
+
+function blitframebuffer_multisampled_readbuffer(readbufferFormat, drawbufferFormat, filter) {
+ debug("");
+ debug("Test blitFramebuffer when the read buffer is a multisampled srgb image. The filter is: " + wtu.glEnumToString(gl, filter));
+ debug("read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat));
+
+ // Draw to a multi-sampled srgb image, and blit to a srgb image.
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb0);
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, readbufferFormat, size, size);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb0);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ var color = [252, 122, 15, 255];
+ var expectedColor = wtu.linearToSRGB(color);
+ for (var i = 0; i < 4; ++i) {
+ color[i] = color[i] / 255;
+ }
+ // Draw a rectangle. Fill it with solid color.
+ // Note that the draw buffer is a multisampled srgb image. So during drawing, the color will be converted into srgb color space.
+ gl.useProgram(program);
+ wtu.drawFloatColorQuad(gl, color);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ blitframebuffer_helper(readbufferFormat, drawbufferFormat, filter);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Blit from a multi-sampled srgb image to a srgb image should succeed");
+
+ // Compare
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_blit);
+ wtu.checkCanvasRect(gl, 0, 0, size, size, expectedColor);
+}
+
+gl.bindTexture(gl.TEXTURE_2D, null);
+gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+gl.deleteRenderbuffer(rb0);
+gl.deleteTexture(tex_blit);
+gl.deleteFramebuffer(fb0);
+gl.deleteFramebuffer(fbo_blit);
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-outside-readbuffer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-outside-readbuffer.html
new file mode 100644
index 000000000..00c5f86f3
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-outside-readbuffer.html
@@ -0,0 +1,289 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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/glsl-conformance-test.js"></script>
+</head>
+<body>
+<canvas id="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of blitFramebuffer.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+function checkPixel(color, expectedColor) {
+ var tolerance = 3;
+ return (Math.abs(color[0] - expectedColor[0]) <= tolerance &&
+ Math.abs(color[1] - expectedColor[1]) <= tolerance &&
+ Math.abs(color[2] - expectedColor[2]) <= tolerance &&
+ Math.abs(color[3] - expectedColor[3]) <= tolerance);
+}
+
+function blitframebuffer_outside_readbuffer(readbufferFormat, drawbufferFormat) {
+ debug("");
+ debug("blitting outside of read framebuffer, read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat));
+
+ // Initiate data to read framebuffer
+ var size_read = 3;
+ var uint_read = new Uint8Array(size_read * size_read * 4);
+ var start = 0x20;
+ for (var ii = 0; ii < size_read * size_read * 4; ii += 4) {
+ for (var jj = 0; jj < 3; ++jj) {
+ uint_read[ii + jj] = start;
+ }
+ uint_read[ii + 3] = 0xff;
+ start += 0x10;
+ }
+
+ // Create read framebuffer and feed data to read buffer
+ // Read buffer may has srgb image
+ var tex_read = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex_read);
+ gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size_read, size_read, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_read);
+
+ var fbo_read = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0);
+
+ // Initiate data to draw framebuffer
+ var size_draw = 7;
+ var uint_draw = new Uint8Array(size_draw * size_draw * 4);
+ for (var ii = 0; ii < size_draw * size_draw * 4; ii += 4) {
+ for (var jj = 0; jj < 3; ++jj) {
+ uint_draw[ii + jj] = 0x10;
+ }
+ uint_draw[ii + 3] = 0xff;
+ }
+
+ // Create draw framebuffer and feed data to draw buffer
+ // Draw buffer may has srgb image
+ var tex_draw = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex_draw);
+ 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, drawbufferFormat, size_draw, size_draw, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_draw);
+
+ var fbo_draw = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0);
+
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ var ref = [
+ // The reference pixels of the 1st line: (0, 0) ~ (6, 0)
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+
+ // The reference pixels of the 2nd line: (0, 1) ~ (6, 1)
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+
+ // The reference pixels of the 3rd line: (0, 2) ~ (6, 2)
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x20, 0x20, 0x20, 0xff], [0x30, 0x30, 0x30, 0xff],
+ [0x40, 0x40, 0x40, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+
+ // The reference pixels of the 4th line: (0, 3) ~ (6, 3)
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x50, 0x50, 0x50, 0xff], [0x60, 0x60, 0x60, 0xff],
+ [0x70, 0x70, 0x70, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+
+ // The reference pixels of the 5th line: (0, 4) ~ (6, 4)
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x80, 0x80, 0x80, 0xff], [0x90, 0x90, 0x90, 0xff],
+ [0xa0, 0xa0, 0xa0, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+
+ // The reference pixels of the 6th line: (0, 5) ~ (6, 5)
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+
+ // The reference pixels of the 7th line: (0, 6) ~ (6, 6)
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+ [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff],
+ ];
+
+ // The 1st round test: blit read framebuffer to the image in draw framebuffer
+ // All directions of the read region have pixels outside of the read buffer
+ // The src region and/or dst region may be reversed during blitting.
+ var test1 = [
+ [-1, 4, 1, 6], // reverse neither src nor dst
+ [4, -1, 1, 6], // reverse src only
+ [-1, 4, 6, 1], // reverse dst only
+ [4, -1, 6, 1] // reverse both src and dst
+ ];
+
+ var readbufferHasSRGBImage = (readbufferFormat == gl.SRGB8_ALPHA8);
+ var drawbufferHasSRGBImage = (drawbufferFormat == gl.SRGB8_ALPHA8);
+
+ for (var i = 0; i < 4; ++i) {
+ debug("");
+ switch (i) {
+ case 0: debug("reverse neither src region nor dst region"); break;
+ case 1: debug("reverse src region only"); break;
+ case 2: debug("reverse dst region only"); break;
+ case 3: debug("reverse both src region and dst region"); break;
+ }
+ var srcStart = test1[i][0];
+ var srcEnd = test1[i][1];
+ var dstStart = test1[i][2];
+ var dstEnd = test1[i][3];
+ var realBlittedDstStart = 2;
+ var realBlittedDstEnd = 5;
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+ gl.blitFramebuffer(srcStart, srcStart, srcEnd, srcEnd, dstStart, dstStart, dstEnd, dstEnd, gl.COLOR_BUFFER_BIT, gl.LINEAR);
+
+ // Read pixels and check the correctness.
+ var pixels = new Uint8Array(size_draw * size_draw * 4);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw);
+ gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+
+ for (var ii = 0; ii < size_draw; ++ii) {
+ for (var jj = 0; jj < size_draw; ++jj) {
+ var loc = ii * size_draw + jj;
+ var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]];
+
+ // We may need to reverse the reference loc if necessary
+ var ref_loc = loc;
+ var reverse_src = (srcStart < srcEnd);
+ var reverse_dst = (dstStart < dstEnd);
+ var reversed = reverse_src ^ reverse_dst;
+ if (reversed) {
+ ref_loc = (size_draw - ii - 1) * size_draw + (size_draw - jj -1);
+ }
+ var expectedColor = ref[ref_loc];
+
+ // We may need to covert the color space for pixels in blit region
+ if ((readbufferHasSRGBImage ^ drawbufferHasSRGBImage) &&
+ (ii >= realBlittedDstStart && ii < realBlittedDstEnd && jj >= realBlittedDstStart && jj < realBlittedDstEnd)) {
+ if (drawbufferHasSRGBImage) {
+ expectedColor = wtu.linearToSRGB(expectedColor);
+ } else {
+ expectedColor = wtu.sRGBToLinear(expectedColor);
+ }
+ }
+ if (checkPixel(color, expectedColor) == true) {
+ testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!");
+ } else {
+ testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")");
+ }
+ }
+ }
+ }
+
+ // The 2nd round test: blit read framebuffer to the image in draw framebuffer
+ // Only one direction of the read region have pixels outside of the read buffer
+ var tests = [
+ [-1, 0], // pixels are outside the left edge of the read buffer
+ [0, -1], // pixels are outside the bottom edge of the read buffer
+ [1, 0], // pixels are outside the right edge of the read buffer
+ [0, 1] // pixels are outside the top edge of the read buffer
+ ];
+ for (var i = 0; i < 4; ++i) {
+ debug("");
+ switch (i) {
+ case 0: debug("verify that pixels lying outside the left edge of the read buffer should remain untouched"); break;
+ case 1: debug("verify that pixels lying outside the bottom edge of the read buffer should remain untouched"); break;
+ case 2: debug("verify that pixels lying outside the right edge of the read buffer should remain untouched"); break;
+ case 3: debug("verify that pixels lying outside the top edge of the read buffer should remain untouched"); break;
+ }
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+ var srcX = tests[i][0];
+ var srcY = tests[i][1];
+ var offset = dstStart - srcStart;
+ gl.blitFramebuffer(srcX, srcY, srcX + size_read, srcY + size_read,
+ srcX + offset, srcY + offset, srcX + offset + size_read, srcY + offset + size_read,
+ gl.COLOR_BUFFER_BIT, gl.LINEAR);
+
+ // Read pixels and check the correctness.
+ var pixels = new Uint8Array(size_draw * size_draw * 4);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw);
+ gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+ for (var ii = srcY + offset; ii < srcY + offset + size_read; ++ii) {
+ for (var jj = srcX + offset; jj < srcX + offset + size_read; ++jj) {
+ var loc = ii * size_draw + jj;
+ var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]];
+ var expectedColor = ref[loc];
+ // We may need to covert the color space for pixels in blit region
+ if ((readbufferHasSRGBImage ^ drawbufferHasSRGBImage) &&
+ (ii >= realBlittedDstStart && ii < realBlittedDstEnd && jj >= realBlittedDstStart && jj < realBlittedDstEnd)) {
+ if (drawbufferHasSRGBImage) {
+ expectedColor = wtu.linearToSRGB(expectedColor);
+ } else {
+ expectedColor = wtu.sRGBToLinear(expectedColor);
+ }
+ }
+ if (checkPixel(color, expectedColor) == true) {
+ testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!");
+ } else {
+ testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")");
+ }
+ }
+ }
+ }
+ } else {
+ testFailed("framebuffer not complete");
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fbo_read);
+ gl.deleteFramebuffer(fbo_draw);
+ gl.deleteTexture(tex_read);
+ gl.deleteTexture(tex_draw);
+};
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+ blitframebuffer_outside_readbuffer(gl.RGBA8, gl.RGBA8);
+ blitframebuffer_outside_readbuffer(gl.RGBA8, gl.SRGB8_ALPHA8);
+ blitframebuffer_outside_readbuffer(gl.SRGB8_ALPHA8, gl.RGBA8);
+ blitframebuffer_outside_readbuffer(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8);
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-scissor-enabled.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-scissor-enabled.html
new file mode 100644
index 000000000..d1077b9d4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-scissor-enabled.html
@@ -0,0 +1,182 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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/glsl-conformance-test.js"></script>
+</head>
+<body>
+<canvas id="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of blitFramebuffer when scissor test is enabled.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+// Define the src region and dst region for blitFramebuffer
+var blit_src = [0, 0, 4, 4];
+var blit_dst = [2, 2, 6, 6];
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ var bounds = [
+ [0, 0, 4, 4], // Partially intersects with blitFramebuffer's dst region
+ [0, 0, 2, 2], // No intersection with blitFramebuffer's dst region
+ ];
+
+ // We can compute the real drawing area by intersecting the scissor bound with dst region of blitting.
+ var intersections = [
+ [2, 2, 4, 4],
+ [0, 0, 0, 0],
+ ];
+
+ for (var ii = 0; ii < bounds.length; ++ii) {
+ blitframebuffer_scissor(gl.RGBA8, gl.RGBA8, bounds[ii], intersections[ii]);
+ blitframebuffer_scissor(gl.RGBA8, gl.SRGB8_ALPHA8, bounds[ii], intersections[ii]);
+ blitframebuffer_scissor(gl.SRGB8_ALPHA8, gl.RGBA8, bounds[ii], intersections[ii]);
+ blitframebuffer_scissor(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, bounds[ii], intersections[ii]);
+ }
+}
+
+function checkPixel(color, expectedColor) {
+ var tolerance = 3;
+ return (Math.abs(color[0] - expectedColor[0]) <= tolerance &&
+ Math.abs(color[1] - expectedColor[1]) <= tolerance &&
+ Math.abs(color[2] - expectedColor[2]) <= tolerance &&
+ Math.abs(color[3] - expectedColor[3]) <= tolerance);
+}
+
+function blitframebuffer_scissor(readbufferFormat, drawbufferFormat, bound, intersection) {
+ debug("");
+ debug("read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat));
+
+
+ // Initiate data to read framebuffer
+ var size = 8;
+ var data = new Uint8Array(size * size * 4);
+ var color = [250, 100, 15, 255];
+ for (var ii = 0; ii < size * size * 4; ii += 4) {
+ for (var jj = 0; jj < 4; ++jj) {
+ data[ii + jj] = color[jj];
+ }
+ }
+
+ // Feed data to read buffer. Feed 0 to draw buffer.
+ var tex_read = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex_read);
+ gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
+
+ var fbo_read = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0);
+
+ var tex_draw = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex_draw);
+ gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ var fbo_draw = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0);
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+
+ // Enable scissor test. Then blit framebuffer.
+ gl.enable(gl.SCISSOR_TEST);
+ gl.scissor(bound[0], bound[1], bound[2], bound[3]);
+ gl.blitFramebuffer(blit_src[0], blit_src[1], blit_src[2], blit_src[3], blit_dst[0], blit_dst[1], blit_dst[2], blit_dst[3], gl.COLOR_BUFFER_BIT, gl.LINEAR);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitframebuffer should succeed");
+
+ // Read pixels and Comparison
+ var pixels = new Uint8Array(size * size * 4);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw);
+ gl.readPixels(0, 0, size, size, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should succeed");
+
+ var blitColor;
+ var expectedColor;
+ var clearColor = [0, 0, 0, 0];
+
+ if (readbufferFormat == drawbufferFormat) {
+ blitColor = color;
+ } else if (readbufferFormat == gl.SRGB8_ALPHA8) {
+ blitColor = wtu.sRGBToLinear(color);
+ } else {
+ blitColor = wtu.linearToSRGB(color);
+ }
+
+ var failed = false;
+ for (var ii = 0; ii < size; ++ii) {
+ for (var jj = 0; jj < size; ++jj) {
+ if (ii >= intersection[0] && jj >= intersection[1] && ii < intersection[2] && jj < intersection[3]) {
+ expectedColor = blitColor;
+ } else {
+ expectedColor = clearColor;
+ }
+ var index = (ii * size + jj) * 4;
+ var pixelColor = [pixels[index], pixels[index + 1], pixels[index + 2], pixels[index + 3]];
+ if (checkPixel(pixelColor, expectedColor) == false) {
+ failed = true;
+ debug("Pixels comparison failed. Pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + pixelColor + ")");
+ }
+ }
+ }
+ if (failed == false) {
+ testPassed("All pixels comparision passed!");
+ }
+
+ // Deinit
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fbo_read);
+ gl.deleteFramebuffer(fbo_draw);
+ gl.deleteTexture(tex_read);
+ gl.deleteTexture(tex_draw);
+};
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-size-overflow.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-size-overflow.html
new file mode 100644
index 000000000..71e3ab7d9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-size-overflow.html
@@ -0,0 +1,98 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies blitFramebuffer won't cause a crash when the computed sizes might overflow.");
+
+var width = 8;
+var height = 8;
+
+var gl = wtu.create3DContext("example", undefined, 2);
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+ blit_region_test();
+}
+
+function blit_region_test() {
+
+ debug("");
+ debug("Begin to run blitFramebuffer. The computed width/height of src and/or dst region might overflow during blitting.");
+ var tex0 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex0);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ var fb0 = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0);
+
+ var tex1 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ var fb1 = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex1, 0);
+ if ((gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) ||
+ (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+
+ var max = 0x7fffffff;
+ gl.blitFramebuffer(0, 0, max, max, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.blitFramebuffer(0, 0, width, height, 0, 0, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.blitFramebuffer(0, 0, max, max, 0, 0, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+
+ gl.blitFramebuffer(-1, -1, max, max, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.blitFramebuffer(0, 0, width, height, -1, -1, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.blitFramebuffer(-1, -1, max, max, -1, -1, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.blitFramebuffer(-max - 1, -max - 1, max, max, -max - 1, -max - 1, max, max, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ testPassed("Congratulations! blitFramebuffer doesn't cause the browser crash when the computed width/height of src and/or dst region might overflow.");
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html
new file mode 100644
index 000000000..39803416f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html
@@ -0,0 +1,229 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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/glsl-conformance-test.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of blitFramebuffer with multiple draw buffers (srgb image and linear image).");
+
+var gl = wtu.create3DContext("canvas", undefined, 2);
+var linearMask = 1;
+var srgbMask = 2;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ var filters = [gl.LINEAR, gl.NEAREST];
+ var drawbuffersFormats = [linearMask, srgbMask, linearMask | srgbMask];
+ for (var ii = 0; ii < filters.length; ++ii) {
+ for (var jj = 0; jj < drawbuffersFormats.length; ++jj) {
+ blitframebuffer_srgb_and_linear_drawbuffers(gl.SRGB8_ALPHA8, drawbuffersFormats[jj], filters[ii]);
+ blitframebuffer_srgb_and_linear_drawbuffers(gl.RGBA8, drawbuffersFormats[jj], filters[ii]);
+ }
+ }
+}
+
+function blitframebuffer_srgb_and_linear_drawbuffers(readbufferFormat, drawbuffersFormatMask, filter) {
+ debug("");
+ debug("The filter is: " + wtu.glEnumToString(gl, filter));
+ debug("Read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat));
+ var drawbuffersFormat = "\0";
+ if (drawbuffersFormatMask & linearMask) {
+ drawbuffersFormat += " linear ";
+ }
+ if (drawbuffersFormatMask & srgbMask) {
+ drawbuffersFormat += " srgb ";
+ }
+ debug("The test have multiple draw buffers, the images are: " + drawbuffersFormat);
+
+ var tex_srgb0 = gl.createTexture();
+ var tex_srgb1 = gl.createTexture();
+ var tex_linear0 = gl.createTexture();
+ var tex_linear1 = gl.createTexture();
+ var tex_read = gl.createTexture();
+ var fbo_read = gl.createFramebuffer();
+ var fbo_draw = gl.createFramebuffer();
+
+ // Create read buffer and feed data to the read buffer
+ var size = 8;
+ var data = new Uint8Array(size * size * 4);
+ var color = [250, 100, 15, 255];
+ for (var ii = 0; ii < size * size * 4; ii += 4) {
+ for (var jj = 0; jj < 4; ++jj) {
+ data[ii + jj] = color[jj];
+ }
+ }
+ gl.bindTexture(gl.TEXTURE_2D, tex_read);
+ gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup read framebuffer should succeed");
+
+ // Create multiple textures. Attach them as fbo's draw buffers.
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
+
+ var drawbuffers = [gl.NONE, gl.NONE, gl.NONE, gl.NONE];
+ if (drawbuffersFormatMask & srgbMask) {
+ gl.bindTexture(gl.TEXTURE_2D, tex_srgb0);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_srgb0, 0);
+ gl.bindTexture(gl.TEXTURE_2D, tex_srgb1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, tex_srgb1, 0);
+ drawbuffers[0] = gl.COLOR_ATTACHMENT0;
+ drawbuffers[2] = gl.COLOR_ATTACHMENT2;
+ }
+
+ if (drawbuffersFormatMask & linearMask) {
+ gl.bindTexture(gl.TEXTURE_2D, tex_linear0);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex_linear0, 0);
+ gl.bindTexture(gl.TEXTURE_2D, tex_linear1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT3, gl.TEXTURE_2D, tex_linear1, 0);
+ drawbuffers[1] = gl.COLOR_ATTACHMENT1;
+ drawbuffers[3] = gl.COLOR_ATTACHMENT3;
+ }
+
+ gl.drawBuffers(drawbuffers);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup draw framebuffer should succeed");
+
+ if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
+ gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete when setup draw framebuffer.");
+ return;
+ }
+
+ // Blit to multiple draw buffers with srgb images and linear images
+ var dstSize = size - 1;
+ gl.blitFramebuffer(0, 0, size, size, 0, 0, dstSize, dstSize, gl.COLOR_BUFFER_BIT, filter);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitframebuffer should succeed");
+
+ // Read pixels from srgb images and linear images
+ var srgbPixels0 = new Uint8Array(dstSize * dstSize * 4);
+ var srgbPixels1 = new Uint8Array(dstSize * dstSize * 4);
+ var linearPixels0 = new Uint8Array(dstSize * dstSize * 4);
+ var linearPixels1 = new Uint8Array(dstSize * dstSize * 4);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw);
+ if (drawbuffersFormatMask & srgbMask) {
+ gl.readBuffer(gl.COLOR_ATTACHMENT0);
+ gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, srgbPixels0);
+ gl.readBuffer(gl.COLOR_ATTACHMENT2);
+ gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, srgbPixels1);
+ }
+
+ if (drawbuffersFormatMask & linearMask) {
+ gl.readBuffer(gl.COLOR_ATTACHMENT1);
+ gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, linearPixels0);
+ gl.readBuffer(gl.COLOR_ATTACHMENT3);
+ gl.readPixels(0, 0, dstSize, dstSize, gl.RGBA, gl.UNSIGNED_BYTE, linearPixels1);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readpixels should succeed");
+
+ // Compare
+ var expectedSRGBColor = (readbufferFormat == gl.SRGB8_ALPHA8) ? color : wtu.linearToSRGB(color);
+ var expectedLinearColor = (readbufferFormat == gl.SRGB8_ALPHA8) ? wtu.sRGBToLinear(color) : color;
+ var failed = false;
+ for (var ii = 0; ii < dstSize; ++ii) {
+ for (var jj = 0; jj < dstSize; ++jj) {
+ var index = (ii * dstSize + jj) * 4;
+ if (drawbuffersFormatMask & srgbMask) {
+ var srgbColor0 = [srgbPixels0[index], srgbPixels0[index + 1], srgbPixels0[index + 2], srgbPixels0[index + 3]];
+ if (checkPixel(srgbColor0, expectedSRGBColor) == false) {
+ failed = true;
+ debug("Pixels comparison failed for the 1st sRGB image. Pixel at [" + jj + ", " + ii + "] should be (" + expectedSRGBColor + "), but the actual color is (" + srgbColor0 + ")");
+ }
+ var srgbColor1 = [srgbPixels1[index], srgbPixels1[index + 1], srgbPixels1[index + 2], srgbPixels1[index + 3]];
+ if (checkPixel(srgbColor1, expectedSRGBColor) == false) {
+ failed = true;
+ debug("Pixels comparison failed for the 2nd sRGB image. Pixel at [" + jj + ", " + ii + "] should be (" + expectedSRGBColor + "), but the actual color is (" + srgbColor1 + ")");
+ }
+ }
+
+ if (drawbuffersFormatMask & linearMask) {
+ var linearColor0 = [linearPixels0[index], linearPixels0[index + 1], linearPixels0[index + 2], linearPixels0[index + 3]];
+ if (checkPixel(linearColor0, expectedLinearColor) == false) {
+ failed = true;
+ debug("Pixel comparison failed for the 1st linear image. Pixel at [" + jj + ", " + ii + "] should be (" + color + "), but the actual color is (" + linearColor0 + ")");
+ }
+ var linearColor1 = [linearPixels1[index], linearPixels1[index + 1], linearPixels1[index + 2], linearPixels1[index + 3]];
+ if (checkPixel(linearColor1, expectedLinearColor) == false) {
+ failed = true;
+ debug("Pixel comparison failed for the 2nd linear image. Pixel at [" + jj + ", " + ii + "] should be (" + color + "), but the actual color is (" + linearColor1 + ")");
+ }
+ }
+ }
+ }
+ if (failed == false) {
+ testPassed("All pixels comparision passed!");
+ }
+
+ // deinit
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ gl.deleteTexture(tex_srgb0);
+ gl.deleteTexture(tex_linear0);
+ gl.deleteTexture(tex_srgb1);
+ gl.deleteTexture(tex_linear1);
+ gl.deleteTexture(tex_read);
+ gl.deleteFramebuffer(fbo_read);
+ gl.deleteFramebuffer(fbo_draw);
+}
+
+function checkPixel(color, expectedColor) {
+ var tolerance = 3;
+ return (Math.abs(color[0] - expectedColor[0]) <= tolerance &&
+ Math.abs(color[1] - expectedColor[1]) <= tolerance &&
+ Math.abs(color[2] - expectedColor[2]) <= tolerance &&
+ Math.abs(color[3] - expectedColor[3]) <= tolerance);
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-stencil-only.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-stencil-only.html
new file mode 100644
index 000000000..9817b6240
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-stencil-only.html
@@ -0,0 +1,192 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer Stencil-only 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/glsl-conformance-test.js"></script>
+
+<script id="vs" type="x-shader/x-vertex">#version 300 es
+in vec4 position;
+void main() {
+ gl_Position = position;
+}
+</script>
+<script id="fs" type="x-shader/x-fragment">#version 300 es
+out mediump vec4 colorOut;
+uniform mediump vec3 color;
+void main() {
+ colorOut = vec4(color, 1.0);
+}
+</script>
+
+</head>
+<body>
+<canvas id="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test covers some edge cases of blitFramebuffer with stencil.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+var program, colorLoc;
+
+function init_buffer(format) {
+ var buf = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, buf)
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 16, 16);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ var rbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER, format, 16, 16);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER,
+ gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo);
+
+ gl.clearBufferfi(gl.DEPTH_STENCIL, 0, 1.0, 0);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after buffer init");
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ return { fbo: buf, color: tex, depthStencil: rbo };
+}
+
+var quadVB;
+
+function drawQuad(depth) {
+ if (!quadVB) {
+ quadVB = gl.createBuffer()
+ }
+
+ var quadVerts = new Float32Array(3 * 6);
+ quadVerts[0] = -1.0; quadVerts[1] = 1.0; quadVerts[2] = depth;
+ quadVerts[3] = -1.0; quadVerts[4] = -1.0; quadVerts[5] = depth;
+ quadVerts[6] = 1.0; quadVerts[7] = -1.0; quadVerts[8] = depth;
+ quadVerts[9] = -1.0; quadVerts[10] = 1.0; quadVerts[11] = depth;
+ quadVerts[12] = 1.0; quadVerts[13] = -1.0; quadVerts[14] = depth;
+ quadVerts[15] = 1.0; quadVerts[16] = 1.0; quadVerts[17] = depth;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, quadVB);
+ gl.bufferData(gl.ARRAY_BUFFER, quadVerts, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0);
+ gl.enableVertexAttribArray(0);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawQuad");
+}
+
+// Test based on dEQP-GLES3.functional.blit.depth_stencil.depth_24_stencil8_stencil_only
+function test_stencil_only_blit(format) {
+ debug("testing format: " + wtu.glEnumToString(format))
+
+ var src = init_buffer(format);
+ var dest = init_buffer(format);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, src.fbo);
+ gl.viewport(0, 0, 16, 16);
+
+ // Fill source with red, depth = 0.5, stencil = 7
+ gl.enable(gl.DEPTH_TEST);
+ gl.enable(gl.STENCIL_TEST);
+ gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
+ gl.stencilFunc(gl.ALWAYS, 7, 0xFF);
+ gl.uniform3f(colorLoc, 1.0, 0.0, 0.0);
+ drawQuad(0.5);
+
+ // Fill dest with yellow, depth = 0.0, stencil = 1
+ gl.bindFramebuffer(gl.FRAMEBUFFER, dest.fbo);
+ gl.stencilFunc(gl.ALWAYS, 1, 0xff);
+ gl.uniform3f(colorLoc, 1.0, 1.0, 0.0);
+ drawQuad(0.0);
+
+ // Perform copy.
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, src.fbo);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, dest.fbo);
+ gl.blitFramebuffer(0, 0, 16, 16, 0, 0, 16, 16, gl.STENCIL_BUFFER_BIT, gl.NEAREST);
+
+ // Render blue where depth < 0, decrement on depth failure.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, dest.fbo);
+ gl.stencilOp(gl.KEEP, gl.DECR, gl.KEEP);
+ gl.stencilFunc(gl.ALWAYS, 0, 0xff);
+
+ gl.uniform3f(colorLoc, 0.0, 0.0, 1.0);
+ drawQuad(0.0);
+
+ // Render green where stencil == 6.
+ gl.disable(gl.DEPTH_TEST);
+ gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
+ gl.stencilFunc(gl.EQUAL, 6, 0xff);
+
+ gl.uniform3f(colorLoc, 0.0, 1.0, 0.0);
+ drawQuad(0.0);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after test");
+ wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0, 255, 0, 255],
+ "stencil test should be green");
+
+ gl.deleteFramebuffer(src.fbo);
+ gl.deleteFramebuffer(dest.fbo);
+ gl.deleteTexture(src.color);
+ gl.deleteTexture(dest.color);
+ gl.deleteRenderbuffer(src.depthStencil);
+ gl.deleteRenderbuffer(dest.depthStencil);
+}
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ program = wtu.setupProgram(gl, ["vs", "fs"], ["position"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after program initialization");
+ shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)', 'true');
+
+ colorLoc = gl.getUniformLocation(program, "color")
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "query uniform location");
+ shouldBeNonNull('colorLoc')
+
+ test_stencil_only_blit(gl.DEPTH24_STENCIL8);
+ test_stencil_only_blit(gl.DEPTH32F_STENCIL8);
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-test.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-test.html
new file mode 100644
index 000000000..0322abac3
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-test.html
@@ -0,0 +1,342 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL BlitFramebuffer 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="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of blitFramebuffer for some corner cases.");
+
+var width = 8;
+var height = 8;
+
+var gl = wtu.create3DContext("example", undefined, 2);
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+ blit_framebuffer_feedback_loop();
+ blit_framebuffer_multisampling_srgb();
+}
+
+
+function blit_framebuffer_feedback_loop() {
+
+ debug("");
+ debug("This test vefify that whether the src resource and dst resource have identical image.");
+ // Create read fbo and its color attachment.
+ var tex_2d = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex_2d);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.generateMipmap(gl.TEXTURE_2D);
+
+ var fb0 = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 0);
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+
+ // Create draw fbo and its color attachment.
+ var rb0 = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb0);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, width, height);
+
+ var fb1 = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0);
+ if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+
+ // Blit framebuffer, all conditions are OK.
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed.");
+
+ // Blit framebuffer, the src buffer and the dst buffer should not be identical.
+ // Exactly the same read/draw fbo
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb0);
+ gl.blitFramebuffer(0, 0, 2, 2, 4, 4, 6, 6, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw buffer are identical.");
+
+ // Exactly the same read/draw framebuffer: default framebuffer
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ gl.blitFramebuffer(0, 0, 2, 2, 4, 4, 6, 6, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw buffer are identical.");
+
+ // The same image with the same level bound to read/draw buffer.
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 0);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 0);
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
+ gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 4, 4, 6, 6, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw color buffer are identical.");
+
+ // The same image in read/draw buffer, but different levels are bound to read/draw buffer respectively.
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_2d, 1);
+ if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed if read/draw buffer has the same image with different levels.");
+
+ // The same cube_map image in read/draw buffer, but different faces are bound to read/draw buffer respectively.
+ var tex_cube_map = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex_cube_map);
+ gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, tex_cube_map, 0);
+ if ((gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) ||
+ (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed if read/draw buffer has the same CUBE_MAP image with different faces.");
+
+ // The same 3D/2D_ARRAY image in read/draw buffer, but different layers are bound to read/draw buffer respectively.
+ var tex_2d_array = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex_2d_array);
+ var depth = 2;
+ gl.texImage3D(gl.TEXTURE_2D_ARRAY, 0, gl.RGBA8, width, height, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ var level = 0, layer = 0;
+ gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex_2d_array, level, layer);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ layer = 1;
+ gl.framebufferTextureLayer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex_2d_array, level, layer);
+ if ((gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) ||
+ (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed if read/draw buffer has the same 3D/2D_ARRAY image with different layers.");
+
+ // The same image are bound as depth buffer in both read framebuffer and draw framebuffer
+ var rb1 = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb1);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0);
+ gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb1);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, tex_cube_map, 0);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb1);
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
+ gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ // But the mask doesn't have depth buffer bit.
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed.");
+
+ // The mask has depth buffer bit.
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw framebuffer have identical depth buffer attachment.");
+
+ // The same image are bound as stencil buffer in both read framebuffer and draw framebuffer
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb1);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb1);
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
+ gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ // But the mask doesn't have stencil buffer bit.
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed.");
+
+ // The mask has stencil buffer bit.
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw framebuffer have identical stencil buffer attachment.");
+
+ // The same image are bound as color buffer in both read framebuffer and draw framebuffer
+ var rb2 = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb2);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0);
+ gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
+ gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb2);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, tex_cube_map, 0);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex_cube_map, 0);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb1);
+ if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
+ gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ // But the mask doesn't have color buffer bit.
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.DEPTH_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed.");
+
+ // The mask has color buffer bit, but the same image is not specified as draw buffer.
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer should succeed.");
+
+ // The mask has color buffer bit, the same image is specified as both read buffer and draw buffer.
+ gl.drawBuffers([gl.COLOR_ATTACHENT0, gl.COLOR_ATTACHMENT1]);
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT, gl.NEAREST);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer should generate INVALID_OPERATION if read/draw buffers have identical color buffer attachment.");
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ gl.deleteTexture(tex_2d);
+ gl.deleteTexture(tex_cube_map);
+ gl.deleteTexture(tex_2d_array);
+ gl.deleteRenderbuffer(rb0);
+ gl.deleteRenderbuffer(rb1);
+ gl.deleteRenderbuffer(rb2);
+ gl.deleteFramebuffer(fb0);
+ gl.deleteFramebuffer(fb1);
+};
+
+function blit_framebuffer_multisampling_srgb() {
+
+ debug("");
+ debug("This test vefify the functionality of blitframebuffer from or to a multisampled srgb image.");
+
+ // Read buffer can have multisampled srgb image, but draw buffers can not.
+ var rb0 = gl.createRenderbuffer();
+ var fb0 = gl.createFramebuffer();
+ var rb1 = gl.createRenderbuffer();
+ var fb1 = gl.createFramebuffer();
+ var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.SRGB8_ALPHA8, gl.SAMPLES);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb0);
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl.SRGB8_ALPHA8, width, height);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb0);
+ gl.framebufferRenderbuffer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0);
+
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb1);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.SRGB8_ALPHA8, width, height);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb1);
+ if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
+ gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.LINEAR);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "blitFramebuffer from multisampled srgb image should succeed.");
+
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb1);
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl.SRGB8_ALPHA8, width, height);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb1);
+ if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.LINEAR);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer to a multisampled srgb image should generate INVALID_OPERATION.");
+
+ // BlitFramebuffer from a multisampled srgb image, the src region and the dst region must be exactly the same.
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb1);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.SRGB8_ALPHA8, width, height);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb1);
+ if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 2, 2, 4, 4, gl.COLOR_BUFFER_BIT, gl.LINEAR);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer from a multisampled srgb image, the src region and the dst region must be exactly the same.");
+
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 4, 4, gl.COLOR_BUFFER_BIT, gl.LINEAR);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer from a multisampled srgb image, the src region and the dst region must be exactly the same.");
+
+ // BlitFramebuffer from a multisampled srgb image, the format/type must be exactly the same. So blit from a multisampled srgb image to a linear image is invalid.
+ 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.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb1);
+ gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ if (gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+ gl.blitFramebuffer(0, 0, 2, 2, 0, 0, 2, 2, gl.COLOR_BUFFER_BIT, gl.LINEAR);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blitFramebuffer from a multisampled srgb image, the format/type must be exactly the same.");
+
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ gl.deleteRenderbuffer(rb0);
+ gl.deleteRenderbuffer(rb1);
+ gl.deleteTexture(tex);
+ gl.deleteFramebuffer(fb0);
+ gl.deleteFramebuffer(fb1);
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html
new file mode 100644
index 000000000..e09a4473a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html
@@ -0,0 +1,130 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL 2 Resizing With PBO Bound 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="canvas1" style="width: 256px; height: 256px;"> </canvas>
+<canvas id="canvas2" style="width: 256px; height: 256px;"> </canvas>
+<div id="console"></div>
+<script>
+"use strict";
+
+description("Verifies that resizing the canvas (recreating the backing framebuffer) works correctly while a PBO is bound.");
+
+debug("");
+debug("Regression test for Chromium <a href='https://bugs.chromium.org/p/chromium/issues/detail?id=644572'>Issue 644572</a>");
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas;
+var largeSize = 256;
+var smallSize = 128;
+var currentSize;
+var gl;
+var numFrames = 0;
+var testNumber = 0;
+var pbo;
+
+function nextTest() {
+ ++testNumber;
+ numFrames = 0;
+ currentSize = largeSize;
+ if (testNumber > 2) {
+ finishTest();
+ return;
+ }
+
+ canvas = document.getElementById("canvas" + testNumber);
+ canvas.width = currentSize;
+ canvas.height = currentSize;
+ var usePreserveDrawingBuffer = (testNumber == 1) ? true : false;
+ debug("Testing preserveDrawingBuffer = " + usePreserveDrawingBuffer);
+ gl = wtu.create3DContext(canvas, { preserveDrawingBuffer: usePreserveDrawingBuffer }, 2);
+
+ if (!gl) {
+ testFailed("context does not exist");
+ } else {
+ testPassed("context exists");
+
+ gl.clearColor(0, 1, 0, 1);
+
+ pbo = gl.createBuffer();
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo);
+
+ wtu.requestAnimFrame(render);
+ }
+}
+
+function render() {
+ if (++numFrames < 4) {
+ if (currentSize == largeSize) {
+ canvas.height = smallSize;
+ currentSize = smallSize;
+ } else {
+ canvas.height = largeSize;
+ currentSize = largeSize;
+ }
+ }
+
+ gl.viewport(0, 0, largeSize, currentSize);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ // Check the four corners
+ var green = [ 0, 255, 0, 255 ];
+ var inset = 3;
+ wtu.checkCanvasRect(gl, inset, inset, 1, 1, green, "lower left should be green", 1);
+ wtu.checkCanvasRect(gl, largeSize - inset, inset, 1, 1, green, "lower right should be green", 1);
+ wtu.checkCanvasRect(gl, inset, currentSize - inset, 1, 1, green, "upper left should be green", 1);
+ wtu.checkCanvasRect(gl, largeSize - inset, currentSize - inset, 1, 1, green, "upper right should be green", 1);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error");
+ if (gl.getParameter(gl.PIXEL_UNPACK_BUFFER_BINDING) != pbo) {
+ testFailed("Pixel unpack buffer binding was lost");
+ }
+
+ if (numFrames < 4) {
+ wtu.requestAnimFrame(render);
+ } else {
+ wtu.requestAnimFrame(nextTest);
+ }
+}
+
+wtu.requestAnimFrame(nextTest);
+
+</script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-func-buffer-type-match.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-func-buffer-type-match.html
new file mode 100644
index 000000000..ac16ea251
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-func-buffer-type-match.html
@@ -0,0 +1,166 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test clear and clearBuffer functions have to match fbo's buffer format</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>
+"use strict";
+description("This tests the WebGL2 specific constraint that clear or clearBuffer* functions have to be compatible with fbo's buffer format");
+
+var setupRenderbuffer = function(attachment, format) {
+ var renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, format, canvas.width, canvas.height);
+ return renderbuffer;
+}
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, undefined, 2);
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ var fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+
+ debug("");
+ debug("Signed integer buffer");
+
+ var colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0, gl.RGBA8);
+ var colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1, gl.RGBA32I);
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clear and INT buffer");
+
+ gl.clearBufferfv(gl.COLOR, 1, new Float32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferfv and INT buffer");
+
+ gl.clearBufferuiv(gl.COLOR, 1, new Uint32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferuiv and INT buffer");
+
+ debug("Set up draw buffer so INT buffer is set to NONE");
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clear and INT buffer is NONE");
+
+ gl.clearBufferfv(gl.COLOR, 1, new Float32Array(4));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv and INT buffer is NONE");
+
+ gl.clearBufferuiv(gl.COLOR, 1, new Uint32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferuiv and float buffer");
+
+ debug("");
+ debug("Unsigned integer buffer");
+
+ colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0, gl.RGBA32UI);
+ colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1, gl.RGBA8);
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clear and UINT buffer");
+
+ gl.clearBufferfv(gl.COLOR, 0, new Float32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferfv and UINT buffer");
+
+ gl.clearBufferiv(gl.COLOR, 0, new Int32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferiv and UINT buffer");
+
+ debug("Set up draw buffer so INT buffer is set to NONE");
+ gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1]);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clear and UINT buffer is NONE");
+
+ gl.clearBufferfv(gl.COLOR, 0, new Float32Array(4));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv and UINT buffer is NONE");
+
+ gl.clearBufferiv(gl.COLOR, 0, new Int32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferiv and float buffer");
+
+ debug("");
+ debug("Float buffer");
+
+ colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0, gl.RGBA8);
+ var numAttachments = 1;
+ var ext = gl.getExtension("EXT_color_buffer_float");
+ var bufferType = "float buffer";
+ if (ext) {
+ debug("EXT_color_buffer_float is available: testing RGBA8 + RGBA32F");
+ colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1, gl.RGBA32F);
+ ++numAttachments;
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
+ } else {
+ debug("EXT_color_buffer_float is unavailable: testing RGBA8");
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
+ bufferType = "RGBA8 buffer";
+ }
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clear and " + bufferType);
+
+ for (var ii = 0; ii < numAttachments; ++ii) {
+ gl.clearBufferfv(gl.COLOR, ii, new Float32Array(4));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv and " + bufferType);
+
+ gl.clearBufferiv(gl.COLOR, ii, new Int32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferiv and " + bufferType);
+
+ gl.clearBufferuiv(gl.COLOR, ii, new Uint32Array(4));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "clearBufferuiv and " + bufferType);
+ }
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteRenderbuffer(colorbuffer);
+ gl.deleteRenderbuffer(colorbuffer1);
+}
+
+debug("");
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no error");
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-srgb-color-buffer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-srgb-color-buffer.html
new file mode 100644
index 000000000..b721a5d5f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clear-srgb-color-buffer.html
@@ -0,0 +1,109 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Clear sRGB Color 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>
+<script src="../../js/glsl-conformance-test.js"></script>
+</head>
+<body>
+<canvas id="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of clearing srgb color buffer.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+var tex = gl.createTexture();
+var fbo = gl.createFramebuffer();
+var size = 8;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Create a srgb color buffer
+ init();
+
+ clear_srgb_color_buffer(0);
+ clear_srgb_color_buffer(1);
+}
+
+function init() {
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ } else {
+ testPassed("framebuffer complete!");
+ }
+}
+
+function clear_srgb_color_buffer(iter) {
+ debug("");
+ debug("Clear sRGB color buffer through glClear or glClearBufferfv");
+
+ var color = [0x33, 0x88, 0xbb, 0xff];
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+
+ if (iter == 0) {
+ gl.clearColor(color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ } else {
+ var data = new Float32Array([color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255]);
+ gl.clearBufferfv(gl.COLOR, 0, data);
+ }
+
+ var color_ref = wtu.linearToSRGB(color);
+ wtu.checkCanvasRect(gl, 0, 0, size, size, color_ref);
+}
+
+gl.bindTexture(gl.TEXTURE_2D, null);
+gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+gl.deleteTexture(tex);
+gl.deleteFramebuffer(fbo);
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clipping-wide-points.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clipping-wide-points.html
new file mode 100644
index 000000000..8ca5305ec
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/clipping-wide-points.html
@@ -0,0 +1,47 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<title>Clipping wide points test</title>
+<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="testbed" width="1" height="1"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+var contextVersion = 2;
+</script>
+<script src="../../js/tests/clipping-wide-points.js"></script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html
new file mode 100644
index 000000000..b09491b6b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html
@@ -0,0 +1,581 @@
+<!--
+
+/*
+** Copyright (c) 2013 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>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>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="64" height="64"> </canvas>
+<div id="console"></div>
+<script id="vshaderESSL3" type="x-shader/x-vertex">#version 300 es
+in vec4 a_position;
+void main() {
+ gl_Position = a_position;
+}
+</script>
+<script id="vshaderESSL1" type="x-shader/x-vertex">
+attribute vec4 a_position;
+void main() {
+ gl_Position = a_position;
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+uniform vec4 u_colors[$(numDrawingBuffers)];
+
+// Only one out variable - does not need explicit output layout (ESSL 3 section 4.3.8.2)
+out vec4 my_FragData[$(numDrawingBuffers)];
+void main() {
+$(assignUColorsToFragData)
+}
+</script>
+<script id="fshaderRed" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+
+out vec4 my_FragColor;
+void main() {
+ my_FragColor = vec4(1, 0, 0, 1);
+}
+</script>
+<script id="fshaderBlueESSL1" type="x-shader/x-fragment">
+precision mediump float;
+
+void main() {
+ gl_FragColor = vec4(0, 0, 1, 1);
+}
+</script>
+<script id="fshaderBuiltInConstEnabled" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+
+out vec4 my_FragColor;
+void main() {
+ my_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 Multiple Render Targets.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var output = document.getElementById("console");
+var gl = wtu.create3DContext(canvas, null, 2);
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ if (testParameters()) {
+ runShadersTest();
+ runAttachmentTest();
+ runDrawTests();
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function createDrawBuffersProgram(scriptId, sub) {
+ var fsource = wtu.getScript(scriptId);
+ fsource = wtu.replaceParams(fsource, sub);
+ wtu.addShaderSource(output, "fragment shader", fsource);
+ return wtu.setupProgram(gl, ["vshaderESSL3", fsource], ["a_position"]);
+}
+
+function runShadersTest() {
+ debug("");
+ debug("test shaders");
+
+ var sub = {numDrawingBuffers: gl.getParameter(gl.MAX_DRAW_BUFFERS)};
+ var program = createDrawBuffersProgram("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");
+}
+
+function makeArray(size, value) {
+ var array = []
+ for (var ii = 0; ii < size; ++ii) {
+ array.push(value);
+ }
+ return array;
+}
+
+function makeColorAttachmentArray(size) {
+ var array = []
+ for (var ii = 0; ii < size; ++ii) {
+ array.push(gl.COLOR_ATTACHMENT0 + ii);
+ }
+ return array;
+}
+
+function runAttachmentTest() {
+ debug("");
+ debug("test attachment enabled");
+
+ var maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
+ var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+
+ 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));
+ gl.drawBuffers(makeArray(maxDrawingBuffers, gl.NONE));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with array NONE of size " + maxColorAttachments);
+ var bufs = makeColorAttachmentArray(maxDrawingBuffers);
+ gl.drawBuffers(bufs);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with array attachments of size " + maxColorAttachments);
+ bufs[0] = gl.NONE;
+ gl.drawBuffers(bufs);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers with mixed array attachments of size " + maxColorAttachments);
+ if (maxDrawingBuffers > 1) {
+ bufs[0] = gl.COLOR_ATTACHMENT1;
+ bufs[1] = gl.COLOR_ATTACHMENT0;
+ gl.drawBuffers(bufs);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be able to call drawBuffers with out of order attachments of size " + maxColorAttachments);
+ var bufs = makeColorAttachmentArray(Math.floor(maxDrawingBuffers / 2));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffers 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(gl.MAX_DRAW_BUFFERS);
+ var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+ var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
+ var maxUsable = Math.min(maxDrawingBuffers, maxColorAttachments, maxUniformVectors);
+ var half = Math.floor(maxUsable / 2);
+ var bufs = makeColorAttachmentArray(maxUsable);
+ var nones = makeArray(maxUsable, gl.NONE);
+
+ [fb, fb2, halfFB1, halfFB2, endsFB, middleFB].forEach(function(fbo) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.drawBuffers(bufs);
+ });
+
+ var checkProgram = wtu.setupTexturedQuad(gl);
+ var redProgram = wtu.setupProgram(gl, ["vshaderESSL3", "fshaderRed"], ["a_position"]);
+ var blueProgramESSL1 = wtu.setupProgram(gl, ["vshaderESSL1", "fshaderBlueESSL1"], ["a_position"]);
+
+ var assignCode = [];
+ for (var i = 0; i < maxDrawingBuffers; ++i) {
+ assignCode.push(" my_FragData[" + i + "] = u_colors[" + i + "];");
+ }
+
+ var drawProgram = createDrawBuffersProgram("fshader",
+ {numDrawingBuffers: maxDrawingBuffers, assignUColorsToFragData: assignCode.join("\n")});
+ 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,
+ location: location,
+ 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 checkAttachmentsForColorFn = function(attachments, colorFn) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.useProgram(checkProgram);
+ attachments.forEach(function(attachment, index) {
+ gl.bindTexture(gl.TEXTURE_2D, attachment.texture);
+ wtu.clearAndDrawUnitQuad(gl);
+ var expectedColor = colorFn(attachment, index);
+ var tolerance = 0;
+ expectedColor.forEach(function(v) {
+ if (v != 0 && v != 255) {
+ tolerance = 8;
+ }
+ });
+ wtu.checkCanvas(gl, expectedColor, "attachment " + index + " should be " + expectedColor.toString(), tolerance);
+ });
+ debug("");
+ };
+
+ var checkAttachmentsForColor = function(attachments, color) {
+ checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return color || attachment.color;
+ });
+ };
+
+ 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(gl.DRAW_BUFFER0 + 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);
+ //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);
+ 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);
+
+ checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return testFn(attachment, index) ? attachment.color : [0, 0, 0, 0];
+ });
+ };
+
+ gl.useProgram(drawProgram);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ gl.drawBuffers(bufs);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.drawBuffers(bufs);
+
+ wtu.drawUnitQuad(gl);
+
+ debug("test that each texture got the correct color.");
+
+ 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);
+
+ checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
+
+ debug("test that NONE draws nothing");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.drawBuffers(nones);
+ gl.useProgram(redProgram);
+ wtu.clearAndDrawUnitQuad(gl);
+
+ checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
+
+ // GLES3 spec section 3.9.2 Shader Outputs
+ debug("test that gl_FragColor only writes to color number zero");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.drawBuffers(bufs);
+ gl.useProgram(blueProgramESSL1);
+ wtu.drawUnitQuad(gl);
+
+ checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return (index == 0) ? [0, 0, 255, 255] : [0, 255, 0, 255];
+ });
+
+ // If there is only a single output, the location defaults to zero if not specified.
+ // See GLSL ES Spec 3.00.4, Section 4.3.8.2, Output Layout Qualifiers.
+ debug("test that an OpenGL ES Shading Language 3.00 shader with a single output color defaults to color number zero");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.drawBuffers(bufs);
+ gl.useProgram(redProgram);
+ wtu.drawUnitQuad(gl);
+
+ checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return (index == 0) ? [255, 0, 0, 255] : [0, 255, 0, 255];
+ });
+
+ if (maxUsable > 1) {
+ // Prepare for following tests by clearing all attachments to red.
+ debug("prepare by clearing all attachments to red");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.drawBuffers(bufs);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
+
+ var bufs1 = makeColorAttachmentArray(maxUsable);
+ var bufs2 = makeColorAttachmentArray(maxUsable);
+ for (var ii = 0; ii < maxUsable; ++ii) {
+ if (ii < half) {
+ bufs1[ii] = gl.NONE;
+ } else {
+ bufs2[ii] = gl.NONE;
+ }
+ }
+
+ debug("test setting first half to NONE and clearing");
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.drawBuffers(bufs1);
+ gl.clearColor(0, 1, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ 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);
+
+ 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);
+ gl.drawBuffers(bufs);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawBuffers(bufs2);
+ gl.clearColor(0, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ 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);
+
+ checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return index < half ? attachment.color : [255, 0, 0, 255];
+ });
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB1);
+ gl.drawBuffers(bufs);
+ drawAndCheckAttachments(
+ halfFB1, "framebuffer that only has first half of attachments",
+ function(attachment, index) {
+ return index < half;
+ });
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB2);
+ gl.drawBuffers(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);
+ gl.drawBuffers(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);
+ gl.drawBuffers(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 keeps drawbuffer state");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ gl.drawBuffers(nones);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.drawBuffers(bufs);
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ gl.useProgram(drawProgram);
+ wtu.drawUnitQuad(gl);
+ checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.useProgram(drawProgram);
+ wtu.drawUnitQuad(gl);
+ 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(gl.DRAW_BUFFER0 + " + 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(gl.DRAW_BUFFER0 + " + ii + ")", "gl.NONE");
+ }
+
+ // WebGL generates FRAMEBUFFER_INCOMPLETE_DIMENSIONS when attached images have different sizes.
+ // This behavior differs from GLES 3.
+ 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_INCOMPLETE_DIMENSIONS");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
+
+ // TODO: Rendering when framebuffer attachments have mismatched size should be tested, maybe in a separate test.
+
+ 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(drawProgram);
+}
+
+function testParameters() {
+ debug("");
+ debug("check that MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS are valid");
+ var maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
+ var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+ debug("MAX_DRAW_BUFFERS = " + maxDrawBuffers);
+ debug("MAX_COLOR_ATTACHMENTS = " + maxColorAttachments);
+ if (maxDrawBuffers != maxColorAttachments) {
+ testFailed("MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS should be the same");
+ return false;
+ }
+ if (maxDrawBuffers < 4) {
+ testFailed("MAX_DRAW_BUFFERS should be at least 4");
+ return false;
+ }
+ return true;
+}
+
+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/rendering/element-index-uint.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/element-index-uint.html
new file mode 100644
index 000000000..f19529022
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/element-index-uint.html
@@ -0,0 +1,426 @@
+<!--
+
+/*
+** Copyright (c) 2013 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Uint element indices 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 Uint element indices.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var gl = 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, null, 2);
+
+ 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"));
+
+ 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 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.setupNoTexCoordTextureProgram(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 readLocation(x, y) {
+ var pixels = new Uint8Array(1 * 1 * 4);
+ gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+ return pixels;
+ };
+ function testPixel(blackList, whiteList) {
+ 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;
+ var source = readLocation(x, y);
+ if (Math.abs(source[0] - expected) > 2) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return testList(blackList, 0) && testList(whiteList, 255);
+ };
+ function verifyDraw(drawNumber, s) {
+ gl.clearColor(1.0, 1.0, 1.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
+
+ var blackList = [];
+ var whiteList = [];
+ 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) {
+ blackList.push(points[n]);
+ } else {
+ whiteList.push(points[n]);
+ }
+ }
+ if (testPixel(blackList, whiteList)) {
+ testPassed("Draw " + drawNumber + " passed pixel test");
+ } else {
+ testFailed("Draw " + drawNumber + " failed pixel test");
+ }
+ };
+
+ setupDraw(0.5);
+ verifyDraw(0, 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);
+ shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
+
+ 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)");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "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, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "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)");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "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/conformance2/rendering/framebuffer-completeness-unaffected.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-completeness-unaffected.html
new file mode 100644
index 000000000..f614607f8
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-completeness-unaffected.html
@@ -0,0 +1,113 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test drawBuffers, readBuffer, and fbo completeness</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>
+// In MacOSX, if drawBuffers() and readBuffer() both select an attachment with no image attached,
+// fbo becomes incomplete. However, drawBuffers() and readBuffer() should not affect fbo completeness.
+
+"use strict";
+description("This tests drawBuffers, readBuffer, and fbo completeness");
+
+var setupRenderbuffer = function(attachment) {
+ var renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, canvas.width, canvas.height);
+ return renderbuffer;
+}
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, undefined, 2);
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ var fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+
+ debug("fbo with two color images attached should be complete");
+ var colorbuffer = setupRenderbuffer(gl.COLOR_ATTACHMENT0);
+ var colorbuffer1 = setupRenderbuffer(gl.COLOR_ATTACHMENT1);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ debug("drawBuffers selects ATTACHMENT1, fbo should be complete");
+ gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1]);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ debug("remove image attached to ATTACHMENT1, fbo should be complete");
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, null);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ // Setting of GL_READ_BUFFER and GL_DRAW_BUFFERs affects framebuffer completeness on Mac Intel.
+ // Chromium bug: crbug.com/630800
+ // Apple Radar: 28236629
+ //debug("set read buffer to ATTACHMENT1, fbo should be complete");
+ //gl.readBuffer(gl.COLOR_ATTACHMENT1);
+ //shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ debug("drawBuffers selects ATTACHMENT0, fbo should be complete");
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ debug("drawBuffers selects ATTACHMENT1, fbo should be complete");
+ gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1]);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ debug("set read buffer to ATTACHMENT0, fbo should be complete");
+ gl.readBuffer(gl.COLOR_ATTACHMENT0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteRenderbuffer(colorbuffer);
+ gl.deleteRenderbuffer(colorbuffer1);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no error after setup and clear render buffer");
+}
+
+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/rendering/framebuffer-unsupported.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-unsupported.html
new file mode 100644
index 000000000..2188ab0fc
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-unsupported.html
@@ -0,0 +1,155 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL 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");
+
+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();
+ var fb = gl.createFramebuffer();
+ 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, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex1, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex2, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, tex1, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fb);
+ fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ 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, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, texCube, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, texCube, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_CUBE_MAP_POSITIVE_X, texCube, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]);
+
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fb);
+ fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ var tex3d = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_3D, tex3d);
+ gl.texImage3D(gl.TEXTURE_3D,
+ 0, // level
+ gl.RGBA, // internalFormat
+ 2, // width
+ 2, // height
+ 2, // depth
+ 0, // border
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ new Uint8Array(4 * 2 * 2 * 2)); // data
+ gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex3d, 0, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, tex3d, 0, 1);
+ checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]);
+ gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, tex3d, 0, 0);
+ checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]);
+
+ // Clean up
+ gl.deleteTexture(tex1);
+ gl.deleteTexture(tex2);
+ gl.deleteTexture(texCube);
+ gl.deleteTexture(tex3d);
+ gl.deleteFramebuffer(fb);
+}
+
+description("This tests FRAMEBUFFER_UNSUPPORTED.");
+
+shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, 2)");
+
+testImageAttachedTwoPoints();
+
+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/rendering/fs-color-type-mismatch-color-buffer-type.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html
new file mode 100644
index 000000000..19eb6ff82
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html
@@ -0,0 +1,190 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>The Color Types of Fragment Shader's Outputs Should Match The Data Types of Color Buffers</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="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script id="vshader" type="x-shader/x-vertex">#version 300 es
+in highp vec4 aPosition;
+void main() {
+ gl_Position = aPosition;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+out vec4 oColor;
+void main() {
+ oColor = vec4(1.0, 0.0, 0.0, 0.0);
+}
+</script>
+
+<script id="fshaderMRT" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+out vec4 oColor[2];
+void main() {
+ oColor[0] = vec4(1.0, 0.0, 0.0, 0.0);
+}
+</script>
+
+<script id="fshaderRealMRT" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+out vec4 oColor[2];
+void main() {
+ oColor[0] = vec4(1.0, 0.0, 0.0, 0.0);
+ oColor[1] = vec4(0.0, 1.0, 0.0, 0.0);
+}
+</script>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies that the color types of fragment shader's outputs should match color buffers' types.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+var width = 8;
+var height = 8;
+var tex0;
+var tex1;
+var rb0;
+var rb1;
+var fbo = gl.createFramebuffer();
+var program0;
+var program1;
+var program2;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ init();
+
+ // COLOR_ATTACHMENT0 is fixed-point data, which can be converted to float.
+ // COLOR_ATTACHMENT1 is integer data. The fragment outputs are all float.
+ allocate_textures();
+ check_type_match();
+ allocate_renderbuffers();
+ check_type_match();
+}
+
+function check_type_match() {
+ gl.useProgram(program0);
+ rendering([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR);
+ rendering([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.NO_ERROR);
+
+ gl.useProgram(program1);
+ rendering([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR);
+ rendering([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION);
+
+ gl.useProgram(program2);
+ rendering([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR);
+ rendering([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION);
+}
+
+function init() {
+ program0 = wtu.setupProgram(gl, ['vshader', 'fshader'], ['aPosition'], [0]);
+ program1 = wtu.setupProgram(gl, ['vshader', 'fshaderMRT'], ['aPosition'], [0]);
+ program2 = wtu.setupProgram(gl, ['vshader', 'fshaderRealMRT'], ['aPosition'], [0]);
+ if (!program0 || !program1 || !program2) {
+ testFailed("Failed to set up program");
+ return;
+ }
+ testPassed("Succeed to set up program");
+
+ wtu.setupUnitQuad(gl, 0, 1);
+ gl.viewport(0, 0, width, height);
+}
+
+function allocate_textures() {
+ tex0 = gl.createTexture();
+ tex1 = gl.createTexture();
+ wtu.fillTexture(gl, tex0, width, height, [0xff, 0x0, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA);
+ wtu.fillTexture(gl, tex1, width, height, [0x0, 0xff, 0x0, 0xff], 0, gl.RGBA_INTEGER, gl.UNSIGNED_BYTE, gl.RGBA8UI);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex1, 0);
+}
+
+function allocate_renderbuffers() {
+ rb0 = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb0);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, width, height);
+ rb1 = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb1);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8UI, width, height);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1);
+}
+
+function rendering(draw_buffers, error) {
+ gl.drawBuffers(draw_buffers);
+
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+
+ wtu.drawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, error, "If color buffers' type mismatch the type of fragment shader's outputs, geneate INVALID_OPERATION. Otherwise, it should be NO_ERROR");
+}
+
+gl.bindTexture(gl.TEXTURE_2D, null);
+gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+gl.useProgram(null);
+gl.deleteTexture(tex0);
+gl.deleteTexture(tex1);
+gl.deleteRenderbuffer(rb0);
+gl.deleteRenderbuffer(rb1);
+gl.deleteFramebuffer(fbo);
+gl.deleteProgram(program0);
+gl.deleteProgram(program1);
+gl.deleteProgram(program2);
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-arrays.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-arrays.html
new file mode 100644
index 000000000..dee7b387f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-arrays.html
@@ -0,0 +1,242 @@
+<!--
+
+/*
+** Copyright (c) 2013 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL 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>
+</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>
+"use strict";
+description("This test verifies the functionality of Instanced Arrays.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, 2);
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ runDivisorTest();
+ runOutputTests();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runDivisorTest() {
+ debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR");
+
+ shouldBe("gl.VERTEX_ATTRIB_ARRAY_DIVISOR", "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, gl.VERTEX_ATTRIB_ARRAY_DIVISOR);
+ 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);
+ }
+ }
+
+ gl.vertexAttribDivisor(max_vertex_attribs, 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "vertexAttribDivisor index set greater than or equal to MAX_VERTEX_ATTRIBS should be an invalid value");
+
+ gl.vertexAttribDivisor(max_vertex_attribs-1, 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertexAttribDivisor index set less than MAX_VERTEX_ATTRIBS should succeed");
+
+ var queried_value = gl.getVertexAttrib(max_vertex_attribs-1, gl.VERTEX_ATTRIB_ARRAY_DIVISOR);
+ if(queried_value == 2){
+ testPassed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR matches expecation");
+ }
+ else{
+ testFailed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR should be: 2, returned value was: " + queried_value);
+ }
+}
+
+function runOutputTests() {
+ var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
+ var instanceCount = 4;
+
+ 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.clearColor(0, 0, 0, 0);
+
+ var positionLoc = 0;
+ var offsetLoc = 2;
+ var colorLoc = 3;
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['aPosition', 'aOffset', 'aColor'], [positionLoc, offsetLoc, colorLoc]);
+
+ 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);
+ gl.vertexAttribDivisor(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
+ ]);
+ 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);
+ gl.vertexAttribDivisor(colorLoc, 1);
+
+ // Draw 1: Draw Non-indexed instances
+ debug("Testing drawArraysInstanced");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.setupUnitQuad(gl, 0);
+
+ // Test drawArraysInstanced error conditions
+ gl.drawArraysInstanced(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]);
+
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, -1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstanced cannot have a primcount less than 0");
+
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, -1, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstanced cannot have a count less than 0");
+
+ gl.vertexAttribDivisor(positionLoc, 1);
+ gl.drawArraysInstanced(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 drawArraysInstanced");
+ gl.vertexAttribDivisor(positionLoc, 0);
+
+ gl.drawArraysInstanced(gl.POINTS, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with POINTS should succeed");
+ gl.drawArraysInstanced(gl.LINES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with LINES should succeed");
+ gl.drawArraysInstanced(gl.LINE_LIST, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with LINE_LIST should return succeed");
+ gl.drawArraysInstanced(gl.TRI_LIST, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced with TRI_LIST should succeed");
+
+ gl.drawArraysInstanced(desktopGL['QUAD_STRIP'], 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstanced with QUAD_STRIP should return INVALID_ENUM");
+ gl.drawArraysInstanced(desktopGL['QUADS'], 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstanced with QUADS should return INVALID_ENUM");
+ gl.drawArraysInstanced(desktopGL['POLYGON'], 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstanced with POLYGON should return INVALID_ENUM");
+
+ // Draw 2: Draw indexed instances
+ debug("Testing drawElementsInstanced");
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.setupIndexedQuad(gl, 1, 0);
+ gl.drawElementsInstanced(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 drawElementsInstanced error conditions
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, -1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstanced cannot have a primcount less than 0");
+
+ gl.drawElementsInstanced(gl.TRIANGLES, -1, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstanced cannot have a count less than 0");
+
+ gl.vertexAttribDivisor(positionLoc, 1);
+ gl.drawElementsInstanced(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 drawElementsInstanced");
+ gl.vertexAttribDivisor(positionLoc, 0);
+
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with UNSIGNED_BYTE should succeed");
+
+ gl.drawElementsInstanced(gl.POINTS, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with POINTS should succeed");
+ gl.drawElementsInstanced(gl.LINES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with LINES should succeed");
+ gl.drawElementsInstanced(gl.LINE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with LINE_LIST should return succeed");
+ gl.drawElementsInstanced(gl.TRI_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced with TRI_LIST should succeed");
+
+ gl.drawElementsInstanced(desktopGL['QUAD_STRIP'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstanced with QUAD_STRIP should return INVALID_ENUM");
+ gl.drawElementsInstanced(desktopGL['QUADS'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstanced with QUADS should return INVALID_ENUM");
+ gl.drawElementsInstanced(desktopGL['POLYGON'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstanced with POLYGON should return INVALID_ENUM");
+}
+
+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/rendering/instanced-rendering-bug.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-rendering-bug.html
new file mode 100644
index 000000000..14d576f8d
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/instanced-rendering-bug.html
@@ -0,0 +1,275 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL 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>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 128px; height: 128px;"> </canvas>
+<div id="console"></div>
+<script id="outputVertexShader" type="x-shader/x-vertex">#version 300 es
+in highp vec2 aPosition;
+in highp float aOffset;
+in highp float aColor;
+out mediump float vColor;
+void main() {
+ gl_Position = vec4(aPosition, 0.0, 1.0) + vec4(aOffset, 0.0, 0.0, 0.0);
+ vColor = aColor;
+}
+</script>
+
+<script id="outputFragmentShader" type="x-shader/x-fragment">#version 300 es
+layout(location = 0) out mediump vec4 oColor;
+in mediump float vColor;
+void main() {
+ oColor = vec4(vColor, 0.0, 0.0, 1.0);
+}
+</script>
+
+<script>
+"use strict";
+description("This test verifies a bug related with instanced rendering on Mac AMD.");
+debug("http://crbug.com/645298");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, 2);
+
+// The second and fourth test cases fail - it seems if the divisor doesn't change,
+// the next instanced draw call behaves incorrectly.
+// Also note that if we don't perform a readPixels (in wtu.checkCanvasRect), the bug
+// isn't triggered.
+var testCases = [
+ { instanceCount: 8, divisor: 4 },
+ { instanceCount: 6, divisor: 4 },
+ { instanceCount: 6, divisor: 3 },
+ { instanceCount: 8, divisor: 3 },
+];
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ for (var ii = 0; ii < testCases.length; ++ii) {
+ runDrawArraysTest(testCases[ii].instanceCount, testCases[ii].divisor);
+ }
+
+ for (var ii = 0; ii < testCases.length; ++ii) {
+ runDrawElementsTest(testCases[ii].instanceCount, testCases[ii].divisor);
+ }
+}
+
+function runDrawArraysTest(instanceCount, divisor) {
+ debug("");
+ debug("Testing drawArraysInstanced: instanceCount = " + instanceCount + ", divisor = " + divisor);
+
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var vao = gl.createVertexArray();
+ gl.bindVertexArray(vao);
+
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"]);
+ var positionLoc = gl.getAttribLocation(program, "aPosition");
+ var offsetLoc = gl.getAttribLocation(program, "aOffset");
+ var colorLoc = gl.getAttribLocation(program, "aColor");
+ if (!program || positionLoc < 0 || offsetLoc < 0 || colorLoc < 0) {
+ testFailed("Set up program failed");
+ return;
+ }
+ testPassed("Set up program succeeded");
+
+ var scale = 1.0 / instanceCount;
+
+ gl.enableVertexAttribArray(positionLoc);
+ gl.vertexAttribDivisor(positionLoc, 0);
+ var positions = new Float32Array([
+ 1.0 * scale, 1.0,
+ -1.0 * scale, 1.0,
+ -1.0 * scale, -1.0,
+ 1.0 * scale, 1.0,
+ -1.0 * scale, -1.0,
+ 1.0 * scale, -1.0,
+ ]);
+ var positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
+
+ gl.enableVertexAttribArray(offsetLoc);
+ gl.vertexAttribDivisor(offsetLoc, 1);
+ var offsets = new Float32Array(instanceCount);
+ for (var ii = 0; ii < instanceCount; ++ii) {
+ offsets[ii] = scale * (1 - instanceCount + ii * 2);
+ }
+ var offsetBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(offsetLoc, 1, gl.FLOAT, false, 0, 0);
+
+ gl.enableVertexAttribArray(colorLoc);
+ gl.vertexAttribDivisor(colorLoc, divisor);
+ var colorCount = instanceCount / divisor;
+ if ((instanceCount % divisor) != 0)
+ colorCount++;
+ var colors = new Float32Array(colorCount);
+ for (var ii = 0; ii < colorCount; ++ii) {
+ colors[ii] = 1.0 / colorCount * (ii + 1);
+ }
+ var colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(colorLoc, 1, gl.FLOAT, false, 0, 0);
+
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced should succeed");
+
+ var colorIndex = -1;
+ for (var ii = 0; ii < instanceCount; ++ii) {
+ if ((ii % divisor) == 0)
+ colorIndex++;
+ var refColor = [ Math.floor(colors[colorIndex] * 255), 0, 0, 255 ];
+ wtu.checkCanvasRect(gl, Math.floor(canvas.width / instanceCount * ii) + 1, 0, 1, canvas.height, refColor,
+ "instance " + ii + " should be " + refColor, 2);
+ }
+
+ gl.deleteBuffer(positionBuffer);
+ gl.deleteBuffer(offsetBuffer);
+ gl.deleteBuffer(colorBuffer);
+ gl.deleteProgram(program);
+ gl.deleteVertexArray(vao);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ gl.useProgram(null);
+ gl.bindVertexArray(null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clean up should succeed");
+}
+
+function runDrawElementsTest(instanceCount, divisor) {
+ debug("");
+ debug("Testing drawElementsInstanced: instanceCount = " + instanceCount + ", divisor = " + divisor);
+
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var vao = gl.createVertexArray();
+ gl.bindVertexArray(vao);
+
+ var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"]);
+ var positionLoc = gl.getAttribLocation(program, "aPosition");
+ var offsetLoc = gl.getAttribLocation(program, "aOffset");
+ var colorLoc = gl.getAttribLocation(program, "aColor");
+ if (!program || positionLoc < 0 || offsetLoc < 0 || colorLoc < 0) {
+ testFailed("Set up program failed");
+ return;
+ }
+ testPassed("Set up program succeeded");
+
+ var scale = 1.0 / instanceCount;
+
+ gl.enableVertexAttribArray(positionLoc);
+ gl.vertexAttribDivisor(positionLoc, 0);
+ var positions = new Float32Array([
+ 1.0 * scale, 1.0,
+ -1.0 * scale, 1.0,
+ -1.0 * scale, -1.0,
+ 1.0 * scale, -1.0,
+ ]);
+ var positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
+
+ gl.enableVertexAttribArray(offsetLoc);
+ gl.vertexAttribDivisor(offsetLoc, 1);
+ var offsets = new Float32Array(instanceCount);
+ for (var ii = 0; ii < instanceCount; ++ii) {
+ offsets[ii] = scale * (1 - instanceCount + ii * 2);
+ }
+ var offsetBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(offsetLoc, 1, gl.FLOAT, false, 0, 0);
+
+ gl.enableVertexAttribArray(colorLoc);
+ gl.vertexAttribDivisor(colorLoc, divisor);
+ var colorCount = instanceCount / divisor;
+ if ((instanceCount % divisor) != 0)
+ colorCount++;
+ var colors = new Float32Array(colorCount);
+ for (var ii = 0; ii < colorCount; ++ii) {
+ colors[ii] = 1.0 / colorCount * (ii + 1);
+ }
+ var colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(colorLoc, 1, gl.FLOAT, false, 0, 0);
+
+ var indexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ var indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced should succeed");
+
+ var colorIndex = -1;
+ for (var ii = 0; ii < instanceCount; ++ii) {
+ if ((ii % divisor) == 0)
+ colorIndex++;
+ var refColor = [ Math.floor(colors[colorIndex] * 255), 0, 0, 255 ];
+ wtu.checkCanvasRect(gl, Math.floor(canvas.width / instanceCount * ii) + 1, 0, 1, canvas.height, refColor,
+ "instance " + ii + " should be " + refColor, 2);
+ }
+
+ gl.deleteBuffer(positionBuffer);
+ gl.deleteBuffer(offsetBuffer);
+ gl.deleteBuffer(colorBuffer);
+ gl.deleteBuffer(indexBuffer);
+ gl.deleteProgram(program);
+ gl.deleteVertexArray(vao);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ gl.useProgram(null);
+ gl.bindVertexArray(null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clean up should succeed");
+}
+
+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/rendering/out-of-bounds-index-buffers-after-copying.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/out-of-bounds-index-buffers-after-copying.html
new file mode 100644
index 000000000..e01f71753
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/out-of-bounds-index-buffers-after-copying.html
@@ -0,0 +1,207 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+-->
+<!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 Out-of-Bounds Index Buffer Caused by CopyBufferSubData Conformance Test</title>
+</head>
+<body>
+<canvas id="canvas" width="8" height="8" style="width: 100px; height: 100px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script id="vsCheckOutOfBounds" type="x-shader/x-vertex">
+ #define TEST_CASE_IN_BOUND 1
+ #define TEST_CASE_OUT_OF_BOUND 2
+
+ precision mediump float;
+ attribute vec2 position;
+ attribute vec4 vecRandom;
+ varying vec4 v_color;
+ uniform int u_testCase;
+
+ bool testFloatComponentAccurate(float component) {
+ return component == 0.2;
+ }
+ // Per the spec, each component can either contain existing contents
+ // of the buffer or 0.
+ bool testFloatComponent(float component) {
+ return (component == 0.2 || component == 0.0);
+ }
+ // The last component is additionally allowed to be 1.0.
+ bool testLastFloatComponent(float component) {
+ return testFloatComponent(component) || component == 1.0;
+ }
+
+ bool testData(vec4 data) {
+ if (u_testCase == TEST_CASE_IN_BOUND) {
+ return (testFloatComponentAccurate(data.x) &&
+ testFloatComponentAccurate(data.y) &&
+ testFloatComponentAccurate(data.z) &&
+ testFloatComponentAccurate(data.w));
+ } else if (u_testCase == TEST_CASE_OUT_OF_BOUND) {
+ return (testFloatComponent(data.x) &&
+ testFloatComponent(data.y) &&
+ testFloatComponent(data.z) &&
+ testLastFloatComponent(data.w));
+ }
+ return false;
+ }
+
+ void main() {
+ if (testData(vecRandom)) {
+ v_color = vec4(0.0, 1.0, 0.0, 1.0); // green -- We're good
+ } else {
+ v_color = vec4(1.0, 0.0, 0.0, 1.0); // red -- Unexpected value
+ }
+ gl_Position = vec4(position, 0.0, 1.0);
+ }
+</script>
+<script>
+"use strict";
+description("This test verifies that out-of-bounds index buffers caused by CopyBufferSubData behave according to spec.");
+
+// Ensure that drawElements flags either no error or INVALID_OPERATION. In the case of INVALID_OPERATION,
+// no canvas pixels can be touched. In the case of NO_ERROR, all written values must either be the
+// zero vertex or a value in the vertex buffer. See vsCheckOutOfBounds shader.
+function verifyOutOfBoundsIndex(gl) {
+ var error = gl.getError();
+ if (error === gl.INVALID_OPERATION) {
+ testPassed("drawElements flagged INVALID_OPERATION, which is valid so long as all canvas pixels were not touched.");
+ wtu.checkCanvas(gl, [0, 0, 255, 255]);
+ } else if (error === gl.NO_ERROR) {
+ testPassed("drawElements flagged NO_ERROR, which is valid so long as all canvas pixels are green.");
+ wtu.checkCanvas(gl, [0, 255, 0, 255]);
+ } else {
+ testFailed("Invalid error flagged by drawElements. Should be INVALID_OPERATION or NO_ERROR");
+ }
+}
+
+// Create an element array buffer with a tri-strip that starts at startIndex and make
+// it the active element array buffer.
+function prepareElementArrayBuffer(gl, startIndex) {
+ var glElementArrayBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, glElementArrayBuffer);
+ var quadIndices = new Uint16Array(4);
+ for (var i = 0; i < quadIndices.length; i++) {
+ quadIndices[i] = startIndex + i;
+ }
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices, gl.STATIC_DRAW);
+ return glElementArrayBuffer;
+}
+
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false}, 2);
+
+var numberOfQuads = 200;
+
+// Create a vertex buffer with 200 properly formed tri-strip quads. These quads will cover the canvas texture
+// such that every single pixel is touched by the fragment shader.
+var quadBuffer = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);
+var quadPositions = new Float32Array(numberOfQuads * /*ComponentsPerQuad*/2 * /*VerticesPerQuad*/4);
+for (var i = 0; i < quadPositions.length; i += /*ComponentsPerQuad*/2 * /*VerticesPerQuad*/4) {
+ quadPositions[i+0] = -1.0; // upper left
+ quadPositions[i+1] = 1.0;
+ quadPositions[i+2] = 1.0; // upper right
+ quadPositions[i+3] = 1.0;
+ quadPositions[i+4] = -1.0; // lower left
+ quadPositions[i+5] = -1.0;
+ quadPositions[i+6] = 1.0; // lower right
+ quadPositions[i+7] = -1.0;
+}
+gl.bufferData(gl.ARRAY_BUFFER, quadPositions, gl.STATIC_DRAW);
+gl.enableVertexAttribArray(0);
+gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+
+// Create a small vertex buffer with determined-ahead-of-time "random" values (0.2). This buffer will be
+// the one indexed off the end.
+var vertexBuffer = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+gl.bufferData(gl.ARRAY_BUFFER,
+ new Float32Array([0.2, 0.2, 0.2, 0.2,
+ 0.2, 0.2, 0.2, 0.2,
+ 0.2, 0.2, 0.2, 0.2,
+ 0.2, 0.2, 0.2, 0.2]),
+ gl.STATIC_DRAW);
+gl.enableVertexAttribArray(1);
+gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);
+
+// Setup the verification program.
+var program = wtu.setupProgram(gl, ["vsCheckOutOfBounds", wtu.simpleVertexColorFragmentShader], ["position", "vecRandom"]);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Shader and buffer setup should generate no errors");
+var loc = gl.getUniformLocation(program, "u_testCase");
+shouldBeNonNull(loc);
+
+debug("");
+debug("Test -- Vertex indices are in bounds.");
+gl.uniform1i(loc, 1); // TEST_CASE_IN_BOUND == 1
+gl.clearColor(0.0, 0.0, 1.0, 1.0); // Start with blue to indicate no pixels touched.
+gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+var elementArrayBuffer = prepareElementArrayBuffer(gl, /*StartIndex*/0);
+gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, /*offset*/0);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Draw call should generate no errors");
+wtu.checkCanvas(gl, [0, 255, 0, 255]);
+
+debug("");
+debug("Test -- Index off the end of the vertex buffer near the beginning of the out of bounds area.");
+gl.uniform1i(loc, 2); // TEST_CASE_OUT_OF_BOUND == 2
+gl.clearColor(0.0, 0.0, 1.0, 1.0); // Start with blue to indicate no pixels touched.
+gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+var outOfBoundsElementArrayBuffer = prepareElementArrayBuffer(gl, /*StartIndex*/4);
+gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, outOfBoundsElementArrayBuffer);
+gl.bindBuffer(gl.COPY_WRITE_BUFFER, elementArrayBuffer);
+gl.copyBufferSubData(gl.ELEMENT_ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 4 * Uint16Array.BYTES_PER_ELEMENT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "copyBufferSubData should generate no errors");
+gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementArrayBuffer);
+gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, /*offset*/0);
+verifyOutOfBoundsIndex(gl);
+
+debug("");
+debug("Test -- Index off the end of the vertex buffer near the end of the out of bounds area.")
+gl.uniform1i(loc, 2); // TEST_CASE_OUT_OF_BOUND == 2
+gl.clearColor(0.0, 0.0, 1.0, 1.0); // Start with blue to indicate no pixels touched.
+gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+outOfBoundsElementArrayBuffer = prepareElementArrayBuffer(gl, /*StartIndex*/numberOfQuads - 4);
+gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementArrayBuffer);
+gl.bindBuffer(gl.COPY_READ_BUFFER, outOfBoundsElementArrayBuffer);
+gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.ELEMENT_ARRAY_BUFFER, 0, 0, 4 * Uint16Array.BYTES_PER_ELEMENT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "copyBufferSubData should generate no errors");
+gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, /*offset*/0);
+verifyOutOfBoundsIndex(gl);
+
+debug("");
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Running tests should generate no errors");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html
new file mode 100644
index 000000000..9bbfe3a7b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html
@@ -0,0 +1,148 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Rendering and Sampling Feedback Loop 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="example" width="8" height="8"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+
+<script id="vshader" type="x-shader/x-vertex">#version 300 es
+in highp vec4 aPosition;
+in vec2 aTexCoord;
+out vec2 texCoord;
+void main() {
+ gl_Position = aPosition;
+ texCoord = aTexCoord;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+uniform sampler2D tex;
+in vec2 texCoord;
+out vec4 oColor;
+void main() {
+ oColor = texture(tex, texCoord);
+}
+</script>
+
+<script>
+"use strict";
+
+var wtu = WebGLTestUtils;
+description("This test verifies the functionality of rendering to the same texture where it samples from.");
+
+var gl = wtu.create3DContext("example", undefined, 2);
+
+var width = 8;
+var height = 8;
+var tex0;
+var tex1;
+var fbo;
+var program;
+var positionLoc;
+var texCoordLoc;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ init();
+
+ // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
+ allocate_resource();
+
+ rendering_sampling_feedback_loop([gl.NONE, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION);
+ rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1], gl.INVALID_OPERATION);
+ rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR);
+}
+
+function init() {
+ program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['aPosition', 'aTexCoord'], [0, 1]);
+ positionLoc = gl.getAttribLocation(program, "aPosition");
+ texCoordLoc = gl.getAttribLocation(program, "aTexCoord");
+ if (!program || positionLoc < 0 || texCoordLoc < 0) {
+ testFailed("Set up program failed");
+ return;
+ }
+ testPassed("Set up program succeeded");
+
+ wtu.setupUnitQuad(gl, 0, 1);
+ gl.viewport(0, 0, width, height);
+}
+
+function allocate_resource() {
+ tex0 = gl.createTexture();
+ tex1 = gl.createTexture();
+ fbo = gl.createFramebuffer();
+ wtu.fillTexture(gl, tex0, width, height, [0xff, 0x0, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA);
+ wtu.fillTexture(gl, tex1, width, height, [0x0, 0xff, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA);
+
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
+ var texLoc = gl.getUniformLocation(program, "tex");
+ gl.uniform1i(texLoc, 0);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex1, 0);
+}
+
+function rendering_sampling_feedback_loop(draw_buffers, error) {
+ gl.drawBuffers(draw_buffers);
+
+ // Make sure framebuffer is complete before feedback loop detection
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Framebuffer incomplete.");
+ return;
+ }
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, error, "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise, it should be NO_ERROR");
+}
+
+gl.bindTexture(gl.TEXTURE_2D, null);
+gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+gl.deleteTexture(tex0);
+gl.deleteTexture(tex1);
+gl.deleteFramebuffer(fbo);
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rgb-format-support.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rgb-format-support.html
new file mode 100644
index 000000000..bb67edffb
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rgb-format-support.html
@@ -0,0 +1,132 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!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>
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description("Verify RGB/RGB8 textures and renderbuffers support");
+
+var gl = wtu.create3DContext(undefined, undefined, 2);
+
+function testRenderbuffer(width, height) {
+ var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGB8, gl.SAMPLES);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from getInternalformatParameter()");
+
+ if (!samples || samples.length == 0) {
+ testFailed("getInternalformatParameter on RGB8 fails to return valid samples");
+ return;
+ }
+
+ for (var idx = 0; idx < samples.length + 2; ++idx) {
+ debug("");
+ var renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ var sampleCount = 0;
+ switch (idx) {
+ case samples.length:
+ sampleCount = 0;
+ break;
+ case samples.length + 1:
+ sampleCount = -1; // non multisampled
+ break;
+ default:
+ sampleCount = samples[idx];
+ }
+
+ if (sampleCount < 0) {
+ debug("test non-multisampled RGB8 renderbuffer");
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB8, 2, 2);
+ } else {
+ debug("test RGB8 renderbuffer with " + sampleCount + " samples");
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGB8, width, height);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from renderbufferStorage{Multisample}");
+
+ 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 renderbuffer is incomplete");
+ } else {
+ testPassed("framebuffer with renderbuffer is complete");
+ }
+
+ gl.clearColor(1, 0, 1, 1);
+ gl.clear(gl.COLOR_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear()");
+ }
+}
+
+function testTexture(width, height) {
+ var formats = [ "RGB", "RGB8" ];
+ for (var idx = 0; idx < formats.length; ++idx) {
+ debug("");
+ debug("test texture format " + formats[idx]);
+ var internalformat = gl[formats[idx]];
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalformat, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture setup");
+
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("framebuffer with texture is incomplete");
+ } else {
+ testPassed("framebuffer with texture is complete");
+ }
+
+ gl.clearColor(1, 0, 1, 1);
+ gl.clear(gl.COLOR_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear()");
+ }
+}
+
+if (!gl) {
+ testFailed('canvas.getContext() failed');
+} else {
+ testRenderbuffer(2, 2);
+ testTexture(2, 2);
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/uniform-block-buffer-size.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/uniform-block-buffer-size.html
new file mode 100644
index 000000000..96b111ec4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/uniform-block-buffer-size.html
@@ -0,0 +1,249 @@
+<!--
+
+/*
+** Copyright (c) 2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL UniformBlock Buffer Size 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='vshader' type='x-shader/x-vertex'>#version 300 es
+layout(location=0) in vec3 p;
+void main()
+{
+ gl_Position = vec4(p.xyz, 1.0);
+}
+</script>
+<script id='fshader' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+
+uniform UBOData {
+ float UBORed;
+ float UBOGreen;
+ float UBOBlue;
+};
+
+void main()
+{
+ oColor = vec4(UBORed, UBOGreen, UBOBlue, 1.0);
+}
+</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 an active UniformBlock should be populated with a large enough buffer object");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, 2);
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ runDrawArraysTests();
+ runDrawElementsTests();
+}
+
+function runDrawArraysTests() {
+ debug("");
+ debug("Testing drawArrays and drawArraysInstanced");
+
+ var instanceCount = 4;
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshader']);
+ if (!program) {
+ testFailed("Could not compile shader with uniform blocks without error");
+ return;
+ }
+
+ var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
+ var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
+ var uniformIndices = gl.getUniformIndices(program, ["UBORed", "UBOGreen", "UBOBlue"]);
+ var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+
+ if (uniformOffsets.length < 3) {
+ testFailed("Could not query uniform offsets");
+ return;
+ }
+
+ var uboArray = new ArrayBuffer(blockSize);
+ var uboFloatView = new Float32Array(uboArray);
+ uboFloatView[uniformOffsets[0] / Float32Array.BYTES_PER_ELEMENT] = 1.0; // UBORed
+ uboFloatView[uniformOffsets[1] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOGreen
+ uboFloatView[uniformOffsets[2] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOBlue
+
+ var binding = 1;
+ gl.uniformBlockBinding(program, blockIndex, binding);
+
+ wtu.setupUnitQuad(gl);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Set up succeeded");
+
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: UniformBlock is not backed by a buffer");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: UniformBlock is not backed by a buffer");
+
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, buffer);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: UniformBlock is backed by a buffer with no data store");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: UniformBlock is backed by a buffer with no data store");
+
+ var arrayNotLargeEnough = new ArrayBuffer(blockSize - 1);
+ gl.bufferData(gl.UNIFORM_BUFFER, arrayNotLargeEnough, gl.DYNAMIC_DRAW);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: UniformBlock not populated with a large enough buffer");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: UniformBlock not populated with a large enough buffer");
+
+ gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView, gl.DYNAMIC_DRAW);
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays: should be able to draw with sufficient data for UniformBlock");
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced: should be able to draw with sufficient data for UniformBlock");
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
+
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, binding, buffer, 0, blockSize -1);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: bindBufferRange set size too small for UniformBlock");
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArraysInstanced: bindBufferRange set size too small for UniformBlock");
+}
+
+function runDrawElementsTests() {
+ debug("");
+ debug("Testing drawElements, drawRangeElements and drawElementsInstanced");
+
+ var instanceCount = 4;
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshader']);
+ if (!program) {
+ testFailed("Could not compile shader with uniform blocks without error");
+ return;
+ }
+
+ var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
+ var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
+ var uniformIndices = gl.getUniformIndices(program, ["UBORed", "UBOGreen", "UBOBlue"]);
+ var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+
+ if (uniformOffsets.length < 3) {
+ testFailed("Could not query uniform offsets");
+ return;
+ }
+
+ var uboArray = new ArrayBuffer(blockSize);
+ var uboFloatView = new Float32Array(uboArray);
+ uboFloatView[uniformOffsets[0] / Float32Array.BYTES_PER_ELEMENT] = 1.0; // UBORed
+ uboFloatView[uniformOffsets[1] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOGreen
+ uboFloatView[uniformOffsets[2] / Float32Array.BYTES_PER_ELEMENT] = 0.0; // UBOBlue
+
+ var binding = 1;
+ gl.uniformBlockBinding(program, blockIndex, binding);
+
+ wtu.setupIndexedQuad(gl, 1, 0);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Set up succeeded");
+
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer);
+
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: UniformBlock is not backed by a buffer");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: UniformBlock is not backed by a buffer");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: UniformBlock is not backed a buffer");
+
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, buffer);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: UniformBlock is populated with a buffer with no data store");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: UniformBlock is populated with a buffer with no data store");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: UniformBlock is populated with a buffer with no data store");
+
+ var arrayNotLargeEnough = new ArrayBuffer(blockSize - 1);
+ gl.bufferData(gl.UNIFORM_BUFFER, arrayNotLargeEnough, gl.DYNAMIC_DRAW);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: UniformBlock not populated with a large enough buffer");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: UniformBlock not populated with a large enough buffer");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: UniformBlock not populated with a large enough buffer");
+
+ gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView, gl.DYNAMIC_DRAW);
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements: should be able to draw with sufficient data for UniformBlock");
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawRangeElements: should be able to draw with sufficient data for UniformBlock");
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced: should be able to draw with sufficient data for UniformBlock");
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
+
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, binding, buffer, 0, blockSize -1);
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: bindBufferRange set size too small for UniformBlock");
+ gl.drawRangeElements(gl.TRIANGLES, 0, 5, 6, gl.UNSIGNED_SHORT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawRangeElements: bindBufferRange set size too small for UniformBlock");
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElementsInstanced: bindBufferRange set size too small for UniformBlock");
+}
+
+debug("");
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>