drawingbuffer-storage-test.js (8105B)
1 /* 2 Copyright (c) 2023 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 "use strict"; 8 9 let gl; 10 let oldViewport; 11 let width; 12 let height; 13 let format; 14 let hasDrawingBufferStorage; 15 let maxRenderbufferSize; 16 17 function runTest(contextVersion) { 18 description(); 19 debug(""); 20 21 function initialize() { 22 let canvas = document.createElement("canvas"); 23 gl = wtu.create3DContext(canvas, {antialias: false}); 24 if (!gl) { 25 testFailed("context does not exist"); 26 return [0, 0]; 27 } 28 29 hasDrawingBufferStorage = `drawingBufferStorage` in gl; 30 if (!hasDrawingBufferStorage) { 31 testPassed("drawingBufferStorage not present -- skipping test"); 32 return; 33 } 34 35 maxRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); 36 } 37 38 function testPixel(expected, actual, tol) { 39 let str = 'approx equal: expected: ' + expected + ', actual: ' + actual + ', tolerance: ' + tol; 40 for (let i = 0; i < 4; ++i) { 41 if (Math.abs(expected[i] - actual[i]) > tol) { 42 testFailed(str); 43 return; 44 } 45 } 46 testPassed(str); 47 } 48 49 function srgbToLinear(x) { 50 if (x < 0.0) 51 return 0.0; 52 if (x < 0.04045) 53 return x / 12.92; 54 if (x < 1.0) { 55 return Math.pow((x + 0.055)/1.044, 2.4); 56 } 57 return 1.0; 58 } 59 60 function testClearColor() { 61 // Make a fresh canvas. 62 let canvas = document.createElement("canvas"); 63 canvas.width = 16; 64 canvas.height = 16; 65 66 gl = wtu.create3DContext(canvas, {antialias: false}); 67 if (!gl) { 68 testFailed("context does not exist"); 69 return; 70 } 71 testPassed("context exists"); 72 shouldBe('gl.drawingBufferFormat', 'gl.RGBA8'); 73 74 let testCase = function(f, size, clearColor, expectedPixel, tolerance) { 75 format = f; 76 width = size[0]; 77 height = size[1]; 78 79 gl.drawingBufferStorage(format, width, height); 80 shouldBe('gl.getError()', 'gl.NO_ERROR'); 81 82 shouldBe('gl.drawingBufferFormat', 'format'); 83 shouldBe('gl.drawingBufferWidth', 'width'); 84 shouldBe('gl.drawingBufferHeight', 'height'); 85 86 gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); 87 gl.clear(gl.COLOR_BUFFER_BIT); 88 89 let buf; 90 if (format == 0x881A /*RGBA16F*/) { 91 buf = new Float32Array(4); 92 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, buf); 93 } else { 94 buf = new Uint8Array(4); 95 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); 96 } 97 testPixel(expectedPixel, buf, tolerance); 98 } 99 100 debug('Testing RGBA8'); 101 testCase(gl.RGBA8, [16, 32], 102 [16 / 255, 32 / 255, 64 / 255, 128 / 255], 103 [16, 32, 64, 128], 104 0); 105 106 // WebGL 1 must use EXT_sRGB for SRGB8_ALPHA8. 107 let srgb8_alpha8 = gl.SRGB8_ALPHA8; 108 if (!srgb8_alpha8) { 109 let ext = gl.getExtension('EXT_sRGB'); 110 if (ext) { 111 srgb8_alpha8 = ext.SRGB8_ALPHA8_EXT; 112 } 113 } 114 if (srgb8_alpha8) { 115 debug('Testing SRGB8_ALPHA8'); 116 testCase(srgb8_alpha8, [16, 32], 117 [srgbToLinear(64/255), srgbToLinear(16/255), srgbToLinear(32/255), 128 / 255], 118 [64, 16, 32, 128], 119 1); 120 } 121 122 if (gl.getExtension('EXT_color_buffer_float')) { 123 // WebGL 1 must use EXT_color_buffer_half_float for RGBA16F. 124 let rgba16f = gl.RGBA16F; 125 if (!rgba16f) { 126 let ext = gl.getExtension('EXT_color_buffer_half_float'); 127 if (ext) { 128 rgba16f = ext.RGBA16F_EXT; 129 } 130 } 131 132 debug('Testing RGBA16F'); 133 testCase(rgba16f, [18, 28], 134 [0.25, 0.5, 0.75, 0.125], 135 [0.25, 0.5, 0.75, 0.125], 136 0.00001); 137 } else { 138 debug('Skipping RGBA16F'); 139 } 140 141 shouldBe('gl.getError()', 'gl.NO_ERROR'); 142 } 143 144 function testNoAlpha() { 145 let canvas = document.createElement("canvas"); 146 canvas.width = 16; 147 canvas.height = 16; 148 gl = wtu.create3DContext(canvas, {alpha:false}); 149 if (!gl) { 150 testFailed("context does not exist"); 151 return; 152 } 153 debug('Testing alpha:false'); 154 155 // Report RGB8 for the format. 156 shouldBe('gl.drawingBufferFormat', 'gl.RGB8'); 157 158 // If WebGLContextAttributes.alpha is false, generate INVALID_OPERATION. 159 gl.drawingBufferStorage(gl.RGBA8, 16, 16); 160 shouldBe('gl.getError()', 'gl.INVALID_OPERATION'); 161 } 162 163 function testMissingExtension() { 164 let canvas = document.createElement("canvas"); 165 canvas.width = 16; 166 canvas.height = 16; 167 gl = wtu.create3DContext(canvas); 168 if (!gl) { 169 testFailed("context does not exist"); 170 return; 171 } 172 173 debug('Testing use of RGBA16F without enabling EXT_color_buffer_float'); 174 gl.drawingBufferStorage(gl.RGBA16F, 16, 16); 175 shouldBe('gl.getError()', 'gl.INVALID_ENUM'); 176 } 177 178 function testMaxSize() { 179 let canvas = document.createElement("canvas"); 180 canvas.width = 16; 181 canvas.height = 16; 182 gl = wtu.create3DContext(canvas); 183 if (!gl) { 184 testFailed("context does not exist"); 185 return; 186 } 187 188 debug('Testing maximum size'); 189 gl.drawingBufferStorage(gl.RGBA8, maxRenderbufferSize, maxRenderbufferSize); 190 shouldBe('gl.getError()', 'gl.NONE'); 191 shouldBe('gl.drawingBufferWidth', 'maxRenderbufferSize'); 192 shouldBe('gl.drawingBufferHeight', 'maxRenderbufferSize'); 193 194 debug('Testing over-maximum width and ehgith'); 195 gl.drawingBufferStorage(gl.RGBA8, maxRenderbufferSize+1, 16); 196 shouldBe('gl.getError()', 'gl.INVALID_VALUE'); 197 gl.drawingBufferStorage(gl.RGBA8, 16, maxRenderbufferSize+1); 198 shouldBe('gl.getError()', 'gl.INVALID_VALUE'); 199 shouldBe('gl.drawingBufferWidth', 'maxRenderbufferSize'); 200 shouldBe('gl.drawingBufferHeight', 'maxRenderbufferSize'); 201 } 202 203 function testDrawToCanvas() { 204 let canvasGL = document.createElement("canvas"); 205 canvasGL.width = 16; 206 canvasGL.height = 16; 207 gl = wtu.create3DContext(canvasGL); 208 if (!gl) { 209 testFailed("context does not exist"); 210 return; 211 } 212 213 let canvas2D = document.createElement("canvas"); 214 canvas2D.width = 16; 215 canvas2D.height = 16; 216 let ctx = canvas2D.getContext('2d'); 217 let imageData = new ImageData(16, 16); 218 219 let testCase = function(f, clearColor, canvasColor, tolerance) { 220 gl.drawingBufferStorage(f, 16, 16); 221 gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); 222 gl.clear(gl.COLOR_BUFFER_BIT); 223 224 ctx.putImageData(imageData, 0, 0); 225 ctx.drawImage(canvasGL, 0, 0); 226 testPixel(canvasColor, ctx.getImageData(8, 8, 1, 1).data, tolerance); 227 } 228 229 debug('Drawing RGBA to canvas'); 230 testCase(gl.RGBA8, [16/255, 32/255, 64/255, 64/255], [64, 128, 255, 64], 0); 231 232 // WebGL 1 must use EXT_sRGB for SRGB8_ALPHA8. 233 let srgb8_alpha8 = gl.SRGB8_ALPHA8; 234 if (!srgb8_alpha8) { 235 let ext = gl.getExtension('EXT_sRGB'); 236 if (ext) { 237 srgb8_alpha8 = ext.SRGB8_ALPHA8_EXT; 238 } 239 } 240 if (srgb8_alpha8) { 241 debug('Drawing opaque SRGB8_ALPHA8 to canvas'); 242 testCase(srgb8_alpha8, 243 [srgbToLinear(64/255), srgbToLinear(32/255), srgbToLinear(16/255), 1.0], 244 [64, 32, 16, 255], 245 1); 246 247 debug('Drawing transparent SRGB8_ALPHA8 to canvas'); 248 // We set the tolerance to 5 because of compounding error. The backbuffer 249 // may be off by 1, and then un-premultiplying alpha of 64/55 will multiply 250 // that error by 4. Then add one to be safe. 251 testCase(srgb8_alpha8, 252 [srgbToLinear(32/255), srgbToLinear(64/255), srgbToLinear(16/255), 64/255], 253 [128, 255, 64, 64], 254 5); 255 } 256 257 if (gl.getExtension('EXT_color_buffer_float')) { 258 debug('Drawing transparent RGBA16F to canvas'); 259 testCase(gl.RGBA16F, 260 [32/255, 64/255, 16/255, 64/255], 261 [128, 255, 64, 64], 262 1); 263 } 264 } 265 266 let wtu = WebGLTestUtils; 267 initialize(); 268 if (hasDrawingBufferStorage) { 269 testClearColor(); 270 testNoAlpha(); 271 testMissingExtension(); 272 testMaxSize(); 273 testDrawToCanvas(); 274 } 275 }