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