| File: | root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp |
| Warning: | line 422, column 9 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // | |||
| 2 | // Copyright 2018 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 | // RewriteStructSamplers: Extract samplers from structs. | |||
| 7 | // | |||
| 8 | ||||
| 9 | #include "compiler/translator/tree_ops/RewriteStructSamplers.h" | |||
| 10 | ||||
| 11 | #include "compiler/translator/ImmutableStringBuilder.h" | |||
| 12 | #include "compiler/translator/SymbolTable.h" | |||
| 13 | #include "compiler/translator/tree_util/IntermNode_util.h" | |||
| 14 | #include "compiler/translator/tree_util/IntermTraverse.h" | |||
| 15 | ||||
| 16 | namespace sh | |||
| 17 | { | |||
| 18 | namespace | |||
| 19 | { | |||
| 20 | ||||
| 21 | // Used to map one structure type to another (one where the samplers are removed). | |||
| 22 | struct StructureData | |||
| 23 | { | |||
| 24 | // The structure this was replaced with. If nullptr, it means the structure is removed (because | |||
| 25 | // it had all samplers). | |||
| 26 | const TStructure *modified; | |||
| 27 | // Indexed by the field index of original structure, to get the field index of the modified | |||
| 28 | // structure. For example: | |||
| 29 | // | |||
| 30 | // struct Original | |||
| 31 | // { | |||
| 32 | // sampler2D s1; | |||
| 33 | // vec4 f1; | |||
| 34 | // sampler2D s2; | |||
| 35 | // sampler2D s3; | |||
| 36 | // vec4 f2; | |||
| 37 | // }; | |||
| 38 | // | |||
| 39 | // struct Modified | |||
| 40 | // { | |||
| 41 | // vec4 f1; | |||
| 42 | // vec4 f2; | |||
| 43 | // }; | |||
| 44 | // | |||
| 45 | // fieldMap: | |||
| 46 | // 0 -> Invalid | |||
| 47 | // 1 -> 0 | |||
| 48 | // 2 -> Invalid | |||
| 49 | // 3 -> Invalid | |||
| 50 | // 4 -> 1 | |||
| 51 | // | |||
| 52 | TVector<int> fieldMap; | |||
| 53 | }; | |||
| 54 | ||||
| 55 | using StructureMap = angle::HashMap<const TStructure *, StructureData>; | |||
| 56 | using StructureUniformMap = angle::HashMap<const TVariable *, const TVariable *>; | |||
| 57 | using ExtractedSamplerMap = angle::HashMap<std::string, const TVariable *>; | |||
| 58 | ||||
| 59 | TIntermTyped *RewriteModifiedStructFieldSelectionExpression( | |||
| 60 | TCompiler *compiler, | |||
| 61 | TIntermBinary *node, | |||
| 62 | const StructureMap &structureMap, | |||
| 63 | const StructureUniformMap &structureUniformMap, | |||
| 64 | const ExtractedSamplerMap &extractedSamplers); | |||
| 65 | ||||
| 66 | TIntermTyped *RewriteExpressionVisitBinaryHelper(TCompiler *compiler, | |||
| 67 | TIntermBinary *node, | |||
| 68 | const StructureMap &structureMap, | |||
| 69 | const StructureUniformMap &structureUniformMap, | |||
| 70 | const ExtractedSamplerMap &extractedSamplers) | |||
| 71 | { | |||
| 72 | // Only interested in EOpIndexDirectStruct binary nodes. | |||
| 73 | if (node->getOp() != EOpIndexDirectStruct) | |||
| 74 | { | |||
| 75 | return nullptr; | |||
| 76 | } | |||
| 77 | ||||
| 78 | const TStructure *structure = node->getLeft()->getType().getStruct(); | |||
| 79 | ASSERT(structure)(structure ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 79, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 79 << "): " << "structure" )); | |||
| 80 | ||||
| 81 | // If the result of the index is not a sampler and the struct is not replaced, there's nothing | |||
| 82 | // to do. | |||
| 83 | if (!node->getType().isSampler() && structureMap.find(structure) == structureMap.end()) | |||
| 84 | { | |||
| 85 | return nullptr; | |||
| 86 | } | |||
| 87 | ||||
| 88 | // Otherwise, replace the whole expression such that: | |||
| 89 | // | |||
| 90 | // - if sampler, it's indexed with whatever indices the parent structs were indexed with, | |||
| 91 | // - otherwise, the chain of field selections is rewritten by modifying the base uniform so all | |||
| 92 | // the intermediate nodes would have the correct type (and therefore fields). | |||
| 93 | ASSERT(structureMap.find(structure) != structureMap.end())(structureMap.find(structure) != structureMap.end() ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 93, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 93 << "): " << "structureMap.find(structure) != structureMap.end()" )); | |||
| 94 | ||||
| 95 | return RewriteModifiedStructFieldSelectionExpression(compiler, node, structureMap, | |||
| 96 | structureUniformMap, extractedSamplers); | |||
| 97 | } | |||
| 98 | ||||
| 99 | // Given an expression, this traverser calculates a new expression where sampler-in-structs are | |||
| 100 | // replaced with their extracted ones, and field indices are adjusted for the rest of the fields. | |||
| 101 | // In particular, this is run on the right node of EOpIndexIndirect binary nodes, so that the | |||
| 102 | // expression in the index gets a chance to go through this transformation. | |||
| 103 | class RewriteExpressionTraverser final : public TIntermTraverser | |||
| 104 | { | |||
| 105 | public: | |||
| 106 | explicit RewriteExpressionTraverser(TCompiler *compiler, | |||
| 107 | const StructureMap &structureMap, | |||
| 108 | const StructureUniformMap &structureUniformMap, | |||
| 109 | const ExtractedSamplerMap &extractedSamplers) | |||
| 110 | : TIntermTraverser(true, false, false), | |||
| 111 | mCompiler(compiler), | |||
| 112 | mStructureMap(structureMap), | |||
| 113 | mStructureUniformMap(structureUniformMap), | |||
| 114 | mExtractedSamplers(extractedSamplers) | |||
| 115 | {} | |||
| 116 | ||||
| 117 | bool visitBinary(Visit visit, TIntermBinary *node) override | |||
| 118 | { | |||
| 119 | TIntermTyped *rewritten = RewriteExpressionVisitBinaryHelper( | |||
| 120 | mCompiler, node, mStructureMap, mStructureUniformMap, mExtractedSamplers); | |||
| 121 | ||||
| 122 | if (rewritten == nullptr) | |||
| 123 | { | |||
| 124 | return true; | |||
| 125 | } | |||
| 126 | ||||
| 127 | queueReplacement(rewritten, OriginalNode::IS_DROPPED); | |||
| 128 | ||||
| 129 | // Don't iterate as the expression is rewritten. | |||
| 130 | return false; | |||
| 131 | } | |||
| 132 | ||||
| 133 | void visitSymbol(TIntermSymbol *node) override | |||
| 134 | { | |||
| 135 | // It's impossible to reach here with a symbol that needs replacement. | |||
| 136 | // MonomorphizeUnsupportedFunctions makes sure that whole structs containing | |||
| 137 | // samplers are not passed to functions, so any instance of the struct uniform is | |||
| 138 | // necessarily indexed right away. visitBinary should have already taken care of it. | |||
| 139 | ASSERT(mStructureUniformMap.find(&node->variable()) == mStructureUniformMap.end())(mStructureUniformMap.find(&node->variable()) == mStructureUniformMap .end() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 139, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 139 << "): " << "mStructureUniformMap.find(&node->variable()) == mStructureUniformMap.end()" )); | |||
| 140 | } | |||
| 141 | ||||
| 142 | private: | |||
| 143 | TCompiler *mCompiler; | |||
| 144 | ||||
| 145 | // See RewriteStructSamplersTraverser. | |||
| 146 | const StructureMap &mStructureMap; | |||
| 147 | const StructureUniformMap &mStructureUniformMap; | |||
| 148 | const ExtractedSamplerMap &mExtractedSamplers; | |||
| 149 | }; | |||
| 150 | ||||
| 151 | // Rewrite the index of an EOpIndexIndirect expression. The root can never need replacing, because | |||
| 152 | // it cannot be a sampler itself or of a struct type. | |||
| 153 | void RewriteIndexExpression(TCompiler *compiler, | |||
| 154 | TIntermTyped *expression, | |||
| 155 | const StructureMap &structureMap, | |||
| 156 | const StructureUniformMap &structureUniformMap, | |||
| 157 | const ExtractedSamplerMap &extractedSamplers) | |||
| 158 | { | |||
| 159 | RewriteExpressionTraverser traverser(compiler, structureMap, structureUniformMap, | |||
| 160 | extractedSamplers); | |||
| 161 | expression->traverse(&traverser); | |||
| 162 | bool valid = traverser.updateTree(compiler, expression); | |||
| 163 | ASSERT(valid)(valid ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 163, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 163 << "): " << "valid")); | |||
| 164 | } | |||
| 165 | ||||
| 166 | // Given an expression such as the following: | |||
| 167 | // | |||
| 168 | // EOpIndexDirectStruct (sampler) | |||
| 169 | // / \ | |||
| 170 | // EOpIndex* field index | |||
| 171 | // / \ | |||
| 172 | // EOpIndexDirectStruct index 2 | |||
| 173 | // / \ | |||
| 174 | // EOpIndex* field index | |||
| 175 | // / \ | |||
| 176 | // EOpIndexDirectStruct index 1 | |||
| 177 | // / \ | |||
| 178 | // Uniform Struct field index | |||
| 179 | // | |||
| 180 | // produces: | |||
| 181 | // | |||
| 182 | // EOpIndex* | |||
| 183 | // / \ | |||
| 184 | // EOpIndex* index 2 | |||
| 185 | // / \ | |||
| 186 | // sampler index 1 | |||
| 187 | // | |||
| 188 | // Alternatively, if the expression is as such: | |||
| 189 | // | |||
| 190 | // EOpIndexDirectStruct | |||
| 191 | // / \ | |||
| 192 | // (modified struct type) EOpIndex* field index | |||
| 193 | // / \ | |||
| 194 | // EOpIndexDirectStruct index 2 | |||
| 195 | // / \ | |||
| 196 | // EOpIndex* field index | |||
| 197 | // / \ | |||
| 198 | // EOpIndexDirectStruct index 1 | |||
| 199 | // / \ | |||
| 200 | // Uniform Struct field index | |||
| 201 | // | |||
| 202 | // produces: | |||
| 203 | // | |||
| 204 | // EOpIndexDirectStruct | |||
| 205 | // / \ | |||
| 206 | // EOpIndex* mapped field index | |||
| 207 | // / \ | |||
| 208 | // EOpIndexDirectStruct index 2 | |||
| 209 | // / \ | |||
| 210 | // EOpIndex* mapped field index | |||
| 211 | // / \ | |||
| 212 | // EOpIndexDirectStruct index 1 | |||
| 213 | // / \ | |||
| 214 | // Uniform Struct mapped field index | |||
| 215 | // | |||
| 216 | TIntermTyped *RewriteModifiedStructFieldSelectionExpression( | |||
| 217 | TCompiler *compiler, | |||
| 218 | TIntermBinary *node, | |||
| 219 | const StructureMap &structureMap, | |||
| 220 | const StructureUniformMap &structureUniformMap, | |||
| 221 | const ExtractedSamplerMap &extractedSamplers) | |||
| 222 | { | |||
| 223 | ASSERT(node->getOp() == EOpIndexDirectStruct)(node->getOp() == EOpIndexDirectStruct ? static_cast<void >(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl ::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 223, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 223 << "): " << "node->getOp() == EOpIndexDirectStruct" )); | |||
| 224 | ||||
| 225 | const bool isSampler = node->getType().isSampler(); | |||
| 226 | ||||
| 227 | TIntermSymbol *baseUniform = nullptr; | |||
| 228 | std::string samplerName; | |||
| 229 | ||||
| 230 | TVector<TIntermBinary *> indexNodeStack; | |||
| 231 | ||||
| 232 | // Iterate once and build the name of the sampler. | |||
| 233 | TIntermBinary *iter = node; | |||
| 234 | while (baseUniform == nullptr) | |||
| 235 | { | |||
| 236 | indexNodeStack.push_back(iter); | |||
| 237 | baseUniform = iter->getLeft()->getAsSymbolNode(); | |||
| 238 | ||||
| 239 | if (isSampler) | |||
| 240 | { | |||
| 241 | if (iter->getOp() == EOpIndexDirectStruct) | |||
| 242 | { | |||
| 243 | // When indexed into a struct, get the field name instead and construct the sampler | |||
| 244 | // name. | |||
| 245 | samplerName.insert(0, iter->getIndexStructFieldName().data()); | |||
| 246 | samplerName.insert(0, "_"); | |||
| 247 | } | |||
| 248 | ||||
| 249 | if (baseUniform) | |||
| 250 | { | |||
| 251 | // If left is a symbol, we have reached the end of the chain. Use the struct name | |||
| 252 | // to finish building the name of the sampler. | |||
| 253 | samplerName.insert(0, baseUniform->variable().name().data()); | |||
| 254 | } | |||
| 255 | } | |||
| 256 | ||||
| 257 | iter = iter->getLeft()->getAsBinaryNode(); | |||
| 258 | } | |||
| 259 | ||||
| 260 | TIntermTyped *rewritten = nullptr; | |||
| 261 | ||||
| 262 | if (isSampler) | |||
| 263 | { | |||
| 264 | ASSERT(extractedSamplers.find(samplerName) != extractedSamplers.end())(extractedSamplers.find(samplerName) != extractedSamplers.end () ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 264, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 264 << "): " << "extractedSamplers.find(samplerName) != extractedSamplers.end()" )); | |||
| 265 | rewritten = new TIntermSymbol(extractedSamplers.at(samplerName)); | |||
| 266 | } | |||
| 267 | else | |||
| 268 | { | |||
| 269 | const TVariable *baseUniformVar = &baseUniform->variable(); | |||
| 270 | ASSERT(structureUniformMap.find(baseUniformVar) != structureUniformMap.end())(structureUniformMap.find(baseUniformVar) != structureUniformMap .end() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 270, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 270 << "): " << "structureUniformMap.find(baseUniformVar) != structureUniformMap.end()" )); | |||
| 271 | rewritten = new TIntermSymbol(structureUniformMap.at(baseUniformVar)); | |||
| 272 | } | |||
| 273 | ||||
| 274 | // Iterate again and build the expression from bottom up. | |||
| 275 | for (auto it = indexNodeStack.rbegin(); it != indexNodeStack.rend(); ++it) | |||
| 276 | { | |||
| 277 | TIntermBinary *indexNode = *it; | |||
| 278 | ||||
| 279 | switch (indexNode->getOp()) | |||
| 280 | { | |||
| 281 | case EOpIndexDirectStruct: | |||
| 282 | if (!isSampler) | |||
| 283 | { | |||
| 284 | // Remap the field. | |||
| 285 | const TStructure *structure = indexNode->getLeft()->getType().getStruct(); | |||
| 286 | ASSERT(structureMap.find(structure) != structureMap.end())(structureMap.find(structure) != structureMap.end() ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 286, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 286 << "): " << "structureMap.find(structure) != structureMap.end()" )); | |||
| 287 | ||||
| 288 | TIntermConstantUnion *asConstantUnion = | |||
| 289 | indexNode->getRight()->getAsConstantUnion(); | |||
| 290 | ASSERT(asConstantUnion)(asConstantUnion ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 290, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 290 << "): " << "asConstantUnion" )); | |||
| 291 | ||||
| 292 | const int fieldIndex = asConstantUnion->getIConst(0); | |||
| 293 | ASSERT(fieldIndex <(fieldIndex < static_cast<int>(structureMap.at(structure ).fieldMap.size()) ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 294, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 294 << "): " << "fieldIndex < static_cast<int>(structureMap.at(structure).fieldMap.size())" )) | |||
| 294 | static_cast<int>(structureMap.at(structure).fieldMap.size()))(fieldIndex < static_cast<int>(structureMap.at(structure ).fieldMap.size()) ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 294, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 294 << "): " << "fieldIndex < static_cast<int>(structureMap.at(structure).fieldMap.size())" )); | |||
| 295 | ||||
| 296 | const int mappedFieldIndex = structureMap.at(structure).fieldMap[fieldIndex]; | |||
| 297 | ||||
| 298 | rewritten = new TIntermBinary(EOpIndexDirectStruct, rewritten, | |||
| 299 | CreateIndexNode(mappedFieldIndex)); | |||
| 300 | } | |||
| 301 | break; | |||
| 302 | ||||
| 303 | case EOpIndexDirect: | |||
| 304 | rewritten = new TIntermBinary(EOpIndexDirect, rewritten, indexNode->getRight()); | |||
| 305 | break; | |||
| 306 | ||||
| 307 | case EOpIndexIndirect: | |||
| 308 | { | |||
| 309 | // Run RewriteExpressionTraverser on the right node. It may itself be an expression | |||
| 310 | // with a sampler inside that needs to be rewritten, or simply use a field of a | |||
| 311 | // struct that's remapped. | |||
| 312 | TIntermTyped *indexExpression = indexNode->getRight(); | |||
| 313 | RewriteIndexExpression(compiler, indexExpression, structureMap, structureUniformMap, | |||
| 314 | extractedSamplers); | |||
| 315 | rewritten = new TIntermBinary(EOpIndexIndirect, rewritten, indexExpression); | |||
| 316 | break; | |||
| 317 | } | |||
| 318 | ||||
| 319 | default: | |||
| 320 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 320, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 320 << ")"; } while (0); | |||
| 321 | break; | |||
| 322 | } | |||
| 323 | } | |||
| 324 | ||||
| 325 | return rewritten; | |||
| 326 | } | |||
| 327 | ||||
| 328 | class RewriteStructSamplersTraverser final : public TIntermTraverser | |||
| 329 | { | |||
| 330 | public: | |||
| 331 | explicit RewriteStructSamplersTraverser(TCompiler *compiler, TSymbolTable *symbolTable) | |||
| 332 | : TIntermTraverser(true, false, false, symbolTable), | |||
| 333 | mCompiler(compiler), | |||
| 334 | mRemovedUniformsCount(0) | |||
| 335 | {} | |||
| 336 | ||||
| 337 | int removedUniformsCount() const { return mRemovedUniformsCount; } | |||
| 338 | ||||
| 339 | // Each struct sampler declaration is stripped of its samplers. New uniforms are added for each | |||
| 340 | // stripped struct sampler. | |||
| 341 | bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override | |||
| 342 | { | |||
| 343 | if (!mInGlobalScope) | |||
| ||||
| 344 | { | |||
| 345 | return true; | |||
| 346 | } | |||
| 347 | ||||
| 348 | const TIntermSequence &sequence = *(decl->getSequence()); | |||
| 349 | TIntermTyped *declarator = sequence.front()->getAsTyped(); | |||
| 350 | const TType &type = declarator->getType(); | |||
| 351 | ||||
| 352 | if (!type.isStructureContainingSamplers()) | |||
| 353 | { | |||
| 354 | return false; | |||
| 355 | } | |||
| 356 | ||||
| 357 | TIntermSequence newSequence; | |||
| 358 | ||||
| 359 | if (type.isStructSpecifier()) | |||
| 360 | { | |||
| 361 | // If this is just a struct definition (not a uniform variable declaration of a | |||
| 362 | // struct type), just remove the samplers. They are not instantiated yet. | |||
| 363 | const TStructure *structure = type.getStruct(); | |||
| 364 | ASSERT(structure && mStructureMap.find(structure) == mStructureMap.end())(structure && mStructureMap.find(structure) == mStructureMap .end() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 364, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 364 << "): " << "structure && mStructureMap.find(structure) == mStructureMap.end()" )); | |||
| 365 | ||||
| 366 | stripStructSpecifierSamplers(structure, &newSequence); | |||
| 367 | } | |||
| 368 | else | |||
| 369 | { | |||
| 370 | const TStructure *structure = type.getStruct(); | |||
| 371 | ||||
| 372 | // If the structure is defined at the same time, create the mapping to the stripped | |||
| 373 | // version first. | |||
| 374 | if (mStructureMap.find(structure) == mStructureMap.end()) | |||
| 375 | { | |||
| 376 | stripStructSpecifierSamplers(structure, &newSequence); | |||
| 377 | } | |||
| 378 | ||||
| 379 | // Then, extract the samplers from the struct and create global-scope variables instead. | |||
| 380 | TIntermSymbol *asSymbol = declarator->getAsSymbolNode(); | |||
| 381 | ASSERT(asSymbol)(asSymbol ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 381, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 381 << "): " << "asSymbol" )); | |||
| 382 | const TVariable &variable = asSymbol->variable(); | |||
| 383 | ASSERT(variable.symbolType() != SymbolType::Empty)(variable.symbolType() != SymbolType::Empty ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 383, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 383 << "): " << "variable.symbolType() != SymbolType::Empty" )); | |||
| 384 | ||||
| 385 | extractStructSamplerUniforms(variable, structure, &newSequence); | |||
| 386 | } | |||
| 387 | ||||
| 388 | mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, | |||
| 389 | std::move(newSequence)); | |||
| 390 | ||||
| 391 | return false; | |||
| 392 | } | |||
| 393 | ||||
| 394 | // Same implementation as in RewriteExpressionTraverser. That traverser cannot replace root. | |||
| 395 | bool visitBinary(Visit visit, TIntermBinary *node) override | |||
| 396 | { | |||
| 397 | TIntermTyped *rewritten = RewriteExpressionVisitBinaryHelper( | |||
| 398 | mCompiler, node, mStructureMap, mStructureUniformMap, mExtractedSamplers); | |||
| 399 | ||||
| 400 | if (rewritten == nullptr) | |||
| 401 | { | |||
| 402 | return true; | |||
| 403 | } | |||
| 404 | ||||
| 405 | queueReplacement(rewritten, OriginalNode::IS_DROPPED); | |||
| 406 | ||||
| 407 | // Don't iterate as the expression is rewritten. | |||
| 408 | return false; | |||
| 409 | } | |||
| 410 | ||||
| 411 | // Same implementation as in RewriteExpressionTraverser. That traverser cannot replace root. | |||
| 412 | void visitSymbol(TIntermSymbol *node) override | |||
| 413 | { | |||
| 414 | ASSERT(mStructureUniformMap.find(&node->variable()) == mStructureUniformMap.end())(mStructureUniformMap.find(&node->variable()) == mStructureUniformMap .end() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 414, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 414 << "): " << "mStructureUniformMap.find(&node->variable()) == mStructureUniformMap.end()" )); | |||
| 415 | } | |||
| 416 | ||||
| 417 | private: | |||
| 418 | // Removes all samplers from a struct specifier. | |||
| 419 | void stripStructSpecifierSamplers(const TStructure *structure, TIntermSequence *newSequence) | |||
| 420 | { | |||
| 421 | TFieldList *newFieldList = new TFieldList; | |||
| 422 | ASSERT(structure->containsSamplers())(structure->containsSamplers() ? static_cast<void>(0 ) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 422, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 422 << "): " << "structure->containsSamplers()" )); | |||
| ||||
| 423 | ||||
| 424 | // Add this struct to the struct map | |||
| 425 | ASSERT(mStructureMap.find(structure) == mStructureMap.end())(mStructureMap.find(structure) == mStructureMap.end() ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 425, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 425 << "): " << "mStructureMap.find(structure) == mStructureMap.end()" )); | |||
| 426 | StructureData *modifiedData = &mStructureMap[structure]; | |||
| 427 | ||||
| 428 | modifiedData->modified = nullptr; | |||
| 429 | modifiedData->fieldMap.resize(structure->fields().size(), std::numeric_limits<int>::max()); | |||
| 430 | ||||
| 431 | for (size_t fieldIndex = 0; fieldIndex < structure->fields().size(); ++fieldIndex) | |||
| 432 | { | |||
| 433 | const TField *field = structure->fields()[fieldIndex]; | |||
| 434 | const TType &fieldType = *field->type(); | |||
| 435 | ||||
| 436 | // If the field is a sampler, or a struct that's entirely removed, skip it. | |||
| 437 | if (!fieldType.isSampler() && !isRemovedStructType(fieldType)) | |||
| 438 | { | |||
| 439 | TType *newType = nullptr; | |||
| 440 | ||||
| 441 | // Otherwise, if it's a struct that's replaced, create a new field of the replaced | |||
| 442 | // type. | |||
| 443 | if (fieldType.isStructureContainingSamplers()) | |||
| 444 | { | |||
| 445 | const TStructure *fieldStruct = fieldType.getStruct(); | |||
| 446 | ASSERT(mStructureMap.find(fieldStruct) != mStructureMap.end())(mStructureMap.find(fieldStruct) != mStructureMap.end() ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 446, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 446 << "): " << "mStructureMap.find(fieldStruct) != mStructureMap.end()" )); | |||
| 447 | ||||
| 448 | const TStructure *modifiedStruct = mStructureMap[fieldStruct].modified; | |||
| 449 | ASSERT(modifiedStruct)(modifiedStruct ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 449, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 449 << "): " << "modifiedStruct" )); | |||
| 450 | ||||
| 451 | newType = new TType(modifiedStruct, true); | |||
| 452 | if (fieldType.isArray()) | |||
| 453 | { | |||
| 454 | newType->makeArrays(fieldType.getArraySizes()); | |||
| 455 | } | |||
| 456 | } | |||
| 457 | else | |||
| 458 | { | |||
| 459 | // If not, duplicate the field as is. | |||
| 460 | newType = new TType(fieldType); | |||
| 461 | } | |||
| 462 | ||||
| 463 | // Record the mapping of the field indices, so future EOpIndexDirectStruct's into | |||
| 464 | // this struct can be fixed up. | |||
| 465 | modifiedData->fieldMap[fieldIndex] = static_cast<int>(newFieldList->size()); | |||
| 466 | ||||
| 467 | TField *newField = | |||
| 468 | new TField(newType, field->name(), field->line(), field->symbolType()); | |||
| 469 | newFieldList->push_back(newField); | |||
| 470 | } | |||
| 471 | } | |||
| 472 | ||||
| 473 | // Prune empty structs. | |||
| 474 | if (newFieldList->empty()) | |||
| 475 | { | |||
| 476 | return; | |||
| 477 | } | |||
| 478 | ||||
| 479 | // Declare a new struct with the same name and the new fields. | |||
| 480 | modifiedData->modified = | |||
| 481 | new TStructure(mSymbolTable, structure->name(), newFieldList, structure->symbolType()); | |||
| 482 | TType *newStructType = new TType(modifiedData->modified, true); | |||
| 483 | TVariable *newStructVar = | |||
| 484 | new TVariable(mSymbolTable, kEmptyImmutableString, newStructType, SymbolType::Empty); | |||
| 485 | TIntermSymbol *newStructRef = new TIntermSymbol(newStructVar); | |||
| 486 | ||||
| 487 | TIntermDeclaration *structDecl = new TIntermDeclaration; | |||
| 488 | structDecl->appendDeclarator(newStructRef); | |||
| 489 | ||||
| 490 | newSequence->push_back(structDecl); | |||
| 491 | } | |||
| 492 | ||||
| 493 | // Returns true if the type is a struct that was removed because we extracted all the members. | |||
| 494 | bool isRemovedStructType(const TType &type) const | |||
| 495 | { | |||
| 496 | const TStructure *structure = type.getStruct(); | |||
| 497 | if (structure == nullptr) | |||
| 498 | { | |||
| 499 | // Not a struct | |||
| 500 | return false; | |||
| 501 | } | |||
| 502 | ||||
| 503 | // A struct is removed if it is in the map, but doesn't have a replacement struct. | |||
| 504 | auto iter = mStructureMap.find(structure); | |||
| 505 | return iter != mStructureMap.end() && iter->second.modified == nullptr; | |||
| 506 | } | |||
| 507 | ||||
| 508 | // Removes samplers from struct uniforms. For each sampler removed also adds a new globally | |||
| 509 | // defined sampler uniform. | |||
| 510 | void extractStructSamplerUniforms(const TVariable &variable, | |||
| 511 | const TStructure *structure, | |||
| 512 | TIntermSequence *newSequence) | |||
| 513 | { | |||
| 514 | ASSERT(structure->containsSamplers())(structure->containsSamplers() ? static_cast<void>(0 ) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 514, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 514 << "): " << "structure->containsSamplers()" )); | |||
| 515 | ASSERT(mStructureMap.find(structure) != mStructureMap.end())(mStructureMap.find(structure) != mStructureMap.end() ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 515, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 515 << "): " << "mStructureMap.find(structure) != mStructureMap.end()" )); | |||
| 516 | ||||
| 517 | const TType &type = variable.getType(); | |||
| 518 | enterArray(type); | |||
| 519 | ||||
| 520 | for (const TField *field : structure->fields()) | |||
| 521 | { | |||
| 522 | extractFieldSamplers(variable.name().data(), field, newSequence); | |||
| 523 | } | |||
| 524 | ||||
| 525 | // If there's a replacement structure (because there are non-sampler fields in the struct), | |||
| 526 | // add a declaration with that type. | |||
| 527 | const TStructure *modified = mStructureMap[structure].modified; | |||
| 528 | if (modified != nullptr) | |||
| 529 | { | |||
| 530 | TType *newType = new TType(modified, false); | |||
| 531 | if (type.isArray()) | |||
| 532 | { | |||
| 533 | newType->makeArrays(type.getArraySizes()); | |||
| 534 | } | |||
| 535 | newType->setQualifier(EvqUniform); | |||
| 536 | const TVariable *newVariable = | |||
| 537 | new TVariable(mSymbolTable, variable.name(), newType, variable.symbolType()); | |||
| 538 | ||||
| 539 | TIntermDeclaration *newDecl = new TIntermDeclaration(); | |||
| 540 | newDecl->appendDeclarator(new TIntermSymbol(newVariable)); | |||
| 541 | ||||
| 542 | newSequence->push_back(newDecl); | |||
| 543 | ||||
| 544 | ASSERT(mStructureUniformMap.find(&variable) == mStructureUniformMap.end())(mStructureUniformMap.find(&variable) == mStructureUniformMap .end() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 544, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 544 << "): " << "mStructureUniformMap.find(&variable) == mStructureUniformMap.end()" )); | |||
| 545 | mStructureUniformMap[&variable] = newVariable; | |||
| 546 | } | |||
| 547 | else | |||
| 548 | { | |||
| 549 | mRemovedUniformsCount++; | |||
| 550 | } | |||
| 551 | ||||
| 552 | exitArray(type); | |||
| 553 | } | |||
| 554 | ||||
| 555 | // Extracts samplers from a field of a struct. Works with nested structs and arrays. | |||
| 556 | void extractFieldSamplers(const std::string &prefix, | |||
| 557 | const TField *field, | |||
| 558 | TIntermSequence *newSequence) | |||
| 559 | { | |||
| 560 | const TType &fieldType = *field->type(); | |||
| 561 | if (fieldType.isSampler() || fieldType.isStructureContainingSamplers()) | |||
| 562 | { | |||
| 563 | std::string newPrefix = prefix + "_" + field->name().data(); | |||
| 564 | ||||
| 565 | if (fieldType.isSampler()) | |||
| 566 | { | |||
| 567 | extractSampler(newPrefix, fieldType, newSequence); | |||
| 568 | } | |||
| 569 | else | |||
| 570 | { | |||
| 571 | enterArray(fieldType); | |||
| 572 | const TStructure *structure = fieldType.getStruct(); | |||
| 573 | for (const TField *nestedField : structure->fields()) | |||
| 574 | { | |||
| 575 | extractFieldSamplers(newPrefix, nestedField, newSequence); | |||
| 576 | } | |||
| 577 | exitArray(fieldType); | |||
| 578 | } | |||
| 579 | } | |||
| 580 | } | |||
| 581 | ||||
| 582 | void GenerateArraySizesFromStack(TVector<unsigned int> *sizesOut) | |||
| 583 | { | |||
| 584 | sizesOut->reserve(mArraySizeStack.size()); | |||
| 585 | ||||
| 586 | for (auto it = mArraySizeStack.rbegin(); it != mArraySizeStack.rend(); ++it) | |||
| 587 | { | |||
| 588 | sizesOut->push_back(*it); | |||
| 589 | } | |||
| 590 | } | |||
| 591 | ||||
| 592 | // Extracts a sampler from a struct. Declares the new extracted sampler. | |||
| 593 | void extractSampler(const std::string &newName, | |||
| 594 | const TType &fieldType, | |||
| 595 | TIntermSequence *newSequence) | |||
| 596 | { | |||
| 597 | ASSERT(fieldType.isSampler())(fieldType.isSampler() ? static_cast<void>(0) : (!((::gl ::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 597, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 597 << "): " << "fieldType.isSampler()" )); | |||
| 598 | ||||
| 599 | TType *newType = new TType(fieldType); | |||
| 600 | ||||
| 601 | // Add array dimensions accumulated so far due to struct arrays. Note that to support | |||
| 602 | // nested arrays, mArraySizeStack has the outermost size in the front. |makeArrays| thus | |||
| 603 | // expects this in reverse order. | |||
| 604 | TVector<unsigned int> parentArraySizes; | |||
| 605 | GenerateArraySizesFromStack(&parentArraySizes); | |||
| 606 | newType->makeArrays(parentArraySizes); | |||
| 607 | ||||
| 608 | ImmutableStringBuilder nameBuilder(newName.size() + 1); | |||
| 609 | nameBuilder << newName; | |||
| 610 | ||||
| 611 | newType->setQualifier(EvqUniform); | |||
| 612 | TVariable *newVariable = | |||
| 613 | new TVariable(mSymbolTable, nameBuilder, newType, SymbolType::AngleInternal); | |||
| 614 | TIntermSymbol *newSymbol = new TIntermSymbol(newVariable); | |||
| 615 | ||||
| 616 | TIntermDeclaration *samplerDecl = new TIntermDeclaration; | |||
| 617 | samplerDecl->appendDeclarator(newSymbol); | |||
| 618 | ||||
| 619 | newSequence->push_back(samplerDecl); | |||
| 620 | ||||
| 621 | // TODO: Use a temp name instead of generating a name as currently done. There is no | |||
| 622 | // guarantee that these generated names cannot clash. Create a mapping from the previous | |||
| 623 | // name to the name assigned to the temp variable so ShaderVariable::mappedName can be | |||
| 624 | // updated post-transformation. http://anglebug.com/4301 | |||
| 625 | ASSERT(mExtractedSamplers.find(newName) == mExtractedSamplers.end())(mExtractedSamplers.find(newName) == mExtractedSamplers.end() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" , __FUNCTION__, 625, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp" << ":" << 625 << "): " << "mExtractedSamplers.find(newName) == mExtractedSamplers.end()" )); | |||
| 626 | mExtractedSamplers[newName] = newVariable; | |||
| 627 | } | |||
| 628 | ||||
| 629 | void enterArray(const TType &arrayType) | |||
| 630 | { | |||
| 631 | const TSpan<const unsigned int> &arraySizes = arrayType.getArraySizes(); | |||
| 632 | for (auto it = arraySizes.rbegin(); it != arraySizes.rend(); ++it) | |||
| 633 | { | |||
| 634 | unsigned int arraySize = *it; | |||
| 635 | mArraySizeStack.push_back(arraySize); | |||
| 636 | } | |||
| 637 | } | |||
| 638 | ||||
| 639 | void exitArray(const TType &arrayType) | |||
| 640 | { | |||
| 641 | mArraySizeStack.resize(mArraySizeStack.size() - arrayType.getNumArraySizes()); | |||
| 642 | } | |||
| 643 | ||||
| 644 | TCompiler *mCompiler; | |||
| 645 | int mRemovedUniformsCount; | |||
| 646 | ||||
| 647 | // Map structures with samplers to ones that have their samplers removed. | |||
| 648 | StructureMap mStructureMap; | |||
| 649 | ||||
| 650 | // Map uniform variables of structure type that are replaced with another variable. | |||
| 651 | StructureUniformMap mStructureUniformMap; | |||
| 652 | ||||
| 653 | // Map a constructed sampler name to its variable. Used to replace an expression that uses this | |||
| 654 | // sampler with the extracted one. | |||
| 655 | ExtractedSamplerMap mExtractedSamplers; | |||
| 656 | ||||
| 657 | // A stack of array sizes. Used to figure out the array dimensions of the extracted sampler, | |||
| 658 | // for example when it's nested in an array of structs in an array of structs. | |||
| 659 | TVector<unsigned int> mArraySizeStack; | |||
| 660 | }; | |||
| 661 | } // anonymous namespace | |||
| 662 | ||||
| 663 | bool RewriteStructSamplers(TCompiler *compiler, | |||
| 664 | TIntermBlock *root, | |||
| 665 | TSymbolTable *symbolTable, | |||
| 666 | int *removedUniformsCountOut) | |||
| 667 | { | |||
| 668 | RewriteStructSamplersTraverser traverser(compiler, symbolTable); | |||
| 669 | root->traverse(&traverser); | |||
| 670 | *removedUniformsCountOut = traverser.removedUniformsCount(); | |||
| 671 | return traverser.updateTree(compiler, root); | |||
| 672 | } | |||
| 673 | } // namespace sh |