4 ** Copyright (c) 2013 The Khronos Group Inc.
6 ** Permission is hereby granted, free of charge, to any person obtaining a
7 ** copy of this software and/or associated documentation files (the
8 ** "Materials"), to deal in the Materials without restriction, including
9 ** without limitation the rights to use, copy, modify, merge, publish,
10 ** distribute, sublicense, and/or sell copies of the Materials, and to
11 ** permit persons to whom the Materials are furnished to do so, subject to
12 ** the following conditions:
14 ** The above copyright notice and this permission notice shall be included
15 ** in all copies or substantial portions of the Materials.
17 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
31 <meta charset="utf-8">
32 <title>WebGL WEBGL_draw_buffers Conformance Tests</title>
33 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
34 <script src="../../resources/js-test-pre.js"></script>
35 <script src="../resources/webgl-test-utils.js"></script>
38 <div id="description"></div>
39 <canvas id="canvas" width="64" height="64"> </canvas>
40 <div id="console"></div>
41 <script id="vshader" type="x-shader/x-vertex">
42 attribute vec4 a_position;
44 gl_Position = a_position;
47 <script id="fshader" type="x-shader/x-fragment">
48 #extension GL_EXT_draw_buffers : require
49 precision mediump float;
50 uniform vec4 u_colors[$(numDrawingBuffers)];
52 for (int i = 0; i < $(numDrawingBuffers); ++i) {
53 gl_FragData[i] = u_colors[i];
57 <script id="fshaderRed" type="x-shader/x-fragment">
58 precision mediump float;
60 gl_FragColor = vec4(1,0,0,1);
63 <script id="fshaderMacroDisabled" type="x-shader/x-fragment">
64 #ifdef GL_EXT_draw_buffers
67 precision mediump float;
69 gl_FragColor = vec4(0,0,0,0);
72 <script id="fshaderMacroEnabled" type="x-shader/x-fragment">
73 #ifdef GL_EXT_draw_buffers
74 #if GL_EXT_draw_buffers == 1
77 #define CODE this_code_is_bad_it_should_have_compiled
80 #define CODE this_code_is_bad_it_should_have_compiled
83 precision mediump float;
85 gl_FragColor = vec4(0,0,0,0);
88 <script id="fshaderBuiltInConstEnabled" type="x-shader/x-fragment">
89 precision mediump float;
91 gl_FragColor = (gl_MaxDrawBuffers == $(numDrawingBuffers)) ? vec4(0,1,0,1) : vec4(1,0,0,1);
96 description("This test verifies the functionality of the WEBGL_draw_buffers extension, if it is available.");
100 var wtu = WebGLTestUtils;
101 var canvas = document.getElementById("canvas");
102 var output = document.getElementById("console");
103 var gl = wtu.create3DContext(canvas);
107 var extensionConstants = [
108 { name: "MAX_COLOR_ATTACHMENTS_WEBGL", enum: 0x8CDF, expectedFn: function(v) { return v >= 4; }, passMsg: " should be >= 4"},
109 { name: "MAX_DRAW_BUFFERS_WEBGL", enum: 0x8824, expectedFn: function(v) { return v > 0; }, passMsg: " should be > 0"},
111 { name: "COLOR_ATTACHMENT0_WEBGL", enum: 0x8CE0, },
112 { name: "COLOR_ATTACHMENT1_WEBGL", enum: 0x8CE1, },
113 { name: "COLOR_ATTACHMENT2_WEBGL", enum: 0x8CE2, },
114 { name: "COLOR_ATTACHMENT3_WEBGL", enum: 0x8CE3, },
115 { name: "COLOR_ATTACHMENT4_WEBGL", enum: 0x8CE4, },
116 { name: "COLOR_ATTACHMENT5_WEBGL", enum: 0x8CE5, },
117 { name: "COLOR_ATTACHMENT6_WEBGL", enum: 0x8CE6, },
118 { name: "COLOR_ATTACHMENT7_WEBGL", enum: 0x8CE7, },
119 { name: "COLOR_ATTACHMENT8_WEBGL", enum: 0x8CE8, },
120 { name: "COLOR_ATTACHMENT9_WEBGL", enum: 0x8CE9, },
121 { name: "COLOR_ATTACHMENT10_WEBGL", enum: 0x8CEA, },
122 { name: "COLOR_ATTACHMENT11_WEBGL", enum: 0x8CEB, },
123 { name: "COLOR_ATTACHMENT12_WEBGL", enum: 0x8CEC, },
124 { name: "COLOR_ATTACHMENT13_WEBGL", enum: 0x8CED, },
125 { name: "COLOR_ATTACHMENT14_WEBGL", enum: 0x8CEE, },
126 { name: "COLOR_ATTACHMENT15_WEBGL", enum: 0x8CEF, },
128 { name: "DRAW_BUFFER0_WEBGL", enum: 0x8825, },
129 { name: "DRAW_BUFFER1_WEBGL", enum: 0x8826, },
130 { name: "DRAW_BUFFER2_WEBGL", enum: 0x8827, },
131 { name: "DRAW_BUFFER3_WEBGL", enum: 0x8828, },
132 { name: "DRAW_BUFFER4_WEBGL", enum: 0x8829, },
133 { name: "DRAW_BUFFER5_WEBGL", enum: 0x882A, },
134 { name: "DRAW_BUFFER6_WEBGL", enum: 0x882B, },
135 { name: "DRAW_BUFFER7_WEBGL", enum: 0x882C, },
136 { name: "DRAW_BUFFER8_WEBGL", enum: 0x882D, },
137 { name: "DRAW_BUFFER9_WEBGL", enum: 0x882E, },
138 { name: "DRAW_BUFFER10_WEBGL", enum: 0x882F, },
139 { name: "DRAW_BUFFER11_WEBGL", enum: 0x8830, },
140 { name: "DRAW_BUFFER12_WEBGL", enum: 0x8831, },
141 { name: "DRAW_BUFFER13_WEBGL", enum: 0x8832, },
142 { name: "DRAW_BUFFER14_WEBGL", enum: 0x8833, },
143 { name: "DRAW_BUFFER15_WEBGL", enum: 0x8834, },
147 testFailed("WebGL context does not exist");
149 testPassed("WebGL context exists");
151 // Run tests with extension disabled
152 runEnumTestDisabled();
153 runShadersTestDisabled();
154 runAttachmentTestDisabled();
158 // Query the extension and store globally so shouldBe can access it
159 ext = gl.getExtension("WEBGL_draw_buffers");
161 testPassed("No WEBGL_draw_buffers support -- this is legal");
163 runSupportedTest(false);
165 testPassed("Successfully enabled WEBGL_draw_buffers extension");
167 runSupportedTest(true);
168 runEnumTestEnabled();
169 runShadersTestEnabled();
170 runAttachmentTestEnabled();
176 function createExtDrawBuffersProgram(scriptId, sub) {
177 var fsource = wtu.getScript(scriptId);
178 fsource = wtu.replaceParams(fsource, sub);
179 wtu.addShaderSource(output, "fragment shader", fsource);
180 return wtu.setupProgram(gl, ["vshader", fsource], ["a_position"]);
183 function runSupportedTest(extensionEnabled) {
184 var supported = gl.getSupportedExtensions();
185 if (supported.indexOf("WEBGL_draw_buffers") >= 0) {
186 if (extensionEnabled) {
187 testPassed("WEBGL_draw_buffers listed as supported and getExtension succeeded");
189 testFailed("WEBGL_draw_buffers listed as supported but getExtension failed");
192 if (extensionEnabled) {
193 testFailed("WEBGL_draw_buffers not listed as supported but getExtension succeeded");
195 testPassed("WEBGL_draw_buffers not listed as supported and getExtension failed -- this is legal");
200 function runEnumTestDisabled() {
202 debug("Testing binding enum with extension disabled");
204 // Use the constant directly as we don't have the extension
205 extensionConstants.forEach(function(c) {
207 gl.getParameter(c.enum);
208 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, c.name + " should not be queryable if extension is disabled");
211 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
214 function runEnumTestEnabled() {
216 debug("Testing enums with extension enabled");
218 extensionConstants.forEach(function(c) {
219 shouldBe("ext." + c.name, "0x" + c.enum.toString(16));
221 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "before getParameter");
222 debug(c.name + ": 0x" + ext[c.name].toString(16));
223 expectTrue(c.expectedFn(gl.getParameter(ext[c.name])), "gl.getParameter(ext." + c.name + ")" + c.passMsg);
224 wtu.glErrorShouldBe(gl, gl.NO_ERROR, c.name + " query should succeed if extension is enabled");
228 shouldBeTrue("gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL) >= gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL)");
230 debug("Testing drawBuffersWEBGL with default drawing buffer");
231 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
232 wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, "ext.drawBuffersWEBGL([])");
233 wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, "ext.drawBuffersWEBGL([gl.NONE, gl.NONE])");
234 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "ext.drawBuffersWEBGL([ext.COLOR_ATTACHMENT0_WEBGL])");
235 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
236 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.NONE])");
237 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.NONE");
238 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "ext.drawBuffersWEBGL([gl.BACK])");
239 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL)", "gl.BACK");
240 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
243 function testShaders(tests, sub) {
244 tests.forEach(function(test) {
245 var shaders = [wtu.getScript(test.shaders[0]), wtu.replaceParams(wtu.getScript(test.shaders[1]), sub)];
246 wtu.addShaderSource(output, "vertex shader", shaders[0]);
247 wtu.addShaderSource(output, "fragment shader", shaders[1]);
248 var program = wtu.setupProgram(gl, shaders, ["a_position"]);
249 var programLinkedSuccessfully = (program != null);
250 var expectedProgramToLinkSuccessfully = (test.expectFailure == true);
251 expectTrue(programLinkedSuccessfully != expectedProgramToLinkSuccessfully, test.msg);
252 gl.deleteProgram(program);
256 function runShadersTestDisabled() {
258 debug("test shaders disabled");
261 { shaders: ["vshader", "fshaderMacroDisabled"],
262 msg: "GL_EXT_draw_buffers should not be defined in GLSL",
264 { shaders: ["vshader", "fshader"],
265 msg: "#extension GL_EXT_draw_buffers should not be allowed in GLSL",
268 ], {numDrawingBuffers: 1});
269 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
272 function runShadersTestEnabled() {
274 debug("test shaders enabled");
276 var sub = {numDrawingBuffers: gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL)};
278 { shaders: ["vshader", "fshaderMacroEnabled"],
279 msg: "GL_EXT_draw_buffers should be defined as 1 in GLSL",
281 { shaders: ["vshader", "fshader"],
282 msg: "fragment shader containing the #extension directive should compile",
286 var program = createExtDrawBuffersProgram("fshaderBuiltInConstEnabled", sub);
287 wtu.setupUnitQuad(gl);
288 wtu.clearAndDrawUnitQuad(gl);
289 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
290 gl.deleteProgram(program);
291 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
294 function runAttachmentTestDisabled() {
296 debug("test attachment disabled");
297 var tex = gl.createTexture();
298 var fb = gl.createFramebuffer();
299 gl.bindTexture(gl.TEXTURE_2D, tex);
300 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
301 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + 1, gl.TEXTURE_2D, tex, 0);
302 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach to gl.COLOR_ATTACHMENT1");
303 gl.deleteFramebuffer(fb);
304 gl.deleteTexture(tex);
305 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
308 function makeArray(size, value) {
310 for (var ii = 0; ii < size; ++ii) {
316 function makeColorAttachmentArray(size) {
318 for (var ii = 0; ii < size; ++ii) {
319 array.push(gl.COLOR_ATTACHMENT0 + ii);
324 function runAttachmentTestEnabled() {
326 debug("test attachment enabled");
328 var maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
329 var maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL);
331 var tex = gl.createTexture();
332 var fb = gl.createFramebuffer();
333 gl.bindTexture(gl.TEXTURE_2D, tex);
334 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
335 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments, gl.TEXTURE_2D, tex, 0);
336 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "should not be able to attach pass the max attachment point: gl.COLOR_ATTACHMENT0 + " + maxColorAttachments);
337 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + maxColorAttachments - 1, gl.TEXTURE_2D, tex, 0);
338 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to attach to the max attachment point: gl.COLOR_ATTACHMENT0 + " + (maxColorAttachments - 1));
339 ext.drawBuffersWEBGL(makeArray(maxDrawingBuffers, gl.NONE));
340 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with array NONE of size " + maxColorAttachments);
341 var bufs = makeColorAttachmentArray(maxDrawingBuffers);
342 ext.drawBuffersWEBGL(bufs);
343 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with array attachments of size " + maxColorAttachments);
345 ext.drawBuffersWEBGL(bufs);
346 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with mixed array attachments of size " + maxColorAttachments);
347 if (maxDrawingBuffers > 1) {
348 bufs[0] = ext.COLOR_ATTACHMENT1_WEBGL;
349 bufs[1] = ext.COLOR_ATTACHMENT0_WEBGL;
350 ext.drawBuffersWEBGL(bufs);
351 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should not be able to call drawBuffersWEBGL with out of order attachments of size " + maxColorAttachments);
352 var bufs = makeColorAttachmentArray(Math.floor(maxDrawingBuffers / 2));
353 ext.drawBuffersWEBGL(bufs);
354 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call drawBuffersWEBGL with short array of attachments of size " + bufs.length);
357 gl.deleteFramebuffer(fb);
358 gl.deleteTexture(tex);
359 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
362 function makeColorByIndex(index) {
363 var low = (index - 1) % 15 + 1;
364 var high = (index - 1) / 15;
366 var zeroOrOne = function(v) {
370 var oneOrTwo = function(v) {
374 var makeComponent = function(b0, b1, b2) {
375 return Math.floor(255 * zeroOrOne(b0) / oneOrTwo(b1) / oneOrTwo(b2));
378 makeComponent(low & (1 << 0), high & (1 << 0), high & (1 << 4)),
379 makeComponent(low & (1 << 1), high & (1 << 1), high & (1 << 5)),
380 makeComponent(low & (1 << 2), high & (1 << 2), high & (1 << 6)),
381 makeComponent(low & (1 << 3), high & (1 << 3), high & (1 << 7)),
385 function runDrawTests() {
387 debug("--------- draw tests -----------");
388 var fb = gl.createFramebuffer();
389 var fb2 = gl.createFramebuffer();
390 var halfFB1 = gl.createFramebuffer();
391 var halfFB2 = gl.createFramebuffer();
392 var endsFB = gl.createFramebuffer();
393 var middleFB = gl.createFramebuffer();
395 var maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
396 var maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL);
397 var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
398 var maxUsable = Math.min(maxDrawingBuffers, maxColorAttachments, maxUniformVectors);
399 var half = Math.floor(maxUsable / 2);
400 var bufs = makeColorAttachmentArray(maxUsable);
401 var nones = makeArray(maxUsable, gl.NONE);
403 [fb, fb2, halfFB1, halfFB2, endsFB, middleFB].forEach(function(fbo) {
404 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
405 ext.drawBuffersWEBGL(bufs);
408 var checkProgram = wtu.setupTexturedQuad(gl);
409 var redProgram = wtu.setupProgram(gl, ["vshader", "fshaderRed"], ["a_position"]);
410 var drawProgram = createExtDrawBuffersProgram("fshader", {numDrawingBuffers: maxDrawingBuffers});
413 var attachments = [];
414 // Makes 6 framebuffers.
415 // fb and fb2 have all the attachments.
416 // halfFB1 has the first half of the attachments
417 // halfFB2 has the second half of the attachments
418 // endsFB has the first and last attachments
419 // middleFB has all but the first and last attachments
420 for (var ii = 0; ii < maxUsable; ++ii) {
421 var tex = gl.createTexture();
422 gl.bindTexture(gl.TEXTURE_2D, tex);
423 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
424 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
425 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
426 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
427 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
428 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
429 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
430 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
431 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
432 gl.bindFramebuffer(gl.FRAMEBUFFER, ii < half ? halfFB1 : halfFB2);
433 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
434 gl.bindFramebuffer(gl.FRAMEBUFFER, (ii == 0 || ii == (maxUsable - 1)) ? endsFB : middleFB);
435 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ii, gl.TEXTURE_2D, tex, 0);
436 var location = gl.getUniformLocation(drawProgram, "u_colors[" + ii + "]");
437 var color = makeColorByIndex(ii + 1);
438 var floatColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
439 gl.uniform4fv(location, floatColor);
446 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
447 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
448 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
449 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
451 var checkAttachmentsForColorFn = function(attachments, colorFn) {
452 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
453 gl.useProgram(checkProgram);
454 attachments.forEach(function(attachment, index) {
455 gl.bindTexture(gl.TEXTURE_2D, attachment.texture);
456 wtu.clearAndDrawUnitQuad(gl);
457 var expectedColor = colorFn(attachment, index);
459 expectedColor.forEach(function(v) {
460 if (v != 0 && v != 255) {
464 wtu.checkCanvas(gl, expectedColor, "attachment " + index + " should be " + expectedColor.toString(), tolerance);
469 var checkAttachmentsForColor = function(attachments, color) {
470 checkAttachmentsForColorFn(attachments, function(attachment, index) {
471 return color || attachment.color;
475 var drawAndCheckAttachments = function(testFB, msg, testFn) {
476 debug("test clearing " + msg);
478 gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
480 attachments.forEach(function(attachment, index) {
481 debug("attachment: " + index + " = " + wtu.glEnumToString(gl, gl.getParameter(ext.DRAW_BUFFER0_WEBGL + index)) +
482 ", " + wtu.glEnumToString(gl, gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + index, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)));
485 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
486 debug("framebuffer not complete");
491 // Clear all the attachments
492 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
493 gl.clearColor(0, 0, 0, 0);
494 gl.clear(gl.COLOR_BUFFER_BIT);
495 //checkAttachmentsForColorFn(attachments, function(attachment, index) {
496 // return [0, 0, 0, 0];
500 // Clear some attachments using testFB
501 gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
503 gl.clearColor(0, 1, 0, 1);
504 gl.clear(gl.COLOR_BUFFER_BIT);
505 checkAttachmentsForColorFn(attachments, function(attachment, index) {
506 return testFn(attachment, index) ? [0, 255, 0, 255] : [0, 0, 0, 0];
509 debug("test drawing to " + msg);
511 // Draw to some attachments using testFB
512 gl.useProgram(drawProgram);
513 gl.bindFramebuffer(gl.FRAMEBUFFER, testFB);
514 wtu.drawUnitQuad(gl);
516 checkAttachmentsForColorFn(attachments, function(attachment, index) {
517 return testFn(attachment, index) ? attachment.color : [0, 0, 0, 0];
521 gl.useProgram(drawProgram);
522 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
523 ext.drawBuffersWEBGL(bufs);
524 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
525 ext.drawBuffersWEBGL(bufs);
527 wtu.drawUnitQuad(gl);
529 debug("test that each texture got the correct color.");
531 checkAttachmentsForColor(attachments);
533 debug("test clearing clears all the textures");
534 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
535 gl.clearColor(0, 1, 0, 1);
536 gl.clear(gl.COLOR_BUFFER_BIT);
538 checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
540 debug("test that NONE draws nothing");
541 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
542 ext.drawBuffersWEBGL(nones);
543 gl.useProgram(redProgram);
544 wtu.clearAndDrawUnitQuad(gl);
546 checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
548 debug("test that gl_FragColor broadcasts");
549 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
550 ext.drawBuffersWEBGL(bufs);
551 gl.useProgram(redProgram);
552 wtu.drawUnitQuad(gl);
554 checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
557 var bufs1 = makeColorAttachmentArray(maxUsable);
558 var bufs2 = makeColorAttachmentArray(maxUsable);
559 for (var ii = 0; ii < maxUsable; ++ii) {
567 debug("test setting first half to NONE and clearing");
569 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
570 ext.drawBuffersWEBGL(bufs1);
571 gl.clearColor(0, 1, 0, 1);
572 gl.clear(gl.COLOR_BUFFER_BIT);
574 checkAttachmentsForColorFn(attachments, function(attachment, index) {
575 return index < half ? [255, 0, 0, 255] : [0, 255, 0, 255];
578 debug("test setting first half to NONE and drawing");
580 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
581 gl.useProgram(drawProgram);
582 wtu.drawUnitQuad(gl);
584 checkAttachmentsForColorFn(attachments, function(attachment, index) {
585 return index < half ? [255, 0, 0, 255] : attachment.color;
588 debug("test setting second half to NONE and clearing");
590 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
591 ext.drawBuffersWEBGL(bufs);
592 gl.clearColor(1, 0, 0, 1);
593 gl.clear(gl.COLOR_BUFFER_BIT);
594 ext.drawBuffersWEBGL(bufs2);
595 gl.clearColor(0, 0, 1, 1);
596 gl.clear(gl.COLOR_BUFFER_BIT);
597 checkAttachmentsForColorFn(attachments, function(attachment, index) {
598 return index < half ? [0, 0, 255, 255] : [255, 0, 0, 255];
601 debug("test setting second half to NONE and drawing");
603 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
604 gl.useProgram(drawProgram);
605 wtu.drawUnitQuad(gl);
607 checkAttachmentsForColorFn(attachments, function(attachment, index) {
608 return index < half ? attachment.color : [255, 0, 0, 255];
611 gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB1);
612 ext.drawBuffersWEBGL(bufs);
613 drawAndCheckAttachments(
614 halfFB1, "framebuffer that only has first half of attachments",
615 function(attachment, index) {
619 gl.bindFramebuffer(gl.FRAMEBUFFER, halfFB2);
620 ext.drawBuffersWEBGL(bufs);
621 drawAndCheckAttachments(
622 halfFB2, "framebuffer that only has second half of attachments",
623 function(attachment, index) {
624 return index >= half;
628 gl.bindFramebuffer(gl.FRAMEBUFFER, endsFB);
629 ext.drawBuffersWEBGL(bufs);
630 drawAndCheckAttachments(
631 endsFB, "framebuffer that only has first and last attachments",
632 function(attachment, index) {
633 return index == 0 || index == (maxUsable - 1);
636 gl.bindFramebuffer(gl.FRAMEBUFFER, middleFB);
637 ext.drawBuffersWEBGL(bufs);
638 drawAndCheckAttachments(
640 "framebuffer that has all but the first and last attachments",
641 function(attachment, index) {
642 return index != 0 && index != (maxUsable - 1);
647 debug("test switching between fbos does not affect any color attachment contents");
648 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
649 ext.drawBuffersWEBGL(nones);
651 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
652 ext.drawBuffersWEBGL(bufs);
653 gl.clearColor(1, 0, 0, 1);
654 gl.clear(gl.COLOR_BUFFER_BIT);
655 checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
657 // fb2 still has the NONE draw buffers from before, so this draw should be a no-op.
658 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
659 gl.useProgram(drawProgram);
660 wtu.drawUnitQuad(gl);
661 checkAttachmentsForColor(attachments, [255, 0, 0, 255]);
663 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
664 gl.useProgram(drawProgram);
665 wtu.drawUnitQuad(gl);
666 checkAttachmentsForColor(attachments);
668 debug("test queries");
669 debug("check framebuffer with all attachments on");
670 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
671 for (var ii = 0; ii < maxUsable; ++ii) {
672 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL + " + ii + ")", "gl.COLOR_ATTACHMENT0 + " + ii);
675 debug("check framebuffer with all attachments off");
676 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
677 for (var ii = 0; ii < maxUsable; ++ii) {
678 shouldBe("gl.getParameter(ext.DRAW_BUFFER0_WEBGL + " + ii + ")", "gl.NONE");
681 debug("test attachment size mis-match");
682 gl.bindTexture(gl.TEXTURE_2D, attachments[0].texture);
683 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width * 2, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
684 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
685 shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
686 gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
687 shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
689 gl.deleteFramebuffer(fb);
690 gl.deleteFramebuffer(fb2);
691 gl.deleteFramebuffer(halfFB1);
692 gl.deleteFramebuffer(halfFB2);
693 attachments.forEach(function(attachment) {
694 gl.deleteTexture(attachment.texture);
696 gl.deleteProgram(checkProgram);
697 gl.deleteProgram(redProgram);
698 gl.deleteProgram(drawProgram);
701 function runPreserveTests() {
703 debug("--------- preserve tests -----------");
705 debug("Testing that frame buffer is cleared after compositing");
706 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
708 gl.clearColor(1, 1, 0, 1);
709 gl.clear(gl.COLOR_BUFFER_BIT);
710 wtu.checkCanvas(gl, [255, 255, 0, 255], "should be yellow");
712 // set the draw buffer to NONE
713 ext.drawBuffersWEBGL([gl.NONE]);
714 gl.clearColor(1, 0, 1, 1);
715 gl.clear(gl.COLOR_BUFFER_BIT);
717 // make sure the canvas is still clear
718 wtu.checkCanvas(gl, [255, 255, 0, 255], "should be yellow");
720 wtu.waitForComposite(function() {
721 gl.clearColor(1, 0, 0, 1);
722 gl.clear(gl.COLOR_BUFFER_BIT);
723 wtu.checkCanvas(gl, [0, 0, 0, 0], "should be clear");
724 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");