summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html445
1 files changed, 445 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html
new file mode 100644
index 0000000000..e548eea46c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html
@@ -0,0 +1,445 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL WEBGL_shader_pixel_local_storage Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/desktop-gl-constants.js"></script>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/compositing-test.js"></script>
+<script src="../../js/tests/invalid-vertex-attrib-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="128" height="128" style="background-color:#080"> </canvas>
+<canvas id="canvas_no_alpha" width="128" height="128"> </canvas>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_shader_pixel_local_storage " +
+ "extension, if it is available.");
+
+const wtu = WebGLTestUtils;
+const canvas = document.getElementById("canvas");
+const gl = wtu.create3DContext(canvas, {alpha: true}, 2);
+const gl_no_alpha = wtu.create3DContext("canvas_no_alpha", {alpha: false}, 2);
+let pls = null;
+
+// Outputs a fullscreen quad from a 4-vertex triangle strip.
+const fullscreenQuadVertexShader = `#version 300 es
+void main() {
+ gl_Position.x = (gl_VertexID & 1) == 0 ? -1. : 1.;
+ gl_Position.y = (gl_VertexID & 2) == 0 ? -1. : 1.;
+ gl_Position.zw = vec2(0, 1);
+}`;
+
+function arraysEqual(a, b) {
+ if (typeof a !== typeof b)
+ return false;
+ if (a.length != b.length)
+ return false;
+ for (let i = 0; i < a.length; ++i) {
+ if (a[i] !== b[i])
+ return false;
+ }
+ return true;
+}
+
+async function runTest() {
+ if (!gl) {
+ testFailed("WebGL2 context does not exist");
+ finishTest();
+ return;
+ }
+
+ debug("\nCheck the behavior surrounding WEBGL_shader_pixel_local_storage being enabled.");
+ checkExtensionNotSupportedWhenDisabled();
+ checkDependencyExtensionsEnabled(false);
+ debug("Enable WEBGL_shader_pixel_local_storage.");
+ pls = gl.getExtension("WEBGL_shader_pixel_local_storage");
+ wtu.runExtensionSupportedTest(gl, "WEBGL_shader_pixel_local_storage", pls != null);
+ if (!pls) {
+ finishTest();
+ return;
+ }
+ checkDependencyExtensionsEnabled(true);
+
+ checkImplementationDependentLimits();
+ checkInitialValues();
+ checkWebGLNonNormativeBehavior();
+
+ await checkRendering(gl);
+ await checkRendering(gl_no_alpha);
+
+ finishTest();
+}
+
+function checkExtensionNotSupportedWhenDisabled() {
+ debug("\nCheck that a context does not support WEBGL_shader_pixel_local_storage before it is " +
+ "enabled");
+ shouldBeNull("gl.getParameter(0x96E0 /*MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
+ shouldBeNull(
+ "gl.getParameter(0x96E1 /*MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL*/)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
+ shouldBeNull(
+ "gl.getParameter(0x96E2 /*MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
+ shouldBeNull(
+ "gl.getParameter(0x96E3 /*PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL*/)");
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension");
+ wtu.glErrorShouldBe(gl, gl.NONE);
+}
+
+function checkDependencyExtensionsEnabled(enabled) {
+ debug("\nCheck that dependency extensions of WEBGL_shader_pixel_local_storage are " +
+ (enabled ? "enabled" : "disabled"));
+ if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "OES_draw_buffers_indexed") !== undefined) {
+ gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 1);
+ wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM,
+ "OES_draw_buffers_indexed not enabled or disabled as expected");
+ }
+ if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_color_buffer_float") !== undefined) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, gl.createRenderbuffer());
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32F, 1, 1);
+ wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM,
+ "EXT_color_buffer_float not enabled or disabled as expected");
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ }
+ if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_color_buffer_half_float") !== undefined) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, gl.createRenderbuffer());
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RG16F, 1, 1);
+ wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM,
+ "EXT_color_buffer_half_float not enabled or disabled as expected");
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ }
+}
+
+function checkImplementationDependentLimits() {
+ debug("\nVerify conformant implementation-dependent PLS limits.");
+ window.MAX_PIXEL_LOCAL_STORAGE_PLANES =
+ gl.getParameter(pls.MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL);
+ window.MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE =
+ gl.getParameter(pls.MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL);
+ window.MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES =
+ gl.getParameter(pls.MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL);
+ wtu.glErrorShouldBe(gl, gl.NONE, "Pixel local storage queries should be supported.");
+
+ window.MAX_COLOR_ATTACHMENTS = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+ window.MAX_DRAW_BUFFERS = gl.getParameter(gl.MAX_DRAW_BUFFERS);
+
+ // Table 6.X: Impementation Dependent Pixel Local Storage Limits.
+ shouldBeTrue("MAX_PIXEL_LOCAL_STORAGE_PLANES >= 4");
+ shouldBeTrue("MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE >= 0");
+ shouldBeTrue("MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= 4");
+
+ // Logical deductions based on 6.X.
+ shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >=
+ MAX_PIXEL_LOCAL_STORAGE_PLANES`);
+ shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >=
+ MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE`);
+ shouldBeTrue(`MAX_COLOR_ATTACHMENTS + MAX_PIXEL_LOCAL_STORAGE_PLANES >=
+ MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`);
+ shouldBeTrue(`MAX_DRAW_BUFFERS + MAX_PIXEL_LOCAL_STORAGE_PLANES >=
+ MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`);
+}
+
+function checkInitialValues() {
+ debug("\nCheck that PLS state has the correct initial values.");
+ shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
+ wtu.glErrorShouldBe(
+ gl, gl.NONE,
+ "It's valid to query GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL even when fbo 0 is bound.");
+
+ // Table 6.Y: Pixel Local Storage State
+ gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer());
+ shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
+ debug("Check the initial clear values for each plane.");
+ const MAX_PIXEL_LOCAL_STORAGE_PLANES =
+ gl.getParameter(pls.MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL);
+ for (let i = 0; i < MAX_PIXEL_LOCAL_STORAGE_PLANES; ++i)
+ {
+ expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ i, pls.PIXEL_LOCAL_FORMAT_WEBGL) == gl.NONE);
+ expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ i, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) == null);
+ expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ i, pls.PIXEL_LOCAL_TEXTURE_LEVEL_WEBGL) == 0);
+ expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ i, pls.PIXEL_LOCAL_TEXTURE_LAYER_WEBGL) == 0);
+ expectTrue(arraysEqual(
+ pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ i, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL),
+ new Float32Array([0, 0, 0, 0])));
+ expectTrue(arraysEqual(
+ pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ i, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL),
+ new Int32Array([0, 0, 0, 0])));
+ expectTrue(arraysEqual(
+ pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ i, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL),
+ new Uint32Array([0, 0, 0, 0])));
+ }
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+}
+
+function checkWebGLNonNormativeBehavior() {
+ debug("\nCheck the WebGL-specific behavior not found in the " +
+ "ANGLE_shader_pixel_local_storage specification.");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer());
+
+ debug("If 'texture' has been deleted, generates an INVALID_OPERATION error.");
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ const tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ gl.deleteTexture(tex);
+ pls.framebufferTexturePixelLocalStorageWEBGL(0, tex, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
+
+ debug("\nIf 'texture' was generated by a different WebGL2RenderingContext than this one, " +
+ "generates an INVALID_OPERATION error.");
+ const gl2 = wtu.create3DContext(null, null, 2);
+ const tex2 = gl2.createTexture();
+ gl2.bindTexture(gl2.TEXTURE_2D, tex2);
+ gl2.texStorage2D(gl2.TEXTURE_2D, 1, gl2.RGBA8, 1, 1);
+ pls.framebufferTexturePixelLocalStorageWEBGL(0, tex2, 0, 0);
+ wtu.glErrorShouldBe(gl2, gl2.NONE);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
+
+ debug("\nIf value has less than srcOffset + 4 elements, generates an INVALID_VALUE error.");
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ pls.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(3));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(3));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueivWEBGL(3, [0, 0, 0]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueuivWEBGL(4, new Uint32Array(3));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValuefvWEBGL(2, new Float32Array(5), 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0, 0, 0], 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueivWEBGL(0, new Int32Array(5), 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueivWEBGL(1, [0, 0, 0, 0, 0], 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueuivWEBGL(2, new Uint32Array(5), 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ pls.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0, 0, 0], 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ debug("\nCheck that srcOffset works properly.");
+ const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ pls.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(arr), 1);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 0, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL),
+ new Float32Array([1, 2, 3, 4]))`);
+ pls.framebufferPixelLocalClearValuefvWEBGL(1, arr, 2);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 1, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL),
+ [2, 3, 4, 5])`);
+ pls.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(arr), 3);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 2, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL),
+ new Float32Array([3, 4, 5, 6]))`);
+ pls.framebufferPixelLocalClearValueivWEBGL(3, arr, 4);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 3, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL),
+ [4, 5, 6, 7])`);
+ pls.framebufferPixelLocalClearValueuivWEBGL(2, new Uint32Array(arr), 5);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 2, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL),
+ new Uint32Array([5, 6, 7, 8]))`);
+ pls.framebufferPixelLocalClearValueuivWEBGL(1, arr, 6);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 1, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL),
+ [6, 7, 8, 9])`);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+
+ debug("\nCheck that PIXEL_LOCAL_TEXTURE_NAME_WEBGL returns a WebGLTexture.");
+ shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === null`);
+ window.validTex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, validTex);
+ gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1);
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ pls.framebufferTexturePixelLocalStorageWEBGL(0, validTex, 0, 0);
+ shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === validTex`);
+ pls.framebufferTexturePixelLocalStorageWEBGL(0, null, 0, 0);
+ shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL(
+ 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === null`);
+
+ wtu.glErrorShouldBe(gl, gl.NONE);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+}
+
+async function checkRendering(localGL) {
+ const localCanvas = localGL.canvas;
+ const alpha = localGL.getContextAttributes().alpha;
+ debug("\nCheck very simple rendering with {alpha: " + alpha + "}");
+
+ const localPLS = localGL.getExtension("WEBGL_shader_pixel_local_storage");
+ if (!localPLS) {
+ testFailed("localGL doesn't support pixel local storage.");
+ return;
+ }
+
+ const tex = localGL.createTexture();
+ localGL.bindTexture(localGL.TEXTURE_2D, tex);
+ localGL.texStorage2D(localGL.TEXTURE_2D, 1, localGL.RGBA8, localCanvas.width, localCanvas.height);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+
+ const plsFBO = localGL.createFramebuffer();
+ localGL.bindFramebuffer(localGL.FRAMEBUFFER, plsFBO);
+ localPLS.framebufferTexturePixelLocalStorageWEBGL(0, tex, 0, 0);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+
+ localGL.viewport(0, 0, localCanvas.width, localCanvas.height);
+
+ // Adds a uniform color into the existing color in pixel local storage.
+ const fs = `#version 300 es
+ #extension GL_ANGLE_shader_pixel_local_storage : require
+ precision lowp float;
+ uniform vec4 color;
+ layout(binding=0, rgba8) uniform lowp pixelLocalANGLE pls;
+ void main() {
+ vec4 newColor = color + pixelLocalLoadANGLE(pls);
+ pixelLocalStoreANGLE(pls, newColor);
+ }`;
+
+ const program = wtu.setupProgram(localGL, [fullscreenQuadVertexShader, fs]);
+ if (!program) {
+ testFailed("Failed to compile program.");
+ return;
+ }
+
+ localGL.useProgram(program);
+ const colorUniLocation = localGL.getUniformLocation(program, "color");
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+
+ // Disable color mask to ensure PLS and canvas manage their own color masks properly.
+ localGL.colorMask(false, true, false, true);
+
+ // Set global variables for shouldBeTrue().
+ window.localGL = localGL;
+ window.localPLS = localPLS;
+
+ debug("\nCheck that pixel local storage works properly");
+ localGL.disable(localGL.DITHER);
+ localPLS.beginPixelLocalStorageWEBGL([localPLS.LOAD_OP_ZERO_WEBGL]);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+ shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1");
+
+ localGL.uniform4f(colorUniLocation, 0, 1, 0, 0);
+ localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4);
+
+ localPLS.pixelLocalStorageBarrierWEBGL();
+
+ localGL.uniform4f(colorUniLocation, 1, 0, 0, 0);
+ localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4);
+
+ localPLS.endPixelLocalStorageWEBGL([localPLS.STORE_OP_STORE_WEBGL]);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+ shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
+
+ const readFBO = localGL.createFramebuffer();
+ localGL.bindFramebuffer(localGL.READ_FRAMEBUFFER, readFBO);
+ localGL.framebufferTexture2D(localGL.READ_FRAMEBUFFER, localGL.COLOR_ATTACHMENT0,
+ localGL.TEXTURE_2D, tex, 0);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+ wtu.checkCanvas(localGL, [255, 255, 0, 0]);
+
+ debug("\nCheck that alpha is properly handled in the main canvas.");
+ localGL.bindFramebuffer(localGL.DRAW_FRAMEBUFFER, null);
+ localGL.blitFramebuffer(0, 0, localCanvas.width, localCanvas.height, 0, 0, localCanvas.width,
+ localCanvas.height, localGL.COLOR_BUFFER_BIT, localGL.NEAREST);
+ localGL.bindFramebuffer(localGL.FRAMEBUFFER, null);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+ wtu.checkCanvas(localGL, [255, 255, 0, alpha ? 0 : 255]);
+
+ localGL.bindFramebuffer(localGL.FRAMEBUFFER, plsFBO);
+ localPLS.beginPixelLocalStorageWEBGL([localPLS.LOAD_OP_LOAD_WEBGL]);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+ shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1");
+
+ debug("\nGoing down from composite.");
+
+ // The canvas should get cleared after compositing, even if PLS is active and color mask is
+ // disabled.
+ await new Promise(resolve => wtu.waitForComposite(resolve));
+
+ // Reset global variables for shouldBeTrue() after await.
+ window.localGL = localGL;
+ window.localPLS = localPLS;
+
+ debug("\nBack from composite!");
+ debug("\nPLS should still be active on plsFBO even after being interrupted for compositing.");
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+ shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1");
+
+ localGL.uniform4f(colorUniLocation, 0, 0, 1, 0);
+ localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4);
+
+ localPLS.endPixelLocalStorageWEBGL([localPLS.STORE_OP_STORE_WEBGL]);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+ shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
+
+ debug("\nThe canvas should have gotten cleared while PLS was active.");
+ localGL.bindFramebuffer(localGL.FRAMEBUFFER, null);
+ wtu.checkCanvas(localGL, [0, 0, 0, alpha ? 0 : 255]);
+
+ debug("\nThe additional PLS draw to plsFBO should have still worked after being interrupted " +
+ "for compositing.");
+ localGL.bindFramebuffer(localGL.READ_FRAMEBUFFER, readFBO);
+ wtu.checkCanvas(localGL, [255, 255, 255, 0]);
+ wtu.glErrorShouldBe(localGL, localGL.NONE);
+
+ // Draws 'tex' to the canvas.
+ const fs2 = `#version 300 es
+ uniform lowp sampler2D tex;
+ out lowp vec4 fragColor;
+ void main() {
+ ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
+ fragColor = texelFetch(tex, pixelCoord, 0);
+ }`;
+
+ const program2 = wtu.setupProgram(localGL, [fullscreenQuadVertexShader, fs2]);
+ if (!program2) {
+ testFailed("Failed to compile program2.");
+ return;
+ }
+
+ debug("\nBlue should still be disabled in the color mask. Alpha is not disabled but should be " +
+ "implicitly disabled since the canvas doesn't have alpha.");
+ localGL.useProgram(program2);
+ localGL.uniform1i(localGL.getUniformLocation(program2, "tex"), 0);
+ localGL.bindFramebuffer(localGL.FRAMEBUFFER, null);
+ localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4);
+ wtu.checkCanvas(localGL, [0, 255, 0, alpha ? 0 : 255]);
+
+ debug("\nThe client's color mask should have been preserved.");
+ shouldBeTrue(`arraysEqual(localGL.getParameter(localGL.COLOR_WRITEMASK),
+ [false, true, false, true])`);
+}
+
+runTest();
+var successfullyParsed = true;
+</script>
+</body>
+</html>