blending.html (8308B)
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 <link rel="stylesheet" href="../../resources/js-test-style.css"/> 12 <script src="../../js/js-test-pre.js"></script> 13 <script src="../../js/webgl-test-utils.js"></script> 14 15 <script id="eVsSrc" type="text/plain"> 16 void main() 17 { 18 gl_PointSize = 1.0; 19 gl_Position = vec4(0, 0, 0, 1); 20 } 21 </script> 22 23 <script id="eFsSrc" type="text/plain"> 24 precision mediump float; 25 uniform vec4 uColor; 26 27 void main() 28 { 29 gl_FragColor = uColor; 30 } 31 </script> 32 33 </head> 34 <body> 35 <div id="description"></div> 36 <div id="console"></div> 37 <script> 38 "use strict"; 39 description('Blending tests'); 40 41 const wtu = WebGLTestUtils; 42 43 function CreateContext() { 44 const gl = wtu.create3DContext(); 45 gl.viewport(0, 0, 1, 1); 46 47 gl.prog = wtu.setupProgram(gl, [eVsSrc.innerHTML, eFsSrc.innerHTML]); 48 gl.prog.uColor = (() => { 49 const loc = gl.getUniformLocation(gl.prog, 'uColor'); 50 return x => gl.uniform4fv(loc, x); 51 })(); 52 gl.useProgram(gl.prog); 53 gl.prog.uColor([1 / 255, 2 / 255, 3 / 255, 4 / 255]); 54 55 gl.drawAndRead = type => { 56 gl.drawArrays(gl.POINTS, 0, 1); 57 let ret; 58 if (type == gl.UNSIGNED_BYTE) { 59 ret = new Uint8Array(4); 60 } else if (type == gl.FLOAT) { 61 ret = new Float32Array(4); 62 } 63 gl.readPixels(0, 0, 1, 1, gl.RGBA, type, ret); 64 return ret; 65 }; 66 67 gl.enable(gl.BLEND); 68 gl.blendFunc(gl.CONSTANT_COLOR, gl.ZERO); 69 70 return gl; 71 } 72 73 function CreateValidFb(gl, formats) { 74 const fb = gl.createFramebuffer(); 75 gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 76 77 for (let i in formats) { 78 i = i|0; // Otherwise i is a string. :( 79 const f = formats[i]; 80 if (!f) 81 continue; 82 if (f.length == 1) { 83 const rb = gl.createRenderbuffer(); 84 gl.bindRenderbuffer(gl.RENDERBUFFER, rb); 85 gl.renderbufferStorage(gl.RENDERBUFFER, f[0], 1, 1); 86 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0+i, 87 gl.RENDERBUFFER, rb); 88 continue; 89 } 90 if (f.length == 3) { 91 let internalFormat = f[0]; 92 if (internalFormat === undefined) { 93 internalFormat = f[1]; 94 } 95 96 const tex = gl.createTexture(); 97 gl.bindTexture(gl.TEXTURE_2D, tex); 98 gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1,1,0, f[1],f[2], null); 99 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0+i, 100 gl.TEXTURE_2D, tex, 0); 101 continue; 102 } 103 throw new Error('Invalid format length: ' + f); 104 } 105 106 const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); 107 if (status != gl.FRAMEBUFFER_COMPLETE) { 108 gl.deleteFramebuffer(fb); 109 return null; 110 } 111 return fb; 112 } 113 114 let was, fb; 115 116 const TESTS = [ 117 () => { 118 debug(''); 119 debug('Clamping of blendColor args:'); 120 121 const gl = wtu.create3DContext(); 122 if (!gl.texImage3D) { // WebGL 1.0 123 // WebGL 1.0 clamps without EXT_color_buffer_half_float or WEBGL_color_buffer_float. 124 gl.blendColor(1000, 1, 1, 1); 125 const was = gl.getParameter(gl.BLEND_COLOR); 126 expectArray(was, [1, 1, 1, 1]); 127 128 const ext = gl.getExtension('EXT_color_buffer_half_float') || 129 gl.getExtension('WEBGL_color_buffer_float'); 130 if (!ext) return; 131 } 132 133 // WebGL 2.0 or extended WebGL 1.0 may still clamp the value on store 134 // when the underlying platform does the same. 135 gl.blendColor(1000, 1, 1, 1); 136 const was = gl.getParameter(gl.BLEND_COLOR); 137 if (was[0] == 1000) { 138 expectArray(was, [1000, 1, 1, 1]); 139 } else { 140 debug("Platform does not support unclamped blend color.") 141 expectArray(was, [1, 1, 1, 1]); 142 } 143 }, 144 () => { 145 debug(''); 146 debug('Blending for RGBA8:'); 147 148 const gl = CreateContext(); 149 fb = CreateValidFb(gl, [[gl.RGBA8, gl.RGBA, gl.UNSIGNED_BYTE]]); 150 shouldBeNonNull('fb'); 151 152 // Regardless of the context version and enabled extensions, 153 // the value will be clamped at draw time, 154 gl.blendColor(10, 1, 1, 1); 155 const was = gl.drawAndRead(gl.UNSIGNED_BYTE); 156 expectArray(was, [1, 2, 3, 4]); 157 158 if (gl.getExtension('EXT_color_buffer_half_float') || 159 gl.getExtension('WEBGL_color_buffer_float') || 160 gl.getExtension('EXT_color_buffer_float')) 161 { 162 debug('Enable floating-point color buffers and retest'); 163 gl.blendColor(1000, 1, 1, 1); 164 const was = gl.drawAndRead(gl.UNSIGNED_BYTE); 165 expectArray(was, [1, 2, 3, 4]); 166 } 167 }, 168 () => { 169 debug(''); 170 debug('Blending for RGBA16F:'); 171 172 const gl = CreateContext(); 173 174 // Set the value before enabling the extension. 175 // It must be clamped only on WebGL 1.0 contexts. 176 gl.blendColor(10, 1, 1, 1); 177 if (!gl.getExtension('EXT_color_buffer_half_float')) { 178 testPassed('Missing ext EXT_color_buffer_half_float is optional, skipping.'); 179 return; 180 } 181 if (!gl.texImage3D) { // WebGL 1.0 182 const ext = gl.getExtension('OES_texture_half_float'); 183 gl.HALF_FLOAT = ext.HALF_FLOAT_OES; // These aren't the same value, but this'll work. 184 } 185 186 fb = CreateValidFb(gl, [[gl.RGBA16F, gl.RGBA, gl.HALF_FLOAT]]); 187 shouldBeNonNull('fb'); 188 gl.prog.uColor([1, 2, 3, 4]); 189 190 let was = gl.drawAndRead(gl.FLOAT); 191 if (!gl.texImage3D) { // WebGL 1.0 192 expectArray(was, [1, 2, 3, 4]); 193 } else { 194 // Some WebGL 2.0 implementations may clamp the blend color anyway. 195 const r = gl.getParameter(gl.BLEND_COLOR)[0]; 196 expectArray(was, [r, 2, 3, 4]); 197 } 198 199 // Re-set the value after the extension was enabled. 200 gl.blendColor(100, 1, 1, 1); 201 const r = gl.getParameter(gl.BLEND_COLOR)[0]; 202 was = gl.drawAndRead(gl.FLOAT); 203 expectArray(was, [r, 2, 3, 4]); 204 }, 205 () => { 206 debug(''); 207 debug('Blending for RGBA32F:'); 208 209 const gl = CreateContext(); 210 211 // Set the value before enabling the extension. 212 // It must be clamped only on WebGL 1.0 contexts. 213 gl.blendColor(10, 1, 1, 1); 214 if (gl.texImage3D) { // WebGL 2.0 215 if (!gl.getExtension('EXT_color_buffer_float')) { 216 testPassed('Missing ext EXT_color_buffer_float is optional, skipping.'); 217 return; 218 } 219 } else { 220 if (!gl.getExtension('WEBGL_color_buffer_float')) { 221 testPassed('Missing ext WEBGL_color_buffer_float is optional, skipping.'); 222 return; 223 } 224 gl.getExtension('OES_texture_float'); 225 } 226 fb = CreateValidFb(gl, [[gl.RGBA32F, gl.RGBA, gl.FLOAT]]); 227 shouldBeNonNull('fb'); 228 gl.prog.uColor([1, 2, 3, 4]); 229 230 let was = gl.drawAndRead(gl.FLOAT); 231 if (!gl.texImage3D) { // WebGL 1.0 232 expectArray(was, [1, 2, 3, 4]); 233 } else { 234 // Some WebGL 2.0 implementations may clamp the blend color anyway. 235 const r = gl.getParameter(gl.BLEND_COLOR)[0]; 236 expectArray(was, [r, 2, 3, 4]); 237 } 238 239 // Re-set the value after the extension was enabled. 240 gl.blendColor(100, 1, 1, 1); 241 const r = gl.getParameter(gl.BLEND_COLOR)[0]; 242 was = gl.drawAndRead(gl.FLOAT); 243 244 if (!gl.getExtension('EXT_float_blend')) { 245 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, 'Should not be able to blend 32F formats.'); 246 return; 247 } 248 wtu.glErrorShouldBe(gl, 0, 'Should be able to blend 32F formats.'); 249 expectArray(was, [r, 2, 3, 4]); 250 }, 251 ]; 252 253 async function Test() { 254 for (const fn of TESTS) { 255 await wtu.dispatchPromise(fn); 256 } 257 wtu.destroyAllContexts(); 258 finishTest(); 259 } 260 261 Test(); 262 263 var successfullyParsed = true; 264 </script> 265 </body> 266 </html>