MeshInstanceGroupList.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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 <Mesh/MeshInstanceGroupKey.h>
  10. #include <Atom/RPI.Public/MeshDrawPacket.h>
  11. #include <Atom/Utils/StableDynamicArray.h>
  12. #include <AtomCore/std/parallel/concurrency_checker.h>
  13. #include <AzCore/std/containers/vector.h>
  14. #include <AzCore/std/containers/unordered_map.h>
  15. namespace AZ::Render
  16. {
  17. //! This struct contains all the data for a group of meshes that are capable of being rendered
  18. //! with a single instanced draw call
  19. struct MeshInstanceGroupData
  20. {
  21. // The original draw packet, shared by every instance
  22. RPI::MeshDrawPacket m_drawPacket;
  23. // We modify the original draw packet each frame with a new instance count and a new root constant offset
  24. // The instance count and offset varies per view, so we keep one modifiable copy of the draw packet for each view
  25. AZStd::vector<RHI::Ptr<RHI::DrawPacket>> m_perViewDrawPackets;
  26. // All draw items in a draw packet share the same root constant layout
  27. uint32_t m_drawRootConstantOffset = 0;
  28. // The current instance group count
  29. uint32_t m_count = 0;
  30. // The page that this instance group belongs to
  31. uint32_t m_pageIndex = 0;
  32. // We store a key with the data to make it faster to remove the instance without needing to recreate the key
  33. // or store it with the data for each individual instance
  34. MeshInstanceGroupKey m_key;
  35. // Event to signal to any data instance that refers to this InstanceGroup that the draw packet has been updated
  36. AZ::Event<> m_updateDrawPacketEvent;
  37. // Connecting to an AZ::Event is not thread safe, so we need to protect that with a lock
  38. AZStd::mutex m_eventLock;
  39. // Enable draw motion or not. Set to true if any of mesh instance use this group has the same flag set in their ModelDataInstance
  40. bool m_isDrawMotion = false;
  41. // If the group is transparent, sort depth in reverse
  42. bool m_isTransparent = false;
  43. };
  44. //! Manages all the instance groups used by mesh instancing.
  45. //!
  46. //! Data is stored in pages. There is also a map that stores a handle the data in the array, and its reference count.
  47. //! This map is used to determine if the instance group is already known, and how to access it.
  48. class MeshInstanceGroupList
  49. {
  50. public:
  51. using WeakHandle = StableDynamicArrayWeakHandle<MeshInstanceGroupData>;
  52. using OwningHandle = StableDynamicArrayHandle<MeshInstanceGroupData>;
  53. using StableDynamicArrayType = StableDynamicArray<MeshInstanceGroupData, 4096>;
  54. using ParallelRanges = StableDynamicArrayType::ParallelRanges;
  55. // When adding a new entry, we get back both the index and the count of meshes in the group after inserting
  56. // The count can be used to determine if this is the first mesh in the group (and thus intialization may be required)
  57. // As well as to determine if the mesh has reached the threshold at which it can become instanced,
  58. // if support for such a threshold is added
  59. struct InsertResult
  60. {
  61. StableDynamicArrayWeakHandle<MeshInstanceGroupData> m_handle;
  62. uint32_t m_instanceCount = 0;
  63. uint32_t m_pageIndex = 0;
  64. };
  65. // Adds a new instance group if none with a matching key exists, or increments the reference count if one already does,
  66. // and returns the handle to data and the number of instances in the group
  67. InsertResult Add(const MeshInstanceGroupKey& key);
  68. // Decrements the reference count of an instance group, and removes the data if the count drops to 0
  69. // Removing a instance group will not affect any previously returned handles for other instance groups
  70. void Remove(const MeshInstanceGroupKey& key);
  71. // Returns the number of instance groups
  72. uint32_t GetInstanceGroupCount() const;
  73. // Returns parallel ranges for the underlying instance group data. Each range corresponds to a page of data.
  74. ParallelRanges GetParallelRanges();
  75. // Direct access via handle is thread safe while adding and removing other instance groups
  76. MeshInstanceGroupData& operator[](WeakHandle handle);
  77. const MeshInstanceGroupData& operator[](WeakHandle handle) const;
  78. struct IndexMapEntry
  79. {
  80. IndexMapEntry() = default;
  81. IndexMapEntry(IndexMapEntry&& rhs)
  82. {
  83. m_handle = AZStd::move(rhs.m_handle);
  84. m_count = rhs.m_count;
  85. }
  86. // Handle to the entry in the stable array
  87. OwningHandle m_handle;
  88. // Reference count
  89. uint32_t m_count = 0;
  90. };
  91. using DataMap = AZStd::unordered_map<MeshInstanceGroupKey, IndexMapEntry>;
  92. private:
  93. StableDynamicArrayType m_instanceGroupData;
  94. DataMap m_dataMap;
  95. AZStd::concurrency_checker m_instanceDataConcurrencyChecker;
  96. };
  97. } // namespace AZ::Render