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

This commit is contained in:
pereslav
2021-10-05 15:53:39 +01:00
372 changed files with 126496 additions and 1331 deletions
@@ -122,6 +122,7 @@ class TestAutomation(TestAutomationBase):
from . import Debugger_HappyPath_TargetMultipleEntities as test_module
self._run_test(request, workspace, editor, test_module)
@pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
def test_EditMenu_Default_UndoRedo(self, request, workspace, editor, launcher_platform, project):
from . import EditMenu_Default_UndoRedo as test_module
self._run_test(request, workspace, editor, test_module)
@@ -181,6 +182,7 @@ class TestAutomation(TestAutomationBase):
from . import NodePalette_SearchText_Deletion as test_module
self._run_test(request, workspace, editor, test_module)
@pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
def test_VariableManager_UnpinVariableType_Works(self, request, workspace, editor, launcher_platform):
from . import VariableManager_UnpinVariableType_Works as test_module
self._run_test(request, workspace, editor, test_module)
@@ -142,8 +142,7 @@ void GetSelectedEntitiesSetWithFlattenedHierarchy(AzToolsFramework::EntityIdSet&
}
SandboxIntegrationManager::SandboxIntegrationManager()
: m_inObjectPickMode(false)
, m_startedUndoRecordingNestingLevel(0)
: m_startedUndoRecordingNestingLevel(0)
, m_dc(nullptr)
, m_notificationWindowManager(new AzToolsFramework::SliceOverridesNotificationWindowManager())
{
@@ -1000,62 +999,6 @@ void SandboxIntegrationManager::SetupSliceContextMenu_Modify(QMenu* menu, const
revertAction->setEnabled(canRevert);
}
void SandboxIntegrationManager::HandleObjectModeSelection(const AZ::Vector2& point, [[maybe_unused]] int flags, bool& handled)
{
// Todo - Use a custom "edit tool". This will eliminate the need for this bus message entirely, which technically
// makes this feature less intrusive on Sandbox.
// UPDATE: This is now provided by EditorPickEntitySelection when the new Viewport Interaction Model changes are enabled.
if (m_inObjectPickMode)
{
CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
const QPoint viewPoint(static_cast<int>(point.GetX()), static_cast<int>(point.GetY()));
HitContext hitInfo;
hitInfo.view = view;
if (view->HitTest(viewPoint, hitInfo))
{
if (hitInfo.object && (hitInfo.object->GetType() == OBJTYPE_AZENTITY))
{
CComponentEntityObject* entityObject = static_cast<CComponentEntityObject*>(hitInfo.object);
AzToolsFramework::EditorPickModeRequestBus::Broadcast(
&AzToolsFramework::EditorPickModeRequests::PickModeSelectEntity, entityObject->GetAssociatedEntityId());
}
}
AzToolsFramework::EditorPickModeRequestBus::Broadcast(
&AzToolsFramework::EditorPickModeRequests::StopEntityPickMode);
handled = true;
}
}
void SandboxIntegrationManager::UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr)
{
if (m_inObjectPickMode)
{
cursorId = static_cast<AZ::u64>(STD_CURSOR_HAND);
cursorStr = "Pick an entity...";
}
}
void SandboxIntegrationManager::OnEntityPickModeStarted()
{
m_inObjectPickMode = true;
// Currently this object pick mode is activated only via PropertyEntityIdCtrl picker.
// When the picker button is clicked, we transfer focus to the viewport so the
// spacebar can still be used to activate selection helpers.
if (CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport())
{
view->SetFocus();
}
}
void SandboxIntegrationManager::OnEntityPickModeStopped()
{
m_inObjectPickMode = false;
}
void SandboxIntegrationManager::CreateEditorRepresentation(AZ::Entity* entity)
{
IEditor* editor = GetIEditor();
@@ -93,7 +93,6 @@ namespace AzToolsFramework
class SandboxIntegrationManager
: private AzToolsFramework::ToolsApplicationEvents::Bus::Handler
, private AzToolsFramework::EditorRequests::Bus::Handler
, private AzToolsFramework::EditorPickModeNotificationBus::Handler
, private AzToolsFramework::EditorContextMenuBus::Handler
, private AzToolsFramework::EditorWindowRequests::Bus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
@@ -140,8 +139,6 @@ private:
QDockWidget* InstanceViewPane(const char* paneName) override;
void CloseViewPane(const char* paneName) override;
void BrowseForAssets(AzToolsFramework::AssetBrowser::AssetSelectionModel& selection) override;
void HandleObjectModeSelection(const AZ::Vector2& point, int flags, bool& handled) override;
void UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr) override;
void CreateEditorRepresentation(AZ::Entity* entity) override;
bool DestroyEditorRepresentation(AZ::EntityId entityId, bool deleteAZEntity) override;
void CloneSelection(bool& handled) override;
@@ -175,10 +172,6 @@ private:
QWidget* GetAppMainWindow() override;
//////////////////////////////////////////////////////////////////////////
// EditorPickModeNotificationBus
void OnEntityPickModeStarted() override;
void OnEntityPickModeStopped() override;
//////////////////////////////////////////////////////////////////////////
// AzToolsFramework::EditorContextMenu::Bus::Handler overrides
void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override;
@@ -281,7 +274,6 @@ private:
private:
AZ::Vector2 m_contextMenuViewPoint;
int m_inObjectPickMode;
short m_startedUndoRecordingNestingLevel; // used in OnBegin/EndUndo to ensure we only accept undo's we started recording
AzToolsFramework::SliceOverridesNotificationWindowManager* m_notificationWindowManager;
+2 -2
View File
@@ -101,13 +101,13 @@ public:
if (fresh.size() < m_stackNames.size())
{
beginRemoveRows(createIndex(-1, -1), static_cast<int>(fresh.size()), static_cast<int>(m_stackNames.size() - 1));
beginRemoveRows(QModelIndex(), static_cast<int>(fresh.size()), static_cast<int>(m_stackNames.size() - 1));
m_stackNames = fresh;
endRemoveRows();
}
else
{
beginInsertRows(createIndex(-1, -1), static_cast<int>(m_stackNames.size()), static_cast<int>(fresh.size() - 1));
beginInsertRows(QModelIndex(), static_cast<int>(m_stackNames.size()), static_cast<int>(fresh.size() - 1));
m_stackNames = fresh;
endInsertRows();
}
+1 -1
View File
@@ -157,7 +157,7 @@ public:
virtual Vec3 SnapToGrid(const Vec3& vec) = 0;
//! Get selection procision tolerance.
//! Get selection precision tolerance.
virtual float GetSelectionTolerance() const = 0;
//////////////////////////////////////////////////////////////////////////
@@ -23,6 +23,7 @@
#include <AzCore/Console/LoggerSystemComponent.h>
#include <AzCore/EBus/EventSchedulerSystemComponent.h>
#include <AzCore/Task/TaskGraphSystemComponent.h>
#include <AzCore/Statistics/StatisticalProfilerProxySystemComponent.h>
namespace AZ
{
@@ -44,6 +45,10 @@ namespace AZ
EventSchedulerSystemComponent::CreateDescriptor(),
TaskGraphSystemComponent::CreateDescriptor(),
#if !defined(_RELEASE)
Statistics::StatisticalProfilerProxySystemComponent::CreateDescriptor(),
#endif
#if !defined(AZCORE_EXCLUDE_LUA)
ScriptSystemComponent::CreateDescriptor(),
#endif // #if !defined(AZCORE_EXCLUDE_LUA)
@@ -58,6 +63,10 @@ namespace AZ
azrtti_typeid<LoggerSystemComponent>(),
azrtti_typeid<EventSchedulerSystemComponent>(),
azrtti_typeid<TaskGraphSystemComponent>(),
#if !defined(_RELEASE)
azrtti_typeid<Statistics::StatisticalProfilerProxySystemComponent>(),
#endif
};
}
}
@@ -1367,9 +1367,6 @@ namespace AZ
#endif
}
//=========================================================================
// Tick
//=========================================================================
void ComponentApplication::Tick(float deltaOverride /*= -1.f*/)
{
{
@@ -1397,9 +1394,6 @@ namespace AZ
}
}
//=========================================================================
// Tick
//=========================================================================
void ComponentApplication::TickSystem()
{
AZ_PROFILE_SCOPE(System, "Component application tick");
@@ -1547,5 +1541,4 @@ namespace AZ
AZ::SettingsRegistryScriptUtils::ReflectSettingsRegistryToBehaviorContext(*behaviorContext);
}
}
} // namespace AZ
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/ComponentApplicationBus.h>
@@ -11,6 +11,7 @@
#include <AzCore/Module/Environment.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Statistics/StatisticalProfilerProxy.h>
AZ_DEFINE_BUDGET(Animation);
AZ_DEFINE_BUDGET(Audio);
@@ -30,8 +31,7 @@ namespace AZ::Debug
};
Budget::Budget(const char* name)
: m_name{ name }
, m_crc{ Crc32(name) }
: Budget( name, Crc32(name) )
{
}
@@ -40,6 +40,10 @@ namespace AZ::Debug
, m_crc{ crc }
{
m_impl = aznew BudgetImpl;
if (auto statsProfiler = Interface<Statistics::StatisticalProfilerProxy>::Get(); statsProfiler)
{
statsProfiler->RegisterProfilerId(m_crc);
}
}
Budget::~Budget()
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/Debug/Budget.h>
#include <AzCore/Statistics/StatisticalProfilerProxy.h>
#ifdef USE_PIX
#include <AzCore/PlatformIncl.h>
@@ -44,7 +45,10 @@
#define AZ_PROFILE_INTERVAL_START(...)
#define AZ_PROFILE_INTERVAL_START_COLORED(...)
#define AZ_PROFILE_INTERVAL_END(...)
#define AZ_PROFILE_INTERVAL_SCOPED(...)
#define AZ_PROFILE_INTERVAL_SCOPED(budget, scopeNameId, ...) \
static constexpr AZ::Crc32 AZ_JOIN(blockId, __LINE__)(scopeNameId); \
AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(AZ_CRC_CE(#budget), AZ_JOIN(blockId, __LINE__));
#endif
#ifndef AZ_PROFILE_DATAPOINT
+4 -4
View File
@@ -12,7 +12,7 @@
* that Open 3D Engine uses to dispatch notifications and receive requests.
* EBuses are configurable and support many different use cases.
* For more information about %EBuses, see AZ::EBus in this guide and
* [Event Bus](http://docs.aws.amazon.com/lumberyard/latest/developerguide/asset-pipeline-ebus.html)
* [Event Bus](https://o3de.org/docs/user-guide/engine/ebus/)
* in the *Open 3D Engine Developer Guide*.
*/
@@ -62,7 +62,7 @@ namespace AZ
* @endcode
*
* For more information about %EBuses, see EBus in this guide and
* [Event Bus](http://docs.aws.amazon.com/lumberyard/latest/developerguide/asset-pipeline-ebus.html)
* [Event Bus](https://o3de.org/docs/user-guide/engine/ebus/)
* in the *Open 3D Engine Developer Guide*.
*/
struct EBusTraits
@@ -259,8 +259,8 @@ namespace AZ
*
* EBuses are configurable and support many different use cases.
* For more information about EBuses, see
* [Event Bus](http://docs.aws.amazon.com/lumberyard/latest/developerguide/asset-pipeline-ebus.html)
* and [Components and EBuses: Best Practices ](http://docs.aws.amazon.com/lumberyard/latest/developerguide/component-entity-system-pg-components-ebuses-best-practices.html)
* [Event Bus](https://o3de.org/docs/user-guide/engine/ebus/)
* and [Components and EBuses: Best Practices ](https://o3de.org/docs/user-guide/components/development/entity-system-pg-components-ebuses-best-practices/)
* in the *Open 3D Engine Developer Guide*.
*
* ## How Components Use EBuses
@@ -35,6 +35,7 @@ namespace Platform
SystemFile::SizeType Length(FileHandleType handle, const SystemFile* systemFile);
bool Exists(const char* fileName);
bool IsDirectory(const char* filePath);
void FindFiles(const char* filter, SystemFile::FindFileCB cb);
AZ::u64 ModificationTime(const char* fileName);
SystemFile::SizeType Length(const char* fileName);
@@ -235,6 +236,11 @@ bool SystemFile::Exists(const char* fileName)
return Platform::Exists(fileName);
}
bool SystemFile::IsDirectory(const char* filePath)
{
return Platform::IsDirectory(filePath);
}
void SystemFile::FindFiles(const char* filter, FindFileCB cb)
{
Platform::FindFiles(filter, cb);
@@ -99,6 +99,8 @@ namespace AZ
// Utility functions
/// Check if a file or directory exists.
static bool Exists(const char* path);
/// Check if path is a directory
static bool IsDirectory(const char* path);
/// FindFiles
typedef AZStd::function<bool /* true to continue to enumerate otherwise false */ (const char* /* fileName*/, bool /* true if file, false if folder*/)> FindFileCB;
static void FindFiles(const char* filter, FindFileCB cb);
-1
View File
@@ -5,7 +5,6 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/base.h>
@@ -180,6 +180,13 @@ namespace AZ
bool IsGreaterEqualThan(const Vector2& v) const;
//! @}
//! Floor/Ceil/Round functions, operate on each component individually, result will be a new Vector2.
//! @{
Vector2 GetFloor() const;
Vector2 GetCeil() const;
Vector2 GetRound() const; // Ties to even (banker's rounding)
//! @}
//! Min/Max functions, operate on each component individually, result will be a new Vector2.
//! @{
Vector2 GetMin(const Vector2& v) const;
@@ -398,6 +398,24 @@ namespace AZ
}
AZ_MATH_INLINE Vector2 Vector2::GetFloor() const
{
return Vector2(Simd::Vec2::Floor(m_value));
}
AZ_MATH_INLINE Vector2 Vector2::GetCeil() const
{
return Vector2(Simd::Vec2::Ceil(m_value));
}
AZ_MATH_INLINE Vector2 Vector2::GetRound() const
{
return Vector2(Simd::Vec2::Round(m_value));
}
AZ_MATH_INLINE Vector2 Vector2::GetMin(const Vector2& v) const
{
#if AZ_TRAIT_USE_PLATFORM_SIMD_SCALAR
@@ -211,6 +211,13 @@ namespace AZ
bool IsGreaterEqualThan(const Vector3& rhs) const;
//! @}
//! Floor/Ceil/Round functions, operate on each component individually, result will be a new Vector3.
//! @{
Vector3 GetFloor() const;
Vector3 GetCeil() const;
Vector3 GetRound() const; // Ties to even (banker's rounding)
//! @}
//! Min/Max functions, operate on each component individually, result will be a new Vector3.
//! @{
Vector3 GetMin(const Vector3& v) const;
@@ -481,6 +481,24 @@ namespace AZ
}
AZ_MATH_INLINE Vector3 Vector3::GetFloor() const
{
return Vector3(Simd::Vec3::Floor(m_value));
}
AZ_MATH_INLINE Vector3 Vector3::GetCeil() const
{
return Vector3(Simd::Vec3::Ceil(m_value));
}
AZ_MATH_INLINE Vector3 Vector3::GetRound() const
{
return Vector3(Simd::Vec3::Round(m_value));
}
AZ_MATH_INLINE Vector3 Vector3::GetMin(const Vector3& v) const
{
#if AZ_TRAIT_USE_PLATFORM_SIMD_SCALAR
@@ -189,6 +189,13 @@ namespace AZ
bool IsGreaterEqualThan(const Vector4& rhs) const;
//! @}
//! Floor/Ceil/Round functions, operate on each component individually, result will be a new Vector4.
//! @{
Vector4 GetFloor() const;
Vector4 GetCeil() const;
Vector4 GetRound() const; // Ties to even (banker's rounding)
//! @}
//! Min/Max functions, operate on each component individually, result will be a new Vector4.
//! @{
Vector4 GetMin(const Vector4& v) const;
@@ -464,6 +464,24 @@ namespace AZ
}
AZ_MATH_INLINE Vector4 Vector4::GetFloor() const
{
return Vector4(Simd::Vec4::Floor(m_value));
}
AZ_MATH_INLINE Vector4 Vector4::GetCeil() const
{
return Vector4(Simd::Vec4::Ceil(m_value));
}
AZ_MATH_INLINE Vector4 Vector4::GetRound() const
{
return Vector4(Simd::Vec4::Round(m_value));
}
AZ_MATH_INLINE Vector4 Vector4::GetMin(const Vector4& v) const
{
#if AZ_TRAIT_USE_PLATFORM_SIMD_SCALAR
@@ -1,106 +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 "RunningStatisticsManager.h"
namespace AzFramework
{
namespace Statistics
{
bool RunningStatisticsManager::ContainsStatistic(const AZStd::string& name)
{
auto iterator = m_statisticsNamesToIndexMap.find(name);
return iterator != m_statisticsNamesToIndexMap.end();
}
bool RunningStatisticsManager::AddStatistic(const AZStd::string& name, const AZStd::string& units)
{
if (ContainsStatistic(name))
{
return false;
}
AddStatisticValidated(name, units);
return true;
}
void RunningStatisticsManager::RemoveStatistic(const AZStd::string& name)
{
auto iterator = m_statisticsNamesToIndexMap.find(name);
if (iterator == m_statisticsNamesToIndexMap.end())
{
return;
}
AZ::u32 itemIndex = iterator->second;
m_statistics.erase(m_statistics.begin() + itemIndex);
m_statisticsNamesToIndexMap.erase(iterator);
//Update the indices in m_statisticsNamesToIndexMap.
while (itemIndex < m_statistics.size())
{
const AZStd::string& statName = m_statistics[itemIndex].GetName();
m_statisticsNamesToIndexMap[statName] = itemIndex;
++itemIndex;
}
}
void RunningStatisticsManager::ResetStatistic(const AZStd::string& name)
{
NamedRunningStatistic* stat = GetStatistic(name);
if (!stat)
{
return;
}
stat->Reset();
}
void RunningStatisticsManager::ResetAllStatistics()
{
for (NamedRunningStatistic& stat : m_statistics)
{
stat.Reset();
}
}
void RunningStatisticsManager::PushSampleForStatistic(const AZStd::string& name, double value)
{
NamedRunningStatistic* stat = GetStatistic(name);
if (!stat)
{
return;
}
stat->PushSample(value);
}
NamedRunningStatistic* RunningStatisticsManager::GetStatistic(const AZStd::string& name, AZ::u32* indexOut)
{
auto iterator = m_statisticsNamesToIndexMap.find(name);
if (iterator == m_statisticsNamesToIndexMap.end())
{
return nullptr;
}
const AZ::u32 index = iterator->second;
if (indexOut)
{
*indexOut = index;
}
return &m_statistics[index];
}
const AZStd::vector<NamedRunningStatistic>& RunningStatisticsManager::GetAllStatistics() const
{
return m_statistics;
}
void RunningStatisticsManager::AddStatisticValidated(const AZStd::string& name, const AZStd::string& units)
{
m_statistics.emplace_back(NamedRunningStatistic(name, units));
const AZ::u32 itemIndex = static_cast<AZ::u32>(m_statistics.size() - 1);
m_statisticsNamesToIndexMap[name] = itemIndex;
}
}//namespace Statistics
}//namespace AzFramework
@@ -8,7 +8,6 @@
#pragma once
#include <AzCore/EBus/BusImpl.h> //Just to get AZ::NullMutex
#include <AzCore/std/chrono/types.h>
#include <AzCore/Statistics/StatisticsManager.h>
#include <AzCore/std/chrono/chrono.h>
#include <AzCore/std/parallel/scoped_lock.h>
@@ -37,8 +36,7 @@ namespace AZ
//! are some things to consider when working with the StatisticalProfilerProxy:
//! The StatisticalProfilerProxy OWNS an array of StatisticalProfiler<AZStd::string, AZStd::shared_spin_mutex>.
//! You can "manage" one of those StatisticalProfiler by getting a reference to it and
//! add Running statistics etc. See The TerrainProfilers mentioned above to see concrete use
//! cases on how to work with the StatisticalProfilerProxy.
//! add Running statistics etc.
template <class StatIdType = AZStd::string, class MutexType = AZ::NullMutex>
class StatisticalProfiler
{
@@ -7,28 +7,12 @@
*/
#pragma once
#include <AzCore/std/chrono/types.h>
#include <AzCore/std/parallel/shared_spin_mutex.h>
#include <AzCore/std/parallel/scoped_lock.h>
#include <AzCore/std/containers/bitset.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Statistics/StatisticalProfiler.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/shared_spin_mutex.h>
#if defined(AZ_STATISTICAL_PROFILING_ENABLED)
#if defined(AZ_PROFILE_SCOPE)
#undef AZ_PROFILE_SCOPE
#endif // #if defined(AZ_PROFILE_SCOPE)
#define AZ_PROFILE_SCOPE(profiler, scopeNameId) \
static const AZStd::string AZ_JOIN(blockName, __LINE__)(scopeNameId); \
AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(profiler, AZ_JOIN(blockName, __LINE__));
#endif //#if defined(AZ_STATISTICAL_PROFILING_ENABLED)
namespace AZ::Statistics
{
using StatisticalProfilerId = uint32_t;
@@ -65,7 +49,7 @@ namespace AZ::Statistics
public:
AZ_TYPE_INFO(StatisticalProfilerProxy, "{1103D0EB-1C32-4854-B9D9-40A2D65BDBD2}");
using StatIdType = AZStd::string;
using StatIdType = AZ::Crc32;
using StatisticalProfilerType = StatisticalProfiler<StatIdType, AZStd::shared_spin_mutex>;
//! A Convenience class used to measure time performance of scopes of code
@@ -94,6 +78,7 @@ namespace AZ::Statistics
}
m_startTime = AZStd::chrono::high_resolution_clock::now();
}
~TimedScope()
{
if (!m_profilerProxy)
@@ -122,7 +107,6 @@ namespace AZ::Statistics
StatisticalProfilerProxy()
{
// TODO:BUDGETS Query available budgets at registration time and create an associated profiler per type
AZ::Interface<StatisticalProfilerProxy>::Register(this);
}
@@ -135,30 +119,54 @@ namespace AZ::Statistics
StatisticalProfilerProxy(StatisticalProfilerProxy&&) = delete;
StatisticalProfilerProxy& operator=(StatisticalProfilerProxy&&) = delete;
void RegisterProfilerId(StatisticalProfilerId id)
{
m_profilers.try_emplace(id, ProfilerInfo());
}
bool IsProfilerActive(StatisticalProfilerId id) const
{
return m_activeProfilersFlag[static_cast<AZStd::size_t>(id)];
auto iter = m_profilers.find(id);
return (iter != m_profilers.end()) ? iter->second.m_enabled : false;
}
StatisticalProfilerType& GetProfiler(StatisticalProfilerId id)
{
return m_profilers[static_cast<AZStd::size_t>(id)];
auto iter = m_profilers.try_emplace(id, ProfilerInfo()).first;
return iter->second.m_profiler;
}
void ActivateProfiler(StatisticalProfilerId id, bool activate)
void ActivateProfiler(StatisticalProfilerId id, bool activate, bool autoCreate = true)
{
m_activeProfilersFlag[static_cast<AZStd::size_t>(id)] = activate;
if (autoCreate)
{
auto iter = m_profilers.try_emplace(id, ProfilerInfo()).first;
iter->second.m_enabled = activate;
}
else if (auto iter = m_profilers.find(id); iter != m_profilers.end())
{
iter->second.m_enabled = activate;
}
}
void PushSample(StatisticalProfilerId id, const StatIdType& statId, double value)
{
m_profilers[static_cast<AZStd::size_t>(id)].PushSample(statId, value);
if (auto iter = m_profilers.find(id); iter != m_profilers.end())
{
iter->second.m_profiler.PushSample(statId, value);
}
}
private:
// TODO:BUDGETS the number of bits allocated here must be based on the number of budgets available at profiler registration time
AZStd::bitset<128> m_activeProfilersFlag;
AZStd::vector<StatisticalProfilerType> m_profilers;
struct ProfilerInfo
{
StatisticalProfilerType m_profiler;
bool m_enabled{ false };
};
using ProfilerMap = AZStd::unordered_map<StatisticalProfilerId, ProfilerInfo>;
ProfilerMap m_profilers;
}; // class StatisticalProfilerProxy
}; // namespace AZ::Statistics
+64 -1
View File
@@ -13,14 +13,26 @@
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/RTTI/TypeSafeIntegral.h>
#include <AzCore/std/time.h>
#include <AzCore/std/chrono/chrono.h>
namespace AZ
{
//! This is a strong typedef for representing a millisecond value since application start.
AZ_TYPE_SAFE_INTEGRAL(TimeMs, int64_t);
//! This is a strong typedef for representing a microsecond value since application start.
//! Using int64_t as the underlying type, this is good to represent approximately 292,471 years
AZ_TYPE_SAFE_INTEGRAL(TimeUs, int64_t);
//! @class ITime
//! @brief This is an AZ::Interface<> for managing time related operations.
//! AZ::ITime and associated types may not operate in realtime. These abstractions are to allow our application
//! simulation to operate both slower and faster than realtime in a well defined and user controllable manner
//! The rate at which time passes for AZ::ITime is controlled by the cvar t_scale
//! t_scale == 0 means simulation time should halt
//! 0 < t_scale < 1 will cause time to pass slower than realtime, with t_scale 0.1 being roughly 1/10th realtime
//! t_scale == 1 will cause time to pass at roughly realtime
//! t_scale > 1 will cause time to pass faster than normal, with t_scale 10 being roughly 10x realtime
class ITime
{
public:
@@ -33,6 +45,10 @@ namespace AZ
//! @return the number of milliseconds that have elapsed since application start
virtual TimeMs GetElapsedTimeMs() const = 0;
//! Returns the number of microseconds since application start.
//! @return the number of microseconds that have elapsed since application start
virtual TimeUs GetElapsedTimeUs() const = 0;
AZ_DISABLE_COPY_MOVE(ITime);
};
@@ -51,6 +67,53 @@ namespace AZ
{
return AZ::Interface<ITime>::Get()->GetElapsedTimeMs();
}
}
//! This is a simple convenience wrapper
inline TimeUs GetElapsedTimeUs()
{
return AZ::Interface<ITime>::Get()->GetElapsedTimeUs();
}
//! Converts from milliseconds to microseconds
inline TimeUs TimeMsToUs(TimeMs value)
{
return static_cast<TimeUs>(value * static_cast<TimeMs>(1000));
}
//! Converts from microseconds to milliseconds
inline TimeMs TimeUsToMs(TimeUs value)
{
return static_cast<TimeMs>(value / static_cast<TimeUs>(1000));
}
//! Converts from milliseconds to seconds
inline float TimeMsToSeconds(TimeMs value)
{
return static_cast<float>(value) / 1000.0f;
}
//! Converts from microseconds to seconds
inline float TimeUsToSeconds(TimeUs value)
{
return static_cast<float>(value) / 1000000.0f;
}
//! Converts from milliseconds to AZStd::chrono::time_point
inline auto TimeMsToChrono(TimeMs value)
{
auto epoch = AZStd::chrono::time_point<AZStd::chrono::high_resolution_clock>();
auto chronoValue = AZStd::chrono::milliseconds(aznumeric_cast<int64_t>(value));
return epoch + chronoValue;
}
//! Converts from microseconds to AZStd::chrono::time_point
inline auto TimeUsToChrono(TimeUs value)
{
auto epoch = AZStd::chrono::time_point<AZStd::chrono::high_resolution_clock>();
auto chronoValue = AZStd::chrono::microseconds(aznumeric_cast<int64_t>(value));
return epoch + chronoValue;
}
} // namespace AZ
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(AZ::TimeMs);
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(AZ::TimeUs);
@@ -35,7 +35,7 @@ namespace AZ
TimeSystemComponent::TimeSystemComponent()
{
m_lastInvokedTimeMs = static_cast<TimeMs>(AZStd::GetTimeNowMicroSecond() / 1000);
m_lastInvokedTimeUs = static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
AZ::Interface<ITime>::Register(this);
ITimeRequestBus::Handler::BusConnect();
}
@@ -58,18 +58,23 @@ namespace AZ
TimeMs TimeSystemComponent::GetElapsedTimeMs() const
{
TimeMs currentTime = static_cast<TimeMs>(AZStd::GetTimeNowMicroSecond() / 1000);
TimeMs deltaTime = currentTime - m_lastInvokedTimeMs;
return TimeUsToMs(GetElapsedTimeUs());
}
TimeUs TimeSystemComponent::GetElapsedTimeUs() const
{
TimeUs currentTime = static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
TimeUs deltaTime = currentTime - m_lastInvokedTimeUs;
if (t_scale != 1.0f)
{
float floatDelta = static_cast<float>(deltaTime) * t_scale;
deltaTime = static_cast<TimeMs>(static_cast<int64_t>(floatDelta));
deltaTime = static_cast<TimeUs>(static_cast<int64_t>(floatDelta));
}
m_accumulatedTimeMs += deltaTime;
m_lastInvokedTimeMs = currentTime;
m_accumulatedTimeUs += deltaTime;
m_lastInvokedTimeUs = currentTime;
return m_accumulatedTimeMs;
return m_accumulatedTimeUs;
}
}
@@ -39,11 +39,12 @@ namespace AZ
//! ITime overrides.
//! @{
TimeMs GetElapsedTimeMs() const override;
TimeUs GetElapsedTimeUs() const override;
//! @}
private:
mutable TimeMs m_lastInvokedTimeMs = TimeMs{0};
mutable TimeMs m_accumulatedTimeMs = TimeMs{0};
mutable TimeUs m_lastInvokedTimeUs = TimeUs{0};
mutable TimeUs m_accumulatedTimeUs = TimeUs{0};
};
}
@@ -368,6 +368,21 @@ namespace Platform
return access(fileName, F_OK) == 0;
}
}
bool IsDirectory(const char* filePath)
{
if (AZ::Android::Utils::IsApkPath(filePath))
{
return AZ::Android::APKFileHandler::IsDirectory(AZ::Android::Utils::StripApkPrefix(filePath).c_str());
}
struct stat result;
if (stat(filePath, &result) == 0)
{
return S_ISDIR(result.st_mode);
}
return false;
}
} // namespace AZ::IO::Platform
} // namespace AZ::IO
@@ -38,7 +38,7 @@ namespace AZ
{
return false;
}
for (size_t i = tracerPidOffset; i < numRead; ++i)
for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i)
{
if (!::isspace(processStatusView[i]))
{
@@ -249,6 +249,16 @@ namespace Platform
{
return access(fileName, F_OK) == 0;
}
bool IsDirectory(const char* filePath)
{
struct stat result;
if (stat(filePath, &result) == 0)
{
return S_ISDIR(result.st_mode);
}
return false;
}
}
} // namespace AZ::IO
@@ -10,6 +10,7 @@
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/FileIOEventBus.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/PlatformIncl.h>
#include <AzCore/Utils/Utils.h>
@@ -18,7 +19,7 @@
namespace AZ::IO
{
using FixedMaxPathWString = AZStd::fixed_wstring<MaxPathLength>;
namespace
{
//=========================================================================
@@ -28,16 +29,9 @@ namespace
//=========================================================================
DWORD GetAttributes(const char* fileName)
{
wchar_t fileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
{
return GetFileAttributesW(fileNameW);
}
else
{
return INVALID_FILE_ATTRIBUTES;
}
FixedMaxPathWString fileNameW;
AZStd::to_wstring(fileNameW, fileName);
return GetFileAttributesW(fileNameW.c_str());
}
//=========================================================================
@@ -47,16 +41,9 @@ namespace
//=========================================================================
BOOL SetAttributes(const char* fileName, DWORD fileAttributes)
{
wchar_t fileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
{
return SetFileAttributesW(fileNameW, fileAttributes);
}
else
{
return FALSE;
}
FixedMaxPathWString fileNameW;
AZStd::to_wstring(fileNameW, fileName);
return SetFileAttributesW(fileNameW.c_str(), fileAttributes);
}
//=========================================================================
@@ -68,9 +55,9 @@ namespace
// * GetLastError() on Windows-like platforms
// * errno on Unix platforms
//=========================================================================
bool CreateDirRecursive(wchar_t* dirPath)
bool CreateDirRecursive(AZ::IO::FixedMaxPathWString& dirPath)
{
if (CreateDirectoryW(dirPath, nullptr))
if (CreateDirectoryW(dirPath.c_str(), nullptr))
{
return true; // Created without error
}
@@ -78,28 +65,24 @@ namespace
if (error == ERROR_PATH_NOT_FOUND)
{
// try to create our parent hierarchy
for (size_t i = wcslen(dirPath); i > 0; --i)
if (size_t i = dirPath.find_last_of(LR"(/\)"); i != FixedMaxPathWString::npos)
{
if (dirPath[i] == L'/' || dirPath[i] == L'\\')
wchar_t delimiter = dirPath[i];
dirPath[i] = 0; // null-terminate at the previous slash
const bool ret = CreateDirRecursive(dirPath);
dirPath[i] = delimiter; // restore slash
if (ret)
{
wchar_t delimiter = dirPath[i];
dirPath[i] = 0; // null-terminate at the previous slash
bool ret = CreateDirRecursive(dirPath);
dirPath[i] = delimiter; // restore slash
if (ret)
{
// now that our parent is created, try to create again
return CreateDirectoryW(dirPath, nullptr) != 0;
}
return false;
// now that our parent is created, try to create again
return CreateDirectoryW(dirPath.c_str(), nullptr) != 0;
}
}
// if we reach here then there was no parent folder to create, so we failed for other reasons
}
else if (error == ERROR_ALREADY_EXISTS)
{
DWORD attributes = GetFileAttributesW(dirPath);
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
DWORD attributes = GetFileAttributesW(dirPath.c_str());
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
return false;
}
@@ -152,13 +135,10 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
CreatePath(m_fileName.c_str());
}
wchar_t fileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
AZ::IO::FixedMaxPathWString fileNameW;
AZStd::to_wstring(fileNameW, m_fileName);
m_handle = INVALID_HANDLE_VALUE;
if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName.c_str(), AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
{
m_handle = CreateFileW(fileNameW, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
}
m_handle = CreateFileW(fileNameW.c_str(), dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
if (m_handle == INVALID_HANDLE_VALUE)
{
@@ -350,6 +330,12 @@ namespace Platform
return GetAttributes(fileName) != INVALID_FILE_ATTRIBUTES;
}
bool IsDirectory(const char* filePath)
{
DWORD attributes = GetAttributes(filePath);
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
void FindFiles(const char* filter, SystemFile::FindFileCB cb)
{
@@ -357,35 +343,26 @@ namespace Platform
HANDLE hFile;
int lastError;
wchar_t filterW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
AZ::IO::FixedMaxPathWString filterW;
AZStd::to_wstring(filterW, filter);
hFile = INVALID_HANDLE_VALUE;
if (mbstowcs_s(&numCharsConverted, filterW, filter, AZ_ARRAY_SIZE(filterW) - 1) == 0)
{
hFile = FindFirstFile(filterW, &fd);
}
hFile = FindFirstFileW(filterW.c_str(), &fd);
if (hFile != INVALID_HANDLE_VALUE)
{
const char* fileName;
char fileNameA[AZ_MAX_PATH_LEN];
fileName = NULL;
if (wcstombs_s(&numCharsConverted, fileNameA, fd.cFileName, AZ_ARRAY_SIZE(fileNameA) - 1) == 0)
{
fileName = fileNameA;
}
AZ::IO::FixedMaxPathString fileNameUtf8;
AZStd::to_string(fileNameUtf8, fd.cFileName);
fileName = fileNameUtf8.c_str();
cb(fileName, (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
// List all the other files in the directory.
while (FindNextFileW(hFile, &fd) != 0)
{
fileName = NULL;
if (wcstombs_s(&numCharsConverted, fileNameA, fd.cFileName, AZ_ARRAY_SIZE(fileNameA) - 1) == 0)
{
fileName = fileNameA;
}
AZStd::to_string(fileNameUtf8, fd.cFileName);
fileName = fileNameUtf8.c_str();
cb(fileName, (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
}
@@ -411,12 +388,9 @@ namespace Platform
{
HANDLE handle = nullptr;
wchar_t fileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
{
handle = CreateFileW(fileNameW, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
}
AZ::IO::FixedMaxPathWString fileNameW;
AZStd::to_wstring(fileNameW, fileName);
handle = CreateFileW(fileNameW.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE)
{
@@ -448,12 +422,9 @@ namespace Platform
WIN32_FILE_ATTRIBUTE_DATA data = { 0 };
BOOL result = FALSE;
wchar_t fileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
{
result = GetFileAttributesExW(fileNameW, GetFileExInfoStandard, &data);
}
AZ::IO::FixedMaxPathWString fileNameW;
AZStd::to_wstring(fileNameW, fileName);
result = GetFileAttributesExW(fileNameW.c_str(), GetFileExInfoStandard, &data);
if (result)
{
@@ -473,18 +444,11 @@ namespace Platform
bool Delete(const char* fileName)
{
wchar_t fileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
{
if (DeleteFileW(fileNameW) == 0)
{
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
return false;
}
}
else
AZ::IO::FixedMaxPathWString fileNameW;
AZStd::to_wstring(fileNameW, fileName);
if (DeleteFileW(fileNameW.c_str()) == 0)
{
EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
return false;
}
@@ -493,20 +457,13 @@ namespace Platform
bool Rename(const char* sourceFileName, const char* targetFileName, bool overwrite)
{
wchar_t sourceFileNameW[AZ_MAX_PATH_LEN];
wchar_t targetFileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, sourceFileNameW, sourceFileName, AZ_ARRAY_SIZE(sourceFileNameW) - 1) == 0 &&
mbstowcs_s(&numCharsConverted, targetFileNameW, targetFileName, AZ_ARRAY_SIZE(targetFileNameW) - 1) == 0)
{
if (MoveFileExW(sourceFileNameW, targetFileNameW, overwrite ? MOVEFILE_REPLACE_EXISTING : 0) == 0)
{
EBUS_EVENT(FileIOEventBus, OnError, nullptr, sourceFileName, (int)GetLastError());
return false;
}
}
else
AZ::IO::FixedMaxPathWString sourceFileNameW;
AZStd::to_wstring(sourceFileNameW, sourceFileName);
AZ::IO::FixedMaxPathWString targetFileNameW;
AZStd::to_wstring(targetFileNameW, targetFileName);
if (MoveFileExW(sourceFileNameW.c_str(), targetFileNameW.c_str(), overwrite ? MOVEFILE_REPLACE_EXISTING : 0) == 0)
{
EBUS_EVENT(FileIOEventBus, OnError, nullptr, sourceFileName, (int)GetLastError());
return false;
}
@@ -543,17 +500,14 @@ namespace Platform
{
if (dirName)
{
wchar_t dirPath[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, dirPath, dirName, AZ_ARRAY_SIZE(dirPath) - 1) == 0)
AZ::IO::FixedMaxPathWString dirNameW;
AZStd::to_wstring(dirNameW, dirName);
bool success = CreateDirRecursive(dirNameW);
if (!success)
{
bool success = CreateDirRecursive(dirPath);
if (!success)
{
EBUS_EVENT(FileIOEventBus, OnError, nullptr, dirName, (int)GetLastError());
}
return success;
EBUS_EVENT(FileIOEventBus, OnError, nullptr, dirName, (int)GetLastError());
}
return success;
}
return false;
}
@@ -562,12 +516,9 @@ namespace Platform
{
if (dirName)
{
wchar_t dirNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
if (mbstowcs_s(&numCharsConverted, dirNameW, dirName, AZ_ARRAY_SIZE(dirNameW) - 1) == 0)
{
return RemoveDirectory(dirNameW) != 0;
}
AZ::IO::FixedMaxPathWString dirNameW;
AZStd::to_wstring(dirNameW, dirName);
return RemoveDirectory(dirNameW.c_str()) != 0;
}
return false;
@@ -30,6 +30,8 @@
namespace UnitTest
{
constexpr AZ::u32 ProfilerProxyGroup = AZ_CRC_CE("StatisticalProfilerProxyTests");
class StatisticalProfilerTest
: public AllocatorsFixture
{
@@ -98,10 +100,10 @@ namespace UnitTest
AZ::Statistics::StatisticalProfiler<AZ::Crc32> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -175,10 +177,10 @@ namespace UnitTest
AZ::Statistics::StatisticalProfiler<AZ::Crc32, AZStd::shared_spin_mutex> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -317,26 +319,26 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance = "PerformanceResult";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock = "Block";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
proxy->ActivateProfiler(ProfilerProxyGroup, true);
const int iter_count = 10;
{
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdPerformance)
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdBlock)
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdBlock)
counter++;
}
}
@@ -348,7 +350,7 @@ namespace UnitTest
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
//Clean Up
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
proxy->ActivateProfiler(ProfilerProxyGroup, false);
#undef CODE_PROFILER_PROXY_PUSH_TIME
@@ -362,12 +364,12 @@ namespace UnitTest
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread1("simple_thread1");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread1_loop("simple_thread1_loop");
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread1);
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread1);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread1_loop);
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread1_loop);
counter++;
}
}
@@ -377,12 +379,12 @@ namespace UnitTest
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread2("simple_thread2");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread2_loop("simple_thread2_loop");
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread2);
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread2);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread2_loop);
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread2_loop);
counter++;
}
}
@@ -392,12 +394,13 @@ namespace UnitTest
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread3("simple_thread3");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread3_loop("simple_thread3_loop");
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread3);
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread3);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread3_loop);
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread3_loop);
counter++;
}
}
@@ -408,21 +411,21 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1 = "simple_thread1";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1("simple_thread1");
const AZStd::string statNameThread1("simple_thread1");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop = "simple_thread1_loop";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop("simple_thread1_loop");
const AZStd::string statNameThread1Loop("simple_thread1_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2 = "simple_thread2";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2("simple_thread2");
const AZStd::string statNameThread2("simple_thread2");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop = "simple_thread2_loop";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop("simple_thread2_loop");
const AZStd::string statNameThread2Loop("simple_thread2_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3 = "simple_thread3";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3("simple_thread3");
const AZStd::string statNameThread3("simple_thread3");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop = "simple_thread3_loop";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop("simple_thread3_loop");
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
@@ -432,7 +435,7 @@ namespace UnitTest
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
proxy->ActivateProfiler(ProfilerProxyGroup, true);
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 10;
@@ -459,7 +462,7 @@ namespace UnitTest
EXPECT_EQ(profiler.GetStatistic(statIdThread3Loop)->GetNumSamples(), iter_count);
//Clean Up
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
proxy->ActivateProfiler(ProfilerProxyGroup, false);
}
/** Trace message handler to track messages during tests
@@ -566,10 +569,10 @@ namespace UnitTest
AZ::Statistics::StatisticalProfiler<AZ::Crc32> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -647,10 +650,10 @@ namespace UnitTest
AZ::Statistics::StatisticalProfiler<AZ::Crc32, AZStd::shared_spin_mutex> profiler;
const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -745,26 +748,26 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance = "PerformanceResult";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock = "Block";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
proxy->ActivateProfiler(ProfilerProxyGroup, true);
const int iter_count = 1000000;
{
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdPerformance)
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdBlock)
CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdBlock)
counter++;
}
}
@@ -778,7 +781,7 @@ namespace UnitTest
profiler.LogAndResetStats("StatisticalProfilerProxy");
//Clean Up
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
proxy->ActivateProfiler(ProfilerProxyGroup, false);
}
#undef CODE_PROFILER_PROXY_PUSH_TIME
@@ -788,21 +791,21 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface<AZ::Statistics::StatisticalProfilerProxy>::Get();
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1 = "simple_thread1";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1("simple_thread1");
const AZStd::string statNameThread1("simple_thread1");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop = "simple_thread1_loop";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop("simple_thread1_loop");
const AZStd::string statNameThread1Loop("simple_thread1_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2 = "simple_thread2";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2("simple_thread2");
const AZStd::string statNameThread2("simple_thread2");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop = "simple_thread2_loop";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop("simple_thread2_loop");
const AZStd::string statNameThread2Loop("simple_thread2_loop");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3 = "simple_thread3";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3("simple_thread3");
const AZStd::string statNameThread3("simple_thread3");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop = "simple_thread3_loop";
const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop("simple_thread3_loop");
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
@@ -812,7 +815,7 @@ namespace UnitTest
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
proxy->ActivateProfiler(ProfilerProxyGroup, true);
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 1000000;
@@ -841,7 +844,7 @@ namespace UnitTest
profiler.LogAndResetStats("3_Threads_StatisticalProfilerProxy");
//Clean Up
proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
proxy->ActivateProfiler(ProfilerProxyGroup, false);
}
}//namespace UnitTest
@@ -0,0 +1,56 @@
/*
* 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/Time/TimeSystemComponent.h>
#include <AzCore/UnitTest/TestTypes.h>
namespace UnitTest
{
class TimeTests
: public AllocatorsFixture
{
public:
void SetUp() override
{
SetupAllocator();
m_timeComponent = new AZ::TimeSystemComponent;
}
void TearDown() override
{
delete m_timeComponent;
TeardownAllocator();
}
AZ::TimeSystemComponent* m_timeComponent = nullptr;
};
TEST_F(TimeTests, TestConversionUsToMs)
{
AZ::TimeUs timeUs = AZ::TimeUs{ 1000 };
AZ::TimeMs timeMs = AZ::TimeUsToMs(timeUs);
EXPECT_EQ(timeMs, AZ::TimeMs{ 1 });
}
TEST_F(TimeTests, TestConversionMsToUs)
{
AZ::TimeMs timeMs = AZ::TimeMs{ 1000 };
AZ::TimeUs timeUs = AZ::TimeMsToUs(timeMs);
EXPECT_EQ(timeUs, AZ::TimeUs{ 1000000 });
}
TEST_F(TimeTests, TestClocks)
{
AZ::TimeUs timeUs = AZ::GetElapsedTimeUs();
AZ::TimeMs timeMs = AZ::GetElapsedTimeMs();
AZ::TimeMs timeUsToMs = AZ::TimeUsToMs(timeUs);
int64_t delta = static_cast<int64_t>(timeMs) - static_cast<int64_t>(timeUsToMs);
EXPECT_LT(abs(delta), 1);
}
}
@@ -61,6 +61,7 @@ set(FILES
Slice.cpp
State.cpp
Statistics.cpp
StatisticalProfiler.cpp
StreamerTests.cpp
StringFunc.cpp
SystemFile.cpp
@@ -127,6 +128,7 @@ set(FILES
Serialization/Json/UnorderedSetSerializerTests.cpp
Serialization/Json/UnsupportedTypesSerializerTests.cpp
Serialization/Json/UuidSerializerTests.cpp
Time/TimeTests.cpp
Math/AabbTests.cpp
Math/ColorTests.cpp
Math/CrcTests.cpp
@@ -281,6 +281,14 @@ namespace AZ
return SystemFile::Exists(resolvedPath);
}
bool LocalFileIO::IsDirectory(const char* filePath)
{
char resolvedPath[AZ_MAX_PATH_LEN];
ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
return SystemFile::IsDirectory(resolvedPath);
}
void LocalFileIO::CheckInvalidWrite([[maybe_unused]] const char* path)
{
#if defined(AZ_ENABLE_TRACING)
@@ -28,9 +28,12 @@ namespace AzFramework
//! @note This is used to drive event driven updates to the visibility system.
virtual void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) = 0;
//! Returns the cached union of all component Aabbs.
//! Returns the cached union of all component Aabbs in local entity space.
virtual AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const = 0;
//! Returns the cached union of all component Aabbs in world space.
virtual AZ::Aabb GetEntityWorldBoundsUnion(AZ::EntityId entityId) const = 0;
//! Writes the current changes made to all entities (transforms and bounds) to the visibility system.
//! @note During normal operation this is called every frame in OnTick but can
//! also be called explicitly (e.g. For testing purposes).
@@ -128,6 +128,24 @@ namespace AzFramework
return AZ::Aabb::CreateNull();
}
AZ::Aabb EntityVisibilityBoundsUnionSystem::GetEntityWorldBoundsUnion(const AZ::EntityId entityId) const
{
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
if (entity != nullptr)
{
// if the entity is not found in the mapping then return a null Aabb, this is to mimic
// as closely as possible the behavior of an individual GetLocalBounds call to an Entity that
// had been deleted (there would be no response, leaving the default value assigned)
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
{
return instance_it->second.m_localEntityBoundsUnion.GetTranslated(entity->GetTransform()->GetWorldTranslation());
}
}
return AZ::Aabb::CreateNull();
}
void EntityVisibilityBoundsUnionSystem::ProcessEntityBoundsUnionRequests()
{
AZ_PROFILE_FUNCTION(AzFramework);
@@ -31,6 +31,7 @@ namespace AzFramework
// EntityBoundsUnionRequestBus overrides ...
void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) override;
AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const override;
AZ::Aabb GetEntityWorldBoundsUnion(AZ::EntityId entityId) const override;
void ProcessEntityBoundsUnionRequests() override;
void OnTransformUpdated(AZ::Entity* entity) override;
@@ -40,26 +40,6 @@ namespace AZ
{
namespace IO
{
bool LocalFileIO::IsDirectory(const char* filePath)
{
ANDROID_IO_PROFILE_SECTION_ARGS("IsDir:%s", filePath);
char resolvedPath[AZ_MAX_PATH_LEN];
ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
if (AZ::Android::Utils::IsApkPath(resolvedPath))
{
return AZ::Android::APKFileHandler::IsDirectory(AZ::Android::Utils::StripApkPrefix(resolvedPath).c_str());
}
struct stat result;
if (stat(resolvedPath, &result) == 0)
{
return S_ISDIR(result.st_mode);
}
return false;
}
Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath)
{
char resolvedSourcePath[AZ_MAX_PATH_LEN];
@@ -17,19 +17,6 @@ namespace AZ
{
namespace IO
{
bool LocalFileIO::IsDirectory(const char* filePath)
{
char resolvedPath[AZ_MAX_PATH_LEN] = {0};
ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
struct stat result;
if (stat(resolvedPath, &result) == 0)
{
return S_ISDIR(result.st_mode);
}
return false;
}
Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath)
{
char resolvedSourceFilePath[AZ_MAX_PATH_LEN] = {0};
@@ -15,22 +15,6 @@ namespace AZ
{
namespace IO
{
bool LocalFileIO::IsDirectory(const char* filePath)
{
char resolvedPath[AZ_MAX_PATH_LEN];
ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
wchar_t resolvedPathW[AZ_MAX_PATH_LEN];
AZStd::to_wstring(resolvedPathW, AZ_MAX_PATH_LEN, resolvedPath);
DWORD fileAttributes = GetFileAttributesW(resolvedPathW);
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
{
return false;
}
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
Result LocalFileIO::FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback)
{
char resolvedPath[AZ_MAX_PATH_LEN];
+142 -193
View File
@@ -14,7 +14,6 @@
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/IO/FileOperations.h>
#include <time.h>
#include <AzTest/Utils.h>
@@ -30,21 +29,6 @@ using namespace AZ;
using namespace AZ::IO;
using namespace AZ::Debug;
namespace PathUtil
{
AZStd::string AddSlash(const AZStd::string& path)
{
if (path.empty() || path[path.length() - 1] == '/')
{
return path;
}
if (path[path.length() - 1] == '\\')
{
return path.substr(0, path.length() - 1) + "/";
}
return path + "/";
}
}
namespace UnitTest
{
@@ -161,15 +145,16 @@ namespace UnitTest
: public ScopedAllocatorSetupFixture
{
public:
AZStd::string m_root;
AZStd::string folderName;
AZStd::string deepFolder;
AZStd::string extraFolder;
AZ::Test::ScopedAutoTempDirectory m_tempDir;
AZ::IO::Path m_root;
AZ::IO::Path m_folderName;
AZ::IO::Path m_deepFolder;
AZ::IO::Path m_extraFolder;
AZStd::string fileRoot;
AZStd::string file01Name;
AZStd::string file02Name;
AZStd::string file03Name;
AZ::IO::Path m_fileRoot;
AZ::IO::Path m_file01Name;
AZ::IO::Path m_file02Name;
AZ::IO::Path m_file03Name;
int m_randomFolderKey = 0;
FolderFixture()
@@ -179,43 +164,13 @@ namespace UnitTest
void ChooseRandomFolder()
{
char currentDir[AZ_MAX_PATH_LEN];
AZ::Utils::GetExecutableDirectory(currentDir, AZ_MAX_PATH_LEN);
folderName = currentDir;
folderName.append("/temp");
m_root = folderName;
if (folderName.size() > 0)
{
folderName = PathUtil::AddSlash(folderName);
}
AZStd::string tempName = AZStd::string::format("tmp%08x", m_randomFolderKey);
folderName.append(tempName.c_str());
folderName = PathUtil::AddSlash(folderName);
AZStd::replace(folderName.begin(), folderName.end(), '\\', '/');
// Make sure the drive letter is capitalized
if (folderName.size() > 2)
{
if (folderName[1] == ':')
{
folderName[0] = static_cast<char>(toupper(folderName[0]));
}
}
deepFolder = folderName;
deepFolder.append("test");
deepFolder = PathUtil::AddSlash(deepFolder);
deepFolder.append("subdir");
extraFolder = deepFolder;
extraFolder = PathUtil::AddSlash(extraFolder);
extraFolder.append("subdir2");
m_root = m_tempDir.GetDirectory();
m_folderName = m_root / AZStd::string::format("tmp%08x", m_randomFolderKey);
m_deepFolder = m_folderName / "test" / "subdir";
m_extraFolder = m_deepFolder / "subdir2";
// make a couple files there, and in the root:
fileRoot = PathUtil::AddSlash(extraFolder);
m_fileRoot = m_extraFolder;
}
void SetUp() override
@@ -229,37 +184,33 @@ namespace UnitTest
{
ChooseRandomFolder();
++m_randomFolderKey;
} while (local.IsDirectory(fileRoot.c_str()));
} while (local.IsDirectory(m_fileRoot.c_str()));
file01Name = fileRoot + "file01.txt";
file02Name = fileRoot + "file02.asdf";
file03Name = fileRoot + "test123.wha";
m_file01Name = m_fileRoot / "file01.txt";
m_file02Name = m_fileRoot / "file02.asdf";
m_file03Name = m_fileRoot / "test123.wha";
}
void TearDown() override
{
if ((!folderName.empty())&&(strstr(folderName.c_str(), "/temp") != nullptr))
{
// cleanup!
LocalFileIO local;
local.DestroyPath(folderName.c_str());
}
}
void CreateTestFiles()
{
constexpr auto openMode = SystemFile::OpenMode::SF_OPEN_WRITE_ONLY
| SystemFile::OpenMode::SF_OPEN_CREATE
| SystemFile::OpenMode::SF_OPEN_CREATE_NEW;
constexpr AZStd::string_view testContent("this is just a test");
LocalFileIO local;
AZ_TEST_ASSERT(local.CreatePath(fileRoot.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(fileRoot.c_str()));
for (const AZStd::string& filename : { file01Name, file02Name, file03Name })
AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
for (const AZ::IO::Path& filename : { m_file01Name, m_file02Name, m_file03Name })
{
#ifdef AZ_COMPILER_MSVC
FILE* tempFile;
fopen_s(&tempFile, filename.c_str(), "wb");
#else
FILE* tempFile = fopen(filename.c_str(), "wb");
#endif
fwrite("this is just a test", 1, 19, tempFile);
fclose(tempFile);
SystemFile tempFile;
tempFile.Open(filename.c_str(), openMode);
tempFile.Write(testContent.data(), testContent.size());
tempFile.Close();
}
}
};
@@ -272,28 +223,23 @@ namespace UnitTest
{
LocalFileIO local;
AZ_TEST_ASSERT(!local.Exists(folderName.c_str()));
AZ_TEST_ASSERT(!local.Exists(m_folderName.c_str()));
AZStd::string longPathCreateTest = folderName;
longPathCreateTest.append("one");
longPathCreateTest = PathUtil::AddSlash(longPathCreateTest);
longPathCreateTest.append("two");
longPathCreateTest = PathUtil::AddSlash(longPathCreateTest);
longPathCreateTest.append("three");
AZ::IO::Path longPathCreateTest = m_folderName / "one" / "two" / "three";
AZ_TEST_ASSERT(!local.Exists(longPathCreateTest.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(longPathCreateTest.c_str()));
AZ_TEST_ASSERT(local.CreatePath(longPathCreateTest.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(longPathCreateTest.c_str()));
AZ_TEST_ASSERT(!local.Exists(deepFolder.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(deepFolder.c_str()));
AZ_TEST_ASSERT(local.CreatePath(deepFolder.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(deepFolder.c_str()));
AZ_TEST_ASSERT(!local.Exists(m_deepFolder.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(m_deepFolder.c_str()));
AZ_TEST_ASSERT(local.CreatePath(m_deepFolder.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(m_deepFolder.c_str()));
AZ_TEST_ASSERT(local.Exists(deepFolder.c_str()));
AZ_TEST_ASSERT(local.CreatePath(deepFolder.c_str()));
AZ_TEST_ASSERT(local.Exists(deepFolder.c_str()));
AZ_TEST_ASSERT(local.Exists(m_deepFolder.c_str()));
AZ_TEST_ASSERT(local.CreatePath(m_deepFolder.c_str()));
AZ_TEST_ASSERT(local.Exists(m_deepFolder.c_str()));
}
};
@@ -310,16 +256,19 @@ namespace UnitTest
{
LocalFileIO local;
AZ_TEST_ASSERT(!local.Exists(fileRoot.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(fileRoot.c_str()));
AZ_TEST_ASSERT(local.CreatePath(fileRoot.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(fileRoot.c_str()));
AZ_TEST_ASSERT(!local.Exists(m_fileRoot.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(m_fileRoot.c_str()));
AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
FILE* tempFile = nullptr;
azfopen(&tempFile, file01Name.c_str(), "wb");
fwrite("this is just a test", 1, 19, tempFile);
fclose(tempFile);
constexpr auto openMode = SystemFile::OpenMode::SF_OPEN_WRITE_ONLY
| SystemFile::OpenMode::SF_OPEN_CREATE
| SystemFile::OpenMode::SF_OPEN_CREATE_NEW;
SystemFile tempFile;
tempFile.Open(m_file01Name.c_str(), openMode);
constexpr AZStd::string_view testContent("this is just a test");
tempFile.Write(testContent.data(), testContent.size());
tempFile.Close();
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ_TEST_ASSERT(!local.Open("", AZ::IO::OpenMode::ModeWrite, fileHandle));
@@ -327,12 +276,12 @@ namespace UnitTest
// test size without opening:
AZ::u64 fs = 0;
AZ_TEST_ASSERT(local.Size(file01Name.c_str(), fs));
AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), fs));
AZ_TEST_ASSERT(fs == 19);
fileHandle = AZ::IO::InvalidHandle;
AZ::u64 modTimeA = local.ModificationTime(file01Name.c_str());
AZ::u64 modTimeA = local.ModificationTime(m_file01Name.c_str());
AZ_TEST_ASSERT(modTimeA != 0);
// test invalid handle ops:
@@ -344,14 +293,14 @@ namespace UnitTest
AZ_TEST_ASSERT(!local.Read(fileHandle, nullptr, 0, false));
AZ_TEST_ASSERT(!local.Tell(fileHandle, fs));
AZ_TEST_ASSERT(!local.Exists((file01Name + "notexist").c_str()));
AZ_TEST_ASSERT(!local.Exists((m_file01Name.Native() + "notexist").c_str()));
AZ_TEST_ASSERT(local.Exists(file01Name.c_str()));
AZ_TEST_ASSERT(!local.IsReadOnly(file01Name.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(file01Name.c_str()));
AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
AZ_TEST_ASSERT(!local.IsReadOnly(m_file01Name.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(m_file01Name.c_str()));
// test reads and seeks.
AZ_TEST_ASSERT(local.Open(file01Name.c_str(), AZ::IO::OpenMode::ModeRead, fileHandle));
AZ_TEST_ASSERT(local.Open(m_file01Name.c_str(), AZ::IO::OpenMode::ModeRead, fileHandle));
AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
// use this again later...
@@ -368,7 +317,7 @@ namespace UnitTest
// test size without opening, after its already open:
fs = 0;
AZ_TEST_ASSERT(local.Size(file01Name.c_str(), fs));
AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), fs));
AZ_TEST_ASSERT(fs == 19);
AZ::u64 offs = 0;
@@ -442,22 +391,22 @@ namespace UnitTest
#if AZ_TRAIT_AZFRAMEWORKTEST_PERFORM_CHMOD_TEST
#if AZ_TRAIT_USE_WINDOWS_FILE_API
_chmod(file01Name.c_str(), _S_IREAD);
_chmod(m_file01Name.c_str(), _S_IREAD);
#else
chmod(file01Name.c_str(), S_IRUSR | S_IRGRP | S_IROTH);
chmod(m_file01Name.c_str(), S_IRUSR | S_IRGRP | S_IROTH);
#endif
AZ_TEST_ASSERT(local.IsReadOnly(file01Name.c_str()));
AZ_TEST_ASSERT(local.IsReadOnly(m_file01Name.c_str()));
#if AZ_TRAIT_USE_WINDOWS_FILE_API
_chmod(file01Name.c_str(), _S_IREAD | _S_IWRITE);
_chmod(m_file01Name.c_str(), _S_IREAD | _S_IWRITE);
#else
chmod(file01Name.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
chmod(m_file01Name.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
#endif
#endif
AZ_TEST_ASSERT(!local.IsReadOnly(file01Name.c_str()));
AZ_TEST_ASSERT(!local.IsReadOnly(m_file01Name.c_str()));
}
};
@@ -474,14 +423,14 @@ namespace UnitTest
{
LocalFileIO local;
AZ_TEST_ASSERT(local.CreatePath(fileRoot.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(fileRoot.c_str()));
AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
{
#ifdef AZ_COMPILER_MSVC
FILE* tempFile;
fopen_s(&tempFile, file01Name.c_str(), "wb");
fopen_s(&tempFile, m_file01Name.c_str(), "wb");
#else
FILE* tempFile = fopen(file01Name.c_str(), "wb");
FILE* tempFile = fopen(m_file01Name.c_str(), "wb");
#endif
fwrite("this is just a test", 1, 19, tempFile);
fclose(tempFile);
@@ -489,47 +438,47 @@ namespace UnitTest
// make sure attributes are copied (such as modtime) even if they're copied:
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
AZ_TEST_ASSERT(local.Copy(file01Name.c_str(), file02Name.c_str()));
AZ_TEST_ASSERT(local.Copy(m_file01Name.c_str(), m_file02Name.c_str()));
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
AZ_TEST_ASSERT(local.Copy(file01Name.c_str(), file03Name.c_str()));
AZ_TEST_ASSERT(local.Copy(m_file01Name.c_str(), m_file03Name.c_str()));
AZ_TEST_ASSERT(local.Exists(file01Name.c_str()));
AZ_TEST_ASSERT(local.Exists(file02Name.c_str()));
AZ_TEST_ASSERT(local.Exists(file03Name.c_str()));
AZ_TEST_ASSERT(!local.DestroyPath(file01Name.c_str())); // you may not destroy files.
AZ_TEST_ASSERT(!local.DestroyPath(file02Name.c_str()));
AZ_TEST_ASSERT(!local.DestroyPath(file03Name.c_str()));
AZ_TEST_ASSERT(local.Exists(file01Name.c_str()));
AZ_TEST_ASSERT(local.Exists(file02Name.c_str()));
AZ_TEST_ASSERT(local.Exists(file03Name.c_str()));
AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
AZ_TEST_ASSERT(local.Exists(m_file02Name.c_str()));
AZ_TEST_ASSERT(local.Exists(m_file03Name.c_str()));
AZ_TEST_ASSERT(!local.DestroyPath(m_file01Name.c_str())); // you may not destroy files.
AZ_TEST_ASSERT(!local.DestroyPath(m_file02Name.c_str()));
AZ_TEST_ASSERT(!local.DestroyPath(m_file03Name.c_str()));
AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
AZ_TEST_ASSERT(local.Exists(m_file02Name.c_str()));
AZ_TEST_ASSERT(local.Exists(m_file03Name.c_str()));
AZ::u64 f1s = 0;
AZ::u64 f2s = 0;
AZ::u64 f3s = 0;
AZ_TEST_ASSERT(local.Size(file01Name.c_str(), f1s));
AZ_TEST_ASSERT(local.Size(file02Name.c_str(), f2s));
AZ_TEST_ASSERT(local.Size(file03Name.c_str(), f3s));
AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), f1s));
AZ_TEST_ASSERT(local.Size(m_file02Name.c_str(), f2s));
AZ_TEST_ASSERT(local.Size(m_file03Name.c_str(), f3s));
AZ_TEST_ASSERT(f1s == f2s);
AZ_TEST_ASSERT(f1s == f3s);
// Copying over top other files is allowed
SystemFile file;
EXPECT_TRUE(file.Open(file01Name.c_str(), SystemFile::SF_OPEN_WRITE_ONLY));
EXPECT_TRUE(file.Open(m_file01Name.c_str(), SystemFile::SF_OPEN_WRITE_ONLY));
file.Write("this is just a test that is longer", 34);
file.Close();
// make sure attributes are copied (such as modtime) even if they're copied:
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
EXPECT_TRUE(local.Copy(file01Name.c_str(), file02Name.c_str()));
EXPECT_TRUE(local.Copy(m_file01Name.c_str(), m_file02Name.c_str()));
f1s = 0;
f2s = 0;
f3s = 0;
EXPECT_TRUE(local.Size(file01Name.c_str(), f1s));
EXPECT_TRUE(local.Size(file02Name.c_str(), f2s));
EXPECT_TRUE(local.Size(file03Name.c_str(), f3s));
EXPECT_TRUE(local.Size(m_file01Name.c_str(), f1s));
EXPECT_TRUE(local.Size(m_file02Name.c_str(), f2s));
EXPECT_TRUE(local.Size(m_file03Name.c_str(), f3s));
EXPECT_EQ(f1s, f2s);
EXPECT_NE(f1s, f3s);
}
@@ -552,37 +501,37 @@ namespace UnitTest
AZ::u64 modTimeC = 0;
AZ::u64 modTimeD = 0;
modTimeC = local.ModificationTime(file02Name.c_str());
modTimeD = local.ModificationTime(file03Name.c_str());
modTimeC = local.ModificationTime(m_file02Name.c_str());
modTimeD = local.ModificationTime(m_file03Name.c_str());
// make sure modtimes are in ascending order (at least)
AZ_TEST_ASSERT(modTimeD >= modTimeC);
// now touch some of the files. This is also how we test append mode, and write mode.
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ_TEST_ASSERT(local.Open(file02Name.c_str(), AZ::IO::OpenMode::ModeAppend | AZ::IO::OpenMode::ModeBinary, fileHandle));
AZ_TEST_ASSERT(local.Open(m_file02Name.c_str(), AZ::IO::OpenMode::ModeAppend | AZ::IO::OpenMode::ModeBinary, fileHandle));
AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
AZ_TEST_ASSERT(local.Write(fileHandle, "more", 4));
AZ_TEST_ASSERT(local.Close(fileHandle));
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
// No-append-mode
AZ_TEST_ASSERT(local.Open(file03Name.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary, fileHandle));
AZ_TEST_ASSERT(local.Open(m_file03Name.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary, fileHandle));
AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
AZ_TEST_ASSERT(local.Write(fileHandle, "more", 4));
AZ_TEST_ASSERT(local.Close(fileHandle));
modTimeC = local.ModificationTime(file02Name.c_str());
modTimeD = local.ModificationTime(file03Name.c_str());
modTimeC = local.ModificationTime(m_file02Name.c_str());
modTimeD = local.ModificationTime(m_file03Name.c_str());
AZ_TEST_ASSERT(modTimeD > modTimeC);
AZ::u64 f1s = 0;
AZ::u64 f2s = 0;
AZ::u64 f3s = 0;
AZ_TEST_ASSERT(local.Size(file01Name.c_str(), f1s));
AZ_TEST_ASSERT(local.Size(file02Name.c_str(), f2s));
AZ_TEST_ASSERT(local.Size(file03Name.c_str(), f3s));
AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), f1s));
AZ_TEST_ASSERT(local.Size(m_file02Name.c_str(), f2s));
AZ_TEST_ASSERT(local.Size(m_file03Name.c_str(), f3s));
AZ_TEST_ASSERT(f2s == f1s + 4);
AZ_TEST_ASSERT(f3s == 4);
}
@@ -603,8 +552,8 @@ namespace UnitTest
CreateTestFiles();
AZStd::vector<AZStd::string> resultFiles;
bool foundOK = local.FindFiles(fileRoot.c_str(), "*",
AZStd::vector<AZ::IO::Path> resultFiles;
bool foundOK = local.FindFiles(m_fileRoot.c_str(), "*",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -616,7 +565,7 @@ namespace UnitTest
resultFiles.clear();
foundOK = local.FindFiles(fileRoot.c_str(), "*",
foundOK = local.FindFiles(m_fileRoot.c_str(), "*",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -627,7 +576,7 @@ namespace UnitTest
AZ_TEST_ASSERT(resultFiles.size() == 3);
// note: following tests accumulate more files without clearing resultfiles.
foundOK = local.FindFiles(fileRoot.c_str(), "*.txt",
foundOK = local.FindFiles(m_fileRoot.c_str(), "*.txt",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -637,7 +586,7 @@ namespace UnitTest
AZ_TEST_ASSERT(foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 4);
foundOK = local.FindFiles(fileRoot.c_str(), "file*.asdf",
foundOK = local.FindFiles(m_fileRoot.c_str(), "file*.asdf",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -647,7 +596,7 @@ namespace UnitTest
AZ_TEST_ASSERT(foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 5);
foundOK = local.FindFiles(fileRoot.c_str(), "asaf.asdf",
foundOK = local.FindFiles(m_fileRoot.c_str(), "asaf.asdf",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -660,7 +609,7 @@ namespace UnitTest
resultFiles.clear();
// test to make sure directories show up:
foundOK = local.FindFiles(deepFolder.c_str(), "*",
foundOK = local.FindFiles(m_deepFolder.c_str(), "*",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -668,11 +617,11 @@ namespace UnitTest
});
// canonicalize the name in the same way that find does.
//AZStd::replace() extraFolder.replace('\\', '/'); FIXME PPATEL
//AZStd::replace() m_extraFolder.replace('\\', '/'); FIXME PPATEL
AZ_TEST_ASSERT(foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 1);
AZ_TEST_ASSERT(resultFiles[0] == extraFolder);
AZ_TEST_ASSERT(resultFiles[0] == m_extraFolder);
resultFiles.clear();
foundOK = local.FindFiles("o:137787621!@#$%^&&**())_+[])_", "asaf.asdf",
[&](const char* filePath) -> bool
@@ -684,13 +633,13 @@ namespace UnitTest
AZ_TEST_ASSERT(!foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 0);
AZStd::string file04Name = fileRoot + "test.wha";
AZ::IO::Path file04Name = m_fileRoot / "test.wha";
// test rename
AZ_TEST_ASSERT(local.Rename(file03Name.c_str(), file04Name.c_str()));
AZ_TEST_ASSERT(!local.Rename(file03Name.c_str(), file04Name.c_str()));
AZ_TEST_ASSERT(local.Rename(m_file03Name.c_str(), file04Name.c_str()));
AZ_TEST_ASSERT(!local.Rename(m_file03Name.c_str(), file04Name.c_str()));
AZ_TEST_ASSERT(local.Rename(file04Name.c_str(), file04Name.c_str())); // this is valid and ok
AZ_TEST_ASSERT(local.Exists(file04Name.c_str()));
AZ_TEST_ASSERT(!local.Exists(file03Name.c_str()));
AZ_TEST_ASSERT(!local.Exists(m_file03Name.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(file04Name.c_str()));
AZ::u64 f3s = 0;
@@ -698,8 +647,8 @@ namespace UnitTest
AZ_TEST_ASSERT(f3s == 19);
// deep destroy directory:
AZ_TEST_ASSERT(local.DestroyPath(folderName.c_str()));
AZ_TEST_ASSERT(!local.Exists(folderName.c_str()));
AZ_TEST_ASSERT(local.DestroyPath(m_folderName.c_str()));
AZ_TEST_ASSERT(!local.Exists(m_folderName.c_str()));
}
};
@@ -715,7 +664,7 @@ namespace UnitTest
AZ::IO::LocalFileIO local;
// test aliases
local.SetAlias("@test@", folderName.c_str());
local.SetAlias("@test@", m_folderName.c_str());
const char* testDest1 = local.GetAlias("@test@");
AZ_TEST_ASSERT(testDest1 != nullptr);
const char* testDest2 = local.GetAlias("@NOPE@");
@@ -725,18 +674,18 @@ namespace UnitTest
// test resolving
const char* aliasTestPath = "@test@\\some\\path\\somefile.txt";
char aliasResolvedPath[AZ_MAX_PATH_LEN];
bool resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, AZ_MAX_PATH_LEN);
char aliasResolvedPath[AZ::IO::MaxPathLength];
bool resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, AZ::IO::MaxPathLength);
AZ_TEST_ASSERT(resolveDidWork);
AZStd::string expectedResolvedPath = folderName + "some/path/somefile.txt";
AZ::IO::Path expectedResolvedPath = m_folderName / "some/path/somefile.txt";
AZ_TEST_ASSERT(aliasResolvedPath == expectedResolvedPath);
// more resolve path tests with invalid inputs
const char* testPath = nullptr;
char* testResolvedPath = nullptr;
resolveDidWork = local.ResolvePath(testPath, aliasResolvedPath, AZ_MAX_PATH_LEN);
resolveDidWork = local.ResolvePath(testPath, aliasResolvedPath, AZ::IO::MaxPathLength);
AZ_TEST_ASSERT(!resolveDidWork);
resolveDidWork = local.ResolvePath(aliasTestPath, testResolvedPath, AZ_MAX_PATH_LEN);
resolveDidWork = local.ResolvePath(aliasTestPath, testResolvedPath, AZ::IO::MaxPathLength);
AZ_TEST_ASSERT(!resolveDidWork);
resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, 0);
AZ_TEST_ASSERT(!resolveDidWork);
@@ -751,7 +700,7 @@ namespace UnitTest
// Test that sending in a too small output path fails,
// if the output buffer is too small to hold the resolved path
size_t SMALLER_THAN_FINAL_RESOLVED_PATH = expectedResolvedPath.length() - 1;
size_t SMALLER_THAN_FINAL_RESOLVED_PATH = expectedResolvedPath.Native().length() - 1;
AZ_TEST_START_TRACE_SUPPRESSION;
resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, SMALLER_THAN_FINAL_RESOLVED_PATH);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
@@ -766,22 +715,23 @@ namespace UnitTest
TEST_F(AliasTest, ResolvePath_PathViewOverload_Succeeds)
{
AZ::IO::LocalFileIO local;
local.SetAlias("@test@", folderName.c_str());
local.SetAlias("@test@", m_folderName.c_str());
AZ::IO::PathView aliasTestPath = "@test@\\some\\path\\somefile.txt";
AZ::IO::FixedMaxPath aliasResolvedPath;
ASSERT_TRUE(local.ResolvePath(aliasResolvedPath, aliasTestPath));
const auto expectedResolvedPath = AZ::IO::FixedMaxPathString::format("%ssome/path/somefile.txt", folderName.c_str());
EXPECT_STREQ(expectedResolvedPath.c_str(), aliasResolvedPath.c_str());
AZ::IO::Path expectedResolvedPath = m_folderName / "some" / "path" / "somefile.txt";
EXPECT_EQ(expectedResolvedPath, aliasResolvedPath);
AZStd::optional<AZ::IO::FixedMaxPath> optionalResolvedPath = local.ResolvePath(aliasTestPath);
ASSERT_TRUE(optionalResolvedPath);
EXPECT_STREQ(expectedResolvedPath.c_str(), optionalResolvedPath->c_str());
EXPECT_EQ(expectedResolvedPath, optionalResolvedPath.value());
}
TEST_F(AliasTest, ResolvePath_PathViewOverloadWithEmptyPath_Fails)
{
AZ::IO::LocalFileIO local;
local.SetAlias("@test@", folderName.c_str());
local.SetAlias("@test@", m_folderName.c_str());
AZ::IO::FixedMaxPath aliasResolvedPath;
EXPECT_FALSE(local.ResolvePath(aliasResolvedPath, {}));
}
@@ -860,24 +810,23 @@ namespace UnitTest
{
LocalFileIO localFileIO;
AZ::IO::FileIOBase::SetInstance(&localFileIO);
AZStd::string path;
AzFramework::StringFunc::Path::GetFullPath(file01Name.c_str(), path);
AZ::IO::Path path = m_file01Name.ParentPath();
AZ_TEST_ASSERT(localFileIO.CreatePath(path.c_str()));
AzFramework::StringFunc::Path::GetFullPath(file02Name.c_str(), path);
path = m_file01Name.ParentPath();
AZ_TEST_ASSERT(localFileIO.CreatePath(path.c_str()));
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
localFileIO.Open(file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
localFileIO.Write(fileHandle, "DummyFile", 9);
localFileIO.Close(fileHandle);
AZ::IO::HandleType fileHandle1 = AZ::IO::InvalidHandle;
localFileIO.Open(file02Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle1);
localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle1);
localFileIO.Write(fileHandle1, "TestFile", 8);
localFileIO.Close(fileHandle1);
fileHandle1 = AZ::IO::InvalidHandle;
localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
static const size_t testStringLen = 256;
char testString[testStringLen] = { 0 };
localFileIO.Read(fileHandle1, testString, testStringLen);
@@ -885,50 +834,50 @@ namespace UnitTest
AZ_TEST_ASSERT(strncmp(testString, "TestFile", 8) == 0);
// try swapping files when none of the files are in use
AZ_TEST_ASSERT(AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
AZ_TEST_ASSERT(AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
fileHandle1 = AZ::IO::InvalidHandle;
localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
testString[0] = '\0';
localFileIO.Read(fileHandle1, testString, testStringLen);
localFileIO.Close(fileHandle1);
AZ_TEST_ASSERT(strncmp(testString, "DummyFile", 9) == 0);
//try swapping files when source file is not present, this should fail
AZ_TEST_ASSERT(!AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
AZ_TEST_ASSERT(!AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
fileHandle = AZ::IO::InvalidHandle;
localFileIO.Open(file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
localFileIO.Write(fileHandle, "TestFile", 8);
localFileIO.Close(fileHandle);
#if AZ_TRAIT_AZFRAMEWORKTEST_MOVE_WHILE_OPEN
fileHandle1 = AZ::IO::InvalidHandle;
localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
testString[0] = '\0';
localFileIO.Read(fileHandle1, testString, testStringLen);
// try swapping files when the destination file is open for read only,
// since window is unable to move files that are open for read, this will fail.
AZ_TEST_ASSERT(!AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
AZ_TEST_ASSERT(!AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
localFileIO.Close(fileHandle1);
#endif
fileHandle = AZ::IO::InvalidHandle;
localFileIO.Open(file01Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle);
localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle);
// try swapping files when the source file is open for read only
AZ_TEST_ASSERT(AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
AZ_TEST_ASSERT(AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
localFileIO.Close(fileHandle);
fileHandle1 = AZ::IO::InvalidHandle;
localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
testString[0] = '\0';
localFileIO.Read(fileHandle1, testString, testStringLen);
AZ_TEST_ASSERT(strncmp(testString, "TestFile", 8) == 0);
localFileIO.Close(fileHandle1);
localFileIO.Remove(file01Name.c_str());
localFileIO.Remove(file02Name.c_str());
localFileIO.Remove(m_file01Name.c_str());
localFileIO.Remove(m_file02Name.c_str());
localFileIO.DestroyPath(m_root.c_str());
AZ::IO::FileIOBase::SetInstance(nullptr);
@@ -6,16 +6,25 @@ namespace {{ xml.attrib['Name'] }}
{
switch (aznumeric_cast<int32_t>(packetHeader.GetPacketType()))
{
{% set packet_ns = namespace(handshake=false) %}
{% for Packet in xml.iter('Packet') %}
{% if ('HandshakePacket' in Packet.attrib) and (Packet.attrib['HandshakePacket']|booleanTrue == true) %}
{% set packet_ns.handshake = True %}
{% endif %}
{% endfor %}
{% for Packet in xml.iter('Packet') %}
case aznumeric_cast<int32_t>({{ Packet.attrib['Name'] }}::Type):
{
AZLOG(Debug_DispatchPackets, "Received packet %s", "{{ Packet.attrib['Name'] }}");
{% if ('HandshakePacket' not in Packet.attrib) or (Packet.attrib['HandshakePacket'] == 'false') %}
if (!handler.IsHandshakeComplete())
{% if packet_ns.handshake %}
{% if ('HandshakePacket' not in Packet.attrib) or (Packet.attrib['HandshakePacket'] == 'false') %}
if (!handler.IsHandshakeComplete(connection))
{
return AzNetworking::PacketDispatchResult::Skipped;
}
{% endif %}
{% endif %}
{% endif %}
{{ Packet.attrib['Name'] }} packet;
if (!serializer.Serialize(packet, "Packet"))
@@ -94,6 +94,7 @@ namespace AzNetworking
class ITimeoutHandler
{
public:
virtual ~ITimeoutHandler() = default;
//! Handler callback for timed out items.
//! @param item containing registered timeout details
@@ -103,13 +103,13 @@ namespace AzNetworking
//! @return boolean true on success
virtual bool Disconnect(ConnectionId connectionId, DisconnectReason reason) = 0;
//! Sets whether this connection interface can disconnect by virtue of a timeout
//! @param timeoutEnabled If this connection interface will automatically disconnect due to a timeout
virtual void SetTimeoutEnabled(bool timeoutEnabled) = 0;
//! Sets the timeout time in milliseconds, 0 ms means timeouts are disabled.
//! @param timeoutMs the number of milliseconds with no traffic before we timeout and close a connection
virtual void SetTimeoutMs(AZ::TimeMs timeoutMs) = 0;
//! Whether this connection interface will disconnect by virtue of a time out (does not account for cvars affecting all connections)
//! @return boolean true if this connection will not disconnect on timeout (does not account for cvars affecting all connections)
virtual bool IsTimeoutEnabled() const = 0;
//! Retrieves the timeout time in milliseconds for this network interface, 0 ms means timeouts are disabled.
//! @return the timeout time in milliseconds for this network interface, 0 ms means timeouts are disabled
virtual AZ::TimeMs GetTimeoutMs() const = 0;
//! Const access to the metrics tracked by this network interface.
//! @return const reference to the metrics tracked by this network interface
@@ -321,4 +321,19 @@ namespace AzNetworking
return serializer.IsValid();
}
};
template <>
struct SerializeObjectHelper<AZ::Aabb>
{
static bool SerializeObject(ISerializer& serializer, AZ::Aabb& value)
{
AZ::Vector3 minValue = value.GetMin();
AZ::Vector3 maxValue = value.GetMax();
serializer.Serialize(minValue, "minValue");
serializer.Serialize(maxValue, "maxValue");
value.SetMin(minValue);
value.SetMax(maxValue);
return serializer.IsValid();
}
};
}
@@ -22,14 +22,15 @@ namespace AzNetworking
#endif
AZ_CVAR(bool, net_TcpTimeoutConnections, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Boolean value on whether we should timeout Tcp connections");
AZ_CVAR(AZ::TimeMs, net_TcpHearthbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Tcp connection heartbeat frequency");
AZ_CVAR(AZ::TimeMs, net_TcpTimeoutTimeMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Tcp connection");
AZ_CVAR(AZ::TimeMs, net_TcpHeartbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Tcp connection heartbeat frequency");
AZ_CVAR(AZ::TimeMs, net_TcpDefaultTimeoutMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Tcp connection");
TcpNetworkInterface::TcpNetworkInterface(AZ::Name name, IConnectionListener& connectionListener, TrustZone trustZone, TcpListenThread& listenThread)
: m_name(name)
, m_trustZone(trustZone)
, m_connectionListener(connectionListener)
, m_listenThread(listenThread)
, m_timeoutMs(net_TcpDefaultTimeoutMs)
{
;
}
@@ -97,7 +98,7 @@ namespace AzNetworking
}
AZLOG_INFO("Adding new socket %d", static_cast<int32_t>(tcpSocket->GetSocketFd()));
const TimeoutId newTimeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast<uint64_t>(tcpSocket->GetSocketFd()), net_TcpHearthbeatTimeMs);
const TimeoutId newTimeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast<uint64_t>(tcpSocket->GetSocketFd()), net_TcpHeartbeatTimeMs);
connection->SetTimeoutId(newTimeoutId);
connection->SendReliablePacket(CorePackets::InitiateConnectionPacket());
m_connectionListener.OnConnect(connection.get());
@@ -174,14 +175,14 @@ namespace AzNetworking
return connection->Disconnect(reason, TerminationEndpoint::Local);
}
void TcpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled)
void TcpNetworkInterface::SetTimeoutMs(AZ::TimeMs timeoutMs)
{
m_timeoutEnabled = timeoutEnabled;
m_timeoutMs = timeoutMs;
}
bool TcpNetworkInterface::IsTimeoutEnabled() const
AZ::TimeMs TcpNetworkInterface::GetTimeoutMs() const
{
return m_timeoutEnabled;
return m_timeoutMs;
}
void TcpNetworkInterface::QueueNewConnection(const PendingConnection& pendingConnection)
@@ -257,7 +258,7 @@ namespace AzNetworking
return;
}
AZLOG(NET_TcpTraffic, "Adding new socket %d", static_cast<int32_t>(tcpSocket.GetSocketFd()));
const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast<uint64_t>(tcpSocket.GetSocketFd()), net_TcpTimeoutTimeMs);
const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast<uint64_t>(tcpSocket.GetSocketFd()), m_timeoutMs);
AZStd::unique_ptr<TcpConnection> connection = AZStd::make_unique<TcpConnection>(connectionId, remoteAddress, *this, tcpSocket, timeoutId);
AZ_Assert(connection->GetConnectionRole() == ConnectionRole::Acceptor, "Invalid role for connection");
GetConnectionListener().OnConnect(connection.get());
@@ -316,7 +317,7 @@ namespace AzNetworking
{
tcpConnection->SendReliablePacket(CorePackets::HeartbeatPacket());
}
else if (net_TcpTimeoutConnections && m_networkInterface.IsTimeoutEnabled())
else if (net_TcpTimeoutConnections && (m_networkInterface.GetTimeoutMs() > AZ::TimeMs{ 0 }))
{
tcpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local);
return TimeoutResult::Delete;
@@ -99,8 +99,8 @@ namespace AzNetworking
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
bool StopListening() override;
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
void SetTimeoutEnabled(bool timeoutEnabled) override;
bool IsTimeoutEnabled() const override;
void SetTimeoutMs(AZ::TimeMs timeoutMs) override;
AZ::TimeMs GetTimeoutMs() const override;
//! @}
//! Queues a new incoming connection for this network interface.
@@ -156,7 +156,7 @@ namespace AzNetworking
AZ::Name m_name;
TrustZone m_trustZone;
uint16_t m_port = 0;
bool m_timeoutEnabled = true;
AZ::TimeMs m_timeoutMs = AZ::TimeMs{ 0 };
IConnectionListener& m_connectionListener;
TcpConnectionSet m_connectionSet;
TcpSocketManager m_tcpSocketManager;
@@ -53,18 +53,11 @@ namespace AzNetworking
{
Close();
if (!SocketCreateInternal())
{
return false;
}
if (!BindSocketForListenInternal(port))
{
return false;
}
if (!(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
if (!SocketCreateInternal()
|| !BindSocketForListenInternal(port)
|| !(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
{
Close();
return false;
}
@@ -75,18 +68,11 @@ namespace AzNetworking
{
Close();
if (!SocketCreateInternal())
{
return false;
}
if (!BindSocketForConnectInternal(address))
{
return false;
}
if (!(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
if (!SocketCreateInternal()
|| !BindSocketForConnectInternal(address)
|| !(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
{
Close();
return false;
}
@@ -31,8 +31,8 @@ namespace AzNetworking
AZ_CVAR(bool, net_UdpTimeoutConnections, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Boolean value on whether we should timeout Udp connections");
AZ_CVAR(AZ::TimeMs, net_UdpPacketTimeSliceMs, AZ::TimeMs{ 8 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The number of milliseconds to allow for packet processing");
AZ_CVAR(AZ::TimeMs, net_UdpHearthbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Udp connection heartbeat frequency");
AZ_CVAR(AZ::TimeMs, net_UdpTimeoutTimeMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Udp connection");
AZ_CVAR(AZ::TimeMs, net_UdpHeartbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Udp connection heartbeat frequency");
AZ_CVAR(AZ::TimeMs, net_UdpDefaultTimeoutMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Udp connection");
AZ_CVAR(AZ::TimeMs, net_MinPacketTimeoutMs, AZ::TimeMs{ 200 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Minimum time to wait before timing out an unacked packet");
AZ_CVAR(int32_t, net_MaxTimeoutsPerFrame, 1000, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Maximum number of packet timeouts to allow to process in a single frame");
AZ_CVAR(float, net_RttFudgeScalar, 2.0f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Scalar value to multiply computed Rtt by to determine an optimal packet timeout threshold");
@@ -61,6 +61,7 @@ namespace AzNetworking
, m_connectionListener(connectionListener)
, m_socket(net_UdpUseEncryption ? new DtlsSocket() : new UdpSocket())
, m_readerThread(readerThread)
, m_timeoutMs(net_UdpDefaultTimeoutMs)
{
const AZ::CVarFixedString compressor = static_cast<AZ::CVarFixedString>(net_UdpCompressor);
const AZ::Name compressorName = AZ::Name(compressor);
@@ -138,7 +139,7 @@ namespace AzNetworking
}
const ConnectionId connectionId = m_connectionSet.GetNextConnectionId();
const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast<uint64_t>(connectionId), net_UdpHearthbeatTimeMs);
const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast<uint64_t>(connectionId), m_timeoutMs);
AZStd::unique_ptr<UdpConnection> connection = AZStd::make_unique<UdpConnection>(connectionId, remoteAddress, *this, ConnectionRole::Connector);
UdpPacketEncodingBuffer dtlsData;
@@ -403,14 +404,14 @@ namespace AzNetworking
return connection->Disconnect(reason, TerminationEndpoint::Local);
}
void UdpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled)
void UdpNetworkInterface::SetTimeoutMs(AZ::TimeMs timeoutMs)
{
m_timeoutEnabled = timeoutEnabled;
m_timeoutMs = timeoutMs;
}
bool UdpNetworkInterface::IsTimeoutEnabled() const
AZ::TimeMs UdpNetworkInterface::GetTimeoutMs() const
{
return m_timeoutEnabled;
return m_timeoutMs;
}
bool UdpNetworkInterface::IsEncrypted() const
@@ -681,7 +682,7 @@ namespace AzNetworking
// How long should we sit in the timeout queue before heartbeating or disconnecting
const ConnectionId connectionId = m_connectionSet.GetNextConnectionId();
const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast<uint64_t>(connectionId), net_UdpTimeoutTimeMs);
const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast<uint64_t>(connectionId), m_timeoutMs);
AZLOG(Debug_UdpConnect, "Accepted new Udp Connection");
AZStd::unique_ptr<UdpConnection> connection = AZStd::make_unique<UdpConnection>(connectionId, connectPacket.m_address, *this, ConnectionRole::Acceptor);
@@ -745,7 +746,7 @@ namespace AzNetworking
{
udpConnection->SendUnreliablePacket(CorePackets::HeartbeatPacket());
}
else if (net_UdpTimeoutConnections && m_networkInterface.IsTimeoutEnabled())
else if (net_UdpTimeoutConnections && (m_networkInterface.GetTimeoutMs() > AZ::TimeMs{ 0 }))
{
udpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local);
return TimeoutResult::Delete;
@@ -104,8 +104,8 @@ namespace AzNetworking
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
bool StopListening() override;
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
void SetTimeoutEnabled(bool timeoutEnabled) override;
bool IsTimeoutEnabled() const override;
void SetTimeoutMs(AZ::TimeMs timeoutMs) override;
AZ::TimeMs GetTimeoutMs() const override;
//! @}
//! Returns true if this is an encrypted socket, false if not.
@@ -181,7 +181,7 @@ namespace AzNetworking
TrustZone m_trustZone;
uint16_t m_port = 0;
bool m_allowIncomingConnections = false;
bool m_timeoutEnabled = true;
AZ::TimeMs m_timeoutMs = AZ::TimeMs{ 0 };
IConnectionListener& m_connectionListener;
UdpConnectionSet m_connectionSet;
TimeoutQueue m_connectionTimeoutQueue;
@@ -79,17 +79,15 @@ namespace AzNetworking
{
const int32_t error = GetLastNetworkError();
AZLOG_ERROR("Failed to bind UDP socket to port %u (%d:%s)", uint32_t(port), error, GetNetworkErrorDesc(error));
Close();
return false;
}
}
if (!SetSocketBufferSizes(m_socketFd, net_UdpSendBufferSize, net_UdpRecvBufferSize))
{
return false;
}
if (!SetSocketNonBlocking(m_socketFd))
if (!SetSocketBufferSizes(m_socketFd, net_UdpSendBufferSize, net_UdpRecvBufferSize)
|| !SetSocketNonBlocking(m_socketFd))
{
Close();
return false;
}
@@ -149,8 +149,9 @@ namespace UnitTest
EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
testClient.m_clientNetworkInterface->SetTimeoutEnabled(true);
EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled());
const AZ::TimeMs timeoutMs = AZ::TimeMs{ 100 };
testClient.m_clientNetworkInterface->SetTimeoutMs(timeoutMs);
EXPECT_EQ(testClient.m_clientNetworkInterface->GetTimeoutMs(), timeoutMs);
EXPECT_TRUE(testServer.m_serverNetworkInterface->StopListening());
}
@@ -279,8 +279,9 @@ namespace UnitTest
EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
testClient.m_clientNetworkInterface->SetTimeoutEnabled(true);
EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled());
const AZ::TimeMs timeoutMs = AZ::TimeMs{ 100 };
testClient.m_clientNetworkInterface->SetTimeoutMs(timeoutMs);
EXPECT_EQ(testClient.m_clientNetworkInterface->GetTimeoutMs(), timeoutMs);
EXPECT_FALSE(dynamic_cast<UdpNetworkInterface*>(testClient.m_clientNetworkInterface)->IsEncrypted());
+27
View File
@@ -0,0 +1,27 @@
/*
* 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 <ostream>
#include <AzCore/IO/Path/Path.h>
namespace AZ::IO
{
void PrintTo(const AZ::IO::PathView& path, ::std::ostream* os)
{
*os << "path: " << AZ::IO::Path(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str();
}
void PrintTo(const AZ::IO::Path& path, ::std::ostream* os)
{
*os << "path: " << AZ::IO::Path(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str();
}
void PrintTo(const AZ::IO::FixedMaxPath& path, ::std::ostream* os)
{
*os << "path: " << AZ::IO::FixedMaxPath(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str();
}
}
+40
View File
@@ -0,0 +1,40 @@
/*
* 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 <iosfwd>
#include <AzCore/IO/Path/Path_fwd.h>
namespace AZStd
{
template<class Element, class Traits, class Allocator>
class basic_string;
template <class Element, class Traits>
class basic_string_view;
template <class Element, size_t MaxElementCount, class Traits>
class basic_fixed_string;
template<class Element, class Traits, class Allocator>
void PrintTo(const AZStd::basic_string<Element, Traits, Allocator>& value, ::std::ostream* os);
template<class Element, class Traits>
void PrintTo(const AZStd::basic_string_view<Element, Traits>& value, ::std::ostream* os);
template <class Element, size_t MaxElementCount, class Traits>
void PrintTo(const AZStd::basic_fixed_string<Element, MaxElementCount, Traits>& value, ::std::ostream* os);
}
namespace AZ::IO
{
// Add Googletest printers for the AZ::IO::Path classes
void PrintTo(const AZ::IO::PathView& path, ::std::ostream* os);
void PrintTo(const AZ::IO::Path& path, ::std::ostream* os);
void PrintTo(const AZ::IO::FixedMaxPath& path, ::std::ostream* os);
}
#include <AzTest/Printers.inl>
+34
View File
@@ -0,0 +1,34 @@
/*
* 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 <ostream>
#include <string_view>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/fixed_string.h>
namespace AZStd
{
template<class Element, class Traits, class Allocator>
void PrintTo(const AZStd::basic_string<Element, Traits, Allocator>& value, ::std::ostream* os)
{
*os << value.c_str();
}
template<class Element, class Traits>
void PrintTo(const AZStd::basic_string_view<Element, Traits>& value, ::std::ostream* os)
{
*os << ::std::string_view(value.data(), value.size());
}
template <class Element, size_t MaxElementCount, class Traits>
void PrintTo(const AZStd::basic_fixed_string<Element, MaxElementCount, Traits>& value, ::std::ostream* os)
{
*os << value.c_str();
}
}
+1 -1
View File
@@ -9,8 +9,8 @@
#include <string>
#include <vector>
#include <AzCore/std/string/string.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzTest/Printers.h>
namespace AZ
{
namespace Test
@@ -11,6 +11,9 @@ set(FILES
AzTest.cpp
ColorizedOutput.cpp
Platform.h
Printers.h
Printers.inl
Printers.cpp
Utils.h
Utils.cpp
GemTestEnvironment.cpp
@@ -764,12 +764,6 @@ namespace AzToolsFramework
//! Spawn asset browser for the appropriate asset types.
virtual void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) = 0;
/// Allow interception of selection / left-mouse clicks in ObjectMode, for customizing selection behavior.
virtual void HandleObjectModeSelection(const AZ::Vector2& /*point*/, int /*flags*/, bool& /*handled*/) {}
/// Allow interception of cursor, for customizing selection behavior.
virtual void UpdateObjectModeCursor(AZ::u32& /*cursorId*/, AZStd::string& /*cursorStr*/) {}
/// Creates editor-side representation of an underlying entity.
virtual void CreateEditorRepresentation(AZ::Entity* /*entity*/) { }
@@ -21,7 +21,7 @@
namespace AzToolsFramework
{
constexpr const char s_traceName[] = "ArchiveComponent";
[[maybe_unused]] constexpr const char s_traceName[] = "ArchiveComponent";
constexpr AZ::u32 s_compressionMethod = AZ::IO::INestedArchive::METHOD_DEFLATE;
constexpr AZ::s32 s_compressionLevel = AZ::IO::INestedArchive::LEVEL_NORMAL;
constexpr CompressionCodec::Codec s_compressionCodec = CompressionCodec::Codec::ZLIB;
@@ -927,7 +927,7 @@ namespace AzToolsFramework
PrefabDomValue& instance = instanceIterator->value;
AZ_Assert(instance.IsObject(), "Nested instance DOM provided is not a valid JSON object.");
PrefabDomValueReference sourceTemplateName = PrefabDomUtils::FindPrefabDomValue(instance, PrefabDomUtils::SourceName);
[[maybe_unused]] PrefabDomValueReference sourceTemplateName = PrefabDomUtils::FindPrefabDomValue(instance, PrefabDomUtils::SourceName);
AZ_Assert(sourceTemplateName, "Couldn't find source template name in the DOM of the nested instance while creating a link.");
AZ_Assert(sourceTemplateName->get() == sourceTemplate.GetFilePath().c_str(),
"The name of the source template in the nested instance DOM does not match the name of the source template already loaded");
@@ -9,6 +9,7 @@
#include "AssetProcessorManagerTest.h"
#include "native/AssetManager/PathDependencyManager.h"
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzToolsFramework/Asset/AssetProcessorMessages.h>
#include <AzToolsFramework/ToolsFileUtils/ToolsFileUtils.h>
#include <AzTest/AzTest.h>
@@ -4130,11 +4131,21 @@ struct LockedFileTest
MOCK_METHOD2(SendResponse, size_t (unsigned, const AzFramework::AssetSystem::BaseAssetProcessorMessage&));
MOCK_METHOD1(RemoveResponseHandler, void (unsigned));
size_t Send(unsigned, const AzFramework::AssetSystem::BaseAssetProcessorMessage&) override
size_t Send(unsigned, const AzFramework::AssetSystem::BaseAssetProcessorMessage& message) override
{
if(m_callback)
using SourceFileNotificationMessage = AzToolsFramework::AssetSystem::SourceFileNotificationMessage;
switch (message.GetMessageType())
{
m_callback();
case SourceFileNotificationMessage::MessageType:
if (const auto sourceFileMessage = azrtti_cast<const SourceFileNotificationMessage*>(&message);
sourceFileMessage != nullptr && sourceFileMessage->m_type == SourceFileNotificationMessage::NotificationType::FileRemoved
&& m_callback)
{
m_callback();
}
break;
default:
break;
}
return 0;
@@ -168,7 +168,9 @@ namespace AssetProcessor
if (childItem)
{
return createIndex(row, column, childItem);
QModelIndex index = createIndex(row, column, childItem);
Q_ASSERT(checkIndex(index));
return index;
}
return QModelIndex();
}
@@ -197,7 +199,9 @@ namespace AssetProcessor
{
return QModelIndex();
}
return createIndex(parentItem->GetRow(), 0, parentItem);
QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem);
Q_ASSERT(checkIndex(parentIndex));
return parentIndex;
}
bool AssetTreeModel::hasChildren(const QModelIndex &parent) const
@@ -92,6 +92,7 @@ namespace AssetProcessor
}
QModelIndex parentIndex = createIndex(parent->GetRow(), 0, parent);
Q_ASSERT(checkIndex(parentIndex));
beginRemoveRows(parentIndex, assetToRemove->GetRow(), assetToRemove->GetRow());
@@ -179,6 +180,8 @@ namespace AssetProcessor
QModelIndex existingIndexStart = createIndex(existingEntry->second->GetRow(), 0, existingEntry->second);
QModelIndex existingIndexEnd = createIndex(existingEntry->second->GetRow(), existingEntry->second->GetColumnCount() - 1, existingEntry->second);
Q_ASSERT(checkIndex(existingIndexStart));
Q_ASSERT(checkIndex(existingIndexEnd));
dataChanged(existingIndexStart, existingIndexEnd);
return;
}
@@ -205,7 +208,8 @@ namespace AssetProcessor
{
if (!modelIsResetting)
{
QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem);
QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem);
Q_ASSERT(checkIndex(parentIndex));
beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount());
}
nextParent = parentItem->CreateChild(ProductAssetTreeItemData::MakeShared(nullptr, currentFullFolderPath.Native(), currentPath.c_str(), true, AZ::Uuid::CreateNull()));
@@ -231,7 +235,8 @@ namespace AssetProcessor
if (!modelIsResetting)
{
QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem);
QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem);
Q_ASSERT(checkIndex(parentIndex));
beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount());
}
@@ -13,6 +13,7 @@
#include <AzCore/IO/Path/Path.h>
#include <native/utilities/assetUtils.h>
#include <AzCore/Console/IConsole.h>
#include <QDebug>
namespace AssetProcessor
{
@@ -102,7 +103,8 @@ namespace AssetProcessor
{
if (!modelIsResetting)
{
QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem);
QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem);
Q_ASSERT(checkIndex(parentIndex));
beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount());
}
nextParent = parentItem->CreateChild(SourceAssetTreeItemData::MakeShared(nullptr, nullptr, currentFullFolderPath.Native(), currentPath.c_str(), true));
@@ -118,7 +120,8 @@ namespace AssetProcessor
if (!modelIsResetting)
{
QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem);
QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem);
Q_ASSERT(checkIndex(parentIndex));
beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount());
}
@@ -173,7 +176,8 @@ namespace AssetProcessor
return;
}
QModelIndex parentIndex = createIndex(parent->GetRow(), 0, parent);
QModelIndex parentIndex = parent == m_root.get() ? QModelIndex() : createIndex(parent->GetRow(), 0, parent);
Q_ASSERT(checkIndex(parentIndex));
beginRemoveRows(parentIndex, assetToRemove->GetRow(), assetToRemove->GetRow());
@@ -8,6 +8,7 @@
#include <ProjectUtils.h>
#include <ProjectManagerDefs.h>
#include <QProcessEnvironment>
#include <QDir>
namespace O3DE::ProjectManager
{
@@ -18,7 +19,10 @@ namespace O3DE::ProjectManager
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment()
{
return AZ::Success(QProcessEnvironment(QProcessEnvironment::systemEnvironment()));
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
currentEnvironment.insert("CC", "clang-12");
currentEnvironment.insert("CXX", "clang++-12");
return AZ::Success(currentEnvironment);
}
AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform()
@@ -27,7 +31,7 @@ namespace O3DE::ProjectManager
auto whichCMakeResult = ProjectUtils::ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}, QProcessEnvironment::systemEnvironment());
if (!whichCMakeResult.IsSuccess())
{
return AZ::Failure(QObject::tr("CMake not found. \n\n"
return AZ::Failure(QObject::tr("CMake not found. <br><br>"
"Make sure that the minimum version of CMake is installed and available from the command prompt. "
"Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information."));
}
@@ -45,10 +49,42 @@ namespace O3DE::ProjectManager
return AZ::Success(supportClangCommand);
}
}
return AZ::Failure(QObject::tr("Clang not found. \n\n"
return AZ::Failure(QObject::tr("Clang not found. <br><br>"
"Make sure that the clang is installed and available from the command prompt. "
"Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information."));
}
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
{
AZ::Outcome processEnvResult = GetCommandLineProcessEnvironment();
if (!processEnvResult.IsSuccess())
{
return AZ::Failure(processEnvResult.GetError());
}
QString projectBuildPath = QDir(projectPath).filePath(ProjectBuildPathPostfix);
AZ::Outcome projectBuildPathResult = GetProjectBuildPath(projectPath);
if (projectBuildPathResult.IsSuccess())
{
projectBuildPath = projectBuildPathResult.GetValue();
}
QProcess process;
process.setProcessEnvironment(processEnvResult.GetValue());
// if the project build path is relative, it should be relative to the project path
process.setWorkingDirectory(projectPath);
process.setProgram("cmake-gui");
process.setArguments({ "-S", projectPath, "-B", projectBuildPath });
if(!process.startDetached())
{
return AZ::Failure(QObject::tr("Failed to start CMake GUI"));
}
return AZ::Success();
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -8,6 +8,7 @@
#include <ProjectUtils.h>
#include <QProcess>
#include <QStandardPaths>
namespace O3DE::ProjectManager
{
@@ -61,5 +62,37 @@ namespace O3DE::ProjectManager
return AZ::Success(xcodeBuilderVersionNumber);
}
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
{
const QString cmakeHelp = QObject::tr("Please verify you've installed CMake.app from "
"<a href=\"https://cmake.org\">cmake.org</a> or, if using HomeBrew, "
"have installed it with <pre>brew install --cask cmake</pre>");
QString cmakeAppPath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, "CMake.app", QStandardPaths::LocateDirectory);
if (cmakeAppPath.isEmpty())
{
return AZ::Failure(QObject::tr("CMake.app not found.") + cmakeHelp);
}
QString projectBuildPath = QDir(projectPath).filePath(ProjectBuildPathPostfix);
AZ::Outcome result = GetProjectBuildPath(projectPath);
if (result.IsSuccess())
{
projectBuildPath = result.GetValue();
}
QProcess process;
// if the project build path is relative, it should be relative to the project path
process.setWorkingDirectory(projectPath);
process.setProgram("open");
process.setArguments({"-a", "CMake", "--args", "-S", projectPath, "-B", projectBuildPath});
if(!process.startDetached())
{
return AZ::Failure(QObject::tr("CMake.app failed to open.") + cmakeHelp);
}
return AZ::Success();
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -92,12 +92,43 @@ namespace O3DE::ProjectManager
}
}
return AZ::Failure(QObject::tr("Visual Studio 2019 version 16.9.2 or higher not found.\n\n"
return AZ::Failure(QObject::tr("Visual Studio 2019 version 16.9.2 or higher not found.<br><br>"
"Visual Studio 2019 is required to build this project."
" Install any edition of <a href='https://visualstudio.microsoft.com/downloads/'>Visual Studio 2019</a>"
" or update to a newer version before proceeding to the next step."
" While installing configure Visual Studio with these <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#visual-studio-configuration'>workloads</a>."));
}
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
{
AZ::Outcome processEnvResult = GetCommandLineProcessEnvironment();
if (!processEnvResult.IsSuccess())
{
return AZ::Failure(processEnvResult.GetError());
}
QString projectBuildPath = QDir(projectPath).filePath(ProjectBuildPathPostfix);
AZ::Outcome projectBuildPathResult = GetProjectBuildPath(projectPath);
if (projectBuildPathResult.IsSuccess())
{
projectBuildPath = projectBuildPathResult.GetValue();
}
QProcess process;
process.setProcessEnvironment(processEnvResult.GetValue());
// if the project build path is relative, it should be relative to the project path
process.setWorkingDirectory(projectPath);
process.setProgram("cmake-gui");
process.setArguments({ "-S", projectPath, "-B", projectBuildPath });
if(!process.startDetached())
{
return AZ::Failure(QObject::tr("Failed to start CMake GUI"));
}
return AZ::Success();
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -438,6 +438,11 @@ QTabBar::tab:focus {
max-height:26px;
}
#projectActionButton, #openEditorButton {
min-height:26px;
max-height:26px;
}
#labelButtonOverlay {
background-color: rgba(50,50,50,200);
min-width:210px;
@@ -1,5 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" fill="#444444"/>
<rect x="10" y="6" width="4" height="15" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2L22 22H2L12 2ZM13 20V18H11V20H13ZM13 7H11V16.0862H13V7Z" fill="#F0C32D"/>
</svg>

Before

Width:  |  Height:  |  Size: 333 B

After

Width:  |  Height:  |  Size: 287 B

@@ -88,6 +88,7 @@ namespace O3DE::ProjectManager
QHBoxLayout* horizontalButtonLayout = new QHBoxLayout();
horizontalButtonLayout->addSpacing(34);
m_actionButton = new QPushButton(tr("Project Action"), this);
m_actionButton->setObjectName("projectActionButton");
m_actionButton->setVisible(false);
horizontalButtonLayout->addWidget(m_actionButton);
horizontalButtonLayout->addSpacing(34);
@@ -198,6 +199,7 @@ namespace O3DE::ProjectManager
QMenu* menu = new QMenu(this);
menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); });
menu->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); });
menu->addAction(tr("Open CMake GUI..."), this, [this]() { emit OpenCMakeGUI(m_projectInfo); });
menu->addSeparator();
menu->addAction(tr("Open Project folder..."), this, [this]()
{
@@ -259,15 +261,39 @@ namespace O3DE::ProjectManager
}
projectActionButton->setText(text);
projectActionButton->setMenu(nullptr);
m_actionButtonConnection = connect(projectActionButton, &QPushButton::clicked, lambda);
}
void ProjectButton::SetProjectBuildButtonAction()
void ProjectButton::ShowDefaultBuildButton()
{
m_projectImageLabel->GetWarningLabel()->setText(tr("Building project required."));
m_projectImageLabel->GetWarningIcon()->setVisible(true);
m_projectImageLabel->GetWarningLabel()->setVisible(true);
SetProjectButtonAction(tr("Build Project"), [this]() { emit BuildProject(m_projectInfo); });
QPushButton* projectActionButton = m_projectImageLabel->GetActionButton();
projectActionButton->setVisible(true);
projectActionButton->setText(tr("Build Project"));
disconnect(m_actionButtonConnection);
QMenu* menu = new QMenu(this);
QAction* autoBuildAction = menu->addAction(tr("Build Now"));
connect( autoBuildAction, &QAction::triggered, this, [this](){ emit BuildProject(m_projectInfo); });
QAction* openCMakeAction = menu->addAction(tr("Open CMake GUI..."));
connect( openCMakeAction, &QAction::triggered, this, [this](){ emit OpenCMakeGUI(m_projectInfo); });
projectActionButton->setMenu(menu);
}
void ProjectButton::ShowBuildRequired()
{
ShowWarning(true, tr("Building project required"));
ShowDefaultBuildButton();
}
void ProjectButton::ShowWarning(bool show, const QString& warning)
{
m_projectImageLabel->GetWarningLabel()->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
m_projectImageLabel->GetWarningLabel()->setText(warning);
m_projectImageLabel->GetWarningLabel()->setVisible(show);
m_projectImageLabel->GetWarningIcon()->setVisible(show);
}
void ProjectButton::SetBuildLogsLink(const QUrl& logUrl)
@@ -279,18 +305,15 @@ namespace O3DE::ProjectManager
{
if (!logUrl.isEmpty())
{
m_projectImageLabel->GetWarningLabel()->setText(tr("Failed to build. Click to <a href=\"logs\">view logs</a>."));
ShowWarning(show, tr("Failed to build. Click to <a href=\"logs\">view logs</a>."));
}
else
{
m_projectImageLabel->GetWarningLabel()->setText(tr("Project failed to build."));
ShowWarning(show, tr("Project failed to build."));
}
m_projectImageLabel->GetWarningLabel()->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
m_projectImageLabel->GetWarningIcon()->setVisible(show);
m_projectImageLabel->GetWarningLabel()->setVisible(show);
m_projectImageLabel->SetLogUrl(logUrl);
SetProjectButtonAction(tr("Build Project"), [this]() { emit BuildProject(m_projectInfo); });
SetBuildLogsLink(logUrl);
ShowDefaultBuildButton();
}
void ProjectButton::SetProjectBuilding()
@@ -82,9 +82,9 @@ namespace O3DE::ProjectManager
void RestoreDefaultState();
void SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda);
void SetProjectBuildButtonAction();
void SetBuildLogsLink(const QUrl& logUrl);
void ShowBuildFailed(bool show, const QUrl& logUrl);
void ShowBuildRequired();
void SetProjectBuilding();
void SetLaunchButtonEnabled(bool enabled);
@@ -99,10 +99,13 @@ namespace O3DE::ProjectManager
void RemoveProject(const QString& projectName);
void DeleteProject(const QString& projectName);
void BuildProject(const ProjectInfo& projectInfo);
void OpenCMakeGUI(const ProjectInfo& projectInfo);
private:
void enterEvent(QEvent* event) override;
void leaveEvent(QEvent* event) override;
void ShowWarning(bool show, const QString& warning);
void ShowDefaultBuildButton();
ProjectInfo m_projectInfo;
@@ -9,6 +9,8 @@
#include <ProjectUtils.h>
#include <ProjectManagerDefs.h>
#include <PythonBindingsInterface.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/IO/Path/Path.h>
#include <QFileDialog>
#include <QDir>
@@ -537,5 +539,33 @@ namespace O3DE::ProjectManager
QString resultOutput = execProcess.readAllStandardOutput();
return AZ::Success(resultOutput);
}
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath)
{
auto registry = AZ::SettingsRegistry::Get();
// the project_build_path should be in the user settings registry inside the project folder
AZ::IO::FixedMaxPath projectUserPath(projectPath.toUtf8().constData());
projectUserPath /= AZ::SettingsRegistryInterface::DevUserRegistryFolder;
if (!QDir(projectUserPath.c_str()).exists())
{
return AZ::Failure(QObject::tr("Failed to find the user registry folder %1").arg(projectUserPath.c_str()));
}
AZ::SettingsRegistryInterface::Specializations specializations;
if(!registry->MergeSettingsFolder(projectUserPath.Native(), specializations, AZ_TRAIT_OS_PLATFORM_CODENAME))
{
return AZ::Failure(QObject::tr("Failed to merge registry settings in user registry folder %1").arg(projectUserPath.c_str()));
}
AZ::IO::FixedMaxPath projectBuildPath;
if (!registry->Get(projectBuildPath.Native(), AZ::SettingsRegistryMergeUtils::ProjectBuildPath))
{
return AZ::Failure(QObject::tr("No project build path setting was found in the user registry folder %1").arg(projectUserPath.c_str()));
}
return AZ::Success(QString(projectBuildPath.c_str()));
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -42,6 +42,8 @@ namespace O3DE::ProjectManager
int commandTimeoutSeconds = ProjectCommandLineTimeoutSeconds);
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment();
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath);
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath);
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -185,6 +185,15 @@ namespace O3DE::ProjectManager
connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject);
connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject);
connect(projectButton, &ProjectButton::BuildProject, this, &ProjectsScreen::QueueBuildProject);
connect(projectButton, &ProjectButton::OpenCMakeGUI, this,
[this](const ProjectInfo& projectInfo)
{
AZ::Outcome result = ProjectUtils::OpenCMakeGUI(projectInfo.m_path);
if (!result)
{
QMessageBox::critical(this, tr("Failed to open CMake GUI"), result.GetError(), QMessageBox::Ok);
}
});
return projectButton;
}
@@ -308,7 +317,7 @@ namespace O3DE::ProjectManager
}
else
{
projectIter.value()->SetProjectBuildButtonAction();
projectIter.value()->ShowBuildRequired();
}
}
}
@@ -40,6 +40,7 @@
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
"IsPowerOf2": true,
"MipMapSetting": {
@@ -61,6 +62,7 @@
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
"IsPowerOf2": true,
"MipMapSetting": {
@@ -37,6 +37,7 @@
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -56,6 +57,7 @@
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -28,6 +28,7 @@
"_amb",
"_ambientocclusion"
],
"MaxTextureSize": 2048,
"PixelFormat": "ASTC_4x4"
},
"ios": {
@@ -41,6 +42,7 @@
"_amb",
"_ambientocclusion"
],
"MaxTextureSize": 2048,
"PixelFormat": "ASTC_4x4"
},
"mac": {
@@ -25,6 +25,7 @@
"_decal"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -39,6 +40,7 @@
"_decal"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -46,6 +46,7 @@
"_h"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
"IsPowerOf2": true,
"SizeReduceLevel": 3,
@@ -71,6 +72,7 @@
"_h"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
"IsPowerOf2": true,
"MipMapSetting": {
@@ -30,6 +30,7 @@
"_emit"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true
},
"ios": {
@@ -44,6 +45,7 @@
"_emit"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true
},
"mac": {
@@ -28,6 +28,7 @@
"_bump"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipRenormalize": true,
"MipMapSetting": {
@@ -43,6 +44,7 @@
"_bump"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipRenormalize": true,
"MipMapSetting": {
@@ -39,6 +39,7 @@
],
"PixelFormat": "ASTC_4x4",
"PixelFormatAlpha": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"GlossFromNormal": 1,
"MipRenormalize": true,
@@ -60,6 +61,7 @@
],
"PixelFormat": "ASTC_4x4",
"PixelFormatAlpha": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"GlossFromNormal": 1,
"MipRenormalize": true,
@@ -32,6 +32,7 @@
],
"PixelFormat": "ASTC_4x4",
"PixelFormatAlpha": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"GlossFromNormal": 1,
"UseLegacyGloss": true,
@@ -50,6 +51,7 @@
],
"PixelFormat": "ASTC_4x4",
"PixelFormatAlpha": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"GlossFromNormal": 1,
"UseLegacyGloss": true,
@@ -45,6 +45,7 @@
"_blend"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -68,6 +69,7 @@
"_blend"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -58,6 +58,7 @@
"_rough"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -87,6 +88,7 @@
"_rough"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -23,6 +23,7 @@
"_spec"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -35,6 +36,7 @@
"_spec"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -27,6 +27,7 @@
"_refl"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -41,6 +42,7 @@
"_refl"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -88,6 +88,7 @@ namespace AZ
dependent.push_back(AZ_CRC("CoreLightsService", 0x91932ef6));
dependent.push_back(AZ_CRC("DynamicDrawService", 0x023c1673));
dependent.push_back(AZ_CRC("CommonService", 0x6398eec4));
dependent.push_back(AZ_CRC_CE("HairService"));
}
void BootstrapSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
@@ -468,6 +468,14 @@
"Name": "OpaqueParentTemplate",
"Path": "Passes/OpaqueParent.pass"
},
{
"Name": "ThumbnailPipeline",
"Path": "Passes/ThumbnailPipeline.pass"
},
{
"Name": "ThumbnailPipelineRenderToTexture",
"Path": "Passes/ThumbnailPipelineRenderToTexture.pass"
},
{
"Name": "TransparentParentTemplate",
"Path": "Passes/TransparentParent.pass"
@@ -0,0 +1,463 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "ThumbnailPipeline",
"PassClass": "ParentPass",
"Slots": [
{
"Name": "SwapChainOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
}
],
"PassRequests": [
{
"Name": "MorphTargetPass",
"TemplateName": "MorphTargetPassTemplate"
},
{
"Name": "SkinningPass",
"TemplateName": "SkinningPassTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshOutputStream",
"AttachmentRef": {
"Pass": "MorphTargetPass",
"Attachment": "MorphTargetDeltaOutput"
}
}
]
},
{
"Name": "RayTracingAccelerationStructurePass",
"TemplateName": "RayTracingAccelerationStructurePassTemplate"
},
{
"Name": "DiffuseProbeGridUpdatePass",
"TemplateName": "DiffuseProbeGridUpdatePassTemplate",
"ExecuteAfter": [
"RayTracingAccelerationStructurePass"
]
},
{
"Name": "DepthPrePass",
"TemplateName": "DepthMSAAParentTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshes",
"AttachmentRef": {
"Pass": "SkinningPass",
"Attachment": "SkinnedMeshOutputStream"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "MotionVectorPass",
"TemplateName": "MotionVectorParentTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshes",
"AttachmentRef": {
"Pass": "SkinningPass",
"Attachment": "SkinnedMeshOutputStream"
}
},
{
"LocalSlot": "Depth",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "LightCullingPass",
"TemplateName": "LightCullingParentTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshes",
"AttachmentRef": {
"Pass": "SkinningPass",
"Attachment": "SkinnedMeshOutputStream"
}
},
{
"LocalSlot": "DepthMSAA",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthMSAA"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "ShadowPass",
"TemplateName": "ShadowParentTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshes",
"AttachmentRef": {
"Pass": "SkinningPass",
"Attachment": "SkinnedMeshOutputStream"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "OpaquePass",
"TemplateName": "OpaqueParentTemplate",
"Connections": [
{
"LocalSlot": "DirectionalShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalShadowmap"
}
},
{
"LocalSlot": "DirectionalESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalESM"
}
},
{
"LocalSlot": "ProjectedShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedShadowmap"
}
},
{
"LocalSlot": "ProjectedESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedESM"
}
},
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "LightListRemapped",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "LightListRemapped"
}
},
{
"LocalSlot": "DepthLinear",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "DepthStencil",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthMSAA"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "TransparentPass",
"TemplateName": "TransparentParentTemplate",
"Connections": [
{
"LocalSlot": "DirectionalShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalShadowmap"
}
},
{
"LocalSlot": "DirectionalESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalESM"
}
},
{
"LocalSlot": "ProjectedShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedShadowmap"
}
},
{
"LocalSlot": "ProjectedESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedESM"
}
},
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "LightListRemapped",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "LightListRemapped"
}
},
{
"LocalSlot": "InputLinearDepth",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "DepthStencil",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "OpaquePass",
"Attachment": "Output"
}
}
]
},
{
"Name": "DeferredFogPass",
"TemplateName": "DeferredFogPassTemplate",
"Enabled": false,
"Connections": [
{
"LocalSlot": "InputLinearDepth",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "InputDepthStencil",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "RenderTargetInputOutput",
"AttachmentRef": {
"Pass": "TransparentPass",
"Attachment": "InputOutput"
}
}
],
"PassData": {
"$type": "FullscreenTrianglePassData",
"ShaderAsset": {
"FilePath": "Shaders/ScreenSpace/DeferredFog.shader"
},
"PipelineViewTag": "MainCamera"
}
},
{
"Name": "ReflectionCopyFrameBufferPass",
"TemplateName": "ReflectionCopyFrameBufferPassTemplate",
"Enabled": false,
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "DeferredFogPass",
"Attachment": "RenderTargetInputOutput"
}
}
]
},
{
"Name": "PostProcessPass",
"TemplateName": "PostProcessParentTemplate",
"Connections": [
{
"LocalSlot": "LightingInput",
"AttachmentRef": {
"Pass": "DeferredFogPass",
"Attachment": "RenderTargetInputOutput"
}
},
{
"LocalSlot": "Depth",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "MotionVectors",
"AttachmentRef": {
"Pass": "MotionVectorPass",
"Attachment": "MotionVectorOutput"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "AuxGeomPass",
"TemplateName": "AuxGeomPassTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "ColorInputOutput",
"AttachmentRef": {
"Pass": "PostProcessPass",
"Attachment": "Output"
}
},
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}
],
"PassData": {
"$type": "RasterPassData",
"DrawListTag": "auxgeom",
"PipelineViewTag": "MainCamera"
}
},
{
"Name": "DebugOverlayPass",
"TemplateName": "DebugOverlayParentTemplate",
"Connections": [
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "RawLightingInput",
"AttachmentRef": {
"Pass": "PostProcessPass",
"Attachment": "RawLightingOutput"
}
},
{
"LocalSlot": "LuminanceMipChainInput",
"AttachmentRef": {
"Pass": "PostProcessPass",
"Attachment": "LuminanceMipChainOutput"
}
},
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "AuxGeomPass",
"Attachment": "ColorInputOutput"
}
}
]
},
{
"Name": "UIPass",
"TemplateName": "UIParentTemplate",
"Connections": [
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "DebugOverlayPass",
"Attachment": "InputOutput"
}
},
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}
]
},
{
"Name": "CopyToSwapChain",
"TemplateName": "FullscreenCopyTemplate",
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "UIPass",
"Attachment": "InputOutput"
}
},
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
}
]
}
}
}
@@ -0,0 +1,32 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "ThumbnailPipelineRenderToTexture",
"PassClass": "RenderToTexturePass",
"PassData": {
"$type": "RenderToTexturePassData",
"OutputWidth": 512,
"OutputHeight": 512,
"OutputFormat": "R8G8B8A8_UNORM"
},
"PassRequests": [
{
"Name": "Pipeline",
"TemplateName": "ThumbnailPipeline",
"Connections": [
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "Output"
}
}
]
}
]
}
}
}
@@ -70,6 +70,8 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface)
float4 baseMap = 0;
float2 normalMap = 0;
// Each texture array handles a size permutation.
// e.g. it could be that tex array 0 handles 256x256 and tex array 1 handles 512x64, etc.
switch(textureArrayIndex)
{
case 0:
@@ -8,14 +8,14 @@
#pragma once
option bool o_specularF0_enableMultiScatterCompensation;
option bool o_specularF0_enableMultiScatterCompensation = true;
option bool o_enableShadows = true;
option bool o_enableDirectionalLights = true;
option bool o_enablePunctualLights = true;
option bool o_enableAreaLights = true;
option bool o_enableIBL = true;
option bool o_enableSubsurfaceScattering;
option bool o_clearCoat_feature_enabled;
option bool o_enableSubsurfaceScattering = false;
option bool o_clearCoat_feature_enabled = false;
option enum class TransmissionMode {None, ThickObject, ThinObject} o_transmission_mode;
option bool o_meshUseForwardPassIBLSpecular = false;
option bool o_materialUseForwardPassIBLSpecular = false;
@@ -8,6 +8,7 @@
#pragma once
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
#include <Atom/Features/PBR/Lights/CapsuleLight.azsli>
#include <Atom/Features/PBR/Lights/DirectionalLight.azsli>
#include <Atom/Features/PBR/Lights/DiskLight.azsli>
@@ -8,7 +8,7 @@
#pragma once
#include <Atom/Features/PBR/Lights/LightTypesCommon.azsli>
#include <Atom/Features/LightCulling/LightCullingTileIterator.azsli>
void ApplySimplePointLight(ViewSrg::SimplePointLight light, Surface surface, inout LightingData lightingData)
{
@@ -10,7 +10,6 @@
#include <scenesrg.srgi>
#include <viewsrg.srgi>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
#include <Atom/Features/Shadow/ShadowmapAtlasLib.azsli>
#include <Atom/RPI/Math.azsli>
#include "BicubicPcfFilters.azsli"
@@ -160,6 +160,8 @@ set(FILES
Passes/LuminanceHistogramGenerator.pass
Passes/MainPipeline.pass
Passes/MainPipelineRenderToTexture.pass
Passes/ThumbnailPipeline.pass
Passes/ThumbnailPipelineRenderToTexture.pass
Passes/MeshMotionVector.pass
Passes/ModulateTexture.pass
Passes/MorphTarget.pass
@@ -301,23 +301,50 @@ namespace AZ
return;
}
if (material.IsValid())
if (GetMaterialUsedByDecal(handle) == material)
{
AZ_Assert(m_decalData.GetData(handle.GetIndex()).m_textureArrayIndex == DecalData::UnusedIndex, "Setting Material on a decal more than once is not currently supported.");
const auto iter = m_materialToTextureArrayLookupTable.find(material);
if (iter != m_materialToTextureArrayLookupTable.end())
{
// This material is already loaded and registered with this feature processor
iter->second.m_useCount++;
SetDecalTextureLocation(handle, iter->second.m_location);
return;
}
// Material not loaded so queue it up for loading.
QueueMaterialLoadForDecal(material, handle);
return;
}
const auto decalIndex = handle.GetIndex();
const bool isValidMaterialBeingUsedCurrently = m_decalData.GetData(decalIndex).m_textureArrayIndex != DecalData::UnusedIndex;
if (isValidMaterialBeingUsedCurrently)
{
RemoveMaterialFromDecal(decalIndex);
}
if (!material.IsValid())
{
return;
}
const auto iter = m_materialToTextureArrayLookupTable.find(material);
if (iter != m_materialToTextureArrayLookupTable.end())
{
// This material is already loaded and registered with this feature processor
iter->second.m_useCount++;
SetDecalTextureLocation(handle, iter->second.m_location);
return;
}
// Material not loaded so queue it up for loading.
QueueMaterialLoadForDecal(material, handle);
}
void DecalTextureArrayFeatureProcessor::RemoveMaterialFromDecal(const uint16_t decalIndex)
{
auto& decalData = m_decalData.GetData(decalIndex);
DecalLocation decalLocation;
decalLocation.textureArrayIndex = decalData.m_textureArrayIndex;
decalLocation.textureIndex = decalData.m_textureIndex;
RemoveDecalFromTextureArrays(decalLocation);
decalData.m_textureArrayIndex = DecalData::UnusedIndex;
decalData.m_textureIndex = DecalData::UnusedIndex;
m_deviceBufferNeedsUpdate = true;
}
void DecalTextureArrayFeatureProcessor::CacheShaderIndices()
@@ -114,6 +114,7 @@ namespace AZ
AZStd::optional<DecalLocation> AddMaterialToTextureArrays(const AZ::RPI::MaterialAsset* materialAsset);
int FindTextureArrayWithSize(const RHI::Size& size) const;
void RemoveMaterialFromDecal(const uint16_t decalIndex);
void SetDecalTextureLocation(const DecalHandle& handle, const DecalLocation location);
void QueueMaterialLoadForDecal(const AZ::Data::AssetId material, const DecalHandle handle);
bool RemoveDecalFromTextureArrays(const DecalLocation decalLocation);

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