diff options
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance/misc')
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> |