• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 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 // RewriteSampleMaskVariable.cpp: Find any references to gl_SampleMask and gl_SampleMaskIn, and
7 // rewrite it with ANGLESampleMask or ANGLESampleMaskIn.
8 //
9 
10 #include "compiler/translator/tree_util/RewriteSampleMaskVariable.h"
11 
12 #include "common/bitset_utils.h"
13 #include "common/debug.h"
14 #include "common/utilities.h"
15 #include "compiler/translator/SymbolTable.h"
16 #include "compiler/translator/tree_util/BuiltIn.h"
17 #include "compiler/translator/tree_util/IntermNode_util.h"
18 #include "compiler/translator/tree_util/IntermTraverse.h"
19 #include "compiler/translator/tree_util/RunAtTheBeginningOfShader.h"
20 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
21 
22 namespace sh
23 {
24 namespace
25 {
26 constexpr int kMaxIndexForSampleMaskVar = 0;
27 constexpr int kFullSampleMask           = 0xFFFFFFFF;
28 
29 // Traverse the tree and collect the redeclaration and replace all non constant index references of
30 // gl_SampleMask or gl_SampleMaskIn with constant index references
31 class GLSampleMaskRelatedReferenceTraverser : public TIntermTraverser
32 {
33   public:
GLSampleMaskRelatedReferenceTraverser(const TIntermSymbol ** redeclaredSymOut,const ImmutableString & targetStr)34     GLSampleMaskRelatedReferenceTraverser(const TIntermSymbol **redeclaredSymOut,
35                                           const ImmutableString &targetStr)
36         : TIntermTraverser(true, false, false),
37           mRedeclaredSym(redeclaredSymOut),
38           mTargetStr(targetStr)
39     {
40         *mRedeclaredSym = nullptr;
41     }
42 
visitDeclaration(Visit visit,TIntermDeclaration * node)43     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
44     {
45         // If gl_SampleMask is redeclared, we need to collect its information
46         const TIntermSequence &sequence = *(node->getSequence());
47 
48         if (sequence.size() != 1)
49         {
50             return true;
51         }
52 
53         TIntermTyped *variable = sequence.front()->getAsTyped();
54         TIntermSymbol *symbol  = variable->getAsSymbolNode();
55         if (symbol == nullptr || symbol->getName() != mTargetStr)
56         {
57             return true;
58         }
59 
60         *mRedeclaredSym = symbol;
61 
62         return true;
63     }
64 
visitBinary(Visit visit,TIntermBinary * node)65     bool visitBinary(Visit visit, TIntermBinary *node) override
66     {
67         TOperator op = node->getOp();
68         if (op != EOpIndexDirect && op != EOpIndexIndirect)
69         {
70             return true;
71         }
72         TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
73         if (!left)
74         {
75             return true;
76         }
77         if (left->getName() != mTargetStr)
78         {
79             return true;
80         }
81         const TConstantUnion *constIdx = node->getRight()->getConstantValue();
82         if (!constIdx)
83         {
84             if (node->getRight()->hasSideEffects())
85             {
86                 insertStatementInParentBlock(node->getRight());
87             }
88 
89             queueReplacementWithParent(node, node->getRight(),
90                                        CreateIndexNode(kMaxIndexForSampleMaskVar),
91                                        OriginalNode::IS_DROPPED);
92         }
93 
94         return true;
95     }
96 
97   private:
98     const TIntermSymbol **mRedeclaredSym;
99     const ImmutableString mTargetStr;
100 };
101 
102 }  // anonymous namespace
103 
RewriteSampleMask(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const TIntermTyped * numSamplesUniform)104 ANGLE_NO_DISCARD bool RewriteSampleMask(TCompiler *compiler,
105                                         TIntermBlock *root,
106                                         TSymbolTable *symbolTable,
107                                         const TIntermTyped *numSamplesUniform)
108 {
109     const TIntermSymbol *redeclaredGLSampleMask = nullptr;
110     GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMask,
111                                                          ImmutableString("gl_SampleMask"));
112 
113     root->traverse(&indexTraverser);
114     if (!indexTraverser.updateTree(compiler, root))
115     {
116         return false;
117     }
118 
119     // Retrieve gl_SampleMask variable reference
120     // Search user redeclared it first
121     const TVariable *glSampleMaskVar = nullptr;
122     if (redeclaredGLSampleMask)
123     {
124         glSampleMaskVar = &redeclaredGLSampleMask->variable();
125     }
126     else
127     {
128         // User defined not found, find in built-in table
129         glSampleMaskVar = static_cast<const TVariable *>(
130             symbolTable->findBuiltIn(ImmutableString("gl_SampleMask"), 320));
131     }
132     if (!glSampleMaskVar)
133     {
134         return false;
135     }
136 
137     // Current ANGLE assumes that the maximum number of samples is less than or equal to
138     // VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
139     const unsigned int arraySizeOfSampleMask = glSampleMaskVar->getType().getOutermostArraySize();
140     ASSERT(arraySizeOfSampleMask == 1);
141 
142     TIntermSymbol *glSampleMaskSymbol = new TIntermSymbol(glSampleMaskVar);
143 
144     // if (ANGLEUniforms.numSamples == 1)
145     // {
146     //     gl_SampleMask[0] = int(0xFFFFFFFF);
147     // }
148     TIntermConstantUnion *singleSampleCount = CreateUIntNode(1);
149     TIntermBinary *equalTo =
150         new TIntermBinary(EOpEqual, numSamplesUniform->deepCopy(), singleSampleCount);
151 
152     TIntermBlock *trueBlock = new TIntermBlock();
153 
154     TIntermBinary *sampleMaskVar = new TIntermBinary(EOpIndexDirect, glSampleMaskSymbol->deepCopy(),
155                                                      CreateIndexNode(kMaxIndexForSampleMaskVar));
156     TIntermConstantUnion *fullSampleMask = CreateIndexNode(kFullSampleMask);
157     TIntermBinary *assignment = new TIntermBinary(EOpAssign, sampleMaskVar, fullSampleMask);
158 
159     trueBlock->appendStatement(assignment);
160 
161     TIntermIfElse *multiSampleOrNot = new TIntermIfElse(equalTo, trueBlock, nullptr);
162 
163     return RunAtTheEndOfShader(compiler, root, multiSampleOrNot, symbolTable);
164 }
165 
RewriteSampleMaskIn(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)166 ANGLE_NO_DISCARD bool RewriteSampleMaskIn(TCompiler *compiler,
167                                           TIntermBlock *root,
168                                           TSymbolTable *symbolTable)
169 {
170     const TIntermSymbol *redeclaredGLSampleMaskIn = nullptr;
171     GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMaskIn,
172                                                          ImmutableString("gl_SampleMaskIn"));
173 
174     root->traverse(&indexTraverser);
175     if (!indexTraverser.updateTree(compiler, root))
176     {
177         return false;
178     }
179 
180     // Retrieve gl_SampleMaskIn variable reference
181     const TVariable *glSampleMaskInVar = nullptr;
182     glSampleMaskInVar                  = static_cast<const TVariable *>(
183         symbolTable->findBuiltIn(ImmutableString("gl_SampleMaskIn"), 320));
184     if (!glSampleMaskInVar)
185     {
186         return false;
187     }
188 
189     // Current ANGLE assumes that the maximum number of samples is less than or equal to
190     // VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
191     const unsigned int arraySizeOfSampleMaskIn =
192         glSampleMaskInVar->getType().getOutermostArraySize();
193     ASSERT(arraySizeOfSampleMaskIn == 1);
194 
195     return true;
196 }
197 
198 }  // namespace sh
199