[LYN-6838] Various Monolithic shutdown fixes for the GameLauncher (#4564)

* Added a stateless allocator which uses AZ_OS_MALLOC/AZ_OS_FREE to
allocate memory for objects in static memory.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the Maestro and LyShine Anim Nodes to use the
stateless_allocator for its static containers.

This prevents crashes in static de-init due to the SystemAllocator being
destroyed at that poitn

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the EBus AllocatorType to use the EBusEnvironmentAllocator

Because the EBus Context resides in static memory, the SystemAllocator
lifetime is shorter than the EBus Context.

This results in shutdown crashes in monolithic builds due to all of the
gem modules being linked in as static libraries and the EBus context now
destructing at the point of the executable static de-init, instead of
the module de-init, where the SystemAllocator would still be around.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fixed an assortment of shutdown issues due to deleting objects after
AZ allocators are no longer available

Fixed the NameDictionary IsReady() function to not assert when the
dictionary when invoked after the environment variable it was stored in
was destroyed.
Updated the NameData destructor to check that the NameDictionary
IsReady() before attempting to remove itself from the dictionary

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fixed NameDictionary destory workflow, to reset the EnvironmentVariable
instance

Updated the EnvironmentVariable instance to store the NameDictionary as a
value.

Added a rvalue reference `Set` function overload to the
EnvironmentVariable class to support move only types.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Clang 6.0.0 build fixes

The C++17 std::launder feature isn't available in that compiler version

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
This commit is contained in:
lumberyard-employee-dm
2021-10-13 09:38:36 -05:00
committed by GitHub
parent 3af07e5117
commit 97e9f4dc7d
23 changed files with 302 additions and 90 deletions
+4 -2
View File
@@ -77,9 +77,11 @@ namespace AZ
public:
/**
* Allocator used by the EBus.
* The default setting is AZStd::allocator, which uses AZ::SystemAllocator.
* The default setting is Internal EBusEnvironmentAllocator
* EBus code stores their Context instances in static memory
* Therfore the configured allocator must last as long as the EBus in a module
*/
using AllocatorType = AZStd::allocator;
using AllocatorType = AZ::Internal::EBusEnvironmentAllocator;
/**
* Defines how many handlers can connect to an address on the EBus
@@ -34,7 +34,9 @@ namespace AZ
friend IAllocator;
friend class AllocatorBase;
friend class Debug::AllocationRecords;
friend class AZ::Internal::EnvironmentVariableHolder<AllocatorManager>;
template<typename T, typename... Args> friend constexpr auto AZStd::construct_at(T*, Args&&... args)
->AZStd::enable_if_t<AZStd::is_void_v<AZStd::void_t<decltype(new (AZStd::declval<void*>()) T(AZStd::forward<Args>(args)...))>>, T*>;
template<typename T> constexpr friend void AZStd::destroy_at(T*);
public:
typedef AZStd::function<void (IAllocator* allocator, size_t /*byteSize*/, size_t /*alignment*/, int/* flags*/, const char* /*name*/, const char* /*fileName*/, int lineNum /*=0*/)> OutOfMemoryCBType;
@@ -251,16 +251,15 @@ namespace AZ
class EnvironmentVariableHolder
: public EnvironmentVariableHolderBase
{
void ConstructImpl(const AZStd::true_type& /* AZStd::has_trivial_constructor<T> */)
{
memset(&m_value, 0, sizeof(T));
}
template<class... Args>
void ConstructImpl(const AZStd::false_type& /* AZStd::has_trivial_constructor<T> */, Args&&... args)
void ConstructImpl(Args&&... args)
{
// Construction of non-trivial types is left up to the type's constructor.
new(&m_value) T(AZStd::forward<Args>(args)...);
// Use std::launder to ensure that the compiler treats the T* reinterpret_cast as a new object
#if __cpp_lib_launder
AZStd::construct_at(std::launder(reinterpret_cast<T*>(&m_value)), AZStd::forward<Args>(args)...);
#else
AZStd::construct_at(reinterpret_cast<T*>(&m_value), AZStd::forward<Args>(args)...);
#endif
}
static void DestructDispatchNoLock(EnvironmentVariableHolderBase *base, DestroyTarget selfDestruct)
{
@@ -274,10 +273,12 @@ namespace AZ
AZ_Assert(self->m_isConstructed, "Variable is not constructed. Please check your logic and guard if needed!");
self->m_isConstructed = false;
self->m_moduleOwner = nullptr;
if constexpr(!AZStd::is_trivially_destructible_v<T>)
{
reinterpret_cast<T*>(&self->m_value)->~T();
}
// Use std::launder to ensure that the compiler treats the T* reinterpret_cast as a new object
#if __cpp_lib_launder
AZStd::destroy_at(std::launder(reinterpret_cast<T*>(&self->m_value)));
#else
AZStd::destroy_at(reinterpret_cast<T*>(&self->m_value));
#endif
}
public:
EnvironmentVariableHolder(u32 guid, bool isOwnershipTransfer, Environment::AllocatorInterface* allocator)
@@ -303,24 +304,13 @@ namespace AZ
UnregisterAndDestroy(DestructDispatchNoLock, moduleRelease);
}
void Construct()
{
AZStd::lock_guard<AZStd::spin_mutex> lock(m_mutex);
if (!m_isConstructed)
{
ConstructImpl(AZStd::is_trivially_constructible<T>{});
m_isConstructed = true;
m_moduleOwner = Environment::GetModuleId();
}
}
template <class... Args>
void Construct(Args&&... args)
{
AZStd::lock_guard<AZStd::spin_mutex> lock(m_mutex);
if (!m_isConstructed)
{
ConstructImpl(typename AZStd::false_type(), AZStd::forward<Args>(args)...);
ConstructImpl(AZStd::forward<Args>(args)...);
m_isConstructed = true;
m_moduleOwner = Environment::GetModuleId();
}
@@ -333,7 +323,7 @@ namespace AZ
}
// variable storage
typename AZStd::aligned_storage<sizeof(T), AZStd::alignment_of<T>::value>::type m_value;
AZStd::aligned_storage_for_t<T> m_value;
static int s_moduleUseCount;
};
@@ -468,6 +458,11 @@ namespace AZ
Get() = value;
}
void Set(T&& value)
{
Get() = AZStd::move(value);
}
explicit operator bool() const
{
return IsValid();
@@ -42,7 +42,10 @@ namespace AZ
AZ_Assert(m_useCount > 0, "m_useCount is already 0!");
if (m_useCount.fetch_sub(1) == 1)
{
AZ::NameDictionary::Instance().TryReleaseName(hash);
if (AZ::NameDictionary::IsReady())
{
AZ::NameDictionary::Instance().TryReleaseName(hash);
}
}
}
}
@@ -21,23 +21,18 @@ namespace AZ
namespace NameDictionaryInternal
{
static AZ::EnvironmentVariable<NameDictionary*> s_instance = nullptr;
static AZ::EnvironmentVariable<NameDictionary> s_instance = nullptr;
}
void NameDictionary::Create()
{
using namespace NameDictionaryInternal;
AZ_Assert(!s_instance || !s_instance.Get(), "NameDictionary already created!");
AZ_Assert(!s_instance, "NameDictionary already created!");
if (!s_instance)
{
s_instance = AZ::Environment::CreateVariable<NameDictionary*>(NameDictionaryInstanceName);
}
if (!s_instance.Get())
{
s_instance.Set(aznew NameDictionary());
s_instance = AZ::Environment::CreateVariable<NameDictionary>(NameDictionaryInstanceName);
}
}
@@ -46,8 +41,7 @@ namespace AZ
using namespace NameDictionaryInternal;
AZ_Assert(s_instance, "NameDictionary not created!");
delete (*s_instance);
*s_instance = nullptr;
s_instance.Reset();
}
bool NameDictionary::IsReady()
@@ -56,10 +50,10 @@ namespace AZ
if (!s_instance)
{
s_instance = Environment::FindVariable<NameDictionary*>(NameDictionaryInstanceName);
s_instance = Environment::FindVariable<NameDictionary>(NameDictionaryInstanceName);
}
return s_instance && *s_instance;
return s_instance.IsConstructed();
}
NameDictionary& NameDictionary::Instance()
@@ -68,12 +62,12 @@ namespace AZ
if (!s_instance)
{
s_instance = Environment::FindVariable<NameDictionary*>(NameDictionaryInstanceName);
s_instance = Environment::FindVariable<NameDictionary>(NameDictionaryInstanceName);
}
AZ_Assert(s_instance && *s_instance, "NameDictionary has not been initialized yet.");
AZ_Assert(s_instance.IsConstructed(), "NameDictionary has not been initialized yet.");
return *(*s_instance);
return *s_instance;
}
NameDictionary::NameDictionary()
@@ -16,7 +16,7 @@
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/Name/Name.h>
namespace MaterialEditor
namespace MaterialEditor
{
class MaterialEditorCoreComponent;
}
@@ -34,14 +34,14 @@ namespace AZ
{
class NameData;
};
//! Maintains a list of unique strings for Name objects.
//! The main benefit of the Name system is very fast string equality comparison, because every
//! unique name has a unique ID. The NameDictionary's purpose is to guarantee name IDs do not
//! unique name has a unique ID. The NameDictionary's purpose is to guarantee name IDs do not
//! collide. It also saves memory by removing duplicate strings.
//!
//! Benchmarks have shown that creating a new Name object can be quite slow when the name doesn't
//! already exist in the NameDictionary, but is comparable to creating an AZStd::string for names
//! Benchmarks have shown that creating a new Name object can be quite slow when the name doesn't
//! already exist in the NameDictionary, but is comparable to creating an AZStd::string for names
//! that already exist.
class NameDictionary final
{
@@ -51,7 +51,10 @@ namespace AZ
friend Name;
friend Internal::NameData;
friend UnitTest::NameDictionaryTester;
template<typename T, typename... Args> friend constexpr auto AZStd::construct_at(T*, Args&&... args)
-> AZStd::enable_if_t<AZStd::is_void_v<AZStd::void_t<decltype(new (AZStd::declval<void*>()) T(AZStd::forward<Args>(args)...))>>, T*>;
template<typename T> constexpr friend void AZStd::destroy_at(T*);
public:
static void Create();
@@ -62,7 +65,7 @@ namespace AZ
//! Makes a Name from the provided raw string. If an entry already exists in the dictionary, it is shared.
//! Otherwise, it is added to the internal dictionary.
//!
//!
//! @param name The name to resolve against the dictionary.
//! @return A Name instance holding a dictionary entry associated with the provided raw string.
Name MakeName(AZStd::string_view name);
@@ -84,13 +87,13 @@ namespace AZ
// Attempts to release the name from the dictionary, but checks to make sure
// a reference wasn't taken by another thread.
void TryReleaseName(Name::Hash hash);
//////////////////////////////////////////////////////////////////////////
// Calculates a hash for the provided name string.
// Does not attempt to resolve hash collisions; that is handled elsewhere.
Name::Hash CalcHash(AZStd::string_view name);
AZStd::unordered_map<Name::Hash, Internal::NameData*> m_dictionary;
mutable AZStd::shared_mutex m_sharedMutex;
};
@@ -0,0 +1,94 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/std/allocator_stateless.h>
#include <AzCore/Memory/OSAllocator.h>
namespace AZStd
{
stateless_allocator::stateless_allocator(const char* name)
: m_name(name) {}
const char* stateless_allocator::get_name() const
{
return m_name;
}
void stateless_allocator::set_name(const char* name)
{
m_name = name;
}
auto stateless_allocator::allocate(size_type byteSize) -> pointer_type
{
return allocate(byteSize, AZ_DEFAULT_ALIGNMENT, 0);
}
auto stateless_allocator::allocate(size_type byteSize, size_type alignment, int) -> pointer_type
{
pointer_type address = AZ_OS_MALLOC(byteSize, alignment);
if (address == nullptr)
{
AZ_Error("Memory", false, "stateless_allocator ran out of system memory!\n");
}
return address;
}
void stateless_allocator::deallocate(pointer_type ptr, size_type)
{
AZ_OS_FREE(ptr);
}
void stateless_allocator::deallocate(pointer_type ptr, size_type, size_type)
{
AZ_OS_FREE(ptr);
}
auto stateless_allocator::max_size() const -> size_type
{
return AZ_CORE_MAX_ALLOCATOR_SIZE;
}
stateless_allocator stateless_allocator::select_on_container_copy_construction() const
{
return *this;
}
auto stateless_allocator::resize(pointer_type, size_type) -> size_type
{
return 0;
}
bool stateless_allocator::is_lock_free()
{
return false;
}
bool stateless_allocator::is_stale_read_allowed()
{
return false;
}
bool stateless_allocator::is_delayed_recycling()
{
return false;
}
// comparison operators
bool operator==(const stateless_allocator&, const stateless_allocator&)
{
return true;
}
bool operator!=(const stateless_allocator&, const stateless_allocator&)
{
return false;
}
}
@@ -0,0 +1,61 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/base.h>
#include <AzCore/std/typetraits/integral_constant.h>
#include <AzCore/RTTI/TypeInfoSimple.h>
namespace AZStd
{
class stateless_allocator
{
public:
AZ_TYPE_INFO(stateless_allocator, "{E4976C53-0B20-4F39-8D41-0A76F59A7D68}");
using value_type = uint8_t;
using pointer_type = void*;
using size_type = size_t;
using difference_type = ptrdiff_t;
using allow_memory_leaks = AZStd::true_type;
stateless_allocator(const char* name = "AZStd::stateless_allocator");
stateless_allocator(const stateless_allocator& rhs) = default;
stateless_allocator& operator=(const stateless_allocator& rhs) = default;
const char* get_name() const;
void set_name(const char* name);
pointer_type allocate(size_type byteSize);
pointer_type allocate(size_type byteSize, size_type alignment, int flags = 0);
void deallocate(pointer_type ptr, size_type alignment);
void deallocate(pointer_type ptr, size_type byteSize, size_type alignment);
// max_size actually returns the true maximum size of a single allocation
size_type max_size() const;
// Returns a copy of the allocator
stateless_allocator select_on_container_copy_construction() const;
//! extensions
size_type resize(pointer_type ptr, size_type newSize);
bool is_lock_free();
bool is_stale_read_allowed();
bool is_delayed_recycling();
private:
const char* m_name;
};
bool operator==(const stateless_allocator& left, const stateless_allocator& right);
bool operator!=(const stateless_allocator& left, const stateless_allocator& right);
}
@@ -12,6 +12,8 @@ set(FILES
allocator.h
allocator_ref.h
allocator_stack.h
allocator_stateless.cpp
allocator_stateless.h
allocator_static.h
allocator_traits.h
any.h
@@ -20,7 +20,7 @@
namespace AZStd
{
// alias std::pointer_traits into the AZStd::namespace
// alias std::pointer_traits into the AZStd::namespace
using std::pointer_traits;
//! Bring the names of uninitialized_default_construct and
@@ -229,7 +229,7 @@ namespace AZStd
//! `new (declval<void*>()) T(declval<Args>()...)` is well-formed
template <typename T, typename... Args>
constexpr auto construct_at(T* ptr, Args&&... args)
-> enable_if_t<is_void_v<void_t<decltype(new (declval<void*>()) T(AZStd::forward<Args>(args)...))>>, T*>
-> enable_if_t<AZStd::is_void_v<AZStd::void_t<decltype(new (AZStd::declval<void*>()) T(AZStd::forward<Args>(args)...))>>, T*>
{
return ::new (ptr) T(AZStd::forward<Args>(args)...);
}
@@ -487,7 +487,7 @@ namespace AZStd
{
//! Implements the C++17 uninitialized_move function
//! The functions accepts two input iterators and an output iterator
//! It performs an AZStd::move on each in in the range of the input iterator
//! It performs an AZStd::move on each in in the range of the input iterator
//! and stores the result in location pointed by the output iterator
template <typename InputIt, typename ForwardIt>
ForwardIt uninitialized_move(InputIt first, InputIt last, ForwardIt result)
+3 -2
View File
@@ -13,6 +13,7 @@
#include <AzCore/Math/Crc.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/allocator_stateless.h>
#include <Range.h>
#include <AnimKey.h>
@@ -181,7 +182,7 @@ public:
private:
AnimParamType m_type;
AZStd::string m_name;
AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator> m_name;
};
namespace AZStd
@@ -617,7 +618,7 @@ public:
, valueType(_valueType)
, flags(_flags) {};
AZStd::string name; // parameter name.
AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator> name; // parameter name.
CAnimParamType paramType; // parameter id.
AnimValueType valueType; // value type, defines type of track to use for animating this parameter.
ESupportedParamFlags flags; // combination of flags from ESupportedParamFlags.
+8
View File
@@ -13,6 +13,7 @@
#include <unordered_map>
#include <unordered_set>
#include <AzCore/std/allocator_stateless.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/string/string.h>
@@ -491,6 +492,13 @@ namespace stl
return type;
}
//! Specialization of string to const char cast.
template <>
inline const char* constchar_cast(const AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator>& type)
{
return type.c_str();
}
//! Specialization of string to const char cast.
template <>
inline const char* constchar_cast(const AZStd::string& type)
@@ -357,7 +357,7 @@ namespace AZ
// Texture2DArray<float2> m_decalTextureArrayNormalMaps0;
// Texture2DArray<float2> m_decalTextureArrayNormalMaps1;
// Texture2DArray<float2> m_decalTextureArrayNormalMaps2;
static const AZStd::array<AZStd::string, DecalMapType_Num> ShaderNames = { "m_decalTextureArrayDiffuse",
static constexpr AZStd::array<AZStd::string_view, DecalMapType_Num> ShaderNames = { "m_decalTextureArrayDiffuse",
"m_decalTextureArrayNormalMaps" };
for (int mapType = 0; mapType < DecalMapType_Num; ++mapType)
@@ -365,7 +365,7 @@ namespace AZ
for (int texArrayIdx = 0; texArrayIdx < NumTextureArrays; ++texArrayIdx)
{
const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get();
const AZStd::string baseName = ShaderNames[mapType] + AZStd::to_string(texArrayIdx);
const AZStd::string baseName = AZStd::string(ShaderNames[mapType]) + AZStd::to_string(texArrayIdx);
m_decalTextureArrayIndices[texArrayIdx][mapType] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str()));
AZ_Warning(
@@ -346,7 +346,7 @@ namespace AZ::Render
void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector<RPI::RenderPipelineId>& validPipelineIds)
{
static const Name LightTypeName = Name("projected");
const Name LightTypeName = Name("projected");
const auto* passSystem = RPI::PassSystemInterface::Get();
const AZStd::vector<RPI::Pass*> passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate"));
@@ -16,12 +16,27 @@ namespace AZ
{
static const uint32_t s_minVulkanSupportedVersion = VK_API_VERSION_1_0;
static EnvironmentVariable<Instance> s_vulkanInstance;
static constexpr const char* s_vulkanInstanceKey = "VulkanInstance";
Instance& Instance::GetInstance()
{
static Instance s_instance;
return s_instance;
if (!s_vulkanInstance)
{
s_vulkanInstance = Environment::FindVariable<Instance>(s_vulkanInstanceKey);
if (!s_vulkanInstance)
{
s_vulkanInstance = Environment::CreateVariable<Instance>(s_vulkanInstanceKey);
}
}
return s_vulkanInstance.Get();
}
void Instance::Reset()
{
s_vulkanInstance.Reset();
}
Instance::~Instance()
{
@@ -34,6 +34,7 @@ namespace AZ
};
static Instance& GetInstance();
static void Reset();
~Instance();
bool Init(const Descriptor& descriptor);
void Shutdown();
@@ -101,6 +101,7 @@ namespace AZ
RHI::FactoryManagerBus::Broadcast(&RHI::FactoryManagerRequest::UnregisterFactory, this);
Instance::GetInstance().Shutdown();
Instance::Reset();
}
Name SystemComponent::GetName()
@@ -90,6 +90,9 @@ namespace AudioSystemGem
AudioSystemGemSystemComponent::~AudioSystemGemSystemComponent()
{
// The audio system uses the Audio::AudioSystemAllocator
// so it needs to be deleted before the allocator is shutdown
m_audioSystem.reset();
Audio::Platform::ShutdownAudioAllocators();
}
+4 -3
View File
@@ -15,6 +15,7 @@
#include <AzCore/Interface/Interface.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/std/containers/fixed_unordered_map.h>
#include <AzFramework/Input/Buses/Requests/InputTextEntryRequestBus.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
@@ -31,11 +32,11 @@ using namespace AzFramework;
using namespace ImGui;
// Wheel Delta const value.
const constexpr uint32_t IMGUI_WHEEL_DELTA = 120; // From WinUser.h, for Linux
static const constexpr uint32_t IMGUI_WHEEL_DELTA = 120; // From WinUser.h, for Linux
// Typedef and local static map to hold LyInput->ImGui Nav mappings ( filled up in Initialize() )
typedef AZStd::pair<AzFramework::InputChannelId, ImGuiNavInput_> LyButtonImGuiNavIndexPair;
typedef AZStd::unordered_map<AzFramework::InputChannelId, ImGuiNavInput_> LyButtonImGuiNavIndexMap;
using LyButtonImGuiNavIndexPair = AZStd::pair<AzFramework::InputChannelId, ImGuiNavInput_>;
using LyButtonImGuiNavIndexMap = AZStd::fixed_unordered_map<AzFramework::InputChannelId, ImGuiNavInput_, 11, 32>;
static LyButtonImGuiNavIndexMap s_lyInputToImGuiNavIndexMap;
/**
@@ -13,6 +13,7 @@
#include <LyShine/Animation/IUiAnimation.h>
#include "UiAnimationSystem.h"
#include <AzCore/std/allocator_stateless.h>
/*!
@@ -39,7 +40,7 @@ public:
, valueType(_valueType)
, flags(_flags) {};
AZStd::string name; // parameter name.
AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator> name; // parameter name.
CUiAnimParamType paramType; // parameter id.
EUiAnimValue valueType; // value type, defines type of track to use for animating this parameter.
ESupportedParamFlags flags; // combination of flags from ESupportedParamFlags.
@@ -14,9 +14,11 @@
#include "UiAnimSerialize.h"
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/std/allocator_stateless.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/containers/unordered_map.h>
#include <StlUtils.h>
#include <StaticInstance.h>
#include <ISystem.h>
#include <ILog.h>
#include <IConsole.h>
@@ -25,22 +27,31 @@
#include <IViewSystem.h>
//////////////////////////////////////////////////////////////////////////
// Serialization for anim nodes & param types
#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.find(eUiAnimNodeType_ ## name) == g_animNodeEnumToStringMap.end()); \
g_animNodeEnumToStringMap[eUiAnimNodeType_ ## name] = AZ_STRINGIZE(name); \
g_animNodeStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name;
namespace
{
using UiAnimParamSystemString = AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator>;
#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.find(eUiAnimParamType_ ## name) == g_animParamEnumToStringMap.end()); \
template <typename KeyType, typename MappedType, typename Compare = AZStd::less<KeyType>>
using UiAnimSystemOrderedMap = AZStd::map<KeyType, MappedType, Compare, AZStd::stateless_allocator>;
template <typename KeyType, typename MappedType, typename Hasher = AZStd::hash<KeyType>, typename EqualKey = AZStd::equal_to<KeyType>>
using UiAnimSystemUnorderedMap = AZStd::unordered_map<KeyType, MappedType, Hasher, EqualKey, AZStd::stateless_allocator>;
}
// Serialization for anim nodes & param types
#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.contains(eUiAnimNodeType_ ## name)); \
g_animNodeEnumToStringMap[eUiAnimNodeType_ ## name] = AZ_STRINGIZE(name); \
g_animNodeStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name;
#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.contains(eUiAnimParamType_ ## name)); \
g_animParamEnumToStringMap[eUiAnimParamType_ ## name] = AZ_STRINGIZE(name); \
g_animParamStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name;
g_animParamStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name;
namespace
{
AZStd::unordered_map<int, AZStd::string> g_animNodeEnumToStringMap;
StaticInstance<std::map<AZStd::string, EUiAnimNodeType, stl::less_stricmp<AZStd::string> >> g_animNodeStringToEnumMap;
UiAnimSystemUnorderedMap<int, UiAnimParamSystemString> g_animNodeEnumToStringMap;
UiAnimSystemOrderedMap<UiAnimParamSystemString, EUiAnimNodeType, stl::less_stricmp<UiAnimParamSystemString>> g_animNodeStringToEnumMap;
AZStd::unordered_map<int, AZStd::string> g_animParamEnumToStringMap;
StaticInstance<std::map<AZStd::string, EUiAnimParamType, stl::less_stricmp<AZStd::string> >> g_animParamStringToEnumMap;
UiAnimSystemUnorderedMap<int, UiAnimParamSystemString> g_animParamEnumToStringMap;
UiAnimSystemOrderedMap<UiAnimParamSystemString, EUiAnimParamType, stl::less_stricmp<UiAnimParamSystemString>> g_animParamStringToEnumMap;
// If you get an assert in this function, it means two node types have the same enum value.
void RegisterNodeTypes()
@@ -8,6 +8,7 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/allocator_stateless.h>
#include "AnimPostFXNode.h"
#include "AnimSplineTrack.h"
#include "CompoundSplineTrack.h"
@@ -38,7 +39,7 @@ public:
virtual void GetDefault(bool& val) const = 0;
virtual void GetDefault(Vec4& val) const = 0;
AZStd::string m_name;
AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator> m_name;
protected:
virtual ~CControlParamBase(){}
+24 -11
View File
@@ -8,6 +8,9 @@
#include <AzCore/Component/Entity.h>
#include <AzCore/std/allocator_stateless.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzFramework/Components/CameraBus.h>
#include <Maestro/Bus/SequenceComponentBus.h>
#include "Movie.h"
@@ -73,22 +76,32 @@ static SMovieSequenceAutoComplete s_movieSequenceAutoComplete;
#endif
//////////////////////////////////////////////////////////////////////////
// Serialization for anim nodes & param types
#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.find(AnimNodeType::name) == g_animNodeEnumToStringMap.end()); \
g_animNodeEnumToStringMap[AnimNodeType::name] = AZ_STRINGIZE(name); \
g_animNodeStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = AnimNodeType::name;
namespace
{
using AnimParamSystemString = AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator>;
#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.find(AnimParamType::name) == g_animParamEnumToStringMap.end()); \
g_animParamEnumToStringMap[AnimParamType::name] = AZ_STRINGIZE(name); \
g_animParamStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = AnimParamType::name;
template <typename KeyType, typename MappedType, typename Compare = AZStd::less<KeyType>>
using AnimSystemOrderedMap = AZStd::map<KeyType, MappedType, Compare, AZStd::stateless_allocator>;
template <typename KeyType, typename MappedType, typename Hasher = AZStd::hash<KeyType>, typename EqualKey = AZStd::equal_to<KeyType>>
using AnimSystemUnorderedMap = AZStd::unordered_map<KeyType, MappedType, Hasher, EqualKey, AZStd::stateless_allocator>;
}
// Serialization for anim nodes & param types
#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.contains(AnimNodeType::name)); \
g_animNodeEnumToStringMap[AnimNodeType::name] = AZ_STRINGIZE(name); \
g_animNodeStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimNodeType::name;
#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.contains(AnimParamType::name)); \
g_animParamEnumToStringMap[AnimParamType::name] = AZ_STRINGIZE(name); \
g_animParamStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimParamType::name;
namespace
{
AZStd::unordered_map<AnimNodeType, AZStd::string> g_animNodeEnumToStringMap;
StaticInstance<std::map<AZStd::string, AnimNodeType, stl::less_stricmp<AZStd::string> >> g_animNodeStringToEnumMap;
AnimSystemUnorderedMap<AnimNodeType, AnimParamSystemString> g_animNodeEnumToStringMap;
AnimSystemOrderedMap<AnimParamSystemString, AnimNodeType, stl::less_stricmp<AnimParamSystemString>> g_animNodeStringToEnumMap;
AZStd::unordered_map<AnimParamType, AZStd::string> g_animParamEnumToStringMap;
StaticInstance<std::map<AZStd::string, AnimParamType, stl::less_stricmp<AZStd::string> >> g_animParamStringToEnumMap;
AnimSystemUnorderedMap<AnimParamType, AnimParamSystemString> g_animParamEnumToStringMap;
AnimSystemOrderedMap<AnimParamSystemString, AnimParamType, stl::less_stricmp<AnimParamSystemString>> g_animParamStringToEnumMap;
// If you get an assert in this function, it means two node types have the same enum value.
void RegisterNodeTypes()