framebuffer-object-attachment.html (30256B)
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 --> 6 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> 18 19 <script> 20 "use strict"; 21 var wtu = WebGLTestUtils; 22 var gl; 23 24 function checkFramebuffer(expected) { 25 var actual = gl.checkFramebufferStatus(gl.FRAMEBUFFER); 26 if (expected.indexOf(actual) < 0) { 27 var msg = "checkFramebufferStatus expects ["; 28 for (var index = 0; index < expected.length; ++index) { 29 msg += wtu.glEnumToString(gl, expected[index]); 30 if (index + 1 < expected.length) 31 msg += ", "; 32 } 33 msg += "], was " + wtu.glEnumToString(gl, actual); 34 testFailed(msg); 35 } else { 36 var msg = "checkFramebufferStatus got " + wtu.glEnumToString(gl, actual) + 37 " as expected"; 38 testPassed(msg); 39 } 40 } 41 42 function checkBufferBits(attachment0, attachment1) { 43 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) 44 return; 45 var haveDepthBuffer = attachment0 == gl.DEPTH_ATTACHMENT || 46 attachment0 == gl.DEPTH_STENCIL_ATTACHMENT || 47 attachment1 == gl.DEPTH_ATTACHMENT || 48 attachment1 == gl.DEPTH_STENCIL_ATTACHMENT; 49 var haveStencilBuffer = attachment0 == gl.STENCIL_ATTACHMENT || 50 attachment0 == gl.DEPTH_STENCIL_ATTACHMENT || 51 attachment1 == gl.STENCIL_ATTACHMENT || 52 attachment1 == gl.DEPTH_STENCIL_ATTACHMENT; 53 shouldBeTrue("gl.getParameter(gl.RED_BITS) + gl.getParameter(gl.GREEN_BITS) + " + 54 "gl.getParameter(gl.BLUE_BITS) + gl.getParameter(gl.ALPHA_BITS) >= 16"); 55 if (haveDepthBuffer) 56 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) >= 16"); 57 else 58 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) == 0"); 59 if (haveStencilBuffer) 60 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) >= 8"); 61 else 62 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) == 0"); 63 } 64 65 66 function testFramebufferWebGL1RequiredCombinations() { 67 debug("Checking combinations of framebuffer attachments required to be valid by WebGL 1"); 68 69 // Per discussion with the OpenGL ES working group, the following framebuffer attachment 70 // combinations are required to work in all WebGL 1 implementations: 71 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture 72 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer 73 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer 74 75 var fbo = gl.createFramebuffer(); 76 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 77 78 var width = 64; 79 var height = 64; 80 81 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture 82 var texture = gl.createTexture(); 83 gl.bindTexture(gl.TEXTURE_2D, texture); 84 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 85 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 86 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 87 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 88 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 89 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); 90 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 91 checkBufferBits(); 92 93 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer 94 var renderbuffer = gl.createRenderbuffer(); 95 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); 96 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height); 97 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer); 98 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 99 checkBufferBits(gl.DEPTH_ATTACHMENT); 100 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null); 101 102 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer 103 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height); 104 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer); 105 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 106 checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT); 107 108 // Clean up 109 gl.deleteRenderbuffer(renderbuffer); 110 gl.deleteTexture(texture); 111 gl.deleteFramebuffer(fbo); 112 } 113 114 function testDepthStencilAttachmentBehaviors(testOrphanedRenderbuffers) { 115 let suffix = testOrphanedRenderbuffers ? " with deleted renderbuffer" : ""; 116 debug(""); 117 debug("Checking ES3 DEPTH_STENCIL_ATTACHMENT behaviors are implemented for WebGL 2" + suffix); 118 // DEPTH_STENCIL_ATTACHMENT is treated as an independent attachment point in WebGL 1; 119 // however, in WebGL 2, it is treated as an alias for DEPTH_ATTACHMENT + STENCIL_ATTACHMENT. 120 var size = 16; 121 122 var fbo = gl.createFramebuffer(); 123 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 124 var colorBuffer = gl.createRenderbuffer(); 125 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer); 126 gl.framebufferRenderbuffer( 127 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer); 128 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, size, size); 129 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 130 131 function createDepthBuffer() { 132 let buffer = gl.createRenderbuffer(); 133 gl.bindRenderbuffer(gl.RENDERBUFFER, buffer); 134 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size); 135 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 136 return buffer; 137 } 138 139 function createStencilBuffer() { 140 let buffer = gl.createRenderbuffer(); 141 gl.bindRenderbuffer(gl.RENDERBUFFER, buffer); 142 gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, size, size); 143 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 144 return buffer; 145 } 146 147 function createDepthStencilBuffer() { 148 let buffer = gl.createRenderbuffer(); 149 gl.bindRenderbuffer(gl.RENDERBUFFER, buffer); 150 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, size, size); 151 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 152 return buffer; 153 } 154 155 function orphan(renderbuffer) { 156 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 157 gl.deleteRenderbuffer(renderbuffer); 158 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 159 } 160 161 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 162 163 debug(""); 164 debug("color + depth" + suffix); 165 var depthBuffer = createDepthBuffer(); 166 gl.framebufferRenderbuffer( 167 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); 168 if (testOrphanedRenderbuffers) 169 orphan(depthBuffer); 170 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer); 171 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 172 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 173 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); 174 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 175 checkBufferBits(gl.DEPTH_ATTACHMENT); 176 177 debug(""); 178 debug("color + depth + stencil: depth != stencil" + suffix); 179 var stencilBuffer = createStencilBuffer(); 180 gl.framebufferRenderbuffer( 181 gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, stencilBuffer); 182 if (testOrphanedRenderbuffers) 183 orphan(stencilBuffer); 184 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer); 185 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", stencilBuffer); 186 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 187 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); 188 checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]); 189 190 gl.framebufferRenderbuffer( 191 gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null); 192 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer); 193 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 194 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 195 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); 196 197 debug(""); 198 debug("color + depth: DEPTH_STENCIL for DEPTH_ATTACHMENT" + suffix); 199 var depthStencilBuffer = createDepthStencilBuffer(); 200 gl.framebufferRenderbuffer( 201 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); 202 if (testOrphanedRenderbuffers) 203 orphan(depthStencilBuffer); 204 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 205 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 206 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 207 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); 208 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 209 checkBufferBits(gl.DEPTH_ATTACHMENT); 210 211 debug(""); 212 debug("color + depth + stencil: DEPTH_STENCIL for DEPTH_ATTACHMENT and STENCIL_ATTACHMENT" + suffix); 213 if (testOrphanedRenderbuffers) { 214 depthStencilBuffer = createDepthStencilBuffer(); 215 gl.framebufferRenderbuffer( 216 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); 217 } 218 gl.framebufferRenderbuffer( 219 gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); 220 if (testOrphanedRenderbuffers) 221 orphan(depthStencilBuffer); 222 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 223 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 224 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 225 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 226 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 227 checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT); 228 229 debug(""); 230 debug("color + depth_stencil" + suffix); 231 var texture = gl.createTexture(); 232 gl.bindTexture(gl.TEXTURE_2D, texture); 233 gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH24_STENCIL8, size, size, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null); 234 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, texture, 0); 235 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture); 236 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture); 237 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture); 238 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 239 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 240 241 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, null, 0); 242 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 243 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 244 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 245 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 246 247 if (testOrphanedRenderbuffers) 248 depthStencilBuffer = createDepthStencilBuffer(); 249 gl.framebufferRenderbuffer( 250 gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); 251 if (testOrphanedRenderbuffers) 252 orphan(depthStencilBuffer); 253 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 254 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 255 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 256 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 257 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 258 checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT); 259 260 debug(""); 261 debug("DEPTH_STENCIL_ATTACHMENT overwrites DEPTH_ATTACHMENT/STENCIL_ATTACHMENT" + suffix); 262 if (testOrphanedRenderbuffers) 263 depthBuffer = createDepthBuffer(); 264 gl.framebufferRenderbuffer( 265 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); 266 if (testOrphanedRenderbuffers) 267 orphan(depthBuffer); 268 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer); 269 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 270 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 271 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); 272 273 if (testOrphanedRenderbuffers) 274 depthStencilBuffer = createDepthStencilBuffer(); 275 gl.framebufferRenderbuffer( 276 gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); 277 if (testOrphanedRenderbuffers) 278 orphan(depthStencilBuffer); 279 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 280 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 281 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 282 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 283 284 gl.framebufferRenderbuffer( 285 gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, null); 286 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 287 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 288 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 289 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 290 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 291 checkBufferBits(); 292 293 debug(""); 294 debug("STENCIL_ATTACHMENT overwrites stencil set by DEPTH_STENCIL_ATTACHMENT" + suffix); 295 if (testOrphanedRenderbuffers) 296 depthStencilBuffer = createDepthStencilBuffer(); 297 gl.framebufferRenderbuffer( 298 gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); 299 if (testOrphanedRenderbuffers) 300 orphan(depthStencilBuffer); 301 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 302 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 303 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 304 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 305 306 gl.framebufferRenderbuffer( 307 gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null); 308 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 309 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 310 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 311 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); 312 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 313 checkBufferBits(gl.DEPTH_ATTACHMENT); 314 315 debug(""); 316 debug("DEPTH_ATTACHMENT overwrites depth set by DEPTH_STENCIL_ATTACHMENT" + suffix); 317 if (testOrphanedRenderbuffers) 318 depthStencilBuffer = createDepthStencilBuffer(); 319 gl.framebufferRenderbuffer( 320 gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); 321 if (testOrphanedRenderbuffers) 322 orphan(depthStencilBuffer); 323 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 324 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 325 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 326 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 327 328 gl.framebufferRenderbuffer( 329 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null); 330 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 331 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); 332 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); 333 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); 334 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 335 checkBufferBits(gl.STENCIL_ATTACHMENT); 336 } 337 338 function testFramebufferIncompleteAttachment() { 339 var fbo = gl.createFramebuffer(); 340 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 341 var colorBuffer = gl.createRenderbuffer(); 342 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer); 343 gl.framebufferRenderbuffer( 344 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer); 345 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16); 346 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 347 348 debug(""); 349 debug("Wrong storage type for type of attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); 350 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 16, 16); 351 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT]); 352 353 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16); 354 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 355 356 debug(""); 357 debug("0 size attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); 358 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0); 359 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT]); 360 361 gl.deleteRenderbuffer(colorBuffer); 362 gl.deleteFramebuffer(fbo); 363 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 364 } 365 366 function testFramebufferIncompleteMissingAttachment() { 367 debug(""); 368 debug("No attachments should be INCOMPLETE_FRAMEBUFFER_MISSING_ATTACHMENT"); 369 var fbo = gl.createFramebuffer(); 370 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 371 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT]); 372 373 var colorBuffer = gl.createRenderbuffer(); 374 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer); 375 gl.framebufferRenderbuffer( 376 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer); 377 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16); 378 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 379 380 gl.framebufferRenderbuffer( 381 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, null); 382 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT]); 383 384 gl.deleteRenderbuffer(colorBuffer); 385 gl.deleteFramebuffer(fbo); 386 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 387 } 388 389 function testFramebufferWithImagesOfDifferentSizes() { 390 debug(""); 391 debug("Attachments of different sizes should NOT be allowed"); 392 393 var fbo = gl.createFramebuffer(); 394 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 395 var colorBuffer = gl.createRenderbuffer(); 396 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer); 397 gl.framebufferRenderbuffer( 398 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer); 399 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16); 400 401 var depthBuffer = gl.createRenderbuffer(); 402 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); 403 gl.framebufferRenderbuffer( 404 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); 405 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 16, 16); 406 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 407 checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); 408 409 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 32, 16); 410 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS]); 411 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer); 412 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 32); 413 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS]); 414 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 415 416 var tex = gl.createTexture(); 417 gl.bindTexture(gl.TEXTURE_2D, tex); 418 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 419 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); 420 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 421 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) { 422 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 423 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS]); 424 } 425 426 gl.deleteTexture(tex); 427 gl.deleteRenderbuffer(depthBuffer); 428 gl.deleteRenderbuffer(colorBuffer); 429 gl.deleteFramebuffer(fbo); 430 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 431 } 432 433 function testUsingIncompleteFramebuffer() { 434 debug(""); 435 debug("Test drawing or reading from an incomplete framebuffer"); 436 var program = wtu.setupTexturedQuad(gl); 437 var tex = gl.createTexture(); 438 wtu.fillTexture(gl, tex, 1, 1, [0,255,0,255]); 439 440 var fbo = gl.createFramebuffer(); 441 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 442 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT]); 443 debug(""); 444 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION"); 445 testRenderingAndReading(); 446 447 var colorBuffer = gl.createRenderbuffer(); 448 gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer); 449 gl.framebufferRenderbuffer( 450 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer); 451 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0); 452 checkFramebuffer([gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT]); 453 debug(""); 454 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION"); 455 testRenderingAndReading(); 456 457 function testRenderingAndReading() { 458 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 459 wtu.clearAndDrawUnitQuad(gl); 460 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "drawArrays with incomplete framebuffer"); 461 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4)); 462 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "readPixels from incomplete framebuffer"); 463 // copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OPERATION because 464 // the framebuffer is invalid OR INVALID_OPERATION because in the case of no attachments 465 // the framebuffer is not of a compatible type. 466 gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1); 467 wtu.glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION], 468 "copyTexImage2D from incomplete framebuffer"); 469 gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 1, 1, 0); 470 wtu.glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION], 471 "copyTexSubImage2D from incomplete framebuffer"); 472 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 473 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "clear with incomplete framebuffer"); 474 } 475 476 gl.deleteRenderbuffer(colorBuffer); 477 gl.deleteFramebuffer(fbo); 478 gl.deleteTexture(tex); 479 gl.deleteProgram(program); 480 } 481 482 function testReadingFromMissingAttachment() { 483 debug(""); 484 debug("Test drawing or reading from a framebuffer with no color image"); 485 486 var fbo = gl.createFramebuffer(); 487 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 488 var object_type = gl.getFramebufferAttachmentParameter( 489 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE); 490 if (object_type != gl.NONE) 491 testFailed("object type from empty attachment point should be NONE"); 492 else 493 testPassed("object type from empty attachment point is NONE"); 494 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query should not generate error"); 495 496 var object_name = gl.getFramebufferAttachmentParameter( 497 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME); 498 if (object_name) 499 testFailed("object name from empty attachment point should be null"); 500 else 501 testPassed("object name from empty attachment point is null"); 502 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query should not generate error"); 503 504 var size = 16; 505 506 // The only scenario we can verify is an attempt to read or copy 507 // from a missing color attachment while the framebuffer is still 508 // complete. 509 var depthBuffer = gl.createRenderbuffer(); 510 gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); 511 gl.framebufferRenderbuffer( 512 gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); 513 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size); 514 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After depth renderbuffer setup"); 515 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) { 516 // The FBO has no color attachment. ReadPixels, CopyTexImage2D, 517 // and CopyTexSubImage2D should all generate INVALID_OPERATION. 518 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before ReadPixels from missing attachment"); 519 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4)); 520 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After ReadPixels from missing attachment"); 521 522 var tex = gl.createTexture(); 523 gl.bindTexture(gl.TEXTURE_2D, tex); 524 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before CopyTexImage2D from missing attachment"); 525 gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, size, size, 0); 526 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After CopyTexImage2D from missing attachment"); 527 528 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 529 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Before CopyTexSubImage2D from missing attachment"); 530 gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, size, size); 531 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "After CopyTexSubImage2D from missing attachment"); 532 533 gl.deleteTexture(tex); 534 } 535 536 gl.deleteRenderbuffer(depthBuffer); 537 gl.deleteFramebuffer(fbo); 538 } 539 540 description("Test framebuffer object attachment behaviors"); 541 542 shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, 2)"); 543 544 testFramebufferWebGL1RequiredCombinations(); 545 testDepthStencilAttachmentBehaviors(false); 546 testDepthStencilAttachmentBehaviors(true); 547 testFramebufferIncompleteAttachment(); 548 testFramebufferIncompleteMissingAttachment(); 549 testFramebufferWithImagesOfDifferentSizes(); 550 testUsingIncompleteFramebuffer(); 551 testReadingFromMissingAttachment(); 552 553 // - 554 555 debug(""); 556 debug("Test calling framebufferTexture2D with impossible mip levels."); 557 558 const fb = gl.createFramebuffer(); 559 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 560 561 const tex = gl.createTexture(); 562 gl.bindTexture(gl.TEXTURE_2D, tex); 563 564 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 1000); 565 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Mip level attachment impossibly high."); 566 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 10); 567 wtu.glErrorShouldBe(gl, 0, "Mip level attachment within acceptable range."); 568 569 // Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1636517 : 570 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 1000); 571 wtu.glErrorShouldBe(gl, 0, "Mip level detachment can be impossibly high."); 572 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "0"); 573 574 // - 575 576 debug("") 577 var successfullyParsed = true; 578 </script> 579 580 <script src="../../js/js-test-post.js"></script> 581 </body> 582 </html>