Material editor asynchronously loads lighting and model presets

changed several sequential blocking loads into asynchronous loads to improve material editor startup time

Signed-off-by: Guthrie Adams <guthadam@amazon.com>
This commit is contained in:
Guthrie Adams
2021-12-06 17:12:06 -06:00
parent 35b7705119
commit 1cef580cad
2 changed files with 63 additions and 71 deletions
@@ -9,7 +9,6 @@
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <Atom/Viewport/MaterialViewportNotificationBus.h>
#include <Atom/Viewport/MaterialViewportSettings.h>
#include <AzCore/Component/TickBus.h>
@@ -135,11 +134,19 @@ namespace MaterialEditor
{
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
MaterialViewportRequestBus::Handler::BusDisconnect();
ClearContent();
}
void MaterialViewportComponent::ClearContent()
{
AZ::Data::AssetBus::MultiHandler::BusDisconnect();
m_lightingPresetAssets.clear();
m_lightingPresetVector.clear();
m_lightingPresetLastSavePathMap.clear();
m_lightingPresetSelection.reset();
m_modelPresetAssets.clear();
m_modelPresetVector.clear();
m_modelPresetLastSavePathMap.clear();
m_modelPresetSelection.reset();
@@ -151,84 +158,36 @@ namespace MaterialEditor
MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnBeginReloadContent);
const AZStd::string selectedLightingPresetNameOld = m_viewportSettings->m_selectedLightingPresetName;
m_lightingPresetVector.clear();
m_lightingPresetLastSavePathMap.clear();
m_lightingPresetSelection.reset();
const AZStd::string selectedModelPresetNameOld = m_viewportSettings->m_selectedModelPresetName;
m_modelPresetVector.clear();
m_modelPresetLastSavePathMap.clear();
m_modelPresetSelection.reset();
AZStd::vector<AZ::Data::AssetInfo> lightingAssetInfoVector;
AZStd::vector<AZ::Data::AssetInfo> modelAssetInfoVector;
ClearContent();
// Enumerate and load all the relevant preset files in the project.
// (The files are stored in a temporary list instead of processed in the callback because deep operations inside
// AssetCatalogRequestBus::EnumerateAssets can lead to deadlocked)
AZ::Data::AssetCatalogRequests::AssetEnumerationCB enumerateCB = [&lightingAssetInfoVector, &modelAssetInfoVector]([[maybe_unused]] const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info)
AZ::Data::AssetCatalogRequests::AssetEnumerationCB enumerateCB = [this]([[maybe_unused]] const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info)
{
if (AzFramework::StringFunc::EndsWith(info.m_relativePath.c_str(), ".lightingpreset.azasset"))
{
lightingAssetInfoVector.push_back(info);
m_lightingPresetAssets[info.m_assetId] = { info.m_assetId, info.m_assetType };
AZ::Data::AssetBus::MultiHandler::BusConnect(info.m_assetId);
}
else if (AzFramework::StringFunc::EndsWith(info.m_relativePath.c_str(), ".modelpreset.azasset"))
{
modelAssetInfoVector.push_back(info);
m_modelPresetAssets[info.m_assetId] = { info.m_assetId, info.m_assetType };
AZ::Data::AssetBus::MultiHandler::BusConnect(info.m_assetId);
}
};
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, enumerateCB, nullptr);
for (const auto& info : lightingAssetInfoVector)
for (auto& assetPair : m_lightingPresetAssets)
{
if (info.m_assetId.IsValid())
{
AZ::Data::Asset<AZ::RPI::AnyAsset> asset = AZ::RPI::AssetUtils::LoadAssetById<AZ::RPI::AnyAsset>(
info.m_assetId, AZ::RPI::AssetUtils::TraceLevel::Warning);
if (asset)
{
const AZ::Render::LightingPreset* preset = asset->GetDataAs<AZ::Render::LightingPreset>();
if (preset)
{
auto presetPtr = AddLightingPreset(*preset);
m_lightingPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId);
AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str());
}
}
}
assetPair.second.QueueLoad();
}
for (const auto& info : modelAssetInfoVector)
for (auto& assetPair : m_modelPresetAssets)
{
if (info.m_assetId.IsValid())
{
AZ::Data::Asset<AZ::RPI::AnyAsset> asset =
AZ::RPI::AssetUtils::LoadAssetById<AZ::RPI::AnyAsset>(info.m_assetId, AZ::RPI::AssetUtils::TraceLevel::Warning);
if (asset)
{
const AZ::Render::ModelPreset* preset = asset->GetDataAs<AZ::Render::ModelPreset>();
if (preset)
{
auto presetPtr = AddModelPreset(*preset);
m_modelPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId);
AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str());
}
}
}
assetPair.second.QueueLoad();
}
// If there was a prior selection, this will keep the same configuration selected.
// Otherwise, these strings are empty and the operation will be ignored.
SelectLightingPresetByName(selectedLightingPresetNameOld);
SelectModelPresetByName(selectedModelPresetNameOld);
MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnEndReloadContent);
AZ_TracePrintf("Material Editor", "Finished loading viewport configurations.\n");
}
AZ::Render::LightingPresetPtr MaterialViewportComponent::AddLightingPreset(const AZ::Render::LightingPreset& preset)
@@ -237,12 +196,6 @@ namespace MaterialEditor
auto presetPtr = m_lightingPresetVector.back();
MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetAdded, presetPtr);
if (m_lightingPresetVector.size() == 1)
{
SelectLightingPreset(presetPtr);
}
return presetPtr;
}
@@ -314,12 +267,6 @@ namespace MaterialEditor
auto presetPtr = m_modelPresetVector.back();
MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetAdded, presetPtr);
if (m_modelPresetVector.size() == 1)
{
SelectModelPreset(presetPtr);
}
return presetPtr;
}
@@ -443,6 +390,39 @@ namespace MaterialEditor
return m_viewportSettings->m_displayMapperOperationType;
}
inline void MaterialViewportComponent::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
{
if (AZ::Data::Asset<AZ::RPI::AnyAsset> anyAsset = asset)
{
if (const auto lightingPreset = anyAsset->GetDataAs<AZ::Render::LightingPreset>())
{
auto presetPtr = AddLightingPreset(*lightingPreset);
const auto& presetPath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(anyAsset.GetId());
m_lightingPresetAssets[anyAsset.GetId()] = anyAsset;
m_lightingPresetLastSavePathMap[presetPtr] = presetPath;
AZ_TracePrintf("Material Editor", "Loaded Preset: %s\n", presetPath.c_str());
}
if (const auto modelPreset = anyAsset->GetDataAs<AZ::Render::ModelPreset>())
{
auto presetPtr = AddModelPreset(*modelPreset);
const auto& presetPath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(anyAsset.GetId());
m_modelPresetAssets[anyAsset.GetId()] = anyAsset;
m_modelPresetLastSavePathMap[presetPtr] = presetPath;
AZ_TracePrintf("Material Editor", "Loaded Preset: %s\n", presetPath.c_str());
}
}
AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());
if (!AZ::Data::AssetBus::MultiHandler::BusIsConnected())
{
SelectLightingPresetByName(m_viewportSettings->m_selectedLightingPresetName);
SelectModelPresetByName(m_viewportSettings->m_selectedModelPresetName);
MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnEndReloadContent);
AZ_TracePrintf("Material Editor", "Finished loading viewport configurations.\n");
}
}
void MaterialViewportComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
{
AZ::TickBus::QueueFunction([this]() {
@@ -11,8 +11,10 @@
#include <ACES/Aces.h>
#include <Atom/Feature/Utils/LightingPreset.h>
#include <Atom/Feature/Utils/ModelPreset.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <Atom/Viewport/MaterialViewportRequestBus.h>
#include <Atom/Viewport/MaterialViewportSettings.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
@@ -22,6 +24,7 @@ namespace MaterialEditor
class MaterialViewportComponent
: public AZ::Component
, private MaterialViewportRequestBus::Handler
, private AZ::Data::AssetBus::MultiHandler
, private AzFramework::AssetCatalogEventBus::Handler
{
public:
@@ -46,6 +49,8 @@ namespace MaterialEditor
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
void ClearContent();
////////////////////////////////////////////////////////////////////////
// MaterialViewportRequestBus::Handler overrides ...
void ReloadContent() override;
@@ -82,14 +87,21 @@ namespace MaterialEditor
AZ::Render::DisplayMapperOperationType GetDisplayMapperOperationType() const override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// AZ::Data::AssetBus::MultiHandler overrides ...
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// AzFramework::AssetCatalogEventBus::Handler overrides ...
void OnCatalogLoaded(const char* catalogFile) override;
////////////////////////////////////////////////////////////////////////
AZStd::unordered_map<AZ::Data::AssetId, AZ::Data::Asset<AZ::RPI::AnyAsset>> m_lightingPresetAssets;
AZ::Render::LightingPresetPtrVector m_lightingPresetVector;
AZ::Render::LightingPresetPtr m_lightingPresetSelection;
AZStd::unordered_map<AZ::Data::AssetId, AZ::Data::Asset<AZ::RPI::AnyAsset>> m_modelPresetAssets;
AZ::Render::ModelPresetPtrVector m_modelPresetVector;
AZ::Render::ModelPresetPtr m_modelPresetSelection;