EmulateMultiDrawShaderBuiltins.cpp (9974B)
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 // EmulateGLDrawID is an AST traverser to convert the gl_DrawID builtin 7 // to a uniform int 8 // 9 // EmulateGLBaseVertex is an AST traverser to convert the gl_BaseVertex builtin 10 // to a uniform int 11 // 12 // EmulateGLBaseInstance is an AST traverser to convert the gl_BaseInstance builtin 13 // to a uniform int 14 // 15 16 #include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h" 17 18 #include "angle_gl.h" 19 #include "compiler/translator/StaticType.h" 20 #include "compiler/translator/Symbol.h" 21 #include "compiler/translator/SymbolTable.h" 22 #include "compiler/translator/tree_util/BuiltIn.h" 23 #include "compiler/translator/tree_util/IntermTraverse.h" 24 #include "compiler/translator/tree_util/ReplaceVariable.h" 25 #include "compiler/translator/util.h" 26 27 namespace sh 28 { 29 30 namespace 31 { 32 33 constexpr const ImmutableString kEmulatedGLDrawIDName("angle_DrawID"); 34 35 class FindGLDrawIDTraverser : public TIntermTraverser 36 { 37 public: 38 FindGLDrawIDTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {} 39 40 const TVariable *getGLDrawIDBuiltinVariable() { return mVariable; } 41 42 protected: 43 void visitSymbol(TIntermSymbol *node) override 44 { 45 if (&node->variable() == BuiltInVariable::gl_DrawID()) 46 { 47 mVariable = &node->variable(); 48 } 49 } 50 51 private: 52 const TVariable *mVariable; 53 }; 54 55 class AddBaseVertexToGLVertexIDTraverser : public TIntermTraverser 56 { 57 public: 58 AddBaseVertexToGLVertexIDTraverser() : TIntermTraverser(true, false, false) {} 59 60 protected: 61 void visitSymbol(TIntermSymbol *node) override 62 { 63 if (&node->variable() == BuiltInVariable::gl_VertexID()) 64 { 65 66 TIntermSymbol *baseVertexRef = new TIntermSymbol(BuiltInVariable::gl_BaseVertex()); 67 68 TIntermBinary *addBaseVertex = new TIntermBinary(EOpAdd, node, baseVertexRef); 69 queueReplacement(addBaseVertex, OriginalNode::BECOMES_CHILD); 70 } 71 } 72 }; 73 74 constexpr const ImmutableString kEmulatedGLBaseVertexName("angle_BaseVertex"); 75 76 class FindGLBaseVertexTraverser : public TIntermTraverser 77 { 78 public: 79 FindGLBaseVertexTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {} 80 81 const TVariable *getGLBaseVertexBuiltinVariable() { return mVariable; } 82 83 protected: 84 void visitSymbol(TIntermSymbol *node) override 85 { 86 if (&node->variable() == BuiltInVariable::gl_BaseVertex()) 87 { 88 mVariable = &node->variable(); 89 } 90 } 91 92 private: 93 const TVariable *mVariable; 94 }; 95 96 constexpr const ImmutableString kEmulatedGLBaseInstanceName("angle_BaseInstance"); 97 98 class FindGLBaseInstanceTraverser : public TIntermTraverser 99 { 100 public: 101 FindGLBaseInstanceTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {} 102 103 const TVariable *getGLBaseInstanceBuiltinVariable() { return mVariable; } 104 105 protected: 106 void visitSymbol(TIntermSymbol *node) override 107 { 108 if (&node->variable() == BuiltInVariable::gl_BaseInstance()) 109 { 110 mVariable = &node->variable(); 111 } 112 } 113 114 private: 115 const TVariable *mVariable; 116 }; 117 118 } // namespace 119 120 bool EmulateGLDrawID(TCompiler *compiler, 121 TIntermBlock *root, 122 TSymbolTable *symbolTable, 123 std::vector<sh::ShaderVariable> *uniforms, 124 bool shouldCollect) 125 { 126 FindGLDrawIDTraverser traverser; 127 root->traverse(&traverser); 128 const TVariable *builtInVariable = traverser.getGLDrawIDBuiltinVariable(); 129 if (builtInVariable) 130 { 131 const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>(); 132 const TVariable *drawID = 133 new TVariable(symbolTable, kEmulatedGLDrawIDName, type, SymbolType::AngleInternal); 134 const TIntermSymbol *drawIDSymbol = new TIntermSymbol(drawID); 135 136 // AngleInternal variables don't get collected 137 if (shouldCollect) 138 { 139 ShaderVariable uniform; 140 uniform.name = kEmulatedGLDrawIDName.data(); 141 uniform.mappedName = kEmulatedGLDrawIDName.data(); 142 uniform.type = GLVariableType(*type); 143 uniform.precision = GLVariablePrecision(*type); 144 uniform.staticUse = symbolTable->isStaticallyUsed(*builtInVariable); 145 uniform.active = true; 146 uniform.binding = type->getLayoutQualifier().binding; 147 uniform.location = type->getLayoutQualifier().location; 148 uniform.offset = type->getLayoutQualifier().offset; 149 uniform.rasterOrdered = type->getLayoutQualifier().rasterOrdered; 150 uniform.readonly = type->getMemoryQualifier().readonly; 151 uniform.writeonly = type->getMemoryQualifier().writeonly; 152 uniforms->push_back(uniform); 153 } 154 155 DeclareGlobalVariable(root, drawID); 156 if (!ReplaceVariableWithTyped(compiler, root, builtInVariable, drawIDSymbol)) 157 { 158 return false; 159 } 160 } 161 162 return true; 163 } 164 165 bool EmulateGLBaseVertexBaseInstance(TCompiler *compiler, 166 TIntermBlock *root, 167 TSymbolTable *symbolTable, 168 std::vector<sh::ShaderVariable> *uniforms, 169 bool shouldCollect, 170 bool addBaseVertexToVertexID) 171 { 172 bool addBaseVertex = false, addBaseInstance = false; 173 ShaderVariable uniformBaseVertex, uniformBaseInstance; 174 175 if (addBaseVertexToVertexID) 176 { 177 // This is a workaround for Mac AMD GPU 178 // Replace gl_VertexID with (gl_VertexID + gl_BaseVertex) 179 AddBaseVertexToGLVertexIDTraverser traverserVertexID; 180 root->traverse(&traverserVertexID); 181 if (!traverserVertexID.updateTree(compiler, root)) 182 { 183 return false; 184 } 185 } 186 187 FindGLBaseVertexTraverser traverserBaseVertex; 188 root->traverse(&traverserBaseVertex); 189 const TVariable *builtInVariableBaseVertex = 190 traverserBaseVertex.getGLBaseVertexBuiltinVariable(); 191 192 if (builtInVariableBaseVertex) 193 { 194 const TVariable *baseVertex = BuiltInVariable::angle_BaseVertex(); 195 const TType &type = baseVertex->getType(); 196 const TIntermSymbol *baseVertexSymbol = new TIntermSymbol(baseVertex); 197 198 // AngleInternal variables don't get collected 199 if (shouldCollect) 200 { 201 uniformBaseVertex.name = kEmulatedGLBaseVertexName.data(); 202 uniformBaseVertex.mappedName = kEmulatedGLBaseVertexName.data(); 203 uniformBaseVertex.type = GLVariableType(type); 204 uniformBaseVertex.precision = GLVariablePrecision(type); 205 uniformBaseVertex.staticUse = symbolTable->isStaticallyUsed(*builtInVariableBaseVertex); 206 uniformBaseVertex.active = true; 207 uniformBaseVertex.binding = type.getLayoutQualifier().binding; 208 uniformBaseVertex.location = type.getLayoutQualifier().location; 209 uniformBaseVertex.offset = type.getLayoutQualifier().offset; 210 uniformBaseVertex.rasterOrdered = type.getLayoutQualifier().rasterOrdered; 211 uniformBaseVertex.readonly = type.getMemoryQualifier().readonly; 212 uniformBaseVertex.writeonly = type.getMemoryQualifier().writeonly; 213 addBaseVertex = true; 214 } 215 216 DeclareGlobalVariable(root, baseVertex); 217 if (!ReplaceVariableWithTyped(compiler, root, builtInVariableBaseVertex, baseVertexSymbol)) 218 { 219 return false; 220 } 221 } 222 223 FindGLBaseInstanceTraverser traverserInstance; 224 root->traverse(&traverserInstance); 225 const TVariable *builtInVariableBaseInstance = 226 traverserInstance.getGLBaseInstanceBuiltinVariable(); 227 228 if (builtInVariableBaseInstance) 229 { 230 const TVariable *baseInstance = BuiltInVariable::angle_BaseInstance(); 231 const TType &type = baseInstance->getType(); 232 const TIntermSymbol *baseInstanceSymbol = new TIntermSymbol(baseInstance); 233 234 // AngleInternal variables don't get collected 235 if (shouldCollect) 236 { 237 uniformBaseInstance.name = kEmulatedGLBaseInstanceName.data(); 238 uniformBaseInstance.mappedName = kEmulatedGLBaseInstanceName.data(); 239 uniformBaseInstance.type = GLVariableType(type); 240 uniformBaseInstance.precision = GLVariablePrecision(type); 241 uniformBaseInstance.staticUse = 242 symbolTable->isStaticallyUsed(*builtInVariableBaseInstance); 243 uniformBaseInstance.active = true; 244 uniformBaseInstance.binding = type.getLayoutQualifier().binding; 245 uniformBaseInstance.location = type.getLayoutQualifier().location; 246 uniformBaseInstance.offset = type.getLayoutQualifier().offset; 247 uniformBaseInstance.rasterOrdered = type.getLayoutQualifier().rasterOrdered; 248 uniformBaseInstance.readonly = type.getMemoryQualifier().readonly; 249 uniformBaseInstance.writeonly = type.getMemoryQualifier().writeonly; 250 addBaseInstance = true; 251 } 252 253 DeclareGlobalVariable(root, baseInstance); 254 if (!ReplaceVariableWithTyped(compiler, root, builtInVariableBaseInstance, 255 baseInstanceSymbol)) 256 { 257 return false; 258 } 259 } 260 261 // Make sure the order in uniforms is the same as the traverse order 262 if (addBaseInstance) 263 { 264 uniforms->push_back(uniformBaseInstance); 265 } 266 if (addBaseVertex) 267 { 268 uniforms->push_back(uniformBaseVertex); 269 } 270 271 return true; 272 } 273 274 } // namespace sh