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