Implement support for dual source blending in ES

Use EXT_blend_func_extended to implement dual source blending in OpenGL
ES. The extension is the ES version of ARB_blend_func_extended.

The extension provides gl_SecondaryFragColorEXT for ES 2.0 contexts.
The extension provides glBindFragDataLocationIndexed to bind a custom
fragment shader output to the secondary color for ES 3.0 contexts.

For ES 3.1 contexts, the extension would also give
"layout (location=0, index=1)" output varible layout modifier syntax,
but it is not used in this patch.

The extension needs #extension GL_EXT_blend_func_extended : require
directive for the variables to be available in ES 2.0. For ES 3.0, the
directive relaxes the rules for the amount of output variables without
layout location qualifiers.

OpenGL continues to use GL_ARB_blend_func_extended for dual source
blending.

Review URL: https://codereview.chromium.org/1266773003
This commit is contained in:
kkinnunen 2015-07-30 22:47:04 -07:00 committed by Commit bot
parent bf49e46aca
commit d94708e71e
5 changed files with 52 additions and 14 deletions

View File

@ -497,6 +497,11 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) {
GET_PROC(BindTexture);
GET_PROC_SUFFIX(BindVertexArray, OES);
if (version >= GR_GL_VER(3,0) && extensions.has("GL_EXT_blend_func_extended")) {
GET_PROC_SUFFIX(BindFragDataLocation, EXT);
GET_PROC_SUFFIX(BindFragDataLocationIndexed, EXT);
}
if (extensions.has("GL_KHR_blend_equation_advanced")) {
GET_PROC_SUFFIX(BlendBarrier, KHR);
} else if (extensions.has("GL_NV_blend_equation_advanced")) {

View File

@ -294,8 +294,14 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
fMultisampleDisableSupport = ctxInfo.hasExtension("GL_EXT_multisample_compatibility");
}
if (kGL_GrGLStandard == standard && version >= GR_GL_VER(3, 0)) {
fBindFragDataLocationSupport = true;
if (kGL_GrGLStandard == standard) {
if (version >= GR_GL_VER(3, 0)) {
fBindFragDataLocationSupport = true;
}
} else {
if (version >= GR_GL_VER(3, 0) && ctxInfo.hasExtension("GL_EXT_blend_func_extended")) {
fBindFragDataLocationSupport = true;
}
}
/**************************************************************************
@ -318,6 +324,8 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
ctxInfo.glslGeneration() >= k150_GrGLSLGeneration;
}
else {
glslCaps->fDualSourceBlendingSupport = ctxInfo.hasExtension("GL_EXT_blend_func_extended");
glslCaps->fShaderDerivativeSupport = ctxInfo.version() >= GR_GL_VER(3, 0) ||
ctxInfo.hasExtension("GL_OES_standard_derivatives");
}

View File

@ -390,13 +390,22 @@ bool GrGLInterface::validate() const {
}
// Dual source blending
if (kGL_GrGLStandard == fStandard &&
(glVer >= GR_GL_VER(3,3) || fExtensions.has("GL_ARB_blend_func_extended"))) {
if (NULL == fFunctions.fBindFragDataLocationIndexed) {
RETURN_FALSE_INTERFACE
if (kGL_GrGLStandard == fStandard) {
if (glVer >= GR_GL_VER(3,3) || fExtensions.has("GL_ARB_blend_func_extended")) {
if (NULL == fFunctions.fBindFragDataLocationIndexed) {
RETURN_FALSE_INTERFACE
}
}
} else {
if (glVer >= GR_GL_VER(3,0) && fExtensions.has("GL_EXT_blend_func_extended")) {
if (NULL == fFunctions.fBindFragDataLocation ||
NULL == fFunctions.fBindFragDataLocationIndexed) {
RETURN_FALSE_INTERFACE
}
}
}
// glGetStringi was added in version 3.0 of both desktop and ES.
if (glVer >= GR_GL_VER(3, 0)) {
if (NULL == fFunctions.fGetStringi) {

View File

@ -16,7 +16,7 @@
const char* GrGLFragmentShaderBuilder::kDstTextureColorName = "_dstColor";
static const char* declared_color_output_name() { return "fsColorOut"; }
static const char* dual_source_output_name() { return "dualSourceOut"; }
static const char* declared_secondary_color_output_name() { return "fsSecondaryColorOut"; }
static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
SkASSERT(GrBlendEquationIsAdvanced(equation));
@ -240,8 +240,19 @@ void GrGLFragmentShaderBuilder::enableCustomOutput() {
void GrGLFragmentShaderBuilder::enableSecondaryOutput() {
SkASSERT(!fHasSecondaryOutput);
fHasSecondaryOutput = true;
fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
dual_source_output_name());
if (kGLES_GrGLStandard == fProgramBuilder->gpu()->ctxInfo().standard()) {
this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, "GL_EXT_blend_func_extended");
}
// If the primary output is declared, we must declare also the secondary output
// and vice versa, since it is not allowed to use a built-in gl_FragColor and a custom
// output. The condition also co-incides with the condition in whici GLES SL 2.0
// requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a custom output.
const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
if (caps.mustDeclareFragmentShaderOutput()) {
fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
declared_secondary_color_output_name());
}
}
const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
@ -249,7 +260,9 @@ const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
}
const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const {
return dual_source_output_name();
const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
return caps.mustDeclareFragmentShaderOutput() ? declared_secondary_color_output_name()
: "gl_SecondaryFragColorEXT";
}
bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
@ -270,11 +283,13 @@ bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
}
void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
if (fHasCustomColorOutput && fProgramBuilder->gpu()->glCaps().bindFragDataLocationSupport()) {
const GrGLCaps& caps = fProgramBuilder->gpu()->glCaps();
if (fHasCustomColorOutput && caps.bindFragDataLocationSupport()) {
GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
}
if (fHasSecondaryOutput) {
GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_name()));
if (fHasSecondaryOutput && caps.glslCaps()->mustDeclareFragmentShaderOutput()) {
GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
declared_secondary_color_output_name()));
}
}

View File

@ -131,7 +131,8 @@ private:
enum GLSLPrivateFeature {
kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
kBlendEquationAdvanced_GLSLPrivateFeature,
kLastGLSLPrivateFeature = kBlendEquationAdvanced_GLSLPrivateFeature
kBlendFuncExtended_GLSLPrivateFeature,
kLastGLSLPrivateFeature = kBlendFuncExtended_GLSLPrivateFeature
};
// Interpretation of DstReadKey when generating code