1 //
2 // Copyright 2021 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 // EmulateFragColorData: Emulate gl_FragColor and gl_FragData.
7 //
8
9 #include "compiler/translator/tree_ops/vulkan/EmulateFragColorData.h"
10
11 #include "compiler/translator/Compiler.h"
12 #include "compiler/translator/ImmutableStringBuilder.h"
13 #include "compiler/translator/StaticType.h"
14 #include "compiler/translator/SymbolTable.h"
15 #include "compiler/translator/tree_util/IntermNode_util.h"
16 #include "compiler/translator/tree_util/IntermTraverse.h"
17 #include "compiler/translator/tree_util/ReplaceVariable.h"
18
19 namespace sh
20 {
21 namespace
22 {
23 // Traverser that:
24 //
25 // 1. Declares outputs corresponding to gl_FragColor and gl_FragData (and their corresponding
26 // Secondary versions for framebuffer fetch).
27 // 2. Replaces built-in references with these variables.
28 class EmulateFragColorDataTraverser : public TIntermTraverser
29 {
30 public:
EmulateFragColorDataTraverser(TCompiler * compiler,TSymbolTable * symbolTable)31 EmulateFragColorDataTraverser(TCompiler *compiler, TSymbolTable *symbolTable)
32 : TIntermTraverser(true, false, false, symbolTable), mResources(compiler->getResources())
33 {}
34
visitSymbol(TIntermSymbol * symbol)35 void visitSymbol(TIntermSymbol *symbol) override
36 {
37 const TVariable *variable = &symbol->variable();
38 const TType &type = variable->getType();
39
40 // If this built-in was already visited, reuse the variable defined for it.
41 auto replacement = mVariableMap.find(variable);
42 if (replacement != mVariableMap.end())
43 {
44 queueReplacement(replacement->second->deepCopy(), OriginalNode::IS_DROPPED);
45 return;
46 }
47
48 unsigned int arraySize = 0;
49 int index = 0;
50 const char *name = "";
51
52 // Replace the built-ins being emulated with a variable of the appropriate type.
53 switch (type.getQualifier())
54 {
55 case EvqFragColor:
56 name = "webgl_FragColor";
57 break;
58 case EvqFragData:
59 name = "webgl_FragData";
60 arraySize = mResources.MaxDrawBuffers;
61 break;
62 case EvqSecondaryFragColorEXT:
63 name = "webgl_SecondaryFragColor";
64 index = 1;
65 break;
66 case EvqSecondaryFragDataEXT:
67 name = "webgl_SecondaryFragData";
68 index = 1;
69 arraySize = mResources.MaxDualSourceDrawBuffers;
70 break;
71 default:
72 // Not the built-in we are looking for.
73 return;
74 }
75
76 TType *outputType = new TType(*StaticType::GetQualified<EbtFloat, EvqFragmentOut, 4, 1>());
77 if (arraySize > 0)
78 {
79 outputType->makeArray(arraySize);
80 }
81 if (index > 0)
82 {
83 TLayoutQualifier layoutQualifier = outputType->getLayoutQualifier();
84 layoutQualifier.index = index;
85 outputType->setLayoutQualifier(layoutQualifier);
86 }
87
88 TVariable *replacementVar = new TVariable(mSymbolTable, ImmutableString(name), outputType,
89 SymbolType::AngleInternal);
90
91 TIntermSymbol *newSymbol = new TIntermSymbol(replacementVar);
92 mVariableMap[variable] = newSymbol;
93
94 queueReplacement(newSymbol, OriginalNode::IS_DROPPED);
95 }
96
addDeclarations(TIntermBlock * root)97 void addDeclarations(TIntermBlock *root)
98 {
99 // Insert the declaration before the first function.
100 size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
101 TIntermSequence declarations;
102
103 for (auto &replaced : mVariableMap)
104 {
105 TIntermDeclaration *decl = new TIntermDeclaration;
106 TIntermSymbol *symbol = replaced.second->deepCopy()->getAsSymbolNode();
107 decl->appendDeclarator(symbol);
108 declarations.push_back(decl);
109 }
110
111 root->insertChildNodes(firstFunctionIndex, declarations);
112 }
113
114 private:
115 const ShBuiltInResources &mResources;
116
117 // A map of already replaced built-in variables.
118 VariableReplacementMap mVariableMap;
119 };
120 } // anonymous namespace
121
EmulateFragColorData(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)122 bool EmulateFragColorData(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable)
123 {
124 if (compiler->getShaderType() != GL_FRAGMENT_SHADER)
125 {
126 return true;
127 }
128
129 EmulateFragColorDataTraverser traverser(compiler, symbolTable);
130 root->traverse(&traverser);
131 if (!traverser.updateTree(compiler, root))
132 {
133 return false;
134 }
135
136 traverser.addDeclarations(root);
137 return compiler->validateAST(root);
138 }
139 } // namespace sh
140