• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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