• 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 // ReplaceForShaderFramebufferFetch.h: Find any references to gl_LastFragData, and replace it with
7 // ANGLELastFragData.
8 //
9 
10 #include "compiler/translator/tree_ops/vulkan/ReplaceForShaderFramebufferFetch.h"
11 
12 #include "common/bitset_utils.h"
13 #include "compiler/translator/ImmutableStringBuilder.h"
14 #include "compiler/translator/StaticType.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/SpecializationConstant.h"
21 #include "compiler/translator/util.h"
22 
23 namespace sh
24 {
25 namespace
26 {
27 
28 using InputAttachmentIdxSet = angle::BitSet<32>;
29 using MapForReplacement     = const std::map<const TVariable *, const TIntermTyped *>;
30 
31 constexpr unsigned int kInputAttachmentZero = 0;
32 constexpr unsigned int kArraySizeZero       = 0;
33 
34 enum class InputType
35 {
36     SubpassInput = 0,
37     SubpassInputMS,
38     ISubpassInput,
39     ISubpassInputMS,
40     USubpassInput,
41     USubpassInputMS,
42 
43     InvalidEnum,
44     EnumCount = InvalidEnum,
45 };
46 
47 class InputAttachmentReferenceTraverser : public TIntermTraverser
48 {
49   public:
InputAttachmentReferenceTraverser(std::map<unsigned int,TIntermSymbol * > * declaredSymOut,unsigned int * maxInputAttachmentIndex,InputAttachmentIdxSet * constIndicesOut,bool * usedNonConstIndex)50     InputAttachmentReferenceTraverser(std::map<unsigned int, TIntermSymbol *> *declaredSymOut,
51                                       unsigned int *maxInputAttachmentIndex,
52                                       InputAttachmentIdxSet *constIndicesOut,
53                                       bool *usedNonConstIndex)
54         : TIntermTraverser(true, false, false),
55           mDeclaredSym(declaredSymOut),
56           mMaxInputAttachmentIndex(maxInputAttachmentIndex),
57           mConstInputAttachmentIndices(constIndicesOut),
58           mUsedNonConstIndex(usedNonConstIndex)
59     {
60         mDeclaredSym->clear();
61         *mMaxInputAttachmentIndex = 0;
62         mConstInputAttachmentIndices->reset();
63         *mUsedNonConstIndex = false;
64     }
65 
66     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
67     bool visitBinary(Visit visit, TIntermBinary *node) override;
68 
69   private:
70     void setInputAttachmentIndex(unsigned int index);
71 
72     std::map<unsigned int, TIntermSymbol *> *mDeclaredSym;
73     unsigned int *mMaxInputAttachmentIndex;
74     InputAttachmentIdxSet *mConstInputAttachmentIndices;
75     bool *mUsedNonConstIndex;
76 };
77 
78 class ReplaceVariableTraverser : public TIntermTraverser
79 {
80   public:
ReplaceVariableTraverser(const std::map<const TVariable *,const TIntermTyped * > & replacementMap)81     ReplaceVariableTraverser(
82         const std::map<const TVariable *, const TIntermTyped *> &replacementMap)
83         : TIntermTraverser(true, false, false), mReplacementMap(replacementMap)
84     {}
85 
ReplaceVariableTraverser(const TVariable * toBeReplaced,const TIntermTyped * replacement)86     ReplaceVariableTraverser(const TVariable *toBeReplaced, const TIntermTyped *replacement)
87         : TIntermTraverser(true, false, false), mReplacementMap({{toBeReplaced, replacement}})
88     {}
89 
90     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
91     void visitSymbol(TIntermSymbol *node) override;
92 
93   private:
94     const std::map<const TVariable *, const TIntermTyped *> mReplacementMap;
95 };
96 
setInputAttachmentIndex(unsigned int inputAttachmentIdx)97 void InputAttachmentReferenceTraverser::setInputAttachmentIndex(unsigned int inputAttachmentIdx)
98 {
99     ASSERT(inputAttachmentIdx < mConstInputAttachmentIndices->size());
100     mConstInputAttachmentIndices->set(inputAttachmentIdx);
101     *mMaxInputAttachmentIndex = std::max(*mMaxInputAttachmentIndex, inputAttachmentIdx);
102 }
103 
visitDeclaration(Visit visit,TIntermDeclaration * node)104 bool InputAttachmentReferenceTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
105 {
106     const TIntermSequence &sequence = *(node->getSequence());
107 
108     if (sequence.size() != 1)
109     {
110         return true;
111     }
112 
113     TIntermTyped *variable = sequence.front()->getAsTyped();
114     TIntermSymbol *symbol  = variable->getAsSymbolNode();
115     if (symbol == nullptr)
116     {
117         return true;
118     }
119 
120     if (symbol->getType().getQualifier() == EvqFragmentInOut)
121     {
122         unsigned int inputAttachmentIdx = symbol->getType().getLayoutQualifier().location;
123 
124         if (symbol->getType().isArray())
125         {
126             for (unsigned int index = 0; index < symbol->getType().getOutermostArraySize(); index++)
127             {
128                 unsigned int realInputAttachmentIdx = inputAttachmentIdx + index;
129                 setInputAttachmentIndex(realInputAttachmentIdx);
130             }
131         }
132         else
133         {
134             setInputAttachmentIndex(inputAttachmentIdx);
135         }
136 
137         mDeclaredSym->emplace(inputAttachmentIdx, symbol);
138     }
139 
140     return true;
141 }
142 
visitBinary(Visit visit,TIntermBinary * node)143 bool InputAttachmentReferenceTraverser::visitBinary(Visit visit, TIntermBinary *node)
144 {
145     TOperator op = node->getOp();
146     if (op != EOpIndexDirect && op != EOpIndexIndirect)
147     {
148         return true;
149     }
150 
151     TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
152     if (!left)
153     {
154         return true;
155     }
156     else if (left->getName() != "gl_LastFragData")
157     {
158         return true;
159     }
160 
161     const TConstantUnion *constIdx = node->getRight()->getConstantValue();
162     if (!constIdx)
163     {
164         // If the shader code uses gl_LastFragData with a non-const index, the input attachment
165         // variable should be created as the maximum number. So, the previous redeclared
166         // variable will be reset.
167         mDeclaredSym->clear();
168 
169         *mUsedNonConstIndex = true;
170         mDeclaredSym->emplace(0, left);
171         return true;
172     }
173     else
174     {
175         unsigned int idx = 0;
176         switch (constIdx->getType())
177         {
178             case EbtInt:
179                 idx = constIdx->getIConst();
180                 break;
181             case EbtUInt:
182                 idx = constIdx->getUConst();
183                 break;
184             case EbtFloat:
185                 idx = static_cast<unsigned int>(constIdx->getFConst());
186                 break;
187             case EbtBool:
188                 idx = constIdx->getBConst() ? 1 : 0;
189                 break;
190             default:
191                 UNREACHABLE();
192                 break;
193         }
194         ASSERT(idx < mConstInputAttachmentIndices->size());
195         mConstInputAttachmentIndices->set(idx);
196 
197         *mMaxInputAttachmentIndex = std::max(*mMaxInputAttachmentIndex, idx);
198         mDeclaredSym->emplace(idx, left);
199     }
200 
201     return true;
202 }
203 
visitDeclaration(Visit visit,TIntermDeclaration * node)204 bool ReplaceVariableTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
205 {
206     const TIntermSequence &sequence = *(node->getSequence());
207     if (sequence.size() != 1)
208     {
209         return true;
210     }
211 
212     TIntermTyped *nodeType = sequence.front()->getAsTyped();
213     TIntermSymbol *symbol  = nodeType->getAsSymbolNode();
214     if (symbol == nullptr)
215     {
216         return true;
217     }
218 
219     const TVariable *variable = &symbol->variable();
220     if (mReplacementMap.find(variable) != mReplacementMap.end())
221     {
222         TIntermSequence emptyReplacement;
223         mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
224                                         std::move(emptyReplacement));
225 
226         return true;
227     }
228 
229     return true;
230 }
231 
visitSymbol(TIntermSymbol * node)232 void ReplaceVariableTraverser::visitSymbol(TIntermSymbol *node)
233 {
234     const TVariable *variable = &node->variable();
235     if (mReplacementMap.find(variable) != mReplacementMap.end())
236     {
237         queueReplacement(mReplacementMap.at(variable)->deepCopy(), OriginalNode::IS_DROPPED);
238     }
239 }
240 
GetInputTypeOfSubpassInput(const TBasicType & basicType)241 InputType GetInputTypeOfSubpassInput(const TBasicType &basicType)
242 {
243     switch (basicType)
244     {
245         case TBasicType::EbtSubpassInput:
246             return InputType::SubpassInput;
247         case TBasicType::EbtSubpassInputMS:
248             return InputType::SubpassInputMS;
249         case TBasicType::EbtISubpassInput:
250             return InputType::ISubpassInput;
251         case TBasicType::EbtISubpassInputMS:
252             return InputType::ISubpassInputMS;
253         case TBasicType::EbtUSubpassInput:
254             return InputType::USubpassInput;
255         case TBasicType::EbtUSubpassInputMS:
256             return InputType::USubpassInputMS;
257         default:
258             UNREACHABLE();
259             return InputType::InvalidEnum;
260     }
261 }
262 
GetBasicTypeOfSubpassInput(const InputType & inputType)263 TBasicType GetBasicTypeOfSubpassInput(const InputType &inputType)
264 {
265     switch (inputType)
266     {
267         case InputType::SubpassInput:
268             return EbtSubpassInput;
269         case InputType::SubpassInputMS:
270             return EbtSubpassInputMS;
271         case InputType::ISubpassInput:
272             return EbtISubpassInput;
273         case InputType::ISubpassInputMS:
274             return EbtISubpassInputMS;
275         case InputType::USubpassInput:
276             return EbtUSubpassInput;
277         case InputType::USubpassInputMS:
278             return EbtUSubpassInputMS;
279         default:
280             UNREACHABLE();
281             return TBasicType::EbtVoid;
282     }
283 }
284 
GetBasicTypeForSubpassInput(const TBasicType & inputType)285 TBasicType GetBasicTypeForSubpassInput(const TBasicType &inputType)
286 {
287     switch (inputType)
288     {
289         case EbtFloat:
290             return EbtSubpassInput;
291         case EbtInt:
292             return EbtISubpassInput;
293         case EbtUInt:
294             return EbtUSubpassInput;
295         default:
296             UNREACHABLE();
297             return EbtVoid;
298     }
299 }
300 
GetBasicTypeForSubpassInput(const TIntermSymbol * originSymbol)301 TBasicType GetBasicTypeForSubpassInput(const TIntermSymbol *originSymbol)
302 {
303     if (originSymbol->getName().beginsWith("gl_LastFragData"))
304     {
305         return GetBasicTypeForSubpassInput(EbtFloat);
306     }
307 
308     return GetBasicTypeForSubpassInput(originSymbol->getBasicType());
309 }
310 
GetTypeNameOfSubpassInput(const InputType & inputType)311 ImmutableString GetTypeNameOfSubpassInput(const InputType &inputType)
312 {
313     switch (inputType)
314     {
315         case InputType::SubpassInput:
316             return ImmutableString("subpassInput");
317         case InputType::SubpassInputMS:
318             return ImmutableString("subpassInputMS");
319         case InputType::ISubpassInput:
320             return ImmutableString("isubpassInput");
321         case InputType::ISubpassInputMS:
322             return ImmutableString("isubpassInputMS");
323         case InputType::USubpassInput:
324             return ImmutableString("usubpassInput");
325         case InputType::USubpassInputMS:
326             return ImmutableString("usubpassInputMS");
327         default:
328             UNREACHABLE();
329             return kEmptyImmutableString;
330     }
331 }
332 
GetFunctionNameOfSubpassLoad(const InputType & inputType)333 ImmutableString GetFunctionNameOfSubpassLoad(const InputType &inputType)
334 {
335     switch (inputType)
336     {
337         case InputType::SubpassInput:
338         case InputType::ISubpassInput:
339         case InputType::USubpassInput:
340             return ImmutableString("subpassLoad");
341         case InputType::SubpassInputMS:
342         case InputType::ISubpassInputMS:
343         case InputType::USubpassInputMS:
344             return ImmutableString("subpassLoadMS");
345         default:
346             UNREACHABLE();
347             return kEmptyImmutableString;
348     }
349 }
350 
CreateSubpassLoadFuncCall(TSymbolTable * symbolTable,std::map<InputType,TFunction * > * functionMap,const InputType & inputType,TIntermSequence * arguments)351 TIntermAggregate *CreateSubpassLoadFuncCall(TSymbolTable *symbolTable,
352                                             std::map<InputType, TFunction *> *functionMap,
353                                             const InputType &inputType,
354                                             TIntermSequence *arguments)
355 {
356     TBasicType subpassInputType = GetBasicTypeOfSubpassInput(inputType);
357     ASSERT(subpassInputType != TBasicType::EbtVoid);
358 
359     TFunction **currentFunc = &(*functionMap)[inputType];
360     if (*currentFunc == nullptr)
361     {
362         TType *inputAttachmentType = new TType(subpassInputType, EbpUndefined, EvqUniform, 1);
363         *currentFunc = new TFunction(symbolTable, GetFunctionNameOfSubpassLoad(inputType),
364                                      SymbolType::AngleInternal,
365                                      new TType(EbtFloat, EbpUndefined, EvqGlobal, 4, 1), true);
366         (*currentFunc)
367             ->addParameter(new TVariable(symbolTable, GetTypeNameOfSubpassInput(inputType),
368                                          inputAttachmentType, SymbolType::AngleInternal));
369     }
370 
371     return TIntermAggregate::CreateFunctionCall(**currentFunc, arguments);
372 }
373 
374 class ReplaceSubpassInputUtils
375 {
376   public:
ReplaceSubpassInputUtils(TCompiler * compiler,TSymbolTable * symbolTable,TIntermBlock * root,std::vector<ShaderVariable> * uniforms,const bool usedNonConstIndex,const InputAttachmentIdxSet & constIndices,const std::map<unsigned int,TIntermSymbol * > & declaredVarVec)377     ReplaceSubpassInputUtils(TCompiler *compiler,
378                              TSymbolTable *symbolTable,
379                              TIntermBlock *root,
380                              std::vector<ShaderVariable> *uniforms,
381                              const bool usedNonConstIndex,
382                              const InputAttachmentIdxSet &constIndices,
383                              const std::map<unsigned int, TIntermSymbol *> &declaredVarVec)
384         : mCompiler(compiler),
385           mSymbolTable(symbolTable),
386           mRoot(root),
387           mUniforms(uniforms),
388           mUsedNonConstIndex(usedNonConstIndex),
389           mConstIndices(constIndices),
390           mDeclaredVarVec(declaredVarVec)
391     {
392         mDeclareVariables.clear();
393         mInputAttachmentArrayIdSeq = 0;
394         mInputAttachmentVarList.clear();
395         mDataLoadVarList.clear();
396         mFunctionMap.clear();
397     }
398     virtual ~ReplaceSubpassInputUtils() = default;
399 
400     virtual bool declareSubpassInputVariables() = 0;
declareVariablesForFetch(const unsigned int inputAttachmentIndex,const TVariable * dataLoadVar)401     void declareVariablesForFetch(const unsigned int inputAttachmentIndex,
402                                   const TVariable *dataLoadVar)
403     {
404         mDataLoadVarList[inputAttachmentIndex] = dataLoadVar;
405 
406         TIntermDeclaration *dataLoadVarDecl = new TIntermDeclaration;
407         TIntermSymbol *dataLoadVarDeclarator =
408             new TIntermSymbol(mDataLoadVarList[inputAttachmentIndex]);
409         dataLoadVarDecl->appendDeclarator(dataLoadVarDeclarator);
410         mDeclareVariables.push_back(dataLoadVarDecl);
411     }
412 
413     virtual bool loadInputAttachmentData() = 0;
414 
submitNewDeclaration()415     void submitNewDeclaration()
416     {
417         for (unsigned int index = 0; index < mDeclareVariables.size(); index++)
418         {
419             mRoot->insertStatement(index, mDeclareVariables[index]);
420         }
421 
422         mDeclareVariables.clear();
423     }
424 
425   protected:
426     bool declareSubpassInputVariableImpl(const TIntermSymbol *declaredVarSym,
427                                          const unsigned int inputAttachmentIndex);
428     void addInputAttachmentUniform(const unsigned int inputAttachmentIndex);
429 
430     TIntermNode *assignSubpassLoad(TIntermTyped *resultVar,
431                                    TIntermTyped *inputAttachmentSymbol,
432                                    const int targetVecSize);
433     TIntermNode *loadInputAttachmentDataImpl(const size_t arraySize,
434                                              const unsigned int inputAttachmentIndex,
435                                              const TVariable *loadInputAttachmentDataVar);
436 
437     ImmutableString getInputAttachmentName(unsigned int index);
438     ImmutableString getInputAttachmentArrayName();
439 
440     TCompiler *mCompiler;
441     TSymbolTable *mSymbolTable;
442     TIntermBlock *mRoot;
443     std::vector<ShaderVariable> *mUniforms;
444     const bool mUsedNonConstIndex;
445     const InputAttachmentIdxSet mConstIndices;
446     const std::map<unsigned int, TIntermSymbol *> mDeclaredVarVec;
447 
448     TIntermSequence mDeclareVariables;
449     unsigned int mInputAttachmentArrayIdSeq;
450     std::map<InputType, TFunction *> mFunctionMap;
451     std::map<unsigned int, TVariable *> mInputAttachmentVarList;
452     std::map<unsigned int, const TVariable *> mDataLoadVarList;
453 };
454 
getInputAttachmentArrayName()455 ImmutableString ReplaceSubpassInputUtils::getInputAttachmentArrayName()
456 {
457     constexpr ImmutableString suffix("Array");
458     std::stringstream nameStream = sh::InitializeStream<std::stringstream>();
459     nameStream << sh::vk::kInputAttachmentName << suffix << mInputAttachmentArrayIdSeq++;
460     return ImmutableString(nameStream.str());
461 }
462 
getInputAttachmentName(unsigned int index)463 ImmutableString ReplaceSubpassInputUtils::getInputAttachmentName(unsigned int index)
464 {
465     std::stringstream nameStream = sh::InitializeStream<std::stringstream>();
466     nameStream << sh::vk::kInputAttachmentName << index;
467     return ImmutableString(nameStream.str());
468 }
469 
declareSubpassInputVariableImpl(const TIntermSymbol * declaredVarSym,const unsigned int inputAttachmentIndex)470 bool ReplaceSubpassInputUtils::declareSubpassInputVariableImpl(
471     const TIntermSymbol *declaredVarSym,
472     const unsigned int inputAttachmentIndex)
473 {
474     TBasicType subpassInputType = GetBasicTypeForSubpassInput(declaredVarSym);
475     if (subpassInputType == EbtVoid)
476     {
477         return false;
478     }
479 
480     TType *inputAttachmentType = new TType(subpassInputType, EbpUndefined, EvqUniform, 1);
481     TLayoutQualifier inputAttachmentQualifier     = inputAttachmentType->getLayoutQualifier();
482     inputAttachmentQualifier.inputAttachmentIndex = inputAttachmentIndex;
483     inputAttachmentType->setLayoutQualifier(inputAttachmentQualifier);
484 
485     mInputAttachmentVarList[inputAttachmentIndex] =
486         new TVariable(mSymbolTable, getInputAttachmentName(inputAttachmentIndex),
487                       inputAttachmentType, SymbolType::AngleInternal);
488     TIntermSymbol *inputAttachmentDeclarator =
489         new TIntermSymbol(mInputAttachmentVarList[inputAttachmentIndex]);
490 
491     TIntermDeclaration *inputAttachmentDecl = new TIntermDeclaration;
492     inputAttachmentDecl->appendDeclarator(inputAttachmentDeclarator);
493 
494     mDeclareVariables.push_back(inputAttachmentDecl);
495 
496     return true;
497 }
498 
addInputAttachmentUniform(const unsigned int inputAttachmentIndex)499 void ReplaceSubpassInputUtils::addInputAttachmentUniform(const unsigned int inputAttachmentIndex)
500 {
501     const TVariable *inputAttachmentVar = mInputAttachmentVarList[inputAttachmentIndex];
502 
503     ShaderVariable inputAttachmentUniform;
504     inputAttachmentUniform.active    = true;
505     inputAttachmentUniform.staticUse = true;
506     inputAttachmentUniform.name.assign(inputAttachmentVar->name().data(),
507                                        inputAttachmentVar->name().length());
508     inputAttachmentUniform.mappedName.assign(inputAttachmentUniform.name);
509     inputAttachmentUniform.isFragmentInOut = true;
510     inputAttachmentUniform.location =
511         inputAttachmentVar->getType().getLayoutQualifier().inputAttachmentIndex;
512     mUniforms->push_back(inputAttachmentUniform);
513 }
514 
assignSubpassLoad(TIntermTyped * resultVar,TIntermTyped * inputAttachmentSymbol,const int targetVecSize)515 TIntermNode *ReplaceSubpassInputUtils::assignSubpassLoad(TIntermTyped *resultVar,
516                                                          TIntermTyped *inputAttachmentSymbol,
517                                                          const int targetVecSize)
518 {
519     TIntermSequence *subpassArguments = new TIntermSequence();
520     subpassArguments->push_back(inputAttachmentSymbol);
521 
522     TIntermAggregate *subpassLoadFuncCall = CreateSubpassLoadFuncCall(
523         mSymbolTable, &mFunctionMap,
524         GetInputTypeOfSubpassInput(inputAttachmentSymbol->getBasicType()), subpassArguments);
525 
526     TVector<int> fieldOffsets(targetVecSize);
527     for (int i = 0; i < targetVecSize; i++)
528     {
529         fieldOffsets[i] = i;
530     }
531 
532     TIntermTyped *right = new TIntermSwizzle(subpassLoadFuncCall, fieldOffsets);
533 
534     return new TIntermBinary(EOpAssign, resultVar, right);
535 }
536 
loadInputAttachmentDataImpl(const size_t arraySize,const unsigned int inputAttachmentIndex,const TVariable * loadInputAttachmentDataVar)537 TIntermNode *ReplaceSubpassInputUtils::loadInputAttachmentDataImpl(
538     const size_t arraySize,
539     const unsigned int inputAttachmentIndex,
540     const TVariable *loadInputAttachmentDataVar)
541 {
542     TIntermNode *retExpression = nullptr;
543 
544     TIntermSymbol *loadInputAttachmentDataSymbol = new TIntermSymbol(loadInputAttachmentDataVar);
545 
546     TIntermTyped *left = nullptr;
547 
548     if (arraySize > 0)
549     {
550         TIntermBlock *blockNode = new TIntermBlock();
551 
552         for (uint32_t index = 0; index < arraySize; index++)
553         {
554             uint32_t attachmentIndex = inputAttachmentIndex + index;
555 
556             left = new TIntermBinary(EOpIndexDirect, loadInputAttachmentDataSymbol->deepCopy(),
557                                      CreateIndexNode(index));
558 
559             blockNode->appendStatement(
560                 assignSubpassLoad(left, new TIntermSymbol(mInputAttachmentVarList[attachmentIndex]),
561                                   left->getNominalSize()));
562         }
563 
564         retExpression = blockNode;
565     }
566     else
567     {
568         if (loadInputAttachmentDataSymbol->isArray())
569         {
570             left = new TIntermBinary(EOpIndexDirect, loadInputAttachmentDataSymbol->deepCopy(),
571                                      CreateIndexNode(inputAttachmentIndex));
572         }
573         else
574         {
575             left = loadInputAttachmentDataSymbol->deepCopy();
576         }
577 
578         retExpression = assignSubpassLoad(
579             left, new TIntermSymbol(mInputAttachmentVarList[inputAttachmentIndex]),
580             left->getNominalSize());
581     }
582 
583     return retExpression;
584 }
585 
586 class ReplaceGlLastFragDataUtils : public ReplaceSubpassInputUtils
587 {
588   public:
ReplaceGlLastFragDataUtils(TCompiler * compiler,TSymbolTable * symbolTable,TIntermBlock * root,std::vector<ShaderVariable> * uniforms,const bool usedNonConstIndex,const InputAttachmentIdxSet & constIndices,const std::map<unsigned int,TIntermSymbol * > & declaredVarVec)589     ReplaceGlLastFragDataUtils(TCompiler *compiler,
590                                TSymbolTable *symbolTable,
591                                TIntermBlock *root,
592                                std::vector<ShaderVariable> *uniforms,
593                                const bool usedNonConstIndex,
594                                const InputAttachmentIdxSet &constIndices,
595                                const std::map<unsigned int, TIntermSymbol *> &declaredVarVec)
596         : ReplaceSubpassInputUtils(compiler,
597                                    symbolTable,
598                                    root,
599                                    uniforms,
600                                    usedNonConstIndex,
601                                    constIndices,
602                                    declaredVarVec)
603     {}
604 
605     bool declareSubpassInputVariables() override;
606     bool loadInputAttachmentData() override;
607 };
608 
declareSubpassInputVariables()609 bool ReplaceGlLastFragDataUtils::declareSubpassInputVariables()
610 {
611     for (auto declaredVar : mDeclaredVarVec)
612     {
613         const unsigned int inputAttachmentIndex = declaredVar.first;
614         if (mConstIndices.test(inputAttachmentIndex))
615         {
616             if (!declareSubpassInputVariableImpl(declaredVar.second, inputAttachmentIndex))
617             {
618                 return false;
619             }
620 
621             addInputAttachmentUniform(inputAttachmentIndex);
622         }
623     }
624 
625     return true;
626 }
627 
loadInputAttachmentData()628 bool ReplaceGlLastFragDataUtils::loadInputAttachmentData()
629 {
630     TIntermNode *loadInputAttachmentBlock = new TIntermBlock();
631 
632     for (auto declaredVar : mDeclaredVarVec)
633     {
634         const unsigned int inputAttachmentIndex = declaredVar.first;
635         if (mConstIndices.test(inputAttachmentIndex))
636         {
637             loadInputAttachmentBlock->getAsBlock()->appendStatement(loadInputAttachmentDataImpl(
638                 kArraySizeZero, inputAttachmentIndex, mDataLoadVarList[kArraySizeZero]));
639         }
640     }
641 
642     ASSERT(loadInputAttachmentBlock->getChildCount() > 0);
643     if (!RunAtTheBeginningOfShader(mCompiler, mRoot, loadInputAttachmentBlock))
644     {
645         return false;
646     }
647 
648     return true;
649 }
650 
651 class ReplaceInOutUtils : public ReplaceSubpassInputUtils
652 {
653   public:
ReplaceInOutUtils(TCompiler * compiler,TSymbolTable * symbolTable,TIntermBlock * root,std::vector<ShaderVariable> * uniforms,const bool usedNonConstIndex,const InputAttachmentIdxSet & constIndices,const std::map<unsigned int,TIntermSymbol * > & declaredVarVec)654     ReplaceInOutUtils(TCompiler *compiler,
655                       TSymbolTable *symbolTable,
656                       TIntermBlock *root,
657                       std::vector<ShaderVariable> *uniforms,
658                       const bool usedNonConstIndex,
659                       const InputAttachmentIdxSet &constIndices,
660                       const std::map<unsigned int, TIntermSymbol *> &declaredVarVec)
661         : ReplaceSubpassInputUtils(compiler,
662                                    symbolTable,
663                                    root,
664                                    uniforms,
665                                    usedNonConstIndex,
666                                    constIndices,
667                                    declaredVarVec)
668     {}
669 
670     bool declareSubpassInputVariables() override;
671     bool loadInputAttachmentData() override;
672 };
673 
declareSubpassInputVariables()674 bool ReplaceInOutUtils::declareSubpassInputVariables()
675 {
676     for (auto declaredVar : mDeclaredVarVec)
677     {
678         const unsigned int inputAttachmentIndex = declaredVar.first;
679         const unsigned int arraySize =
680             (declaredVar.second->isArray() ? declaredVar.second->getOutermostArraySize() : 1);
681 
682         for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
683         {
684             unsigned int attachmentIndex = inputAttachmentIndex + arrayIndex;
685 
686             if (!declareSubpassInputVariableImpl(declaredVar.second, attachmentIndex))
687             {
688                 return false;
689             }
690 
691             addInputAttachmentUniform(attachmentIndex);
692         }
693     }
694 
695     return true;
696 }
697 
loadInputAttachmentData()698 bool ReplaceInOutUtils::loadInputAttachmentData()
699 {
700     TIntermBlock *loadInputAttachmentBlock = new TIntermBlock();
701 
702     for (auto declaredVar : mDeclaredVarVec)
703     {
704         const unsigned int inputAttachmentIndex = declaredVar.first;
705         size_t arraySize =
706             (declaredVar.second->isArray() ? declaredVar.second->getOutermostArraySize() : 0);
707         loadInputAttachmentBlock->appendStatement(loadInputAttachmentDataImpl(
708             arraySize, inputAttachmentIndex, mDataLoadVarList[inputAttachmentIndex]));
709     }
710 
711     ASSERT(loadInputAttachmentBlock->getChildCount() > 0);
712     if (!RunAtTheBeginningOfShader(mCompiler, mRoot, loadInputAttachmentBlock))
713     {
714         return false;
715     }
716 
717     return true;
718 }
719 
720 }  // anonymous namespace
721 
ReplaceLastFragData(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,std::vector<ShaderVariable> * uniforms)722 ANGLE_NO_DISCARD bool ReplaceLastFragData(TCompiler *compiler,
723                                           TIntermBlock *root,
724                                           TSymbolTable *symbolTable,
725                                           std::vector<ShaderVariable> *uniforms)
726 {
727     // Common variables
728     InputAttachmentIdxSet constIndices;
729     std::map<unsigned int, TIntermSymbol *> glLastFragDataUsageMap;
730     unsigned int maxInputAttachmentIndex = 0;
731     bool usedNonConstIndex               = false;
732 
733     // Get informations for gl_LastFragData
734     InputAttachmentReferenceTraverser informationTraverser(
735         &glLastFragDataUsageMap, &maxInputAttachmentIndex, &constIndices, &usedNonConstIndex);
736     root->traverse(&informationTraverser);
737     if (constIndices.none() && !usedNonConstIndex)
738     {
739         // No references of gl_LastFragData
740         return true;
741     }
742 
743     // Declare subpassInput uniform variables
744     ReplaceGlLastFragDataUtils replaceSubpassInputUtils(compiler, symbolTable, root, uniforms,
745                                                         usedNonConstIndex, constIndices,
746                                                         glLastFragDataUsageMap);
747     if (!replaceSubpassInputUtils.declareSubpassInputVariables())
748     {
749         return false;
750     }
751 
752     // Declare the variables which store the result of subpassLoad function
753     const TVariable *glLastFragDataVar = nullptr;
754     if (glLastFragDataUsageMap.size() > 0)
755     {
756         glLastFragDataVar = &glLastFragDataUsageMap.begin()->second->variable();
757     }
758     else
759     {
760         glLastFragDataVar = static_cast<const TVariable *>(
761             symbolTable->findBuiltIn(ImmutableString("gl_LastFragData"), 100));
762     }
763     if (!glLastFragDataVar)
764     {
765         return false;
766     }
767 
768     const TBasicType loadVarBasicType = glLastFragDataVar->getType().getBasicType();
769     const TPrecision loadVarPrecision = glLastFragDataVar->getType().getPrecision();
770     const unsigned int loadVarVecSize = glLastFragDataVar->getType().getNominalSize();
771     const int loadVarArraySize        = glLastFragDataVar->getType().getOutermostArraySize();
772 
773     ImmutableString loadVarName("ANGLELastFragData");
774     TType *loadVarType = new TType(loadVarBasicType, loadVarPrecision, EvqGlobal,
775                                    static_cast<unsigned char>(loadVarVecSize));
776     loadVarType->makeArray(loadVarArraySize);
777 
778     TVariable *loadVar =
779         new TVariable(symbolTable, loadVarName, loadVarType, SymbolType::AngleInternal);
780     replaceSubpassInputUtils.declareVariablesForFetch(kInputAttachmentZero, loadVar);
781 
782     replaceSubpassInputUtils.submitNewDeclaration();
783 
784     // 3) Add the routine for reading InputAttachment data
785     if (!replaceSubpassInputUtils.loadInputAttachmentData())
786     {
787         return false;
788     }
789 
790     // 4) Replace gl_LastFragData with ANGLELastFragData
791     ReplaceVariableTraverser replaceTraverser(glLastFragDataVar, new TIntermSymbol(loadVar));
792     root->traverse(&replaceTraverser);
793     if (!replaceTraverser.updateTree(compiler, root))
794     {
795         return false;
796     }
797 
798     return true;
799 }
800 
ReplaceInOutVariables(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,std::vector<ShaderVariable> * uniforms)801 ANGLE_NO_DISCARD bool ReplaceInOutVariables(TCompiler *compiler,
802                                             TIntermBlock *root,
803                                             TSymbolTable *symbolTable,
804                                             std::vector<ShaderVariable> *uniforms)
805 {
806     // Common variables
807     InputAttachmentIdxSet constIndices;
808     std::map<unsigned int, TIntermSymbol *> declaredInOutVarMap;
809     unsigned int maxInputAttachmentIndex = 0;
810     bool usedNonConstIndex               = false;
811 
812     // Get informations for gl_LastFragData
813     InputAttachmentReferenceTraverser informationTraverser(
814         &declaredInOutVarMap, &maxInputAttachmentIndex, &constIndices, &usedNonConstIndex);
815     root->traverse(&informationTraverser);
816     if (declaredInOutVarMap.size() == 0)
817     {
818         // No references of the variable decorated with a inout qualifier
819         return true;
820     }
821 
822     // Declare subpassInput uniform variables
823     ReplaceInOutUtils replaceSubpassInputUtils(compiler, symbolTable, root, uniforms,
824                                                usedNonConstIndex, constIndices,
825                                                declaredInOutVarMap);
826     if (!replaceSubpassInputUtils.declareSubpassInputVariables())
827     {
828         return false;
829     }
830 
831     std::map<unsigned int, const TVariable *> toBeReplaced;
832     std::map<unsigned int, const TVariable *> newOutVarArray;
833     for (auto originInOutVarIter : declaredInOutVarMap)
834     {
835         const unsigned int inputAttachmentIndex = originInOutVarIter.first;
836         const TIntermSymbol *originInOutVar     = originInOutVarIter.second;
837 
838         const TBasicType loadVarBasicType = originInOutVar->getType().getBasicType();
839         const TPrecision loadVarPrecision = originInOutVar->getType().getPrecision();
840         const unsigned int loadVarVecSize = originInOutVar->getType().getNominalSize();
841         const unsigned int loadVarArraySize =
842             (originInOutVar->isArray() ? originInOutVar->getOutermostArraySize() : 0);
843 
844         TType *newOutVarType = new TType(loadVarBasicType, loadVarPrecision, EvqGlobal,
845                                          static_cast<unsigned char>(loadVarVecSize));
846 
847         // We just want to use the original variable decorated with a inout qualifier, except
848         // the qualifier itself. The qualifier will be changed from inout to out.
849         newOutVarType->setQualifier(TQualifier::EvqFragmentOut);
850 
851         if (loadVarArraySize > 0)
852         {
853             newOutVarType->makeArray(loadVarArraySize);
854         }
855 
856         TVariable *newOutVar = new TVariable(symbolTable, originInOutVar->getName(), newOutVarType,
857                                              SymbolType::UserDefined);
858         newOutVarArray[inputAttachmentIndex] = newOutVar;
859         replaceSubpassInputUtils.declareVariablesForFetch(inputAttachmentIndex,
860                                                           newOutVarArray[inputAttachmentIndex]);
861 
862         toBeReplaced[inputAttachmentIndex] = &originInOutVar->variable();
863     }
864 
865     replaceSubpassInputUtils.submitNewDeclaration();
866 
867     // 3) Add the routine for reading InputAttachment data
868     if (!replaceSubpassInputUtils.loadInputAttachmentData())
869     {
870         return false;
871     }
872 
873     std::map<const TVariable *, const TIntermTyped *> replacementMap;
874     for (auto newOutVar = newOutVarArray.begin(); newOutVar != newOutVarArray.end(); newOutVar++)
875     {
876         const unsigned int index            = newOutVar->first;
877         replacementMap[toBeReplaced[index]] = new TIntermSymbol(newOutVar->second);
878     }
879 
880     // 4) Replace previous 'inout' variable with newly created 'inout' variable
881     ReplaceVariableTraverser replaceTraverser(replacementMap);
882     root->traverse(&replaceTraverser);
883     if (!replaceTraverser.updateTree(compiler, root))
884     {
885         return false;
886     }
887 
888     return true;
889 }
890 
891 }  // namespace sh
892