| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <link rel="stylesheet" href="resources/webgl_test_files/resources/js-test-style.css"/> |
| <script src="resources/webgl_test_files/js/js-test-pre.js"></script> |
| <script src="resources/webgl_test_files/js/webgl-test-utils.js"></script> |
| </head> |
| <body onload="test()"> |
| <div id="description"></div> |
| <div id="console"></div> |
| <canvas id="canvas" width="2" height="2"></canvas> |
| <script> |
| "use strict"; |
| description("Test that draw buffer state is properly synced when framebuffer is bound to DRAW after modifications while bound to READ."); |
| |
| var wtu = WebGLTestUtils; |
| var gl; |
| |
| function test() |
| { |
| var canvas = document.getElementById("canvas"); |
| gl = wtu.create3DContext(canvas, undefined, 2); |
| |
| if (!gl) { |
| testFailed("WebGL2 context does not exist"); |
| finishTest(); |
| return; |
| } |
| |
| testDetachWhileBoundToRead(); |
| testAttachWhileBoundToRead(); |
| testMultipleDrawBuffers(); |
| |
| finishTest(); |
| } |
| |
| // Test 1: Detach texture while bound to READ, then rebind to DRAW |
| function testDetachWhileBoundToRead() |
| { |
| debug(""); |
| debug("Test 1: Detach while bound to READ_FRAMEBUFFER, then rebind to DRAW_FRAMEBUFFER"); |
| |
| var fb = gl.createFramebuffer(); |
| var texture = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_2D, texture); |
| gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); |
| |
| // Bind to DRAW, configure draw buffers, attach texture |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); |
| gl.drawBuffers([gl.COLOR_ATTACHMENT0]); |
| gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); |
| |
| // Verify initial state |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0"); |
| shouldBe("gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup should succeed"); |
| |
| // Switch to READ only |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); |
| gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb); |
| |
| // Detach texture while bound to READ only |
| gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "detach while bound to READ should succeed"); |
| |
| // Bind back to DRAW - draw buffer state should be synced |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); |
| |
| // getParameter returns user-set values, not internal filtered state |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0"); |
| |
| // Framebuffer has no attachments, so it's incomplete |
| shouldBe("gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); |
| |
| // Cleanup |
| gl.deleteFramebuffer(fb); |
| gl.deleteTexture(texture); |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); |
| gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); |
| } |
| |
| // Test 2: Attach texture while bound to READ, then rebind to DRAW |
| function testAttachWhileBoundToRead() |
| { |
| debug(""); |
| debug("Test 2: Attach while bound to READ_FRAMEBUFFER, then rebind to DRAW_FRAMEBUFFER"); |
| |
| var fb = gl.createFramebuffer(); |
| var texture = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_2D, texture); |
| gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); |
| |
| // Bind to DRAW, configure draw buffers (but don't attach yet) |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); |
| gl.drawBuffers([gl.COLOR_ATTACHMENT0]); |
| |
| // getParameter returns user-set values |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0"); |
| |
| // Framebuffer is incomplete - no attachment yet |
| shouldBe("gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); |
| |
| // Switch to READ only |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); |
| gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb); |
| |
| // Attach texture while bound to READ only |
| gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "attach while bound to READ should succeed"); |
| |
| // Bind back to DRAW - draw buffer state should be synced |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); |
| |
| // Draw buffer should now be COLOR_ATTACHMENT0 (attachment exists) |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0"); |
| |
| // Framebuffer should be complete |
| shouldBe("gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); |
| |
| // Cleanup |
| gl.deleteFramebuffer(fb); |
| gl.deleteTexture(texture); |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); |
| gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); |
| } |
| |
| // Test 3: Multiple draw buffers with partial detachment |
| function testMultipleDrawBuffers() |
| { |
| debug(""); |
| debug("Test 3: Multiple draw buffers with partial detachment while bound to READ"); |
| |
| var fb = gl.createFramebuffer(); |
| var texture0 = gl.createTexture(); |
| var texture1 = gl.createTexture(); |
| |
| gl.bindTexture(gl.TEXTURE_2D, texture0); |
| gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); |
| gl.bindTexture(gl.TEXTURE_2D, texture1); |
| gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); |
| |
| // Bind to DRAW, configure both draw buffers, attach both textures |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); |
| gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); |
| gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture0, 0); |
| gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, texture1, 0); |
| |
| // Verify initial state |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0"); |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER1)", "gl.COLOR_ATTACHMENT1"); |
| shouldBe("gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); |
| |
| // Switch to READ only |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); |
| gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb); |
| |
| // Detach texture1 from COLOR_ATTACHMENT1 while bound to READ |
| gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, null, 0); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "partial detach while bound to READ should succeed"); |
| |
| // Bind back to DRAW - draw buffer state should be synced |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); |
| |
| // getParameter returns user-set values |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER0)", "gl.COLOR_ATTACHMENT0"); |
| shouldBe("gl.getParameter(gl.DRAW_BUFFER1)", "gl.COLOR_ATTACHMENT1"); |
| |
| // Framebuffer should be complete (internal state filters out detached COLOR_ATTACHMENT1) |
| shouldBe("gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); |
| |
| // Cleanup |
| gl.deleteFramebuffer(fb); |
| gl.deleteTexture(texture0); |
| gl.deleteTexture(texture1); |
| gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); |
| gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); |
| } |
| </script> |
| </body> |
| </html> |