548 lines
23 KiB
JavaScript
548 lines
23 KiB
JavaScript
"use strict";
|
|
description("This test verifies the functionality of the WEBGL_blend_func_extended extension, if it is available.");
|
|
|
|
debug("");
|
|
|
|
var wtu = WebGLTestUtils;
|
|
var gl = wtu.create3DContext("c", undefined, contextVersion);
|
|
var ext;
|
|
|
|
function runTestNoExtension() {
|
|
debug("");
|
|
debug("Testing getParameter without the extension");
|
|
shouldBeNull("gl.getParameter(0x88FC /* MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL */)");
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown");
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
|
|
if (contextVersion == 1) {
|
|
debug("");
|
|
debug("Testing SRC_ALPHA_SATURATE without the extension");
|
|
|
|
gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFunc dfactor");
|
|
gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstRGB");
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstAlpha");
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
}
|
|
|
|
debug("");
|
|
debug("Testing SRC1 blend funcs without the extension");
|
|
|
|
const extFuncs = {
|
|
SRC1_COLOR_WEBGL: 0x88F9,
|
|
SRC1_ALPHA_WEBGL: 0x8589,
|
|
ONE_MINUS_SRC1_COLOR_WEBGL: 0x88FA,
|
|
ONE_MINUS_SRC1_ALPHA_WEBGL: 0x88FB
|
|
};
|
|
|
|
for (const func in extFuncs) {
|
|
gl.blendFunc(extFuncs[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc sfactor`);
|
|
gl.blendFunc(gl.ONE, extFuncs[func]);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc dfactor`);
|
|
gl.blendFuncSeparate(extFuncs[func], gl.ONE, gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcRGB`);
|
|
gl.blendFuncSeparate(gl.ONE, extFuncs[func], gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstRGB`);
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, extFuncs[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcAlpha`);
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, extFuncs[func]);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstAlpha`);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
}
|
|
|
|
const dbi = gl.getExtension("OES_draw_buffers_indexed");
|
|
if (!dbi) return;
|
|
|
|
debug("");
|
|
debug("Testing indexed SRC1 blend funcs without the extension");
|
|
for (const func in extFuncs) {
|
|
dbi.blendFunciOES(0, extFuncs[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES src`);
|
|
dbi.blendFunciOES(0, gl.ONE, extFuncs[func]);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES dst`);
|
|
dbi.blendFuncSeparateiOES(0, extFuncs[func], gl.ONE, gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcRGB`);
|
|
dbi.blendFuncSeparateiOES(0, gl.ONE, extFuncs[func], gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstRGB`);
|
|
dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, extFuncs[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcAlpha`);
|
|
dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, extFuncs[func]);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstAlpha`);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
}
|
|
}
|
|
|
|
function runEnumTests() {
|
|
debug("");
|
|
debug("Testing enums");
|
|
shouldBe("ext.SRC1_COLOR_WEBGL", "0x88F9");
|
|
shouldBe("ext.SRC1_ALPHA_WEBGL", "0x8589");
|
|
shouldBe("ext.ONE_MINUS_SRC1_COLOR_WEBGL", "0x88FA");
|
|
shouldBe("ext.ONE_MINUS_SRC1_ALPHA_WEBGL", "0x88FB");
|
|
shouldBe("ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL", "0x88FC");
|
|
}
|
|
|
|
function runQueryTests() {
|
|
debug("");
|
|
debug("Testing getParameter");
|
|
shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL)", "1");
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
|
|
if (contextVersion == 1) {
|
|
debug("");
|
|
debug("Testing SRC_ALPHA_SATURATE with the extension");
|
|
|
|
gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFunc dfactor");
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE");
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE");
|
|
gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstRGB");
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE");
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstAlpha");
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE");
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
}
|
|
|
|
const extFuncs = [
|
|
"SRC1_COLOR_WEBGL",
|
|
"SRC1_ALPHA_WEBGL",
|
|
"ONE_MINUS_SRC1_COLOR_WEBGL",
|
|
"ONE_MINUS_SRC1_ALPHA_WEBGL"
|
|
];
|
|
|
|
debug("");
|
|
debug("Testing blend state updates with SRC1 blend funcs");
|
|
for (const func of extFuncs) {
|
|
gl.blendFunc(ext[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc sfactor`);
|
|
shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`);
|
|
shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`);
|
|
gl.blendFunc(gl.ONE, ext[func]);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc dfactor`);
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`);
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`);
|
|
gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcRGB`);
|
|
shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`);
|
|
gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstRGB`);
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`);
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcAlpha`);
|
|
shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`);
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstAlpha`);
|
|
shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
}
|
|
|
|
const dbi = gl.getExtension("OES_draw_buffers_indexed");
|
|
if (!dbi) return;
|
|
|
|
debug("");
|
|
debug("Testing indexed blend state updates with SRC1 blend funcs");
|
|
for (const func of extFuncs) {
|
|
dbi.blendFunciOES(0, ext[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES src`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`);
|
|
dbi.blendFunciOES(0, gl.ONE, ext[func]);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES dst`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`);
|
|
dbi.blendFuncSeparateiOES(0, ext[func], gl.ONE, gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcRGB`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`);
|
|
dbi.blendFuncSeparateiOES(0, gl.ONE, ext[func], gl.ONE, gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstRGB`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`);
|
|
dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, ext[func], gl.ONE);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcAlpha`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`);
|
|
dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, ext[func]);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstAlpha`);
|
|
shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|
}
|
|
}
|
|
|
|
function runShaderTests(extensionEnabled) {
|
|
debug("");
|
|
debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
|
|
|
|
const shaderSets = [];
|
|
|
|
const macro100 = `precision mediump float;
|
|
void main() {
|
|
#ifdef GL_EXT_blend_func_extended
|
|
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
#else
|
|
#error no GL_EXT_blend_func_extended;
|
|
#endif
|
|
}`;
|
|
const macro300 = `#version 300 es
|
|
out mediump vec4 my_FragColor;
|
|
void main() {
|
|
#ifdef GL_EXT_blend_func_extended
|
|
my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
#else
|
|
#error no GL_EXT_blend_func_extended;
|
|
#endif
|
|
}`;
|
|
shaderSets.push([wtu.simpleVertexShader, macro100]);
|
|
if (contextVersion == 2) {
|
|
shaderSets.push([wtu.simpleVertexShaderESSL300, macro300]);
|
|
}
|
|
|
|
for (const shaders of shaderSets) {
|
|
// Expect the macro shader to succeed ONLY if enabled
|
|
if (wtu.setupProgram(gl, shaders)) {
|
|
if (extensionEnabled) {
|
|
testPassed("Macro defined in shaders when extension is enabled");
|
|
} else {
|
|
testFailed("Macro defined in shaders when extension is disabled");
|
|
}
|
|
} else {
|
|
if (extensionEnabled) {
|
|
testFailed("Macro not defined in shaders when extension is enabled");
|
|
} else {
|
|
testPassed("Macro not defined in shaders when extension is disabled");
|
|
}
|
|
}
|
|
}
|
|
|
|
shaderSets.length = 0;
|
|
|
|
const missing100 = `
|
|
void main() {
|
|
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
shaderSets.push([wtu.simpleVertexShader, missing100]);
|
|
|
|
const missing300 = `#version 300 es
|
|
layout(location = 0) out mediump vec4 oColor0;
|
|
layout(location = 0, index = 1) out mediump vec4 oColor1;
|
|
void main() {
|
|
oColor0 = vec4(1.0, 0.0, 0.0, 1.0);
|
|
oColor1 = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
if (contextVersion == 2) {
|
|
shaderSets.push([wtu.simpleVertexShaderESSL300, missing300]);
|
|
}
|
|
|
|
// Always expect the shader missing the #extension pragma to fail (whether enabled or not)
|
|
for (const shaders of shaderSets) {
|
|
if (wtu.setupProgram(gl, shaders)) {
|
|
testFailed("Secondary fragment output allowed without #extension pragma");
|
|
} else {
|
|
testPassed("Secondary fragment output disallowed without #extension pragma");
|
|
}
|
|
}
|
|
|
|
shaderSets.length = 0;
|
|
|
|
const valid100 = `#extension GL_EXT_blend_func_extended : enable
|
|
void main() {
|
|
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
shaderSets.push([wtu.simpleVertexShader, valid100]);
|
|
|
|
const valid300 = `#version 300 es
|
|
#extension GL_EXT_blend_func_extended : enable
|
|
layout(location = 0) out mediump vec4 oColor0;
|
|
layout(location = 0, index = 1) out mediump vec4 oColor1;
|
|
void main() {
|
|
oColor0 = vec4(1.0, 0.0, 0.0, 1.0);
|
|
oColor1 = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
if (contextVersion == 2) {
|
|
shaderSets.push([wtu.simpleVertexShaderESSL300, valid300]);
|
|
}
|
|
|
|
// Try to compile a shader using a secondary fragment output that should only succeed if enabled
|
|
for (const shaders of shaderSets) {
|
|
if (wtu.setupProgram(gl, shaders)) {
|
|
if (extensionEnabled) {
|
|
testPassed("Secondary fragment output compiled successfully when extension enabled");
|
|
} else {
|
|
testFailed("Secondary fragment output compiled successfully when extension disabled");
|
|
}
|
|
} else {
|
|
if (extensionEnabled) {
|
|
testFailed("Secondary fragment output failed to compile when extension enabled");
|
|
} else {
|
|
testPassed("Secondary fragment output failed to compile when extension disabled");
|
|
}
|
|
}
|
|
}
|
|
|
|
// ESSL 3.00: Testing that multiple outputs require explicit locations
|
|
if (contextVersion == 2) {
|
|
const locations300 = `#version 300 es
|
|
#extension GL_EXT_blend_func_extended : enable
|
|
out mediump vec4 color0;
|
|
out mediump vec4 color1;
|
|
void main() {
|
|
color0 = vec4(1.0, 0.0, 0.0, 1.0);
|
|
color1 = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, locations300])) {
|
|
testFailed("Multiple fragment outputs compiled successfully without explicit locations");
|
|
} else {
|
|
testPassed("Multiple fragment outputs failed to compile without explicit locations");
|
|
}
|
|
}
|
|
}
|
|
|
|
function runMissingOutputsTests() {
|
|
debug("");
|
|
debug("Test draw calls with missing fragment outputs");
|
|
|
|
wtu.setupUnitQuad(gl);
|
|
gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL);
|
|
|
|
for (const enabled of [false, true]) {
|
|
if (enabled) {
|
|
gl.enable(gl.BLEND);
|
|
} else {
|
|
gl.disable(gl.BLEND);
|
|
}
|
|
|
|
for (const maskedOut of [false, true]) {
|
|
gl.colorMask(!maskedOut, false, false, false);
|
|
|
|
const label = `Dual-source blending ${enabled ? "ENABLED" : "DISABLED"}, ` +
|
|
`missing fragment outputs, and ` +
|
|
`${maskedOut ? "" : "NOT "}all color channels masked out`;
|
|
debug(`ESSL 1.00: ${label}`);
|
|
|
|
{
|
|
const none = "void main() {}";
|
|
wtu.setupProgram(gl, [wtu.simpleVertexShader, none]);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION,
|
|
"no fragment outputs");
|
|
}
|
|
|
|
{
|
|
const fragColor = `
|
|
void main() {
|
|
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
}`;
|
|
wtu.setupProgram(gl, [wtu.simpleVertexShader, fragColor]);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION,
|
|
"only gl_FragColor");
|
|
}
|
|
|
|
{
|
|
const secondaryFragColor = `#extension GL_EXT_blend_func_extended : enable
|
|
void main() {
|
|
gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
wtu.setupProgram(gl, [wtu.simpleVertexShader, secondaryFragColor]);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION,
|
|
"only gl_SecondaryFragColorEXT");
|
|
}
|
|
|
|
if (contextVersion == 1) continue;
|
|
|
|
debug(`ESSL 3.00: ${label}`);
|
|
|
|
{
|
|
const none = `#version 300 es
|
|
void main() {}`;
|
|
wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, none]);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION,
|
|
"no fragment outputs");
|
|
}
|
|
|
|
{
|
|
const color0 = `#version 300 es
|
|
out mediump vec4 color0;
|
|
void main() {
|
|
color0 = vec4(1.0, 0.0, 0.0, 1.0);
|
|
}`;
|
|
wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color0]);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION,
|
|
"only index 0 output");
|
|
}
|
|
|
|
{
|
|
const color1 = `#version 300 es
|
|
#extension GL_EXT_blend_func_extended : enable
|
|
layout(location = 0, index = 1) out mediump vec4 color1;
|
|
void main() {
|
|
color1 = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color1]);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION,
|
|
"only index 1 output");
|
|
}
|
|
}
|
|
}
|
|
gl.colorMask(true, true, true, true);
|
|
}
|
|
|
|
function runDrawBuffersLimitTests() {
|
|
const dbi = gl.getExtension("OES_draw_buffers_indexed");
|
|
if (!dbi) return;
|
|
|
|
debug("");
|
|
debug("Testing that dual-source blending limits the number of active draw buffers");
|
|
|
|
const rb0 = gl.createRenderbuffer();
|
|
gl.bindRenderbuffer(gl.RENDERBUFFER, rb0);
|
|
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1);
|
|
|
|
const rb1 = gl.createRenderbuffer();
|
|
gl.bindRenderbuffer(gl.RENDERBUFFER, rb1);
|
|
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1);
|
|
|
|
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
|
|
const fbo = gl.createFramebuffer();
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0);
|
|
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1);
|
|
wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
|
|
|
|
const fs = `#version 300 es
|
|
#extension GL_EXT_blend_func_extended : enable
|
|
layout(location = 0, index = 0) out mediump vec4 color0;
|
|
layout(location = 0, index = 1) out mediump vec4 color1;
|
|
void main() {
|
|
color0 = vec4(1.0, 0.0, 0.0, 1.0);
|
|
color1 = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}`;
|
|
wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, fs]);
|
|
|
|
wtu.setupUnitQuad(gl);
|
|
|
|
// Enable both draw buffers
|
|
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
|
|
|
|
// Mask out draw buffer 1 to pass missing fragment outputs check
|
|
dbi.colorMaskiOES(1, false, false, false, false);
|
|
|
|
const extFuncs = [
|
|
"SRC1_COLOR_WEBGL",
|
|
"SRC1_ALPHA_WEBGL",
|
|
"ONE_MINUS_SRC1_COLOR_WEBGL",
|
|
"ONE_MINUS_SRC1_ALPHA_WEBGL"
|
|
];
|
|
|
|
for (const func of extFuncs) {
|
|
for (let slot = 0; slot < 4; slot++) {
|
|
let param;
|
|
switch (slot) {
|
|
case 0:
|
|
param = "srcRGB";
|
|
gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE);
|
|
break;
|
|
case 1:
|
|
param = "dstRGB";
|
|
gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE);
|
|
break;
|
|
case 2:
|
|
param = "srcAlpha";
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE);
|
|
break;
|
|
case 3:
|
|
param = "dstAlpha";
|
|
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]);
|
|
break;
|
|
}
|
|
debug(`Testing ${func} with ${param}`);
|
|
|
|
// Limit must be applied even with blending disabled
|
|
gl.disable(gl.BLEND);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending disabled");
|
|
|
|
gl.enable(gl.BLEND);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending enabled");
|
|
|
|
// Limit is not applied when non-SRC1 funcs are used
|
|
gl.blendFunc(gl.ONE, gl.ONE);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "dual-source blending disabled");
|
|
}
|
|
}
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
}
|
|
|
|
function runBlendingTests() {
|
|
debug("");
|
|
debug("Testing rendering with two most common dual-source blending configurations");
|
|
|
|
const fs = `#extension GL_EXT_blend_func_extended : enable
|
|
uniform mediump vec4 u_src0;
|
|
uniform mediump vec4 u_src1;
|
|
void main() {
|
|
gl_FragColor = u_src0;
|
|
gl_SecondaryFragColorEXT = u_src1;
|
|
}`;
|
|
const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, fs]);
|
|
const uSrc0 = gl.getUniformLocation(program, "u_src0");
|
|
const uSrc1 = gl.getUniformLocation(program, "u_src1");
|
|
|
|
gl.enable(gl.BLEND);
|
|
wtu.setupUnitQuad(gl);
|
|
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL);
|
|
gl.uniform4f(uSrc0, 0.250, 0.375, 0.500, 0.625);
|
|
gl.uniform4f(uSrc1, 0.125, 0.125, 0.125, 0.125);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.checkCanvas(gl, [96, 128, 159, 191], "Multiply destination by SRC1 and add SRC0", 2);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
gl.blendFunc(ext.SRC1_COLOR_WEBGL, ext.ONE_MINUS_SRC1_COLOR_WEBGL);
|
|
gl.uniform4f(uSrc0, 0.125, 0.125, 0.125, 0.125);
|
|
gl.uniform4f(uSrc1, 0.500, 0.375, 0.250, 0.125);
|
|
wtu.drawUnitQuad(gl);
|
|
wtu.checkCanvas(gl, [143, 171, 199, 227], "Per-channel color interpolation using SRC1", 2);
|
|
}
|
|
|
|
function runTest() {
|
|
if (!gl) {
|
|
testFailed("context does not exist");
|
|
return;
|
|
}
|
|
testPassed("context exists");
|
|
|
|
runTestNoExtension();
|
|
runShaderTests(false);
|
|
|
|
ext = gl.getExtension("WEBGL_blend_func_extended");
|
|
wtu.runExtensionSupportedTest(gl, "WEBGL_blend_func_extended", ext !== null);
|
|
|
|
if (ext !== null) {
|
|
runEnumTests();
|
|
runQueryTests();
|
|
runShaderTests(true);
|
|
runMissingOutputsTests();
|
|
runDrawBuffersLimitTests();
|
|
runBlendingTests();
|
|
} else {
|
|
testPassed("No WEBGL_blend_func_extended support -- this is legal");
|
|
}
|
|
}
|
|
|
|
runTest();
|
|
|
|
var successfullyParsed = true;
|