5 <script src=
"../../../resources/js-test.js"></script>
6 <script src=
"resources/webgl-test.js"></script>
7 <script src=
"resources/webgl-test-utils.js"></script>
10 <div id=
"description"></div>
11 <div id=
"console"></div>
15 window
.internals
.settings
.setWebGLErrorsToConsoleEnabled(false);
17 var wtu
= WebGLTestUtils
;
22 var depthStencilBuffer
;
27 const ALLOW_COMPLETE
= 0x01;
28 const ALLOW_UNSUPPORTED
= 0x02;
29 const ALLOW_INCOMPLETE_ATTACHMENT
= 0x04;
31 function checkFramebufferForAllowedStatuses(allowedStatuses
)
33 // If the framebuffer is in an error state for multiple reasons,
34 // we can't guarantee which one will be reported.
35 var status
= gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
);
36 var statusAllowed
= ((allowedStatuses
& ALLOW_COMPLETE
) && (status
== gl
.FRAMEBUFFER_COMPLETE
)) ||
37 ((allowedStatuses
& ALLOW_UNSUPPORTED
) && (status
== gl
.FRAMEBUFFER_UNSUPPORTED
)) ||
38 ((allowedStatuses
& ALLOW_INCOMPLETE_ATTACHMENT
) && (status
== gl
.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
));
39 var msg
= "gl.checkFramebufferStatus(gl.FRAMEBUFFER) returned " + status
;
46 function checkBufferBits(attachment0
, attachment1
)
48 if (gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) != gl
.FRAMEBUFFER_COMPLETE
)
51 var haveDepthBuffer
= attachment0
== gl
.DEPTH_ATTACHMENT
||
52 attachment0
== gl
.DEPTH_STENCIL_ATTACHMENT
||
53 attachment1
== gl
.DEPTH_ATTACHMENT
||
54 attachment1
== gl
.DEPTH_STENCIL_ATTACHMENT
;
55 var haveStencilBuffer
= attachment0
== gl
.STENCIL_ATTACHMENT
||
56 attachment0
== gl
.DEPTH_STENCIL_ATTACHMENT
||
57 attachment1
== gl
.STENCIL_ATTACHMENT
||
58 attachment1
== gl
.DEPTH_STENCIL_ATTACHMENT
;
60 shouldBeTrue("gl.getParameter(gl.RED_BITS) + gl.getParameter(gl.GREEN_BITS) + gl.getParameter(gl.BLUE_BITS) + gl.getParameter(gl.ALPHA_BITS) >= 16");
63 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) >= 16");
65 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) == 0");
67 if (haveStencilBuffer
)
68 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) >= 8");
70 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) == 0");
73 function testAttachment(attachment
, buffer
, allowedStatuses
)
75 shouldBeNonNull("fbo = gl.createFramebuffer()");
76 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
77 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
78 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, attachment
, gl
.RENDERBUFFER
, buffer
);
79 glErrorShouldBe(gl
, gl
.NO_ERROR
);
80 checkFramebufferForAllowedStatuses(allowedStatuses
);
81 if ((allowedStatuses
& ALLOW_COMPLETE
) == 0) {
82 gl
.clear(gl
.COLOR_BUFFER_BIT
);
83 glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
);
84 gl
.readPixels(0, 0, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, new Uint8Array(width
* height
* 4));
85 glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
);
87 checkBufferBits(attachment
);
88 gl
.deleteFramebuffer(fbo
);
91 function testAttachments(attachment0
, buffer0
, attachment1
, buffer1
, allowedStatuses
)
93 shouldBeNonNull("fbo = gl.createFramebuffer()");
94 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
95 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
96 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, attachment0
, gl
.RENDERBUFFER
, buffer0
);
97 glErrorShouldBe(gl
, gl
.NO_ERROR
);
98 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, attachment1
, gl
.RENDERBUFFER
, buffer1
);
99 glErrorShouldBe(gl
, gl
.NO_ERROR
);
100 checkFramebufferForAllowedStatuses(allowedStatuses
);
101 checkBufferBits(attachment0
, attachment1
);
102 gl
.deleteFramebuffer(fbo
);
105 function testColorRenderbuffer(internalformat
, allowedStatuses
)
107 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
108 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
109 gl
.renderbufferStorage(gl
.RENDERBUFFER
, internalformat
, width
, height
);
110 glErrorShouldBe(gl
, gl
.NO_ERROR
);
111 testAttachment(gl
.COLOR_ATTACHMENT0
, colorBuffer
, allowedStatuses
);
114 function testDepthStencilRenderbuffer(allowedStatuses
)
116 shouldBeNonNull("depthStencilBuffer = gl.createRenderbuffer()");
117 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthStencilBuffer
);
118 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_STENCIL
, width
, height
);
119 glErrorShouldBe(gl
, gl
.NO_ERROR
);
121 // OpenGL itself doesn't seem to guarantee that e.g. a 2 x 0
122 // renderbuffer will report 2 for its width when queried.
123 if (!(height
== 0 && width
> 0))
124 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)", "width");
125 if (!(width
== 0 && height
> 0))
126 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT)", "height");
127 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_INTERNAL_FORMAT)", "gl.DEPTH_STENCIL");
128 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_RED_SIZE)", "0");
129 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_GREEN_SIZE)", "0");
130 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_BLUE_SIZE)", "0");
131 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_ALPHA_SIZE)", "0");
132 // Avoid verifying these for zero-sized renderbuffers for the time
133 // being since it appears that even OpenGL doesn't guarantee them.
134 if (width
> 0 && height
> 0) {
135 shouldBeTrue("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_DEPTH_SIZE) > 0");
136 shouldBeTrue("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_STENCIL_SIZE) > 0");
138 glErrorShouldBe(gl
, gl
.NO_ERROR
);
139 testAttachment(gl
.DEPTH_STENCIL_ATTACHMENT
, depthStencilBuffer
, allowedStatuses
);
140 testDepthStencilDepthStencil();
143 function testDepthStencilDepthStencil()
145 if (!width
|| !height
) {
150 { firstFormat
: gl
.DEPTH_COMPONENT16
,
151 firstAttach
: gl
.DEPTH_ATTACHMENT
,
152 secondFormat
: gl
.DEPTH_STENCIL
,
153 secondAttach
: gl
.DEPTH_STENCIL_ATTACHMENT
155 { firstFormat
: gl
.DEPTH_STENCIL
,
156 firstAttach
: gl
.DEPTH_STENCIL_ATTACHMENT
,
157 secondFormat
: gl
.DEPTH_COMPONENT16
,
158 secondAttach
: gl
.DEPTH_ATTACHMENT
161 for (var ii
= 0; ii
< tests
.length
; ++ii
) {
162 var test
= tests
[ii
];
163 for (var jj
= 0; jj
< 2; ++jj
) {
164 var fbo
= gl
.createFramebuffer();
165 var tex
= gl
.createTexture();
166 var firstRb
= gl
.createRenderbuffer();
169 debug("test: " + wtu
.glEnumToString(gl
, test
.firstFormat
) + " vs " + wtu
.glEnumToString(gl
, test
.secondFormat
) + " with " + (jj
? "unbind" : "delete"));
171 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
172 // attach texture as color
173 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
174 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, width
, height
, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
175 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, tex
, 0);
178 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, firstRb
);
179 gl
.renderbufferStorage(gl
.RENDERBUFFER
, test
.firstFormat
, width
, height
);
180 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, test
.firstAttach
, gl
.RENDERBUFFER
, firstRb
);
182 if (gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) == gl
.FRAMEBUFFER_COMPLETE
) {
183 gl
.enable(gl
.DEPTH_TEST
);
184 var program
= wtu
.setupColorQuad(gl
);
186 wtu
.drawUByteColorQuad(gl
, [0, 255, 0, 255]);
187 wtu
.drawUByteColorQuad(gl
, [255, 0, 0, 255]); // should not draw since DEPTH_FUNC == LESS
188 wtu
.checkCanvasRect(gl
, 0, 0, width
, height
, [0, 255, 0, 255], "should be green");
190 var secondRb
= gl
.createRenderbuffer();
193 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, secondRb
);
194 gl
.renderbufferStorage(gl
.RENDERBUFFER
, test
.secondFormat
, width
, height
);
195 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, test
.secondAttach
, gl
.RENDERBUFFER
, secondRb
);
199 debug("test deleting second renderbuffer");
200 gl
.deleteRenderbuffer(secondRb
);
203 debug("test unbinding second renderbuffer");
204 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, test
.secondAttach
, gl
.RENDERBUFFER
, null);
207 // If the first attachment is not restored this may fail
208 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
209 glErrorShouldBe(gl
, gl
.NO_ERROR
);
211 // If the first attachment is not restored this may fail.
212 gl
.clear(gl
.DEPTH_BUFFER_BIT
);
213 wtu
.drawUByteColorQuad(gl
, [0, 255, 0, 255]);
214 wtu
.drawUByteColorQuad(gl
, [255, 0, 0, 255]); // should not draw since DEPTH_FUNC == LESS
215 wtu
.checkCanvasRect(gl
, 0, 0, width
, height
, [0, 255, 0, 255], "should be green");
216 gl
.disable(gl
.DEPTH_TEST
);
219 gl
.deleteRenderbuffer(secondRb
);
223 gl
.deleteRenderbuffer(secondRb
);
224 gl
.deleteFramebuffer(fbo
);
227 glErrorShouldBe(gl
, gl
.NO_ERROR
);
230 description("Test framebuffer object attachment behaviors");
232 for (width
= 0; width
<= 2; width
+= 2)
234 for (height
= 0; height
<= 2; height
+= 2)
237 debug("Dimensions " + width
+ " x " + height
);
239 debug("Create renderbuffers");
240 shouldBeNonNull("gl = create3DContext()");
241 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
242 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
243 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, width
, height
);
244 glErrorShouldBe(gl
, gl
.NO_ERROR
);
245 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
246 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthBuffer
);
247 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, width
, height
);
248 glErrorShouldBe(gl
, gl
.NO_ERROR
);
249 shouldBeNonNull("stencilBuffer = gl.createRenderbuffer()");
250 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, stencilBuffer
);
251 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.STENCIL_INDEX8
, width
, height
);
252 glErrorShouldBe(gl
, gl
.NO_ERROR
);
253 shouldBeNonNull("depthStencilBuffer = gl.createRenderbuffer()");
254 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthStencilBuffer
);
255 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_STENCIL
, width
, height
);
256 glErrorShouldBe(gl
, gl
.NO_ERROR
);
258 var allowedStatusForGoodCase
259 = (width
== 0 || height
== 0) ? ALLOW_INCOMPLETE_ATTACHMENT
: ALLOW_COMPLETE
;
261 // some cases involving stencil seem to be implementation-dependent
262 var allowedStatusForImplDependentCase
= allowedStatusForGoodCase
| ALLOW_UNSUPPORTED
;
264 debug("Attach depth using DEPTH_ATTACHMENT");
265 testAttachment(gl
.DEPTH_ATTACHMENT
, depthBuffer
, allowedStatusForGoodCase
);
266 debug("Attach depth using STENCIL_ATTACHMENT");
267 testAttachment(gl
.STENCIL_ATTACHMENT
, depthBuffer
, ALLOW_INCOMPLETE_ATTACHMENT
);
268 debug("Attach depth using DEPTH_STENCIL_ATTACHMENT");
269 testAttachment(gl
.DEPTH_STENCIL_ATTACHMENT
, depthBuffer
, ALLOW_INCOMPLETE_ATTACHMENT
);
270 debug("Attach stencil using STENCIL_ATTACHMENT");
271 testAttachment(gl
.STENCIL_ATTACHMENT
, stencilBuffer
, allowedStatusForImplDependentCase
);
272 debug("Attach stencil using DEPTH_ATTACHMENT");
273 testAttachment(gl
.DEPTH_ATTACHMENT
, stencilBuffer
, ALLOW_INCOMPLETE_ATTACHMENT
);
274 debug("Attach stencil using DEPTH_STENCIL_ATTACHMENT");
275 testAttachment(gl
.DEPTH_STENCIL_ATTACHMENT
, stencilBuffer
, ALLOW_INCOMPLETE_ATTACHMENT
);
276 debug("Attach depthStencil using DEPTH_STENCIL_ATTACHMENT");
277 testAttachment(gl
.DEPTH_STENCIL_ATTACHMENT
, depthStencilBuffer
, allowedStatusForGoodCase
);
278 debug("Attach depthStencil using DEPTH_ATTACHMENT");
279 testAttachment(gl
.DEPTH_ATTACHMENT
, depthStencilBuffer
, ALLOW_INCOMPLETE_ATTACHMENT
);
280 debug("Attach depthStencil using STENCIL_ATTACHMENT");
281 testAttachment(gl
.STENCIL_ATTACHMENT
, depthStencilBuffer
, ALLOW_INCOMPLETE_ATTACHMENT
);
283 var allowedStatusForConflictedAttachment
284 = (width
== 0 || height
== 0) ? ALLOW_UNSUPPORTED
| ALLOW_INCOMPLETE_ATTACHMENT
287 debug("Attach depth, then stencil, causing conflict");
288 testAttachments(gl
.DEPTH_ATTACHMENT
, depthBuffer
, gl
.STENCIL_ATTACHMENT
, stencilBuffer
, allowedStatusForConflictedAttachment
);
289 debug("Attach stencil, then depth, causing conflict");
290 testAttachments(gl
.STENCIL_ATTACHMENT
, stencilBuffer
, gl
.DEPTH_ATTACHMENT
, depthBuffer
, allowedStatusForConflictedAttachment
);
291 debug("Attach depth, then depthStencil, causing conflict");
292 testAttachments(gl
.DEPTH_ATTACHMENT
, depthBuffer
, gl
.DEPTH_STENCIL_ATTACHMENT
, depthStencilBuffer
, allowedStatusForConflictedAttachment
);
293 debug("Attach depthStencil, then depth, causing conflict");
294 testAttachments(gl
.DEPTH_STENCIL_ATTACHMENT
, depthStencilBuffer
, gl
.DEPTH_ATTACHMENT
, depthBuffer
, allowedStatusForConflictedAttachment
);
295 debug("Attach stencil, then depthStencil, causing conflict");
296 testAttachments(gl
.DEPTH_ATTACHMENT
, depthBuffer
, gl
.DEPTH_STENCIL_ATTACHMENT
, depthStencilBuffer
, allowedStatusForConflictedAttachment
);
297 debug("Attach depthStencil, then stencil, causing conflict");
298 testAttachments(gl
.DEPTH_STENCIL_ATTACHMENT
, depthStencilBuffer
, gl
.STENCIL_ATTACHMENT
, stencilBuffer
, allowedStatusForConflictedAttachment
);
300 debug("Attach color renderbuffer with internalformat == RGBA4");
301 testColorRenderbuffer(gl
.RGBA4
, allowedStatusForGoodCase
);
303 debug("Attach color renderbuffer with internalformat == RGB5_A1");
304 testColorRenderbuffer(gl
.RGB5_A1
, allowedStatusForGoodCase
);
306 debug("Attach color renderbuffer with internalformat == RGB565");
307 testColorRenderbuffer(gl
.RGB565
, allowedStatusForGoodCase
);
309 debug("Create and attach depthStencil renderbuffer");
310 testDepthStencilRenderbuffer(allowedStatusForGoodCase
);
314 // Determine if we can attach both color and depth or color and depth_stencil
318 function checkValidColorDepthCombination() {
319 shouldBeNonNull("fbo = gl.createFramebuffer()");
320 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
321 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
322 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
323 gl
.framebufferRenderbuffer(
324 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
325 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
327 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
328 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthBuffer
);
330 return tryDepth(gl
.DEPTH_COMPONENT16
, gl
.DEPTH_ATTACHMENT
) || tryDepth(gl
.DEPTH_STENCIL
, gl
.DEPTH_STENCIL_ATTACHMENT
);
332 function tryDepth(try_format
, try_attachment
) {
333 if (depthAttachment
) {
334 // If we've tried once unattach the old one.
335 gl
.framebufferRenderbuffer(
336 gl
.FRAMEBUFFER
, depthAttachment
, gl
.RENDERBUFFER
, null);
338 depthFormat
= try_format
;
339 depthAttachment
= try_attachment
;
340 gl
.framebufferRenderbuffer(
341 gl
.FRAMEBUFFER
, depthAttachment
, gl
.RENDERBUFFER
, depthBuffer
);
342 gl
.renderbufferStorage(gl
.RENDERBUFFER
, depthFormat
, 16, 16);
343 glErrorShouldBe(gl
, gl
.NO_ERROR
);
344 return gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) == gl
.FRAMEBUFFER_COMPLETE
;
348 if (checkValidColorDepthCombination()) {
349 testFramebufferIncompleteDimensions();
350 testFramebufferIncompleteAttachment();
351 testFramebufferIncompleteMissingAttachment();
352 testUsingIncompleteFramebuffer();
355 function checkFramebuffer(expected
) {
356 var actual
= gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
);
357 var msg
= "gl.checkFramebufferStatus(gl.FRAMEBUFFER) should be " + wtu
.glEnumToString(gl
, expected
) + " was " + wtu
.glEnumToString(gl
, actual
);
358 if (expected
!= gl
.FRAMEBUFFER_COMPLETE
) {
359 msg
+= " or FRAMEBUFFER_UNSUPPORTED";
361 if (actual
== expected
||
362 (expected
!= gl
.FRAMEBUFFER_COMPLETE
&&
363 actual
== gl
.FRAMBUFFER_UNSUPPORTED
)) {
370 function testUsingIncompleteFramebuffer() {
372 debug("Test drawing or reading from an incomplete framebuffer");
373 var program
= wtu
.setupTexturedQuad(gl
);
374 var tex
= gl
.createTexture();
375 wtu
.fillTexture(gl
, tex
, 1, 1, [0,255,0,255]);
377 shouldBeNonNull("fbo = gl.createFramebuffer()");
378 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
379 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
380 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
381 gl
.framebufferRenderbuffer(
382 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
383 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
385 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
386 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthBuffer
);
387 gl
.framebufferRenderbuffer(
388 gl
.FRAMEBUFFER
, depthAttachment
, gl
.RENDERBUFFER
, depthBuffer
);
389 gl
.renderbufferStorage(gl
.RENDERBUFFER
, depthFormat
, 16, 16);
390 glErrorShouldBe(gl
, gl
.NO_ERROR
);
391 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
393 // We pick this combination because it works on desktop OpenGL but should not work on OpenGL ES 2.0
394 gl
.renderbufferStorage(gl
.RENDERBUFFER
, depthFormat
, 32, 16);
395 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_DIMENSIONS
);
397 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
398 testRenderingAndReading();
400 shouldBeNonNull("fbo2 = gl.createFramebuffer()");
401 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo2
);
402 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
);
404 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
405 testRenderingAndReading();
407 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
408 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
409 gl
.framebufferRenderbuffer(
410 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
411 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 0, 0);
413 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
414 testRenderingAndReading();
416 function testRenderingAndReading() {
417 glErrorShouldBe(gl
, gl
.NO_ERROR
);
419 glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
, "drawArrays with incomplete framebuffer");
420 gl
.readPixels(0, 0, 1, 1, gl
.RGBA
, gl
.UNSIGNED_BYTE
, new Uint8Array(4));
421 glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
, "readPixels from incomplete framebuffer");
422 // copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OPERATION because
423 // the framebuffer is invalid OR INVALID_OPERATION because in the case of no attachments
424 // the framebuffer is not of a compatible type.
425 gl
.copyTexSubImage2D(gl
.TEXTURE_2D
, 0, 0, 0, 0, 0, 1, 1);
426 glErrorShouldBe(gl
, [gl
.INVALID_FRAMEBUFFER_OPERATION
, gl
.INVALID_OPERATION
], "copyTexImage2D from incomplete framebuffer");
427 gl
.copyTexImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 0, 0, 1, 1, 0);
428 glErrorShouldBe(gl
, [gl
.INVALID_FRAMEBUFFER_OPERATION
, gl
.INVALID_OPERATION
], "copyTexSubImage2D from incomplete framebuffer");
429 gl
.clear(gl
.COLOR_BUFFER_BIT
| gl
.DEPTH_BUFFER_BIT
);
430 glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
, "clear with incomplete framebuffer");
434 function testFramebufferIncompleteAttachment() {
435 shouldBeNonNull("fbo = gl.createFramebuffer()");
436 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
437 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
438 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
439 gl
.framebufferRenderbuffer(
440 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
441 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
442 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
445 debug("Wrong storage type for type of attachment be FRAMEBUFFER_INCOMPLETE_ATTACHMENT (OpenGL ES 2.0 4.4.5)");
446 gl
.renderbufferStorage(gl
.RENDERBUFFER
, depthFormat
, 16, 16);
447 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
);
449 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
450 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
453 debug("0 size attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT (OpenGL ES 2.0 4.4.5)");
454 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 0, 0);
455 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
);
457 glErrorShouldBe(gl
, gl
.NO_ERROR
);
460 function testFramebufferIncompleteMissingAttachment() {
462 debug("No attachments should be INCOMPLETE_FRAMEBUFFER_MISSING_ATTACHMENT (OpenGL ES 2.0 4.4.5)");
463 shouldBeNonNull("fbo = gl.createFramebuffer()");
464 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
465 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
);
467 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
468 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
469 gl
.framebufferRenderbuffer(
470 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
471 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
472 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
474 gl
.framebufferRenderbuffer(
475 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, null);
476 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
);
478 glErrorShouldBe(gl
, gl
.NO_ERROR
);
481 function testFramebufferIncompleteDimensions() {
483 debug("Attachments of different sizes should be FRAMEBUFFER_INCOMPLETE_DIMENSIONS (OpenGL ES 2.0 4.4.5)");
485 shouldBeNonNull("fbo = gl.createFramebuffer()");
486 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
487 shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
488 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
489 gl
.framebufferRenderbuffer(
490 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
491 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
493 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()");
494 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthBuffer
);
495 gl
.framebufferRenderbuffer(
496 gl
.FRAMEBUFFER
, depthAttachment
, gl
.RENDERBUFFER
, depthBuffer
);
497 gl
.renderbufferStorage(gl
.RENDERBUFFER
, depthFormat
, 16, 16);
498 glErrorShouldBe(gl
, gl
.NO_ERROR
);
499 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
501 gl
.renderbufferStorage(gl
.RENDERBUFFER
, depthFormat
, 32, 16);
502 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_DIMENSIONS
);
503 gl
.renderbufferStorage(gl
.RENDERBUFFER
, depthFormat
, 16, 16);
504 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
505 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
506 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 32);
507 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_DIMENSIONS
);
508 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
509 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
510 glErrorShouldBe(gl
, gl
.NO_ERROR
);
512 var tex
= gl
.createTexture();
513 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
514 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 16, 16, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
515 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, tex
, 0);
516 glErrorShouldBe(gl
, gl
.NO_ERROR
);
517 if (gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) != gl
.FRAMEBUFFER_COMPLETE
) {
521 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 32, 16, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
522 checkFramebuffer(gl
.FRAMEBUFFER_INCOMPLETE_DIMENSIONS
);
523 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 16, 16, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
524 checkFramebuffer(gl
.FRAMEBUFFER_COMPLETE
);
526 glErrorShouldBe(gl
, gl
.NO_ERROR
);
529 successfullyParsed
= true;