tor-browser

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

RemoveInactiveInterfaceVariables.cpp (8143B)


      1 //
      2 // Copyright 2019 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 // RemoveInactiveInterfaceVariables.h:
      7 //  Drop shader interface variable declarations for those that are inactive.
      8 //
      9 
     10 #include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
     11 
     12 #include "compiler/translator/SymbolTable.h"
     13 #include "compiler/translator/tree_util/IntermTraverse.h"
     14 #include "compiler/translator/util.h"
     15 
     16 namespace sh
     17 {
     18 
     19 namespace
     20 {
     21 
     22 // Traverser that removes all declarations that correspond to inactive variables.
     23 class RemoveInactiveInterfaceVariablesTraverser : public TIntermTraverser
     24 {
     25  public:
     26    RemoveInactiveInterfaceVariablesTraverser(
     27        TSymbolTable *symbolTable,
     28        const std::vector<sh::ShaderVariable> &attributes,
     29        const std::vector<sh::ShaderVariable> &inputVaryings,
     30        const std::vector<sh::ShaderVariable> &outputVariables,
     31        const std::vector<sh::ShaderVariable> &uniforms,
     32        const std::vector<sh::InterfaceBlock> &interfaceBlocks,
     33        bool removeFragmentOutputs);
     34 
     35    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
     36    bool visitBinary(Visit visit, TIntermBinary *node) override;
     37 
     38  private:
     39    const std::vector<sh::ShaderVariable> &mAttributes;
     40    const std::vector<sh::ShaderVariable> &mInputVaryings;
     41    const std::vector<sh::ShaderVariable> &mOutputVariables;
     42    const std::vector<sh::ShaderVariable> &mUniforms;
     43    const std::vector<sh::InterfaceBlock> &mInterfaceBlocks;
     44    bool mRemoveFragmentOutputs;
     45 };
     46 
     47 RemoveInactiveInterfaceVariablesTraverser::RemoveInactiveInterfaceVariablesTraverser(
     48    TSymbolTable *symbolTable,
     49    const std::vector<sh::ShaderVariable> &attributes,
     50    const std::vector<sh::ShaderVariable> &inputVaryings,
     51    const std::vector<sh::ShaderVariable> &outputVariables,
     52    const std::vector<sh::ShaderVariable> &uniforms,
     53    const std::vector<sh::InterfaceBlock> &interfaceBlocks,
     54    bool removeFragmentOutputs)
     55    : TIntermTraverser(true, false, false, symbolTable),
     56      mAttributes(attributes),
     57      mInputVaryings(inputVaryings),
     58      mOutputVariables(outputVariables),
     59      mUniforms(uniforms),
     60      mInterfaceBlocks(interfaceBlocks),
     61      mRemoveFragmentOutputs(removeFragmentOutputs)
     62 {}
     63 
     64 template <typename Variable>
     65 bool IsVariableActive(const std::vector<Variable> &mVars, const ImmutableString &name)
     66 {
     67    for (const Variable &var : mVars)
     68    {
     69        if (name == var.name)
     70        {
     71            return var.active;
     72        }
     73    }
     74    UNREACHABLE();
     75    return true;
     76 }
     77 
     78 bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit,
     79                                                                 TIntermDeclaration *node)
     80 {
     81    // SeparateDeclarations should have already been run.
     82    ASSERT(node->getSequence()->size() == 1u);
     83 
     84    TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
     85    ASSERT(declarator);
     86 
     87    TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
     88    if (!asSymbol)
     89    {
     90        return false;
     91    }
     92 
     93    const TType &type = declarator->getType();
     94 
     95    // Remove all shader interface variables except outputs, i.e. uniforms, interface blocks and
     96    // inputs.
     97    //
     98    // Imagine a situation where the VS doesn't write to a varying but the FS reads from it.  This
     99    // is allowed, though the value of the varying is undefined.  If the varying is removed here,
    100    // the situation is changed to VS not declaring the varying, but the FS reading from it, which
    101    // is not allowed.  That's why inactive shader outputs are not removed.
    102    //
    103    // Inactive fragment shader outputs can be removed though, as there is no next stage.
    104    bool removeDeclaration     = false;
    105    const TQualifier qualifier = type.getQualifier();
    106 
    107    if (type.isInterfaceBlock())
    108    {
    109        // When a member has an explicit location, interface block should not be removed.
    110        // If the member or interface would be removed, GetProgramResource could not return the
    111        // location.
    112        if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn &&
    113            type.getQualifier() != EvqPatchOut)
    114        {
    115            removeDeclaration =
    116                !IsVariableActive(mInterfaceBlocks, type.getInterfaceBlock()->name());
    117        }
    118    }
    119    else if (qualifier == EvqUniform)
    120    {
    121        removeDeclaration = !IsVariableActive(mUniforms, asSymbol->getName());
    122    }
    123    else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
    124    {
    125        removeDeclaration = !IsVariableActive(mAttributes, asSymbol->getName());
    126    }
    127    else if (IsShaderIn(qualifier))
    128    {
    129        removeDeclaration = !IsVariableActive(mInputVaryings, asSymbol->getName());
    130    }
    131    else if (qualifier == EvqFragmentOut)
    132    {
    133        removeDeclaration =
    134            !IsVariableActive(mOutputVariables, asSymbol->getName()) && mRemoveFragmentOutputs;
    135    }
    136 
    137    if (removeDeclaration)
    138    {
    139        TIntermSequence replacement;
    140 
    141        // If the declaration was of a struct, keep the struct declaration itself.
    142        if (type.isStructSpecifier())
    143        {
    144            TType *structSpecifierType      = new TType(type.getStruct(), true);
    145            TVariable *emptyVariable        = new TVariable(mSymbolTable, kEmptyImmutableString,
    146                                                            structSpecifierType, SymbolType::Empty);
    147            TIntermDeclaration *declaration = new TIntermDeclaration();
    148            declaration->appendDeclarator(new TIntermSymbol(emptyVariable));
    149            replacement.push_back(declaration);
    150        }
    151 
    152        mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
    153                                        std::move(replacement));
    154    }
    155 
    156    return false;
    157 }
    158 
    159 bool RemoveInactiveInterfaceVariablesTraverser::visitBinary(Visit visit, TIntermBinary *node)
    160 {
    161    // Remove any code that initOutputVariables might have added corresponding to inactive
    162    // output variables.  This code is always in the form of `variable = ...;`.
    163    if (node->getOp() != EOpAssign)
    164    {
    165        // Don't recurse, won't find the initialization nested in another expression.
    166        return false;
    167    }
    168 
    169    // Get the symbol being initialized, and check if it's an inactive output.  If it is, this must
    170    // necessarily be initialization code that ANGLE has added (and wasn't there in the original
    171    // shader; if it was, the symbol wouldn't have been inactive).
    172    TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode();
    173    if (symbol == nullptr)
    174    {
    175        return false;
    176    }
    177 
    178    const TQualifier qualifier = symbol->getType().getQualifier();
    179    if (qualifier != EvqFragmentOut || IsVariableActive(mOutputVariables, symbol->getName()))
    180    {
    181        return false;
    182    }
    183 
    184    // Drop the initialization code.
    185    TIntermSequence replacement;
    186    mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, std::move(replacement));
    187    return false;
    188 }
    189 
    190 }  // namespace
    191 
    192 bool RemoveInactiveInterfaceVariables(TCompiler *compiler,
    193                                      TIntermBlock *root,
    194                                      TSymbolTable *symbolTable,
    195                                      const std::vector<sh::ShaderVariable> &attributes,
    196                                      const std::vector<sh::ShaderVariable> &inputVaryings,
    197                                      const std::vector<sh::ShaderVariable> &outputVariables,
    198                                      const std::vector<sh::ShaderVariable> &uniforms,
    199                                      const std::vector<sh::InterfaceBlock> &interfaceBlocks,
    200                                      bool removeFragmentOutputs)
    201 {
    202    RemoveInactiveInterfaceVariablesTraverser traverser(symbolTable, attributes, inputVaryings,
    203                                                        outputVariables, uniforms, interfaceBlocks,
    204                                                        removeFragmentOutputs);
    205    root->traverse(&traverser);
    206    return traverser.updateTree(compiler, root);
    207 }
    208 
    209 }  // namespace sh