Edit

kc3-lang/angle/src/compiler/translator/tree_util/RewriteSampleMaskVariable.cpp

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-07-26 21:24:25
    Hash : 7c6da493
    Message : Translator: Make sure built-in variables are consistent Some transformations left the tree in an inconsistent state, for example if it used gl_SampleMask from ES3.1+OES_sample_variables and the transformation added a usage of gl_SampleMask from ES3.2. The offending transformations are fixed and AST validation is improved to catch such errors. Bug: angleproject:4889 Change-Id: I9d9ea5bb43a9408dd4c6dc3e89ec20d60dfeff73 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3054613 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>

  • src/compiler/translator/tree_util/RewriteSampleMaskVariable.cpp
  • //
    // Copyright 2020 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // RewriteSampleMaskVariable.cpp: Find any references to gl_SampleMask and gl_SampleMaskIn, and
    // rewrite it with ANGLESampleMask or ANGLESampleMaskIn.
    //
    
    #include "compiler/translator/tree_util/RewriteSampleMaskVariable.h"
    
    #include "common/bitset_utils.h"
    #include "common/debug.h"
    #include "common/utilities.h"
    #include "compiler/translator/Compiler.h"
    #include "compiler/translator/SymbolTable.h"
    #include "compiler/translator/tree_util/BuiltIn.h"
    #include "compiler/translator/tree_util/IntermNode_util.h"
    #include "compiler/translator/tree_util/IntermTraverse.h"
    #include "compiler/translator/tree_util/RunAtTheBeginningOfShader.h"
    #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
    
    namespace sh
    {
    namespace
    {
    constexpr int kMaxIndexForSampleMaskVar = 0;
    constexpr int kFullSampleMask           = 0xFFFFFFFF;
    
    // Traverse the tree and collect the redeclaration and replace all non constant index references of
    // gl_SampleMask or gl_SampleMaskIn with constant index references
    class GLSampleMaskRelatedReferenceTraverser : public TIntermTraverser
    {
      public:
        GLSampleMaskRelatedReferenceTraverser(const TIntermSymbol **redeclaredSymOut,
                                              const ImmutableString &targetStr)
            : TIntermTraverser(true, false, false),
              mRedeclaredSym(redeclaredSymOut),
              mTargetStr(targetStr)
        {
            *mRedeclaredSym = nullptr;
        }
    
        bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
        {
            // If gl_SampleMask is redeclared, we need to collect its information
            const TIntermSequence &sequence = *(node->getSequence());
    
            if (sequence.size() != 1)
            {
                return true;
            }
    
            TIntermTyped *variable = sequence.front()->getAsTyped();
            TIntermSymbol *symbol  = variable->getAsSymbolNode();
            if (symbol == nullptr || symbol->getName() != mTargetStr)
            {
                return true;
            }
    
            *mRedeclaredSym = symbol;
    
            return true;
        }
    
        bool visitBinary(Visit visit, TIntermBinary *node) override
        {
            TOperator op = node->getOp();
            if (op != EOpIndexDirect && op != EOpIndexIndirect)
            {
                return true;
            }
            TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
            if (!left)
            {
                return true;
            }
            if (left->getName() != mTargetStr)
            {
                return true;
            }
            const TConstantUnion *constIdx = node->getRight()->getConstantValue();
            if (!constIdx)
            {
                if (node->getRight()->hasSideEffects())
                {
                    insertStatementInParentBlock(node->getRight());
                }
    
                queueReplacementWithParent(node, node->getRight(),
                                           CreateIndexNode(kMaxIndexForSampleMaskVar),
                                           OriginalNode::IS_DROPPED);
            }
    
            return true;
        }
    
      private:
        const TIntermSymbol **mRedeclaredSym;
        const ImmutableString mTargetStr;
    };
    
    }  // anonymous namespace
    
    ANGLE_NO_DISCARD bool RewriteSampleMask(TCompiler *compiler,
                                            TIntermBlock *root,
                                            TSymbolTable *symbolTable,
                                            const TIntermTyped *numSamplesUniform)
    {
        const TIntermSymbol *redeclaredGLSampleMask = nullptr;
        GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMask,
                                                             ImmutableString("gl_SampleMask"));
    
        root->traverse(&indexTraverser);
        if (!indexTraverser.updateTree(compiler, root))
        {
            return false;
        }
    
        // Retrieve gl_SampleMask variable reference
        // Search user redeclared it first
        const TVariable *glSampleMaskVar = nullptr;
        if (redeclaredGLSampleMask)
        {
            glSampleMaskVar = &redeclaredGLSampleMask->variable();
        }
        else
        {
            // User defined not found, find in built-in table
            glSampleMaskVar = static_cast<const TVariable *>(symbolTable->findBuiltIn(
                ImmutableString("gl_SampleMask"), compiler->getShaderVersion()));
        }
        if (!glSampleMaskVar)
        {
            return false;
        }
    
        // Current ANGLE assumes that the maximum number of samples is less than or equal to
        // VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
        const unsigned int arraySizeOfSampleMask = glSampleMaskVar->getType().getOutermostArraySize();
        ASSERT(arraySizeOfSampleMask == 1);
    
        TIntermSymbol *glSampleMaskSymbol = new TIntermSymbol(glSampleMaskVar);
    
        // if (ANGLEUniforms.numSamples == 1)
        // {
        //     gl_SampleMask[0] = int(0xFFFFFFFF);
        // }
        TIntermConstantUnion *singleSampleCount = CreateUIntNode(1);
        TIntermBinary *equalTo =
            new TIntermBinary(EOpEqual, numSamplesUniform->deepCopy(), singleSampleCount);
    
        TIntermBlock *trueBlock = new TIntermBlock();
    
        TIntermBinary *sampleMaskVar = new TIntermBinary(EOpIndexDirect, glSampleMaskSymbol->deepCopy(),
                                                         CreateIndexNode(kMaxIndexForSampleMaskVar));
        TIntermConstantUnion *fullSampleMask = CreateIndexNode(kFullSampleMask);
        TIntermBinary *assignment = new TIntermBinary(EOpAssign, sampleMaskVar, fullSampleMask);
    
        trueBlock->appendStatement(assignment);
    
        TIntermIfElse *multiSampleOrNot = new TIntermIfElse(equalTo, trueBlock, nullptr);
    
        return RunAtTheEndOfShader(compiler, root, multiSampleOrNot, symbolTable);
    }
    
    ANGLE_NO_DISCARD bool RewriteSampleMaskIn(TCompiler *compiler,
                                              TIntermBlock *root,
                                              TSymbolTable *symbolTable)
    {
        const TIntermSymbol *redeclaredGLSampleMaskIn = nullptr;
        GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMaskIn,
                                                             ImmutableString("gl_SampleMaskIn"));
    
        root->traverse(&indexTraverser);
        if (!indexTraverser.updateTree(compiler, root))
        {
            return false;
        }
    
        // Retrieve gl_SampleMaskIn variable reference
        const TVariable *glSampleMaskInVar = nullptr;
        glSampleMaskInVar                  = static_cast<const TVariable *>(
            symbolTable->findBuiltIn(ImmutableString("gl_SampleMaskIn"), compiler->getShaderVersion()));
        if (!glSampleMaskInVar)
        {
            return false;
        }
    
        // Current ANGLE assumes that the maximum number of samples is less than or equal to
        // VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
        const unsigned int arraySizeOfSampleMaskIn =
            glSampleMaskInVar->getType().getOutermostArraySize();
        ASSERT(arraySizeOfSampleMaskIn == 1);
    
        return true;
    }
    
    }  // namespace sh