summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance/misc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /dom/canvas/test/webgl-conf/checkout/conformance/misc
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance/misc')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/00_test_list.txt17
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/bad-arguments-test.html100
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/boolean-argument-conversion.html115
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/delayed-drawing.html64
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/error-reporting.html75
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/expando-loss.html223
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/functions-returning-strings.html104
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/hint.html124
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/instanceof-test.html44
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/invalid-passed-params.html170
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/is-object.html78
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/null-object-behaviour.html89
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/object-deletion-behaviour.html443
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/shader-precision-format.html340
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/type-conversion-test.html151
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/uninitialized-test.html262
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific-stencil-settings.html299
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific.html91
18 files changed, 2789 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance/misc/00_test_list.txt
new file mode 100644
index 0000000000..3cbdf888f4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/00_test_list.txt
@@ -0,0 +1,17 @@
+bad-arguments-test.html
+--min-version 1.0.2 boolean-argument-conversion.html
+--min-version 1.0.2 delayed-drawing.html
+error-reporting.html
+--min-version 1.0.4 expando-loss.html
+functions-returning-strings.html
+--min-version 1.0.4 hint.html
+--max-version 1.9.9 instanceof-test.html
+invalid-passed-params.html
+is-object.html
+null-object-behaviour.html
+object-deletion-behaviour.html
+shader-precision-format.html
+type-conversion-test.html
+uninitialized-test.html
+webgl-specific.html
+--min-version 1.0.4 webgl-specific-stencil-settings.html
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/bad-arguments-test.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/bad-arguments-test.html
new file mode 100644
index 0000000000..2ae7d91bf3
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/bad-arguments-test.html
@@ -0,0 +1,100 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description("Tests calling WebGL APIs with wrong argument types");
+
+
+var testArguments = [
+ { value: "foo",
+ throwsForNullables: true },
+ { value: 0,
+ throwsForNullables: true },
+ { value: null,
+ throwsForNullables: false },
+ { value: undefined,
+ throwsForNullables: false }
+];
+
+var argument;
+
+var context = wtu.create3DContext();
+var program;
+var shader;
+var loc;
+wtu.loadStandardProgramAsync(context, function(success, prog) {
+ program = prog;
+ wtu.loadStandardVertexShaderAsync(context, function(success, s) {
+ shader = s;
+
+ assertMsg(program != null, "Program Compiled");
+ assertMsg(shader != null, "Shader Compiled");
+
+ loc = context.getUniformLocation(program, "u_modelViewProjMatrix");
+ assertMsg(loc != null, "getUniformLocation succeeded");
+
+ for (var i = 0; i < testArguments.length; ++i) {
+ argument = testArguments[i].value;
+
+ debug('Testing argument: ' + argument);
+
+ // These functions don't accept nullable arguments any more.
+ shouldThrow("context.compileShader(argument)");
+ shouldThrow("context.linkProgram(argument)");
+ shouldThrow("context.attachShader(program, argument)");
+ shouldThrow("context.attachShader(argument, shader)");
+ shouldThrow("context.detachShader(program, argument)");
+ shouldThrow("context.detachShader(argument, shader)");
+ shouldThrow("context.shaderSource(argument, 'foo')");
+ shouldThrow("context.bindAttribLocation(argument, 0, 'foo')");
+ shouldThrow("context.getProgramInfoLog(argument)");
+ shouldThrow("context.getProgramParameter(argument, 0)");
+ shouldThrow("context.getShaderInfoLog(argument)");
+ shouldThrow("context.getShaderParameter(argument, 0)");
+ shouldThrow("context.getShaderSource(argument)");
+ shouldThrow("context.getUniform(argument, loc)");
+ shouldThrow("context.getUniform(program, argument)");
+ shouldThrow("context.getUniformLocation(argument, 'u_modelViewProjMatrix')");
+
+ // The following entry points still accept nullable arguments.
+ var func;
+ if (testArguments[i].throwsForNullables) {
+ func = shouldThrow;
+ } else {
+ func = shouldBeUndefined;
+ }
+
+ func("context.bindBuffer(context.ARRAY_BUFFER, argument)");
+ func("context.bindFramebuffer(context.FRAMEBUFFER, argument)");
+ func("context.bindRenderbuffer(context.RENDERBUFFER, argument)");
+ func("context.bindTexture(context.TEXTURE_2D, argument)");
+ func("context.framebufferRenderbuffer(context.FRAMEBUFFER, context.DEPTH_ATTACHMENT, context.RENDERBUFFER, argument)");
+ func("context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, argument, 0)");
+ func("context.uniform2fv(argument, new Float32Array([0.0, 0.0]))");
+ func("context.uniform2iv(argument, new Int32Array([0, 0]))");
+ func("context.uniformMatrix2fv(argument, false, new Float32Array([0.0, 0.0, 0.0, 0.0]))");
+ func("context.useProgram(argument)");
+ }
+ finishTest();
+ });
+});
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/boolean-argument-conversion.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/boolean-argument-conversion.html
new file mode 100644
index 0000000000..1423673bda
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/boolean-argument-conversion.html
@@ -0,0 +1,115 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/test-eval.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description("Test that conversion of boolean arguments of WebGL functions follows EcmaScript 9.2. ToBoolean");
+debug("");
+debug("When an object is converted to a boolean, it should always evaluate as true. Any valueOf() method should not even get called. See Mozilla bug 727590 where Gecko incorrectly converted such an argument to a Number instead of a Boolean, giving the wrong behavior. See 9.2 and 9.3 in the EcmaScript specification.");
+debug("");
+var gl = wtu.create3DContext();
+var program = wtu.loadStandardProgram(gl);
+var shader = wtu.loadStandardVertexShader(gl);
+var shouldGenerateGLError = wtu.shouldGenerateGLError;
+
+assertMsg(program != null, "Program Compiled");
+assertMsg(shader != null, "Shader Compiled");
+
+var uloc = gl.getUniformLocation(program, "u_modelViewProjMatrix");
+var aloc = gl.getAttribLocation(program, "a_vertex");
+
+gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from initialization.");
+assertMsg(uloc, "Uniform not found");
+assertMsg(aloc >= 0, "Attribute not found");
+
+var boolArg = { valueOf: function() { throw "Converting an Object to a Boolean should just give 'true' without further evaluation"; } }
+
+function shouldNotThrowWithBoolArgs(code) {
+ try {
+ TestEval(code);
+ } catch(e) {
+ testFailed(code + " threw exception: " + e);
+ return;
+ }
+ testPassed(code + " converted its boolean arguments correctly");
+}
+
+shouldNotThrowWithBoolArgs(
+ "gl.colorMask(boolArg, boolArg, boolArg, boolArg)"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.depthMask(boolArg)"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.sampleCoverage(1, boolArg)"
+);
+
+function zeroArray(length) {
+ var a = new Array(length);
+ for (var i = 0; i < length; i++)
+ a[i] = 0;
+ return a;
+}
+
+function zeroFloat32Array(length) {
+ var a = new Float32Array(length);
+ for (var i = 0; i < length; i++)
+ a[i] = 0;
+ return a;
+}
+
+shouldNotThrowWithBoolArgs(
+ "gl.uniformMatrix2fv(uloc, boolArg, zeroFloat32Array(4))"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.uniformMatrix2fv(uloc, boolArg, zeroArray(4))"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.uniformMatrix3fv(uloc, boolArg, zeroFloat32Array(9))"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.uniformMatrix3fv(uloc, boolArg, zeroArray(9))"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.uniformMatrix4fv(uloc, boolArg, zeroFloat32Array(16))"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.uniformMatrix4fv(uloc, boolArg, zeroArray(16))"
+);
+
+shouldNotThrowWithBoolArgs(
+ "gl.vertexAttribPointer(aloc, 4, gl.FLOAT, boolArg, 4, 0)"
+);
+
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/delayed-drawing.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/delayed-drawing.html
new file mode 100644
index 0000000000..4dc9ea8f3a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/delayed-drawing.html
@@ -0,0 +1,64 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Delayed Drawing 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>
+<canvas id="example" width="4" height="4" style="width: 40px; height: 30px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+enableJSTestPreVerboseLogging();
+description(document.title);
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("example");
+var program = wtu.setupTexturedQuad(gl);
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
+
+var tex = gl.createTexture();
+wtu.fillTexture(gl, tex, 5, 3, [0, 192, 128, 255]);
+
+var loc = gl.getUniformLocation(program, "tex");
+gl.uniform1i(loc, 0);
+
+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);
+
+
+drawAndCheck();
+
+setTimeout(step2, 1000);
+
+function step2() {
+ drawAndCheck();
+ finishTest();
+}
+
+function drawAndCheck() {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors before drawing.");
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from drawing.");
+ wtu.checkCanvas(
+ gl, [0, 192, 128, 255],
+ "draw should be 0, 192, 128, 255");
+}
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
+
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/error-reporting.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/error-reporting.html
new file mode 100644
index 0000000000..bfba0abc86
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/error-reporting.html
@@ -0,0 +1,75 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("Tests generation of synthetic and real GL errors");
+
+var wtu = WebGLTestUtils;
+var context = wtu.create3DContext();
+var program = wtu.loadStandardProgram(context);
+
+// Other tests like incorrect-context-object-behaviour already test the raising
+// of many synthetic GL errors. This test verifies the raising of certain
+// known real GL errors, and contains a few regression tests for bugs
+// discovered in the synthetic error generation and in the WebGL
+// implementation itself.
+
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+
+debug("Testing getActiveAttrib");
+shouldThrow("context.getActiveAttrib(null, 2)");
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+// Error state should be clear by this point
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+// Real OpenGL error
+shouldBeNull("context.getActiveAttrib(program, 2)");
+wtu.glErrorShouldBe(context, context.INVALID_VALUE);
+// Error state should be clear by this point
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+
+debug("Testing getActiveUniform");
+shouldThrow("context.getActiveUniform(null, 0)");
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+// Error state should be clear by this point
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+// Real OpenGL error
+shouldBeNull("context.getActiveUniform(program, 50)");
+wtu.glErrorShouldBe(context, context.INVALID_VALUE);
+// Error state should be clear by this point
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+
+debug("Testing attempts to manipulate the default framebuffer");
+shouldBeUndefined("context.bindFramebuffer(context.FRAMEBUFFER, null)");
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+shouldBeUndefined("context.framebufferRenderbuffer(context.FRAMEBUFFER, context.DEPTH_ATTACHMENT, context.RENDERBUFFER, null)");
+// Synthetic OpenGL error
+wtu.glErrorShouldBe(context, context.INVALID_OPERATION);
+// Error state should be clear by this point
+wtu.glErrorShouldBe(context, context.NO_ERROR);
+shouldBeUndefined("context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, null, 0)");
+// Synthetic OpenGL error
+wtu.glErrorShouldBe(context, context.INVALID_OPERATION);
+// Error state should be clear by this point
+wtu.glErrorShouldBe(context, context.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/conformance/misc/expando-loss.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/expando-loss.html
new file mode 100644
index 0000000000..9e1f041f02
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/expando-loss.html
@@ -0,0 +1,223 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<title>WebGL Object Expandos Conformance Test</title>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<script>
+"use strict";
+description("This test verifies that WebGL object expandos are preserved across garbage collections.");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+
+// Helpers that set expandos and verify they are set to the correct value.
+var expandoValue = "WebGL is awesome!"
+function setTestExpandos(instance) {
+ instance.expando1 = expandoValue;
+ instance.expando2 = { subvalue : expandoValue };
+}
+function verifyTestExpandos(instance, msg) {
+ assertMsg(instance.expando1 === expandoValue, msg + ": Expect basic expando to survive despite GC.");
+ assertMsg(instance.expando2 && instance.expando2.subvalue === expandoValue, msg + ": Expect subobject expando to survive despite GC.");
+}
+
+// Tests that we don't get expando loss for bound resources where the
+// only remaining reference is internal to WebGL
+function testBasicBindings() {
+ debug('Basic Bindings');
+
+ // Test data that describes how to create, bind, and retrieve an object off of the context
+ var glProt = Object.getPrototypeOf(gl);
+ var simpleData = [
+ {
+ creationFn: glProt.createTexture,
+ bindFn: glProt.bindTexture,
+ bindConstant: glProt.TEXTURE_2D,
+ retrieveConstant: glProt.TEXTURE_BINDING_2D,
+ name: "TEXTURE_BINDING_2D",
+ },
+ {
+ creationFn: glProt.createFramebuffer,
+ bindFn: glProt.bindFramebuffer,
+ bindConstant: glProt.FRAMEBUFFER,
+ retrieveConstant: glProt.FRAMEBUFFER_BINDING,
+ name: "FRAMEBUFFER_BINDING",
+ },
+ {
+ creationFn: glProt.createRenderbuffer,
+ bindFn: glProt.bindRenderbuffer,
+ bindConstant: glProt.RENDERBUFFER,
+ retrieveConstant: glProt.RENDERBUFFER_BINDING,
+ name: "RENDERBUFFER_BINDING",
+ },
+ {
+ creationFn: glProt.createBuffer,
+ bindFn: glProt.bindBuffer,
+ bindConstant: glProt.ELEMENT_ARRAY_BUFFER,
+ retrieveConstant: glProt.ELEMENT_ARRAY_BUFFER_BINDING,
+ name: "ELEMENT_ARRAY_BUFFER_BINDING",
+ },
+ {
+ creationFn: glProt.createBuffer,
+ bindFn: glProt.bindBuffer,
+ bindConstant: glProt.ARRAY_BUFFER,
+ retrieveConstant: glProt.ARRAY_BUFFER_BINDING,
+ name: "ARRAY_BUFFER_BINDING",
+ },
+ {
+ creationFn: glProt.createTexture,
+ bindFn: glProt.bindTexture,
+ bindConstant: glProt.TEXTURE_CUBE_MAP,
+ retrieveConstant: glProt.TEXTURE_BINDING_CUBE_MAP,
+ name: "TEXTURE_BINDING_CUBE_MAP",
+ },
+ ];
+
+ simpleData.forEach(function(test) {
+ var instance = test.creationFn.apply(gl, []);
+ var msg = "getParameter(" + test.name + ")";
+ setTestExpandos(instance);
+
+ test.bindFn.apply(gl, [test.bindConstant, instance]);
+ assertMsg(instance === gl.getParameter(test.retrieveConstant), msg + " returns instance that was bound.");
+
+ // Garbage collect Javascript references. Remaining references should be internal to WebGL.
+ instance = null;
+ webglHarnessCollectGarbage();
+
+ verifyTestExpandos(gl.getParameter(test.retrieveConstant), msg);
+ });
+
+ debug('');
+}
+
+// Attach a couple of shaders to a program and verify no expando loss when you call
+// getAttachedShaders and getParameter(CURRENT_PROGRAM).
+function testProgramsAndShaders() {
+ debug('Programs and Shaders');
+
+ var vs = wtu.loadShader(gl, wtu.simpleVertexShader, gl.VERTEX_SHADER);
+ setTestExpandos(vs);
+
+ var fs = wtu.loadShader(gl, wtu.simpleColorFragmentShader, gl.FRAGMENT_SHADER);
+ setTestExpandos(fs);
+
+ var program = wtu.setupProgram(gl, [vs, fs]);
+ setTestExpandos(program);
+ assertMsg(program === gl.getParameter(gl.CURRENT_PROGRAM), "getParameter(gl.CURRENT_PROGRAM) return instance set with useProgram");
+
+ var attachedShaders = gl.getAttachedShaders(program);
+ assertMsg(attachedShaders.indexOf(vs) !== -1, "Vertex shader instance found in getAttachedShaders");
+ assertMsg(attachedShaders.indexOf(fs) !== -1, "Fragment shader instance found in getAttachedShaders");
+
+ // Garbage collect Javascript references. Remaining references should be internal to WebGL.
+ attachedShaders = null;
+ program = null;
+ vs = null;
+ fs = null;
+ webglHarnessCollectGarbage();
+
+ var currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);
+ verifyTestExpandos(currentProgram, "Current program");
+ shouldBeType(currentProgram, 'WebGLProgram');
+
+ var retrievedShaders = gl.getAttachedShaders(currentProgram);
+ verifyTestExpandos(retrievedShaders[0], "Shader[0]");
+ shouldBeType(retrievedShaders[0], "WebGLShader");
+ verifyTestExpandos(retrievedShaders[1], "Shader[1]");
+ shouldBeType(retrievedShaders[1], "WebGLShader");
+
+ debug('');
+}
+
+// Attach a buffer via vertexAttribPointer and verify no expando loss when you call getVertexAttrib.
+function testVertexAttributeBuffers() {
+ debug('Vertex Attribute Buffers');
+
+ var program = wtu.setupSimpleColorProgram(gl);
+ var position = gl.getAttribLocation(program, "vPosition");
+
+ var buffer = gl.createBuffer();
+ setTestExpandos(buffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
+ assertMsg(buffer === gl.getVertexAttrib(position, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING),
+ "getVertexAttrib(VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) return instance set with vertexAttribPointer");
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+
+ // Garbage collect Javascript references. Remaining references should be internal to WebGL.
+ buffer = null;
+ program = null;
+ webglHarnessCollectGarbage();
+
+ var retrievedBuffer = gl.getVertexAttrib(position, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
+ verifyTestExpandos(retrievedBuffer, "Vertex Attribute Buffer");
+ shouldBeType(retrievedBuffer, 'WebGLBuffer');
+
+ debug('');
+}
+
+// Attach renderbuffers to framebuffers and verify no expando loss ocurrs when you call
+// getFramebufferAttachmentParameter
+function testFrameBufferAttachments() {
+ debug('FrameBuffer Attachments');
+
+ var framebuffer = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+ var attachments = [
+ { enum: gl.COLOR_ATTACHMENT0, name: "COLOR_ATTACHMENT0" },
+ { enum: gl.DEPTH_ATTACHMENT, name: "DEPTH_ATTACHMENT" },
+ { enum: gl.STENCIL_ATTACHMENT, name: "STENCIL_ATTACHMENT" },
+ { enum: gl.DEPTH_STENCIL_ATTACHMENT,name: "DEPTH_STENCIL_ATTACHMENT" },
+ ];
+
+ // Attach a renderbuffer to all attachment points.
+ attachments.forEach(function(attachment) {
+ var renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ setTestExpandos(renderbuffer);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment.enum, gl.RENDERBUFFER, renderbuffer);
+ assertMsg(renderbuffer === gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment.enum, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME),
+ "getFramebufferAttachmentParameter(" + attachment.name + ") returns instance set with framebufferRenderbuffer");
+ renderbuffer = null;
+ });
+
+ // Garbage collect Javascript references. Remaining references should be internal to WebGL.
+ webglHarnessCollectGarbage();
+
+ // Verify all attached renderbuffers have expandos.
+ attachments.forEach(function(attachment) {
+ var retrievedRenderbuffer = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment.enum, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
+ verifyTestExpandos(retrievedRenderbuffer, attachment.name);
+ shouldBeType(retrievedRenderbuffer, 'WebGLRenderbuffer');
+ });
+
+ debug('');
+}
+
+// Run tests
+testBasicBindings();
+testProgramsAndShaders();
+testVertexAttributeBuffers();
+testFrameBufferAttachments();
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/functions-returning-strings.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/functions-returning-strings.html
new file mode 100644
index 0000000000..15e89e46f6
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/functions-returning-strings.html
@@ -0,0 +1,104 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/test-eval.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+"use strict";
+description("Test that functions returning strings really do return strings (and not e.g. null)");
+debug("");
+
+var validVertexShaderString =
+ "attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex; }";
+var validFragmentShaderString =
+ "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }";
+
+function shouldReturnString(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = TestEval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + ' should return a string. Threw exception ' + exception);
+ else if (typeof _av == "string")
+ testPassed(_a + ' returns a string');
+ else
+ testFailed(_a + ' should return a string. Returns: "' + _av + '"');
+}
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas");
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ var vs = gl.createShader(gl.VERTEX_SHADER);
+ shouldReturnString("gl.getShaderSource(vs)");
+ shouldReturnString("gl.getShaderInfoLog(vs)");
+ gl.shaderSource(vs, validVertexShaderString);
+ gl.compileShader(vs);
+ shouldReturnString("gl.getShaderSource(vs)");
+ shouldReturnString("gl.getShaderInfoLog(vs)");
+
+ var fs = gl.createShader(gl.FRAGMENT_SHADER);
+ shouldReturnString("gl.getShaderSource(fs)");
+ shouldReturnString("gl.getShaderInfoLog(fs)");
+ gl.shaderSource(fs, validFragmentShaderString);
+ gl.compileShader(fs);
+ shouldReturnString("gl.getShaderSource(fs)");
+ shouldReturnString("gl.getShaderInfoLog(fs)");
+
+ var prog = gl.createProgram();
+ shouldReturnString("gl.getProgramInfoLog(prog)");
+ gl.attachShader(prog, vs);
+ gl.attachShader(prog, fs);
+ gl.linkProgram(prog);
+ shouldReturnString("gl.getProgramInfoLog(prog)");
+
+ // Make sure different numbers of extensions doesn't result in
+ // different test output.
+ var exts = gl.getSupportedExtensions();
+ var allPassed = true;
+ for (var ii = 0; ii < exts.length; ++ii) {
+ var s = exts[ii];
+ if (typeof s != "string") {
+ shouldReturnString("gl.getSupportedExtensions()[" + s + "]");
+ allPassed = false;
+ }
+ }
+ if (allPassed) {
+ testPassed('getSupportedExtensions() returns an array of strings');
+ }
+
+ shouldReturnString("gl.getParameter(gl.VENDOR)");
+ shouldReturnString("gl.getParameter(gl.RENDERER)");
+ shouldReturnString("gl.getParameter(gl.VERSION)");
+ shouldReturnString("gl.getParameter(gl.SHADING_LANGUAGE_VERSION)");
+}
+
+debug("");
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/hint.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/hint.html
new file mode 100644
index 0000000000..f49f2248fc
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/hint.html
@@ -0,0 +1,124 @@
+<!--
+Copyright (c) 2022 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+const wtu = WebGLTestUtils;
+description("Tests webgl.hint()");
+
+const gl = wtu.create3DContext();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup should succeed");
+
+// From https://kdashg.github.io/misc/gl/search-headers.html#str=_HINT
+const HINT_TARGETS = {
+ GL_GENERATE_MIPMAP_HINT: 0x8192,
+ GL_FRAGMENT_SHADER_DERIVATIVE_HINT: 0x8B8B,
+ GL_BINNING_CONTROL_HINT_QCOM: 0x8FB0,
+ GL_PROGRAM_BINARY_RETRIEVABLE_HINT: 0x8257,
+ GL_LINE_SMOOTH_HINT: 0x0C52,
+ GL_POLYGON_SMOOTH_HINT: 0x0C53,
+ EGL_PRODUCER_MAX_FRAME_HINT_NV: 0x3337,
+ EGL_CONSUMER_MAX_FRAME_HINT_NV: 0x3338,
+ EGL_YUV_COLOR_SPACE_HINT_EXT: 0x327B,
+ EGL_SAMPLE_RANGE_HINT_EXT: 0x327C,
+ EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT: 0x327D,
+ EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT: 0x327E,
+ EGL_LOCK_USAGE_HINT_KHR: 0x30C5,
+ GL_TEXTURE_COMPRESSION_HINT: 0x84EF,
+ GL_TEXTURE_STORAGE_HINT_APPLE: 0x85BC,
+ GL_TRANSFORM_HINT_APPLE: 0x85B1,
+ GL_VERTEX_ARRAY_STORAGE_HINT_APPLE: 0x851F,
+ GL_CLIP_VOLUME_CLIPPING_HINT_EXT: 0x80F0,
+ GL_PACK_CMYK_HINT_EXT: 0x800E,
+ GL_UNPACK_CMYK_HINT_EXT: 0x800F,
+ GL_MULTISAMPLE_FILTER_HINT_NV: 0x8534,
+ GL_PREFER_DOUBLEBUFFER_HINT_PGI: 0x1A1F8,
+ GL_CONSERVE_MEMORY_HINT_PGI: 0x1A1FD,
+ GL_RECLAIM_MEMORY_HINT_PGI: 0x1A1FE,
+ GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI: 0x1A203,
+ GL_NATIVE_GRAPHICS_END_HINT_PGI: 0x1A204,
+ GL_ALWAYS_FAST_HINT_PGI: 0x1A20C,
+ GL_ALWAYS_SOFT_HINT_PGI: 0x1A20D,
+ GL_ALLOW_DRAW_OBJ_HINT_PGI: 0x1A20E,
+ GL_ALLOW_DRAW_WIN_HINT_PGI: 0x1A20F,
+ GL_ALLOW_DRAW_FRG_HINT_PGI: 0x1A210,
+ GL_ALLOW_DRAW_MEM_HINT_PGI: 0x1A211,
+ GL_STRICT_DEPTHFUNC_HINT_PGI: 0x1A216,
+ GL_STRICT_LIGHTING_HINT_PGI: 0x1A217,
+ GL_STRICT_SCISSOR_HINT_PGI: 0x1A218,
+ GL_FULL_STIPPLE_HINT_PGI: 0x1A219,
+ GL_CLIP_NEAR_HINT_PGI: 0x1A220,
+ GL_CLIP_FAR_HINT_PGI: 0x1A221,
+ GL_WIDE_LINE_HINT_PGI: 0x1A222,
+ GL_BACK_NORMALS_HINT_PGI: 0x1A223,
+ GL_VERTEX_DATA_HINT_PGI: 0x1A22A,
+ GL_VERTEX_CONSISTENT_HINT_PGI: 0x1A22B,
+ GL_MATERIAL_SIDE_HINT_PGI: 0x1A22C,
+ GL_MAX_VERTEX_HINT_PGI: 0x1A22D,
+ GL_GENERATE_MIPMAP_HINT_SGIS: 0x8192,
+ GL_CONVOLUTION_HINT_SGIX: 0x8316,
+ GL_SCALEBIAS_HINT_SGIX: 0x8322,
+ GL_TEXTURE_MULTI_BUFFER_HINT_SGIX: 0x812E,
+ GL_VERTEX_PRECLIP_HINT_SGIX: 0x83EF,
+ GL_PHONG_HINT_WIN: 0x80EB,
+};
+
+async function testValidTargets(validTargets) {
+ Object.entries(HINT_TARGETS).forEach(kv => {
+ const [k,v] = kv;
+ let targetError = gl.INVALID_ENUM;
+ if (validTargets[v]) {
+ targetError = 0;
+ }
+ debug("");
+ debug(k);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, `gl.hint(HINT_TARGETS.${k}, gl.DONT_CARE-1)`);
+ wtu.shouldGenerateGLError(gl, targetError, `gl.hint(HINT_TARGETS.${k}, gl.DONT_CARE)`);
+ wtu.shouldGenerateGLError(gl, targetError, `gl.hint(HINT_TARGETS.${k}, gl.FASTEST)`);
+ wtu.shouldGenerateGLError(gl, targetError, `gl.hint(HINT_TARGETS.${k}, gl.NICEST)`);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, `gl.hint(HINT_TARGETS.${k}, gl.NICEST+1)`);
+ });
+}
+
+(async () => {
+ const validTargets = {};
+ validTargets[HINT_TARGETS.GL_GENERATE_MIPMAP_HINT] = true;
+
+ if (gl.FRAGMENT_SHADER_DERIVATIVE_HINT) { // webgl2
+ validTargets[gl.FRAGMENT_SHADER_DERIVATIVE_HINT] = true;
+ }
+ testValidTargets(validTargets);
+
+ const ext = gl.getExtension("OES_standard_derivatives");
+ if (ext) {
+ debug("");
+ debug("");
+ debug("-----------------------------------------");
+ debug("Test with OES_standard_derivatives enabled");
+ debug("");
+ validTargets[ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES] = true;
+ testValidTargets(validTargets);
+ }
+
+ finishTest();
+})();
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/instanceof-test.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/instanceof-test.html
new file mode 100644
index 0000000000..aa2464e7a1
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/instanceof-test.html
@@ -0,0 +1,44 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL instanceof 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>
+<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+varying vec2 texCoord;
+void main()
+{
+ gl_Position = vPosition;
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform vec4 color;
+void main()
+{
+ gl_FragColor = color;
+}
+</script>
+
+<script>
+var contextVersion = 1;
+</script>
+<script src="../../js/tests/instanceof-test.js"></script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/invalid-passed-params.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/invalid-passed-params.html
new file mode 100644
index 0000000000..3f1ca805da
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/invalid-passed-params.html
@@ -0,0 +1,170 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/desktop-gl-constants.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("Test for invalid passed parameters");
+
+var wtu = WebGLTestUtils;
+var context = wtu.create3DContext();
+var contextVersion = wtu.getDefault3DContextVersion();
+
+debug("");
+debug("Test createShader()");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.createShader(context.FRAGMENT_SHADER)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.createShader(context.VERTEX_SHADER)");
+wtu.shouldGenerateGLError(context, context.INVALID_ENUM, "context.createShader(0)");
+wtu.shouldGenerateGLError(context, context.INVALID_ENUM, "context.createShader(context.TRIANGLES)");
+
+debug("");
+debug("Test clear()");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.clear(desktopGL['ACCUM_BUFFER_BIT'])");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.clear(desktopGL['ACCUM_BUFFER_BIT'] | context.COLOR_BUFFER_BIT)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.clear(desktopGL['ACCUM_BUFFER_BIT'] | context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT | context.STENCIL_BUFFER_BIT)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT | context.STENCIL_BUFFER_BIT)");
+
+debug("");
+debug("Test {copy}Tex{Sub}Image2D with negative offset/width/height");
+var tex = context.createTexture();
+var pixels = new Uint8Array(2 * 2 * 4);
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.bindTexture(context.TEXTURE_2D, tex)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, -16, -16, 0, context.RGBA, context.UNSIGNED_BYTE, null)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, 16, 16, 0, context.RGBA, context.UNSIGNED_BYTE, null)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.texSubImage2D(context.TEXTURE_2D, 0, -1, -1, 2, 2, context.RGBA, context.UNSIGNED_BYTE, pixels)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.texSubImage2D(context.TEXTURE_2D, 0, 0, 0, -1, -1, context.RGBA, context.UNSIGNED_BYTE, pixels)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.texSubImage2D(context.TEXTURE_2D, 0, 0, 0, 2, 2, context.RGBA, context.UNSIGNED_BYTE, pixels)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.copyTexImage2D(context.TEXTURE_2D, 0, context.RGBA, 0, 0, -1, -1, 0)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.copyTexImage2D(context.TEXTURE_2D, 0, context.RGBA, 0, 0, 16, 16, 0)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.copyTexSubImage2D(context.TEXTURE_2D, 0, -1, -1, 0, 0, 2, 2)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.copyTexSubImage2D(context.TEXTURE_2D, 0, 0, 0, 0, 0, -1, -1)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.copyTexSubImage2D(context.TEXTURE_2D, 0, 0, 0, 0, 0, 2, 2)");
+
+debug("");
+debug("Test renderbufferStorage() with negative width/height");
+var renderbuffer = context.createRenderbuffer();
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.bindRenderbuffer(context.RENDERBUFFER, renderbuffer)");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.renderbufferStorage(context.RENDERBUFFER, context.RGBA4, -2, -2)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.renderbufferStorage(context.RENDERBUFFER, context.RGBA4, 16, 16)");
+
+debug("");
+debug("Test scissor() with negative width/height");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.scissor(0, 0, -2, -2)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.scissor(0, 0, 16, 16)");
+
+debug("");
+debug("Test viewport() with negative width/height");
+wtu.shouldGenerateGLError(context, context.INVALID_VALUE, "context.viewport(0, 0, -2, -2)");
+wtu.shouldGenerateGLError(context, context.NO_ERROR, "context.viewport(0, 0, 16, 16)");
+
+debug("");
+debug("Set up a program to test invalid characters");
+var invalidSet = ['"', '$', '`', '@', '\\', "'"];
+var validUniformName = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
+var validAttribName = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+function generateShaderSource(opt_invalidIdentifierChar, opt_invalidCommentChar) {
+ var invalidIdentifierString = "";
+ var invalidCommentString = "";
+ if (opt_invalidIdentifierChar != undefined) {
+ invalidIdentifierString += opt_invalidIdentifierChar;
+ }
+ if (opt_invalidCommentChar != undefined) {
+ invalidCommentString += opt_invalidCommentChar;
+ }
+ return "uniform float " + validUniformName + invalidIdentifierString + ";\n"
+ + "varying float " + validAttribName + ";\n"
+ + "void main() {\n"
+ + validAttribName + " = " + validUniformName + ";\n"
+ + "gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }\n"
+ + "//.+-/*%<>[](){}^|&~=!:;,?# " + invalidCommentString;
+}
+var vShader = context.createShader(context.VERTEX_SHADER);
+context.shaderSource(vShader, generateShaderSource());
+context.compileShader(vShader);
+shouldBe("context.getError()", "context.NO_ERROR");
+var fShader = context.createShader(context.FRAGMENT_SHADER);
+context.shaderSource(fShader, "precision mediump float;\n"
+ + "varying float " + validAttribName + ";\n"
+ + "void main() {\n"
+ + "gl_FragColor = vec4(" + validAttribName + ", 0.0, 0.0, 1.0); }");
+context.compileShader(fShader);
+shouldBe("context.getError()", "context.NO_ERROR");
+var program = context.createProgram();
+context.attachShader(program, vShader);
+context.attachShader(program, fShader);
+context.linkProgram(program);
+var linkStatus = context.getProgramParameter(program, context.LINK_STATUS);
+shouldBeTrue("linkStatus");
+if (!linkStatus)
+ debug(context.getProgramInfoLog(program));
+shouldBe("context.getError()", "context.NO_ERROR");
+context.bindAttribLocation(program, 1, validAttribName);
+shouldBe("context.getError()", "context.NO_ERROR");
+context.getAttribLocation(program, validAttribName);
+shouldBe("context.getError()", "context.NO_ERROR");
+context.getUniformLocation(program, validUniformName);
+shouldBe("context.getError()", "context.NO_ERROR");
+
+debug("");
+debug("Test shaderSource() with invalid characters");
+for (var i = 0; i < invalidSet.length; ++i) {
+ // Backslash as line-continuation is allowed in WebGL 2.0.
+ if (contextVersion > 1 && invalidSet[i] == '\\')
+ continue;
+ // With recent specification changes from
+ // https://github.com/KhronosGroup/WebGL/pull/3206 , shaderSource no
+ // longer generates INVALID_VALUE.
+ var validShaderSource = generateShaderSource(undefined, invalidSet[i]);
+ context.shaderSource(vShader, validShaderSource);
+ shouldBe("context.getError()", "context.NO_ERROR");
+ var invalidShaderSource = generateShaderSource(invalidSet[i], undefined);
+ context.shaderSource(vShader, invalidShaderSource);
+ shouldBe("context.getError()", "context.NO_ERROR");
+}
+
+debug("");
+debug("Test bindAttribLocation() with invalid characters");
+for (var i = 0; i < invalidSet.length; ++i) {
+ var invalidName = validAttribName + invalidSet[i];
+ context.bindAttribLocation(program, 1, invalidName);
+ shouldBe("context.getError()", "context.INVALID_VALUE");
+}
+
+debug("");
+debug("Test getAttribLocation() with invalid characters");
+for (var i = 0; i < invalidSet.length; ++i) {
+ var invalidName = validAttribName + invalidSet[i];
+ context.getAttribLocation(program, invalidName);
+ shouldBe("context.getError()", "context.INVALID_VALUE");
+}
+
+debug("");
+debug("Test getUniformLocation() with invalid characters");
+for (var i = 0; i < invalidSet.length; ++i) {
+ var invalidName = validUniformName + invalidSet[i];
+ context.getUniformLocation(program, invalidName);
+ shouldBe("context.getError()", "context.INVALID_VALUE");
+}
+
+debug("")
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/is-object.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/is-object.html
new file mode 100644
index 0000000000..f6255ae573
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/is-object.html
@@ -0,0 +1,78 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas">
+<script>
+"use strict";
+var wtu;
+var canvas;
+var gl;
+var shouldGenerateGLError;
+
+var buffer;
+var framebuffer;
+var program;
+var renderbuffer;
+var shader;
+var texture;
+
+description("Tests 'is' calls against non-bound and deleted objects");
+
+wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas");
+shouldGenerateGLError = wtu.shouldGenerateGLError;
+
+shouldGenerateGLError(gl, gl.NO_ERROR, "buffer = gl.createBuffer()");
+shouldBeFalse("gl.isBuffer(buffer)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)");
+shouldBeTrue("gl.isBuffer(buffer)");
+debug("");
+
+shouldGenerateGLError(gl, gl.NO_ERROR, "framebuffer = gl.createFramebuffer()");
+shouldBeFalse("gl.isFramebuffer(framebuffer)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)");
+shouldBeTrue("gl.isFramebuffer(framebuffer)");
+debug("");
+
+shouldGenerateGLError(gl, gl.NO_ERROR, "renderbuffer = gl.createRenderbuffer()");
+shouldBeFalse("gl.isRenderbuffer(renderbuffer)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer)");
+shouldBeTrue("gl.isRenderbuffer(renderbuffer)");
+debug("");
+
+shouldGenerateGLError(gl, gl.NO_ERROR, "texture = gl.createTexture()");
+shouldBeFalse("gl.isTexture(texture)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, texture)");
+shouldBeTrue("gl.isTexture(texture)");
+debug("");
+
+shouldGenerateGLError(gl, gl.NO_ERROR, "program = gl.createProgram()");
+shouldBeTrue("gl.isProgram(program)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteProgram(program)");
+shouldBeFalse("gl.isProgram(program)");
+debug("");
+
+shouldGenerateGLError(gl, gl.NO_ERROR, "shader = gl.createShader(gl.VERTEX_SHADER)");
+shouldBeTrue("gl.isShader(shader)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteShader(shader)");
+shouldBeFalse("gl.isShader(shader)");
+debug("");
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/null-object-behaviour.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/null-object-behaviour.html
new file mode 100644
index 0000000000..a08584cf05
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/null-object-behaviour.html
@@ -0,0 +1,89 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description("Tests calling WebGL APIs without providing the necessary objects");
+
+var context = wtu.create3DContext();
+var program = wtu.loadStandardProgram(context);
+var shader = wtu.loadStandardVertexShader(context);
+var shouldGenerateGLError = wtu.shouldGenerateGLError;
+
+assertMsg(program != null, "Program Compiled");
+assertMsg(shader != null, "Shader Compiled");
+shouldThrow("context.compileShader(undefined)");
+shouldThrow("context.linkProgram(undefined)");
+shouldThrow("context.attachShader(undefined, undefined)");
+shouldThrow("context.attachShader(program, undefined)");
+shouldThrow("context.attachShader(undefined, shader)");
+shouldThrow("context.detachShader(program, undefined)");
+shouldThrow("context.detachShader(undefined, shader)");
+shouldThrow("context.shaderSource(undefined, undefined)");
+shouldThrow("context.shaderSource(undefined, 'foo')");
+shouldThrow("context.bindAttribLocation(undefined, 0, 'foo')");
+shouldThrow("context.bindBuffer(context.ARRAY_BUFFER, 0)");
+shouldThrow("context.bindFramebuffer(context.FRAMEBUFFER, 0)");
+shouldThrow("context.bindRenderbuffer(context.RENDERBUFFER, 0)");
+shouldThrow("context.bindTexture(context.TEXTURE_2D, 0)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindBuffer(context.ARRAY_BUFFER, null)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindFramebuffer(context.FRAMEBUFFER, null)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindRenderbuffer(context.RENDERBUFFER, null)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindTexture(context.TEXTURE_2D, null)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindBuffer(context.ARRAY_BUFFER, undefined)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindFramebuffer(context.FRAMEBUFFER, undefined)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindRenderbuffer(context.RENDERBUFFER, undefined)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindTexture(context.TEXTURE_2D, undefined)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.framebufferRenderbuffer(context.FRAMEBUFFER, context.DEPTH_ATTACHMENT, context.RENDERBUFFER, null)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, null, 0)");
+shouldThrow("context.getProgramParameter(undefined, 0)");
+shouldThrow("context.getProgramInfoLog(undefined, 0)");
+shouldThrow("context.getShaderParameter(undefined, 0)");
+shouldThrow("context.getShaderInfoLog(undefined, 0)");
+shouldThrow("context.getShaderSource(undefined)");
+shouldThrow("context.getUniform(undefined, null)");
+shouldThrow("context.getUniformLocation(undefined, 'foo')");
+
+debug("");
+debug("check with bindings");
+context.bindBuffer(context.ARRAY_BUFFER, context.createBuffer());
+context.bindTexture(context.TEXTURE_2D, context.createTexture());
+shouldGenerateGLError(context, context.NO_ERROR, "context.bufferData(context.ARRAY_BUFFER, 1, context.STATIC_DRAW)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.getBufferParameter(context.ARRAY_BUFFER, context.BUFFER_SIZE)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, 1, 1, 0, context.RGBA, context.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]))");
+shouldGenerateGLError(context, context.NO_ERROR, "context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER, context.NEAREST)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.getTexParameter(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER)");
+
+debug("");
+debug("check without bindings");
+context.bindBuffer(context.ARRAY_BUFFER, null);
+context.bindTexture(context.TEXTURE_2D, null);
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.bufferData(context.ARRAY_BUFFER, 1, context.STATIC_DRAW)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.getBufferParameter(context.ARRAY_BUFFER, context.BUFFER_SIZE)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, 1, 1, 0, context.RGBA, context.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]))");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER, context.NEAREST)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.getTexParameter(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER)");
+
+
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/object-deletion-behaviour.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/object-deletion-behaviour.html
new file mode 100644
index 0000000000..54730ec4eb
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/object-deletion-behaviour.html
@@ -0,0 +1,443 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("Tests deletion behavior for buffer, texture, renderbuffer, shader, and program");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext();
+var shouldGenerateGLError = wtu.shouldGenerateGLError;
+var contextVersion = wtu.getDefault3DContextVersion();
+
+debug("");
+debug("shader and program deletion");
+
+var vertexShader = wtu.loadStandardVertexShader(gl);
+assertMsg(vertexShader, "vertex shader loaded");
+var fragmentShader = wtu.loadStandardFragmentShader(gl);
+assertMsg(fragmentShader, "fragment shader loaded");
+
+var program = gl.createProgram();
+shouldBeNonNull("program");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.attachShader(program, vertexShader)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.attachShader(program, fragmentShader)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.linkProgram(program)");
+shouldBeTrue("gl.getProgramParameter(program, gl.LINK_STATUS)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.useProgram(program)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteShader(vertexShader)");
+shouldBeTrue("gl.isShader(vertexShader)");
+shouldBeTrue("gl.getShaderParameter(vertexShader, gl.DELETE_STATUS)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.detachShader(program, vertexShader)");
+shouldBeFalse("gl.isShader(vertexShader)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteShader(fragmentShader)");
+shouldBeTrue("gl.isShader(fragmentShader)");
+shouldBeTrue("gl.getShaderParameter(fragmentShader, gl.DELETE_STATUS)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteProgram(program)");
+shouldBeTrue("gl.isProgram(program)");
+shouldBeTrue("gl.getProgramParameter(program, gl.DELETE_STATUS)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.useProgram(null)");
+shouldBeFalse("gl.isProgram(program)");
+shouldBeFalse("gl.isShader(fragmentShader)");
+
+debug("");
+debug("texture deletion");
+
+var fbo = gl.createFramebuffer(), fbo2 = gl.createFramebuffer(), fbo3 = gl.createFramebuffer();
+shouldBeNonNull("fbo");
+shouldBeNonNull("fbo2");
+shouldBeNonNull("fbo3");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+
+var tex = gl.createTexture();
+shouldBeNonNull("tex");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
+shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "tex");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
+shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex");
+shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.TEXTURE");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
+// Deleting a texture bound to the currently-bound fbo is the same as
+// detaching the textue from fbo first, then delete the texture.
+shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
+if (contextVersion > 1) {
+ shouldBeNull("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+} else {
+ shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+}
+shouldBeFalse("gl.isTexture(tex)");
+shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindTexture(gl.TEXTURE_2D, tex)");
+shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
+
+var texCubeMap = gl.createTexture();
+shouldBeNonNull("texCubeMap");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCubeMap)");
+shouldBe("gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP)", "texCubeMap");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(texCubeMap)");
+shouldBeFalse("gl.isTexture(texCubeMap)");
+shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCubeMap)");
+shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP)");
+
+var t = gl.createTexture();
+shouldBeNonNull("t");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, t)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(t)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindTexture(gl.TEXTURE_2D, t)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)");
+
+var t2 = gl.createTexture();
+shouldBeNonNull("t2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, t2)");
+shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "t2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE1)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, t2)");
+shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "t2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(t2)");
+shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)");
+shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
+
+debug("");
+debug("renderbuffer deletion");
+
+var rbo = gl.createRenderbuffer(), rbo2 = gl.createRenderbuffer(), rbo3 = gl.createRenderbuffer();
+shouldBeNonNull("rbo");
+shouldBeNonNull("rbo2");
+shouldBeNonNull("rbo3");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
+shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
+shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rbo");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
+// Deleting a renderbuffer bound to the currently-bound fbo is the same as
+// detaching the renderbuffer from fbo first, then delete the renderbuffer.
+shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
+if (contextVersion > 1) {
+ shouldBeNull("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+} else {
+ shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+}
+shouldBeFalse("gl.isRenderbuffer(rbo)");
+shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
+shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo2)");
+shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo3)");
+shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo2");
+
+debug("");
+debug("using deleted renderbuffer");
+rbo = gl.createRenderbuffer();
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
+if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ // make backbuffer red
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(1,0,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // make fbo green
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // Bind backbuffer.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ // delete renderbuffer. It should still be attached to fbo though.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
+ // Use fbo that has deleted rbo.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,0,255,255], "fbo should be blue")');
+ // Bind backbuffer.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
+}
+
+debug("");
+debug("renderbuffer attached twice to same framebuffer");
+rbo = gl.createRenderbuffer();
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
+if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ rbo2 = gl.createRenderbuffer();
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo2)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
+ // attach rbo2 at two attachment points incompatible with it
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rbo2)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo2)");
+ shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rbo2");
+ shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rbo2");
+ // fbo can't be complete as rbo2 is attached at incompatible attachment points
+ shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ // now we delete rbo2, which detaches it from the two attachment points where it currently is attached
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo2)");
+ shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
+ shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
+ // we should now be in the same state as before with only rbo attached, so fbo should be complete again
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rbo");
+}
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+
+
+
+debug("");
+debug("using deleted texture");
+tex = gl.createTexture();
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)");
+if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ // make fbo green
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // Bind backbuffer.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ // delete texture. It should still be attached to fbo though.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [255,0,0,255], "backbuffer should be red")');
+ // Use fbo that has deleted texture.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,255,0,255], "fbo should be green")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,0,255,255], "fbo should be blue")');
+ // Bind backbuffer.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
+}
+
+debug("");
+debug("using deleted renderbuffer");
+rbo = gl.createRenderbuffer();
+shouldBeNonNull("rbo");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
+if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ // make backbuffer red
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(1,0,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // make fbo green
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // delete renderbuffer. It should still be attached to fbo2 though.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
+ // fbo has no attachments
+ shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ // Use fbo2 that has deleted rbo.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,0,255,255], "fbo should be blue")');
+ shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rbo");
+
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ if (contextVersion > 1) {
+ shouldBeNull("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+ } else {
+ shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+ }
+ shouldGenerateGLError(gl, gl.NONE, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)");
+ shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ // Bind backbuffer.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
+}
+
+debug("");
+debug("using deleted texture");
+tex = gl.createTexture();
+shouldBeNonNull("tex");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)");
+if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
+ // make fbo green
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // delete texture. It should still be attached to fbo2 though.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
+ // fbo has no attachments
+ shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ // Use fbo that has deleted texture.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,255,0,255], "fbo should be green")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,0,255,255], "fbo should be blue")');
+ shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex");
+
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ if (contextVersion > 1) {
+ shouldBeNull("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+ } else {
+ shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+ }
+ shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ // Bind backbuffer.
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
+}
+
+debug("");
+debug("buffer deletion");
+
+var buffer = gl.createBuffer();
+shouldBeNonNull("buffer");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)");
+shouldBe("gl.getParameter(gl.ARRAY_BUFFER_BINDING)", "buffer");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(buffer)");
+shouldBeFalse("gl.isBuffer(buffer)");
+shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)");
+shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
+
+var buffer2 = gl.createBuffer();
+shouldBeNonNull("buffer2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer2)");
+shouldBe("gl.getParameter(gl.ARRAY_BUFFER_BINDING)", "buffer2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, null)");
+shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(buffer2)");
+shouldBeFalse("gl.isBuffer(buffer2)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer2)");
+shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
+
+var bufferElement = gl.createBuffer();
+shouldBeNonNull("bufferElement");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferElement)");
+shouldBe("gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING)", "bufferElement");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(bufferElement)");
+shouldBeFalse("gl.isBuffer(bufferElement)");
+shouldBeNull("gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferElement)");
+shouldBeNull("gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING)");
+
+var b = gl.createBuffer();
+shouldBeNonNull("b");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, b)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(b)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindBuffer(gl.ARRAY_BUFFER, b)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW)");
+
+var b1 = gl.createBuffer();
+shouldBeNonNull("b1");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, b1);");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.enableVertexAttribArray(1);");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);");
+var b2 = gl.createBuffer();
+shouldBeNonNull("b2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, b2);");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.enableVertexAttribArray(2);");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.vertexAttribPointer(2, 4, gl.FLOAT, false, 0, 0);");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.enableVertexAttribArray(3);");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.vertexAttribPointer(3, 4, gl.FLOAT, false, 0, 0);");
+shouldBe("gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b1");
+shouldBe("gl.getVertexAttrib(2, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b2");
+shouldBe("gl.getVertexAttrib(3, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(b2);");
+shouldBe("gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b1");
+shouldBeNull("gl.getVertexAttrib(2, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)");
+shouldBeNull("gl.getVertexAttrib(3, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(b1);");
+shouldBeNull("gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)");
+
+debug("");
+debug("framebuffer deletion");
+
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldBe("gl.getParameter(gl.FRAMEBUFFER_BINDING)", "fbo");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fbo)");
+shouldBeFalse("gl.isFramebuffer(fbo)");
+shouldBeNull("gl.getParameter(gl.FRAMEBUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldBeNull("gl.getParameter(gl.FRAMEBUFFER_BINDING)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
+shouldBe("gl.getParameter(gl.FRAMEBUFFER_BINDING)", "fbo2");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fbo3)");
+shouldBe("gl.getParameter(gl.FRAMEBUFFER_BINDING)", "fbo2");
+
+fbo = gl.createFramebuffer();
+rbo = gl.createRenderbuffer();
+shouldBeNonNull("fbo");
+shouldBeNonNull("rbo");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
+shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
+if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
+ // set backbuffer to red
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(1,0,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // set framebuffer to green
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ // check framebuffer
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 16, 16, 1, 1, [0,0,0,0], "outside fbo should be black")');
+ // delete framebuffer. because this was the bound fbo the backbuffer should be active now
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fbo)");
+ // check backbuffer
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 300, 150, [255,0,0,255], "backbuffer should be red")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 300, 0, 300, 300, [0,0,0,0], "outside backbuffer should be black")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 150, 300, 300, [0,0,0,0], "outside backbuffer should be black")');
+ // check drawing to backbuffer
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 300, 150, [0,255,0,255], "fbo should be green")');
+ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
+ // check again because many buggy implementations will have bound to the true backbuffer on deleteFramebuffer.
+ shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 300, 150, [0,255,0,255], "fbo should be green")');
+}
+
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/shader-precision-format.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/shader-precision-format.html
new file mode 100644
index 0000000000..46be2a8145
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/shader-precision-format.html
@@ -0,0 +1,340 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL shader precision format 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>
+<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description(document.title);
+debug("Tests that WebGLShaderPrecisionFormat class and getShaderPrecisionFormat work.");
+debug("");
+var gl = wtu.create3DContext("canvas");
+
+function verifyShaderPrecisionFormat(shadertype, precisiontype) {
+ shouldBeTrue('gl.getShaderPrecisionFormat(' + shadertype + ', ' +
+ precisiontype + ') instanceof WebGLShaderPrecisionFormat');
+}
+
+debug("");
+debug("Test that getShaderPrecisionFormat returns a WebGLShaderPrecisionFormat object.");
+debug("");
+
+verifyShaderPrecisionFormat('gl.VERTEX_SHADER', 'gl.LOW_FLOAT');
+verifyShaderPrecisionFormat('gl.VERTEX_SHADER', 'gl.MEDIUM_FLOAT');
+verifyShaderPrecisionFormat('gl.VERTEX_SHADER', 'gl.HIGH_FLOAT');
+verifyShaderPrecisionFormat('gl.VERTEX_SHADER', 'gl.LOW_INT');
+verifyShaderPrecisionFormat('gl.VERTEX_SHADER', 'gl.MEDIUM_INT');
+verifyShaderPrecisionFormat('gl.VERTEX_SHADER', 'gl.HIGH_INT');
+verifyShaderPrecisionFormat('gl.FRAGMENT_SHADER', 'gl.LOW_FLOAT');
+verifyShaderPrecisionFormat('gl.FRAGMENT_SHADER', 'gl.MEDIUM_FLOAT');
+verifyShaderPrecisionFormat('gl.FRAGMENT_SHADER', 'gl.HIGH_FLOAT');
+verifyShaderPrecisionFormat('gl.FRAGMENT_SHADER', 'gl.LOW_INT');
+verifyShaderPrecisionFormat('gl.FRAGMENT_SHADER', 'gl.MEDIUM_INT');
+verifyShaderPrecisionFormat('gl.FRAGMENT_SHADER', 'gl.HIGH_INT');
+
+debug("");
+debug("Test that getShaderPrecisionFormat throws an error with invalid parameters.");
+debug("");
+
+wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, 'gl.getShaderPrecisionFormat(gl.HIGH_INT, gl.VERTEX_SHADER)');
+
+debug("");
+debug("Test that WebGLShaderPrecisionFormat values are sensible.");
+debug("");
+
+// The minimum values are from OpenGL ES Shading Language spec, section 4.5.
+
+var shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.LOW_FLOAT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 1');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 1');
+shouldBeTrue('shaderPrecisionFormat.precision >= 8');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 14');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 14');
+shouldBeTrue('shaderPrecisionFormat.precision >= 10');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 62');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 62');
+shouldBeTrue('shaderPrecisionFormat.precision >= 16');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.LOW_INT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 8');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 8');
+shouldBeTrue('shaderPrecisionFormat.precision == 0');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_INT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 10');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 10');
+shouldBeTrue('shaderPrecisionFormat.precision == 0');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_INT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 16');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 16');
+shouldBeTrue('shaderPrecisionFormat.precision == 0');
+
+var shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.LOW_FLOAT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 1');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 1');
+shouldBeTrue('shaderPrecisionFormat.precision >= 8');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 14');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 14');
+shouldBeTrue('shaderPrecisionFormat.precision >= 10');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.LOW_INT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 8');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 8');
+shouldBeTrue('shaderPrecisionFormat.precision == 0');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_INT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin >= 10');
+shouldBeTrue('shaderPrecisionFormat.rangeMax >= 10');
+shouldBeTrue('shaderPrecisionFormat.precision == 0');
+
+debug("");
+debug("Test optional highp support in fragment shaders.");
+debug("");
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
+shouldBeTrue('(shaderPrecisionFormat.rangeMin == 0 && shaderPrecisionFormat.rangeMax == 0 && shaderPrecisionFormat.precision == 0) || (shaderPrecisionFormat.rangeMin >= 62 && shaderPrecisionFormat.rangeMax >= 62 && shaderPrecisionFormat.precision >= 16)');
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_INT);
+shouldBeTrue('(shaderPrecisionFormat.rangeMin == 0 && shaderPrecisionFormat.rangeMax == 0 && shaderPrecisionFormat.precision == 0) || (shaderPrecisionFormat.rangeMin >= 16 && shaderPrecisionFormat.rangeMax >= 16 && shaderPrecisionFormat.precision == 0)');
+
+debug("");
+debug("Test that getShaderPrecisionFormat returns the same thing every call.");
+debug("");
+
+shaderPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.LOW_FLOAT);
+var shaderPrecisionFormat2 = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.LOW_FLOAT);
+shouldBeTrue('shaderPrecisionFormat.rangeMin == shaderPrecisionFormat2.rangeMin');
+shouldBeTrue('shaderPrecisionFormat.rangeMax == shaderPrecisionFormat2.rangeMax');
+shouldBeTrue('shaderPrecisionFormat.precision == shaderPrecisionFormat2.precision');
+
+debug("");
+debug("Test that specified precision matches rendering results");
+debug("");
+
+function testRenderPrecisionSetup(gl, shaderPair) {
+ const program = wtu.setupProgram(gl, shaderPair);
+
+ // Create a buffer and setup an attribute.
+ // We wouldn't need this except for a bug in Safari and arguably
+ // this should be removed from the test but we can't test the test itself
+ // without until the bug is fixed.
+ // see https://bugs.webkit.org/show_bug.cgi?id=197592
+ {
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
+ gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW);
+ const loc = gl.getAttribLocation(program, 'position');
+ gl.enableVertexAttribArray(loc);
+ gl.vertexAttribPointer(loc, 1, gl.UNSIGNED_BYTE, false, 0, 0);
+ }
+
+ gl.useProgram(program);
+
+ return program;
+}
+
+function testRenderPrecision(gl, shaderType, type, precision, expected, msg) {
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.POINTS, 0, 1);
+
+ const pixel = new Uint8Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
+
+ wtu.checkCanvasRect(gl, 0, 0, 1, 1, expected, msg, 5);
+}
+
+function testRenderPrecisionFloat(gl, precisionEnum, precision) {
+ function test(gl, shaderPair, shaderType) {
+ const format = gl.getShaderPrecisionFormat(shaderType, precisionEnum);
+ const value = 2 ** format.precision - 1;
+
+ const length = v => Math.sqrt(v.reduce((sum, v) => sum + v * v, 0));
+ const normalize = (v) => {
+ const l = length(v);
+ return v.map(v => v / l);
+ };
+
+ const input = [Math.sqrt(value), Math.sqrt(value), Math.sqrt(value)];
+ const expected = [...normalize(input).map(v => (v * 0.5 + 0.5) * 255 | 0), 255];
+
+ const msg = `${wtu.glEnumToString(gl, shaderType)}: ${precision} float precision: ${format.precision}, rangeMin: ${format.rangeMin}, rangeMax: ${format.rangeMax}`;
+ const program = testRenderPrecisionSetup(gl, shaderPair);
+ const vLocation = gl.getUniformLocation(program, 'v');
+ gl.uniform3fv(vLocation, input);
+ testRenderPrecision(gl, shaderType, 'float', precision, expected, msg);
+ }
+
+ {
+ const vs = `
+ attribute vec4 position;
+ uniform ${precision} vec3 v;
+ varying ${precision} vec4 v_result;
+ void main() {
+ gl_Position = position;
+ gl_PointSize = 1.0;
+ v_result = vec4(normalize(v) * 0.5 + 0.5, 1);
+ }
+ `;
+
+ const fs = `
+ precision ${precision} float;
+ varying ${precision} vec4 v_result;
+ void main() {
+ gl_FragColor = v_result;
+ }
+ `;
+
+ test(gl, [vs, fs], gl.VERTEX_SHADER);
+ }
+
+ {
+ const vs = `
+ attribute vec4 position;
+ void main() {
+ gl_Position = position;
+ gl_PointSize = 1.0;
+ }
+ `;
+
+ const fs = `
+ precision ${precision} float;
+ uniform ${precision} vec3 v;
+ void main() {
+ gl_FragColor = vec4(normalize(v) * 0.5 + 0.5, 1);
+ }
+ `;
+
+ test(gl, [vs, fs], gl.FRAGMENT_SHADER);
+ }
+}
+
+function testRenderPrecisionInt(gl, precisionEnum, precision) {
+ function test(gl, shaderPair, shaderType) {
+ const format = gl.getShaderPrecisionFormat(shaderType, precisionEnum);
+ const value = 1 << (format.rangeMax - 1);
+
+ const input = [value, value, value, value];
+ const expected = [255, 255, 255, 255];
+
+ const msg = `${wtu.glEnumToString(gl, shaderType)}: ${precision} int precision: ${format.precision}, rangeMin: ${format.rangeMin}, rangeMax: ${format.rangeMax}`;
+ const program = testRenderPrecisionSetup(gl, shaderPair);
+ gl.uniform1i(gl.getUniformLocation(program, 'v'), value);
+ gl.uniform1f(gl.getUniformLocation(program, 'f'), value);
+ testRenderPrecision(gl, shaderType, 'int', precision, expected, msg);
+ }
+
+ {
+ const vs = `
+ attribute vec4 position;
+ uniform ${precision} int v;
+ uniform highp float f;
+ varying vec4 v_result;
+
+ void main() {
+ gl_Position = position;
+ gl_PointSize = 1.0;
+ float diff = abs(float(v) - f);
+ bool pass = diff < 1.0;
+ v_result = vec4(pass);
+ }
+ `;
+
+ const fs = `
+ precision mediump float;
+ varying vec4 v_result;
+ void main() {
+ gl_FragColor = v_result;
+ }
+ `;
+ test(gl, [vs, fs], gl.VERTEX_SHADER);
+ }
+
+ {
+ const vs = `
+ attribute vec4 position;
+ void main() {
+ gl_Position = position;
+ gl_PointSize = 1.0;
+ }
+ `;
+
+ const fs = `
+ precision ${precision} float;
+ uniform ${precision} int v;
+ uniform mediump float f;
+
+ void main() {
+ mediump float diff = abs(float(v) - f);
+ bool pass = diff < 1.0;
+ gl_FragColor = vec4(pass);
+ }
+ `;
+
+ test(gl, [vs, fs], gl.FRAGMENT_SHADER);
+ }
+}
+
+// because the canvas can be 16 bit IIRC
+const fb = gl.createFramebuffer(gl.FRAMEBUFFER);
+gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+
+const tex = gl.createTexture();
+gl.bindTexture(gl.TEXTURE_2D, tex);
+gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+gl.framebufferTexture2D(
+ gl.FRAMEBUFFER,
+ gl.COLOR_ATTACHMENT0,
+ gl.TEXTURE_2D,
+ tex,
+ 0);
+
+gl.viewport(0, 0, 1, 1);
+
+{
+ testRenderPrecisionFloat(gl, gl.LOW_FLOAT, 'lowp');
+ testRenderPrecisionFloat(gl, gl.MEDIUM_FLOAT, 'mediump');
+
+ const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
+ if (format.precision !== 0) {
+ testRenderPrecisionFloat(gl, gl.HIGH_FLOAT, 'highp');
+ }
+}
+
+{
+ testRenderPrecisionInt(gl, gl.LOW_INT, 'lowp');
+ testRenderPrecisionInt(gl, gl.MEDIUM_INT, 'mediump');
+
+ const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_INT);
+ if (format.rangeMax !== 0) {
+ testRenderPrecisionInt(gl, gl.HIGH_INT, 'highp');
+ }
+}
+
+finishTest();
+</script>
+
+</body>
+</html>
+
+
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/type-conversion-test.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/type-conversion-test.html
new file mode 100644
index 0000000000..bb04f3ba00
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/type-conversion-test.html
@@ -0,0 +1,151 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description("Tests calling WebGL APIs with various types");
+
+var context = wtu.create3DContext();
+var program = wtu.loadStandardProgram(context);
+var shader = wtu.loadStandardVertexShader(context);
+
+assertMsg(program != null, "Program Compiled");
+assertMsg(shader != null, "Shader Compiled");
+
+var loc = context.getUniformLocation(program, "u_modelViewProjMatrix");
+assertMsg(loc != null, "getUniformLocation succeeded");
+
+var buffer = context.createBuffer();
+context.bindBuffer(context.ARRAY_BUFFER, buffer);
+var texture = context.createTexture();
+context.bindTexture(context.TEXTURE_2D, texture);
+context.useProgram(program);
+
+var args = [
+ { type: "number", value: 0 },
+ { type: "number", value: 2 },
+ { type: "string that is NaN", value: "foo", },
+ { type: "string that is number", value: "2", },
+ { type: "null", value: null },
+ { type: "Empty Array", value: [] },
+ { type: "Object", value: {} },
+ { type: "Array of Number", value: [2] },
+ { type: "Array of String", value: ["foo"] },
+ { type: "Array of String that is number", value: ["0"] },
+ { type: "Array of String that is number", value: ["2"] },
+ { type: "TypedArray", value: new Float32Array(1) }
+];
+
+var argument;
+
+for (var i = 0; i < args.length; ++i) {
+ argument = args[i].value;
+ var func1 = shouldBeUndefined;
+ var func2 = shouldBeNonNull;
+ if (argument == 2) {
+ func2 = shouldBeNull;
+ }
+ var func3 = shouldBeNull;
+ debug("");
+ debug("testing type of " + args[i].type + " : value = " + argument);
+ func1("context.bindAttribLocation(program, argument, 'foo')");
+ func1("context.blendColor(argument, argument, argument, argument)");
+ func1("context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW)");
+ func1("context.bufferData(context.ARRAY_BUFFER, new Float32Array(10), context.STATIC_DRAW)");
+ func1("context.bufferSubData(context.ARRAY_BUFFER, argument, new Float32Array(2))");
+ func1("context.clear(argument)")
+ func1("context.clearColor(argument, 0, 0, 0)");
+ func1("context.clearColor(0, argument, 0, 0)");
+ func1("context.clearColor(0, 0, argument, 0)");
+ func1("context.clearColor(0, 0, 0, argument)");
+ func1("context.clearDepth(argument)");
+ func1("context.clearStencil(argument)");
+ func1("context.copyTexImage2D(context.TEXTURE_2D, argument, context.RGBA, 0, 0, 1, 1, 0)");
+ func1("context.copyTexImage2D(context.TEXTURE_2D, 0, context.RGBA, argument, 0, 1, 1, 0)");
+ func1("context.copyTexImage2D(context.TEXTURE_2D, 0, context.RGBA, 0, argument, 1, 1, 0)");
+ func1("context.copyTexImage2D(context.TEXTURE_2D, 0, context.RGBA, 0, 0, argument, 1, 0)");
+ func1("context.copyTexImage2D(context.TEXTURE_2D, 0, context.RGBA, 0, 0, 0, argument, 0)");
+ func1("context.copyTexSubImage2D(context.TEXTURE_2D, argument, 0, 0, 0, 0, 0, 0)");
+ func1("context.copyTexSubImage2D(context.TEXTURE_2D, 0, argument, 0, 0, 0, 0, 0)");
+ func1("context.copyTexSubImage2D(context.TEXTURE_2D, 0, 0, argument, 0, 0, 0, 0)");
+ func1("context.copyTexSubImage2D(context.TEXTURE_2D, 0, 0, 0, argument, 0, 0, 0)");
+ func1("context.copyTexSubImage2D(context.TEXTURE_2D, 0, 0, 0, 0, argument, 0, 0)");
+ func1("context.copyTexSubImage2D(context.TEXTURE_2D, 0, 0, 0, 0, 0, argument, 0)");
+ func1("context.copyTexSubImage2D(context.TEXTURE_2D, 0, 0, 0, 0, 0, 0, argument)");
+ func1("context.depthMask(argument)");
+ func1("context.depthRange(argument, 1)");
+ func1("context.depthRange(0, argument)");
+ func1("context.drawArrays(context.POINTS, argument, 1)");
+ func1("context.drawArrays(context.POINTS, 0, argument)");
+ //func1("context.drawElements(...)");
+ func1("context.enableVertexAttribArray(argument)");
+ func1("context.disableVertexAttribArray(argument)");
+ func2("context.getActiveAttrib(program, argument)");
+ func2("context.getActiveUniform(program, argument)");
+ func3("context.getParameter(argument)");
+ func1("context.lineWidth(argument)");
+ func1("context.polygonOffset(argument, 0)");
+ func1("context.polygonOffset(0, argument)");
+ //func1("context.readPixels(...)");
+ //func1("context.renderbufferStorage(...)");
+ func1("context.sampleCoverage(argument, 0)");
+ func1("context.sampleCoverage(0, argument)");
+ func1("context.scissor(argument, 0, 10, 10)");
+ func1("context.scissor(0, argument, 10, 10)");
+ func1("context.scissor(0, 0, argument, 10)");
+ func1("context.scissor(0, 0, 10, argument)");
+ func1("context.shaderSource(shader, argument)");
+ func1("context.stencilFunc(context.NEVER, argument, 255)");
+ func1("context.stencilFunc(context.NEVER, 0, argument)");
+ //func1("context.stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)");
+ func1("context.stencilMask(argument)");
+ //func1("context.stencilMaskSeparate(context.FRONT, argument);
+ //func1("context.texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView pixels)");
+ //func1("context.texParameterf(GLenum target, GLenum pname, GLfloat param)");
+ //func1("context.texParameteri(GLenum target, GLenum pname, GLint param)");
+ //func1("context.texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,GLsizei width, GLsizei height,GLenum format, GLenum type, ArrayBufferView pixels)");
+ func1("context.uniform1i(loc, argument)");
+ func1("context.uniform2i(loc, argument, 0)");
+ func1("context.uniform2i(loc, 0, argument)");
+ func1("context.uniform3i(loc, argument, 0, 0)");
+ func1("context.uniform3i(loc, 0, argument, 0)");
+ func1("context.uniform3i(loc, 0, 0, argument)");
+ func1("context.uniform4i(loc, argument, 0, 0, 0)");
+ func1("context.uniform4i(loc, 0, argument, 0, 0)");
+ func1("context.uniform4i(loc, 0, 0, argument, 0)");
+ func1("context.uniform4i(loc, 0, 0, 0, argument)");
+ func1("context.uniform1f(loc, argument)");
+ func1("context.uniform2f(loc, argument, 0)");
+ func1("context.uniform2f(loc, 0, argument)");
+ func1("context.uniform3f(loc, argument, 0, 0)");
+ func1("context.uniform3f(loc, 0, argument, 0)");
+ func1("context.uniform3f(loc, 0, 0, argument)");
+ func1("context.uniform4f(loc, argument, 0, 0, 0)");
+ func1("context.uniform4f(loc, 0, argument, 0, 0)");
+ func1("context.uniform4f(loc, 0, 0, argument, 0)");
+ func1("context.uniform4f(loc, 0, 0, 0, argument)");
+}
+
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
+
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/uninitialized-test.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/uninitialized-test.html
new file mode 100644
index 0000000000..c8f935dd1b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/uninitialized-test.html
@@ -0,0 +1,262 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Uninitialized GL Resources 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>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+"use strict";
+description("Tests to check user code cannot access uninitialized data from GL resources.");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas");
+if (!gl)
+ testFailed("Context created.");
+else
+ testPassed("Context created.");
+
+function setupTexture(texWidth, texHeight) {
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texWidth, texHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ // this can be quite undeterministic so to improve odds of seeing uninitialized data write bits
+ // into tex then delete texture then re-create one with same characteristics (driver will likely reuse mem)
+ // with this trick on r59046 WebKit/OSX I get FAIL 100% of the time instead of ~15% of the time.
+
+ var badData = new Uint8Array(texWidth * texHeight * 4);
+ for (var i = 0; i < badData.length; ++i)
+ badData[i] = i % 255;
+
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, texWidth, texHeight, gl.RGBA, gl.UNSIGNED_BYTE, badData);
+ gl.finish(); // make sure it has been uploaded
+
+ gl.deleteTexture(texture);
+ gl.finish(); // make sure it has been deleted
+
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ return texture;
+}
+
+function checkNonZeroPixels(texture, texWidth, texHeight, skipX, skipY, skipWidth, skipHeight, skipR, skipG, skipB, skipA) {
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ var fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ var data = new Uint8Array(texWidth * texHeight * 4);
+ gl.readPixels(0, 0, texWidth, texHeight, gl.RGBA, gl.UNSIGNED_BYTE, data);
+
+ var k = 0;
+ for (var y = 0; y < texHeight; ++y) {
+ for (var x = 0; x < texWidth; ++x) {
+ var index = (y * texWidth + x) * 4;
+ if (x >= skipX && x < skipX + skipWidth && y >= skipY && y < skipY + skipHeight) {
+ if (data[index] != skipR || data[index + 1] != skipG || data[index + 2] != skipB || data[index + 3] != skipA) {
+ testFailed("non-zero pixel values are wrong");
+ return;
+ }
+ } else {
+ for (var i = 0; i < 4; ++i) {
+ if (data[index + i] != 0)
+ k++;
+ }
+ }
+ }
+ }
+ if (k) {
+ testFailed("Found " + k + " non-zero bytes");
+ } else {
+ testPassed("All data initialized");
+ }
+}
+
+var width = 512;
+var height = 512;
+
+debug("");
+debug("Reading an uninitialized texture (texImage2D) should succeed with all bytes set to 0.");
+
+var tex = setupTexture(width, height);
+gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+checkNonZeroPixels(tex, width, height, 0, 0, 0, 0, 0, 0, 0, 0);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Reading a partially initialized texture (texImage2D) should succeed with all uninitialized bytes set to 0 and initialized bytes untouched.");
+
+var tex = setupTexture(width, height);
+gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+var data = new Uint8Array(4);
+var r = 108;
+var g = 72;
+var b = 36;
+var a = 9;
+data[0] = r;
+data[1] = g;
+data[2] = b;
+data[3] = a;
+gl.texSubImage2D(gl.TEXTURE_2D, 0, width/2, height/2, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, data);
+checkNonZeroPixels(tex, width, height, width/2, height/2, 1, 1, r, g, b, a);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Reading an uninitialized portion of a texture (copyTexImage2D) should succeed with all bytes set to 0.");
+
+var tex = setupTexture(width, height);
+var fbo = gl.createFramebuffer();
+gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+var rbo = gl.createRenderbuffer();
+gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+var fboWidth = 16;
+var fboHeight = 16;
+gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, fboWidth, fboHeight);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
+shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+gl.clearColor(1.0, 0.0, 0.0, 1.0);
+gl.clear(gl.COLOR_BUFFER_BIT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, width, height, 0);
+checkNonZeroPixels(tex, width, height, 0, 0, fboWidth, fboHeight, 255, 0, 0, 255);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Reading an uninitialized portion of a texture (copyTexImage2D with negative x and y) should succeed with all bytes set to 0.");
+
+var tex = setupTexture(width, height);
+var fbo = gl.createFramebuffer();
+gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+var rbo = gl.createRenderbuffer();
+gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+var fboWidth = 16;
+var fboHeight = 16;
+gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, fboWidth, fboHeight);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
+shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+gl.clearColor(1.0, 0.0, 0.0, 1.0);
+gl.clear(gl.COLOR_BUFFER_BIT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+var x = -8;
+var y = -8;
+gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, x, y, width, height, 0);
+checkNonZeroPixels(tex, width, height, -x, -y, fboWidth, fboHeight, 255, 0, 0, 255);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Reading an uninitialized portion of a texture (copyTexImage2D from WebGL internal fbo) should succeed with all bytes set to 0.");
+
+var tex = setupTexture(width, height);
+gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+gl.clearColor(0.0, 1.0, 0.0, 0.0);
+gl.clear(gl.COLOR_BUFFER_BIT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, width, height, 0);
+checkNonZeroPixels(tex, width, height, 0, 0, gl.canvas.width, gl.canvas.height, 0, 255, 0, 0);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Reading an uninitialized portion of a texture (copyTexSubImage2D) should succeed with all bytes set to 0.");
+
+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);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+var fbo = gl.createFramebuffer();
+gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+var rbo = gl.createRenderbuffer();
+gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+var fboWidth = 16;
+var fboHeight = 16;
+gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, fboWidth, fboHeight);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
+shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+gl.clearColor(1.0, 0.0, 0.0, 1.0);
+gl.clear(gl.COLOR_BUFFER_BIT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
+checkNonZeroPixels(tex, width, height, 0, 0, fboWidth, fboHeight, 255, 0, 0, 255);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Reading an uninitialized portion of a texture (copyTexSubImage2D with negative x and y) should succeed with all bytes set to 0.");
+
+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);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+var fbo = gl.createFramebuffer();
+gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+var rbo = gl.createRenderbuffer();
+gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+var fboWidth = 16;
+var fboHeight = 16;
+gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, fboWidth, fboHeight);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
+shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+gl.clearColor(1.0, 0.0, 0.0, 1.0);
+gl.clear(gl.COLOR_BUFFER_BIT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+var x = -8;
+var y = -8;
+gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x, y, width, height);
+checkNonZeroPixels(tex, width, height, -x, -y, fboWidth, fboHeight, 255, 0, 0, 255);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Reading an uninitialized portion of a texture (copyTexSubImage2D from WebGL internal fbo) should succeed with all bytes set to 0.");
+
+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);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+gl.clearColor(0.0, 1.0, 0.0, 0.0);
+gl.clear(gl.COLOR_BUFFER_BIT);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
+checkNonZeroPixels(tex, width, height, 0, 0, canvas.width, canvas.height, 0, 255, 0, 0);
+gl.deleteTexture(tex);
+gl.finish();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+//TODO: uninitialized vertex array buffer
+//TODO: uninitialized vertex elements buffer
+//TODO: uninitialized framebuffer? (implementations would need to do a GL clear at first binding?)
+//TODO: uninitialized renderbuffer? (implementations would need to do a GL clear at first binding?)
+//TODO: uninitialized uniform arrays?
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
+
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific-stencil-settings.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific-stencil-settings.html
new file mode 100644
index 0000000000..770a107dc9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific-stencil-settings.html
@@ -0,0 +1,299 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL stencil mask/func front-state-back-state equality test</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description("Tests that stencil mask/func are validated correctly when the front state and back state differ.");
+
+var gl;
+
+function checkDrawError(errIfMismatch) {
+ wtu.shouldGenerateGLError(gl, errIfMismatch, "wtu.dummySetProgramAndDrawNothing(gl)");
+}
+
+function setStencilMask(mask) {
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilMaskSeparate(gl.FRONT, " + mask[0] + ")");
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilMaskSeparate(gl.BACK, " + mask[1] + ")");
+}
+
+function testStencilMaskCase(mask, error) {
+ setStencilMask(mask);
+ // If an error is generated, it should be at draw time.
+ checkDrawError(error);
+}
+
+function testStencilMask(errIfMismatch) {
+ testStencilMaskCase([0, 256], gl.NO_ERROR);
+ testStencilMaskCase([1, 256], errIfMismatch);
+ testStencilMaskCase([1, 257], gl.NO_ERROR);
+ testStencilMaskCase([1, 258], errIfMismatch);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilMask(1023)", "resetting stencilMask");
+}
+
+function setStencilFunc(ref, mask) {
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilFuncSeparate(gl.FRONT, gl.ALWAYS, " + ref[0] + ", " + mask[0] + ")");
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilFuncSeparate(gl.BACK, gl.ALWAYS, " + ref[1] + ", " + mask[1] + ")");
+}
+
+function testStencilFuncCase(ref, mask, error) {
+ setStencilFunc(ref, mask);
+ // If an error is generated, it should be at draw time.
+ checkDrawError(error);
+}
+
+function testStencilFunc(errIfMismatch) {
+ testStencilFuncCase([ 256, 257], [1023, 1023], gl.NO_ERROR);
+ testStencilFuncCase([ 256, 254], [1023, 1023], errIfMismatch);
+
+ testStencilFuncCase([ -1, 0], [1023, 1023], gl.NO_ERROR);
+ testStencilFuncCase([ -1, 254], [1023, 1023], errIfMismatch);
+
+ testStencilFuncCase([ 0, 0], [ 1, 257], gl.NO_ERROR);
+ testStencilFuncCase([ 0, 0], [ 1, 258], errIfMismatch);
+
+ testStencilFuncCase([ 1, 1], [1024, 2048], gl.NO_ERROR);
+ testStencilFuncCase([ 1, 1], [2048, 1024], gl.NO_ERROR);
+
+ testStencilFuncCase([ -1, -1], [1023, 1023], gl.NO_ERROR);
+ testStencilFuncCase([ -1, 0], [1023, 1023], gl.NO_ERROR);
+ testStencilFuncCase([ 0, -1], [1023, 1023], gl.NO_ERROR);
+ testStencilFuncCase([ 0, 0], [1023, 1023], gl.NO_ERROR);
+
+ testStencilFuncCase([ -1, 255], [1023, 1023], errIfMismatch);
+ testStencilFuncCase([ 0, 256], [1023, 1023], errIfMismatch);
+ testStencilFuncCase([ 0, 1024], [1023, 1023], errIfMismatch);
+ testStencilFuncCase([ 1, 257], [1023, 1023], errIfMismatch);
+ testStencilFuncCase([ 255, -1], [1023, 1023], errIfMismatch);
+ testStencilFuncCase([ 256, 0], [1023, 1023], errIfMismatch);
+ testStencilFuncCase([1024, 0], [1023, 1023], errIfMismatch);
+ testStencilFuncCase([ 257, 1], [1023, 1023], errIfMismatch);
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilFunc(gl.ALWAYS, 0, 1023)", "resetting stencilFunc");
+}
+
+//
+// Tests of the default framebuffer
+//
+
+debug("");
+
+debug("Testing default framebuffer with { stencil: true }");
+gl = wtu.create3DContext(undefined, { stencil: true });
+{
+ gl.enable(gl.STENCIL_TEST);
+ testStencilMaskCase([1, 256], gl.INVALID_OPERATION);
+ testStencilFuncCase([256, 0], [1023, 1023], gl.INVALID_OPERATION);
+}
+
+debug("Testing default framebuffer with { stencil: false }");
+gl = wtu.create3DContext(undefined, { stencil: false });
+{
+ // with { stencil: false }
+ gl.enable(gl.STENCIL_TEST);
+ testStencilMaskCase([1, 256], gl.NO_ERROR);
+ testStencilFuncCase([256, 0], [1023, 1023], gl.NO_ERROR);
+}
+// (continue using this GL context for the other tests)
+
+//
+// Tests with a framebuffer object
+//
+
+const fb = gl.createFramebuffer();
+gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+const colorRB = gl.createRenderbuffer();
+gl.bindRenderbuffer(gl.RENDERBUFFER, colorRB);
+gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 1, 1);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRB);
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "initial framebuffer setup")
+
+function runWithStencilSettings(haveDepthBuffer, haveStencilBuffer, enableStencilTest, fn) {
+ let rbo = null;
+ let attachment;
+ if (haveDepthBuffer || haveStencilBuffer) {
+ rbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+
+ let internalformat;
+ if (haveDepthBuffer && haveStencilBuffer) {
+ internalformat = gl.DEPTH_STENCIL;
+ attachment = gl.DEPTH_STENCIL_ATTACHMENT;
+ } else if (haveDepthBuffer) {
+ internalformat = gl.DEPTH_COMPONENT16;
+ attachment = gl.DEPTH_ATTACHMENT;
+ } else if (haveStencilBuffer) {
+ internalformat = gl.STENCIL_INDEX8;
+ attachment = gl.STENCIL_ATTACHMENT;
+ }
+ gl.renderbufferStorage(gl.RENDERBUFFER, internalformat, 1, 1);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, rbo);
+ }
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "depth/stencil renderbuffer setup")
+
+ if (enableStencilTest) {
+ gl.enable(gl.STENCIL_TEST);
+ } else {
+ gl.disable(gl.STENCIL_TEST);
+ }
+
+ fn();
+
+ if (rbo) {
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, null);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ gl.deleteRenderbuffer(rbo);
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "depth/stencil renderbuffer cleanup")
+}
+
+function testStencilSettings(haveDepthBuffer, haveStencilBuffer, enableStencilTest, errIfMismatch) {
+ debug("");
+ debug("With depthbuffer=" + haveDepthBuffer +
+ ", stencilbuffer=" + haveStencilBuffer +
+ ", stencilTest=" + enableStencilTest +
+ ", expecting error=" + wtu.glEnumToString(gl, errIfMismatch) +
+ " for mismatching mask or func settings.");
+
+ runWithStencilSettings(haveDepthBuffer, haveStencilBuffer, enableStencilTest, () => {
+ // Errors should be the same for both mask and func, because stencil test
+ // and stencil write are always enabled/disabled in tandem.
+ testStencilMask(errIfMismatch);
+ testStencilFunc(errIfMismatch);
+ });
+}
+
+debug("");
+debug("Base case checks:");
+testStencilMaskCase([0, 0], gl.NO_ERROR);
+testStencilFuncCase([0, 0], [1023, 1023], gl.NO_ERROR);
+
+// haveDepthBuffer
+// | haveStencilBuffer
+// | | enableStencilTest
+// | | | errIfMismatch
+testStencilSettings(false, false, false, gl.NO_ERROR);
+testStencilSettings( true, false, false, gl.NO_ERROR);
+testStencilSettings(false, true, false, gl.NO_ERROR);
+testStencilSettings( true, true, false, gl.NO_ERROR);
+
+testStencilSettings(false, false, true, gl.NO_ERROR);
+testStencilSettings( true, false, true, gl.NO_ERROR);
+testStencilSettings(false, true, true, gl.INVALID_OPERATION);
+testStencilSettings( true, true, true, gl.INVALID_OPERATION);
+
+//
+// Tests to make sure the stencil validation check, if cached, is invalidated correctly.
+//
+
+debug("");
+
+debug("Setup for stencil validation cache invalidation tests");
+setStencilMask([1, 258]);
+setStencilFunc([0, 256], [1023, 1023]);
+
+debug("Test with enabling/disabling stencil test");
+runWithStencilSettings(false, true, false, () => {
+ checkDrawError(gl.NO_ERROR);
+ gl.enable(gl.STENCIL_TEST);
+ checkDrawError(gl.INVALID_OPERATION);
+ gl.disable(gl.STENCIL_TEST);
+ checkDrawError(gl.NO_ERROR);
+});
+
+debug("Test with swapping in a new FBO");
+runWithStencilSettings(false, false, true, () => {
+ // no error with no stencil buffer
+ checkDrawError(gl.NO_ERROR);
+
+ // swap in a new FBO with a stencil buffer
+ const fb2 = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, colorRB);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRB);
+ const rbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, 1, 1);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ // this draw sholud detect the new fbo state
+ checkDrawError(gl.INVALID_OPERATION);
+
+ gl.deleteFramebuffer(fb2);
+ gl.deleteRenderbuffer(rbo)
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+});
+
+debug("Test with adding a stencil attachment");
+runWithStencilSettings(false, false, true, () => {
+ // no error with no stencil buffer
+ checkDrawError(gl.NO_ERROR);
+
+ // add a stencil attachment
+ const rbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, 1, 1);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ // this draw sholud detect the new fbo state
+ checkDrawError(gl.INVALID_OPERATION);
+
+ gl.deleteRenderbuffer(rbo)
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+});
+
+debug("Test with reallocating the DEPTH_STENCIL attachment from depth to depth+stencil");
+runWithStencilSettings(false, false, true, () => {
+ // attach a depth buffer to the DEPTH_STENCIL attachment
+ const rbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ // this draw is invalid, but it still might trigger caching of the stencil validation
+ checkDrawError(gl.INVALID_FRAMEBUFFER_OPERATION);
+
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 1, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ // this draw sholud detect the new fbo state
+ checkDrawError(gl.INVALID_OPERATION);
+
+ gl.deleteRenderbuffer(rbo)
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+});
+
+gl.deleteFramebuffer(fb);
+gl.deleteRenderbuffer(colorRB);
+
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific.html b/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific.html
new file mode 100644
index 0000000000..a4cdc8c782
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific.html
@@ -0,0 +1,91 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL GLES2 difference test.</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+"use strict";
+var wtu = WebGLTestUtils;
+description("Tests the few differences between WebGL and GLES2");
+
+var gl = wtu.create3DContext();
+var program = wtu.loadStandardProgram(gl);
+gl.useProgram(program);
+var vertexObject = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+gl.enableVertexAttribArray(0);
+gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup should succeed");
+
+debug("");
+debug("Verify that constant color and constant alpha cannot be used together as source and destination factors in the blend function");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.CONSTANT_COLOR, gl.CONSTANT_ALPHA)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.ONE_MINUS_CONSTANT_COLOR, gl.CONSTANT_ALPHA)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_ALPHA)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.ONE_MINUS_CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_ALPHA)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.CONSTANT_ALPHA, gl.CONSTANT_COLOR)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.CONSTANT_ALPHA, gl.ONE_MINUS_CONSTANT_COLOR)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.ONE_MINUS_CONSTANT_ALPHA, gl.CONSTANT_COLOR)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFunc(gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_CONSTANT_COLOR)");
+
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.CONSTANT_COLOR, gl.CONSTANT_ALPHA, gl.ONE, gl.ZERO)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.ONE_MINUS_CONSTANT_COLOR, gl.CONSTANT_ALPHA, gl.ONE, gl.ZERO)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE, gl.ZERO)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.ONE_MINUS_CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE, gl.ZERO)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.CONSTANT_ALPHA, gl.CONSTANT_COLOR, gl.ONE, gl.ZERO)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.CONSTANT_ALPHA, gl.ONE_MINUS_CONSTANT_COLOR, gl.ONE, gl.ZERO)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.ONE_MINUS_CONSTANT_ALPHA, gl.CONSTANT_COLOR, gl.ONE, gl.ZERO)");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_CONSTANT_COLOR, gl.ONE, gl.ZERO)");
+
+debug("");
+debug("Verify that in depthRange zNear <= zFar");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.depthRange(20, 10)");
+
+debug("");
+debug("Verify that *LENGTH are undefined");
+shouldBeUndefined(gl.INFO_LOG_LENGTH);
+shouldBeUndefined(gl.SHADER_SOURCE_LENGTH);
+shouldBeUndefined(gl.ACTIVE_UNIFORM_MAX_LENGTH);
+shouldBeUndefined(gl.ACTIVE_ATTRIB_MAX_LENGTH);
+shouldBeUndefined(gl.ACTIVE_ATTRIBUTE_MAX_LENGTH);
+
+debug("");
+debug("Verify that UNPACK_COLORSPACE_CONVERSION_WEBGL is supported");
+shouldBe("gl.getParameter(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL)", "gl.BROWSER_DEFAULT_WEBGL");
+gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+shouldBe("gl.getParameter(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL)", "gl.NONE");
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "set/get UNPACK_COLORSPACE_CONVERSION_WEBGL should generate no error");
+
+debug("");
+debug("Verify that drawingBufferWidth and drawingBufferHeights are implemented");
+shouldBeTrue("gl.drawingBufferWidth >= 0 && gl.drawingBufferHeight >= 0");
+
+debug("");
+debug("Verify that bindAttribLocation rejects names start with webgl_ or _webgl_");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindAttribLocation(program, 0, 'webgl_a')");
+wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bindAttribLocation(program, 0, '_webgl_a')");
+
+debug("");
+debug("Verify that NaN line width is not accepted");
+wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, "gl.lineWidth(NaN)");
+
+var successfullyParsed = true;
+</script>
+
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>