Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / conformance / extensions / webgl-draw-buffers.html
bloba33844f6b47f0a5534e0e33320bb7f4496eb6884
1 <!--
2 Copyright (c) 2019 The Khronos Group Inc.
3 Use of this source code is governed by an MIT-style license that can be
4 found in the LICENSE.txt file.
5 -->
7 <!DOCTYPE html>
8 <html>
9 <head>
10 <meta charset="utf-8">
11 <title>WebGL WEBGL_draw_buffers Conformance Tests</title>
12 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
13 <script src="../../js/js-test-pre.js"></script>
14 <script src="../../js/webgl-test-utils.js"></script>
15 <script src="../../js/tests/webgl-draw-buffers-utils.js"></script>
16 </head>
17 <body>
18 <div id="description"></div>
19 <canvas id="canvas" width="64" height="64"> </canvas>
20 <div id="console"></div>
21 <script id="fshader" type="x-shader/x-fragment">
22 #extension GL_EXT_draw_buffers : require
23 precision mediump float;
24 uniform vec4 u_colors[$(numDrawingBuffers)];
25 void main() {
26 for (int i = 0; i < $(numDrawingBuffers); ++i) {
27 gl_FragData[i] = u_colors[i];
30 </script>
31 <script id="fshaderNoWrite" type="x-shader/x-fragment">
32 #extension GL_EXT_draw_buffers : require
33 void main() {
35 </script>
36 <script id="fshaderRed" type="x-shader/x-fragment">
37 precision mediump float;
38 void main() {
39 gl_FragColor = vec4(1,0,0,1);
41 </script>
42 <script id="fshaderRedWithExtension" type="x-shader/x-fragment">
43 #extension GL_EXT_draw_buffers : require
44 precision mediump float;
45 void main() {
46 gl_FragColor = vec4(1,0,0,1);
48 </script>
49 <script id="fshaderMacroDisabled" type="x-shader/x-fragment">
50 #ifdef GL_EXT_draw_buffers
51 bad code here
52 #endif
53 precision mediump float;
54 void main() {
55 gl_FragColor = vec4(0,0,0,0);
57 </script>
58 <script id="fshaderMacroEnabled" type="x-shader/x-fragment">
59 #ifdef GL_EXT_draw_buffers
60 #if GL_EXT_draw_buffers == 1
61 #define CODE
62 #else
63 #define CODE this_code_is_bad_it_should_have_compiled
64 #endif
65 #else
66 #define CODE this_code_is_bad_it_should_have_compiled
67 #endif
68 CODE
69 precision mediump float;
70 void main() {
71 gl_FragColor = vec4(0,0,0,0);
73 </script>
74 <script id="fshaderBuiltInConstEnabled" type="x-shader/x-fragment">
75 precision mediump float;
76 void main() {
77 gl_FragColor = (gl_MaxDrawBuffers == $(numDrawingBuffers)) ? vec4(0,1,0,1) : vec4(1,0,0,1);
79 </script>
80 <script>
81 "use strict";
82 description("This test verifies the functionality of the WEBGL_draw_buffers extension, if it is available.");
84 debug("");
86 var wtu = WebGLTestUtils;
87 var canvas = document.getElementById("canvas");
88 var gl = wtu.create3DContext(canvas);
89 var ext = null;
90 var programWithMaxDrawBuffersEqualOne = null;
91 var drawBuffersUtils;
92 let fb;
94 var extensionConstants = [
95 { name: "MAX_COLOR_ATTACHMENTS_WEBGL", enum: 0x8CDF, expectedFn: function(v) { return v >= 4; }, passMsg: " should be >= 4"},
96 { name: "MAX_DRAW_BUFFERS_WEBGL", enum: 0x8824, expectedFn: function(v) { return v > 0; }, passMsg: " should be > 0"},
98 { name: "COLOR_ATTACHMENT0_WEBGL", enum: 0x8CE0, },
99 { name: "COLOR_ATTACHMENT1_WEBGL", enum: 0x8CE1, },
100 { name: "COLOR_ATTACHMENT2_WEBGL", enum: 0x8CE2, },
101 { name: "COLOR_ATTACHMENT3_WEBGL", enum: 0x8CE3, },
102 { name: "COLOR_ATTACHMENT4_WEBGL", enum: 0x8CE4, },
103 { name: "COLOR_ATTACHMENT5_WEBGL", enum: 0x8CE5, },
104 { name: "COLOR_ATTACHMENT6_WEBGL", enum: 0x8CE6, },
105 { name: "COLOR_ATTACHMENT7_WEBGL", enum: 0x8CE7, },
106 { name: "COLOR_ATTACHMENT8_WEBGL", enum: 0x8CE8, },
107 { name: "COLOR_ATTACHMENT9_WEBGL", enum: 0x8CE9, },
108 { name: "COLOR_ATTACHMENT10_WEBGL", enum: 0x8CEA, },
109 { name: "COLOR_ATTACHMENT11_WEBGL", enum: 0x8CEB, },
110 { name: "COLOR_ATTACHMENT12_WEBGL", enum: 0x8CEC, },
111 { name: "COLOR_ATTACHMENT13_WEBGL", enum: 0x8CED, },
112 { name: "COLOR_ATTACHMENT14_WEBGL", enum: 0x8CEE, },
113 { name: "COLOR_ATTACHMENT15_WEBGL", enum: 0x8CEF, },
115 { name: "DRAW_BUFFER0_WEBGL", enum: 0x8825, },
116 { name: "DRAW_BUFFER1_WEBGL", enum: 0x8826, },
117 { name: "DRAW_BUFFER2_WEBGL", enum: 0x8827, },
118 { name: "DRAW_BUFFER3_WEBGL", enum: 0x8828, },
119 { name: "DRAW_BUFFER4_WEBGL", enum: 0x8829, },
120 { name: "DRAW_BUFFER5_WEBGL", enum: 0x882A, },
121 { name: "DRAW_BUFFER6_WEBGL", enum: 0x882B, },
122 { name: "DRAW_BUFFER7_WEBGL", enum: 0x882C, },
123 { name: "DRAW_BUFFER8_WEBGL", enum: 0x882D, },
124 { name: "DRAW_BUFFER9_WEBGL", enum: 0x882E, },
125 { name: "DRAW_BUFFER10_WEBGL", enum: 0x882F, },
126 { name: "DRAW_BUFFER11_WEBGL", enum: 0x8830, },
127 { name: "DRAW_BUFFER12_WEBGL", enum: 0x8831, },
128 { name: "DRAW_BUFFER13_WEBGL", enum: 0x8832, },
129 { name: "DRAW_BUFFER14_WEBGL", enum: 0x8833, },
130 { name: "DRAW_BUFFER15_WEBGL", enum: 0x8834, },
133 if (!gl) {
134 testFailed("WebGL context does not exist");
135 } else {
136 testPassed("WebGL context exists");
138 // Run tests with extension disabled
139 runEnumTestDisabled();
140 runShadersTestDisabled();
141 runAttachmentTestDisabled();
143 debug("");
145 // Query the extension and store globally so shouldBe can access it
146 ext = gl.getExtension("WEBGL_draw_buffers");
147 if (!ext) {
148 testPassed("No WEBGL_draw_buffers support -- this is legal");
150 runSupportedTest(false);
151 finishTest();
152 } else {
153 testPassed("Successfully enabled WEBGL_draw_buffers extension");
155 drawBuffersUtils = WebGLDrawBuffersUtils(gl, ext);
156 runSupportedTest(true);
157 runEnumTestEnabled();
158 runShadersTestEnabled();
159 runAttachmentTestEnabled();
160 runDrawTests();
161 runPreserveTests();
165 function createExtDrawBuffersProgram(scriptId, sub) {
166 var fsource = wtu.getScript(scriptId);
167 fsource = wtu.replaceParams(fsource, sub);
168 return wtu.setupProgram(gl, [wtu.simpleVertexShader, fsource], ["vPosition"], undefined, true);
171 function runSupportedTest(extensionEnabled) {
172 var supported = gl.getSupportedExtensions();
173 if (supported.indexOf("WEBGL_draw_buffers") >= 0) {
174 if (extensionEnabled) {
175 testPassed("WEBGL_draw_buffers listed as supported and getExtension succeeded");
176 } else {
177 testFailed("WEBGL_draw_buffers listed as supported but getExtension failed");
179 } else {
180 if (extensionEnabled) {
181 testFailed("WEBGL_draw_buffers not listed as supported but getExtension succeeded");
182 } else {
183 testPassed("WEBGL_draw_buffers not listed as supported and getExtension failed -- this is legal");
188 function runEnumTestDisabled() {
189 debug("");
190 debug("Testing binding enum with extension disabled");
192 // Use the constant directly as we don't have the extension
193 extensionConstants.forEach(function(c) {
194 if (c.expectedFn) {
195 shouldBeNull(`gl.getParameter(${c.enum})`);
196 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, c.name + " should not be queryable if extension is disabled");
199 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
202 function runEnumTestEnabled() {
203 debug("");
204 debug("Testing enums with extension enabled");
206 extensionConstants.forEach(function(c) {
207 shouldBe("ext." + c.name, "0x" + c.enum.toString(16));
208 if (c.expectedFn) {
209 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "before getParameter");
210 debug(c.name + ": 0x" + ext[c.name].toString(16));
211 expectTrue(c.expectedFn(gl.getParameter(ext[c.name])), "gl.getParameter(ext." + c.name + ")" + c.passMsg);
212 wtu.glErrorShouldBe(gl, gl.NO_ERROR, c.name + " query should succeed if extension is enabled");
216 shouldBeTrue("gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL) >= gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL)");
218 debug("Testing drawBuffersWEBGL with default drawing buffer");
219 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
220 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "ext.drawBuffersWEBGL([])");
221 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "ext.drawBuffersWEBGL([gl.NONE, gl.NONE])");
222 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "ext.drawBuffersWEBGL([ext.COLOR_ATTACHMENT0_WEBGL])");
223 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
224 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.NONE])");
225 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.NONE");
226 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.BACK])");
227 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
228 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
230 debug("Testing drawBuffers and getParameter with bindFramebuffer, without drawing.");
231 fb = gl.createFramebuffer();
232 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
233 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.COLOR_ATTACHMENT0");
234 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL+1)", "gl.NONE");
235 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.NONE])");
236 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
237 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
238 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
239 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.NONE");
241 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.NONE,gl.COLOR_ATTACHMENT0+1])");
242 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.NONE");
243 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL+1)", "gl.COLOR_ATTACHMENT0+1");
245 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.COLOR_ATTACHMENT0,gl.COLOR_ATTACHMENT0+1])");
246 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.COLOR_ATTACHMENT0");
247 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL+1)", "gl.COLOR_ATTACHMENT0+1");
249 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fb)");
250 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
253 function testShaders(tests, sub) {
254 tests.forEach(function(test) {
255 var shaders = [wtu.simpleVertexShader, wtu.replaceParams(wtu.getScript(test.fragmentShaderTemplate), sub)];
256 var program = wtu.setupProgram(gl, shaders, ["vPosition"], undefined, true);
257 var programLinkedSuccessfully = (program != null);
258 var expectedProgramToLinkSuccessfully = (test.expectFailure == true);
259 expectTrue(programLinkedSuccessfully != expectedProgramToLinkSuccessfully, test.msg);
260 gl.deleteProgram(program);
264 function runShadersTestDisabled() {
265 debug("");
266 debug("test shaders disabled");
268 var sub = {numDrawingBuffers: 1};
269 testShaders([
270 { fragmentShaderTemplate: "fshaderMacroDisabled",
271 msg: "GL_EXT_draw_buffers should not be defined in GLSL",
273 { fragmentShaderTemplate: "fshader",
274 msg: "#extension GL_EXT_draw_buffers should not be allowed in GLSL",
275 expectFailure: true,
277 ], sub);
279 programWithMaxDrawBuffersEqualOne = createExtDrawBuffersProgram("fshaderBuiltInConstEnabled", sub);
280 wtu.setupUnitQuad(gl);
281 wtu.clearAndDrawUnitQuad(gl);
282 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
283 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
286 function runShadersTestEnabled() {
287 debug("");
288 debug("test shaders enabled");
290 var sub = {numDrawingBuffers: gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL)};
291 testShaders([
292 { fragmentShaderTemplate: "fshaderMacroEnabled",
293 msg: "GL_EXT_draw_buffers should be defined as 1 in GLSL",
295 { fragmentShaderTemplate: "fshader",
296 msg: "fragment shader containing the #extension directive should compile",
298 ], sub);
300 var program = createExtDrawBuffersProgram("fshaderBuiltInConstEnabled", sub);
301 wtu.setupUnitQuad(gl);
302 wtu.clearAndDrawUnitQuad(gl);
303 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
304 gl.deleteProgram(program);
305 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
307 debug("");
308 debug("test that gl_MaxDrawBuffers is frozen at link time and enabling the extension won't change it.");
309 gl.useProgram(programWithMaxDrawBuffersEqualOne);
310 wtu.clearAndDrawUnitQuad(gl);
311 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
312 gl.deleteProgram(programWithMaxDrawBuffersEqualOne);
313 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
316 function runAttachmentTestDisabled() {
317 debug("");
318 debug("test attachment disabled");
319 var tex = gl.createTexture();
320 var fb = gl.createFramebuffer();
321 gl.bindTexture(gl.TEXTURE_2D, tex);
322 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
323 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + 1, gl.TEXTURE_2D, tex, 0);
324 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach to gl.COLOR_ATTACHMENT1");
325 gl.deleteFramebuffer(fb);
326 gl.deleteTexture(tex);
327 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
330 function makeArray(size, value) {
331 var array = []
332 for (var ii = 0; ii < size; ++ii) {
333 array.push(value);
335 return array;
338 function runAttachmentTestEnabled() {
339 debug("");
340 debug("test attachment enabled");
342 var maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
343 var maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL);
345 var tex = gl.createTexture();
346 var fb = gl.createFramebuffer();
347 gl.bindTexture(gl.TEXTURE_2D, tex);
348 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
349 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments, gl.TEXTURE_2D, tex, 0);
350 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach pass the max attachment point: gl.COLOR_ATTACHMENT0 + " + maxColorAttachments);
351 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments - 1, gl.TEXTURE_2D, tex, 0);
352 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to attach to the max attachment point: gl.COLOR_ATTACHMENT0 + " + (maxColorAttachments - 1));
353 ext.drawBuffersWEBGL(makeArray(maxDrawingBuffers, gl.NONE));
354 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with array NONE of size " + maxColorAttachments);
355 var bufs = drawBuffersUtils.makeColorAttachmentArray(maxDrawingBuffers);
356 ext.drawBuffersWEBGL(bufs);
357 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with array attachments of size " + maxColorAttachments);
358 bufs[0] = gl.NONE;
359 ext.drawBuffersWEBGL(bufs);
360 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with mixed array attachments of size " + maxColorAttachments);
361 if (maxDrawingBuffers > 1) {
362 bufs[0] = ext.COLOR_ATTACHMENT1_WEBGL;
363 bufs[1] = ext.COLOR_ATTACHMENT0_WEBGL;
364 ext.drawBuffersWEBGL(bufs);
365 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be able to call drawBuffersWEBGL with out of order attachments of size " + maxColorAttachments);
366 var bufs = drawBuffersUtils.makeColorAttachmentArray(Math.floor(maxDrawingBuffers / 2));
367 ext.drawBuffersWEBGL(bufs);
368 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with short array of attachments of size " + bufs.length);
371 gl.deleteFramebuffer(fb);
372 gl.deleteTexture(tex);
373 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
376 function makeColorByIndex(index) {
377 var low = (index - 1) % 15 + 1;
378 var high = (index - 1) / 15;
380 var zeroOrOne = function(v) {
381 return v ? 1 : 0;
384 var oneOrTwo = function(v) {
385 return v ? 2 : 1;
388 var makeComponent = function(b0, b1, b2) {
389 return Math.floor(255 * zeroOrOne(b0) / oneOrTwo(b1) / oneOrTwo(b2));
391 return [
392 makeComponent(low & (1 << 0), high & (1 << 0), high & (1 << 4)),
393 makeComponent(low & (1 << 1), high & (1 << 1), high & (1 << 5)),
394 makeComponent(low & (1 << 2), high & (1 << 2), high & (1 << 6)),
395 makeComponent(low & (1 << 3), high & (1 << 3), high & (1 << 7)),
399 function runDrawTests() {
400 debug("");
401 debug("--------- draw tests -----------");
402 var fb = gl.createFramebuffer();
403 var fb2 = gl.createFramebuffer();
404 var halfFB1 = gl.createFramebuffer();
405 var halfFB2 = gl.createFramebuffer();
406 var endsFB = gl.createFramebuffer();
407 var middleFB = gl.createFramebuffer();
409 var maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
410 var maxUsable = drawBuffersUtils.getMaxUsableColorAttachments();
411 var half = Math.floor(maxUsable / 2);
412 var bufs = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
413 var nones = makeArray(maxUsable, gl.NONE);
415 [fb, fb2, halfFB1, halfFB2, endsFB, middleFB].forEach(function(fbo) {
416 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
417 ext.drawBuffersWEBGL(bufs);
420 var checkProgram = wtu.setupTexturedQuad(gl);
421 var redProgram = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderRed"], ["vPosition"]);
422 var redProgramWithExtension = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderRedWithExtension"], ["vPosition"]);
423 var drawProgram = createExtDrawBuffersProgram("fshader", {numDrawingBuffers: maxDrawingBuffers});
424 var width = 64;
425 var height = 64;
426 var attachments = [];
427 // Makes 6 framebuffers.
428 // fb and fb2 have all the attachments.
429 // halfFB1 has the first half of the attachments
430 // halfFB2 has the second half of the attachments
431 // endsFB has the first and last attachments
432 // middleFB has all but the first and last attachments
433 for (var ii = 0; ii < maxUsable; ++ii) {
434 var tex = gl.createTexture();
435 gl.bindTexture(gl.TEXTURE_2D, tex);
436 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
437 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
438 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
439 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
440 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
441 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
442 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
443 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
444 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
445 gl.bindFramebuffer(gl.FRAMEBUFFER, ii < half ? halfFB1 : halfFB2);
446 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
447 gl.bindFramebuffer(gl.FRAMEBUFFER, (ii == 0 || ii == (maxUsable - 1)) ? endsFB : middleFB);
448 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
449 var location = gl.getUniformLocation(drawProgram, "u_colors[" + ii + "]");
450 var color = makeColorByIndex(ii + 1);
451 var floatColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
452 gl.uniform4fv(location, floatColor);
453 attachments.push({
454 texture: tex,
455 color: color
458 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
459 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
460 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
461 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
463 var drawAndCheckAttachments = function(testFB, msg, testFn) {
464 debug("test clearing " + msg);
466 gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
468 attachments.forEach(function(attachment, index) {
469 debug("attachment: " + index + " = " + wtu.glEnumToString(gl, gl.getParameter(ext.DRAW_BUFFER0_WEBGL + index)) +
470 ", " + wtu.glEnumToString(gl, gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + index, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)));
473 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
474 debug("framebuffer not complete");
475 debug("");
476 return;
479 // Clear all the attachments
480 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
481 gl.clearColor(0, 0, 0, 0);
482 gl.clear(gl.COLOR_BUFFER_BIT);
483 //drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
484 // return [0, 0, 0, 0];
485 //});
486 //debug("--");
488 // Clear some attachments using testFB
489 gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
491 gl.clearColor(0, 1, 0, 1);
492 gl.clear(gl.COLOR_BUFFER_BIT);
493 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
494 return testFn(attachment, index) ? [0, 255, 0, 255] : [0, 0, 0, 0];
497 debug("test drawing to " + msg);
499 // Draw to some attachments using testFB
500 gl.useProgram(drawProgram);
501 gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
502 wtu.drawUnitQuad(gl);
504 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
505 return testFn(attachment, index) ? attachment.color : [0, 0, 0, 0];
509 gl.useProgram(drawProgram);
510 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
511 ext.drawBuffersWEBGL(bufs);
512 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
513 ext.drawBuffersWEBGL(bufs);
515 wtu.drawUnitQuad(gl);
517 debug("test that each texture got the correct color.");
519 drawBuffersUtils.checkAttachmentsForColor(attachments);
521 debug("test clearing clears all the textures");
522 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
523 gl.clearColor(0, 1, 0, 1);
524 gl.clear(gl.COLOR_BUFFER_BIT);
526 drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
528 debug("test a fragment shader writing to neither gl_FragColor nor gl_FragData does not touch attachments");
529 var noWriteProgram = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderNoWrite"], ["vPosition"]);
530 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no GL error setting up the program");
531 if (!noWriteProgram) {
532 testFailed("Setup a program where fragment shader writes nothing failed");
533 } else {
534 gl.useProgram(noWriteProgram);
535 wtu.drawUnitQuad(gl);
536 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
537 drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
538 gl.deleteProgram(noWriteProgram);
541 debug("test that NONE draws nothing");
542 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
543 ext.drawBuffersWEBGL(nones);
544 gl.useProgram(redProgram);
545 wtu.clearAndDrawUnitQuad(gl);
547 drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
549 debug("test that gl_FragColor does not broadcast unless extension is enabled in fragment shader");
550 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
551 ext.drawBuffersWEBGL(bufs);
552 gl.useProgram(redProgram);
553 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
554 wtu.drawUnitQuad(gl);
555 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
556 gl.colorMask(false, false, false, false);
557 wtu.drawUnitQuad(gl);
558 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors when all 4 channels of color mask are disabled.");
559 gl.colorMask(false, true, false, false);
560 wtu.drawUnitQuad(gl);
561 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "partially diabled color mask shall have no impact.");
562 gl.colorMask(true, true, true, true);
564 debug("test that gl_FragColor broadcasts if extension is enabled in fragment shader");
565 gl.clear(gl.COLOR_BUFFER_BIT);
566 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
567 ext.drawBuffersWEBGL(bufs);
568 gl.useProgram(redProgramWithExtension);
569 wtu.drawUnitQuad(gl);
571 drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
573 if (maxUsable > 1) {
574 // First half of color buffers disable.
575 var bufs1 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
576 // Second half of color buffers disable.
577 var bufs2 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
578 // Color buffers with even indices disabled.
579 var bufs3 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
580 // Color buffers with odd indices disabled.
581 var bufs4 = drawBuffersUtils.makeColorAttachmentArray(maxUsable);
582 for (var ii = 0; ii < maxUsable; ++ii) {
583 if (ii < half) {
584 bufs1[ii] = gl.NONE;
585 } else {
586 bufs2[ii] = gl.NONE;
588 if (ii % 2) {
589 bufs3[ii] = gl.NONE;
590 } else {
591 bufs4[ii] = gl.NONE;
595 debug("test setting first half to NONE and clearing");
597 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
598 // We should clear all buffers rather than depending on the previous
599 // gl_FragColor broadcasts test to succeed and setting the colors.
600 ext.drawBuffersWEBGL(bufs);
601 gl.clearColor(1, 0, 0, 1);
602 gl.clear(gl.COLOR_BUFFER_BIT);
604 ext.drawBuffersWEBGL(bufs1);
605 gl.clearColor(0, 1, 0, 1);
606 gl.clear(gl.COLOR_BUFFER_BIT);
608 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
609 return index < half ? [255, 0, 0, 255] : [0, 255, 0, 255];
612 debug("test setting first half to NONE and drawing");
614 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
615 gl.useProgram(drawProgram);
616 wtu.drawUnitQuad(gl);
618 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
619 return index < half ? [255, 0, 0, 255] : attachment.color;
622 debug("test setting second half to NONE and clearing");
624 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
625 ext.drawBuffersWEBGL(bufs);
626 gl.clearColor(1, 0, 0, 1);
627 gl.clear(gl.COLOR_BUFFER_BIT);
629 ext.drawBuffersWEBGL(bufs2);
630 gl.clearColor(0, 0, 1, 1);
631 gl.clear(gl.COLOR_BUFFER_BIT);
632 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
633 return index < half ? [0, 0, 255, 255] : [255, 0, 0, 255];
636 debug("test setting second half to NONE and drawing");
638 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
639 gl.useProgram(drawProgram);
640 wtu.drawUnitQuad(gl);
642 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
643 return index < half ? attachment.color : [255, 0, 0, 255];
646 debug("test setting buffers with even indices to NONE and clearing");
648 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
649 ext.drawBuffersWEBGL(bufs);
650 gl.clearColor(1, 0, 0, 1);
651 gl.clear(gl.COLOR_BUFFER_BIT);
652 ext.drawBuffersWEBGL(bufs3);
653 gl.clearColor(1, 0, 1, 1);
654 gl.clear(gl.COLOR_BUFFER_BIT);
656 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
657 return (index % 2) ? [255, 0, 0, 255] : [255, 0, 255, 255];
660 debug("test setting buffers with odd indices to NONE and drawing");
662 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
663 ext.drawBuffersWEBGL(bufs);
664 gl.clearColor(0, 0, 0, 1);
665 gl.clear(gl.COLOR_BUFFER_BIT);
666 gl.useProgram(drawProgram);
667 ext.drawBuffersWEBGL(bufs4);
668 wtu.drawUnitQuad(gl);
670 drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
671 return (index % 2 == 0) ? [0, 0, 0, 255] : attachment.color;
674 gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB1);
675 ext.drawBuffersWEBGL(bufs);
676 drawAndCheckAttachments(
677 halfFB1, "framebuffer that only has first half of attachments",
678 function(attachment, index) {
679 return index < half;
682 gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB2);
683 ext.drawBuffersWEBGL(bufs);
684 drawAndCheckAttachments(
685 halfFB2, "framebuffer that only has second half of attachments",
686 function(attachment, index) {
687 return index >= half;
690 if (maxUsable > 2) {
691 gl.bindFramebuffer(gl.FRAMEBUFFER, endsFB);
692 ext.drawBuffersWEBGL(bufs);
693 drawAndCheckAttachments(
694 endsFB, "framebuffer that only has first and last attachments",
695 function(attachment, index) {
696 return index == 0 || index == (maxUsable - 1);
699 gl.bindFramebuffer(gl.FRAMEBUFFER, middleFB);
700 ext.drawBuffersWEBGL(bufs);
701 drawAndCheckAttachments(
702 middleFB,
703 "framebuffer that has all but the first and last attachments",
704 function(attachment, index) {
705 return index != 0 && index != (maxUsable - 1);
710 debug("test switching between fbos does not affect any color attachment contents");
711 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
712 ext.drawBuffersWEBGL(nones);
714 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
715 ext.drawBuffersWEBGL(bufs);
716 gl.clearColor(1, 0, 0, 1);
717 gl.clear(gl.COLOR_BUFFER_BIT);
718 drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
720 // fb2 still has the NONE draw buffers from before, so this draw should be a no-op.
721 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
722 gl.useProgram(drawProgram);
723 wtu.drawUnitQuad(gl);
724 drawBuffersUtils.checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
726 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
727 gl.useProgram(drawProgram);
728 wtu.drawUnitQuad(gl);
729 drawBuffersUtils.checkAttachmentsForColor(attachments);
731 debug("test queries");
732 debug("check framebuffer with all attachments on");
733 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
734 for (var ii = 0; ii < maxUsable; ++ii) {
735 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL + " + ii + ")", "gl.COLOR_ATTACHMENT0 + " + ii);
738 debug("check framebuffer with all attachments off");
739 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
740 for (var ii = 0; ii < maxUsable; ++ii) {
741 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL + " + ii + ")", "gl.NONE");
744 debug("test attachment size mis-match");
745 gl.bindTexture(gl.TEXTURE_2D, attachments[0].texture);
746 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width * 2, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
747 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
748 shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
749 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
750 shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
752 gl.deleteFramebuffer(fb);
753 gl.deleteFramebuffer(fb2);
754 gl.deleteFramebuffer(halfFB1);
755 gl.deleteFramebuffer(halfFB2);
756 attachments.forEach(function(attachment) {
757 gl.deleteTexture(attachment.texture);
759 gl.deleteProgram(checkProgram);
760 gl.deleteProgram(redProgram);
761 gl.deleteProgram(redProgramWithExtension);
762 gl.deleteProgram(drawProgram);
765 function runPreserveTests() {
766 debug("");
767 debug("--------- preserve tests -----------");
769 debug("Testing that frame buffer is cleared after compositing");
770 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
772 gl.clearColor(1, 1, 0, 1);
773 gl.clear(gl.COLOR_BUFFER_BIT);
774 wtu.checkCanvas(gl, [255, 255, 0, 255], "should be yellow");
776 // set the draw buffer to NONE
777 ext.drawBuffersWEBGL([gl.NONE]);
778 gl.clearColor(1, 0, 1, 1);
779 gl.clear(gl.COLOR_BUFFER_BIT);
781 // make sure the canvas is still clear
782 wtu.checkCanvas(gl, [255, 255, 0, 255], "should be yellow");
784 wtu.waitForComposite(function() {
785 gl.clearColor(1, 0, 0, 1);
786 gl.clear(gl.COLOR_BUFFER_BIT);
787 wtu.checkCanvas(gl, [0, 0, 0, 0], "should be clear");
788 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
790 runEndTests();
794 function runEndTests() {
795 // Create new context and verify shader tests with no extension still succeeds.
796 debug("");
797 debug("Testing new context with no extension");
798 gl = wtu.create3DContext();
799 if (!gl) {
800 testFailed("New WebGL context does not exist");
801 } else {
802 testPassed("New WebGL context exists");
803 runEnumTestDisabled();
804 runShadersTestDisabled();
805 runAttachmentTestDisabled();
808 finishTest();
810 </script>
811 </body>
812 </html>