From 97e9f4dc7d7ce343c4a64547d30dc91d274c0277 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:38:36 -0500 Subject: [PATCH] [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> --- Code/Framework/AzCore/AzCore/EBus/EBus.h | 6 +- .../AzCore/AzCore/Memory/AllocatorManager.h | 4 +- .../AzCore/AzCore/Module/Environment.h | 45 ++++----- .../AzCore/AzCore/Name/Internal/NameData.cpp | 5 +- .../AzCore/AzCore/Name/NameDictionary.cpp | 24 ++--- .../AzCore/AzCore/Name/NameDictionary.h | 21 +++-- .../AzCore/AzCore/std/allocator_stateless.cpp | 94 +++++++++++++++++++ .../AzCore/AzCore/std/allocator_stateless.h | 61 ++++++++++++ .../AzCore/AzCore/std/azstd_files.cmake | 2 + .../AzCore/AzCore/std/createdestroy.h | 6 +- Code/Legacy/CryCommon/IMovieSystem.h | 5 +- Code/Legacy/CryCommon/StlUtils.h | 8 ++ .../DecalTextureArrayFeatureProcessor.cpp | 4 +- .../ProjectedShadowFeatureProcessor.cpp | 2 +- .../RHI/Vulkan/Code/Source/RHI/Instance.cpp | 19 +++- .../RHI/Vulkan/Code/Source/RHI/Instance.h | 1 + .../Code/Source/RHI/SystemComponent.cpp | 1 + .../Source/AudioSystemGemSystemComponent.cpp | 3 + Gems/ImGui/Code/Source/ImGuiManager.cpp | 7 +- Gems/LyShine/Code/Source/Animation/AnimNode.h | 3 +- .../Source/Animation/UiAnimationSystem.cpp | 33 ++++--- .../Code/Source/Cinematics/AnimPostFXNode.cpp | 3 +- Gems/Maestro/Code/Source/Cinematics/Movie.cpp | 35 ++++--- 23 files changed, 302 insertions(+), 90 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp create mode 100644 Code/Framework/AzCore/AzCore/std/allocator_stateless.h diff --git a/Code/Framework/AzCore/AzCore/EBus/EBus.h b/Code/Framework/AzCore/AzCore/EBus/EBus.h index a3dc10b103..67cffb4e41 100644 --- a/Code/Framework/AzCore/AzCore/EBus/EBus.h +++ b/Code/Framework/AzCore/AzCore/EBus/EBus.h @@ -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 diff --git a/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h b/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h index be0ab4a0a0..14dec68ad1 100644 --- a/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h +++ b/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h @@ -34,7 +34,9 @@ namespace AZ friend IAllocator; friend class AllocatorBase; friend class Debug::AllocationRecords; - friend class AZ::Internal::EnvironmentVariableHolder; + template friend constexpr auto AZStd::construct_at(T*, Args&&... args) + ->AZStd::enable_if_t()) T(AZStd::forward(args)...))>>, T*>; + template constexpr friend void AZStd::destroy_at(T*); public: typedef AZStd::function OutOfMemoryCBType; diff --git a/Code/Framework/AzCore/AzCore/Module/Environment.h b/Code/Framework/AzCore/AzCore/Module/Environment.h index e87ff81446..a2dcfbd8fa 100644 --- a/Code/Framework/AzCore/AzCore/Module/Environment.h +++ b/Code/Framework/AzCore/AzCore/Module/Environment.h @@ -251,16 +251,15 @@ namespace AZ class EnvironmentVariableHolder : public EnvironmentVariableHolderBase { - void ConstructImpl(const AZStd::true_type& /* AZStd::has_trivial_constructor */) - { - memset(&m_value, 0, sizeof(T)); - } - template - void ConstructImpl(const AZStd::false_type& /* AZStd::has_trivial_constructor */, 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)...); + // 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(&m_value)), AZStd::forward(args)...); + #else + AZStd::construct_at(reinterpret_cast(&m_value), AZStd::forward(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) - { - reinterpret_cast(&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(&self->m_value))); + #else + AZStd::destroy_at(reinterpret_cast(&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 lock(m_mutex); - if (!m_isConstructed) - { - ConstructImpl(AZStd::is_trivially_constructible{}); - m_isConstructed = true; - m_moduleOwner = Environment::GetModuleId(); - } - } - template void Construct(Args&&... args) { AZStd::lock_guard lock(m_mutex); if (!m_isConstructed) { - ConstructImpl(typename AZStd::false_type(), AZStd::forward(args)...); + ConstructImpl(AZStd::forward(args)...); m_isConstructed = true; m_moduleOwner = Environment::GetModuleId(); } @@ -333,7 +323,7 @@ namespace AZ } // variable storage - typename AZStd::aligned_storage::value>::type m_value; + AZStd::aligned_storage_for_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(); diff --git a/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp b/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp index 0086e68c6d..574b0bcc7e 100644 --- a/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp +++ b/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp @@ -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); + } } } } diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index 8e8011add9..3047a2894e 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -21,23 +21,18 @@ namespace AZ namespace NameDictionaryInternal { - static AZ::EnvironmentVariable s_instance = nullptr; + static AZ::EnvironmentVariable 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(NameDictionaryInstanceName); - } - - if (!s_instance.Get()) - { - s_instance.Set(aznew NameDictionary()); + s_instance = AZ::Environment::CreateVariable(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(NameDictionaryInstanceName); + s_instance = Environment::FindVariable(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(NameDictionaryInstanceName); + s_instance = Environment::FindVariable(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() diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.h b/Code/Framework/AzCore/AzCore/Name/NameDictionary.h index fa13dbd682..8f9af4be3a 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.h +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.h @@ -16,7 +16,7 @@ #include #include -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 friend constexpr auto AZStd::construct_at(T*, Args&&... args) + -> AZStd::enable_if_t()) T(AZStd::forward(args)...))>>, T*>; + template 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 m_dictionary; mutable AZStd::shared_mutex m_sharedMutex; }; diff --git a/Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp b/Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp new file mode 100644 index 0000000000..5806cc485c --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp @@ -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 +#include + +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; + } +} diff --git a/Code/Framework/AzCore/AzCore/std/allocator_stateless.h b/Code/Framework/AzCore/AzCore/std/allocator_stateless.h new file mode 100644 index 0000000000..b73c680c32 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/allocator_stateless.h @@ -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 +#include +#include + +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); +} diff --git a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake index 08e72c5649..2746489f8c 100644 --- a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake +++ b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake @@ -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 diff --git a/Code/Framework/AzCore/AzCore/std/createdestroy.h b/Code/Framework/AzCore/AzCore/std/createdestroy.h index 0fa6e4ed40..355374a13a 100644 --- a/Code/Framework/AzCore/AzCore/std/createdestroy.h +++ b/Code/Framework/AzCore/AzCore/std/createdestroy.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()) T(declval()...)` is well-formed template constexpr auto construct_at(T* ptr, Args&&... args) - -> enable_if_t()) T(AZStd::forward(args)...))>>, T*> + -> enable_if_t()) T(AZStd::forward(args)...))>>, T*> { return ::new (ptr) T(AZStd::forward(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 ForwardIt uninitialized_move(InputIt first, InputIt last, ForwardIt result) diff --git a/Code/Legacy/CryCommon/IMovieSystem.h b/Code/Legacy/CryCommon/IMovieSystem.h index 6cc5a06c8f..4da08d3bbf 100644 --- a/Code/Legacy/CryCommon/IMovieSystem.h +++ b/Code/Legacy/CryCommon/IMovieSystem.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -181,7 +182,7 @@ public: private: AnimParamType m_type; - AZStd::string m_name; + AZStd::basic_string, AZStd::stateless_allocator> m_name; }; namespace AZStd @@ -617,7 +618,7 @@ public: , valueType(_valueType) , flags(_flags) {}; - AZStd::string name; // parameter name. + AZStd::basic_string, 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. diff --git a/Code/Legacy/CryCommon/StlUtils.h b/Code/Legacy/CryCommon/StlUtils.h index 4aafd4dd0e..f5128a564f 100644 --- a/Code/Legacy/CryCommon/StlUtils.h +++ b/Code/Legacy/CryCommon/StlUtils.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -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, 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) diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index 472dbff5c8..e9bc1a1277 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -357,7 +357,7 @@ namespace AZ // Texture2DArray m_decalTextureArrayNormalMaps0; // Texture2DArray m_decalTextureArrayNormalMaps1; // Texture2DArray m_decalTextureArrayNormalMaps2; - static const AZStd::array ShaderNames = { "m_decalTextureArrayDiffuse", + static constexpr AZStd::array 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( diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index c0202c7c74..6452b312c8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -346,7 +346,7 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds) { - static const Name LightTypeName = Name("projected"); + const Name LightTypeName = Name("projected"); const auto* passSystem = RPI::PassSystemInterface::Get(); const AZStd::vector passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp index c2fe16b551..2dce5d85f3 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp @@ -16,12 +16,27 @@ namespace AZ { static const uint32_t s_minVulkanSupportedVersion = VK_API_VERSION_1_0; + static EnvironmentVariable 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(s_vulkanInstanceKey); + if (!s_vulkanInstance) + { + s_vulkanInstance = Environment::CreateVariable(s_vulkanInstanceKey); + } + } + + return s_vulkanInstance.Get(); } + void Instance::Reset() + { + s_vulkanInstance.Reset(); + } Instance::~Instance() { diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h index 40a6951c2d..efa8d36d2b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h @@ -34,6 +34,7 @@ namespace AZ }; static Instance& GetInstance(); + static void Reset(); ~Instance(); bool Init(const Descriptor& descriptor); void Shutdown(); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp index 36e0c2b2f5..0d401003d9 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp @@ -101,6 +101,7 @@ namespace AZ RHI::FactoryManagerBus::Broadcast(&RHI::FactoryManagerRequest::UnregisterFactory, this); Instance::GetInstance().Shutdown(); + Instance::Reset(); } Name SystemComponent::GetName() diff --git a/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp b/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp index b1e7e3ac18..1af927a7e7 100644 --- a/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp +++ b/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp @@ -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(); } diff --git a/Gems/ImGui/Code/Source/ImGuiManager.cpp b/Gems/ImGui/Code/Source/ImGuiManager.cpp index 6fc1ea8b71..d631e2f83e 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.cpp +++ b/Gems/ImGui/Code/Source/ImGuiManager.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -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 LyButtonImGuiNavIndexPair; -typedef AZStd::unordered_map LyButtonImGuiNavIndexMap; +using LyButtonImGuiNavIndexPair = AZStd::pair; +using LyButtonImGuiNavIndexMap = AZStd::fixed_unordered_map; static LyButtonImGuiNavIndexMap s_lyInputToImGuiNavIndexMap; /** diff --git a/Gems/LyShine/Code/Source/Animation/AnimNode.h b/Gems/LyShine/Code/Source/Animation/AnimNode.h index 0076276204..4d139e99ca 100644 --- a/Gems/LyShine/Code/Source/Animation/AnimNode.h +++ b/Gems/LyShine/Code/Source/Animation/AnimNode.h @@ -13,6 +13,7 @@ #include #include "UiAnimationSystem.h" +#include /*! @@ -39,7 +40,7 @@ public: , valueType(_valueType) , flags(_flags) {}; - AZStd::string name; // parameter name. + AZStd::basic_string, 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. diff --git a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp index 012eaacd1b..cab6ae3fa6 100644 --- a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp +++ b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp @@ -14,9 +14,11 @@ #include "UiAnimSerialize.h" #include +#include +#include +#include #include -#include #include #include #include @@ -25,22 +27,31 @@ #include ////////////////////////////////////////////////////////////////////////// -// 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, AZStd::stateless_allocator>; -#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.find(eUiAnimParamType_ ## name) == g_animParamEnumToStringMap.end()); \ + template > + using UiAnimSystemOrderedMap = AZStd::map; + template , typename EqualKey = AZStd::equal_to> + using UiAnimSystemUnorderedMap = AZStd::unordered_map; +} +// 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 g_animNodeEnumToStringMap; - StaticInstance >> g_animNodeStringToEnumMap; + UiAnimSystemUnorderedMap g_animNodeEnumToStringMap; + UiAnimSystemOrderedMap> g_animNodeStringToEnumMap; - AZStd::unordered_map g_animParamEnumToStringMap; - StaticInstance >> g_animParamStringToEnumMap; + UiAnimSystemUnorderedMap g_animParamEnumToStringMap; + UiAnimSystemOrderedMap> g_animParamStringToEnumMap; // If you get an assert in this function, it means two node types have the same enum value. void RegisterNodeTypes() diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp index 7e32301b71..b535033351 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp @@ -8,6 +8,7 @@ #include +#include #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, AZStd::stateless_allocator> m_name; protected: virtual ~CControlParamBase(){} diff --git a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp index 3654af52dd..9c4356560d 100644 --- a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp @@ -8,6 +8,9 @@ #include +#include +#include +#include #include #include #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, 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 > + using AnimSystemOrderedMap = AZStd::map; + template , typename EqualKey = AZStd::equal_to> + using AnimSystemUnorderedMap = AZStd::unordered_map; +} + +// 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 g_animNodeEnumToStringMap; - StaticInstance >> g_animNodeStringToEnumMap; + AnimSystemUnorderedMap g_animNodeEnumToStringMap; + AnimSystemOrderedMap> g_animNodeStringToEnumMap; - AZStd::unordered_map g_animParamEnumToStringMap; - StaticInstance >> g_animParamStringToEnumMap; + AnimSystemUnorderedMap g_animParamEnumToStringMap; + AnimSystemOrderedMap> g_animParamStringToEnumMap; // If you get an assert in this function, it means two node types have the same enum value. void RegisterNodeTypes()