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