AreaSystemComponent.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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/Component/Component.h>
  10. #include <Vegetation/Ebuses/AreaSystemRequestBus.h>
  11. #include <Vegetation/Ebuses/AreaRequestBus.h>
  12. #include <Vegetation/Ebuses/SystemConfigurationBus.h>
  13. #include <AzCore/std/parallel/semaphore.h>
  14. #include <AzCore/Component/TickBus.h>
  15. #include <AzCore/std/parallel/thread.h>
  16. #include <GradientSignal/Ebuses/SectorDataRequestBus.h>
  17. #include <SurfaceData/SurfaceDataSystemNotificationBus.h>
  18. #include <CrySystemBus.h>
  19. #include <ISystem.h>
  20. #include <AzFramework/Terrain/TerrainDataRequestBus.h>
  21. namespace Vegetation
  22. {
  23. struct DebugData;
  24. enum class SnapMode : AZ::u8
  25. {
  26. Corner = 0,
  27. Center
  28. };
  29. /**
  30. * The configuration for managing areas mostly the dimensions of the sectors
  31. */
  32. class AreaSystemConfig
  33. : public AZ::ComponentConfig
  34. {
  35. public:
  36. AZ_CLASS_ALLOCATOR(AreaSystemConfig, AZ::SystemAllocator);
  37. AZ_RTTI(AreaSystemConfig, "{14CCBE43-52DD-4F56-92A8-2BB011A0F7A2}", AZ::ComponentConfig);
  38. static void Reflect(AZ::ReflectContext* context);
  39. bool operator == (const AreaSystemConfig& other) const
  40. {
  41. return m_viewRectangleSize == other.m_viewRectangleSize
  42. && m_sectorDensity == other.m_sectorDensity
  43. && m_sectorSizeInMeters == other.m_sectorSizeInMeters
  44. && m_threadProcessingIntervalMs == other.m_threadProcessingIntervalMs
  45. && m_sectorSearchPadding == other.m_sectorSearchPadding
  46. && m_sectorPointSnapMode == other.m_sectorPointSnapMode;
  47. }
  48. int m_viewRectangleSize = 13;
  49. int m_sectorDensity = 20;
  50. int m_sectorSizeInMeters = 16;
  51. int m_threadProcessingIntervalMs = 500;
  52. int m_sectorSearchPadding = 0;
  53. SnapMode m_sectorPointSnapMode = SnapMode::Corner;
  54. private:
  55. static const int s_maxViewRectangleSize;
  56. static const int s_maxSectorDensity;
  57. static const int s_maxSectorSizeInMeters;
  58. static const int s_maxInstancesPerMeter;
  59. static const int64_t s_maxVegetationInstances;
  60. AZ::Outcome<void, AZStd::string> ValidateViewArea(void* newValue, const AZ::Uuid& valueType);
  61. AZ::Outcome<void, AZStd::string> ValidateSectorDensity(void* newValue, const AZ::Uuid& valueType);
  62. AZ::Outcome<void, AZStd::string> ValidateSectorSize(void* newValue, const AZ::Uuid& valueType);
  63. };
  64. /**
  65. * Manages an sectors and claims while the camera scrolls through the 3D world
  66. */
  67. class AreaSystemComponent
  68. : public AZ::Component
  69. , private AZ::TickBus::Handler
  70. , private AreaSystemRequestBus::Handler
  71. , private GradientSignal::SectorDataRequestBus::Handler
  72. , private SystemConfigurationRequestBus::Handler
  73. , private CrySystemEventBus::Handler
  74. , private ISystemEventListener
  75. , private SurfaceData::SurfaceDataSystemNotificationBus::Handler
  76. , private AzFramework::Terrain::TerrainDataNotificationBus::Handler
  77. {
  78. public:
  79. friend class EditorAreaSystemComponent;
  80. AZ_COMPONENT(AreaSystemComponent, "{7CE8E791-6BC6-4C88-8727-A476DE00F9A1}");
  81. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
  82. static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
  83. static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
  84. static void Reflect(AZ::ReflectContext* context);
  85. AreaSystemComponent(const AreaSystemConfig& configuration);
  86. AreaSystemComponent() = default;
  87. ~AreaSystemComponent() = default;
  88. //////////////////////////////////////////////////////////////////////////
  89. // AZ::Component interface implementation
  90. void Init() override;
  91. void Activate() override;
  92. void Deactivate() override;
  93. bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
  94. bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
  95. //////////////////////////////////////////////////////////////////////////
  96. // AreaSystemRequestBus
  97. void RegisterArea(AZ::EntityId areaId, AZ::u32 layer, AZ::u32 priority, const AZ::Aabb& bounds) override;
  98. void UnregisterArea(AZ::EntityId areaId) override;
  99. void RefreshArea(AZ::EntityId areaId, AZ::u32 layer, AZ::u32 priority, const AZ::Aabb& bounds) override;
  100. void RefreshAllAreas() override;
  101. void ClearAllAreas() override;
  102. void MuteArea(AZ::EntityId areaId) override;
  103. void UnmuteArea(AZ::EntityId areaId) override;
  104. void EnumerateInstancesInOverlappingSectors(const AZ::Aabb& bounds, AreaSystemEnumerateCallback callback) const override;
  105. void EnumerateInstancesInAabb(const AZ::Aabb& bounds, AreaSystemEnumerateCallback callback) const override;
  106. AZStd::size_t GetInstanceCountInAabb(const AZ::Aabb& bounds) const override;
  107. AZStd::vector<Vegetation::InstanceData> GetInstancesInAabb(const AZ::Aabb& bounds) const override;
  108. //////////////////////////////////////////////////////////////////////////
  109. // GradientSignal::SectorDataRequestBus
  110. void GetPointsPerMeter(float& value) const override;
  111. //////////////////////////////////////////////////////////////////////////
  112. // AZ::TickBus
  113. void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
  114. //////////////////////////////////////////////////////////////////////////
  115. // SystemConfigurationRequestBus
  116. void UpdateSystemConfig(const AZ::ComponentConfig* config) override;
  117. void GetSystemConfig(AZ::ComponentConfig* config) const override;
  118. //////////////////////////////////////////////////////////////////////////
  119. // SurfaceData::SurfaceDataSystemNotificationBus
  120. void OnSurfaceChanged(
  121. const AZ::EntityId& entityId,
  122. const AZ::Aabb& oldBounds,
  123. const AZ::Aabb& newBounds,
  124. const SurfaceData::SurfaceTagSet& changedSurfaceTags) override;
  125. ////////////////////////////////////////////////////////////////////////////
  126. // CrySystemEvents
  127. void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override;
  128. void OnCrySystemShutdown(ISystem& system) override;
  129. void OnCryEditorBeginLevelExport() override;
  130. void OnCryEditorEndLevelExport(bool /*success*/) override;
  131. void OnCryEditorCloseScene() override;
  132. //////////////////////////////////////////////////////////////////////////
  133. // ISystemEventListener
  134. void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) override;
  135. //////////////////////////////////////////////////////////////////////////
  136. // TerrainDataNotificationBus
  137. void OnTerrainDataCreateBegin() override;
  138. void OnTerrainDataDestroyBegin() override;
  139. private:
  140. using ClaimContainer = AZStd::unordered_map<ClaimHandle, InstanceData>;
  141. using ClaimContainerEntry = AZStd::pair<ClaimHandle, InstanceData>;
  142. using SectorId = AZStd::pair<int, int>;
  143. // SectorInfo contains basic sector information and the set of "plantable points" in the sector that have been claimed
  144. struct SectorInfo
  145. {
  146. AZ_CLASS_ALLOCATOR(SectorInfo, AZ::SystemAllocator);
  147. SectorId m_id = {};
  148. AZ::Aabb m_bounds = {};
  149. //! Keeps track of points that have been claimed. This is not cleared at the start of an update pass
  150. ClaimContainer m_claimedWorldPoints;
  151. //! Keeps track of previous state of sector while filling to avoid redundant instance destroy/create calls
  152. ClaimContainer m_claimedWorldPointsBeforeFill;
  153. ClaimContext m_baseContext;
  154. int GetSectorX() const { return m_id.first; }
  155. int GetSectorY() const { return m_id.second; }
  156. };
  157. // VegetationAreaInfo contains the basic information we need for tracking which vegetation areas to apply
  158. // to which sectors, and in which order.
  159. struct VegetationAreaInfo
  160. {
  161. AZ_CLASS_ALLOCATOR(VegetationAreaInfo, AZ::SystemAllocator);
  162. AZ::EntityId m_id;
  163. AZ::Aabb m_bounds = {};
  164. AZ::u32 m_layer = {};
  165. AZ::u32 m_priority = {};
  166. };
  167. using VegetationAreaMap = AZStd::unordered_map<AZ::EntityId, VegetationAreaInfo>;
  168. using VegetationAreaSet = AZStd::unordered_set<AZ::EntityId>;
  169. using VegetationAreaVector = AZStd::vector<VegetationAreaInfo>;
  170. using UnregisteredVegetationAreaMap = AZStd::unordered_map<SectorId, AZStd::unordered_set<AZ::EntityId>>;
  171. //! Helper class to track whether or not a visible sector is dirty. Different instances of this
  172. //! class are used to track different reasons for being dirty.
  173. //! This is a class instead of just an unordered_set<> so that we can also encapsulate the optimization
  174. //! of tracking when *all* sectors are dirty.
  175. class DirtySectors
  176. {
  177. public:
  178. DirtySectors() = default;
  179. ~DirtySectors() = default;
  180. void MarkDirty(const SectorId& id);
  181. void MarkAllDirty();
  182. bool IsAllDirty() const { return m_allSectorsDirty; }
  183. bool IsNoneDirty() const { return (!m_allSectorsDirty) && m_dirtySet.empty(); }
  184. bool IsDirty(const SectorId& id) const;
  185. void Clear();
  186. private:
  187. using DirtySectorSet = AZStd::unordered_set<SectorId>;
  188. DirtySectorSet m_dirtySet;
  189. //! Flag when *all* existing sectors are dirty
  190. bool m_allSectorsDirty = false;
  191. };
  192. // ViewRect is a helper struct to manage the "scrolling view rectangle". This view rectangle controls the
  193. // set of active spawned vegetation.
  194. struct ViewRect
  195. {
  196. int m_x = 0;
  197. int m_y = 0;
  198. int m_width = 0;
  199. int m_height = 0;
  200. AZ::Aabb m_viewRectBounds = AZ::Aabb::CreateNull();
  201. ViewRect() = default;
  202. ViewRect(int inX, int inY, int inW, int inH, AZ::Aabb viewRectBounds)
  203. : m_x(inX)
  204. , m_y(inY)
  205. , m_width(inW)
  206. , m_height(inH)
  207. , m_viewRectBounds(viewRectBounds)
  208. {
  209. }
  210. bool IsInside(const SectorId& sector) const;
  211. ViewRect Overlap(const ViewRect& b) const;
  212. bool operator !=(const ViewRect& b);
  213. bool operator ==(const ViewRect& b);
  214. size_t GetNumSectors() const;
  215. int GetMinXSector() const { return m_x; }
  216. int GetMinYSector() const { return m_y; }
  217. int GetMaxXSector() const { return m_x + m_width - 1; }
  218. int GetMaxYSector() const { return m_y + m_height - 1; }
  219. SectorId GetMinSector() const { return SectorId(GetMinXSector(), GetMinYSector()); }
  220. SectorId GetMaxSector() const { return SectorId(GetMaxXSector(), GetMaxYSector()); }
  221. AZ::Aabb GetViewRectBounds() const { return m_viewRectBounds; }
  222. };
  223. // Forward declarations, these get defined further down.
  224. class UpdateContext;
  225. class PersistentThreadData;
  226. // Thread-local copies of main state. We make copies of this to ensure that we can process sectors safely on
  227. // the vegetation thread while these values potentially get changed on the main thread without needing to wrap
  228. // all access with mutexes.
  229. struct CachedMainThreadData
  230. {
  231. float m_worldToSector = 0.0f;
  232. ViewRect m_currViewRect = {};
  233. int m_sectorSizeInMeters = 0;
  234. int m_sectorDensity = 0;
  235. SnapMode m_sectorPointSnapMode = SnapMode::Corner;
  236. };
  237. // VegetationThreadTasks is the task queue that's used equally by the main thread and the vegetation thread.
  238. // The main thread generally queues the tasks, and the vegetation thread processes them.
  239. // Any data used from this class requires mutexes, atomics, or other thread protection.
  240. class VegetationThreadTasks
  241. {
  242. public:
  243. void QueueVegetationTask(AZStd::function<void(UpdateContext* context, PersistentThreadData* threadData, VegetationThreadTasks * vegTasks)> func);
  244. void ProcessVegetationThreadTasks(UpdateContext* context, PersistentThreadData* threadData);
  245. bool VegetationThreadTasksPending()
  246. {
  247. AZStd::lock_guard<decltype(m_vegetationThreadTaskMutex)> lock(m_vegetationThreadTaskMutex);
  248. return !m_vegetationThreadTasks.empty();
  249. }
  250. //! Get sector by 2d veg map coordinates.
  251. const SectorInfo* GetSector(const SectorId& sectorId) const;
  252. SectorInfo* GetSector(const SectorId& sectorId);
  253. SectorInfo* CreateSector(const SectorId& sectorId, int sectorDensity, int sectorSizeInMeters, SnapMode sectorPointSnapMode);
  254. void UpdateSectorPoints(SectorInfo& sectorInfo, int sectorDensity, int sectorSizeInMeters, SnapMode sectorPointSnapMode);
  255. void FillSector(SectorInfo& sectorInfo, const VegetationAreaVector& activeAreas);
  256. void DeleteSector(const SectorId& sectorId);
  257. void ClearSectors();
  258. //! Gets the AABB for a sector
  259. static AZ::Aabb GetSectorBounds(const SectorId& sectorId, int sectorSizeInMeters);
  260. void FetchDebugData();
  261. void MarkDirtySectors(const AZ::Aabb& bounds, DirtySectors& dirtySet, float worldToSector, const ViewRect& viewRect);
  262. void AddUnregisteredVegetationArea(const VegetationAreaInfo& area, float worldToSector, const ViewRect& viewRect);
  263. //! 2D Array rolling window of sectors that store vegetation objects.
  264. using SectorRollingWindow = AZStd::unordered_map<SectorId, SectorInfo>;
  265. mutable AZStd::recursive_mutex m_sectorRollingWindowMutex;
  266. SectorRollingWindow m_sectorRollingWindow;
  267. private:
  268. // claiming logic
  269. void CreateClaim(SectorInfo& sectorInfo, const ClaimHandle handle, const InstanceData& instanceData);
  270. ClaimHandle CreateClaimHandle(const SectorInfo& sectorInfo, uint32_t index) const;
  271. void ReleaseUnusedClaims(SectorInfo& sectorInfo);
  272. void ReleaseUnregisteredClaims(SectorInfo& sectorInfo);
  273. //! Creates a new sector
  274. void UpdateSectorCallbacks(SectorInfo& sectorInfo);
  275. static void EmptySector(SectorInfo& sectorInfo);
  276. // Calls the given function on each sector in the box
  277. template<class Fn>
  278. static void EnumerateSectorsInAabb(const AZ::Aabb& bounds, float worldToSector, const ViewRect& viewRect, Fn&& fn);
  279. //! Queued list of vegetation area state update requests. These get queued on the main thread, and processed
  280. //! on the vegetation thread.
  281. mutable AZStd::recursive_mutex m_vegetationThreadTaskMutex;
  282. using VegetationThreadTaskList = AZStd::list<AZStd::function<void(UpdateContext* context, PersistentThreadData* threadData, VegetationThreadTasks* vegTasks)>>;
  283. VegetationThreadTaskList m_vegetationThreadTasks;
  284. //! Map from sectors to areas affecting that sector which have been unregistered and need to have their claims released
  285. //! Note: This is only updated from the vegetation thread when processing vegetation tasks.
  286. UnregisteredVegetationAreaMap m_unregisteredVegetationAreaSet;
  287. //! Cached pointer to the debug data.
  288. //! Note: This doesn't have an associated mutex because DebugData itself consists purely of atomics
  289. DebugData* m_debugData = nullptr;
  290. };
  291. //! Helper struct to hold the state data used by the vegetation thread. This contains all the data
  292. //! that should persist between thread runs, which lets us completely shut down the thread when there's
  293. //! no work to do.
  294. //! This also contains the vegetation thread mutex and state variables, which are accessed by both threads
  295. //! to manage synchronization.
  296. class PersistentThreadData
  297. {
  298. public:
  299. // This mutex is active the entire time the vegetation thread is running. Its main purpose
  300. // is to ensure we don't have component activations / deactivations that occur while the vegetation
  301. // thread is still processing.
  302. mutable AZStd::recursive_mutex m_vegetationThreadMutex;
  303. // Current state of the vegetation thread
  304. enum class VegetationThreadState
  305. {
  306. Stopped,
  307. Running,
  308. InterruptRequested
  309. };
  310. AZStd::atomic<VegetationThreadState> m_vegetationThreadState{ VegetationThreadState::Stopped };
  311. // Current state of data synchronization between main thread and vegetation thread
  312. enum class VegetationDataSyncState
  313. {
  314. Synchronized,
  315. Dirty,
  316. Updating
  317. };
  318. AZStd::atomic<VegetationDataSyncState> m_vegetationDataSyncState{ VegetationDataSyncState::Synchronized };
  319. //! Reset the states that can get recalculated when the vegetation thread is run.
  320. //! This does *not* reset the states on registered vegetation area lists, since those only
  321. //! get filled out once.
  322. void Init()
  323. {
  324. m_activeAreasDirty = true;
  325. m_activeAreas.clear();
  326. m_activeAreasInBubble.clear();
  327. m_dirtySectorContents.Clear();
  328. m_dirtySectorSurfacePoints.Clear();
  329. }
  330. void InterruptVegetationThread();
  331. // The following state is public because it's accessed by queued vegetation tasks and UpdateContext. It should
  332. // eventually be encapsulated a little better.
  333. //! set of sectors that need their contents refreshed
  334. DirtySectors m_dirtySectorContents;
  335. //! set of sectors that need their surface points recalculated (which implies also needing the contents refreshed)
  336. DirtySectors m_dirtySectorSurfacePoints;
  337. VegetationAreaMap m_globalVegetationAreaMap;
  338. VegetationAreaSet m_ignoredVegetationAreaSet;
  339. //! Determines when to refresh the set of active areas
  340. bool m_activeAreasDirty = true;
  341. protected:
  342. // Only UpdateContext is allowed to directly access the persisted thread state.
  343. friend class UpdateContext;
  344. // This is effectively a local variable in UpdateActiveVegetationAreas, but is kept
  345. // persistent to avoid potentially frequent reallocation.
  346. VegetationAreaVector m_activeAreas;
  347. //! The set of active vegetation areas that overlap the current view rectangle
  348. VegetationAreaVector m_activeAreasInBubble;
  349. };
  350. // UpdateContext is the logic that normally runs on the vegetation thread. It processes all of the logic needed to update and fill
  351. // any vegetation sectors that are currently within the view rectangle. Occasionally the logic will be triggered on the main thread
  352. // in cases such as shutdown when the vegetation thread isn't running any we need to perform the cleanup synchronously.
  353. class UpdateContext
  354. {
  355. public:
  356. UpdateContext() = default;
  357. void Run(PersistentThreadData* threadData, VegetationThreadTasks* vegTasks, CachedMainThreadData* cachedMainThreadData);
  358. void UpdateActiveVegetationAreas(PersistentThreadData* threadData, const ViewRect& viewRect);
  359. const CachedMainThreadData& GetCachedMainThreadData() { return m_cachedMainThreadData; }
  360. private:
  361. bool UpdateSectorWorkLists(PersistentThreadData* threadData, VegetationThreadTasks* vegTasks);
  362. bool UpdateOneSector(PersistentThreadData* threadData, VegetationThreadTasks* vegTasks);
  363. enum class UpdateMode
  364. {
  365. Create,
  366. RebuildSurfaceCacheAndFill,
  367. Fill
  368. };
  369. // The sorted work list of sectors to delete. The list is recreated every time UpdateSectorWorkLists() is run.
  370. AZStd::vector<SectorId> m_deleteWorkList;
  371. // The sorted work list of sectors to create / update. This is incrementally modified when UpdateSectorWorkLists()
  372. // is run, because any previously-requested updates that are still in view need to be preserved. They can't simply
  373. // be recalculated.
  374. AZStd::vector<AZStd::pair<SectorId, UpdateMode>> m_updateWorkList;
  375. // Sector counts of the number of expected sectors in the view rectangle vs the number of sectors
  376. // currently active. These are used to "load balance" sector deletes and creates so that we don't have
  377. // too many sectors active at any one point in time.
  378. size_t m_viewRectSectorCount = 0;
  379. // Thread-local copy of the main thread's m_cachedMainThreadData. This way we can read from it on the vegetation
  380. // thread without requiring mutexes.
  381. CachedMainThreadData m_cachedMainThreadData;
  382. };
  383. bool ApplyPendingConfigChanges();
  384. void ReleaseData();
  385. void ReleaseAllClaims();
  386. void ReleaseWithoutCleanup();
  387. bool CalculateViewRect();
  388. //! Get sector id by world coordinates.
  389. static SectorId GetSectorId(const AZ::Vector3& worldPos, float worldToSector);
  390. // All of this state data should only get accessed by the main thread. A subset of this data gets copied
  391. // into CachedMainThreadData for the vegetation thread to be able to query in a lockless manner.
  392. AreaSystemConfig m_configuration;
  393. float m_worldToSector = 0.0f; //! world to sector scaling ratio.
  394. ViewRect m_currViewRect = {};
  395. float m_vegetationThreadTaskTimer = 0.0f;
  396. ISystem* m_system = nullptr;
  397. bool m_configDirty = false;
  398. AreaSystemConfig m_pendingConfigUpdate;
  399. // The vegetation task queue gets read/written from both threads, and uses atomics + mutexes for synchronization.
  400. VegetationThreadTasks m_vegTasks;
  401. // This state should only get read or written from the vegetation thread, except for component initialization.
  402. PersistentThreadData m_threadData;
  403. // This state gets written to from the main thread, and gets copied and read from the vegetation thread.
  404. CachedMainThreadData m_cachedMainThreadData;
  405. };
  406. }