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