multisampling-depth-resolve.html (6066B)
1 <!-- 2 Copyright (c) 2022 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>WebGL framebuffer to texture conformance test.</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 <canvas id="canvas"></canvas> 18 <div id="description"></div> 19 <div id="console"></div> 20 <script> 21 "use strict"; 22 description("Test resolving multisample depth buffer"); 23 debug('Reduced test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=238118">https://bugs.webkit.org/show_bug.cgi?id=238118</a>'); 24 25 // Reproduces an inconistent behavior where if: 26 // 1) You render into a multisampling frame buffer 27 // 2) Geometry is drawn with DEPTH_TEST disabled and then enabled 28 // 3) More than one frame is rendered via requestAnimationFrame 29 30 const size = 64; 31 const halfSize = size / 2; 32 33 let wtu = WebGLTestUtils; 34 let canvas = document.getElementById("canvas"); 35 canvas.width = size; 36 canvas.height = size; 37 38 let gl = wtu.create3DContext("canvas", {}, 2); 39 40 function createTexture(res, format, bytes) { 41 let texture = gl.createTexture(); 42 gl.bindTexture(gl.TEXTURE_2D, texture); 43 gl.texStorage2D(gl.TEXTURE_2D, 1, format, res, res); 44 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 45 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 46 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 47 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 48 gl.bindTexture(gl.TEXTURE_2D, null); 49 return texture; 50 } 51 52 function createRenderBuffer(res, format, samples) { 53 let rb = gl.createRenderbuffer(); 54 gl.bindRenderbuffer(gl.RENDERBUFFER, rb); 55 if (samples > 1) 56 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, format, res, res); 57 else 58 gl.renderbufferStorage(gl.RENDERBUFFER, format, res, res); 59 return rb; 60 } 61 62 let yellowQuadVAO = gl.createVertexArray(); 63 gl.bindVertexArray(yellowQuadVAO); 64 let yellowQuadProgram = wtu.setupColorQuad(gl, 0, { scale: 0.75 }); 65 66 let blueQuadVAO = gl.createVertexArray(); 67 gl.bindVertexArray(blueQuadVAO); 68 let blueQuadProgram = wtu.setupColorQuad(gl, 0, { scale: 0.5 }); 69 70 let fsVAO = gl.createVertexArray(); 71 gl.bindVertexArray(fsVAO); 72 let fsProgram = wtu.setupTexturedQuad(gl, 0, 1); 73 gl.useProgram(fsProgram); 74 let fsTexLoc = gl.getUniformLocation(fsProgram, "tex"); 75 gl.uniform1i(fsTexLoc, 0); 76 77 // An incorrect render can occur if... 78 79 // 1) You use renderbufferStorageMultisample. 80 const msaaSamples = 4; 81 const colorRB = createRenderBuffer(size, gl.RGBA8, msaaSamples); 82 const depthRB = createRenderBuffer(size, gl.DEPTH_COMPONENT16, msaaSamples); 83 const resolveTex = createTexture(size, gl.RGBA8); 84 85 let renderFBO = gl.createFramebuffer(); 86 gl.bindFramebuffer(gl.FRAMEBUFFER, renderFBO); 87 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRB); 88 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthRB); 89 90 let resolveFBO = gl.createFramebuffer(); 91 gl.bindFramebuffer(gl.FRAMEBUFFER, resolveFBO); 92 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, resolveTex, 0); 93 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 94 95 gl.disable(gl.CULL_FACE); 96 gl.disable(gl.BLEND); 97 98 var frameCount = 0; 99 function runTest() { 100 // 2) Render from requestAnimationFrame, only starting with the 2nd frame. 101 gl.bindFramebuffer(gl.FRAMEBUFFER, renderFBO); 102 103 // Clear background red 104 gl.clearColor(1, 0, 0, 1); 105 gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); 106 107 // 3) You disable gl.DEPTH_TEST 108 gl.disable(gl.DEPTH_TEST); 109 gl.depthMask(false); 110 111 gl.bindVertexArray(yellowQuadVAO); 112 gl.useProgram(yellowQuadProgram); 113 wtu.drawUByteColorQuad(gl, [ 255, 255, 0, 255 ]); 114 115 // 4) And re-enable gl.DEPTH_TEST 116 gl.enable(gl.DEPTH_TEST); 117 gl.depthMask(true); 118 119 gl.bindVertexArray(blueQuadVAO); 120 gl.useProgram(blueQuadProgram); 121 wtu.drawUByteColorQuad(gl, [ 0, 0, 255, 255 ]); 122 123 // Resolve the multisample framebuffer to a texture 124 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, renderFBO); 125 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, resolveFBO); 126 gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 0.0, 0.0]); 127 gl.blitFramebuffer(0, 0, size, size, 128 0, 0, size, size, 129 gl.COLOR_BUFFER_BIT, gl.LINEAR); 130 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); 131 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); 132 133 // Draw the resolved texture to the backbuffer 134 gl.bindTexture(gl.TEXTURE_2D, resolveTex); 135 gl.useProgram(fsProgram); 136 gl.bindVertexArray(fsVAO); 137 wtu.drawUnitQuad(gl); 138 139 // 5) The incorrect render can occur on the second rendered frame, called from 140 // requestAnimationFrame. 141 frameCount++; 142 if (frameCount == 2) { 143 checkRenderingResults("multisampling-depth-resolve"); 144 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors at the end of the test."); 145 finishTest(); 146 } else { 147 requestAnimationFrame(runTest); 148 } 149 } 150 151 requestAnimationFrame(runTest); 152 153 function checkRenderingResults(prefix) { 154 // Outer color should be red 155 wtu.checkCanvasRect(gl, 156 1, 1, 157 2, 2, 158 [255, 0, 0, 255], 159 prefix + ": outer pixels should be red"); 160 161 // Outer quad should be rendered yellow. 162 wtu.checkCanvasRect(gl, 163 10, 10, 164 2, 2, 165 [255, 255, 0, 255], 166 prefix + ": outer quad should be yellow"); 167 168 // Center quad should be rendered blue. 169 wtu.checkCanvasRect(gl, 170 halfSize / 2 + 1, halfSize / 2 + 1, 171 2, 2, 172 [0, 0, 255, 255], 173 prefix + ": center quad should be blue"); 174 } 175 176 var successfullyParsed = true; 177 </script> 178 </body> 179 </html>