diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index 9d11eef6fc..87c5c6cb03 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -1117,7 +1117,7 @@ namespace AZ return asset; } - void AssetManager::UpdateDebugStatus(AZ::Data::Asset asset) + void AssetManager::UpdateDebugStatus(const AZ::Data::Asset& asset) { if(!m_debugAssetEvents) { diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.h b/Code/Framework/AzCore/AzCore/Asset/AssetManager.h index 7df2972a3d..81568d936e 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.h @@ -358,7 +358,7 @@ namespace AZ Asset GetAssetInternal(const AssetId& assetId, const AssetType& assetType, AssetLoadBehavior assetReferenceLoadBehavior, const AssetLoadParameters& loadParams = AssetLoadParameters{}, AssetInfo assetInfo = AssetInfo(), bool signalLoaded = false); - void UpdateDebugStatus(AZ::Data::Asset asset); + void UpdateDebugStatus(const AZ::Data::Asset& asset); /** * Gets a root asset and dependencies as individual async loads if necessary. diff --git a/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp b/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp index 4f62550216..4dcc969434 100644 --- a/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp +++ b/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp @@ -145,24 +145,36 @@ namespace SurfaceData void EditorSurfaceDataSystemComponent::OnCatalogLoaded(const char* /*catalogFile*/) { - //automatically register all surface tag list assets + //automatically register all existing surface tag list assets at Editor startup - // First run through all the assets and trigger loads on them. + AZStd::vector surfaceTagAssetIds; + + // First run through all the assets and gather up the asset IDs for all surface tag list assets AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, - [this](const AZ::Data::AssetId assetId, const AZ::Data::AssetInfo& assetInfo) { + [&surfaceTagAssetIds](const AZ::Data::AssetId assetId, const AZ::Data::AssetInfo& assetInfo) { const auto assetType = azrtti_typeid(); if (assetInfo.m_assetType == assetType) { - m_surfaceTagNameAssets[assetId] = AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, AZ::Data::AssetLoadBehavior::Default); + surfaceTagAssetIds.emplace_back(assetId); } }, nullptr); - // After all the loads are triggered, block to make sure they've all completed. - for (auto& asset : m_surfaceTagNameAssets) + // Next, trigger all the loads. This is done outside of EnumerateAssets to ensure that we don't have any deadlocks caused by + // lock inversion. If this thread locks AssetCatalogRequestBus mutex with EnumerateAssets, then locks m_assetMutex in + // AssetManager::FindOrCreateAsset, it's possible for those locks to get locked in reverse on a loading thread, causing a deadlock. + for (auto& assetId : surfaceTagAssetIds) { - asset.second.BlockUntilLoadComplete(); + m_surfaceTagNameAssets[assetId] = AZ::Data::AssetManager::Instance().GetAsset( + assetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); + + // If any assets are still loading (which they likely will be), listen for the OnAssetReady event and refresh the Editor + // UI as each one finishes loading. + if (!m_surfaceTagNameAssets[assetId].IsReady()) + { + AZ::Data::AssetBus::MultiHandler::BusConnect(assetId); + } } }