deleted-object-behavior.html (11921B)
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 <title>Deleted Object Behavior</title> 12 <link rel="stylesheet" href="../../resources/js-test-style.css"/> 13 <script src="../../js/js-test-pre.js"></script> 14 <script src="../../js/webgl-test-utils.js"></script> 15 </head> 16 <body> 17 <div id="description"></div> 18 <div id="canvases"> 19 <canvas id="canvas1"> 20 </div> 21 <div id="console"></div> 22 23 <script> 24 "use strict"; 25 description("Verifies behavior of deleted objects"); 26 27 const wtu = WebGLTestUtils; 28 const canvas1 = document.getElementById("canvas1"); 29 const sz = 64; 30 canvas1.width = sz; 31 canvas1.height = sz; 32 const gl = wtu.create3DContext("canvas1"); 33 let tex, rb; // for shouldBe 34 35 function testBoundFBOTexture() { 36 debug("Verifies that a texture attached to a bound framebuffer and then deleted is automatically detached"); 37 38 let fb = gl.createFramebuffer(); 39 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 40 tex = gl.createTexture(); 41 gl.bindTexture(gl.TEXTURE_2D, tex); 42 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sz, sz, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 43 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); 44 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup"); 45 // The WebGL 1.0 spec guarantees that this combination of attachments results 46 // in a complete framebuffer. 47 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE", 48 "Framebuffer should be complete after setup"); 49 debug("Texture should still be bound to the context"); 50 shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "tex"); 51 // Delete the texture. 52 gl.deleteTexture(tex); 53 debug("Texture should have been unbound from the context"); 54 shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)"); 55 debug("Framebuffer should report that the texture was detached"); 56 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE"); 57 debug("Framebuffer should be incomplete after texture was deleted"); 58 shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); 59 debug("Texture should not report that it's still a texture after deletion"); 60 shouldBe("gl.isTexture(tex)", "false"); 61 // Framebuffer should not function. 62 gl.clearColor(0.0, 1.0, 0.0, 1.0); 63 gl.clear(gl.COLOR_BUFFER_BIT); 64 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "Framebuffer should not work after deleting its only attachment"); 65 // Default framebuffer shouldn't have been touched. 66 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 67 wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black"); 68 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying default framebuffer's contents"); 69 // Attempt to bind deleted texture should fail. 70 gl.bindTexture(gl.TEXTURE_2D, tex); 71 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted texture"); 72 debug(""); 73 gl.deleteFramebuffer(fb); 74 } 75 76 function testUnboundFBOTexture() { 77 debug("Verifies that a texture attached to an unbound framebuffer and then deleted remains usable until detached"); 78 79 let fb = gl.createFramebuffer(); 80 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 81 tex = gl.createTexture(); 82 gl.bindTexture(gl.TEXTURE_2D, tex); 83 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sz, sz, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 84 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); 85 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup"); 86 // The WebGL 1.0 spec guarantees that this combination of attachments results 87 // in a complete framebuffer. 88 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE", 89 "Framebuffer should be complete after setup"); 90 // Unbind the framebuffer from the context so that deleting the texture 91 // doesn't automatically unbind it from the framebuffer. 92 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 93 debug("Texture should still be bound to the context"); 94 shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "tex"); 95 // Delete the texture. 96 gl.deleteTexture(tex); 97 debug("Texture should have been unbound from the context"); 98 shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)"); 99 // Framebuffer should still be complete. 100 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 101 debug("Framebuffer should still be complete after texture was deleted"); 102 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); 103 debug("Framebuffer should report that the texture is still attached"); 104 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex"); 105 debug("Texture should not report that it's still a texture after deletion"); 106 shouldBe("gl.isTexture(tex)", "false"); 107 // Framebuffer should still function. 108 gl.clearColor(0.0, 1.0, 0.0, 1.0); 109 gl.clear(gl.COLOR_BUFFER_BIT); 110 wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 255, 0, 255], "framebuffer should be green"); 111 // Deleting texture a second time should not unbind it from the framebuffer. 112 gl.deleteTexture(tex); 113 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "deleting an object twice is not an error"); 114 debug("Framebuffer should still report that the texture is attached"); 115 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex"); 116 // Default framebuffer shouldn't have been touched. 117 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 118 wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black"); 119 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying framebuffers' contents"); 120 // Attempt to bind deleted texture should fail. 121 gl.bindTexture(gl.TEXTURE_2D, tex); 122 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted texture"); 123 debug(""); 124 gl.deleteFramebuffer(fb); 125 } 126 127 function testBoundFBORenderbuffer() { 128 debug("Verifies that a renderbuffer attached to a bound framebuffer and then deleted is automatically detached"); 129 130 let fb = gl.createFramebuffer(); 131 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 132 rb = gl.createRenderbuffer(); 133 gl.bindRenderbuffer(gl.RENDERBUFFER, rb); 134 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, sz, sz) 135 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb); 136 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup"); 137 // The WebGL 1.0 spec doesn't guarantee that this framebuffer configuration 138 // will be complete. 139 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { 140 debug("Framebuffer with GL_RGBA4 renderbuffer was incomplete; skipping test"); 141 return; 142 } 143 debug("Renderbuffer should still be bound to the context"); 144 shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rb"); 145 // Delete the renderbuffer. 146 gl.deleteRenderbuffer(rb); 147 debug("Renderbuffer should have been unbound from the context"); 148 shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)"); 149 debug("Framebuffer should report that the texture was detached"); 150 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE"); 151 debug("Framebuffer should be incomplete after renderbuffer was deleted"); 152 shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); 153 debug("Renderbuffer should not report that it's still a renderbuffer after deletion"); 154 shouldBe("gl.isRenderbuffer(rb)", "false"); 155 // Framebuffer should not function. 156 gl.clearColor(0.0, 1.0, 0.0, 1.0); 157 gl.clear(gl.COLOR_BUFFER_BIT); 158 wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "Framebuffer should not work after deleting its only attachment"); 159 // Default framebuffer shouldn't have been touched. 160 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 161 wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black"); 162 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying framebuffers' contents"); 163 // Attempt to bind deleted renderbuffer should fail. 164 gl.bindRenderbuffer(gl.RENDERBUFFER, rb); 165 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted renderbuffer"); 166 debug(""); 167 gl.deleteFramebuffer(fb); 168 } 169 170 function testUnboundFBORenderbuffer() { 171 debug("Verifies that a renderbuffer attached to an unbound framebuffer and then deleted remains usable until detached"); 172 173 let fb = gl.createFramebuffer(); 174 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 175 rb = gl.createRenderbuffer(); 176 gl.bindRenderbuffer(gl.RENDERBUFFER, rb); 177 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, sz, sz) 178 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb); 179 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup"); 180 // The WebGL 1.0 spec doesn't guarantee that this framebuffer configuration 181 // will be complete. 182 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { 183 debug("Framebuffer with GL_RGBA4 renderbuffer was incomplete; skipping test"); 184 return; 185 } 186 // Unbind the framebuffer from the context so that deleting the renderbuffer 187 // doesn't automatically unbind it from the framebuffer. 188 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 189 debug("Renderbuffer should still be bound to the context"); 190 shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rb"); 191 // Delete the renderbuffer. 192 gl.deleteRenderbuffer(rb); 193 debug("Renderbuffer should have been unbound from the context"); 194 shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)"); 195 // Framebuffer should still be complete. 196 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 197 debug("Framebuffer should still be complete after renderbuffer was deleted"); 198 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); 199 debug("Framebuffer should report that the renderbuffer is still attached"); 200 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rb"); 201 debug("Renderbuffer should not report that it's still a renderbuffer after deletion"); 202 shouldBe("gl.isRenderbuffer(rb)", "false"); 203 // Framebuffer should still function. 204 gl.clearColor(0.0, 1.0, 0.0, 1.0); 205 gl.clear(gl.COLOR_BUFFER_BIT); 206 // Use a high tolerance to accommodate low bit depth precision. 207 wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 255, 0, 255], "framebuffer should be green", 20); 208 // Deleting renderbuffer a second time should not unbind it from the framebuffer. 209 gl.deleteRenderbuffer(rb); 210 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "deleting an object twice is not an error"); 211 debug("Framebuffer should still report that the renderbuffer is attached"); 212 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rb"); 213 // Default framebuffer shouldn't have been touched. 214 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 215 wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black"); 216 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying framebuffers' contents"); 217 // Attempt to bind deleted renderbuffer should fail. 218 gl.bindRenderbuffer(gl.RENDERBUFFER, rb); 219 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted renderbuffer"); 220 debug(""); 221 gl.deleteFramebuffer(fb); 222 } 223 224 function runTests() { 225 testBoundFBOTexture(); 226 testUnboundFBOTexture(); 227 testBoundFBORenderbuffer(); 228 testUnboundFBORenderbuffer(); 229 finishTest(); 230 } 231 232 requestAnimationFrame(runTests); 233 234 var successfullyParsed = true; 235 </script> 236 </body> 237 </html>