MeshInstanceGroupList.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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. class ModelDataInstance;
  18. //! This struct contains all the data for a group of meshes that are capable of being rendered
  19. //! with a single instanced draw call
  20. struct MeshInstanceGroupData
  21. {
  22. // The original draw packet, shared by every instance
  23. RPI::MeshDrawPacket m_drawPacket;
  24. // We modify the original draw packet each frame with a new instance count and a new root constant offset
  25. // The instance count and offset varies per view, so we keep one modifiable copy of the draw packet for each view
  26. AZStd::vector<RHI::Ptr<RHI::DrawPacket>> m_perViewDrawPackets;
  27. // All draw items in a draw packet share the same root constant layout
  28. uint32_t m_drawRootConstantOffset = 0;
  29. // The current instance group count
  30. uint32_t m_count = 0;
  31. // The page that this instance group belongs to
  32. uint32_t m_pageIndex = 0;
  33. // We store a key with the data to make it faster to remove the instance without needing to recreate the key
  34. // or store it with the data for each individual instance
  35. MeshInstanceGroupKey m_key;
  36. // A list of ModelDataInstances which are referencing this instance group
  37. AZStd::set<ModelDataInstance*> m_associatedInstances;
  38. // Mutex for adding/removing associated ModelDataInstance
  39. AZStd::mutex m_eventLock;
  40. // Enable draw motion or not. Set to true if any of mesh instance use this group has the same flag set in their ModelDataInstance
  41. bool m_isDrawMotion = false;
  42. // If the group is transparent, sort depth in reverse
  43. bool m_isTransparent = false;
  44. // For per-mesh shader options
  45. // If all the ModelDataInstances within this group are using the same shader option value, then we can apply the mesh shader options to the draw packet.
  46. // These are two variables which are used to indicate which shader option should be applied and which value is applied.
  47. // combined shader options from any ModelDataInstance which use this group
  48. uint32_t m_shaderOptionFlags = 0;
  49. // flag shader option flags which are in use
  50. uint32_t m_shaderOptionFlagMask = 0;
  51. // Update mesh draw packet
  52. // Return true if DrawPacket was rebuilt
  53. bool UpdateDrawPacket(const RPI::Scene& parentScene, bool forceUpdate);
  54. // Update shader option flags for the instance group
  55. // It goes through the cullable's m_shaderOptionFlags of each associated ModelDataInstance and get combined m_shaderOptionFlags and m_shaderOptionFlagMask
  56. // Return true if flags or mask changed.
  57. bool UpdateShaderOptionFlags();
  58. // Add/remove an associated ModelDataInstance (thread safe)
  59. void AddAssociatedInstance(ModelDataInstance* instance);
  60. void RemoveAssociatedInstance(ModelDataInstance* instance);
  61. };
  62. //! Manages all the instance groups used by mesh instancing.
  63. //!
  64. //! Data is stored in pages. There is also a map that stores a handle the data in the array, and its reference count.
  65. //! This map is used to determine if the instance group is already known, and how to access it.
  66. class MeshInstanceGroupList
  67. {
  68. public:
  69. using WeakHandle = StableDynamicArrayWeakHandle<MeshInstanceGroupData>;
  70. using OwningHandle = StableDynamicArrayHandle<MeshInstanceGroupData>;
  71. using StableDynamicArrayType = StableDynamicArray<MeshInstanceGroupData, 4096>;
  72. using ParallelRanges = StableDynamicArrayType::ParallelRanges;
  73. // When adding a new entry, we get back both the index and the count of meshes in the group after inserting
  74. // The count can be used to determine if this is the first mesh in the group (and thus intialization may be required)
  75. // As well as to determine if the mesh has reached the threshold at which it can become instanced,
  76. // if support for such a threshold is added
  77. struct InsertResult
  78. {
  79. StableDynamicArrayWeakHandle<MeshInstanceGroupData> m_handle;
  80. uint32_t m_instanceCount = 0;
  81. uint32_t m_pageIndex = 0;
  82. };
  83. // Adds a new instance group if none with a matching key exists, or increments the reference count if one already does,
  84. // and returns the handle to data and the number of instances in the group
  85. InsertResult Add(const MeshInstanceGroupKey& key);
  86. // Decrements the reference count of an instance group, and removes the data if the count drops to 0
  87. // Removing a instance group will not affect any previously returned handles for other instance groups
  88. void Remove(const MeshInstanceGroupKey& key);
  89. // Returns the number of instance groups
  90. uint32_t GetInstanceGroupCount() const;
  91. // Returns parallel ranges for the underlying instance group data. Each range corresponds to a page of data.
  92. ParallelRanges GetParallelRanges();
  93. // Direct access via handle is thread safe while adding and removing other instance groups
  94. MeshInstanceGroupData& operator[](WeakHandle handle);
  95. const MeshInstanceGroupData& operator[](WeakHandle handle) const;
  96. struct IndexMapEntry
  97. {
  98. IndexMapEntry() = default;
  99. IndexMapEntry(IndexMapEntry&& rhs)
  100. {
  101. m_handle = AZStd::move(rhs.m_handle);
  102. m_count = rhs.m_count;
  103. }
  104. // Handle to the entry in the stable array
  105. OwningHandle m_handle;
  106. // Reference count
  107. uint32_t m_count = 0;
  108. };
  109. using DataMap = AZStd::unordered_map<MeshInstanceGroupKey, IndexMapEntry>;
  110. private:
  111. StableDynamicArrayType m_instanceGroupData;
  112. DataMap m_dataMap;
  113. AZStd::concurrency_checker m_instanceDataConcurrencyChecker;
  114. };
  115. } // namespace AZ::Render