AsyncLoadTracker.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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. namespace AZ
  10. {
  11. namespace Render
  12. {
  13. // AsyncLoadTracker is for use by Feature Processors to track in-flight loading of assets that their sub-objects need.
  14. // For instance, the individual decals that are controlled by the decal FeatureProcessor will need materials to be loaded in asynchronously before use.
  15. template<typename FeatureProcessorHandle>
  16. class AsyncLoadTracker
  17. {
  18. public:
  19. using MaterialAssetPtr = AZ::Data::Asset<AZ::RPI::MaterialAsset>;
  20. void TrackAssetLoad(const FeatureProcessorHandle handle, const MaterialAssetPtr asset)
  21. {
  22. if (IsAssetLoading(handle))
  23. {
  24. // We might have a case where a decal was told to load an asset, then while the load was being fulfilled, it was told to
  25. // switch to a different asset. That is why we are removing the existing handle rather than just returning.
  26. RemoveHandle(handle);
  27. }
  28. Add(handle, asset);
  29. }
  30. bool IsAssetLoading(const AZ::Data::AssetId asset) const
  31. {
  32. return m_inFlightHandlesByAsset.count(asset) > 0;
  33. }
  34. bool IsAssetLoading(const FeatureProcessorHandle handle) const
  35. {
  36. return m_inFlightHandles.count(handle) > 0;
  37. }
  38. AZStd::vector<FeatureProcessorHandle> GetHandlesByAsset(const AZ::Data::AssetId asset) const
  39. {
  40. const auto iter = m_inFlightHandlesByAsset.find(asset);
  41. if (iter != m_inFlightHandlesByAsset.end())
  42. {
  43. return iter->second;
  44. }
  45. else
  46. {
  47. return {};
  48. }
  49. }
  50. void RemoveAllHandlesWithAsset(const AZ::Data::AssetId asset)
  51. {
  52. const auto iter = m_inFlightHandlesByAsset.find(asset);
  53. if (iter == m_inFlightHandlesByAsset.end())
  54. {
  55. return;
  56. }
  57. auto& handleList = iter->second;
  58. for (auto& handle : handleList)
  59. {
  60. EraseFromInFlightHandles(handle);
  61. }
  62. m_inFlightHandlesByAsset.erase(iter);
  63. }
  64. void RemoveHandle(const FeatureProcessorHandle handle)
  65. {
  66. const auto asset = EraseFromInFlightHandles(handle);
  67. AZ_Assert(m_inFlightHandlesByAsset.count(asset.GetId()) > 0, "AsyncLoadTracker in a bad state");
  68. auto& handleList = m_inFlightHandlesByAsset[asset.GetId()];
  69. EraseFromVector(handleList, handle);
  70. if (handleList.empty())
  71. {
  72. m_inFlightHandlesByAsset.erase(asset.GetId());
  73. }
  74. }
  75. bool AreAnyLoadsInFlight() const
  76. {
  77. return !m_inFlightHandles.empty();
  78. }
  79. private:
  80. // Helper function that erases from an AZStd::vector via swap() and pop_back()
  81. template<typename T, typename U>
  82. static void EraseFromVector(AZStd::vector<T>& vec, const U elementToErase)
  83. {
  84. const auto iter = AZStd::find(vec.begin(), vec.end(), elementToErase);
  85. AZ_Assert(iter != vec.end(), "EraseFromVector failed to find the given object");
  86. AZStd::swap(*iter, vec.back());
  87. vec.pop_back();
  88. }
  89. void Add(const FeatureProcessorHandle handle, const MaterialAssetPtr asset)
  90. {
  91. AZ_Assert(m_inFlightHandles.count(handle) == 0, "AsyncLoadTracker::Add() - told to add a handle that was already being tracked.");
  92. m_inFlightHandlesByAsset[asset.GetId()].push_back(handle);
  93. m_inFlightHandles[handle] = asset;
  94. }
  95. MaterialAssetPtr EraseFromInFlightHandles(const FeatureProcessorHandle handle)
  96. {
  97. const auto iter = m_inFlightHandles.find(handle);
  98. AZ_Assert(iter != m_inFlightHandles.end(), "Told to remove handle that was not present");
  99. const auto asset = iter->second;
  100. m_inFlightHandles.erase(iter);
  101. return asset;
  102. }
  103. // Tracks all objects that need a particular asset
  104. AZStd::unordered_map<AZ::Data::AssetId, AZStd::vector<FeatureProcessorHandle>> m_inFlightHandlesByAsset;
  105. // Hash table that tracks the reverse of the m_inFlightHandlesByAsset hash table.
  106. // i.e. for each object, it stores what asset that it needs.
  107. AZStd::unordered_map<FeatureProcessorHandle, MaterialAssetPtr> m_inFlightHandles;
  108. };
  109. }
  110. }