Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / conformance / renderbuffers / framebuffer-object-attachment.html
blobb15e1386c7e3b75a68ae08824c83822923daa2b0
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 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
12 <script src="../../js/js-test-pre.js"></script>
13 <script src="../../js/webgl-test-utils.js"></script>
14 </head>
15 <body>
16 <div id="description"></div>
17 <div id="console"></div>
19 <script>
20 "use strict";
21 var wtu = WebGLTestUtils;
22 var gl;
23 var fbo;
24 var depthBuffer;
25 var stencilBuffer;
26 var depthStencilBuffer;
27 var colorBuffer;
28 var width;
29 var height;
31 var ALLOW_COMPLETE = 0x01;
32 var ALLOW_UNSUPPORTED = 0x02;
33 var ALLOW_INCOMPLETE_ATTACHMENT = 0x04;
35 function checkFramebufferForAllowedStatuses(allowedStatuses)
37 // If the framebuffer is in an error state for multiple reasons,
38 // we can't guarantee which one will be reported.
39 var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
40 var statusAllowed = ((allowedStatuses & ALLOW_COMPLETE) && (status == gl.FRAMEBUFFER_COMPLETE)) ||
41 ((allowedStatuses & ALLOW_UNSUPPORTED) && (status == gl.FRAMEBUFFER_UNSUPPORTED)) ||
42 ((allowedStatuses & ALLOW_INCOMPLETE_ATTACHMENT) && (status == gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT));
43 var msg = "gl.checkFramebufferStatus(gl.FRAMEBUFFER) returned " + status;
44 if (statusAllowed)
45 testPassed(msg);
46 else
47 testFailed(msg);
50 function checkBufferBits(attachment0, attachment1)
52 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
53 return;
55 var haveDepthBuffer = attachment0 == gl.DEPTH_ATTACHMENT ||
56 attachment0 == gl.DEPTH_STENCIL_ATTACHMENT ||
57 attachment1 == gl.DEPTH_ATTACHMENT ||
58 attachment1 == gl.DEPTH_STENCIL_ATTACHMENT;
59 var haveStencilBuffer = attachment0 == gl.STENCIL_ATTACHMENT ||
60 attachment0 == gl.DEPTH_STENCIL_ATTACHMENT ||
61 attachment1 == gl.STENCIL_ATTACHMENT ||
62 attachment1 == gl.DEPTH_STENCIL_ATTACHMENT;
64 shouldBeTrue("gl.getParameter(gl.RED_BITS) + gl.getParameter(gl.GREEN_BITS) + gl.getParameter(gl.BLUE_BITS) + gl.getParameter(gl.ALPHA_BITS) >= 16");
66 if (haveDepthBuffer)
67 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) >= 16");
68 else
69 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) == 0");
71 if (haveStencilBuffer)
72 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) >= 8");
73 else
74 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) == 0");
77 function testAttachment(attachment, buffer, allowedStatuses)
79 shouldBeNonNull("fbo = gl.createFramebuffer()");
80 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
81 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
82 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, buffer);
83 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
84 checkFramebufferForAllowedStatuses(allowedStatuses);
85 if ((allowedStatuses & ALLOW_COMPLETE) == 0) {
86 gl.clear(gl.COLOR_BUFFER_BIT);
87 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION);
88 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(width * height * 4));
89 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION);
91 checkBufferBits(attachment);
92 gl.deleteFramebuffer(fbo);
95 function testAttachments(attachment0, buffer0, attachment1, buffer1, allowedStatuses)
97 shouldBeNonNull("fbo = gl.createFramebuffer()");
98 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
99 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
100 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment0, gl.RENDERBUFFER, buffer0);
101 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
102 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment1, gl.RENDERBUFFER, buffer1);
103 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
104 checkFramebufferForAllowedStatuses(allowedStatuses);
105 checkBufferBits(attachment0, attachment1);
106 gl.deleteFramebuffer(fbo);
109 function testColorRenderbuffer(internalformat, allowedStatuses)
111 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
112 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
113 gl.renderbufferStorage(gl.RENDERBUFFER, internalformat, width, height);
114 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
115 testAttachment(gl.COLOR_ATTACHMENT0, colorBuffer, allowedStatuses);
118 function testDepthStencilRenderbuffer(allowedStatuses)
120 shouldBeNonNull("depthStencilBuffer = gl.createRenderbuffer()");
121 gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
122 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
123 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
125 // OpenGL itself doesn't seem to guarantee that e.g. a 2 x 0
126 // renderbuffer will report 2 for its width when queried.
127 if (!(height == 0 && width > 0))
128 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)", "width");
129 if (!(width == 0 && height > 0))
130 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT)", "height");
131 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_INTERNAL_FORMAT)", "gl.DEPTH_STENCIL");
132 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_RED_SIZE)", "0");
133 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_GREEN_SIZE)", "0");
134 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_BLUE_SIZE)", "0");
135 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_ALPHA_SIZE)", "0");
136 // Avoid verifying these for zero-sized renderbuffers for the time
137 // being since it appears that even OpenGL doesn't guarantee them.
138 if (width > 0 && height > 0) {
139 shouldBeTrue("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_DEPTH_SIZE) > 0");
140 shouldBeTrue("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_STENCIL_SIZE) > 0");
142 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
143 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatuses);
144 testDepthStencilDepthStencil();
147 function testDepthStencilDepthStencil()
149 if (!width || !height) {
150 return;
153 var tests = [
154 { firstFormat: gl.DEPTH_COMPONENT16,
155 firstAttach: gl.DEPTH_ATTACHMENT,
156 secondFormat: gl.DEPTH_STENCIL,
157 secondAttach: gl.DEPTH_STENCIL_ATTACHMENT
159 { firstFormat: gl.DEPTH_STENCIL,
160 firstAttach: gl.DEPTH_STENCIL_ATTACHMENT,
161 secondFormat: gl.DEPTH_COMPONENT16,
162 secondAttach: gl.DEPTH_ATTACHMENT
165 for (var ii = 0; ii < tests.length; ++ii) {
166 var test = tests[ii];
167 for (var jj = 0; jj < 2; ++jj) {
168 var fbo = gl.createFramebuffer();
169 var tex = gl.createTexture();
170 var firstRb = gl.createRenderbuffer();
172 debug("");
173 debug("test: " + wtu.glEnumToString(gl, test.firstFormat) + " vs " + wtu.glEnumToString(gl, test.secondFormat) + " with " + (jj ? "unbind" : "delete"));
175 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
176 // attach texture as color
177 gl.bindTexture(gl.TEXTURE_2D, tex);
178 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
179 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
181 // attach first
182 gl.bindRenderbuffer(gl.RENDERBUFFER, firstRb);
183 gl.renderbufferStorage(gl.RENDERBUFFER, test.firstFormat, width, height);
184 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, test.firstAttach, gl.RENDERBUFFER, firstRb);
186 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
187 gl.enable(gl.DEPTH_TEST);
188 var program = wtu.setupColorQuad(gl);
189 // Test it works
190 wtu.drawUByteColorQuad(gl, [0, 255, 0, 255]);
191 wtu.drawUByteColorQuad(gl, [255, 0, 0, 255]); // should not draw since DEPTH_FUNC == LESS
192 wtu.checkCanvasRect(gl, 0, 0, width, height, [0, 255, 0, 255], "should be green");
194 var secondRb = gl.createRenderbuffer();
196 // attach second
197 gl.bindRenderbuffer(gl.RENDERBUFFER, secondRb);
198 gl.renderbufferStorage(gl.RENDERBUFFER, test.secondFormat, width, height);
199 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, test.secondAttach, gl.RENDERBUFFER, secondRb);
201 if (jj == 0) {
202 // now delete it
203 debug("test deleting second renderbuffer");
204 gl.deleteRenderbuffer(secondRb);
205 } else {
206 // unbind it
207 debug("test unbinding second renderbuffer");
208 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, test.secondAttach, gl.RENDERBUFFER, null);
211 // If the first attachment is not restored this may fail
212 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
213 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
215 // If the first attachment is not restored this may fail.
216 gl.clear(gl.DEPTH_BUFFER_BIT);
217 wtu.drawUByteColorQuad(gl, [0, 255, 0, 255]);
218 wtu.drawUByteColorQuad(gl, [255, 0, 0, 255]); // should not draw since DEPTH_FUNC == LESS
219 wtu.checkCanvasRect(gl, 0, 0, width, height, [0, 255, 0, 255], "should be green");
220 gl.disable(gl.DEPTH_TEST);
222 if (jj == 1) {
223 gl.deleteRenderbuffer(secondRb);
226 gl.deleteRenderbuffer(secondRb);
227 gl.deleteFramebuffer(fbo);
230 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
233 description("Test framebuffer object attachment behaviors");
235 shouldBeNonNull("gl = wtu.create3DContext()");
237 function testFramebufferRequiredCombinations() {
238 debug("Checking combinations of framebuffer attachments required to be valid");
240 // Per discussion with the OpenGL ES working group, the following framebuffer attachment
241 // combinations are required to work in all WebGL implementations:
242 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
243 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
244 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
246 var fbo = gl.createFramebuffer();
247 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
249 var width = 64;
250 var height = 64;
252 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
253 var texture = gl.createTexture();
254 gl.bindTexture(gl.TEXTURE_2D, texture);
255 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
256 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
257 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
258 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
259 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
260 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
261 checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
262 checkBufferBits();
264 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
265 var renderbuffer = gl.createRenderbuffer();
266 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
267 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
268 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
269 checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
270 checkBufferBits(gl.DEPTH_ATTACHMENT);
271 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null);
273 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
274 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
275 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
276 checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
277 checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT);
279 // Clean up
280 gl.deleteRenderbuffer(renderbuffer);
281 gl.deleteTexture(texture);
282 gl.deleteFramebuffer(fbo);
285 testFramebufferRequiredCombinations();
287 for (width = 0; width <= 2; width += 2)
289 for (height = 0; height <= 2; height += 2)
291 debug("");
292 debug("Dimensions " + width + " x " + height);
294 debug("Create renderbuffers");
295 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
296 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
297 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, width, height);
298 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
299 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
300 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
301 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
302 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
303 shouldBeNonNull("stencilBuffer = gl.createRenderbuffer()");
304 gl.bindRenderbuffer(gl.RENDERBUFFER, stencilBuffer);
305 gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, width, height);
306 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
307 shouldBeNonNull("depthStencilBuffer = gl.createRenderbuffer()");
308 gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
309 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
310 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
312 var allowedStatusForGoodCase
313 = (width == 0 || height == 0) ? ALLOW_INCOMPLETE_ATTACHMENT : ALLOW_COMPLETE;
315 // some cases involving stencil seem to be implementation-dependent
316 var allowedStatusForImplDependentCase = allowedStatusForGoodCase | ALLOW_UNSUPPORTED;
318 debug("Attach depth using DEPTH_ATTACHMENT");
319 testAttachment(gl.DEPTH_ATTACHMENT, depthBuffer, allowedStatusForGoodCase);
320 debug("Attach depth using STENCIL_ATTACHMENT");
321 testAttachment(gl.STENCIL_ATTACHMENT, depthBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
322 debug("Attach depth using DEPTH_STENCIL_ATTACHMENT");
323 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
324 debug("Attach stencil using STENCIL_ATTACHMENT");
325 testAttachment(gl.STENCIL_ATTACHMENT, stencilBuffer, allowedStatusForImplDependentCase);
326 debug("Attach stencil using DEPTH_ATTACHMENT");
327 testAttachment(gl.DEPTH_ATTACHMENT, stencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
328 debug("Attach stencil using DEPTH_STENCIL_ATTACHMENT");
329 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, stencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
330 debug("Attach depthStencil using DEPTH_STENCIL_ATTACHMENT");
331 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatusForGoodCase);
332 debug("Attach depthStencil using DEPTH_ATTACHMENT");
333 testAttachment(gl.DEPTH_ATTACHMENT, depthStencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
334 debug("Attach depthStencil using STENCIL_ATTACHMENT");
335 testAttachment(gl.STENCIL_ATTACHMENT, depthStencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
337 var allowedStatusForConflictedAttachment
338 = (width == 0 || height == 0) ? ALLOW_UNSUPPORTED | ALLOW_INCOMPLETE_ATTACHMENT
339 : ALLOW_UNSUPPORTED;
341 debug("Attach depth, then stencil, causing conflict");
342 testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.STENCIL_ATTACHMENT, stencilBuffer, allowedStatusForConflictedAttachment);
343 debug("Attach stencil, then depth, causing conflict");
344 testAttachments(gl.STENCIL_ATTACHMENT, stencilBuffer, gl.DEPTH_ATTACHMENT, depthBuffer, allowedStatusForConflictedAttachment);
345 debug("Attach depth, then depthStencil, causing conflict");
346 testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatusForConflictedAttachment);
347 debug("Attach depthStencil, then depth, causing conflict");
348 testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.DEPTH_ATTACHMENT, depthBuffer, allowedStatusForConflictedAttachment);
349 debug("Attach stencil, then depthStencil, causing conflict");
350 testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatusForConflictedAttachment);
351 debug("Attach depthStencil, then stencil, causing conflict");
352 testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.STENCIL_ATTACHMENT, stencilBuffer, allowedStatusForConflictedAttachment);
354 debug("Attach color renderbuffer with internalformat == RGBA4");
355 testColorRenderbuffer(gl.RGBA4, allowedStatusForGoodCase);
357 debug("Attach color renderbuffer with internalformat == RGB5_A1");
358 testColorRenderbuffer(gl.RGB5_A1, allowedStatusForGoodCase);
360 debug("Attach color renderbuffer with internalformat == RGB565");
361 testColorRenderbuffer(gl.RGB565, allowedStatusForGoodCase);
363 debug("Create and attach depthStencil renderbuffer");
364 testDepthStencilRenderbuffer(allowedStatusForGoodCase);
368 // Determine if we can attach both color and depth or color and depth_stencil
369 var depthFormat;
370 var depthAttachment;
372 function checkValidColorDepthCombination() {
373 shouldBeNonNull("fbo = gl.createFramebuffer()");
374 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
375 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
376 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
377 gl.framebufferRenderbuffer(
378 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
379 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
381 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
382 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
384 return tryDepth(gl.DEPTH_COMPONENT16, gl.DEPTH_ATTACHMENT) || tryDepth(gl.DEPTH_STENCIL, gl.DEPTH_STENCIL_ATTACHMENT);
386 function tryDepth(try_format, try_attachment) {
387 if (depthAttachment) {
388 // If we've tried once unattach the old one.
389 gl.framebufferRenderbuffer(
390 gl.FRAMEBUFFER, depthAttachment, gl.RENDERBUFFER, null);
392 depthFormat = try_format;
393 depthAttachment = try_attachment;
394 gl.framebufferRenderbuffer(
395 gl.FRAMEBUFFER, depthAttachment, gl.RENDERBUFFER, depthBuffer);
396 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 16, 16);
397 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
398 return gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE;
402 if (checkValidColorDepthCombination()) {
403 testFramebufferIncompleteDimensions();
404 testFramebufferIncompleteAttachment();
405 testFramebufferIncompleteMissingAttachment();
406 testUsingIncompleteFramebuffer();
407 testReadingFromMissingAttachment();
408 testBindRenderbufferBeforeFramebufferAttach();
411 function checkFramebuffer(expected) {
412 var actual = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
413 var msg = "gl.checkFramebufferStatus(gl.FRAMEBUFFER) should be " + wtu.glEnumToString(gl, expected) + " was " + wtu.glEnumToString(gl, actual);
414 if (expected != gl.FRAMEBUFFER_COMPLETE) {
415 msg += " or FRAMEBUFFER_UNSUPPORTED";
417 if (actual == expected ||
418 (expected != gl.FRAMEBUFFER_COMPLETE &&
419 actual == gl.FRAMBUFFER_UNSUPPORTED)) {
420 testPassed(msg);
421 } else {
422 testFailed(msg);
426 function testUsingIncompleteFramebuffer() {
427 debug("");
428 debug("Test drawing or reading from an incomplete framebuffer");
429 var program = wtu.setupTexturedQuad(gl);
430 var tex = gl.createTexture();
431 wtu.fillTexture(gl, tex, 1, 1, [0,255,0,255]);
433 shouldBeNonNull("fbo = gl.createFramebuffer()");
434 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
435 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
436 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
437 gl.framebufferRenderbuffer(
438 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
439 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
441 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
442 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
443 gl.framebufferRenderbuffer(
444 gl.FRAMEBUFFER, depthAttachment, gl.RENDERBUFFER, depthBuffer);
445 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 16, 16);
446 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
447 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
449 // We pick this combination because it works on desktop OpenGL but should not work on OpenGL ES 2.0
450 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 32, 16);
451 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
452 debug("");
453 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
454 testRenderingAndReading();
456 shouldBeNonNull("fbo2 = gl.createFramebuffer()");
457 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2);
458 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
459 debug("");
460 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
461 testRenderingAndReading();
463 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
464 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
465 gl.framebufferRenderbuffer(
466 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
467 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0);
468 debug("");
469 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
470 testRenderingAndReading();
472 function testRenderingAndReading() {
473 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
474 wtu.clearAndDrawUnitQuad(gl);
475 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "drawArrays with incomplete framebuffer");
476 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
477 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "readPixels from incomplete framebuffer");
478 // copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OPERATION because
479 // the framebuffer is invalid OR INVALID_OPERATION because in the case of no attachments
480 // the framebuffer is not of a compatible type.
481 gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
482 wtu.glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION], "copyTexImage2D from incomplete framebuffer");
483 gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 1, 1, 0);
484 wtu.glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION], "copyTexSubImage2D from incomplete framebuffer");
485 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
486 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "clear with incomplete framebuffer");
490 function testFramebufferIncompleteAttachment() {
491 shouldBeNonNull("fbo = gl.createFramebuffer()");
492 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
493 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
494 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
495 gl.framebufferRenderbuffer(
496 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
497 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
498 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
500 debug("");
501 debug("Wrong storage type for type of attachment be FRAMEBUFFER_INCOMPLETE_ATTACHMENT (OpenGL ES 2.0 4.4.5)");
502 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 16, 16);
503 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
505 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
506 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
508 debug("");
509 debug("0 size attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT (OpenGL ES 2.0 4.4.5)");
510 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0);
511 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
513 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
516 function testFramebufferIncompleteMissingAttachment() {
517 debug("");
518 debug("No attachments should be INCOMPLETE_FRAMEBUFFER_MISSING_ATTACHMENT (OpenGL ES 2.0 4.4.5)");
519 shouldBeNonNull("fbo = gl.createFramebuffer()");
520 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
521 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
523 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
524 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
525 gl.framebufferRenderbuffer(
526 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
527 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
528 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
530 gl.framebufferRenderbuffer(
531 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, null);
532 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
534 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
537 function testFramebufferIncompleteDimensions() {
538 debug("");
539 debug("Attachments of different sizes should be FRAMEBUFFER_INCOMPLETE_DIMENSIONS (OpenGL ES 2.0 4.4.5)");
541 shouldBeNonNull("fbo = gl.createFramebuffer()");
542 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
543 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
544 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
545 gl.framebufferRenderbuffer(
546 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
547 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
549 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
550 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
551 gl.framebufferRenderbuffer(
552 gl.FRAMEBUFFER, depthAttachment, gl.RENDERBUFFER, depthBuffer);
553 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 16, 16);
554 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
555 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
557 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 32, 16);
558 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
559 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 16, 16);
560 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
561 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
562 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 32);
563 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
564 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16);
565 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
566 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
568 var tex = gl.createTexture();
569 gl.bindTexture(gl.TEXTURE_2D, tex);
570 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
571 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
572 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
573 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
574 return;
577 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
578 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
579 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
580 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE);
582 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
585 function testReadingFromMissingAttachment() {
586 debug("");
587 debug("Test drawing or reading from a missing framebuffer attachment");
589 shouldBeNonNull("fbo = gl.createFramebuffer()");
590 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
592 var size = 16;
594 // The only scenario we can verify is an attempt to read or copy
595 // from a missing color attachment while the framebuffer is still
596 // complete.
597 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
598 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
599 gl.framebufferRenderbuffer(
600 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
601 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size);
602 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After depth renderbuffer setup");
603 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
604 debug("Unable to allocate a framebuffer with just a depth attachment; this is legal");
605 // Try just a depth/stencil renderbuffer
606 gl.framebufferRenderbuffer(
607 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null);
608 shouldBeNonNull("depthStencilBuffer = gl.createRenderbuffer()");
609 gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
610 gl.framebufferRenderbuffer(
611 gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
612 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, size, size);
613 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After depth+stencil renderbuffer setup");
614 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
615 debug("Unable to allocate a framebuffer with just a depth+stencil attachment; this is legal");
616 return;
620 // The FBO has no color attachment. ReadPixels, CopyTexImage2D,
621 // and CopyTexSubImage2D should all generate INVALID_OPERATION.
622 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before ReadPixels from missing attachment");
623 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
624 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After ReadPixels from missing attachment");
626 var tex = gl.createTexture();
627 gl.bindTexture(gl.TEXTURE_2D, tex);
628 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before CopyTexImage2D from missing attachment");
629 gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, size, size, 0);
630 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After CopyTexImage2D from missing attachment");
632 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
633 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before CopyTexSubImage2D from missing attachment");
634 gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, size, size);
635 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After CopyTexSubImage2D from missing attachment");
638 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
639 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
640 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
641 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
642 function testBindRenderbufferBeforeFramebufferAttach() {
643 debug("");
644 debug("Test calling framebufferRenderbuffer before bindRenderbuffer.");
646 let fbo = gl.createFramebuffer();
647 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
649 let attachmentTypes = [
650 gl.COLOR_ATTACHMENT0,
651 gl.DEPTH_ATTACHMENT,
652 gl.STENCIL_ATTACHMENT,
653 gl.DEPTH_STENCIL_ATTACHMENT
656 attachmentTypes.forEach(function(attachmentType) {
657 let strAttachmentType = wtu.glEnumToString(gl, attachmentType);
658 debug("");
659 debug("Testing " + strAttachmentType);
660 let rbo = gl.createRenderbuffer();
661 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachmentType, gl.RENDERBUFFER, rbo);
662 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bindRenderbuffer must be called before attachment to " + strAttachmentType);
663 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl." + strAttachmentType + ", gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
664 gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachmentType, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
665 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Only OBJECT_TYPE can be queried when no image is attached");
666 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachmentType, gl.RENDERBUFFER, null);
667 gl.deleteRenderbuffer(rbo);
670 gl.deleteFramebuffer(fbo);
673 var successfullyParsed = true;
674 </script>
676 <script src="../../js/js-test-post.js"></script>
677 </body>
678 </html>