1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef sw_SpirvShader_hpp 16 #define sw_SpirvShader_hpp 17 18 #include "SamplerCore.hpp" 19 #include "ShaderCore.hpp" 20 #include "SpirvBinary.hpp" 21 #include "SpirvID.hpp" 22 #include "Device/Config.hpp" 23 #include "Device/Sampler.hpp" 24 #include "System/Debug.hpp" 25 #include "System/Math.hpp" 26 #include "System/Types.hpp" 27 #include "Vulkan/VkConfig.hpp" 28 #include "Vulkan/VkDescriptorSet.hpp" 29 30 #define SPV_ENABLE_UTILITY_CODE 31 #include <spirv/unified1/spirv.hpp> 32 33 #include <array> 34 #include <atomic> 35 #include <cstdint> 36 #include <cstring> 37 #include <deque> 38 #include <functional> 39 #include <memory> 40 #include <string> 41 #include <type_traits> 42 #include <unordered_map> 43 #include <unordered_set> 44 #include <vector> 45 46 #undef Yield // b/127920555 47 48 namespace vk { 49 50 class Device; 51 class PipelineLayout; 52 class ImageView; 53 class Sampler; 54 class RenderPass; 55 struct SampledImageDescriptor; 56 struct SamplerState; 57 58 } // namespace vk 59 60 namespace sw { 61 62 // Forward declarations. 63 class SpirvRoutine; 64 65 // Incrementally constructed complex bundle of rvalues 66 // Effectively a restricted vector, supporting only: 67 // - allocation to a (runtime-known) fixed component count 68 // - in-place construction of elements 69 // - const operator[] 70 class Intermediate 71 { 72 public: Intermediate(uint32_t componentCount)73 Intermediate(uint32_t componentCount) 74 : componentCount(componentCount) 75 , scalar(new rr::Value *[componentCount]) 76 { 77 for(auto i = 0u; i < componentCount; i++) { scalar[i] = nullptr; } 78 } 79 ~Intermediate()80 ~Intermediate() 81 { 82 delete[] scalar; 83 } 84 85 // TypeHint is used as a hint for rr::PrintValue::Ty<sw::Intermediate> to 86 // decide the format used to print the intermediate data. 87 enum class TypeHint 88 { 89 Float, 90 Int, 91 UInt 92 }; 93 move(uint32_t i,RValue<SIMD::Float> && scalar)94 void move(uint32_t i, RValue<SIMD::Float> &&scalar) { emplace(i, scalar.value(), TypeHint::Float); } move(uint32_t i,RValue<SIMD::Int> && scalar)95 void move(uint32_t i, RValue<SIMD::Int> &&scalar) { emplace(i, scalar.value(), TypeHint::Int); } move(uint32_t i,RValue<SIMD::UInt> && scalar)96 void move(uint32_t i, RValue<SIMD::UInt> &&scalar) { emplace(i, scalar.value(), TypeHint::UInt); } 97 move(uint32_t i,const RValue<SIMD::Float> & scalar)98 void move(uint32_t i, const RValue<SIMD::Float> &scalar) { emplace(i, scalar.value(), TypeHint::Float); } move(uint32_t i,const RValue<SIMD::Int> & scalar)99 void move(uint32_t i, const RValue<SIMD::Int> &scalar) { emplace(i, scalar.value(), TypeHint::Int); } move(uint32_t i,const RValue<SIMD::UInt> & scalar)100 void move(uint32_t i, const RValue<SIMD::UInt> &scalar) { emplace(i, scalar.value(), TypeHint::UInt); } 101 102 // Value retrieval functions. Float(uint32_t i) const103 RValue<SIMD::Float> Float(uint32_t i) const 104 { 105 ASSERT(i < componentCount); 106 ASSERT(scalar[i] != nullptr); 107 RR_PRINT_ONLY(typeHint = TypeHint::Float;) 108 return As<SIMD::Float>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Float>(scalar) 109 } 110 Int(uint32_t i) const111 RValue<SIMD::Int> Int(uint32_t i) const 112 { 113 ASSERT(i < componentCount); 114 ASSERT(scalar[i] != nullptr); 115 RR_PRINT_ONLY(typeHint = TypeHint::Int;) 116 return As<SIMD::Int>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Int>(scalar) 117 } 118 UInt(uint32_t i) const119 RValue<SIMD::UInt> UInt(uint32_t i) const 120 { 121 ASSERT(i < componentCount); 122 ASSERT(scalar[i] != nullptr); 123 RR_PRINT_ONLY(typeHint = TypeHint::UInt;) 124 return As<SIMD::UInt>(scalar[i]); // TODO(b/128539387): RValue<SIMD::UInt>(scalar) 125 } 126 127 // No copy/move construction or assignment 128 Intermediate(const Intermediate &) = delete; 129 Intermediate(Intermediate &&) = delete; 130 Intermediate &operator=(const Intermediate &) = delete; 131 Intermediate &operator=(Intermediate &&) = delete; 132 133 const uint32_t componentCount; 134 135 private: emplace(uint32_t i,rr::Value * value,TypeHint type)136 void emplace(uint32_t i, rr::Value *value, TypeHint type) 137 { 138 ASSERT(i < componentCount); 139 ASSERT(scalar[i] == nullptr); 140 scalar[i] = value; 141 RR_PRINT_ONLY(typeHint = type;) 142 } 143 144 rr::Value **const scalar; 145 146 #ifdef ENABLE_RR_PRINT 147 friend struct rr::PrintValue::Ty<sw::Intermediate>; 148 mutable TypeHint typeHint = TypeHint::Float; 149 #endif // ENABLE_RR_PRINT 150 }; 151 152 // The Spirv class parses a SPIR-V binary and provides utilities for retrieving 153 // information about instructions, objects, types, etc. 154 class Spirv 155 { 156 public: 157 Spirv(VkShaderStageFlagBits stage, 158 const char *entryPointName, 159 const SpirvBinary &insns); 160 161 ~Spirv(); 162 163 SpirvBinary insns; 164 165 class Type; 166 class Object; 167 168 // Pseudo-iterator over SPIR-V instructions, designed to support range-based-for. 169 class InsnIterator 170 { 171 public: 172 InsnIterator() = default; 173 InsnIterator(const InsnIterator &other) = default; 174 InsnIterator &operator=(const InsnIterator &other) = default; 175 InsnIterator(SpirvBinary::const_iterator iter)176 explicit InsnIterator(SpirvBinary::const_iterator iter) 177 : iter{ iter } 178 { 179 } 180 opcode() const181 spv::Op opcode() const 182 { 183 return static_cast<spv::Op>(*iter & spv::OpCodeMask); 184 } 185 wordCount() const186 uint32_t wordCount() const 187 { 188 return *iter >> spv::WordCountShift; 189 } 190 word(uint32_t n) const191 uint32_t word(uint32_t n) const 192 { 193 ASSERT(n < wordCount()); 194 return iter[n]; 195 } 196 data() const197 const uint32_t *data() const 198 { 199 return &iter[0]; 200 } 201 string(uint32_t n) const202 const char *string(uint32_t n) const 203 { 204 return reinterpret_cast<const char *>(&iter[n]); 205 } 206 207 // Returns the number of whole-words that a string literal starting at 208 // word n consumes. If the end of the intruction is reached before the 209 // null-terminator is found, then the function DABORT()s and 0 is 210 // returned. stringSizeInWords(uint32_t n) const211 uint32_t stringSizeInWords(uint32_t n) const 212 { 213 uint32_t c = wordCount(); 214 for(uint32_t i = n; n < c; i++) 215 { 216 const char *s = string(i); 217 // SPIR-V spec 2.2.1. Instructions: 218 // A string is interpreted as a nul-terminated stream of 219 // characters. The character set is Unicode in the UTF-8 220 // encoding scheme. The UTF-8 octets (8-bit bytes) are packed 221 // four per word, following the little-endian convention (i.e., 222 // the first octet is in the lowest-order 8 bits of the word). 223 // The final word contains the string's nul-termination 224 // character (0), and all contents past the end of the string in 225 // the final word are padded with 0. 226 if(s[3] == 0) 227 { 228 return 1 + i - n; 229 } 230 } 231 DABORT("SPIR-V string literal was not null-terminated"); 232 return 0; 233 } 234 hasResultAndType() const235 bool hasResultAndType() const 236 { 237 bool hasResult = false, hasResultType = false; 238 spv::HasResultAndType(opcode(), &hasResult, &hasResultType); 239 240 return hasResultType; 241 } 242 resultTypeId() const243 SpirvID<Type> resultTypeId() const 244 { 245 ASSERT(hasResultAndType()); 246 return word(1); 247 } 248 resultId() const249 SpirvID<Object> resultId() const 250 { 251 ASSERT(hasResultAndType()); 252 return word(2); 253 } 254 distanceFrom(const InsnIterator & other) const255 uint32_t distanceFrom(const InsnIterator &other) const 256 { 257 return static_cast<uint32_t>(iter - other.iter); 258 } 259 operator ==(const InsnIterator & other) const260 bool operator==(const InsnIterator &other) const 261 { 262 return iter == other.iter; 263 } 264 operator !=(const InsnIterator & other) const265 bool operator!=(const InsnIterator &other) const 266 { 267 return iter != other.iter; 268 } 269 operator *() const270 InsnIterator operator*() const 271 { 272 return *this; 273 } 274 operator ++()275 InsnIterator &operator++() 276 { 277 iter += wordCount(); 278 return *this; 279 } 280 operator ++(int)281 InsnIterator const operator++(int) 282 { 283 InsnIterator ret{ *this }; 284 iter += wordCount(); 285 return ret; 286 } 287 288 private: 289 SpirvBinary::const_iterator iter; 290 }; 291 292 // Range-based-for interface begin() const293 InsnIterator begin() const 294 { 295 // Skip over the header words 296 return InsnIterator{ insns.cbegin() + 5 }; 297 } 298 end() const299 InsnIterator end() const 300 { 301 return InsnIterator{ insns.cend() }; 302 } 303 304 // A range of contiguous instruction words. 305 struct Span 306 { Spansw::Spirv::Span307 Span(const InsnIterator &insn, uint32_t offset, uint32_t size) 308 : insn(insn) 309 , offset(offset) 310 , wordCount(size) 311 {} 312 operator []sw::Spirv::Span313 uint32_t operator[](uint32_t index) const 314 { 315 ASSERT(index < wordCount); 316 return insn.word(offset + index); 317 } 318 sizesw::Spirv::Span319 uint32_t size() const 320 { 321 return wordCount; 322 } 323 324 private: 325 const InsnIterator &insn; 326 const uint32_t offset; 327 const uint32_t wordCount; 328 }; 329 330 class Type 331 { 332 public: 333 using ID = SpirvID<Type>; 334 opcode() const335 spv::Op opcode() const { return definition.opcode(); } 336 337 InsnIterator definition; 338 spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1); 339 uint32_t componentCount = 0; 340 bool isBuiltInBlock = false; 341 342 // Inner element type for pointers, arrays, vectors and matrices. 343 ID element; 344 }; 345 346 class Object 347 { 348 public: 349 using ID = SpirvID<Object>; 350 opcode() const351 spv::Op opcode() const { return definition.opcode(); } typeId() const352 Type::ID typeId() const { return definition.resultTypeId(); } id() const353 Object::ID id() const { return definition.resultId(); } 354 355 bool isConstantZero() const; 356 357 InsnIterator definition; 358 std::vector<uint32_t> constantValue; 359 360 enum class Kind 361 { 362 // Invalid default kind. 363 // If we get left with an object in this state, the module was 364 // broken. 365 Unknown, 366 367 // TODO: Better document this kind. 368 // A shader interface variable pointer. 369 // Pointer with uniform address across all lanes. 370 // Pointer held by SpirvRoutine::pointers 371 InterfaceVariable, 372 373 // Constant value held by Object::constantValue. 374 Constant, 375 376 // Value held by SpirvRoutine::intermediates. 377 Intermediate, 378 379 // Pointer held by SpirvRoutine::pointers 380 Pointer, 381 382 // Combination of an image pointer and a sampler ID 383 SampledImage, 384 385 // A pointer to a vk::DescriptorSet*. 386 // Pointer held by SpirvRoutine::pointers. 387 DescriptorSet, 388 }; 389 390 Kind kind = Kind::Unknown; 391 }; 392 393 // Block is an interval of SPIR-V instructions, starting with the 394 // opening OpLabel, and ending with a termination instruction. 395 class Block 396 { 397 public: 398 using ID = SpirvID<Block>; 399 using Set = std::unordered_set<ID>; 400 401 // Edge represents the graph edge between two blocks. 402 struct Edge 403 { 404 ID from; 405 ID to; 406 operator ==sw::Spirv::Block::Edge407 bool operator==(const Edge &other) const { return from == other.from && to == other.to; } 408 409 struct Hash 410 { operator ()sw::Spirv::Block::Edge::Hash411 std::size_t operator()(const Edge &edge) const noexcept 412 { 413 return std::hash<uint32_t>()(edge.from.value() * 31 + edge.to.value()); 414 } 415 }; 416 }; 417 418 Block() = default; 419 Block(const Block &other) = default; 420 Block &operator=(const Block &other) = default; 421 explicit Block(InsnIterator begin, InsnIterator end); 422 423 /* range-based-for interface */ begin() const424 inline InsnIterator begin() const { return begin_; } end() const425 inline InsnIterator end() const { return end_; } 426 427 enum Kind 428 { 429 Simple, // OpBranch or other simple terminator. 430 StructuredBranchConditional, // OpSelectionMerge + OpBranchConditional 431 UnstructuredBranchConditional, // OpBranchConditional 432 StructuredSwitch, // OpSelectionMerge + OpSwitch 433 UnstructuredSwitch, // OpSwitch 434 Loop, // OpLoopMerge + [OpBranchConditional | OpBranch] 435 }; 436 437 Kind kind = Simple; 438 InsnIterator mergeInstruction; // Structured control flow merge instruction. 439 InsnIterator branchInstruction; // Branch instruction. 440 ID mergeBlock; // Structured flow merge block. 441 ID continueTarget; // Loop continue block. 442 Set ins; // Blocks that branch into this block. 443 Set outs; // Blocks that this block branches to. 444 bool isLoopMerge = false; 445 446 private: 447 InsnIterator begin_; 448 InsnIterator end_; 449 }; 450 451 class Function 452 { 453 public: 454 using ID = SpirvID<Function>; 455 456 // Walks all reachable the blocks starting from id adding them to 457 // reachable. 458 void TraverseReachableBlocks(Block::ID id, Block::Set &reachable) const; 459 460 // AssignBlockFields() performs the following for all reachable blocks: 461 // * Assigns Block::ins with the identifiers of all blocks that contain 462 // this block in their Block::outs. 463 // * Sets Block::isLoopMerge to true if the block is the merge of a 464 // another loop block. 465 void AssignBlockFields(); 466 467 // ForeachBlockDependency calls f with each dependency of the given 468 // block. A dependency is an incoming block that is not a loop-back 469 // edge. 470 void ForeachBlockDependency(Block::ID blockId, std::function<void(Block::ID)> f) const; 471 472 // ExistsPath returns true if there's a direct or indirect flow from 473 // the 'from' block to the 'to' block that does not pass through 474 // notPassingThrough. 475 bool ExistsPath(Block::ID from, Block::ID to, Block::ID notPassingThrough) const; 476 getBlock(Block::ID id) const477 const Block &getBlock(Block::ID id) const 478 { 479 auto it = blocks.find(id); 480 ASSERT_MSG(it != blocks.end(), "Unknown block %d", id.value()); 481 return it->second; 482 } 483 484 Block::ID entry; // function entry point block. 485 HandleMap<Block> blocks; // blocks belonging to this function. 486 Type::ID type; // type of the function. 487 Type::ID result; // return type. 488 }; 489 490 using String = std::string; 491 using StringID = SpirvID<std::string>; 492 493 class Extension 494 { 495 public: 496 using ID = SpirvID<Extension>; 497 498 enum Name 499 { 500 Unknown, 501 GLSLstd450, 502 OpenCLDebugInfo100, 503 NonSemanticInfo, 504 }; 505 506 Name name; 507 }; 508 509 struct TypeOrObject 510 {}; 511 512 // TypeOrObjectID is an identifier that represents a Type or an Object, 513 // and supports implicit casting to and from Type::ID or Object::ID. 514 class TypeOrObjectID : public SpirvID<TypeOrObject> 515 { 516 public: 517 using Hash = std::hash<SpirvID<TypeOrObject>>; 518 TypeOrObjectID(uint32_t id)519 inline TypeOrObjectID(uint32_t id) 520 : SpirvID(id) 521 {} TypeOrObjectID(Type::ID id)522 inline TypeOrObjectID(Type::ID id) 523 : SpirvID(id.value()) 524 {} TypeOrObjectID(Object::ID id)525 inline TypeOrObjectID(Object::ID id) 526 : SpirvID(id.value()) 527 {} operator Type::ID() const528 inline operator Type::ID() const { return Type::ID(value()); } operator Object::ID() const529 inline operator Object::ID() const { return Object::ID(value()); } 530 }; 531 532 // This method is for retrieving an ID that uniquely identifies the 533 // shader entry point represented by this object. getIdentifier() const534 uint64_t getIdentifier() const 535 { 536 return ((uint64_t)entryPoint.value() << 32) | insns.getIdentifier(); 537 } 538 539 struct ExecutionModes 540 { 541 bool EarlyFragmentTests : 1; 542 bool DepthReplacing : 1; 543 bool DepthGreater : 1; 544 bool DepthLess : 1; 545 bool DepthUnchanged : 1; 546 bool StencilRefReplacing : 1; 547 548 // Compute workgroup dimensions 549 Object::ID WorkgroupSizeX = 1; 550 Object::ID WorkgroupSizeY = 1; 551 Object::ID WorkgroupSizeZ = 1; 552 bool useWorkgroupSizeId = false; 553 }; 554 getExecutionModes() const555 const ExecutionModes &getExecutionModes() const 556 { 557 return executionModes; 558 } 559 560 struct Analysis 561 { 562 bool ContainsDiscard : 1; // OpKill, OpTerminateInvocation, or OpDemoteToHelperInvocation 563 bool ContainsControlBarriers : 1; 564 bool NeedsCentroid : 1; 565 bool ContainsSampleQualifier : 1; 566 bool ContainsImageWrite : 1; 567 }; 568 getAnalysis() const569 const Analysis &getAnalysis() const { return analysis; } containsImageWrite() const570 bool containsImageWrite() const { return analysis.ContainsImageWrite; } 571 coverageModified() const572 bool coverageModified() const 573 { 574 return analysis.ContainsDiscard || 575 (outputBuiltins.find(spv::BuiltInSampleMask) != outputBuiltins.end()); 576 } 577 578 struct Capabilities 579 { 580 bool Matrix : 1; 581 bool Shader : 1; 582 bool StorageImageMultisample : 1; 583 bool ClipDistance : 1; 584 bool CullDistance : 1; 585 bool ImageCubeArray : 1; 586 bool SampleRateShading : 1; 587 bool InputAttachment : 1; 588 bool Sampled1D : 1; 589 bool Image1D : 1; 590 bool SampledBuffer : 1; 591 bool SampledCubeArray : 1; 592 bool ImageBuffer : 1; 593 bool ImageMSArray : 1; 594 bool StorageImageExtendedFormats : 1; 595 bool ImageQuery : 1; 596 bool DerivativeControl : 1; 597 bool DotProductInputAll : 1; 598 bool DotProductInput4x8Bit : 1; 599 bool DotProductInput4x8BitPacked : 1; 600 bool DotProduct : 1; 601 bool InterpolationFunction : 1; 602 bool StorageImageWriteWithoutFormat : 1; 603 bool GroupNonUniform : 1; 604 bool GroupNonUniformVote : 1; 605 bool GroupNonUniformBallot : 1; 606 bool GroupNonUniformShuffle : 1; 607 bool GroupNonUniformShuffleRelative : 1; 608 bool GroupNonUniformArithmetic : 1; 609 bool GroupNonUniformQuad : 1; 610 bool DeviceGroup : 1; 611 bool MultiView : 1; 612 bool SignedZeroInfNanPreserve : 1; 613 bool DemoteToHelperInvocation : 1; 614 bool StencilExportEXT : 1; 615 bool VulkanMemoryModel : 1; 616 bool VulkanMemoryModelDeviceScope : 1; 617 bool ShaderNonUniform : 1; 618 bool RuntimeDescriptorArray : 1; 619 bool StorageBufferArrayNonUniformIndexing : 1; 620 bool StorageTexelBufferArrayNonUniformIndexing : 1; 621 bool StorageTexelBufferArrayDynamicIndexing : 1; 622 bool UniformTexelBufferArrayNonUniformIndexing : 1; 623 bool UniformTexelBufferArrayDynamicIndexing : 1; 624 bool UniformBufferArrayNonUniformIndex : 1; 625 bool SampledImageArrayNonUniformIndexing : 1; 626 bool StorageImageArrayNonUniformIndexing : 1; 627 bool PhysicalStorageBufferAddresses : 1; 628 }; 629 getUsedCapabilities() const630 const Capabilities &getUsedCapabilities() const 631 { 632 return capabilities; 633 } 634 635 // getNumOutputClipDistances() returns the number of ClipDistances 636 // outputted by this shader. getNumOutputClipDistances() const637 unsigned int getNumOutputClipDistances() const 638 { 639 if(getUsedCapabilities().ClipDistance) 640 { 641 auto it = outputBuiltins.find(spv::BuiltInClipDistance); 642 if(it != outputBuiltins.end()) 643 { 644 return it->second.SizeInComponents; 645 } 646 } 647 return 0; 648 } 649 650 // getNumOutputCullDistances() returns the number of CullDistances 651 // outputted by this shader. getNumOutputCullDistances() const652 unsigned int getNumOutputCullDistances() const 653 { 654 if(getUsedCapabilities().CullDistance) 655 { 656 auto it = outputBuiltins.find(spv::BuiltInCullDistance); 657 if(it != outputBuiltins.end()) 658 { 659 return it->second.SizeInComponents; 660 } 661 } 662 return 0; 663 } 664 665 enum AttribType : unsigned char 666 { 667 ATTRIBTYPE_FLOAT, 668 ATTRIBTYPE_INT, 669 ATTRIBTYPE_UINT, 670 ATTRIBTYPE_UNUSED, 671 672 ATTRIBTYPE_LAST = ATTRIBTYPE_UINT 673 }; 674 hasBuiltinInput(spv::BuiltIn b) const675 bool hasBuiltinInput(spv::BuiltIn b) const 676 { 677 return inputBuiltins.find(b) != inputBuiltins.end(); 678 } 679 hasBuiltinOutput(spv::BuiltIn b) const680 bool hasBuiltinOutput(spv::BuiltIn b) const 681 { 682 return outputBuiltins.find(b) != outputBuiltins.end(); 683 } 684 685 struct Decorations 686 { 687 int32_t Location = -1; 688 int32_t Component = 0; 689 spv::BuiltIn BuiltIn = static_cast<spv::BuiltIn>(-1); 690 int32_t Offset = -1; 691 int32_t ArrayStride = -1; 692 int32_t MatrixStride = 1; 693 694 bool HasLocation : 1; 695 bool HasComponent : 1; 696 bool HasBuiltIn : 1; 697 bool HasOffset : 1; 698 bool HasArrayStride : 1; 699 bool HasMatrixStride : 1; 700 bool HasRowMajor : 1; // whether RowMajor bit is valid. 701 702 bool Flat : 1; 703 bool Centroid : 1; 704 bool NoPerspective : 1; 705 bool Block : 1; 706 bool BufferBlock : 1; 707 bool RelaxedPrecision : 1; 708 bool RowMajor : 1; // RowMajor if true; ColMajor if false 709 bool InsideMatrix : 1; // pseudo-decoration for whether we're inside a matrix. 710 bool NonUniform : 1; 711 Decorationssw::Spirv::Decorations712 Decorations() 713 : Location{ -1 } 714 , Component{ 0 } 715 , BuiltIn{ static_cast<spv::BuiltIn>(-1) } 716 , Offset{ -1 } 717 , ArrayStride{ -1 } 718 , MatrixStride{ -1 } 719 , HasLocation{ false } 720 , HasComponent{ false } 721 , HasBuiltIn{ false } 722 , HasOffset{ false } 723 , HasArrayStride{ false } 724 , HasMatrixStride{ false } 725 , HasRowMajor{ false } 726 , Flat{ false } 727 , Centroid{ false } 728 , NoPerspective{ false } 729 , Block{ false } 730 , BufferBlock{ false } 731 , RelaxedPrecision{ false } 732 , RowMajor{ false } 733 , InsideMatrix{ false } 734 , NonUniform{ false } 735 { 736 } 737 738 Decorations(const Decorations &) = default; 739 Decorations& operator= (const Decorations &) = default; 740 741 void Apply(const Decorations &src); 742 743 void Apply(spv::Decoration decoration, uint32_t arg); 744 }; 745 746 std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations; 747 std::unordered_map<Type::ID, std::vector<Decorations>> memberDecorations; 748 749 struct DescriptorDecorations 750 { 751 int32_t DescriptorSet = -1; 752 int32_t Binding = -1; 753 int32_t InputAttachmentIndex = -1; 754 755 void Apply(const DescriptorDecorations &src); 756 }; 757 758 std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations; 759 760 struct InterfaceComponent 761 { 762 AttribType Type; 763 764 union 765 { 766 struct 767 { 768 bool Flat : 1; 769 bool Centroid : 1; 770 bool NoPerspective : 1; 771 }; 772 773 uint8_t DecorationBits; 774 }; 775 InterfaceComponentsw::Spirv::InterfaceComponent776 InterfaceComponent() 777 : Type{ ATTRIBTYPE_UNUSED } 778 , DecorationBits{ 0 } 779 { 780 } 781 }; 782 783 struct BuiltinMapping 784 { 785 Object::ID Id; 786 uint32_t FirstComponent; 787 uint32_t SizeInComponents; 788 }; 789 790 struct WorkgroupMemory 791 { 792 // allocates a new variable of size bytes with the given identifier. allocatesw::Spirv::WorkgroupMemory793 inline void allocate(Object::ID id, uint32_t size) 794 { 795 uint32_t offset = totalSize; 796 auto it = offsets.emplace(id, offset); 797 ASSERT_MSG(it.second, "WorkgroupMemory already has an allocation for object %d", int(id.value())); 798 totalSize += size; 799 } 800 // returns the byte offset of the variable with the given identifier. offsetOfsw::Spirv::WorkgroupMemory801 inline uint32_t offsetOf(Object::ID id) const 802 { 803 auto it = offsets.find(id); 804 ASSERT_MSG(it != offsets.end(), "WorkgroupMemory has no allocation for object %d", int(id.value())); 805 return it->second; 806 } 807 // returns the total allocated size in bytes. sizesw::Spirv::WorkgroupMemory808 inline uint32_t size() const { return totalSize; } 809 810 private: 811 uint32_t totalSize = 0; // in bytes 812 std::unordered_map<Object::ID, uint32_t> offsets; // in bytes 813 }; 814 815 std::vector<InterfaceComponent> inputs; 816 std::vector<InterfaceComponent> outputs; 817 818 uint32_t getWorkgroupSizeX() const; 819 uint32_t getWorkgroupSizeY() const; 820 uint32_t getWorkgroupSizeZ() const; 821 822 using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>; 823 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins; 824 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins; 825 WorkgroupMemory workgroupMemory; 826 827 Function::ID entryPoint; 828 spv::ExecutionModel executionModel = spv::ExecutionModelMax; // Invalid prior to OpEntryPoint parsing. 829 ExecutionModes executionModes = {}; 830 Capabilities capabilities = {}; 831 spv::AddressingModel addressingModel = spv::AddressingModelLogical; 832 spv::MemoryModel memoryModel = spv::MemoryModelSimple; 833 HandleMap<Extension> extensionsByID; 834 std::unordered_set<uint32_t> extensionsImported; 835 836 Analysis analysis = {}; 837 838 HandleMap<Type> types; 839 HandleMap<Object> defs; 840 841 // TODO(b/247020580): Encapsulate 842 public: 843 HandleMap<Function> functions; 844 std::unordered_map<StringID, String> strings; 845 846 // DeclareType creates a Type for the given OpTypeX instruction, storing 847 // it into the types map. It is called from the analysis pass (constructor). 848 void DeclareType(InsnIterator insn); 849 850 void ProcessExecutionMode(InsnIterator it); 851 852 uint32_t ComputeTypeSize(InsnIterator insn); 853 Decorations GetDecorationsForId(TypeOrObjectID id) const; 854 void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const; 855 void ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const; 856 void ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, const Span &indexIds) const; 857 858 // Creates an Object for the instruction's result in 'defs'. 859 void DefineResult(const InsnIterator &insn); 860 861 using InterfaceVisitor = std::function<void(Decorations const, AttribType)>; 862 863 void VisitInterface(Object::ID id, const InterfaceVisitor &v) const; 864 865 int VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &v) const; 866 867 // MemoryElement describes a scalar element within a structure, and is 868 // used by the callback function of VisitMemoryObject(). 869 struct MemoryElement 870 { 871 uint32_t index; // index of the scalar element 872 uint32_t offset; // offset (in bytes) from the base of the object 873 const Type &type; // element type 874 }; 875 876 using MemoryVisitor = std::function<void(const MemoryElement &)>; 877 878 // VisitMemoryObject() walks a type tree in an explicitly laid out 879 // storage class, calling the MemoryVisitor for each scalar element 880 // within the 881 void VisitMemoryObject(Object::ID id, bool resultIsPointer, const MemoryVisitor &v) const; 882 883 // VisitMemoryObjectInner() is internally called by VisitMemoryObject() 884 void VisitMemoryObjectInner(Type::ID id, Decorations d, uint32_t &index, uint32_t offset, bool resultIsPointer, const MemoryVisitor &v) const; 885 886 Object &CreateConstant(InsnIterator it); 887 888 void ProcessInterfaceVariable(Object &object); 889 getType(Type::ID id) const890 const Type &getType(Type::ID id) const 891 { 892 auto it = types.find(id); 893 ASSERT_MSG(it != types.end(), "Unknown type %d", id.value()); 894 return it->second; 895 } 896 getType(const Object & object) const897 const Type &getType(const Object &object) const 898 { 899 return getType(object.typeId()); 900 } 901 getObject(Object::ID id) const902 const Object &getObject(Object::ID id) const 903 { 904 auto it = defs.find(id); 905 ASSERT_MSG(it != defs.end(), "Unknown object %d", id.value()); 906 return it->second; 907 } 908 getObjectType(Object::ID id) const909 const Type &getObjectType(Object::ID id) const 910 { 911 return getType(getObject(id)); 912 } 913 getFunction(Function::ID id) const914 const Function &getFunction(Function::ID id) const 915 { 916 auto it = functions.find(id); 917 ASSERT_MSG(it != functions.end(), "Unknown function %d", id.value()); 918 return it->second; 919 } 920 getString(StringID id) const921 const String &getString(StringID id) const 922 { 923 auto it = strings.find(id); 924 ASSERT_MSG(it != strings.end(), "Unknown string %d", id.value()); 925 return it->second; 926 } 927 getExtension(Extension::ID id) const928 const Extension &getExtension(Extension::ID id) const 929 { 930 auto it = extensionsByID.find(id); 931 ASSERT_MSG(it != extensionsByID.end(), "Unknown extension %d", id.value()); 932 return it->second; 933 } 934 935 // Returns the *component* offset in the literal for the given access chain. 936 uint32_t WalkLiteralAccessChain(Type::ID id, const Span &indexes) const; 937 938 uint32_t GetConstScalarInt(Object::ID id) const; 939 void EvalSpecConstantOp(InsnIterator insn); 940 void EvalSpecConstantUnaryOp(InsnIterator insn); 941 void EvalSpecConstantBinaryOp(InsnIterator insn); 942 943 // Fragment input interpolation functions 944 uint32_t GetNumInputComponents(int32_t location) const; 945 uint32_t GetPackedInterpolant(int32_t location) const; 946 947 // WriteCFGGraphVizDotFile() writes a graphviz dot file of the shader's 948 // control flow to the given file path. 949 void WriteCFGGraphVizDotFile(const char *path) const; 950 951 // OpcodeName() returns the name of the opcode op. 952 static const char *OpcodeName(spv::Op opcode); 953 static std::memory_order MemoryOrder(spv::MemorySemanticsMask memorySemantics); 954 955 // IsStatement() returns true if the given opcode actually performs 956 // work (as opposed to declaring a type, defining a function start / end, 957 // etc). 958 static bool IsStatement(spv::Op opcode); 959 960 // HasTypeAndResult() returns true if the given opcode's instruction 961 // has a result type ID and result ID, i.e. defines an Object. 962 static bool HasTypeAndResult(spv::Op opcode); 963 964 // Returns 0 when invalid. 965 static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model); 966 967 static bool StoresInHelperInvocationsHaveNoEffect(spv::StorageClass storageClass); 968 static bool IsExplicitLayout(spv::StorageClass storageClass); 969 static bool IsTerminator(spv::Op opcode); 970 }; 971 972 // The SpirvShader class holds a parsed SPIR-V shader but also the pipeline 973 // state which affects code emission when passing it to SpirvEmitter. 974 class SpirvShader : public Spirv 975 { 976 public: 977 SpirvShader(VkShaderStageFlagBits stage, 978 const char *entryPointName, 979 const SpirvBinary &insns, 980 const vk::RenderPass *renderPass, 981 uint32_t subpassIndex, 982 bool robustBufferAccess); 983 984 ~SpirvShader(); 985 986 // TODO(b/247020580): Move to SpirvRoutine 987 void emitProlog(SpirvRoutine *routine) const; 988 void emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount = 0) const; 989 void emitEpilog(SpirvRoutine *routine) const; 990 getRobustBufferAccess() const991 bool getRobustBufferAccess() const { return robustBufferAccess; } 992 OutOfBoundsBehavior getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const; 993 getInputAttachmentFormat(int32_t index) const994 vk::Format getInputAttachmentFormat(int32_t index) const { return inputAttachmentFormats[index]; } 995 996 private: 997 const bool robustBufferAccess; 998 999 std::vector<vk::Format> inputAttachmentFormats; 1000 }; 1001 1002 // The SpirvEmitter class translates the parsed SPIR-V shader into Reactor code. 1003 class SpirvEmitter 1004 { 1005 using Type = Spirv::Type; 1006 using Object = Spirv::Object; 1007 using Block = Spirv::Block; 1008 using InsnIterator = Spirv::InsnIterator; 1009 using Decorations = Spirv::Decorations; 1010 using Span = Spirv::Span; 1011 1012 public: 1013 static void emit(const SpirvShader &shader, 1014 SpirvRoutine *routine, 1015 Spirv::Function::ID entryPoint, 1016 RValue<SIMD::Int> activeLaneMask, 1017 RValue<SIMD::Int> storesAndAtomicsMask, 1018 const vk::DescriptorSet::Bindings &descriptorSets, 1019 unsigned int multiSampleCount); 1020 1021 // Helper for calling rr::Yield with result cast to an rr::Int. 1022 enum class YieldResult 1023 { 1024 ControlBarrier = 0, 1025 }; 1026 1027 private: 1028 SpirvEmitter(const SpirvShader &shader, 1029 SpirvRoutine *routine, 1030 Spirv::Function::ID entryPoint, 1031 RValue<SIMD::Int> activeLaneMask, 1032 RValue<SIMD::Int> storesAndAtomicsMask, 1033 const vk::DescriptorSet::Bindings &descriptorSets, 1034 unsigned int multiSampleCount); 1035 1036 // Returns the mask describing the active lanes as updated by dynamic 1037 // control flow. Active lanes include helper invocations, used for 1038 // calculating fragment derivitives, which must not perform memory 1039 // stores or atomic writes. 1040 // 1041 // Use activeStoresAndAtomicsMask() to consider both control flow and 1042 // lanes which are permitted to perform memory stores and atomic 1043 // operations activeLaneMask() const1044 RValue<SIMD::Int> activeLaneMask() const 1045 { 1046 ASSERT(activeLaneMaskValue != nullptr); 1047 return RValue<SIMD::Int>(activeLaneMaskValue); 1048 } 1049 1050 // Returns the immutable lane mask that describes which lanes are 1051 // permitted to perform memory stores and atomic operations. 1052 // Note that unlike activeStoresAndAtomicsMask() this mask *does not* 1053 // consider lanes that have been made inactive due to control flow. storesAndAtomicsMask() const1054 RValue<SIMD::Int> storesAndAtomicsMask() const 1055 { 1056 ASSERT(storesAndAtomicsMaskValue != nullptr); 1057 return RValue<SIMD::Int>(storesAndAtomicsMaskValue); 1058 } 1059 1060 // Returns a lane mask that describes which lanes are permitted to 1061 // perform memory stores and atomic operations, considering lanes that 1062 // may have been made inactive due to control flow. activeStoresAndAtomicsMask() const1063 RValue<SIMD::Int> activeStoresAndAtomicsMask() const 1064 { 1065 return activeLaneMask() & storesAndAtomicsMask(); 1066 } 1067 1068 // Add a new active lane mask edge from the current block to out. 1069 // The edge mask value will be (mask AND activeLaneMaskValue). 1070 // If multiple active lane masks are added for the same edge, then 1071 // they will be ORed together. 1072 void addOutputActiveLaneMaskEdge(Block::ID out, RValue<SIMD::Int> mask); 1073 1074 // Add a new active lane mask for the edge from -> to. 1075 // If multiple active lane masks are added for the same edge, then 1076 // they will be ORed together. 1077 void addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask); 1078 1079 // OpImageSample variants 1080 enum Variant : uint32_t 1081 { 1082 None, // No Dref or Proj. Also used by OpImageFetch and OpImageQueryLod. 1083 Dref, 1084 Proj, 1085 ProjDref, 1086 VARIANT_LAST = ProjDref 1087 }; 1088 1089 // Compact representation of image instruction state that is passed to the 1090 // trampoline function for retrieving/generating the corresponding sampling routine. 1091 struct ImageInstructionSignature 1092 { ImageInstructionSignaturesw::SpirvEmitter::ImageInstructionSignature1093 ImageInstructionSignature(Variant variant, SamplerMethod samplerMethod) 1094 { 1095 this->variant = variant; 1096 this->samplerMethod = samplerMethod; 1097 } 1098 1099 // Unmarshal from raw 32-bit data ImageInstructionSignaturesw::SpirvEmitter::ImageInstructionSignature1100 explicit ImageInstructionSignature(uint32_t signature) 1101 : signature(signature) 1102 {} 1103 getSamplerFunctionsw::SpirvEmitter::ImageInstructionSignature1104 SamplerFunction getSamplerFunction() const 1105 { 1106 return { samplerMethod, offset != 0, sample != 0 }; 1107 } 1108 isDrefsw::SpirvEmitter::ImageInstructionSignature1109 bool isDref() const 1110 { 1111 return (variant == Dref) || (variant == ProjDref); 1112 } 1113 isProjsw::SpirvEmitter::ImageInstructionSignature1114 bool isProj() const 1115 { 1116 return (variant == Proj) || (variant == ProjDref); 1117 } 1118 hasLodsw::SpirvEmitter::ImageInstructionSignature1119 bool hasLod() const 1120 { 1121 return samplerMethod == Lod || samplerMethod == Fetch; // We always pass a Lod operand for Fetch operations. 1122 } 1123 hasGradsw::SpirvEmitter::ImageInstructionSignature1124 bool hasGrad() const 1125 { 1126 return samplerMethod == Grad; 1127 } 1128 1129 union 1130 { 1131 struct 1132 { 1133 Variant variant : BITS(VARIANT_LAST); 1134 SamplerMethod samplerMethod : BITS(SAMPLER_METHOD_LAST); 1135 uint32_t gatherComponent : 2; 1136 uint32_t dim : BITS(spv::DimSubpassData); // spv::Dim 1137 uint32_t arrayed : 1; 1138 uint32_t imageFormat : BITS(spv::ImageFormatR64i); // spv::ImageFormat 1139 1140 // Parameters are passed to the sampling routine in this order: 1141 uint32_t coordinates : 3; // 1-4 (does not contain projection component) 1142 /* uint32_t dref : 1; */ // Indicated by Variant::ProjDref|Dref 1143 /* uint32_t lodOrBias : 1; */ // Indicated by SamplerMethod::Lod|Bias|Fetch 1144 uint32_t grad : 2; // 0-3 components (for each of dx / dy) 1145 uint32_t offset : 2; // 0-3 components 1146 uint32_t sample : 1; // 0-1 scalar integer 1147 }; 1148 1149 uint32_t signature = 0; 1150 }; 1151 }; 1152 1153 // This gets stored as a literal in the generated code, so it should be compact. 1154 static_assert(sizeof(ImageInstructionSignature) == sizeof(uint32_t), "ImageInstructionSignature must be 32-bit"); 1155 1156 struct ImageInstruction : public ImageInstructionSignature 1157 { 1158 ImageInstruction(InsnIterator insn, const Spirv &shader, const SpirvEmitter &state); 1159 1160 const uint32_t position; 1161 1162 Type::ID resultTypeId = 0; 1163 Object::ID resultId = 0; 1164 Object::ID imageId = 0; 1165 Object::ID samplerId = 0; 1166 Object::ID coordinateId = 0; 1167 Object::ID texelId = 0; 1168 Object::ID drefId = 0; 1169 Object::ID lodOrBiasId = 0; 1170 Object::ID gradDxId = 0; 1171 Object::ID gradDyId = 0; 1172 Object::ID offsetId = 0; 1173 Object::ID sampleId = 0; 1174 1175 private: 1176 static ImageInstructionSignature parseVariantAndMethod(InsnIterator insn); 1177 static uint32_t getImageOperandsIndex(InsnIterator insn); 1178 static uint32_t getImageOperandsMask(InsnIterator insn); 1179 }; 1180 1181 class SampledImagePointer : public SIMD::Pointer 1182 { 1183 public: SampledImagePointer(SIMD::Pointer image,Object::ID sampler)1184 SampledImagePointer(SIMD::Pointer image, Object::ID sampler) 1185 : SIMD::Pointer(image) 1186 , samplerId(sampler) 1187 {} 1188 Object::ID samplerId; 1189 }; 1190 1191 // Generic wrapper over either per-lane intermediate value, or a constant. 1192 // Constants are transparently widened to per-lane values in operator[]. 1193 // This is appropriate in most cases -- if we're not going to do something 1194 // significantly different based on whether the value is uniform across lanes. 1195 class Operand 1196 { 1197 public: 1198 Operand(const Spirv &shader, const SpirvEmitter &state, Object::ID objectId); 1199 Operand(const Intermediate &value); 1200 Float(uint32_t i) const1201 RValue<SIMD::Float> Float(uint32_t i) const 1202 { 1203 ASSERT(i < componentCount); 1204 1205 if(intermediate) 1206 { 1207 return intermediate->Float(i); 1208 } 1209 1210 // Constructing a constant SIMD::Float is not guaranteed to preserve the data's exact 1211 // bit pattern, but SPIR-V provides 32-bit words representing "the bit pattern for the constant". 1212 // Thus we must first construct an integer constant, and bitcast to float. 1213 return As<SIMD::Float>(SIMD::UInt(constant[i])); 1214 } 1215 Int(uint32_t i) const1216 RValue<SIMD::Int> Int(uint32_t i) const 1217 { 1218 ASSERT(i < componentCount); 1219 1220 if(intermediate) 1221 { 1222 return intermediate->Int(i); 1223 } 1224 1225 return SIMD::Int(constant[i]); 1226 } 1227 UInt(uint32_t i) const1228 RValue<SIMD::UInt> UInt(uint32_t i) const 1229 { 1230 ASSERT(i < componentCount); 1231 1232 if(intermediate) 1233 { 1234 return intermediate->UInt(i); 1235 } 1236 1237 return SIMD::UInt(constant[i]); 1238 } 1239 Pointer() const1240 const SIMD::Pointer &Pointer() const 1241 { 1242 ASSERT(intermediate == nullptr); 1243 1244 return *pointer; 1245 } 1246 isPointer() const1247 bool isPointer() const 1248 { 1249 return (pointer != nullptr); 1250 } 1251 SampledImage() const1252 const SampledImagePointer &SampledImage() const 1253 { 1254 ASSERT(intermediate == nullptr); 1255 1256 return *sampledImage; 1257 } 1258 isSampledImage() const1259 bool isSampledImage() const 1260 { 1261 return (sampledImage != nullptr); 1262 } 1263 1264 private: 1265 RR_PRINT_ONLY(friend struct rr::PrintValue::Ty<Operand>;) 1266 1267 // Delegate constructor 1268 Operand(const SpirvEmitter &state, const Object &object); 1269 1270 const uint32_t *constant = nullptr; 1271 const Intermediate *intermediate = nullptr; 1272 const SIMD::Pointer *pointer = nullptr; 1273 const SampledImagePointer *sampledImage = nullptr; 1274 1275 public: 1276 const uint32_t componentCount; 1277 }; 1278 RR_PRINT_ONLY(friend struct rr::PrintValue::Ty<Operand>;)1279 RR_PRINT_ONLY(friend struct rr::PrintValue::Ty<Operand>;) 1280 1281 Intermediate &createIntermediate(Object::ID id, uint32_t componentCount) 1282 { 1283 auto it = intermediates.emplace(std::piecewise_construct, 1284 std::forward_as_tuple(id), 1285 std::forward_as_tuple(componentCount)); 1286 ASSERT_MSG(it.second, "Intermediate %d created twice", id.value()); 1287 return it.first->second; 1288 } 1289 getIntermediate(Object::ID id) const1290 const Intermediate &getIntermediate(Object::ID id) const 1291 { 1292 auto it = intermediates.find(id); 1293 ASSERT_MSG(it != intermediates.end(), "Unknown intermediate %d", id.value()); 1294 return it->second; 1295 } 1296 createPointer(Object::ID id,SIMD::Pointer ptr)1297 void createPointer(Object::ID id, SIMD::Pointer ptr) 1298 { 1299 bool added = pointers.emplace(id, ptr).second; 1300 ASSERT_MSG(added, "Pointer %d created twice", id.value()); 1301 } 1302 getPointer(Object::ID id) const1303 const SIMD::Pointer &getPointer(Object::ID id) const 1304 { 1305 auto it = pointers.find(id); 1306 ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value()); 1307 return it->second; 1308 } 1309 createSampledImage(Object::ID id,SampledImagePointer ptr)1310 void createSampledImage(Object::ID id, SampledImagePointer ptr) 1311 { 1312 bool added = sampledImages.emplace(id, ptr).second; 1313 ASSERT_MSG(added, "Sampled image %d created twice", id.value()); 1314 } 1315 getSampledImage(Object::ID id) const1316 const SampledImagePointer &getSampledImage(Object::ID id) const 1317 { 1318 auto it = sampledImages.find(id); 1319 ASSERT_MSG(it != sampledImages.end(), "Unknown sampled image %d", id.value()); 1320 return it->second; 1321 } 1322 isSampledImage(Object::ID id) const1323 bool isSampledImage(Object::ID id) const 1324 { 1325 return sampledImages.find(id) != sampledImages.end(); 1326 } 1327 getImage(Object::ID id) const1328 const SIMD::Pointer &getImage(Object::ID id) const 1329 { 1330 return isSampledImage(id) ? getSampledImage(id) : getPointer(id); 1331 } 1332 1333 void EmitVariable(InsnIterator insn); 1334 void EmitLoad(InsnIterator insn); 1335 void EmitStore(InsnIterator insn); 1336 void EmitAccessChain(InsnIterator insn); 1337 void EmitCompositeConstruct(InsnIterator insn); 1338 void EmitCompositeInsert(InsnIterator insn); 1339 void EmitCompositeExtract(InsnIterator insn); 1340 void EmitVectorShuffle(InsnIterator insn); 1341 void EmitVectorTimesScalar(InsnIterator insn); 1342 void EmitMatrixTimesVector(InsnIterator insn); 1343 void EmitVectorTimesMatrix(InsnIterator insn); 1344 void EmitMatrixTimesMatrix(InsnIterator insn); 1345 void EmitOuterProduct(InsnIterator insn); 1346 void EmitTranspose(InsnIterator insn); 1347 void EmitVectorExtractDynamic(InsnIterator insn); 1348 void EmitVectorInsertDynamic(InsnIterator insn); 1349 void EmitUnaryOp(InsnIterator insn); 1350 void EmitBinaryOp(InsnIterator insn); 1351 void EmitDot(InsnIterator insn); 1352 void EmitSelect(InsnIterator insn); 1353 void EmitExtendedInstruction(InsnIterator insn); 1354 void EmitExtGLSLstd450(InsnIterator insn); 1355 void EmitAny(InsnIterator insn); 1356 void EmitAll(InsnIterator insn); 1357 void EmitBranch(InsnIterator insn); 1358 void EmitBranchConditional(InsnIterator insn); 1359 void EmitSwitch(InsnIterator insn); 1360 void EmitUnreachable(InsnIterator insn); 1361 void EmitReturn(InsnIterator insn); 1362 void EmitTerminateInvocation(InsnIterator insn); 1363 void EmitDemoteToHelperInvocation(InsnIterator insn); 1364 void EmitIsHelperInvocation(InsnIterator insn); 1365 void EmitFunctionCall(InsnIterator insn); 1366 void EmitPhi(InsnIterator insn); 1367 void EmitImageSample(const ImageInstruction &instruction); 1368 void EmitImageQuerySizeLod(InsnIterator insn); 1369 void EmitImageQuerySize(InsnIterator insn); 1370 void EmitImageQueryLevels(InsnIterator insn); 1371 void EmitImageQuerySamples(InsnIterator insn); 1372 void EmitImageRead(const ImageInstruction &instruction); 1373 void EmitImageWrite(const ImageInstruction &instruction); 1374 void EmitImageTexelPointer(const ImageInstruction &instruction); 1375 void EmitAtomicOp(InsnIterator insn); 1376 void EmitAtomicCompareExchange(InsnIterator insn); 1377 void EmitSampledImage(InsnIterator insn); 1378 void EmitImage(InsnIterator insn); 1379 void EmitCopyObject(InsnIterator insn); 1380 void EmitCopyMemory(InsnIterator insn); 1381 void EmitControlBarrier(InsnIterator insn); 1382 void EmitMemoryBarrier(InsnIterator insn); 1383 void EmitGroupNonUniform(InsnIterator insn); 1384 void EmitArrayLength(InsnIterator insn); 1385 void EmitBitcastPointer(Object::ID resultID, Operand &src); 1386 1387 enum InterpolationType 1388 { 1389 Centroid, 1390 AtSample, 1391 AtOffset, 1392 }; 1393 SIMD::Float EmitInterpolate(const SIMD::Pointer &ptr, int32_t location, Object::ID paramId, 1394 uint32_t component, InterpolationType type) const; 1395 1396 SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, Object::ID elementId, const Span &indexIds, bool nonUniform) const; 1397 SIMD::Pointer WalkAccessChain(Object::ID id, Object::ID elementId, const Span &indexIds, bool nonUniform) const; 1398 1399 // Returns true if data in the given storage class is word-interleaved 1400 // by each SIMD vector lane, otherwise data is stored linerally. 1401 // 1402 // Each lane addresses a single word, picked by a base pointer and an 1403 // integer offset. 1404 // 1405 // A word is currently 32 bits (single float, int32_t, uint32_t). 1406 // A lane is a single element of a SIMD vector register. 1407 // 1408 // Storage interleaved by lane - (IsStorageInterleavedByLane() == true): 1409 // --------------------------------------------------------------------- 1410 // 1411 // Address = PtrBase + sizeof(Word) * (SIMD::Width * LaneOffset + LaneIndex) 1412 // 1413 // Assuming SIMD::Width == 4: 1414 // 1415 // Lane[0] | Lane[1] | Lane[2] | Lane[3] 1416 // ===========+===========+===========+========== 1417 // LaneOffset=0: | Word[0] | Word[1] | Word[2] | Word[3] 1418 // ---------------+-----------+-----------+-----------+---------- 1419 // LaneOffset=1: | Word[4] | Word[5] | Word[6] | Word[7] 1420 // ---------------+-----------+-----------+-----------+---------- 1421 // LaneOffset=2: | Word[8] | Word[9] | Word[a] | Word[b] 1422 // ---------------+-----------+-----------+-----------+---------- 1423 // LaneOffset=3: | Word[c] | Word[d] | Word[e] | Word[f] 1424 // 1425 // 1426 // Linear storage - (IsStorageInterleavedByLane() == false): 1427 // --------------------------------------------------------- 1428 // 1429 // Address = PtrBase + sizeof(Word) * LaneOffset 1430 // 1431 // Lane[0] | Lane[1] | Lane[2] | Lane[3] 1432 // ===========+===========+===========+========== 1433 // LaneOffset=0: | Word[0] | Word[0] | Word[0] | Word[0] 1434 // ---------------+-----------+-----------+-----------+---------- 1435 // LaneOffset=1: | Word[1] | Word[1] | Word[1] | Word[1] 1436 // ---------------+-----------+-----------+-----------+---------- 1437 // LaneOffset=2: | Word[2] | Word[2] | Word[2] | Word[2] 1438 // ---------------+-----------+-----------+-----------+---------- 1439 // LaneOffset=3: | Word[3] | Word[3] | Word[3] | Word[3] 1440 // 1441 1442 static bool IsStorageInterleavedByLane(spv::StorageClass storageClass); 1443 static SIMD::Pointer GetElementPointer(SIMD::Pointer structure, uint32_t offset, spv::StorageClass storageClass); 1444 1445 // Returns a SIMD::Pointer to the underlying data for the given pointer 1446 // object. 1447 // Handles objects of the following kinds: 1448 // - DescriptorSet 1449 // - Pointer 1450 // - InterfaceVariable 1451 // Calling GetPointerToData with objects of any other kind will assert. 1452 SIMD::Pointer GetPointerToData(Object::ID id, SIMD::Int arrayIndex, bool nonUniform) const; 1453 void OffsetToElement(SIMD::Pointer &ptr, Object::ID elementId, int32_t arrayStride) const; 1454 1455 /* image istructions */ 1456 1457 // Emits code to sample an image, regardless of whether any SIMD lanes are active. 1458 void EmitImageSampleUnconditional(Array<SIMD::Float> &out, const ImageInstruction &instruction) const; 1459 1460 Pointer<Byte> getSamplerDescriptor(Pointer<Byte> imageDescriptor, const ImageInstruction &instruction) const; 1461 Pointer<Byte> getSamplerDescriptor(Pointer<Byte> imageDescriptor, const ImageInstruction &instruction, int laneIdx) const; 1462 Pointer<Byte> lookupSamplerFunction(Pointer<Byte> imageDescriptor, Pointer<Byte> samplerDescriptor, const ImageInstruction &instruction) const; 1463 void callSamplerFunction(Pointer<Byte> samplerFunction, Array<SIMD::Float> &out, Pointer<Byte> imageDescriptor, const ImageInstruction &instruction) const; 1464 1465 void GetImageDimensions(const Type &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const; 1466 struct TexelAddressData 1467 { 1468 bool isArrayed; 1469 spv::Dim dim; 1470 int dims, texelSize; 1471 SIMD::Int u, v, w, ptrOffset; 1472 }; 1473 static TexelAddressData setupTexelAddressData(SIMD::Int rowPitch, SIMD::Int slicePitch, SIMD::Int samplePitch, ImageInstructionSignature instruction, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, const SpirvRoutine *routine); 1474 static SIMD::Pointer GetNonUniformTexelAddress(ImageInstructionSignature instruction, SIMD::Pointer descriptor, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, OutOfBoundsBehavior outOfBoundsBehavior, SIMD::Int activeLaneMask, const SpirvRoutine *routine); 1475 static SIMD::Pointer GetTexelAddress(ImageInstructionSignature instruction, Pointer<Byte> descriptor, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, OutOfBoundsBehavior outOfBoundsBehavior, const SpirvRoutine *routine); 1476 static void WriteImage(ImageInstructionSignature instruction, Pointer<Byte> descriptor, const Pointer<SIMD::Int> &coord, const Pointer<SIMD::Int> &texelAndMask, vk::Format imageFormat); 1477 1478 /* control flow */ 1479 1480 // Lookup the active lane mask for the edge from -> to. 1481 // If from is unreachable, then a mask of all zeros is returned. 1482 // Asserts if from is reachable and the edge does not exist. 1483 RValue<SIMD::Int> GetActiveLaneMaskEdge(Block::ID from, Block::ID to) const; 1484 1485 // Updates the current active lane mask. 1486 void SetActiveLaneMask(RValue<SIMD::Int> mask); 1487 void SetStoresAndAtomicsMask(RValue<SIMD::Int> mask); 1488 1489 // Emit all the unvisited blocks (except for ignore) in DFS order, 1490 // starting with id. 1491 void EmitBlocks(Block::ID id, Block::ID ignore = 0); 1492 void EmitNonLoop(); 1493 void EmitLoop(); 1494 1495 void EmitInstructions(InsnIterator begin, InsnIterator end); 1496 void EmitInstruction(InsnIterator insn); 1497 1498 // Helper for implementing OpStore, which doesn't take an InsnIterator so it 1499 // can also store independent operands. 1500 void Store(Object::ID pointerId, const Operand &value, bool atomic, std::memory_order memoryOrder) const; 1501 1502 // LoadPhi loads the phi values from the alloca storage and places the 1503 // load values into the intermediate with the phi's result id. 1504 void LoadPhi(InsnIterator insn); 1505 1506 // StorePhi updates the phi's alloca storage value using the incoming 1507 // values from blocks that are both in the OpPhi instruction and in 1508 // filter. 1509 void StorePhi(Block::ID blockID, InsnIterator insn, const std::unordered_set<Block::ID> &filter); 1510 1511 // Emits a rr::Fence for the given MemorySemanticsMask. 1512 void Fence(spv::MemorySemanticsMask semantics) const; 1513 1514 void Yield(YieldResult res) const; 1515 1516 // Helper as we often need to take dot products as part of doing other things. 1517 static SIMD::Float FDot(unsigned numComponents, const Operand &x, const Operand &y); 1518 static SIMD::Int SDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum); 1519 static SIMD::UInt UDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum); 1520 static SIMD::Int SUDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum); 1521 static SIMD::Int AddSat(RValue<SIMD::Int> a, RValue<SIMD::Int> b); 1522 static SIMD::UInt AddSat(RValue<SIMD::UInt> a, RValue<SIMD::UInt> b); 1523 1524 using ImageSampler = void(void *texture, void *uvsIn, void *texelOut, void *constants); 1525 static ImageSampler *getImageSampler(const vk::Device *device, uint32_t signature, uint32_t samplerId, uint32_t imageViewId); 1526 static std::shared_ptr<rr::Routine> emitSamplerRoutine(ImageInstructionSignature instruction, const Sampler &samplerState); 1527 static std::shared_ptr<rr::Routine> emitWriteRoutine(ImageInstructionSignature instruction, const Sampler &samplerState); 1528 1529 // TODO(b/129523279): Eliminate conversion and use vk::Sampler members directly. 1530 static sw::FilterType convertFilterMode(const vk::SamplerState *samplerState, VkImageViewType imageViewType, SamplerMethod samplerMethod); 1531 static sw::MipmapType convertMipmapMode(const vk::SamplerState *samplerState); 1532 static sw::AddressingMode convertAddressingMode(int coordinateIndex, const vk::SamplerState *samplerState, VkImageViewType imageViewType); 1533 1534 const SpirvShader &shader; 1535 SpirvRoutine *const routine; // The current routine being built. 1536 Spirv::Function::ID function; // The current function being built. 1537 Block::ID block; // The current block being built. 1538 rr::Value *activeLaneMaskValue = nullptr; // The current active lane mask. 1539 rr::Value *storesAndAtomicsMaskValue = nullptr; // The current atomics mask. 1540 Spirv::Block::Set visited; // Blocks already built. 1541 std::unordered_map<Block::Edge, RValue<SIMD::Int>, Block::Edge::Hash> edgeActiveLaneMasks; 1542 std::deque<Block::ID> *pending; 1543 1544 const vk::DescriptorSet::Bindings &descriptorSets; 1545 1546 std::unordered_map<Object::ID, Intermediate> intermediates; 1547 std::unordered_map<Object::ID, std::vector<SIMD::Float>> phis; 1548 std::unordered_map<Object::ID, SIMD::Pointer> pointers; 1549 std::unordered_map<Object::ID, SampledImagePointer> sampledImages; 1550 1551 const unsigned int multiSampleCount; 1552 }; 1553 1554 class SpirvRoutine 1555 { 1556 using Object = Spirv::Object; 1557 1558 public: 1559 SpirvRoutine(const vk::PipelineLayout *pipelineLayout); 1560 1561 using Variable = Array<SIMD::Float>; 1562 1563 // Single-entry 'inline' sampler routine cache. 1564 struct SamplerCache 1565 { 1566 Pointer<Byte> imageDescriptor = nullptr; 1567 Int samplerId; 1568 1569 Pointer<Byte> function; 1570 }; 1571 1572 enum Interpolation 1573 { 1574 Perspective = 0, 1575 Linear, 1576 Flat, 1577 }; 1578 1579 struct InterpolationData 1580 { 1581 Pointer<Byte> primitive; 1582 SIMD::Float x; 1583 SIMD::Float y; 1584 SIMD::Float rhw; 1585 SIMD::Float xCentroid; 1586 SIMD::Float yCentroid; 1587 SIMD::Float rhwCentroid; 1588 }; 1589 1590 const vk::PipelineLayout *const pipelineLayout; 1591 1592 std::unordered_map<Object::ID, Variable> variables; 1593 std::unordered_map<uint32_t, SamplerCache> samplerCache; // Indexed by the instruction position, in words. 1594 SIMD::Float inputs[MAX_INTERFACE_COMPONENTS]; 1595 Interpolation inputsInterpolation[MAX_INTERFACE_COMPONENTS]; 1596 SIMD::Float outputs[MAX_INTERFACE_COMPONENTS]; 1597 InterpolationData interpolationData; 1598 1599 Pointer<Byte> device; 1600 Pointer<Byte> workgroupMemory; 1601 Pointer<Pointer<Byte>> descriptorSets; 1602 Pointer<Int> descriptorDynamicOffsets; 1603 Pointer<Byte> pushConstants; 1604 Pointer<Byte> constants; 1605 Int discardMask = 0; 1606 1607 // Shader invocation state. 1608 // Not all of these variables are used for every type of shader, and some 1609 // are only used when debugging. See b/146486064 for more information. 1610 // Give careful consideration to the runtime performance loss before adding 1611 // more state here. 1612 std::array<SIMD::Int, 2> windowSpacePosition; // TODO(b/236162233): SIMD::Int2 1613 Int layer; // slice offset into input attachments for multiview, even if the shader doesn't use ViewIndex 1614 Int instanceID; 1615 SIMD::Int vertexIndex; 1616 std::array<SIMD::Float, 4> fragCoord; // TODO(b/236162233): SIMD::Float4 1617 std::array<SIMD::Float, 2> pointCoord; // TODO(b/236162233): SIMD::Float2 1618 SIMD::Int helperInvocation; 1619 Int4 numWorkgroups; 1620 Int4 workgroupID; 1621 Int4 workgroupSize; 1622 Int subgroupsPerWorkgroup; 1623 Int invocationsPerSubgroup; 1624 Int subgroupIndex; 1625 SIMD::Int localInvocationIndex; 1626 std::array<SIMD::Int, 3> localInvocationID; // TODO(b/236162233): SIMD::Int3 1627 std::array<SIMD::Int, 3> globalInvocationID; // TODO(b/236162233): SIMD::Int3 1628 createVariable(Object::ID id,uint32_t componentCount)1629 void createVariable(Object::ID id, uint32_t componentCount) 1630 { 1631 bool added = variables.emplace(id, Variable(componentCount)).second; 1632 ASSERT_MSG(added, "Variable %d created twice", id.value()); 1633 } 1634 getVariable(Object::ID id)1635 Variable &getVariable(Object::ID id) 1636 { 1637 auto it = variables.find(id); 1638 ASSERT_MSG(it != variables.end(), "Unknown variables %d", id.value()); 1639 return it->second; 1640 } 1641 1642 // setImmutableInputBuiltins() sets all the immutable input builtins, 1643 // common for all shader types. 1644 void setImmutableInputBuiltins(const SpirvShader *shader); 1645 1646 static SIMD::Float interpolateAtXY(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw, Pointer<Byte> planeEquation, Interpolation interpolation); 1647 1648 // setInputBuiltin() calls f() with the builtin and value if the shader 1649 // uses the input builtin, otherwise the call is a no-op. 1650 // F is a function with the signature: 1651 // void(const Spirv::BuiltinMapping& builtin, Array<SIMD::Float>& value) 1652 template<typename F> setInputBuiltin(const SpirvShader * shader,spv::BuiltIn id,F && f)1653 inline void setInputBuiltin(const SpirvShader *shader, spv::BuiltIn id, F &&f) 1654 { 1655 auto it = shader->inputBuiltins.find(id); 1656 if(it != shader->inputBuiltins.end()) 1657 { 1658 const auto &builtin = it->second; 1659 f(builtin, getVariable(builtin.Id)); 1660 } 1661 } 1662 }; 1663 1664 } // namespace sw 1665 1666 #endif // sw_SpirvShader_hpp 1667