Merge branch 'development' of https://github.com/o3de/o3de into carlitosan/development

monroegm-disable-blank-issue-2
chcurran 4 years ago
commit 5e91be38ba

@ -1,51 +0,0 @@
/*
* 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 <viewsrg.srgi>
#include <Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultObjectSrg.azsli>
#include <Atom/RPI/Assets/ShaderLib/Atom/RPI/TangentSpace.azsli>
struct VertexInput
{
float3 m_position : POSITION;
float3 m_normal : NORMAL;
float4 m_tangent : TANGENT;
float3 m_bitangent : BITANGENT;
float2 m_uv : UV0;
};
struct VertexOutput
{
float4 m_position : SV_Position;
float3 m_normal : NORMAL;
float3 m_tangent : TANGENT;
float3 m_bitangent : BITANGENT;
float2 m_uv : UV0;
float3 m_view : VIEW;
};
VertexOutput CommonVS(VertexInput input)
{
float4x4 objectToWorld = ObjectSrg::GetWorldMatrix();
float3x3 objectToWorldIT = ObjectSrg::GetWorldMatrixInverseTranspose();
VertexOutput output;
float3 worldPosition = mul(objectToWorld, float4(input.m_position, 1)).xyz;
output.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0));
output.m_uv = input.m_uv;
output.m_view = worldPosition - ViewSrg::m_worldPosition;
ConstructTBN(input.m_normal, input.m_tangent, input.m_bitangent, objectToWorld, objectToWorldIT, output.m_normal, output.m_tangent, output.m_bitangent);
return output;
}

@ -10,6 +10,7 @@
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ {
struct Uuid;

@ -8,14 +8,25 @@
#pragma once
// This is disabled by default because it puts in costly runtime checking of casted values.
// You can either change it here to enable it across the engine, or use push/pop_macro to enable per file/feature.
// Note that if using push/pop_macro, you may get some of the functions not inline and the definition coming from
// another compilation unit, in such case, you will have to push/pop_macro on that compilation unit as well.
// #define AZ_NUMERICCAST_ENABLED 1
#if !AZ_NUMERICCAST_ENABLED
#define aznumeric_cast static_cast
#else
#include <AzCore/Casting/numeric_cast_internal.h>
#include <AzCore/std/typetraits/is_arithmetic.h>
#include <AzCore/std/typetraits/is_class.h>
#include <AzCore/std/typetraits/is_enum.h>
#include <AzCore/std/typetraits/is_floating_point.h>
#include <AzCore/std/typetraits/is_integral.h>
#include <AzCore/std/typetraits/is_same.h>
#include <AzCore/std/typetraits/is_signed.h>
#include <AzCore/std/typetraits/is_unsigned.h>
#include <AzCore/std/typetraits/remove_cvref.h>
#include <AzCore/std/typetraits/underlying_type.h>
#include <AzCore/std/utils.h>
@ -28,7 +39,7 @@
// enabled.
//
// Because we can't do partial function specialization, I'm using enable_if to chop up the implementation into one of these
// implementations. If none of these fit, then we will get a compile error because it is an unknown conversionr.
// implementations. If none of these fit, then we will get a compile error because it is an unknown conversion.
//
//--------------------------------------------
// TYPE <- TYPE DigitLoss
@ -51,85 +62,7 @@
// (K) Floating Floating Y
*/
// This is disabled by default because it puts in costly runtime checking of casted values.
// You can either change it here to enable it across the engine, or use push/pop_macro to enable per file/feature.
// Note that if using push/pop_macro, you may get some of the functions not inline and the definition coming from
// another compilation unit, in such case, you will have to push/pop_macro on that compilation unit as well.
// #define AZ_NUMERICCAST_ENABLED 1
#if AZ_NUMERICCAST_ENABLED
#define AZ_NUMERIC_ASSERT(expr, ...) AZ_Assert(expr, __VA_ARGS__)
#else
#define AZ_NUMERIC_ASSERT(expr, ...) void(0)
#endif
#pragma push_macro("max")
#undef max
namespace NumericCastInternal
{
template <typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value
, bool> ::type UnderflowsToType(const FromType& value)
{
return (value < static_cast<FromType>(std::numeric_limits<ToType>::lowest()));
}
template <typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value
, bool> ::type UnderflowsToType(const FromType& value)
{
return (static_cast<ToType>(value) < std::numeric_limits<ToType>::lowest());
}
template <typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value
, bool> ::type OverflowsToType(const FromType& value)
{
return (value > static_cast<FromType>(std::numeric_limits<ToType>::max()));
}
template <typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value
, bool> ::type OverflowsToType(const FromType& value)
{
return (static_cast<ToType>(value) > std::numeric_limits<ToType>::max());
}
template <typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value
&& std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits
&& AZStd::is_signed<FromType>::value && AZStd::is_unsigned<ToType>::value
, bool> ::type FitsInToType(const FromType& value)
{
return !NumericCastInternal::UnderflowsToType<ToType>(value);
}
template <typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value
&& (std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits)
&& AZStd::is_unsigned<FromType>::value
, bool> ::type FitsInToType(const FromType& value)
{
return !NumericCastInternal::OverflowsToType<ToType>(value);
}
template <typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
(!AZStd::is_integral<FromType>::value || !AZStd::is_integral<ToType>::value)
|| ((std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits) && (AZStd::is_unsigned<FromType>::value || AZStd::is_signed<ToType>::value))
|| ((std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits) && AZStd::is_signed<FromType>::value)
, bool> ::type FitsInToType(const FromType& value)
{
return !NumericCastInternal::OverflowsToType<ToType>(value) && !NumericCastInternal::UnderflowsToType<ToType>(value);
}
} // namespace AZ
// INTEGER -> INTEGER
// (A) Not losing digits or risking sign loss
@ -276,8 +209,10 @@ inline constexpr auto aznumeric_cast(FromType&& value) ->
return static_cast<ToType>(value);
}
#endif
// This is a helper class that lets us induce the destination type of a numeric cast
// It should never be directly used by anything other than azlossy_caster.
// It should never be directly used by anything other than aznumeric_caster.
namespace AZ
{
template <typename FromType>
@ -295,7 +230,7 @@ namespace AZ
FromType m_value;
};
}
} // namespace AZ
// This is the primary function we should use when doing numeric casting, since it induces the
// type we need to cast to from the code rather than requiring an explicit coupling in the source.
@ -305,4 +240,3 @@ inline constexpr AZ::NumericCasted<FromType> aznumeric_caster(FromType value)
return AZ::NumericCasted<FromType>(value);
}
#pragma pop_macro("max")

@ -0,0 +1,81 @@
/*
* 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/typetraits/conditional.h>
#include <AzCore/std/typetraits/is_floating_point.h>
#include <AzCore/std/typetraits/is_integral.h>
#include <AzCore/std/typetraits/is_signed.h>
#include <AzCore/std/typetraits/is_unsigned.h>
#include <limits>
namespace NumericCastInternal
{
template<typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value, bool>::type
UnderflowsToType(const FromType& value)
{
return (value < static_cast<FromType>(std::numeric_limits<ToType>::lowest()));
}
template<typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value, bool>::type
UnderflowsToType(const FromType& value)
{
return (static_cast<ToType>(value) < std::numeric_limits<ToType>::lowest());
}
template<typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value, bool>::type
OverflowsToType(const FromType& value)
{
return (value > static_cast<FromType>(std::numeric_limits<ToType>::max()));
}
template<typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value, bool>::type
OverflowsToType(const FromType& value)
{
return (static_cast<ToType>(value) > std::numeric_limits<ToType>::max());
}
template<typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value &&
std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits && AZStd::is_signed<FromType>::value &&
AZStd::is_unsigned<ToType>::value,
bool>::type
FitsInToType(const FromType& value)
{
return !NumericCastInternal::UnderflowsToType<ToType>(value);
}
template<typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value &&
(std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits) && AZStd::is_unsigned<FromType>::value,
bool>::type
FitsInToType(const FromType& value)
{
return !NumericCastInternal::OverflowsToType<ToType>(value);
}
template<typename ToType, typename FromType>
inline constexpr typename AZStd::enable_if<
(!AZStd::is_integral<FromType>::value || !AZStd::is_integral<ToType>::value) ||
((std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits) &&
(AZStd::is_unsigned<FromType>::value || AZStd::is_signed<ToType>::value)) ||
((std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits) && AZStd::is_signed<FromType>::value),
bool>::type
FitsInToType(const FromType& value)
{
return !NumericCastInternal::OverflowsToType<ToType>(value) && !NumericCastInternal::UnderflowsToType<ToType>(value);
}
}

@ -84,8 +84,9 @@ namespace AZ
static TypeId genericComponentWrapperTypeId("{68D358CA-89B9-4730-8BA6-E181DEA28FDE}");
for (auto& [componentKey, component] : componentMap)
{
// if underlying type is genericComponentWrapperTypeId, the template is null and the component should not be addded
if (component->GetUnderlyingComponentType() != genericComponentWrapperTypeId)
// if the component didn't serialize (i.e. is null) or the underlying type is genericComponentWrapperTypeId, the
// template is null and the component should not be addded
if (component && (component->GetUnderlyingComponentType() != genericComponentWrapperTypeId))
{
entityInstance->m_components.emplace_back(component);
}

@ -256,8 +256,22 @@ namespace AZ::IO
template <typename PathResultType>
static constexpr void MakeRelativeTo(PathResultType& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base);
template <typename PathResultType>
static constexpr void LexicallyNormalInplace(PathResultType& pathResult, const AZ::IO::PathView& path);
struct PathIterable;
//! Returns a structure that provides a view of the path parts which can be used for iteration
//! Only the path parts that correspond to creating an normalized path is returned
//! This function is useful for returning a "view" into a normalized path without the need
//! to allocate memory for the heap
static constexpr PathIterable GetNormalPathParts(const AZ::IO::PathView& path) noexcept;
// joins the input path to the Path Iterable structure using similiar logic to Path::Append
// If the input path is absolute it will replace the current PathIterable otherwise
// the input path will be appended to the Path Iterable structure
// For example a PathIterable with parts = ['C:', '/', 'foo']
// If the path input = 'bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar']
// If the path input = 'C:/bar', then the new PathIterable parts = [C:', '/', 'bar']
// If the path input = 'C:bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar' ]
// If the path input = 'D:bar', then the new PathIterable parts = [D:, 'bar' ]
static constexpr void AppendNormalPathParts(PathIterable& pathIterableResult, const AZ::IO::PathView& path) noexcept;
constexpr int compare_string_view(AZStd::string_view other) const;
constexpr AZStd::string_view root_name_view() const;
@ -442,14 +456,15 @@ namespace AZ::IO
constexpr void swap(BasicPath& rhs) noexcept;
// native format observers
constexpr const string_type& Native() const noexcept;
constexpr const string_type& Native() const& noexcept;
constexpr const string_type&& Native() const&& noexcept;
constexpr const value_type* c_str() const noexcept;
constexpr explicit operator string_type() const;
// Adds support for retrieving a modifiable copy of the underlying string
// Any modifications to the string invalidates existing PathIterators
constexpr string_type& Native() noexcept;
constexpr explicit operator string_type&() noexcept;
constexpr string_type& Native() & noexcept;
constexpr string_type&& Native() && noexcept;
//! The string and wstring functions cannot be constexpr until AZStd::basic_string is made constexpr.
//! This cannot occur until C++20 as operator new/delete cannot be used within constexpr functions

File diff suppressed because it is too large Load Diff

@ -0,0 +1,162 @@
/*
* 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/containers/array.h>
#include <AzCore/IO/Path/PathParser.inl>
namespace AZ::IO
{
struct PathView::PathIterable
{
inline static constexpr size_t MaxPathParts = 64;
using PartKindPair = AZStd::pair<AZStd::string_view, AZ::IO::parser::PathPartKind>;
using PartKindArray = AZStd::array<PartKindPair, MaxPathParts>;
constexpr PathIterable() = default;
[[nodiscard]] constexpr bool empty() const noexcept;
constexpr auto size() const noexcept-> size_t;
constexpr auto begin() noexcept-> PartKindArray::iterator;
constexpr auto begin() const noexcept -> PartKindArray::const_iterator;
constexpr auto cbegin() const noexcept -> PartKindArray::const_iterator;
constexpr auto end() noexcept -> PartKindArray::iterator;
constexpr auto end() const noexcept -> PartKindArray::const_iterator;
constexpr auto cend() const noexcept -> PartKindArray::const_iterator;
constexpr auto rbegin() noexcept -> PartKindArray::reverse_iterator;
constexpr auto rbegin() const noexcept -> PartKindArray::const_reverse_iterator;
constexpr auto crbegin() const noexcept -> PartKindArray::const_reverse_iterator;
constexpr auto rend() noexcept -> PartKindArray::reverse_iterator;
constexpr auto rend() const noexcept -> PartKindArray::const_reverse_iterator;
constexpr auto crend() const noexcept -> PartKindArray::const_reverse_iterator;
[[nodiscard]] constexpr bool IsAbsolute() const noexcept;
private:
template <typename... Args>
constexpr PartKindPair& emplace_back(Args&&... args) noexcept;
constexpr void pop_back() noexcept;
constexpr const PartKindPair& back() const noexcept;
constexpr PartKindPair& back() noexcept;
constexpr const PartKindPair& front() const noexcept;
constexpr PartKindPair& front() noexcept;
constexpr void clear() noexcept;
friend constexpr auto PathView::GetNormalPathParts(const AZ::IO::PathView&) noexcept -> PathIterable;
friend constexpr auto PathView::AppendNormalPathParts(PathIterable& pathIterable, const AZ::IO::PathView&) noexcept -> void;
PartKindArray m_parts{};
size_t m_size{};
};
// public
[[nodiscard]] constexpr auto PathView::PathIterable::empty() const noexcept -> bool
{
return m_size == 0;
}
constexpr auto PathView::PathIterable::size() const noexcept -> size_t
{
return m_size;
}
constexpr auto PathView::PathIterable::begin() noexcept -> PartKindArray::iterator
{
return m_parts.begin();
}
constexpr auto PathView::PathIterable::begin() const noexcept -> PartKindArray::const_iterator
{
return m_parts.begin();
}
constexpr auto PathView::PathIterable::cbegin() const noexcept -> PartKindArray::const_iterator
{
return begin();
}
constexpr auto PathView::PathIterable::end() noexcept -> PartKindArray::iterator
{
return begin() + size();
}
constexpr auto PathView::PathIterable::end() const noexcept -> PartKindArray::const_iterator
{
return begin() + size();
}
constexpr auto PathView::PathIterable::cend() const noexcept -> PartKindArray::const_iterator
{
return end();
}
constexpr auto PathView::PathIterable::rbegin() noexcept -> PartKindArray::reverse_iterator
{
return PartKindArray::reverse_iterator(begin() + size());
}
constexpr auto PathView::PathIterable::rbegin() const noexcept -> PartKindArray::const_reverse_iterator
{
return PartKindArray::const_reverse_iterator(begin() + size());
}
constexpr auto PathView::PathIterable::crbegin() const noexcept -> PartKindArray::const_reverse_iterator
{
return rbegin();
}
constexpr auto PathView::PathIterable::rend() noexcept -> PartKindArray::reverse_iterator
{
return PartKindArray::reverse_iterator(begin());
}
constexpr auto PathView::PathIterable::rend() const noexcept -> PartKindArray::const_reverse_iterator
{
return PartKindArray::const_reverse_iterator(begin());
}
constexpr auto PathView::PathIterable::crend() const noexcept -> PartKindArray::const_reverse_iterator
{
return rend();
}
[[nodiscard]] constexpr auto PathView::PathIterable::IsAbsolute() const noexcept -> bool
{
return !empty() && (front().second == parser::PathPartKind::PK_RootSep
|| (size() > 1 && front().second == parser::PathPartKind::PK_RootName && m_parts[1].second == parser::PathPartKind::PK_RootSep));
}
// private
template <typename... Args>
constexpr auto PathView::PathIterable::emplace_back(Args&&... args) noexcept -> PartKindPair&
{
AZ_Assert(m_size < MaxPathParts, "PathIterable cannot be made out of a path with more than %zu parts", MaxPathParts);
m_parts[m_size++] = PartKindPair{ AZStd::forward<Args>(args)... };
return back();
}
constexpr auto PathView::PathIterable::pop_back() noexcept -> void
{
AZ_Assert(m_size > 0, "Cannot pop_back() from a PathIterable with 0 parts");
--m_size;
}
constexpr auto PathView::PathIterable::back() const noexcept -> const PartKindPair&
{
AZ_Assert(!empty(), "back() was invoked on PathIterable with 0 parts");
return m_parts[m_size - 1];
}
constexpr auto PathView::PathIterable::back() noexcept -> PartKindPair&
{
AZ_Assert(!empty(), "back() was invoked on PathIterable with 0 parts");
return m_parts[m_size - 1];
}
constexpr auto PathView::PathIterable::front() const noexcept -> const PartKindPair&
{
AZ_Assert(!empty(), "front() was invoked on PathIterable with 0 parts");
return m_parts[0];
}
constexpr auto PathView::PathIterable::front() noexcept -> PartKindPair&
{
AZ_Assert(!empty(), "front() was invoked on PathIterable with 0 parts");
return m_parts[0];
}
constexpr auto PathView::PathIterable::clear() noexcept -> void
{
m_size = 0;
}
}

@ -0,0 +1,706 @@
/*
* 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/AzCore_Traits_Platform.h>
#include <AzCore/Casting/numeric_cast.h>
namespace AZ::IO::Internal
{
constexpr bool IsSeparator(const char elem)
{
return elem == '/' || elem == '\\';
}
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::Internal::is_input_iterator_v<InputIt>>>
static constexpr bool HasDrivePrefix(InputIt first, EndIt last)
{
size_t prefixSize = AZStd::distance(first, last);
if (prefixSize < 2 || *AZStd::next(first, 1) != ':')
{
// Drive prefix must be at least two characters and have a colon for the second character
return false;
}
constexpr size_t ValidDrivePrefixRange = 26;
// Uppercase the drive letter by bitwise and'ing out the the 2^5 bit
unsigned char driveLetter = static_cast<unsigned char>(*first);
driveLetter &= 0b1101'1111;
// normalize the character value in the range of A-Z -> 0-25
driveLetter -= 'A';
return driveLetter < ValidDrivePrefixRange;
}
static constexpr bool HasDrivePrefix(AZStd::string_view prefix)
{
return HasDrivePrefix(prefix.begin(), prefix.end());
}
//! Returns an iterator past the end of the consumed root name
//! Windows root names can have include drive letter within them
template <typename InputIt>
constexpr auto ConsumeRootName(InputIt entryBeginIter, InputIt entryEndIter, const char preferredSeparator)
-> AZStd::enable_if_t<AZStd::Internal::is_forward_iterator_v<InputIt>, InputIt>
{
if (preferredSeparator == PosixPathSeparator)
{
// If the preferred separator is forward slash the parser is in posix path
// parsing mode, which doesn't have a root name,
// unless we're on a posix platform that uses a custom path root separator
#if defined(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR)
const AZStd::string_view path{ entryBeginIter, entryEndIter };
const auto positionOfPathSeparator = path.find(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR);
if (positionOfPathSeparator != AZStd::string_view::npos)
{
return AZStd::next(entryBeginIter, positionOfPathSeparator + 1);
}
#endif
return entryBeginIter;
}
else
{
// Information for GetRootName has been gathered from Microsoft <filesystem> header
// Below are examples of paths and what there root-name will return
// "/" - returns ""
// "foo/" - returns ""
// "C:DriveRelative" - returns "C:"
// "C:\\DriveAbsolute" - returns "C:"
// "C://DriveAbsolute" - returns "C:"
// "\\server\share" - returns "\\server"
// The following paths are based on the UNC specification to work with paths longer than the 260 character path limit
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#maximum-path-length-limitation
// \\?\device - returns "\\?"
// \??\device - returns "\??"
// \\.\device - returns "\\."
AZStd::string_view path{ entryBeginIter, entryEndIter };
if (path.size() < 2)
{
// A root name is either <drive letter><colon> or a network path
// therefore it has a least two characters
return entryBeginIter;
}
if (HasDrivePrefix(path))
{
// If the path has a drive prefix, then it has a root name of <driver letter><colon>
return AZStd::next(entryBeginIter, 2);
}
if (!Internal::IsSeparator(path[0]))
{
// At this point all other root names start with a path separator
return entryBeginIter;
}
// Check if the path has the form of "\\?\, "\??\" or "\\.\"
const bool pathInUncForm = path.size() >= 4 && Internal::IsSeparator(path[3])
&& (path.size() == 4 || !Internal::IsSeparator(path[4]));
if (pathInUncForm)
{
// \\?\<0 or more> or \\.\$<zero or more>
const bool slashQuestionMark = Internal::IsSeparator(path[1]) && (path[2] == '?' || path[2] == '.');
// \??\<0 or more>
const bool questionMarkTwice = path[1] == '?' && path[2] == '?';
if (slashQuestionMark || questionMarkTwice)
{
// Return the root value root slash - i.e "\\?"
return AZStd::next(entryBeginIter, 3);
}
}
if (path.size() >= 3 && Internal::IsSeparator(path[1]) && !Internal::IsSeparator(path[2]))
{
// Find the next path separator for network paths that have the form of \\server\share
constexpr AZStd::string_view PathSeparators = { "/\\" };
size_t nextPathSeparatorOffset = path.find_first_of(PathSeparators, 3);
return AZStd::next(entryBeginIter, nextPathSeparatorOffset != AZStd::string_view::npos ? nextPathSeparatorOffset : path.size());
}
return entryBeginIter;
}
}
//! Returns an iterator past the end of the consumed path separator(s)
template <typename InputIt>
constexpr InputIt ConsumeSeparator(InputIt entryBeginIter, InputIt entryEndIter) noexcept
{
return AZStd::find_if_not(entryBeginIter, entryEndIter, [](const char elem) { return Internal::IsSeparator(elem); });
}
//! Returns an iterator past the end of the consumed filename
template <typename InputIt>
constexpr InputIt ConsumeName(InputIt entryBeginIter, InputIt entryEndIter) noexcept
{
return AZStd::find_if(entryBeginIter, entryEndIter, [](const char elem) { return Internal::IsSeparator(elem); });
}
//! Check if a path is absolute on a OS basis
//! If the preferred separator is '/' just checks if the path starts with a '/
//! Otherwise a check for a Windows absolute path occurs
//! Windows absolute paths can include a RootName
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::Internal::is_input_iterator_v<InputIt>>>
static constexpr bool IsAbsolute(InputIt first, EndIt last, const char preferredSeparator)
{
size_t pathSize = AZStd::distance(first, last);
// If the preferred separator is a forward slash
// than an absolute path is simply one that starts with a forward slash,
// unless we're on a posix platform that uses a custom path root separator
if (preferredSeparator == PosixPathSeparator)
{
#if defined(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR)
const AZStd::string_view path{ first, last };
return path.find(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR) != AZStd::string_view::npos;
#else
return pathSize > 0 && IsSeparator(*first);
#endif
}
else
{
if (Internal::HasDrivePrefix(first, last))
{
// If a windows path ends starts with C:foo it is a root relative path
// A path is absolute root absolute on windows if it starts with <drive_letter><colon><path_separator>
return pathSize > 2 && Internal::IsSeparator(*AZStd::next(first, 2));
}
return first != ConsumeRootName(first, last, preferredSeparator);
}
}
static constexpr bool IsAbsolute(AZStd::string_view pathView, const char preferredSeparator)
{
// Uses the template preferred to branch on the absolute path check
// logic
return IsAbsolute(pathView.begin(), pathView.end(), preferredSeparator);
}
// Compares path segments using either Posix or Windows path rules based on the path separator in use
// Posix paths perform a case-sensitive comparison, while Windows paths perform a case-insensitive comparison
static int ComparePathSegment(AZStd::string_view left, AZStd::string_view right, char pathSeparator)
{
const size_t maxCharsToCompare = (AZStd::min)(left.size(), right.size());
int charCompareResult = pathSeparator == PosixPathSeparator
? maxCharsToCompare ? strncmp(left.data(), right.data(), maxCharsToCompare) : 0
: maxCharsToCompare ? azstrnicmp(left.data(), right.data(), maxCharsToCompare) : 0;
return charCompareResult == 0
? static_cast<int>(aznumeric_cast<ptrdiff_t>(left.size()) - aznumeric_cast<ptrdiff_t>(right.size()))
: charCompareResult;
}
}
//! PathParser implementation
//! For internal use only
namespace AZ::IO::parser
{
using parser_path_type = PathView;
using string_view_pair = AZStd::pair<AZStd::string_view, AZStd::string_view>;
using PosPtr = const typename parser_path_type::value_type*;
enum ParserState : uint8_t
{
// Zero is a special sentinel value used by default constructed iterators.
PS_BeforeBegin = PathIterator<PathView>::BeforeBegin,
PS_InRootName = PathIterator<PathView>::InRootName,
PS_InRootDir = PathIterator<PathView>::InRootDir,
PS_InFilenames = PathIterator<PathView>::InFilenames,
PS_AtEnd = PathIterator<PathView>::AtEnd
};
struct PathParser
{
AZStd::string_view m_path_view;
AZStd::string_view m_path_raw_entry;
ParserState m_parser_state{};
const char m_preferred_separator{ AZ_TRAIT_OS_PATH_SEPARATOR };
constexpr PathParser(AZStd::string_view path, ParserState state, const char preferredSeparator) noexcept
: m_path_view(path)
, m_parser_state(state)
, m_preferred_separator(preferredSeparator)
{
}
constexpr PathParser(AZStd::string_view path, AZStd::string_view entry, ParserState state, const char preferredSeparator) noexcept
: m_path_view(path)
, m_path_raw_entry(entry)
, m_parser_state(static_cast<ParserState>(state))
, m_preferred_separator(preferredSeparator)
{
}
constexpr static PathParser CreateBegin(AZStd::string_view path, const char preferredSeparator) noexcept
{
PathParser pathParser(path, PS_BeforeBegin, preferredSeparator);
pathParser.Increment();
return pathParser;
}
constexpr static PathParser CreateEnd(AZStd::string_view path, const char preferredSeparator) noexcept
{
PathParser pathParser(path, PS_AtEnd, preferredSeparator);
return pathParser;
}
constexpr PosPtr Peek() const noexcept
{
auto tokenEnd = getNextTokenStartPos();
auto End = m_path_view.end();
return tokenEnd == End ? nullptr : tokenEnd;
}
constexpr void Increment() noexcept
{
const PosPtr pathEnd = m_path_view.end();
const PosPtr currentPathEntry = getNextTokenStartPos();
if (currentPathEntry == pathEnd)
{
return MakeState(PS_AtEnd);
}
switch (m_parser_state)
{
case PS_BeforeBegin:
{
/*
* First the determine if the path contains only a root-name such as "C:" or is a filename such as "foo"
* root-relative path(Windows only) - C:foo
* root-absolute path - C:\foo
* root-absolute path - /foo
* relative path - foo
*
* Try to consume the root-name then the root directory to determine if path entry
* being parsed is a root-name or filename
* The State transitions from BeforeBegin are
* "C:", "\\server\", "\\?\", "\??\", "\\.\" -> Root Name
* "/", "\" -> Root Directory
* "path/foo", "foo" -> Filename
*/
auto rootNameEnd = Internal::ConsumeRootName(currentPathEntry, pathEnd, m_preferred_separator);
if (currentPathEntry != rootNameEnd)
{
// Transition to the Root Name state
return MakeState(PS_InRootName, currentPathEntry, rootNameEnd);
}
[[fallthrough]];
}
case PS_InRootName:
{
auto rootDirEnd = Internal::ConsumeSeparator(currentPathEntry, pathEnd);
if (currentPathEntry != rootDirEnd)
{
// Transition to Root Directory state
return MakeState(PS_InRootDir, currentPathEntry, rootDirEnd);
}
[[fallthrough]];
}
case PS_InRootDir:
{
auto filenameEnd = Internal::ConsumeName(currentPathEntry, pathEnd);
if (currentPathEntry != filenameEnd)
{
return MakeState(PS_InFilenames, currentPathEntry, filenameEnd);
}
[[fallthrough]];
}
case PS_InFilenames:
{
auto separatorEnd = Internal::ConsumeSeparator(currentPathEntry, pathEnd);
if (separatorEnd != pathEnd)
{
// find the end of the current filename entry
auto filenameEnd = Internal::ConsumeName(separatorEnd, pathEnd);
return MakeState(PS_InFilenames, separatorEnd, filenameEnd);
}
// If after consuming the separator that path entry is at the end iterator
// move the path state to AtEnd
return MakeState(PS_AtEnd);
}
case PS_AtEnd:
AZ_Assert(false, "Path Parser cannot be incremented when it is in the AtEnd state");
}
}
constexpr void Decrement() noexcept
{
auto pathStart = m_path_view.begin();
auto currentPathEntry = getCurrentTokenStartPos();
if (currentPathEntry == pathStart)
{
// we're decrementing the begin
return MakeState(PS_BeforeBegin);
}
switch (m_parser_state)
{
case PS_AtEnd:
{
/*
* First the determine if the path contains only a root-name such as "C:" or is a filename such as "foo"
* root-relative path(Windows only) - C:foo
* root-absolute path - C:\foo
* root-absolute path - /foo
* relative path - foo
* Try to consume the root-name then the root directory to determine if path entry
* being parsed is a root-name or filename
* The State transitions from AtEnd are
* "/path/foo/", "foo/", "C:foo\", "C:\foo\" -> Trailing Separator
* "/path/foo", "foo", "C:foo", "C:\foo" -> Filename
* "/", "C:\" or "\\server\" -> Root Directory
* "C:", "\\server", "\\?", "\??", "\\." -> Root Name
*/
auto rootNameEnd = Internal::ConsumeRootName(pathStart, currentPathEntry, m_preferred_separator);
if (pathStart != rootNameEnd && currentPathEntry == rootNameEnd)
{
// Transition to the Root Name state
return MakeState(PS_InRootName, pathStart, currentPathEntry);
}
auto rootDirEnd = Internal::ConsumeSeparator(rootNameEnd, currentPathEntry);
if (rootNameEnd != rootDirEnd && currentPathEntry == rootDirEnd)
{
// Transition to Root Directory state
return MakeState(PS_InRootDir, rootNameEnd, currentPathEntry);
}
auto filenameEnd = currentPathEntry;
if (Internal::IsSeparator(*(filenameEnd - 1)))
{
// The last character a path separator that isn't root directory
// consume all the preceding path separators
filenameEnd = Internal::ConsumeSeparator(AZStd::make_reverse_iterator(filenameEnd),
AZStd::make_reverse_iterator(rootDirEnd)).base();
}
// The previous state will be Filename, so the beginning of the filename is searched found
auto filenameBegin = Internal::ConsumeName(AZStd::make_reverse_iterator(filenameEnd),
AZStd::make_reverse_iterator(rootDirEnd)).base();
return MakeState(PS_InFilenames, filenameBegin, filenameEnd);
}
case PS_InFilenames:
{
/* The State transitions from Filename are
* "/path/foo" -> Filename
* ^
* "C:\foo" -> Root Directory
* ^
* "C:foo" -> Root Name
* ^
* "foo" -> This case has been taken care of by the current path entry != path start check
* ^
*/
auto rootNameEnd = Internal::ConsumeRootName(pathStart, currentPathEntry, m_preferred_separator);
if (pathStart != rootNameEnd && currentPathEntry == rootNameEnd)
{
// Transition to the Root Name state
return MakeState(PS_InRootName, pathStart, rootNameEnd);
}
auto rootDirEnd = Internal::ConsumeSeparator(rootNameEnd, currentPathEntry);
if (rootNameEnd != rootDirEnd && currentPathEntry == rootDirEnd)
{
// Transition to Root Directory state
return MakeState(PS_InRootDir, rootNameEnd, rootDirEnd);
}
// The previous state will be Filename again, so first the end of that filename is found
// proceeded by finding the beginning of that filename
auto filenameEnd = Internal::ConsumeSeparator(AZStd::make_reverse_iterator(currentPathEntry),
AZStd::make_reverse_iterator(rootDirEnd)).base();
auto filenameBegin = Internal::ConsumeName(AZStd::make_reverse_iterator(filenameEnd),
AZStd::make_reverse_iterator(rootDirEnd)).base();
return MakeState(PS_InFilenames, filenameBegin, filenameEnd);
}
case PS_InRootDir:
{
/* The State transitions from Root Directory are
* "C:\" "\\server\", "\\?\", "\??\", "\\.\" -> Root Name
* ^ ^ ^ ^ ^
* "/" -> This case has been taken care of by the current path entry != path start check
* ^
*/
return MakeState(PS_InRootName, pathStart, currentPathEntry);
}
case PS_InRootName:
// The only valid state transition from Root Name is BeforeBegin
return MakeState(PS_BeforeBegin);
case PS_BeforeBegin:
AZ_Assert(false, "Path Parser cannot be decremented when it is in the BeforeBegin State");
}
}
//! Return a view of the current element in the path processor state
constexpr AZStd::string_view operator*() const noexcept
{
switch (m_parser_state)
{
case PS_BeforeBegin:
[[fallthrough]];
case PS_AtEnd:
[[fallthrough]];
case PS_InRootDir:
return m_preferred_separator == '/' ? "/" : "\\";
case PS_InRootName:
case PS_InFilenames:
return m_path_raw_entry;
default:
AZ_Assert(false, "Path Parser is in an invalid state");
}
return {};
}
constexpr explicit operator bool() const noexcept
{
return m_parser_state != PS_BeforeBegin && m_parser_state != PS_AtEnd;
}
constexpr PathParser& operator++() noexcept
{
Increment();
return *this;
}
constexpr PathParser& operator--() noexcept
{
Decrement();
return *this;
}
constexpr bool AtEnd() const noexcept
{
return m_parser_state == PS_AtEnd;
}
constexpr bool InRootDir() const noexcept
{
return m_parser_state == PS_InRootDir;
}
constexpr bool InRootName() const noexcept
{
return m_parser_state == PS_InRootName;
}
constexpr bool InRootPath() const noexcept
{
return InRootName() || InRootDir();
}
private:
constexpr void MakeState(ParserState newState, typename AZStd::string_view::iterator start, typename AZStd::string_view::iterator end) noexcept
{
m_parser_state = newState;
m_path_raw_entry = AZStd::string_view(start, end);
}
constexpr void MakeState(ParserState newState) noexcept
{
m_parser_state = newState;
m_path_raw_entry = {};
}
//! Return a pointer to the first character after the currently lexed element.
constexpr typename AZStd::string_view::iterator getNextTokenStartPos() const noexcept
{
switch (m_parser_state)
{
case PS_BeforeBegin:
return m_path_view.begin();
case PS_InRootName:
case PS_InRootDir:
case PS_InFilenames:
return m_path_raw_entry.end();
case PS_AtEnd:
return m_path_view.end();
default:
AZ_Assert(false, "Path Parser is in an invalid state");
}
return m_path_view.end();
}
//! Return a pointer to the first character in the currently lexed element.
constexpr typename AZStd::string_view::iterator getCurrentTokenStartPos() const noexcept
{
switch (m_parser_state)
{
case PS_BeforeBegin:
case PS_InRootName:
return m_path_view.begin();
case PS_InRootDir:
case PS_InFilenames:
return m_path_raw_entry.begin();
case PS_AtEnd:
return m_path_view.end();
default:
AZ_Assert(false, "Path Parser is in an invalid state");
}
return m_path_view.end();
}
};
constexpr string_view_pair SeparateFilename(const AZStd::string_view& srcView)
{
if (srcView == "." || srcView == ".." || srcView.empty())
{
return string_view_pair{ srcView, "" };
}
auto pos = srcView.find_last_of('.');
if (pos == AZStd::string_view::npos || pos == 0)
{
return string_view_pair{ srcView, AZStd::string_view{} };
}
return string_view_pair{ srcView.substr(0, pos), srcView.substr(pos) };
}
// path part consumption
constexpr bool ConsumeRootName(PathParser* pathParser)
{
static_assert(PS_BeforeBegin == 1 && PS_InRootName == 2,
"PathParser must be in state before begin or in the root name in order to consume the root name");
while (pathParser->m_parser_state <= PS_InRootName)
{
++(*pathParser);
}
return pathParser->m_parser_state == PS_AtEnd;
}
constexpr bool ConsumeRootDir(PathParser* pathParser)
{
static_assert(PS_BeforeBegin == 1 && PS_InRootName == 2 && PS_InRootDir == 3,
"PathParser must be in state before begin, in the root name or in the root directory in order to consume the root directory");
while (pathParser->m_parser_state <= PS_InRootDir)
{
++(*pathParser);
}
return pathParser->m_parser_state == PS_AtEnd;
}
// path.comparisons
constexpr int CompareRootName(PathParser* lhsPathParser, PathParser* rhsPathParser)
{
if (!lhsPathParser->InRootName() && !rhsPathParser->InRootName())
{
return 0;
}
auto GetRootName = [](PathParser* pathParser) constexpr -> AZStd::string_view
{
return pathParser->InRootName() ? **pathParser : "";
};
int res = Internal::ComparePathSegment(GetRootName(lhsPathParser), GetRootName(rhsPathParser), lhsPathParser->m_preferred_separator);
ConsumeRootName(lhsPathParser);
ConsumeRootName(rhsPathParser);
return res;
}
constexpr int CompareRootDir(PathParser* lhsPathParser, PathParser* rhsPathParser)
{
if (!lhsPathParser->InRootDir() && rhsPathParser->InRootDir())
{
return -1;
}
else if (lhsPathParser->InRootDir() && !rhsPathParser->InRootDir())
{
return 1;
}
else
{
ConsumeRootDir(lhsPathParser);
ConsumeRootDir(rhsPathParser);
return 0;
}
}
constexpr int CompareRelative(PathParser* lhsPathParserPtr, PathParser* rhsPathParserPtr)
{
auto& lhsPathParser = *lhsPathParserPtr;
auto& rhsPathParser = *rhsPathParserPtr;
while (lhsPathParser && rhsPathParser)
{
if (int res = Internal::ComparePathSegment(*lhsPathParser, *rhsPathParser, lhsPathParser.m_preferred_separator);
res != 0)
{
return res;
}
++lhsPathParser;
++rhsPathParser;
}
return 0;
}
constexpr int CompareEndState(PathParser* lhsPathParser, PathParser* rhsPathParser)
{
if (lhsPathParser->AtEnd() && !rhsPathParser->AtEnd())
{
return -1;
}
else if (!lhsPathParser->AtEnd() && rhsPathParser->AtEnd())
{
return 1;
}
return 0;
}
constexpr int DetermineLexicalElementCount(PathParser pathParser)
{
int count = 0;
for (; pathParser; ++pathParser)
{
auto pathElement = *pathParser;
if (pathElement == "..")
{
--count;
}
else if (pathElement != "." && pathElement != "")
{
++count;
}
}
return count;
}
enum class PathPartKind : uint8_t
{
PK_None,
PK_RootName,
PK_RootSep,
PK_Filename,
PK_Dot,
PK_DotDot,
};
constexpr PathPartKind ClassifyPathPart(const PathParser& parser)
{
// Check each parser state to determine the PathPartKind
if (parser.m_parser_state == PS_InRootDir)
{
return PathPartKind::PK_RootSep;
}
if (parser.m_parser_state == PS_InRootName)
{
return PathPartKind::PK_RootName;
}
// Fallback to checking parser pathEntry view value
// to determine if the special "." or ".." values are being used
AZStd::string_view pathPart = *parser;
if (pathPart == ".")
{
return PathPartKind::PK_Dot;
}
if (pathPart == "..")
{
return PathPartKind::PK_DotDot;
}
// Return PathPartKind of PK_ilename if the parser state doesn't match
// the states of InRootDir or InRootName and the filename
// isn't made up of the special directory values of "." and ".."
return PathPartKind::PK_Filename;
}
}

@ -7,18 +7,17 @@
*/
#pragma once
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Script/ScriptContext.h>
#include <AzCore/Script/ScriptContextAttributes.h>
#include <AzCore/ScriptCanvas/ScriptCanvasAttributes.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/string/tokenize.h>
#include <AzCore/ScriptCanvas/ScriptCanvasOnDemandNames.h>
#include <AzCore/RTTI/AzStdOnDemandPrettyName.inl>
#include <AzCore/RTTI/AzStdOnDemandReflectionLuaFunctions.inl>
#include <AzCore/EBus/Event.h>
#ifndef AZ_USE_CUSTOM_SCRIPT_BIND
struct lua_State;
struct lua_Debug;
#endif // AZ_USE_CUSTOM_SCRIPT_BIND
// forward declare specialized types
namespace AZStd
@ -59,6 +58,26 @@ namespace AZ
class BehaviorContext;
class ScriptDataContext;
namespace OnDemandLuaFunctions
{
inline void AnyToLua(lua_State* lua, BehaviorValueParameter& param);
}
namespace ScriptCanvasOnDemandReflection
{
template<typename T>
struct OnDemandPrettyName;
template<typename T>
struct OnDemandToolTip;
template<typename T>
struct OnDemandCategoryName;
}
namespace CommonOnDemandReflections
{
void ReflectCommonString(ReflectContext* context);
void ReflectCommonStringView(ReflectContext* context);
void ReflectStdAny(ReflectContext* context);
void ReflectVoidOutcome(ReflectContext* context);
}
/// OnDemand reflection for AZStd::basic_string
template<class Element, class Traits, class Allocator>
struct OnDemandReflection< AZStd::basic_string<Element, Traits, Allocator> >
@ -66,108 +85,16 @@ namespace AZ
using ContainerType = AZStd::basic_string<Element, Traits, Allocator>;
using SizeType = typename ContainerType::size_type;
using ValueType = typename ContainerType::value_type;
static void Reflect(ReflectContext* context)
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
constexpr bool is_string = AZStd::is_same_v<Element, char> && AZStd::is_same_v<Traits, AZStd::char_traits<char>>
&& AZStd::is_same_v<Allocator, AZStd::allocator>;
if constexpr(is_string)
{
behaviorContext->Class<ContainerType>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->template Constructor<typename ContainerType::value_type*>()
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructBasicString<Element, Traits, Allocator>)
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
->template WrappingMember<const char*>(&ContainerType::c_str)
->Method("c_str", &ContainerType::c_str)
->Method("Length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); })
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
->Method("Equal", [](const ContainerType& lhs, const ContainerType& rhs)
{
return lhs == rhs;
})
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
->Method("Find", [](ContainerType* thisPtr, const ContainerType& stringToFind, const int& startPos)
{
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
})
->Method("Substring", [](ContainerType* thisPtr, const int& pos, const int& len)
{
return thisPtr->substr(pos, len);
})
->Method("Replace", [](ContainerType* thisPtr, const ContainerType& stringToReplace, const ContainerType& replacementString)
{
SizeType startPos = 0;
while ((startPos = thisPtr->find(stringToReplace, startPos)) != ContainerType::npos && !stringToReplace.empty())
{
thisPtr->replace(startPos, stringToReplace.length(), replacementString);
startPos += replacementString.length();
}
return *thisPtr;
})
->Method("ReplaceByIndex", [](ContainerType* thisPtr, const int& beginIndex, const int& endIndex, const ContainerType& replacementString)
{
thisPtr->replace(beginIndex, endIndex - beginIndex + 1, replacementString);
return *thisPtr;
})
->Method("Add", [](ContainerType* thisPtr, const ContainerType& addend)
{
return *thisPtr + addend;
})
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Concat)
->Method("TrimLeft", [](ContainerType* thisPtr)
{
auto wsfront = AZStd::find_if_not(thisPtr->begin(), thisPtr->end(), [](char c) {return AZStd::is_space(c);});
thisPtr->erase(thisPtr->begin(), wsfront);
return *thisPtr;
})
->Method("TrimRight", [](ContainerType* thisPtr)
{
auto wsend = AZStd::find_if_not(thisPtr->rbegin(), thisPtr->rend(), [](char c) {return AZStd::is_space(c);});
thisPtr->erase(wsend.base(), thisPtr->end());
return *thisPtr;
})
->Method("ToLower", [](ContainerType* thisPtr)
{
ContainerType toLowerString;
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
{
toLowerString.push_back(static_cast<ValueType>(tolower(*itr)));
}
return toLowerString;
})
->Method("ToUpper", [](ContainerType* thisPtr)
{
ContainerType toUpperString;
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
{
toUpperString.push_back(static_cast<ValueType>(toupper(*itr)));
}
return toUpperString;
})
->Method("Join", [](AZStd::vector<ContainerType>* stringsToJoinPtr, const ContainerType& joinStr)
{
ContainerType joinString;
for (auto& stringToJoin : *stringsToJoinPtr)
{
joinString.append(stringToJoin).append(joinStr);
}
//Cut off the last join str
if (!stringsToJoinPtr->empty())
{
joinString = joinString.substr(0, joinString.length() - joinStr.length());
}
return joinString;
})
->Method("Split", [](ContainerType* thisPtr, const ContainerType& splitter)
{
AZStd::vector<ContainerType> splitStringList;
AZStd::tokenize(*thisPtr, splitter, splitStringList);
return splitStringList;
})
;
CommonOnDemandReflections::ReflectCommonString(context);
}
static_assert (is_string, "Unspecialized basic_string<> template reflection requested.");
}
};
@ -181,44 +108,9 @@ namespace AZ
static void Reflect(ReflectContext* context)
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<ContainerType>()
->Attribute(AZ::Script::Attributes::Category, "Core")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->template Constructor<typename ContainerType::value_type*>()
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructStringView<Element, Traits>)
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
->Method("ToString", [](const ContainerType& stringView) { return static_cast<AZStd::string>(stringView).c_str(); }, { { { "Reference", "String view object being converted to string" } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Converts string_view to string")
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
->template WrappingMember<const char*>(&ContainerType::data)
->Method("data", &ContainerType::data)
->Attribute(AZ::Script::Attributes::ToolTip, "Returns reference to raw string data")
->Method("length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); }, { { { "This", "Reference to the object the method is being performed on" } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
->Method("size", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->size()); }, { { { "This", "Reference to the object the method is being performed on" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
->Method("find", [](ContainerType* thisPtr, ContainerType stringToFind, int startPos)
{
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
}, { { { "This", "Reference to the object the method is being performed on" }, { "View", "View to search " }, { "Position", "Index in view to start search" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Searches for supplied string within this string")
->Method("substr", [](ContainerType* thisPtr, int pos, int len)
{
return thisPtr->substr(pos, len);
}, { {{"This", "Reference to the object the method is being performed on"}, {"Position", "Index in view that indicates the beginning of the sub string"}, {"Count", "Length of characters that sub string view occupies" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Creates a sub view of this string view. The string data is not actually modified")
->Method("remove_prefix", [](ContainerType* thisPtr, int n) {thisPtr->remove_prefix(n); },
{ { { "This", "Reference to the object the method is being performed on" }, { "Count", "Number of characters to remove from start of view" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the beginning of this sub view")
->Method("remove_suffix", [](ContainerType* thisPtr, int n) {thisPtr->remove_suffix(n); },
{ { { "This", "Reference to the object the method is being performed on" } ,{ "Count", "Number of characters to remove from end of view" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the end of this sub view")
;
}
constexpr bool is_common = AZStd::is_same_v<Element,char> && AZStd::is_same_v<Traits,AZStd::char_traits<char>>;
static_assert (is_common, "Unspecialized basic_string_view<> template reflection requested.");
CommonOnDemandReflections::ReflectCommonStringView(context);
}
};
@ -228,7 +120,7 @@ namespace AZ
{
using ContainerType = AZStd::intrusive_ptr<T>;
// TODO: Count reflection types for a proper un-reflect
// TODO: Count reflection types for a proper un-reflect
static void CustomConstructor(ContainerType* thisPtr, ScriptDataContext& dc)
{
@ -276,7 +168,7 @@ namespace AZ
{
using ContainerType = AZStd::shared_ptr<T>;
// TODO: Count reflection types for a proper un-reflect
// TODO: Count reflection types for a proper un-reflect
static void CustomConstructor(ContainerType* thisPtr, ScriptDataContext& dc)
{
@ -435,7 +327,7 @@ namespace AZ
thisPtr[uindex] = value;
}
static bool EraseCheck_VM(ContainerType& thisPtr, AZ::u64 index)
{
if (index < thisPtr.size())
@ -448,7 +340,7 @@ namespace AZ
return false;
}
}
static ContainerType& ErasePost_VM(ContainerType& thisPtr, AZ::u64 /*index*/)
{
return thisPtr;
@ -604,7 +496,7 @@ namespace AZ
return AZ::Failure(AZStd::string::format("Index out of bounds: %zu (size: %zu)", index, thisContainer.size()));
}
}
static AZ::Outcome<void, void> Replace(ContainerType& thisContainer, size_t index, T& value)
{
if (index >= 0 && index < thisContainer.size())
@ -634,7 +526,7 @@ namespace AZ
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Method(k_accessElementName, &At, {{ {}, { "Index", "The index to read from", nullptr, BehaviorParameter::Traits::TR_INDEX }}})
->Method(k_sizeName, [](ContainerType*) { return aznumeric_cast<int>(N); })
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
@ -743,27 +635,8 @@ namespace AZ
template<> // in case someone has an issue with bool
struct OnDemandReflection<AZ::Outcome<void, void>>
{
using OutcomeType = AZ::Outcome<void, void>;
static void Reflect(ReflectContext* context)
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
// note we can reflect iterator types and support iterators, as of know we want to keep it simple
behaviorContext->Class<OutcomeType>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, true)
->Attribute(AZ::ScriptCanvasAttributes::PrettyName, &ScriptCanvasOnDemandReflection::OnDemandPrettyName<OutcomeType>::Get)
->Attribute(AZ::Script::Attributes::ToolTip, &ScriptCanvasOnDemandReflection::OnDemandToolTip<OutcomeType>::Get)
->Attribute(AZ::Script::Attributes::Category, &ScriptCanvasOnDemandReflection::OnDemandCategoryName<OutcomeType>::Get)
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AttributeIsValid::IfPresent)
->Method("Failure", []() -> OutcomeType { return AZ::Failure(); })
->Method("Success", []() -> OutcomeType { return AZ::Success(); })
->Method("IsSuccess", &OutcomeType::IsSuccess)
;
}
static void Reflect(ReflectContext* context) {
CommonOnDemandReflections::ReflectVoidOutcome(context);
}
};
@ -1179,16 +1052,8 @@ namespace AZ
template <>
struct OnDemandReflection<AZStd::any>
{
static void Reflect(ReflectContext* context)
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<AZStd::any>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(Script::Attributes::Ignore, true) // Don't reflect any type to script (there should never be an any instance in script)
->Attribute(Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&AZ::OnDemandLuaFunctions::AnyToLua, &OnDemandLuaFunctions::AnyFromLua))
;
}
static void Reflect(ReflectContext* context) {
CommonOnDemandReflections::ReflectStdAny(context);
}
};

@ -0,0 +1,208 @@
/*
* 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/Math/Uuid.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/std/string/alphanum.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/tokenize.h>
#include <AzCore/RTTI/AzStdOnDemandReflection.inl>
#include <AzCore/RTTI/AzStdOnDemandReflectionLuaFunctions.inl>
namespace AZ::CommonOnDemandReflections
{
void ReflectCommonString(ReflectContext* context)
{
using ContainerType = AZStd::string;
using SizeType = typename ContainerType::size_type;
using ValueType = typename ContainerType::value_type;
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<ContainerType>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->template Constructor<typename ContainerType::value_type*>()
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructBasicString<ContainerType::value_type, ContainerType::traits_type, ContainerType::allocator_type>)
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
->template WrappingMember<const char*>(&ContainerType::c_str)
->Method("c_str", &ContainerType::c_str)
->Method("Length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); })
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
->Method("Equal", [](const ContainerType& lhs, const ContainerType& rhs)
{
return lhs == rhs;
})
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
->Method("Find", [](ContainerType* thisPtr, const ContainerType& stringToFind, const int& startPos)
{
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
})
->Method("Substring", [](ContainerType* thisPtr, const int& pos, const int& len)
{
return thisPtr->substr(pos, len);
})
->Method("Replace", [](ContainerType* thisPtr, const ContainerType& stringToReplace, const ContainerType& replacementString)
{
SizeType startPos = 0;
while ((startPos = thisPtr->find(stringToReplace, startPos)) != ContainerType::npos && !stringToReplace.empty())
{
thisPtr->replace(startPos, stringToReplace.length(), replacementString);
startPos += replacementString.length();
}
return *thisPtr;
})
->Method("ReplaceByIndex", [](ContainerType* thisPtr, const int& beginIndex, const int& endIndex, const ContainerType& replacementString)
{
thisPtr->replace(beginIndex, endIndex - beginIndex + 1, replacementString);
return *thisPtr;
})
->Method("Add", [](ContainerType* thisPtr, const ContainerType& addend)
{
return *thisPtr + addend;
})
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Concat)
->Method("TrimLeft", [](ContainerType* thisPtr)
{
auto wsfront = AZStd::find_if_not(thisPtr->begin(), thisPtr->end(), [](char c) {return AZStd::is_space(c);});
thisPtr->erase(thisPtr->begin(), wsfront);
return *thisPtr;
})
->Method("TrimRight", [](ContainerType* thisPtr)
{
auto wsend = AZStd::find_if_not(thisPtr->rbegin(), thisPtr->rend(), [](char c) {return AZStd::is_space(c);});
thisPtr->erase(wsend.base(), thisPtr->end());
return *thisPtr;
})
->Method("ToLower", [](ContainerType* thisPtr)
{
ContainerType toLowerString;
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
{
toLowerString.push_back(static_cast<ValueType>(tolower(*itr)));
}
return toLowerString;
})
->Method("ToUpper", [](ContainerType* thisPtr)
{
ContainerType toUpperString;
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
{
toUpperString.push_back(static_cast<ValueType>(toupper(*itr)));
}
return toUpperString;
})
->Method("Join", [](AZStd::vector<ContainerType>* stringsToJoinPtr, const ContainerType& joinStr)
{
ContainerType joinString;
for (auto& stringToJoin : *stringsToJoinPtr)
{
joinString.append(stringToJoin).append(joinStr);
}
//Cut off the last join str
if (!stringsToJoinPtr->empty())
{
joinString = joinString.substr(0, joinString.length() - joinStr.length());
}
return joinString;
})
->Method("Split", [](ContainerType* thisPtr, const ContainerType& splitter)
{
AZStd::vector<ContainerType> splitStringList;
AZStd::tokenize(*thisPtr, splitter, splitStringList);
return splitStringList;
})
;
}
}
void ReflectCommonStringView(ReflectContext* context)
{
using ContainerType = AZStd::string_view;
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<ContainerType>()
->Attribute(AZ::Script::Attributes::Category, "Core")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->template Constructor<typename ContainerType::value_type*>()
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructStringView<ContainerType::value_type, ContainerType::traits_type>)
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
->Method("ToString", [](const ContainerType& stringView) { return static_cast<AZStd::string>(stringView).c_str(); }, { { { "Reference", "String view object being converted to string" } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Converts string_view to string")
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
->template WrappingMember<const char*>(&ContainerType::data)
->Method("data", &ContainerType::data)
->Attribute(AZ::Script::Attributes::ToolTip, "Returns reference to raw string data")
->Method("length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); }, { { { "This", "Reference to the object the method is being performed on" } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
->Method("size", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->size()); }, { { { "This", "Reference to the object the method is being performed on" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
->Method("find", [](ContainerType* thisPtr, ContainerType stringToFind, int startPos)
{
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
}, { { { "This", "Reference to the object the method is being performed on" }, { "View", "View to search " }, { "Position", "Index in view to start search" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Searches for supplied string within this string")
->Method("substr", [](ContainerType* thisPtr, int pos, int len)
{
return thisPtr->substr(pos, len);
}, { {{"This", "Reference to the object the method is being performed on"}, {"Position", "Index in view that indicates the beginning of the sub string"}, {"Count", "Length of characters that sub string view occupies" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Creates a sub view of this string view. The string data is not actually modified")
->Method("remove_prefix", [](ContainerType* thisPtr, int n) {thisPtr->remove_prefix(n); },
{ { { "This", "Reference to the object the method is being performed on" }, { "Count", "Number of characters to remove from start of view" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the beginning of this sub view")
->Method("remove_suffix", [](ContainerType* thisPtr, int n) {thisPtr->remove_suffix(n); },
{ { { "This", "Reference to the object the method is being performed on" } ,{ "Count", "Number of characters to remove from end of view" }} })
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the end of this sub view")
;
}
}
void ReflectVoidOutcome(ReflectContext* context)
{
using OutcomeType = AZ::Outcome<void, void>;
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
// note we can reflect iterator types and support iterators, as of know we want to keep it simple
behaviorContext->Class<OutcomeType>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, true)
->Attribute(AZ::ScriptCanvasAttributes::PrettyName, &ScriptCanvasOnDemandReflection::OnDemandPrettyName<OutcomeType>::Get)
->Attribute(AZ::Script::Attributes::ToolTip, &ScriptCanvasOnDemandReflection::OnDemandToolTip<OutcomeType>::Get)
->Attribute(AZ::Script::Attributes::Category, &ScriptCanvasOnDemandReflection::OnDemandCategoryName<OutcomeType>::Get)
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AttributeIsValid::IfPresent)
->Method("Failure", []() -> OutcomeType { return AZ::Failure(); })
->Method("Success", []() -> OutcomeType { return AZ::Success(); })
->Method("IsSuccess", &OutcomeType::IsSuccess)
;
}
}
void ReflectStdAny(ReflectContext* context)
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<AZStd::any>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(
Script::Attributes::Ignore, true) // Don't reflect any type to script (there should never be an any instance in script)
->Attribute(
Script::Attributes::ReaderWriterOverride,
ScriptContext::CustomReaderWriter(&AZ::OnDemandLuaFunctions::AnyToLua, &OnDemandLuaFunctions::AnyFromLua));
}
}
} // namespace AZ

@ -8,14 +8,14 @@
#pragma once
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Casting/numeric_cast_internal.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/std/string/string_view.h>
#include <AzCore/std/string/osstring.h>
namespace AZ
{
//! A helper function to casts between numeric types, and consider the data which is being converted comse from user data.
//! A helper function to casts between numeric types, and consider the data which is being converted comes from user data.
//! If a conversion from FromType to ToType will not cause overflow or underflow, the result is stored in result, and the function returns Success
//! Otherwise, the target is left untouched.
template <typename ToType, typename FromType>
@ -24,9 +24,9 @@ namespace AZ
{
using namespace JsonSerializationResult;
if (NumericCastInternal::FitsInToType<ToType>(value))
if (NumericCastInternal::template FitsInToType<ToType>(value))
{
result = aznumeric_cast<ToType>(value);
result = static_cast<ToType>(value);
return reporting("Successfully cast number.", ResultCode(Tasks::Convert, Outcomes::Success), path);
}
else

@ -6,6 +6,7 @@
*
*/
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>

@ -35,6 +35,7 @@ set(FILES
Asset/AssetInternal/WeakAsset.h
Casting/lossy_cast.h
Casting/numeric_cast.h
Casting/numeric_cast_internal.h
Component/Component.cpp
Component/Component.h
Component/ComponentApplication.cpp
@ -176,6 +177,8 @@ set(FILES
IO/Path/Path.cpp
IO/Path/Path.h
IO/Path/Path.inl
IO/Path/PathIterable.inl
IO/Path/PathParser.inl
IO/Path/Path_fwd.h
IO/SystemFile.cpp
IO/SystemFile.h
@ -440,6 +443,7 @@ set(FILES
RTTI/AttributeReader.h
RTTI/AzStdOnDemandPrettyName.inl
RTTI/AzStdOnDemandReflection.inl
RTTI/AzStdOnDemandReflectionSpecializations.cpp
RTTI/AzStdOnDemandReflectionLuaFunctions.inl
RTTI/BehaviorContext.cpp
RTTI/BehaviorContext.h

@ -15,7 +15,7 @@ namespace AZStd
{
namespace Platform
{
void PostThreadRun();
unsigned __stdcall PostThreadRun();
HANDLE CreateThread(unsigned stackSize, unsigned (__stdcall* threadRunFunction)(void*), AZStd::Internal::thread_info* ti, unsigned int* id);
unsigned HardwareConcurrency();
void SetThreadName(HANDLE hThread, const char* threadName);
@ -40,9 +40,7 @@ namespace AZStd
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to client listeners
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to the profiler.
Platform::PostThreadRun();
return 0;
return Platform::PostThreadRun();
}
/**

@ -16,9 +16,10 @@ namespace AZStd
{
namespace Platform
{
void PostThreadRun()
unsigned __stdcall PostThreadRun()
{
_endthreadex(0);
return 0;
}
HANDLE CreateThread(unsigned stackSize, unsigned (__stdcall* threadRunFunction)(void*), AZStd::Internal::thread_info* ti, unsigned int* id)

@ -56,7 +56,7 @@ namespace UnitTest
}
// filesystem::path::is_absolute test
// PathView::IsAbsolute test
TEST_F(PathFixture, IsAbsolute_ReturnsTrue)
{
using fixed_max_path = AZ::IO::FixedMaxPath;
@ -88,7 +88,7 @@ namespace UnitTest
static_assert(IsAbsolute());
}
// filesystem::path::is_relative test
// PathView::isRelative test
TEST_F(PathFixture, IsRelative_ReturnsTrue)
{
using fixed_max_path = AZ::IO::FixedMaxPath;
@ -573,7 +573,16 @@ namespace UnitTest
PathLexicallyNormalParams{ '/', "foo/./bar/..", "foo" },
PathLexicallyNormalParams{ '/', "foo/.///bar/../", "foo" },
PathLexicallyNormalParams{ '/', R"(/foo\./bar\..\)", "/foo" },
PathLexicallyNormalParams{ '\\', R"(C:/O3DE/dev/Cache\game/../pc)", R"(C:\O3DE\dev\Cache\pc)" }
PathLexicallyNormalParams{ '/', R"(/..)", "/" },
PathLexicallyNormalParams{ '\\', R"(C:/O3DE/dev/Cache\game/../pc)", R"(C:\O3DE\dev\Cache\pc)" },
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:bar)", R"(C:\foo\bar)" },
PathLexicallyNormalParams{ '\\', R"(C:foo/C:bar)", R"(C:foo\bar)" },
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:/bar)", R"(C:\bar)" },
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:)", R"(C:\foo)" },
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:/)", R"(C:\)" },
PathLexicallyNormalParams{ '\\', R"(C:/foo/D:bar)", R"(D:bar)" },
PathLexicallyNormalParams{ '\\', R"(..)", R"(..)" },
PathLexicallyNormalParams{ '\\', R"(foo/../../bar)", R"(..\bar)" }
)
);
@ -641,7 +650,12 @@ namespace UnitTest
PathViewLexicallyProximateParams{ '\\', "C:\\a\\b", "C:\\a\\d\\c", "..\\..\\b", false },
PathViewLexicallyProximateParams{ '\\', "C:a\\b", "C:\\a\\b", "C:a\\b", false },
PathViewLexicallyProximateParams{ '\\', "C:\\a\\b", "C:a\\b", "C:\\a\\b", false },
PathViewLexicallyProximateParams{ '\\', "E:\\a\\b", "F:\\a\\b", "E:\\a\\b", false }
PathViewLexicallyProximateParams{ '\\', "E:\\a\\b", "F:\\a\\b", "E:\\a\\b", false },
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/asset.txt", "d:\\o3de\\Project\\Cache", "asset.txt", true },
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/pc/..", "d:\\o3de\\Project\\Cache", "pc\\..", true },
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/pc/asset.txt/..", "d:\\o3de\\Project\\Cache\\", "pc\\asset.txt\\..", true },
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache\\", "D:\\o3de\\Project\\Cache/", ".", true },
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/../foo", "D:\\o3de\\Project\\Cache", "..\\foo", false }
)
);

@ -10,11 +10,12 @@
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <AzCore/Settings/SettingsRegistryScriptUtils.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/containers/variant.h>
namespace SettingsRegistryScriptUtilsTests
{
static constexpr const char* SettingsRegistryScriptClassName = "SettingsRegistryInterface";
class SettingsRegistryBehaviorContextFixture
: public UnitTest::ScopedAllocatorSetupFixture
@ -77,7 +78,7 @@ namespace SettingsRegistryScriptUtilsTests
// so the invoking the getter on global Settings Registry should succeed, but return nullptr
EXPECT_TRUE(globalSettingsRegistryGetter->InvokeResult(settingsRegistryObject));
EXPECT_EQ(nullptr, settingsRegistryObject.m_settingsRegistry);
// Register the Settings Registry stored on the fixture with the SettingsRegistry Interface<T>
AZ::SettingsRegistry::Register(m_registry.get());
EXPECT_TRUE(globalSettingsRegistryGetter->InvokeResult(settingsRegistryObject));
@ -227,7 +228,7 @@ namespace SettingsRegistryScriptUtilsTests
R"( "intIndex": -55)" "\n"
R"( })" "\n"
R"(])";
// Populate the settings registry to match the expected json values
m_registry->Set("/TestObject/boolValue", false);
m_registry->Set("/TestObject/intValue", aznumeric_cast<AZ::s64>(17));
@ -562,4 +563,4 @@ namespace SettingsRegistryScriptUtilsTests
SettingsRegistryBehaviorContextParams{ "/TestObject/stringValue", AZStd::string_view{"Hello World"}, "GetString", "SetString" }
)
);
}
}

@ -18,6 +18,7 @@
#include <AzCore/std/functional.h>
#include <AzCore/std/parallel/thread.h>
#include <AzCore/std/string/string.h>
#include <AzCore/PlatformIncl.h>
#include <AzFramework/CommandLine/CommandLine.h>

@ -689,9 +689,6 @@ namespace AZ::IO
return AZ::IO::InvalidHandle;
}
AZ_PROFILE_SCOPE(Game, "File: %.*s Archive: %p",
aznumeric_cast<int>(pName.size()), pName.data(), this);
SAutoCollectFileAccessTime accessTime(this);
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
@ -1915,7 +1912,7 @@ namespace AZ::IO
return m_pFileEntry->nFileDataOffset;
}
bool Archive::MakeDir(AZStd::string_view szPathIn, [[maybe_unused]] bool bGamePathMapping)
bool Archive::MakeDir(AZStd::string_view szPathIn)
{
AZ::IO::StackString pathStr{ szPathIn };
// Determine if there is a period ('.') after the last slash to determine if the path contains a file.
@ -2330,7 +2327,9 @@ namespace AZ::IO
// we only want to record ASSET access
// assets are identified as things which start with no alias, or with the @assets@ alias
auto assetPath = AZ::IO::FileIOBase::GetInstance()->ConvertToAlias(szFilename);
if (assetPath && assetPath->Native().starts_with("@assets@"))
if (assetPath && (assetPath->Native().starts_with("@assets@")
|| assetPath->Native().starts_with("@root@")
|| assetPath->Native().starts_with("@projectplatformcache@")))
{
IResourceList* pList = GetResourceList(m_eRecordFileOpenList);

@ -249,7 +249,7 @@ namespace AZ::IO
IArchive::SignedFileSize GetFileSizeOnDisk(AZStd::string_view filename) override;
// creates a directory
bool MakeDir(AZStd::string_view szPath, bool bGamePathMapping = false) override;
bool MakeDir(AZStd::string_view szPath) override;
// compresses the raw data into raw data. The buffer for compressed data itself with the heap passed. Uses method 8 (deflate)
// returns one of the Z_* errors (Z_OK upon success)

@ -335,7 +335,7 @@ namespace AZ::IO
virtual IArchive::SignedFileSize GetFileSizeOnDisk(AZStd::string_view filename) = 0;
// creates a directory
virtual bool MakeDir(AZStd::string_view szPath, bool bGamePathMapping = false) = 0;
virtual bool MakeDir(AZStd::string_view szPath) = 0;
// open the physical archive file - creates if it doesn't exist
// returns NULL if it's invalid or can't open the file

@ -287,11 +287,8 @@ namespace AZ
const char* assetAliasPath = GetAlias("@assets@");
if (path && assetAliasPath)
{
AZStd::string assetsAlias(assetAliasPath);
AZStd::string pathString = path;
AZStd::to_lower(assetsAlias.begin(), assetsAlias.end());
AZStd::to_lower(pathString.begin(), pathString.end());
if (AZ::IO::PathView(pathString.c_str()).IsRelativeTo(assetsAlias.c_str()))
const AZ::IO::PathView pathView(path);
if (pathView.IsRelativeTo(assetAliasPath))
{
AZ_Error("FileIO", false, "You may not alter data inside the asset cache. Please check the call stack and consider writing into the source asset folder instead.\n"
"Attempted write location: %s", path);
@ -587,26 +584,11 @@ namespace AZ
// strings that are shorter than the alias's mapped path without checking.
if ((longestMatch == 0) || (resolvedAlias.size() > longestMatch) && (resolvedAlias.size() <= bufStringLength))
{
// custom strcmp that ignores slash directions
constexpr AZStd::string_view pathSeparators{ "/\\" };
bool allMatch = AZStd::equal(resolvedAlias.begin(), resolvedAlias.end(), inBuffer.begin(),
[&pathSeparators](const char lhs, const char rhs)
// Check if the input path is relative to the alias value
if (AZ::IO::PathView(inBuffer).IsRelativeTo(AZ::IO::PathView(resolvedAlias)))
{
const bool lhsIsSeparator = pathSeparators.find_first_of(lhs) != AZStd::string_view::npos;
const bool rhsIsSeparator = pathSeparators.find_first_of(lhs) != AZStd::string_view::npos;
return (lhsIsSeparator && rhsIsSeparator) || tolower(lhs) == tolower(rhs);
});
if (allMatch)
{
// Either the resolvedAlias path must match the path exactly or the path must have a path separator character
// right after the resolved alias
if (const size_t matchLen = resolvedAlias.size();
matchLen == bufStringLength || (pathSeparators.find_first_of(inBuffer[matchLen]) != AZStd::string_view::npos))
{
longestMatch = matchLen;
longestAlias = alias;
}
longestMatch = resolvedAlias.size();
longestAlias = alias;
}
}
}
@ -712,6 +694,7 @@ namespace AZ
const char* assetAliasPath = GetAlias("@assets@");
const char* rootAliasPath = GetAlias("@root@");
const char* projectPlatformCacheAliasPath = GetAlias("@projectplatformcache@");
const bool lowercasePath = (assetAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, assetAliasPath)) ||
(rootAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, rootAliasPath)) ||
(projectPlatformCacheAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, projectPlatformCacheAliasPath));

@ -83,7 +83,7 @@ namespace AzFramework::ProjectManager
return ProjectPathCheckResult::ProjectManagerLaunchFailed;
}
bool LaunchProjectManager(const AZStd::string& commandLineArgs)
bool LaunchProjectManager([[maybe_unused]]const AZStd::string& commandLineArgs)
{
bool launchSuccess = false;
#if (AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER)

@ -7,6 +7,7 @@
*/
#include "TerrainDataRequestBus.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace AzFramework
{

@ -45,8 +45,6 @@ namespace AzFramework
void EntityVisibilityBoundsUnionSystem::OnEntityActivated(AZ::Entity* entity)
{
AZ_PROFILE_FUNCTION(AzFramework);
// ignore any entity that might activate which does not have a TransformComponent
if (entity->GetTransform() == nullptr)
{
@ -68,8 +66,6 @@ namespace AzFramework
void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(AZ::Entity* entity)
{
AZ_PROFILE_FUNCTION(AzFramework);
// ignore any entity that might deactivate which does not have a TransformComponent
if (entity->GetTransform() == nullptr)
{
@ -89,8 +85,6 @@ namespace AzFramework
void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance)
{
AZ_PROFILE_FUNCTION(AzFramework);
if (const auto& localEntityBoundsUnions = instance.m_localEntityBoundsUnion; localEntityBoundsUnions.IsValid())
{
// note: worldEntityBounds will not be a 'tight-fit' Aabb but that of a transformed local aabb
@ -155,8 +149,6 @@ namespace AzFramework
void EntityVisibilityBoundsUnionSystem::OnTransformUpdated(AZ::Entity* entity)
{
AZ_PROFILE_FUNCTION(AzFramework);
// update the world transform of the visibility bounds union
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())

@ -21,9 +21,6 @@ namespace AzFramework
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported."
return nullptr;
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_XLIB
#error "Linux Window Manager XLIB not supported."
return nullptr;
#else
#error "Linux Window Manager not recognized."
return nullptr;

@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h>

@ -17,9 +17,6 @@ namespace AzFramework
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported."
return nullptr;
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_XLIB
#error "Linux Window Manager XLIB not supported."
return nullptr;
#else
#error "Linux Window Manager not recognized."
return nullptr;

@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h>

@ -7,7 +7,7 @@
#
# Based on the linux window manager trait, perform the appropriate additional build configurations
# Only 'xcb', 'wayland', and 'xlib' are recognized
# Only 'xcb' and 'wayland' are recognized
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
find_library(XCB_LIBRARY xcb)
@ -23,10 +23,6 @@ elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland")
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND)
elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "xlib")
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XLIB)
else()
message(FATAL_ERROR, "Linux Window Manager ${PAL_TRAIT_LINUX_WINDOW_MANAGER} is not recognized")

@ -608,6 +608,9 @@ namespace UnitTest
archive->ClosePack(genericArchiveFileName);
cpfio.Remove(genericArchiveFileName);
// create the asset alias directory
cpfio.CreatePath("@assets@");
// create generic file
HandleType normalFileHandle;
@ -848,13 +851,17 @@ namespace UnitTest
const char *assetsPath = ioBase->GetAlias("@assets@");
ASSERT_NE(nullptr, assetsPath);
AZStd::string stringToAdd = AZStd::string::format("%s/textures/test.dds", assetsPath);
auto stringToAdd = AZ::IO::Path(assetsPath) / "textures" / "test.dds";
reslist->Clear();
reslist->Add(stringToAdd.c_str());
reslist->Add(stringToAdd.Native());
// it normalizes the string, so the slashes flip and everything is lowercased.
EXPECT_STREQ(reslist->GetFirst(), "@assets@/textures/test.dds");
AZ::IO::FixedMaxPath resolvedAddedPath;
AZ::IO::FixedMaxPath resolvedResourcePath;
EXPECT_TRUE(ioBase->ReplaceAlias(resolvedAddedPath, "@assets@/textures/test.dds"));
EXPECT_TRUE(ioBase->ReplaceAlias(resolvedResourcePath, reslist->GetFirst()));
EXPECT_EQ(resolvedAddedPath, resolvedResourcePath);
reslist->Clear();
}

@ -9,6 +9,7 @@
#include <cmath>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Debug/Trace.h>
#include <AzQtComponents/Components/DockTabBar.h>
#include <AzQtComponents/Components/FancyDocking.h>

@ -114,7 +114,7 @@ void GradientSlider::mouseMoveEvent(QMouseEvent* event)
{
int intValue = Slider::valueFromPosition(this, event->pos(), width(), height(), rect().bottom());
qreal value = (aznumeric_cast<qreal, int>(intValue - minimum()) / aznumeric_cast<qreal, int>(maximum() - minimum()));
qreal value = (aznumeric_cast<qreal>(intValue - minimum()) / aznumeric_cast<qreal>(maximum() - minimum()));
const QString toolTipText = m_toolTipFunction(value);

@ -312,8 +312,6 @@ namespace AzToolsFramework
void EditorVisibleEntityDataCache::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
{
AZ_PROFILE_FUNCTION(AzToolsFramework);
const AZ::EntityId entityId = *AZ::TransformNotificationBus::GetCurrentBusId();
if (AZStd::optional<size_t> entityIndex = GetVisibleEntityIndexFromId(entityId))

@ -70,7 +70,7 @@ struct CryPakMock
MOCK_METHOD2(IsFileExist, bool(AZStd::string_view sFilename, EFileSearchLocation));
MOCK_METHOD1(IsFolder, bool(AZStd::string_view sPath));
MOCK_METHOD1(GetFileSizeOnDisk, AZ::IO::IArchive::SignedFileSize(AZStd::string_view filename));
MOCK_METHOD2(MakeDir, bool(AZStd::string_view szPath, bool bGamePathMapping));
MOCK_METHOD1(MakeDir, bool(AZStd::string_view szPath));
MOCK_METHOD4(OpenArchive, AZStd::intrusive_ptr<AZ::IO::INestedArchive> (AZStd::string_view szPath, AZStd::string_view bindRoot, uint32_t nFlags, AZStd::intrusive_ptr<AZ::IO::MemoryBlock> pData));
MOCK_METHOD1(GetFileArchivePath, const char* (AZ::IO::HandleType f));
MOCK_METHOD5(RawCompress, int(const void* pUncompressed, size_t* pDestSize, void* pCompressed, size_t nSrcSize, int nLevel));

@ -6,9 +6,10 @@
*
*/
#include <AzCore/AzCore_Traits_Platform.h>
// Description : Linux/Mac port support for Win32API calls
#if !defined(WIN32)
#if AZ_TRAIT_LEGACY_CRYCOMMON_USE_WINDOWS_STUBS
#include "platform.h" // Note: This should be first to get consistent debugging definitions
@ -1391,4 +1392,4 @@ __finddata64_t::~__finddata64_t()
}
#endif //defined(APPLE) || defined(LINUX)
#endif // !defined(WIN32)
#endif // AZ_TRAIT_LEGACY_CRYCOMMON_USE_WINDOWS_STUBS

@ -131,7 +131,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include "SystemEventDispatcher.h"
#include "HMDBus.h"
#include "zlib.h"
#include "RemoteConsole/RemoteConsole.h"
#include <PNoise3.h>

@ -273,11 +273,7 @@ static const char* GetLastSystemErrorMessage()
return szBuffer;
}
#else
return 0;
#endif //WIN32
return 0;
}

@ -441,7 +441,7 @@ namespace O3DE::ProjectManager
return true;
}
bool ReplaceFile(const QString& origFile, const QString& newFile, QWidget* parent, bool interactive)
bool ReplaceProjectFile(const QString& origFile, const QString& newFile, QWidget* parent, bool interactive)
{
QFileInfo original(origFile);
if (original.exists())

@ -25,7 +25,7 @@ namespace O3DE::ProjectManager
bool DeleteProjectFiles(const QString& path, bool force = false);
bool MoveProject(QString origPath, QString newPath, QWidget* parent, bool skipRegister = false);
bool ReplaceFile(const QString& origFile, const QString& newFile, QWidget* parent = nullptr, bool interactive = true);
bool ReplaceProjectFile(const QString& origFile, const QString& newFile, QWidget* parent = nullptr, bool interactive = true);
bool FindSupportedCompiler(QWidget* parent = nullptr);
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform();

@ -242,7 +242,7 @@ namespace O3DE::ProjectManager
if (!newProjectSettings.m_newPreviewImagePath.isEmpty())
{
if (!ProjectUtils::ReplaceFile(
if (!ProjectUtils::ReplaceProjectFile(
QDir(newProjectSettings.m_path).filePath(newProjectSettings.m_iconPath), newProjectSettings.m_newPreviewImagePath))
{
QMessageBox::critical(this, tr("File replace failed"), tr("Failed to replace project preview image."));

@ -202,7 +202,7 @@ namespace O3DE::ProjectManager
TEST_F(ProjectManagerUtilsTests, ReplaceFile_Succeeds)
#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
{
EXPECT_TRUE(ReplaceFile(m_projectAOrigFilePath, m_projectAReplaceFilePath, nullptr, false));
EXPECT_TRUE(ReplaceProjectFile(m_projectAOrigFilePath, m_projectAReplaceFilePath, nullptr, false));
QFile origFile(m_projectAOrigFilePath);
EXPECT_TRUE(origFile.open(QIODevice::ReadOnly));

@ -8,6 +8,7 @@
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/limits.h>
namespace AZ

@ -26,9 +26,6 @@ ly_add_target(
Gem::HttpRequestor
3rdParty::AWSNativeSDK::AWSClientAuth
3rdParty::AWSNativeSDK::Core
RUNTIME_DEPENDENCIES
Gem::AWSCore
Gem::HttpRequestor
)
ly_add_target(
@ -48,17 +45,45 @@ ly_add_target(
3rdParty::AWSNativeSDK::Core
PUBLIC
Gem::AWSClientAuth.Static
RUNTIME_DEPENDENCIES
Gem::AWSCore
Gem::HttpRequestor
)
# Load the "Gem::AWSClientAuth" module in all types of applications.
ly_create_alias(NAME AWSClientAuth.Servers NAMESPACE Gem TARGETS Gem::AWSClientAuth)
ly_create_alias(NAME AWSClientAuth.Clients NAMESPACE Gem TARGETS Gem::AWSClientAuth)
ly_create_alias(
NAME AWSClientAuth.Servers
NAMESPACE Gem
TARGETS
Gem::AWSClientAuth
Gem::AWSCore.Servers
Gem::HttpRequestor.Servers
)
ly_create_alias(
NAME AWSClientAuth.Clients
NAMESPACE Gem
TARGETS
Gem::AWSClientAuth
Gem::AWSCore.Clients
Gem::HttpRequestor.Clients
)
if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_create_alias(NAME AWSClientAuth.Tools NAMESPACE Gem TARGETS Gem::AWSClientAuth)
ly_create_alias(NAME AWSClientAuth.Builders NAMESPACE Gem TARGETS Gem::AWSClientAuth)
ly_create_alias(
NAME AWSClientAuth.Tools
NAMESPACE Gem
TARGETS
Gem::AWSClientAuth
Gem::AWSCore.Tools
Gem::HttpRequestor.Tools
)
ly_create_alias(
NAME AWSClientAuth.Builders
NAMESPACE Gem
TARGETS
Gem::AWSClientAuth
Gem::AWSCore.Builders
Gem::HttpRequestor.Builders
)
endif()
################################################################################

@ -8,11 +8,15 @@
#pragma once
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/std/string/string.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
namespace AZ
{
class ReflectContext;
}
namespace AWSClientAuth
{
//! Client auth AWS Credentials object for serialization.
@ -54,31 +58,8 @@ namespace AWSClientAuth
return m_sessionToken;
}
static void Reflect(AZ::ReflectContext* context)
{
auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ClientAuthAWSCredentials>()
->Field("AWSAccessKeyId", &ClientAuthAWSCredentials::m_accessKeyId)
->Field("AWSSecretKey", &ClientAuthAWSCredentials::m_secretKey)
->Field("AWSSessionToken", &ClientAuthAWSCredentials::m_sessionToken);
}
static void Reflect(AZ::ReflectContext* context);
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<ClientAuthAWSCredentials>()
->Attribute(AZ::Script::Attributes::Category, "AWSClientAuth")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Constructor()
->Constructor<const ClientAuthAWSCredentials&>()
->Property("AWSAccessKeyId", BehaviorValueGetter(&ClientAuthAWSCredentials::m_accessKeyId), BehaviorValueSetter(&ClientAuthAWSCredentials::m_accessKeyId))
->Property("AWSSecretKey", BehaviorValueGetter(&ClientAuthAWSCredentials::m_secretKey), BehaviorValueSetter(&ClientAuthAWSCredentials::m_secretKey))
->Property("AWSSessionToken", BehaviorValueGetter(&ClientAuthAWSCredentials::m_sessionToken), BehaviorValueSetter(&ClientAuthAWSCredentials::m_sessionToken));
}
}
private:
AZStd::string m_accessKeyId;

@ -0,0 +1,50 @@
/*
* 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 <Authorization/ClientAuthAWSCredentials.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/AzStdOnDemandReflection.inl>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/AZStdContainers.inl>
namespace AWSClientAuth
{
void ClientAuthAWSCredentials::Reflect(AZ::ReflectContext* context)
{
auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ClientAuthAWSCredentials>()
->Field("AWSAccessKeyId", &ClientAuthAWSCredentials::m_accessKeyId)
->Field("AWSSecretKey", &ClientAuthAWSCredentials::m_secretKey)
->Field("AWSSessionToken", &ClientAuthAWSCredentials::m_sessionToken);
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<ClientAuthAWSCredentials>()
->Attribute(AZ::Script::Attributes::Category, "AWSClientAuth")
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Constructor()
->Constructor<const ClientAuthAWSCredentials&>()
->Property(
"AWSAccessKeyId", BehaviorValueGetter(&ClientAuthAWSCredentials::m_accessKeyId),
BehaviorValueSetter(&ClientAuthAWSCredentials::m_accessKeyId))
->Property(
"AWSSecretKey", BehaviorValueGetter(&ClientAuthAWSCredentials::m_secretKey),
BehaviorValueSetter(&ClientAuthAWSCredentials::m_secretKey))
->Property(
"AWSSessionToken", BehaviorValueGetter(&ClientAuthAWSCredentials::m_sessionToken),
BehaviorValueSetter(&ClientAuthAWSCredentials::m_sessionToken));
}
}
} // namespace AWSClientAuth

@ -42,6 +42,7 @@ set(FILES
Source/Authentication/LWAAuthenticationProvider.cpp
Source/Authentication/GoogleAuthenticationProvider.cpp
Source/Authorization/ClientAuthAWSCredentials.cpp
Source/Authorization/AWSCognitoAuthorizationController.cpp
Source/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.cpp

@ -45,8 +45,19 @@ ly_add_target(
)
# clients and servers will use the above Gem::AWSCore module.
ly_create_alias(NAME AWSCore.Servers NAMESPACE Gem TARGETS Gem::AWSCore)
ly_create_alias(NAME AWSCore.Clients NAMESPACE Gem TARGETS Gem::AWSCore)
ly_create_alias(
NAME AWSCore.Servers
NAMESPACE Gem
TARGETS
Gem::AWSCore
)
ly_create_alias(
NAME AWSCore.Clients
NAMESPACE Gem
TARGETS
Gem::AWSCore
)
if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
@ -84,8 +95,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
PRIVATE
AZ::AzCore
Gem::AWSCore.Editor.Static
RUNTIME_DEPENDENCIES
Gem::AWSCore
)
# This target is not a real gem module
@ -106,8 +115,21 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_dependencies(AWSCore.Editor AWSCore.ResourceMappingTool)
# Builders and Tools (such as the Editor use AWSCore.Editor) use the .Editor module above.
ly_create_alias(NAME AWSCore.Tools NAMESPACE Gem TARGETS Gem::AWSCore.Editor)
ly_create_alias(NAME AWSCore.Builders NAMESPACE Gem TARGETS Gem::AWSCore.Editor)
ly_create_alias(
NAME AWSCore.Tools
NAMESPACE Gem
TARGETS
Gem::AWSCore
Gem::AWSCore.Editor
)
ly_create_alias(
NAME AWSCore.Builders
NAMESPACE Gem
TARGETS
Gem::AWSCore
Gem::AWSCore.Editor
)
endif()

@ -45,13 +45,26 @@ ly_add_target(
PUBLIC
Gem::AWSGameLift.Client.Static
RUNTIME_DEPENDENCIES
Gem::AWSCore
Gem::AWSCore.Clients
)
# Load the "Gem::AWSGameLift" module in all types of applications.
if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_create_alias(NAME AWSGameLift.Tools NAMESPACE Gem TARGETS Gem::AWSGameLift.Clients)
ly_create_alias(NAME AWSGameLift.Builders NAMESPACE Gem TARGETS Gem::AWSGameLift.Clients)
ly_create_alias(
NAME AWSGameLift.Tools
NAMESPACE Gem
TARGETS
Gem::AWSCore.Tools
Gem::AWSGameLift.Clients
)
ly_create_alias(
NAME AWSGameLift.Builders
NAMESPACE Gem
TARGETS
Gem::AWSCore.Builders
Gem::AWSGameLift.Clients
)
endif()
################################################################################

@ -40,16 +40,41 @@ ly_add_target(
AZ::AzCore
AZ::AzFramework
Gem::AWSMetrics.Static
RUNTIME_DEPENDENCIES
Gem::AWSCore
)
# Load the "Gem::AWSMetrics" module in all types of applications.
ly_create_alias(NAME AWSMetrics.Servers NAMESPACE Gem TARGETS Gem::AWSMetrics)
ly_create_alias(NAME AWSMetrics.Clients NAMESPACE Gem TARGETS Gem::AWSMetrics)
ly_create_alias(
NAME AWSMetrics.Servers
NAMESPACE Gem
TARGETS
Gem::AWSCore.Servers
Gem::AWSMetrics
)
ly_create_alias(
NAME AWSMetrics.Clients
NAMESPACE Gem
TARGETS
Gem::AWSCore.Clients
Gem::AWSMetrics
)
if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_create_alias(NAME AWSMetrics.Tools NAMESPACE Gem TARGETS Gem::AWSMetrics)
ly_create_alias(NAME AWSMetrics.Builders NAMESPACE Gem TARGETS Gem::AWSMetrics)
ly_create_alias(
NAME AWSMetrics.Tools
NAMESPACE Gem
TARGETS
Gem::AWSCore.Tools
Gem::AWSMetrics
)
ly_create_alias(
NAME AWSMetrics.Builders
NAMESPACE Gem
TARGETS
Gem::AWSCore.Builders
Gem::AWSMetrics
)
endif()
################################################################################

@ -14,11 +14,11 @@
#include <AzCore/std/string/regex.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
@ -56,7 +56,7 @@ namespace AZ
m_predefinedMacros.begin(), m_predefinedMacros.end(),
[&](const AZStd::string& predefinedMacro) {
// Haystack, needle, bCaseSensitive
if (!AzFramework::StringFunc::StartsWith(predefinedMacro, macroName, true))
if (!AZ::StringFunc::StartsWith(predefinedMacro, macroName, true))
{
return false;
}
@ -117,11 +117,11 @@ namespace AZ
char localBuffer[DefaultFprintfBufferSize];
va_list args;
va_start(args, format);
int count = azvsnprintf(localBuffer, DefaultFprintfBufferSize, format, args);
va_end(args);
char* result = localBuffer;
// @result will be bound to @biggerData in case @localBuffer is not big enough.
@ -134,7 +134,7 @@ namespace AZ
count++; // vsnprintf returns a size that doesn't include the null character.
biggerData.reset(new char[count]);
result = &biggerData[0];
// Remark: for MacOS & Linux it is important to call va_start again before
// each call to azvsnprintf. Not required for Windows.
va_start(args, format);
@ -149,7 +149,7 @@ namespace AZ
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l?view=msvc-160
// In particular: "If the number of characters to write is greater than count,
// these functions return -1 indicating that output has been truncated."
// There wasn't enough space in the local store.
// Remark: for MacOS & Linux it is important to call va_start again before
// each call to azvsnprintf. Not required for Windows.
@ -157,10 +157,10 @@ namespace AZ
count = azvscprintf(format, args);
count += 1; // vscprintf returns a size that doesn't include the null character.
va_end(args);
biggerData.reset(new char[count]);
result = &biggerData[0];
va_start(args, format);
count = azvsnprintf(result, count, format, args);
va_end(args);
@ -191,7 +191,7 @@ namespace AZ
// definitions for the linker
AZStd::mutex McppBinder::s_mcppExclusiveProtection;
McppBinder* McppBinder::s_currentInstance = nullptr;
McppBinder* McppBinder::s_currentInstance = nullptr;
// McppBinder ends
///////////////////////////////////////////////////////////////////////
@ -204,7 +204,7 @@ namespace AZ
// create the argc/argv
const char* processName = "builder";
const char* inputPath = fullPath.c_str();
const char* inputPath = fullPath.c_str();
// let's create the equivalent of that expression but in dynamic form:
//const char* argv[] = { processName, szInPath, "-C", "-+", "-D macro1"..., "-I path"..., NULL };
AZStd::vector< const char* > argv;
@ -230,7 +230,7 @@ namespace AZ
argv.push_back(nullptr); // usual argv terminator
// output the command line:
AZStd::string stringifiedCommandLine;
AzFramework::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end() - 1, " ");
AZ::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end() - 1, " ");
AZ_TracePrintf("Preprocessor", "%s", stringifiedCommandLine.c_str());
// when we don't specify an -o outfile, mcpp uses stdout.
// the trick is that since we hijacked putc & puts, stdout will not be written.
@ -238,17 +238,12 @@ namespace AZ
return result;
}
static void VerifySameFolder(const AZStd::string& path1, const AZStd::string& path2)
static void VerifySameFolder([[maybe_unused]] AZStd::string_view path1, [[maybe_unused]] AZStd::string_view path2)
{
AZStd::string folder1, folder2;
AzFramework::StringFunc::Path::GetFolderPath(path1.c_str(), folder1);
AzFramework::StringFunc::Path::GetFolderPath(path2.c_str(), folder2);
AzFramework::StringFunc::Path::Normalize(folder1);
AzFramework::StringFunc::Path::Normalize(folder2);
AZ_Warning("Preprocessing",
folder1 == folder2,
"The preprocessed file %s is in a different folder than its origin %s. Watch for #include problems with relative paths.",
path1.c_str(), path2.c_str()
AZ::IO::PathView(path1).ParentPath().LexicallyNormal() == AZ::IO::PathView(path2).ParentPath().LexicallyNormal(),
"The preprocessed file %.*s is in a different folder than its origin %.*s. Watch for #include problems with relative paths.",
AZ_STRING_ARG(path1), AZ_STRING_ARG(path2)
);
}
@ -260,7 +255,7 @@ namespace AZ
// containing file names, to match the ORIGINAL source, and not the actual source in use by azslc.
// That gymnastic is better for error messages anyway, so instead of making the SRG layout builder more intelligent,
// we'll fake the origin of the file, by setting the original source as a filename
// note that it is not possible to build a file in a different folder and fake it to a file eslewhere because relative includes will fail.
// note that it is not possible to build a file in a different folder and fake it to a file elsewhere because relative includes will fail.
void MutateLineDirectivesFileOrigin(
AZStd::string& sourceCode,
AZStd::string newFileOrigin)
@ -272,11 +267,11 @@ namespace AZ
// we will use that as the information of the source path to mutate.
if (sourceCode.starts_with("#line"))
{
auto firstQuote = sourceCode.find('"');
auto secondQuote = sourceCode.find('"', firstQuote + 1);
auto firstQuote = sourceCode.find('"');
auto secondQuote = firstQuote != AZStd::string::npos ? sourceCode.find('"', firstQuote + 1) : AZStd::string::npos;
auto originalFile = sourceCode.substr(firstQuote + 1, secondQuote - firstQuote - 1); // start +1, count -1 because we don't want the quotes included.
VerifySameFolder(originalFile, newFileOrigin);
[[maybe_unused]] bool didReplace = AzFramework::StringFunc::Replace(sourceCode, originalFile.c_str(), newFileOrigin.c_str(), true /*case sensitive*/);
[[maybe_unused]] bool didReplace = AZ::StringFunc::Replace(sourceCode, originalFile.c_str(), newFileOrigin.c_str(), true /*case sensitive*/);
AZ_Assert(didReplace, "Failed to replace %s for %s in preprocessed source.", originalFile.c_str(), newFileOrigin.c_str());
}
else
@ -285,26 +280,6 @@ namespace AZ
}
}
namespace
{
template< typename Container1, typename Container2 >
void TransferContent(Container1& destination, Container2&& source)
{
destination.insert(AZStd::end(destination),
AZStd::make_move_iterator(AZStd::begin(source)),
AZStd::make_move_iterator(AZStd::end(source)));
}
void DeleteFromSet(const AZStd::string& string, AZStd::set<AZStd::string>& set)
{
auto iter = set.find(string);
if (iter != set.end())
{
set.erase(iter);
}
}
}
// populate options with scan folders and contents of parsing shader_global_build_options.json
void InitializePreprocessorOptions(
PreprocessorOptions& options, [[maybe_unused]] const char* builderName, const char* optionalIncludeFolder)
@ -315,44 +290,61 @@ namespace AZ
bool success = true;
AZStd::vector<AZStd::string> scanFoldersVector;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(success,
&AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
scanFoldersVector);
&AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
scanFoldersVector);
AZ_Warning(builderName, success, "Preprocessor option: Could not acquire a list of scan folders from the database.");
// we transfer to a set, to order the folders, uniquify them, and ensure deterministic build behavior
AZStd::set<AZStd::string> scanFoldersSet;
// Add the project path to list of include paths
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
scanFoldersSet.emplace(projectPath.c_str(), projectPath.size());
AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
auto FindPath = [](AZ::IO::PathView searchPath)
{
return [searchPath](AZStd::string_view includePathView)
{
return searchPath == AZ::IO::PathView(includePathView);
};
};
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(projectPath));
it == options.m_projectIncludePaths.end())
{
options.m_projectIncludePaths.emplace_back(projectPath.c_str(), projectPath.Native().size());
}
if (optionalIncludeFolder)
{
scanFoldersSet.emplace(optionalIncludeFolder, strnlen(optionalIncludeFolder, AZ::IO::MaxPathLength));
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(optionalIncludeFolder));
it == options.m_projectIncludePaths.end())
{
if (AZ::IO::SystemFile::Exists(optionalIncludeFolder))
{
options.m_projectIncludePaths.emplace_back(AZStd::move(AZ::IO::Path(optionalIncludeFolder).LexicallyNormal().Native()));
}
}
}
// but while we transfer to the set, we're going to keep only folders where +/ShaderLib exists
for (AZStd::string folder : scanFoldersVector)
for (AZ::IO::Path shaderScanFolder : scanFoldersVector)
{
AzFramework::StringFunc::Path::Join(folder.c_str(), "ShaderLib", folder);
if (AZ::IO::SystemFile::Exists(folder.c_str()))
shaderScanFolder /= "ShaderLib";
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(shaderScanFolder));
it == options.m_projectIncludePaths.end())
{
scanFoldersSet.emplace(std::move(folder));
// the folders constructed this fashion constitute the base of automatic include search paths
if (AZ::IO::SystemFile::Exists(shaderScanFolder.c_str()))
{
options.m_projectIncludePaths.emplace_back(AZStd::move(shaderScanFolder.LexicallyNormal().Native()));
}
}
} // the folders constructed this fashion constitute the base of automatic include search paths
// get the engine root:
AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath();
}
// add optional additional options
for (AZStd::string& path : options.m_projectIncludePaths)
// finally the <engineroot>/Gems fallback
AZ::IO::Path engineGemsFolder(AZStd::string_view{ AZ::Utils::GetEnginePath() });
engineGemsFolder /= "Gems";
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(engineGemsFolder));
it == options.m_projectIncludePaths.end())
{
path = (engineRoot / path).String();
DeleteFromSet(path, scanFoldersSet); // no need to add a path two times.
if (AZ::IO::SystemFile::Exists(engineGemsFolder.c_str()))
{
options.m_projectIncludePaths.emplace_back(AZStd::move(engineGemsFolder.Native()));
}
}
// back-insert the default paths (after the config-read paths we just read)
TransferContent(/*to:*/options.m_projectIncludePaths, /*from:*/scanFoldersSet);
// finally the <engineroot>/Gems fallback
AZStd::string gemsFolder;
AzFramework::StringFunc::Path::Join(engineRoot.c_str(), "Gems", gemsFolder);
options.m_projectIncludePaths.push_back(gemsFolder);
}
} // namespace ShaderBuilder

@ -253,34 +253,6 @@ namespace AZ
RPI::SceneDescriptor sceneDesc;
AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc);
atomScene->EnableAllFeatureProcessors();
// Setup scene srg modification callback.
RPI::ShaderResourceGroupCallback callback = [this](RPI::ShaderResourceGroup* srg)
{
if (srg == nullptr)
{
return;
}
bool needCompile = false;
RHI::ShaderInputConstantIndex timeIndex = srg->FindShaderInputConstantIndex(Name{ "m_time" });
if (timeIndex.IsValid())
{
srg->SetConstant(timeIndex, m_simulateTime);
needCompile = true;
}
RHI::ShaderInputConstantIndex deltaTimeIndex = srg->FindShaderInputConstantIndex(Name{ "m_deltaTime" });
if (deltaTimeIndex.IsValid())
{
srg->SetConstant(deltaTimeIndex, m_deltaTime);
needCompile = true;
}
if (needCompile)
{
srg->Compile();
}
};
atomScene->SetShaderResourceGroupCallback(callback);
atomScene->Activate();
// Register scene to RPI system so it will be processed/rendered per tick
@ -408,11 +380,8 @@ namespace AZ
m_renderPipelineId = "";
}
void BootstrapSystemComponent::OnTick(float deltaTime, [[maybe_unused]] ScriptTimePoint time)
void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
{
m_simulateTime += deltaTime;
m_deltaTime = deltaTime;
// Temp: When running in the launcher without the legacy renderer
// we need to call RenderTick on the viewport context each frame.
if (m_viewportContext)

@ -105,9 +105,6 @@ namespace AZ
RPI::ScenePtr m_defaultScene = nullptr;
AZStd::shared_ptr<AzFramework::Scene> m_defaultFrameworkScene = nullptr;
float m_simulateTime = 0;
float m_deltaTime = 0.016f;
bool m_isAssetCatalogLoaded = false;
// The id of the render pipeline created by this component

@ -11,6 +11,6 @@
// Please review README.md to understand how this file is used in SceneSrg.azsrg generation
#ifdef AZ_COLLECTING_PARTIAL_SRGS
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/SceneTimeSrg.azsli>
#include <Atom/RPI/ShaderResourceGroups/DefaultSceneSrg.azsli>
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/SceneSrg.azsli>
#endif

@ -78,10 +78,12 @@ void MainCS(uint3 dispatch_id : SV_DispatchThreadID)
const float speed = exposureDifference > 0.0 ? ViewSrg::m_exposureControl.m_speedUp : ViewSrg::m_exposureControl.m_speedDown;
// Update the adjustment for this frame based on the frame deltaTime and speed
float exposureAdjustment = exposureDifference * SceneSrg::m_deltaTime * speed;
float deltaTime = clamp(SceneSrg::m_time - PassSrg::m_eyeAdaptationData[0].m_setValueTime, 0.0f, 1.0f);
float exposureAdjustment = exposureDifference * deltaTime * speed;
float newExposureLog2 = previousFrameExposureLog2 + exposureAdjustment;
// Store the linear exposure so it can be used by the look modification transform later.
// newExposureLog2 is negated because m_exposureValue is used to correct for a given exposure.
PassSrg::m_eyeAdaptationData[0].m_exposureValue = pow(2.0f, -newExposureLog2);
PassSrg::m_eyeAdaptationData[0].m_setValueTime = SceneSrg::m_time;
}

@ -8,5 +8,6 @@
struct EyeAdaptation
{
float m_exposureValue; // current frame's exposure value in stops (logarithmic space)
float m_exposureValue; // current frame's exposure value in stops (logarithmic space)
float m_setValueTime; // the time when the m_exposureValue was set
};

@ -289,7 +289,6 @@ set(FILES
ShaderLib/Atom/Features/Vertex/VertexHelper.azsli
ShaderResourceGroups/SceneSrg.azsli
ShaderResourceGroups/SceneSrgAll.azsli
ShaderResourceGroups/SceneTimeSrg.azsli
ShaderResourceGroups/ViewSrg.azsli
ShaderResourceGroups/ViewSrgAll.azsli
ShaderResourceGroups/CoreLights/SceneSrg.azsli

@ -12,6 +12,7 @@
#include <Atom/RHI/Buffer.h>
#include <Atom/RHI/BufferPool.h>
#include <Atom/RPI.Public/FeatureProcessor.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
namespace AZ
@ -36,8 +37,6 @@ namespace AZ
void Activate() override;
//! Releases GPU resources.
void Deactivate() override;
//! Binds buffers
void Render(const FeatureProcessor::RenderPacket& packet) override;
// RPI::SceneNotificationBus overrides ...
void OnBeginPrepareRender() override;
@ -68,11 +67,13 @@ namespace AZ
// Prepare GPU buffers for object transformation matrices
// Create the buffers if they don't exist. Otherwise, resize them if they are not large enough for the matrices
void PrepareBuffers();
Data::Instance<RPI::ShaderResourceGroup> m_sceneSrg;
RHI::ShaderInputBufferIndex m_objectToWorldBufferIndex;
RHI::ShaderInputBufferIndex m_objectToWorldInverseTransposeBufferIndex;
RHI::ShaderInputBufferIndex m_objectToWorldHistoryBufferIndex;
void UpdateSceneSrg(RPI::ShaderResourceGroup *sceneSrg);
RPI::Scene::PrepareSceneSrgEvent::Handler m_updateSceneSrgHandler;
RHI::ShaderInputNameIndex m_objectToWorldBufferIndex = "m_objectToWorldBuffer";
RHI::ShaderInputNameIndex m_objectToWorldInverseTransposeBufferIndex = "m_objectToWorldInverseTransposeBuffer";
RHI::ShaderInputNameIndex m_objectToWorldHistoryBufferIndex = "m_objectToWorldHistoryBuffer";
// Stores transforms that are uploaded to a GPU buffer. Used slots have float12(matrix3x4) values, empty slots
// have a uint32_t that points to the next empty slot like a linked list. m_firstAvailableMeshTransformIndex stores the first

@ -479,8 +479,6 @@ namespace AZ
: m_modelAsset(modelAsset)
, m_parent(parent)
{
AZ_PROFILE_FUNCTION(AzRender);
if (!m_modelAsset.GetId().IsValid())
{
AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id.");
@ -508,7 +506,6 @@ namespace AZ
//! AssetBus::Handler overrides...
void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
AZ_PROFILE_FUNCTION(AzRender);
Data::Asset<RPI::ModelAsset> modelAsset = asset;
// Assign the fully loaded asset back to the mesh handle to not only hold asset id, but the actual data as well.
@ -580,8 +577,6 @@ namespace AZ
void MeshDataInstance::Init(Data::Instance<RPI::Model> model)
{
AZ_PROFILE_FUNCTION(AzRender);
m_model = model;
const size_t modelLodCount = m_model->GetLodCount();
m_drawPacketListsByLod.resize(modelLodCount);
@ -612,8 +607,6 @@ namespace AZ
void MeshDataInstance::BuildDrawPacketList(size_t modelLodIndex)
{
AZ_PROFILE_FUNCTION(AzRender);
RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex];
const size_t meshCount = modelLod.GetMeshes().size();

@ -36,8 +36,6 @@ namespace AZ
m_viewPtr = view;
m_viewSrg = view->GetShaderResourceGroup();
m_exposureControlBufferInputIndex = m_viewSrg->FindShaderInputBufferIndex(Name("m_exposureControl"));
m_eyeAdaptationBuffer.Init(m_viewSrg, idNumber);
}
@ -109,14 +107,10 @@ namespace AZ
m_eyeAdaptationBuffer.UpdateSrg();
if (m_exposureControlBufferInputIndex.IsValid())
m_viewSrg->SetBufferView(m_exposureControlBufferInputIndex, m_buffer->GetBufferView());
if (m_viewPtr)
{
m_viewSrg->SetBufferView(m_exposureControlBufferInputIndex, m_buffer->GetBufferView());
if (m_viewPtr)
{
m_viewPtr->InvalidateSrg();
}
m_viewPtr->InvalidateSrg();
}
}

@ -52,6 +52,7 @@ namespace AZ
struct ExposureCalculationData
{
float m_exposureValue = 1.0f;
float m_setValueTime = 0;
};
void BuildInternal() override;

@ -36,11 +36,8 @@ namespace AZ
void TransformServiceFeatureProcessor::Activate()
{
m_sceneSrg = GetParentScene()->GetShaderResourceGroup();
m_objectToWorldBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldBuffer"});
m_objectToWorldInverseTransposeBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldInverseTransposeBuffer"});
m_objectToWorldHistoryBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldHistoryBuffer"});
m_updateSceneSrgHandler = RPI::Scene::PrepareSceneSrgEvent::Handler([this](RPI::ShaderResourceGroup *sceneSrg) { this->UpdateSceneSrg(sceneSrg); });
GetParentScene()->ConnectEvent(m_updateSceneSrgHandler);
m_deviceBufferNeedsUpdate = true;
m_objectToWorldTransforms.reserve(BufferReserveCount);
@ -62,9 +59,14 @@ namespace AZ
m_firstAvailableTransformIndex = NoAvailableTransformIndices;
m_objectToWorldBufferIndex.Reset();
m_objectToWorldInverseTransposeBufferIndex.Reset();
m_objectToWorldHistoryBufferIndex.Reset();
m_isWriteable = false;
RPI::SceneNotificationBus::Handler::BusDisconnect();
m_updateSceneSrgHandler.Disconnect();
}
void TransformServiceFeatureProcessor::PrepareBuffers()
@ -131,16 +133,11 @@ namespace AZ
}
}
void TransformServiceFeatureProcessor::Render([[maybe_unused]] const FeatureProcessor::RenderPacket& packet)
void TransformServiceFeatureProcessor::UpdateSceneSrg(RPI::ShaderResourceGroup *sceneSrg)
{
AZ_ATOM_PROFILE_FUNCTION("RPI", "TransformServiceFeatureProcessor: Render");
AZ_UNUSED(packet);
AZ_Assert(!m_isWriteable, "Must be called between OnBeginPrepareRender() and OnEndPrepareRender()");
m_sceneSrg->SetBufferView(m_objectToWorldBufferIndex, m_objectToWorldBuffer->GetBufferView());
m_sceneSrg->SetBufferView(m_objectToWorldInverseTransposeBufferIndex, m_objectToWorldInverseTransposeBuffer->GetBufferView());
m_sceneSrg->SetBufferView(m_objectToWorldHistoryBufferIndex, m_objectToWorldHistoryBuffer->GetBufferView());
sceneSrg->SetBufferView(m_objectToWorldBufferIndex, m_objectToWorldBuffer->GetBufferView());
sceneSrg->SetBufferView(m_objectToWorldInverseTransposeBufferIndex, m_objectToWorldInverseTransposeBuffer->GetBufferView());
sceneSrg->SetBufferView(m_objectToWorldHistoryBufferIndex, m_objectToWorldHistoryBuffer->GetBufferView());
}
void TransformServiceFeatureProcessor::OnBeginPrepareRender()

@ -42,6 +42,7 @@ ly_add_target(
FILES_CMAKE
atom_rhi_public_files.cmake
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
${pal_source_dir}/platform_private_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source

@ -50,24 +50,21 @@ namespace AZ
class RayTracingPipelineState;
class RayTracingShaderTable;
/* Priority of a Factory. The lower the number the higher the priority.
* Used when there's multiple factories available and the user hasn't define
* a priority.
*/
//! Priority of a Factory. The lower the number the higher the priority.
//! Used when there's multiple factories available and the user hasn't define
//! a priority.
using APIPriority = uint32_t;
static const APIPriority APITopPriority = 1;
static const APIPriority APILowPriority = 10;
static const APIPriority APIMiddlePriority = (APILowPriority - APITopPriority) / 2;
/**
* The factory is an interface for creating RHI data structures. The platform system should
* register itself with the factory by calling Register, and unregister on shutdown with
* Unregister.
*
* A call to Get will return the active instance. In the event that it's unclear whether
* a platform instance exists, you must call IsReady to determine whether it's safe to
* call Get. Calling Get without a registered platform will result in an assert.
*/
//! The factory is an interface for creating RHI data structures. The platform system should
//! register itself with the factory by calling Register, and unregister on shutdown with
//! Unregister.
//!
//! A call to Get will return the active instance. In the event that it's unclear whether
//! a platform instance exists, you must call IsReady to determine whether it's safe to
//! call Get. Calling Get without a registered platform will result in an assert.
class Factory
{
public:
@ -79,78 +76,78 @@ namespace AZ
// Note that you have to delete these for safety reasons, you will trip a static_assert if you do not
AZ_DISABLE_COPY_MOVE(Factory);
/// Returns the component service name CRC used by the platform RHI system component.
//! Returns the component service name CRC used by the platform RHI system component.
static uint32_t GetComponentService();
/// Returns the component service name CRC used by the Factory manager component.
//! Returns the component service name CRC used by the Factory manager component.
static uint32_t GetManagerComponentService();
/// Returns the component service name CRC used by the platform RHI system component.
//! Returns the component service name CRC used by the platform RHI system component.
static uint32_t GetPlatformService();
/// Registers the global factory instance.
//! Registers the global factory instance.
static void Register(Factory* instance);
/// Unregisters the global factory instance.
//! Unregisters the global factory instance.
static void Unregister(Factory* instance);
/// Returns whether the factory is initialized and active in this module.
//! Returns whether the factory is initialized and active in this module.
static bool IsReady();
/// Access the global factory instance.
//! Access the global factory instance.
static Factory& Get();
#if defined(USE_RENDERDOC)
/// Access the RenderDoc API pointer if available.
/// The availability of the render doc API at runtime depends on the following:
/// - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake)
/// - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable
/// - The module loaded successfully at runtime, and the API function pointer was retrieved successfully
//! Access the RenderDoc API pointer if available.
//! The availability of the render doc API at runtime depends on the following:
//! - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake)
//! - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable
//! - The module loaded successfully at runtime, and the API function pointer was retrieved successfully
static RENDERDOC_API_1_1_2* GetRenderDocAPI();
#endif
//! Returns true if RenderDoc dll is loaded
static bool IsRenderDocModuleLoaded();
/// Returns the name of the Factory.
//! Returns true if Pix dll is loaded
static bool IsPixModuleLoaded();
//! Returns the name of the Factory.
virtual Name GetName() = 0;
/// Returns the APIType of the factory.
//! Returns the APIType of the factory.
virtual APIType GetType() = 0;
/// Returns the default priority of the factory in case there's no priorities set in the FactoryManager.
//! Returns the default priority of the factory in case there's no priorities set in the FactoryManager.
virtual APIPriority GetDefaultPriority() = 0;
/**
* Purpose: The API Unique Index will be encoded in the 2 Most Significant Bits of a ShaderVariantAsset ProductSubId (a 32bits integer).
* Returns a number in the range [0..3].
* In theory any given AssetBuilderSdk::PlatformInfo can support several RHI::APITypes.
* In reality "pc" only supports DX12 & Vulkan.
* "ios" supports only Metal.
* "mac" supports only Metal.
* "android" supports only Vulkan.
* So, for all practical purposes, a single PlatformInfo won't support more than 2 ShaderPlatformInterfaces, but for the sake of
* hedging our bets into the future We assume no more than 4 ShaderPlatformInterfaces will ever be supported for any given PlatformInfo.
* REMARK: It is the responsibility of the Factory subclass to return a unique number between 0...3.
* For example DX12 can return 0, while Vulkan should return 1 (Satisfies "pc", "android" and "linux").
* Metal can return 0 because it is the only ShaderPlatformInterface for "ios", "mac" and "appletv".
* See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
*/
//! Purpose: The API Unique Index will be encoded in the 2 Most Significant Bits of a ShaderVariantAsset ProductSubId (a 32bits integer).
//! Returns a number in the range [0..3].
//! In theory any given AssetBuilderSdk::PlatformInfo can support several RHI::APITypes.
//! In reality "pc" only supports DX12 & Vulkan.
//! "ios" supports only Metal.
//! "mac" supports only Metal.
//! "android" supports only Vulkan.
//! So, for all practical purposes, a single PlatformInfo won't support more than 2 ShaderPlatformInterfaces, but for the sake of
//! hedging our bets into the future We assume no more than 4 ShaderPlatformInterfaces will ever be supported for any given PlatformInfo.
//! REMARK: It is the responsibility of the Factory subclass to return a unique number between 0...3.
//! For example DX12 can return 0, while Vulkan should return 1 (Satisfies "pc", "android" and "linux").
//! Metal can return 0 because it is the only ShaderPlatformInterface for "ios", "mac" and "appletv".
//! See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
virtual uint32_t GetAPIUniqueIndex() const = 0;
/**
* Collects the set of physical devices on the system and returns a list of them. Physical
* devices represent the hardware attached to the system. Physical devices can be grouped
* into nodes for linked setups (e.g. SLI / Crossfire). They can also represent software
* reference implementations. Check the PhysicalDeviceType on the descriptor to inspect
* this information.
*/
//! Collects the set of physical devices on the system and returns a list of them. Physical
//! devices represent the hardware attached to the system. Physical devices can be grouped
//! into nodes for linked setups (e.g. SLI / Crossfire). They can also represent software
//! reference implementations. Check the PhysicalDeviceType on the descriptor to inspect
//! this information.
virtual PhysicalDeviceList EnumeratePhysicalDevices() = 0;
/**
* Factory Creation Methods:
*
* Returns the platform-specific derived variant of the RHI type. All instances are created
* in an uninitialized state; the operation simply allocates the memory for the appropriate
* platform type and returns the pointer.
*/
//! Factory Creation Methods:
//!
//! Returns the platform-specific derived variant of the RHI type. All instances are created
//! in an uninitialized state; the operation simply allocates the memory for the appropriate
//! platform type and returns the pointer.
virtual Ptr<Buffer> CreateBuffer() = 0;

@ -0,0 +1,11 @@
#
# 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
#
#
set(FILES
../Common/Unimplemented/Empty_Unimplemented.cpp
)

@ -0,0 +1,21 @@
/*
* 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/string/string.h>
namespace AZ::RHI::Platform
{
bool IsPixDllInjected([[maybe_unused]] const char* dllName)
{
return false;
}
AZStd::wstring GetLatestWinPixGpuCapturerPath()
{
return L"";
}
}

@ -0,0 +1,11 @@
#
# 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
#
#
set(FILES
../Common/Unimplemented/Empty_Unimplemented.cpp
)

@ -0,0 +1,11 @@
#
# 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
#
#
set(FILES
../Common/Unimplemented/Empty_Unimplemented.cpp
)

@ -8,3 +8,4 @@
#pragma once
#define AZ_TRAIT_RENDERDOC_MODULE "renderdoc.dll"
#define AZ_TRAIT_PIX_MODULE "WinPixGpuCapturer.dll"

@ -0,0 +1,59 @@
/*
* 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 <filesystem>
#include <shlobj.h>
#include <AzCore/base.h>
#include <AzCore/std/string/string.h>
namespace AZ::RHI::Platform
{
bool IsPixDllInjected(const char* dllName)
{
bool isDllLoaded = false;
wchar_t fileNameW[256];
size_t numCharsConverted;
errno_t wcharResult = mbstowcs_s(&numCharsConverted, fileNameW, dllName, AZ_ARRAY_SIZE(fileNameW) - 1);
if (wcharResult == 0)
{
isDllLoaded = NULL != GetModuleHandleW(fileNameW);
}
return isDllLoaded;
}
AZStd::wstring GetLatestWinPixGpuCapturerPath()
{
LPWSTR programFilesPath = nullptr;
SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &programFilesPath);
std::filesystem::path pixInstallationPath = programFilesPath;
pixInstallationPath /= "Microsoft PIX";
std::wstring newestVersionFound;
for (auto const& directory_entry : std::filesystem::directory_iterator(pixInstallationPath))
{
if (directory_entry.is_directory())
{
if (newestVersionFound.empty() || newestVersionFound < directory_entry.path().filename().c_str())
{
newestVersionFound = directory_entry.path().filename().c_str();
}
}
}
if (newestVersionFound.empty())
{
return L"";
}
std::wstring finalPath = pixInstallationPath / newestVersionFound / L"WinPixGpuCapturer.dll";
return AZStd::wstring(finalPath.c_str());
}
}

@ -0,0 +1,11 @@
#
# 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
#
#
set(FILES
RHI/Factory_windows.cpp
)

@ -0,0 +1,11 @@
#
# 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
#
#
set(FILES
../Common/Unimplemented/Empty_Unimplemented.cpp
)

@ -11,20 +11,33 @@
#include <AzCore/Interface/Interface.h>
#include <AzCore/Component/TickBus.h>
#if defined(USE_RENDERDOC)
#if defined(USE_RENDERDOC) || defined(USE_PIX)
#include <AzCore/Module/DynamicModuleHandle.h>
#include <Atom/RHI/RHIUtils.h>
#include <Atom_RHI_Traits_Platform.h>
#endif
#if defined(USE_RENDERDOC)
static AZStd::unique_ptr<AZ::DynamicModuleHandle> s_renderDocModule;
static RENDERDOC_API_1_1_2* s_renderDocApi = nullptr;
static bool s_isRenderDocDllLoaded = false;
#endif
#if defined(USE_PIX)
static AZStd::unique_ptr<AZ::DynamicModuleHandle> s_pixModule;
static bool s_isPixGpuCaptureDllLoaded = false;
#endif
namespace AZ
{
namespace RHI
{
namespace Platform
{
bool IsPixDllInjected(const char* dllName);
AZStd::wstring GetLatestWinPixGpuCapturerPath();
}
uint32_t Factory::GetComponentService()
{
return AZ_CRC("RHIService", 0x45d8e053);
@ -53,6 +66,7 @@ namespace AZ
{
if (s_renderDocModule->Load(false))
{
s_isRenderDocDllLoaded = true;
pRENDERDOC_GetAPI renderDocGetAPI = s_renderDocModule->GetFunction<pRENDERDOC_GetAPI>("RENDERDOC_GetAPI");
if (renderDocGetAPI)
{
@ -78,8 +92,30 @@ namespace AZ
}
}
}
#endif // defined(USE_RENDERDOC)
#endif
#if defined(USE_PIX)
// If GPU capture is requested, we need to load the pix library as early as possible (before device queries/factories are made)
bool enablePixGPU = RHI::QueryCommandLineOption("enablePixGPU");
if (enablePixGPU && AZ_TRAIT_PIX_MODULE && !s_pixModule)
{
//Get the path to the latest pix install directory
AZStd::wstring pixGpuDllPath = Platform::GetLatestWinPixGpuCapturerPath();
AZStd::string dllPath;
AZStd::to_string(dllPath, pixGpuDllPath);
s_pixModule = DynamicModuleHandle::Create(dllPath.c_str());
if (s_pixModule)
{
if (!s_pixModule->Load(false))
{
AZ_Printf("RHISystem", "Pix capture requested but module failed to load.\n");
}
}
}
//Pix dll can still be injected even if we do not pass in enablePixGPU. This can be done if we launch the app from Pix.
s_isPixGpuCaptureDllLoaded = Platform::IsPixDllInjected(AZ_TRAIT_PIX_MODULE);
#endif
}
void Factory::Register(Factory* instance)
@ -116,6 +152,12 @@ namespace AZ
{
s_renderDocModule->Unload();
}
#endif
#if defined(USE_PIX)
if (s_pixModule)
{
s_pixModule->Unload();
}
#endif
}
@ -137,5 +179,23 @@ namespace AZ
return s_renderDocApi;
}
#endif
bool Factory::IsRenderDocModuleLoaded()
{
#if defined(USE_RENDERDOC)
return s_isRenderDocDllLoaded;
#else
return false;
#endif
}
bool Factory::IsPixModuleLoaded()
{
#if defined(USE_PIX)
return s_isPixGpuCaptureDllLoaded;
#else
return false;
#endif
}
}
}

@ -417,7 +417,6 @@ namespace AZ
void FrameScheduler::ExecuteContextInternal(FrameGraphExecuteGroup& group, uint32_t index)
{
AZ_PROFILE_FUNCTION(RHI);
FrameGraphExecuteContext* executeContext = group.BeginContext(index);
{

@ -278,8 +278,6 @@ namespace AZ
const PipelineState* PipelineStateCache::AcquirePipelineState(PipelineLibraryHandle handle, const PipelineStateDescriptor& descriptor)
{
AZ_PROFILE_FUNCTION(RHI);
if (handle.IsNull())
{
return nullptr;

@ -258,6 +258,14 @@ namespace AZ
return RHI::ResultCode::Success;
}
RHI::ResultCode Device::CreateSwapChain(
[[maybe_unused]] const DXGI_SWAP_CHAIN_DESCX& swapChainDesc,
[[maybe_unused]] AZStd::array<RHI::Ptr<ID3D12Resource>, RHI::Limits::Device::FrameCountMax>& outSwapChainResources)
{
AZ_Assert(false, "Wrong Device::CreateSwapChain function called on Windows.");
return RHI::ResultCode::Fail;
}
AZStd::vector<RHI::Format> Device::GetValidSwapChainImageFormats(const RHI::WindowHandle& windowHandle) const
{
AZStd::vector<RHI::Format> formatsList;
@ -317,5 +325,10 @@ namespace AZ
return formatsList;
}
void Device::BeginFrameInternal()
{
m_commandQueueContext.Begin();
}
}
}

@ -0,0 +1,10 @@
/*
* 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 <RHI/SwapChain_Windows.h>

@ -5,15 +5,28 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <RHI/SwapChain.h>
#include <RHI/SwapChain_Windows.h>
#include <RHI/Device.h>
#include <RHI/Conversions.h>
#include <RHI/Image.h>
#include <RHI/NsightAftermath.h>
namespace AZ
{
namespace DX12
{
RHI::Ptr<SwapChain> SwapChain::Create()
{
return aznew SwapChain();
}
Device& SwapChain::GetDevice() const
{
return static_cast<Device&>(RHI::SwapChain::GetDevice());
}
RHI::ResultCode SwapChain::InitInternal(RHI::Device& deviceBase, const RHI::SwapChainDescriptor& descriptor, RHI::SwapChainDimensions* nativeDimensions)
{
// Check whether tearing support is available for full screen borderless windowed mode.
@ -165,6 +178,47 @@ namespace AZ
return GetCurrentImageIndex();
}
RHI::ResultCode SwapChain::InitImageInternal(const InitImageRequest& request)
{
Device& device = GetDevice();
Microsoft::WRL::ComPtr<ID3D12Resource> resource;
DX12::AssertSuccess(m_swapChain->GetBuffer(request.m_imageIndex, IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf())));
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo;
device.GetImageAllocationInfo(request.m_descriptor, allocationInfo);
Name name(AZStd::string::format("SwapChainImage_%d", request.m_imageIndex));
Image& image = static_cast<Image&>(*request.m_image);
image.m_memoryView = MemoryView(resource.Get(), 0, allocationInfo.SizeInBytes, allocationInfo.Alignment, MemoryViewType::Image);
image.SetName(name);
image.GenerateSubresourceLayouts();
// Overwrite m_initialAttachmentState because Swapchain images are created with D3D12_RESOURCE_STATE_COMMON state
image.SetAttachmentState(D3D12_RESOURCE_STATE_COMMON);
RHI::HeapMemoryUsage& memoryUsage = m_memoryUsage.GetHeapMemoryUsage(RHI::HeapMemoryLevel::Device);
memoryUsage.m_reservedInBytes += allocationInfo.SizeInBytes;
memoryUsage.m_residentInBytes += allocationInfo.SizeInBytes;
return RHI::ResultCode::Success;
}
void SwapChain::ShutdownResourceInternal(RHI::Resource& resourceBase)
{
Image& image = static_cast<Image&>(resourceBase);
const size_t sizeInBytes = image.GetMemoryView().GetSize();
RHI::HeapMemoryUsage& memoryUsage = m_memoryUsage.GetHeapMemoryUsage(RHI::HeapMemoryLevel::Device);
memoryUsage.m_reservedInBytes -= sizeInBytes;
memoryUsage.m_residentInBytes -= sizeInBytes;
GetDevice().QueueForRelease(image.m_memoryView);
image.m_memoryView = {};
}
RHI::ResultCode SwapChain::ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions)
{
GetDevice().WaitForIdle();

@ -0,0 +1,60 @@
/*
* 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 <Atom/RHI/SwapChain.h>
#include <RHI/DX12.h>
namespace AZ
{
namespace DX12
{
class Device;
class SwapChain
: public RHI::SwapChain
{
public:
AZ_RTTI(SwapChain, "{974AC6A9-5009-47BE-BD7E-61348BF623F0}", RHI::SwapChain);
AZ_CLASS_ALLOCATOR(SwapChain, AZ::SystemAllocator, 0);
static RHI::Ptr<SwapChain> Create();
Device& GetDevice() const;
private:
SwapChain() = default;
friend class SwapChainFactory;
//////////////////////////////////////////////////////////////////////////
// RHI::SwapChain
RHI::ResultCode InitInternal(RHI::Device& deviceBase, const RHI::SwapChainDescriptor& descriptor, RHI::SwapChainDimensions* nativeDimensions) override;
void ShutdownInternal() override;
uint32_t PresentInternal() override;
RHI::ResultCode InitImageInternal(const InitImageRequest& request) override;
void ShutdownResourceInternal(RHI::Resource& resourceBase) override;
RHI::ResultCode ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions) override;
bool IsExclusiveFullScreenPreferred() const override;
bool GetExclusiveFullScreenState() const override;
bool SetExclusiveFullScreenState(bool fullScreenState) override;
//////////////////////////////////////////////////////////////////////////
void ConfigureDisplayMode(const RHI::SwapChainDimensions& dimensions);
void EnsureColorSpace(const DXGI_COLOR_SPACE_TYPE& colorSpace);
void DisableHdr();
void SetHDRMetaData(float maxOutputNits, float minOutputNits, float maxContentLightLevel, float maxFrameAverageLightLevel);
static const uint32_t InvalidColorSpace = 0xFFFFFFFE;
DXGI_COLOR_SPACE_TYPE m_colorSpace = static_cast<DXGI_COLOR_SPACE_TYPE>(InvalidColorSpace);
RHI::Ptr<IDXGISwapChainX> m_swapChain;
bool m_isInFullScreenExclusiveState = false; //!< Was SetFullscreenState used to enter full screen exclusive state?
bool m_isTearingSupported = false; //!< Is tearing support available for full screen borderless windowed mode?
};
}
}

@ -22,7 +22,9 @@ set(FILES
RHI/DX12_Windows.cpp
RHI/DX12_Windows.h
RHI/SystemComponent_Windows.cpp
RHI/SwapChain_Platform.h
RHI/SwapChain_Windows.cpp
RHI/SwapChain_Windows.h
RHI/NsightAftermathGpuCrashTracker_Windows.cpp
RHI/NsightAftermathGpuCrashTracker_Windows.h
RHI/NsightAftermath_Windows.cpp

@ -41,6 +41,8 @@
#define DX12_COMMANDLIST_TIMER_DETAIL(id)
#endif
#define PIX_MARKER_CMDLIST_COL 0xFF0000FF
namespace AZ
{
namespace DX12
@ -94,16 +96,22 @@ namespace AZ
{
SetName(name);
PIXBeginEvent(0xFF0000FF, name.GetCStr());
PIXBeginEvent(GetCommandList(), 0xFF0000FF, name.GetCStr());
PIXBeginEvent(PIX_MARKER_CMDLIST_COL, name.GetCStr());
if (RHI::Factory::Get().IsPixModuleLoaded() || RHI::Factory::Get().IsRenderDocModuleLoaded())
{
PIXBeginEvent(GetCommandList(), PIX_MARKER_CMDLIST_COL, name.GetCStr());
}
}
void CommandList::Close()
{
FlushBarriers();
PIXEndEvent(GetCommandList());
PIXEndEvent();
if (RHI::Factory::Get().IsPixModuleLoaded() || RHI::Factory::Get().IsRenderDocModuleLoaded())
{
PIXEndEvent(GetCommandList());
}
CommandListBase::Close();
}

@ -189,11 +189,6 @@ namespace AZ
m_commandQueueContext.UpdateCpuTimingStatistics(cpuTimingStatistics);
}
void Device::BeginFrameInternal()
{
m_commandQueueContext.Begin();
}
void Device::EndFrameInternal()
{
AZ_TRACE_METHOD();

@ -57,6 +57,10 @@ namespace AZ
const DXGI_SWAP_CHAIN_DESCX& swapChainDesc,
RHI::Ptr<IDXGISwapChainX>& swapChain);
RHI::ResultCode CreateSwapChain(
const DXGI_SWAP_CHAIN_DESCX& swapChainDesc,
AZStd::array<RHI::Ptr<ID3D12Resource>, RHI::Limits::Device::FrameCountMax>& outSwapChainResources);
void GetImageAllocationInfo(
const RHI::ImageDescriptor& descriptor,
D3D12_RESOURCE_ALLOCATION_INFO& info);

@ -7,6 +7,7 @@
*/
#include <RHI/Device.h>
#include <RHI/PipelineLibrary.h>
#include <Atom/RHI/Factory.h>
namespace AZ
{
@ -46,7 +47,16 @@ namespace AZ
#if defined (AZ_DX12_USE_PIPELINE_LIBRARY)
AZStd::array_view<uint8_t> bytes;
if (serializedData)
bool shouldCreateLibFromSerializedData = true;
if (RHI::Factory::Get().IsRenderDocModuleLoaded() || RHI::Factory::Get().IsPixModuleLoaded())
{
// CreatePipelineLibrary api does not function properly if Renderdoc or Pix is enabled
shouldCreateLibFromSerializedData = false;
}
if (serializedData && shouldCreateLibFromSerializedData)
{
bytes = serializedData->GetData();
}
@ -205,10 +215,11 @@ namespace AZ
RHI::ResultCode PipelineLibrary::MergeIntoInternal([[maybe_unused]] AZStd::array_view<const RHI::PipelineLibrary*> pipelineLibraries)
{
#if defined(USE_PIX) || defined(USE_RENDERDOC)
// StorePipeline api does not function properly if Pix or RenderDoc is enabled
return RHI::ResultCode::Fail;
#else
if (RHI::Factory::Get().IsRenderDocModuleLoaded() || RHI::Factory::Get().IsPixModuleLoaded())
{
// StorePipeline api does not function properly if RenderDoc or Pix is enabled
return RHI::ResultCode::Fail;
}
#if defined (AZ_DX12_USE_PIPELINE_LIBRARY)
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
@ -226,8 +237,7 @@ namespace AZ
}
}
#endif
return RHI::ResultCode::Success;
#endif
return RHI::ResultCode::Success;
}
RHI::ConstPtr<RHI::PipelineLibraryData> PipelineLibrary::GetSerializedDataInternal() const
@ -252,7 +262,11 @@ namespace AZ
bool PipelineLibrary::IsMergeRequired() const
{
#if defined (AZ_DX12_USE_PIPELINE_LIBRARY)
return !m_pipelineStates.empty();
#else
return false;
#endif
}
}
}

@ -28,11 +28,11 @@ namespace AZ
}
#endif
RHI::ResultCode RayTracingPipelineState::InitInternal(RHI::Device& deviceBase, [[maybe_unused]]const RHI::RayTracingPipelineStateDescriptor* descriptor)
RHI::ResultCode RayTracingPipelineState::InitInternal([[maybe_unused]]RHI::Device& deviceBase, [[maybe_unused]]const RHI::RayTracingPipelineStateDescriptor* descriptor)
{
#ifdef AZ_DX12_DXR_SUPPORT
Device& device = static_cast<Device&>(deviceBase);
#ifdef AZ_DX12_DXR_SUPPORT
size_t dxilLibraryCount = descriptor->GetShaderLibraries().size();
size_t hitGroupCount = descriptor->GetHitGroups().size();

@ -18,6 +18,7 @@
#include <Atom/RHI/ResourcePool.h>
#include <Atom/RHI/ImageScopeAttachment.h>
#include <Atom/RHI/BufferScopeAttachment.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RHI/ResolveScopeAttachment.h>
#include <AzCore/Debug/EventTrace.h>
@ -309,8 +310,11 @@ namespace AZ
commandList.GetValidator().BeginScope(*this);
PIXBeginEvent(0xFFFF00FF, GetId().GetCStr());
PIXBeginEvent(commandList.GetCommandList(), 0xFFFF00FF, GetId().GetCStr());
if (RHI::Factory::Get().IsPixModuleLoaded() || RHI::Factory::Get().IsRenderDocModuleLoaded())
{
PIXBeginEvent(commandList.GetCommandList(), 0xFFFF00FF, GetId().GetCStr());
}
commandList.SetAftermathEventMarker(GetId().GetCStr());
@ -424,7 +428,10 @@ namespace AZ
}
}
PIXEndEvent(commandList.GetCommandList());
if (RHI::Factory::Get().IsPixModuleLoaded() || RHI::Factory::Get().IsRenderDocModuleLoaded())
{
PIXEndEvent(commandList.GetCommandList());
}
PIXEndEvent();
commandList.GetValidator().EndScope();

@ -1,73 +0,0 @@
/*
* 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 <RHI/SwapChain.h>
#include <RHI/Device.h>
#include <RHI/Conversions.h>
#include <RHI/Image.h>
#include <Atom/RHI/MemoryStatisticsBuilder.h>
#include <Atom/RHI.Reflect/AttachmentEnums.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/conversions.h>
namespace AZ
{
namespace DX12
{
RHI::Ptr<SwapChain> SwapChain::Create()
{
return aznew SwapChain();
}
Device& SwapChain::GetDevice() const
{
return static_cast<Device&>(Base::GetDevice());
}
RHI::ResultCode SwapChain::InitImageInternal(const InitImageRequest& request)
{
Device& device = GetDevice();
Microsoft::WRL::ComPtr<ID3D12Resource> resource;
DX12::AssertSuccess(m_swapChain->GetBuffer(request.m_imageIndex, IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf())));
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo;
device.GetImageAllocationInfo(request.m_descriptor, allocationInfo);
Name name(AZStd::string::format("SwapChainImage_%d", request.m_imageIndex));
Image& image = static_cast<Image&>(*request.m_image);
image.m_memoryView = MemoryView(resource.Get(), 0, allocationInfo.SizeInBytes, allocationInfo.Alignment, MemoryViewType::Image);
image.SetName(name);
image.GenerateSubresourceLayouts();
// Overwrite m_initialAttachmentState because Swapchain images are created with D3D12_RESOURCE_STATE_COMMON state
image.SetAttachmentState(D3D12_RESOURCE_STATE_COMMON);
RHI::HeapMemoryUsage& memoryUsage = m_memoryUsage.GetHeapMemoryUsage(RHI::HeapMemoryLevel::Device);
memoryUsage.m_reservedInBytes += allocationInfo.SizeInBytes;
memoryUsage.m_residentInBytes += allocationInfo.SizeInBytes;
return RHI::ResultCode::Success;
}
void SwapChain::ShutdownResourceInternal(RHI::Resource& resourceBase)
{
Image& image = static_cast<Image&>(resourceBase);
const size_t sizeInBytes = image.GetMemoryView().GetSize();
RHI::HeapMemoryUsage& memoryUsage = m_memoryUsage.GetHeapMemoryUsage(RHI::HeapMemoryLevel::Device);
memoryUsage.m_reservedInBytes -= sizeInBytes;
memoryUsage.m_residentInBytes -= sizeInBytes;
GetDevice().QueueForRelease(image.m_memoryView);
image.m_memoryView = {};
}
}
}

@ -7,56 +7,4 @@
*/
#pragma once
#include <Atom/RHI/SwapChain.h>
#include <RHI/DX12.h>
namespace AZ
{
namespace DX12
{
class Device;
class Image;
class CommandQueue;
class SwapChain
: public RHI::SwapChain
{
using Base = RHI::SwapChain;
public:
AZ_RTTI(SwapChain, "{974AC6A9-5009-47BE-BD7E-61348BF623F0}", Base);
AZ_CLASS_ALLOCATOR(SwapChain, AZ::SystemAllocator, 0);
static RHI::Ptr<SwapChain> Create();
Device& GetDevice() const;
private:
SwapChain() = default;
//////////////////////////////////////////////////////////////////////////
// RHI::SwapChain
RHI::ResultCode InitInternal(RHI::Device& deviceBase, const RHI::SwapChainDescriptor& descriptor, RHI::SwapChainDimensions* nativeDimensions) override;
void ShutdownInternal() override;
uint32_t PresentInternal() override;
RHI::ResultCode InitImageInternal(const InitImageRequest& request) override;
void ShutdownResourceInternal(RHI::Resource& resourceBase) override;
RHI::ResultCode ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions) override;
bool IsExclusiveFullScreenPreferred() const override;
bool GetExclusiveFullScreenState() const override;
bool SetExclusiveFullScreenState(bool fullScreenState) override;
//////////////////////////////////////////////////////////////////////////
void ConfigureDisplayMode(const RHI::SwapChainDimensions& dimensions);
void EnsureColorSpace(const DXGI_COLOR_SPACE_TYPE& colorSpace);
void DisableHdr();
void SetHDRMetaData(float maxOutputNits, float minOutputNits, float maxContentLightLevel, float maxFrameAverageLightLevel);
static const uint32_t InvalidColorSpace = 0xFFFFFFFE;
DXGI_COLOR_SPACE_TYPE m_colorSpace = static_cast<DXGI_COLOR_SPACE_TYPE>(InvalidColorSpace);
RHI::Ptr<IDXGISwapChainX> m_swapChain;
bool m_isInFullScreenExclusiveState = false; //!< Was SetFullscreenState used to enter full screen exclusive state?
bool m_isTearingSupported = false; //!< Is tearing support available for full screen borderless windowed mode?
};
}
}
#include <RHI/SwapChain_Platform.h>

@ -95,7 +95,6 @@ set(FILES
Source/RHI/ShaderResourceGroup.h
Source/RHI/ShaderResourceGroupPool.cpp
Source/RHI/ShaderResourceGroupPool.h
Source/RHI/SwapChain.cpp
Source/RHI/SwapChain.h
Source/RHI/DX12.cpp
Source/RHI/DX12.h

@ -14,10 +14,6 @@ elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland")
set(GLAD_VULKAN_COMPILE_DEFINITIONS
VK_USE_PLATFORM_WAYLAND_KHR
)
elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "xlib")
set(GLAD_VULKAN_COMPILE_DEFINITIONS
VK_USE_PLATFORM_XLIB_KHR
)
else()
message(FATAL_ERROR, "Linux Window Manager ${PAL_TRAIT_LINUX_WINDOW_MANAGER} is not recognized")
endif()

@ -19,9 +19,12 @@ if(NOT PAL_TRAIT_ATOM_RHI_VULKAN_SUPPORTED)
NAMESPACE Gem
FILES_CMAKE
atom_rhi_vulkan_stub_module.cmake
atom_rhi_vulkan_reflect_common_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include
Source
${pal_include_dir}
Include/Atom/RHI.Loader/Glad
BUILD_DEPENDENCIES
PRIVATE

@ -5,6 +5,8 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RHI.Reflect/Vulkan/ReflectSystemComponent.h>
#include <AzCore/Module/Module.h>
namespace AZ
@ -17,7 +19,12 @@ namespace AZ
public:
AZ_RTTI(PlatformModule, "{958CB096-796C-42C7-9B29-17C6FE792C30}", Module);
PlatformModule() = default;
PlatformModule()
{
m_descriptors.insert(m_descriptors.end(), {
ReflectSystemComponent::CreateDescriptor()
});
}
~PlatformModule() override = default;
AZ::ComponentTypeList GetRequiredSystemComponents() const override

@ -41,9 +41,6 @@ namespace AZ
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported."
return RHI::ResultCode::Unimplemented;
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_XLIB
#error "Linux Window Manager XLIB not supported."
return RHI::ResultCode::Unimplemented;
#else
#error "Linux Window Manager not recognized."
return RHI::ResultCode::Unimplemented;

@ -129,10 +129,6 @@ namespace AZ
void RemoveRenderPipeline(const RenderPipelineId& pipelineId);
//! Set a callback function to set values for scene's srg.
//! The callback function is usually defined by the one who create the scene since it knows how the layout look like.
void SetShaderResourceGroupCallback(ShaderResourceGroupCallback callback);
const RHI::ShaderResourceGroup* GetRHIShaderResourceGroup() const;
Data::Instance<ShaderResourceGroup> GetShaderResourceGroup() const;
@ -166,9 +162,13 @@ namespace AZ
RenderPipelinePtr FindRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle);
using PrepareSceneSrgEvent = AZ::Event<RPI::ShaderResourceGroup*>;
//! Connect a handler to listen to the event that the Scene is ready to update and compile its scene srg
//! User should use this event to update the part scene srg they know of
void ConnectEvent(PrepareSceneSrgEvent::Handler& handler);
protected:
// SceneFinder overrides...
Scene* FindSelf();
void OnSceneNotifictaionHandlerConnected(SceneNotification* handler);
// Cpu simulation which runs all active FeatureProcessor Simulate() functions.
@ -183,7 +183,7 @@ namespace AZ
// Function called when the current frame is finished rendering.
void OnFrameEnd();
// Update and compile view srgs
// Update and compile scene and view srgs
// This is called after PassSystem's FramePrepare so passes can still modify view srgs in its FramePrepareIntenal function before they are submitted to command list
void UpdateSrgs();
@ -200,6 +200,10 @@ namespace AZ
// Add a created feature processor to this scene
void AddFeatureProcessor(FeatureProcessorPtr fp);
// Send out event to PrepareSceneSrgEvent::Handlers so they can update scene srg as needed
// This happens in UpdateSrgs()
void PrepareSceneSrg();
// List of feature processors that are active for this scene
AZStd::vector<FeatureProcessorPtr> m_featureProcessors;
@ -215,9 +219,10 @@ namespace AZ
AZ::RPI::FeatureProcessor::SimulatePacket m_simulatePacket;
AZ::RPI::FeatureProcessor::RenderPacket m_renderPacket;
// Scene's srg and its set function
// Scene's srg
Data::Instance<ShaderResourceGroup> m_srg;
ShaderResourceGroupCallback m_srgCallback;
// Event to for prepare scene srg
PrepareSceneSrgEvent m_prepareSrgEvent;
// The uuid to identify this scene.
SceneId m_id;
@ -234,6 +239,8 @@ namespace AZ
// Registry which allocates draw filter tag for RenderPipeline
RHI::Ptr<RHI::DrawFilterTagRegistry> m_drawFilterTagRegistry;
float m_simulationTime;
};
// --- Template functions ---

@ -80,7 +80,6 @@ namespace AZ
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = SceneId;
virtual Scene* FindSelf() = 0;
virtual void OnSceneNotifictaionHandlerConnected(SceneNotification* handler) = 0;
};

@ -124,7 +124,6 @@ namespace AZ
bool MeshDrawPacket::DoUpdate(const Scene& parentScene)
{
AZ_PROFILE_FUNCTION(RPI);
const ModelLod::Mesh& mesh = m_modelLod->GetMeshes()[m_modelLodMeshIndex];
if (!m_material)
@ -155,8 +154,6 @@ namespace AZ
auto appendShader = [&](const ShaderCollection::Item& shaderItem)
{
AZ_PROFILE_SCOPE(RPI, "appendShader()");
// Skip the shader item without creating the shader instance
// if the mesh is not going to be rendered based on the draw tag
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
@ -256,7 +253,6 @@ namespace AZ
Data::Instance<ShaderResourceGroup> drawSrg;
if (drawSrgLayout)
{
AZ_PROFILE_SCOPE(RPI, "create drawSrg");
// If the DrawSrg exists we must create and bind it, otherwise the CommandList will fail validation for SRG being null
drawSrg = RPI::ShaderResourceGroup::Create(shader->GetAsset(), shader->GetSupervariantIndex(), drawSrgLayout->GetName());

@ -264,8 +264,6 @@ namespace AZ
const MaterialModelUvOverrideMap& materialModelUvMap,
const MaterialUvNameMap& materialUvNameMap) const
{
AZ_PROFILE_FUNCTION(RPI);
streamBufferViewsOut.clear();
RHI::InputStreamLayoutBuilder layoutBuilder;
@ -366,8 +364,6 @@ namespace AZ
const MaterialModelUvOverrideMap& materialModelUvMap,
const MaterialUvNameMap& materialUvNameMap) const
{
AZ_PROFILE_FUNCTION(RPI);
const Mesh& mesh = m_meshes[meshIndex];
auto defaultUv = FindDefaultUvStream(meshIndex, materialUvNameMap);

@ -308,10 +308,10 @@ namespace AZ
// The fix is to clear the buffer outside of the callback.
for (int32_t i = 0; i < RHI::Limits::Device::FrameCountMax; i++)
{
if (m_isReadbackComplete[m_readbackBufferCurrentIndex])
if (m_isReadbackComplete[i])
{
m_isReadbackComplete[m_readbackBufferCurrentIndex] = false;
m_readbackBufferArray[m_readbackBufferCurrentIndex] = nullptr;
m_isReadbackComplete[i] = false;
m_readbackBufferArray[i] = nullptr;
}
}
// Loop the triple buffer index and cache the current index to the callback.

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save