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