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 const std::vector<sh::ShaderVariable> &attributes,
28 const std::vector<sh::ShaderVariable> &inputVaryings,
29 const std::vector<sh::ShaderVariable> &outputVariables,
30 const std::vector<sh::ShaderVariable> &uniforms,
31 const std::vector<sh::InterfaceBlock> &interfaceBlocks);
32
33 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
34
35 private:
36 const std::vector<sh::ShaderVariable> &mAttributes;
37 const std::vector<sh::ShaderVariable> &mInputVaryings;
38 const std::vector<sh::ShaderVariable> &mOutputVariables;
39 const std::vector<sh::ShaderVariable> &mUniforms;
40 const std::vector<sh::InterfaceBlock> &mInterfaceBlocks;
41 };
42
RemoveInactiveInterfaceVariablesTraverser(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)43 RemoveInactiveInterfaceVariablesTraverser::RemoveInactiveInterfaceVariablesTraverser(
44 const std::vector<sh::ShaderVariable> &attributes,
45 const std::vector<sh::ShaderVariable> &inputVaryings,
46 const std::vector<sh::ShaderVariable> &outputVariables,
47 const std::vector<sh::ShaderVariable> &uniforms,
48 const std::vector<sh::InterfaceBlock> &interfaceBlocks)
49 : TIntermTraverser(true, false, false),
50 mAttributes(attributes),
51 mInputVaryings(inputVaryings),
52 mOutputVariables(outputVariables),
53 mUniforms(uniforms),
54 mInterfaceBlocks(interfaceBlocks)
55 {}
56
57 template <typename Variable>
IsVariableActive(const std::vector<Variable> & mVars,const ImmutableString & name)58 bool IsVariableActive(const std::vector<Variable> &mVars, const ImmutableString &name)
59 {
60 for (const Variable &var : mVars)
61 {
62 if (name == var.name)
63 {
64 return var.active;
65 }
66 }
67 UNREACHABLE();
68 return true;
69 }
70
visitDeclaration(Visit visit,TIntermDeclaration * node)71 bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit,
72 TIntermDeclaration *node)
73 {
74 // SeparateDeclarations should have already been run.
75 ASSERT(node->getSequence()->size() == 1u);
76
77 TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
78 ASSERT(declarator);
79
80 TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
81 if (!asSymbol)
82 {
83 return false;
84 }
85
86 const TType &type = declarator->getType();
87
88 // Remove all shader interface variables except outputs, i.e. uniforms, interface blocks and
89 // inputs.
90 //
91 // Imagine a situation where the VS doesn't write to a varying but the FS reads from it. This
92 // is allowed, though the value of the varying is undefined. If the varying is removed here,
93 // the situation is changed to VS not declaring the varying, but the FS reading from it, which
94 // is not allowed. That's why inactive shader outputs are not removed.
95 //
96 // Inactive fragment shader outputs can be removed though, as there is no next stage.
97 bool removeDeclaration = false;
98 const TQualifier qualifier = type.getQualifier();
99
100 if (type.isInterfaceBlock())
101 {
102 removeDeclaration = !IsVariableActive(mInterfaceBlocks, type.getInterfaceBlock()->name());
103 }
104 else if (qualifier == EvqUniform)
105 {
106 removeDeclaration = !IsVariableActive(mUniforms, asSymbol->getName());
107 }
108 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
109 {
110 removeDeclaration = !IsVariableActive(mAttributes, asSymbol->getName());
111 }
112 else if (IsShaderIn(qualifier))
113 {
114 removeDeclaration = !IsVariableActive(mInputVaryings, asSymbol->getName());
115 }
116 else if (qualifier == EvqFragmentOut)
117 {
118 removeDeclaration = !IsVariableActive(mOutputVariables, asSymbol->getName());
119 }
120
121 if (removeDeclaration)
122 {
123 TIntermSequence emptySequence;
124 mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, emptySequence);
125 }
126
127 return false;
128 }
129
130 } // namespace
131
RemoveInactiveInterfaceVariables(TCompiler * compiler,TIntermBlock * root,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)132 bool RemoveInactiveInterfaceVariables(TCompiler *compiler,
133 TIntermBlock *root,
134 const std::vector<sh::ShaderVariable> &attributes,
135 const std::vector<sh::ShaderVariable> &inputVaryings,
136 const std::vector<sh::ShaderVariable> &outputVariables,
137 const std::vector<sh::ShaderVariable> &uniforms,
138 const std::vector<sh::InterfaceBlock> &interfaceBlocks)
139 {
140 RemoveInactiveInterfaceVariablesTraverser traverser(attributes, inputVaryings, outputVariables,
141 uniforms, interfaceBlocks);
142 root->traverse(&traverser);
143 return traverser.updateTree(compiler, root);
144 }
145
146 } // namespace sh
147