DxilSignatureAllocator.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilSignatureAllocator.h //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Classes used for allocating signature elements. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #pragma once
  12. #include "dxc/DXIL/DxilConstants.h"
  13. #include <vector>
  14. namespace hlsl {
  15. class DxilSignatureAllocator {
  16. public:
  17. class PackElement {
  18. public:
  19. virtual ~PackElement() {}
  20. virtual uint32_t GetID() const = 0;
  21. virtual DXIL::SemanticKind GetKind() const = 0;
  22. virtual DXIL::InterpolationMode GetInterpolationMode() const = 0;
  23. virtual DXIL::SemanticInterpretationKind GetInterpretation() const = 0;
  24. virtual DXIL::SignatureDataWidth GetDataBitWidth() const = 0;
  25. virtual uint32_t GetRows() const = 0;
  26. virtual uint32_t GetCols() const = 0;
  27. virtual bool IsAllocated() const = 0;
  28. virtual uint32_t GetStartRow() const = 0;
  29. virtual uint32_t GetStartCol() const = 0;
  30. virtual void ClearLocation() = 0;
  31. virtual void SetLocation(uint32_t StartRow, uint32_t StartCol) = 0;
  32. };
  33. class DummyElement : public PackElement {
  34. public:
  35. uint32_t id;
  36. uint32_t rows, cols;
  37. uint32_t row, col;
  38. DXIL::SemanticKind kind;
  39. DXIL::InterpolationMode interpolation;
  40. DXIL::SemanticInterpretationKind interpretation;
  41. DXIL::SignatureDataWidth dataBitWidth;
  42. uint32_t indexFlags;
  43. public:
  44. DummyElement(uint32_t index = 0) : id(index), rows(1), cols(1), row((uint32_t)-1), col((uint32_t)-1),
  45. kind(DXIL::SemanticKind::Arbitrary),
  46. interpolation(DXIL::InterpolationMode::Undefined),
  47. interpretation(DXIL::SemanticInterpretationKind::Arb),
  48. dataBitWidth(DXIL::SignatureDataWidth::Undefined),
  49. indexFlags(0)
  50. {}
  51. ~DummyElement() override {}
  52. uint32_t GetID() const override { return id; }
  53. DXIL::SemanticKind GetKind() const override { return kind; }
  54. DXIL::InterpolationMode GetInterpolationMode() const override { return interpolation; }
  55. DXIL::SemanticInterpretationKind GetInterpretation() const override { return interpretation; }
  56. DXIL::SignatureDataWidth GetDataBitWidth() const override { return dataBitWidth; }
  57. uint32_t GetRows() const override { return rows; }
  58. uint32_t GetCols() const override { return cols; }
  59. bool IsAllocated() const override { return row != (uint32_t)-1; }
  60. uint32_t GetStartRow() const override { return row; }
  61. uint32_t GetStartCol() const override { return col; }
  62. void ClearLocation() override { row = col = (uint32_t)-1; }
  63. void SetLocation(uint32_t Row, uint32_t Col) override { row = Row; col = Col; }
  64. };
  65. // index flags
  66. static const uint8_t kIndexedUp = 1 << 0; // Indexing continues upwards
  67. static const uint8_t kIndexedDown = 1 << 1; // Indexing continues downwards
  68. static uint8_t GetIndexFlags(unsigned row, unsigned rows) {
  69. return ((row > 0) ? kIndexedUp : 0) | ((row < rows - 1) ? kIndexedDown : 0);
  70. }
  71. // element flags
  72. static const uint8_t kEFOccupied = 1 << 0;
  73. static const uint8_t kEFArbitrary = 1 << 1;
  74. static const uint8_t kEFSGV = 1 << 2;
  75. static const uint8_t kEFSV = 1 << 3;
  76. static const uint8_t kEFTessFactor = 1 << 4;
  77. static const uint8_t kEFClipCull = 1 << 5;
  78. static const uint8_t kEFConflictsWithIndexed = kEFSGV | kEFSV;
  79. static uint8_t GetElementFlags(const PackElement *SE);
  80. // The following two functions enforce the rules of component ordering when packing different
  81. // kinds of elements into the same register.
  82. // given element flags, return element flags that conflict when placed to the left of the element
  83. static uint8_t GetConflictFlagsLeft(uint8_t flags);
  84. // given element flags, return element flags that conflict when placed to the right of the element
  85. static uint8_t GetConflictFlagsRight(uint8_t flags);
  86. enum ConflictType {
  87. kNoConflict = 0,
  88. kConflictsWithIndexed,
  89. kConflictsWithIndexedTessFactor,
  90. kConflictsWithInterpolationMode,
  91. kInsufficientFreeComponents,
  92. kOverlapElement,
  93. kIllegalComponentOrder,
  94. kConflictFit,
  95. kConflictDataWidth,
  96. };
  97. struct PackedRegister {
  98. // Flags:
  99. // - for occupied components, they signify element flags
  100. // - for unoccupied components, they signify conflict flags
  101. uint8_t Flags[4];
  102. DXIL::InterpolationMode Interp : 8;
  103. uint8_t IndexFlags : 2;
  104. uint8_t IndexingFixed : 1;
  105. DXIL::SignatureDataWidth DataWidth; // length of each scalar type in bytes. (2 or 4 for now)
  106. PackedRegister();
  107. ConflictType DetectRowConflict(uint8_t flags, uint8_t indexFlags, DXIL::InterpolationMode interp, unsigned width, DXIL::SignatureDataWidth dataWidth);
  108. ConflictType DetectColConflict(uint8_t flags, unsigned col, unsigned width);
  109. void PlaceElement(uint8_t flags, uint8_t indexFlags, DXIL::InterpolationMode interp, unsigned col, unsigned width, DXIL::SignatureDataWidth dataWidth);
  110. };
  111. DxilSignatureAllocator(unsigned numRegisters, bool useMinPrecision);
  112. bool GetIgnoreIndexing() const { return m_bIgnoreIndexing; }
  113. void SetIgnoreIndexing(bool ignoreIndexing) { m_bIgnoreIndexing = ignoreIndexing; }
  114. ConflictType DetectRowConflict(const PackElement *SE, unsigned row);
  115. ConflictType DetectColConflict(const PackElement *SE, unsigned row, unsigned col);
  116. void PlaceElement(const PackElement *SE, unsigned row, unsigned col);
  117. // FindNext/PackNext return found/packed location + element rows if found,
  118. // otherwise, they return 0.
  119. unsigned FindNext(unsigned &foundRow, unsigned &foundCol,
  120. PackElement* SE, unsigned startRow, unsigned numRows, unsigned startCol = 0);
  121. unsigned PackNext(PackElement* SE, unsigned startRow, unsigned numRows, unsigned startCol = 0);
  122. // Simple greedy in-order packer used by PackOptimized
  123. unsigned PackGreedy(std::vector<PackElement*> elements, unsigned startRow, unsigned numRows, unsigned startCol = 0);
  124. // Optimized packing algorithm - appended elements may affect positions of prior elements.
  125. unsigned PackOptimized(std::vector<PackElement*> elements, unsigned startRow, unsigned numRows);
  126. // Pack in a prefix-stable way - appended elements do not affect positions of prior elements.
  127. unsigned PackPrefixStable(std::vector<PackElement*> elements, unsigned startRow, unsigned numRows);
  128. bool UseMinPrecision() const { return m_bUseMinPrecision; }
  129. protected:
  130. std::vector<PackedRegister> m_Registers;
  131. bool m_bIgnoreIndexing;
  132. bool m_bUseMinPrecision;
  133. };
  134. } // namespace hlsl