webgl-blend-func-extended.js (23203B)
1 "use strict"; 2 description("This test verifies the functionality of the WEBGL_blend_func_extended extension, if it is available."); 3 4 debug(""); 5 6 var wtu = WebGLTestUtils; 7 var gl = wtu.create3DContext("c", undefined, contextVersion); 8 var ext; 9 10 function runTestNoExtension() { 11 debug(""); 12 debug("Testing getParameter without the extension"); 13 shouldBeNull("gl.getParameter(0x88FC /* MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL */)"); 14 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown"); 15 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 16 17 if (contextVersion == 1) { 18 debug(""); 19 debug("Testing SRC_ALPHA_SATURATE without the extension"); 20 21 gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE); 22 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFunc dfactor"); 23 gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE); 24 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstRGB"); 25 gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE); 26 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstAlpha"); 27 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 28 } 29 30 debug(""); 31 debug("Testing SRC1 blend funcs without the extension"); 32 33 const extFuncs = { 34 SRC1_COLOR_WEBGL: 0x88F9, 35 SRC1_ALPHA_WEBGL: 0x8589, 36 ONE_MINUS_SRC1_COLOR_WEBGL: 0x88FA, 37 ONE_MINUS_SRC1_ALPHA_WEBGL: 0x88FB 38 }; 39 40 for (const func in extFuncs) { 41 gl.blendFunc(extFuncs[func], gl.ONE); 42 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc sfactor`); 43 gl.blendFunc(gl.ONE, extFuncs[func]); 44 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc dfactor`); 45 gl.blendFuncSeparate(extFuncs[func], gl.ONE, gl.ONE, gl.ONE); 46 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcRGB`); 47 gl.blendFuncSeparate(gl.ONE, extFuncs[func], gl.ONE, gl.ONE); 48 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstRGB`); 49 gl.blendFuncSeparate(gl.ONE, gl.ONE, extFuncs[func], gl.ONE); 50 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcAlpha`); 51 gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, extFuncs[func]); 52 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstAlpha`); 53 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 54 } 55 56 const dbi = gl.getExtension("OES_draw_buffers_indexed"); 57 if (!dbi) return; 58 59 debug(""); 60 debug("Testing indexed SRC1 blend funcs without the extension"); 61 for (const func in extFuncs) { 62 dbi.blendFunciOES(0, extFuncs[func], gl.ONE); 63 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES src`); 64 dbi.blendFunciOES(0, gl.ONE, extFuncs[func]); 65 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES dst`); 66 dbi.blendFuncSeparateiOES(0, extFuncs[func], gl.ONE, gl.ONE, gl.ONE); 67 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcRGB`); 68 dbi.blendFuncSeparateiOES(0, gl.ONE, extFuncs[func], gl.ONE, gl.ONE); 69 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstRGB`); 70 dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, extFuncs[func], gl.ONE); 71 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcAlpha`); 72 dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, extFuncs[func]); 73 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstAlpha`); 74 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 75 } 76 } 77 78 function runEnumTests() { 79 debug(""); 80 debug("Testing enums"); 81 shouldBe("ext.SRC1_COLOR_WEBGL", "0x88F9"); 82 shouldBe("ext.SRC1_ALPHA_WEBGL", "0x8589"); 83 shouldBe("ext.ONE_MINUS_SRC1_COLOR_WEBGL", "0x88FA"); 84 shouldBe("ext.ONE_MINUS_SRC1_ALPHA_WEBGL", "0x88FB"); 85 shouldBe("ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL", "0x88FC"); 86 } 87 88 function runQueryTests() { 89 debug(""); 90 debug("Testing getParameter"); 91 shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL)", "1"); 92 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 93 94 if (contextVersion == 1) { 95 debug(""); 96 debug("Testing SRC_ALPHA_SATURATE with the extension"); 97 98 gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE); 99 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFunc dfactor"); 100 shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE"); 101 shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE"); 102 gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE); 103 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstRGB"); 104 shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE"); 105 gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE); 106 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstAlpha"); 107 shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE"); 108 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 109 } 110 111 const extFuncs = [ 112 "SRC1_COLOR_WEBGL", 113 "SRC1_ALPHA_WEBGL", 114 "ONE_MINUS_SRC1_COLOR_WEBGL", 115 "ONE_MINUS_SRC1_ALPHA_WEBGL" 116 ]; 117 118 debug(""); 119 debug("Testing blend state updates with SRC1 blend funcs"); 120 for (const func of extFuncs) { 121 gl.blendFunc(ext[func], gl.ONE); 122 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc sfactor`); 123 shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`); 124 shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`); 125 gl.blendFunc(gl.ONE, ext[func]); 126 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc dfactor`); 127 shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`); 128 shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`); 129 gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE); 130 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcRGB`); 131 shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`); 132 gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE); 133 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstRGB`); 134 shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`); 135 gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE); 136 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcAlpha`); 137 shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`); 138 gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]); 139 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstAlpha`); 140 shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`); 141 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 142 } 143 144 const dbi = gl.getExtension("OES_draw_buffers_indexed"); 145 if (!dbi) return; 146 147 debug(""); 148 debug("Testing indexed blend state updates with SRC1 blend funcs"); 149 for (const func of extFuncs) { 150 dbi.blendFunciOES(0, ext[func], gl.ONE); 151 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES src`); 152 shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`); 153 shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`); 154 dbi.blendFunciOES(0, gl.ONE, ext[func]); 155 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES dst`); 156 shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`); 157 shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`); 158 dbi.blendFuncSeparateiOES(0, ext[func], gl.ONE, gl.ONE, gl.ONE); 159 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcRGB`); 160 shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`); 161 dbi.blendFuncSeparateiOES(0, gl.ONE, ext[func], gl.ONE, gl.ONE); 162 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstRGB`); 163 shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`); 164 dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, ext[func], gl.ONE); 165 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcAlpha`); 166 shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`); 167 dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, ext[func]); 168 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstAlpha`); 169 shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`); 170 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 171 } 172 } 173 174 function runShaderTests(extensionEnabled) { 175 debug(""); 176 debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); 177 178 const shaderSets = []; 179 180 const macro100 = `precision mediump float; 181 void main() { 182 #ifdef GL_EXT_blend_func_extended 183 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 184 #else 185 #error no GL_EXT_blend_func_extended; 186 #endif 187 }`; 188 const macro300 = `#version 300 es 189 out mediump vec4 my_FragColor; 190 void main() { 191 #ifdef GL_EXT_blend_func_extended 192 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 193 #else 194 #error no GL_EXT_blend_func_extended; 195 #endif 196 }`; 197 shaderSets.push([wtu.simpleVertexShader, macro100]); 198 if (contextVersion == 2) { 199 shaderSets.push([wtu.simpleVertexShaderESSL300, macro300]); 200 } 201 202 for (const shaders of shaderSets) { 203 // Expect the macro shader to succeed ONLY if enabled 204 if (wtu.setupProgram(gl, shaders)) { 205 if (extensionEnabled) { 206 testPassed("Macro defined in shaders when extension is enabled"); 207 } else { 208 testFailed("Macro defined in shaders when extension is disabled"); 209 } 210 } else { 211 if (extensionEnabled) { 212 testFailed("Macro not defined in shaders when extension is enabled"); 213 } else { 214 testPassed("Macro not defined in shaders when extension is disabled"); 215 } 216 } 217 } 218 219 shaderSets.length = 0; 220 221 const missing100 = ` 222 void main() { 223 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 224 gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); 225 }`; 226 shaderSets.push([wtu.simpleVertexShader, missing100]); 227 228 const missing300 = `#version 300 es 229 layout(location = 0) out mediump vec4 oColor0; 230 layout(location = 0, index = 1) out mediump vec4 oColor1; 231 void main() { 232 oColor0 = vec4(1.0, 0.0, 0.0, 1.0); 233 oColor1 = vec4(0.0, 1.0, 0.0, 1.0); 234 }`; 235 if (contextVersion == 2) { 236 shaderSets.push([wtu.simpleVertexShaderESSL300, missing300]); 237 } 238 239 // Always expect the shader missing the #extension pragma to fail (whether enabled or not) 240 for (const shaders of shaderSets) { 241 if (wtu.setupProgram(gl, shaders)) { 242 testFailed("Secondary fragment output allowed without #extension pragma"); 243 } else { 244 testPassed("Secondary fragment output disallowed without #extension pragma"); 245 } 246 } 247 248 shaderSets.length = 0; 249 250 const valid100 = `#extension GL_EXT_blend_func_extended : enable 251 void main() { 252 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 253 gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); 254 }`; 255 shaderSets.push([wtu.simpleVertexShader, valid100]); 256 257 const valid300 = `#version 300 es 258 #extension GL_EXT_blend_func_extended : enable 259 layout(location = 0) out mediump vec4 oColor0; 260 layout(location = 0, index = 1) out mediump vec4 oColor1; 261 void main() { 262 oColor0 = vec4(1.0, 0.0, 0.0, 1.0); 263 oColor1 = vec4(0.0, 1.0, 0.0, 1.0); 264 }`; 265 if (contextVersion == 2) { 266 shaderSets.push([wtu.simpleVertexShaderESSL300, valid300]); 267 } 268 269 // Try to compile a shader using a secondary fragment output that should only succeed if enabled 270 for (const shaders of shaderSets) { 271 if (wtu.setupProgram(gl, shaders)) { 272 if (extensionEnabled) { 273 testPassed("Secondary fragment output compiled successfully when extension enabled"); 274 } else { 275 testFailed("Secondary fragment output compiled successfully when extension disabled"); 276 } 277 } else { 278 if (extensionEnabled) { 279 testFailed("Secondary fragment output failed to compile when extension enabled"); 280 } else { 281 testPassed("Secondary fragment output failed to compile when extension disabled"); 282 } 283 } 284 } 285 286 // ESSL 3.00: Testing that multiple outputs require explicit locations 287 if (contextVersion == 2) { 288 const locations300 = `#version 300 es 289 #extension GL_EXT_blend_func_extended : enable 290 out mediump vec4 color0; 291 out mediump vec4 color1; 292 void main() { 293 color0 = vec4(1.0, 0.0, 0.0, 1.0); 294 color1 = vec4(0.0, 1.0, 0.0, 1.0); 295 }`; 296 if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, locations300])) { 297 testFailed("Multiple fragment outputs compiled successfully without explicit locations"); 298 } else { 299 testPassed("Multiple fragment outputs failed to compile without explicit locations"); 300 } 301 } 302 } 303 304 function runMissingOutputsTests() { 305 debug(""); 306 debug("Test draw calls with missing fragment outputs"); 307 308 wtu.setupUnitQuad(gl); 309 gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL); 310 311 for (const enabled of [false, true]) { 312 if (enabled) { 313 gl.enable(gl.BLEND); 314 } else { 315 gl.disable(gl.BLEND); 316 } 317 318 for (const maskedOut of [false, true]) { 319 gl.colorMask(!maskedOut, false, false, false); 320 321 const label = `Dual-source blending ${enabled ? "ENABLED" : "DISABLED"}, ` + 322 `missing fragment outputs, and ` + 323 `${maskedOut ? "" : "NOT "}all color channels masked out`; 324 debug(`ESSL 1.00: ${label}`); 325 326 { 327 const none = "void main() {}"; 328 wtu.setupProgram(gl, [wtu.simpleVertexShader, none]); 329 wtu.drawUnitQuad(gl); 330 wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, 331 "no fragment outputs"); 332 } 333 334 { 335 const fragColor = ` 336 void main() { 337 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 338 }`; 339 wtu.setupProgram(gl, [wtu.simpleVertexShader, fragColor]); 340 wtu.drawUnitQuad(gl); 341 wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION, 342 "only gl_FragColor"); 343 } 344 345 { 346 const secondaryFragColor = `#extension GL_EXT_blend_func_extended : enable 347 void main() { 348 gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); 349 }`; 350 wtu.setupProgram(gl, [wtu.simpleVertexShader, secondaryFragColor]); 351 wtu.drawUnitQuad(gl); 352 wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, 353 "only gl_SecondaryFragColorEXT"); 354 } 355 356 if (contextVersion == 1) continue; 357 358 debug(`ESSL 3.00: ${label}`); 359 360 { 361 const none = `#version 300 es 362 void main() {}`; 363 wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, none]); 364 wtu.drawUnitQuad(gl); 365 wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, 366 "no fragment outputs"); 367 } 368 369 { 370 const color0 = `#version 300 es 371 out mediump vec4 color0; 372 void main() { 373 color0 = vec4(1.0, 0.0, 0.0, 1.0); 374 }`; 375 wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color0]); 376 wtu.drawUnitQuad(gl); 377 wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION, 378 "only index 0 output"); 379 } 380 381 { 382 const color1 = `#version 300 es 383 #extension GL_EXT_blend_func_extended : enable 384 layout(location = 0, index = 1) out mediump vec4 color1; 385 void main() { 386 color1 = vec4(0.0, 1.0, 0.0, 1.0); 387 }`; 388 wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color1]); 389 wtu.drawUnitQuad(gl); 390 wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, 391 "only index 1 output"); 392 } 393 } 394 } 395 gl.colorMask(true, true, true, true); 396 } 397 398 function runDrawBuffersLimitTests() { 399 const dbi = gl.getExtension("OES_draw_buffers_indexed"); 400 if (!dbi) return; 401 402 debug(""); 403 debug("Testing that dual-source blending limits the number of active draw buffers"); 404 405 const rb0 = gl.createRenderbuffer(); 406 gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); 407 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); 408 409 const rb1 = gl.createRenderbuffer(); 410 gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); 411 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); 412 413 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 414 415 const fbo = gl.createFramebuffer(); 416 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 417 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); 418 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1); 419 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); 420 421 const fs = `#version 300 es 422 #extension GL_EXT_blend_func_extended : enable 423 layout(location = 0, index = 0) out mediump vec4 color0; 424 layout(location = 0, index = 1) out mediump vec4 color1; 425 void main() { 426 color0 = vec4(1.0, 0.0, 0.0, 1.0); 427 color1 = vec4(0.0, 1.0, 0.0, 1.0); 428 }`; 429 wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, fs]); 430 431 wtu.setupUnitQuad(gl); 432 433 // Enable both draw buffers 434 gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); 435 436 // Mask out draw buffer 1 to pass missing fragment outputs check 437 dbi.colorMaskiOES(1, false, false, false, false); 438 439 const extFuncs = [ 440 "SRC1_COLOR_WEBGL", 441 "SRC1_ALPHA_WEBGL", 442 "ONE_MINUS_SRC1_COLOR_WEBGL", 443 "ONE_MINUS_SRC1_ALPHA_WEBGL" 444 ]; 445 446 for (const func of extFuncs) { 447 for (let slot = 0; slot < 4; slot++) { 448 let param; 449 switch (slot) { 450 case 0: 451 param = "srcRGB"; 452 gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE); 453 break; 454 case 1: 455 param = "dstRGB"; 456 gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE); 457 break; 458 case 2: 459 param = "srcAlpha"; 460 gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE); 461 break; 462 case 3: 463 param = "dstAlpha"; 464 gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]); 465 break; 466 } 467 debug(`Testing ${func} with ${param}`); 468 469 // Limit must be applied even with blending disabled 470 gl.disable(gl.BLEND); 471 wtu.drawUnitQuad(gl); 472 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending disabled"); 473 474 gl.enable(gl.BLEND); 475 wtu.drawUnitQuad(gl); 476 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending enabled"); 477 478 // Limit is not applied when non-SRC1 funcs are used 479 gl.blendFunc(gl.ONE, gl.ONE); 480 wtu.drawUnitQuad(gl); 481 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "dual-source blending disabled"); 482 } 483 } 484 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 485 } 486 487 function runBlendingTests() { 488 debug(""); 489 debug("Testing rendering with two most common dual-source blending configurations"); 490 491 const fs = `#extension GL_EXT_blend_func_extended : enable 492 uniform mediump vec4 u_src0; 493 uniform mediump vec4 u_src1; 494 void main() { 495 gl_FragColor = u_src0; 496 gl_SecondaryFragColorEXT = u_src1; 497 }`; 498 const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, fs]); 499 const uSrc0 = gl.getUniformLocation(program, "u_src0"); 500 const uSrc1 = gl.getUniformLocation(program, "u_src1"); 501 502 gl.enable(gl.BLEND); 503 wtu.setupUnitQuad(gl); 504 gl.clearColor(1.0, 1.0, 1.0, 1.0); 505 506 gl.clear(gl.COLOR_BUFFER_BIT); 507 gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL); 508 gl.uniform4f(uSrc0, 0.250, 0.375, 0.500, 0.625); 509 gl.uniform4f(uSrc1, 0.125, 0.125, 0.125, 0.125); 510 wtu.drawUnitQuad(gl); 511 wtu.checkCanvas(gl, [96, 128, 159, 191], "Multiply destination by SRC1 and add SRC0", 2); 512 513 gl.clear(gl.COLOR_BUFFER_BIT); 514 gl.blendFunc(ext.SRC1_COLOR_WEBGL, ext.ONE_MINUS_SRC1_COLOR_WEBGL); 515 gl.uniform4f(uSrc0, 0.125, 0.125, 0.125, 0.125); 516 gl.uniform4f(uSrc1, 0.500, 0.375, 0.250, 0.125); 517 wtu.drawUnitQuad(gl); 518 wtu.checkCanvas(gl, [143, 171, 199, 227], "Per-channel color interpolation using SRC1", 2); 519 } 520 521 function runTest() { 522 if (!gl) { 523 testFailed("context does not exist"); 524 return; 525 } 526 testPassed("context exists"); 527 528 runTestNoExtension(); 529 runShaderTests(false); 530 531 ext = gl.getExtension("WEBGL_blend_func_extended"); 532 wtu.runExtensionSupportedTest(gl, "WEBGL_blend_func_extended", ext !== null); 533 534 if (ext !== null) { 535 runEnumTests(); 536 runQueryTests(); 537 runShaderTests(true); 538 runMissingOutputsTests(); 539 runDrawBuffersLimitTests(); 540 runBlendingTests(); 541 } else { 542 testPassed("No WEBGL_blend_func_extended support -- this is legal"); 543 } 544 } 545 546 runTest(); 547 548 var successfullyParsed = true;