diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:42 +0000 |
commit | da4c7e7ed675c3bf405668739c3012d140856109 (patch) | |
tree | cdd868dba063fecba609a1d819de271f0d51b23e /dom/canvas/test/webgl-conf/checkout/js | |
parent | Adding upstream version 125.0.3. (diff) | |
download | firefox-da4c7e7ed675c3bf405668739c3012d140856109.tar.xz firefox-da4c7e7ed675c3bf405668739c3012d140856109.zip |
Adding upstream version 126.0.upstream/126.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/js')
10 files changed, 944 insertions, 23 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js b/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js index e1cb9f749c..adc1f8a5aa 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js +++ b/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js @@ -93,20 +93,25 @@ const RESULTS = { fail: 0, }; +// We cache these values since they will potentially be accessed many (100k+) +// times and accessing window can be significantly slower than a local variable. +const locationPathname = window.location.pathname; +const webglTestHarness = window.parent.webglTestHarness; + function reportTestResultsToHarness(success, msg) { if (success) { RESULTS.pass += 1; } else { RESULTS.fail += 1; } - if (window.parent.webglTestHarness) { - window.parent.webglTestHarness.reportResults(window.location.pathname, success, msg); + if (webglTestHarness) { + webglTestHarness.reportResults(locationPathname, success, msg); } } function reportSkippedTestResultsToHarness(success, msg) { - if (window.parent.webglTestHarness) { - window.parent.webglTestHarness.reportResults(window.location.pathname, success, msg, true); + if (webglTestHarness) { + webglTestHarness.reportResults(locationPathname, success, msg, true); } } @@ -116,8 +121,8 @@ function notifyFinishedToHarness() { } window._didNotifyFinishedToHarness = true; - if (window.parent.webglTestHarness) { - window.parent.webglTestHarness.notifyFinished(window.location.pathname); + if (webglTestHarness) { + webglTestHarness.notifyFinished(locationPathname); } if (window.nonKhronosFrameworkNotifyDone) { window.nonKhronosFrameworkNotifyDone(); @@ -268,9 +273,9 @@ function getCurrentTestName() */ function testPassedOptions(msg, addSpan) { + reportTestResultsToHarness(true, _currentTestName + ": " + msg); if (addSpan && !quietMode()) { - reportTestResultsToHarness(true, _currentTestName + ": " + msg); _addSpan('<span><span class="pass">PASS</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(msg) + '</span>'); } if (_jsTestPreVerboseLogging) { @@ -285,9 +290,9 @@ function testPassedOptions(msg, addSpan) */ function testSkippedOptions(msg, addSpan) { + reportSkippedTestResultsToHarness(true, _currentTestName + ": " + msg); if (addSpan && !quietMode()) { - reportSkippedTestResultsToHarness(true, _currentTestName + ": " + msg); _addSpan('<span><span class="warn">SKIP</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(msg) + '</span>'); } if (_jsTestPreVerboseLogging) { 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 index 46d155f5f1..04396c9b32 100644 --- 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 @@ -67,6 +67,10 @@ let testCompressedFormatsUnavailableWhenExtensionDisabled = function(gl, compres 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."); + if (gl.texStorage2D) { + gl.texStorage2D(gl.TEXTURE_2D, 1, compressedFormats[name], testSize, testSize); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with texStorage2D with extension disabled."); + } } } gl.bindTexture(gl.TEXTURE_2D, null); @@ -255,4 +259,4 @@ return { testTexStorageLevelDimensions: testTexStorageLevelDimensions, }; -})();
\ No newline at end of file +})(); diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/drawingbuffer-storage-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/drawingbuffer-storage-test.js new file mode 100644 index 0000000000..330171b320 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/drawingbuffer-storage-test.js @@ -0,0 +1,275 @@ +/* +Copyright (c) 2023 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 gl; +let oldViewport; +let width; +let height; +let format; +let hasDrawingBufferStorage; +let maxRenderbufferSize; + +function runTest(contextVersion) { + description(); + debug(""); + + function initialize() { + let canvas = document.createElement("canvas"); + gl = wtu.create3DContext(canvas, {antialias: false}); + if (!gl) { + testFailed("context does not exist"); + return [0, 0]; + } + + hasDrawingBufferStorage = `drawingBufferStorage` in gl; + if (!hasDrawingBufferStorage) { + testPassed("drawingBufferStorage not present -- skipping test"); + return; + } + + maxRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); + } + + function testPixel(expected, actual, tol) { + let str = 'approx equal: expected: ' + expected + ', actual: ' + actual + ', tolerance: ' + tol; + for (let i = 0; i < 4; ++i) { + if (Math.abs(expected[i] - actual[i]) > tol) { + testFailed(str); + return; + } + } + testPassed(str); + } + + function srgbToLinear(x) { + if (x < 0.0) + return 0.0; + if (x < 0.04045) + return x / 12.92; + if (x < 1.0) { + return Math.pow((x + 0.055)/1.044, 2.4); + } + return 1.0; + } + + function testClearColor() { + // Make a fresh canvas. + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + + gl = wtu.create3DContext(canvas, {antialias: false}); + if (!gl) { + testFailed("context does not exist"); + return; + } + testPassed("context exists"); + shouldBe('gl.drawingBufferFormat', 'gl.RGBA8'); + + let testCase = function(f, size, clearColor, expectedPixel, tolerance) { + format = f; + width = size[0]; + height = size[1]; + + gl.drawingBufferStorage(format, width, height); + shouldBe('gl.getError()', 'gl.NO_ERROR'); + + shouldBe('gl.drawingBufferFormat', 'format'); + shouldBe('gl.drawingBufferWidth', 'width'); + shouldBe('gl.drawingBufferHeight', 'height'); + + gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + gl.clear(gl.COLOR_BUFFER_BIT); + + let buf; + if (format == 0x881A /*RGBA16F*/) { + buf = new Float32Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, buf); + } else { + buf = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); + } + testPixel(expectedPixel, buf, tolerance); + } + + debug('Testing RGBA8'); + testCase(gl.RGBA8, [16, 32], + [16 / 255, 32 / 255, 64 / 255, 128 / 255], + [16, 32, 64, 128], + 0); + + // WebGL 1 must use EXT_sRGB for SRGB8_ALPHA8. + let srgb8_alpha8 = gl.SRGB8_ALPHA8; + if (!srgb8_alpha8) { + let ext = gl.getExtension('EXT_sRGB'); + if (ext) { + srgb8_alpha8 = ext.SRGB8_ALPHA8_EXT; + } + } + if (srgb8_alpha8) { + debug('Testing SRGB8_ALPHA8'); + testCase(srgb8_alpha8, [16, 32], + [srgbToLinear(64/255), srgbToLinear(16/255), srgbToLinear(32/255), 128 / 255], + [64, 16, 32, 128], + 1); + } + + if (gl.getExtension('EXT_color_buffer_float')) { + // WebGL 1 must use EXT_color_buffer_half_float for RGBA16F. + let rgba16f = gl.RGBA16F; + if (!rgba16f) { + let ext = gl.getExtension('EXT_color_buffer_half_float'); + if (ext) { + rgba16f = ext.RGBA16F_EXT; + } + } + + debug('Testing RGBA16F'); + testCase(rgba16f, [18, 28], + [0.25, 0.5, 0.75, 0.125], + [0.25, 0.5, 0.75, 0.125], + 0.00001); + } else { + debug('Skipping RGBA16F'); + } + + shouldBe('gl.getError()', 'gl.NO_ERROR'); + } + + function testNoAlpha() { + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + gl = wtu.create3DContext(canvas, {alpha:false}); + if (!gl) { + testFailed("context does not exist"); + return; + } + debug('Testing alpha:false'); + + // Report RGB8 for the format. + shouldBe('gl.drawingBufferFormat', 'gl.RGB8'); + + // If WebGLContextAttributes.alpha is false, generate INVALID_OPERATION. + gl.drawingBufferStorage(gl.RGBA8, 16, 16); + shouldBe('gl.getError()', 'gl.INVALID_OPERATION'); + } + + function testMissingExtension() { + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + gl = wtu.create3DContext(canvas); + if (!gl) { + testFailed("context does not exist"); + return; + } + + debug('Testing use of RGBA16F without enabling EXT_color_buffer_float'); + gl.drawingBufferStorage(gl.RGBA16F, 16, 16); + shouldBe('gl.getError()', 'gl.INVALID_ENUM'); + } + + function testMaxSize() { + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + gl = wtu.create3DContext(canvas); + if (!gl) { + testFailed("context does not exist"); + return; + } + + debug('Testing maximum size'); + gl.drawingBufferStorage(gl.RGBA8, maxRenderbufferSize, maxRenderbufferSize); + shouldBe('gl.getError()', 'gl.NONE'); + shouldBe('gl.drawingBufferWidth', 'maxRenderbufferSize'); + shouldBe('gl.drawingBufferHeight', 'maxRenderbufferSize'); + + debug('Testing over-maximum width and ehgith'); + gl.drawingBufferStorage(gl.RGBA8, maxRenderbufferSize+1, 16); + shouldBe('gl.getError()', 'gl.INVALID_VALUE'); + gl.drawingBufferStorage(gl.RGBA8, 16, maxRenderbufferSize+1); + shouldBe('gl.getError()', 'gl.INVALID_VALUE'); + shouldBe('gl.drawingBufferWidth', 'maxRenderbufferSize'); + shouldBe('gl.drawingBufferHeight', 'maxRenderbufferSize'); + } + + function testDrawToCanvas() { + let canvasGL = document.createElement("canvas"); + canvasGL.width = 16; + canvasGL.height = 16; + gl = wtu.create3DContext(canvasGL); + if (!gl) { + testFailed("context does not exist"); + return; + } + + let canvas2D = document.createElement("canvas"); + canvas2D.width = 16; + canvas2D.height = 16; + let ctx = canvas2D.getContext('2d'); + let imageData = new ImageData(16, 16); + + let testCase = function(f, clearColor, canvasColor, tolerance) { + gl.drawingBufferStorage(f, 16, 16); + gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + gl.clear(gl.COLOR_BUFFER_BIT); + + ctx.putImageData(imageData, 0, 0); + ctx.drawImage(canvasGL, 0, 0); + testPixel(canvasColor, ctx.getImageData(8, 8, 1, 1).data, tolerance); + } + + debug('Drawing RGBA to canvas'); + testCase(gl.RGBA8, [16/255, 32/255, 64/255, 64/255], [64, 128, 255, 64], 0); + + // WebGL 1 must use EXT_sRGB for SRGB8_ALPHA8. + let srgb8_alpha8 = gl.SRGB8_ALPHA8; + if (!srgb8_alpha8) { + let ext = gl.getExtension('EXT_sRGB'); + if (ext) { + srgb8_alpha8 = ext.SRGB8_ALPHA8_EXT; + } + } + if (srgb8_alpha8) { + debug('Drawing opaque SRGB8_ALPHA8 to canvas'); + testCase(srgb8_alpha8, + [srgbToLinear(64/255), srgbToLinear(32/255), srgbToLinear(16/255), 1.0], + [64, 32, 16, 255], + 1); + + debug('Drawing transparent SRGB8_ALPHA8 to canvas'); + // We set the tolerance to 5 because of compounding error. The backbuffer + // may be off by 1, and then un-premultiplying alpha of 64/55 will multiply + // that error by 4. Then add one to be safe. + testCase(srgb8_alpha8, + [srgbToLinear(32/255), srgbToLinear(64/255), srgbToLinear(16/255), 64/255], + [128, 255, 64, 64], + 5); + } + + if (gl.getExtension('EXT_color_buffer_float')) { + debug('Drawing transparent RGBA16F to canvas'); + testCase(gl.RGBA16F, + [32/255, 64/255, 16/255, 64/255], + [128, 255, 64, 64], + 1); + } + } + + let wtu = WebGLTestUtils; + initialize(); + if (hasDrawingBufferStorage) { + testClearColor(); + testNoAlpha(); + testMissingExtension(); + testMaxSize(); + testDrawToCanvas(); + } +} 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 index 51509e8a6e..2975ec0fe4 100644 --- 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 @@ -422,6 +422,33 @@ if (!gl) { runRGB16FNegativeTest(); } + if (version == 1) { + debug(""); + debug("Testing that component type framebuffer attachment queries are rejected with the extension disabled"); + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup renderbuffer should succeed."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail."); + gl.deleteRenderbuffer(rbo); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup texture should succeed."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail."); + gl.deleteTexture(tex); + + gl.deleteFramebuffer(fbo); + } + let oesTextureHalfFloat = null; if (version == 1) { // oesTextureHalfFloat implicitly enables EXT_color_buffer_half_float if supported @@ -466,6 +493,47 @@ if (!gl) { runCopyTexImageTest(true); runUniqueObjectTest(); + + { + debug(""); + debug("Testing that component type framebuffer attachment queries are accepted with the extension enabled"); + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT'); + gl.renderbufferStorage(gl.RENDERBUFFER, ext.RGBA16F_EXT, 8, 8); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid renderbuffer attachment queries."); + + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 8, 8); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after depth-stencil renderbuffer setup."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)'); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Component type query is not allowed for combined depth-stencil attachments."); + gl.deleteRenderbuffer(rbo); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT'); + const tex_ext = gl.getExtension("OES_texture_half_float"); + if (version > 1 || tex_ext) { + if (version > 1) + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, 8, 8, 0, gl.RGBA, gl.HALF_FLOAT, null); + else + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, tex_ext.HALF_FLOAT_OES, null); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT'); + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid texture attachment queries."); + gl.deleteTexture(tex); + + gl.deleteFramebuffer(fbo); + } } } 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 index 14cf4628be..504b70564e 100644 --- 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 @@ -14,7 +14,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { 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() 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 index 6e8bcf96e9..8dadde2d69 100644 --- 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 @@ -27,7 +27,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { 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() 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 index a268f7d8d5..b1dbd33913 100644 --- 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 @@ -14,7 +14,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { 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() 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 index 0c2c40e8a5..43ad660070 100644 --- 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 @@ -29,7 +29,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { 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() diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-blend-func-extended.js b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-blend-func-extended.js new file mode 100644 index 0000000000..086d9cfb16 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-blend-func-extended.js @@ -0,0 +1,548 @@ +"use strict"; +description("This test verifies the functionality of the WEBGL_blend_func_extended extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", undefined, contextVersion); +var ext; + +function runTestNoExtension() { + debug(""); + debug("Testing getParameter without the extension"); + shouldBeNull("gl.getParameter(0x88FC /* MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + if (contextVersion == 1) { + debug(""); + debug("Testing SRC_ALPHA_SATURATE without the extension"); + + gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFunc dfactor"); + gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstRGB"); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstAlpha"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + debug(""); + debug("Testing SRC1 blend funcs without the extension"); + + const extFuncs = { + SRC1_COLOR_WEBGL: 0x88F9, + SRC1_ALPHA_WEBGL: 0x8589, + ONE_MINUS_SRC1_COLOR_WEBGL: 0x88FA, + ONE_MINUS_SRC1_ALPHA_WEBGL: 0x88FB + }; + + for (const func in extFuncs) { + gl.blendFunc(extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc sfactor`); + gl.blendFunc(gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc dfactor`); + gl.blendFuncSeparate(extFuncs[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcRGB`); + gl.blendFuncSeparate(gl.ONE, extFuncs[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstRGB`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcAlpha`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstAlpha`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + const dbi = gl.getExtension("OES_draw_buffers_indexed"); + if (!dbi) return; + + debug(""); + debug("Testing indexed SRC1 blend funcs without the extension"); + for (const func in extFuncs) { + dbi.blendFunciOES(0, extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES src`); + dbi.blendFunciOES(0, gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES dst`); + dbi.blendFuncSeparateiOES(0, extFuncs[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcRGB`); + dbi.blendFuncSeparateiOES(0, gl.ONE, extFuncs[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstRGB`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcAlpha`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstAlpha`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } +} + +function runEnumTests() { + debug(""); + debug("Testing enums"); + shouldBe("ext.SRC1_COLOR_WEBGL", "0x88F9"); + shouldBe("ext.SRC1_ALPHA_WEBGL", "0x8589"); + shouldBe("ext.ONE_MINUS_SRC1_COLOR_WEBGL", "0x88FA"); + shouldBe("ext.ONE_MINUS_SRC1_ALPHA_WEBGL", "0x88FB"); + shouldBe("ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL", "0x88FC"); +} + +function runQueryTests() { + debug(""); + debug("Testing getParameter"); + shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL)", "1"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + if (contextVersion == 1) { + debug(""); + debug("Testing SRC_ALPHA_SATURATE with the extension"); + + gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFunc dfactor"); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE"); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE"); + gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstRGB"); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE"); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstAlpha"); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + const extFuncs = [ + "SRC1_COLOR_WEBGL", + "SRC1_ALPHA_WEBGL", + "ONE_MINUS_SRC1_COLOR_WEBGL", + "ONE_MINUS_SRC1_ALPHA_WEBGL" + ]; + + debug(""); + debug("Testing blend state updates with SRC1 blend funcs"); + for (const func of extFuncs) { + gl.blendFunc(ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc sfactor`); + shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`); + shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`); + gl.blendFunc(gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc dfactor`); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`); + gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcRGB`); + shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`); + gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstRGB`); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcAlpha`); + shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstAlpha`); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + const dbi = gl.getExtension("OES_draw_buffers_indexed"); + if (!dbi) return; + + debug(""); + debug("Testing indexed blend state updates with SRC1 blend funcs"); + for (const func of extFuncs) { + dbi.blendFunciOES(0, ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES src`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`); + dbi.blendFunciOES(0, gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES dst`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, ext[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcRGB`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, gl.ONE, ext[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstRGB`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcAlpha`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstAlpha`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } +} + +function runShaderTests(extensionEnabled) { + debug(""); + debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); + + const shaderSets = []; + + const macro100 = `precision mediump float; + void main() { + #ifdef GL_EXT_blend_func_extended + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_EXT_blend_func_extended; + #endif + }`; + const macro300 = `#version 300 es + out mediump vec4 my_FragColor; + void main() { + #ifdef GL_EXT_blend_func_extended + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_EXT_blend_func_extended; + #endif + }`; + shaderSets.push([wtu.simpleVertexShader, macro100]); + if (contextVersion == 2) { + shaderSets.push([wtu.simpleVertexShaderESSL300, macro300]); + } + + for (const shaders of shaderSets) { + // Expect the macro shader to succeed ONLY if enabled + if (wtu.setupProgram(gl, shaders)) { + if (extensionEnabled) { + testPassed("Macro defined in shaders when extension is enabled"); + } else { + testFailed("Macro defined in shaders when extension is disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Macro not defined in shaders when extension is enabled"); + } else { + testPassed("Macro not defined in shaders when extension is disabled"); + } + } + } + + shaderSets.length = 0; + + const missing100 = ` + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); + }`; + shaderSets.push([wtu.simpleVertexShader, missing100]); + + const missing300 = `#version 300 es + layout(location = 0) out mediump vec4 oColor0; + layout(location = 0, index = 1) out mediump vec4 oColor1; + void main() { + oColor0 = vec4(1.0, 0.0, 0.0, 1.0); + oColor1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + if (contextVersion == 2) { + shaderSets.push([wtu.simpleVertexShaderESSL300, missing300]); + } + + // Always expect the shader missing the #extension pragma to fail (whether enabled or not) + for (const shaders of shaderSets) { + if (wtu.setupProgram(gl, shaders)) { + testFailed("Secondary fragment output allowed without #extension pragma"); + } else { + testPassed("Secondary fragment output disallowed without #extension pragma"); + } + } + + shaderSets.length = 0; + + const valid100 = `#extension GL_EXT_blend_func_extended : enable + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); + }`; + shaderSets.push([wtu.simpleVertexShader, valid100]); + + const valid300 = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + layout(location = 0) out mediump vec4 oColor0; + layout(location = 0, index = 1) out mediump vec4 oColor1; + void main() { + oColor0 = vec4(1.0, 0.0, 0.0, 1.0); + oColor1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + if (contextVersion == 2) { + shaderSets.push([wtu.simpleVertexShaderESSL300, valid300]); + } + + // Try to compile a shader using a secondary fragment output that should only succeed if enabled + for (const shaders of shaderSets) { + if (wtu.setupProgram(gl, shaders)) { + if (extensionEnabled) { + testPassed("Secondary fragment output compiled successfully when extension enabled"); + } else { + testFailed("Secondary fragment output compiled successfully when extension disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Secondary fragment output failed to compile when extension enabled"); + } else { + testPassed("Secondary fragment output failed to compile when extension disabled"); + } + } + } + + // ESSL 3.00: Testing that multiple outputs require explicit locations + if (contextVersion == 2) { + const locations300 = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + out mediump vec4 color0; + out mediump vec4 color1; + void main() { + color0 = vec4(1.0, 0.0, 0.0, 1.0); + color1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, locations300])) { + testFailed("Multiple fragment outputs compiled successfully without explicit locations"); + } else { + testPassed("Multiple fragment outputs failed to compile without explicit locations"); + } + } +} + +function runMissingOutputsTests() { + debug(""); + debug("Test draw calls with missing fragment outputs"); + + wtu.setupUnitQuad(gl); + gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL); + + for (const enabled of [false, true]) { + if (enabled) { + gl.enable(gl.BLEND); + } else { + gl.disable(gl.BLEND); + } + + for (const maskedOut of [false, true]) { + gl.colorMask(!maskedOut, false, false, false); + + const label = `Dual-source blending ${enabled ? "ENABLED" : "DISABLED"}, ` + + `missing fragment outputs, and ` + + `${maskedOut ? "" : "NOT "}all color channels masked out`; + debug(`ESSL 1.00: ${label}`); + + { + const none = "void main() {}"; + wtu.setupProgram(gl, [wtu.simpleVertexShader, none]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "no fragment outputs"); + } + + { + const fragColor = ` + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShader, fragColor]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only gl_FragColor"); + } + + { + const secondaryFragColor = `#extension GL_EXT_blend_func_extended : enable + void main() { + gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShader, secondaryFragColor]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only gl_SecondaryFragColorEXT"); + } + + if (contextVersion == 1) continue; + + debug(`ESSL 3.00: ${label}`); + + { + const none = `#version 300 es + void main() {}`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, none]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "no fragment outputs"); + } + + { + const color0 = `#version 300 es + out mediump vec4 color0; + void main() { + color0 = vec4(1.0, 0.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color0]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only index 0 output"); + } + + { + const color1 = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + layout(location = 0, index = 1) out mediump vec4 color1; + void main() { + color1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color1]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only index 1 output"); + } + } + } + gl.colorMask(true, true, true, true); +} + +function runDrawBuffersLimitTests() { + const dbi = gl.getExtension("OES_draw_buffers_indexed"); + if (!dbi) return; + + debug(""); + debug("Testing that dual-source blending limits the number of active draw buffers"); + + const rb0 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); + + const rb1 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); + + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1); + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + const fs = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + layout(location = 0, index = 0) out mediump vec4 color0; + layout(location = 0, index = 1) out mediump vec4 color1; + void main() { + color0 = vec4(1.0, 0.0, 0.0, 1.0); + color1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, fs]); + + wtu.setupUnitQuad(gl); + + // Enable both draw buffers + gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); + + // Mask out draw buffer 1 to pass missing fragment outputs check + dbi.colorMaskiOES(1, false, false, false, false); + + const extFuncs = [ + "SRC1_COLOR_WEBGL", + "SRC1_ALPHA_WEBGL", + "ONE_MINUS_SRC1_COLOR_WEBGL", + "ONE_MINUS_SRC1_ALPHA_WEBGL" + ]; + + for (const func of extFuncs) { + for (let slot = 0; slot < 4; slot++) { + let param; + switch (slot) { + case 0: + param = "srcRGB"; + gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE); + break; + case 1: + param = "dstRGB"; + gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE); + break; + case 2: + param = "srcAlpha"; + gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE); + break; + case 3: + param = "dstAlpha"; + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]); + break; + } + debug(`Testing ${func} with ${param}`); + + // Limit must be applied even with blending disabled + gl.disable(gl.BLEND); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending disabled"); + + gl.enable(gl.BLEND); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending enabled"); + + // Limit is not applied when non-SRC1 funcs are used + gl.blendFunc(gl.ONE, gl.ONE); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "dual-source blending disabled"); + } + } + gl.bindFramebuffer(gl.FRAMEBUFFER, null); +} + +function runBlendingTests() { + debug(""); + debug("Testing rendering with two most common dual-source blending configurations"); + + const fs = `#extension GL_EXT_blend_func_extended : enable + uniform mediump vec4 u_src0; + uniform mediump vec4 u_src1; + void main() { + gl_FragColor = u_src0; + gl_SecondaryFragColorEXT = u_src1; + }`; + const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, fs]); + const uSrc0 = gl.getUniformLocation(program, "u_src0"); + const uSrc1 = gl.getUniformLocation(program, "u_src1"); + + gl.enable(gl.BLEND); + wtu.setupUnitQuad(gl); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + + gl.clear(gl.COLOR_BUFFER_BIT); + gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL); + gl.uniform4f(uSrc0, 0.250, 0.375, 0.500, 0.625); + gl.uniform4f(uSrc1, 0.125, 0.125, 0.125, 0.125); + wtu.drawUnitQuad(gl); + wtu.checkCanvas(gl, [96, 128, 159, 191], "Multiply destination by SRC1 and add SRC0", 2); + + gl.clear(gl.COLOR_BUFFER_BIT); + gl.blendFunc(ext.SRC1_COLOR_WEBGL, ext.ONE_MINUS_SRC1_COLOR_WEBGL); + gl.uniform4f(uSrc0, 0.125, 0.125, 0.125, 0.125); + gl.uniform4f(uSrc1, 0.500, 0.375, 0.250, 0.125); + wtu.drawUnitQuad(gl); + wtu.checkCanvas(gl, [143, 171, 199, 227], "Per-channel color interpolation using SRC1", 2); +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + return; + } + testPassed("context exists"); + + runTestNoExtension(); + runShaderTests(false); + + ext = gl.getExtension("WEBGL_blend_func_extended"); + wtu.runExtensionSupportedTest(gl, "WEBGL_blend_func_extended", ext !== null); + + if (ext !== null) { + runEnumTests(); + runQueryTests(); + runShaderTests(true); + runMissingOutputsTests(); + runDrawBuffersLimitTests(); + runBlendingTests(); + } else { + testPassed("No WEBGL_blend_func_extended support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; diff --git a/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js index f48d9d2ad7..ca6cbfcd36 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js +++ b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js @@ -538,15 +538,36 @@ TestHarness.prototype.runTests = function(opt_options) { this.startNextTest(); }; -TestHarness.prototype.setTimeout = function(test) { - var that = this; - test.timeoutId = this.window.setTimeout(function() { - that.timeout(test); - }, this.timeoutDelay); +TestHarness.prototype._bumpTimeout = function(test) { + const newTimeoutAt = performance.now() + this.timeoutDelay; + if (test.timeoutAt) { + test.timeoutAt = newTimeoutAt; + return; + } + test.timeoutAt = newTimeoutAt; + + const harness = this; + + function enqueueWatchdog() { + const remaining = test.timeoutAt - performance.now(); + //console.log(`watchdog started at ${performance.now()}, ${test.timeoutAt} requested`); + this.window.setTimeout(() => { + if (!test.timeoutAt) return; // Timeout was cleared. + const remainingAtCheckTime = test.timeoutAt - performance.now(); + if (performance.now() >= test.timeoutAt) { + //console.log(`watchdog won at ${performance.now()}, ${test.timeoutAt} requested`); + harness.timeout(test); + return; + } + //console.log(`watchdog lost at ${performance.now()}, as ${test.timeoutAt} is now requested`); + enqueueWatchdog(); + }, remaining); + } + enqueueWatchdog(); }; TestHarness.prototype.clearTimeout = function(test) { - this.window.clearTimeout(test.timeoutId); + test.timeoutAt = null; }; TestHarness.prototype.startNextTest = function() { @@ -577,7 +598,7 @@ TestHarness.prototype.startTest = function(iframe, testFile, webglVersion) { "dumpShaders": this.dumpShaders, "quiet": this.quiet }); - this.setTimeout(test); + this._bumpTimeout(test); } else { this.reportResults(url, !!this.allowSkip, "skipped", true); this.notifyFinished(url); @@ -595,11 +616,15 @@ TestHarness.prototype.getTest = function(url) { TestHarness.prototype.reportResults = function(url, success, msg, skipped) { url = FilterURL(url); var test = this.getTest(url); - this.clearTimeout(test); - log((success ? "PASS" : "FAIL") + ": " + msg); + if (0) { + // This is too slow to leave on for tests like + // deqp/functional/gles3/vertexarrays/multiple_attributes.output.html + // which has 33013505 calls to reportResults. + log((success ? "PASS" : "FAIL") + ": " + msg); + } this.reportFunc(TestHarness.reportType.TEST_RESULT, url, msg, success, skipped); // For each result we get, reset the timeout - this.setTimeout(test); + this._bumpTimeout(test); }; TestHarness.prototype.dequeTest = function(test) { |