diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp | 116 |
1 files changed, 91 insertions, 25 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp index cd37aeacd1..26f0e81ba7 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp @@ -3,64 +3,101 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// ValidateOutputs validates fragment shader outputs. It checks for conflicting locations, +// out-of-range locations, that locations are specified when using multiple outputs, and YUV output +// validity. #include "compiler/translator/ValidateOutputs.h" + +#include <set> + #include "compiler/translator/InfoSink.h" -#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/ParseContext.h" +namespace sh +{ + namespace { -void error(int *errorCount, TInfoSinkBase &sink, const TIntermSymbol &symbol, const char *reason) +void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics) { - sink.prefix(EPrefixError); - sink.location(symbol.getLine()); - sink << "'" << symbol.getSymbol() << "' : " << reason << "\n"; - (*errorCount)++; + diagnostics->error(symbol.getLine(), reason, symbol.getSymbol().c_str()); } -} // namespace +class ValidateOutputsTraverser : public TIntermTraverser +{ + public: + ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, int maxDrawBuffers); + + void validate(TDiagnostics *diagnostics) const; + + void visitSymbol(TIntermSymbol *) override; -ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers) + private: + int mMaxDrawBuffers; + bool mAllowUnspecifiedOutputLocationResolution; + bool mUsesFragDepth; + + typedef std::vector<TIntermSymbol *> OutputVector; + OutputVector mOutputs; + OutputVector mUnspecifiedLocationOutputs; + OutputVector mYuvOutputs; + std::set<std::string> mVisitedSymbols; +}; + +ValidateOutputsTraverser::ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, + int maxDrawBuffers) : TIntermTraverser(true, false, false), mMaxDrawBuffers(maxDrawBuffers), mAllowUnspecifiedOutputLocationResolution( - IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended")) + IsExtensionEnabled(extBehavior, TExtension::EXT_blend_func_extended)), + mUsesFragDepth(false) { } -void ValidateOutputs::visitSymbol(TIntermSymbol *symbol) +void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol) { - TString name = symbol->getSymbol(); + TString name = symbol->getSymbol(); TQualifier qualifier = symbol->getQualifier(); - if (mVisitedSymbols.count(name) == 1) + if (mVisitedSymbols.count(name.c_str()) == 1) return; - mVisitedSymbols.insert(name); + mVisitedSymbols.insert(name.c_str()); if (qualifier == EvqFragmentOut) { - if (symbol->getType().getLayoutQualifier().location == -1) + if (symbol->getType().getLayoutQualifier().location != -1) { - mUnspecifiedLocationOutputs.push_back(symbol); + mOutputs.push_back(symbol); + } + else if (symbol->getType().getLayoutQualifier().yuv == true) + { + mYuvOutputs.push_back(symbol); } else { - mOutputs.push_back(symbol); + mUnspecifiedLocationOutputs.push_back(symbol); } } + else if (qualifier == EvqFragDepth || qualifier == EvqFragDepthEXT) + { + mUsesFragDepth = true; + } } -int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const +void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const { + ASSERT(diagnostics); 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); + ASSERT(!type.isArrayOfArrays()); // Disallowed in GLSL ES 3.10 section 4.3.6. + const size_t elementCount = + static_cast<size_t>(type.isArray() ? type.getOutermostArraySize() : 1u); const size_t location = static_cast<size_t>(type.getLayoutQualifier().location); ASSERT(type.getLayoutQualifier().location != -1); @@ -75,7 +112,7 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const std::stringstream strstr; strstr << "conflicting output locations with previously defined output '" << validOutputs[offsetLocation]->getSymbol() << "'"; - error(&errorCount, sink, *symbol, strstr.str().c_str()); + error(*symbol, strstr.str().c_str(), diagnostics); } else { @@ -87,9 +124,10 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const { if (elementCount > 0) { - error(&errorCount, sink, *symbol, + error(*symbol, elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS" - : "output location must be < MAX_DRAW_BUFFERS"); + : "output location must be < MAX_DRAW_BUFFERS", + diagnostics); } } } @@ -100,9 +138,37 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const { for (const auto &symbol : mUnspecifiedLocationOutputs) { - error(&errorCount, sink, *symbol, - "must explicitly specify all locations when using multiple fragment outputs"); + error(*symbol, + "must explicitly specify all locations when using multiple fragment outputs", + diagnostics); } } - return errorCount; + + if (!mYuvOutputs.empty() && (mYuvOutputs.size() > 1 || mUsesFragDepth || !mOutputs.empty() || + !mUnspecifiedLocationOutputs.empty())) + { + for (const auto &symbol : mYuvOutputs) + { + error(*symbol, + "not allowed to specify yuv qualifier when using depth or multiple color " + "fragment outputs", + diagnostics); + } + } +} + +} // anonymous namespace + +bool ValidateOutputs(TIntermBlock *root, + const TExtensionBehavior &extBehavior, + int maxDrawBuffers, + TDiagnostics *diagnostics) +{ + ValidateOutputsTraverser validateOutputs(extBehavior, maxDrawBuffers); + root->traverse(&validateOutputs); + int numErrorsBefore = diagnostics->numErrors(); + validateOutputs.validate(diagnostics); + return (diagnostics->numErrors() == numErrorsBefore); } + +} // namespace sh |