Implement GL_KHR_blend_equation_advanced.

This commit is contained in:
John Kessenich
2015-08-30 05:43:51 -06:00
parent d6c37b190b
commit c8b2e36f52
8 changed files with 148 additions and 4 deletions

View File

@@ -294,6 +294,30 @@ enum TLayoutDepth {
EldCount
};
enum TBlendEquationShift {
// No 'EBlendNone':
// These are used as bit-shift amounts. A mask of such shifts will have type 'int',
// and in that space, 0 means no bits set, or none. In this enum, 0 means (1 << 0), a bit is set.
EBlendMultiply,
EBlendScreen,
EBlendOverlay,
EBlendDarken,
EBlendLighten,
EBlendColordodge,
EBlendColorburn,
EBlendHardlight,
EBlendSoftlight,
EBlendDifference,
EBlendExclusion,
EBlendHslHue,
EBlendHslSaturation,
EBlendHslColor,
EBlendHslLuminosity,
EBlendAllEquations,
EBlendCount
};
class TQualifier {
public:
void clear()
@@ -669,6 +693,28 @@ public:
default: return "none";
}
}
static const char* getBlendEquationString(TBlendEquationShift e)
{
switch (e) {
case EBlendMultiply: return "blend_support_multiply";
case EBlendScreen: return "blend_support_screen";
case EBlendOverlay: return "blend_support_overlay";
case EBlendDarken: return "blend_support_darken";
case EBlendLighten: return "blend_support_lighten";
case EBlendColordodge: return "blend_support_colordodge";
case EBlendColorburn: return "blend_support_colorburn";
case EBlendHardlight: return "blend_support_hardlight";
case EBlendSoftlight: return "blend_support_softlight";
case EBlendDifference: return "blend_support_difference";
case EBlendExclusion: return "blend_support_exclusion";
case EBlendHslHue: return "blend_support_hsl_hue";
case EBlendHslSaturation: return "blend_support_hsl_saturation";
case EBlendHslColor: return "blend_support_hsl_color";
case EBlendHslLuminosity: return "blend_support_hsl_luminosity";
case EBlendAllEquations: return "blend_support_all_equations";
default: return "unknown";
}
}
static const char* getGeometryString(TLayoutGeometry geometry)
{
switch (geometry) {
@@ -728,6 +774,7 @@ struct TShaderQualifiers {
int localSize[3]; // compute shader
bool earlyFragmentTests; // fragment input
TLayoutDepth layoutDepth;
bool blendEquation; // true if any blend equation was specified
void init()
{
@@ -744,6 +791,7 @@ struct TShaderQualifiers {
localSize[2] = 1;
earlyFragmentTests = false;
layoutDepth = EldNone;
blendEquation = false;
}
// Merge in characteristics from the 'src' qualifier. They can override when
@@ -774,6 +822,8 @@ struct TShaderQualifiers {
earlyFragmentTests = true;
if (src.layoutDepth)
layoutDepth = src.layoutDepth;
if (src.blendEquation)
blendEquation = src.blendEquation;
}
};

View File

@@ -2379,6 +2379,9 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
return;
if (publicType.shaderQualifiers.blendEquation)
error(loc, "can only be applied to a standalone 'out'", "blend equation", "");
// now, knowing it is a shader in/out, do all the in/out semantic checks
if (publicType.basicType == EbtBool) {
@@ -3694,6 +3697,21 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
return;
}
}
if (id.compare(0, 13, "blend_support") == 0) {
bool found = false;
for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
if (id == TQualifier::getBlendEquationString(be)) {
requireExtensions(loc, 1, &E_GL_KHR_blend_equation_advanced, "blend equation");
intermediate.addBlendEquation(be);
publicType.shaderQualifiers.blendEquation = true;
found = true;
break;
}
}
if (! found)
error(loc, "unknown blend equation", "blend_support", "");
return;
}
}
error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
}
@@ -4232,6 +4250,9 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
if (shaderQualifiers.localSize[i] > 1)
error(loc, message, "local_size", "");
}
if (shaderQualifiers.blendEquation)
error(loc, message, "blend equation", "");
// TBD: correctness: are any of these missing? pixelCenterInteger, originUpperLeft, spacing, order, pointmode, earlyfragment, depth
}
// Correct and/or advance an object's offset layout qualifier.
@@ -5480,6 +5501,10 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
else
error(loc, "can only apply to 'in'", "early_fragment_tests", "");
}
if (publicType.shaderQualifiers.blendEquation) {
if (publicType.qualifier.storage != EvqVaryingOut)
error(loc, "can only apply to 'out'", "blend equation", "");
}
const TQualifier& qualifier = publicType.qualifier;

View File

@@ -179,8 +179,8 @@ void TParseContext::initializeExtensionBehavior()
extensionBehavior[E_GL_GOOGLE_include_directive] = EBhDisable;
// AEP
extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisablePartial;
extensionBehavior[E_GL_KHR_blend_equation_advanced] = EBhDisablePartial;
extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisable;
extensionBehavior[E_GL_KHR_blend_equation_advanced] = EBhDisable;
extensionBehavior[E_GL_OES_sample_variables] = EBhDisable;
extensionBehavior[E_GL_OES_shader_image_atomic] = EBhDisable;
extensionBehavior[E_GL_OES_shader_multisample_interpolation] = EBhDisable;

View File

@@ -740,6 +740,15 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
infoSink.debug << "using early_fragment_tests\n";
if (depthLayout != EldNone)
infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
if (blendEquations != 0) {
infoSink.debug << "using";
// blendEquations is a mask, decode it
for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
if (blendEquations & (1 << be))
infoSink.debug << " " << TQualifier::getBlendEquationString(be);
}
infoSink.debug << "\n";
}
break;
case EShLangCompute:

View File

@@ -88,6 +88,8 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
else if (depthLayout != unit.depthLayout)
error(infoSink, "Contradictory depth layouts");
blendEquations |= unit.blendEquations;
if (inputPrimitive == ElgNone)
inputPrimitive = unit.inputPrimitive;
else if (inputPrimitive != unit.inputPrimitive)

View File

@@ -127,7 +127,7 @@ public:
explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), treeRoot(0), profile(p), version(v),
numMains(0), numErrors(0), recursive(false),
invocations(0), vertices(0), inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false),
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), xfbMode(false)
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), blendEquations(0), xfbMode(false)
{
localSize[0] = 1;
localSize[1] = 1;
@@ -277,6 +277,9 @@ public:
}
TLayoutDepth getDepth() const { return depthLayout; }
void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
unsigned int getBlendEquations() const { return blendEquations; }
void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
void merge(TInfoSink&, TIntermediate&);
void finalCheck(TInfoSink&);
@@ -332,6 +335,7 @@ protected:
int localSize[3];
bool earlyFragmentTests;
TLayoutDepth depthLayout;
int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift
bool xfbMode;
typedef std::list<TCall> TGraph;