tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ValidateOutputs.cpp (6165B)


      1 //
      2 // Copyright 2013 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 // ValidateOutputs validates fragment shader outputs. It checks for conflicting locations,
      7 // out-of-range locations, that locations are specified when using multiple outputs, and YUV output
      8 // validity.
      9 
     10 #include "compiler/translator/ValidateOutputs.h"
     11 
     12 #include <set>
     13 
     14 #include "compiler/translator/InfoSink.h"
     15 #include "compiler/translator/ParseContext.h"
     16 #include "compiler/translator/tree_util/IntermTraverse.h"
     17 
     18 namespace sh
     19 {
     20 
     21 namespace
     22 {
     23 
     24 void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
     25 {
     26    diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
     27 }
     28 
     29 class ValidateOutputsTraverser : public TIntermTraverser
     30 {
     31  public:
     32    ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, int maxDrawBuffers);
     33 
     34    void validate(TDiagnostics *diagnostics) const;
     35 
     36    void visitSymbol(TIntermSymbol *) override;
     37 
     38  private:
     39    int mMaxDrawBuffers;
     40    bool mAllowUnspecifiedOutputLocationResolution;
     41    bool mUsesFragDepth;
     42 
     43    typedef std::vector<TIntermSymbol *> OutputVector;
     44    OutputVector mOutputs;
     45    OutputVector mUnspecifiedLocationOutputs;
     46    OutputVector mYuvOutputs;
     47    std::set<int> mVisitedSymbols;  // Visited symbol ids.
     48 };
     49 
     50 ValidateOutputsTraverser::ValidateOutputsTraverser(const TExtensionBehavior &extBehavior,
     51                                                   int maxDrawBuffers)
     52    : TIntermTraverser(true, false, false),
     53      mMaxDrawBuffers(maxDrawBuffers),
     54      mAllowUnspecifiedOutputLocationResolution(
     55          IsExtensionEnabled(extBehavior, TExtension::EXT_blend_func_extended)),
     56      mUsesFragDepth(false)
     57 {}
     58 
     59 void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol)
     60 {
     61    if (symbol->variable().symbolType() == SymbolType::Empty)
     62        return;
     63 
     64    if (mVisitedSymbols.count(symbol->uniqueId().get()) == 1)
     65        return;
     66 
     67    mVisitedSymbols.insert(symbol->uniqueId().get());
     68 
     69    TQualifier qualifier = symbol->getQualifier();
     70    if (qualifier == EvqFragmentOut)
     71    {
     72        if (symbol->getType().getLayoutQualifier().location != -1)
     73        {
     74            mOutputs.push_back(symbol);
     75        }
     76        else if (symbol->getType().getLayoutQualifier().yuv == true)
     77        {
     78            mYuvOutputs.push_back(symbol);
     79        }
     80        else
     81        {
     82            mUnspecifiedLocationOutputs.push_back(symbol);
     83        }
     84    }
     85    else if (qualifier == EvqFragDepth)
     86    {
     87        mUsesFragDepth = true;
     88    }
     89 }
     90 
     91 void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const
     92 {
     93    ASSERT(diagnostics);
     94    OutputVector validOutputs(mMaxDrawBuffers, nullptr);
     95    OutputVector validSecondaryOutputs(mMaxDrawBuffers, nullptr);
     96 
     97    for (const auto &symbol : mOutputs)
     98    {
     99        const TType &type = symbol->getType();
    100        ASSERT(!type.isArrayOfArrays());  // Disallowed in GLSL ES 3.10 section 4.3.6.
    101        const size_t elementCount =
    102            static_cast<size_t>(type.isArray() ? type.getOutermostArraySize() : 1u);
    103        const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
    104 
    105        ASSERT(type.getLayoutQualifier().location != -1);
    106 
    107        OutputVector *validOutputsToUse = &validOutputs;
    108        // The default index is 0, so we only assign the output to secondary outputs in case the
    109        // index is explicitly set to 1.
    110        if (type.getLayoutQualifier().index == 1)
    111        {
    112            validOutputsToUse = &validSecondaryOutputs;
    113        }
    114 
    115        if (location + elementCount <= validOutputsToUse->size())
    116        {
    117            for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
    118            {
    119                const size_t offsetLocation = location + elementIndex;
    120                if ((*validOutputsToUse)[offsetLocation])
    121                {
    122                    std::stringstream strstr = sh::InitializeStream<std::stringstream>();
    123                    strstr << "conflicting output locations with previously defined output '"
    124                           << (*validOutputsToUse)[offsetLocation]->getName() << "'";
    125                    error(*symbol, strstr.str().c_str(), diagnostics);
    126                }
    127                else
    128                {
    129                    (*validOutputsToUse)[offsetLocation] = symbol;
    130                }
    131            }
    132        }
    133        else
    134        {
    135            if (elementCount > 0)
    136            {
    137                error(*symbol,
    138                      elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
    139                                       : "output location must be < MAX_DRAW_BUFFERS",
    140                      diagnostics);
    141            }
    142        }
    143    }
    144 
    145    if (!mAllowUnspecifiedOutputLocationResolution &&
    146        ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
    147         mUnspecifiedLocationOutputs.size() > 1))
    148    {
    149        for (const auto &symbol : mUnspecifiedLocationOutputs)
    150        {
    151            error(*symbol,
    152                  "must explicitly specify all locations when using multiple fragment outputs",
    153                  diagnostics);
    154        }
    155    }
    156 
    157    if (!mYuvOutputs.empty() && (mYuvOutputs.size() > 1 || mUsesFragDepth || !mOutputs.empty() ||
    158                                 !mUnspecifiedLocationOutputs.empty()))
    159    {
    160        for (const auto &symbol : mYuvOutputs)
    161        {
    162            error(*symbol,
    163                  "not allowed to specify yuv qualifier when using depth or multiple color "
    164                  "fragment outputs",
    165                  diagnostics);
    166        }
    167    }
    168 }
    169 
    170 }  // anonymous namespace
    171 
    172 bool ValidateOutputs(TIntermBlock *root,
    173                     const TExtensionBehavior &extBehavior,
    174                     int maxDrawBuffers,
    175                     TDiagnostics *diagnostics)
    176 {
    177    ValidateOutputsTraverser validateOutputs(extBehavior, maxDrawBuffers);
    178    root->traverse(&validateOutputs);
    179    int numErrorsBefore = diagnostics->numErrors();
    180    validateOutputs.validate(diagnostics);
    181    return (diagnostics->numErrors() == numErrorsBefore);
    182 }
    183 
    184 }  // namespace sh