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.
10 <meta charset=
"utf-8">
11 <title>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>
18 <div id=
"description"></div>
19 <canvas id=
"canvas" width=
"64" height=
"64"> </canvas>
20 <div id=
"console"></div>
21 <script id=
"vshaderESSL3" type=
"x-shader/x-vertex">#version
300 es
24 gl_Position = a_position;
27 <script id=
"vshaderESSL1" type=
"x-shader/x-vertex">
28 attribute vec4 a_position;
30 gl_Position = a_position;
33 <script id=
"fshader" type=
"x-shader/x-fragment">#version
300 es
34 precision mediump float;
35 uniform vec4 u_colors[$(numDrawingBuffers)];
37 // Only one out variable - does not need explicit output layout (ESSL
3 section
4.3.8.2)
38 out vec4 my_FragData[$(numDrawingBuffers)];
40 $(assignUColorsToFragData)
43 <script id=
"fshaderDiscard" type=
"x-shader/x-fragment">#version
300 es
44 precision mediump float;
45 uniform vec4 u_colors[$(numDrawingBuffers)];
48 // Only one out variable - does not need explicit output layout (ESSL
3 section
4.3.8.2)
49 out vec4 my_FragData[$(numDrawingBuffers)];
51 $(assignUColorsToFragData)
57 <script id=
"fshaderRed" type=
"x-shader/x-fragment">#version
300 es
58 precision mediump float;
60 out vec4 my_FragColor;
62 my_FragColor = vec4(
1,
0,
0,
1);
65 <script id=
"fshaderBlueESSL1" type=
"x-shader/x-fragment">
66 precision mediump float;
69 gl_FragColor = vec4(
0,
0,
1,
1);
72 <script id=
"fshaderBuiltInConstEnabled" type=
"x-shader/x-fragment">#version
300 es
73 precision mediump float;
75 out vec4 my_FragColor;
77 my_FragColor = (gl_MaxDrawBuffers == $(numDrawingBuffers)) ? vec4(
0,
1,
0,
1) : vec4(
1,
0,
0,
1);
82 description("This test verifies the functionality of Multiple Render Targets.");
86 var wtu
= WebGLTestUtils
;
87 var canvas
= document
.getElementById("canvas");
88 var gl
= wtu
.create3DContext(canvas
, null, 2);
93 testFailed("WebGL context does not exist");
95 testPassed("WebGL context exists");
96 drawBuffersUtils
= WebGLDrawBuffersUtils(gl
);
98 if (testParameters()) {
104 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors");
107 function createDrawBuffersProgram(scriptId
, sub
) {
108 var fsource
= wtu
.getScript(scriptId
);
109 fsource
= wtu
.replaceParams(fsource
, sub
);
110 return wtu
.setupProgram(gl
, ["vshaderESSL3", fsource
], ["a_position"], undefined, true);
113 function runShadersTest() {
115 debug("test shaders");
117 var sub
= {numDrawingBuffers
: gl
.getParameter(gl
.MAX_DRAW_BUFFERS
)};
118 var program
= createDrawBuffersProgram("fshaderBuiltInConstEnabled", sub
);
119 wtu
.setupUnitQuad(gl
);
120 wtu
.clearAndDrawUnitQuad(gl
);
121 wtu
.checkCanvas(gl
, [0, 255, 0, 255], "should be green");
122 gl
.deleteProgram(program
);
123 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors");
126 function makeArray(size
, value
) {
128 for (var ii
= 0; ii
< size
; ++ii
) {
134 function runAttachmentTest() {
136 debug("test attachment enabled");
138 var maxDrawingBuffers
= gl
.getParameter(gl
.MAX_DRAW_BUFFERS
);
139 var maxColorAttachments
= gl
.getParameter(gl
.MAX_COLOR_ATTACHMENTS
);
141 var tex
= gl
.createTexture();
142 fb
= gl
.createFramebuffer();
143 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
144 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
145 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
+ maxColorAttachments
, gl
.TEXTURE_2D
, tex
, 0);
146 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "should not be able to attach pass the max attachment point: gl.COLOR_ATTACHMENT0 + " + maxColorAttachments
);
147 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
+ maxColorAttachments
- 1, gl
.TEXTURE_2D
, tex
, 0);
148 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be able to attach to the max attachment point: gl.COLOR_ATTACHMENT0 + " + (maxColorAttachments
- 1));
149 gl
.drawBuffers(makeArray(maxDrawingBuffers
, gl
.NONE
));
150 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be able to call drawBuffers with array NONE of size " + maxColorAttachments
);
151 var bufs
= drawBuffersUtils
.makeColorAttachmentArray(maxDrawingBuffers
);
152 gl
.drawBuffers(bufs
);
153 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be able to call drawBuffers with array attachments of size " + maxColorAttachments
);
155 gl
.drawBuffers(bufs
);
156 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be able to call drawBuffers with mixed array attachments of size " + maxColorAttachments
);
157 if (maxDrawingBuffers
> 1) {
158 bufs
[0] = gl
.COLOR_ATTACHMENT1
;
159 bufs
[1] = gl
.COLOR_ATTACHMENT0
;
160 gl
.drawBuffers(bufs
);
161 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "should not be able to call drawBuffers with out of order attachments of size " + maxColorAttachments
);
162 var bufs
= drawBuffersUtils
.makeColorAttachmentArray(Math
.floor(maxDrawingBuffers
/ 2));
163 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be able to call drawBuffers with short array of attachments of size " + bufs
.length
);
166 gl
.deleteFramebuffer(fb
);
167 gl
.deleteTexture(tex
);
168 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors");
170 debug("Testing drawBuffers and getParameter with bindFramebuffer, without drawing.");
171 fb
= gl
.createFramebuffer();
172 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
173 shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0");
174 shouldBe("gl.getParameter(gl.DRAW_BUFFER0+1)", "gl.NONE");
175 wtu
.shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawBuffers([gl.NONE])");
176 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, null);
177 shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.BACK");
178 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
179 shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.NONE");
181 wtu
.shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawBuffers([gl.NONE,gl.COLOR_ATTACHMENT0+1])");
182 shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.NONE");
183 shouldBe("gl.getParameter(gl.DRAW_BUFFER0+1)", "gl.COLOR_ATTACHMENT0+1");
185 wtu
.shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawBuffers([gl.COLOR_ATTACHMENT0,gl.COLOR_ATTACHMENT0+1])");
186 shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0");
187 shouldBe("gl.getParameter(gl.DRAW_BUFFER0+1)", "gl.COLOR_ATTACHMENT0+1");
189 wtu
.shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.deleteFramebuffer(fb)");
190 shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.BACK");
193 function makeColorByIndex(index
) {
194 var low
= (index
- 1) % 15 + 1;
195 var high
= (index
- 1) / 15;
197 var zeroOrOne = function(v
) {
201 var oneOrTwo = function(v
) {
205 var makeComponent = function(b0
, b1
, b2
) {
206 return Math
.floor(255 * zeroOrOne(b0
) / oneOrTwo(b1
) / oneOrTwo(b2
));
209 makeComponent(low
& (1 << 0), high
& (1 << 0), high
& (1 << 4)),
210 makeComponent(low
& (1 << 1), high
& (1 << 1), high
& (1 << 5)),
211 makeComponent(low
& (1 << 2), high
& (1 << 2), high
& (1 << 6)),
212 makeComponent(low
& (1 << 3), high
& (1 << 3), high
& (1 << 7)),
216 function runDrawTests() {
218 debug("--------- draw tests -----------");
219 var fb
= gl
.createFramebuffer();
220 var fb2
= gl
.createFramebuffer();
221 var halfFB1
= gl
.createFramebuffer();
222 var halfFB2
= gl
.createFramebuffer();
223 var endsFB
= gl
.createFramebuffer();
224 var middleFB
= gl
.createFramebuffer();
226 var maxDrawingBuffers
= gl
.getParameter(gl
.MAX_DRAW_BUFFERS
);
227 var maxUsable
= drawBuffersUtils
.getMaxUsableColorAttachments();
228 var half
= Math
.floor(maxUsable
/ 2);
229 var bufs
= drawBuffersUtils
.makeColorAttachmentArray(maxUsable
);
230 var nones
= makeArray(maxUsable
, gl
.NONE
);
232 [fb
, fb2
, halfFB1
, halfFB2
, endsFB
, middleFB
].forEach(function(fbo
) {
233 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
234 gl
.drawBuffers(bufs
);
237 var checkProgram
= wtu
.setupTexturedQuad(gl
);
238 var redProgram
= wtu
.setupProgram(gl
, ["vshaderESSL3", "fshaderRed"], ["a_position"]);
239 var blueProgramESSL1
= wtu
.setupProgram(gl
, ["vshaderESSL1", "fshaderBlueESSL1"], ["a_position"]);
242 for (var i
= 0; i
< maxDrawingBuffers
; ++i
) {
243 assignCode
.push(" my_FragData[" + i
+ "] = u_colors[" + i
+ "];");
246 var drawProgram
= createDrawBuffersProgram("fshader",
247 {numDrawingBuffers
: maxDrawingBuffers
, assignUColorsToFragData
: assignCode
.join("\n")});
250 var attachments
= [];
251 // Makes 6 framebuffers.
252 // fb and fb2 have all the attachments.
253 // halfFB1 has the first half of the attachments
254 // halfFB2 has the second half of the attachments
255 // endsFB has the first and last attachments
256 // middleFB has all but the first and last attachments
257 for (var ii
= 0; ii
< maxUsable
; ++ii
) {
258 var tex
= gl
.createTexture();
259 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
260 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, width
, height
, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
261 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MIN_FILTER
, gl
.NEAREST
);
262 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MAG_FILTER
, gl
.NEAREST
);
263 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_S
, gl
.CLAMP_TO_EDGE
);
264 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_T
, gl
.CLAMP_TO_EDGE
);
265 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
266 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
+ ii
, gl
.TEXTURE_2D
, tex
, 0);
267 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
268 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
+ ii
, gl
.TEXTURE_2D
, tex
, 0);
269 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, ii
< half
? halfFB1
: halfFB2
);
270 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
+ ii
, gl
.TEXTURE_2D
, tex
, 0);
271 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, (ii
== 0 || ii
== (maxUsable
- 1)) ? endsFB
: middleFB
);
272 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
+ ii
, gl
.TEXTURE_2D
, tex
, 0);
273 var location
= gl
.getUniformLocation(drawProgram
, "u_colors[" + ii
+ "]");
274 var color
= makeColorByIndex(ii
+ 1);
275 var floatColor
= [color
[0] / 255, color
[1] / 255, color
[2] / 255, color
[3] / 255];
276 gl
.uniform4fv(location
, floatColor
);
282 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
283 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
284 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
285 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
287 var drawAndCheckAttachments = function(testFB
, msg
, testFn
) {
288 debug("test clearing " + msg
);
290 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, testFB
);
292 attachments
.forEach(function(attachment
, index
) {
293 debug("attachment: " + index
+ " = " + wtu
.glEnumToString(gl
, gl
.getParameter(gl
.DRAW_BUFFER0
+ index
)) +
294 ", " + wtu
.glEnumToString(gl
, gl
.getFramebufferAttachmentParameter(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
+ index
, gl
.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
)));
297 if (gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) != gl
.FRAMEBUFFER_COMPLETE
) {
298 debug("framebuffer not complete");
303 // Clear all the attachments
304 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
305 gl
.clearColor(0, 0, 0, 0);
306 gl
.clear(gl
.COLOR_BUFFER_BIT
);
307 //drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
308 // return [0, 0, 0, 0];
312 // Clear some attachments using testFB
313 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, testFB
);
315 gl
.clearColor(0, 1, 0, 1);
316 gl
.clear(gl
.COLOR_BUFFER_BIT
);
317 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
318 return testFn(attachment
, index
) ? [0, 255, 0, 255] : [0, 0, 0, 0];
321 debug("test drawing to " + msg
);
323 // Draw to some attachments using testFB
324 gl
.useProgram(drawProgram
);
325 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, testFB
);
326 wtu
.drawUnitQuad(gl
);
328 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
329 return testFn(attachment
, index
) ? attachment
.color
: [0, 0, 0, 0];
333 gl
.useProgram(drawProgram
);
334 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
335 gl
.drawBuffers(bufs
);
336 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
337 gl
.drawBuffers(bufs
);
339 wtu
.drawUnitQuad(gl
);
341 debug("test that each texture got the correct color.");
343 drawBuffersUtils
.checkAttachmentsForColor(attachments
);
345 debug("test clearing clears all the textures");
346 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
347 gl
.clearColor(0, 1, 0, 1);
348 gl
.clear(gl
.COLOR_BUFFER_BIT
);
350 drawBuffersUtils
.checkAttachmentsForColor(attachments
, [0, 255, 0, 255]);
352 debug("test that NONE draws nothing");
353 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
354 gl
.drawBuffers(nones
);
355 gl
.useProgram(redProgram
);
356 wtu
.clearAndDrawUnitQuad(gl
);
358 drawBuffersUtils
.checkAttachmentsForColor(attachments
, [0, 255, 0, 255]);
360 // GLES3 spec section 3.9.2 Shader Outputs
361 debug("test that gl_FragColor only writes to color number zero");
362 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
363 gl
.drawBuffers(bufs
);
364 gl
.useProgram(blueProgramESSL1
);
366 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors");
367 wtu
.drawUnitQuad(gl
);
368 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "Active draw buffers with missing frag outputs.");
369 gl
.enable(gl
.RASTERIZER_DISCARD
);
370 wtu
.drawUnitQuad(gl
);
371 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors when RASTERIZER_DISCARD is enabled.");
372 gl
.disable(gl
.RASTERIZER_DISCARD
);
373 gl
.colorMask(false, false, false, false);
374 wtu
.drawUnitQuad(gl
);
375 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors when all 4 channels of color mask are disabled.");
376 gl
.colorMask(false, true, false, false);
377 wtu
.drawUnitQuad(gl
);
378 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "partially diabled color mask shall have no impact.");
379 gl
.colorMask(true, true, true, true);
381 gl
.drawBuffers([gl
.COLOR_ATTACHMENT0
]);
382 wtu
.drawUnitQuad(gl
);
384 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
385 return (index
== 0) ? [0, 0, 255, 255] : [0, 255, 0, 255];
388 // If there is only a single output, the location defaults to zero if not specified.
389 // See GLSL ES Spec 3.00.4, Section 4.3.8.2, Output Layout Qualifiers.
390 debug("test that an OpenGL ES Shading Language 3.00 shader with a single output color defaults to color number zero");
391 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
392 gl
.drawBuffers(bufs
);
393 gl
.useProgram(redProgram
);
395 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors");
396 wtu
.drawUnitQuad(gl
);
397 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "Active draw buffers with missing frag outputs.");
399 gl
.drawBuffers([gl
.COLOR_ATTACHMENT0
]);
400 wtu
.drawUnitQuad(gl
);
402 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
403 return (index
== 0) ? [255, 0, 0, 255] : [0, 255, 0, 255];
407 // Prepare for following tests by clearing all attachments to red.
408 debug("prepare by clearing all attachments to red");
409 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
410 gl
.drawBuffers(bufs
);
411 gl
.clearColor(1, 0, 0, 1);
412 gl
.clear(gl
.COLOR_BUFFER_BIT
);
413 drawBuffersUtils
.checkAttachmentsForColor(attachments
, [255, 0, 0, 255]);
415 var bufs1
= drawBuffersUtils
.makeColorAttachmentArray(maxUsable
);
416 var bufs2
= drawBuffersUtils
.makeColorAttachmentArray(maxUsable
);
417 for (var ii
= 0; ii
< maxUsable
; ++ii
) {
425 debug("test setting first half to NONE and clearing");
427 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
428 gl
.drawBuffers(bufs1
);
429 gl
.clearColor(0, 1, 0, 1);
430 gl
.clear(gl
.COLOR_BUFFER_BIT
);
432 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
433 return index
< half
? [255, 0, 0, 255] : [0, 255, 0, 255];
436 debug("test setting first half to NONE and drawing");
438 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
439 gl
.useProgram(drawProgram
);
440 wtu
.drawUnitQuad(gl
);
442 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
443 return index
< half
? [255, 0, 0, 255] : attachment
.color
;
446 debug("test setting second half to NONE and clearing");
448 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
449 gl
.drawBuffers(bufs
);
450 gl
.clearColor(1, 0, 0, 1);
451 gl
.clear(gl
.COLOR_BUFFER_BIT
);
452 gl
.drawBuffers(bufs2
);
453 gl
.clearColor(0, 0, 1, 1);
454 gl
.clear(gl
.COLOR_BUFFER_BIT
);
455 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
456 return index
< half
? [0, 0, 255, 255] : [255, 0, 0, 255];
459 debug("test setting second half to NONE and drawing");
461 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
462 gl
.useProgram(drawProgram
);
463 wtu
.drawUnitQuad(gl
);
465 drawBuffersUtils
.checkAttachmentsForColorFn(attachments
, function(attachment
, index
) {
466 return index
< half
? attachment
.color
: [255, 0, 0, 255];
469 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, halfFB1
);
470 gl
.drawBuffers(bufs
);
471 drawAndCheckAttachments(
472 halfFB1
, "framebuffer that only has first half of attachments",
473 function(attachment
, index
) {
477 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, halfFB2
);
478 gl
.drawBuffers(bufs
);
479 drawAndCheckAttachments(
480 halfFB2
, "framebuffer that only has second half of attachments",
481 function(attachment
, index
) {
482 return index
>= half
;
486 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, endsFB
);
487 gl
.drawBuffers(bufs
);
488 drawAndCheckAttachments(
489 endsFB
, "framebuffer that only has first and last attachments",
490 function(attachment
, index
) {
491 return index
== 0 || index
== (maxUsable
- 1);
494 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, middleFB
);
495 gl
.drawBuffers(bufs
);
496 drawAndCheckAttachments(
498 "framebuffer that has all but the first and last attachments",
499 function(attachment
, index
) {
500 return index
!= 0 && index
!= (maxUsable
- 1);
505 debug("test switching between fbos keeps drawbuffer state");
506 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
507 gl
.drawBuffers(nones
);
509 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
510 gl
.drawBuffers(bufs
);
511 gl
.clearColor(1, 0, 0, 1);
512 gl
.clear(gl
.COLOR_BUFFER_BIT
);
513 drawBuffersUtils
.checkAttachmentsForColor(attachments
, [255, 0, 0, 255]);
515 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
516 gl
.useProgram(drawProgram
);
517 wtu
.drawUnitQuad(gl
);
518 drawBuffersUtils
.checkAttachmentsForColor(attachments
, [255, 0, 0, 255]);
520 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
521 gl
.useProgram(drawProgram
);
522 wtu
.drawUnitQuad(gl
);
523 drawBuffersUtils
.checkAttachmentsForColor(attachments
);
525 debug("test that none of the attachments are written in case the fragment shader discards");
526 var discardProgram
= createDrawBuffersProgram("fshaderDiscard",
527 {numDrawingBuffers
: maxDrawingBuffers
, assignUColorsToFragData
: assignCode
.join("\n")});
528 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
529 gl
.drawBuffers(bufs
);
530 gl
.clearColor(0, 0, 0, 0);
531 gl
.clear(gl
.COLOR_BUFFER_BIT
);
532 gl
.useProgram(discardProgram
);
533 wtu
.drawUnitQuad(gl
);
534 drawBuffersUtils
.checkAttachmentsForColor(attachments
, [0, 0, 0, 0]);
536 debug("test queries");
537 debug("check framebuffer with all attachments on");
538 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
539 for (var ii
= 0; ii
< maxUsable
; ++ii
) {
540 shouldBe("gl.getParameter(gl.DRAW_BUFFER0 + " + ii
+ ")", "gl.COLOR_ATTACHMENT0 + " + ii
);
543 debug("check framebuffer with all attachments off");
544 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
545 for (var ii
= 0; ii
< maxUsable
; ++ii
) {
546 shouldBe("gl.getParameter(gl.DRAW_BUFFER0 + " + ii
+ ")", "gl.NONE");
549 // WebGL generates FRAMEBUFFER_INCOMPLETE_DIMENSIONS when attached images have different sizes.
550 // This behavior differs from GLES 3.
552 debug("test attachment size mis-match");
553 gl
.bindTexture(gl
.TEXTURE_2D
, attachments
[0].texture
);
554 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, width
* 2, height
, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
555 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
556 shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
557 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb2
);
558 shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
560 // TODO: Rendering when framebuffer attachments have mismatched size should be tested, maybe in a separate test.
562 gl
.deleteFramebuffer(fb
);
563 gl
.deleteFramebuffer(fb2
);
564 gl
.deleteFramebuffer(halfFB1
);
565 gl
.deleteFramebuffer(halfFB2
);
566 attachments
.forEach(function(attachment
) {
567 gl
.deleteTexture(attachment
.texture
);
569 gl
.deleteProgram(checkProgram
);
570 gl
.deleteProgram(redProgram
);
571 gl
.deleteProgram(drawProgram
);
574 function testParameters() {
576 debug("check that MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS are valid");
577 var maxDrawBuffers
= gl
.getParameter(gl
.MAX_DRAW_BUFFERS
);
578 var maxColorAttachments
= gl
.getParameter(gl
.MAX_COLOR_ATTACHMENTS
);
579 debug("MAX_DRAW_BUFFERS = " + maxDrawBuffers
);
580 debug("MAX_COLOR_ATTACHMENTS = " + maxColorAttachments
);
581 if (maxDrawBuffers
!= maxColorAttachments
) {
582 testFailed("MAX_DRAW_BUFFERS and MAX_COLOR_ATTACHMENTS should be the same");
585 if (maxDrawBuffers
< 4) {
586 testFailed("MAX_DRAW_BUFFERS should be at least 4");
593 var successfullyParsed
= true;
595 <script src=
"../../js/js-test-post.js"></script>