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 "SpirvID.hpp" 21 #include "Device/Config.hpp" 22 #include "Device/Sampler.hpp" 23 #include "System/Debug.hpp" 24 #include "System/Types.hpp" 25 #include "Vulkan/VkConfig.h" 26 #include "Vulkan/VkDescriptorSet.hpp" 27 28 #include <spirv/unified1/spirv.hpp> 29 30 #include <array> 31 #include <atomic> 32 #include <cstdint> 33 #include <cstring> 34 #include <deque> 35 #include <functional> 36 #include <memory> 37 #include <string> 38 #include <type_traits> 39 #include <unordered_map> 40 #include <unordered_set> 41 #include <vector> 42 43 #undef Yield // b/127920555 44 45 namespace vk { 46 47 class PipelineLayout; 48 class ImageView; 49 class Sampler; 50 class RenderPass; 51 struct SampledImageDescriptor; 52 53 namespace dbg { 54 class Context; 55 } // namespace dbg 56 57 } // namespace vk 58 59 namespace sw { 60 61 // Forward declarations. 62 class SpirvRoutine; 63 64 // Incrementally constructed complex bundle of rvalues 65 // Effectively a restricted vector, supporting only: 66 // - allocation to a (runtime-known) fixed size 67 // - in-place construction of elements 68 // - const operator[] 69 class Intermediate 70 { 71 public: Intermediate(uint32_t size)72 Intermediate(uint32_t size) 73 : scalar(new rr::Value *[size]) 74 , size(size) 75 { 76 memset(scalar, 0, sizeof(rr::Value *) * size); 77 } 78 ~Intermediate()79 ~Intermediate() 80 { 81 delete[] scalar; 82 } 83 move(uint32_t i,RValue<SIMD::Float> && scalar)84 void move(uint32_t i, RValue<SIMD::Float> &&scalar) { emplace(i, scalar.value); } move(uint32_t i,RValue<SIMD::Int> && scalar)85 void move(uint32_t i, RValue<SIMD::Int> &&scalar) { emplace(i, scalar.value); } move(uint32_t i,RValue<SIMD::UInt> && scalar)86 void move(uint32_t i, RValue<SIMD::UInt> &&scalar) { emplace(i, scalar.value); } 87 move(uint32_t i,const RValue<SIMD::Float> & scalar)88 void move(uint32_t i, const RValue<SIMD::Float> &scalar) { emplace(i, scalar.value); } move(uint32_t i,const RValue<SIMD::Int> & scalar)89 void move(uint32_t i, const RValue<SIMD::Int> &scalar) { emplace(i, scalar.value); } move(uint32_t i,const RValue<SIMD::UInt> & scalar)90 void move(uint32_t i, const RValue<SIMD::UInt> &scalar) { emplace(i, scalar.value); } 91 92 // Value retrieval functions. Float(uint32_t i) const93 RValue<SIMD::Float> Float(uint32_t i) const 94 { 95 ASSERT(i < size); 96 ASSERT(scalar[i] != nullptr); 97 return As<SIMD::Float>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Float>(scalar) 98 } 99 Int(uint32_t i) const100 RValue<SIMD::Int> Int(uint32_t i) const 101 { 102 ASSERT(i < size); 103 ASSERT(scalar[i] != nullptr); 104 return As<SIMD::Int>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Int>(scalar) 105 } 106 UInt(uint32_t i) const107 RValue<SIMD::UInt> UInt(uint32_t i) const 108 { 109 ASSERT(i < size); 110 ASSERT(scalar[i] != nullptr); 111 return As<SIMD::UInt>(scalar[i]); // TODO(b/128539387): RValue<SIMD::UInt>(scalar) 112 } 113 114 // No copy/move construction or assignment 115 Intermediate(Intermediate const &) = delete; 116 Intermediate(Intermediate &&) = delete; 117 Intermediate &operator=(Intermediate const &) = delete; 118 Intermediate &operator=(Intermediate &&) = delete; 119 120 private: emplace(uint32_t i,rr::Value * value)121 void emplace(uint32_t i, rr::Value *value) 122 { 123 ASSERT(i < size); 124 ASSERT(scalar[i] == nullptr); 125 scalar[i] = value; 126 } 127 128 rr::Value **const scalar; 129 uint32_t size; 130 }; 131 132 class SpirvShader 133 { 134 public: 135 using InsnStore = std::vector<uint32_t>; 136 InsnStore insns; 137 138 using ImageSampler = void(void *texture, void *sampler, void *uvsIn, void *texelOut, void *constants); 139 140 enum class YieldResult 141 { 142 ControlBarrier, 143 }; 144 145 /* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */ 146 class InsnIterator 147 { 148 InsnStore::const_iterator iter; 149 150 public: opcode() const151 spv::Op opcode() const 152 { 153 return static_cast<spv::Op>(*iter & spv::OpCodeMask); 154 } 155 wordCount() const156 uint32_t wordCount() const 157 { 158 return *iter >> spv::WordCountShift; 159 } 160 word(uint32_t n) const161 uint32_t word(uint32_t n) const 162 { 163 ASSERT(n < wordCount()); 164 return iter[n]; 165 } 166 wordPointer(uint32_t n) const167 uint32_t const *wordPointer(uint32_t n) const 168 { 169 ASSERT(n < wordCount()); 170 return &iter[n]; 171 } 172 string(uint32_t n) const173 const char *string(uint32_t n) const 174 { 175 return reinterpret_cast<const char *>(wordPointer(n)); 176 } 177 operator ==(InsnIterator const & other) const178 bool operator==(InsnIterator const &other) const 179 { 180 return iter == other.iter; 181 } 182 operator !=(InsnIterator const & other) const183 bool operator!=(InsnIterator const &other) const 184 { 185 return iter != other.iter; 186 } 187 operator *() const188 InsnIterator operator*() const 189 { 190 return *this; 191 } 192 operator ++()193 InsnIterator &operator++() 194 { 195 iter += wordCount(); 196 return *this; 197 } 198 operator ++(int)199 InsnIterator const operator++(int) 200 { 201 InsnIterator ret{ *this }; 202 iter += wordCount(); 203 return ret; 204 } 205 206 InsnIterator(InsnIterator const &other) = default; 207 208 InsnIterator() = default; 209 InsnIterator(InsnStore::const_iterator iter)210 explicit InsnIterator(InsnStore::const_iterator iter) 211 : iter{ iter } 212 { 213 } 214 }; 215 216 /* range-based-for interface */ begin() const217 InsnIterator begin() const 218 { 219 return InsnIterator{ insns.cbegin() + 5 }; 220 } 221 end() const222 InsnIterator end() const 223 { 224 return InsnIterator{ insns.cend() }; 225 } 226 227 class Type 228 { 229 public: 230 using ID = SpirvID<Type>; 231 opcode() const232 spv::Op opcode() const { return definition.opcode(); } 233 234 InsnIterator definition; 235 spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1); 236 uint32_t sizeInComponents = 0; 237 bool isBuiltInBlock = false; 238 239 // Inner element type for pointers, arrays, vectors and matrices. 240 ID element; 241 }; 242 243 class Object 244 { 245 public: 246 using ID = SpirvID<Object>; 247 opcode() const248 spv::Op opcode() const { return definition.opcode(); } 249 250 InsnIterator definition; 251 Type::ID type; 252 std::unique_ptr<uint32_t[]> constantValue = nullptr; 253 254 enum class Kind 255 { 256 // Invalid default kind. 257 // If we get left with an object in this state, the module was 258 // broken. 259 Unknown, 260 261 // TODO: Better document this kind. 262 // A shader interface variable pointer. 263 // Pointer with uniform address across all lanes. 264 // Pointer held by SpirvRoutine::pointers 265 InterfaceVariable, 266 267 // Constant value held by Object::constantValue. 268 Constant, 269 270 // Value held by SpirvRoutine::intermediates. 271 Intermediate, 272 273 // Pointer held by SpirvRoutine::pointers 274 Pointer, 275 276 // A pointer to a vk::DescriptorSet*. 277 // Pointer held by SpirvRoutine::pointers. 278 DescriptorSet, 279 }; 280 281 Kind kind = Kind::Unknown; 282 }; 283 284 // Block is an interval of SPIR-V instructions, starting with the 285 // opening OpLabel, and ending with a termination instruction. 286 class Block 287 { 288 public: 289 using ID = SpirvID<Block>; 290 using Set = std::unordered_set<ID>; 291 292 // Edge represents the graph edge between two blocks. 293 struct Edge 294 { 295 ID from; 296 ID to; 297 operator ==sw::SpirvShader::Block::Edge298 bool operator==(const Edge &other) const { return from == other.from && to == other.to; } 299 300 struct Hash 301 { operator ()sw::SpirvShader::Block::Edge::Hash302 std::size_t operator()(const Edge &edge) const noexcept 303 { 304 return std::hash<uint32_t>()(edge.from.value() * 31 + edge.to.value()); 305 } 306 }; 307 }; 308 309 Block() = default; 310 Block(const Block &other) = default; 311 explicit Block(InsnIterator begin, InsnIterator end); 312 313 /* range-based-for interface */ begin() const314 inline InsnIterator begin() const { return begin_; } end() const315 inline InsnIterator end() const { return end_; } 316 317 enum Kind 318 { 319 Simple, // OpBranch or other simple terminator. 320 StructuredBranchConditional, // OpSelectionMerge + OpBranchConditional 321 UnstructuredBranchConditional, // OpBranchConditional 322 StructuredSwitch, // OpSelectionMerge + OpSwitch 323 UnstructuredSwitch, // OpSwitch 324 Loop, // OpLoopMerge + [OpBranchConditional | OpBranch] 325 }; 326 327 Kind kind = Simple; 328 InsnIterator mergeInstruction; // Structured control flow merge instruction. 329 InsnIterator branchInstruction; // Branch instruction. 330 ID mergeBlock; // Structured flow merge block. 331 ID continueTarget; // Loop continue block. 332 Set ins; // Blocks that branch into this block. 333 Set outs; // Blocks that this block branches to. 334 bool isLoopMerge = false; 335 336 private: 337 InsnIterator begin_; 338 InsnIterator end_; 339 }; 340 341 class Function 342 { 343 public: 344 using ID = SpirvID<Function>; 345 346 // Walks all reachable the blocks starting from id adding them to 347 // reachable. 348 void TraverseReachableBlocks(Block::ID id, Block::Set &reachable) const; 349 350 // AssignBlockFields() performs the following for all reachable blocks: 351 // * Assigns Block::ins with the identifiers of all blocks that contain 352 // this block in their Block::outs. 353 // * Sets Block::isLoopMerge to true if the block is the merge of a 354 // another loop block. 355 void AssignBlockFields(); 356 357 // ForeachBlockDependency calls f with each dependency of the given 358 // block. A dependency is an incoming block that is not a loop-back 359 // edge. 360 void ForeachBlockDependency(Block::ID blockId, std::function<void(Block::ID)> f) const; 361 362 // ExistsPath returns true if there's a direct or indirect flow from 363 // the 'from' block to the 'to' block that does not pass through 364 // notPassingThrough. 365 bool ExistsPath(Block::ID from, Block::ID to, Block::ID notPassingThrough) const; 366 getBlock(Block::ID id) const367 Block const &getBlock(Block::ID id) const 368 { 369 auto it = blocks.find(id); 370 ASSERT_MSG(it != blocks.end(), "Unknown block %d", id.value()); 371 return it->second; 372 } 373 374 Block::ID entry; // function entry point block. 375 HandleMap<Block> blocks; // blocks belonging to this function. 376 Type::ID type; // type of the function. 377 Type::ID result; // return type. 378 }; 379 380 using String = std::string; 381 using StringID = SpirvID<std::string>; 382 383 class Extension 384 { 385 public: 386 using ID = SpirvID<Extension>; 387 388 enum Name 389 { 390 Unknown, 391 GLSLstd450, 392 OpenCLDebugInfo100 393 }; 394 395 Name name; 396 }; 397 398 struct TypeOrObject 399 {}; // Dummy struct to represent a Type or Object. 400 401 // TypeOrObjectID is an identifier that represents a Type or an Object, 402 // and supports implicit casting to and from Type::ID or Object::ID. 403 class TypeOrObjectID : public SpirvID<TypeOrObject> 404 { 405 public: 406 using Hash = std::hash<SpirvID<TypeOrObject>>; 407 TypeOrObjectID(uint32_t id)408 inline TypeOrObjectID(uint32_t id) 409 : SpirvID(id) 410 {} TypeOrObjectID(Type::ID id)411 inline TypeOrObjectID(Type::ID id) 412 : SpirvID(id.value()) 413 {} TypeOrObjectID(Object::ID id)414 inline TypeOrObjectID(Object::ID id) 415 : SpirvID(id.value()) 416 {} operator Type::ID() const417 inline operator Type::ID() const { return Type::ID(value()); } operator Object::ID() const418 inline operator Object::ID() const { return Object::ID(value()); } 419 }; 420 421 // OpImageSample variants 422 enum Variant 423 { 424 None, // No Dref or Proj. Also used by OpImageFetch and OpImageQueryLod. 425 Dref, 426 Proj, 427 ProjDref, 428 VARIANT_LAST = ProjDref 429 }; 430 431 // Compact representation of image instruction parameters that is passed to the 432 // trampoline function for retrieving/generating the corresponding sampling routine. 433 struct ImageInstruction 434 { ImageInstructionsw::SpirvShader::ImageInstruction435 ImageInstruction(Variant variant, SamplerMethod samplerMethod) 436 : parameters(0) 437 { 438 this->variant = variant; 439 this->samplerMethod = samplerMethod; 440 } 441 442 // Unmarshal from raw 32-bit data ImageInstructionsw::SpirvShader::ImageInstruction443 ImageInstruction(uint32_t parameters) 444 : parameters(parameters) 445 {} 446 getSamplerFunctionsw::SpirvShader::ImageInstruction447 SamplerFunction getSamplerFunction() const 448 { 449 return { static_cast<SamplerMethod>(samplerMethod), offset != 0, sample != 0 }; 450 } 451 isDrefsw::SpirvShader::ImageInstruction452 bool isDref() const 453 { 454 return (variant == Dref) || (variant == ProjDref); 455 } 456 isProjsw::SpirvShader::ImageInstruction457 bool isProj() const 458 { 459 return (variant == Proj) || (variant == ProjDref); 460 } 461 462 union 463 { 464 struct 465 { 466 uint32_t variant : BITS(VARIANT_LAST); 467 uint32_t samplerMethod : BITS(SAMPLER_METHOD_LAST); 468 uint32_t gatherComponent : 2; 469 470 // Parameters are passed to the sampling routine in this order: 471 uint32_t coordinates : 3; // 1-4 (does not contain projection component) 472 // uint32_t dref : 1; // Indicated by Variant::ProjDref|Dref 473 // uint32_t lodOrBias : 1; // Indicated by SamplerMethod::Lod|Bias|Fetch 474 uint32_t grad : 2; // 0-3 components (for each of dx / dy) 475 uint32_t offset : 2; // 0-3 components 476 uint32_t sample : 1; // 0-1 scalar integer 477 }; 478 479 uint32_t parameters; 480 }; 481 }; 482 483 static_assert(sizeof(ImageInstruction) == sizeof(uint32_t), "ImageInstruction must be 32-bit"); 484 485 // This method is for retrieving an ID that uniquely identifies the 486 // shader entry point represented by this object. getSerialID() const487 uint64_t getSerialID() const 488 { 489 return ((uint64_t)entryPoint.value() << 32) | codeSerialID; 490 } 491 492 SpirvShader(uint32_t codeSerialID, 493 VkShaderStageFlagBits stage, 494 const char *entryPointName, 495 InsnStore const &insns, 496 const vk::RenderPass *renderPass, 497 uint32_t subpassIndex, 498 bool robustBufferAccess, 499 const std::shared_ptr<vk::dbg::Context> &dbgctx); 500 501 ~SpirvShader(); 502 503 struct Modes 504 { 505 bool EarlyFragmentTests : 1; 506 bool DepthReplacing : 1; 507 bool DepthGreater : 1; 508 bool DepthLess : 1; 509 bool DepthUnchanged : 1; 510 bool ContainsKill : 1; 511 bool ContainsControlBarriers : 1; 512 bool NeedsCentroid : 1; 513 514 // Compute workgroup dimensions 515 int WorkgroupSizeX = 1, WorkgroupSizeY = 1, WorkgroupSizeZ = 1; 516 }; 517 getModes() const518 Modes const &getModes() const 519 { 520 return modes; 521 } 522 523 struct Capabilities 524 { 525 bool Matrix : 1; 526 bool Shader : 1; 527 bool ClipDistance : 1; 528 bool CullDistance : 1; 529 bool InputAttachment : 1; 530 bool Sampled1D : 1; 531 bool Image1D : 1; 532 bool ImageCubeArray : 1; 533 bool SampledBuffer : 1; 534 bool SampledCubeArray : 1; 535 bool ImageBuffer : 1; 536 bool StorageImageExtendedFormats : 1; 537 bool ImageQuery : 1; 538 bool DerivativeControl : 1; 539 bool GroupNonUniform : 1; 540 bool GroupNonUniformVote : 1; 541 bool GroupNonUniformBallot : 1; 542 bool GroupNonUniformShuffle : 1; 543 bool GroupNonUniformShuffleRelative : 1; 544 bool GroupNonUniformArithmetic : 1; 545 bool DeviceGroup : 1; 546 bool MultiView : 1; 547 bool StencilExportEXT : 1; 548 }; 549 getUsedCapabilities() const550 Capabilities const &getUsedCapabilities() const 551 { 552 return capabilities; 553 } 554 555 // getNumOutputClipDistances() returns the number of ClipDistances 556 // outputted by this shader. getNumOutputClipDistances() const557 unsigned int getNumOutputClipDistances() const 558 { 559 if(getUsedCapabilities().ClipDistance) 560 { 561 auto it = outputBuiltins.find(spv::BuiltInClipDistance); 562 if(it != outputBuiltins.end()) 563 { 564 return it->second.SizeInComponents; 565 } 566 } 567 return 0; 568 } 569 570 // getNumOutputCullDistances() returns the number of CullDistances 571 // outputted by this shader. getNumOutputCullDistances() const572 unsigned int getNumOutputCullDistances() const 573 { 574 if(getUsedCapabilities().CullDistance) 575 { 576 auto it = outputBuiltins.find(spv::BuiltInCullDistance); 577 if(it != outputBuiltins.end()) 578 { 579 return it->second.SizeInComponents; 580 } 581 } 582 return 0; 583 } 584 585 enum AttribType : unsigned char 586 { 587 ATTRIBTYPE_FLOAT, 588 ATTRIBTYPE_INT, 589 ATTRIBTYPE_UINT, 590 ATTRIBTYPE_UNUSED, 591 592 ATTRIBTYPE_LAST = ATTRIBTYPE_UINT 593 }; 594 hasBuiltinInput(spv::BuiltIn b) const595 bool hasBuiltinInput(spv::BuiltIn b) const 596 { 597 return inputBuiltins.find(b) != inputBuiltins.end(); 598 } 599 hasBuiltinOutput(spv::BuiltIn b) const600 bool hasBuiltinOutput(spv::BuiltIn b) const 601 { 602 return outputBuiltins.find(b) != outputBuiltins.end(); 603 } 604 605 struct Decorations 606 { 607 int32_t Location = -1; 608 int32_t Component = 0; 609 spv::BuiltIn BuiltIn = static_cast<spv::BuiltIn>(-1); 610 int32_t Offset = -1; 611 int32_t ArrayStride = -1; 612 int32_t MatrixStride = 1; 613 614 bool HasLocation : 1; 615 bool HasComponent : 1; 616 bool HasBuiltIn : 1; 617 bool HasOffset : 1; 618 bool HasArrayStride : 1; 619 bool HasMatrixStride : 1; 620 bool HasRowMajor : 1; // whether RowMajor bit is valid. 621 622 bool Flat : 1; 623 bool Centroid : 1; 624 bool NoPerspective : 1; 625 bool Block : 1; 626 bool BufferBlock : 1; 627 bool RelaxedPrecision : 1; 628 bool RowMajor : 1; // RowMajor if true; ColMajor if false 629 bool InsideMatrix : 1; // pseudo-decoration for whether we're inside a matrix. 630 Decorationssw::SpirvShader::Decorations631 Decorations() 632 : Location{ -1 } 633 , Component{ 0 } 634 , BuiltIn{ static_cast<spv::BuiltIn>(-1) } 635 , Offset{ -1 } 636 , ArrayStride{ -1 } 637 , MatrixStride{ -1 } 638 , HasLocation{ false } 639 , HasComponent{ false } 640 , HasBuiltIn{ false } 641 , HasOffset{ false } 642 , HasArrayStride{ false } 643 , HasMatrixStride{ false } 644 , HasRowMajor{ false } 645 , Flat{ false } 646 , Centroid{ false } 647 , NoPerspective{ false } 648 , Block{ false } 649 , BufferBlock{ false } 650 , RelaxedPrecision{ false } 651 , RowMajor{ false } 652 , InsideMatrix{ false } 653 { 654 } 655 656 Decorations(Decorations const &) = default; 657 658 void Apply(Decorations const &src); 659 660 void Apply(spv::Decoration decoration, uint32_t arg); 661 }; 662 663 std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations; 664 std::unordered_map<Type::ID, std::vector<Decorations>> memberDecorations; 665 666 struct DescriptorDecorations 667 { 668 int32_t DescriptorSet = -1; 669 int32_t Binding = -1; 670 int32_t InputAttachmentIndex = -1; 671 672 void Apply(DescriptorDecorations const &src); 673 }; 674 675 std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations; 676 std::vector<VkFormat> inputAttachmentFormats; 677 678 struct InterfaceComponent 679 { 680 AttribType Type; 681 682 union 683 { 684 struct 685 { 686 bool Flat : 1; 687 bool Centroid : 1; 688 bool NoPerspective : 1; 689 }; 690 691 uint8_t DecorationBits; 692 }; 693 InterfaceComponentsw::SpirvShader::InterfaceComponent694 InterfaceComponent() 695 : Type{ ATTRIBTYPE_UNUSED } 696 , DecorationBits{ 0 } 697 { 698 } 699 }; 700 701 struct BuiltinMapping 702 { 703 Object::ID Id; 704 uint32_t FirstComponent; 705 uint32_t SizeInComponents; 706 }; 707 708 struct WorkgroupMemory 709 { 710 // allocates a new variable of size bytes with the given identifier. allocatesw::SpirvShader::WorkgroupMemory711 inline void allocate(Object::ID id, uint32_t size) 712 { 713 uint32_t offset = totalSize; 714 auto it = offsets.emplace(id, offset); 715 ASSERT_MSG(it.second, "WorkgroupMemory already has an allocation for object %d", int(id.value())); 716 totalSize += size; 717 } 718 // returns the byte offset of the variable with the given identifier. offsetOfsw::SpirvShader::WorkgroupMemory719 inline uint32_t offsetOf(Object::ID id) const 720 { 721 auto it = offsets.find(id); 722 ASSERT_MSG(it != offsets.end(), "WorkgroupMemory has no allocation for object %d", int(id.value())); 723 return it->second; 724 } 725 // returns the total allocated size in bytes. sizesw::SpirvShader::WorkgroupMemory726 inline uint32_t size() const { return totalSize; } 727 728 private: 729 uint32_t totalSize = 0; // in bytes 730 std::unordered_map<Object::ID, uint32_t> offsets; // in bytes 731 }; 732 733 std::vector<InterfaceComponent> inputs; 734 std::vector<InterfaceComponent> outputs; 735 736 void emitProlog(SpirvRoutine *routine) const; 737 void emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets) const; 738 void emitEpilog(SpirvRoutine *routine) const; 739 740 using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>; 741 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins; 742 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins; 743 WorkgroupMemory workgroupMemory; 744 745 private: 746 const uint32_t codeSerialID; 747 Modes modes = {}; 748 Capabilities capabilities = {}; 749 HandleMap<Type> types; 750 HandleMap<Object> defs; 751 HandleMap<Function> functions; 752 std::unordered_map<StringID, String> strings; 753 HandleMap<Extension> extensionsByID; 754 std::unordered_set<Extension::Name> extensionsImported; 755 Function::ID entryPoint; 756 757 const bool robustBufferAccess = true; 758 spv::ExecutionModel executionModel = spv::ExecutionModelMax; // Invalid prior to OpEntryPoint parsing. 759 760 // DeclareType creates a Type for the given OpTypeX instruction, storing 761 // it into the types map. It is called from the analysis pass (constructor). 762 void DeclareType(InsnIterator insn); 763 764 void ProcessExecutionMode(InsnIterator it); 765 766 uint32_t ComputeTypeSize(InsnIterator insn); 767 void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const; 768 void ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const; 769 void ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds) const; 770 771 // Creates an Object for the instruction's result in 'defs'. 772 void DefineResult(const InsnIterator &insn); 773 774 // Processes the OpenCL.Debug.100 instruction for the initial definition 775 // pass of the SPIR-V. 776 void DefineOpenCLDebugInfo100(const InsnIterator &insn); 777 778 // Returns true if data in the given storage class is word-interleaved 779 // by each SIMD vector lane, otherwise data is stored linerally. 780 // 781 // Each lane addresses a single word, picked by a base pointer and an 782 // integer offset. 783 // 784 // A word is currently 32 bits (single float, int32_t, uint32_t). 785 // A lane is a single element of a SIMD vector register. 786 // 787 // Storage interleaved by lane - (IsStorageInterleavedByLane() == true): 788 // --------------------------------------------------------------------- 789 // 790 // Address = PtrBase + sizeof(Word) * (SIMD::Width * LaneOffset + LaneIndex) 791 // 792 // Assuming SIMD::Width == 4: 793 // 794 // Lane[0] | Lane[1] | Lane[2] | Lane[3] 795 // ===========+===========+===========+========== 796 // LaneOffset=0: | Word[0] | Word[1] | Word[2] | Word[3] 797 // ---------------+-----------+-----------+-----------+---------- 798 // LaneOffset=1: | Word[4] | Word[5] | Word[6] | Word[7] 799 // ---------------+-----------+-----------+-----------+---------- 800 // LaneOffset=2: | Word[8] | Word[9] | Word[a] | Word[b] 801 // ---------------+-----------+-----------+-----------+---------- 802 // LaneOffset=3: | Word[c] | Word[d] | Word[e] | Word[f] 803 // 804 // 805 // Linear storage - (IsStorageInterleavedByLane() == false): 806 // --------------------------------------------------------- 807 // 808 // Address = PtrBase + sizeof(Word) * LaneOffset 809 // 810 // Lane[0] | Lane[1] | Lane[2] | Lane[3] 811 // ===========+===========+===========+========== 812 // LaneOffset=0: | Word[0] | Word[0] | Word[0] | Word[0] 813 // ---------------+-----------+-----------+-----------+---------- 814 // LaneOffset=1: | Word[1] | Word[1] | Word[1] | Word[1] 815 // ---------------+-----------+-----------+-----------+---------- 816 // LaneOffset=2: | Word[2] | Word[2] | Word[2] | Word[2] 817 // ---------------+-----------+-----------+-----------+---------- 818 // LaneOffset=3: | Word[3] | Word[3] | Word[3] | Word[3] 819 // 820 static bool IsStorageInterleavedByLane(spv::StorageClass storageClass); 821 static bool IsExplicitLayout(spv::StorageClass storageClass); 822 823 static sw::SIMD::Pointer InterleaveByLane(sw::SIMD::Pointer p); 824 825 // Output storage buffers and images should not be affected by helper invocations 826 static bool StoresInHelperInvocation(spv::StorageClass storageClass); 827 828 using InterfaceVisitor = std::function<void(Decorations const, AttribType)>; 829 830 void VisitInterface(Object::ID id, const InterfaceVisitor &v) const; 831 832 int VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &v) const; 833 834 // MemoryElement describes a scalar element within a structure, and is 835 // used by the callback function of VisitMemoryObject(). 836 struct MemoryElement 837 { 838 uint32_t index; // index of the scalar element 839 uint32_t offset; // offset (in bytes) from the base of the object 840 const Type &type; // element type 841 }; 842 843 using MemoryVisitor = std::function<void(const MemoryElement &)>; 844 845 // VisitMemoryObject() walks a type tree in an explicitly laid out 846 // storage class, calling the MemoryVisitor for each scalar element 847 // within the 848 void VisitMemoryObject(Object::ID id, const MemoryVisitor &v) const; 849 850 // VisitMemoryObjectInner() is internally called by VisitMemoryObject() 851 void VisitMemoryObjectInner(Type::ID id, Decorations d, uint32_t &index, uint32_t offset, const MemoryVisitor &v) const; 852 853 Object &CreateConstant(InsnIterator it); 854 855 void ProcessInterfaceVariable(Object &object); 856 857 // EmitState holds control-flow state for the emit() pass. 858 class EmitState 859 { 860 public: EmitState(SpirvRoutine * routine,Function::ID function,RValue<SIMD::Int> activeLaneMask,RValue<SIMD::Int> storesAndAtomicsMask,const vk::DescriptorSet::Bindings & descriptorSets,bool robustBufferAccess,spv::ExecutionModel executionModel)861 EmitState(SpirvRoutine *routine, 862 Function::ID function, 863 RValue<SIMD::Int> activeLaneMask, 864 RValue<SIMD::Int> storesAndAtomicsMask, 865 const vk::DescriptorSet::Bindings &descriptorSets, 866 bool robustBufferAccess, 867 spv::ExecutionModel executionModel) 868 : routine(routine) 869 , function(function) 870 , activeLaneMaskValue(activeLaneMask.value) 871 , storesAndAtomicsMaskValue(storesAndAtomicsMask.value) 872 , descriptorSets(descriptorSets) 873 , robustBufferAccess(robustBufferAccess) 874 , executionModel(executionModel) 875 { 876 ASSERT(executionModelToStage(executionModel) != VkShaderStageFlagBits(0)); // Must parse OpEntryPoint before emitting. 877 } 878 activeLaneMask() const879 RValue<SIMD::Int> activeLaneMask() const 880 { 881 ASSERT(activeLaneMaskValue != nullptr); 882 return RValue<SIMD::Int>(activeLaneMaskValue); 883 } 884 storesAndAtomicsMask() const885 RValue<SIMD::Int> storesAndAtomicsMask() const 886 { 887 ASSERT(storesAndAtomicsMaskValue != nullptr); 888 return RValue<SIMD::Int>(storesAndAtomicsMaskValue); 889 } 890 891 // Add a new active lane mask edge from the current block to out. 892 // The edge mask value will be (mask AND activeLaneMaskValue). 893 // If multiple active lane masks are added for the same edge, then 894 // they will be ORed together. 895 void addOutputActiveLaneMaskEdge(Block::ID out, RValue<SIMD::Int> mask); 896 897 // Add a new active lane mask for the edge from -> to. 898 // If multiple active lane masks are added for the same edge, then 899 // they will be ORed together. 900 void addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask); 901 902 SpirvRoutine *routine = nullptr; // The current routine being built. 903 Function::ID function; // The current function being built. 904 Block::ID block; // The current block being built. 905 rr::Value *activeLaneMaskValue = nullptr; // The current active lane mask. 906 rr::Value *storesAndAtomicsMaskValue = nullptr; // The current atomics mask. 907 Block::Set visited; // Blocks already built. 908 std::unordered_map<Block::Edge, RValue<SIMD::Int>, Block::Edge::Hash> edgeActiveLaneMasks; 909 std::deque<Block::ID> *pending; 910 911 const vk::DescriptorSet::Bindings &descriptorSets; 912 913 OutOfBoundsBehavior getOutOfBoundsBehavior(spv::StorageClass storageClass) const; 914 createIntermediate(Object::ID id,uint32_t size)915 Intermediate &createIntermediate(Object::ID id, uint32_t size) 916 { 917 auto it = intermediates.emplace(std::piecewise_construct, 918 std::forward_as_tuple(id), 919 std::forward_as_tuple(size)); 920 ASSERT_MSG(it.second, "Intermediate %d created twice", id.value()); 921 return it.first->second; 922 } 923 getIntermediate(Object::ID id) const924 Intermediate const &getIntermediate(Object::ID id) const 925 { 926 auto it = intermediates.find(id); 927 ASSERT_MSG(it != intermediates.end(), "Unknown intermediate %d", id.value()); 928 return it->second; 929 } 930 createPointer(Object::ID id,SIMD::Pointer ptr)931 void createPointer(Object::ID id, SIMD::Pointer ptr) 932 { 933 bool added = pointers.emplace(id, ptr).second; 934 ASSERT_MSG(added, "Pointer %d created twice", id.value()); 935 } 936 getPointer(Object::ID id) const937 SIMD::Pointer const &getPointer(Object::ID id) const 938 { 939 auto it = pointers.find(id); 940 ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value()); 941 return it->second; 942 } 943 944 private: 945 std::unordered_map<Object::ID, Intermediate> intermediates; 946 std::unordered_map<Object::ID, SIMD::Pointer> pointers; 947 948 const bool robustBufferAccess = true; // Emit robustBufferAccess safe code. 949 const spv::ExecutionModel executionModel = spv::ExecutionModelMax; 950 }; 951 952 // EmitResult is an enumerator of result values from the Emit functions. 953 enum class EmitResult 954 { 955 Continue, // No termination instructions. 956 Terminator, // Reached a termination instruction. 957 }; 958 959 // Generic wrapper over either per-lane intermediate value, or a constant. 960 // Constants are transparently widened to per-lane values in operator[]. 961 // This is appropriate in most cases -- if we're not going to do something 962 // significantly different based on whether the value is uniform across lanes. 963 class GenericValue 964 { 965 SpirvShader::Object const &obj; 966 Intermediate const *intermediate; 967 968 public: 969 GenericValue(SpirvShader const *shader, EmitState const *state, SpirvShader::Object::ID objId); 970 Float(uint32_t i) const971 RValue<SIMD::Float> Float(uint32_t i) const 972 { 973 if(intermediate) 974 { 975 return intermediate->Float(i); 976 } 977 978 // Constructing a constant SIMD::Float is not guaranteed to preserve the data's exact 979 // bit pattern, but SPIR-V provides 32-bit words representing "the bit pattern for the constant". 980 // Thus we must first construct an integer constant, and bitcast to float. 981 ASSERT(obj.kind == SpirvShader::Object::Kind::Constant); 982 auto constantValue = reinterpret_cast<uint32_t *>(obj.constantValue.get()); 983 return As<SIMD::Float>(SIMD::UInt(constantValue[i])); 984 } 985 Int(uint32_t i) const986 RValue<SIMD::Int> Int(uint32_t i) const 987 { 988 if(intermediate) 989 { 990 return intermediate->Int(i); 991 } 992 ASSERT(obj.kind == SpirvShader::Object::Kind::Constant); 993 auto constantValue = reinterpret_cast<int *>(obj.constantValue.get()); 994 return SIMD::Int(constantValue[i]); 995 } 996 UInt(uint32_t i) const997 RValue<SIMD::UInt> UInt(uint32_t i) const 998 { 999 if(intermediate) 1000 { 1001 return intermediate->UInt(i); 1002 } 1003 ASSERT(obj.kind == SpirvShader::Object::Kind::Constant); 1004 auto constantValue = reinterpret_cast<uint32_t *>(obj.constantValue.get()); 1005 return SIMD::UInt(constantValue[i]); 1006 } 1007 1008 SpirvShader::Type::ID const type; 1009 }; 1010 getType(Type::ID id) const1011 Type const &getType(Type::ID id) const 1012 { 1013 auto it = types.find(id); 1014 ASSERT_MSG(it != types.end(), "Unknown type %d", id.value()); 1015 return it->second; 1016 } 1017 getObject(Object::ID id) const1018 Object const &getObject(Object::ID id) const 1019 { 1020 auto it = defs.find(id); 1021 ASSERT_MSG(it != defs.end(), "Unknown object %d", id.value()); 1022 return it->second; 1023 } 1024 getFunction(Function::ID id) const1025 Function const &getFunction(Function::ID id) const 1026 { 1027 auto it = functions.find(id); 1028 ASSERT_MSG(it != functions.end(), "Unknown function %d", id.value()); 1029 return it->second; 1030 } 1031 getString(StringID id) const1032 String const &getString(StringID id) const 1033 { 1034 auto it = strings.find(id); 1035 ASSERT_MSG(it != strings.end(), "Unknown string %d", id.value()); 1036 return it->second; 1037 } 1038 getExtension(Extension::ID id) const1039 Extension const &getExtension(Extension::ID id) const 1040 { 1041 auto it = extensionsByID.find(id); 1042 ASSERT_MSG(it != extensionsByID.end(), "Unknown extension %d", id.value()); 1043 return it->second; 1044 } 1045 1046 // Returns a SIMD::Pointer to the underlying data for the given pointer 1047 // object. 1048 // Handles objects of the following kinds: 1049 // • DescriptorSet 1050 // • DivergentPointer 1051 // • InterfaceVariable 1052 // • NonDivergentPointer 1053 // Calling GetPointerToData with objects of any other kind will assert. 1054 SIMD::Pointer GetPointerToData(Object::ID id, int arrayIndex, EmitState const *state) const; 1055 1056 SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const; 1057 SIMD::Pointer WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const; 1058 1059 // Returns the *component* offset in the literal for the given access chain. 1060 uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const; 1061 1062 // Lookup the active lane mask for the edge from -> to. 1063 // If from is unreachable, then a mask of all zeros is returned. 1064 // Asserts if from is reachable and the edge does not exist. 1065 RValue<SIMD::Int> GetActiveLaneMaskEdge(EmitState *state, Block::ID from, Block::ID to) const; 1066 1067 // Updates the current active lane mask. 1068 void SetActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const; 1069 1070 // Emit all the unvisited blocks (except for ignore) in DFS order, 1071 // starting with id. 1072 void EmitBlocks(Block::ID id, EmitState *state, Block::ID ignore = 0) const; 1073 void EmitNonLoop(EmitState *state) const; 1074 void EmitLoop(EmitState *state) const; 1075 1076 void EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const; 1077 EmitResult EmitInstruction(InsnIterator insn, EmitState *state) const; 1078 1079 // Emit pass instructions: 1080 EmitResult EmitVariable(InsnIterator insn, EmitState *state) const; 1081 EmitResult EmitLoad(InsnIterator insn, EmitState *state) const; 1082 EmitResult EmitStore(InsnIterator insn, EmitState *state) const; 1083 EmitResult EmitAccessChain(InsnIterator insn, EmitState *state) const; 1084 EmitResult EmitCompositeConstruct(InsnIterator insn, EmitState *state) const; 1085 EmitResult EmitCompositeInsert(InsnIterator insn, EmitState *state) const; 1086 EmitResult EmitCompositeExtract(InsnIterator insn, EmitState *state) const; 1087 EmitResult EmitVectorShuffle(InsnIterator insn, EmitState *state) const; 1088 EmitResult EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const; 1089 EmitResult EmitMatrixTimesVector(InsnIterator insn, EmitState *state) const; 1090 EmitResult EmitVectorTimesMatrix(InsnIterator insn, EmitState *state) const; 1091 EmitResult EmitMatrixTimesMatrix(InsnIterator insn, EmitState *state) const; 1092 EmitResult EmitOuterProduct(InsnIterator insn, EmitState *state) const; 1093 EmitResult EmitTranspose(InsnIterator insn, EmitState *state) const; 1094 EmitResult EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const; 1095 EmitResult EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const; 1096 EmitResult EmitUnaryOp(InsnIterator insn, EmitState *state) const; 1097 EmitResult EmitBinaryOp(InsnIterator insn, EmitState *state) const; 1098 EmitResult EmitDot(InsnIterator insn, EmitState *state) const; 1099 EmitResult EmitSelect(InsnIterator insn, EmitState *state) const; 1100 EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const; 1101 EmitResult EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const; 1102 EmitResult EmitOpenCLDebugInfo100(InsnIterator insn, EmitState *state) const; 1103 EmitResult EmitLine(InsnIterator insn, EmitState *state) const; 1104 EmitResult EmitAny(InsnIterator insn, EmitState *state) const; 1105 EmitResult EmitAll(InsnIterator insn, EmitState *state) const; 1106 EmitResult EmitBranch(InsnIterator insn, EmitState *state) const; 1107 EmitResult EmitBranchConditional(InsnIterator insn, EmitState *state) const; 1108 EmitResult EmitSwitch(InsnIterator insn, EmitState *state) const; 1109 EmitResult EmitUnreachable(InsnIterator insn, EmitState *state) const; 1110 EmitResult EmitReturn(InsnIterator insn, EmitState *state) const; 1111 EmitResult EmitKill(InsnIterator insn, EmitState *state) const; 1112 EmitResult EmitFunctionCall(InsnIterator insn, EmitState *state) const; 1113 EmitResult EmitPhi(InsnIterator insn, EmitState *state) const; 1114 EmitResult EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const; 1115 EmitResult EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const; 1116 EmitResult EmitImageGather(Variant variant, InsnIterator insn, EmitState *state) const; 1117 EmitResult EmitImageFetch(InsnIterator insn, EmitState *state) const; 1118 EmitResult EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const; 1119 EmitResult EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const; 1120 EmitResult EmitImageQuerySize(InsnIterator insn, EmitState *state) const; 1121 EmitResult EmitImageQueryLod(InsnIterator insn, EmitState *state) const; 1122 EmitResult EmitImageQueryLevels(InsnIterator insn, EmitState *state) const; 1123 EmitResult EmitImageQuerySamples(InsnIterator insn, EmitState *state) const; 1124 EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const; 1125 EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const; 1126 EmitResult EmitImageTexelPointer(InsnIterator insn, EmitState *state) const; 1127 EmitResult EmitAtomicOp(InsnIterator insn, EmitState *state) const; 1128 EmitResult EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const; 1129 EmitResult EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const; 1130 EmitResult EmitCopyObject(InsnIterator insn, EmitState *state) const; 1131 EmitResult EmitCopyMemory(InsnIterator insn, EmitState *state) const; 1132 EmitResult EmitControlBarrier(InsnIterator insn, EmitState *state) const; 1133 EmitResult EmitMemoryBarrier(InsnIterator insn, EmitState *state) const; 1134 EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const; 1135 EmitResult EmitArrayLength(InsnIterator insn, EmitState *state) const; 1136 1137 void GetImageDimensions(EmitState const *state, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const; 1138 SIMD::Pointer GetTexelAddress(EmitState const *state, SIMD::Pointer base, GenericValue const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const; 1139 uint32_t GetConstScalarInt(Object::ID id) const; 1140 void EvalSpecConstantOp(InsnIterator insn); 1141 void EvalSpecConstantUnaryOp(InsnIterator insn); 1142 void EvalSpecConstantBinaryOp(InsnIterator insn); 1143 1144 // LoadPhi loads the phi values from the alloca storage and places the 1145 // load values into the intermediate with the phi's result id. 1146 void LoadPhi(InsnIterator insn, EmitState *state) const; 1147 1148 // StorePhi updates the phi's alloca storage value using the incoming 1149 // values from blocks that are both in the OpPhi instruction and in 1150 // filter. 1151 void StorePhi(Block::ID blockID, InsnIterator insn, EmitState *state, std::unordered_set<SpirvShader::Block::ID> const &filter) const; 1152 1153 // Emits a rr::Fence for the given MemorySemanticsMask. 1154 void Fence(spv::MemorySemanticsMask semantics) const; 1155 1156 // Helper for calling rr::Yield with res cast to an rr::Int. 1157 void Yield(YieldResult res) const; 1158 1159 // OpcodeName() returns the name of the opcode op. 1160 // If NDEBUG is defined, then OpcodeName() will only return the numerical code. 1161 static std::string OpcodeName(spv::Op op); 1162 static std::memory_order MemoryOrder(spv::MemorySemanticsMask memorySemantics); 1163 1164 // IsStatement() returns true if the given opcode actually performs 1165 // work (as opposed to declaring a type, defining a function start / end, 1166 // etc). 1167 static bool IsStatement(spv::Op op); 1168 1169 // Helper as we often need to take dot products as part of doing other things. 1170 SIMD::Float Dot(unsigned numComponents, GenericValue const &x, GenericValue const &y) const; 1171 1172 // Splits x into a floating-point significand in the range [0.5, 1.0) 1173 // and an integral exponent of two, such that: 1174 // x = significand * 2^exponent 1175 // Returns the pair <significand, exponent> 1176 std::pair<SIMD::Float, SIMD::Int> Frexp(RValue<SIMD::Float> val) const; 1177 1178 static ImageSampler *getImageSampler(uint32_t instruction, vk::SampledImageDescriptor const *imageDescriptor, const vk::Sampler *sampler); 1179 static std::shared_ptr<rr::Routine> emitSamplerRoutine(ImageInstruction instruction, const Sampler &samplerState); 1180 1181 // TODO(b/129523279): Eliminate conversion and use vk::Sampler members directly. 1182 static sw::FilterType convertFilterMode(const vk::Sampler *sampler); 1183 static sw::MipmapType convertMipmapMode(const vk::Sampler *sampler); 1184 static sw::AddressingMode convertAddressingMode(int coordinateIndex, const vk::Sampler *sampler, VkImageViewType imageViewType); 1185 1186 // Returns 0 when invalid. 1187 static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model); 1188 1189 // Debugger API functions. When ENABLE_VK_DEBUGGER is not defined, these 1190 // are all no-ops. 1191 1192 // dbgInit() initializes the debugger code generation. 1193 // All other dbgXXX() functions are no-op until this is called. 1194 void dbgInit(const std::shared_ptr<vk::dbg::Context> &dbgctx); 1195 1196 // dbgTerm() terminates the debugger code generation. 1197 void dbgTerm(); 1198 1199 // dbgCreateFile() generates a synthetic file containing the disassembly 1200 // of the SPIR-V shader. This is the file displayed in the debug 1201 // session. 1202 void dbgCreateFile(); 1203 1204 // dbgBeginEmit() sets up the debugging state for the shader. 1205 void dbgBeginEmit(EmitState *state) const; 1206 1207 // dbgEndEmit() tears down the debugging state for the shader. 1208 void dbgEndEmit(EmitState *state) const; 1209 1210 // dbgBeginEmitInstruction() updates the current debugger location for 1211 // the given instruction. 1212 void dbgBeginEmitInstruction(InsnIterator insn, EmitState *state) const; 1213 1214 // dbgEndEmitInstruction() creates any new debugger variables for the 1215 // instruction that just completed. 1216 void dbgEndEmitInstruction(InsnIterator insn, EmitState *state) const; 1217 1218 // dbgExposeIntermediate() exposes the intermediate with the given ID to 1219 // the debugger. 1220 void dbgExposeIntermediate(Object::ID id, EmitState *state) const; 1221 1222 // dbgUpdateActiveLaneMask() updates the active lane masks to the 1223 // debugger. 1224 void dbgUpdateActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const; 1225 1226 // dbgDeclareResult() associates resultId as the result of the given 1227 // instruction. 1228 void dbgDeclareResult(const InsnIterator &insn, Object::ID resultId) const; 1229 1230 // Impl holds forward declaration structs and pointers to state for the 1231 // private implementations in the corresponding SpirvShaderXXX.cpp files. 1232 // This allows access to the private members of the SpirvShader, without 1233 // littering the header with implementation details. 1234 struct Impl 1235 { 1236 struct Debugger; 1237 struct Group; 1238 Debugger *debugger = nullptr; 1239 }; 1240 Impl impl; 1241 }; 1242 1243 class SpirvRoutine 1244 { 1245 public: 1246 SpirvRoutine(vk::PipelineLayout const *pipelineLayout); 1247 1248 using Variable = Array<SIMD::Float>; 1249 1250 struct SamplerCache 1251 { 1252 Pointer<Byte> imageDescriptor = nullptr; 1253 Pointer<Byte> sampler; 1254 Pointer<Byte> function; 1255 }; 1256 1257 vk::PipelineLayout const *const pipelineLayout; 1258 1259 std::unordered_map<SpirvShader::Object::ID, Variable> variables; 1260 std::unordered_map<SpirvShader::Object::ID, SamplerCache> samplerCache; 1261 Variable inputs = Variable{ MAX_INTERFACE_COMPONENTS }; 1262 Variable outputs = Variable{ MAX_INTERFACE_COMPONENTS }; 1263 1264 Pointer<Byte> workgroupMemory; 1265 Pointer<Pointer<Byte>> descriptorSets; 1266 Pointer<Int> descriptorDynamicOffsets; 1267 Pointer<Byte> pushConstants; 1268 Pointer<Byte> constants; 1269 Int killMask = Int{ 0 }; 1270 1271 // Shader invocation state. 1272 // Not all of these variables are used for every type of shader, and some 1273 // are only used when debugging. See b/146486064 for more information. 1274 // Give careful consideration to the runtime performance loss before adding 1275 // more state here. 1276 SIMD::Int windowSpacePosition[2]; 1277 Int viewID; // slice offset into input attachments for multiview, even if the shader doesn't use ViewIndex 1278 Int instanceID; 1279 SIMD::Int vertexIndex; 1280 std::array<SIMD::Float, 4> fragCoord; 1281 std::array<SIMD::Float, 4> pointCoord; 1282 SIMD::Int helperInvocation; 1283 Int4 numWorkgroups; 1284 Int4 workgroupID; 1285 Int4 workgroupSize; 1286 Int subgroupsPerWorkgroup; 1287 Int invocationsPerSubgroup; 1288 Int subgroupIndex; 1289 SIMD::Int localInvocationIndex; 1290 std::array<SIMD::Int, 3> localInvocationID; 1291 std::array<SIMD::Int, 3> globalInvocationID; 1292 1293 Pointer<Byte> dbgState; // Pointer to a debugger state. 1294 createVariable(SpirvShader::Object::ID id,uint32_t size)1295 void createVariable(SpirvShader::Object::ID id, uint32_t size) 1296 { 1297 bool added = variables.emplace(id, Variable(size)).second; 1298 ASSERT_MSG(added, "Variable %d created twice", id.value()); 1299 } 1300 getVariable(SpirvShader::Object::ID id)1301 Variable &getVariable(SpirvShader::Object::ID id) 1302 { 1303 auto it = variables.find(id); 1304 ASSERT_MSG(it != variables.end(), "Unknown variables %d", id.value()); 1305 return it->second; 1306 } 1307 1308 // setImmutableInputBuiltins() sets all the immutable input builtins, 1309 // common for all shader types. 1310 void setImmutableInputBuiltins(SpirvShader const *shader); 1311 1312 // setInputBuiltin() calls f() with the builtin and value if the shader 1313 // uses the input builtin, otherwise the call is a no-op. 1314 // F is a function with the signature: 1315 // void(const SpirvShader::BuiltinMapping& builtin, Array<SIMD::Float>& value) 1316 template<typename F> setInputBuiltin(SpirvShader const * shader,spv::BuiltIn id,F && f)1317 inline void setInputBuiltin(SpirvShader const *shader, spv::BuiltIn id, F &&f) 1318 { 1319 auto it = shader->inputBuiltins.find(id); 1320 if(it != shader->inputBuiltins.end()) 1321 { 1322 const auto &builtin = it->second; 1323 f(builtin, getVariable(builtin.Id)); 1324 } 1325 } 1326 1327 private: 1328 // The phis are only accessible to SpirvShader as they are only used and 1329 // exist between calls to SpirvShader::emitProlog() and 1330 // SpirvShader::emitEpilog(). 1331 friend class SpirvShader; 1332 1333 std::unordered_map<SpirvShader::Object::ID, Variable> phis; 1334 }; 1335 1336 } // namespace sw 1337 1338 #endif // sw_SpirvShader_hpp 1339