summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/js/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/test/webgl-conf/checkout/js/tests
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/js/tests')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js825
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js92
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js136
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js133
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js138
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js258
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js52
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js473
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js237
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js169
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js44
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js123
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js183
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js1090
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js263
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js105
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js129
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js183
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js163
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js247
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js151
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js57
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js321
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js263
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js664
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js292
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js468
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js49
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js74
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js56
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js49
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js46
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js83
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js240
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js257
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js140
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js291
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js298
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js287
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js226
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js48
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js74
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js56
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js49
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js45
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js83
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js259
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js260
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js104
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js244
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js212
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js865
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js435
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js563
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js299
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js73
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js72
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js226
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js69
59 files changed, 13391 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js
new file mode 100644
index 0000000000..7c30104379
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js
@@ -0,0 +1,825 @@
+/*
+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.
+*/
+
+// Some variables that will be used in this file
+var canvas;
+var gl;
+var OES_vertex_array_object;
+var uniformLocation;
+var extension;
+var buffer;
+var framebuffer;
+var program;
+var renderbuffer;
+var shader;
+var texture;
+var arrayBuffer;
+var arrayBufferView;
+var vertexArrayObject;
+var imageData;
+var float32array;
+var int32array;
+
+var OES_texture_float;
+var new_WEBGL_lose_context;
+var allowRestore;
+var contextLostEventFired;
+var contextRestoredEventFired;
+var newExtension;
+
+function compareGLError(glError, evalStr) {
+ var exception;
+ try {
+ eval(evalStr);
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ return false;
+ } else {
+ if (gl.getError() == glError)
+ return true;
+ return false;
+ }
+}
+
+function contextCreation(contextType) {
+ canvas = new OffscreenCanvas(10, 10);
+ gl = canvas.getContext(contextType);
+
+ if (contextType == 'webgl') {
+ if (gl instanceof WebGLRenderingContext)
+ return true;
+ return false;
+ } else if (contextType == 'webgl2') {
+ if (gl instanceof WebGL2RenderingContext)
+ return true;
+ return false;
+ } else {
+ return false;
+ }
+}
+
+function transferredOffscreenCanvasCreation(placeholder, width, height) {
+ placeholder.width = width;
+ placeholder.height = height;
+ return placeholder.transferControlToOffscreen();
+}
+
+function assertWidthAndHeight(entity, entityName, width, height) {
+ if (entity.width == width && entity.height == height) {
+ testPassed("The width and height of " + entityName + " are correct.");
+ return;
+ }
+ var errMsg = "";
+ if (entity.width != width) {
+ errMsg += "The width of " + entityName + " is " + entity.width + " while expected value is " + width + ". ";
+ }
+ if (entity.height != height) {
+ errMsg += "The height of " + entityName + " is " + entity.height + " while expected value is " + height + ". ";
+ }
+ testFailed(errMsg);
+}
+
+var webgl1Methods = [
+ "getContextAttributes",
+ "activeTexture",
+ "attachShader",
+ "bindAttribLocation",
+ "bindBuffer",
+ "bindFramebuffer",
+ "bindRenderbuffer",
+ "bindTexture",
+ "blendColor",
+ "blendEquation",
+ "blendEquationSeparate",
+ "blendFunc",
+ "blendFuncSeparate",
+ "bufferData",
+ "bufferSubData",
+ "checkFramebufferStatus",
+ "clear",
+ "clearColor",
+ "clearDepth",
+ "clearStencil",
+ "colorMask",
+ "compileShader",
+ "compressedTexImage2D",
+ "compressedTexSubImage2D",
+ "copyTexImage2D",
+ "copyTexSubImage2D",
+ "createBuffer",
+ "createFramebuffer",
+ "createProgram",
+ "createRenderbuffer",
+ "createShader",
+ "createTexture",
+ "cullFace",
+ "deleteBuffer",
+ "deleteFramebuffer",
+ "deleteProgram",
+ "deleteRenderbuffer",
+ "deleteShader",
+ "deleteTexture",
+ "depthFunc",
+ "depthMask",
+ "depthRange",
+ "detachShader",
+ "disable",
+ "disableVertexAttribArray",
+ "drawArrays",
+ "drawElements",
+ "enable",
+ "enableVertexAttribArray",
+ "finish",
+ "flush",
+ "framebufferRenderbuffer",
+ "framebufferTexture2D",
+ "frontFace",
+ "generateMipmap",
+ "getActiveAttrib",
+ "getActiveUniform",
+ "getAttachedShaders",
+ "getAttribLocation",
+ "getParameter",
+ "getBufferParameter",
+ "getError",
+ "getExtension",
+ "getFramebufferAttachmentParameter",
+ "getProgramParameter",
+ "getProgramInfoLog",
+ "getRenderbufferParameter",
+ "getShaderParameter",
+ "getShaderInfoLog",
+ "getShaderPrecisionFormat",
+ "getShaderSource",
+ "getSupportedExtensions",
+ "getTexParameter",
+ "getUniform",
+ "getUniformLocation",
+ "getVertexAttrib",
+ "getVertexAttribOffset",
+ "hint",
+ "isBuffer",
+ "isContextLost",
+ "isEnabled",
+ "isFramebuffer",
+ "isProgram",
+ "isRenderbuffer",
+ "isShader",
+ "isTexture",
+ "lineWidth",
+ "linkProgram",
+ "pixelStorei",
+ "polygonOffset",
+ "readPixels",
+ "renderbufferStorage",
+ "sampleCoverage",
+ "scissor",
+ "shaderSource",
+ "stencilFunc",
+ "stencilFuncSeparate",
+ "stencilMask",
+ "stencilMaskSeparate",
+ "stencilOp",
+ "stencilOpSeparate",
+ "texImage2D",
+ "texParameterf",
+ "texParameteri",
+ "texSubImage2D",
+ "uniform1f",
+ "uniform1fv",
+ "uniform1i",
+ "uniform1iv",
+ "uniform2f",
+ "uniform2fv",
+ "uniform2i",
+ "uniform2iv",
+ "uniform3f",
+ "uniform3fv",
+ "uniform3i",
+ "uniform3iv",
+ "uniform4f",
+ "uniform4fv",
+ "uniform4i",
+ "uniform4iv",
+ "uniformMatrix2fv",
+ "uniformMatrix3fv",
+ "uniformMatrix4fv",
+ "useProgram",
+ "validateProgram",
+ "vertexAttrib1f",
+ "vertexAttrib1fv",
+ "vertexAttrib2f",
+ "vertexAttrib2fv",
+ "vertexAttrib3f",
+ "vertexAttrib3fv",
+ "vertexAttrib4f",
+ "vertexAttrib4fv",
+ "vertexAttribPointer",
+ "viewport",
+];
+
+var webgl2Methods = [
+ "getBufferSubData",
+ "copyBufferSubData",
+ "blitFramebuffer",
+ "framebufferTextureLayer",
+ "getInternalformatParameter",
+ "invalidateFramebuffer",
+ "invalidateSubFramebuffer",
+ "readBuffer",
+ "renderbufferStorageMultisample",
+ "texImage3D",
+ "texStorage2D",
+ "texStorage3D",
+ "texSubImage3D",
+ "copyTexSubImage3D",
+ "compressedTexImage3D",
+ "compressedTexSubImage3D",
+ "getFragDataLocation",
+ "uniform1ui",
+ "uniform2ui",
+ "uniform3ui",
+ "uniform4ui",
+ "uniform1uiv",
+ "uniform2uiv",
+ "uniform3uiv",
+ "uniform4uiv",
+ "uniformMatrix2x3fv",
+ "uniformMatrix3x2fv",
+ "uniformMatrix2x4fv",
+ "uniformMatrix4x2fv",
+ "uniformMatrix3x4fv",
+ "uniformMatrix4x3fv",
+ "vertexAttribI4i",
+ "vertexAttribI4iv",
+ "vertexAttribI4ui",
+ "vertexAttribI4uiv",
+ "vertexAttribIPointer",
+ "vertexAttribDivisor",
+ "drawArraysInstanced",
+ "drawElementsInstanced",
+ "drawRangeElements",
+ "drawBuffers",
+ "clearBufferiv",
+ "clearBufferuiv",
+ "clearBufferfv",
+ "clearBufferfi",
+ "createQuery",
+ "deleteQuery",
+ "isQuery",
+ "beginQuery",
+ "endQuery",
+ "getQuery",
+ "getQueryParameter",
+ "createSampler",
+ "deleteSampler",
+ "isSampler",
+ "bindSampler",
+ "samplerParameteri",
+ "samplerParameterf",
+ "getSamplerParameter",
+ "fenceSync",
+ "isSync",
+ "deleteSync",
+ "clientWaitSync",
+ "waitSync",
+ "getSyncParameter",
+ "createTransformFeedback",
+ "deleteTransformFeedback",
+ "isTransformFeedback",
+ "bindTransformFeedback",
+ "beginTransformFeedback",
+ "endTransformFeedback",
+ "transformFeedbackVaryings",
+ "getTransformFeedbackVarying",
+ "pauseTransformFeedback",
+ "resumeTransformFeedback",
+ "bindBufferBase",
+ "bindBufferRange",
+ "getIndexedParameter",
+ "getUniformIndices",
+ "getActiveUniforms",
+ "getUniformBlockIndex",
+ "getActiveUniformBlockParameter",
+ "getActiveUniformBlockName",
+ "uniformBlockBinding",
+ "createVertexArray",
+ "deleteVertexArray",
+ "isVertexArray",
+ "bindVertexArray",
+];
+
+function assertFunction(v, f) {
+ try {
+ if (typeof v[f] != "function") {
+ return false;
+ } else {
+ return true;
+ }
+ } catch(e) {
+ return false;
+ }
+}
+
+function testAPIs(contextType) {
+ canvas = new OffscreenCanvas(10, 10);
+ gl = canvas.getContext(contextType);
+ var passed = true;
+ var methods;
+ if (contextType == 'webgl')
+ methods = webgl1Methods;
+ else
+ methods = webgl1Methods.concat(webgl2Methods);
+ for (var i=0; i<methods.length; i++) {
+ var r = assertFunction(gl, methods[i]);
+ passed = passed && r;
+ }
+
+ methods.push(...["makeXRCompatible"]);
+ var extended = false;
+ for (var i in gl) {
+ if (typeof gl[i] == "function" && methods.indexOf(i) == -1) {
+ if (!extended) {
+ extended = true;
+ }
+ }
+ }
+
+ if (!passed || extended)
+ return false;
+ return true;
+}
+
+var simpleTextureVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'attribute vec2 texCoord0;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' texCoord = texCoord0;',
+ '}'].join('\n');
+
+var simpleTextureFragmentShader = [
+ 'precision mediump float;',
+ 'uniform sampler2D tex;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_FragData[0] = texture2D(tex, texCoord);',
+ '}'].join('\n');
+
+function getShader(gl, shaderStr, type)
+{
+ var shader = gl.createShader(type);
+ gl.shaderSource(shader, shaderStr);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
+ return null;
+ return shader;
+}
+
+function setupProgram(gl, shaders, opt_attribs, opt_locations)
+{
+ var vertexShader = getShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER);
+ var fragmentShader = getShader(gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER);
+ var program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+
+ if (opt_attribs) {
+ for (var ii = 0; ii < opt_attribs.length; ++ii) {
+ gl.bindAttribLocation(
+ program,
+ opt_locations ? opt_locations[ii] : ii,
+ opt_attribs[ii]);
+ }
+ }
+ gl.linkProgram(program);
+
+ // Check the link status
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ // something went wrong with the link
+ gl.deleteProgram(program);
+ return null;
+ }
+ gl.useProgram(program);
+ return program;
+}
+
+function setupSimpleTextureProgram(gl, opt_positionLocation, opt_texcoordLocation)
+{
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ return setupProgram(gl,
+ [simpleTextureVertexShader, simpleTextureFragmentShader],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+}
+
+function testLostContextWithoutRestore()
+{
+ // Functions with special return values.
+ if (!gl.isContextLost())
+ return false;
+
+ if (gl.getError() != gl.CONTEXT_LOST_WEBGL)
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_UNSUPPORTED ||
+ gl.getAttribLocation(program, 'u_modelViewProjMatrix') != -1 ||
+ gl.getVertexAttribOffset(0, gl.VERTEX_ATTRIB_ARRAY_POINTER) != 0)
+ return false;
+
+ // Test the extension itself.
+ if (!compareGLError(gl.INVALID_OPERATION, "extension.loseContext()"))
+ return false;
+
+ imageData = new ImageData(1, 1);
+ float32array = new Float32Array(1);
+ int32array = new Int32Array(1);
+
+ // Functions returning void should return immediately.
+ // This is untestable, but we can at least be sure they cause no errors
+ // and the codepaths are exercised.
+ if (!compareGLError(gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.attachShader(program, shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, texture)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendColor(1.0, 1.0, 1.0, 1.0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendEquation(gl.FUNC_ADD)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.ONE, gl.ONE)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, 0, gl.STATIC_DRAW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBufferView, gl.STATIC_DRAW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBuffer, gl.STATIC_DRAW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clearColor(1, 1, 1, 1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clearDepth(1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clearStencil(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.colorMask(1, 1, 1, 1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.compileShader(shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.cullFace(gl.FRONT)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteBuffer(buffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteFramebuffer(framebuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteRenderbuffer(renderbuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteShader(shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteTexture(texture)") ||
+ !compareGLError(gl.NO_ERROR, "gl.depthFunc(gl.NEVER)") ||
+ !compareGLError(gl.NO_ERROR, "gl.depthMask(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.depthRange(0, 1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.detachShader(program, shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.disable(gl.BLEND)") ||
+ !compareGLError(gl.NO_ERROR, "gl.disableVertexAttribArray(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.drawArrays(gl.POINTS, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.drawElements(gl.POINTS, 0, gl.UNSIGNED_SHORT, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)") ||
+ !compareGLError(gl.NO_ERROR, "gl.enableVertexAttribArray(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.finish()") ||
+ !compareGLError(gl.NO_ERROR, "gl.flush()") ||
+ !compareGLError(gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.frontFace(gl.CW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.generateMipmap(gl.TEXTURE_2D)") ||
+ !compareGLError(gl.NO_ERROR, "gl.hint(gl.GENERATE_MIPMAP_HINT, gl.FASTEST)") ||
+ !compareGLError(gl.NO_ERROR, "gl.lineWidth(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.linkProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.polygonOffset(0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.sampleCoverage(0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.scissor(0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.shaderSource(shader, '')") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilFunc(gl.NEVER, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilFuncSeparate(gl.FRONT, gl.NEVER, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilMask(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilMaskSeparate(gl.FRONT, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.KEEP)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1f(uniformLocation, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, [0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1i(uniformLocation, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, [0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2f(uniformLocation, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, [0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2i(uniformLocation, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, [0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3f(uniformLocation, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, [0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3i(uniformLocation, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, [0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4f(uniformLocation, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4i(uniformLocation, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.useProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.validateProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1f(0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, [0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2f(0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, [0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3f(0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, [0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4f(0, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttribPointer(0, 0, gl.FLOAT, false, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.viewport(0, 0, 0, 0)"))
+ return false;
+
+ // Functions return nullable values should all return null.
+ if (gl.createBuffer() != null ||
+ gl.createFramebuffer() != null ||
+ gl.createProgram() != null ||
+ gl.createRenderbuffer() != null ||
+ gl.createShader(gl.GL_VERTEX_SHADER) != null ||
+ gl.createTexture() != null ||
+ gl.getActiveAttrib(program, 0) != null ||
+ gl.getActiveUniform(program, 0) != null ||
+ gl.getAttachedShaders(program) != null ||
+ gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE) != null ||
+ gl.getContextAttributes() != null ||
+ gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) != null ||
+ gl.getParameter(gl.CURRENT_PROGRAM) != null ||
+ gl.getProgramInfoLog(program) != null ||
+ gl.getProgramParameter(program, gl.LINK_STATUS) != null ||
+ gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH) != null ||
+ gl.getShaderInfoLog(shader) != null ||
+ gl.getShaderParameter(shader, gl.SHADER_TYPE) != null ||
+ gl.getShaderSource(shader) != null ||
+ gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S) != null ||
+ gl.getUniform(program, uniformLocation) != null ||
+ gl.getUniformLocation(program, 'vPosition') != null ||
+ gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) != null ||
+ gl.getSupportedExtensions() != null ||
+ gl.getExtension("WEBGL_lose_context") != null)
+ return false;
+
+ // "Is" queries should all return false.
+ if (gl.isBuffer(buffer) || gl.isEnabled(gl.BLEND) || gl.isFramebuffer(framebuffer) ||
+ gl.isProgram(program) || gl.isRenderbuffer(renderbuffer) || gl.isShader(shader) ||
+ gl.isTexture(texture))
+ return false;
+
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ // test extensions
+ if (OES_vertex_array_object) {
+ if (!compareGLError(gl.NO_ERROR, "OES_vertex_array_object.bindVertexArrayOES(vertexArrayObject)") ||
+ !compareGLError(gl.NO_ERROR, "OES_vertex_array_object.isVertexArrayOES(vertexArrayObject)") ||
+ !compareGLError(gl.NO_ERROR, "OES_vertex_array_object.deleteVertexArrayOES(vertexArrayObject)"))
+ return false;
+ if (OES_vertex_array_object.createVertexArrayOES() != null)
+ return false;
+ }
+ return true;
+}
+function testValidContext()
+{
+ if (gl.isContextLost())
+ return false;
+
+ arrayBuffer = new ArrayBuffer(4);
+ arrayBufferView = new Int8Array(arrayBuffer);
+
+ // Generate resources for testing.
+ buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ framebuffer = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+ program = setupSimpleTextureProgram(gl);
+ renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ shader = gl.createShader(gl.VERTEX_SHADER);
+ texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ // Test is queries that will later be false
+ if (!compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)"))
+ return false;
+ if (!gl.isBuffer(buffer) || !gl.isEnabled(gl.BLEND) || !gl.isFramebuffer(framebuffer) ||
+ !gl.isProgram(program) || !gl.isRenderbuffer(renderbuffer) || !gl.isShader(shader) ||
+ !gl.isTexture(texture))
+ return false;
+
+ if (OES_vertex_array_object) {
+ vertexArrayObject = OES_vertex_array_object.createVertexArrayOES();
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+ if (!OES_vertex_array_object.isVertexArrayOES(vertexArrayObject))
+ return false;
+ }
+ return true;
+}
+
+function setupTest()
+{
+ canvas = new OffscreenCanvas(10, 10);
+ gl = canvas.getContext('webgl');
+ WEBGL_lose_context = gl.getExtension("WEBGL_lose_context");
+ if (!WEBGL_lose_context)
+ return false;
+
+ // Try to get a few extensions
+ OES_vertex_array_object = gl.getExtension("OES_vertex_array_object");
+ OES_texture_float = gl.getExtension("OES_texture_float");
+
+ return true;
+}
+
+function testOriginalContext()
+{
+ if (gl.isContextLost())
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+ return true;
+}
+
+function testLostContext(e)
+{
+ if (contextLostEventFired)
+ return false;
+ contextLostEventFired = true;
+ if (!gl.isContextLost())
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+ if (allowRestore)
+ e.preventDefault();
+ return true;
+}
+
+function testLosingAndRestoringContext()
+{
+ return new Promise(function(resolve, reject) {
+ if (!setupTest())
+ reject("Test failed");
+
+ canvas.addEventListener("webglcontextlost", function(e) {
+ if (!testLostContext(e))
+ reject("Test failed");
+ // restore the context after this event has exited.
+ setTimeout(function() {
+ if (!compareGLError(gl.NO_ERROR, "WEBGL_lose_context.restoreContext()"))
+ reject("Test failed");
+ // The context should still be lost. It will not get restored until the
+ // webglrestorecontext event is fired.
+ if (!gl.isContextLost())
+ reject("Test failed");
+ if (gl.getError() != gl.NO_ERROR)
+ reject("Test failed");
+ // gl methods should still be no-ops
+ if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)"))
+ reject("Test failed");
+ }, 0);
+ });
+ canvas.addEventListener("webglcontextrestored", function() {
+ if (!testRestoredContext())
+ reject("Test failed");
+ else
+ resolve("Test passed");
+ });
+ allowRestore = true;
+ contextLostEventFired = false;
+ contextRestoredEventFired = false;
+
+ if (!testOriginalContext())
+ reject("Test failed");
+ WEBGL_lose_context.loseContext();
+ // The context should be lost immediately.
+ if (!gl.isContextLost())
+ reject("Test failed");
+ if (gl.getError() != gl.CONTEXT_LOST_WEBGL)
+ reject("Test failed");
+ if (gl.getError() != gl.NO_ERROR)
+ reject("Test failed");
+ // gl methods should be no-ops
+ if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)"))
+ reject("Test failed");
+ // but the event should not have been fired.
+ if (contextLostEventFired)
+ reject("Test failed");
+ });
+}
+
+function reGetExtensionAndTestForProperty(gl, name, expectProperty) {
+ var newExtension = gl.getExtension(name);
+ // NOTE: while getting a extension after context lost/restored is allowed to fail
+ // for the purpose the conformance tests it is not.
+ //
+ // Hypothetically the user can switch GPUs live. For example on Windows, install 2 GPUs,
+ // then in the control panen enable 1, disable the others and visa versa. Since the GPUs
+ // have different capabilities one or the other may not support a particlar extension.
+ //
+ // But, for the purpose of the conformance tests the context is expected to restore
+ // on the same GPU and therefore the extensions that succeeded previously should
+ // succeed on restore.
+ if (newExtension == null)
+ return false;
+ if (expectProperty) {
+ if (!(newExtension.webglTestProperty === true))
+ return false;
+ } else {
+ if (!(newExtension.webglTestProperty === undefined))
+ return false;
+ }
+ return newExtension;
+}
+
+
+function testOESTextureFloat() {
+ if (OES_texture_float) {
+ // Extension must still be lost.
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ if (!compareGLError(gl.INVALID_ENUM, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)"))
+ return false;
+ // Try re-enabling extension
+ OES_texture_float = reGetExtensionAndTestForProperty(gl, "OES_texture_float", false);
+ if (!compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)"))
+ return false;
+ return true;
+ }
+}
+
+function testOESVertexArrayObject() {
+ if (OES_vertex_array_object) {
+ // Extension must still be lost.
+ if (OES_vertex_array_object.createVertexArrayOES() != null)
+ return false;
+ // Try re-enabling extension
+
+ var old_OES_vertex_array_object = OES_vertex_array_object;
+ OES_vertex_array_object = reGetExtensionAndTestForProperty(gl, "OES_vertex_array_object", false);
+ if (OES_vertex_array_object.createVertexArrayOES() == null)
+ return false;
+ if (old_OES_vertex_array_object.createVertexArrayOES() != null)
+ return false;
+ return true;
+ }
+}
+
+function testExtensions() {
+ if (!testOESTextureFloat() || !testOESVertexArrayObject())
+ return false;
+ return true;
+}
+
+function testRestoredContext()
+{
+ if (contextRestoredEventFired)
+ return false;
+ contextRestoredEventFired = true;
+ if (gl.isContextLost())
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ if (!testExtensions())
+ return false;
+ return true;
+}
+
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js b/dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js
new file mode 100644
index 0000000000..6b8fc00599
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js
@@ -0,0 +1,92 @@
+/*
+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.
+*/
+
+'use strict';
+description("This test ensures clipping works with wide points whose centers are out of the viewport");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("testbed", undefined, contextVersion);
+
+var pointSize;
+
+function setupProgram() {
+ var vs = "attribute vec4 pos;" +
+ "uniform float pointSize; " +
+ "void main() {" +
+ " gl_PointSize = pointSize;" +
+ " gl_Position = pos;" +
+ "}";
+ var fs = "precision mediump float;" +
+ "void main() {" +
+ " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);" +
+ "}";
+ var program = wtu.setupProgram(gl, [vs, fs], ['pos']);
+ if (program) {
+ var loc = gl.getUniformLocation(program, 'pointSize');
+ gl.uniform1f(loc, pointSize);
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors after setting up program");
+ }
+ return program;
+}
+
+function runOneTestCase(vertex) {
+ debug("");
+ debug("testing point at (" + vertex[0] + ", " + vertex[1] + ", " + vertex[2] + ")");
+ var data = new Float32Array(vertex);
+ gl.bufferSubData(gl.ARRAY_BUFFER, 0, data);
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 255, 0]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors after running one test case");
+}
+
+function runTests() {
+ if (!gl) {
+ testFailed("context does not exist");
+ return;
+ }
+
+ var range = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE);
+ if (range[1] < 2.0) {
+ testPassed("ALIASDED_POINT_SIZE_RANGE less than 2");
+ return;
+ }
+ pointSize = 2.0;
+
+ var data = new Float32Array(4);
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
+
+ var program = setupProgram();
+ if (!program) {
+ testFailed("fail to set up program");
+ return;
+ }
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DITHER);
+ gl.disable(gl.DEPTH_TEST);
+
+ gl.clearColor(1.0, 0.0, 0.0, 1.0);
+
+ var vertices = [
+ [ 0.99, 0.5, 0.0, 1.0 ],
+ [ 1.01, 0.5, 0.0, 1.0 ],
+ [ 0.5, 0.99, 0.0, 1.0 ],
+ [ 0.5, 1.01, 0.0, 1.0 ],
+ ];
+ for (var idx = 0; idx < vertices.length; ++idx) {
+ runOneTestCase(vertices[idx]);
+ }
+}
+
+runTests();
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js
new file mode 100644
index 0000000000..ceccbc406e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js
@@ -0,0 +1,136 @@
+var createCompositingTestFn = (function() {
+
+const width = 20;
+const height = 20;
+
+function waitForComposite() {
+ debug('wait for composite');
+ return new Promise(resolve => wtu.waitForComposite(resolve));
+}
+
+async function testPreserveDrawingBufferFalse(gl, drawFn, clear) {
+ debug('');
+ debug(`test preserveDrawingBuffer: false with ${drawFn.name} ${clear ? 'with' : 'without'} clear`);
+
+ if (clear) {
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ if (drawFn(gl)) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+
+ // enable scissor here, before compositing, to make sure it's correctly
+ // ignored and restored
+ const halfWidth = gl.canvas.width / 2;
+ const halfHeight = gl.canvas.height / 2;
+ gl.scissor(0, halfHeight, halfWidth, halfHeight);
+ gl.enable(gl.SCISSOR_TEST);
+
+ await waitForComposite();
+
+ // scissor was set earlier
+ gl.clearColor(0, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ wtu.checkCanvasRect(gl, 0, halfHeight, halfWidth, halfHeight, [0, 0, 255, 255],
+ "cleared corner should be blue, stencil should be preserved");
+ wtu.checkCanvasRect(gl, 0, 0, halfWidth, halfHeight, [0, 0, 0, 0],
+ "remainder of buffer should be cleared");
+
+ gl.disable(gl.SCISSOR_TEST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+async function testPreserveDrawingBufferTrue(gl, drawFn, clear) {
+ debug('');
+ debug(`test preserveDrawingBuffer: true with ${drawFn.name} ${clear ? 'with' : 'without'} clear`);
+
+ if (clear) {
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ const skipTest = drawFn(gl);
+ if (skipTest) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+
+ await waitForComposite();
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function setupWebGL({
+ webglVersion,
+ shadersFn,
+ attribs,
+}) {
+ const existingCanvases = document.querySelectorAll('canvas');
+ const canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ canvas.style.display = 'block';
+ canvas.style.position = 'fixed';
+ canvas.style.left = `${existingCanvases.length * 25}px`;
+ canvas.style.top = '0';
+ // The canvas needs to be visible or the test will fail.
+ document.body.insertBefore(canvas, [...existingCanvases].pop());
+ const gl = wtu.create3DContext(canvas, attribs, webglVersion);
+ if (!gl) {
+ testFailed('WebGL context creation failed');
+ return gl;
+ }
+
+ const shaders = shadersFn(gl);
+ const program = wtu.setupProgram(gl, shaders, ["position"]);
+ if (!program) {
+ debug(`program failed to compile: ${wtu.getLastError()}`);
+ }
+ const positionBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ -1, 1,
+ 1, -1,
+ 1, 1,
+ ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ const indexBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuf);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0, 1, 2, 3, 4, 5]), gl.STATIC_DRAW);
+ return gl;
+}
+
+function createCompositingTestFn(options) {
+ const glPreserveDrawingBufferFalse = setupWebGL({
+ ...options,
+ attribs: {antialias: false},
+ });
+ const glPreserveDrawingBufferTrue = setupWebGL({
+ ...options,
+ attribs: {antialias: false, preserveDrawingBuffer: true},
+ });
+ return async function(drawFn) {
+ debug('---');
+ await testPreserveDrawingBufferFalse(glPreserveDrawingBufferFalse, drawFn, false);
+ await testPreserveDrawingBufferFalse(glPreserveDrawingBufferFalse, drawFn, true);
+
+ await testPreserveDrawingBufferTrue(glPreserveDrawingBufferTrue, drawFn, false);
+ await testPreserveDrawingBufferTrue(glPreserveDrawingBufferTrue, drawFn, true);
+ };
+}
+
+return createCompositingTestFn;
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js
new file mode 100644
index 0000000000..41a49bced4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js
@@ -0,0 +1,133 @@
+/*
+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.
+*/
+
+'use strict';
+
+// ESSL 1.00 spec section 5.8 (also ESSL 3.00 spec section 5.8):
+// "The l-value and the expression must satisfy the semantic requirements of both op and equals (=)"
+// In the semantic requirements of assignment (=):
+// "The lvalue-expression and rvalue-expression must have the same type"
+
+var runTest = function(contextVersion) {
+ var vertexTemplateESSL1 = [
+ 'precision mediump float;',
+
+ 'uniform $(rtype) ur;',
+ 'uniform $(ltype) ul;',
+
+ 'void main() {',
+ ' $(ltype) a = ul;',
+ ' a $(op) ur;',
+ ' gl_Position = vec4(float(a$(ltypeToScalar)));',
+ '}'
+ ].join('\n');
+
+ var vertexTemplateESSL3 = [
+ '#version 300 es',
+ vertexTemplateESSL1
+ ].join('\n');
+
+ var fragmentTemplateESSL1 = [
+ 'precision mediump float;',
+
+ 'uniform $(rtype) ur;',
+ 'uniform $(ltype) ul;',
+
+ 'void main() {',
+ ' $(ltype) a = ul;',
+ ' a $(op) ur;',
+ ' gl_FragColor = vec4(float(a$(ltypeToScalar)));',
+ '}'
+ ].join('\n');
+
+ var fragmentTemplateESSL3 = [
+ '#version 300 es',
+ 'out mediump vec4 my_FragColor;',
+ fragmentTemplateESSL1
+ ].join('\n').replace('gl_FragColor', 'my_FragColor');
+
+ var isNonSquareMatrix = function(typeStr) {
+ return typeStr.substring(0, 3) == 'mat' &&
+ typeStr.length > 5 &&
+ typeStr[3] != typeStr[5];
+ }
+
+ var vsTemplate = contextVersion < 2 ? vertexTemplateESSL1 : vertexTemplateESSL3;
+ var fsTemplate = contextVersion < 2 ? fragmentTemplateESSL1 : fragmentTemplateESSL3;
+
+ var wtu = WebGLTestUtils;
+
+ var tests = [];
+
+ var baseTypes = ['float', 'int'];
+ var vecTypes = [['vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4'], ['ivec2', 'ivec3', 'ivec4']];
+ if (contextVersion >= 2) {
+ vecTypes[0] = ['vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'mat2x3', 'mat2x4', 'mat3x2', 'mat3x4', 'mat4x2', 'mat4x3'];
+ }
+ var ops = ['+=', '-=', '*=', '/='];
+
+ var fs, vs;
+ for (var k = 0; k < ops.length; ++k) {
+ var op = ops[k];
+ for (var i = 0; i < baseTypes.length; ++i) {
+ var baseType = baseTypes[i];
+ for (var j = 0; j < vecTypes[i].length; ++j) {
+ var vecType = vecTypes[i][j];
+ var vecTypeToScalar = vecType.substring(0, 3) == 'mat' ? '[0].x' : '.x';
+
+ var pushTest = function(ltype, rtype, ltypeToScalar, expectSuccess) {
+ vs = wtu.replaceParams(vsTemplate, {ltype: ltype, rtype: rtype, ltypeToScalar: ltypeToScalar, op: op});
+ fs = wtu.replaceParams(fsTemplate, {ltype: ltype, rtype: rtype, ltypeToScalar: ltypeToScalar, op: op});
+ tests.push({
+ vShaderSource: vs,
+ vShaderSuccess: expectSuccess,
+ linkSuccess: expectSuccess,
+ passMsg: ltype + " " + op + " " + rtype + " in a vertex shader should " + (expectSuccess ? "succeed." : "fail.")
+ });
+ tests.push({
+ fShaderSource: fs,
+ fShaderSuccess: expectSuccess,
+ linkSuccess: expectSuccess,
+ passMsg: ltype + " " + op + " " + rtype + " in a fragment shader should " + (expectSuccess ? "succeed." : "fail.")
+ });
+ }
+
+ // "scalar op= vector" is not okay, since the result of op is a vector,
+ // which can't be assigned to a scalar.
+ pushTest(baseType, vecType, '', false);
+
+ if (j > 0) {
+ var vecType2 = vecTypes[i][j - 1];
+ // "vector1 op= vector2" is not okay when vector1 and vector2 have
+ // non-matching dimensions.
+ pushTest(vecType, vecType2, vecTypeToScalar, false);
+ }
+
+ // "vector op= scalar" is okay.
+ pushTest(vecType, baseType, vecTypeToScalar, true);
+
+ // vecX *= matX is okay (effectively, this treats vector as a row vector).
+ if (vecType.substring(0, 3) == 'vec' && op == '*=') {
+ pushTest(vecType, 'mat' + vecType[3], vecTypeToScalar, true);
+ }
+
+ if (op != '*=' || !isNonSquareMatrix(vecType)) {
+ // "vector1 op= vector2" is okay when vector1 and vector2 have the same
+ // type (does a component-wise operation or matrix multiplication).
+ pushTest(vecType, vecType, vecTypeToScalar, true);
+ } else {
+ // non-square matrices can only be compound multiplied with a square matrix.
+ pushTest(vecType, vecType, vecTypeToScalar, false);
+ pushTest(vecType, 'mat' + vecType[3], vecTypeToScalar, true);
+ }
+ }
+ }
+ }
+
+ GLSLConformanceTester.runTests(tests, contextVersion);
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js
new file mode 100644
index 0000000000..7886181f4c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js
@@ -0,0 +1,138 @@
+"use strict";
+description("This test ensures WebGL implementations correctly implement querying for compressed textures when extensions are disabled.");
+
+debug("");
+
+const wtu = WebGLTestUtils;
+const gl = wtu.create3DContext(null, undefined, contextVersion);
+
+const COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
+const COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+
+let formats = null;
+let ext;
+
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION],
+ "gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 10, 10, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8));");
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)");
+ shouldBeNonNull("formats");
+ shouldBe("formats.length", "0");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4*4*4));");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM,
+ "gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8));");
+
+ // Check too-many and too-few args.
+
+ wtu.shouldThrow(gl, false, "too many args", function() {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 4, 4, 0, new Uint8Array(8), null);
+ });
+ wtu.shouldThrow(gl, TypeError, "too few args", function() {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 4, 4, 0);
+ });
+
+ wtu.shouldThrow(gl, false, "too many args", function() {
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8), null);
+ });
+ wtu.shouldThrow(gl, TypeError, "too few args", function() {
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
+ });
+
+ // -
+
+ let pbo;
+ // WebGL 2.0 specific
+ if (gl.PIXEL_UNPACK_BUFFER) {
+ pbo = gl.createBuffer();
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ function validateExt(extName, enumName, blockSize, blockByteSize, expectedSubImageError) {
+ debug('\n---------------------------');
+ debug('\n' + extName);
+ ext = gl.getExtension(extName);
+ if (!ext) {
+ testPassed(`Optional ext ${extName} MAY be unsupported.`);
+ return;
+ }
+ testPassed(`Optional ext ${extName} is supported.`);
+
+ const data = new Uint8Array(blockByteSize);
+
+ const views = [
+ data,
+ new Uint8ClampedArray(data.buffer),
+ new Int8Array(data.buffer),
+ new Uint16Array(data.buffer),
+ new Int16Array(data.buffer),
+ new Uint32Array(data.buffer),
+ new Int32Array(data.buffer),
+ new Float32Array(data.buffer),
+ new DataView(data.buffer),
+ ];
+ if (window.SharedArrayBuffer) {
+ const sharedBuffer = new SharedArrayBuffer(blockByteSize);
+ views.push(
+ new Uint8Array(sharedBuffer),
+ new Uint8ClampedArray(sharedBuffer),
+ new DataView(sharedBuffer)
+ );
+ }
+
+ for (const view of views) {
+ window.g_view = view;
+ debug(`\nfrom ${view.constructor.name} of ${view.buffer.constructor.name}`);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, g_view)`);
+
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, g_view)`);
+ }
+
+ if (pbo) {
+ debug('\nfrom PBO');
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.bufferData(gl.PIXEL_UNPACK_BUFFER, ${blockByteSize}*2, gl.STATIC_DRAW)`);
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, 0)`);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, 1)`);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, ${blockByteSize})`);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, ${blockByteSize+1})`);
+
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, 0)`);
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, 1)`);
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, ${blockByteSize})`);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, ${blockByteSize+1})`);
+
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ }
+ }
+
+ validateExt('WEBGL_compressed_texture_s3tc', 'COMPRESSED_RGBA_S3TC_DXT5_EXT', 4, 16, gl.NO_ERROR);
+ validateExt('WEBGL_compressed_texture_etc1', 'COMPRESSED_RGB_ETC1_WEBGL', 4, 8, gl.INVALID_OPERATION);
+ validateExt('WEBGL_compressed_texture_etc', 'COMPRESSED_RGBA8_ETC2_EAC', 4, 16, gl.NO_ERROR);
+ validateExt('WEBGL_compressed_texture_astc', 'COMPRESSED_RGBA_ASTC_4x4_KHR', 4, 16, gl.NO_ERROR);
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js
new file mode 100644
index 0000000000..46d155f5f1
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js
@@ -0,0 +1,258 @@
+/*
+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.
+*/
+
+"use strict";
+
+let CompressedTextureUtils = (function() {
+
+let formatToString = function(ext, format) {
+ for (let p in ext) {
+ if (ext[p] == format) {
+ return p;
+ }
+ }
+ return "0x" + format.toString(16);
+};
+
+/**
+ * Make an image element from Uint8Array bitmap data.
+ * @param {number} imageHeight Height of the data in pixels.
+ * @param {number} imageWidth Width of the data in pixels.
+ * @param {number} dataWidth Width of each row in the data buffer, in pixels.
+ * @param {Uint8Array} data Image data buffer to display. Each pixel takes up 4 bytes in the array regardless of the alpha parameter.
+ * @param {boolean} alpha True if alpha data should be taken from data. Otherwise alpha channel is set to 255.
+ * @return {HTMLImageElement} The image element.
+ */
+let makeScaledImage = function(imageWidth, imageHeight, dataWidth, data, alpha, opt_scale) {
+ let scale = opt_scale ? opt_scale : 8;
+ let c = document.createElement("canvas");
+ c.width = imageWidth * scale;
+ c.height = imageHeight * scale;
+ let ctx = c.getContext("2d");
+ for (let yy = 0; yy < imageHeight; ++yy) {
+ for (let xx = 0; xx < imageWidth; ++xx) {
+ let offset = (yy * dataWidth + xx) * 4;
+ ctx.fillStyle = "rgba(" +
+ data[offset + 0] + "," +
+ data[offset + 1] + "," +
+ data[offset + 2] + "," +
+ (alpha ? data[offset + 3] / 255 : 1) + ")";
+ ctx.fillRect(xx * scale, yy * scale, scale, scale);
+ }
+ }
+ return wtu.makeImageFromCanvas(c);
+};
+
+let insertCaptionedImg = function(parent, caption, img) {
+ let div = document.createElement("div");
+ div.appendChild(img);
+ let label = document.createElement("div");
+ label.appendChild(document.createTextNode(caption));
+ div.appendChild(label);
+ parent.appendChild(div);
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} compressedFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ */
+let testCompressedFormatsUnavailableWhenExtensionDisabled = function(gl, compressedFormats, expectedByteLength, testSize) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ for (let name in compressedFormats) {
+ if (compressedFormats.hasOwnProperty(name)) {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, compressedFormats[name], testSize, testSize, 0, new Uint8Array(expectedByteLength(testSize, testSize, compressedFormats[name])));
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with extension disabled.");
+ }
+ }
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} expectedFormats Mapping from format names to format enum values.
+ */
+let testCompressedFormatsListed = function(gl, expectedFormats) {
+ debug("");
+ debug("Testing that every format is listed by the compressed texture formats query");
+
+ let supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
+
+ let failed;
+ let count = 0;
+ for (let name in expectedFormats) {
+ if (expectedFormats.hasOwnProperty(name)) {
+ ++count;
+ let format = expectedFormats[name];
+ failed = true;
+ for (let ii = 0; ii < supportedFormats.length; ++ii) {
+ if (format == supportedFormats[ii]) {
+ testPassed("supported format " + name + " exists");
+ failed = false;
+ break;
+ }
+ }
+ if (failed) {
+ testFailed("supported format " + name + " does not exist");
+ }
+ }
+ }
+ if (supportedFormats.length != count) {
+ testFailed("Incorrect number of supported formats, was " + supportedFormats.length + " should be " + count);
+ }
+};
+
+/**
+ * @param {Object} ext Compressed texture extension object.
+ * @param {Object} expectedFormats Mapping from format names to format enum values.
+ */
+let testCorrectEnumValuesInExt = function(ext, expectedFormats) {
+ debug("");
+ debug("Testing that format enum values in the extension object are correct");
+
+ for (name in expectedFormats) {
+ if (expectedFormats.hasOwnProperty(name)) {
+ if (isResultCorrect(ext[name], expectedFormats[name])) {
+ testPassed("Enum value for " + name + " matches 0x" + ext[name].toString(16));
+ } else {
+ testFailed("Enum value for " + name + " mismatch: 0x" + ext[name].toString(16) + " should be 0x" + expectedFormats[name].toString(16));
+ }
+ }
+ }
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} validFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
+ */
+let testFormatRestrictionsOnBufferSize = function(gl, validFormats, expectedByteLength, getBlockDimensions) {
+ debug("");
+ debug("Testing format restrictions on texture upload buffer size");
+
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ for (let formatId in validFormats) {
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ let expectedSize = expectedByteLength(blockSize.width * 4, blockSize.height * 4, format);
+ let data = new Uint8Array(expectedSize);
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 3, blockSize.height * 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small width)");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 5, blockSize.height * 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large width)");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 3, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small height)");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 5, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large height)");
+ }
+ }
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} validFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
+ * @param {number} width Width of the image in pixels.
+ * @param {number} height Height of the image in pixels.
+ * @param {Object} subImageConfigs configs for compressedTexSubImage calls
+ */
+let testTexSubImageDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, width, height, subImageConfigs) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ for (let formatId in validFormats) {
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ debug("testing " + ctu.formatToString(ext, format));
+ let expectedSize = expectedByteLength(width, height, format);
+ let data = new Uint8Array(expectedSize);
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setting up compressed texture");
+
+ for (let i = 0, len = subImageConfigs.length; i < len; ++i) {
+ let c = subImageConfigs[i];
+ let subData = new Uint8Array(expectedByteLength(c.width, c.height, format));
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, c.xoffset, c.yoffset, c.width, c.height, format, subData);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ }
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+};
+
+let testTexImageLevelDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, imageConfigs) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ for (let formatId in validFormats) {
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ debug("testing " + ctu.formatToString(ext, format));
+
+ for (let i = 0, len = imageConfigs.length; i < len; ++i) {
+ let c = imageConfigs[i];
+ let data = new Uint8Array(expectedByteLength(c.width, c.height, format));
+ gl.compressedTexImage2D(gl.TEXTURE_2D, c.level, format, c.width, c.height, 0, data);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ }
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+}
+
+let testTexStorageLevelDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, imageConfigs) {
+ for (let formatId in validFormats) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ debug("testing " + ctu.formatToString(ext, format));
+
+ for (let i = 0, len = imageConfigs.length; i < len; ++i) {
+ let c = imageConfigs[i];
+ let data = new Uint8Array(expectedByteLength(c.width, c.height, format));
+ if (i == 0) {
+ gl.texStorage2D(gl.TEXTURE_2D, imageConfigs.length, format, c.width, c.height);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, i, 0, 0, c.width, c.height, format, data);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ }
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+ }
+}
+
+return {
+ formatToString: formatToString,
+ insertCaptionedImg: insertCaptionedImg,
+ makeScaledImage: makeScaledImage,
+ testCompressedFormatsListed: testCompressedFormatsListed,
+ testCompressedFormatsUnavailableWhenExtensionDisabled: testCompressedFormatsUnavailableWhenExtensionDisabled,
+ testCorrectEnumValuesInExt: testCorrectEnumValuesInExt,
+ testFormatRestrictionsOnBufferSize: testFormatRestrictionsOnBufferSize,
+ testTexSubImageDimensions: testTexSubImageDimensions,
+ testTexImageLevelDimensions: testTexImageLevelDimensions,
+ testTexStorageLevelDimensions: testTexStorageLevelDimensions,
+};
+
+})(); \ No newline at end of file
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js b/dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js
new file mode 100644
index 0000000000..f6476463d2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js
@@ -0,0 +1,52 @@
+"use strict";
+
+// Properties to be ignored because they were added in versions of the
+// spec that are backward-compatible with this version
+const IGNORED_METHODS = [
+ // There is no official spec for the commit API yet, the proposal link is:
+ // https://wiki.whatwg.org/wiki/OffscreenCanvas
+ "commit",
+
+ // For WebXR integration:
+ "makeXRCompatible",
+];
+
+function assertFunction(v, f) {
+ try {
+ if (typeof v[f] != "function") {
+ testFailed(`Property either does not exist or is not a function: ${f}`);
+ return false;
+ } else {
+ return true;
+ }
+ } catch(e) {
+ testFailed(`Trying to access the property '${f}' threw an error: ${e.toString()}`);
+ }
+}
+
+function testContextMethods(gl, requiredContextMethods) {
+ const acceptableMethods = [].concat(requiredContextMethods, IGNORED_METHODS);
+
+ let passed = true;
+ requiredContextMethods.forEach(method => {
+ const r = assertFunction(gl, method);
+ passed = passed && r;
+ });
+ if (passed) {
+ testPassed("All WebGL methods found.");
+ }
+ let extended = false;
+ for (let propertyName of Object.getOwnPropertyNames(gl)) {
+ if (typeof gl[propertyName] == "function" && !acceptableMethods.includes(propertyName)) {
+ if (!extended) {
+ extended = true;
+ testFailed("Also found the following extra methods:");
+ }
+ testFailed(propertyName);
+ }
+ }
+
+ if (!extended) {
+ testPassed("No extra methods found on WebGL context.");
+ }
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js
new file mode 100644
index 0000000000..51509e8a6e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js
@@ -0,0 +1,473 @@
+"use strict";
+
+function allocateTexture()
+{
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed");
+ return texture;
+}
+
+function checkRenderingResults()
+{
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+}
+
+function arrayToString(arr, size) {
+ var mySize;
+ if (!size)
+ mySize = arr.length;
+ else
+ mySize = size;
+ var out = "[";
+ for (var ii = 0; ii < mySize; ++ii) {
+ if (ii > 0) {
+ out += ", ";
+ }
+ out += arr[ii];
+ }
+ return out + "]";
+}
+
+function runReadbackTest(testProgram, subtractor)
+{
+ // Verify floating point readback
+ debug("Checking readback of floating-point values");
+ var buf = new Float32Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, buf);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels from floating-point framebuffer should succeed");
+ var ok = true;
+ var tolerance = 8.0; // TODO: factor this out from both this test and the subtractor shader above.
+ for (var ii = 0; ii < buf.length; ++ii) {
+ if (Math.abs(buf[ii] - subtractor[ii]) > tolerance) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ testPassed("readPixels of float-type data from floating-point framebuffer succeeded");
+ } else {
+ testFailed("readPixels of float-type data from floating-point framebuffer failed: expected "
+ + arrayToString(subtractor, 4) + ", got " + arrayToString(buf));
+ }
+}
+
+function runFloatTextureRenderTargetTest(enabled, internalFormatString, format, type, testProgram, numberOfChannels, subtractor, texSubImageCover)
+{
+ let internalFormat = eval(internalFormatString);
+ debug("");
+ debug("testing floating-point " + internalFormatString + " texture render target" + (texSubImageCover > 0 ? " after calling texSubImage" : ""));
+
+ var texture = allocateTexture();
+ var width = 2;
+ var height = 2;
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed");
+
+ // Try to use this texture as a render target.
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ var completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (!enabled) {
+ if (completeStatus == gl.FRAMEBUFFER_COMPLETE && !enabled)
+ testFailed("floating-point " + internalFormatString + " render target should not be supported");
+ else
+ testPassed("floating-point " + internalFormatString + " render target should not be supported");
+ return;
+ }
+
+ if (completeStatus != gl.FRAMEBUFFER_COMPLETE) {
+ if (version == 1 && format == gl.RGB)
+ testPassed("floating-point " + internalFormatString + " render target not supported; this is allowed.")
+ else
+ testFailed("floating-point " + internalFormatString + " render target not supported");
+ return;
+ }
+
+ if (texSubImageCover > 0) {
+ // Ensure that replacing the whole texture or a part of it with texSubImage2D doesn't affect renderability
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ var data = new Float32Array(width * height * numberOfChannels * texSubImageCover);
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height * texSubImageCover, format, type, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texSubImage2D should succeed if EXT_color_buffer_half_float is enabled");
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("render target support changed after calling texSubImage2D");
+ return;
+ }
+ }
+
+ var renderProgram =
+ wtu.setupProgram(gl,
+ [wtu.simpleVertexShader, `void main()
+ {
+ gl_FragColor = vec4(1000.0, 1000.0, 1000.0, 1000.0);
+ }`],
+ ['vPosition'],
+ [0]);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering to floating-point texture should succeed");
+
+ // Now sample from the floating-point texture and verify we got the correct values.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.useProgram(testProgram);
+ gl.uniform1i(gl.getUniformLocation(testProgram, "tex"), 0);
+ gl.uniform4fv(gl.getUniformLocation(testProgram, "subtractor"), subtractor);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering from floating-point texture should succeed");
+ checkRenderingResults();
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ runReadbackTest(testProgram, subtractor);
+}
+
+function runFloatRenderbufferRenderTargetTest(enabled, internalFormatString, testProgram, numberOfChannels, subtractor)
+{
+ var internalFormat = eval(internalFormatString);
+ var samples = [0];
+ if (enabled && version > 1) {
+ samples = Array.prototype.slice.call(gl.getInternalformatParameter(gl.RENDERBUFFER, internalFormat, gl.SAMPLES));
+ samples.push(0);
+ }
+ for (var ndx = 0; ndx < samples.length; ++ndx) {
+ debug("");
+ debug("testing floating-point " + internalFormatString + " renderbuffer render target with number of samples " + samples[ndx]);
+
+ var colorbuffer = gl.createRenderbuffer();
+ var width = 2;
+ var height = 2;
+ gl.bindRenderbuffer(gl.RENDERBUFFER, colorbuffer);
+ if (samples[ndx] == 0)
+ gl.renderbufferStorage(gl.RENDERBUFFER, internalFormat, width, height);
+ else
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[ndx], internalFormat, width, height);
+ if (!enabled) {
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "floating-point renderbuffer allocation should fail if EXT_color_buffer_half_float is not enabled or this is a 32 bit format");
+ return;
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point renderbuffer allocation should succeed if EXT_color_buffer_half_float is enabled");
+ }
+
+ // Try to use this renderbuffer as a render target.
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorbuffer);
+
+ var completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (completeStatus != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("floating-point " + internalFormatString + " render target not supported");
+ return;
+ }
+ var resolveColorRbo = null;
+ var resolveFbo = null;
+ if (samples[ndx] > 0) {
+ resolveColorRbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, resolveColorRbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER, internalFormat, width, height);
+ resolveFbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, resolveFbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, resolveColorRbo);
+ completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (completeStatus != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Failed to create resolve framebuffer");
+ return;
+ }
+ }
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.clearColor(1000.0, 1000.0, 1000.0, 1000.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ if (samples[ndx] > 0) {
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, resolveFbo);
+ gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, resolveFbo);
+ }
+ runReadbackTest(testProgram, subtractor);
+ }
+}
+
+function runRGB16FNegativeTest()
+{
+ debug("");
+ debug("testing RGB16F isn't color renderable");
+
+ var texture = allocateTexture();
+ var width = 2;
+ var height = 2;
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB16F, width, height, 0, gl.RGB, gl.FLOAT, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "RGB16F texture allocation should succeed");
+
+ // Try to use this texture as a render target.
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ var completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (completeStatus == gl.FRAMEBUFFER_COMPLETE)
+ testFailed("RGB16F render target should not be supported with or without enabling EXT_color_buffer_half_float");
+ else
+ testPassed("RGB16F render target should not be supported with or without enabling EXT_color_buffer_half_float");
+ gl.deleteTexture(texture);
+
+ var colorbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, colorbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB16F, width, height);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "RGB16F renderbuffer allocation should fail with or without enabling EXT_color_buffer_half_float");
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ gl.deleteRenderbuffer(colorbuffer);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fbo);
+}
+
+function runUniqueObjectTest()
+{
+ debug("");
+ debug("Testing that getExtension() returns the same object each time");
+ gl.getExtension("EXT_color_buffer_half_float").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("EXT_color_buffer_half_float").myProperty', '2');
+}
+
+function runInternalFormatQueryTest()
+{
+ debug("");
+ debug("testing the internal format query");
+
+ var maxSamples = gl.getParameter(gl.MAX_SAMPLES);
+ const formats = [gl.RGBA16F, gl.R16F, gl.RG16F];
+ var firstMultiOnlyFormat = 4;
+ for (var fmt = 0; fmt < formats.length; ++fmt) {
+ var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, formats[fmt], gl.SAMPLES);
+ if (fmt >= firstMultiOnlyFormat && (samples.length == 0 || samples[0] < maxSamples)) {
+ testFailed("the maximum value in SAMPLES should be at least " + maxSamples);
+ return;
+ }
+
+ var prevSampleCount = 0;
+ var sampleCount;
+ for (var ndx = 0; ndx < samples.length; ++ndx, prevSampleCount = sampleCount) {
+ sampleCount = samples[ndx];
+ // sample count must be > 0
+ if (sampleCount <= 0) {
+ testFailed("Expected sample count to be at least one; got " + sampleCount);
+ return;
+ }
+
+ // samples must be ordered descending
+ if (ndx > 0 && sampleCount >= prevSampleCount) {
+ testFailed("Expected sample count to be ordered in descending order; got " + prevSampleCount + " at index " + (ndx - 1) + ", and " + sampleCount + " at index " + ndx);
+ return;
+ }
+ }
+ }
+ testPassed("Internal format query succeeded");
+}
+
+function runCopyTexImageTest(enabled)
+{
+ var width = 16;
+ var height = 16;
+ var level = 0;
+ var cases = [
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "R16F", valid: true, renderable: true, },
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "RG16F", valid: true, renderable: true, },
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "RGB16F", valid: true, renderable: true, },
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "RGBA16F", valid: true, renderable: true, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "R16F", valid: true, renderable: false, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "RG16F", valid: true, renderable: false, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "RGB16F", valid: true, renderable: false, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "RGBA16F", valid: false, renderable: false, },
+ { internalformat: "RG16F", format: "RG", destFormat: "R16F", valid: true, renderable: true, },
+ { internalformat: "RG16F", format: "RG", destFormat: "RG16F", valid: true, renderable: true, },
+ { internalformat: "RG16F", format: "RG", destFormat: "RGB16F", valid: false, renderable: true, },
+ { internalformat: "RG16F", format: "RG", destFormat: "RGBA16F", valid: false, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "R16F", valid: true, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "RG16F", valid: false, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "RGB16F", valid: false, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "RGBA16F", valid: false, renderable: true, },
+ ];
+ if (version == 1) {
+ cases = [
+ { valid: true, renderable: true, format: "RGBA", destFormat: "LUMINANCE", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "ALPHA", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "LUMINANCE_ALPHA", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "RGB", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "RGBA", },
+ { valid: true, renderable: true, format: "RGB", destFormat: "LUMINANCE", },
+ { valid: false, renderable: true, format: "RGB", destFormat: "ALPHA", },
+ { valid: false, renderable: true, format: "RGB", destFormat: "LUMINANCE_ALPHA", },
+ { valid: true, renderable: true, format: "RGB", destFormat: "RGB", },
+ { valid: false, renderable: true, format: "RGB", destFormat: "RGBA", },
+ { valid: true, renderable: false, format: "ALPHA", destFormat: "ALPHA", },
+ { valid: true, renderable: false, format: "LUMINANCE", destFormat: "LUMINANCE", },
+ { valid: true, renderable: false, format: "LUMINANCE_ALPHA", destFormat: "LUMINANCE_ALPHA", },
+ ];
+ }
+ cases.forEach(function(testcase) {
+ debug("");
+ debug(`Testing CopyTexImage2D for format: ${testcase.format}, internalformat: ${testcase.internalformat}, destformat: ${testcase.destFormat}`);
+
+ var format = gl[testcase.format];
+ var internalformat = version > 1 ? gl[testcase.internalformat] : format;
+ var type = version > 1 ? gl.HALF_FLOAT : 0x8D61 /* HALF_FLOAT_OES */;
+ var destFormat = gl[testcase.destFormat];
+ var texSrc = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texSrc);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ var data = new Uint16Array(width * height * 4);
+ gl.texImage2D(gl.TEXTURE_2D, level, internalformat, width, height, 0, format, type, data);
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texSrc, level);
+ var texDest = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texDest);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup framebuffer with texture should succeed.");
+ if (enabled && testcase.renderable) {
+ if (version == 1 && format == gl.RGB && gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
+ testPassed("RGB framebuffer attachment not supported. This is allowed.")
+ } else {
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ gl.copyTexImage2D(gl.TEXTURE_2D, level, destFormat, 0, 0, width, height, 0);
+ wtu.glErrorShouldBe(gl, testcase.valid ? gl.NO_ERROR : [gl.INVALID_ENUM, gl.INVALID_OPERATION], "CopyTexImage2D");
+ }
+ } else {
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+ gl.copyTexImage2D(gl.TEXTURE_2D, level, destFormat, 0, 0, width, height, 0);
+ wtu.glErrorShouldBe(gl, [gl.INVALID_ENUM, gl.INVALID_FRAMEBUFFER_OPERATION], "CopyTexImage2D should fail.");
+ }
+
+ gl.deleteTexture(texDest);
+ gl.deleteTexture(texSrc);
+ gl.deleteFramebuffer(fbo);
+ });
+}
+
+description("This test verifies the functionality of the EXT_color_buffer_half_float extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, version);
+
+if (version < 2) {
+ // These are exposed on the extension, but we need them before the extension has been requested so we can
+ // make sure they don't work.
+ gl.R16F = 0x822D;
+ gl.RG16F = 0x822F;
+ gl.RGB16F = 0x881B;
+ gl.RGBA16F = 0x881A;
+}
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ var texturedShaders = [
+ wtu.simpleTextureVertexShader,
+ `precision mediump float;
+ uniform sampler2D tex;
+ uniform vec4 subtractor;
+ varying vec2 texCoord;
+ void main()
+ {
+ vec4 color = texture2D(tex, texCoord);
+ if (abs(color.r - subtractor.r) +
+ abs(color.g - subtractor.g) +
+ abs(color.b - subtractor.b) +
+ abs(color.a - subtractor.a) < 16.0) {
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+ }`,
+ ];
+ var testProgram =
+ wtu.setupProgram(gl,
+ texturedShaders,
+ ['vPosition', 'texCoord0'],
+ [0, 1]);
+ var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
+
+ if (version > 1) {
+ // Ensure these formats can't be used for rendering if the extension is disabled
+ runFloatTextureRenderTargetTest(false, "gl.R16F", gl.RED, gl.FLOAT);
+ runFloatTextureRenderTargetTest(false, "gl.RG16F", gl.RG, gl.FLOAT);
+ runFloatTextureRenderTargetTest(false, "gl.RGBA16F", gl.RGBA, gl.FLOAT);
+ }
+
+ runFloatRenderbufferRenderTargetTest(false, "gl.R16F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RG16F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RGBA16F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.R32F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RG32F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RGBA32F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.R11F_G11F_B10F");
+
+ if (version > 1) {
+ runCopyTexImageTest(false);
+ // Ensure RGB16F can't be used for rendering.
+ runRGB16FNegativeTest();
+ }
+
+ let oesTextureHalfFloat = null;
+ if (version == 1) {
+ // oesTextureHalfFloat implicitly enables EXT_color_buffer_half_float if supported
+ oesTextureHalfFloat = gl.getExtension("OES_texture_half_float");
+ if (oesTextureHalfFloat && gl.getSupportedExtensions().includes("EXT_color_buffer_half_float")) {
+ runFloatTextureRenderTargetTest(true, "gl.RGBA", gl.RGBA, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 4, [1000, 1000, 1000, 1000], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RGB", gl.RGB, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 3, [1000, 1000, 1000, 1], 0);
+ }
+ }
+
+ var ext = null;
+ if (!(ext = gl.getExtension("EXT_color_buffer_half_float"))) {
+ testPassed("No EXT_color_buffer_half_float support -- this is legal");
+ } else {
+ testPassed("Successfully enabled EXT_color_buffer_half_float extension");
+
+ shouldBe("ext.RGB16F_EXT", "gl.RGB16F");
+ shouldBe("ext.RGBA16F_EXT", "gl.RGBA16F");
+ shouldBe("ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT", "0x8211");
+ shouldBe("ext.UNSIGNED_NORMALIZED_EXT", "0x8C17");
+
+ if (version > 1) {
+ runInternalFormatQueryTest();
+ runFloatTextureRenderTargetTest(true, "gl.R16F", gl.RED, gl.FLOAT, testProgram, 1, [1000, 1, 1, 1], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RG16F", gl.RG, gl.FLOAT, testProgram, 2, [1000, 1000, 1, 1], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RGBA16F", gl.RGBA, gl.FLOAT, testProgram, 4, [1000, 1000, 1000, 1000], 0);
+ runFloatRenderbufferRenderTargetTest(true, "gl.R16F", testProgram, 1, [1000, 1, 1, 1]);
+ runFloatRenderbufferRenderTargetTest(true, "gl.RG16F", testProgram, 2, [1000, 1000, 1, 1]);
+ runFloatRenderbufferRenderTargetTest(true, "gl.RGBA16F", testProgram, 4, [1000, 1000, 1000, 1000]);
+ }
+ if (version == 1) {
+ shouldBeNonNull(oesTextureHalfFloat); // Required by spec
+ runFloatTextureRenderTargetTest(true, "gl.RGBA", gl.RGBA, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 4, [1000, 1000, 1000, 1000], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RGB", gl.RGB, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 3, [1000, 1000, 1000, 1], 0);
+ runFloatTextureRenderTargetTest(false, "gl.LUMINANCE_ALPHA", gl.LUMINANCE_ALPHA, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 2, [1000, 1000, 1000, 1000], 0);
+ runFloatTextureRenderTargetTest(false, "gl.LUMINANCE", gl.LUMINANCE, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 1, [1000, 1, 1, 1], 0);
+ }
+
+ if (version > 1)
+ runRGB16FNegativeTest(); // Ensure EXT_color_buffer_half_float does not enable RGB16F as color renderable.
+
+ runCopyTexImageTest(true);
+
+ runUniqueObjectTest();
+ }
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js
new file mode 100644
index 0000000000..ab2f9f9288
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js
@@ -0,0 +1,237 @@
+'use strict';
+
+const trivialVsSrc = `
+void main()
+{
+ gl_Position = vec4(0,0,0,1);
+}
+`;
+const trivialFsSrc = `
+void main()
+{
+ gl_FragColor = vec4(0,1,0,1);
+}
+`;
+const trivialVsMrtSrc100 = `
+void main()
+{
+ gl_Position = vec4(0,0,0,1);
+}
+`;
+const trivialFsMrtSrc100 = `
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+void main()
+{
+ gl_FragData[0] = vec4(1, 0, 0, 1);
+ gl_FragData[1] = vec4(0, 1, 0, 1);
+}
+`;
+const trivialVsMrtSrc300 = `#version 300 es
+void main()
+{
+ gl_Position = vec4(0,0,0,1);
+}
+`;
+const trivialFsMrtSrc300 = `#version 300 es
+precision mediump float;
+layout(location = 0) out vec4 o_color0;
+layout(location = 1) out vec4 o_color1;
+void main()
+{
+ o_color0 = vec4(1, 0, 0, 1);
+ o_color1 = vec4(0, 1, 0, 1);
+}
+`;
+
+function testExtFloatBlend(internalFormat) {
+ const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1;
+
+ const prog = wtu.setupProgram(gl, [trivialVsSrc, trivialFsSrc]);
+ gl.useProgram(prog);
+
+ const tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.disable(gl.BLEND);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'Float32 draw target without blending');
+
+ gl.enable(gl.BLEND);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+}
+
+function testExtFloatBlendMRTImpl(version, internalFormat, shaders, attachments, drawBuffers) {
+ const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1;
+
+ const prog = wtu.setupProgram(gl, shaders);
+ gl.useProgram(prog);
+
+ const tex1 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ const tex2 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex2);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ const texF1 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texF1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const texF2 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texF2);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, tex1, 0);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, tex2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ drawBuffers(attachments);
+
+ gl.enable(gl.BLEND);
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'No Float32 color attachment');
+
+ if (version < 2) {
+ // EXT_draw_buffers require all color buffers having the same number of bitplanes
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, texF1, 0);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, texF2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+ } else {
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, texF1, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, texF2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, tex1, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ drawBuffers([attachments[0]]);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'Float32 color attachment draw buffer is not enabled');
+
+ drawBuffers(attachments);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, tex2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'No Float32 color attachment');
+ }
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex1);
+ gl.deleteTexture(tex2);
+ gl.deleteTexture(texF1);
+ gl.deleteTexture(texF2);
+}
+
+function testExtFloatBlendMRT(version, drawBuffersExt) {
+ if (version < 2) {
+ if (!drawBuffersExt) return;
+ testExtFloatBlendMRTImpl(
+ version,
+ gl.RGBA,
+ [trivialVsMrtSrc100, trivialFsMrtSrc100],
+ [drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, drawBuffersExt.COLOR_ATTACHMENT1_WEBGL],
+ drawBuffersExt.drawBuffersWEBGL.bind(drawBuffersExt)
+ );
+ } else {
+ testExtFloatBlendMRTImpl(
+ version,
+ gl.RGBA32F,
+ [trivialVsMrtSrc300, trivialFsMrtSrc300],
+ [gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1],
+ gl.drawBuffers.bind(gl)
+ );
+ }
+}
+
+function testExtFloatBlendNonFloat32TypeImpl(internalFormat, formats) {
+ const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1;
+
+ const prog = wtu.setupProgram(gl, [trivialVsSrc, trivialFsSrc]);
+ gl.useProgram(prog);
+
+ gl.enable(gl.BLEND);
+
+ const tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'UNSIGNED_BYTE should blend anyway');
+
+ for (let i = 0, len = formats.length; i < len; i++) {
+ gl.texImage2D(gl.TEXTURE_2D, 0, formats[i][0], 1, 1, 0, formats[i][1], formats[i][2], null);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'Any other float type which is not 32-bit-Float should blend anyway');
+ }
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+}
+
+function testExtFloatBlendNonFloat32Type(version, oesTextureHalfFloat) {
+ if (version < 2) {
+ if (!oesTextureHalfFloat) return;
+ const formats = [
+ [gl.RGBA, gl.RGBA, oesTextureHalfFloat.HALF_FLOAT_OES]
+ ];
+ testExtFloatBlendNonFloat32TypeImpl(gl.RGBA, formats);
+ } else {
+ const formats = [
+ [gl.RGBA16F, gl.RGBA, gl.HALF_FLOAT],
+ [gl.RGBA16F, gl.RGBA, gl.FLOAT],
+ [gl.RG16F, gl.RG, gl.FLOAT],
+ [gl.R16F, gl.RED, gl.FLOAT],
+ [gl.R11F_G11F_B10F, gl.RGB, gl.FLOAT]
+ ];
+ testExtFloatBlendNonFloat32TypeImpl(gl.RGBA32F, formats);
+ }
+}
+
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js
new file mode 100644
index 0000000000..1e60a79717
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js
@@ -0,0 +1,169 @@
+"use strict";
+description("This test verifies the functionality of the EXT_texture_filter_anisotropic extension, if it is available.");
+
+debug("");
+
+let wtu = WebGLTestUtils;
+let canvas = document.getElementById("canvas");
+let gl = wtu.create3DContext(canvas, undefined, contextVersion);
+let ext = null;
+let sampler;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runHintTestDisabled();
+ if (contextVersion >= 2) {
+ runSamplerTestDisabled();
+ }
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "EXT_texture_filter_anisotropic");
+
+ if (!ext) {
+ testPassed("No EXT_texture_filter_anisotropic support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled EXT_texture_filter_anisotropic extension");
+
+ runSupportedTest(true);
+ runHintTestEnabled();
+ if (contextVersion >= 2) {
+ runSamplerTestEnabled();
+ }
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_texture_filter_anisotropic") !== undefined) {
+ if (extensionEnabled) {
+ testPassed("EXT_texture_filter_anisotropic listed as supported and getExtension succeeded");
+ } else {
+ testFailed("EXT_texture_filter_anisotropic listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("EXT_texture_filter_anisotropic not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("EXT_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runHintTestDisabled() {
+ debug("Testing MAX_TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+
+ const MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+ shouldBeNull(`gl.getParameter(${MAX_TEXTURE_MAX_ANISOTROPY_EXT})`);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY_EXT should not be queryable if extension is disabled");
+
+ debug("Testing TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+ const TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+ let texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ shouldBeNull(`gl.getTexParameter(gl.TEXTURE_2D, ${TEXTURE_MAX_ANISOTROPY_EXT})`);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be queryable if extension is disabled");
+
+ gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be settable if extension is disabled");
+
+ gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be settable if extension is disabled");
+
+ gl.deleteTexture(texture);
+}
+
+function runHintTestEnabled() {
+ debug("Testing MAX_TEXTURE_MAX_ANISOTROPY_EXT with extension enabled");
+
+ shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT", "0x84FF");
+
+ let max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY_EXT query should succeed if extension is enabled");
+
+ if (max_anisotropy >= 2) {
+ testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY_EXT is 2.0");
+ } else {
+ testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY_EXT is 2.0, returned values was: " + max_anisotropy);
+ }
+
+ // TODO make a texture and verify initial value == 1 and setting to less than 1 is invalid value
+
+ debug("Testing TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+ shouldBe("ext.TEXTURE_MAX_ANISOTROPY_EXT", "0x84FE");
+
+ let texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ let queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY_EXT query should succeed if extension is enabled");
+
+ if (queried_value == 1) {
+ testPassed("Initial value of TEXTURE_MAX_ANISOTROPY_EXT is 1.0");
+ } else {
+ testFailed("Initial value of TEXTURE_MAX_ANISOTROPY_EXT should be 1.0, returned value was: " + queried_value);
+ }
+
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to < 1 should be an invalid value");
+
+ gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY_EXT set to < 1 should be an invalid value");
+
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to >= 2 should succeed");
+
+ gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY_EXT set to >= 2 should succeed");
+
+ queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ if (queried_value == max_anisotropy) {
+ testPassed("Set value of TEXTURE_MAX_ANISOTROPY_EXT matches expecation");
+ } else {
+ testFailed("Set value of TEXTURE_MAX_ANISOTROPY_EXT should be: " + max_anisotropy + " , returned value was: " + queried_value);
+ }
+
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 1.5);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to 1.5 should succeed");
+
+ queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ if (queried_value == 1.5) {
+ testPassed("Set value of TEXTURE_MAX_ANISOTROPY_EXT matches expecation");
+ } else {
+ testFailed("Set value of TEXTURE_MAX_ANISOTROPY_EXT should be: " + 1.5 + " , returned value was: " + queried_value);
+ }
+
+ gl.deleteTexture(texture);
+}
+
+function runSamplerTestDisabled() {
+ sampler = gl.createSampler();
+ const TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+ gl.samplerParameterf(sampler, TEXTURE_MAX_ANISOTROPY_EXT, 1.0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "setting TEXTURE_MAX_ANISOTROPY_EXT on sampler without extension enabled should fail");
+ shouldBeNull(`gl.getSamplerParameter(sampler, ${TEXTURE_MAX_ANISOTROPY_EXT})`);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "querying TEXTURE_MAX_ANISOTROPY_EXT on sampler without extension enabled should fail");
+ gl.deleteSampler(sampler);
+}
+
+function runSamplerTestEnabled() {
+ let sampler = gl.createSampler();
+ gl.samplerParameterf(sampler, ext.TEXTURE_MAX_ANISOTROPY_EXT, 1.5);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setting TEXTURE_MAX_ANISOTROPY_EXT on sampler should succeed");
+ let queried_value = gl.getSamplerParameter(sampler, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "querying TEXTURE_MAX_ANISOTROPY_EXT on sampler should succeed");
+ if (queried_value == 1.5) {
+ testPassed("Set value of TEXTURE_MAX_ANISOTROPY_EXT on sampler matches expecation");
+ } else {
+ testFailed("Set value of TEXTURE_MAX_ANISOTROPY_EXT on sampler should be: " + 1.5 + " , returned value was: " + queried_value);
+ }
+ gl.deleteSampler(sampler);
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js
new file mode 100644
index 0000000000..4c853fc4fa
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js
@@ -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.
+*/
+
+"use strict";
+
+var runBindAttribLocationAliasingTest = function(wtu, gl, glFragmentShader, vertexShaderTemplate) {
+ var typeInfo = [
+ { type: 'float', asVec4: 'vec4(0.0, $(var), 0.0, 1.0)' },
+ { type: 'vec2', asVec4: 'vec4($(var), 0.0, 1.0)' },
+ { type: 'vec3', asVec4: 'vec4($(var), 1.0)' },
+ { type: 'vec4', asVec4: '$(var)' },
+ ];
+ var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ // Test all type combinations of a_1 and a_2.
+ typeInfo.forEach(function(typeInfo1) {
+ typeInfo.forEach(function(typeInfo2) {
+ debug('attribute_1: ' + typeInfo1.type + ' attribute_2: ' + typeInfo2.type);
+ var replaceParams = {
+ type_1: typeInfo1.type,
+ type_2: typeInfo2.type,
+ gl_Position_1: wtu.replaceParams(typeInfo1.asVec4, {var: 'a_1'}),
+ gl_Position_2: wtu.replaceParams(typeInfo2.asVec4, {var: 'a_2'})
+ };
+ var strVertexShader = wtu.replaceParams(vertexShaderTemplate, replaceParams);
+ var glVertexShader = wtu.loadShader(gl, strVertexShader, gl.VERTEX_SHADER);
+ assertMsg(glVertexShader != null, "Vertex shader compiled successfully.");
+ // Bind both a_1 and a_2 to the same position and verify the link fails.
+ // Do so for all valid positions available.
+ for (var l = 0; l < maxAttributes; l++) {
+ var glProgram = gl.createProgram();
+ gl.bindAttribLocation(glProgram, l, 'a_1');
+ gl.bindAttribLocation(glProgram, l, 'a_2');
+ gl.attachShader(glProgram, glVertexShader);
+ gl.attachShader(glProgram, glFragmentShader);
+ gl.linkProgram(glProgram);
+ var linkStatus = gl.getProgramParameter(glProgram, gl.LINK_STATUS);
+ assertMsg(!linkStatus, "Link should fail when both attributes are aliased to location " + l);
+ }
+ });
+ });
+}; \ No newline at end of file
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js
new file mode 100644
index 0000000000..32d451f7a2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js
@@ -0,0 +1,123 @@
+/*
+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.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description("This test ensures various WebGL functions fail when passed invalid OpenGL ES enums.");
+
+debug("");
+debug("Canvas.getContext");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas", undefined, contextVersion);
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ debug("");
+ debug("Checking gl enums.");
+
+ var buffer = new ArrayBuffer(2);
+ var buf = new Uint16Array(buffer);
+ var tex = gl.createTexture();
+ var program = wtu.createProgram(gl, wtu.loadStandardVertexShader(gl), wtu.loadStandardFragmentShader(gl));
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ var tests = [
+ "gl.disable(desktopGL['CLIP_PLANE0'])",
+ "gl.disable(desktopGL['POINT_SPRITE'])",
+ "gl.getBufferParameter(gl.ARRAY_BUFFER, desktopGL['PIXEL_PACK_BUFFER'])",
+ "gl.hint(desktopGL['PERSPECTIVE_CORRECTION_HINT'], gl.FASTEST)",
+ "gl.isEnabled(desktopGL['CLIP_PLANE0'])",
+ "gl.isEnabled(desktopGL['POINT_SPRITE'])",
+ "gl.pixelStorei(desktopGL['PACK_SWAP_BYTES'], 1)",
+ "gl.getParameter(desktopGL['NUM_COMPRESSED_TEXTURE_FORMATS'])",
+ "gl.getParameter(desktopGL['EXTENSIONS'])",
+ "gl.getParameter(desktopGL['SHADER_COMPILER'])",
+ "gl.getParameter(desktopGL['SHADER_BINARY_FORMATS'])",
+ "gl.getParameter(desktopGL['NUM_SHADER_BINARY_FORMATS'])",
+ ];
+
+ if (contextVersion < 2) {
+ tests = tests.concat([
+ "gl.blendEquation(desktopGL['MIN'])",
+ "gl.blendEquation(desktopGL['MAX'])",
+ "gl.blendEquationSeparate(desktopGL['MIN'], gl.FUNC_ADD)",
+ "gl.blendEquationSeparate(desktopGL['MAX'], gl.FUNC_ADD)",
+ "gl.blendEquationSeparate(gl.FUNC_ADD, desktopGL['MIN'])",
+ "gl.blendEquationSeparate(gl.FUNC_ADD, desktopGL['MAX'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STREAM_READ'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STREAM_COPY'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STATIC_READ'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STATIC_COPY'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['DYNAMIC_READ'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['DYNAMIC_COPY'])",
+ "gl.bindTexture(desktopGL['TEXTURE_2D_ARRAY'], tex)",
+ "gl.bindTexture(desktopGL['TEXTURE_3D'], tex)",
+ ]);
+ } else {
+ tests = tests.concat([
+ "gl.bindTexture(desktopGL['TEXTURE_RECTANGLE_EXT'], tex)",
+ "gl.enable(desktopGL['PRIMITIVE_RESTART_FIXED_INDEX'])",
+ "gl.getActiveUniforms(program, [0], desktopGL['UNIFORM_NAME_LENGTH'])",
+ "gl.getProgramParameter(program, desktopGL['ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH'])",
+ "gl.getProgramParameter(program, desktopGL['TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH'])",
+ "gl.getProgramParameter(program, desktopGL['PROGRAM_BINARY_RETRIEVABLE_HINT'])",
+ "gl.getProgramParameter(program, desktopGL['PROGRAM_BINARY_LENGTH'])",
+ "gl.getParameter(program, desktopGL['NUM_PROGRAM_BINARY_FORMATS'])",
+ ]);
+ }
+
+ for (var ii = 0; ii < tests.length; ++ii) {
+ TestEval(tests[ii]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, tests[ii] + " should return INVALID_ENUM.");
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ tests = [
+ "gl.getTexParameter(gl.TEXTURE_2D, desktopGL['GENERATE_MIPMAP'])",
+ "gl.texParameteri(gl.TEXTURE_2D, desktopGL['GENERATE_MIPMAP'], 1)",
+ "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, desktopGL['CLAMP_TO_BORDER'])",
+ ];
+
+ if (contextVersion < 2) {
+ tests = tests.concat([
+ "gl.texParameteri(desktopGL['TEXTURE_2D_ARRAY'], gl.TEXTURE_MAG_FILTER, gl.NEAREST)",
+ "gl.texParameteri(desktopGL['TEXTURE_3D'], gl.TEXTURE_MAG_FILTER, gl.NEAREST)",
+ ]);
+ } else {
+ tests = tests.concat([
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_R_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_G_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_B_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_A_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], gl.TEXTURE_WRAP_R, desktopGL['CLAMP_TO_BORDER'])",
+ ]);
+ }
+
+ for (var ii = 0; ii < tests.length; ++ii) {
+ TestEval(tests[ii]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, tests[ii] + " should return INVALID_ENUM.");
+ }
+ if (contextVersion >= 2) {
+ var uniformBlockProgram = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(uniformBlockProgram);
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.LINK_STATUS)', 'true');
+ shouldBe('gl.getError()', 'gl.NO_ERROR');
+ gl.getActiveUniformBlockParameter(uniformBlockProgram, 0, desktopGL['UNIFORM_BLOCK_NAME_LENGTH']);
+ shouldBe('gl.getError()', 'gl.INVALID_ENUM');
+ }
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js
new file mode 100644
index 0000000000..8844bbf544
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js
@@ -0,0 +1,183 @@
+/*
+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.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description();
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("example", undefined, contextVersion);
+
+// NOTE: We explicitly do this in a funky order
+// to hopefully find subtle bugs.
+
+var targets = [
+ 'TEXTURE_2D',
+ 'TEXTURE_2D',
+ 'TEXTURE_CUBE_MAP',
+ 'TEXTURE_CUBE_MAP'
+];
+
+if (contextVersion > 1) {
+ targets = targets.concat([
+ 'TEXTURE_2D_ARRAY',
+ 'TEXTURE_2D_ARRAY',
+ 'TEXTURE_3D',
+ 'TEXTURE_3D'
+ ]);
+}
+
+// Create textures on different active textures.
+for (var ii = 0; ii < targets.length; ++ii) {
+ var target = targets[ii];
+ var tex = gl.createTexture();
+ gl.activeTexture(gl.TEXTURE0 + ii);
+ gl.bindTexture(gl[target], tex);
+}
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+
+var states = [
+ { state: 'TEXTURE_WRAP_S', default: 'REPEAT', value1: 'CLAMP_TO_EDGE', value2: 'REPEAT' },
+ { state: 'TEXTURE_WRAP_T', default: 'REPEAT', value1: 'MIRRORED_REPEAT', value2: 'REPEAT' },
+ { state: 'TEXTURE_MAG_FILTER', default: 'LINEAR', value1: 'NEAREST', value2: 'LINEAR' },
+ { state: 'TEXTURE_MIN_FILTER', default: 'NEAREST_MIPMAP_LINEAR', value1: 'LINEAR_MIPMAP_LINEAR', value2: 'NEAREST' }
+];
+
+if (contextVersion > 1) {
+ states = states.concat([
+ { state: 'TEXTURE_WRAP_R', default: 'REPEAT', value1: 'CLAMP_TO_EDGE', value2: 'MIRRORED_REPEAT' },
+ { state: 'TEXTURE_COMPARE_FUNC', default: 'LEQUAL', value1: 'GREATER', value2: 'LESS' },
+ { state: 'TEXTURE_COMPARE_MODE', default: 'NONE', value1: 'COMPARE_REF_TO_TEXTURE', value2: 'NONE' },
+ { state: 'TEXTURE_BASE_LEVEL', default: 0, value1: 100, value2: 99 },
+ { state: 'TEXTURE_MAX_LEVEL', default: 1000, value1: 800, value2: 300 },
+ { state: 'TEXTURE_MIN_LOD', default: -1000.0, value1: -500.0, value2: -999.0 },
+ { state: 'TEXTURE_MAX_LOD', default: 1000.0, value1: 500.0, value2: 999.0 },
+ // Note: For TEXTURE_IMMUTABLE_LEVELS and TEXTURE_IMMUTABLE_FORMAT,
+ // these two pname are used by getTexParameter API only, not available in texParameter[fi] in specifications.
+ // Thus, these two states store default value only.
+ { state: 'TEXTURE_IMMUTABLE_LEVELS', default: 0, },
+ { state: 'TEXTURE_IMMUTABLE_FORMAT', default: false, }
+ ]);
+}
+
+function getStateInfoValue(stateInfo, item, method) {
+ switch (stateInfo.state) {
+ case 'TEXTURE_WRAP_R':
+ case 'TEXTURE_WRAP_S':
+ case 'TEXTURE_WRAP_T':
+ case 'TEXTURE_MAG_FILTER':
+ case 'TEXTURE_MIN_FILTER':
+ case 'TEXTURE_COMPARE_FUNC':
+ case 'TEXTURE_COMPARE_MODE':
+ if (method === 'Get') {
+ return 'gl["' + stateInfo[item] + '"]';
+ } else if (method === 'Set') {
+ return gl[stateInfo[item]];
+ }
+ break;
+ case 'TEXTURE_BASE_LEVEL':
+ case 'TEXTURE_MAX_LEVEL':
+ case 'TEXTURE_MIN_LOD':
+ case 'TEXTURE_MAX_LOD':
+ if (method === 'Get') {
+ return '' + stateInfo[item];
+ } else if (method === 'Set') {
+ return stateInfo[item];
+ }
+ break;
+ case 'TEXTURE_IMMUTABLE_LEVELS':
+ case 'TEXTURE_IMMUTABLE_FORMAT':
+ // Return default value only.
+ return '' + stateInfo.default;
+ default:
+ wtu.error("Not reached!");
+ return null;
+ break;
+ }
+}
+
+function applyStates(fn) {
+ for (var ss = 0; ss < states.length; ++ss) {
+ var stateInfo = states[ss];
+ for (var ii = 0; ii < targets.length; ++ii) {
+ var target = targets[ii];
+ gl.activeTexture(gl.TEXTURE0 + ii);
+ fn(target, stateInfo);
+ }
+ }
+}
+
+// test the default state.
+applyStates(function(target, stateInfo) {
+ var a = 'gl.getTexParameter(gl["' + target + '"], gl["' + stateInfo.state + '"])';
+ var b = getStateInfoValue(stateInfo, 'default', 'Get');
+ shouldBe(a, b);
+});
+
+// test new state
+applyStates(function(target, stateInfo) {
+ switch (stateInfo.state) {
+ case 'TEXTURE_IMMUTABLE_FORMAT':
+ case 'TEXTURE_IMMUTABLE_LEVELS':
+ // Skip these two pname for texParameterf[fi].
+ break;
+ case 'TEXTURE_MIN_LOD':
+ case 'TEXTURE_MAX_LOD':
+ gl.texParameterf(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, 'value1', 'Set'));
+ break;
+ default:
+ gl.texParameteri(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, 'value1', 'Set'));
+ break;
+ }
+});
+
+applyStates(function(target, stateInfo) {
+ var a = 'gl.getTexParameter(gl["' + target + '"], gl["' + stateInfo.state + '"])';
+ var b = getStateInfoValue(stateInfo, 'value1', 'Get');
+ shouldBe(a, b);
+});
+
+// test different states on each target.
+function getItem(count) {
+ return (count % 2) ? 'value2' : 'value1';
+}
+
+applyStates(function() {
+ var count = 0;
+ return function(target, stateInfo) {
+ switch (stateInfo.state) {
+ case 'TEXTURE_IMMUTABLE_FORMAT':
+ case 'TEXTURE_IMMUTABLE_LEVELS':
+ // Skip these two pname for texParameterf[fi].
+ break;
+ case 'TEXTURE_MIN_LOD':
+ case 'TEXTURE_MAX_LOD':
+ gl.texParameterf(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, getItem(count), 'Set'));
+ break;
+ default:
+ gl.texParameteri(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, getItem(count), 'Set'));
+ break;
+ }
+ ++count;
+ }
+}());
+
+applyStates(function() {
+ var count = 0;
+ return function(target, stateInfo) {
+ var a = 'gl.getTexParameter(gl["' + target + '"], gl["' + stateInfo.state + '"])';
+ var b = getStateInfoValue(stateInfo, getItem(count), 'Get');
+ shouldBe(a, b);
+ ++count;
+ };
+}());
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js
new file mode 100644
index 0000000000..bd97434b77
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js
@@ -0,0 +1,1090 @@
+/*
+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.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+const wtu = WebGLTestUtils;
+description("Test of get calls against GL objects like getBufferParameter, etc.");
+
+let gl = wtu.create3DContext(undefined, undefined, contextVersion);
+
+async function testInvalidArgument(funcName, argumentName, validArgumentArray, func) {
+ let validArguments = {};
+ for (let ii = 0; ii < validArgumentArray.length; ++ii) {
+ validArguments[validArgumentArray[ii]] = true;
+ }
+ let success = true;
+ const MAX = 0x10000;
+ const STEP = Math.ceil(MAX / 10);
+ for (let ii = 0; ii < MAX; ii += 1) {
+ if (ii && ii % STEP == 0) {
+ debug(`(${ii} of ${MAX}: ${(ii/MAX*100).toFixed(1)}%)`);
+ await wtu.dispatchPromise(); // Spin the event loop.
+ }
+ if (!validArguments[ii]) {
+ let result = func(ii);
+ if (result !== null) {
+ success = false;
+ testFailed(funcName + " returned " + result + " instead of null for invalid " + argumentName + " enum: " + wtu.glEnumToString(gl, ii));
+ break;
+ }
+ let err = gl.getError();
+ if (err != gl.INVALID_ENUM) {
+ success = false;
+ testFailed(funcName + " did not generate INVALID_ENUM for invalid " + argumentName + " enum: " + wtu.glEnumToString(gl, ii));
+ break;
+ }
+ }
+ }
+ if (success) {
+ testPassed(funcName + " correctly handled invalid " + argumentName + " enums");
+ }
+}
+
+(async () => {
+ debug("");
+ debug("test getBufferParameter");
+ // Test getBufferParameter
+ let bufferTypes = [gl.ARRAY_BUFFER, gl.ELEMENT_ARRAY_BUFFER];
+ if (contextVersion > 1) {
+ bufferTypes = bufferTypes.concat([gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, gl.PIXEL_PACK_BUFFER, gl.PIXEL_UNPACK_BUFFER, gl.TRANSFORM_FEEDBACK_BUFFER, gl.UNIFORM_BUFFER]);
+ }
+ for (let bb = 0; bb < bufferTypes.length; ++bb) {
+ let bufferType = bufferTypes[bb];
+ let buffer = gl.createBuffer();
+ gl.bindBuffer(bufferType, buffer);
+ gl.bufferData(bufferType, 16, gl.DYNAMIC_DRAW);
+ let expression1 = "gl.getBufferParameter(" + bufferType + ", gl.BUFFER_SIZE)";
+ let expression2 = "gl.getBufferParameter(" + bufferType + ", gl.BUFFER_USAGE)";
+ shouldBe(expression1, '16');
+ shouldBe(expression2, 'gl.DYNAMIC_DRAW');
+ await testInvalidArgument("getBufferParameter", "parameter", [gl.BUFFER_SIZE, gl.BUFFER_USAGE], function(bufferType) {
+ return function(parameter) {
+ return gl.getBufferParameter(bufferType, parameter);
+ };
+ }(bufferType));
+ gl.bindBuffer(bufferType, null);
+ }
+ await testInvalidArgument(
+ "getBufferParameter",
+ "target",
+ bufferTypes,
+ function(target) {
+ return gl.getBufferParameter(target, gl.BUFFER_SIZE);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ let testCases = [
+ { contextStencil: true},
+ { contextStencil: false}
+ ];
+
+ for (let run = 0; run < testCases.length; ++run) {
+ debug("");
+ debug("Test getFramebufferAttachmentParameter with stencil " + testCases[run].contextStencil);
+
+ if (testCases[run].contextStencil) {
+ gl = wtu.create3DContext(null, {stencil: true}, contextVersion);
+ } else {
+ gl = wtu.create3DContext(null, {stencil: false}, contextVersion);
+ }
+
+ window.texture = gl.createTexture();
+ window.anotherTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ new Uint8Array([
+ 0, 0, 0, 255,
+ 255, 255, 255, 255,
+ 255, 255, 255, 255,
+ 0, 0, 0, 255]));
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ window.framebuffer = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ let colorAttachmentsNum = 1;
+ if (contextVersion > 1) {
+ gl.bindTexture(gl.TEXTURE_2D, anotherTexture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ new Uint8Array([
+ 0, 0, 0, 255,
+ 255, 255, 255, 255,
+ 255, 255, 255, 255,
+ 0, 0, 0, 255]));
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ colorAttachmentsNum = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + colorAttachmentsNum - 1, gl.TEXTURE_2D, anotherTexture, 0);
+ }
+ window.renderbuffer = gl.createRenderbuffer();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ if (contextVersion == 1)
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 2, 2);
+ else
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, 2, 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
+ if (contextVersion > 1)
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ // The for loop tests two color attachments for WebGL 2: the first one (gl.COLOR_ATTACHMENT0)
+ // and the last one (gl.COLOR_ATTACHMENT0 + gl.MAX_COLOR_ATTACHMENTS - 1).
+ for (let ii = 0; ii < colorAttachmentsNum; ii += (colorAttachmentsNum > 1 ? colorAttachmentsNum - 1 : 1)) {
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.TEXTURE');
+ if (ii == 0)
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'texture');
+ else
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'anotherTexture');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL)', '0');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE)', '0');
+ if (contextVersion > 1) {
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_RED_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_GREEN_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_BLUE_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER)', '0');
+ }
+ }
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.RENDERBUFFER');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'renderbuffer');
+ if (contextVersion > 1) {
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.RENDERBUFFER');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'renderbuffer');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.RENDERBUFFER');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'renderbuffer');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ }
+ let validParametersForFBAttachment =
+ [ gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
+ gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
+ ];
+ if (contextVersion > 1) {
+ validParametersForFBAttachment = validParametersForFBAttachment.concat([
+ gl.FRAMEBUFFER_ATTACHMENT_RED_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE,
+ gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING,
+ gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER
+ ]);
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "parameter",
+ validParametersForFBAttachment,
+ function(parameter) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT, parameter);
+ }
+ );
+ let validTargetsForFBAttachment = [gl.FRAMEBUFFER];
+ if (contextVersion > 1) {
+ validTargetsForFBAttachment = validTargetsForFBAttachment.concat([gl.READ_FRAMEBUFFER, gl.DRAW_FRAMEBUFFER]);
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "target",
+ validTargetsForFBAttachment,
+ function(target) {
+ return gl.getFramebufferAttachmentParameter(target, gl.COLOR_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ let validAttachmentsForFBAttachment = new Array(
+ gl.COLOR_ATTACHMENT0,
+ gl.DEPTH_ATTACHMENT,
+ gl.STENCIL_ATTACHMENT,
+ gl.DEPTH_STENCIL_ATTACHMENT
+ );
+ if (contextVersion > 1) {
+ for (let ii = 1; ii < gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); ++ii) {
+ validAttachmentsForFBAttachment[validAttachmentsForFBAttachment.length] = gl.COLOR_ATTACHMENT0 + ii;
+ }
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "attachment",
+ validAttachmentsForFBAttachment,
+ function(attachment) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ if (contextVersion > 1) {
+ // test default framebuffer
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.FRAMEBUFFER_DEFAULT');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.FRAMEBUFFER_DEFAULT');
+ if (testCases[run].contextStencil)
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.FRAMEBUFFER_DEFAULT');
+ else
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_RED_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_GREEN_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_BLUE_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ if (testCases[run].contextStencil) {
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ } else {
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "parameter",
+ validParametersForFBAttachment,
+ function(parameter) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, parameter);
+ }
+ );
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "target",
+ validTargetsForFBAttachment,
+ function(target) {
+ return gl.getFramebufferAttachmentParameter(target, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "attachment",
+ [ gl.BACK,
+ gl.DEPTH,
+ gl.STENCIL
+ ],
+ function(attachment) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ }
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("test getAttachedShaders");
+ window.standardVert = wtu.loadStandardVertexShader(gl);
+ window.standardFrag = wtu.loadStandardFragmentShader(gl);
+ window.standardProgram = gl.createProgram();
+ gl.attachShader(standardProgram, standardVert);
+ gl.attachShader(standardProgram, standardFrag);
+ gl.linkProgram(standardProgram);
+ window.shaders = gl.getAttachedShaders(standardProgram);
+ shouldBe('shaders.length', '2');
+ shouldBeTrue('shaders[0] == standardVert && shaders[1] == standardFrag || shaders[1] == standardVert && shaders[0] == standardFrag');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldThrow('gl.getAttachedShaders(null)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldThrow('gl.getAttachedShaders(standardVert)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getProgramParameter");
+ shouldBe('gl.getProgramParameter(standardProgram, gl.DELETE_STATUS)', 'false');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.LINK_STATUS)', 'true');
+ shouldBe('typeof gl.getProgramParameter(standardProgram, gl.VALIDATE_STATUS)', '"boolean"');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.ATTACHED_SHADERS)', '2');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.ACTIVE_ATTRIBUTES)', '2');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.ACTIVE_UNIFORMS)', '1');
+ if (contextVersion > 1) {
+ let buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 1024, gl.DYNAMIC_DRAW);
+ window.uniformBlockProgram = wtu.loadUniformBlockProgram(gl);
+ let transformFeedbackVars = ["normal", "ecPosition"];
+ gl.transformFeedbackVaryings(uniformBlockProgram, transformFeedbackVars, gl.INTERLEAVED_ATTRIBS);
+ gl.linkProgram(uniformBlockProgram);
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.LINK_STATUS)', 'true');
+ shouldBe('gl.getError()', 'gl.NO_ERROR');
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.ACTIVE_UNIFORM_BLOCKS)', '1');
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.TRANSFORM_FEEDBACK_VARYINGS)', '2');
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.TRANSFORM_FEEDBACK_BUFFER_MODE)', 'gl.INTERLEAVED_ATTRIBS');
+ }
+ window.program = standardProgram;
+ let validArrayForProgramParameter = [
+ gl.DELETE_STATUS,
+ gl.LINK_STATUS,
+ gl.VALIDATE_STATUS,
+ gl.ATTACHED_SHADERS,
+ gl.ACTIVE_ATTRIBUTES,
+ gl.ACTIVE_UNIFORMS
+ ];
+ if (contextVersion > 1) {
+ validArrayForProgramParameter = validArrayForProgramParameter.concat([
+ gl.ACTIVE_UNIFORM_BLOCKS,
+ gl.TRANSFORM_FEEDBACK_VARYINGS,
+ gl.TRANSFORM_FEEDBACK_BUFFER_MODE
+ ]);
+ program = uniformBlockProgram;
+ }
+ await testInvalidArgument(
+ "getProgramParameter",
+ "parameter",
+ validArrayForProgramParameter,
+ function(parameter) {
+ return gl.getProgramParameter(program, parameter);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getRenderbufferParameter");
+ shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)', '2');
+ shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT)', '2');
+ // Note: we can't test the actual value of the internal format since
+ // the implementation is allowed to change it.
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_INTERNAL_FORMAT)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_DEPTH_SIZE)');
+ let colorbuffer = gl.createRenderbuffer();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 2, 2);
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_RED_SIZE)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_GREEN_SIZE)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_BLUE_SIZE)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_ALPHA_SIZE)');
+ if (contextVersion > 1) {
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA4, 2, 2);
+ shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_SAMPLES)', '4');
+ }
+ let validArrayForRenderbuffer = new Array(
+ gl.RENDERBUFFER_WIDTH,
+ gl.RENDERBUFFER_HEIGHT,
+ gl.RENDERBUFFER_INTERNAL_FORMAT,
+ gl.RENDERBUFFER_RED_SIZE,
+ gl.RENDERBUFFER_GREEN_SIZE,
+ gl.RENDERBUFFER_BLUE_SIZE,
+ gl.RENDERBUFFER_ALPHA_SIZE,
+ gl.RENDERBUFFER_DEPTH_SIZE,
+ gl.RENDERBUFFER_STENCIL_SIZE
+ );
+ if (contextVersion > 1) {
+ validArrayForRenderbuffer[validArrayForRenderbuffer.length] = gl.RENDERBUFFER_SAMPLES;
+ }
+ await testInvalidArgument(
+ "getRenderbufferParameter",
+ "parameter",
+ validArrayForRenderbuffer,
+ function(parameter) {
+ return gl.getRenderbufferParameter(gl.RENDERBUFFER, parameter);
+ });
+ await testInvalidArgument(
+ "getRenderbufferParameter",
+ "target",
+ [ gl.RENDERBUFFER ],
+ function(target) {
+ return gl.getRenderbufferParameter(target, gl.RENDERBUFFER_WIDTH);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getShaderParameter");
+ shouldBe('gl.getShaderParameter(standardVert, gl.SHADER_TYPE)', 'gl.VERTEX_SHADER');
+ shouldBe('gl.getShaderParameter(standardVert, gl.DELETE_STATUS)', 'false');
+ shouldBe('gl.getShaderParameter(standardVert, gl.COMPILE_STATUS)', 'true');
+ await testInvalidArgument(
+ "getShaderParameter",
+ "parameter",
+ [ gl.DELETE_STATUS,
+ gl.COMPILE_STATUS,
+ gl.SHADER_TYPE
+ ],
+ function(parameter) {
+ return gl.getShaderParameter(standardVert, parameter);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getTexParameter");
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ 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);
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T)', 'gl.CLAMP_TO_EDGE');
+ if (contextVersion > 1) {
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 10);
+ gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAX_LOD, 10);
+ gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_LOD, 0);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL)', '0');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC)', 'gl.LEQUAL');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE)', 'gl.COMPARE_REF_TO_TEXTURE');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL)', '10');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAX_LOD)', '10');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_LOD)', '0');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_IMMUTABLE_FORMAT)', 'false');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_IMMUTABLE_LEVELS)', '0');
+ }
+ let validParametersForTexture = [
+ gl.TEXTURE_MAG_FILTER,
+ gl.TEXTURE_MIN_FILTER,
+ gl.TEXTURE_WRAP_S,
+ gl.TEXTURE_WRAP_T,
+ ];
+ if (contextVersion > 1) {
+ validParametersForTexture = validParametersForTexture.concat([
+ gl.TEXTURE_BASE_LEVEL,
+ gl.TEXTURE_COMPARE_FUNC,
+ gl.TEXTURE_COMPARE_MODE,
+ gl.TEXTURE_MAX_LEVEL,
+ gl.TEXTURE_MAX_LOD,
+ gl.TEXTURE_MIN_LOD,
+ gl.TEXTURE_WRAP_R,
+ gl.TEXTURE_IMMUTABLE_FORMAT,
+ gl.TEXTURE_IMMUTABLE_LEVELS,
+ ]);
+ }
+ await testInvalidArgument(
+ "getTexParameter",
+ "parameter",
+ validParametersForTexture,
+ function(parameter) {
+ return gl.getTexParameter(gl.TEXTURE_2D, parameter);
+ }
+ );
+ let validTargetsForTexture = [ gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP];
+ if (contextVersion > 1) {
+ validTargetsForTexture = validTargetsForTexture.concat([ gl.TEXTURE_3D, gl.TEXTURE_2D_ARRAY]);
+ }
+ await testInvalidArgument(
+ "getTexParameter",
+ "target",
+ validTargetsForTexture,
+ function(target) {
+ return gl.getTexParameter(target, gl.TEXTURE_MAG_FILTER);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getUniform with all variants of data types");
+ debug("Boolean uniform variables");
+ window.boolProgram = wtu.loadProgramFromFile(gl, "../../resources/boolUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(boolProgram, gl.LINK_STATUS)', 'true');
+ window.bvalLoc = gl.getUniformLocation(boolProgram, "bval");
+ window.bval2Loc = gl.getUniformLocation(boolProgram, "bval2");
+ window.bval3Loc = gl.getUniformLocation(boolProgram, "bval3");
+ window.bval4Loc = gl.getUniformLocation(boolProgram, "bval4");
+ gl.useProgram(boolProgram);
+ gl.uniform1i(bvalLoc, 1);
+ gl.uniform2i(bval2Loc, 1, 0);
+ gl.uniform3i(bval3Loc, 1, 0, 1);
+ gl.uniform4i(bval4Loc, 1, 0, 1, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(boolProgram, bvalLoc)', 'true');
+ shouldBe('gl.getUniform(boolProgram, bval2Loc)', '[true, false]');
+ shouldBe('gl.getUniform(boolProgram, bval3Loc)', '[true, false, true]');
+ shouldBe('gl.getUniform(boolProgram, bval4Loc)', '[true, false, true, false]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Integer uniform variables");
+ window.intProgram = wtu.loadProgramFromFile(gl, "../../resources/intUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(intProgram, gl.LINK_STATUS)', 'true');
+ window.ivalLoc = gl.getUniformLocation(intProgram, "ival");
+ window.ival2Loc = gl.getUniformLocation(intProgram, "ival2");
+ window.ival3Loc = gl.getUniformLocation(intProgram, "ival3");
+ window.ival4Loc = gl.getUniformLocation(intProgram, "ival4");
+ gl.useProgram(intProgram);
+ gl.uniform1i(ivalLoc, 1);
+ gl.uniform2i(ival2Loc, 2, 3);
+ gl.uniform3i(ival3Loc, 4, 5, 6);
+ gl.uniform4i(ival4Loc, 7, 8, 9, 10);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(intProgram, ivalLoc)', '1');
+ shouldBe('gl.getUniform(intProgram, ival2Loc)', '[2, 3]');
+ shouldBe('gl.getUniform(intProgram, ival3Loc)', '[4, 5, 6]');
+ shouldBe('gl.getUniform(intProgram, ival4Loc)', '[7, 8, 9, 10]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Float uniform variables");
+ window.floatProgram = wtu.loadProgramFromFile(gl, "../../resources/floatUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(floatProgram, gl.LINK_STATUS)', 'true');
+ window.fvalLoc = gl.getUniformLocation(floatProgram, "fval");
+ window.fval2Loc = gl.getUniformLocation(floatProgram, "fval2");
+ window.fval3Loc = gl.getUniformLocation(floatProgram, "fval3");
+ window.fval4Loc = gl.getUniformLocation(floatProgram, "fval4");
+ gl.useProgram(floatProgram);
+ gl.uniform1f(fvalLoc, 11);
+ gl.uniform2f(fval2Loc, 12, 13);
+ gl.uniform3f(fval3Loc, 14, 15, 16);
+ gl.uniform4f(fval4Loc, 17, 18, 19, 20);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(floatProgram, fvalLoc)', '11');
+ shouldBe('gl.getUniform(floatProgram, fval2Loc)', '[12, 13]');
+ shouldBe('gl.getUniform(floatProgram, fval3Loc)', '[14, 15, 16]');
+ shouldBe('gl.getUniform(floatProgram, fval4Loc)', '[17, 18, 19, 20]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Sampler uniform variables");
+ window.samplerProgram = wtu.loadProgramFromFile(gl, "../../resources/noopUniformShader.vert", "../../resources/samplerUniformShader.frag");
+ shouldBe('gl.getProgramParameter(samplerProgram, gl.LINK_STATUS)', 'true');
+ window.s2DValLoc = gl.getUniformLocation(samplerProgram, "s2D");
+ window.sCubeValLoc = gl.getUniformLocation(samplerProgram, "sCube");
+ gl.useProgram(samplerProgram);
+ gl.uniform1i(s2DValLoc, 0);
+ gl.uniform1i(sCubeValLoc, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(samplerProgram, s2DValLoc)', '0');
+ shouldBe('gl.getUniform(samplerProgram, sCubeValLoc)', '1');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Matrix uniform variables");
+ window.matProgram = wtu.loadProgramFromFile(gl, "../../resources/matUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(matProgram, gl.LINK_STATUS)', 'true');
+ window.mval2Loc = gl.getUniformLocation(matProgram, "mval2");
+ window.mval3Loc = gl.getUniformLocation(matProgram, "mval3");
+ window.mval4Loc = gl.getUniformLocation(matProgram, "mval4");
+ gl.useProgram(matProgram);
+ gl.uniformMatrix2fv(mval2Loc, false, [1, 2, 3, 4]);
+ gl.uniformMatrix3fv(mval3Loc, false, [5, 6, 7, 8, 9, 10, 11, 12, 13]);
+ gl.uniformMatrix4fv(mval4Loc, false, [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(matProgram, mval2Loc)', '[1, 2, 3, 4]');
+ shouldBe('gl.getUniform(matProgram, mval3Loc)', '[5, 6, 7, 8, 9, 10, 11, 12, 13]');
+ shouldBe('gl.getUniform(matProgram, mval4Loc)', '[14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ if (contextVersion > 1) {
+ debug("Unsigned Integer uniform variables");
+ window.uintProgram = wtu.loadProgramFromFile(gl, "../../resources/uintUniformShader.vert", "../../resources/noopUniformShaderES3.frag");
+ shouldBe('gl.getProgramParameter(uintProgram, gl.LINK_STATUS)', 'true');
+ window.uvalLoc = gl.getUniformLocation(uintProgram, "uval");
+ window.uval2Loc = gl.getUniformLocation(uintProgram, "uval2");
+ window.uval3Loc = gl.getUniformLocation(uintProgram, "uval3");
+ window.uval4Loc = gl.getUniformLocation(uintProgram, "uval4");
+ gl.useProgram(uintProgram);
+ gl.uniform1ui(uvalLoc, 1);
+ gl.uniform2ui(uval2Loc, 2, 3);
+ gl.uniform3ui(uval3Loc, 4, 5, 6);
+ gl.uniform4ui(uval4Loc, 7, 8, 9, 10);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(uintProgram, uvalLoc)', '1');
+ shouldBe('gl.getUniform(uintProgram, uval2Loc)', '[2, 3]');
+ shouldBe('gl.getUniform(uintProgram, uval3Loc)', '[4, 5, 6]');
+ shouldBe('gl.getUniform(uintProgram, uval4Loc)', '[7, 8, 9, 10]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Matrix uniform variables for WebGL 2");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ window.matForWebGL2Program = wtu.loadProgramFromFile(gl, "../../resources/matForWebGL2UniformShader.vert", "../../resources/noopUniformShaderES3.frag");
+ shouldBe('gl.getProgramParameter(matForWebGL2Program, gl.LINK_STATUS)', 'true');
+ window.mval2x3Loc = gl.getUniformLocation(matForWebGL2Program, "mval2x3");
+ window.mval2x4Loc = gl.getUniformLocation(matForWebGL2Program, "mval2x4");
+ window.mval3x2Loc = gl.getUniformLocation(matForWebGL2Program, "mval3x2");
+ window.mval3x4Loc = gl.getUniformLocation(matForWebGL2Program, "mval3x4");
+ window.mval4x2Loc = gl.getUniformLocation(matForWebGL2Program, "mval4x2");
+ window.mval4x3Loc = gl.getUniformLocation(matForWebGL2Program, "mval4x3");
+ gl.useProgram(matForWebGL2Program);
+ gl.uniformMatrix2x3fv(mval2x3Loc, false, [1, 2, 3, 4, 5, 6]);
+ gl.uniformMatrix2x4fv(mval2x4Loc, false, [7, 8, 9, 10, 11, 12, 13, 14]);
+ gl.uniformMatrix3x2fv(mval3x2Loc, false, [15, 16, 17, 18, 19, 20]);
+ gl.uniformMatrix3x4fv(mval3x4Loc, false, [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
+ gl.uniformMatrix4x2fv(mval4x2Loc, false, [33, 34, 35, 36, 37, 38, 39, 40]);
+ gl.uniformMatrix4x3fv(mval4x3Loc, false, [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(matForWebGL2Program, mval2x3Loc)', '[1, 2, 3, 4, 5, 6]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval2x4Loc)', '[7, 8, 9, 10, 11, 12, 13, 14]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval3x2Loc)', '[15, 16, 17, 18, 19, 20]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval3x4Loc)', '[21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval4x2Loc)', '[33, 34, 35, 36, 37, 38, 39, 40]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval4x3Loc)', '[41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Sampler uniform variables for WebGL2");
+ window.samplerForWebGL2Program = wtu.loadProgramFromFile(gl, "../../resources/noopUniformShaderES3.vert", "../../resources/samplerForWebGL2UniformShader.frag");
+ shouldBe('gl.getProgramParameter(samplerForWebGL2Program, gl.LINK_STATUS)', 'true');
+ window.s3DValLoc = gl.getUniformLocation(samplerForWebGL2Program, "s3D");
+ window.s2DArrayValLoc = gl.getUniformLocation(samplerForWebGL2Program, "s2DArray");
+ gl.useProgram(samplerForWebGL2Program);
+ gl.uniform1i(s3DValLoc, 0);
+ gl.uniform1i(s2DArrayValLoc, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(samplerForWebGL2Program, s3DValLoc)', '0');
+ shouldBe('gl.getUniform(samplerForWebGL2Program, s2DArrayValLoc)', '1');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ }
+
+ debug("");
+ debug("test getVertexAttrib");
+ let array = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ window.buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW);
+ // Vertex attribute 0 is special in that it has no current state, so
+ // fetching GL_CURRENT_VERTEX_ATTRIB generates an error. Use attribute
+ // 1 for these tests instead.
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)', 'buffer');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_ENABLED)', 'true');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_SIZE)', '4');
+ // Stride MUST be the value the user put in.
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_STRIDE)', '0');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_TYPE)', 'gl.FLOAT');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED)', 'false');
+ if (contextVersion > 1) {
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_DIVISOR)', '0');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_INTEGER)', 'false');
+ gl.vertexAttribDivisor(1, 2);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_DIVISOR)', '2');
+ }
+ gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 36, 12);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_STRIDE)', '36');
+ shouldBe('gl.getVertexAttribOffset(1, gl.VERTEX_ATTRIB_ARRAY_POINTER)', '12');
+ gl.disableVertexAttribArray(1);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_ENABLED)', 'false');
+ gl.vertexAttrib4f(1, 5, 6, 7, 8);
+ shouldBe('gl.getVertexAttrib(1, gl.CURRENT_VERTEX_ATTRIB)', '[5, 6, 7, 8]');
+ if (contextVersion > 1) {
+ let intArray = new Int32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ gl.bufferData(gl.ARRAY_BUFFER, intArray, gl.DYNAMIC_DRAW);
+ gl.enableVertexAttribArray(1);
+ // feed fixed-point data to buffer
+ gl.vertexAttribIPointer(1, 4, gl.INT, false, 0, 0);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_TYPE)', 'gl.INT');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_INTEGER)', 'true');
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ let validArrayForVertexAttrib = new Array(
+ gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+ gl.VERTEX_ATTRIB_ARRAY_ENABLED,
+ gl.VERTEX_ATTRIB_ARRAY_SIZE,
+ gl.VERTEX_ATTRIB_ARRAY_STRIDE,
+ gl.VERTEX_ATTRIB_ARRAY_TYPE,
+ gl.VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ gl.CURRENT_VERTEX_ATTRIB
+ );
+ if (contextVersion > 1) {
+ validArrayForVertexAttrib[validArrayForVertexAttrib.length] = gl.VERTEX_ATTRIB_ARRAY_DIVISOR;
+ validArrayForVertexAttrib[validArrayForVertexAttrib.length] = gl.VERTEX_ATTRIB_ARRAY_INTEGER;
+ }
+ await testInvalidArgument(
+ "getVertexAttrib",
+ "parameter",
+ validArrayForVertexAttrib,
+ function(parameter) {
+ return gl.getVertexAttrib(1, parameter);
+ }
+ );
+ let numVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, 'gl.getVertexAttrib(' + numVertexAttribs + ', gl.CURRENT_VERTEX_ATTRIB)');
+
+ debug("");
+ debug("Test cases where name == 0");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+
+ shouldNotBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ gl.deleteTexture(texture);
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ shouldNotBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ gl.deleteRenderbuffer(renderbuffer);
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ gl.deleteBuffer(buffer);
+ shouldBeNull('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ if (contextVersion > 1) {
+ debug("");
+ debug("Test getInternalformatParameter")
+
+ shouldBeNonNull('gl.getInternalformatParameter(gl.RENDERBUFFER, gl.R32I, gl.SAMPLES)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ await testInvalidArgument(
+ "getInternalformatParameter",
+ "target",
+ [ gl.RENDERBUFFER ],
+ function(target) {
+ return gl.getInternalformatParameter(target, gl.R32I, gl.SAMPLES);
+ });
+
+ await testInvalidArgument(
+ "getInternalformatParameter",
+ "pname",
+ [ gl.SAMPLES ],
+ function(pname) {
+ return gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA4, pname);
+ });
+
+ let validArrayForInterformat = new Array(
+ gl.R8, gl.R8_SNORM, gl.RG8, gl.RG8_SNORM,
+ gl.RGB8, gl.RGB8_SNORM, gl.RGB565, gl.RGBA4,
+ gl.RGB5_A1, gl.RGBA8, gl.RGBA8_SNORM, gl.RGB10_A2,
+ gl.RGB10_A2UI, gl.SRGB8, gl.SRGB8_ALPHA8, gl.R16F,
+ gl.RG16F, gl.RGB16F, gl.RGBA16F, gl.R32F,
+ gl.RG32F, gl.RGB32F, gl.RGBA32F, gl.R11F_G11F_B10F,
+ gl.RGB9_E5, gl.R8I, gl.R8UI, gl.R16I,
+ gl.R16UI, gl.R32I, gl.R32UI, gl.RG8I,
+ gl.RG8UI, gl.RG16I, gl.RG16UI, gl.RG32I,
+ gl.RG32UI, gl.RGB8I, gl.RGB8UI, gl.RGB16I,
+ gl.RGB16UI, gl.RGB32I, gl.RGB32UI, gl.RGBA8I,
+ gl.RGBA8UI, gl.RGBA16I, gl.RGBA16UI, gl.RGBA32I,
+ gl.RGBA32UI, gl.RGB, gl.RGBA, gl.DEPTH_STENCIL, gl.DEPTH_COMPONENT16,
+ gl.DEPTH_COMPONENT24, gl.DEPTH_COMPONENT32F, gl.DEPTH24_STENCIL8,
+ gl.DEPTH32F_STENCIL8, gl.STENCIL_INDEX8
+ );
+ await testInvalidArgument(
+ "getInternalformatParameter",
+ "internalformat",
+ validArrayForInterformat,
+ function(internalformat) {
+ return gl.getInternalformatParameter(gl.RENDERBUFFER, internalformat, gl.SAMPLES);
+ });
+
+
+ debug("");
+ debug("Test getIndexedParameter");
+ window.buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 64, gl.DYNAMIC_DRAW);
+ gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 0, buffer, 4, 8);
+ shouldBe('gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)', 'buffer');
+ shouldBe('gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)', '8');
+ shouldBe('gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)', '4');
+ window.buffer1 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer1);
+ gl.bufferData(gl.UNIFORM_BUFFER, 64, gl.DYNAMIC_DRAW);
+ window.offsetUniform = gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT);
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, 1, buffer1, offsetUniform, 8);
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1)', 'buffer1');
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_SIZE, 1)', '8');
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1)', 'offsetUniform');
+
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, 1, null);
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1)', 'null');
+
+ let validArrayForTarget = new Array(
+ gl.TRANSFORM_FEEDBACK_BUFFER_BINDING,
+ gl.TRANSFORM_FEEDBACK_BUFFER_SIZE,
+ gl.TRANSFORM_FEEDBACK_BUFFER_START,
+ gl.UNIFORM_BUFFER_BINDING,
+ gl.UNIFORM_BUFFER_SIZE,
+ gl.UNIFORM_BUFFER_START
+ );
+ await testInvalidArgument(
+ "getIndexedParameter",
+ "target",
+ validArrayForTarget,
+ function(target) {
+ return gl.getIndexedParameter(target, 0);
+ });
+
+ debug("");
+ debug("Test getSamplerParameter");
+ window.sampler = gl.createSampler();
+ gl.samplerParameteri(sampler, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL);
+ gl.samplerParameteri(sampler, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+ gl.samplerParameteri(sampler, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MAX_LOD, 10);
+ gl.samplerParameteri(sampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MIN_LOD, 0);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_COMPARE_FUNC)', 'gl.LEQUAL');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_COMPARE_MODE)', 'gl.COMPARE_REF_TO_TEXTURE');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MAG_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MAX_LOD)', '10');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MIN_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MIN_LOD)', '0');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_WRAP_R)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_WRAP_S)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_WRAP_T)', 'gl.CLAMP_TO_EDGE');
+ let validArrayForSamplerParameter = new Array(
+ gl.TEXTURE_COMPARE_FUNC,
+ gl.TEXTURE_COMPARE_MODE,
+ gl.TEXTURE_MAG_FILTER,
+ gl.TEXTURE_MAX_LOD,
+ gl.TEXTURE_MIN_FILTER,
+ gl.TEXTURE_MIN_LOD,
+ gl.TEXTURE_WRAP_R,
+ gl.TEXTURE_WRAP_S,
+ gl.TEXTURE_WRAP_T
+ );
+ await testInvalidArgument(
+ "getSamplerParameter",
+ "pname",
+ validArrayForSamplerParameter,
+ function(pname) {
+ return gl.getSamplerParameter(sampler, pname);
+ });
+
+ debug("");
+ debug("Test getSyncParameter");
+ window.sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
+ shouldBe('gl.getSyncParameter(sync, gl.OBJECT_TYPE)', 'gl.SYNC_FENCE');
+ let sync_status = gl.getSyncParameter(sync, gl.SYNC_STATUS);
+ switch (sync_status) {
+ case gl.UNSIGNALED:
+ testPassed('gl.getSyncParameter(sync, gl.SYNC_CONDITION) is gl.UNSIGNALED');
+ break;
+ case gl.SIGNALED:
+ testPassed('gl.getSyncParameter(sync, gl.SYNC_CONDITION) is gl.SIGNALED');
+ break;
+ default:
+ testFailed('gl.getSyncParameter(sync, gl.SYNC_CONDITION) was ' + sync_status +
+ ', expected gl.UNSIGNALED or gl.SIGNALED');
+ break;
+ }
+ shouldBe('gl.getSyncParameter(sync, gl.SYNC_CONDITION)', 'gl.SYNC_GPU_COMMANDS_COMPLETE');
+ shouldBe('gl.getSyncParameter(sync, gl.SYNC_FLAGS)', '0');
+ let validArrayForSyncParameter = new Array(
+ gl.OBJECT_TYPE,
+ gl.SYNC_STATUS,
+ gl.SYNC_CONDITION,
+ gl.SYNC_FLAGS
+ );
+ await testInvalidArgument(
+ "getSyncParameter",
+ "pname",
+ validArrayForSyncParameter,
+ function(pname) {
+ return gl.getSyncParameter(sync, pname);
+ });
+
+ debug("");
+ debug("Test getQueryParameter");
+ window.query = gl.createQuery();
+ gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
+ gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
+ shouldBe('gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)', 'false');
+ // Queries' results are tested elsewhere in the conformance suite. It's complicated
+ // to wait for this query's result to become available and verify it.
+ let validArrayForPname = new Array(
+ gl.QUERY_RESULT,
+ gl.QUERY_RESULT_AVAILABLE
+ );
+ await testInvalidArgument(
+ "getQueryParameter",
+ "pname",
+ validArrayForPname,
+ function(pname) {
+ return gl.getQueryParameter(query, pname);
+ }
+ );
+
+ debug("");
+ debug("Test getFragDataLocation");
+ let baseVertShader = '' +
+ '#version 300 es\n' +
+ 'uniform mat4 modelViewMatrix;\n' +
+ 'uniform mat4 projectionMatrix;\n' +
+ 'in vec4 vertex;\n' +
+ 'out vec4 position;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' position = modelViewMatrix * vertex;\n' +
+ ' gl_Position = projectionMatrix * position;\n' +
+ '}\n';
+ let baseFragShader = '' +
+ '#version 300 es\n' +
+ 'in lowp vec4 position;\n' +
+ 'layout(location = 0) out mediump vec4 fragColor;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' fragColor = position;\n' +
+ '}\n';
+ window.vertShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertShader, baseVertShader);
+ gl.compileShader(vertShader);
+ shouldBe('gl.getShaderParameter(vertShader, gl.COMPILE_STATUS)', 'true');
+ window.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragShader, baseFragShader);
+ gl.compileShader(fragShader);
+ shouldBe('gl.getShaderParameter(fragShader, gl.COMPILE_STATUS)', 'true');
+ window.program = gl.createProgram();
+ gl.attachShader(program, vertShader);
+ gl.attachShader(program, fragShader);
+ gl.linkProgram(program);
+ shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)','true');
+ shouldBe('gl.getFragDataLocation(program, "vertexColor")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "modelViewMatrix")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "projectionMatrix")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "position")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "fragColor")', '0');
+
+ debug("");
+ debug("Test getActiveUniforms");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)', 'true');
+ shouldBe('gl.getError()', 'gl.NO_ERROR');
+
+ let numActiveUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
+ let blockIndex = gl.getUniformBlockIndex(program, "Transform");
+ let uniformIndices = [];
+ for (let i = 0; i < numActiveUniforms; i++)
+ uniformIndices.push(i);
+ let types = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_TYPE);
+ let sizes = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_SIZE);
+ let blockIndices = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_BLOCK_INDEX);
+ let offsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ let arrayStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_ARRAY_STRIDE);
+ let matrixStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_MATRIX_STRIDE);
+ let rowMajors = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_IS_ROW_MAJOR);
+ for (let i = 0; i < numActiveUniforms; i++) {
+ if (types[i] != gl.FLOAT_MAT4 && types[i] != gl.FLOAT_MAT3)
+ testFailed("expected value: GL_FLOAT_MAT4 or GL_FLOAT_MAT3" + " actual value for UNIFORM_TYPE for uniform index[" + i + "]:" + wtu.glEnumToString(gl, types[i]));
+ if (sizes[i] != 1)
+ testFailed("expected value: 1" + " actual value for UNIFORM_SIZE for uniform index[" + i + "]:" + sizes[i]);
+ if (blockIndices[i] != blockIndex)
+ testFailed("expected value: 0" + " actual value for UNIFORM_BLOCK_INDEX for uniform index[" + i + "]:" + blockIndices[i]);
+ if (offsets[i] < 0)
+ testFailed("expected value >= 0" + " actual value for UNIFORM_OFFSET for uniform index[" + i + "]:" + offsets[i]);
+ if (arrayStrides[i] != 0)
+ testFailed("expected value: 0" + " actual value for UNIFORM_ARRAY_STRIDE for uniform index[" + i + "]:" + arrayStrides[i]);
+ if (matrixStrides[i] < 0)
+ testFailed("expected value >= 0" + " actual value for UNIFORM_MATRIX_STRIDE for uniform index[" + i + "]:" + matrixStrides[i]);
+ shouldBe(`"${typeof rowMajors[i]}"`, '"boolean"');
+ if (rowMajors[i] != false)
+ testFailed("expected value: 0" + " actual value for UNIFORM_IS_ROW_MAJOR for uniform index[" + i + "]:" + rowMajors[i]);
+ }
+
+ validArrayForPname = new Array(
+ gl.UNIFORM_TYPE,
+ gl.UNIFORM_SIZE,
+ gl.UNIFORM_BLOCK_INDEX,
+ gl.UNIFORM_OFFSET,
+ gl.UNIFORM_ARRAY_STRIDE,
+ gl.UNIFORM_MATRIX_STRIDE,
+ gl.UNIFORM_IS_ROW_MAJOR
+ );
+ await testInvalidArgument(
+ "getActiveUniforms",
+ "pname",
+ validArrayForPname,
+ function(pname) {
+ return gl.getActiveUniforms(program, uniformIndices, pname);
+ }
+ );
+
+ debug("");
+ debug("Test getUniformBlockIndex");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBeTrue('gl.getProgramParameter(program, gl.LINK_STATUS)');
+ shouldBe('gl.getUniformBlockIndex(program, "Transform")', '0');
+ shouldBe('gl.getUniformBlockIndex(program, "u_modelViewMatrix")', 'gl.INVALID_INDEX');
+ shouldBe('gl.getUniformBlockIndex(program, "normal")', 'gl.INVALID_INDEX');
+ shouldBe('gl.getUniformBlockIndex(program, "u_normal")', 'gl.INVALID_INDEX');
+ window.noUniformProgram = wtu.loadStandardProgram(gl);
+ gl.linkProgram(noUniformProgram);
+ shouldBeTrue('gl.getProgramParameter(noUniformProgram, gl.LINK_STATUS)');
+ shouldBe('gl.getUniformBlockIndex(noUniformProgram, "u_modelViewProjMatrix")', 'gl.INVALID_INDEX');
+ shouldBe('gl.getUniformBlockIndex(noUniformProgram, "u_normal")', 'gl.INVALID_INDEX');
+
+ debug("");
+ debug("Test getActiveUniformBlockName");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBeTrue('gl.getProgramParameter(program, gl.LINK_STATUS)');
+ shouldBeEqualToString('gl.getActiveUniformBlockName(program, 0)', 'Transform');
+ shouldBeNull('gl.getActiveUniformBlockName(program, -1)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(program, 1)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(program, gl.INVALID_INDEX)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ window.noLinkProgram = gl.createProgram();
+ shouldBeFalse('gl.getProgramParameter(noLinkProgram, gl.LINK_STATUS)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getActiveUniformBlockName(noLinkProgram, 0)');
+ noUniformProgram = wtu.loadStandardProgram(gl);
+ gl.linkProgram(noUniformProgram);
+ shouldBeTrue('gl.getProgramParameter(noUniformProgram, gl.LINK_STATUS)');
+ shouldBeNull('gl.getActiveUniformBlockName(noUniformProgram, -1)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(noUniformProgram, 0)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(noUniformProgram, gl.INVALID_INDEX)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ debug("");
+ debug("Test getActiveUniformBlockParameter");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBeTrue('gl.getProgramParameter(program, gl.LINK_STATUS)');
+ shouldBe('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_BINDING)', '0');
+ gl.uniformBlockBinding(program, 0, 1);
+ shouldBe('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_BINDING)', '1');
+ // The actual block data size can be bigger than 164, depending on the uniform block layout.
+ shouldBeTrue('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_DATA_SIZE) >= 164');
+ shouldBe('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS)', '3');
+ shouldBeTrue('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER)');
+ shouldBeFalse('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER)');
+ let indices = gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES);
+ for (let i = 0; i < 3; i++) {
+ if (indices[i] < 0)
+ testFailed("expected value >= 0" + " actual value for UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES for uniform index[" + i + "]:" + indices[i]);
+ }
+ validArrayForPname = new Array(
+ gl.UNIFORM_BLOCK_BINDING,
+ gl.UNIFORM_BLOCK_DATA_SIZE,
+ gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS,
+ gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
+ gl.UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
+ gl.UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
+ );
+ await testInvalidArgument(
+ "getActiveUniformBlockParameter",
+ "pname",
+ validArrayForPname,
+ function(pname) {
+ return gl.getActiveUniformBlockParameter(program, 0, pname);
+ }
+ );
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ finishTest();
+})();
+
+let successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js
new file mode 100644
index 0000000000..97cad40868
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js
@@ -0,0 +1,263 @@
+/*
+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.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description("This test ensures WebGL implementations vertexAttrib can be set and read.");
+
+debug("");
+debug("Canvas.getContext");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas", undefined, contextVersion);
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ debug("");
+ debug("Checking gl.vertexAttrib.");
+
+ var numVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ for (var ii = 0; ii < numVertexAttribs; ++ii) {
+ gl.vertexAttrib1fv(ii, [1]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib1fv(ii, new Float32Array([-1]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib2fv(ii, [1, 2]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib2fv(ii, new Float32Array([1, -2]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '-2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib3fv(ii, [1, 2, 3]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib3fv(ii, new Float32Array([1, -2, 3]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '-2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib4fv(ii, [1, 2, 3, 4]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '4');
+
+ gl.vertexAttrib4fv(ii, new Float32Array([1, 2, -3, 4]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '-3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '4');
+
+ gl.vertexAttrib1f(ii, 5);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '5');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib2f(ii, 6, 7);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '6');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '7');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib3f(ii, 7, 8, 9);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '7');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '8');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '9');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib4f(ii, 6, 7, 8, 9);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '6');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '7');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '8');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '9');
+
+ if (contextVersion > 1) {
+ gl.vertexAttribI4i(ii, -1, 0, 1, 2);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Int32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '2');
+
+ gl.vertexAttribI4ui(ii, 0, 1, 2, 3);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Uint32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '3');
+
+ gl.vertexAttribI4iv(ii, [-1, 0, 1, 2]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Int32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '2');
+
+ gl.vertexAttribI4iv(ii, new Int32Array([1, 0, -1, 2]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Int32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '2');
+
+ gl.vertexAttribI4uiv(ii, [0, 1, 2, 3]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Uint32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '3');
+
+ gl.vertexAttribI4uiv(ii, new Uint32Array([0, 2, 1, 3]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Uint32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '3');
+ }
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Checking out-of-range vertexAttrib index");
+ gl.getVertexAttrib(numVertexAttribs, gl.CURRENT_VERTEX_ATTRIB);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1fv(numVertexAttribs, [1]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1fv(numVertexAttribs, new Float32Array([-1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, [1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, new Float32Array([1, -2]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, [1, 2, 3]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, new Float32Array([1, -2, 3]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, [1, 2, 3, 4]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, new Float32Array([1, 2, -3, 4]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1f(numVertexAttribs, 5);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2f(numVertexAttribs, 6, 7);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3f(numVertexAttribs, 7, 8, 9);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4f(numVertexAttribs, 6, 7, 8, 9);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ if (contextVersion > 1) {
+ gl.vertexAttribI4i(numVertexAttribs, -1, 0, 1, 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4ui(numVertexAttribs, 0, 1, 2, 3);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4iv(numVertexAttribs, [-1, 0, 1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4iv(numVertexAttribs, new Int32Array([1, 0, -1, 2]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, [0, 1, 2, 3]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, new Uint32Array([0, 2, 1, 3]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ }
+
+ debug("");
+ debug("Checking invalid array lengths");
+ numVertexAttribs = numVertexAttribs - 1;
+ gl.vertexAttrib1fv(numVertexAttribs, []);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1fv(numVertexAttribs, new Float32Array([]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, [1]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, new Float32Array([1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, [1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, new Float32Array([1, -2]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, [1, 2, 3]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, new Float32Array([1, 2, -3]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ if (contextVersion > 1) {
+ gl.vertexAttribI4iv(numVertexAttribs, [-1, 0, 1]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4iv(numVertexAttribs, new Int32Array([1, 0, -1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, [0, 1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, new Uint32Array([0, 2, 1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ }
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js
new file mode 100644
index 0000000000..edcad3b1f6
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js
@@ -0,0 +1,105 @@
+/*
+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.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+var wtu = WebGLTestUtils;
+description(document.title);
+debug("Tests that instanceof works on WebGL objects.");
+debug("");
+
+function checkGLError(message) {
+ var error = gl.getError();
+ if (error != gl.NO_ERROR) {
+ wtu.error("Error: " + message + " caused " + wtu.glEnumToString(gl, error));
+ }
+}
+
+var gl = wtu.create3DContext("canvas", undefined, contextVersion);
+if (contextVersion === 1) {
+ shouldBeTrue('gl instanceof WebGLRenderingContext');
+} else if (contextVersion === 2) {
+ shouldBeTrue('gl instanceof WebGL2RenderingContext');
+}
+
+shouldBeTrue('gl.createBuffer() instanceof WebGLBuffer');
+checkGLError("createBuffer")
+
+shouldBeTrue('gl.createFramebuffer() instanceof WebGLFramebuffer');
+checkGLError("createFramebuffer")
+
+shouldBeTrue('gl.createProgram() instanceof WebGLProgram');
+checkGLError("createProgram")
+
+shouldBeTrue('gl.createRenderbuffer() instanceof WebGLRenderbuffer');
+checkGLError("createRenderbuffer")
+
+shouldBeTrue('gl.createShader(gl.VERTEX_SHADER) instanceof WebGLShader');
+checkGLError("createShader")
+
+shouldBeTrue('gl.createTexture() instanceof WebGLTexture');
+checkGLError("createTexture")
+
+if (contextVersion > 1) {
+ shouldBeTrue('gl.createQuery() instanceof WebGLQuery');
+ checkGLError("createQuery")
+
+ shouldBeTrue('gl.createSampler() instanceof WebGLSampler');
+ checkGLError("createSampler")
+
+ shouldBeTrue('gl.createTransformFeedback() instanceof WebGLTransformFeedback');
+ checkGLError("createTransformFeedback")
+
+ shouldBeTrue('gl.createVertexArray() instanceof WebGLVertexArrayObject');
+ checkGLError("createVertexArray")
+}
+
+var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['vPosition'], [0]);
+
+shouldBeTrue('gl.getUniformLocation(program, "color") instanceof WebGLUniformLocation');
+checkGLError("getUniformLocation")
+
+shouldBeTrue('gl.getActiveAttrib(program, 0) instanceof WebGLActiveInfo');
+checkGLError("getActiveAttrib")
+
+shouldBeTrue('gl.getActiveUniform(program, 0) instanceof WebGLActiveInfo');
+checkGLError("getActiveUniform")
+
+debug("");
+debug("Tests that those WebGL objects can not be constructed through new operator");
+debug("");
+
+function shouldThrowWithNew(objectType, objectName) {
+ try {
+ new objectType;
+ testFailed('new ' + objectName + ' did not throw');
+ } catch (e) {
+ testPassed('new ' + objectName + ' threw an error');
+ }
+}
+
+shouldThrowWithNew(window.WebGLRenderingContext, 'WebGLRenderingContext');
+shouldThrowWithNew(window.WebGLActiveInfo, 'WebGLActiveInfo');
+shouldThrowWithNew(window.WebGLBuffer, 'WebGLBuffer');
+shouldThrowWithNew(window.WebGLFramebuffer, 'WebGLFramebuffer');
+shouldThrowWithNew(window.WebGLProgram, 'WebGLProgram');
+shouldThrowWithNew(window.WebGLRenderbuffer, 'WebGLRenderbuffer');
+shouldThrowWithNew(window.WebGLShader, 'WebGLShader');
+shouldThrowWithNew(window.WebGLTexture, 'WebGLTexture');
+shouldThrowWithNew(window.WebGLUniformLocation, 'WebGLUniformLocation');
+shouldThrowWithNew(window.WebGLShaderPrecisionFormat, 'WebGLShaderPrecisionFormat');
+if (contextVersion > 1) {
+ shouldThrowWithNew(window.WebGLQuery, 'WebGLQuery');
+ shouldThrowWithNew(window.WebGLSampler, 'WebGLSampler');
+ shouldThrowWithNew(window.WebGLSync, 'WebGLSync');
+ shouldThrowWithNew(window.WebGLTransformFeedback, 'WebGLTransformFeedback');
+ shouldThrowWithNew(window.WebGLVertexArrayObject, 'WebGLVertexArrayObject');
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js
new file mode 100644
index 0000000000..b28c484843
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js
@@ -0,0 +1,129 @@
+var createInvalidAttribTestFn = (function() {
+
+async function testPreserveDrawingBufferTrue(gl, drawFn, clear) {
+ debug('');
+ debug(`test preserveDrawingBuffer: true with ${drawFn.name} ${clear ? 'with' : 'without'} clear`);
+
+ if (clear) {
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ const skipTest = drawFn(gl);
+ if (skipTest) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+
+ await waitForComposite();
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function setupWebGL({
+ webglVersion,
+ shadersFn,
+ attribs,
+}) {
+ const positionBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ -1, 1,
+ 1, -1,
+ 1, 1,
+ ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ const indexBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuf);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0, 1, 2, 3, 4, 5]), gl.STATIC_DRAW);
+ return gl;
+}
+
+function createInvalidAttribTestFn(gl) {
+ const vs = `
+ attribute vec4 vPosition;
+ void main()
+ {
+ gl_Position = vPosition;
+ }
+ `;
+
+ const fs = `
+ precision mediump float;
+ void main()
+ {
+ gl_FragColor = vec4(1, 0, 0, 1);
+ }
+ `
+
+ const program = wtu.setupProgram(gl, [vs, fs], ["vPosition"]);
+ if (!program) {
+ debug(`program failed to compile: ${wtu.getLastError()}`);
+ }
+
+ const positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ -1, 1,
+ 1, -1,
+ 1, 1,
+ ]), gl.STATIC_DRAW);
+
+ const indexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ new Uint8Array([0, 1, 2, 3, 4, 5]),
+ gl.STATIC_DRAW);
+
+ return async function invalidAttribTestFn(drawFn) {
+ debug('');
+
+ // reset attribs
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ const numAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ for (let i = 0; i < numAttribs; ++i) {
+ gl.disableVertexAttribArray(i);
+ gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
+ }
+
+ debug(`test ${drawFn.name} draws with valid attributes`);
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ gl.clearColor(0, 0, 0, 0,);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero");
+
+ drawFn(gl);
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ debug(`test ${drawFn.name} generates INVALID_OPERATION draws with enabled attribute no buffer bound`);
+ gl.enableVertexAttribArray(1);
+
+ gl.clearColor(0, 0, 0, 0,);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero");
+
+ drawFn(gl);
+
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should generate INVALID_OPERATION");
+ wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero");
+ };
+}
+
+return createInvalidAttribTestFn;
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js
new file mode 100644
index 0000000000..45e509f50a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js
@@ -0,0 +1,183 @@
+/*
+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.
+*/
+IterableTest = (function() {
+
+ var wtu = WebGLTestUtils;
+
+ function run(test, iterations) {
+ var target = iterations || 10;
+ var count = 0;
+
+ function doNextTest() {
+ ++count;
+ debug("Test " + count + " of " + target);
+ var success = test();
+ if (count < target && success !== false) {
+ wtu.dispatchPromise(doNextTest);
+ } else {
+ finishTest();
+ }
+ }
+
+ doNextTest();
+ }
+
+ // Creates a canvas and a texture then exits. There are
+ // no references to either so both should be garbage collected.
+ function createContextCreationAndDestructionTest() {
+ var textureSize = null;
+
+ return function() {
+ var canvas = document.createElement("canvas");
+ // This is safe for any device. See drawingBufferWidth in spec.
+ canvas.width = 2048;
+ canvas.height = 2048;
+ var gl = wtu.create3DContext(canvas);
+ if (textureSize === null) {
+ var maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
+ textureSize = Math.min(1024, maxTextureSize);
+ }
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, textureSize, textureSize, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ null);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+
+ return true;
+ };
+ }
+
+ // Creates many small canvases and attaches them to the DOM.
+ // This tests an edge case discovered in Chrome where the creation of multiple
+ // WebGL contexts would eventually lead to context creation failure.
+ // (crbug.com/319265) The test does not require that old contexts remain
+ // valid, only that new ones can be created.
+ function createContextCreationTest() {
+ return function() {
+ var canvas = document.createElement("canvas");
+ canvas.width = 1;
+ canvas.height = 1;
+
+ document.body.appendChild(canvas);
+
+ var gl = wtu.create3DContext(canvas);
+ if (!gl) {
+ return false;
+ }
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+
+ return true;
+ };
+ }
+
+ // Draws rectangle on a passed canvas with preserveDrawingBuffer
+ // and antialiasing ON, tests rect color on every iteration.
+ function createMultisampleCorruptionTest(gl) {
+ var lastContext = null;
+ // Allocate a read back buffer in advance and reuse it for all iterations
+ // to avoid memory issues because of late garbage collection.
+ var readBackBuf = new Uint8Array(gl.canvas.width * gl.canvas.height * 4);
+
+ var program = wtu.loadStandardProgram(gl);
+ var uniforms = wtu.getUniformMap(gl, program);
+ gl.useProgram(program);
+
+ gl.clearColor(1.0, 0.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,2.5,0, 1.5,1.5,0, 2.5,1.5,0 ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ gl.vertexAttrib3f(1, 0.0, 0.0, 1.0);
+
+ var identityMat = new Float32Array([
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ ]);
+
+ gl.uniformMatrix4fv(uniforms.u_modelViewProjMatrix.location, false, identityMat);
+
+ function test() {
+ var gl2 = wtu.create3DContext(null, {antialias: true});
+
+ gl2.canvas.width = gl2.canvas.height = 1024;
+ gl2.canvas.style.width = gl2.canvas.style.height = "1px";
+ document.body.appendChild(gl2.canvas);
+
+ gl2.clearColor(1.0, 0.0, 0.0, 1.0);
+ gl2.clear(gl2.COLOR_BUFFER_BIT);
+
+ if(lastContext) {
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+ var msg = "Canvas should be red";
+ wtu.checkCanvasRectColor(gl,
+ 0, 0, gl.canvas.width, gl.canvas.height,
+ [255, 0, 0, 255], null,
+ function() {
+ testPassed(msg);
+ },
+ function() {
+ testFailed(msg);
+ return false;
+ },
+ debug, readBackBuf);
+ document.body.removeChild(lastContext.canvas);
+ }
+
+ lastContext = gl2;
+ return true;
+ };
+
+ // First pass does initialization
+ test();
+
+ return test;
+ }
+
+ // Draws repeatedly to a large canvas with preserveDrawingBuffer enabled to
+ // try and provoke a context loss.
+ function createPreserveDrawingBufferLeakTest(gl) {
+ var contextActive = true;
+ gl.canvas.addEventListener("webglcontextlost", () => {
+ testFailed("Context was lost");
+ contextActive = false;
+ });
+
+ function test() {
+ var x = Math.random() * gl.drawingBufferWidth;
+ var y = Math.random() * gl.drawingBufferHeight;
+ var width = Math.random() * (gl.drawingBufferWidth - x);
+ var height = Math.random() * (gl.drawingBufferHeight - y);
+
+ gl.enable(gl.SCISSOR_TEST);
+ gl.scissor(x, y, width, height);
+ gl.clearColor(Math.random(), Math.random(), Math.random(), 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+
+ return contextActive;
+ };
+
+ return test;
+ }
+
+ return {
+ run: run,
+
+ createContextCreationAndDestructionTest: createContextCreationAndDestructionTest,
+ createContextCreationTest: createContextCreationTest,
+ createMultisampleCorruptionTest: createMultisampleCorruptionTest,
+ createPreserveDrawingBufferLeakTest: createPreserveDrawingBufferLeakTest
+ };
+
+})();
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js b/dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js
new file mode 100644
index 0000000000..dfa7c02167
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js
@@ -0,0 +1,163 @@
+/*
+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.
+*/
+
+'use strict';
+description("Verifies that lines, both aliased and antialiased, have acceptable quality.");
+
+let wtu = WebGLTestUtils;
+let gl;
+
+let aa_fbo;
+
+function setupWebGL1Test(canvasId, useAntialiasing) {
+ gl = wtu.create3DContext(canvasId, { antialias: useAntialiasing }, contextVersion);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors during WebGL 1.0 setup");
+}
+
+function setupWebGL2Test(canvasId, useAntialiasing) {
+ gl = wtu.create3DContext(canvasId, { antialias: false }, contextVersion);
+ // In WebGL 2.0, we always allocate the back buffer without
+ // antialiasing. The only question is whether we allocate a
+ // framebuffer with a multisampled renderbuffer attachment.
+ aa_fbo = null;
+ if (useAntialiasing) {
+ aa_fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, aa_fbo);
+ let rb = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+ let supported = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES);
+ // Prefer 4, then 8, then max.
+ let preferred = [4, 8];
+ let allocated = false;
+ for (let value of preferred) {
+ if (supported.indexOf(value) >= 0) {
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, value, gl.RGBA8,
+ gl.drawingBufferWidth, gl.drawingBufferHeight);
+ allocated = true;
+ break;
+ }
+ }
+ if (!allocated) {
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, supported[supported.length - 1],
+ gl.RGBA8, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ }
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors during WebGL 2.0 setup");
+}
+
+function setupLines() {
+ let prog = wtu.setupSimpleColorProgram(gl, 0);
+ let loc = gl.getUniformLocation(prog, 'u_color');
+ if (loc == null) {
+ testFailed('Failed to fetch color uniform');
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After setup of line program");
+ gl.uniform4f(loc, 1.0, 1.0, 1.0, 1.0);
+ let buffer = gl.createBuffer();
+ let scale = 0.5;
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -scale, -scale, 0.0, 1.0,
+ -scale, scale, 0.0, 1.0,
+ scale, scale, 0.0, 1.0,
+ scale, -scale, 0.0, 1.0,
+ -scale, -scale, 0.0, 1.0,
+ ]), gl.STATIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After setup of buffer");
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After setup of attribute array");
+}
+
+function renderLines(contextVersion, useAntialiasing) {
+ gl.clearColor(0.0, 0.0, 0.5, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.LINE_STRIP, 0, 5);
+ if (contextVersion == 2 && useAntialiasing) {
+ // Blit aa_fbo into the real back buffer.
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, aa_fbo);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ let w = gl.drawingBufferWidth;
+ let h = gl.drawingBufferHeight;
+ gl.blitFramebuffer(0, 0, w, h,
+ 0, 0, w, h,
+ gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ }
+}
+
+function pixelAboveThreshold(arr, pixelIndex, threshold) {
+ return (arr[4 * pixelIndex + 0] >= threshold &&
+ arr[4 * pixelIndex + 1] >= threshold &&
+ arr[4 * pixelIndex + 2] >= threshold &&
+ arr[4 * pixelIndex + 3] >= threshold);
+}
+
+function checkLine(arr, threshold, direction) {
+ // Count number of crossings from below threshold to above (or equal
+ // to) threshold. Must be equal to 2.
+
+ let numPixels = arr.length / 4;
+ let numUpCrossings = 0;
+ let numDownCrossings = 0;
+ for (let index = 0; index < numPixels - 1; ++index) {
+ let curPixel = pixelAboveThreshold(arr, index, threshold);
+ let nextPixel = pixelAboveThreshold(arr, index + 1, threshold);
+ if (!curPixel && nextPixel) {
+ ++numUpCrossings;
+ } else if (curPixel && !nextPixel) {
+ ++numDownCrossings;
+ }
+ }
+ if (numUpCrossings != numDownCrossings) {
+ testFailed('Found differing numbers of up->down and down->up transitions');
+ }
+ if (numUpCrossings == 2) {
+ testPassed('Found 2 lines, looking in the ' + direction + ' direction');
+ } else {
+ testFailed('Found ' + numUpCrossings + ' lines, looking in the ' +
+ direction + ' direction, expected 2');
+ }
+}
+
+function checkResults() {
+ // Check the middle horizontal and middle vertical line of the canvas.
+ let w = gl.drawingBufferWidth;
+ let h = gl.drawingBufferHeight;
+ let t = 100;
+ let arr = new Uint8Array(4 * w);
+ gl.readPixels(0, Math.floor(h / 2),
+ w, 1, gl.RGBA, gl.UNSIGNED_BYTE, arr);
+ checkLine(arr, t, 'horizontal');
+ arr = new Uint8Array(4 * h);
+ gl.readPixels(Math.floor(w / 2), 0,
+ 1, h, gl.RGBA, gl.UNSIGNED_BYTE, arr);
+ checkLine(arr, t, 'vertical');
+}
+
+function runTest(contextVersion, canvasId, useAntialiasing) {
+ switch (contextVersion) {
+ case 1: {
+ setupWebGL1Test(canvasId, useAntialiasing);
+ break;
+ }
+ case 2: {
+ setupWebGL2Test(canvasId, useAntialiasing);
+ }
+ }
+ setupLines();
+ renderLines(contextVersion, useAntialiasing);
+ checkResults();
+}
+
+function runTests() {
+ runTest(contextVersion, 'testbed', false);
+ runTest(contextVersion, 'testbed2', true);
+}
+
+runTests();
+let successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js b/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js
new file mode 100644
index 0000000000..1202b7868c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js
@@ -0,0 +1,247 @@
+/*
+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.
+*/
+NoOverOptimizeOnUniformArrayTester = (function(){
+
+var vshader = [
+ "attribute vec4 a_position;",
+ "void main()",
+ "{",
+ " gl_Position = a_position;",
+ "}"
+].join('\n');
+
+var fshader_max = [
+ "precision mediump float;",
+ "uniform vec4 colora[$(maxUniformVectors)];",
+ "void main()",
+ "{",
+ " gl_FragColor = vec4(colora[$(usedUniformVector)]);",
+ "}"
+].join('\n');
+
+var fshader_max_ab_ab = [
+ "precision mediump float;",
+ "uniform vec4 $(decl1);",
+ "uniform vec4 $(decl2);",
+ "void main()",
+ "{",
+ "gl_FragColor = vec4($(usage1) + $(usage2));",
+ "}"
+].join('\n');
+
+// MaxInt32 is 2^32-1. We need +1 of that to test overflow conditions
+var MaxInt32PlusOne = 4294967296;
+
+function setupTests(gl) {
+ var tests = [];
+ var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
+
+ // This test is to test drivers the have bugs related to optimizing
+ // an array of uniforms when only 1 of those uniforms is used.
+ tests.push({
+ desc: "using last element",
+ maxUniformVectors: maxUniformVectors,
+ usedUniformVector: maxUniformVectors - 1,
+ shader: "fshader-max",
+ color: [0, 1, 0, 1],
+ arrayName: "colora",
+ extraName: "colorb",
+ });
+ tests.push({
+ desc: "using first element",
+ maxUniformVectors: maxUniformVectors,
+ usedUniformVector: 0,
+ shader: "fshader-max",
+ color: [0, 1, 0, 1],
+ arrayName: "colora",
+ extraName: "colorb",
+ });
+
+ // Generate test shaders. We're trying to force the driver to
+ // overflow from 1 array into the next if it optimizes. So for example if it was C
+ //
+ // int big[4];
+ // int little[1];
+ // big[5] = 124;
+ //
+ // Would end up setting little[0] instead of big. Some drivers optimize
+ // where if you only use say 'big[3]' it will actually only allocate just 1 element
+ // for big.
+ //
+ // But, some drivers have a bug where the fact that they optimized big to 1 element
+ // does not get passed down to glUniform so when setting the uniform 'big[3]' they
+ // overwrite memory.
+ //
+ // If the driver crashes, yea. We found a bug. We can block the driver.
+ // Otherwise we try various combinations so that setting 'little[0]' first
+ // and then setting all elements of 'big' we hope it will overwrite 'little[0]'
+ // which will show the bug and again we can block the driver.
+ //
+ // We don't know how the driver will order, in memory, the various uniforms
+ // or for that matter we don't even know if they will be contiguous in memory
+ // but to hopefully expose any bugs we try various combinations.
+ //
+ // It could be the compiler orders uniforms alphabetically.
+ // It could be it orders them in order of declaration.
+ // It could be it orders them in order of usage.
+ //
+ // We also test using only first element of big or just the last element of big.
+ //
+ for (var nameOrder = 0; nameOrder < 2; ++nameOrder) {
+ var name1 = nameOrder ? "colora" : "colorb";
+ var name2 = nameOrder ? "colorb" : "colora";
+ for (var last = 0; last < 2; ++last) {
+ var usedUniformVector = last ? maxUniformVectors - 2 : 0;
+ for (var declOrder = 0; declOrder < 2; ++declOrder) {
+ var bigName = declOrder ? name1 : name2;
+ var littleName = declOrder ? name2 : name1;
+ var decl1 = bigName + "[" + (maxUniformVectors - 1) + "]";
+ var decl2 = littleName + "[1]";
+ if (declOrder) {
+ var t = decl1;
+ decl1 = decl2;
+ decl2 = t;
+ }
+ for (var usageOrder = 0; usageOrder < 2; ++usageOrder) {
+ var usage1 = bigName + "[" + usedUniformVector + "]";
+ var usage2 = littleName + "[0]";
+ if (usageOrder) {
+ var t = usage1;
+ usage1 = usage2;
+ usage2 = t;
+ }
+ var fSrc = wtu.replaceParams(fshader_max_ab_ab, {
+ decl1: decl1,
+ decl2: decl2,
+ usage1: usage1,
+ usage2: usage2,
+ });
+ var desc = "testing: " + name1 + ":" + name2 + " using " + (last ? "last" : "first") +
+ " creating uniforms " + decl1 + " " + decl2 + " and accessing " + usage1 + " " + usage2;
+ tests.push({
+ desc: desc,
+ maxUniformVectors: maxUniformVectors - 1,
+ usedUniformVector: usedUniformVector,
+ source: fSrc,
+ color: [0, 0, 0, 1],
+ arrayName: bigName,
+ extraName: littleName,
+ });
+ }
+ }
+ }
+ }
+ return tests;
+};
+
+function testUniformOptimizationIssues(test) {
+ debug("");
+ debug(test.desc);
+ var fshader = test.source;
+ if (!fshader) {
+ fshader = wtu.replaceParams(fshader_max, test);
+ }
+
+ var consoleElem = document.getElementById("console");
+ wtu.addShaderSource(
+ consoleElem, "vertex shader", vshader);
+ wtu.addShaderSource(
+ consoleElem, "fragment shader", fshader);
+
+ var program = wtu.loadProgram(gl, vshader, fshader);
+ gl.useProgram(program);
+
+ var colorbLocation = gl.getUniformLocation(program, test.extraName + "[0]");
+ if (colorbLocation) {
+ gl.uniform4fv(colorbLocation, [0, 1, 0, 0]);
+ }
+
+ // Ensure that requesting an array uniform past MaxInt32PlusOne returns no uniform
+ var nameMaxInt32PlusOne = test.arrayName + "[" + (test.usedUniformVector + MaxInt32PlusOne) + "]";
+ assertMsg(gl.getUniformLocation(program, nameMaxInt32PlusOne) === null,
+ "Requesting " + nameMaxInt32PlusOne + " uniform should return a null uniform location");
+
+ // Set just the used uniform
+ var name = test.arrayName + "[" + test.usedUniformVector + "]";
+ var uniformLocation = gl.getUniformLocation(program, name);
+ gl.uniform4fv(uniformLocation, test.color);
+ wtu.setupIndexedQuad(gl, 1);
+ wtu.clearAndDrawIndexedQuad(gl, 1);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+
+ // Set all the unused uniforms
+ var locations = [];
+ var allRequiredUniformLocationsQueryable = true;
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ var name = test.arrayName + "[" + ii + "]";
+ var uniformLocation = gl.getUniformLocation(program, name);
+ locations.push(uniformLocation);
+ if (ii == test.usedUniformVector) {
+ continue;
+ }
+ // Locations > usedUnformVector may not exist.
+ // Locations <= usedUniformVector MUST exist.
+ if (ii <= test.usedUniformVector && (uniformLocation === undefined || uniformLocation === null)) {
+ allRequiredUniformLocationsQueryable = false;
+ }
+ gl.uniform4fv(uniformLocation, [1, 0, 0, 1]);
+ }
+ if (allRequiredUniformLocationsQueryable) {
+ testPassed("allRequiredUniformLocationsQueryable is true.");
+ }
+ else {
+ testFailed("allRequiredUniformLocationsQueryable should be true. Was false.");
+ }
+ var positionLoc = gl.getAttribLocation(program, "a_position");
+ wtu.setupIndexedQuad(gl, 1, positionLoc);
+ wtu.clearAndDrawIndexedQuad(gl, 1);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+
+ // Check we can read & write each uniform.
+ // Note: uniforms past test.usedUniformVector might not exist.
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ gl.uniform4fv(locations[ii], [ii + 4, ii + 2, ii + 3, ii + 1]);
+ }
+
+ var kEpsilon = 0.01;
+ var isSame = function(v1, v2) {
+ return Math.abs(v1 - v2) < kEpsilon;
+ };
+
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ var location = locations[ii];
+ if (location) {
+ var value = gl.getUniform(program, locations[ii]);
+ if (!isSame(value[0], ii + 4) ||
+ !isSame(value[1], ii + 2) ||
+ !isSame(value[2], ii + 3) ||
+ !isSame(value[3], ii + 1)) {
+ testFailed("location: " + ii + " was not correct value");
+ break;
+ }
+ }
+ }
+}
+
+function runOneTest(gl, test) {
+ testUniformOptimizationIssues(test);
+};
+
+function runTests(gl, tests) {
+ debug("");
+ debug("Test drivers don't over optimize unused array elements");
+
+ for (var ii = 0; ii < tests.length; ++ii) {
+ runOneTest(gl, tests[ii]);
+ }
+};
+
+return {
+ setupTests : setupTests,
+ runTests : runTests
+};
+
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js b/dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js
new file mode 100644
index 0000000000..362023ce01
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js
@@ -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.
+*/
+
+function testTexLinear(gl, extensionName, internalFormatWebgl2, pixelType) {
+ var wtu = WebGLTestUtils;
+
+ // Before the extension is enabled
+ var extensionEnabled = false;
+ runTestSuite(extensionEnabled);
+
+ if (!gl.getExtension(extensionName))
+ testPassed("No " + extensionName + " support -- this is legal");
+ else {
+ // After the extension is enabled
+ extensionEnabled = true;
+ runTestSuite(extensionEnabled);
+ }
+
+ function runTestSuite(extensionEnabled)
+ {
+ var magF = [gl.NEAREST, gl.LINEAR];
+ var minF = [gl.NEAREST, gl.LINEAR, gl.NEAREST_MIPMAP_NEAREST, gl.NEAREST_MIPMAP_LINEAR, gl.LINEAR_MIPMAP_NEAREST, gl.LINEAR_MIPMAP_LINEAR];
+ var tex2DFShader = [
+ 'uniform sampler2D tex;',
+ 'void main() {',
+ ' gl_FragData[0] = texture2D(tex, vec2(0.5, 0.5)) * vec4(4.0, 2.0, 2.0, 1);',
+ '}'].join('\n');
+
+ var positionVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ '}'].join('\n');
+
+ var texCubeFShader = [
+ 'uniform samplerCube tex;',
+ 'void main() {',
+ ' gl_FragColor = textureCube(tex, normalize(vec3(0.5, 0.5, 1))) * vec4(4.0, 2.0, 2.0, 1);',
+ '}'].join('\n');
+
+ var vs = wtu.loadShader(gl, positionVertexShader, gl.VERTEX_SHADER);
+ var fs_2d = wtu.loadShader(gl, tex2DFShader, gl.FRAGMENT_SHADER);
+ var fs_cube = wtu.loadShader(gl, texCubeFShader, gl.FRAGMENT_SHADER);
+
+ // TEXTURE_2D
+ var program = wtu.setupProgram(gl, [vs, fs_2d]);
+ gl.useProgram(program);
+ wtu.setupUnitQuad(gl);
+ for (var kk = 0; kk < 2; ++kk) {
+ for (var ii = 0; ii < 6; ++ii) {
+ var linear = false;
+ if (magF[kk] == gl.LINEAR || (minF[ii] != gl.NEAREST && minF[ii] != gl.NEAREST_MIPMAP_NEAREST))
+ linear = true;
+ var color = (!extensionEnabled && linear) ? [0, 0, 0, 255] : [255, 255, 255, 255];
+ runEachTest(gl.TEXTURE_2D, magF[kk], minF[ii], linear, extensionEnabled, color);
+ }
+ }
+
+ // TEXTURE_CUBE_MAP
+ var programCube = wtu.setupProgram(gl, [vs, fs_cube]);
+ gl.useProgram(programCube);
+ wtu.setupUnitQuad(gl);
+ for (var kk = 0; kk < 2; ++kk) {
+ for (var ii = 0; ii < 6; ++ii) {
+ var linear = false;
+ if (magF[kk] == gl.LINEAR || (minF[ii] != gl.NEAREST && minF[ii] != gl.NEAREST_MIPMAP_NEAREST))
+ linear = true;
+ var color = (!extensionEnabled && linear) ? [0, 0, 0, 255] : [255, 255, 255, 255];
+ runEachTest(gl.TEXTURE_CUBE_MAP, magF[kk], minF[ii], linear, extensionEnabled, color);
+ }
+ }
+ }
+
+ function runEachTest(textureTarget, magFilter, minFilter, linear, extensionEnabled, expected)
+ {
+ const format = gl.RGBA;
+ let internalFormat = format;
+ if (wtu.isWebGL2(gl)) {
+ internalFormat = gl[internalFormatWebgl2];
+ }
+ var numberOfChannels = 4;
+ debug("");
+ debug("testing target: " + wtu.glEnumToString(gl,textureTarget) +
+ ", testing format: " + wtu.glEnumToString(gl, format) +
+ ", magFilter is: " + wtu.glEnumToString(gl, magFilter) +
+ ", minFilter is: " + wtu.glEnumToString(gl, minFilter) +
+ ", " + extensionName + " is " + (extensionEnabled ? "enabled": "not enabled")
+ );
+
+ // Generate data.
+ var width = 4;
+ var height = 4;
+ var canvas2d = document.createElement('canvas');
+ canvas2d.width = width;
+ canvas2d.height = height;
+ var ctx2d = canvas2d.getContext('2d');
+ var color = [64, 128, 128, 255];
+ ctx2d.fillStyle = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + color[3] + ")";
+ ctx2d.fillRect(0, 0, width, height);
+
+ var texture = gl.createTexture();
+ gl.bindTexture(textureTarget, texture);
+ gl.texParameteri(textureTarget, gl.TEXTURE_MAG_FILTER, magFilter);
+ gl.texParameteri(textureTarget, gl.TEXTURE_MIN_FILTER, minFilter);
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ if (textureTarget == gl.TEXTURE_2D) {
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, format, gl[pixelType], canvas2d);
+ if (minFilter != gl.NEAREST && minFilter != gl.LINEAR) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during texture setup");
+ gl.generateMipmap(gl.TEXTURE_2D);
+ if (gl.getError() != gl.NO_ERROR) {
+ debug("generateMipmap failed for floating-point TEXTURE_2D -- this is legal -- skipping the rest of this test");
+ return;
+ }
+ }
+ } else if (textureTarget == gl.TEXTURE_CUBE_MAP) {
+ var targets = [
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ for (var tt = 0; tt < targets.length; ++tt)
+ gl.texImage2D(targets[tt], 0, internalFormat, format, gl[pixelType], canvas2d);
+ if (minFilter != gl.NEAREST && minFilter != gl.LINEAR) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during texture setup");
+ gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+ if (gl.getError() != gl.NO_ERROR) {
+ debug("generateMipmap failed for floating-point TEXTURE_CUBE_MAP -- this is legal -- skipping the rest of this test");
+ return;
+ }
+ }
+ }
+ wtu.clearAndDrawUnitQuad(gl);
+ if (!linear) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, pixelType + " texture with non-Linear filter should succeed with NO_ERROR no matter whether " + extensionName + " is enabled or not");
+ } else if (!extensionEnabled) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, pixelType + " texture with Linear filter should produce [0, 0, 0, 1.0] with NO_ERROR if " + extensionName + " isn't enabled");
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, pixelType + " texture with Linear filter should succeed with NO_ERROR if " + extensionName + " is enabled");
+ }
+
+ wtu.checkCanvas(gl, expected, "should be " + expected[0] + "," + expected[1] + "," + expected[2] + "," + expected[3]);
+ }
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js b/dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js
new file mode 100644
index 0000000000..b25a7dd026
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js
@@ -0,0 +1,57 @@
+function testTransferToImageBitmap(webglContextVersion, bitmap) {
+ var internalFormat = "RGBA";
+ var pixelFormat = "RGBA";
+ var pixelType = "UNSIGNED_BYTE";
+
+ var width = 32;
+ var height = 32;
+ var canvas = document.createElement("canvas");
+ canvas.width = width;
+ canvas.height = height;
+ var gl = WebGLTestUtils.create3DContext(canvas);
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ TexImageUtils.setupTexturedQuad(gl, internalFormat);
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ // Set up texture parameters
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ var targets = [gl.TEXTURE_2D];
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], bitmap);
+ }
+ for (var tt = 0; tt < targets.length; ++tt) {
+ // Draw the triangles
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ var buf = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+ _checkCanvas(buf, width, height, webglContextVersion);
+ }
+}
+
+function _checkCanvas(buf, width, height, webglContextVersion)
+{
+ for (var i = 0; i < width * height; i++) {
+ if (buf[i * 4] != 255 || buf[i * 4 + 1] != 255 ||
+ buf[i * 4 + 2] != 0 || buf[i * 4 + 3] != 255) {
+ testFailed("OffscreenCanvas." + webglContextVersion +
+ ": This pixel should be [255, 255, 0, 255], but it is: [" + buf[i * 4] + ", " +
+ buf[i * 4 + 1] + ", " + buf[i * 4 + 2] + ", " + buf[i * 4 + 3] + "].");
+ return;
+ }
+ }
+ testPassed("TransferToImageBitmap test on OffscreenCanvas." + webglContextVersion + " passed");
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js
new file mode 100644
index 0000000000..75e3496dfb
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js
@@ -0,0 +1,321 @@
+/*
+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.
+*/
+
+'use strict';
+
+var OutOfBoundsTest = (function() {
+
+var runCommonInvalidValueTests = function(callTemplate, gl, wtu, ext) {
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: -1, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: -1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: -1, type: 'gl.UNSIGNED_BYTE', offset: 1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: 1, type: 'gl.UNSIGNED_BYTE', offset: -1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: '0xffffffff', type: 'gl.UNSIGNED_BYTE', offset: 0}));
+};
+
+var setupProgramAndBindVertexArray = function(gl, wtu) {
+ var program = wtu.loadStandardProgram(gl);
+
+ gl.useProgram(program);
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.enableVertexAttribArray(0);
+
+ return program;
+};
+
+var setupProgram2 = function(gl, wtu) {
+ var vshader = [
+ 'attribute vec3 aOne;',
+ 'attribute vec2 aTwo;',
+ 'void main() {',
+ ' gl_Position = vec4(aOne, 1.0) + vec4(aTwo, 0.0, 1.0);',
+ '}'
+ ].join('\n');
+
+ var fshader = [
+ 'void main() {',
+ ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);',
+ '}'
+ ].join('\n');
+
+ var program = wtu.setupProgram(gl, [vshader, fshader], [ "aOne", "aTwo" ]);
+ if (!program) {
+ testFailed("failed to create test program");
+ }
+ return program;
+};
+
+var runDrawArraysTest = function(callTemplate, gl, wtu, ext) {
+ var program = setupProgramAndBindVertexArray(gl, wtu);
+
+ debug("Test empty buffer")
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ ]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 1}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 10000}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 1, count: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 100, count: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+
+ debug("")
+ debug("Test buffer with 3 float vectors")
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 3}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 3, count: 2}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 10000}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 100, count: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+
+ debug("")
+ debug("Test buffer with interleaved (3+2) float vectors")
+
+ setupProgram2(gl, wtu);
+
+ var vbo = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+ // enough for 9 vertices, so 3 triangles
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(9*5), gl.STATIC_DRAW);
+
+ // bind first 3 elements, with a stride of 5 float elements
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, 0);
+ // bind 2 elements, starting after the first 3; same stride of 5 float elements
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 5*4, 3*4);
+
+ gl.enableVertexAttribArray(0);
+ gl.enableVertexAttribArray(1);
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9}));
+
+ // negative values must generate INVALID_VALUE; they can never be valid
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: 0, count: -500}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: -200, count: 1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: -200, count: -500}));
+
+ // 0xffffffff needs to convert to a 'long' IDL argument as -1, as per
+ // WebIDL 4.1.7. JS ToInt32(0xffffffff) == -1. Thus INVALID_VALUE.
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: 0, count: '0xffffffff'}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: '0xffffffff', count: '0xffffffff'}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: '0xffffffff', count: 1}));
+
+ // values that could otherwise be valid but aren't due to bindings generate
+ // INVALID_OPERATION
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 10000}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: '0x7fffffff', count: 1}));
+};
+
+var runDrawElementsTest = function(callTemplate, gl, wtu, ext) {
+ var program = setupProgramAndBindVertexArray(gl, wtu);
+ var contextVersion = wtu.getDefault3DContextVersion();
+
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+
+ debug('');
+ debug('Test null index buffer');
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+
+ debug('');
+ debug('Test empty index buffer');
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 10000, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 1, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+
+ debug('');
+ debug('Test buffer with 3 byte indexes');
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2 ]), gl.STATIC_DRAW);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 2}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 10000, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 4}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 10000, type: 'gl.UNSIGNED_BYTE', offset: 10000}));
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, (new Uint8Array([ 3, 0, 1, 2 ])).subarray(1), gl.STATIC_DRAW)');
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, new Uint8Array([ 3, 0, 1]))');
+ var indexValidationError = wtu.shouldGenerateGLError(gl, [gl.INVALID_OPERATION, gl.NO_ERROR], wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, (new Uint8Array([ 3, 0, 1, 2 ])).subarray(1))');
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+
+ debug('');
+ debug('Test buffer with interleaved (3+2) float vectors');
+
+ setupProgram2(gl, wtu);
+
+ var vbo = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+ // enough for 9 vertices, so 3 triangles
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(9*5), gl.STATIC_DRAW);
+
+ // bind first 3 elements, with a stride of 5 float elements
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, 0);
+ // bind 2 elements, starting after the first 3; same stride of 5 float elements
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 5*4, 3*4);
+
+ gl.enableVertexAttribArray(0);
+ gl.enableVertexAttribArray(1);
+
+ var ebo = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
+ // For WebGL 2, PRIMITIVE_RESTART_FIXED_INDEX is always enabled.
+ // 0xffff will be handled as a primitive restart.
+ if (contextVersion <= 1) {
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(
+ [ 0, 1, 2,
+ 1, 2, 0,
+ 2, 0, 1,
+ 201, 202, 203,
+ 0x7fff, 0x7fff, 0x7fff,
+ 0xffff, 0xffff, 0xffff ]),
+ gl.STATIC_DRAW);
+ } else {
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(
+ [ 0, 1, 2,
+ 1, 2, 0,
+ 2, 0, 1,
+ 201, 202, 203,
+ 0x7fff, 0x7fff, 0x7fff,
+ 0xffff - 1, 0xffff - 1, 0xffff - 1 ]),
+ gl.STATIC_DRAW);
+ }
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 9, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+
+
+ // invalid operation with indices that would be valid with correct bindings
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 9, type: 'gl.UNSIGNED_SHORT', offset: 1000}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 12, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 15, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 18, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_SHORT', offset: 2*15}));
+
+ // 0xffffffff needs to convert to a 'long' IDL argument as -1, as per
+ // WebIDL 4.1.7. JS ToInt32(0xffffffff) == -1. Thus INVALID_VALUE.
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: '0xffffffff', type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ // offset is defined as GLintptr, which is long long in IDL (64-bit).
+ // 2^32 - 1 should not overflow, and only result in INVALID_OPERATION.
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 1, type: 'gl.UNSIGNED_SHORT', offset: '0xffffffff'}));
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: '0x7fffffff', type: 'gl.UNSIGNED_SHORT', offset: 0}));
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+
+ // invalid operation with offset that's not a multiple of the type size
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 1}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 2}));
+
+ // invalid operation if no buffer is bound to ELEMENT_ARRAY_BUFFER
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
+
+ debug('');
+ debug('Test buffer setting attrib 0 to a buffer too small and disable it.');
+ var smallVBO = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, smallVBO);
+ gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0x10);
+ gl.disableVertexAttribArray(0);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 2}));
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 2}));
+};
+
+var runInstancedTest = function(callTemplate, gl, wtu, ext) {
+ setupProgram2(gl, wtu);
+
+ // Initialize non-instanced attribute data.
+ // Enough for 9 vertices, so 3 triangles.
+ var vbo = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(9*3), gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+ // Setup buffer for instanced attribute data.
+ var vbo2 = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo2);
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
+
+ gl.enableVertexAttribArray(0);
+ gl.enableVertexAttribArray(1);
+
+ debug('Test out-of-range instanced attributes');
+ debug('');
+
+ debug('Test with an empty buffer for the instanced attribute');
+ ext.vertexAttribDivisorANGLE(1, 1);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 10000, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 1}));
+
+ debug('Test with a buffer with 1 float for the instanced attribute');
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(1), gl.STATIC_DRAW);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 10000, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 1}));
+
+ debug('');
+ debug('Test with a buffer with 2 floats for the instanced attribute');
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(2), gl.STATIC_DRAW);
+ debug('Divisor 1');
+ ext.vertexAttribDivisorANGLE(1, 1);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 2}));
+ debug('Divisor 3');
+ ext.vertexAttribDivisorANGLE(1, 3);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 3}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 4}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 10000}));
+
+ debug('');
+ debug('Test with a buffer with 4 floats for the instanced attribute');
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(4), gl.STATIC_DRAW);
+ debug('Divisor 1');
+ ext.vertexAttribDivisorANGLE(1, 1);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 2}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 3}));
+ debug('Divisor 2');
+ ext.vertexAttribDivisorANGLE(1, 2);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 4}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 5}));
+};
+
+var runDrawArraysInstancedTest = function(callTemplate, gl, wtu, ext) {
+ runInstancedTest(callTemplate, gl, wtu, ext);
+};
+
+var runDrawElementsInstancedTest = function(callTemplate, gl, wtu, ext) {
+ var ebo = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(
+ [ 0, 1, 2,
+ 5, 4, 3,
+ 6, 7, 8 ]),
+ gl.STATIC_DRAW);
+ callTemplate = wtu.replaceParams(callTemplate, {type: 'gl.UNSIGNED_BYTE', offset: '$(offset)', count: '$(count)', primcount: '$(primcount)'});
+ runInstancedTest(callTemplate, gl, wtu, ext);
+};
+
+return {
+ runDrawArraysTest: runDrawArraysTest,
+ runDrawArraysInstancedTest: runDrawArraysInstancedTest,
+ runDrawElementsTest: runDrawElementsTest,
+ runDrawElementsInstancedTest: runDrawElementsInstancedTest
+};
+
+})();
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js
new file mode 100644
index 0000000000..5de4dc88d8
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js
@@ -0,0 +1,263 @@
+/*
+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.
+*/
+
+"use strict";
+
+function createTextureWithNearestFiltering(target)
+{
+ let texture = gl.createTexture();
+ gl.bindTexture(target, texture);
+ gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed");
+ return texture;
+}
+
+// Write a transformation matrix to elements of floatArray starting from index.
+// The matrix transforms a unit square (-1 to 1) to a rectangle with the width scaleX and the left edge at offsetX.
+function setupTranslateAndScaleXMatrix(floatArray, index, scaleX, offsetX)
+{
+ // x position is transformed according to this equation: scaleX * x0 + translateX = offsetX
+ // By substituting x0 with -1 (unit square x value for the left edge), we get the following:
+ let translateX = offsetX + scaleX;
+
+ floatArray[index] = scaleX;
+ floatArray[index + 1] = 0.0;
+ floatArray[index + 2] = 0.0;
+ floatArray[index + 3] = 0.0;
+
+ floatArray[index + 4] = 0.0;
+ floatArray[index + 5] = 1.0;
+ floatArray[index + 6] = 0.0;
+ floatArray[index + 7] = 0.0;
+
+ floatArray[index + 8] = 0.0;
+ floatArray[index + 9] = 0.0;
+ floatArray[index + 10] = 1.0;
+ floatArray[index + 11] = 0.0;
+
+ floatArray[index + 12] = translateX;
+ floatArray[index + 13] = 0.0;
+ floatArray[index + 14] = 0.0;
+ floatArray[index + 15] = 1.0;
+}
+
+// Check the currently bound read framebuffer with dimensions <width> x <height>.
+// The framebuffer should be divided into <strips> equally wide vertical strips, with the one indicated by
+// <coloredStripIndex> colored with <expectedStripColor>. The rest of the framebuffer should be colored transparent black.
+// A two pixel wide region at each edge of the colored region is left unchecked to allow for some tolerance for rasterization.
+function checkVerticalStrip(width, height, strips, coloredStripIndex, expectedStripColor, framebufferDescription)
+{
+ let colorRegionLeftEdge = (width / strips) * coloredStripIndex;
+ let colorRegionRightEdge = (width / strips) * (coloredStripIndex + 1);
+ if (coloredStripIndex > 0) {
+ wtu.checkCanvasRect(gl, 0, 0, colorRegionLeftEdge - 1, height, [0, 0, 0, 0], 'the left edge of ' + framebufferDescription + ' should be untouched');
+ }
+ if (coloredStripIndex < strips - 1) {
+ wtu.checkCanvasRect(gl, colorRegionRightEdge + 1, 0, width - colorRegionRightEdge - 1, height, [0, 0, 0, 0], 'the right edge of ' + framebufferDescription + ' should be untouched');
+ }
+ wtu.checkCanvasRect(gl, colorRegionLeftEdge + 1, 0, colorRegionRightEdge - colorRegionLeftEdge - 2, height, expectedStripColor, 'a thin strip in ' + framebufferDescription + ' should be colored ' + expectedStripColor);
+}
+
+function getMultiviewPassthroughVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+
+ 'void main() {',
+ ' gl_Position = a_position;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+// This shader splits the viewport into <views> equally sized vertical strips.
+// The input quad defined by "a_position" is transformed to fill a different
+// strip in each view.
+function getMultiviewOffsetVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+
+ 'void main() {',
+ ' vec4 pos = a_position;',
+ " // Transform the quad to a thin vertical strip that's offset along the x axis according to the view id.",
+ ' pos.x = (pos.x * 0.5 + 0.5 + float(gl_ViewID_OVR)) * 2.0 / $(num_views).0 - 1.0;',
+ ' gl_Position = pos;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+// This shader transforms the incoming "a_position" with transforms for each
+// view given in the uniform array "transform".
+function getMultiviewRealisticUseCaseVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'uniform mat4 transform[$(num_views)];',
+ 'in vec4 a_position;',
+
+ 'void main() {',
+ " // Transform the quad with the transformation matrix chosen according to gl_ViewID_OVR.",
+ ' vec4 pos = transform[gl_ViewID_OVR] * a_position;',
+ ' gl_Position = pos;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getMultiviewColorFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' uint mask = gl_ViewID_OVR + 1u;',
+ ' my_FragColor = vec4(((mask & 4u) != 0u) ? 1.0 : 0.0,',
+ ' ((mask & 2u) != 0u) ? 1.0 : 0.0,',
+ ' ((mask & 1u) != 0u) ? 1.0 : 0.0,',
+ ' 1.0);',
+ '}'].join('\n');
+}
+
+function getMultiviewColorFragmentShaderForDrawBuffers(drawBuffers) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'out vec4 my_FragColor[$(drawBuffers)];',
+
+ 'void main() {',
+ ' uint mask;'];
+
+ for (let i = 0; i < drawBuffers; ++i) {
+ shaderCode.push(wtu.replaceParams(' mask = gl_ViewID_OVR + $(i)u;', {'i': i + 1}));
+ shaderCode.push(wtu.replaceParams(' my_FragColor[$(i)] = vec4(((mask & 4u) != 0u) ? 1.0 : 0.0,', {'i': i}));
+ shaderCode.push(' ((mask & 2u) != 0u) ? 1.0 : 0.0,');
+ shaderCode.push(' ((mask & 1u) != 0u) ? 1.0 : 0.0,');
+ shaderCode.push(' 1.0);');
+ }
+ shaderCode.push('}');
+ shaderCode = shaderCode.join('\n');
+ return wtu.replaceParams(shaderCode, {'drawBuffers' : drawBuffers});
+}
+
+function getMultiviewVaryingVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+ 'out float testVarying;',
+
+ 'void main() {',
+ ' gl_Position = a_position;',
+ ' testVarying = float(gl_ViewID_OVR);',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getMultiviewVaryingFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'in float testVarying;',
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' int mask = int(testVarying + 0.1) + 1;',
+ ' my_FragColor = vec4(((mask & 4) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 2) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 1) != 0) ? 1.0 : 0.0,',
+ ' 1.0);',
+ '}'].join('\n');
+}
+
+function getMultiviewFlatVaryingVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+ 'flat out int testVarying;',
+
+ 'void main() {',
+ ' gl_Position = a_position;',
+ ' testVarying = int(gl_ViewID_OVR);',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getMultiviewFlatVaryingFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'flat in int testVarying;',
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' int mask = testVarying + 1;',
+ ' my_FragColor = vec4(((mask & 4) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 2) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 1) != 0) ? 1.0 : 0.0,',
+ ' 1.0);',
+ '}'].join('\n');
+}
+
+function getMultiviewInstancedVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+ 'out vec4 color;',
+
+ 'void main() {',
+ ' vec4 pos = a_position;',
+ " // Transform the quad to a thin vertical strip that's offset along the x axis according to the view id and instance id.",
+ ' pos.x = (pos.x * 0.5 + 0.5 + float(gl_ViewID_OVR) + float(gl_InstanceID)) * 2.0 / ($(num_views).0 * 2.0) - 1.0;',
+ ' int mask = gl_InstanceID + 1;',
+ ' color = vec4(((mask & 4) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 2) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 1) != 0) ? 1.0 : 0.0,',
+ ' 1.0);',
+ ' gl_Position = pos;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getInstanceColorFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'in vec4 color;',
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' my_FragColor = color;',
+ '}'].join('\n');
+}
+
+function getExpectedColor(view) {
+ var mask = (view + 1);
+ return [(mask & 4) ? 255 : 0, (mask & 2) ? 255 : 0, (mask & 1) ? 255 : 0, 255];
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js b/dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js
new file mode 100644
index 0000000000..561c1385af
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js
@@ -0,0 +1,664 @@
+/*
+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.
+*/
+
+async function testNonReservedWords(part, numParts) {
+
+ description(`test shaders using reserved words as identifiers compile ${part} of ${numParts}`);
+
+ const DXWords = [
+ "Buffer",
+ "double",
+ "uint",
+ "half",
+ "dword",
+ "string",
+ "texture",
+ "pixelshader",
+ "vertexshader",
+ "switch",
+ "min16float",
+ "min10float",
+ "min16int",
+ "min12int",
+ "min16uint",
+ "vector",
+ "matrix",
+ "float2",
+ "float3",
+ "float4",
+ "float1x1",
+ "float1x2",
+ "float1x3",
+ "float1x4",
+ "float2x1",
+ "float2x2",
+ "float2x3",
+ "float2x4",
+ "float3x1",
+ "float3x2",
+ "float3x3",
+ "float3x4",
+ "float4x1",
+ "float4x2",
+ "float4x3",
+ "float4x4",
+ "int1x1",
+ "int1x2",
+ "int1x3",
+ "int1x4",
+ "int2x1",
+ "int2x2",
+ "int2x3",
+ "int2x4",
+ "int3x1",
+ "int3x2",
+ "int3x3",
+ "int3x4",
+ "int4x1",
+ "int4x2",
+ "int4x3",
+ "int4x4",
+ "double1x1",
+ "double1x2",
+ "double1x3",
+ "double1x4",
+ "double2x1",
+ "double2x2",
+ "double2x3",
+ "double2x4",
+ "double3x1",
+ "double3x2",
+ "double3x3",
+ "double3x4",
+ "double4x1",
+ "double4x2",
+ "double4x3",
+ "double4x4",
+ "abort",
+ "abs",
+ "acos",
+ "all",
+ "AllMemoryBarrier",
+ "AllMemoryBarrierWithGroupSync",
+ "any",
+ "asdouble",
+ "asfloat",
+ "asin",
+ "asint",
+ "asint",
+ "asuint",
+ "asuint",
+ "atan",
+ "atan2",
+ "ceil",
+ "clamp",
+ "clip",
+ "cos",
+ "cosh",
+ "countbits",
+ "cross",
+ "D3DCOLORtoUBYTE4",
+ "ddx",
+ "ddx_coarse",
+ "ddx_fine",
+ "ddy",
+ "ddy_coarse",
+ "ddy_fine",
+ "degrees",
+ "determinant",
+ "DeviceMemoryBarrier",
+ "DeviceMemoryBarrierWithGroupSync",
+ "distance",
+ "dot",
+ "dst",
+ "errorf",
+ "EvaluateAttributeAtCentroid",
+ "EvaluateAttributeAtSample",
+ "EvaluateAttributeSnapped",
+ "exp",
+ "exp2",
+ "f16tof32",
+ "f32tof16",
+ "faceforward",
+ "firstbithigh",
+ "firstbitlow",
+ "floor",
+ "fma",
+ "fmod",
+ "frac",
+ "frexp",
+ "fwidth",
+ "GetRenderTargetSampleCount",
+ "GetRenderTargetSamplePosition",
+ "GroupMemoryBarrier",
+ "GroupMemoryBarrierWithGroupSync",
+ "InterlockedAdd",
+ "InterlockedAnd",
+ "InterlockedCompareExchange",
+ "InterlockedCompareStore",
+ "InterlockedExchange",
+ "InterlockedMax",
+ "InterlockedMin",
+ "InterlockedOr",
+ "InterlockedXor",
+ "isfinite",
+ "isinf",
+ "isnan",
+ "ldexp",
+ "length",
+ "lerp",
+ "lit",
+ "log",
+ "log10",
+ "log2",
+ "mad",
+ "max",
+ "min",
+ "modf",
+ "msad4",
+ "mul",
+ "noise",
+ "normalize",
+ "pow",
+ "printf",
+ "Process2DQuadTessFactorsAvg",
+ "Process2DQuadTessFactorsMax",
+ "Process2DQuadTessFactorsMin",
+ "ProcessIsolineTessFactors",
+ "ProcessQuadTessFactorsAvg",
+ "ProcessQuadTessFactorsMax",
+ "ProcessQuadTessFactorsMin",
+ "ProcessTriTessFactorsAvg",
+ "ProcessTriTessFactorsMax",
+ "ProcessTriTessFactorsMin",
+ "radians",
+ "rcp",
+ "reflect",
+ "refract",
+ "reversebits",
+ "round",
+ "rsqrt",
+ "saturate",
+ "sign",
+ "sin",
+ "sincos",
+ "sinh",
+ "smoothstep",
+ "sqrt",
+ "step",
+ "tan",
+ "tanh",
+ "tex1D",
+ "tex1D",
+ "tex1Dbias",
+ "tex1Dgrad",
+ "tex1Dlod",
+ "tex1Dproj",
+ "tex2D",
+ "tex2D",
+ "tex2Dbias",
+ "tex2Dgrad",
+ "tex2Dlod",
+ "tex2Dproj",
+ "tex3D",
+ "tex3D",
+ "tex3Dbias",
+ "tex3Dgrad",
+ "tex3Dlod",
+ "tex3Dproj",
+ "texCUBE",
+ "texCUBE",
+ "texCUBEbias",
+ "texCUBEgrad",
+ "texCUBElod",
+ "texCUBEproj",
+ "transpose",
+ "trunc"
+ ];
+
+ const GLSL_4_20_11_words = [
+ "attribute",
+ "const",
+ "uniform",
+ "varying",
+ "coherent",
+ "volatile",
+ "restrict",
+ "readonly",
+ "writeonly",
+ "atomic_uint",
+ "layout",
+ "centroid",
+ "flat",
+ "smooth",
+ "noperspective",
+ "patch",
+ "sample",
+ "break",
+ "continue",
+ "do",
+ "for",
+ "while",
+ "switch",
+ "case",
+ "default",
+ "if",
+ "else",
+ "subroutine",
+ "in",
+ "out",
+ "inout",
+ "float",
+ "double",
+ "int",
+ "void",
+ "bool",
+ "true",
+ "false",
+ "invariant",
+ "discard",
+ "return",
+ "mat2",
+ "mat3",
+ "mat4",
+ "dmat2",
+ "dmat3",
+ "dmat4",
+ "mat2x2",
+ "mat2x3",
+ "mat2x4",
+ "dmat2x2",
+ "dmat2x3",
+ "dmat2x4",
+ "mat3x2",
+ "mat3x3",
+ "mat3x4",
+ "dmat3x2",
+ "dmat3x3",
+ "dmat3x4",
+ "mat4x2",
+ "mat4x3",
+ "mat4x4",
+ "dmat4x2",
+ "dmat4x3",
+ "dmat4x4",
+ "vec2",
+ "vec3",
+ "vec4",
+ "ivec2",
+ "ivec3",
+ "ivec4",
+ "bvec2",
+ "bvec3",
+ "bvec4",
+ "dvec2",
+ "dvec3",
+ "dvec4",
+ "uint",
+ "uvec2",
+ "uvec3",
+ "uvec4",
+ "lowp",
+ "mediump",
+ "highp",
+ "precision",
+ "sampler1D",
+ "sampler2D",
+ "sampler3D",
+ "samplerCube",
+ "sampler1DShadow",
+ "sampler2DShadow",
+ "samplerCubeShadow",
+ "sampler1DArray",
+ "sampler2DArray",
+ "sampler1DArrayShadow",
+ "sampler2DArrayShadow",
+ "isampler1D",
+ "isampler2D",
+ "isampler3D",
+ "isamplerCube",
+ "isampler1DArray",
+ "isampler2DArray",
+ "usampler1D",
+ "usampler2D",
+ "usampler3D",
+ "usamplerCube",
+ "usampler1DArray",
+ "usampler2DArray",
+ "sampler2DRect",
+ "sampler2DRectShadow",
+ "isampler2DRect",
+ "usampler2DRect",
+ "samplerBuffer",
+ "isamplerBuffer",
+ "usamplerBuffer",
+ "sampler2DMS",
+ "isampler2DMS",
+ "usampler2DMS",
+ "sampler2DMSArray",
+ "isampler2DMSArray",
+ "usampler2DMSArray",
+ "samplerCubeArray",
+ "samplerCubeArrayShadow",
+ "isamplerCubeArray",
+ "usamplerCubeArray",
+ "image1D",
+ "iimage1D",
+ "uimage1D",
+ "image2D",
+ "iimage2D",
+ "uimage2D",
+ "image3D",
+ "iimage3D",
+ "uimage3D",
+ "image2DRect",
+ "iimage2DRect",
+ "uimage2DRect",
+ "imageCube",
+ "iimageCube",
+ "uimageCube",
+ "imageBuffer",
+ "iimageBuffer",
+ "uimageBuffer",
+ "image1DArray",
+ "iimage1DArray",
+ "uimage1DArray",
+ "image2DArray",
+ "iimage2DArray",
+ "uimage2DArray",
+ "imageCubeArray",
+ "iimageCubeArray",
+ "uimageCubeArray",
+ "image2DMS",
+ "iimage2DMS",
+ "uimage2DMS",
+ "image2DMSArray",
+ "iimage2DMSArray",
+ "uimage2DMSArray",
+ "struct"
+ ];
+
+ const GLSL_4_20_11_future_words = [
+ "common",
+ "partition",
+ "active",
+ "asm",
+ "class",
+ "union",
+ "enum",
+ "typedef",
+ "template",
+ "this",
+ "packed",
+ "resource",
+ "goto",
+ "inline",
+ "noinline",
+ "public",
+ "static",
+ "extern",
+ "external",
+ "interface",
+ "long",
+ "short",
+ "half",
+ "fixed",
+ "unsigned",
+ "superp",
+ "input",
+ "output",
+ "hvec2",
+ "hvec3",
+ "hvec4",
+ "fvec2",
+ "fvec3",
+ "fvec4",
+ "sampler3DRect",
+ "filter",
+ "sizeof",
+ "cast",
+ "namespace",
+ "using",
+ "row_major"
+ ];
+
+ const GLSL_1_0_17_words = [
+ "attribute",
+ "const",
+ "uniform",
+ "varying",
+ "break",
+ "continue",
+ "do",
+ "for",
+ "while",
+ "if",
+ "else",
+ "in",
+ "out",
+ "inout",
+ "float",
+ "int",
+ "void",
+ "bool",
+ "true",
+ "false",
+ "lowp",
+ "mediump",
+ "highp",
+ "precision",
+ "invariant",
+ "discard",
+ "return",
+ "mat2",
+ "mat3",
+ "mat4",
+ "vec2",
+ "vec3",
+ "vec4",
+ "ivec2",
+ "ivec3",
+ "ivec4",
+ "bvec2",
+ "bvec3",
+ "bvec4",
+ "sampler2D",
+ "samplerCube",
+ "struct"
+ ]
+
+ const GLSL_1_0_17_FutureWords = [
+ "asm",
+ "class",
+ "union",
+ "enum",
+ "typedef",
+ "template",
+ "this",
+ "packed",
+ "goto",
+ "switch",
+ "default",
+ "inline",
+ "noinline",
+ "volatile",
+ "public",
+ "static",
+ "extern",
+ "external",
+ "interface",
+ "flat",
+ "long",
+ "short",
+ "double",
+ "half",
+ "fixed",
+ "unsigned",
+ "superp",
+ "input",
+ "output",
+ "hvec2",
+ "hvec3",
+ "hvec4",
+ "dvec2",
+ "dvec3",
+ "dvec4",
+ "fvec2",
+ "fvec3",
+ "fvec4",
+ "sampler1D",
+ "sampler3D",
+ "sampler1DShadow",
+ "sampler2DShadow",
+ "sampler2DRect",
+ "sampler3DRect",
+ "sampler2DRectShadow",
+ "sizeof",
+ "cast",
+ "namespace",
+ "using"
+ ];
+
+ const allBadWords = [
+ ...DXWords,
+ ...GLSL_4_20_11_words,
+ ...GLSL_4_20_11_future_words,
+ ];
+ const numWordsPerPart = Math.ceil(allBadWords.length / numParts);
+ const firstWordNdx = numWordsPerPart * (part - 1);
+ const badWords = allBadWords.slice(firstWordNdx, firstWordNdx + numWordsPerPart);
+ debug(`running tests for words ${firstWordNdx} to ${firstWordNdx + badWords.length - 1} of ${allBadWords.length}`);
+
+ const shaders = {
+ vertexShader0: `
+struct $replaceMe {
+ vec4 $replaceMe;
+};
+struct Foo {
+ $replaceMe $replaceMe;
+};
+attribute vec4 position;
+void main()
+{
+ Foo f;
+ f.$replaceMe.$replaceMe = position;
+ gl_Position = f.$replaceMe.$replaceMe;
+}
+`,
+ fragmentShader0: `
+precision mediump float;
+vec4 $replaceMe() {
+ return vec4(0,1,0,1);
+}
+void main()
+{
+ gl_FragColor = $replaceMe();
+}
+`,
+ vertexShader1: `
+attribute vec4 $replaceMe;
+void main()
+{
+ gl_Position = $replaceMe;
+}
+`,
+ fragmentShader1: `
+precision mediump float;
+vec4 foo(vec4 $replaceMe) {
+ return $replaceMe;
+}
+void main()
+{
+ gl_FragColor = foo(vec4(1,0,1,1));
+}
+`,
+ vertexShader2: `
+varying vec4 $replaceMe;
+attribute vec4 position;
+void main()
+{
+ gl_Position = position;
+ $replaceMe = position;
+}
+`,
+ fragmentShader2: `
+precision mediump float;
+varying vec4 $replaceMe;
+void main()
+{
+ gl_FragColor = $replaceMe;
+}
+`,
+ vertexShader3: `
+attribute vec4 position;
+void main()
+{
+ gl_Position = position;
+}
+`,
+ fragmentShader3: `
+precision mediump float;
+uniform vec4 $replaceMe;
+void main()
+{
+ gl_FragColor = $replaceMe;
+}
+`,
+ };
+
+ const wtu = WebGLTestUtils;
+ const gl = wtu.create3DContext();
+ const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+ const reservedWords = new Set([
+ ...GLSL_1_0_17_words,
+ ...GLSL_1_0_17_FutureWords,
+ ]);
+
+ const checkedWords = new Set();
+
+ const src = [];
+ for (let ii = 0; ii < 4; ++ii) {
+ const vSrc = shaders[`vertexShader${ii}`];
+ const fSrc = shaders[`fragmentShader${ii}`];
+ src.push({vSrc: vSrc, fSrc: fSrc});
+ }
+
+ for (const badWord of badWords) {
+ testWord(badWord);
+ await wait();
+ }
+ finishTest();
+
+ function testWord(word) {
+ if (reservedWords.has(word) || checkedWords.has(word)) {
+ return;
+ }
+ checkedWords.add(word);
+ debug("");
+ debug(`testing: ${word}`);
+
+ for (let ii = 0; ii < src.length; ++ii) {
+ const vs = src[ii].vSrc.replace(/\$replaceMe/g, word);
+ const fs = src[ii].fSrc.replace(/\$replaceMe/g, word);
+
+ let success = true;
+ const program = wtu.loadProgram(gl, vs, fs, function(msg) {
+ debug(msg);
+ success = false;
+ }, true);
+ if (success) {
+ testPassed(`shader with: '${word}' compiled`);
+ } else {
+ testFailed(`shader with: '${word}' failed to compile`);
+ }
+ if (program) {
+ gl.deleteProgram(program);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no GL errors");
+ }
+ }
+} \ No newline at end of file
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js
new file mode 100644
index 0000000000..792f832451
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js
@@ -0,0 +1,292 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var realRedColor = [255, 0, 0];
+ var realGreenColor = [0, 255, 0];
+ var realBlueColor = [0, 0, 255];
+ var realCyanColor = [0, 255, 255];
+ var redColor = realRedColor;
+ var greenColor = realGreenColor;
+ var blueColor = realBlueColor;
+ var cyanColor = realCyanColor;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking a sub-rectangle of a canvas (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+
+ // The sub-rectangle tests only apply to WebGL 2.0 for the
+ // time being, though the tests for the WebGL 1.0
+ // format/internal format/type combinations are generated into
+ // conformance/textures/.
+ if (wtu.getDefault3DContextVersion() < 2) {
+ debug('Test only applies to WebGL 2.0');
+ finishTest();
+ return;
+ }
+
+ gl = wtu.create3DContext("example", { preserveDrawingBuffer: true });
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.RG:
+ case gl.RG_INTEGER:
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 255, 0];
+ break;
+
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var canvas2d = document.createElement('canvas');
+ runTest(canvas2d, setupSourceCanvas2D, '2D-rendered canvas');
+
+ var canvasWebGL = document.createElement('canvas');
+ runTest(canvasWebGL, setupSourceCanvasWebGL, 'WebGL-rendered canvas');
+
+ finishTest();
+ }
+
+ function fillStyle2D(ctx, color) {
+ ctx.fillStyle = 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')';
+ }
+
+ function setupSourceCanvas2D(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('2d');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+ fillStyle2D(ctx, realRedColor);
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ fillStyle2D(ctx, realGreenColor);
+ ctx.fillRect(halfWidth, 0, width - halfWidth, halfHeight);
+ fillStyle2D(ctx, realBlueColor);
+ ctx.fillRect(0, halfHeight, halfWidth, height - halfHeight);
+ fillStyle2D(ctx, realCyanColor);
+ ctx.fillRect(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ }
+
+ function clearColorWebGL(ctx, color) {
+ ctx.clearColor(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ }
+
+ function setupSourceCanvasWebGL(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('webgl');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+
+ ctx.viewport(0, 0, width, height);
+ ctx.enable(ctx.SCISSOR_TEST);
+ // OpenGL origin is lower-left
+ ctx.scissor(0, 0, halfWidth, halfHeight);
+ clearColorWebGL(ctx, realBlueColor);
+ ctx.scissor(halfWidth, 0, width - halfWidth, halfHeight);
+ clearColorWebGL(ctx, realCyanColor);
+ ctx.scissor(0, halfHeight, halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realRedColor);
+ ctx.scissor(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realGreenColor);
+ }
+
+ function runOneIteration(sourceDescription, useTexSubImage2D, flipY,
+ canvas, canvasSize, canvasSetupFunction,
+ sourceSubRectangle, expected,
+ bindingTarget, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('');
+ debug('Testing ' + sourceDescription + ' with ' +
+ (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ', flipY=' + flipY +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ // Initialize the contents of the source canvas.
+ var width = canvasSize[0];
+ var height = canvasSize[1];
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ canvas.width = width;
+ canvas.height = height;
+ canvasSetupFunction(canvas);
+
+ // Upload the source canvas to the texture and draw it to a quad.
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // In this test, this is always specified. It's currently WebGL 2.0-specific.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ // Upload the image into the texture
+ var uploadWidth = sourceSubRectangle[2];
+ var uploadHeight = sourceSubRectangle[3];
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ uploadWidth, uploadHeight, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ uploadWidth, uploadHeight,
+ gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ uploadWidth, uploadHeight, 0,
+ gl[pixelFormat], gl[pixelType], canvas);
+ }
+ }
+
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+
+ // The tests are constructed to upload a single solid color
+ // out of the canvas.
+ var outputCanvasWidth = gl.drawingBufferWidth;
+ var outputCanvasHeight = gl.drawingBufferHeight;
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ var msg = 'should be ' + expected;
+ wtu.checkCanvasRect(gl, 0, 0, outputCanvasWidth, outputCanvasHeight, expected, msg);
+ }
+ }
+
+ function runTest(canvas, canvasSetupFunction, sourceDescription)
+ {
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_2D, program, canvas, canvasSetupFunction, sourceDescription);
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program, canvas, canvasSetupFunction, sourceDescription);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ }
+
+ function runTestOnBindingTarget(bindingTarget, program, canvas, canvasSetupFunction, sourceDescription) {
+ var cases = [
+ // Small canvas cases. Expected that these won't be
+ // GPU-accelerated in most browsers' implementations.
+ { expected: redColor, flipY: false, size: [2, 2], subRect: [0, 0, 1, 1] },
+ { expected: greenColor, flipY: false, size: [2, 2], subRect: [1, 0, 1, 1] },
+ { expected: blueColor, flipY: false, size: [2, 2], subRect: [0, 1, 1, 1] },
+ { expected: cyanColor, flipY: false, size: [2, 2], subRect: [1, 1, 1, 1] },
+ { expected: redColor, flipY: true, size: [2, 2], subRect: [0, 1, 1, 1] },
+ { expected: greenColor, flipY: true, size: [2, 2], subRect: [1, 1, 1, 1] },
+ { expected: blueColor, flipY: true, size: [2, 2], subRect: [0, 0, 1, 1] },
+ { expected: cyanColor, flipY: true, size: [2, 2], subRect: [1, 0, 1, 1] },
+
+ // Larger canvas cases. Expected that these will be
+ // GPU-accelerated in most browsers' implementations.
+ // Changes will be gladly accepted to trigger more
+ // browsers' heuristics to accelerate these canvases.
+ { expected: redColor, flipY: false, size: [384, 384], subRect: [ 0, 0, 192, 192] },
+ { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192] },
+ { expected: blueColor, flipY: false, size: [384, 384], subRect: [ 0, 192, 192, 192] },
+ { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 192, 192, 192] },
+ { expected: blueColor, flipY: true, size: [384, 384], subRect: [ 0, 0, 192, 192] },
+ { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192] },
+ { expected: redColor, flipY: true, size: [384, 384], subRect: [ 0, 192, 192, 192] },
+ { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 192, 192, 192] },
+
+ ];
+
+ for (var i in cases) {
+ runOneIteration(sourceDescription, false, cases[i].flipY,
+ canvas, cases[i].size, canvasSetupFunction,
+ cases[i].subRect,
+ cases[i].expected, bindingTarget, program);
+ runOneIteration(sourceDescription, true, cases[i].flipY,
+ canvas, cases[i].size, canvasSetupFunction,
+ cases[i].subRect,
+ cases[i].expected, bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js
new file mode 100644
index 0000000000..a96eeb9de0
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js
@@ -0,0 +1,468 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var whiteColor = [255, 255, 255, 255];
+ var redColor = [255, 0, 0, 255];
+ var greenColor = [0, 255, 0, 255];
+ var semiTransparentRedColor = [127, 0, 0, 127];
+ var semiTransparentGreenColor = [0, 127, 0, 127];
+ var repeatCount;
+
+ function replicateRedChannel(color)
+ {
+ color[1] = color[0];
+ color[2] = color[0];
+ }
+
+ function zapColorChannels(color)
+ {
+ color[0] = 0;
+ color[1] = 0;
+ color[2] = 0;
+ }
+
+ function setAlphaChannelTo1(color)
+ {
+ color[3] = 255;
+ }
+
+ function replicateAllRedChannels()
+ {
+ replicateRedChannel(redColor);
+ replicateRedChannel(semiTransparentRedColor);
+ replicateRedChannel(greenColor);
+ replicateRedChannel(semiTransparentGreenColor);
+ }
+
+ function setAllAlphaChannelsTo1()
+ {
+ setAlphaChannelTo1(redColor);
+ setAlphaChannelTo1(semiTransparentRedColor);
+ setAlphaChannelTo1(greenColor);
+ setAlphaChannelTo1(semiTransparentGreenColor);
+ }
+
+ function repeatCountForTextureFormat(internalFormat, pixelFormat, pixelType)
+ {
+ // There were bugs in early WebGL 1.0 implementations when repeatedly uploading canvas
+ // elements into textures. In response, this test was changed into a regression test by
+ // repeating all of the cases multiple times. Unfortunately, this means that adding a new
+ // case above significantly increases the run time of the test suite. The problem is made
+ // even worse by the addition of many more texture formats in WebGL 2.0.
+ //
+ // Doing repeated runs with just a couple of WebGL 1.0's supported texture formats acts as a
+ // sufficient regression test for the old bugs. For this reason the test has been changed to
+ // only repeat for those texture formats.
+ if ((internalFormat == 'RGBA' && pixelFormat == 'RGBA' && pixelType == 'UNSIGNED_BYTE') ||
+ (internalFormat == 'RGB' && pixelFormat == 'RGB' && pixelType == 'UNSIGNED_BYTE')) {
+ return 4;
+ }
+
+ return 1;
+ }
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ repeatCount = repeatCountForTextureFormat(internalFormat, pixelFormat, pixelType);
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ // Zap green and blue channels.
+ whiteColor[1] = 0;
+ whiteColor[2] = 0;
+ greenColor[1] = 0;
+ semiTransparentGreenColor[1] = 0;
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ case gl.RG:
+ case gl.RG_INTEGER:
+ // Zap blue channel.
+ whiteColor[2] = 0;
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ case gl.LUMINANCE:
+ // Replicate red channels.
+ replicateAllRedChannels();
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ case gl.ALPHA:
+ // Red, green and blue channels are all 0.0.
+ zapColorChannels(redColor);
+ zapColorChannels(semiTransparentRedColor);
+ zapColorChannels(greenColor);
+ zapColorChannels(semiTransparentGreenColor);
+ zapColorChannels(whiteColor);
+ break;
+ case gl.LUMINANCE_ALPHA:
+ // Replicate red channels.
+ replicateAllRedChannels();
+ break;
+ case gl.RGB:
+ case gl.RGB_INTEGER:
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ default:
+ break;
+ }
+
+ switch (gl[internalFormat]) {
+ case gl.SRGB8:
+ case gl.SRGB8_ALPHA8:
+ semiTransparentRedColor = wtu.sRGBToLinear(semiTransparentRedColor);
+ semiTransparentGreenColor = wtu.sRGBToLinear(semiTransparentGreenColor);
+ break;
+ case gl.RGBA8UI:
+ // For int and uint textures, TexImageUtils outputs the maximum value (in this case,
+ // 255) for the alpha channel all the time because of differences in behavior when
+ // sampling integer textures with and without alpha channels. Since changing this
+ // behavior may have large impact across the test suite, leave it as is for now.
+ setAllAlphaChannelsTo1();
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.clearRect(0, 0, width, height);
+ ctx.fillStyle = "#ff0000";
+ ctx.fillRect(0, 0, width, halfHeight);
+ ctx.fillStyle = "#00ff00";
+ ctx.fillRect(0, halfHeight, width, height - halfHeight);
+ }
+
+ function setCanvasToSemiTransparentRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.clearRect(0, 0, width, height);
+ ctx.fillStyle = "rgba(127, 0, 0, 0.5)";
+ ctx.fillRect(0, 0, width, halfHeight);
+ ctx.fillStyle = "rgba(0, 127, 0, 0.5)";
+ ctx.fillRect(0, halfHeight, width, height - halfHeight);
+ }
+
+ function drawTextInCanvas(ctx, bindingTarget) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ ctx.fillStyle = "#ffffff";
+ ctx.fillRect(0, 0, width, height);
+ ctx.font = '20pt Arial';
+ ctx.fillStyle = 'black';
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText("1234567890", width / 2, height / 4);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasTo257x257SemiTransparent(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToSemiTransparentRedGreen(ctx);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasToMinSemiTransparent(ctx, bindingTarget) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToSemiTransparentRedGreen(ctx);
+ }
+
+ function runOneIteration(canvas, useTexSubImage2D, flipY, semiTransparent, program, bindingTarget, opt_texture, opt_fontTest)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ ' canvas size: ' + canvas.width + 'x' + canvas.height +
+ ' source object type: ' + objType +
+ (opt_fontTest ? " with fonts" : " with" + (semiTransparent ? " semi-transparent" : "") + " red-green"));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], canvas.width, canvas.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], canvas);
+ }
+ }
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? 0 : (height - halfHeight);
+ var bottom = flipY ? (height - halfHeight) : 0;
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ if (opt_fontTest) {
+ // check half is a solid color.
+ wtu.checkCanvasRect(
+ gl, 0, top, width, halfHeight,
+ whiteColor,
+ "should be white");
+ // check other half is not a solid color.
+ wtu.checkCanvasRectColor(
+ gl, 0, bottom, width, halfHeight,
+ whiteColor, 0,
+ function() {
+ testFailed("font missing");
+ },
+ function() {
+ testPassed("font rendered");
+ },
+ debug);
+ } else {
+ var localRed = semiTransparent ? semiTransparentRedColor : redColor;
+ var localGreen = semiTransparent ? semiTransparentGreenColor : greenColor;
+
+ // Allow a tolerance for premultiplication/unmultiplication, especially for texture
+ // formats with lower bit depths.
+ var tolerance = 0;
+ if (semiTransparent) {
+ tolerance = 3;
+ if (pixelType == 'UNSIGNED_SHORT_5_6_5' || internalFormat == 'RGB565') {
+ tolerance = 6;
+ } else if (pixelType == 'UNSIGNED_SHORT_4_4_4_4' || internalFormat == 'RGBA4') {
+ tolerance = 9;
+ } else if (pixelType == 'UNSIGNED_SHORT_5_5_5_1' || internalFormat == 'RGB5_A1') {
+ // Semi-transparent values are allowed to convert to either 1 or 0 for this
+ // single-bit alpha format per OpenGL ES 3.0.5 section 2.1.6.2, "Conversion
+ // from Floating-Point to Normalized Fixed-Point". Ignore alpha for these
+ // tests.
+ tolerance = 6;
+ localRed = localRed.slice(0, 3);
+ localGreen = localGreen.slice(0, 3);
+ } else if (internalFormat == 'RGB10_A2') {
+ // The alpha channel is too low-resolution for any meaningful comparisons.
+ localRed = localRed.slice(0, 3);
+ localGreen = localGreen.slice(0, 3);
+ }
+ }
+
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, localRed,
+ "shouldBe " + localRed, tolerance);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, localGreen,
+ "shouldBe " + localGreen, tolerance);
+ }
+
+ if (!useTexSubImage2D && pixelFormat == "RGBA") {
+ if (pixelType == "FLOAT") {
+ // Attempt to set a pixel in the texture to ensure the texture was
+ // actually created with floats. Regression test for http://crbug.com/484968
+ var pixels = new Float32Array([1000.0, 1000.0, 1000.0, 1000.0]);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, 1, 1, gl[pixelFormat], gl[pixelType], pixels);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Texture should be backed by floats");
+ } else if (pixelType == "HALF_FLOAT_OES" || pixelType == "HALF_FLOAT") {
+ // Attempt to set a pixel in the texture to ensure the texture was
+ // actually created with half-floats. Regression test for http://crbug.com/484968
+ var halfFloatTenK = 0x70E2; // Half float 10000
+ var pixels = new Uint16Array([halfFloatTenK, halfFloatTenK, halfFloatTenK, halfFloatTenK]);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, 1, 1, gl[pixelFormat], gl[pixelType], pixels);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Texture should be backed by half-floats");
+ }
+ }
+ }
+
+ if (false) {
+ var m = wtu.makeImageFromCanvas(gl.canvas);
+ document.getElementById("console").appendChild(m);
+ document.getElementById("console").appendChild(document.createElement("hr"));
+ }
+
+ return texture;
+ }
+
+ function runTest()
+ {
+ var canvas = document.createElement('canvas');
+
+ var cases = [
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: false, font: false, init: setCanvasToMin },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: true, font: false, init: setCanvasToMinSemiTransparent },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: true, font: false },
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: false, font: false, init: setCanvasTo257x257 },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: true, font: false, init: setCanvasTo257x257SemiTransparent },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: true, font: false },
+ ];
+
+ // The font tests don't work with ALPHA-only textures since they draw to the color channels.
+ if (internalFormat != 'ALPHA') {
+ cases = cases.concat([
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: false, font: true, init: drawTextInCanvas },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: false, font: true },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: false, font: true },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: false, font: true },
+ ]);
+ }
+
+ if (window.OffscreenCanvas) {
+ var offscreenCanvas = new OffscreenCanvas(1, 1);
+ cases = cases.concat([
+ { canvas: offscreenCanvas, sub: false, flipY: true, semiTransparent: false, font: false, init: setCanvasToMin },
+ { canvas: offscreenCanvas, sub: false, flipY: false, semiTransparent: false, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: true, semiTransparent: false, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: false, semiTransparent: false, font: false },
+ { canvas: offscreenCanvas, sub: false, flipY: true, semiTransparent: true, font: false, init: setCanvasToMinSemiTransparent },
+ { canvas: offscreenCanvas, sub: false, flipY: false, semiTransparent: true, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: true, semiTransparent: true, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: false, semiTransparent: true, font: false },
+ ]);
+ }
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var count = repeatCount;
+ var caseNdx = 0;
+ var texture = undefined;
+ function runNextTest() {
+ var c = cases[caseNdx];
+ var imageDataBefore = null;
+ if (c.init) {
+ c.init(c.canvas.getContext('2d'), bindingTarget);
+ }
+ texture = runOneIteration(c.canvas, c.sub, c.flipY, c.semiTransparent, program, bindingTarget, texture, c.font);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count) {
+ resolve("SUCCESS");
+ return;
+ }
+ }
+ // While we are working with Canvases, it's really unlikely that
+ // waiting for composition will change anything here, and it's much
+ // slower, so just dispatchPromise. If we want to test with composites,
+ // we should test a more narrow subset of tests.
+ wtu.dispatchPromise(runNextTest);
+ }
+ runNextTest();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_2D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_CUBE_MAP).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js
new file mode 100644
index 0000000000..f434b9834c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js
@@ -0,0 +1,49 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ async function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from a Blob (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ debug('*** Running tests against red-green-semi-transparent.png ***');
+ let response = await fetch(resourcePath + "red-green-semi-transparent.png");
+ let blob = await response.blob();
+ await runImageBitmapTest(blob, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ debug('*** Running tests against red-green-128x128-linear-profile.jpg ***');
+ response = await fetch(resourcePath + "red-green-128x128-linear-profile.jpg");
+ blob = await response.blob();
+ // This test requires a huge tolerance because browsers - at least currently - vary
+ // widely in the colorspace conversion results for this image.
+ let tolerance = 120;
+ await runImageBitmapTest(blob, 1.0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false, tolerance);
+ finishTest();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js
new file mode 100644
index 0000000000..08ee96c0a1
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js
@@ -0,0 +1,74 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an HTMLCanvasElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var testCanvas = document.createElement('canvas');
+ var ctx = testCanvas.getContext("2d");
+ setCanvasToMin(ctx);
+ runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false)
+ .then(() => {
+ setCanvasTo257x257(ctx);
+ return runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.fillStyle = "rgba(255, 0, 0, 1)";
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
+ ctx.fillRect(halfWidth, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 1)";
+ ctx.fillRect(0, halfHeight, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 0.5)";
+ ctx.fillRect(halfWidth, halfHeight, halfWidth, halfHeight);
+ }
+
+ function setCanvasToMin(ctx) {
+ ctx.canvas.width = 2;
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasTo257x257(ctx) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js
new file mode 100644
index 0000000000..09821d8b3f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an ImageBitmap (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ createImageBitmap(imageData, {imageOrientation: "none", premultiplyAlpha: "none"})
+ .catch( () => {
+ testPassed("createImageBitmap with options may be rejected if it is not supported. Retrying without options.");
+ return createImageBitmap(imageData);
+ }).then( bitmap => {
+ return runImageBitmapTest(bitmap, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ }, () => {
+ testFailed("createImageBitmap(imageData) should succeed.");
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js
new file mode 100644
index 0000000000..dd24721fe4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js
@@ -0,0 +1,49 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ runImageBitmapTest(imageData, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false)
+ .then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js
new file mode 100644
index 0000000000..1e4b18129e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an HTMLImageElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var image = new Image();
+ image.onload = function() {
+ bufferedLogToConsole("Source image has been loaded");
+ runImageBitmapTest(image, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false)
+ .then(() => {
+ finishTest();
+ });
+ }
+ image.src = resourcePath + "red-green-semi-transparent.png";
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js
new file mode 100644
index 0000000000..14cf4628be
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js
@@ -0,0 +1,83 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an HTMLVideoElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ finishTest();
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, async function() {
+ await runImageBitmapTest(video, 1, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ runNextVideo();
+ });
+ }
+ runNextVideo();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js
new file mode 100644
index 0000000000..8486b0b659
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js
@@ -0,0 +1,240 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imageData = null;
+ var blackColor = [0, 0, 0];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var canvas2d = document.getElementById("texcanvas");
+ var context2d = canvas2d.getContext("2d");
+ imageData = context2d.createImageData(2, 2);
+ var data = imageData.data;
+ data[0] = 255;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 255;
+ data[4] = 255;
+ data[5] = 0;
+ data[6] = 0;
+ data[7] = 0;
+ data[8] = 0;
+ data[9] = 255;
+ data[10] = 0;
+ data[11] = 255;
+ data[12] = 0;
+ data[13] = 255;
+ data[14] = 0;
+ data[15] = 0;
+
+ runTest();
+ }
+
+ function runOneIteration(useTexSubImage2D, flipY, premultiplyAlpha,
+ sourceSubRectangle, expected,
+ bindingTarget, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('');
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' and premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], imageData);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], imageData);
+ }
+ } else {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], imageData.width, imageData.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], imageData);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], imageData);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ var top = 0;
+ var bottom = height - halfHeight;
+ var left = 0;
+ var right = width - halfWidth;
+
+ var tl, tr, bl, br;
+ if (expected.length == 1) {
+ tl = tr = bl = br = expected[0];
+ } else {
+ tl = expected[0];
+ tr = expected[1];
+ bl = expected[2];
+ br = expected[3];
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ // Check the top pixel and bottom pixel and make sure they have
+ // the right color.
+ wtu.checkCanvasRect(gl, left, top, halfWidth, halfHeight, tl, "shouldBe " + tl);
+ wtu.checkCanvasRect(gl, right, top, halfWidth, halfHeight, tr, "shouldBe " + tr);
+ wtu.checkCanvasRect(gl, left, bottom, halfWidth, halfHeight, bl, "shouldBe " + bl);
+ wtu.checkCanvasRect(gl, right, bottom, halfWidth, halfHeight, br, "shouldBe " + br);
+ }
+ }
+
+ function runTest()
+ {
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_2D, program);
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function runTestOnBindingTarget(bindingTarget, program) {
+ var k = blackColor;
+ var r = redColor;
+ var g = greenColor;
+ var cases = [
+ { expected: [r, r, g, g], flipY: false, premultiplyAlpha: false, sub: false },
+ { expected: [r, r, g, g], flipY: false, premultiplyAlpha: false, sub: true },
+ { expected: [r, k, g, k], flipY: false, premultiplyAlpha: true, sub: false },
+ { expected: [r, k, g, k], flipY: false, premultiplyAlpha: true, sub: true },
+ { expected: [g, g, r, r], flipY: true, premultiplyAlpha: false, sub: false },
+ { expected: [g, g, r, r], flipY: true, premultiplyAlpha: false, sub: true },
+ { expected: [g, k, r, k], flipY: true, premultiplyAlpha: true, sub: false },
+ { expected: [g, k, r, k], flipY: true, premultiplyAlpha: true, sub: true },
+ ];
+
+ if (wtu.getDefault3DContextVersion() > 1) {
+ var morecases = [];
+ // Make 2 copies of the original case: top left and bottom right 1x1 rectangles
+ for (var i = 0; i < cases.length; i++) {
+ for (var subX = 0; subX <= 1; subX++) {
+ var subY = subX == 0 ? 1 : 0;
+ // shallow-copy cases[i] into newcase
+ var newcase = Object.assign({}, cases[i]);
+ newcase.expected = [cases[i].expected[subY * 2 + subX]];
+ newcase.sourceSubRectangle = [subX, subY, 1, 1];
+ morecases.push(newcase);
+ }
+ }
+ cases = cases.concat(morecases);
+ }
+
+ for (var i in cases) {
+ runOneIteration(cases[i].sub, cases[i].flipY, cases[i].premultiplyAlpha,
+ cases[i].sourceSubRectangle, cases[i].expected,
+ bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js
new file mode 100644
index 0000000000..f3802ba777
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js
@@ -0,0 +1,257 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadTexture(gl, resourcePath + "red-green.png", runTest);
+ }
+
+ function runOneIteration(image, useTexSubImage2D, flipY, topColor, bottomColor,
+ sourceSubRectangle, bindingTarget, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with ' + image.width + 'x' + image.height + ' flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], image);
+ }
+ } else {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], image.width, image.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], image);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+ }
+
+ function runTestOnImage(image) {
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+
+
+ if (wtu.getDefault3DContextVersion() > 1) {
+ cases = cases.concat([
+ { sub: false, flipY: false, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: false, flipY: true, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ { sub: false, flipY: true, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ { sub: true, flipY: false, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: true, flipY: true, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ ]);
+ }
+
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ cases[i].sourceSubRectangle,
+ gl.TEXTURE_2D, program);
+ }
+ // cube map texture must be square.
+ if (image.width != image.height)
+ return;
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ for (var i in cases) {
+ if (!cases[i].sourceSubRectangle) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ undefined,
+ gl.TEXTURE_CUBE_MAP, program);
+ }
+ }
+ }
+
+ function runTest(image)
+ {
+ runTestOnImage(image);
+
+ imgCanvas = document.createElement("canvas");
+ imgCanvas.width = 2;
+ imgCanvas.height = 2;
+ var imgCtx = imgCanvas.getContext("2d");
+ var imgData = imgCtx.createImageData(2, 2);
+ imgData.data[0] = redColor[0];
+ imgData.data[1] = redColor[1];
+ imgData.data[2] = redColor[2];
+ imgData.data[3] = 255;
+ imgData.data[4] = redColor[0];
+ imgData.data[5] = redColor[1];
+ imgData.data[6] = redColor[2];
+ imgData.data[7] = 255;
+ imgData.data[8] = greenColor[0];
+ imgData.data[9] = greenColor[1];
+ imgData.data[10] = greenColor[2];
+ imgData.data[11] = 255;
+ imgData.data[12] = greenColor[0];
+ imgData.data[13] = greenColor[1];
+ imgData.data[14] = greenColor[2];
+ imgData.data[15] = 255;
+ imgCtx.putImageData(imgData, 0, 0);
+
+ // apparently Image is different than <img>.
+ var newImage = new Image();
+ newImage.onload = function() {
+ runTest2(newImage);
+ };
+ newImage.onerror = function() {
+ testFailed("Creating image from canvas failed. Image src: " + this.src);
+ finishTest();
+ };
+ newImage.src = imgCanvas.toDataURL();
+ }
+
+ function runTest2(image) {
+ runTestOnImage(image);
+
+ wtu.makeImageFromCanvas(imgCanvas, function() {
+ runTest3(this);
+ });
+ }
+
+ function runTest3(image) {
+ runTestOnImage(image);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js
new file mode 100644
index 0000000000..5cc6a8283e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js
@@ -0,0 +1,140 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking SVG image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadTexture(gl, resourcePath + "red-green.svg", runTest);
+ }
+
+ function runOneIteration(image, useTexSubImage2D, flipY, topColor, bottomColor, bindingTarget, program)
+ {
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP'));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], image.width, image.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], image);
+ }
+ }
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+ }
+
+ function runTest(image)
+ {
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_2D, program);
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_CUBE_MAP, program);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function runTestOnBindingTarget(image, bindingTarget, program) {
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js
new file mode 100644
index 0000000000..6e8bcf96e9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js
@@ -0,0 +1,291 @@
+/*
+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.
+*/
+
+// This block needs to be outside the onload handler in order for this
+// test to run reliably in WebKit's test harness (at least the
+// Chromium port). https://bugs.webkit.org/show_bug.cgi?id=87448
+initTestingHarness();
+
+var old = debug;
+var debug = function(msg) {
+ bufferedLogToConsole(msg);
+ old(msg);
+};
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ // Test each format separately because many browsers implement each
+ // differently. Some might be GPU accelerated, some might not. Etc...
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking video elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function runOneIteration(videoElement, unpackColorSpace, useTexSubImage2D, flipY, topColorName, bottomColorName, sourceSubRectangle, program, bindingTarget)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ unpackColorSpaceString = '';
+ if (unpackColorSpace) {
+ unpackColorSpaceString = ' unpackColorSpace=' + unpackColorSpace;
+ }
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString + unpackColorSpaceString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle target color space.
+ if (unpackColorSpace) {
+ gl.unpackColorSpace = unpackColorSpace;
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the videoElement into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ continue;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ } else {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ var width = videoElement.videoWidth;
+ var height = videoElement.videoHeight;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ width = Math.max(width, height);
+ height = width;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ width, height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var c = document.createElement("canvas");
+ c.width = 16;
+ c.height = 16;
+ c.style.border = "1px solid black";
+ var ctx = c.getContext("2d");
+ ctx.drawImage(videoElement, 0, 0, 16, 16);
+ document.body.appendChild(c);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ // Compute the test colors. This test only tests RGB (not A).
+ const topColor = wtu.colorAsSampledWithInternalFormat(
+ wtu.namedColorInColorSpace(topColorName, unpackColorSpace),
+ internalFormat).slice(0, 3);
+ const bottomColor = wtu.colorAsSampledWithInternalFormat(
+ wtu.namedColorInColorSpace(bottomColorName, unpackColorSpace),
+ internalFormat).slice(0, 3);
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ const tolerance = Math.max(6, tiu.tolerance(internalFormat, pixelFormat, pixelType));
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+ }
+ }
+
+ function runTest(videoElement)
+ {
+ var cases = [
+ { sub: false, flipY: true, topColor: 'Red', bottomColor: 'Green' },
+ { sub: false, flipY: false, topColor: 'Green', bottomColor: 'Red' },
+ { sub: true, flipY: true, topColor: 'Red', bottomColor: 'Green' },
+ { sub: true, flipY: false, topColor: 'Green', bottomColor: 'Red' },
+ ];
+
+ if (wtu.getDefault3DContextVersion() > 1) {
+ cases = cases.concat([
+ { sub: false, flipY: false, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: false, flipY: true, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: false, flipY: false, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ { sub: false, flipY: true, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ { sub: true, flipY: false, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: true, flipY: true, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: true, flipY: false, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ { sub: true, flipY: true, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ ]);
+ }
+
+ cases = tiu.crossProductTestCasesWithUnpackColorSpaces(
+ cases, tiu.unpackColorSpacesToTest(gl));
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ resolve("SUCCESS");
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, runTest);
+ }
+ function runTest() {
+ for (var i in cases) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // Cube map texture must be square but video is not square.
+ if (!cases[i].sub) {
+ break;
+ }
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (cases[i].sourceSubRectangle) {
+ break;
+ }
+ }
+ runOneIteration(video, cases[i].unpackColorSpace, cases[i].sub, cases[i].flipY,
+ cases[i].topColor,
+ cases[i].bottomColor,
+ cases[i].sourceSubRectangle,
+ program, bindingTarget);
+ }
+ runNextVideo();
+ }
+ runNextVideo();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_2D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_CUBE_MAP).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js
new file mode 100644
index 0000000000..acb8768051
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js
@@ -0,0 +1,298 @@
+/*
+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.
+*/
+
+"use strict";
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0, 255];
+ var greenColor = [0, 255, 0, 255];
+ var repeatCount;
+
+ function shouldRepeatTestForTextureFormat(internalFormat, pixelFormat, pixelType)
+ {
+ // There were bugs in early WebGL 1.0 implementations when repeatedly uploading canvas
+ // elements into textures. In response, this test was changed into a regression test by
+ // repeating all of the cases multiple times. Unfortunately, this means that adding a new
+ // case above significantly increases the run time of the test suite. The problem is made
+ // even worse by the addition of many more texture formats in WebGL 2.0.
+ //
+ // Doing repeated runs with just a couple of WebGL 1.0's supported texture formats acts as a
+ // sufficient regression test for the old bugs. For this reason the test has been changed to
+ // only repeat for those texture formats.
+ return ((internalFormat == 'RGBA' && pixelFormat == 'RGBA' && pixelType == 'UNSIGNED_BYTE') ||
+ (internalFormat == 'RGB' && pixelFormat == 'RGB' && pixelType == 'UNSIGNED_BYTE'));
+ }
+
+ async function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking webgl canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ return;
+ }
+
+ repeatCount = (shouldRepeatTestForTextureFormat(internalFormat, pixelFormat, pixelType) ? 4 : 1);
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ await runTest();
+ }
+
+ function setCanvasToRedGreen(ctx, hasAlpha) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ ctx.viewport(0, 0, width, height);
+
+ ctx.enable(ctx.SCISSOR_TEST);
+ ctx.scissor(0, 0, width, halfHeight);
+ if (hasAlpha) {
+ ctx.clearColor(1.0, 0, 0, 1.0);
+ } else {
+ // The WebGL implementation is responsible for making all
+ // alpha values appear as though they were 1.0.
+ ctx.clearColor(1.0, 0, 0, 0.0);
+ }
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.scissor(0, halfHeight, width, height - halfHeight);
+ if (hasAlpha) {
+ ctx.clearColor(0.0, 1.0, 0, 1.0);
+ } else {
+ // The WebGL implementation is responsible for making all
+ // alpha values appear as though they were 1.0.
+ ctx.clearColor(0.0, 1.0, 0, 0.0);
+ }
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.disable(ctx.SCISSOR_TEST);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget, hasAlpha) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx, hasAlpha);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget, hasAlpha) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx, hasAlpha);
+ }
+
+ function runOneIteration(canvas, useTexSubImage2D, alpha, flipY, program, bindingTarget, opt_texture)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ else if (canvas.parentNode)
+ objType = 'canvas attached to DOM';
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') + ' with alpha=' +
+ alpha + ' flipY=' + flipY + ' source object: ' + objType +
+ ' bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ ' canvas size: ' + canvas.width + 'x' + canvas.height + ' with red-green');
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors before pixelStorei setup");
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_FLIP_Y_WEBGL");
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_PREMULTIPLY_ALPHA_WEBGL");
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_COLORSPACE_CONVERSION_WEBGL");
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], canvas.width, canvas.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], canvas);
+ }
+ }
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? (height - halfHeight) : 0;
+ var bottom = flipY ? 0 : (height - halfHeight);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, redColor,
+ "shouldBe " + redColor);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, greenColor,
+ "shouldBe " + greenColor);
+ }
+
+ if (false) {
+ var ma = wtu.makeImageFromCanvas(canvas);
+ document.getElementById("console").appendChild(ma);
+
+ var m = wtu.makeImageFromCanvas(gl.canvas);
+ document.getElementById("console").appendChild(m);
+ document.getElementById("console").appendChild(document.createElement("hr"));
+ }
+
+ return texture;
+ }
+
+ async function runTest()
+ {
+ for (let alpha of [ true, false ]) {
+ let ctx = wtu.create3DContext(null, { alpha:alpha });
+ let canvas = ctx.canvas;
+ // Note: We use preserveDrawingBuffer:true to prevent canvas
+ // visibility from interfering with the tests.
+ let visibleCtx = wtu.create3DContext(null, { preserveDrawingBuffer:true, alpha:alpha });
+ if (!visibleCtx) {
+ testFailed("context does not exist");
+ return;
+ }
+ let visibleCanvas = visibleCtx.canvas;
+ let descriptionNode = document.getElementById("description");
+ document.body.insertBefore(visibleCanvas, descriptionNode);
+
+ let cases = [
+ { sub: false, flipY: true, ctx: ctx, init: setCanvasToMin },
+ { sub: false, flipY: false, ctx: ctx },
+ { sub: true, flipY: true, ctx: ctx },
+ { sub: true, flipY: false, ctx: ctx },
+ { sub: false, flipY: true, ctx: ctx, init: setCanvasTo257x257 },
+ { sub: false, flipY: false, ctx: ctx },
+ { sub: true, flipY: true, ctx: ctx },
+ { sub: true, flipY: false, ctx: ctx },
+ { sub: false, flipY: true, ctx: visibleCtx, init: setCanvasToMin },
+ { sub: false, flipY: false, ctx: visibleCtx },
+ { sub: true, flipY: true, ctx: visibleCtx },
+ { sub: true, flipY: false, ctx: visibleCtx },
+ ];
+
+ if (window.OffscreenCanvas) {
+ let offscreen = new OffscreenCanvas(1, 1);
+ let offscreenCtx = wtu.create3DContext(offscreen, { alpha:alpha });
+ cases = cases.concat([
+ { sub: false, flipY: true, ctx: offscreenCtx, init: setCanvasToMin },
+ { sub: false, flipY: false, ctx: offscreenCtx },
+ { sub: true, flipY: true, ctx: offscreenCtx },
+ { sub: true, flipY: false, ctx: offscreenCtx },
+ ]);
+ }
+
+ async function runTexImageTest(bindingTarget) {
+ let program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ let count = repeatCount;
+ let caseNdx = 0;
+ let texture = undefined;
+ while (true) {
+ let c = cases[caseNdx];
+ if (c.init) {
+ c.init(c.ctx, bindingTarget, alpha);
+ }
+ texture = runOneIteration(c.ctx.canvas, c.sub, alpha, c.flipY, program, bindingTarget, texture);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count)
+ return;
+ }
+ await wtu.dispatchPromise(function() {});
+ }
+ }
+
+ await runTexImageTest(gl.TEXTURE_2D);
+ await runTexImageTest(gl.TEXTURE_CUBE_MAP);
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ }
+
+ return function() {
+ init().then(function(val) {
+ finishTest();
+ });
+ };
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js
new file mode 100644
index 0000000000..85f763a0de
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js
@@ -0,0 +1,287 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var realRedColor = [255, 0, 0];
+ var realGreenColor = [0, 255, 0];
+ var realBlueColor = [0, 0, 255];
+ var realCyanColor = [0, 255, 255];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blueColor = [0, 0, 255];
+ var cyanColor = [0, 255, 255];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking a sub-rectangle of a canvas (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.RG:
+ case gl.RG_INTEGER:
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 255, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var canvas2d = document.createElement('canvas');
+ runTest(canvas2d, setupSourceCanvas2D, '2D-rendered canvas');
+
+ var canvasWebGL = document.createElement('canvas');
+ runTest(canvasWebGL, setupSourceCanvasWebGL, 'WebGL-rendered canvas');
+
+ finishTest();
+ }
+
+ function uploadCanvasToTexture(canvas, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight)
+ {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = canvas.width;
+ var uploadHeight = canvas.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ if (unpackImageHeight) {
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight);
+ }
+ // Upload the image into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], canvas);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload");
+ }
+
+ function fillStyle2D(ctx, color) {
+ ctx.fillStyle = 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')';
+ }
+
+ function setupSourceCanvas2D(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('2d');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+ fillStyle2D(ctx, realRedColor);
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ fillStyle2D(ctx, realGreenColor);
+ ctx.fillRect(halfWidth, 0, width - halfWidth, halfHeight);
+ fillStyle2D(ctx, realBlueColor);
+ ctx.fillRect(0, halfHeight, halfWidth, height - halfHeight);
+ fillStyle2D(ctx, realCyanColor);
+ ctx.fillRect(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ }
+
+ function clearColorWebGL(ctx, color) {
+ ctx.clearColor(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ }
+
+ function setupSourceCanvasWebGL(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('webgl');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+
+ ctx.viewport(0, 0, width, height);
+ ctx.enable(ctx.SCISSOR_TEST);
+ // OpenGL origin is lower-left
+ ctx.scissor(0, 0, halfWidth, halfHeight);
+ clearColorWebGL(ctx, realBlueColor);
+ ctx.scissor(halfWidth, 0, width - halfWidth, halfHeight);
+ clearColorWebGL(ctx, realCyanColor);
+ ctx.scissor(0, halfHeight, halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realRedColor);
+ ctx.scissor(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realGreenColor);
+ }
+
+ function runOneIteration(canvas, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight,
+ rTextureCoord, expectedColor, program,
+ canvasSize, canvasSetupFunction, sourceDescription)
+ {
+ debug('');
+ debug('Testing ' + sourceDescription + ' with ' +
+ (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ', flipY=' + flipY + ', bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ ', sourceSubRectangle=' + sourceSubRectangle +
+ ', depth=' + depth +
+ (unpackImageHeight ? ', unpackImageHeight=' + unpackImageHeight : '') +
+ ', rTextureCoord=' + rTextureCoord);
+
+ // Initialize the contents of the source canvas.
+ var width = canvasSize[0];
+ var height = canvasSize[1];
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ canvas.width = width;
+ canvas.height = height;
+ canvasSetupFunction(canvas);
+
+ uploadCanvasToTexture(canvas, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight);
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed('Shader incorrectly set up; couldn\'t find uRCoord uniform');
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTextureCoord);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check the rendered canvas
+ wtu.checkCanvasRect(gl, 0, 0, canvasSize[0], canvasSize[1], expectedColor, "shouldBe " + expectedColor);
+ }
+
+ function runTest(canvas, canvasSetupFunction, sourceDescription)
+ {
+ var cases = [
+ // Small canvas cases. Expected that these won't be
+ // GPU-accelerated in most browsers' implementations.
+
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { expected: redColor, flipY: false, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { expected: redColor, flipY: false, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+
+ // Larger canvas cases. Expected that these will be
+ // GPU-accelerated in most browsers' implementations.
+ // Changes will be gladly accepted to trigger more
+ // browsers' heuristics to accelerate these canvases.
+
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { expected: redColor, flipY: false, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { expected: redColor, flipY: false, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ ];
+
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(canvas, false, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ runOneIteration(canvas, true, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ }
+
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(canvas, false, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ runOneIteration(canvas, true, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js
new file mode 100644
index 0000000000..c41cc4e897
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js
@@ -0,0 +1,226 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var whiteColor = [255, 255, 255, 255];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ whiteColor = [255, 0, 0, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.RG:
+ case gl.RG_INTEGER:
+ whiteColor = [255, 255, 0, 255];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.fillStyle = "#ff0000";
+ ctx.fillRect(0, 0, width, halfHeight);
+ ctx.fillStyle = "#00ff00";
+ ctx.fillRect(0, halfHeight, width, height - halfHeight);
+ }
+
+ function drawTextInCanvas(ctx, bindingTarget) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ ctx.fillStyle = "#ffffff";
+ ctx.fillRect(0, 0, width, height);
+ ctx.font = '20pt Arial';
+ ctx.fillStyle = 'black';
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText("1234567890", width / 2, height / 4);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function runOneIteration(canvas, flipY, program, bindingTarget, opt_texture, opt_fontTest)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ debug('Testing ' + ' with flipY=' + flipY + ' bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ ' source object: ' + objType + ' canvas size: ' + canvas.width + 'x' + canvas.height + (opt_fontTest ? " with fonts" : " with red-green"));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], canvas.width, canvas.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, canvas.width, canvas.height, 1 /* depth */,
+ gl[pixelFormat], gl[pixelType], canvas);
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? 0 : (height - halfHeight);
+ var bottom = flipY ? (height - halfHeight) : 0;
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ if (opt_fontTest) {
+ // check half is a solid color.
+ wtu.checkCanvasRect(
+ gl, 0, top, width, halfHeight,
+ whiteColor,
+ "should be white");
+ // check other half is not a solid color.
+ wtu.checkCanvasRectColor(
+ gl, 0, bottom, width, halfHeight,
+ whiteColor, 0,
+ function() {
+ testFailed("font missing");
+ },
+ function() {
+ testPassed("font renderered");
+ },
+ debug);
+ } else {
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, redColor,
+ "shouldBe " + redColor);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, greenColor,
+ "shouldBe " + greenColor);
+ }
+
+ return texture;
+ }
+
+ function runTest(canvas)
+ {
+ var canvas = document.createElement('canvas');
+
+ var cases = [
+ { canvas: canvas, flipY: true, font: false, init: setCanvasToMin },
+ { canvas: canvas, flipY: false, font: false },
+ { canvas: canvas, flipY: true, font: false, init: setCanvasTo257x257 },
+ { canvas: canvas, flipY: false, font: false },
+ { canvas: canvas, flipY: true, font: true, init: drawTextInCanvas },
+ { canvas: canvas, flipY: false, font: true },
+ ];
+
+ if (window.OffscreenCanvas) {
+ var offscreenCanvas = new OffscreenCanvas(1, 1);
+ cases = cases.concat([
+ { canvas: offscreenCanvas, flipY: true, font: false, init: setCanvasToMin },
+ { canvas: offscreenCanvas, flipY: false, font: false },
+ ]);
+ }
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ } else { // TEXTURE_2D_ARRAY
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var count = 4;
+ var caseNdx = 0;
+ var texture = undefined;
+ function runNextTest() {
+ var c = cases[caseNdx];
+ if (c.init) {
+ c.init(c.canvas.getContext('2d'), bindingTarget);
+ }
+ texture = runOneIteration(c.canvas, c.flipY, program, bindingTarget, texture, c.font);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count) {
+ resolve("SUCCESS");
+ return;
+ }
+ }
+ wtu.waitForComposite(runNextTest);
+ }
+ runNextTest();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_3D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_2D_ARRAY).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js
new file mode 100644
index 0000000000..b55bdcb143
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js
@@ -0,0 +1,48 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from a Blob (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", resourcePath + "red-green-semi-transparent.png");
+ xhr.responseType = 'blob';
+ xhr.onload = function() {
+ var blob = xhr.response;
+ runImageBitmapTest(blob, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ finishTest();
+ });
+ };
+ xhr.send();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js
new file mode 100644
index 0000000000..805298b377
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js
@@ -0,0 +1,74 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an HTMLCanvasElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var testCanvas = document.createElement('canvas');
+ var ctx = testCanvas.getContext("2d");
+ setCanvasToMin(ctx);
+ runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ setCanvasTo257x257(ctx);
+ return runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true);
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.fillStyle = "rgba(255, 0, 0, 1)";
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
+ ctx.fillRect(halfWidth, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 1)";
+ ctx.fillRect(0, halfHeight, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 0.5)";
+ ctx.fillRect(halfWidth, halfHeight, halfWidth, halfHeight);
+ }
+
+ function setCanvasToMin(ctx) {
+ ctx.canvas.width = 2;
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasTo257x257(ctx) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js
new file mode 100644
index 0000000000..44c9ffa378
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an ImageBitmap (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ createImageBitmap(imageData, {imageOrientation: "none", premultiplyAlpha: "none"})
+ .catch( () => {
+ testPassed("createImageBitmap with options may be rejected if it is not supported. Retrying without options.");
+ return createImageBitmap(imageData);
+ }).then( bitmap => {
+ return runImageBitmapTest(bitmap, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true);
+ }, () => {
+ testFailed("createImageBitmap(imageData) should succeed.");
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js
new file mode 100644
index 0000000000..cca0358e17
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js
@@ -0,0 +1,49 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ runImageBitmapTest(imageData, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js
new file mode 100644
index 0000000000..0f1121bbb9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js
@@ -0,0 +1,45 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an HTMLImageElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var image = new Image();
+ image.onload = function() {
+ runImageBitmapTest(image, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ finishTest();
+ });
+ }
+ image.src = resourcePath + "red-green-semi-transparent.png";
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js
new file mode 100644
index 0000000000..a268f7d8d5
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js
@@ -0,0 +1,83 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an HTMLVideoElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ finishTest();
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, async function() {
+ await runImageBitmapTest(video, 1, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true);
+ runNextVideo();
+ });
+ }
+ runNextVideo();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js
new file mode 100644
index 0000000000..bedf51a96a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js
@@ -0,0 +1,259 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imageData = null;
+ var blackColor = [0, 0, 0];
+ var originalPixels = (function() {
+ // (red|green|blue|cyan)(opaque|transparent)
+ var ro = [255, 0, 0, 255]; var rt = [255, 0, 0, 0];
+ var go = [0, 255, 0, 255]; var gt = [0, 255, 0, 0];
+ var bo = [0, 0, 255, 255]; var bt = [0, 0, 255, 0];
+ var co = [0, 255, 255, 255]; var ct = [0, 255, 255, 0];
+ return [ro, rt, go, gt,
+ ro, rt, go, gt,
+ bo, bt, co, ct,
+ bo, bt, co, ct];
+ })();
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var canvas2d = document.getElementById("texcanvas");
+ var context2d = canvas2d.getContext("2d");
+ imageData = context2d.createImageData(4, 4);
+ var data = imageData.data;
+ for (var i = 0; i < originalPixels.length; i++) {
+ data.set(originalPixels[i], 4 * i);
+ }
+
+ runTest();
+ }
+
+ function runOneIteration(useTexSubImage3D, flipY, premultiplyAlpha, bindingTarget,
+ depth, sourceSubRectangle, rTexCoord, program)
+ {
+ var expected = simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord);
+ var sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle;
+ sourceSubRectangleString += ', rTexCoord=' + rTexCoord;
+ }
+ debug('');
+ debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ sourceSubRectangleString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = imageData.width;
+ var uploadHeight = imageData.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ // Upload the image into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], imageData);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], imageData);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload");
+
+ var tl = expected[0][0];
+ var tr = expected[0][1];
+ var bl = expected[1][0];
+ var br = expected[1][1];
+
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed("Shader incorrectly set up; couldn't find uRCoord uniform");
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTexCoord);
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ var top = 0;
+ var bottom = height - halfHeight;
+ var left = 0;
+ var right = width - halfWidth;
+
+ debug("Checking pixel values");
+ debug("Expecting: " + expected);
+ var expectedH = expected.length;
+ var expectedW = expected[0].length;
+ var texelH = Math.floor(gl.canvas.height / expectedH);
+ var texelW = Math.floor(gl.canvas.width / expectedW);
+ // For each entry of the expected[][] array, check the appropriate
+ // canvas rectangle for correctness.
+ for (var row = 0; row < expectedH; row++) {
+ var y = row * texelH;
+ for (var col = 0; col < expectedW; col++) {
+ var x = col * texelW;
+ var val = expected[row][col];
+ wtu.checkCanvasRect(gl, x, y, texelW, texelH, val, "should be " + val);
+ }
+ }
+ }
+
+ function runTest()
+ {
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_3D, program);
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_2D_ARRAY, program);
+
+ debug("");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord) {
+ var ro = [255, 0, 0]; var rt = premultiplyAlpha ? [0, 0, 0] : [255, 0, 0];
+ var go = [0, 255, 0]; var gt = premultiplyAlpha ? [0, 0, 0] : [0, 255, 0];
+ var bo = [0, 0, 255]; var bt = premultiplyAlpha ? [0, 0, 0] : [0, 0, 255];
+ var co = [0, 255, 255]; var ct = premultiplyAlpha ? [0, 0, 0] : [0, 255, 255];
+ var expected = [[ro, rt, go, gt],
+ [ro, rt, go, gt],
+ [bo, bt, co, ct],
+ [bo, bt, co, ct]];
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ for (var row = 0; row < 4; row++) {
+ for (var col = 0; col < 4; col++) {
+ expected[row][col][1] = 0; // zero the green channel
+ }
+ }
+ // fall-through
+ case gl.RG:
+ case gl.RG_INTEGER:
+ for (var row = 0; row < 4; row++) {
+ for (var col = 0; col < 4; col++) {
+ expected[row][col][2] = 0; // zero the blue channel
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (flipY) {
+ expected.reverse();
+ }
+
+ if (sourceSubRectangle) {
+ let expected2 = [];
+ for (var row = 0; row < sourceSubRectangle[3]; row++) {
+ expected2[row] = [];
+ for (var col = 0; col < sourceSubRectangle[2]; col++) {
+ expected2[row][col] =
+ expected[sourceSubRectangle[1] + row + rTexCoord * sourceSubRectangle[3]][sourceSubRectangle[0] + col];
+ }
+ }
+ expected = expected2;
+ }
+
+ return expected;
+ }
+
+ function runTestOnBindingTarget(bindingTarget, program) {
+ var rects = [
+ undefined,
+ [0, 0, 2, 2],
+ [2, 0, 2, 2],
+ ];
+ var dbg = false; // Set to true for debug output images
+ if (dbg) {
+ (function() {
+ debug("");
+ debug("Original ImageData (transparent pixels appear black):");
+ var cvs = document.createElement("canvas");
+ cvs.width = 4;
+ cvs.height = 4;
+ cvs.style.width = "32px";
+ cvs.style.height = "32px";
+ cvs.style.imageRendering = "pixelated";
+ cvs.style.background = "#000";
+ var ctx = cvs.getContext("2d");
+ ctx.putImageData(imageData, 0, 0);
+ var output = document.getElementById("console");
+ output.appendChild(cvs);
+ })();
+ }
+ for (const sub of [false, true]) {
+ for (const flipY of [false, true]) {
+ for (const premul of [false, true]) {
+ for (let irect = 0; irect < rects.length; irect++) {
+ var rect = rects[irect];
+ let depth = rect ? 2 : 1;
+ for (let rTexCoord = 0; rTexCoord < depth; rTexCoord++) {
+ // TODO: add tests for UNPACK_IMAGE_HEIGHT.
+ runOneIteration(sub, flipY, premul, bindingTarget,
+ depth, rect, rTexCoord, program);
+ if (dbg) {
+ debug("Actual:");
+ var img = document.createElement("img");
+ img.src = gl.canvas.toDataURL("image/png");
+ var output = document.getElementById("console");
+ output.appendChild(img);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js
new file mode 100644
index 0000000000..034bd8ab46
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js
@@ -0,0 +1,260 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blueColor = [0, 0, 255];
+ var cyanColor = [0, 255, 255];
+ var imageURLs = [resourcePath + "red-green.png",
+ resourcePath + "red-green-blue-cyan-4x4.png"];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.RG:
+ case gl.RG_INTEGER:
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 255, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadImagesAsync(imageURLs, runTest);
+ }
+
+ function uploadImageToTexture(image, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight)
+ {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = image.width;
+ var uploadHeight = image.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ if (unpackImageHeight) {
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight);
+ }
+ // Upload the image into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], image);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload");
+ }
+
+ function runRedGreenTest(image) {
+ function runOneIteration(image, useTexSubImage3D, flipY, bindingTarget, topColor, bottomColor, program)
+ {
+ debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY'));
+
+ uploadImageToTexture(image, useTexSubImage3D, flipY, bindingTarget, 1);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].topColor, cases[i].bottomColor, program);
+ }
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].topColor, cases[i].bottomColor, program);
+ }
+ }
+
+ function runRedGreenBlueCyanTest(image) {
+ function runOneIteration(image, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight,
+ rTextureCoord, topColor, bottomColor, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ unpackImageHeightString = '';
+ if (unpackImageHeight) {
+ unpackImageHeightString = ' unpackImageHeight=' + unpackImageHeight;
+ }
+ debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ sourceSubRectangleString + ' depth=' + depth + unpackImageHeightString +
+ ' rTextureCoord=' + rTextureCoord);
+
+ uploadImageToTexture(image, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight);
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed('Shader incorrectly set up; couldn\'t find uRCoord uniform');
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTextureCoord);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+
+ var cases = [
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { flipY: false, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: greenColor, bottomColor: greenColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: greenColor, bottomColor: greenColor },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { flipY: false, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: greenColor, bottomColor: greenColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: greenColor, bottomColor: greenColor },
+ ];
+
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, false, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ runOneIteration(image, true, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ }
+
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, false, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ runOneIteration(image, true, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ }
+ }
+
+ function runTest(imageMap)
+ {
+ runRedGreenTest(imageMap[imageURLs[0]]);
+ runRedGreenBlueCyanTest(imageMap[imageURLs[1]]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js
new file mode 100644
index 0000000000..09a108dee8
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js
@@ -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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking SVG image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadTexture(gl, resourcePath + "red-green.svg", runTest);
+ }
+
+ function runOneIteration(image, flipY, topColor, bottomColor, bindingTarget, program)
+ {
+ debug('Testing ' + ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY'));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ // Upload the image into the texture
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], image.width, image.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, image.width, image.height, 1 /* depth */,
+ gl[pixelFormat], gl[pixelType], image);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+
+ function runTest(image)
+ {
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_3D, program);
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_2D_ARRAY, program);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function runTestOnBindingTarget(image, bindingTarget, program) {
+ var cases = [
+ { flipY: true, topColor: redColor, bottomColor: greenColor },
+ { flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+ for (var i in cases) {
+ runOneIteration(image, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js
new file mode 100644
index 0000000000..0c2c40e8a5
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js
@@ -0,0 +1,244 @@
+/*
+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.
+*/
+
+// This block needs to be outside the onload handler in order for this
+// test to run reliably in WebKit's test harness (at least the
+// Chromium port). https://bugs.webkit.org/show_bug.cgi?id=87448
+initTestingHarness();
+
+var old = debug;
+var debug = function(msg) {
+ bufferedLogToConsole(msg);
+ old(msg);
+};
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ // Test each format separately because many browsers implement each
+ // differently. Some might be GPU accelerated, some might not. Etc...
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.webmvp8.webm", type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.theora.ogv", type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking video elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function runOneIteration(videoElement, flipY, useTexSubImage3D, topColor, bottomColor, program, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight, rTextureCoord)
+ {
+ debug('Testing ' +
+ (useTexSubImage3D ? "texSubImage3D" : "texImage3D") +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ (sourceSubRectangle ? ', sourceSubRectangle=' + sourceSubRectangle : '') +
+ (unpackImageHeight ? ', unpackImageHeight=' + unpackImageHeight : '') +
+ ', depth=' + depth +
+ ', rTextureCoord=' + rTextureCoord);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = videoElement.width;
+ var uploadHeight = videoElement.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ if (unpackImageHeight) {
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight);
+ }
+ // Upload the videoElement into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat],
+ uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0,
+ uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat],
+ uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+
+ var c = document.createElement("canvas");
+ c.width = 16;
+ c.height = 16;
+ c.style.border = "1px solid black";
+ var ctx = c.getContext("2d");
+ ctx.drawImage(videoElement, 0, 0, 16, 16);
+ document.body.appendChild(c);
+
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed('Shader incorrectly set up; couldn\'t find uRCoord uniform');
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTextureCoord);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ const tolerance = 6;
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+ }
+
+ function runTest(videoElement)
+ {
+ var cases = [
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 5, rTextureCoord: 0,
+ topColor: redColor, bottomColor: redColor },
+ // Note that an rTextureCoord of 4.0 satisfies the need to
+ // have it be >= 1.0 for the TEXTURE_3D case, and also its
+ // use as an index in the TEXTURE_2D_ARRAY case.
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 5, rTextureCoord: 4,
+ topColor: greenColor, bottomColor: greenColor },
+ { flipY: false, sourceSubRectangle: [24, 48, 32, 32], depth: 1, rTextureCoord: 0,
+ topColor: greenColor, bottomColor: redColor },
+ { flipY: true, sourceSubRectangle: [24, 48, 32, 32], depth: 1, rTextureCoord: 0,
+ topColor: redColor, bottomColor: greenColor },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 2, unpackImageHeight: 64, rTextureCoord: 0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 2, unpackImageHeight: 64, rTextureCoord: 1,
+ topColor: greenColor, bottomColor: greenColor },
+ ];
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ resolve("SUCCESS");
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, runTest);
+ }
+ function runTest() {
+ for (var i in cases) {
+ runOneIteration(video, cases[i].flipY, false,
+ cases[i].topColor, cases[i].bottomColor,
+ program, bindingTarget, cases[i].depth,
+ cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight,
+ cases[i].rTextureCoord);
+ runOneIteration(video, cases[i].flipY, true,
+ cases[i].topColor, cases[i].bottomColor,
+ program, bindingTarget, cases[i].depth,
+ cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight,
+ cases[i].rTextureCoord);
+ }
+ runNextVideo();
+ }
+ runNextVideo();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_3D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_2D_ARRAY).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js
new file mode 100644
index 0000000000..fe14b0c8eb
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js
@@ -0,0 +1,212 @@
+/*
+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.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking webgl canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ ctx.viewport(0, 0, width, height);
+
+ ctx.enable(ctx.SCISSOR_TEST);
+ ctx.scissor(0, 0, width, halfHeight);
+ ctx.clearColor(1.0, 0, 0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.scissor(0, halfHeight, width, height - halfHeight);
+ ctx.clearColor(0.0, 1.0, 0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.disable(ctx.SCISSOR_TEST);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget) {
+ ctx.canvas.width = 1;
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function runOneIteration(canvas, flipY, program, bindingTarget, opt_texture)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ else if (canvas.parentNode)
+ objType = 'canvas attached to DOM';
+ debug('Testing flipY=' + flipY + ' object type: ' + objType +
+ ' bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ ' canvas size: ' + canvas.width + 'x' + canvas.height + ' with red-green');
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+
+ // Upload the image into the texture
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], canvas.width, canvas.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, canvas.width, canvas.height, 1 /* depth */,
+ gl[pixelFormat], gl[pixelType], canvas);
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? (height - halfHeight) : 0;
+ var bottom = flipY ? 0 : (height - halfHeight);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, redColor, "shouldBe " + redColor);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, greenColor, "shouldBe " + greenColor);
+
+ if (false) {
+ var ma = wtu.makeImageFromCanvas(canvas);
+ document.getElementById("console").appendChild(ma);
+
+ var m = wtu.makeImageFromCanvas(gl.canvas);
+ document.getElementById("console").appendChild(m);
+ document.getElementById("console").appendChild(document.createElement("hr"));
+ }
+
+ return texture;
+ }
+
+ function runTest()
+ {
+ var ctx = wtu.create3DContext();
+ var canvas = ctx.canvas;
+ // Note: We use preserveDrawingBuffer:true to prevent canvas
+ // visibility from interfering with the tests.
+ var visibleCtx = wtu.create3DContext(null, { preserveDrawingBuffer:true });
+ var visibleCanvas = visibleCtx.canvas;
+ var descriptionNode = document.getElementById("description");
+ document.body.insertBefore(visibleCanvas, descriptionNode);
+
+ var cases = [
+ { flipY: true, ctx: ctx, init: setCanvasToMin },
+ { flipY: false, ctx: ctx },
+ { flipY: true, ctx: ctx, init: setCanvasTo257x257 },
+ { flipY: false, ctx: ctx },
+ { flipY: true, ctx: visibleCtx, init: setCanvasToMin},
+ { flipY: false, ctx: visibleCtx },
+ ];
+
+ if (window.OffscreenCanvas) {
+ var offscreen = new OffscreenCanvas(1, 1);
+ var offscreenCtx = wtu.create3DContext(offscreen);
+ cases = cases.concat([
+ { flipY: true, ctx: offscreenCtx, init: setCanvasToMin },
+ { flipY: false, ctx: offscreenCtx },
+ ]);
+ }
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var count = 4;
+ var caseNdx = 0;
+ var texture = undefined;
+ function runNextTest() {
+ var c = cases[caseNdx];
+ if (c.init) {
+ c.init(c.ctx, bindingTarget);
+ }
+ texture = runOneIteration(c.ctx.canvas, c.flipY, program, bindingTarget, texture);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count) {
+ resolve("SUCCESS");
+ return;
+ }
+ }
+ wtu.waitForComposite(runNextTest);
+ }
+ runNextTest();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_3D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_2D_ARRAY).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js
new file mode 100644
index 0000000000..f37f12fe91
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js
@@ -0,0 +1,865 @@
+/*
+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.
+*/
+var TexImageUtils = (function() {
+
+ "use strict";
+
+ var wtu = WebGLTestUtils;
+
+ /**
+ * A vertex shader for a single texture.
+ * @type {string}
+ */
+ var simpleTextureVertexShaderES3 = [
+ '#version 300 es',
+ 'in vec4 vPosition;',
+ 'in vec2 texCoord0;',
+ 'out vec2 texCoord;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' texCoord = texCoord0;',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single unsigned integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usampler2D tex;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' uvec4 data = texture(tex, texCoord);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single signed integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isampler2D tex;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' ivec4 data = texture(tex, texCoord);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single cube map unsigned integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleCubeMapUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usamplerCube tex;',
+ 'uniform highp int face;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ // Transform [0, 1] -> [-1, 1]
+ ' vec2 texC2 = (texCoord * 2.) - 1.;',
+ // Transform 2d tex coord. to each face of TEXTURE_CUBE_MAP coord.
+ ' vec3 texCube = vec3(0., 0., 0.);',
+ ' if (face == 34069) {', // TEXTURE_CUBE_MAP_POSITIVE_X
+ ' texCube = vec3(1., -texC2.y, -texC2.x);',
+ ' } else if (face == 34070) {', // TEXTURE_CUBE_MAP_NEGATIVE_X
+ ' texCube = vec3(-1., -texC2.y, texC2.x);',
+ ' } else if (face == 34071) {', // TEXTURE_CUBE_MAP_POSITIVE_Y
+ ' texCube = vec3(texC2.x, 1., texC2.y);',
+ ' } else if (face == 34072) {', // TEXTURE_CUBE_MAP_NEGATIVE_Y
+ ' texCube = vec3(texC2.x, -1., -texC2.y);',
+ ' } else if (face == 34073) {', // TEXTURE_CUBE_MAP_POSITIVE_Z
+ ' texCube = vec3(texC2.x, -texC2.y, 1.);',
+ ' } else if (face == 34074) {', // TEXTURE_CUBE_MAP_NEGATIVE_Z
+ ' texCube = vec3(-texC2.x, -texC2.y, -1.);',
+ ' }',
+ ' uvec4 data = texture(tex, texCube);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single cube map signed integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleCubeMapIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isamplerCube tex;',
+ 'uniform highp int face;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ // Transform [0, 1] -> [-1, 1]
+ ' vec2 texC2 = (texCoord * 2.) - 1.;',
+ // Transform 2d tex coord. to each face of TEXTURE_CUBE_MAP coord.
+ ' vec3 texCube = vec3(0., 0., 0.);',
+ ' if (face == 34069) {', // TEXTURE_CUBE_MAP_POSITIVE_X
+ ' texCube = vec3(1., -texC2.y, -texC2.x);',
+ ' } else if (face == 34070) {', // TEXTURE_CUBE_MAP_NEGATIVE_X
+ ' texCube = vec3(-1., -texC2.y, texC2.x);',
+ ' } else if (face == 34071) {', // TEXTURE_CUBE_MAP_POSITIVE_Y
+ ' texCube = vec3(texC2.x, 1., texC2.y);',
+ ' } else if (face == 34072) {', // TEXTURE_CUBE_MAP_NEGATIVE_Y
+ ' texCube = vec3(texC2.x, -1., -texC2.y);',
+ ' } else if (face == 34073) {', // TEXTURE_CUBE_MAP_POSITIVE_Z
+ ' texCube = vec3(texC2.x, -texC2.y, 1.);',
+ ' } else if (face == 34074) {', // TEXTURE_CUBE_MAP_NEGATIVE_Z
+ ' texCube = vec3(-texC2.x, -texC2.y, -1.);',
+ ' }',
+ ' ivec4 data = texture(tex, texCube);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 3D texture.
+ * @type {string}
+ */
+ // Note that the tex coordinate r (the uniform uRCoord) is set to 0.0 by default.
+ var simple3DTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump sampler3D tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' fragData = vec4(texture(tex, vec3(texCoord, uRCoord)).rgb, 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 3D unsigned integer texture.
+ * @type {string}
+ */
+ // Note that the tex coordinate r (the uniform uRCoord) is set to 0.0 by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple3DUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usampler3D tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' uvec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 3D signed integer texture.
+ * @type {string}
+ */
+ // Note that the tex coordinate r (the uniform uRCoord) is set to 0.0 by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple3DIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isampler3D tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' ivec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 2D_ARRAY texture.
+ * @type {string}
+ */
+ // Note that the first image in the array (selected by the uniform
+ // uRCoord) is used by default.
+ var simple2DArrayTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump sampler2DArray tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' fragData = vec4(texture(tex, vec3(texCoord, uRCoord)).rgb, 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 2D_ARRAY unsigned integer texture.
+ * @type {string}
+ */
+ // Note that the first image in the array (selected by the uniform
+ // uRCoord) is used by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple2DArrayUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usampler2DArray tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' uvec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 2D_ARRAY signed integer texture.
+ * @type {string}
+ */
+ // Note that the first image in the array (selected by the uniform
+ // uRCoord) is used by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple2DArrayIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isampler2DArray tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' ivec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+
+ /**
+ * Creates a simple texture vertex shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleTextureVertexShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleTextureVertexShaderES3, gl.VERTEX_SHADER);
+ };
+
+ /**
+ * Creates a simple unsigned integer texture fragment shader.
+ * Output is scaled by 1/255 to bring the result into normalized float range.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple signed integer texture fragment shader.
+ * Output is scaled by 1/255 to bring the result into normalized float range.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleIntTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleIntTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple cube map unsigned integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleCubeMapUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleCubeMapUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple cube map signed integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleCubeMapIntTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleCubeMapIntTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 3D texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple3DTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple3DTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 3D unsigned integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple3DUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple3DUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 3D signed integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple3DIntTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple3DIntTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple2DArrayTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple2DArrayTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple2DArrayUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple2DArrayUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimpleUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimpleIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple cube map unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleCubeMapUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl);
+ var fs = setupSimpleCubeMapUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple cube map signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleCubeMapIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl);
+ var fs = setupSimpleCubeMapIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 3D texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple3DTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple3DTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 3D unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple3DUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple3DUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 3D signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple3DIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple3DIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple2DArrayTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple2DArrayTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple2DArrayUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple2DArrayUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple2DArrayIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple2DArrayIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a unsigned integer textured quad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupUintTexturedQuad = function(gl) {
+ var program = setupSimpleUintTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a signed integer textured quad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupIntTexturedQuad = function(gl) {
+ var program = setupSimpleIntTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a textured quad with
+ * a cube map unsigned integer texture.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupUintTexturedQuadWithCubeMap = function(gl)
+ {
+ var program = setupSimpleCubeMapUintTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a textured quad with
+ * a cube map signed integer texture.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupIntTexturedQuadWithCubeMap = function(gl)
+ {
+ var program = setupSimpleCubeMapIntTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Does the GL internal format represent an unsigned integer format
+ * texture?
+ * @return {boolean}
+ */
+ var isUintFormat = function(internalFormat)
+ {
+ return (internalFormat == "R8UI" || internalFormat == "RG8UI" || internalFormat == "RGB8UI" || internalFormat == "RGBA8UI" ||
+ internalFormat == "R16UI" || internalFormat == "RG16UI" || internalFormat == "RGB16UI" || internalFormat == "RGBA16UI" ||
+ internalFormat == "R32UI" || internalFormat == "RG32UI" || internalFormat == "RGB32UI" || internalFormat == "RGBA32UI");
+ };
+
+ /**
+ * Does the GL internal format represent an signed integer format
+ * texture?
+ * @return {boolean}
+ */
+ var isIntFormat = function(internalFormat)
+ {
+ return (internalFormat == "R8I" || internalFormat == "RG8I" || internalFormat == "RGB8I" || internalFormat == "RGBA8I" ||
+ internalFormat == "R16I" || internalFormat == "RG16I" || internalFormat == "RGB16I" || internalFormat == "RGBA16I" ||
+ internalFormat == "R32I" || internalFormat == "RG32I" || internalFormat == "RGB32I" || internalFormat == "RGBA32I");
+ };
+
+ /**
+ * Createa a program and buffers for rendering a textured quad for
+ * tex-image-and-sub-image tests. Handle selection of correct
+ * program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ var setupTexturedQuad = function(gl, internalFormat)
+ {
+ if (isUintFormat(internalFormat))
+ return setupUintTexturedQuad(gl);
+ if (isIntFormat(internalFormat))
+ return setupIntTexturedQuad(gl);
+ return wtu.setupTexturedQuad(gl);
+ };
+
+ /**
+ * Createa a program and buffers for rendering a textured quad with
+ * a cube map for tex-image-and-sub-image tests. Handle selection of
+ * correct program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ function setupTexturedQuadWithCubeMap(gl, internalFormat)
+ {
+ if (isUintFormat(internalFormat))
+ return setupUintTexturedQuadWithCubeMap(gl);
+ if (isIntFormat(internalFormat))
+ return setupIntTexturedQuadWithCubeMap(gl);
+ return wtu.setupTexturedQuadWithCubeMap(gl);
+ }
+
+ /**
+ * Createa a program and buffers for rendering a textured quad with a 3D texture
+ * for tex-image-and-sub-image tests. Handle selection of correct
+ * program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ var setupTexturedQuadWith3D = function(gl, internalFormat)
+ {
+ var program;
+ if (isUintFormat(internalFormat))
+ program = setupSimple3DUintTextureProgram(gl);
+ else if (isIntFormat(internalFormat))
+ program = setupSimple3DIntTextureProgram(gl);
+ else
+ program = setupSimple3DTextureProgram(gl);
+ var uRCoordLoc = gl.getUniformLocation(program, 'uRCoord');
+ gl.uniform1f(uRCoordLoc, 0.0);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Createa a program and buffers for rendering a textured quad with a 2D_ARRAY
+ * texture for tex-image-and-sub-image tests. Handle selection of correct
+ * program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ var setupTexturedQuadWith2DArray = function(gl, internalFormat)
+ {
+ var program;
+ if (isUintFormat(internalFormat))
+ program = setupSimple2DArrayUintTextureProgram(gl);
+ else if (isIntFormat(internalFormat))
+ program = setupSimple2DArrayIntTextureProgram(gl);
+ else
+ program = setupSimple2DArrayTextureProgram(gl);
+ var uRCoordLoc = gl.getUniformLocation(program, 'uRCoord');
+ gl.uniform1f(uRCoordLoc, 0.0);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Return a list of unpack color spaces to test, supported by the specified
+ * WebGLRenderingContext.
+ */
+ var unpackColorSpacesToTest = function(gl)
+ {
+ if ('unpackColorSpace' in gl)
+ return ['srgb', 'display-p3'];
+ else
+ return [undefined];
+ }
+
+ /**
+ * For each entry in unpackColorSpaces, duplicate all of cases, adding an
+ * unpackColorSpace key with its value set to that entry to each case.
+ */
+ var crossProductTestCasesWithUnpackColorSpaces = function(testCaseList, unpackColorSpaces)
+ {
+ var testCaseWithUnpackColorSpace = function(testCase, colorSpace)
+ {
+ return {...testCase, ...{unpackColorSpace:colorSpace}};
+ }
+ var listOfTestCaseLists = unpackColorSpaces.map(colorSpace =>
+ testCaseList.map(testCase => testCaseWithUnpackColorSpace(testCase, colorSpace)));
+ return listOfTestCaseLists.flat();
+ }
+
+ /**
+ * Given given an internalformat, format, and type, return the tolerance
+ * that should be used when comparing an input 8-bit value to one that has
+ * been truncated through the specified formats.
+ */
+ var tolerance = function(internalformat, format, type) {
+ function typeTolerance(type) {
+ switch(type) {
+ case 'UNSIGNED_SHORT_5_6_5':
+ case 'UNSIGNED_SHORT_5_5_5_1':
+ return 255 / 31;
+ case 'UNSIGNED_SHORT_4_4_4_4':
+ return 255 / 15;
+ break;
+ default:
+ return 1;
+ }
+ };
+ function formatTolerance(format) {
+ switch(format) {
+ case 'RGB565':
+ case 'RGB5_A1':
+ return 255/31;
+ case 'RGBA4':
+ return 255/15;
+ default:
+ return 1;
+ }
+ };
+ return Math.max(formatTolerance(internalformat),
+ formatTolerance(format),
+ typeTolerance(type));
+ }
+
+ return {
+ setupTexturedQuad: setupTexturedQuad,
+ setupTexturedQuadWithCubeMap: setupTexturedQuadWithCubeMap,
+ setupTexturedQuadWith3D: setupTexturedQuadWith3D,
+ setupTexturedQuadWith2DArray: setupTexturedQuadWith2DArray,
+ unpackColorSpacesToTest: unpackColorSpacesToTest,
+ crossProductTestCasesWithUnpackColorSpaces: crossProductTestCasesWithUnpackColorSpaces,
+ tolerance: tolerance
+ };
+
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js
new file mode 100644
index 0000000000..8faedf9eaa
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js
@@ -0,0 +1,435 @@
+/*
+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.
+*/
+
+
+function runOneIterationImageBitmapTest(useTexSubImage, bindingTarget, program, bitmap, flipY, premultiplyAlpha, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance)
+{
+ var halfRed = [128, 0, 0];
+ var halfGreen = [0, 128, 0];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blackColor = [0, 0, 0];
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ halfRed = [128, 128, 128];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ halfRed = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ switch (gl[internalFormat]) {
+ case gl.SRGB8:
+ case gl.SRGB8_ALPHA8:
+ halfRed = wtu.sRGBToLinear(halfRed);
+ halfGreen = wtu.sRGBToLinear(halfGreen);
+ break;
+ default:
+ break;
+ }
+
+ var str;
+ if (optionsVal.is3D) {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY');
+ } else {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP');
+ }
+ debug(str);
+ bufferedLogToConsole(str);
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ var targets = [bindingTarget];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+
+ bufferedLogToConsole("Start uploading the image into a texture");
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (optionsVal.is3D) {
+ gl.texImage3D(targets[tt], 0, gl[internalFormat], bitmap.width, bitmap.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(targets[tt], 0, 0, 0, 0, bitmap.width, bitmap.height, 1,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ } else {
+ if (useTexSubImage) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], bitmap.width, bitmap.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], bitmap);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], bitmap);
+ }
+ }
+ }
+ bufferedLogToConsole("Uploading into texture completed");
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var quarterWidth = Math.floor(halfWidth / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var quarterHeight = Math.floor(halfHeight / 2);
+
+ var top = flipY ? quarterHeight : (height - halfHeight + quarterHeight);
+ var bottom = flipY ? (height - halfHeight + quarterHeight) : quarterHeight;
+ var left = quarterWidth;
+ var right = halfWidth + quarterWidth / 2;
+
+ var tl = redColor;
+ var tr = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfRed : (optionsVal.alpha == 1) ? redColor : blackColor) : redColor;
+ var bl = greenColor;
+ var br = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfGreen : (optionsVal.alpha == 1) ? greenColor : blackColor) : greenColor;
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ // Check the top pixel and bottom pixel and make sure they have
+ // the right color.
+ let skipAlphaTests = (premultiplyAlpha === undefined && optionsVal.alpha != 1.0);
+ let skipStr = " (Skipping checking right pixel since premultiplyAlpha was undefined and alpha != 1.0)";
+ bufferedLogToConsole("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, left, bottom, 2, 2, tl, "shouldBe " + tl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, right, bottom, 2, 2, tr, "shouldBe " + tr + " +/-" + tolerance, tolerance);
+ }
+ bufferedLogToConsole("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, left, top, 2, 2, bl, "shouldBe " + bl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, right, top, 2, 2, br, "shouldBe " + br + " +/-" + tolerance, tolerance);
+ }
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+}
+
+function resetUnpackParams(gl)
+{
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_IMAGES, 0);
+ gl.pixelStorei(gl.UNPACK_ROW_LENGTH, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+}
+
+function runOneIterationImageBitmapTestSubSource(useTexSubImage, bindingTarget, program, bitmap, flipY, premultiplyAlpha, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance)
+{
+ var halfRed = [128, 0, 0];
+ var halfGreen = [0, 128, 0];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blackColor = [0, 0, 0];
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ halfRed = [128, 128, 128];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ halfRed = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ switch (gl[internalFormat]) {
+ case gl.SRGB8:
+ case gl.SRGB8_ALPHA8:
+ halfRed = wtu.sRGBToLinear(halfRed);
+ halfGreen = wtu.sRGBToLinear(halfGreen);
+ break;
+ default:
+ break;
+ }
+
+ var str;
+ if (optionsVal.is3D) {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage3D' : 'texImage3D') + '[SubSource]' +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=TEXTURE_3D';
+ } else {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage2D' : 'texImage2D') + '[SubSource]' +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=TEXTURE_2D';
+ }
+ debug(str);
+ bufferedLogToConsole(str);
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ var srcTL = redColor;
+ var srcTR = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfRed : (optionsVal.alpha == 1) ? redColor : blackColor) : redColor;
+ var srcBL = greenColor;
+ var srcBR = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfGreen : (optionsVal.alpha == 1) ? greenColor : blackColor) : greenColor;
+
+ var tl, tr, bl, br;
+
+ bufferedLogToConsole("Start uploading the image into a texture");
+ // Upload the image into the texture
+ if (optionsVal.is3D) {
+ if (useTexSubImage) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], bitmap.width, bitmap.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ // Only upload the left half image to the right half texture.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_IMAGES, 0);
+ gl.texSubImage3D(bindingTarget, 0, bitmap.width / 2, 0, 0, bitmap.width / 2, bitmap.height, 1,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ tl = blackColor;
+ tr = srcTL;
+ bl = blackColor;
+ br = srcBL;
+ } else {
+ // Only upload the bottom middle quarter image
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, bitmap.height / 2);
+ gl.pixelStorei(gl.UNPACK_SKIP_IMAGES, 0);
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], bitmap.width, bitmap.height / 2, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ if (!flipY) {
+ tl = srcBL;
+ tr = srcBR;
+ bl = srcBL;
+ br = srcBR;
+ } else {
+ tl = srcTL;
+ tr = srcTR;
+ bl = srcTL;
+ br = srcTR;
+ }
+ }
+ } else {
+ if (useTexSubImage) {
+ // Initialize the texture to black first
+ gl.texImage2D(bindingTarget, 0, gl[internalFormat], bitmap.width, bitmap.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ // Only upload the left half image to the right half texture.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.texSubImage2D(bindingTarget, 0, bitmap.width / 2, 0, bitmap.width / 2, bitmap.height,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ tl = blackColor;
+ tr = srcTL;
+ bl = blackColor;
+ br = srcBL;
+ } else {
+ // Only upload the right bottom image.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, bitmap.width / 2);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, bitmap.height / 2);
+ gl.texImage2D(bindingTarget, 0, gl[internalFormat], bitmap.width / 2, bitmap.height / 2, 0,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ resetUnpackParams(gl);
+ if (!flipY) {
+ tl = srcBR;
+ tr = srcBR;
+ bl = srcBR;
+ br = srcBR;
+ } else {
+ tl = srcTR;
+ tr = srcTR;
+ bl = srcTR;
+ br = srcTR;
+ }
+ }
+ }
+ bufferedLogToConsole("Uploading into texture completed");
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var quarterWidth = Math.floor(halfWidth / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var quarterHeight = Math.floor(halfHeight / 2);
+
+ var top = flipY ? quarterHeight : (height - halfHeight + quarterHeight);
+ var bottom = flipY ? (height - halfHeight + quarterHeight) : quarterHeight;
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ // Check the top pixel and bottom pixel and make sure they have
+ // the right color.
+ // For right side, check pixels closer to left to avoid border in the video tests.
+ let skipAlphaTests = (premultiplyAlpha === undefined && optionsVal.alpha != 1.0);
+ let skipStr = " (Skipping checking right pixel since premultiplyAlpha was undefined and alpha != 1.0)";
+ bufferedLogToConsole("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, quarterWidth, bottom, 2, 2, tl, "shouldBe " + tl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, halfWidth + quarterWidth / 2, bottom, 2, 2, tr, "shouldBe " + tr + " +/-" + tolerance, tolerance);
+ }
+ bufferedLogToConsole("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, quarterWidth, top, 2, 2, bl, "shouldBe " + bl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, halfWidth + quarterWidth / 2, top, 2, 2, br, "shouldBe " + br + " +/-" + tolerance, tolerance);
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+}
+
+function runTestOnBindingTargetImageBitmap(bindingTarget, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance)
+{
+ cases.forEach(x => {
+ runOneIterationImageBitmapTest(x.sub, bindingTarget, program, x.bitmap,
+ x.bitmap.flipY, x.bitmap.premultiply, optionsVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ });
+
+ if (wtu.getDefault3DContextVersion() <= 1 ||
+ (bindingTarget == gl.TEXTURE_CUBE_MAP || bindingTarget == gl.TEXTURE_2D_ARRAY))
+ {
+ // Skip testing source sub region on TEXTURE_CUBE_MAP and TEXTURE_2D_ARRAY on WebGL2 to save
+ // running time.
+ return;
+ }
+
+ cases.forEach(x => {
+ runOneIterationImageBitmapTestSubSource(x.sub, bindingTarget, program, x.bitmap,
+ x.bitmap.flipY, x.bitmap.premultiply, optionsVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ });
+}
+
+function runImageBitmapTestInternal(bitmaps, alphaVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, is3D, tolerance)
+{
+ var cases = [];
+ bitmaps.forEach(bitmap => {
+ cases.push({bitmap: bitmap, sub: false});
+ cases.push({bitmap: bitmap, sub: true});
+ });
+
+ var optionsVal = {alpha: alphaVal, is3D: is3D};
+ var program;
+ if (is3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_3D, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ } else {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_2D, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ }
+
+ // cube map texture must be square
+ if (bitmaps[0].width == bitmaps[0].height) {
+ if (is3D) {
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_2D_ARRAY, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_CUBE_MAP, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ }
+ }
+}
+
+function runImageBitmapTest(source, alphaVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, is3D, opt_tolerance)
+{
+ if (opt_tolerance === undefined) {
+ opt_tolerance = 10;
+ }
+ var p1 = createImageBitmap(source, {imageOrientation: "none", premultiplyAlpha: "premultiply"})
+ .then(cur => { cur.flipY = false; cur.premultiply = true; return cur; });
+ var p2 = createImageBitmap(source, {imageOrientation: "none", premultiplyAlpha: "none"})
+ .then(cur => { cur.flipY = false; cur.premultiply = false; return cur; });
+ var p3 = createImageBitmap(source, {imageOrientation: "flipY", premultiplyAlpha: "premultiply"})
+ .then(cur => { cur.flipY = true; cur.premultiply = true; return cur; });
+ var p4 = createImageBitmap(source, {imageOrientation: "flipY", premultiplyAlpha: "none"})
+ .then(cur => { cur.flipY = true; cur.premultiply = false; return cur; });
+ return Promise.all([p1, p2, p3, p4])
+ .catch( () => {
+ testPassed("createImageBitmap with options may be rejected if it is not supported. Retrying without options.");
+ // The ImageBitmap's premultiplyAlpha setting will implicitly be
+ // "default", and per spec:
+ // https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#cropped-to-the-source-rectangle-with-formatting
+ // this value is implementation-dependent (either premultiplied or
+ // not). Skip testing the quadrants which have alpha != 1.0.
+ var p = createImageBitmap(source)
+ .then(cur => { cur.flipY = false; cur.premultiply = undefined; return cur; });
+ return Promise.all([p]);
+ }).then( bitmaps => {
+ bufferedLogToConsole("All createImageBitmap promises are resolved");
+ runImageBitmapTestInternal(bitmaps, alphaVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, is3D, opt_tolerance);
+ }, (e) => {
+ // This will fail here when running from file:// instead of https://.
+ testFailed("createImageBitmap(source) failed: \"" + e.message + "\"");
+ });
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js
new file mode 100644
index 0000000000..22261afdb4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js
@@ -0,0 +1,563 @@
+/*
+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.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description("Validate tex functions input parameters");
+
+var wtu = WebGLTestUtils;
+var gl = null;
+var tex = null;
+var error = 0;
+
+shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, contextVersion)");
+shouldBeNonNull("tex = gl.createTexture()");
+gl.bindTexture(gl.TEXTURE_2D, tex);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+function enumToString(value) {
+ return wtu.glEnumToString(gl, value);
+}
+
+function testTexParameter(testCase) {
+ var msg = "paramName: " + enumToString(testCase.pname);
+ error = testCase.expectedError;
+ gl.texParameteri(testCase.target, testCase.pname, testCase.param);
+ wtu.glErrorShouldBe(gl, error, msg);
+ gl.texParameterf(testCase.target, testCase.pname, testCase.param);
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testGetTexParameter(testCase) {
+ var msg = "paramName: " + enumToString(testCase.pname);
+ error = testCase.expectedError;
+ gl.getTexParameter(testCase.target, testCase.pname);
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testTexImage2D(testCase) {
+ var level = 0;
+ var width = 16;
+ var height = 16;
+ var msg = " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target) +
+ " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type) +
+ " border: " + testCase.border;
+
+ gl.texImage2D(testCase.target, level, testCase.internalFormat, width, height, testCase.border, testCase.format, testCase.type, null);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testTexSubImage2D(testCase) {
+ var level = 0;
+ var xoffset = 0;
+ var yoffset = 0;
+ var width = 16;
+ var height = 16;
+ var msg = " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type);
+ var array = new Uint8Array(width * height * 4);
+
+ gl.texSubImage2D(testCase.target, level, xoffset, yoffset, width, height, testCase.format, testCase.type, array);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testCopyTexImage2D(testCase) {
+ var level = 0;
+ var x = 0;
+ var y = 0;
+ var width = 16;
+ var height = 16;
+ var msg = " colorBufferFormat: " + enumToString(testCase.colorBufferFormat) +
+ " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target) +
+ " border: " + testCase.border;
+
+ gl.renderbufferStorage(gl.RENDERBUFFER, testCase.colorBufferFormat, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ gl.copyTexImage2D(testCase.target, level, testCase.internalFormat, x, y, width, height, testCase.border);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testCopyTexSubImage2D(testCase) {
+ var level = 0;
+ var x = 0;
+ var y = 0;
+ var width = 16;
+ var height = 16;
+ var xoffset = 0;
+ var yoffset = 0;
+ var border = 0;
+ var type = gl.UNSIGNED_BYTE;
+ var msg = " colorBufferFormat: " + enumToString(testCase.colorBufferFormat) +
+ " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target);
+
+ gl.renderbufferStorage(gl.RENDERBUFFER, testCase.colorBufferFormat, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ gl.texImage2D(testCase.target, level, testCase.internalFormat, xoffset + width, yoffset + height, border, testCase.internalFormat, type, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ gl.copyTexSubImage2D(testCase.target, level, xoffset, yoffset, x, y, width, height);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testCopyFromInternalFBO(testCase) {
+ var target = gl.TEXTURE_2D;
+ var level = 0;
+ var x = 0;
+ var y = 0;
+ var width = 16;
+ var height = 16;
+ var xoffset = 0;
+ var yoffset = 0;
+ var border = 0;
+ var type = gl.UNSIGNED_BYTE;
+ var msg = " colorBufferFormat: " + enumToString(testCase.contextAlpha ? gl.RGBA : gl.RGB) +
+ " internalFormat: " + enumToString(testCase.internalFormat);
+
+ if (testCase.contextAlpha) {
+ gl = wtu.create3DContext(null, { alpha: true }, contextVersion);
+ } else {
+ gl = wtu.create3DContext(null, { alpha: false }, contextVersion);
+ }
+ shouldBeNonNull("gl");
+ shouldBeNonNull("tex = gl.createTexture()");
+ gl.bindTexture(target, tex);
+ if (testCase.subImage) {
+ gl.texImage2D(target, level, testCase.internalFormat, xoffset + width, yoffset + height, border, testCase.internalFormat, type, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.copyTexImage2D(target, level, testCase.internalFormat, x, y, width, height, border);
+ }
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+// Only for WebGL2.0.
+function testTexImage3D(testCase) {
+ var level = 0;
+ var width = 16;
+ var height = 16;
+ var depth = 16;
+ var msg = " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target) +
+ " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type) +
+ " border: " + testCase.border;
+
+ gl.texImage3D(testCase.target, level, testCase.internalFormat, width, height, depth, testCase.border, testCase.format, testCase.type, null);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testTexSubImage3D(testCase) {
+ var level = 0;
+ var xoffset = 0;
+ var yoffset = 0;
+ var zoffset = 0;
+ var width = 16;
+ var height = 16;
+ var depth = 16;
+ var msg = " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type);
+ var array = new Uint8Array(width * height * depth * 4);
+
+ gl.texSubImage3D(testCase.target, level, xoffset, yoffset, zoffset, width, height, depth, testCase.format, testCase.type, array);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+
+// Start checking.
+
+debug("");
+debug("Checking TexParameter: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: 0x0DE0, // GL_TEXTURE_1D
+ pname: gl.TEXTURE_WRAP_T,
+ param: gl.REPEAT,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: gl.TEXTURE_WRAP_T,
+ param: 0x2900, // GL_CLAMP
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: gl.TEXTURE_WRAP_T,
+ param: gl.REPEAT,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x813A, // GL_TEXTURE_MIN_LOD
+ param: 0,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x8E42, // GL_TEXTURE_SWIZZLE_R
+ param: 0x1903, // GL_RED
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: 0x8072, // GL_TEXTURE_WRAP_R
+ param: 0x2900, // GL_CLAMP
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexParameter(testCases[ii]);
+}
+
+debug("");
+debug("Checking GetTexParameter: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: 0x0DE0, // GL_TEXTURE_1D
+ pname: gl.TEXTURE_WRAP_T,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: gl.TEXTURE_WRAP_T,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x813A, // GL_TEXTURE_MIN_LOD
+ expectedError: gl.INVALID_ENUM }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x8E42, // GL_TEXTURE_SWIZZLE_R
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testGetTexParameter(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+var testCases = [
+ { target: 0x8064, // GL_PROXY_TEXTURE_2D
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ internalFormat: 0x1903, // GL_RED
+ border: 0,
+ format: 0x1903, // GL_RED
+ type: gl.UNSIGNED_BYTE,
+ expectedError: [gl.INVALID_ENUM, gl.INVALID_VALUE, gl.INVALID_OPERATION] },
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 1,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_VALUE },
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGB,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexSubImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: gl.TEXTURE_2D,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ format: 0x1903, // GL_RED
+ type: gl.UNSIGNED_BYTE,
+ expectedError: [gl.INVALID_ENUM, gl.INVALID_OPERATION] },
+ { target: gl.TEXTURE_2D,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: [gl.INVALID_ENUM, gl.INVALID_OPERATION] }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ format: gl.RED,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_2D,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_3D,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexSubImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking CopyTexImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+var colorBuffer = null;
+var fbo = null;
+
+shouldBeNonNull("fbo = gl.createFramebuffer()");
+gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
+gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+testCases = [
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: 0x8054, // GL_RGB16
+ border: 0,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGBA,
+ border: 1,
+ expectedError: gl.INVALID_VALUE },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGBA,
+ border: 0,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGB,
+ border: 0,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion > 1) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_3D,
+ colorBufferFormat: gl.RGB5_A1,
+ internalFormat: gl.RGBA,
+ border: 0,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testCopyTexImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking CopyTexSubImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB5_A1,
+ internalFormat: gl.RGBA,
+ expectedError: gl.NO_ERROR },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGBA,
+ expectedError: gl.INVALID_OPERATION }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testCopyTexSubImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking CopyTex{Sub}Image2D: copy from WebGL internal framebuffer");
+
+testCases = [
+ { contextAlpha: true,
+ internalFormat: gl.RGBA,
+ subImage: false,
+ expectedError: gl.NO_ERROR },
+ { contextAlpha: false,
+ internalFormat: gl.RGBA,
+ subImage: false,
+ expectedError: gl.INVALID_OPERATION },
+ { contextAlpha: true,
+ internalFormat: gl.RGBA,
+ subImage: true,
+ expectedError: gl.NO_ERROR },
+ { contextAlpha: false,
+ internalFormat: gl.RGBA,
+ subImage: true,
+ expectedError: gl.INVALID_OPERATION }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testCopyFromInternalFBO(testCases[ii]);
+}
+
+if (contextVersion > 1) {
+// Create new texture for testing api of WebGL 2.0.
+shouldBeNonNull("tex = gl.createTexture()");
+gl.bindTexture(gl.TEXTURE_3D, tex);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Checking TexImage3D: a set of inputs that are valid in GL but invalid in WebGL");
+
+var testCases = [
+ { target: 0x8070, // GL_PROXY_TEXTURE_3D
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGB,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_OPERATION},
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexImage3D(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexImage3D: bad target, internalformats, formats, types");
+
+var testCases = [
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RG,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: [gl.INVALID_VALUE, gl.INVALID_OPERATION]},
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RG8,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.INT,
+ expectedError: gl.INVALID_OPERATION},
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexImage3D(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexSubImage3D: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: gl.TEXTURE_3D,
+ format: 0x80E0, // GL_BGR
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ format: gl.RGBA,
+ type: 0x8032, // GL_UNSIGNED_BYTE_3_3_2
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexSubImage3D(testCases[ii]);
+}
+
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js b/dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js
new file mode 100644
index 0000000000..a80da8023d
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js
@@ -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.
+*/
+
+// This block needs to be outside the onload handler in order for this
+// test to run reliably in WebKit's test harness (at least the
+// Chromium port). https://bugs.webkit.org/show_bug.cgi?id=87448
+initTestingHarness();
+
+var old = debug;
+var debug = function(msg) {
+ bufferedLogToConsole(msg);
+ old(msg);
+};
+
+function generateTest(desc,
+ internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion,
+ videos) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var c2d = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var currentTolerance = 0;
+
+ function init()
+ {
+ description(desc + ' (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ // Subsume 2D canvas tests into this test case since they usually go down similar code paths and
+ // these tests are usually already set up to run with hardware accelerated video decoding.
+ c2d = document.getElementById("c2d").getContext("2d");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runAllTests();
+ }
+
+ function runOneIteration(videoElement, useTexSubImage2D, flipY, topColor, bottomColor, sourceSubRectangle, program, bindingTarget)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the videoElement into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ continue;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ } else {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ var width = videoElement.videoWidth;
+ var height = videoElement.videoHeight;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ width = Math.max(width, height);
+ height = width;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ width, height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var c = document.createElement("canvas");
+ c.width = 16;
+ c.height = 16;
+ c.style.border = "1px solid black";
+ var ctx = c.getContext("2d");
+ ctx.drawImage(videoElement, 0, 0, 16, 16);
+ document.body.appendChild(c);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ var tolerance = currentTolerance;
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+
+ // Expose bug http://crbug.com/733172.
+ if (sourceSubRectangle) {
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ continue;
+ }
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ }
+ }
+
+ function runCanvas2DTest(videoElement, topColor, bottomColor)
+ {
+ debug('Testing with 2D canvas');
+
+ var canvas = c2d.canvas;
+
+ // Draw the video to the 2D canvas context.
+ c2d.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
+
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ // Origin is upper left in 2D canvas context.
+ var tolerance = currentTolerance;
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(c2d, 4, canvas.height - 8, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(c2d, 4, 4, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+ }
+
+ function runAllTests()
+ {
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ resolve("SUCCESS");
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.comment);
+ debug("video type: " + info.type);
+ // Default to tolerance of 5.
+ currentTolerance = info.tolerance || 5;
+ debug("tolerance: " + currentTolerance);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported; skipping test");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, runTest);
+ }
+ function runTest() {
+ for (var i in cases) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // Cube map texture must be square but video is not square.
+ if (!cases[i].sub) {
+ break;
+ }
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (cases[i].sourceSubRectangle) {
+ break;
+ }
+ }
+ runOneIteration(video, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ cases[i].sourceSubRectangle,
+ program, bindingTarget);
+ }
+ runCanvas2DTest(video, redColor, greenColor);
+ runNextVideo();
+ }
+ runNextVideo();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_2D).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js
new file mode 100644
index 0000000000..2e1b79a677
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js
@@ -0,0 +1,73 @@
+/*
+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.
+*/
+
+// The "name" attribute is a concession to browsers which don't
+// implement the "name" property on function objects.
+var testCases =
+ [ {name: "Float32Array",
+ unsigned: false,
+ integral: false,
+ elementSizeInBytes: 4,
+ testValues: [ -500.5, 500.5 ],
+ expectedValues: [ -500.5, 500.5 ]
+ },
+ {name: "Float64Array",
+ unsigned: false,
+ integral: false,
+ elementSizeInBytes: 8,
+ testValues: [ -500.5, 500.5 ],
+ expectedValues: [ -500.5, 500.5 ]
+ },
+ {name: "Int8Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ -128, 127, -129, 128 ],
+ expectedValues: [ -128, 127, 127, -128 ]
+ },
+ {name: "Int16Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 2,
+ testValues: [ -32768, 32767, -32769, 32768 ],
+ expectedValues: [ -32768, 32767, 32767, -32768 ]
+ },
+ {name: "Int32Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 4,
+ testValues: [ -2147483648, 2147483647, -2147483649, 2147483648 ],
+ expectedValues: [ -2147483648, 2147483647, 2147483647, -2147483648 ]
+ },
+ {name: "Uint8Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ 0, 255, -1, 256 ],
+ expectedValues: [ 0, 255, 255, 0 ]
+ },
+ {name: "Uint8ClampedArray",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ 0, 255, -1, 256 ],
+ expectedValues: [ 0, 255, 0, 255 ]
+ },
+ {name: "Uint16Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 2,
+ testValues: [ 0, 65535, -1, 65536 ],
+ expectedValues: [ 0, 65535, 65535, 0 ]
+ },
+ {name: "Uint32Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 4,
+ testValues: [ 0, 4294967295, -1, 4294967296 ],
+ expectedValues: [ 0, 4294967295, 4294967295, 0 ]
+ }
+ ];
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js
new file mode 100644
index 0000000000..c361a0e8a2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js
@@ -0,0 +1,72 @@
+/*
+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.
+*/
+
+function constructTypedArray(type, data) {
+ if (type == 'Int8Array') {
+ return new Int8Array(data);
+ } else if (type == 'Uint8Array') {
+ return new Uint8Array(data);
+ } else if (type == 'Uint8ClampedArray') {
+ return new Uint8ClampedArray(data);
+ } else if (type == 'Int16Array') {
+ return new Int16Array(data);
+ } else if (type == 'Uint16Array') {
+ return new Uint16Array(data);
+ } else if (type == 'Int32Array') {
+ return new Int32Array(data);
+ } else if (type == 'Uint32Array') {
+ return new Uint32Array(data);
+ } else if (type == 'Float32Array') {
+ return new Float32Array(data);
+ } else if (type == 'Float64Array') {
+ return new Float64Array(data);
+ }
+}
+
+function constructDataView(subType, elementSizeInBytes, data) {
+ var setter = "set" + subType;
+ var byteOffset = 0;
+ var buffer = new ArrayBuffer(elementSizeInBytes * data.length);
+ var dataView = new DataView(buffer);
+ for (var ii = 0; ii < data.length; ++ii) {
+ dataView[setter](byteOffset, data[ii]);
+ byteOffset += elementSizeInBytes;
+ }
+ return dataView;
+}
+
+onmessage = function(event) {
+ var message = event.data;
+ if (message.command == 'copy' ||
+ message.command == 'transfer' ||
+ message.command == 'copyBuffer' ||
+ message.command == 'transferBuffer') {
+ var view;
+ if (message.type != 'DataView') {
+ view = constructTypedArray(message.type, message.data);
+ } else {
+ view = constructDataView(message.subType, message.elementSizeInBytes, message.data);
+ }
+ var valueToSend;
+ if (message.command == 'copy' ||
+ message.command == 'transfer') {
+ valueToSend = view;
+ } else {
+ valueToSend = view.buffer;
+ }
+ var transferablesToSend = undefined;
+ if (message.command == 'transfer' ||
+ message.command == 'transferBuffer') {
+ transferablesToSend = [ view.buffer ];
+ }
+ postMessage(valueToSend, transferablesToSend);
+ } else if (message.command == 'pong') {
+ postMessage(message.data, message.transferables);
+ } else if (message.command == 'ignore') {
+ } else {
+ postMessage('error: unknown message');
+ }
+};
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js
new file mode 100644
index 0000000000..6fad5520f2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js
@@ -0,0 +1,226 @@
+/*
+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.
+*/
+
+'use strict';
+
+var runCompressedTextureSizeLimitTest = function(maxArrayBufferSizeBytes, positiveCubeMapMaxSize) {
+
+ function numLevelsFromSize(size) {
+ var levels = 0;
+ while ((size >> levels) > 0) {
+ ++levels;
+ }
+ return levels;
+ }
+
+ // More formats can be added here when more texture compression extensions are enabled in WebGL.
+ var validFormats = {
+ COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0,
+ COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1,
+ COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2,
+ COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3,
+ };
+
+ // format specific restrictions for COMPRESSED_RGB_S3TC_DXT1_EXT and COMPRESSED_RGBA_S3TC_DXT1_EXT
+ // on the byteLength of the ArrayBufferView, pixels
+ function func1 (width, height)
+ {
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;
+ }
+
+ // format specific restrictions for COMPRESSED_RGBA_S3TC_DXT3_EXT and COMPRESSED_RGBA_S3TC_DXT5_EXT
+ // on the byteLength of the ArrayBufferView, pixels
+ function func2 (width, height)
+ {
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16;
+ }
+
+ var wtu = WebGLTestUtils;
+ var gl = wtu.create3DContext("example");
+ var tests = [
+ // More tests can be added here when more texture compression extensions are enabled in WebGL.
+ // Level 0 image width and height must be a multiple of the sizeStep.
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGB_S3TC_DXT1_EXT, dataType: Uint8Array, func: func1, sizeStep: 4},
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT1_EXT, dataType: Uint8Array, func: func1, sizeStep: 4},
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT3_EXT, dataType: Uint8Array, func: func2, sizeStep: 4},
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT5_EXT, dataType: Uint8Array, func: func2, sizeStep: 4},
+ ];
+
+ // Note: We expressly only use 2 textures because first a texture will be defined
+ // using all mip levels of 1 format, then for a moment it will have mixed formats which
+ // may uncover bugs.
+ var targets = [
+ { target: gl.TEXTURE_2D,
+ maxSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
+ tex: gl.createTexture(),
+ targets: [gl.TEXTURE_2D]
+ },
+ { target: gl.TEXTURE_CUBE_MAP,
+ maxSize: gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE),
+ tex: gl.createTexture(),
+ targets: [
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
+ ]
+ }
+ ];
+
+ function getSharedArrayBufferSize() {
+ var sharedArrayBufferSize = 0;
+ for (var tt = 0; tt < tests.length; ++tt) {
+ var test = tests[tt];
+ for (var trg = 0; trg < targets.length; ++trg) {
+ var t = targets[trg];
+ var bufferSizeNeeded;
+ if (t.target === gl.TEXTURE_CUBE_MAP) {
+ var positiveTestSize = Math.min(2048, t.maxSize);
+ bufferSizeNeeded = test.func(positiveTestSize, positiveTestSize);
+ } else {
+ bufferSizeNeeded = test.func(t.maxSize, test.sizeStep);
+ }
+ if (bufferSizeNeeded > sharedArrayBufferSize) {
+ sharedArrayBufferSize = bufferSizeNeeded;
+ }
+ bufferSizeNeeded = test.func(t.maxSize + test.sizeStep, t.maxSize + test.sizeStep);
+ // ArrayBuffers can be at most 4GB (minus 1 byte).
+ if (bufferSizeNeeded > sharedArrayBufferSize && bufferSizeNeeded <= maxArrayBufferSizeBytes) {
+ sharedArrayBufferSize = bufferSizeNeeded;
+ }
+ }
+ }
+ return sharedArrayBufferSize;
+ }
+
+ // Share an ArrayBuffer among tests to avoid too many large allocations
+ var sharedArrayBuffer = new ArrayBuffer(getSharedArrayBufferSize());
+
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
+
+ var trg = 0;
+ var tt = 0;
+ runNextTest();
+
+ function runNextTest() {
+ var t = targets[trg];
+
+ if (tt == 0) {
+ var tex = t.tex;
+ gl.bindTexture(t.target, tex);
+
+ debug("");
+ debug("max size for " + wtu.glEnumToString(gl, t.target) + ": " + t.maxSize);
+ }
+
+ var test = tests[tt];
+ testFormatType(t, test);
+ ++tt;
+ if (tt == tests.length) {
+ tt = 0;
+ ++trg;
+ if (trg == targets.length) {
+ finishTest();
+ return;
+ }
+ }
+ wtu.dispatchPromise(runNextTest);
+ }
+
+ function testFormatType(t, test) {
+ var positiveTestSize = t.maxSize;
+ var positiveTestOtherDimension = test.sizeStep;
+ if (t.target === gl.TEXTURE_CUBE_MAP) {
+ // Can't always test the maximum size since that can cause OOM:
+ positiveTestSize = Math.min(positiveCubeMapMaxSize, t.maxSize);
+ // Cube map textures need to be square:
+ positiveTestOtherDimension = positiveTestSize;
+ }
+ var positiveTestLevels = numLevelsFromSize(positiveTestSize);
+ var numLevels = numLevelsFromSize(t.maxSize);
+ debug("");
+ debug("num levels: " + numLevels + ", levels used in positive test: " + positiveTestLevels);
+
+ debug("");
+
+ // Query the extension and store globally so shouldBe can access it
+ var ext = wtu.getExtensionWithKnownPrefixes(gl, test.extension);
+ if (ext) {
+
+ testPassed("Successfully enabled " + test.extension + " extension");
+
+ for (var j = 0; j < t.targets.length; ++j) {
+ var target = t.targets[j];
+ debug("");
+ debug(wtu.glEnumToString(gl, target) + " " + wtu.glEnumToString(ext, test.format));
+
+ // positive test
+ var size = positiveTestSize;
+ var otherDimension = positiveTestOtherDimension;
+ for (var i = 0; i < positiveTestLevels; i++) {
+ var pixels = new test.dataType(sharedArrayBuffer, 0, test.func(size, otherDimension));
+ gl.compressedTexImage2D(target, i, test.format, size, otherDimension, 0, pixels);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture should generate NO_ERROR."
+ + "level is " + i + ", size is " + size + "x" + otherDimension);
+ size /= 2;
+ otherDimension /= 2;
+ if (otherDimension < 1) {
+ otherDimension = 1;
+ }
+ }
+
+ var numLevels = numLevelsFromSize(t.maxSize);
+
+ // out of bounds tests
+
+ // width or height out of bounds
+ if (t.target != gl.TEXTURE_CUBE_MAP) {
+ // only width out of bounds
+ var wideAndShortDataSize = test.func(t.maxSize + test.sizeStep, test.sizeStep);
+ var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, wideAndShortDataSize);
+ gl.compressedTexImage2D(target, 0, test.format, t.maxSize + test.sizeStep, test.sizeStep, 0, pixelsNegativeTest1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width out of bounds: should generate INVALID_VALUE."
+ + " level is 0, size is " + (t.maxSize + test.sizeStep) + "x" + (test.sizeStep));
+
+ // only height out of bounds
+ var narrowAndTallDataSize = test.func(test.sizeStep, t.maxSize + test.sizeStep);
+ var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, narrowAndTallDataSize);
+ gl.compressedTexImage2D(target, 0, test.format, test.sizeStep, t.maxSize + test.sizeStep, 0, pixelsNegativeTest1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "height out of bounds: should generate INVALID_VALUE."
+ + " level is 0, size is " + (test.sizeStep) + "x" + (t.maxSize + test.sizeStep));
+ }
+
+ // both width and height out of the maximum bounds simultaneously
+ var squareDataSize = test.func(t.maxSize + test.sizeStep, t.maxSize + test.sizeStep);
+ // this check assumes that each element is 1 byte
+ if (squareDataSize > sharedArrayBuffer.byteLength) {
+ testPassed("Unable to test square texture larger than maximum size due to ArrayBuffer size limitations -- this is legal");
+ } else {
+ var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, squareDataSize);
+ gl.compressedTexImage2D(target, 0, test.format, t.maxSize + test.sizeStep, t.maxSize + test.sizeStep, 0, pixelsNegativeTest1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width and height out of bounds: should generate INVALID_VALUE."
+ + " level is 0, size is " + (t.maxSize + test.sizeStep) + "x" + (t.maxSize + test.sizeStep));
+ }
+
+ // level out of bounds
+ var pixelsNegativeTest2 = new test.dataType(sharedArrayBuffer, 0, test.func(256, 256));
+ gl.compressedTexImage2D(target, numLevels, test.format, 256, 256, 0, pixelsNegativeTest2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "level out of bounds: should generate INVALID_VALUE."
+ + " level is " + numLevels + ", size is 256x256");
+ //width and height out of bounds for specified level
+ gl.compressedTexImage2D(target, numLevels - 1, test.format, 256, 256, 0, pixelsNegativeTest2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width or height out of bounds for specified level: should generate INVALID_VALUE."
+ + " level is " + (numLevels - 1) + ", size is 256x256");
+ }
+ }
+ else {
+ testPassed("No " + test.extension + " extension support -- this is legal");
+ }
+ }
+
+};
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js
new file mode 100644
index 0000000000..ebd0c7ba68
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js
@@ -0,0 +1,69 @@
+/*
+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.
+*/
+
+// This file contains utilities shared between tests for the WEBGL_draw_buffers extension and multiple draw buffers functionality in WebGL 2.0.
+
+'use strict';
+
+var WebGLDrawBuffersUtils = function(gl, ext) {
+
+ var getMaxUsableColorAttachments = function() {
+ var maxDrawingBuffers;
+ var maxColorAttachments;
+ if (ext) {
+ // EXT_draw_buffers
+ maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
+ maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL);
+ } else {
+ // WebGL 2.0
+ maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
+ maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+ }
+ var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
+ return Math.min(maxDrawingBuffers, maxColorAttachments, maxUniformVectors);
+ };
+
+ var makeColorAttachmentArray = function(size) {
+ var array = []
+ for (var ii = 0; ii < size; ++ii) {
+ array.push(gl.COLOR_ATTACHMENT0 + ii);
+ }
+ return array;
+ }
+
+ var checkProgram = wtu.setupTexturedQuad(gl);
+
+ var checkAttachmentsForColorFn = function(attachments, colorFn) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.useProgram(checkProgram);
+ attachments.forEach(function(attachment, index) {
+ gl.bindTexture(gl.TEXTURE_2D, attachment.texture);
+ wtu.clearAndDrawUnitQuad(gl);
+ var expectedColor = colorFn(attachment, index);
+ var tolerance = 0;
+ expectedColor.forEach(function(v) {
+ if (v != 0 && v != 255) {
+ tolerance = 8;
+ }
+ });
+ wtu.checkCanvas(gl, expectedColor, "attachment " + index + " should be " + expectedColor.toString(), tolerance);
+ });
+ debug("");
+ };
+
+ var checkAttachmentsForColor = function(attachments, color) {
+ checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return color || attachment.color;
+ });
+ };
+
+ return {
+ getMaxUsableColorAttachments: getMaxUsableColorAttachments,
+ makeColorAttachmentArray: makeColorAttachmentArray,
+ checkAttachmentsForColorFn: checkAttachmentsForColorFn,
+ checkAttachmentsForColor: checkAttachmentsForColor
+ };
+};