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