RayTracingResourceList.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 <Atom/Feature/RayTracing/RayTracingIndexList.h>
  10. #include <AzCore/std/containers/vector.h>
  11. #include <AzCore/std/containers/map.h>
  12. #include <AzCore/Casting/numeric_cast.h>
  13. namespace AZ
  14. {
  15. namespace Render
  16. {
  17. //! Manages a resource list used by RayTracing.
  18. //!
  19. //! Resources are stored in a flat array. There is also a map that stores the index of the resource
  20. //! in the array, its reference count, and the index in the indirection list. This map is used to determine
  21. //! if the resource is already known, and how to locate its entries in the resource and indirection lists.
  22. //!
  23. //! The indirection list provides a stable index for resources, and is returned to clients of this class.
  24. //! This allows resources to be moved in the resource array without affecting externally held indices,
  25. //! since these refer to the indirection list, which in turn points to the resource list.
  26. template<class TResource>
  27. class RayTracingResourceList
  28. {
  29. public:
  30. using ResourceVector = AZStd::vector<const TResource*>;
  31. using IndexVector = AZStd::vector<uint32_t>;
  32. RayTracingResourceList() = default;
  33. ~RayTracingResourceList() = default;
  34. // adds a resource to the list, or increments the reference count, and returns the index of the resource
  35. // Note: the index returned is an indirection index, meaning it is stable when other entries are removed
  36. uint32_t AddResource(const TResource* resource);
  37. // removes a resource from the list, or decrements the reference count
  38. // Note: removing a resource will not affect any previously returned indices for other resources
  39. void RemoveResource(const TResource* resource);
  40. // returns the resource list
  41. ResourceVector& GetResourceList() { return m_resources; }
  42. // returns the indirection list
  43. const IndexVector& GetIndirectionList() const { return m_indirectionList.GetIndexList(); }
  44. // clears the resource list and all associated state
  45. void Reset();
  46. private:
  47. struct IndexMapEntry
  48. {
  49. // index of the entry in the main list
  50. uint32_t m_index = InvalidIndex;
  51. // index of the entry in the indirection list
  52. uint32_t m_indirectionIndex = InvalidIndex;
  53. // reference count
  54. uint32_t m_count = 0;
  55. };
  56. using ResourceMap = AZStd::map<const TResource*, IndexMapEntry>;
  57. ResourceVector m_resources;
  58. ResourceMap m_resourceMap;
  59. RayTracingIndexList<1> m_indirectionList;
  60. };
  61. template<class TResource>
  62. uint32_t RayTracingResourceList<TResource>::AddResource(const TResource* resource)
  63. {
  64. if (resource == nullptr)
  65. {
  66. return InvalidIndex;
  67. }
  68. uint32_t indirectionIndex = 0;
  69. typename ResourceMap::iterator it = m_resourceMap.find(resource);
  70. if (it == m_resourceMap.end())
  71. {
  72. // resource not found, add it to the resource list and the indirection list
  73. m_resources.push_back(resource);
  74. uint32_t resourceIndex = aznumeric_cast<uint32_t>(m_resources.size()) - 1;
  75. indirectionIndex = m_indirectionList.AddEntry(resourceIndex);
  76. // add the resource map entry containing the true index, indirection index, and reference count
  77. IndexMapEntry entry;
  78. entry.m_index = resourceIndex;
  79. entry.m_indirectionIndex = indirectionIndex;
  80. entry.m_count = 1;
  81. m_resourceMap.insert({ resource, entry });
  82. }
  83. else
  84. {
  85. // resource is already known, update the reference count and return the indirection index
  86. it->second.m_count++;
  87. indirectionIndex = it->second.m_indirectionIndex;
  88. }
  89. return indirectionIndex;
  90. }
  91. template<class TResource>
  92. void RayTracingResourceList<TResource>::RemoveResource(const TResource* resource)
  93. {
  94. if (resource == nullptr)
  95. {
  96. return;
  97. }
  98. typename ResourceMap::iterator it = m_resourceMap.find(resource);
  99. AZ_Assert(it != m_resourceMap.end(), "Unable to find resource in the ResourceMap");
  100. // decrement reference count
  101. it->second.m_count--;
  102. // if the reference count is zero then remove the entry from both the map and the main resource list
  103. if (it->second.m_count == 0)
  104. {
  105. uint32_t resourceIndex = it->second.m_index;
  106. if (resourceIndex < m_resources.size() - 1)
  107. {
  108. // the resource we're removing is in the middle of the list - swap the last entry to this position
  109. typename ResourceMap::iterator itLast = m_resourceMap.find(m_resources.back());
  110. AZ_Assert(itLast != m_resourceMap.end(), "Unable to find the last resource in the ResourceMap");
  111. m_resources[resourceIndex] = m_resources.back();
  112. // update the swapped entry with its new index in the resource list
  113. itLast->second.m_index = resourceIndex;
  114. // update the indirection vector entry of the swapped entry to point to the new position
  115. // Note: any indirection indices returned by AddResource for other resources remain stable, this just updates the indirection entry
  116. m_indirectionList.SetEntry(itLast->second.m_indirectionIndex, resourceIndex);
  117. }
  118. // cache the indirection index so that its okay to erase the iterator
  119. uint32_t cachedIndirectionIndex = it->second.m_indirectionIndex;
  120. // remove the last entry from the resource list
  121. m_resources.pop_back();
  122. // remove the entry from the resource map
  123. m_resourceMap.erase(it);
  124. // remove the entry from the indirection list
  125. m_indirectionList.RemoveEntry(cachedIndirectionIndex);
  126. }
  127. }
  128. template<class TResource>
  129. void RayTracingResourceList<TResource>::Reset()
  130. {
  131. m_resources.clear();
  132. m_resourceMap.clear();
  133. m_indirectionList.Reset();
  134. }
  135. }
  136. }