1 //
2 // Copyright 2019 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 // RemoveInactiveInterfaceVariables.h:
7 // Drop shader interface variable declarations for those that are inactive.
8 //
9
10 #include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
11
12 #include "compiler/translator/SymbolTable.h"
13 #include "compiler/translator/tree_util/IntermTraverse.h"
14 #include "compiler/translator/util.h"
15
16 namespace sh
17 {
18
19 namespace
20 {
21
22 // Traverser that removes all declarations that correspond to inactive variables.
23 class RemoveInactiveInterfaceVariablesTraverser : public TIntermTraverser
24 {
25 public:
26 RemoveInactiveInterfaceVariablesTraverser(
27 TSymbolTable *symbolTable,
28 const std::vector<sh::ShaderVariable> &attributes,
29 const std::vector<sh::ShaderVariable> &inputVaryings,
30 const std::vector<sh::ShaderVariable> &outputVariables,
31 const std::vector<sh::ShaderVariable> &uniforms,
32 const std::vector<sh::InterfaceBlock> &interfaceBlocks);
33
34 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
35
36 private:
37 const std::vector<sh::ShaderVariable> &mAttributes;
38 const std::vector<sh::ShaderVariable> &mInputVaryings;
39 const std::vector<sh::ShaderVariable> &mOutputVariables;
40 const std::vector<sh::ShaderVariable> &mUniforms;
41 const std::vector<sh::InterfaceBlock> &mInterfaceBlocks;
42 };
43
RemoveInactiveInterfaceVariablesTraverser(TSymbolTable * symbolTable,const std::vector<sh::ShaderVariable> & attributes,const std::vector<sh::ShaderVariable> & inputVaryings,const std::vector<sh::ShaderVariable> & outputVariables,const std::vector<sh::ShaderVariable> & uniforms,const std::vector<sh::InterfaceBlock> & interfaceBlocks)44 RemoveInactiveInterfaceVariablesTraverser::RemoveInactiveInterfaceVariablesTraverser(
45 TSymbolTable *symbolTable,
46 const std::vector<sh::ShaderVariable> &attributes,
47 const std::vector<sh::ShaderVariable> &inputVaryings,
48 const std::vector<sh::ShaderVariable> &outputVariables,
49 const std::vector<sh::ShaderVariable> &uniforms,
50 const std::vector<sh::InterfaceBlock> &interfaceBlocks)
51 : TIntermTraverser(true, false, false, symbolTable),
52 mAttributes(attributes),
53 mInputVaryings(inputVaryings),
54 mOutputVariables(outputVariables),
55 mUniforms(uniforms),
56 mInterfaceBlocks(interfaceBlocks)
57 {}
58
59 template <typename Variable>
IsVariableActive(const std::vector<Variable> & mVars,const ImmutableString & name)60 bool IsVariableActive(const std::vector<Variable> &mVars, const ImmutableString &name)
61 {
62 for (const Variable &var : mVars)
63 {
64 if (name == var.name)
65 {
66 return var.active;
67 }
68 }
69 UNREACHABLE();
70 return true;
71 }
72
visitDeclaration(Visit visit,TIntermDeclaration * node)73 bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit,
74 TIntermDeclaration *node)
75 {
76 // SeparateDeclarations should have already been run.
77 ASSERT(node->getSequence()->size() == 1u);
78
79 TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
80 ASSERT(declarator);
81
82 TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
83 if (!asSymbol)
84 {
85 return false;
86 }
87
88 const TType &type = declarator->getType();
89
90 // Remove all shader interface variables except outputs, i.e. uniforms, interface blocks and
91 // inputs.
92 //
93 // Imagine a situation where the VS doesn't write to a varying but the FS reads from it. This
94 // is allowed, though the value of the varying is undefined. If the varying is removed here,
95 // the situation is changed to VS not declaring the varying, but the FS reading from it, which
96 // is not allowed. That's why inactive shader outputs are not removed.
97 //
98 // Inactive fragment shader outputs can be removed though, as there is no next stage.
99 bool removeDeclaration = false;
100 const TQualifier qualifier = type.getQualifier();
101
102 if (type.isInterfaceBlock())
103 {
104 // When a member has an explicit location, interface block should not be removed.
105 // If the member or interface would be removed, GetProgramResource could not return the
106 // location.
107 if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn &&
108 type.getQualifier() != EvqPatchOut)
109 {
110 removeDeclaration =
111 !IsVariableActive(mInterfaceBlocks, type.getInterfaceBlock()->name());
112 }
113 }
114 else if (qualifier == EvqUniform)
115 {
116 removeDeclaration = !IsVariableActive(mUniforms, asSymbol->getName());
117 }
118 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
119 {
120 removeDeclaration = !IsVariableActive(mAttributes, asSymbol->getName());
121 }
122 else if (IsShaderIn(qualifier))
123 {
124 removeDeclaration = !IsVariableActive(mInputVaryings, asSymbol->getName());
125 }
126 else if (qualifier == EvqFragmentOut)
127 {
128 removeDeclaration = !IsVariableActive(mOutputVariables, asSymbol->getName());
129 }
130
131 if (removeDeclaration)
132 {
133 TIntermSequence replacement;
134
135 // If the declaration was of a struct, keep the struct declaration itself.
136 if (type.isStructSpecifier())
137 {
138 TType *structSpecifierType = new TType(type.getStruct(), true);
139 TVariable *emptyVariable = new TVariable(mSymbolTable, kEmptyImmutableString,
140 structSpecifierType, SymbolType::Empty);
141 TIntermDeclaration *declaration = new TIntermDeclaration();
142 declaration->appendDeclarator(new TIntermSymbol(emptyVariable));
143 replacement.push_back(declaration);
144 }
145
146 mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
147 std::move(replacement));
148 }
149
150 return false;
151 }
152
153 } // namespace
154
RemoveInactiveInterfaceVariables(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const std::vector<sh::ShaderVariable> & attributes,const std::vector<sh::ShaderVariable> & inputVaryings,const std::vector<sh::ShaderVariable> & outputVariables,const std::vector<sh::ShaderVariable> & uniforms,const std::vector<sh::InterfaceBlock> & interfaceBlocks)155 bool RemoveInactiveInterfaceVariables(TCompiler *compiler,
156 TIntermBlock *root,
157 TSymbolTable *symbolTable,
158 const std::vector<sh::ShaderVariable> &attributes,
159 const std::vector<sh::ShaderVariable> &inputVaryings,
160 const std::vector<sh::ShaderVariable> &outputVariables,
161 const std::vector<sh::ShaderVariable> &uniforms,
162 const std::vector<sh::InterfaceBlock> &interfaceBlocks)
163 {
164 RemoveInactiveInterfaceVariablesTraverser traverser(symbolTable, attributes, inputVaryings,
165 outputVariables, uniforms, interfaceBlocks);
166 root->traverse(&traverser);
167 return traverser.updateTree(compiler, root);
168 }
169
170 } // namespace sh
171