5 <title>WebGL WEBGL_shader_pixel_local_storage Conformance Tests
</title>
6 <link rel=
"stylesheet" href=
"../../resources/js-test-style.css"/>
7 <script src=
"../../js/desktop-gl-constants.js"></script>
8 <script src=
"../../js/js-test-pre.js"></script>
9 <script src=
"../../js/webgl-test-utils.js"></script>
10 <script src=
"../../js/tests/compositing-test.js"></script>
11 <script src=
"../../js/tests/invalid-vertex-attrib-test.js"></script>
14 <div id=
"description"></div>
15 <canvas id=
"canvas" width=
"128" height=
"128" style=
"background-color:#080"> </canvas>
16 <canvas id=
"canvas_no_alpha" width=
"128" height=
"128"> </canvas>
17 <div id=
"console"></div>
20 description("This test verifies the functionality of the WEBGL_shader_pixel_local_storage " +
21 "extension, if it is available.");
23 const wtu
= WebGLTestUtils
;
24 const canvas
= document
.getElementById("canvas");
25 const gl
= wtu
.create3DContext(canvas
, {alpha
: true}, 2);
26 const gl_no_alpha
= wtu
.create3DContext("canvas_no_alpha", {alpha
: false}, 2);
29 // Outputs a fullscreen quad from a 4-vertex triangle strip.
30 const fullscreenQuadVertexShader
= `#version 300 es
32 gl_Position.x = (gl_VertexID & 1) == 0 ? -1. : 1.;
33 gl_Position.y = (gl_VertexID & 2) == 0 ? -1. : 1.;
34 gl_Position.zw = vec2(0, 1);
37 function arraysEqual(a
, b
) {
38 if (typeof a
!== typeof b
)
40 if (a
.length
!= b
.length
)
42 for (let i
= 0; i
< a
.length
; ++i
) {
49 async
function runTest() {
51 testFailed("WebGL2 context does not exist");
56 debug("\nCheck the behavior surrounding WEBGL_shader_pixel_local_storage being enabled.");
57 checkExtensionNotSupportedWhenDisabled();
58 checkDependencyExtensionsEnabled(false);
59 debug("Enable WEBGL_shader_pixel_local_storage.");
60 pls
= gl
.getExtension("WEBGL_shader_pixel_local_storage");
61 wtu
.runExtensionSupportedTest(gl
, "WEBGL_shader_pixel_local_storage", pls
!= null);
66 checkDependencyExtensionsEnabled(true);
68 checkImplementationDependentLimits();
70 checkWebGLNonNormativeBehavior();
72 await
checkRendering(gl
);
73 await
checkRendering(gl_no_alpha
);
78 function checkExtensionNotSupportedWhenDisabled() {
79 debug("\nCheck that a context does not support WEBGL_shader_pixel_local_storage before it is " +
81 shouldBeNull("gl.getParameter(0x96E0 /*MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)");
82 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "parameter unknown without enabling the extension");
84 "gl.getParameter(0x96E1 /*MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL*/)");
85 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "parameter unknown without enabling the extension");
87 "gl.getParameter(0x96E2 /*MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)");
88 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "parameter unknown without enabling the extension");
90 "gl.getParameter(0x96E3 /*PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL*/)");
91 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "parameter unknown without enabling the extension");
92 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
95 function checkDependencyExtensionsEnabled(enabled
) {
96 debug("\nCheck that dependency extensions of WEBGL_shader_pixel_local_storage are " +
97 (enabled
? "enabled" : "disabled"));
98 if (wtu
.getSupportedExtensionWithKnownPrefixes(gl
, "OES_draw_buffers_indexed") !== undefined) {
99 gl
.getIndexedParameter(gl
.BLEND_EQUATION_RGB
, 1);
100 wtu
.glErrorShouldBe(gl
, enabled
? gl
.NONE
: gl
.INVALID_ENUM
,
101 "OES_draw_buffers_indexed not enabled or disabled as expected");
103 if (wtu
.getSupportedExtensionWithKnownPrefixes(gl
, "EXT_color_buffer_float") !== undefined) {
104 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, gl
.createRenderbuffer());
105 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.R32F
, 1, 1);
106 wtu
.glErrorShouldBe(gl
, enabled
? gl
.NONE
: gl
.INVALID_ENUM
,
107 "EXT_color_buffer_float not enabled or disabled as expected");
108 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, null);
110 if (wtu
.getSupportedExtensionWithKnownPrefixes(gl
, "EXT_color_buffer_half_float") !== undefined) {
111 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, gl
.createRenderbuffer());
112 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RG16F
, 1, 1);
113 wtu
.glErrorShouldBe(gl
, enabled
? gl
.NONE
: gl
.INVALID_ENUM
,
114 "EXT_color_buffer_half_float not enabled or disabled as expected");
115 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, null);
119 function checkImplementationDependentLimits() {
120 debug("\nVerify conformant implementation-dependent PLS limits.");
121 window
.MAX_PIXEL_LOCAL_STORAGE_PLANES
=
122 gl
.getParameter(pls
.MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL
);
123 window
.MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE
=
124 gl
.getParameter(pls
.MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL
);
125 window
.MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES
=
126 gl
.getParameter(pls
.MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL
);
127 wtu
.glErrorShouldBe(gl
, gl
.NONE
, "Pixel local storage queries should be supported.");
129 window
.MAX_COLOR_ATTACHMENTS
= gl
.getParameter(gl
.MAX_COLOR_ATTACHMENTS
);
130 window
.MAX_DRAW_BUFFERS
= gl
.getParameter(gl
.MAX_DRAW_BUFFERS
);
132 // Table 6.X: Impementation Dependent Pixel Local Storage Limits.
133 shouldBeTrue("MAX_PIXEL_LOCAL_STORAGE_PLANES >= 4");
134 shouldBeTrue("MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE >= 0");
135 shouldBeTrue("MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= 4");
137 // Logical deductions based on 6.X.
138 shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >=
139 MAX_PIXEL_LOCAL_STORAGE_PLANES`);
140 shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >=
141 MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE`);
142 shouldBeTrue(`MAX_COLOR_ATTACHMENTS + MAX_PIXEL_LOCAL_STORAGE_PLANES >=
143 MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`);
144 shouldBeTrue(`MAX_DRAW_BUFFERS + MAX_PIXEL_LOCAL_STORAGE_PLANES >=
145 MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`);
148 function checkInitialValues() {
149 debug("\nCheck that PLS state has the correct initial values.");
150 shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
153 "It's valid to query GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL even when fbo 0 is bound.");
155 // Table 6.Y: Pixel Local Storage State
156 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, gl
.createFramebuffer());
157 shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
158 debug("Check the initial clear values for each plane.");
159 const MAX_PIXEL_LOCAL_STORAGE_PLANES
=
160 gl
.getParameter(pls
.MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL
);
161 for (let i
= 0; i
< MAX_PIXEL_LOCAL_STORAGE_PLANES
; ++i
)
163 expectTrue(pls
.getFramebufferPixelLocalStorageParameterWEBGL(
164 i
, pls
.PIXEL_LOCAL_FORMAT_WEBGL
) == gl
.NONE
);
165 expectTrue(pls
.getFramebufferPixelLocalStorageParameterWEBGL(
166 i
, pls
.PIXEL_LOCAL_TEXTURE_NAME_WEBGL
) == null);
167 expectTrue(pls
.getFramebufferPixelLocalStorageParameterWEBGL(
168 i
, pls
.PIXEL_LOCAL_TEXTURE_LEVEL_WEBGL
) == 0);
169 expectTrue(pls
.getFramebufferPixelLocalStorageParameterWEBGL(
170 i
, pls
.PIXEL_LOCAL_TEXTURE_LAYER_WEBGL
) == 0);
171 expectTrue(arraysEqual(
172 pls
.getFramebufferPixelLocalStorageParameterWEBGL(
173 i
, pls
.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL
),
174 new Float32Array([0, 0, 0, 0])));
175 expectTrue(arraysEqual(
176 pls
.getFramebufferPixelLocalStorageParameterWEBGL(
177 i
, pls
.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL
),
178 new Int32Array([0, 0, 0, 0])));
179 expectTrue(arraysEqual(
180 pls
.getFramebufferPixelLocalStorageParameterWEBGL(
181 i
, pls
.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL
),
182 new Uint32Array([0, 0, 0, 0])));
184 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
185 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, null);
188 function checkWebGLNonNormativeBehavior() {
189 debug("\nCheck the WebGL-specific behavior not found in the " +
190 "ANGLE_shader_pixel_local_storage specification.");
191 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, gl
.createFramebuffer());
193 debug("If 'texture' has been deleted, generates an INVALID_OPERATION error.");
194 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
195 const tex
= gl
.createTexture();
196 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
197 gl
.texStorage2D(gl
.TEXTURE_2D
, 1, gl
.RGBA8
, 1, 1);
198 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
199 gl
.deleteTexture(tex
);
200 pls
.framebufferTexturePixelLocalStorageWEBGL(0, tex
, 0, 0);
201 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
203 debug("\nIf 'texture' was generated by a different WebGL2RenderingContext than this one, " +
204 "generates an INVALID_OPERATION error.");
205 const gl2
= wtu
.create3DContext(null, null, 2);
206 const tex2
= gl2
.createTexture();
207 gl2
.bindTexture(gl2
.TEXTURE_2D
, tex2
);
208 gl2
.texStorage2D(gl2
.TEXTURE_2D
, 1, gl2
.RGBA8
, 1, 1);
209 pls
.framebufferTexturePixelLocalStorageWEBGL(0, tex2
, 0, 0);
210 wtu
.glErrorShouldBe(gl2
, gl2
.NONE
);
211 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
213 debug("\nIf value has less than srcOffset + 4 elements, generates an INVALID_VALUE error.");
214 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
215 pls
.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(3));
216 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
217 pls
.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0]);
218 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
219 pls
.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(3));
220 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
221 pls
.framebufferPixelLocalClearValueivWEBGL(3, [0, 0, 0]);
222 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
223 pls
.framebufferPixelLocalClearValueuivWEBGL(4, new Uint32Array(3));
224 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
225 pls
.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0]);
226 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
227 pls
.framebufferPixelLocalClearValuefvWEBGL(2, new Float32Array(5), 2);
228 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
229 pls
.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0, 0, 0], 2);
230 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
231 pls
.framebufferPixelLocalClearValueivWEBGL(0, new Int32Array(5), 2);
232 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
233 pls
.framebufferPixelLocalClearValueivWEBGL(1, [0, 0, 0, 0, 0], 2);
234 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
235 pls
.framebufferPixelLocalClearValueuivWEBGL(2, new Uint32Array(5), 2);
236 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
237 pls
.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0, 0, 0], 2);
238 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
240 debug("\nCheck that srcOffset works properly.");
241 const arr
= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
242 pls
.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(arr
), 1);
243 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
244 shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
245 0, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL),
246 new Float32Array([1, 2, 3, 4]))`);
247 pls
.framebufferPixelLocalClearValuefvWEBGL(1, arr
, 2);
248 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
249 shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
250 1, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL),
252 pls
.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(arr
), 3);
253 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
254 shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
255 2, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL),
256 new Float32Array([3, 4, 5, 6]))`);
257 pls
.framebufferPixelLocalClearValueivWEBGL(3, arr
, 4);
258 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
259 shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
260 3, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL),
262 pls
.framebufferPixelLocalClearValueuivWEBGL(2, new Uint32Array(arr
), 5);
263 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
264 shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
265 2, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL),
266 new Uint32Array([5, 6, 7, 8]))`);
267 pls
.framebufferPixelLocalClearValueuivWEBGL(1, arr
, 6);
268 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
269 shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL(
270 1, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL),
272 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
274 debug("\nCheck that PIXEL_LOCAL_TEXTURE_NAME_WEBGL returns a WebGLTexture.");
275 shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL(
276 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === null`);
277 window
.validTex
= gl
.createTexture();
278 gl
.bindTexture(gl
.TEXTURE_2D
, validTex
);
279 gl
.texStorage2D(gl
.TEXTURE_2D
, 1, gl
.RGBA8
, 1, 1);
280 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
281 pls
.framebufferTexturePixelLocalStorageWEBGL(0, validTex
, 0, 0);
282 shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL(
283 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === validTex`);
284 pls
.framebufferTexturePixelLocalStorageWEBGL(0, null, 0, 0);
285 shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL(
286 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === null`);
288 wtu
.glErrorShouldBe(gl
, gl
.NONE
);
289 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, null);
292 async
function checkRendering(localGL
) {
293 const localCanvas
= localGL
.canvas
;
294 const alpha
= localGL
.getContextAttributes().alpha
;
295 debug("\nCheck very simple rendering with {alpha: " + alpha
+ "}");
297 const localPLS
= localGL
.getExtension("WEBGL_shader_pixel_local_storage");
299 testFailed("localGL doesn't support pixel local storage.");
303 const tex
= localGL
.createTexture();
304 localGL
.bindTexture(localGL
.TEXTURE_2D
, tex
);
305 localGL
.texStorage2D(localGL
.TEXTURE_2D
, 1, localGL
.RGBA8
, localCanvas
.width
, localCanvas
.height
);
306 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
308 const plsFBO
= localGL
.createFramebuffer();
309 localGL
.bindFramebuffer(localGL
.FRAMEBUFFER
, plsFBO
);
310 localPLS
.framebufferTexturePixelLocalStorageWEBGL(0, tex
, 0, 0);
311 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
313 localGL
.viewport(0, 0, localCanvas
.width
, localCanvas
.height
);
315 // Adds a uniform color into the existing color in pixel local storage.
316 const fs
= `#version 300 es
317 #extension GL_ANGLE_shader_pixel_local_storage : require
318 precision lowp float;
320 layout(binding=0, rgba8) uniform lowp pixelLocalANGLE pls;
322 vec4 newColor = color + pixelLocalLoadANGLE(pls);
323 pixelLocalStoreANGLE(pls, newColor);
326 const program
= wtu
.setupProgram(localGL
, [fullscreenQuadVertexShader
, fs
]);
328 testFailed("Failed to compile program.");
332 localGL
.useProgram(program
);
333 const colorUniLocation
= localGL
.getUniformLocation(program
, "color");
334 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
336 // Disable color mask to ensure PLS and canvas manage their own color masks properly.
337 localGL
.colorMask(false, true, false, true);
339 // Set global variables for shouldBeTrue().
340 window
.localGL
= localGL
;
341 window
.localPLS
= localPLS
;
343 debug("\nCheck that pixel local storage works properly");
344 localGL
.disable(localGL
.DITHER
);
345 localPLS
.beginPixelLocalStorageWEBGL([localPLS
.LOAD_OP_ZERO_WEBGL
]);
346 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
347 shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1");
349 localGL
.uniform4f(colorUniLocation
, 0, 1, 0, 0);
350 localGL
.drawArrays(localGL
.TRIANGLE_STRIP
, 0, 4);
352 localPLS
.pixelLocalStorageBarrierWEBGL();
354 localGL
.uniform4f(colorUniLocation
, 1, 0, 0, 0);
355 localGL
.drawArrays(localGL
.TRIANGLE_STRIP
, 0, 4);
357 localPLS
.endPixelLocalStorageWEBGL([localPLS
.STORE_OP_STORE_WEBGL
]);
358 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
359 shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
361 const readFBO
= localGL
.createFramebuffer();
362 localGL
.bindFramebuffer(localGL
.READ_FRAMEBUFFER
, readFBO
);
363 localGL
.framebufferTexture2D(localGL
.READ_FRAMEBUFFER
, localGL
.COLOR_ATTACHMENT0
,
364 localGL
.TEXTURE_2D
, tex
, 0);
365 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
366 wtu
.checkCanvas(localGL
, [255, 255, 0, 0]);
368 debug("\nCheck that alpha is properly handled in the main canvas.");
369 localGL
.bindFramebuffer(localGL
.DRAW_FRAMEBUFFER
, null);
370 localGL
.blitFramebuffer(0, 0, localCanvas
.width
, localCanvas
.height
, 0, 0, localCanvas
.width
,
371 localCanvas
.height
, localGL
.COLOR_BUFFER_BIT
, localGL
.NEAREST
);
372 localGL
.bindFramebuffer(localGL
.FRAMEBUFFER
, null);
373 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
374 wtu
.checkCanvas(localGL
, [255, 255, 0, alpha
? 0 : 255]);
376 localGL
.bindFramebuffer(localGL
.FRAMEBUFFER
, plsFBO
);
377 localPLS
.beginPixelLocalStorageWEBGL([localPLS
.LOAD_OP_LOAD_WEBGL
]);
378 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
379 shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1");
381 debug("\nGoing down from composite.");
383 // The canvas should get cleared after compositing, even if PLS is active and color mask is
385 await
new Promise(resolve
=> wtu
.waitForComposite(resolve
));
387 // Reset global variables for shouldBeTrue() after await.
388 window
.localGL
= localGL
;
389 window
.localPLS
= localPLS
;
391 debug("\nBack from composite!");
392 debug("\nPLS should still be active on plsFBO even after being interrupted for compositing.");
393 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
394 shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1");
396 localGL
.uniform4f(colorUniLocation
, 0, 0, 1, 0);
397 localGL
.drawArrays(localGL
.TRIANGLE_STRIP
, 0, 4);
399 localPLS
.endPixelLocalStorageWEBGL([localPLS
.STORE_OP_STORE_WEBGL
]);
400 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
401 shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0");
403 debug("\nThe canvas should have gotten cleared while PLS was active.");
404 localGL
.bindFramebuffer(localGL
.FRAMEBUFFER
, null);
405 wtu
.checkCanvas(localGL
, [0, 0, 0, alpha
? 0 : 255]);
407 debug("\nThe additional PLS draw to plsFBO should have still worked after being interrupted " +
409 localGL
.bindFramebuffer(localGL
.READ_FRAMEBUFFER
, readFBO
);
410 wtu
.checkCanvas(localGL
, [255, 255, 255, 0]);
411 wtu
.glErrorShouldBe(localGL
, localGL
.NONE
);
413 // Draws 'tex' to the canvas.
414 const fs2
= `#version 300 es
415 uniform lowp sampler2D tex;
416 out lowp vec4 fragColor;
418 ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
419 fragColor = texelFetch(tex, pixelCoord, 0);
422 const program2
= wtu
.setupProgram(localGL
, [fullscreenQuadVertexShader
, fs2
]);
424 testFailed("Failed to compile program2.");
428 debug("\nBlue should still be disabled in the color mask. Alpha is not disabled but should be " +
429 "implicitly disabled since the canvas doesn't have alpha.");
430 localGL
.useProgram(program2
);
431 localGL
.uniform1i(localGL
.getUniformLocation(program2
, "tex"), 0);
432 localGL
.bindFramebuffer(localGL
.FRAMEBUFFER
, null);
433 localGL
.drawArrays(localGL
.TRIANGLE_STRIP
, 0, 4);
434 wtu
.checkCanvas(localGL
, [0, 255, 0, alpha
? 0 : 255]);
436 debug("\nThe client's color mask should have been preserved.");
437 shouldBeTrue(`arraysEqual(localGL.getParameter(localGL.COLOR_WRITEMASK),
438 [false, true, false, true])`);
442 var successfullyParsed
= true;