RayTracingIndexList.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <AzCore/std/containers/vector.h>
  10. #include <AzCore/std/containers/map.h>
  11. #include <AzCore/Casting/numeric_cast.h>
  12. namespace AZ
  13. {
  14. namespace Render
  15. {
  16. static const uint32_t InvalidIndex = aznumeric_cast<uint32_t>(-1);
  17. //! Manages an index list used by RayTracing, with an internal freelist chain.
  18. //!
  19. //! Indices are stored in a flat array, and new indices are either added to the end
  20. //! or in the first available free index.
  21. //!
  22. //! The freelist chain is stored inside array itself, with each entry in the chain pointing
  23. //! to the next free index, and terminated with InvalidIndex. Free list entries have
  24. //! FreeListThreshold added to their value to indicate they are part of the freelist.
  25. template<uint32_t BlockSize>
  26. class RayTracingIndexList
  27. {
  28. public:
  29. RayTracingIndexList() = default;
  30. ~RayTracingIndexList() = default;
  31. // add a BlockSize set of entries to the index list
  32. uint32_t AddEntry(AZStd::array<uint32_t, BlockSize> entry);
  33. // add an entry, non-array version for use when BlockSize == 1
  34. uint32_t AddEntry(uint32_t entry);
  35. // set a BlockSize set of entries at the specified index
  36. void SetEntry(uint32_t index, AZStd::array<uint32_t, BlockSize> entry);
  37. // set an existing entry, non-array version for use when BlockSize == 1
  38. void SetEntry(uint32_t index, uint32_t entry);
  39. // remove BlockSize entries starting at the specified index
  40. void RemoveEntry(uint32_t index);
  41. // returns the index list
  42. using IndexVector = AZStd::vector<uint32_t>;
  43. const IndexVector& GetIndexList() const { return m_indices; }
  44. // returns true if the index is valid
  45. bool IsValidIndex(uint32_t index) const;
  46. // clears the index list and all associated state
  47. void Reset();
  48. private:
  49. // freelist index entries are at or above this value
  50. static const uint32_t FreeListThreshold = 1000000000;
  51. // helper functions to encode/decode freelist chain indices
  52. uint32_t EncodeFreeListIndex(uint32_t index) const { return (index == InvalidIndex) ? InvalidIndex : (index + FreeListThreshold); }
  53. uint32_t DecodeFreeListIndex(uint32_t index) const { return (index == InvalidIndex) ? InvalidIndex : (index - FreeListThreshold); }
  54. // list of indices
  55. IndexVector m_indices;
  56. // starting index of the freelist chain
  57. uint32_t m_freeStartIndex = InvalidIndex;
  58. };
  59. template<uint32_t BlockSize>
  60. uint32_t RayTracingIndexList<BlockSize>::AddEntry(AZStd::array<uint32_t, BlockSize> entry)
  61. {
  62. uint32_t index = 0;
  63. if (m_freeStartIndex == InvalidIndex)
  64. {
  65. // no free entries, insert at the end of the index list
  66. index = aznumeric_cast<uint32_t>(m_indices.size());
  67. m_indices.insert(m_indices.end(), entry.begin(), entry.end());
  68. }
  69. else
  70. {
  71. // get the next free index from the list
  72. uint32_t nextFreeIndex = m_indices[m_freeStartIndex];
  73. // overwrite the indices list with the new entries at the free index
  74. index = m_freeStartIndex;
  75. AZStd::copy(entry.begin(), entry.end(), m_indices.begin() + index);
  76. // move the start of the free index chain to nextFreeIndex
  77. m_freeStartIndex = DecodeFreeListIndex(nextFreeIndex);
  78. }
  79. return index;
  80. }
  81. template<uint32_t BlockSize>
  82. uint32_t RayTracingIndexList<BlockSize>::AddEntry(uint32_t entry)
  83. {
  84. return AddEntry(AZStd::array<uint32_t, 1>{entry});
  85. }
  86. template<uint32_t BlockSize>
  87. void RayTracingIndexList<BlockSize>::SetEntry(uint32_t index, AZStd::array<uint32_t, BlockSize> entry)
  88. {
  89. AZ_Assert(index < m_indices.size(), "Index passed to SetEntry exceeds list size");
  90. AZ_Assert(index % BlockSize == 0, "Index passed must be a multiple of the BlockSize");
  91. AZStd::copy(entry.begin(), entry.end(), m_indices.begin() + index);
  92. }
  93. template<uint32_t BlockSize>
  94. void RayTracingIndexList<BlockSize>::SetEntry(uint32_t index, uint32_t entry)
  95. {
  96. SetEntry(index, AZStd::array<uint32_t, 1>{entry});
  97. }
  98. template<uint32_t BlockSize>
  99. void RayTracingIndexList<BlockSize>::RemoveEntry(uint32_t index)
  100. {
  101. if (m_freeStartIndex == InvalidIndex)
  102. {
  103. // no free entries, just set the start index to this entry
  104. m_freeStartIndex = index;
  105. }
  106. else
  107. {
  108. // walk the free index chain until we reach the end (marked by InvalidIndex)
  109. uint32_t currentIndex = m_freeStartIndex;
  110. uint32_t nextIndex = DecodeFreeListIndex(m_indices[currentIndex]);
  111. while (nextIndex != InvalidIndex)
  112. {
  113. currentIndex = nextIndex;
  114. nextIndex = DecodeFreeListIndex(m_indices[nextIndex]);
  115. }
  116. // store the index
  117. m_indices[currentIndex] = EncodeFreeListIndex(index);
  118. }
  119. // terminate the free index chain by setting the last entry to InvalidIndex
  120. m_indices[index] = InvalidIndex;
  121. }
  122. template<uint32_t BlockSize>
  123. bool RayTracingIndexList<BlockSize>::IsValidIndex(uint32_t index) const
  124. {
  125. return (index < FreeListThreshold);
  126. }
  127. template<uint32_t BlockSize>
  128. void RayTracingIndexList<BlockSize>::Reset()
  129. {
  130. m_indices.clear();
  131. m_freeStartIndex = InvalidIndex;
  132. }
  133. }
  134. }