You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp

683 lines
30 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h>
#include <Atom/RPI.Public/Shader/Metrics/ShaderMetricsSystem.h>
#include <AzCore/Component/TickBus.h>
#include <Atom/RHI/Factory.h>
namespace AZ
{
namespace RPI
{
void ShaderVariantAsyncLoader::Init()
{
m_isServiceShutdown.store(false);
AZStd::thread_desc threadDesc;
threadDesc.m_name = "ShaderVariantAsyncLoader";
m_serviceThread = AZStd::thread(
[this]()
{
this->ThreadServiceLoop();
},
&threadDesc
);
}
void ShaderVariantAsyncLoader::ThreadServiceLoop()
{
AZStd::unordered_set<ShaderVariantAsyncLoader::PairOfShaderAssetAndShaderVariantId> newShaderVariantPendingRequests;
AZStd::unordered_set<Data::AssetId> shaderVariantTreePendingRequests;
AZStd::unordered_set<Data::AssetId> shaderVariantPendingRequests;
while (true)
{
//We'll wait here until there's work to do or this service has been shutdown.
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
m_workCondition.wait(lock, [&]
{
return m_isServiceShutdown.load() ||
!m_newShaderVariantPendingRequests.empty() ||
!m_shaderVariantTreePendingRequests.empty() ||
!m_shaderVariantPendingRequests.empty() ||
!newShaderVariantPendingRequests.empty() ||
!shaderVariantTreePendingRequests.empty() ||
!shaderVariantPendingRequests.empty();
}
);
}
if (m_isServiceShutdown.load())
{
break;
}
{
//Move pending requests to the local lists.
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
AZStd::for_each(
m_newShaderVariantPendingRequests.begin(), m_newShaderVariantPendingRequests.end(),
[&](const ShaderVariantAsyncLoader::PairOfShaderAssetAndShaderVariantId& pair) {
newShaderVariantPendingRequests.insert(pair);
});
m_newShaderVariantPendingRequests.clear();
AZStd::for_each(m_shaderVariantTreePendingRequests.begin(), m_shaderVariantTreePendingRequests.end(),
[&](const Data::AssetId& assetId)
{
shaderVariantTreePendingRequests.insert(assetId);
});
m_shaderVariantTreePendingRequests.clear();
AZStd::for_each(m_shaderVariantPendingRequests.begin(), m_shaderVariantPendingRequests.end(),
[&](const Data::AssetId& assetId)
{
shaderVariantPendingRequests.insert(assetId);
});
m_shaderVariantPendingRequests.clear();
}
// Time to work hard.
auto pairItor = newShaderVariantPendingRequests.begin();
while (pairItor != newShaderVariantPendingRequests.end())
{
auto shaderVariantTreeAsset = GetShaderVariantTreeAsset(pairItor->m_shaderAsset.GetId());
if (shaderVariantTreeAsset)
{
AZ_Assert(shaderVariantTreeAsset.IsReady(), "shaderVariantTreeAsset is not ready!");
// Get the stableId from the variant tree.
auto searchResult = shaderVariantTreeAsset->FindVariantStableId(
pairItor->m_shaderAsset->GetShaderOptionGroupLayout(), pairItor->m_shaderVariantId);
if (searchResult.IsRoot())
{
pairItor = newShaderVariantPendingRequests.erase(pairItor);
continue;
}
// Record the request for metrics.
ShaderMetricsSystem::Get()->RequestShaderVariant(pairItor->m_shaderAsset.Get(), pairItor->m_shaderVariantId, searchResult);
uint32_t shaderVariantProductSubId =
ShaderVariantAsset::MakeAssetProductSubId(RHI::Factory::Get().GetAPIUniqueIndex(), searchResult.GetStableId());
Data::AssetId shaderVariantAssetId(shaderVariantTreeAsset.GetId().m_guid, shaderVariantProductSubId);
shaderVariantPendingRequests.insert(shaderVariantAssetId);
pairItor = newShaderVariantPendingRequests.erase(pairItor);
continue;
}
// If we are here the shaderVariantTreeAsset is not ready, but maybe it is already queued for loading,
// but we try to queue it anyways.
QueueShaderVariantTreeForLoading(*pairItor, shaderVariantTreePendingRequests);
pairItor++;
}
auto variantTreeItor = shaderVariantTreePendingRequests.begin();
while (variantTreeItor != shaderVariantTreePendingRequests.end())
{
if (TryToLoadShaderVariantTreeAsset(*variantTreeItor))
{
variantTreeItor = shaderVariantTreePendingRequests.erase(variantTreeItor);
}
else
{
variantTreeItor++;
}
}
auto variantItor = shaderVariantPendingRequests.begin();
while (variantItor != shaderVariantPendingRequests.end())
{
if (TryToLoadShaderVariantAsset(*variantItor))
{
variantItor = shaderVariantPendingRequests.erase(variantItor);
}
else
{
variantItor++;
}
}
if (!shaderVariantTreePendingRequests.empty() || !shaderVariantPendingRequests.empty())
{
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1000));
}
}
}
void ShaderVariantAsyncLoader::Shutdown()
{
if (m_isServiceShutdown.load())
{
return;
}
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
m_isServiceShutdown.store(true);
}
m_workCondition.notify_one();
m_serviceThread.join();
Data::AssetBus::MultiHandler::BusDisconnect();
m_newShaderVariantPendingRequests.clear();
m_shaderVariantTreePendingRequests.clear();
m_shaderVariantPendingRequests.clear();
m_shaderVariantData.clear();
m_shaderAssetIdToShaderVariantTreeAssetId.clear();
}
///////////////////////////////////////////////////////////////////
// IShaderVariantFinder overrides
bool ShaderVariantAsyncLoader::QueueLoadShaderVariantAssetByVariantId(
Data::Asset<ShaderAsset> shaderAsset, const ShaderVariantId& shaderVariantId)
{
if (m_isServiceShutdown.load())
{
return false;
}
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
PairOfShaderAssetAndShaderVariantId pair = {shaderAsset, shaderVariantId};
m_newShaderVariantPendingRequests.push_back(pair);
}
m_workCondition.notify_one();
return true;
}
bool ShaderVariantAsyncLoader::QueueLoadShaderVariantAsset(
const Data::AssetId& shaderVariantTreeAssetId, ShaderVariantStableId variantStableId)
{
if (m_isServiceShutdown.load())
{
return false;
}
AZ_Assert(variantStableId != RootShaderVariantStableId, "Root Variants Are Found inside ShaderAssets");
uint32_t shaderVariantProductSubId =
ShaderVariantAsset::MakeAssetProductSubId(RHI::Factory::Get().GetAPIUniqueIndex(), variantStableId);
Data::AssetId shaderVariantAssetId(shaderVariantTreeAssetId.m_guid, shaderVariantProductSubId);
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
m_shaderVariantPendingRequests.push_back(shaderVariantAssetId);
}
m_workCondition.notify_one();
return true;
}
bool ShaderVariantAsyncLoader::QueueLoadShaderVariantTreeAsset(const Data::AssetId& shaderAssetId)
{
if (m_isServiceShutdown.load())
{
return false;
}
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
m_shaderVariantTreePendingRequests.push_back(shaderAssetId);
}
m_workCondition.notify_one();
return true;
}
Data::Asset<ShaderVariantAsset> ShaderVariantAsyncLoader::GetShaderVariantAssetByVariantId(
Data::Asset<ShaderAsset> shaderAsset, const ShaderVariantId& shaderVariantId)
{
Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset = GetShaderVariantTreeAsset(shaderAsset.GetId());
if (!shaderVariantTreeAsset)
{
return {};
}
// Find the stable id.
ShaderVariantSearchResult searchResult =
shaderVariantTreeAsset->FindVariantStableId(shaderAsset->GetShaderOptionGroupLayout(), shaderVariantId);
if (searchResult.IsRoot())
{
return shaderAsset->GetRootVariant();
}
// Record the request for metrics.
ShaderMetricsSystem::Get()->RequestShaderVariant(shaderAsset.Get(), shaderVariantId, searchResult);
return GetShaderVariantAsset(shaderVariantTreeAsset.GetId(), searchResult.GetStableId());
}
Data::Asset<ShaderVariantAsset> ShaderVariantAsyncLoader::GetShaderVariantAssetByStableId(
Data::Asset<ShaderAsset> shaderAsset, ShaderVariantStableId shaderVariantStableId)
{
AZ_Assert(shaderVariantStableId != RootShaderVariantStableId, "Root Variants Are Found inside ShaderAssets");
Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset = GetShaderVariantTreeAsset(shaderAsset.GetId());
if (!shaderVariantTreeAsset)
{
return {};
}
return GetShaderVariantAsset(shaderVariantTreeAsset.GetId(), shaderVariantStableId);
}
Data::Asset<ShaderVariantTreeAsset> ShaderVariantAsyncLoader::GetShaderVariantTreeAsset(const Data::AssetId& shaderAssetId)
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto assetIdFindIt = m_shaderAssetIdToShaderVariantTreeAssetId.find(shaderAssetId);
if (assetIdFindIt == m_shaderAssetIdToShaderVariantTreeAssetId.end())
{
return {};
}
const Data::AssetId& shaderVariantTreeAssetId = assetIdFindIt->second;
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt == m_shaderVariantData.end())
{
return {};
}
ShaderVariantCollection& shaderVariantCollection = findIt->second;
if (shaderVariantCollection.m_shaderVariantTree.IsReady())
{
return shaderVariantCollection.m_shaderVariantTree;
}
return {};
}
Data::Asset<ShaderVariantAsset> ShaderVariantAsyncLoader::GetShaderVariantAsset(const Data::AssetId& shaderVariantTreeAssetId, ShaderVariantStableId variantStableId)
{
AZ_Assert(variantStableId != RootShaderVariantStableId, "Root Variants Are Found inside ShaderAssets");
uint32_t shaderVariantProductSubId = ShaderVariantAsset::MakeAssetProductSubId(RHI::Factory::Get().GetAPIUniqueIndex(), variantStableId);
Data::AssetId shaderVariantAssetId(shaderVariantTreeAssetId.m_guid, shaderVariantProductSubId);
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt == m_shaderVariantData.end())
{
return {};
}
ShaderVariantCollection& shaderVariantCollection = findIt->second;
auto& shaderVariantsMap = shaderVariantCollection.m_shaderVariantsMap;
auto variantFindIt = shaderVariantsMap.find(shaderVariantAssetId);
if (variantFindIt == shaderVariantsMap.end())
{
return {};
}
Data::Asset<ShaderVariantAsset> shaderVariantAsset = variantFindIt->second;
if (shaderVariantAsset.IsReady())
{
return shaderVariantAsset;
}
return {};
}
void ShaderVariantAsyncLoader::Reset()
{
// [GFX TODO ATOM-14544] Idealy we want to be able to reset the ShaderVariantAsyncLoader but this is causing some problems that need to be worked out first.
//Shutdown();
//Init();
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// AZ::Data::AssetBus::Handler overrides
void ShaderVariantAsyncLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
//Cast it to our known asset types.
if (asset.GetType() == AZ::AzTypeInfo<ShaderVariantTreeAsset>::Uuid())
{
OnShaderVariantTreeAssetReady(Data::static_pointer_cast<ShaderVariantTreeAsset>(asset));
return;
}
if (asset.GetType() == AZ::AzTypeInfo<ShaderVariantAsset>::Uuid())
{
OnShaderVariantAssetReady(Data::static_pointer_cast<ShaderVariantAsset>(asset));
return;
}
AZ_Error(LogName, false, "Got OnAssetReady for unknown asset type with id=%s and hint=%s\n", asset.GetId().ToString<AZStd::string>().c_str(), asset.GetHint().c_str());
}
void ShaderVariantAsyncLoader::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
return OnAssetReady(asset);
}
void ShaderVariantAsyncLoader::OnAssetError(Data::Asset<Data::AssetData> asset)
{
Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());
//Cast it to our known asset types.
if (asset.GetType() == AZ::AzTypeInfo<ShaderVariantTreeAsset>::Uuid())
{
OnShaderVariantTreeAssetError(Data::static_pointer_cast<ShaderVariantTreeAsset>(asset));
return;
}
if (asset.GetType() == AZ::AzTypeInfo<ShaderVariantAsset>::Uuid())
{
OnShaderVariantAssetError(Data::static_pointer_cast<ShaderVariantAsset>(asset));
return;
}
AZ_Error(LogName, false, "Got OnAssetError for unknown asset type with id=%s and hint=%s\n", asset.GetId().ToString<AZStd::string>().c_str(), asset.GetHint().c_str());
}
///////////////////////////////////////////////////////////////////////
void ShaderVariantAsyncLoader::OnShaderVariantTreeAssetReady(Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset)
{
// Will be used to address the notification bus.
Data::AssetId shaderAssetId;
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAsset.GetId());
if (findIt != m_shaderVariantData.end())
{
ShaderVariantCollection& shaderVariantCollection = findIt->second;
shaderAssetId = shaderVariantCollection.m_shaderAssetId;
shaderVariantCollection.m_shaderVariantTree = shaderVariantTreeAsset;
}
else
{
AZ_Assert(false, "Was expecting a ShaderVariantCollection for shader variant tree asset with id=%s and hint=%s",
shaderVariantTreeAsset.GetId().ToString<AZStd::string>().c_str(), shaderVariantTreeAsset.GetHint().c_str());
return;
}
}
AZ::TickBus::QueueFunction([shaderAssetId, shaderVariantTreeAsset]()
{
ShaderVariantFinderNotificationBus::Event(
shaderAssetId,
&ShaderVariantFinderNotification::OnShaderVariantTreeAssetReady, shaderVariantTreeAsset, false /*isError*/);
});
}
void ShaderVariantAsyncLoader::OnShaderVariantAssetReady(Data::Asset<ShaderVariantAsset> shaderVariantAsset)
{
// Will be used to address the notification bus.
Data::AssetId shaderAssetId;
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
Data::AssetId shaderVariantTreeAssetId(shaderVariantAsset.GetId().m_guid, 0);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt != m_shaderVariantData.end())
{
ShaderVariantCollection& shaderVariantCollection = findIt->second;
shaderAssetId = shaderVariantCollection.m_shaderAssetId;
auto& shaderVariantMap = shaderVariantCollection.m_shaderVariantsMap;
shaderVariantMap.emplace(shaderVariantAsset.GetId(), shaderVariantAsset);
}
else
{
AZ_Assert(false, "Was expecting a ShaderVariantCollection for shader variant asset with id=%s and hint=%s",
shaderVariantAsset.GetId().ToString<AZStd::string>().c_str(), shaderVariantAsset.GetHint().c_str());
return;
}
}
AZ::TickBus::QueueFunction([shaderAssetId, shaderVariantAsset]()
{
ShaderVariantFinderNotificationBus::Event(
shaderAssetId,
&ShaderVariantFinderNotification::OnShaderVariantAssetReady, shaderVariantAsset, false /*isError*/);
});
}
void ShaderVariantAsyncLoader::OnShaderVariantTreeAssetError(Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset)
{
// Will be used to address the notification bus.
Data::AssetId shaderAssetId;
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAsset.GetId());
if (findIt != m_shaderVariantData.end())
{
ShaderVariantCollection& shaderVariantCollection = findIt->second;
shaderAssetId = shaderVariantCollection.m_shaderAssetId;
m_shaderVariantData.erase(findIt);
}
else
{
AZ_Warning(LogName, false, "Was expecting a ShaderVariantCollection for shader variant tree asset with id=%s and hint=%s",
shaderVariantTreeAsset.GetId().ToString<AZStd::string>().c_str(), shaderVariantTreeAsset.GetHint().c_str());
return;
}
}
AZ::TickBus::QueueFunction([shaderAssetId, shaderVariantTreeAsset]()
{
ShaderVariantFinderNotificationBus::Event(
shaderAssetId,
&ShaderVariantFinderNotification::OnShaderVariantTreeAssetReady, shaderVariantTreeAsset, true /*isError*/);
});
}
void ShaderVariantAsyncLoader::OnShaderVariantAssetError(Data::Asset<ShaderVariantAsset> shaderVariantAsset)
{
// Will be used to address the notification bus.
Data::AssetId shaderAssetId;
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
Data::AssetId shaderVariantTreeAssetId(shaderVariantAsset.GetId().m_guid, 0);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt != m_shaderVariantData.end())
{
ShaderVariantCollection& shaderVariantCollection = findIt->second;
shaderAssetId = shaderVariantCollection.m_shaderAssetId;
auto& shaderVariantMap = shaderVariantCollection.m_shaderVariantsMap;
auto shaderVariantFindIt = shaderVariantMap.find(shaderVariantAsset.GetId());
if (shaderVariantFindIt != shaderVariantMap.end())
{
shaderVariantMap.erase(shaderVariantFindIt);
}
}
}
AZ::TickBus::QueueFunction([shaderAssetId, shaderVariantAsset]()
{
ShaderVariantFinderNotificationBus::Event(
shaderAssetId,
&ShaderVariantFinderNotification::OnShaderVariantAssetReady, shaderVariantAsset, true /*isError*/);
});
}
void ShaderVariantAsyncLoader::QueueShaderVariantTreeForLoading(
const PairOfShaderAssetAndShaderVariantId& shaderAndVariantPair,
AZStd::unordered_set<Data::AssetId>& shaderVariantTreePendingRequests)
{
auto shaderAssetId = shaderAndVariantPair.m_shaderAsset.GetId();
if (shaderVariantTreePendingRequests.count(shaderAndVariantPair.m_shaderAsset.GetId()))
{
// Already queued.
return;
}
Data::AssetId shaderVariantTreeAssetId = ShaderVariantTreeAsset::GetShaderVariantTreeAssetIdFromShaderAssetId(shaderAssetId);
if (!shaderVariantTreeAssetId.IsValid())
{
shaderVariantTreePendingRequests.insert(shaderAssetId);
return;
}
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt != m_shaderVariantData.end())
{
// Already queued.
return;
}
}
shaderVariantTreePendingRequests.insert(shaderAssetId);
}
bool ShaderVariantAsyncLoader::TryToLoadShaderVariantTreeAsset(const Data::AssetId& shaderAssetId)
{
Data::AssetId shaderVariantTreeAssetId = ShaderVariantTreeAsset::GetShaderVariantTreeAssetIdFromShaderAssetId(shaderAssetId);
if (!shaderVariantTreeAssetId.IsValid())
{
// Return false in hope to retry later.
return false;
}
//If we already loaded such asset let's simply dispatch the notification on the next tick.
Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset;
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
m_shaderAssetIdToShaderVariantTreeAssetId.emplace(shaderAssetId, shaderVariantTreeAssetId);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt != m_shaderVariantData.end())
{
shaderVariantTreeAsset = findIt->second.m_shaderVariantTree;
}
}
if (shaderVariantTreeAsset.IsReady())
{
AZ::TickBus::QueueFunction([shaderAssetId, shaderVariantTreeAsset]()
{
ShaderVariantFinderNotificationBus::Event(
shaderAssetId,
&ShaderVariantFinderNotification::OnShaderVariantTreeAssetReady, shaderVariantTreeAsset, false /*isError*/);
});
return true;
}
Data::AssetBus::MultiHandler::BusDisconnect(shaderVariantTreeAssetId);
//Let's queue the asset for loading.
shaderVariantTreeAsset = Data::AssetManager::Instance().GetAsset<AZ::RPI::ShaderVariantTreeAsset>(shaderVariantTreeAssetId, AZ::Data::AssetLoadBehavior::QueueLoad);
if (shaderVariantTreeAsset.IsError())
{
// The asset doesn't exist in the database yet. Return false in hope to retry later.
return false;
}
// We need to preserve a reference to shaderVariantTreeAsset, otherwise the asset load will be cancelled.
// This means we have to create the ShaderVariantCollection struct before OnAssetReady is called.
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt != m_shaderVariantData.end())
{
ShaderVariantCollection& shaderVariantCollection = findIt->second;
shaderVariantCollection.m_shaderVariantTree = shaderVariantTreeAsset;
shaderVariantCollection.m_shaderAssetId = shaderAssetId;
}
else
{
m_shaderVariantData.emplace(shaderVariantTreeAssetId, ShaderVariantCollection());
ShaderVariantCollection& collection = m_shaderVariantData[shaderVariantTreeAssetId];
collection.m_shaderAssetId = shaderAssetId;
collection.m_shaderVariantTree = shaderVariantTreeAsset;
}
}
Data::AssetBus::MultiHandler::BusConnect(shaderVariantTreeAssetId);
return true;
}
bool ShaderVariantAsyncLoader::TryToLoadShaderVariantAsset(const Data::AssetId& shaderVariantAssetId)
{
// Will be used to address the notification bus.
Data::AssetId shaderAssetId;
//If we already loaded such asset let's simply dispatch the notification on the next tick.
Data::Asset<ShaderVariantAsset> shaderVariantAsset;
Data::AssetId shaderVariantTreeAssetId(shaderVariantAssetId.m_guid, 0);
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt != m_shaderVariantData.end())
{
ShaderVariantCollection& shaderVariantCollection = findIt->second;
shaderAssetId = shaderVariantCollection.m_shaderAssetId;
auto& shaderVariantMap = shaderVariantCollection.m_shaderVariantsMap;
auto variantFindIt = shaderVariantMap.find(shaderVariantAssetId);
if (variantFindIt != shaderVariantMap.end())
{
shaderVariantAsset = variantFindIt->second;
}
}
else
{
AZ_Assert(false, "Looking for a variant without a tree.");
return true; //Returning true means the requested asset should be removed from the queue.
}
}
if (shaderVariantAsset.IsReady())
{
AZ::TickBus::QueueFunction([shaderAssetId, shaderVariantAsset]()
{
ShaderVariantFinderNotificationBus::Event(
shaderAssetId,
&ShaderVariantFinderNotification::OnShaderVariantAssetReady, shaderVariantAsset, false /*isError*/);
});
return true;
}
Data::AssetBus::MultiHandler::BusDisconnect(shaderVariantAssetId);
// Make sure the asset actually exists
Data::AssetInfo assetInfo;
Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &Data::AssetCatalogRequestBus::Events::GetAssetInfoById, shaderVariantAssetId);
if (!assetInfo.m_assetId.IsValid())
{
// The asset doesn't exist in the database yet. Return false to retry later.
return false;
}
// Let's queue the asset for loading.
shaderVariantAsset = Data::AssetManager::Instance().GetAsset<AZ::RPI::ShaderVariantAsset>(shaderVariantAssetId, AZ::Data::AssetLoadBehavior::QueueLoad);
if (shaderVariantAsset.IsError())
{
// The asset exists (we just checked GetAssetInfoById above) but some error occurred.
return false;
}
// We need to preserve a reference to shaderVariantAsset, otherwise the asset load will be cancelled.
{
AZStd::unique_lock<decltype(m_mutex)> lock(m_mutex);
auto findIt = m_shaderVariantData.find(shaderVariantTreeAssetId);
if (findIt != m_shaderVariantData.end())
{
ShaderVariantCollection& shaderVariantCollection = findIt->second;
auto& shaderVariantMap = shaderVariantCollection.m_shaderVariantsMap;
shaderVariantMap.emplace(shaderVariantAssetId, shaderVariantAsset);
}
else
{
AZ_Assert(false, "Looking for a variant without a tree.");
return true; //Returning true means the requested asset should be removed from the queue.
}
}
Data::AssetBus::MultiHandler::BusConnect(shaderVariantAssetId);
return true;
}
} // namespace RPI
} // namespace AZ