[ATOM-15472] Shader Build Pipeline: Remove Deprecated Files And Funct… (#1079)
* [ATOM-15472] Shader Build Pipeline: Remove Deprecated Files And Functions That Predate The Shader Supervariants These are the essential impactful changes as a result of deprecating the ShaderResourceGroupAsset. * Addressed feedback by @moudgils. Better comments in header files. * More updates related with deprecation of ShaderResourceGroupAsset * Deleted the temporary version 2 classes. * Updated version of the shader asset builders. * Updated version of all the shader related classes impacted by the Supervariant concept and deprecation of ShaderResourceGroupAsset * Changes to *.pass and DGI, Reflections and RayTracing. * changes to material related assets * changes to core lights * Changes to auxgeom/dynamic draw. * changes to decals, lyshine, imguipass * changes to RPI Pass classes * Shader for SceneSrg, ViewSrg and ForwardPass Srgs. * changes to mesh, skinned mesh, Morphtarget. * Fixes to RayTracingPass.cpp & now allow empty srg in shaders. * Updated Atom_RPI.Tests * Simplified InstanceDatabase by removing AddHandler ------------------------------------------------------------------------------------ * Updated DiffuseGI precompiled shaders. Added RayTracingSceneSrg and RayTracingMaterialSrg shader asset. Updated ShaderAssetCreator::Clone to handle the supervariant when processing root variants. Co-authored-by: Doug McDiarmid <dmcdiar@amazon.com> ------------------------------------------------------------------------------------ * Changed semantics for some PassSrg to SRG_PerPass_WithFallback. AuxGeom/FixedShapeProcessor.cpp requires SRG_PerDraw on ObjectSrg. Removed names of SceneSrg and ViewSrg from RPISystemDescriptor.cpp * Moved ShaderLib/Atom/Features/DummyEntryFunctions.azsli To Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/DummyEntryFunctions.azsli Removed redundant checking for finalization in ShaderResourceGroupLayout.cpp * Fixed race condition bug for Shader::FindOrCreate. InstanceDatabase<>::CreateInstance() needs to be atomic for instance creation and initialization. Added optional InstanceHandler::CreateFunctionWithParams to accomodate to the needs of Instances that need more than an asset reference to be able to be created an initialzed. Removed ShaderResourceGroup::FindOrCreate() only ::Create is available now. * Renamed scene_and_view_srgs.* as SceneAndViewSrgs.* Changed GetAzslFileOfOrigin for GetUniqueId * Fixed unit tests. * Reverted the serialization name of m_uniqueId back to "m_azslFileOfOrigin" so precompiled shaders don't fail in layout comparison. * Fixed AtomCore.Tests Removed non-applicable test. InstanceDatabase.AddHandler() is not available anymore. * The Null rhi is re-enabled for shader compilation. Signed-off-by: garrieta <garrieta@amazon.com>
This commit is contained in:
@@ -76,7 +76,7 @@ namespace AZ
|
||||
template <typename Type>
|
||||
friend struct AZStd::IntrusivePtrCountPolicy;
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
friend class InstanceDatabase;
|
||||
|
||||
// Pointer to the InstanceDatabase that owns this instance. Will be null if the InstanceData object
|
||||
|
||||
@@ -46,14 +46,22 @@ namespace AZ
|
||||
*/
|
||||
using CreateFunction = AZStd::function<Instance<Type>(AssetData*)>;
|
||||
|
||||
using CreateFunctionWithParam = AZStd::function<Instance<Type>(AssetData*, const AZStd::any* param)>;
|
||||
|
||||
/**
|
||||
* Deletion takes an asset as input and transfers ownership to the method.
|
||||
*/
|
||||
using DeleteFunction = AZStd::function<void(Type*)>;
|
||||
|
||||
/// [Required] The function to use when creating an instance.
|
||||
/// The system will assert if no creation function is provided.
|
||||
CreateFunction m_createFunction;
|
||||
/// A function to use when creating an instance.
|
||||
/// The system will assert if both @m_createFunction and @m_createFunctionWithParam
|
||||
/// creation functions are invalid.
|
||||
CreateFunction m_createFunction = nullptr;
|
||||
|
||||
/// A function with an additional custom param to use when creating an instance.
|
||||
/// The system will assert if both @m_createFunction and @m_createFunctionWithParam
|
||||
/// creation functions are invalid.
|
||||
CreateFunctionWithParam m_createFunctionWithParam = nullptr;
|
||||
|
||||
/// [Optional] The function to use when deleting an instance.
|
||||
DeleteFunction m_deleteFunction = [](Type* t) { delete t; };
|
||||
@@ -156,28 +164,14 @@ namespace AZ
|
||||
* Use this function when creating an InstanceDatabase that will handle concrete classes of @ref Type.
|
||||
* \param assetType - All instances will be based on subclasses of this asset type.
|
||||
* \param handler - An InstanceHandler that creates instances of @ref assetType assets.
|
||||
* \param checkAssetIds - If true, it will be validated that "instance->m_assetId == asset.GetId()"
|
||||
*/
|
||||
static void Create(const AssetType& assetType, const InstanceHandler<Type>& handler);
|
||||
|
||||
/**
|
||||
* Create the InstanceDatabase with no handlers. Individual handlers must be added using @ref AddHandler().
|
||||
* Use this function when creating an InstanceDatabase that will handle subclasses of @ref Type.
|
||||
* \param assetType - All instances will be based on subclasses of this asset type.
|
||||
*/
|
||||
static void Create(const AssetType& assetType);
|
||||
static void Create(const AssetType& assetType, const InstanceHandler<Type>& handler, bool checkAssetIds = true);
|
||||
|
||||
static void Destroy();
|
||||
static bool IsReady();
|
||||
static InstanceDatabase& Instance();
|
||||
|
||||
/**
|
||||
* Add an InstanceHandler that will create instances for assets of type @ref assetType.
|
||||
*/
|
||||
void AddHandler(const AssetType& assetType, const InstanceHandler<Type>& handler);
|
||||
void AddHandler(const AssetType& assetType, typename InstanceHandler<Type>::CreateFunction createFunction);
|
||||
|
||||
void RemoveHandler(const AssetType& assetType);
|
||||
|
||||
/**
|
||||
* Attempts to find an instance associated with the provided id. If the instance exists, it
|
||||
* is returned. If no instance is found, nullptr is returned. If is safe to call this from
|
||||
@@ -205,18 +199,20 @@ namespace AZ
|
||||
* when acquiring an instance.
|
||||
* @return Returns a smart pointer to the instance, which was either found or created.
|
||||
*/
|
||||
Data::Instance<Type> FindOrCreate(const InstanceId& id, const Asset<AssetData>& asset);
|
||||
Data::Instance<Type> FindOrCreate(const InstanceId& id, const Asset<AssetData>& asset, const AZStd::any* param = nullptr);
|
||||
|
||||
//! Calls the above FindOrCreate using an InstanceId created from the asset
|
||||
Data::Instance<Type> FindOrCreate(const Asset<AssetData>& asset);
|
||||
Data::Instance<Type> FindOrCreate(const Asset<AssetData>& asset, const AZStd::any* param = nullptr);
|
||||
|
||||
//! Calls FindOrCreate using a random InstanceId
|
||||
Data::Instance<Type> Create(const Asset<AssetData>& asset);
|
||||
Data::Instance<Type> Create(const Asset<AssetData>& asset, const AZStd::any* param = nullptr);
|
||||
|
||||
private:
|
||||
InstanceDatabase(const AssetType& assetType);
|
||||
~InstanceDatabase();
|
||||
|
||||
bool m_checkAssetIds = true;
|
||||
//useAssetTypeAsKeyForHandlers;
|
||||
static const char* GetEnvironmentName();
|
||||
|
||||
// Utility function called by InstanceData to remove the instance from the database.
|
||||
@@ -224,11 +220,7 @@ namespace AZ
|
||||
|
||||
void ValidateSameAsset(InstanceData* instance, const Data::Asset<AssetData>& asset) const;
|
||||
|
||||
// Performs a thread-safe search for the InstanceHandler for a given asset type.
|
||||
bool FindHandler(const AssetType& assetType, InstanceHandler<Type>& handlerOut);
|
||||
|
||||
mutable AZStd::shared_mutex m_handlersMutex;
|
||||
AZStd::unordered_map<AssetType, InstanceHandler<Type>> m_handlers;
|
||||
InstanceHandler<Type> m_instanceHandler;
|
||||
|
||||
// m_database uses a recursive_mutex instead of a shared_mutex because it's possible to recursively
|
||||
// create or destroy instances on the same thread while in the midst of creating or destroying an instance.
|
||||
@@ -241,10 +233,11 @@ namespace AZ
|
||||
static EnvironmentVariable<InstanceDatabase*> ms_instance;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
EnvironmentVariable<InstanceDatabase<Type>*> InstanceDatabase<Type>::ms_instance = nullptr;
|
||||
template<typename Type>
|
||||
EnvironmentVariable<InstanceDatabase<Type>*>
|
||||
InstanceDatabase<Type>::ms_instance = nullptr;
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
InstanceDatabase<Type>::~InstanceDatabase()
|
||||
{
|
||||
#ifdef AZ_DEBUG_BUILD
|
||||
@@ -261,52 +254,7 @@ namespace AZ
|
||||
"AZ::Data::%s still has active references.", Type::GetDatabaseName());
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void InstanceDatabase<Type>::AddHandler(const AssetType& assetType, const InstanceHandler<Type>& handler)
|
||||
{
|
||||
AZ_Assert(handler.m_createFunction, "You are required to provide a create function to InstanceDatabase.");
|
||||
|
||||
AZStd::unique_lock<AZStd::shared_mutex> lock(m_handlersMutex);
|
||||
auto result = m_handlers.emplace(assetType, handler);
|
||||
AZ_Assert(result.second, "An InstanceHandler already exists for this AssetType");
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void InstanceDatabase<Type>::AddHandler(const AssetType& assetType, typename InstanceHandler<Type>::CreateFunction createFunction)
|
||||
{
|
||||
InstanceHandler<Type> instanceHandler;
|
||||
instanceHandler.m_createFunction = createFunction;
|
||||
|
||||
AddHandler(assetType, instanceHandler);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void InstanceDatabase<Type>::RemoveHandler(const AssetType& assetType)
|
||||
{
|
||||
AZStd::unique_lock<AZStd::shared_mutex> lock(m_handlersMutex);
|
||||
m_handlers.erase(assetType);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
bool InstanceDatabase<Type>::FindHandler(const AssetType& assetType, InstanceHandler<Type>& handlerOut)
|
||||
{
|
||||
AZStd::shared_lock<AZStd::shared_mutex> lock(m_handlersMutex);
|
||||
|
||||
auto handlerIter = m_handlers.find(assetType);
|
||||
if (handlerIter != m_handlers.end())
|
||||
{
|
||||
// Since the handler is just a couple pointers, we copy the handler so we can
|
||||
// release the lock right away.
|
||||
handlerOut = handlerIter->second;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
Data::Instance<Type> InstanceDatabase<Type>::Find(const InstanceId& id) const
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::recursive_mutex> lock(m_databaseMutex);
|
||||
@@ -318,8 +266,9 @@ namespace AZ
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Data::Instance<Type> InstanceDatabase<Type>::FindOrCreate(const InstanceId& id, const Asset<AssetData>& asset)
|
||||
template<typename Type>
|
||||
Data::Instance<Type> InstanceDatabase<Type>::FindOrCreate(
|
||||
const InstanceId& id, const Asset<AssetData>& asset, const AZStd::any* param)
|
||||
{
|
||||
if (!id.IsValid())
|
||||
{
|
||||
@@ -358,24 +307,6 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
if (!azrtti_istypeof(m_baseAssetType, assetLocal.Get()))
|
||||
{
|
||||
InstanceHandler<Type> instanceHandler;
|
||||
|
||||
// If a handler was incorrectly registered for an unrelated asset type, this is the
|
||||
// first chance we have to discover that fact, because up until now all we had was two
|
||||
// TypeIds.
|
||||
if (FindHandler(assetLocal.GetType(), instanceHandler))
|
||||
{
|
||||
AZ_Assert(false, "An InstanceHandler was added for asset type %s which is not a subclass of the base asset type %s.",
|
||||
assetLocal.GetType().ToString<AZStd::string>().data(),
|
||||
m_baseAssetType.ToString<AZStd::string>().data()
|
||||
);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Take a lock to guard the insertion. Note that this will not guard against recursive insertions on the same thread.
|
||||
AZStd::scoped_lock<AZStd::recursive_mutex> lock(m_databaseMutex);
|
||||
|
||||
@@ -390,48 +321,46 @@ namespace AZ
|
||||
}
|
||||
|
||||
// Emplace a new instance and return it.
|
||||
InstanceHandler<Type> instanceHandler;
|
||||
if (FindHandler(assetLocal.GetType(), instanceHandler))
|
||||
// It's possible for the m_createFunction call to recursively trigger another FindOrCreate call, so be aware that
|
||||
// the contents of m_database may change within this call.
|
||||
Data::Instance<Type> instance = nullptr;
|
||||
if (!param)
|
||||
{
|
||||
// It's possible for the m_createFunction call to recursively trigger another FindOrCreate call, so be aware that
|
||||
// the contents of m_database may change within this call.
|
||||
Data::Instance<Type> instance = instanceHandler.m_createFunction(assetLocal.Get());
|
||||
if (instance)
|
||||
{
|
||||
AZ_Assert(m_database.find(id) == m_database.end(),
|
||||
"Instance creation for asset id %s resulted in a recursive creation of that asset, which was unexpected. "
|
||||
"This asset might be erroneously referencing itself as a dependent asset.", id.ToString<AZStd::string>().c_str());
|
||||
|
||||
instance->m_id = id;
|
||||
instance->m_parentDatabase = this;
|
||||
instance->m_assetId = assetLocal.GetId();
|
||||
instance->m_assetType = assetLocal.GetType();
|
||||
m_database.emplace(id, instance.get());
|
||||
}
|
||||
return AZStd::move(instance);
|
||||
instance = m_instanceHandler.m_createFunction(assetLocal.Get());
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning(
|
||||
"InstanceDatabase", false,
|
||||
"No InstanceHandler found for asset type %s", assetLocal.GetType().ToString<AZStd::string>().data());
|
||||
return nullptr;
|
||||
instance = m_instanceHandler.m_createFunctionWithParam(assetLocal.Get(), param);
|
||||
}
|
||||
|
||||
if (instance)
|
||||
{
|
||||
AZ_Assert(m_database.find(id) == m_database.end(),
|
||||
"Instance creation for asset id %s resulted in a recursive creation of that asset, which was unexpected. "
|
||||
"This asset might be erroneously referencing itself as a dependent asset.", id.ToString<AZStd::string>().c_str());
|
||||
|
||||
instance->m_id = id;
|
||||
instance->m_parentDatabase = this;
|
||||
instance->m_assetId = assetLocal.GetId();
|
||||
instance->m_assetType = assetLocal.GetType();
|
||||
m_database.emplace(id, instance.get());
|
||||
}
|
||||
return AZStd::move(instance);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Data::Instance<Type> InstanceDatabase<Type>::FindOrCreate(const Asset<AssetData>& asset)
|
||||
template<typename Type>
|
||||
Data::Instance<Type> InstanceDatabase<Type>::FindOrCreate(const Asset<AssetData>& asset, const AZStd::any* param)
|
||||
{
|
||||
return FindOrCreate(Data::InstanceId::CreateFromAssetId(asset.GetId()), asset);
|
||||
return FindOrCreate(Data::InstanceId::CreateFromAssetId(asset.GetId()), asset, param);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Data::Instance<Type> InstanceDatabase<Type>::Create(const Asset<AssetData>& asset)
|
||||
template<typename Type>
|
||||
Data::Instance<Type> InstanceDatabase<Type>::Create(const Asset<AssetData>& asset, const AZStd::any* param)
|
||||
{
|
||||
return FindOrCreate(Data::InstanceId::CreateRandom(), asset);
|
||||
return FindOrCreate(Data::InstanceId::CreateRandom(), asset, param);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
void InstanceDatabase<Type>::ReleaseInstance(InstanceData* instance, const InstanceId& instanceId)
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::recursive_mutex> lock(m_databaseMutex);
|
||||
@@ -447,22 +376,13 @@ namespace AZ
|
||||
instance->m_useCount.compare_exchange_strong(expectedRefCount, -1))
|
||||
{
|
||||
m_database.erase(instance->GetId());
|
||||
|
||||
InstanceHandler<Type> instanceHandler;
|
||||
if (FindHandler(instance->GetAssetType(), instanceHandler))
|
||||
{
|
||||
instanceHandler.m_deleteFunction(static_cast<Type*>(instance));
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false,
|
||||
"Cannot delete Instance. No InstanceHandler found for asset type %s", instance->GetAssetType().ToString<AZStd::string>().data());
|
||||
}
|
||||
m_instanceHandler.m_deleteFunction(static_cast<Type*>(instance));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void InstanceDatabase<Type>::ValidateSameAsset(InstanceData* instance, const Data::Asset<AssetData>& asset) const
|
||||
template<typename Type>
|
||||
void InstanceDatabase<Type>::ValidateSameAsset(
|
||||
InstanceData* instance, const Data::Asset<AssetData>& asset) const
|
||||
{
|
||||
/**
|
||||
* The following validation layer is disabled in release, but is designed to catch a couple related edge cases
|
||||
@@ -476,46 +396,47 @@ namespace AZ
|
||||
*/
|
||||
|
||||
#if defined (AZ_DEBUG_BUILD)
|
||||
AZ_Error("InstanceDatabase", instance->m_assetId == asset.GetId(),
|
||||
"InstanceDatabase::FindOrCreate found the requested instance, but a different asset was used to create it. "
|
||||
"Instances of a specific id should be acquired using the same asset. Either make sure the instance id "
|
||||
"is actually unique, or that you are using the same asset each time for that particular id.");
|
||||
if (m_checkAssetIds)
|
||||
{
|
||||
AZ_Error(
|
||||
"InstanceDatabase", (instance->m_assetId == asset.GetId()),
|
||||
"InstanceDatabase::FindOrCreate found the requested instance, but a different asset was used to create it. "
|
||||
"Instances of a specific id should be acquired using the same asset. Either make sure the instance id "
|
||||
"is actually unique, or that you are using the same asset each time for that particular id.");
|
||||
}
|
||||
#else
|
||||
AZ_UNUSED(instance);
|
||||
AZ_UNUSED(asset);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
InstanceDatabase<Type>::InstanceDatabase(const AssetType& assetType)
|
||||
: m_baseAssetType(assetType)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void InstanceDatabase<Type>::Create(const AssetType& assetType)
|
||||
template<typename Type>
|
||||
void InstanceDatabase<Type>::Create(const AssetType& assetType, const InstanceHandler<Type>& handler, bool checkAssetIds)
|
||||
{
|
||||
AZ_Assert(!ms_instance || !ms_instance.Get(), "InstanceDatabase already created!");
|
||||
|
||||
if (!ms_instance)
|
||||
{
|
||||
ms_instance = Environment::CreateVariable<InstanceDatabase*>(GetEnvironmentName());
|
||||
ms_instance = Environment::CreateVariable<InstanceDatabase<Type>*>(GetEnvironmentName());
|
||||
}
|
||||
|
||||
if (!ms_instance.Get())
|
||||
{
|
||||
ms_instance.Set(aznew InstanceDatabase<Type>(assetType));
|
||||
}
|
||||
|
||||
AZ_Assert(handler.m_createFunction || handler.m_createFunctionWithParam, "At least one create function must be valid");
|
||||
ms_instance.Get()->m_instanceHandler = handler;
|
||||
ms_instance.Get()->m_checkAssetIds = checkAssetIds;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void InstanceDatabase<Type>::Create(const AssetType& assetType, const InstanceHandler<Type>& handler)
|
||||
{
|
||||
Create(assetType);
|
||||
Instance().AddHandler(assetType, handler);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
void InstanceDatabase<Type>::Destroy()
|
||||
{
|
||||
AZ_Assert(ms_instance, "InstanceDatabase not created!");
|
||||
@@ -523,7 +444,7 @@ namespace AZ
|
||||
*ms_instance = nullptr;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
bool InstanceDatabase<Type>::IsReady()
|
||||
{
|
||||
if (!ms_instance)
|
||||
@@ -534,7 +455,7 @@ namespace AZ
|
||||
return ms_instance && *ms_instance;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
InstanceDatabase<Type>& InstanceDatabase<Type>::Instance()
|
||||
{
|
||||
if (!ms_instance)
|
||||
@@ -546,10 +467,12 @@ namespace AZ
|
||||
return *(*ms_instance);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template<typename Type>
|
||||
const char* InstanceDatabase<Type>::GetEnvironmentName()
|
||||
{
|
||||
static_assert(HasInstanceDatabaseName<Type>::value, "All classes used as instances in an InstanceDatabase need to define AZ_INSTANCE_DATA in the class.");
|
||||
static_assert(
|
||||
HasInstanceDatabaseName<Type>::value,
|
||||
"All classes used as instances in an InstanceDatabase need to define AZ_INSTANCE_DATA in the class.");
|
||||
return Type::GetDatabaseName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,7 @@ namespace UnitTest
|
||||
static const AssetId s_assetId3{ Uuid("{D9CDAB04-D206-431E-BDC0-1DD615D56197}") };
|
||||
|
||||
// test asset type
|
||||
class TestAssetType
|
||||
: public AssetData
|
||||
class TestAssetType : public AssetData
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(TestAssetType, AZ::SystemAllocator, 0);
|
||||
@@ -47,30 +46,30 @@ namespace UnitTest
|
||||
}
|
||||
};
|
||||
|
||||
class TestInstanceA
|
||||
: public InstanceData
|
||||
class TestInstanceA : public InstanceData
|
||||
{
|
||||
public:
|
||||
AZ_INSTANCE_DATA(TestInstanceA, "{65CBF1C8-F65F-4A84-8A11-B510BC435DB0}");
|
||||
AZ_CLASS_ALLOCATOR(TestInstanceA, AZ::SystemAllocator, 0);
|
||||
|
||||
TestInstanceA(TestAssetType* asset)
|
||||
: m_asset{asset, AZ::Data::AssetLoadBehavior::Default}
|
||||
{}
|
||||
: m_asset{ asset, AZ::Data::AssetLoadBehavior::Default }
|
||||
{
|
||||
}
|
||||
|
||||
Asset<TestAssetType> m_asset;
|
||||
};
|
||||
|
||||
class TestInstanceB
|
||||
: public InstanceData
|
||||
class TestInstanceB : public InstanceData
|
||||
{
|
||||
public:
|
||||
AZ_INSTANCE_DATA(TestInstanceB, "{4ED0A8BF-7800-44B2-AC73-2CB759C61C37}");
|
||||
AZ_CLASS_ALLOCATOR(TestInstanceB, AZ::SystemAllocator, 0);
|
||||
|
||||
TestInstanceB(TestAssetType* asset)
|
||||
: m_asset{asset, AZ::Data::AssetLoadBehavior::Default }
|
||||
{}
|
||||
: m_asset{ asset, AZ::Data::AssetLoadBehavior::Default }
|
||||
{
|
||||
}
|
||||
|
||||
~TestInstanceB()
|
||||
{
|
||||
@@ -86,8 +85,7 @@ namespace UnitTest
|
||||
|
||||
// test asset handler
|
||||
template<typename AssetDataT>
|
||||
class MyAssetHandler
|
||||
: public AssetHandler
|
||||
class MyAssetHandler : public AssetHandler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MyAssetHandler, AZ::SystemAllocator, 0);
|
||||
@@ -120,13 +118,12 @@ namespace UnitTest
|
||||
}
|
||||
};
|
||||
|
||||
class InstanceDatabaseTest
|
||||
: public AllocatorsFixture
|
||||
class InstanceDatabaseTest : public AllocatorsFixture
|
||||
{
|
||||
protected:
|
||||
MyAssetHandler<TestAssetType>* m_assetHandler;
|
||||
public:
|
||||
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
@@ -200,7 +197,7 @@ namespace UnitTest
|
||||
|
||||
AZStd::vector<Uuid> guids;
|
||||
AZStd::vector<Asset<TestAssetType>> assets;
|
||||
|
||||
|
||||
for (size_t i = 0; i < assetIdCount; ++i)
|
||||
{
|
||||
Uuid guid = Uuid::CreateRandom();
|
||||
@@ -211,7 +208,6 @@ namespace UnitTest
|
||||
assets.emplace_back(assetManager.CreateAsset<TestAssetType>(guid, AZ::Data::AssetLoadBehavior::Default));
|
||||
}
|
||||
|
||||
|
||||
AZStd::vector<AZStd::thread> threads;
|
||||
AZStd::mutex mutex;
|
||||
AZStd::atomic<int> threadCount((int)threadCountMax);
|
||||
@@ -232,27 +228,29 @@ namespace UnitTest
|
||||
|
||||
for (size_t i = 0; i < threadCountMax; ++i)
|
||||
{
|
||||
threads.emplace_back([&instanceManager, &threadCount, &cv, &guids, &assets, &durationSeconds]()
|
||||
{
|
||||
AZ::Debug::Timer timer;
|
||||
timer.Stamp();
|
||||
|
||||
while(timer.GetDeltaTimeInSeconds() < durationSeconds)
|
||||
threads.emplace_back(
|
||||
[&instanceManager, &threadCount, &cv, &guids, &assets, &durationSeconds]()
|
||||
{
|
||||
const size_t index = rand() % guids.size();
|
||||
const Uuid uuid = guids[index];
|
||||
const InstanceId instanceId{uuid};
|
||||
const AssetId assetId{uuid};
|
||||
AZ::Debug::Timer timer;
|
||||
timer.Stamp();
|
||||
|
||||
Instance<TestInstanceA> instance = instanceManager.FindOrCreate(instanceId, Asset<TestAssetType>(assetId, azrtti_typeid<TestAssetType>()));
|
||||
EXPECT_NE(instance, nullptr);
|
||||
EXPECT_EQ(instance->GetId(), instanceId);
|
||||
EXPECT_EQ(instance->m_asset, assets[index]);
|
||||
}
|
||||
while (timer.GetDeltaTimeInSeconds() < durationSeconds)
|
||||
{
|
||||
const size_t index = rand() % guids.size();
|
||||
const Uuid uuid = guids[index];
|
||||
const InstanceId instanceId{ uuid };
|
||||
const AssetId assetId{ uuid };
|
||||
|
||||
threadCount--;
|
||||
cv.notify_one();
|
||||
});
|
||||
Instance<TestInstanceA> instance =
|
||||
instanceManager.FindOrCreate(instanceId, Asset<TestAssetType>(assetId, azrtti_typeid<TestAssetType>()));
|
||||
EXPECT_NE(instance, nullptr);
|
||||
EXPECT_EQ(instance->GetId(), instanceId);
|
||||
EXPECT_EQ(instance->m_asset, assets[index]);
|
||||
}
|
||||
|
||||
threadCount--;
|
||||
cv.notify_one();
|
||||
});
|
||||
}
|
||||
|
||||
bool timedOut = false;
|
||||
@@ -261,7 +259,9 @@ namespace UnitTest
|
||||
while (threadCount > 0 && !timedOut)
|
||||
{
|
||||
AZStd::unique_lock<AZStd::mutex> lock(mutex);
|
||||
timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSeconds * 2)));
|
||||
timedOut =
|
||||
(AZStd::cv_status::timeout ==
|
||||
cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSeconds * 2)));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(threadCount == 0) << "One or more threads appear to be deadlocked at " << timer.GetDeltaTimeInSeconds() << " seconds";
|
||||
@@ -280,8 +280,8 @@ namespace UnitTest
|
||||
TEST_F(InstanceDatabaseTest, ParallelInstanceCreate)
|
||||
{
|
||||
// This is the original test scenario from when InstanceDatabase was first implemented
|
||||
// threads, AssetIds, seconds
|
||||
ParallelInstanceCreateHelper( 8, 100, 5 );
|
||||
// threads, AssetIds, seconds
|
||||
ParallelInstanceCreateHelper(8, 100, 5);
|
||||
|
||||
// This value is checked in as 1 so this test doesn't take too much time, but can be increased locally to soak the test.
|
||||
const size_t attempts = 1;
|
||||
@@ -291,10 +291,10 @@ namespace UnitTest
|
||||
printf("Attempt %zu of %zu... \n", i, attempts);
|
||||
|
||||
// The idea behind this series of tests is that there are two threads sharing one Instance, and both threads try to
|
||||
// create or release that instance at the same time.
|
||||
// create or release that instance at the same time.
|
||||
// At the time, this set of scenarios has something like a 10% failure rate.
|
||||
const size_t duration = 2;
|
||||
// threads, AssetIds, seconds
|
||||
// threads, AssetIds, seconds
|
||||
ParallelInstanceCreateHelper(2, 1, duration);
|
||||
ParallelInstanceCreateHelper(4, 1, duration);
|
||||
ParallelInstanceCreateHelper(8, 1, duration);
|
||||
@@ -306,7 +306,7 @@ namespace UnitTest
|
||||
|
||||
// Here we try a bunch of different threadCount:assetCount ratios to be thorough
|
||||
const size_t duration = 2;
|
||||
// threads, AssetIds, seconds
|
||||
// threads, AssetIds, seconds
|
||||
ParallelInstanceCreateHelper(2, 1, duration);
|
||||
ParallelInstanceCreateHelper(4, 1, duration);
|
||||
ParallelInstanceCreateHelper(4, 2, duration);
|
||||
@@ -328,7 +328,10 @@ namespace UnitTest
|
||||
|
||||
// Tests whether the deleter actually calls delete properly without
|
||||
// a parent database.
|
||||
instance->m_onDeleteCallback = [this, &m_deleted] () { m_deleted = true; };
|
||||
instance->m_onDeleteCallback = [this, &m_deleted]()
|
||||
{
|
||||
m_deleted = true;
|
||||
};
|
||||
}
|
||||
|
||||
EXPECT_TRUE(m_deleted);
|
||||
@@ -386,242 +389,4 @@ namespace UnitTest
|
||||
InstanceDatabase<TestInstanceB>::Destroy();
|
||||
}
|
||||
|
||||
|
||||
class InstanceDatabaseTestWithMultipleSubclasses
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
protected:
|
||||
// We have "BaseAsset" with subclasses "FooAsset" and "BarAsset",
|
||||
// and corresponding "BaseInstance" with subclasses "FooInstance" and "BarInstance".
|
||||
// There is one "InstanceDatabse<BaseInstance>" that can create instances of both subtypes.
|
||||
|
||||
class BaseAsset
|
||||
: public AssetData
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(BaseAsset, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(FooAsset, "{35B443A6-D8ED-4C3C-A3F0-D642251F0AA5}", AssetData);
|
||||
|
||||
BaseAsset()
|
||||
{
|
||||
m_status = AssetStatus::Ready;
|
||||
}
|
||||
};
|
||||
|
||||
class BaseInstance
|
||||
: public InstanceData
|
||||
{
|
||||
public:
|
||||
AZ_INSTANCE_DATA(BaseInstance, "{EFEC3406-2CB7-462E-A676-C22177E143E6}");
|
||||
AZ_CLASS_ALLOCATOR(BaseInstance, AZ::SystemAllocator, 0);
|
||||
|
||||
BaseInstance(BaseAsset* asset)
|
||||
: m_asset{ asset, AZ::Data::AssetLoadBehavior::Default }
|
||||
{}
|
||||
|
||||
Asset<BaseAsset> m_asset;
|
||||
};
|
||||
|
||||
class FooAsset
|
||||
: public BaseAsset
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(FooAsset, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(FooAsset, "{74BAE278-3DCA-4ADD-807E-2A6873F9EA3C}", BaseAsset);
|
||||
};
|
||||
|
||||
class BarAsset
|
||||
: public BaseAsset
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(BarAsset, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(FooAsset, "{2BCD66F5-768B-4569-9FC2-DE92ABC9C0BF}", BaseAsset);
|
||||
};
|
||||
|
||||
class FooInstance
|
||||
: public BaseInstance
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(FooInstance, "{B5487509-5518-4591-AC96-03E623A584B7}", BaseInstance);
|
||||
AZ_CLASS_ALLOCATOR(FooInstance, AZ::SystemAllocator, 0);
|
||||
|
||||
FooInstance(BaseAsset* asset)
|
||||
: BaseInstance(asset)
|
||||
{
|
||||
EXPECT_TRUE(azrtti_typeid<FooAsset>() == asset->GetType());
|
||||
}
|
||||
};
|
||||
|
||||
class BarInstance
|
||||
: public BaseInstance
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BarInstance, "{CE9C844A-625D-4899-B7DB-8127D4618D25}", BaseInstance);
|
||||
AZ_CLASS_ALLOCATOR(BarInstance, AZ::SystemAllocator, 0);
|
||||
|
||||
BarInstance(BaseAsset* asset)
|
||||
: BaseInstance(asset)
|
||||
{
|
||||
EXPECT_TRUE(azrtti_typeid<BarAsset>() == asset->GetType());
|
||||
}
|
||||
};
|
||||
|
||||
MyAssetHandler<FooAsset> m_fooAssetHandler;
|
||||
MyAssetHandler<BarAsset> m_barAssetHandler;
|
||||
|
||||
public:
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
AllocatorInstance<PoolAllocator>::Create();
|
||||
AllocatorInstance<ThreadPoolAllocator>::Create();
|
||||
|
||||
// create the asset database
|
||||
{
|
||||
AssetManager::Descriptor desc;
|
||||
AssetManager::Create(desc);
|
||||
}
|
||||
|
||||
// create the instance database
|
||||
{
|
||||
InstanceDatabase<BaseInstance>::Create(azrtti_typeid<BaseAsset>());
|
||||
|
||||
InstanceHandler<BaseInstance> fooHandler;
|
||||
fooHandler.m_createFunction = [](AssetData* assetData)
|
||||
{
|
||||
EXPECT_TRUE(azrtti_istypeof<FooAsset>(assetData));
|
||||
return aznew FooInstance(static_cast<FooAsset*>(assetData));
|
||||
};
|
||||
InstanceDatabase<BaseInstance>::Instance().AddHandler(azrtti_typeid<FooAsset>(), fooHandler);
|
||||
|
||||
// Using a different overload of AddHandler()
|
||||
InstanceDatabase<BaseInstance>::Instance().AddHandler(azrtti_typeid<BarAsset>(), [](AssetData* assetData)
|
||||
{
|
||||
EXPECT_TRUE(azrtti_istypeof<BarAsset>(assetData));
|
||||
return aznew BarInstance(static_cast<BarAsset*>(assetData));
|
||||
});
|
||||
}
|
||||
|
||||
AssetManager::Instance().RegisterHandler(&m_fooAssetHandler, AzTypeInfo<FooAsset>::Uuid());
|
||||
AssetManager::Instance().RegisterHandler(&m_barAssetHandler, AzTypeInfo<BarAsset>::Uuid());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
AssetManager::Instance().UnregisterHandler(&m_fooAssetHandler);
|
||||
AssetManager::Instance().UnregisterHandler(&m_barAssetHandler);
|
||||
AssetManager::Destroy();
|
||||
|
||||
InstanceDatabase<BaseInstance>::Destroy();
|
||||
|
||||
AllocatorInstance<ThreadPoolAllocator>::Destroy();
|
||||
AllocatorInstance<PoolAllocator>::Destroy();
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(InstanceDatabaseTestWithMultipleSubclasses, InstanceCreate)
|
||||
{
|
||||
auto& assetManager = AssetManager::Instance();
|
||||
auto& instanceDatabase = InstanceDatabase<BaseInstance>::Instance();
|
||||
|
||||
Asset<FooAsset> fooAsset = assetManager.CreateAsset<FooAsset>(s_assetId0, AZ::Data::AssetLoadBehavior::Default);
|
||||
Asset<BarAsset> barAsset = assetManager.CreateAsset<BarAsset>(s_assetId1, AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
// Run the creation tests on 'A' first.
|
||||
|
||||
Instance<BaseInstance> fooInstanceA = instanceDatabase.Find(s_instanceId0);
|
||||
EXPECT_EQ(fooInstanceA, nullptr);
|
||||
|
||||
Instance<BaseInstance> barInstanceA = instanceDatabase.Find(s_instanceId1);
|
||||
EXPECT_EQ(barInstanceA, nullptr);
|
||||
|
||||
fooInstanceA = instanceDatabase.FindOrCreate(s_instanceId0, fooAsset);
|
||||
EXPECT_NE(fooInstanceA, nullptr);
|
||||
EXPECT_EQ(fooInstanceA->m_asset, fooAsset);
|
||||
EXPECT_TRUE(azrtti_typeid<FooInstance>() == fooInstanceA->RTTI_GetType());
|
||||
EXPECT_EQ(fooInstanceA, instanceDatabase.Find(s_instanceId0));
|
||||
|
||||
barInstanceA = instanceDatabase.FindOrCreate(s_instanceId1, barAsset);
|
||||
EXPECT_NE(barInstanceA, nullptr);
|
||||
EXPECT_EQ(barInstanceA->m_asset, barAsset);
|
||||
EXPECT_TRUE(azrtti_typeid<BarInstance>() == barInstanceA->RTTI_GetType());
|
||||
EXPECT_EQ(barInstanceA, instanceDatabase.Find(s_instanceId1));
|
||||
|
||||
// Run the same test on 'B' to make sure it works independently.
|
||||
|
||||
Instance<BaseInstance> fooInstanceB = instanceDatabase.Find(s_instanceId2);
|
||||
EXPECT_EQ(fooInstanceB, nullptr);
|
||||
|
||||
Instance<BaseInstance> barInstanceB = instanceDatabase.Find(s_instanceId3);
|
||||
EXPECT_EQ(barInstanceB, nullptr);
|
||||
|
||||
fooInstanceB = instanceDatabase.FindOrCreate(s_instanceId2, fooAsset);
|
||||
EXPECT_NE(fooInstanceB, nullptr);
|
||||
EXPECT_EQ(fooInstanceB->m_asset, fooAsset);
|
||||
EXPECT_TRUE(azrtti_typeid<FooInstance>() == fooInstanceB->RTTI_GetType());
|
||||
EXPECT_EQ(fooInstanceB, instanceDatabase.Find(s_instanceId2));
|
||||
|
||||
barInstanceB = instanceDatabase.FindOrCreate(s_instanceId3, barAsset);
|
||||
EXPECT_NE(barInstanceB, nullptr);
|
||||
EXPECT_EQ(barInstanceB->m_asset, barAsset);
|
||||
EXPECT_TRUE(azrtti_typeid<BarInstance>() == barInstanceB->RTTI_GetType());
|
||||
EXPECT_EQ(barInstanceB, instanceDatabase.Find(s_instanceId3));
|
||||
|
||||
// Make sure the instances are unique
|
||||
|
||||
EXPECT_NE(fooInstanceA, fooInstanceB);
|
||||
EXPECT_NE(barInstanceA, barInstanceB);
|
||||
}
|
||||
|
||||
TEST_F(InstanceDatabaseTestWithMultipleSubclasses, TestError_AddHandler_AssetTypeIsNotSubclass)
|
||||
{
|
||||
MyAssetHandler<TestAssetType> testAssetHandler;
|
||||
AssetManager::Instance().RegisterHandler(&testAssetHandler, azrtti_typeid<TestAssetType>());
|
||||
|
||||
// Register an instance handler with an unrelated asset type. This can't actually
|
||||
// check the AssetType yet because all it has are AssetType GUIDs, no actual data.
|
||||
{
|
||||
InstanceHandler<BaseInstance> instanceHandler;
|
||||
instanceHandler.m_createFunction = [](AssetData* assetData)
|
||||
{
|
||||
return aznew BaseInstance(static_cast<BaseAsset*>(assetData));
|
||||
};
|
||||
|
||||
AssetType unrelatedAssetType = azrtti_typeid<TestAssetType>();
|
||||
|
||||
InstanceDatabase<BaseInstance>::Instance().AddHandler(unrelatedAssetType, instanceHandler);
|
||||
}
|
||||
|
||||
// Try to use the unrelated handler. This is where we'll actually get an error.
|
||||
{
|
||||
AZ_TEST_START_ASSERTTEST;
|
||||
|
||||
Asset<TestAssetType> testAsset = AssetManager::Instance().CreateAsset<TestAssetType>(s_assetId0, AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
EXPECT_EQ(nullptr, InstanceDatabase<BaseInstance>::Instance().FindOrCreate(s_instanceId0, testAsset));
|
||||
|
||||
AZ_TEST_STOP_ASSERTTEST(1);
|
||||
}
|
||||
|
||||
AssetManager::Instance().UnregisterHandler(&testAssetHandler);
|
||||
}
|
||||
|
||||
TEST_F(InstanceDatabaseTestWithMultipleSubclasses, TestError_AddHandler_AlreadyExists)
|
||||
{
|
||||
InstanceHandler<BaseInstance> instanceHandler;
|
||||
instanceHandler.m_createFunction = [](AssetData*)
|
||||
{
|
||||
return nullptr; // Doesn't matter
|
||||
};
|
||||
|
||||
AZ_TEST_START_ASSERTTEST;
|
||||
|
||||
// The SetUp() function already registered a handler for FooAsset so this should fail
|
||||
InstanceDatabase<BaseInstance>::Instance().AddHandler(azrtti_typeid<FooAsset>(), instanceHandler);
|
||||
InstanceDatabase<BaseInstance>::Instance().AddHandler(azrtti_typeid<FooAsset>(), [](AssetData*) { return nullptr; });
|
||||
|
||||
AZ_TEST_STOP_ASSERTTEST(2);
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
Reference in New Issue
Block a user