blitframebuffer-outside-readbuffer.html (13100B)
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>WebGL BlitFramebuffer Tests</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="example" width="8" height="8"></canvas> 18 <div id="description"></div> 19 <div id="console"></div> 20 21 <script> 22 "use strict"; 23 24 var wtu = WebGLTestUtils; 25 description("This test verifies the functionality of blitFramebuffer."); 26 27 var gl = wtu.create3DContext("example", undefined, 2); 28 29 function checkPixel(color, expectedColor) { 30 var tolerance = 3; 31 return (Math.abs(color[0] - expectedColor[0]) <= tolerance && 32 Math.abs(color[1] - expectedColor[1]) <= tolerance && 33 Math.abs(color[2] - expectedColor[2]) <= tolerance && 34 Math.abs(color[3] - expectedColor[3]) <= tolerance); 35 } 36 37 function blitframebuffer_outside_readbuffer(readbufferFormat, drawbufferFormat) { 38 debug(""); 39 debug("blitting outside of read framebuffer, read buffer format is: " + wtu.glEnumToString(gl, readbufferFormat) + ", draw buffer format is: " + wtu.glEnumToString(gl, drawbufferFormat)); 40 41 // Initiate data to read framebuffer 42 var size_read = 3; 43 var uint_read = new Uint8Array(size_read * size_read * 4); 44 var start = 0x20; 45 for (var ii = 0; ii < size_read * size_read * 4; ii += 4) { 46 for (var jj = 0; jj < 3; ++jj) { 47 uint_read[ii + jj] = start; 48 } 49 uint_read[ii + 3] = 0xff; 50 start += 0x10; 51 } 52 53 // Create read framebuffer and feed data to read buffer 54 // Read buffer may has srgb image 55 var tex_read = gl.createTexture(); 56 gl.bindTexture(gl.TEXTURE_2D, tex_read); 57 gl.texImage2D(gl.TEXTURE_2D, 0, readbufferFormat, size_read, size_read, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_read); 58 59 var fbo_read = gl.createFramebuffer(); 60 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); 61 gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_read, 0); 62 63 // Initiate data to draw framebuffer 64 var size_draw = 7; 65 var uint_draw = new Uint8Array(size_draw * size_draw * 4); 66 for (var ii = 0; ii < size_draw * size_draw * 4; ii += 4) { 67 for (var jj = 0; jj < 3; ++jj) { 68 uint_draw[ii + jj] = 0x10; 69 } 70 uint_draw[ii + 3] = 0xff; 71 } 72 73 // Create draw framebuffer and feed data to draw buffer 74 // Draw buffer may has srgb image 75 var tex_draw = gl.createTexture(); 76 gl.bindTexture(gl.TEXTURE_2D, tex_draw); 77 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 78 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 79 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 80 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 81 82 gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size_draw, size_draw, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint_draw); 83 84 var fbo_draw = gl.createFramebuffer(); 85 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); 86 gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_draw, 0); 87 88 if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) { 89 var ref = [ 90 // The reference pixels of the 1st line: (0, 0) ~ (6, 0) 91 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 92 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 93 94 // The reference pixels of the 2nd line: (0, 1) ~ (6, 1) 95 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 96 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 97 98 // The reference pixels of the 3rd line: (0, 2) ~ (6, 2) 99 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x20, 0x20, 0x20, 0xff], [0x30, 0x30, 0x30, 0xff], 100 [0x40, 0x40, 0x40, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 101 102 // The reference pixels of the 4th line: (0, 3) ~ (6, 3) 103 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x50, 0x50, 0x50, 0xff], [0x60, 0x60, 0x60, 0xff], 104 [0x70, 0x70, 0x70, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 105 106 // The reference pixels of the 5th line: (0, 4) ~ (6, 4) 107 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x80, 0x80, 0x80, 0xff], [0x90, 0x90, 0x90, 0xff], 108 [0xa0, 0xa0, 0xa0, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 109 110 // The reference pixels of the 6th line: (0, 5) ~ (6, 5) 111 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 112 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 113 114 // The reference pixels of the 7th line: (0, 6) ~ (6, 6) 115 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 116 [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], [0x10, 0x10, 0x10, 0xff], 117 ]; 118 119 // The 1st round test: blit read framebuffer to the image in draw framebuffer 120 // All directions of the read region have pixels outside of the read buffer 121 // The src region and/or dst region may be reversed during blitting. 122 var test1 = [ 123 [-1, 4, 1, 6], // reverse neither src nor dst 124 [4, -1, 1, 6], // reverse src only 125 [-1, 4, 6, 1], // reverse dst only 126 [4, -1, 6, 1] // reverse both src and dst 127 ]; 128 129 var readbufferHasSRGBImage = (readbufferFormat == gl.SRGB8_ALPHA8); 130 var drawbufferHasSRGBImage = (drawbufferFormat == gl.SRGB8_ALPHA8); 131 132 for (var i = 0; i < 4; ++i) { 133 debug(""); 134 switch (i) { 135 case 0: debug("reverse neither src region nor dst region"); break; 136 case 1: debug("reverse src region only"); break; 137 case 2: debug("reverse dst region only"); break; 138 case 3: debug("reverse both src region and dst region"); break; 139 } 140 var srcStart = test1[i][0]; 141 var srcEnd = test1[i][1]; 142 var dstStart = test1[i][2]; 143 var dstEnd = test1[i][3]; 144 var realBlittedDstStart = 2; 145 var realBlittedDstEnd = 5; 146 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); 147 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); 148 gl.blitFramebuffer(srcStart, srcStart, srcEnd, srcEnd, dstStart, dstStart, dstEnd, dstEnd, gl.COLOR_BUFFER_BIT, gl.LINEAR); 149 150 // Read pixels and check the correctness. 151 var pixels = new Uint8Array(size_draw * size_draw * 4); 152 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); 153 gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels); 154 155 for (var ii = 0; ii < size_draw; ++ii) { 156 for (var jj = 0; jj < size_draw; ++jj) { 157 var loc = ii * size_draw + jj; 158 var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]]; 159 160 // We may need to reverse the reference loc if necessary 161 var ref_loc = loc; 162 var reverse_src = (srcStart < srcEnd); 163 var reverse_dst = (dstStart < dstEnd); 164 var reversed = reverse_src ^ reverse_dst; 165 if (reversed) { 166 ref_loc = (size_draw - ii - 1) * size_draw + (size_draw - jj -1); 167 } 168 var expectedColor = ref[ref_loc]; 169 170 // We may need to covert the color space for pixels in blit region 171 if ((readbufferHasSRGBImage ^ drawbufferHasSRGBImage) && 172 (ii >= realBlittedDstStart && ii < realBlittedDstEnd && jj >= realBlittedDstStart && jj < realBlittedDstEnd)) { 173 if (drawbufferHasSRGBImage) { 174 expectedColor = wtu.linearToSRGB(expectedColor); 175 } else { 176 expectedColor = wtu.sRGBToLinear(expectedColor); 177 } 178 } 179 if (checkPixel(color, expectedColor) == true) { 180 testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!"); 181 } else { 182 testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")"); 183 } 184 } 185 } 186 } 187 188 // The 2nd round test: blit read framebuffer to the image in draw framebuffer 189 // Only one direction of the read region have pixels outside of the read buffer 190 var tests = [ 191 [-1, 0], // pixels are outside the left edge of the read buffer 192 [0, -1], // pixels are outside the bottom edge of the read buffer 193 [1, 0], // pixels are outside the right edge of the read buffer 194 [0, 1] // pixels are outside the top edge of the read buffer 195 ]; 196 for (var i = 0; i < 4; ++i) { 197 debug(""); 198 switch (i) { 199 case 0: debug("verify that pixels lying outside the left edge of the read buffer should remain untouched"); break; 200 case 1: debug("verify that pixels lying outside the bottom edge of the read buffer should remain untouched"); break; 201 case 2: debug("verify that pixels lying outside the right edge of the read buffer should remain untouched"); break; 202 case 3: debug("verify that pixels lying outside the top edge of the read buffer should remain untouched"); break; 203 } 204 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read); 205 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw); 206 var srcX = tests[i][0]; 207 var srcY = tests[i][1]; 208 var offset = dstStart - srcStart; 209 gl.blitFramebuffer(srcX, srcY, srcX + size_read, srcY + size_read, 210 srcX + offset, srcY + offset, srcX + offset + size_read, srcY + offset + size_read, 211 gl.COLOR_BUFFER_BIT, gl.LINEAR); 212 213 // Read pixels and check the correctness. 214 var pixels = new Uint8Array(size_draw * size_draw * 4); 215 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw); 216 gl.readPixels(0, 0, size_draw, size_draw, gl.RGBA, gl.UNSIGNED_BYTE, pixels); 217 for (var ii = srcY + offset; ii < srcY + offset + size_read; ++ii) { 218 for (var jj = srcX + offset; jj < srcX + offset + size_read; ++jj) { 219 var loc = ii * size_draw + jj; 220 var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]]; 221 var expectedColor = ref[loc]; 222 // We may need to covert the color space for pixels in blit region 223 if ((readbufferHasSRGBImage ^ drawbufferHasSRGBImage) && 224 (ii >= realBlittedDstStart && ii < realBlittedDstEnd && jj >= realBlittedDstStart && jj < realBlittedDstEnd)) { 225 if (drawbufferHasSRGBImage) { 226 expectedColor = wtu.linearToSRGB(expectedColor); 227 } else { 228 expectedColor = wtu.sRGBToLinear(expectedColor); 229 } 230 } 231 if (checkPixel(color, expectedColor) == true) { 232 testPassed("pixel at [" + jj + ", " + ii + "] is (" + color + "). It is correct!"); 233 } else { 234 testFailed("pixel at [" + jj + ", " + ii + "] should be (" + expectedColor + "), but the actual color is (" + color + ")"); 235 } 236 } 237 } 238 } 239 } else { 240 testFailed("framebuffer not complete"); 241 } 242 243 gl.bindTexture(gl.TEXTURE_2D, null); 244 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); 245 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); 246 gl.deleteFramebuffer(fbo_read); 247 gl.deleteFramebuffer(fbo_draw); 248 gl.deleteTexture(tex_read); 249 gl.deleteTexture(tex_draw); 250 }; 251 252 if (!gl) { 253 testFailed("WebGL context does not exist"); 254 } else { 255 testPassed("WebGL context exists"); 256 blitframebuffer_outside_readbuffer(gl.RGBA8, gl.RGBA8); 257 blitframebuffer_outside_readbuffer(gl.RGBA8, gl.SRGB8_ALPHA8); 258 blitframebuffer_outside_readbuffer(gl.SRGB8_ALPHA8, gl.RGBA8); 259 blitframebuffer_outside_readbuffer(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8); 260 } 261 262 var successfullyParsed = true; 263 </script> 264 <script src="../../js/js-test-post.js"></script> 265 266 </body> 267 </html>