Implement ES 2,3 parts of EXT_blend_func_extended for shader translation
Exposes gl_SecondaryFragColor, glSecondaryFragData[] and
gl_MaxDualSourceDrawBuffers to GLES SL 1.0.
Relaxes rules for undefined output locations for GLES SL 3.0
and exposes gl_MaxDualSourceDrawBuffers.
If the output GL context is GL ES 2.0 or 3.0:
The emulation layer is expected to turn on EXT_blend_func_extended
if the output GL context supports it.
If the output GL context is GL:
The emulation layer is expected to turn on EXT_blend_func_extended
if the output GL context supports ARB_blend_func_extended or if GL
context is 3.2 or later.
If the source shader spec is GLES SL 2.0: The emulation layer is
expected to inspect the shader compilation output variables upon
linking. If output target is GL SL, the emulation layer should bind
color location 0, index 1 to "angle_SecondaryFragColor" if variable
"gl_SecondaryFragColorEXT" is used. Alternatively, emulation layer
should bind "angle_SecondaryFragData" to locations 0,1,2,3,..., all
color index 1, if "gl_SecondaryFragData" array is used.
(The caller can not bind the locations or specify output variables.)
If the source shader spec is GLES SL 3.0:
The emulation layer is expected to do location auto-resolve of the
the output variables that have undefined output locations that have
not been bound by the caller.
(The caller can not use gl_ built-ins, so nothing to do with those.)
BUG=angleproject:1085
TEST=angle_unittest
Change-Id: I5cafe205b0c29478b0dcd24aa89a7b0000f5d046
Reviewed-on: https://chromium-review.googlesource.com/287580
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Kimmo Kinnunen <kkinnunen@nvidia.com>
diff --git a/src/compiler/translator/BaseTypes.h b/src/compiler/translator/BaseTypes.h
index e43c236..2adb1d3 100644
--- a/src/compiler/translator/BaseTypes.h
+++ b/src/compiler/translator/BaseTypes.h
@@ -290,18 +290,18 @@
//
enum TQualifier
{
- EvqTemporary, // For temporaries (within a function), read/write
- EvqGlobal, // For globals read/write
- EvqConst, // User defined constants and non-output parameters in functions
- EvqAttribute, // Readonly
- EvqVaryingIn, // readonly, fragment shaders only
- EvqVaryingOut, // vertex shaders only read/write
- EvqUniform, // Readonly, vertex and fragment
+ EvqTemporary, // For temporaries (within a function), read/write
+ EvqGlobal, // For globals read/write
+ EvqConst, // User defined constants and non-output parameters in functions
+ EvqAttribute, // Readonly
+ EvqVaryingIn, // readonly, fragment shaders only
+ EvqVaryingOut, // vertex shaders only read/write
+ EvqUniform, // Readonly, vertex and fragment
- EvqVertexIn, // Vertex shader input
- EvqFragmentOut, // Fragment shader output
- EvqVertexOut, // Vertex shader output
- EvqFragmentIn, // Fragment shader input
+ EvqVertexIn, // Vertex shader input
+ EvqFragmentOut, // Fragment shader output
+ EvqVertexOut, // Vertex shader output
+ EvqFragmentIn, // Fragment shader input
// parameters
EvqIn,
@@ -325,20 +325,22 @@
EvqFragColor,
EvqFragData,
EvqFragDepth,
+ EvqSecondaryFragColorEXT, // EXT_blend_func_extended
+ EvqSecondaryFragDataEXT, // EXT_blend_func_extended
// built-ins written by the shader_framebuffer_fetch extension(s)
EvqLastFragColor,
EvqLastFragData,
// GLSL ES 3.0 vertex output and fragment input
- EvqSmooth, // Incomplete qualifier, smooth is the default
- EvqFlat, // Incomplete qualifier
+ EvqSmooth, // Incomplete qualifier, smooth is the default
+ EvqFlat, // Incomplete qualifier
EvqSmoothOut = EvqSmooth,
- EvqFlatOut = EvqFlat,
- EvqCentroidOut, // Implies smooth
+ EvqFlatOut = EvqFlat,
+ EvqCentroidOut, // Implies smooth
EvqSmoothIn,
EvqFlatIn,
- EvqCentroidIn, // Implies smooth
+ EvqCentroidIn, // Implies smooth
// end of list
EvqLast
@@ -413,6 +415,12 @@
case EvqFragColor: return "FragColor"; break;
case EvqFragData: return "FragData"; break;
case EvqFragDepth: return "FragDepth"; break;
+ case EvqSecondaryFragColorEXT:
+ return "SecondaryFragColorEXT";
+ break;
+ case EvqSecondaryFragDataEXT:
+ return "SecondaryFragDataEXT";
+ break;
case EvqLastFragColor: return "LastFragColor"; break;
case EvqLastFragData: return "LastFragData"; break;
case EvqSmoothOut: return "smooth out"; break;
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 6fac29a..396b390 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -461,6 +461,7 @@
<< ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
<< ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
<< ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
+ << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
<< ":EXT_frag_depth:" << compileResources.EXT_frag_depth
<< ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
<< ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
@@ -470,6 +471,7 @@
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
<< ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
+ << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers
<< ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision;
@@ -660,9 +662,9 @@
bool TCompiler::validateOutputs(TIntermNode* root)
{
- ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);
+ ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers);
root->traverse(&validateOutputs);
- return (validateOutputs.numErrors() == 0);
+ return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
}
void TCompiler::rewriteCSSShader(TIntermNode* root)
diff --git a/src/compiler/translator/ExtensionBehavior.h b/src/compiler/translator/ExtensionBehavior.h
index cf4d7fb..782c1c9 100644
--- a/src/compiler/translator/ExtensionBehavior.h
+++ b/src/compiler/translator/ExtensionBehavior.h
@@ -34,4 +34,10 @@
// Mapping between extension name and behavior.
typedef std::map<std::string, TBehavior> TExtensionBehavior;
+inline bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, const char *extension)
+{
+ auto iter = extBehavior.find(extension);
+ return iter != extBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire);
+}
+
#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index 6cb2e22..a5e51dc 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -464,6 +464,12 @@
if (spec != SH_CSS_SHADERS_SPEC)
{
symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers);
+ if (resources.EXT_blend_func_extended)
+ {
+ symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
+ "gl_MaxDualSourceDrawBuffersEXT",
+ resources.MaxDualSourceDrawBuffers);
+ }
}
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors);
@@ -502,6 +508,19 @@
fragData.setArraySize(resources.MaxDrawBuffers);
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
+ if (resources.EXT_blend_func_extended)
+ {
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
+ TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
+ TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
+ secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
+ }
+
if (resources.EXT_frag_depth)
{
symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_frag_depth", new TVariable(NewPoolTString("gl_FragDepthEXT"),
@@ -567,6 +586,8 @@
extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
if (resources.ARB_texture_rectangle)
extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
+ if (resources.EXT_blend_func_extended)
+ extBehavior["GL_EXT_blend_func_extended"] = EBhUndefined;
if (resources.EXT_draw_buffers)
extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
if (resources.EXT_frag_depth)
diff --git a/src/compiler/translator/OutputGLSL.cpp b/src/compiler/translator/OutputGLSL.cpp
index e9266ee..c1675ce 100644
--- a/src/compiler/translator/OutputGLSL.cpp
+++ b/src/compiler/translator/OutputGLSL.cpp
@@ -45,6 +45,14 @@
{
out << "webgl_FragData";
}
+ else if (symbol == "gl_SecondaryFragColorEXT")
+ {
+ out << "angle_SecondaryFragColor";
+ }
+ else if (symbol == "gl_SecondaryFragDataEXT")
+ {
+ out << "angle_SecondaryFragData";
+ }
else
{
TOutputGLSLBase::visitSymbol(node);
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index e7069e4..3700a9c 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1143,15 +1143,7 @@
bool TParseContext::isExtensionEnabled(const char *extension) const
{
- const TExtensionBehavior &extbehavior = extensionBehavior();
- TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
-
- if (iter == extbehavior.end())
- {
- return false;
- }
-
- return (iter->second == EBhEnable || iter->second == EBhRequire);
+ return ::IsExtensionEnabled(extensionBehavior(), extension);
}
void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
@@ -1210,14 +1202,18 @@
// Reject shaders using both gl_FragData and gl_FragColor
TQualifier qualifier = variable->getType().getQualifier();
- if (qualifier == EvqFragData)
+ if (qualifier == EvqFragData || qualifier == EvqSecondaryFragDataEXT)
{
mUsesFragData = true;
}
- else if (qualifier == EvqFragColor)
+ else if (qualifier == EvqFragColor || qualifier == EvqSecondaryFragColorEXT)
{
mUsesFragColor = true;
}
+ if (qualifier == EvqSecondaryFragDataEXT || qualifier == EvqSecondaryFragColorEXT)
+ {
+ mUsesSecondaryOutputs = true;
+ }
// This validation is not quite correct - it's only an error to write to
// both FragData and FragColor. For simplicity, and because users shouldn't
@@ -1225,7 +1221,14 @@
// if they are both referenced, rather than assigned.
if (mUsesFragData && mUsesFragColor)
{
- error(location, "cannot use both gl_FragData and gl_FragColor", name->c_str());
+ const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
+ if (mUsesSecondaryOutputs)
+ {
+ errorMessage =
+ "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
+ " and (gl_FragColor, gl_SecondaryFragColorEXT)";
+ }
+ error(location, errorMessage, name->c_str());
recover();
}
}
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index ea9e12c..3b0b206 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -58,7 +58,8 @@
mPreprocessor(&mDiagnostics, &mDirectiveHandler),
mScanner(nullptr),
mUsesFragData(false),
- mUsesFragColor(false)
+ mUsesFragColor(false),
+ mUsesSecondaryOutputs(false)
{
}
@@ -352,6 +353,8 @@
void *mScanner;
bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
bool mUsesFragColor;
+ bool mUsesSecondaryOutputs; // Track if we are using either gl_SecondaryFragData or
+ // gl_Secondary FragColor or both.
};
int PaParseStrings(
diff --git a/src/compiler/translator/ShaderLang.cpp b/src/compiler/translator/ShaderLang.cpp
index ae9c3a4..8bd426f 100644
--- a/src/compiler/translator/ShaderLang.cpp
+++ b/src/compiler/translator/ShaderLang.cpp
@@ -154,6 +154,7 @@
resources->OES_standard_derivatives = 0;
resources->OES_EGL_image_external = 0;
resources->ARB_texture_rectangle = 0;
+ resources->EXT_blend_func_extended = 0;
resources->EXT_draw_buffers = 0;
resources->EXT_frag_depth = 0;
resources->EXT_shader_texture_lod = 0;
@@ -173,6 +174,9 @@
resources->MinProgramTexelOffset = -8;
resources->MaxProgramTexelOffset = 7;
+ // Extensions constants.
+ resources->MaxDualSourceDrawBuffers = 0;
+
// Disable name hashing by default.
resources->HashFunction = NULL;
diff --git a/src/compiler/translator/SymbolTable.h b/src/compiler/translator/SymbolTable.h
index 4e3a203..ba578d7 100644
--- a/src/compiler/translator/SymbolTable.h
+++ b/src/compiler/translator/SymbolTable.h
@@ -412,6 +412,14 @@
return insert(level, constant);
}
+ bool insertConstIntExt(ESymbolLevel level, const char *ext, const char *name, int value)
+ {
+ TVariable *constant =
+ new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
+ constant->getConstPointer()->setIConst(value);
+ return insert(level, ext, constant);
+ }
+
void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name,
const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0);
diff --git a/src/compiler/translator/TranslatorGLSL.cpp b/src/compiler/translator/TranslatorGLSL.cpp
index 86b3919..305e6bb 100644
--- a/src/compiler/translator/TranslatorGLSL.cpp
+++ b/src/compiler/translator/TranslatorGLSL.cpp
@@ -64,30 +64,70 @@
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
// if it's core profile shaders and they are used.
- if (getShaderType() == GL_FRAGMENT_SHADER && IsGLSL130OrNewer(getOutputType()))
+ if (getShaderType() == GL_FRAGMENT_SHADER)
{
- bool usesGLFragColor = false;
- bool usesGLFragData = false;
- for (auto outputVar : outputVariables)
+ const bool mayHaveESSL1SecondaryOutputs =
+ IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") &&
+ getShaderVersion() == 100;
+ const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
+
+ bool hasGLFragColor = false;
+ bool hasGLFragData = false;
+ bool hasGLSecondaryFragColor = false;
+ bool hasGLSecondaryFragData = false;
+
+ for (const auto &outputVar : outputVariables)
{
- if (outputVar.name == "gl_FragColor")
+ if (declareGLFragmentOutputs)
{
- usesGLFragColor = true;
+ if (outputVar.name == "gl_FragColor")
+ {
+ ASSERT(!hasGLFragColor);
+ hasGLFragColor = true;
+ continue;
+ }
+ else if (outputVar.name == "gl_FragData")
+ {
+ ASSERT(!hasGLFragData);
+ hasGLFragData = true;
+ continue;
+ }
}
- else if (outputVar.name == "gl_FragData")
+ if (mayHaveESSL1SecondaryOutputs)
{
- usesGLFragData = true;
+ if (outputVar.name == "gl_SecondaryFragColorEXT")
+ {
+ ASSERT(!hasGLSecondaryFragColor);
+ hasGLSecondaryFragColor = true;
+ continue;
+ }
+ else if (outputVar.name == "gl_SecondaryFragDataEXT")
+ {
+ ASSERT(!hasGLSecondaryFragData);
+ hasGLSecondaryFragData = true;
+ continue;
+ }
}
}
- ASSERT(!(usesGLFragColor && usesGLFragData));
- if (usesGLFragColor)
+ ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
+ (hasGLFragData || hasGLSecondaryFragData)));
+ if (hasGLFragColor)
{
sink << "out vec4 webgl_FragColor;\n";
}
- if (usesGLFragData)
+ if (hasGLFragData)
{
sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
}
+ if (hasGLSecondaryFragColor)
+ {
+ sink << "out vec4 angle_SecondaryFragColor;\n";
+ }
+ if (hasGLSecondaryFragData)
+ {
+ sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
+ << "];\n";
+ }
}
// Write translated shader.
diff --git a/src/compiler/translator/ValidateOutputs.cpp b/src/compiler/translator/ValidateOutputs.cpp
index 6976309..cd37aea 100644
--- a/src/compiler/translator/ValidateOutputs.cpp
+++ b/src/compiler/translator/ValidateOutputs.cpp
@@ -9,12 +9,23 @@
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/ParseContext.h"
-ValidateOutputs::ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers)
+namespace
+{
+void error(int *errorCount, TInfoSinkBase &sink, const TIntermSymbol &symbol, const char *reason)
+{
+ sink.prefix(EPrefixError);
+ sink.location(symbol.getLine());
+ sink << "'" << symbol.getSymbol() << "' : " << reason << "\n";
+ (*errorCount)++;
+}
+
+} // namespace
+
+ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers)
: TIntermTraverser(true, false, false),
- mSink(sink),
mMaxDrawBuffers(maxDrawBuffers),
- mNumErrors(0),
- mHasUnspecifiedOutputLocation(false)
+ mAllowUnspecifiedOutputLocationResolution(
+ IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended"))
{
}
@@ -30,51 +41,68 @@
if (qualifier == EvqFragmentOut)
{
- const TType &type = symbol->getType();
- const int location = type.getLayoutQualifier().location;
- const bool isUnspecifiedOutputLocation = location == -1;
-
- if (mHasUnspecifiedOutputLocation || (isUnspecifiedOutputLocation && !mOutputMap.empty()))
+ if (symbol->getType().getLayoutQualifier().location == -1)
{
- error(symbol->getLine(), "must explicitly specify all locations when using multiple fragment outputs", name.c_str());
- }
- else if (isUnspecifiedOutputLocation)
- {
- mHasUnspecifiedOutputLocation = true;
+ mUnspecifiedLocationOutputs.push_back(symbol);
}
else
{
- OutputMap::iterator mapEntry = mOutputMap.find(location);
- if (mapEntry == mOutputMap.end())
- {
- const int elementCount = type.isArray() ? type.getArraySize() : 1;
- if (location + elementCount > mMaxDrawBuffers)
- {
- error(symbol->getLine(), "output location must be < MAX_DRAW_BUFFERS", name.c_str());
- }
-
- for (int elementIndex = 0; elementIndex < elementCount; elementIndex++)
- {
- const int offsetLocation = location + elementIndex;
- mOutputMap[offsetLocation] = symbol;
- }
- }
- else
- {
- std::stringstream strstr;
- strstr << "conflicting output locations with previously defined output '"
- << mapEntry->second->getSymbol() << "'";
-
- error(symbol->getLine(), strstr.str().c_str(), name.c_str());
- }
+ mOutputs.push_back(symbol);
}
}
}
-void ValidateOutputs::error(TSourceLoc loc, const char *reason, const char* token)
+int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
{
- mSink.prefix(EPrefixError);
- mSink.location(loc);
- mSink << "'" << token << "' : " << reason << "\n";
- mNumErrors++;
+ OutputVector validOutputs(mMaxDrawBuffers);
+ int errorCount = 0;
+
+ for (const auto &symbol : mOutputs)
+ {
+ const TType &type = symbol->getType();
+ const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1);
+ const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
+
+ ASSERT(type.getLayoutQualifier().location != -1);
+
+ if (location + elementCount <= validOutputs.size())
+ {
+ for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
+ {
+ const size_t offsetLocation = location + elementIndex;
+ if (validOutputs[offsetLocation])
+ {
+ std::stringstream strstr;
+ strstr << "conflicting output locations with previously defined output '"
+ << validOutputs[offsetLocation]->getSymbol() << "'";
+ error(&errorCount, sink, *symbol, strstr.str().c_str());
+ }
+ else
+ {
+ validOutputs[offsetLocation] = symbol;
+ }
+ }
+ }
+ else
+ {
+ if (elementCount > 0)
+ {
+ error(&errorCount, sink, *symbol,
+ elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
+ : "output location must be < MAX_DRAW_BUFFERS");
+ }
+ }
+ }
+
+ if (!mAllowUnspecifiedOutputLocationResolution &&
+ ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
+ mUnspecifiedLocationOutputs.size() > 1))
+ {
+ for (const auto &symbol : mUnspecifiedLocationOutputs)
+ {
+ error(&errorCount, sink, *symbol,
+ "must explicitly specify all locations when using multiple fragment outputs");
+ }
+ }
+ return errorCount;
}
diff --git a/src/compiler/translator/ValidateOutputs.h b/src/compiler/translator/ValidateOutputs.h
index 1538e0f..4ba85d8 100644
--- a/src/compiler/translator/ValidateOutputs.h
+++ b/src/compiler/translator/ValidateOutputs.h
@@ -7,6 +7,7 @@
#ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
#define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
+#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/IntermNode.h"
#include <set>
@@ -16,23 +17,20 @@
class ValidateOutputs : public TIntermTraverser
{
public:
- ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers);
+ ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers);
- int numErrors() const { return mNumErrors; }
+ int validateAndCountErrors(TInfoSinkBase &sink) const;
virtual void visitSymbol(TIntermSymbol*);
private:
- TInfoSinkBase& mSink;
int mMaxDrawBuffers;
- int mNumErrors;
- bool mHasUnspecifiedOutputLocation;
+ bool mAllowUnspecifiedOutputLocationResolution;
- typedef std::map<int, TIntermSymbol*> OutputMap;
- OutputMap mOutputMap;
+ typedef std::vector<TIntermSymbol *> OutputVector;
+ OutputVector mOutputs;
+ OutputVector mUnspecifiedLocationOutputs;
std::set<TString> mVisitedSymbols;
-
- void error(TSourceLoc loc, const char *reason, const char* token);
};
#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
diff --git a/src/compiler/translator/VariableInfo.cpp b/src/compiler/translator/VariableInfo.cpp
index c1c4c2d..d61dc40 100644
--- a/src/compiler/translator/VariableInfo.cpp
+++ b/src/compiler/translator/VariableInfo.cpp
@@ -151,6 +151,8 @@
mFragColorAdded(false),
mFragDataAdded(false),
mFragDepthAdded(false),
+ mSecondaryFragColorEXTAdded(false),
+ mSecondaryFragDataEXTAdded(false),
mHashFunction(hashFunction),
mSymbolTable(symbolTable)
{
@@ -420,6 +422,39 @@
mFragDepthAdded = true;
}
return;
+ case EvqSecondaryFragColorEXT:
+ if (!mSecondaryFragColorEXTAdded)
+ {
+ Attribute info;
+ const char kName[] = "gl_SecondaryFragColorEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mSecondaryFragColorEXTAdded = true;
+ }
+ return;
+ case EvqSecondaryFragDataEXT:
+ if (!mSecondaryFragDataEXTAdded)
+ {
+ Attribute info;
+ const char kName[] = "gl_SecondaryFragDataEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+
+ const TVariable *maxDualSourceDrawBuffersVar = static_cast<const TVariable *>(
+ mSymbolTable.findBuiltIn("gl_MaxDualSourceDrawBuffersEXT", 100));
+ info.arraySize = maxDualSourceDrawBuffersVar->getConstPointer()->getIConst();
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mSecondaryFragDataEXTAdded = true;
+ }
+ return;
default:
break;
}
diff --git a/src/compiler/translator/VariableInfo.h b/src/compiler/translator/VariableInfo.h
index 028c699..af7ceae 100644
--- a/src/compiler/translator/VariableInfo.h
+++ b/src/compiler/translator/VariableInfo.h
@@ -59,6 +59,8 @@
bool mFragColorAdded;
bool mFragDataAdded;
bool mFragDepthAdded;
+ bool mSecondaryFragColorEXTAdded;
+ bool mSecondaryFragDataEXTAdded;
ShHashFunction64 mHashFunction;