| OLD | NEW |
| (Empty) |
| 1 <!DOCTYPE html> | |
| 2 <html> | |
| 3 <head> | |
| 4 <meta charset="utf-8"> | |
| 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> | |
| 8 </head> | |
| 9 <body> | |
| 10 <div id="description"></div> | |
| 11 <div id="console"></div> | |
| 12 | |
| 13 <script> | |
| 14 if (window.internals) | |
| 15 window.internals.settings.setWebGLErrorsToConsoleEnabled(false); | |
| 16 | |
| 17 var wtu = WebGLTestUtils; | |
| 18 var gl; | |
| 19 var fbo; | |
| 20 var depthBuffer; | |
| 21 var stencilBuffer; | |
| 22 var depthStencilBuffer; | |
| 23 var colorBuffer; | |
| 24 var width; | |
| 25 var height; | |
| 26 | |
| 27 const ALLOW_COMPLETE = 0x01; | |
| 28 const ALLOW_UNSUPPORTED = 0x02; | |
| 29 const ALLOW_INCOMPLETE_ATTACHMENT = 0x04; | |
| 30 | |
| 31 function checkFramebufferForAllowedStatuses(allowedStatuses) | |
| 32 { | |
| 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.FRA
MEBUFFER_COMPLETE)) || | |
| 37 ((allowedStatuses & ALLOW_UNSUPPORTED) && (status == gl.
FRAMEBUFFER_UNSUPPORTED)) || | |
| 38 ((allowedStatuses & ALLOW_INCOMPLETE_ATTACHMENT) && (sta
tus == gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT)); | |
| 39 var msg = "gl.checkFramebufferStatus(gl.FRAMEBUFFER) returned " + status; | |
| 40 if (statusAllowed) | |
| 41 testPassed(msg); | |
| 42 else | |
| 43 testFailed(msg); | |
| 44 } | |
| 45 | |
| 46 function checkBufferBits(attachment0, attachment1) | |
| 47 { | |
| 48 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) | |
| 49 return; | |
| 50 | |
| 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; | |
| 59 | |
| 60 shouldBeTrue("gl.getParameter(gl.RED_BITS) + gl.getParameter(gl.GREEN_BITS)
+ gl.getParameter(gl.BLUE_BITS) + gl.getParameter(gl.ALPHA_BITS) >= 16"); | |
| 61 | |
| 62 if (haveDepthBuffer) | |
| 63 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) >= 16"); | |
| 64 else | |
| 65 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) == 0"); | |
| 66 | |
| 67 if (haveStencilBuffer) | |
| 68 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) >= 8"); | |
| 69 else | |
| 70 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) == 0"); | |
| 71 } | |
| 72 | |
| 73 function testAttachment(attachment, buffer, allowedStatuses) | |
| 74 { | |
| 75 shouldBeNonNull("fbo = gl.createFramebuffer()"); | |
| 76 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); | |
| 77 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBU
FFER, colorBuffer); | |
| 78 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, buff
er); | |
| 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 Uint8A
rray(width * height * 4)); | |
| 85 glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION); | |
| 86 } | |
| 87 checkBufferBits(attachment); | |
| 88 gl.deleteFramebuffer(fbo); | |
| 89 } | |
| 90 | |
| 91 function testAttachments(attachment0, buffer0, attachment1, buffer1, allowedStat
uses) | |
| 92 { | |
| 93 shouldBeNonNull("fbo = gl.createFramebuffer()"); | |
| 94 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); | |
| 95 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBU
FFER, colorBuffer); | |
| 96 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment0, gl.RENDERBUFFER, buf
fer0); | |
| 97 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 98 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment1, gl.RENDERBUFFER, buf
fer1); | |
| 99 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 100 checkFramebufferForAllowedStatuses(allowedStatuses); | |
| 101 checkBufferBits(attachment0, attachment1); | |
| 102 gl.deleteFramebuffer(fbo); | |
| 103 } | |
| 104 | |
| 105 function testColorRenderbuffer(internalformat, allowedStatuses) | |
| 106 { | |
| 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); | |
| 112 } | |
| 113 | |
| 114 function testDepthStencilRenderbuffer(allowedStatuses) | |
| 115 { | |
| 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); | |
| 120 | |
| 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_W
IDTH)", "width"); | |
| 125 if (!(width == 0 && height > 0)) | |
| 126 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_H
EIGHT)", "height"); | |
| 127 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_INTER
NAL_FORMAT)", "gl.DEPTH_STENCIL"); | |
| 128 shouldBe("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_RED_S
IZE)", "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.RENDERBUFF
ER_DEPTH_SIZE) > 0"); | |
| 136 shouldBeTrue("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFF
ER_STENCIL_SIZE) > 0"); | |
| 137 } | |
| 138 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 139 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatu
ses); | |
| 140 testDepthStencilDepthStencil(); | |
| 141 } | |
| 142 | |
| 143 function testDepthStencilDepthStencil() | |
| 144 { | |
| 145 if (!width || !height) { | |
| 146 return; | |
| 147 } | |
| 148 | |
| 149 var tests = [ | |
| 150 { firstFormat: gl.DEPTH_COMPONENT16, | |
| 151 firstAttach: gl.DEPTH_ATTACHMENT, | |
| 152 secondFormat: gl.DEPTH_STENCIL, | |
| 153 secondAttach: gl.DEPTH_STENCIL_ATTACHMENT | |
| 154 }, | |
| 155 { firstFormat: gl.DEPTH_STENCIL, | |
| 156 firstAttach: gl.DEPTH_STENCIL_ATTACHMENT, | |
| 157 secondFormat: gl.DEPTH_COMPONENT16, | |
| 158 secondAttach: gl.DEPTH_ATTACHMENT | |
| 159 } | |
| 160 ]; | |
| 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(); | |
| 167 | |
| 168 debug(""); | |
| 169 debug("test: " + wtu.glEnumToString(gl, test.firstFormat) + " vs " +
wtu.glEnumToString(gl, test.secondFormat) + " with " + (jj ? "unbind" : "delete
")); | |
| 170 | |
| 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.TEX
TURE_2D, tex, 0); | |
| 176 | |
| 177 // attach first | |
| 178 gl.bindRenderbuffer(gl.RENDERBUFFER, firstRb); | |
| 179 gl.renderbufferStorage(gl.RENDERBUFFER, test.firstFormat, width, hei
ght); | |
| 180 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, test.firstAttach, gl.REND
ERBUFFER, firstRb); | |
| 181 | |
| 182 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMP
LETE) { | |
| 183 gl.enable(gl.DEPTH_TEST); | |
| 184 var program = wtu.setupColorQuad(gl); | |
| 185 // Test it works | |
| 186 wtu.drawUByteColorQuad(gl, [0, 255, 0, 255]); | |
| 187 wtu.drawUByteColorQuad(gl, [255, 0, 0, 255]); // should not dra
w since DEPTH_FUNC == LESS | |
| 188 wtu.checkCanvasRect(gl, 0, 0, width, height, [0, 255, 0, 255], "
should be green"); | |
| 189 | |
| 190 var secondRb = gl.createRenderbuffer(); | |
| 191 | |
| 192 // attach second | |
| 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); | |
| 196 | |
| 197 if (jj == 0) { | |
| 198 // now delete it | |
| 199 debug("test deleting second renderbuffer"); | |
| 200 gl.deleteRenderbuffer(secondRb); | |
| 201 } else { | |
| 202 // unbind it | |
| 203 debug("test unbinding second renderbuffer"); | |
| 204 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, test.secondAttach,
gl.RENDERBUFFER, null); | |
| 205 } | |
| 206 | |
| 207 // If the first attachment is not restored this may fail | |
| 208 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEB
UFFER_COMPLETE'); | |
| 209 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 210 | |
| 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 dra
w 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); | |
| 217 | |
| 218 if (jj == 1) { | |
| 219 gl.deleteRenderbuffer(secondRb); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 gl.deleteRenderbuffer(secondRb); | |
| 224 gl.deleteFramebuffer(fbo); | |
| 225 } | |
| 226 } | |
| 227 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 228 } | |
| 229 | |
| 230 description("Test framebuffer object attachment behaviors"); | |
| 231 | |
| 232 for (width = 0; width <= 2; width += 2) | |
| 233 { | |
| 234 for (height = 0; height <= 2; height += 2) | |
| 235 { | |
| 236 debug(""); | |
| 237 debug("Dimensions " + width + " x " + height); | |
| 238 | |
| 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, hei
ght); | |
| 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); | |
| 257 | |
| 258 var allowedStatusForGoodCase | |
| 259 = (width == 0 || height == 0) ? ALLOW_INCOMPLETE_ATTACHMENT : ALLOW_
COMPLETE; | |
| 260 | |
| 261 // some cases involving stencil seem to be implementation-dependent | |
| 262 var allowedStatusForImplDependentCase = allowedStatusForGoodCase | ALLOW
_UNSUPPORTED; | |
| 263 | |
| 264 debug("Attach depth using DEPTH_ATTACHMENT"); | |
| 265 testAttachment(gl.DEPTH_ATTACHMENT, depthBuffer, allowedStatusForGoodCas
e); | |
| 266 debug("Attach depth using STENCIL_ATTACHMENT"); | |
| 267 testAttachment(gl.STENCIL_ATTACHMENT, depthBuffer, ALLOW_INCOMPLETE_ATTA
CHMENT); | |
| 268 debug("Attach depth using DEPTH_STENCIL_ATTACHMENT"); | |
| 269 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthBuffer, ALLOW_INCOMPLET
E_ATTACHMENT); | |
| 270 debug("Attach stencil using STENCIL_ATTACHMENT"); | |
| 271 testAttachment(gl.STENCIL_ATTACHMENT, stencilBuffer, allowedStatusForImp
lDependentCase); | |
| 272 debug("Attach stencil using DEPTH_ATTACHMENT"); | |
| 273 testAttachment(gl.DEPTH_ATTACHMENT, stencilBuffer, ALLOW_INCOMPLETE_ATTA
CHMENT); | |
| 274 debug("Attach stencil using DEPTH_STENCIL_ATTACHMENT"); | |
| 275 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, stencilBuffer, ALLOW_INCOMPL
ETE_ATTACHMENT); | |
| 276 debug("Attach depthStencil using DEPTH_STENCIL_ATTACHMENT"); | |
| 277 testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedS
tatusForGoodCase); | |
| 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_INCOMPLE
TE_ATTACHMENT); | |
| 282 | |
| 283 var allowedStatusForConflictedAttachment | |
| 284 = (width == 0 || height == 0) ? ALLOW_UNSUPPORTED | ALLOW_INCOMPLETE
_ATTACHMENT | |
| 285 : ALLOW_UNSUPPORTED; | |
| 286 | |
| 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_ATTACHMEN
T, depthBuffer, allowedStatusForConflictedAttachment); | |
| 291 debug("Attach depth, then depthStencil, causing conflict"); | |
| 292 testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTAC
HMENT, depthStencilBuffer, allowedStatusForConflictedAttachment); | |
| 293 debug("Attach depthStencil, then depth, causing conflict"); | |
| 294 testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.DEPT
H_ATTACHMENT, depthBuffer, allowedStatusForConflictedAttachment); | |
| 295 debug("Attach stencil, then depthStencil, causing conflict"); | |
| 296 testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTAC
HMENT, depthStencilBuffer, allowedStatusForConflictedAttachment); | |
| 297 debug("Attach depthStencil, then stencil, causing conflict"); | |
| 298 testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.STEN
CIL_ATTACHMENT, stencilBuffer, allowedStatusForConflictedAttachment); | |
| 299 | |
| 300 debug("Attach color renderbuffer with internalformat == RGBA4"); | |
| 301 testColorRenderbuffer(gl.RGBA4, allowedStatusForGoodCase); | |
| 302 | |
| 303 debug("Attach color renderbuffer with internalformat == RGB5_A1"); | |
| 304 testColorRenderbuffer(gl.RGB5_A1, allowedStatusForGoodCase); | |
| 305 | |
| 306 debug("Attach color renderbuffer with internalformat == RGB565"); | |
| 307 testColorRenderbuffer(gl.RGB565, allowedStatusForGoodCase); | |
| 308 | |
| 309 debug("Create and attach depthStencil renderbuffer"); | |
| 310 testDepthStencilRenderbuffer(allowedStatusForGoodCase); | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 // Determine if we can attach both color and depth or color and depth_stencil | |
| 315 var depthFormat; | |
| 316 var depthAttachment; | |
| 317 | |
| 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); | |
| 326 | |
| 327 shouldBeNonNull("depthBuffer = gl.createRenderbuffer()"); | |
| 328 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); | |
| 329 | |
| 330 return tryDepth(gl.DEPTH_COMPONENT16, gl.DEPTH_ATTACHMENT) || tryDepth(gl.DE
PTH_STENCIL, gl.DEPTH_STENCIL_ATTACHMENT); | |
| 331 | |
| 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); | |
| 337 } | |
| 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_COMPL
ETE; | |
| 345 } | |
| 346 } | |
| 347 | |
| 348 if (checkValidColorDepthCombination()) { | |
| 349 testFramebufferIncompleteDimensions(); | |
| 350 testFramebufferIncompleteAttachment(); | |
| 351 testFramebufferIncompleteMissingAttachment(); | |
| 352 testUsingIncompleteFramebuffer(); | |
| 353 } | |
| 354 | |
| 355 function checkFramebuffer(expected) { | |
| 356 var actual = gl.checkFramebufferStatus(gl.FRAMEBUFFER); | |
| 357 var msg = "gl.checkFramebufferStatus(gl.FRAMEBUFFER) should be " + wtu.glEnu
mToString(gl, expected) + " was " + wtu.glEnumToString(gl, actual); | |
| 358 if (expected != gl.FRAMEBUFFER_COMPLETE) { | |
| 359 msg += " or FRAMEBUFFER_UNSUPPORTED"; | |
| 360 } | |
| 361 if (actual == expected || | |
| 362 (expected != gl.FRAMEBUFFER_COMPLETE && | |
| 363 actual == gl.FRAMBUFFER_UNSUPPORTED)) { | |
| 364 testPassed(msg); | |
| 365 } else { | |
| 366 testFailed(msg); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 function testUsingIncompleteFramebuffer() { | |
| 371 debug(""); | |
| 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]); | |
| 376 | |
| 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); | |
| 384 | |
| 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); | |
| 392 | |
| 393 // We pick this combination because it works on desktop OpenGL but should no
t work on OpenGL ES 2.0 | |
| 394 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 32, 16); | |
| 395 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS); | |
| 396 debug(""); | |
| 397 debug("Drawing or reading from an incomplete framebuffer should generate INV
ALID_FRAMEBUFFER_OPERATION"); | |
| 398 testRenderingAndReading(); | |
| 399 | |
| 400 shouldBeNonNull("fbo2 = gl.createFramebuffer()"); | |
| 401 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2); | |
| 402 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT); | |
| 403 debug(""); | |
| 404 debug("Drawing or reading from an incomplete framebuffer should generate INV
ALID_FRAMEBUFFER_OPERATION"); | |
| 405 testRenderingAndReading(); | |
| 406 | |
| 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); | |
| 412 debug(""); | |
| 413 debug("Drawing or reading from an incomplete framebuffer should generate INV
ALID_FRAMEBUFFER_OPERATION"); | |
| 414 testRenderingAndReading(); | |
| 415 | |
| 416 function testRenderingAndReading() { | |
| 417 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 418 wtu.drawQuad(gl); | |
| 419 glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "drawArrays with i
ncomplete 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 i
ncomplete framebuffer"); | |
| 422 // copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OP
ERATION because | |
| 423 // the framebuffer is invalid OR INVALID_OPERATION because in the case o
f 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_OPERAT
ION], "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_OPERAT
ION], "copyTexSubImage2D from incomplete framebuffer"); | |
| 429 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | |
| 430 glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "clear with incomp
lete framebuffer"); | |
| 431 } | |
| 432 } | |
| 433 | |
| 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); | |
| 443 | |
| 444 debug(""); | |
| 445 debug("Wrong storage type for type of attachment be FRAMEBUFFER_INCOMPLETE_A
TTACHMENT (OpenGL ES 2.0 4.4.5)"); | |
| 446 gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, 16, 16); | |
| 447 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT); | |
| 448 | |
| 449 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16); | |
| 450 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE); | |
| 451 | |
| 452 debug(""); | |
| 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); | |
| 456 | |
| 457 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 458 } | |
| 459 | |
| 460 function testFramebufferIncompleteMissingAttachment() { | |
| 461 debug(""); | |
| 462 debug("No attachments should be INCOMPLETE_FRAMEBUFFER_MISSING_ATTACHMENT (O
penGL ES 2.0 4.4.5)"); | |
| 463 shouldBeNonNull("fbo = gl.createFramebuffer()"); | |
| 464 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); | |
| 465 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT); | |
| 466 | |
| 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); | |
| 473 | |
| 474 gl.framebufferRenderbuffer( | |
| 475 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, null); | |
| 476 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT); | |
| 477 | |
| 478 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 479 } | |
| 480 | |
| 481 function testFramebufferIncompleteDimensions() { | |
| 482 debug(""); | |
| 483 debug("Attachments of different sizes should be FRAMEBUFFER_INCOMPLETE_DIMEN
SIONS (OpenGL ES 2.0 4.4.5)"); | |
| 484 | |
| 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); | |
| 492 | |
| 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); | |
| 500 | |
| 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); | |
| 511 | |
| 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_BYT
E, 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) { | |
| 518 return; | |
| 519 } | |
| 520 | |
| 521 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 16, 0, gl.RGBA, gl.UNSIGNED_BYT
E, null); | |
| 522 checkFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS); | |
| 523 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYT
E, null); | |
| 524 checkFramebuffer(gl.FRAMEBUFFER_COMPLETE); | |
| 525 | |
| 526 glErrorShouldBe(gl, gl.NO_ERROR); | |
| 527 } | |
| 528 | |
| 529 successfullyParsed = true; | |
| 530 </script> | |
| 531 | |
| 532 </body> | |
| 533 </html> | |
| OLD | NEW |