diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlender.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlender.py
index 13f2a569c1..438a7df732 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlender.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlender.py
@@ -86,6 +86,7 @@ class TestLayerBlender(object):
@pytest.mark.SUITE_periodic
@pytest.mark.dynveg_area
@pytest.mark.parametrize("launcher_platform", ['windows'])
+ @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4170")
def test_LayerBlender_E2E_Launcher(self, workspace, project, launcher, level, remote_console_instance,
launcher_platform):
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43b0dd240e..e659270f84 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,11 +29,11 @@ include(cmake/PAL.cmake)
include(cmake/PALTools.cmake)
include(cmake/RuntimeDependencies.cmake)
include(cmake/Configurations.cmake) # Requires to be after PAL so we get platform variable definitions
-include(cmake/Install.cmake)
include(cmake/Dependencies.cmake)
include(cmake/Deployment.cmake)
include(cmake/3rdParty.cmake)
include(cmake/LYPython.cmake)
+include(cmake/Install.cmake)
include(cmake/LYWrappers.cmake)
include(cmake/Gems.cmake)
include(cmake/UnitTest.cmake)
diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui
index df7474d9d4..a345438aed 100644
--- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui
+++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui
@@ -140,9 +140,6 @@
QAbstractItemView::ScrollPerPixel
-
- false
-
true
@@ -201,6 +198,11 @@
AzToolsFramework/AssetBrowser/Search/SearchWidget.h
1
+
+ AzQtComponents::TableView
+ QTreeView
+ AzQtComponents/Components/Widgets/TableView.h
+
AzToolsFramework::AssetBrowser::AssetBrowserTreeView
QTreeView
@@ -214,7 +216,7 @@
AzToolsFramework::AssetBrowser::AssetBrowserTableView
- QTableView
+ AzQtComponents::TableView
AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
diff --git a/Code/Editor/Core/QtEditorApplication_linux.cpp b/Code/Editor/Core/QtEditorApplication_linux.cpp
index fa39609308..175bef0238 100644
--- a/Code/Editor/Core/QtEditorApplication_linux.cpp
+++ b/Code/Editor/Core/QtEditorApplication_linux.cpp
@@ -8,11 +8,21 @@
#include "QtEditorApplication.h"
+#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include
+#endif
+
namespace Editor
{
- bool EditorQtApplication::nativeEventFilter(const QByteArray& , void* , long* )
+ bool EditorQtApplication::nativeEventFilter([[maybe_unused]] const QByteArray& eventType, void* message, long*)
{
- // TODO_KDAB_LINUX
+ if (GetIEditor()->IsInGameMode())
+ {
+#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+ AzFramework::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast(message));
+#endif
+ return true;
+ }
return false;
}
}
diff --git a/Code/Editor/EditorToolsApplication.cpp b/Code/Editor/EditorToolsApplication.cpp
index 1e5d747e4a..26e608f657 100644
--- a/Code/Editor/EditorToolsApplication.cpp
+++ b/Code/Editor/EditorToolsApplication.cpp
@@ -34,10 +34,14 @@ namespace EditorInternal
: ToolsApplication(argc, argv)
{
EditorToolsApplicationRequests::Bus::Handler::BusConnect();
+ AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
+ AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusConnect();
}
EditorToolsApplication::~EditorToolsApplication()
{
+ AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusDisconnect();
+ AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
EditorToolsApplicationRequests::Bus::Handler::BusDisconnect();
Stop();
}
@@ -48,7 +52,6 @@ namespace EditorInternal
return m_StartupAborted;
}
-
void EditorToolsApplication::RegisterCoreComponents()
{
AzToolsFramework::ToolsApplication::RegisterCoreComponents();
@@ -274,5 +277,14 @@ namespace EditorInternal
Exit();
}
-}
+ AzToolsFramework::ViewportInteraction::KeyboardModifiers EditorToolsApplication::QueryKeyboardModifiers()
+ {
+ return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers());
+ }
+ AZStd::chrono::milliseconds EditorToolsApplication::EditorViewportInputTimeNow()
+ {
+ const auto now = AZStd::chrono::high_resolution_clock::now();
+ return AZStd::chrono::time_point_cast(now).time_since_epoch();
+ }
+} // namespace EditorInternal
diff --git a/Code/Editor/EditorToolsApplication.h b/Code/Editor/EditorToolsApplication.h
index 422772cbc4..d4e6223445 100644
--- a/Code/Editor/EditorToolsApplication.h
+++ b/Code/Editor/EditorToolsApplication.h
@@ -7,7 +7,9 @@
*/
#pragma once
+
#include
+#include
#include "Core/EditorMetricsPlainTextNameRegistration.h"
#include "EditorToolsApplicationAPI.h"
@@ -19,6 +21,8 @@ namespace EditorInternal
class EditorToolsApplication
: public AzToolsFramework::ToolsApplication
, public EditorToolsApplicationRequests::Bus::Handler
+ , public AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
+ , public AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler
{
public:
EditorToolsApplication(int* argc, char*** argv);
@@ -44,6 +48,12 @@ namespace EditorInternal
void CreateReflectionManager() override;
void Reflect(AZ::ReflectContext* context) override;
+ // EditorModifierKeyRequestBus overrides ...
+ AzToolsFramework::ViewportInteraction::KeyboardModifiers QueryKeyboardModifiers() override;
+
+ // EditorViewportInputTimeNowRequestBus overrides ...
+ AZStd::chrono::milliseconds EditorViewportInputTimeNow() override;
+
protected:
// From EditorToolsApplicationRequests
bool OpenLevel(AZStd::string_view levelName) override;
diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp
index 1ed901e514..5b5b52d28f 100644
--- a/Code/Editor/EditorViewportWidget.cpp
+++ b/Code/Editor/EditorViewportWidget.cpp
@@ -744,11 +744,15 @@ void EditorViewportWidget::RenderAll()
{
namespace AztfVi = AzToolsFramework::ViewportInteraction;
+ AztfVi::KeyboardModifiers keyboardModifiers;
+ AztfVi::EditorModifierKeyRequestBus::BroadcastResult(
+ keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers);
+
m_debugDisplay->DepthTestOff();
m_manipulatorManager->DrawManipulators(
*m_debugDisplay, GetCameraState(),
BuildMouseInteractionInternal(
- AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), QueryKeyboardModifiers(),
+ AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), keyboardModifiers,
BuildMousePick(WidgetToViewport(mapFromGlobal(QCursor::pos())))));
m_debugDisplay->DepthTestOn();
}
@@ -959,12 +963,13 @@ QWidget* EditorViewportWidget::GetWidgetForViewportContextMenu()
bool EditorViewportWidget::ShowingWorldSpace()
{
- return QueryKeyboardModifiers().Shift();
-}
+ namespace AztfVi = AzToolsFramework::ViewportInteraction;
-AzToolsFramework::ViewportInteraction::KeyboardModifiers EditorViewportWidget::QueryKeyboardModifiers()
-{
- return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers());
+ AztfVi::KeyboardModifiers keyboardModifiers;
+ AztfVi::EditorModifierKeyRequestBus::BroadcastResult(
+ keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers);
+
+ return keyboardModifiers.Shift();
}
void EditorViewportWidget::SetViewportId(int id)
@@ -1039,7 +1044,6 @@ void EditorViewportWidget::ConnectViewportInteractionRequestBus()
{
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
- AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
m_viewportUi.ConnectViewportUiBus(GetViewportId());
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusConnect();
@@ -1050,7 +1054,6 @@ void EditorViewportWidget::DisconnectViewportInteractionRequestBus()
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusDisconnect();
m_viewportUi.DisconnectViewportUiBus();
- AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusDisconnect();
}
diff --git a/Code/Editor/EditorViewportWidget.h b/Code/Editor/EditorViewportWidget.h
index 6b46524394..49930a2a13 100644
--- a/Code/Editor/EditorViewportWidget.h
+++ b/Code/Editor/EditorViewportWidget.h
@@ -92,7 +92,6 @@ class SANDBOX_API EditorViewportWidget final
, private AzFramework::InputSystemCursorConstraintRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler
- , private AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
, private AZ::RPI::SceneNotificationBus::Handler
{
@@ -212,9 +211,6 @@ private:
// EditorEntityViewportInteractionRequestBus overrides ...
void FindVisibleEntities(AZStd::vector& visibleEntities) override;
- // EditorModifierKeyRequestBus overrides ...
- AzToolsFramework::ViewportInteraction::KeyboardModifiers QueryKeyboardModifiers() override;
-
// Camera::EditorCameraRequestBus overrides ...
void SetViewFromEntityPerspective(const AZ::EntityId& entityId) override;
void SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, bool lockCameraMovement) override;
diff --git a/Code/Editor/Include/IEditorClassFactory.h b/Code/Editor/Include/IEditorClassFactory.h
index 0827dc96dc..dd47f803e2 100644
--- a/Code/Editor/Include/IEditorClassFactory.h
+++ b/Code/Editor/Include/IEditorClassFactory.h
@@ -14,8 +14,10 @@
#define CRYINCLUDE_EDITOR_INCLUDE_IEDITORCLASSFACTORY_H
#pragma once
+#include
#include
#include
+#include
#define DEFINE_UUID(l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
static const GUID uuid() { return { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; }
@@ -34,7 +36,7 @@ struct IUnknown
#endif
#define __uuidof(T) T::uuid()
-#if defined(AZ_PLATFORM_LINUX)
+#if defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
# ifndef _REFGUID_DEFINED
# define _REFGUID_DEFINED
@@ -65,7 +67,7 @@ enum
};
#endif
-#endif // defined(AZ_PLATFORM_LINUX)
+#endif // defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
#include "SandboxAPI.h"
diff --git a/Code/Editor/Platform/Mac/EditorEntitlements.plist b/Code/Editor/Platform/Mac/EditorEntitlements.plist
new file mode 100644
index 0000000000..cefa2bf93b
--- /dev/null
+++ b/Code/Editor/Platform/Mac/EditorEntitlements.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.cs.allow-dyld-environment-variables
+
+ com.apple.security.cs.disable-library-validation
+
+
+
diff --git a/Code/Editor/Platform/Mac/editor_mac.cmake b/Code/Editor/Platform/Mac/editor_mac.cmake
index fdccfafb46..eed955f2e4 100644
--- a/Code/Editor/Platform/Mac/editor_mac.cmake
+++ b/Code/Editor/Platform/Mac/editor_mac.cmake
@@ -12,28 +12,5 @@ set_target_properties(Editor PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_LIST_DIR}/gui_info.plist
RESOURCE ${CMAKE_CURRENT_LIST_DIR}/Images.xcassets
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME EditorAppIcon
+ ENTITLEMENT_FILE_PATH ${CMAKE_CURRENT_LIST_DIR}/EditorEntitlements.plist
)
-
-# We cannot use ly_add_target here because we're already including this file from inside ly_add_target
-# So we need to setup target, dependencies and install logic manually.
-add_executable(EditorDummy Platform/Mac/main_dummy.cpp)
-add_executable(AZ::EditorDummy ALIAS EditorDummy)
-
-ly_target_link_libraries(EditorDummy
- PRIVATE
- AZ::AzCore
- AZ::AzFramework)
-
-ly_add_dependencies(Editor EditorDummy)
-
-# Store the aliased target into a DIRECTORY property
-set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS AZ::EditorDummy)
-
-# Store the directory path in a GLOBAL property so that it can be accessed
-# in the layout install logic. Skip if the directory has already been added
-get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
-if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories)
- set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
-endif()
-
-ly_install_add_install_path_setreg(Editor)
\ No newline at end of file
diff --git a/Code/Editor/Platform/Mac/gui_info.plist b/Code/Editor/Platform/Mac/gui_info.plist
index cc87cbbb47..5b5f94e977 100644
--- a/Code/Editor/Platform/Mac/gui_info.plist
+++ b/Code/Editor/Platform/Mac/gui_info.plist
@@ -3,7 +3,7 @@
CFBundleExecutable
- EditorDummy
+ Editor
CFBundleIdentifier
org.O3DE.Editor
CFBundlePackageType
diff --git a/Code/Editor/Platform/Mac/main_dummy.cpp b/Code/Editor/Platform/Mac/main_dummy.cpp
deleted file mode 100644
index 348a32ab47..0000000000
--- a/Code/Editor/Platform/Mac/main_dummy.cpp
+++ /dev/null
@@ -1,75 +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
-#include
-#include
-#include
-#include
-
-#include
-
-int main(int argc, char* argv[])
-{
- // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
- AZ::ComponentApplication::Descriptor desc;
- AZ::ComponentApplication application;
- application.Create(desc);
-
- AZStd::vector envVars;
-
- const char* homePath = std::getenv("HOME");
- envVars.push_back(AZStd::string::format("HOME=%s", homePath));
-
- if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
- {
- const char* dyldLibPathOrig = std::getenv("DYLD_LIBRARY_PATH");
- AZStd::string dyldSearchPath = AZStd::string::format("DYLD_LIBRARY_PATH=%s", dyldLibPathOrig);
- if (AZ::IO::FixedMaxPath projectModulePath;
- settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
- {
- dyldSearchPath.append(":");
- dyldSearchPath.append(projectModulePath.c_str());
- }
-
- if (AZ::IO::FixedMaxPath installedBinariesFolder;
- settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
- {
- if (AZ::IO::FixedMaxPath engineRootFolder;
- settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
- {
- installedBinariesFolder = engineRootFolder / installedBinariesFolder;
- dyldSearchPath.append(":");
- dyldSearchPath.append(installedBinariesFolder.c_str());
- }
- }
- envVars.push_back(dyldSearchPath);
- }
-
- AZStd::string commandArgs;
- for (int i = 1; i < argc; i++)
- {
- commandArgs.append(argv[i]);
- commandArgs.append(" ");
- }
-
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- AZ::IO::Path processPath{ AZ::IO::PathView(AZ::Utils::GetExecutableDirectory()) };
- processPath /= "Editor";
- processLaunchInfo.m_processExecutableString = AZStd::move(processPath.Native());
- processLaunchInfo.m_commandlineParameters = commandArgs;
- processLaunchInfo.m_environmentVariables = &envVars;
- processLaunchInfo.m_showWindow = true;
-
- AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
-
- application.Destroy();
-
- return 0;
-}
-
diff --git a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
index 2aff57cfb1..cd9f2e79c7 100644
--- a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
+++ b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
@@ -51,4 +51,5 @@ ly_add_target(
AZ::AzCore
AZ::AzToolsFramework
AZ::AzQtComponents
+ Legacy::EditorCore
)
diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.h b/Code/Framework/AzCore/AzCore/Debug/Profiler.h
index 8af48e47f6..56103e8314 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Profiler.h
+++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.h
@@ -59,6 +59,20 @@ namespace AZStd
namespace AZ::Debug
{
+ // interface for externally defined profiler systems
+ class Profiler
+ {
+ public:
+ AZ_RTTI(Profiler, "{3E5D6329-72D1-41BA-9158-68A349D1A4D5}");
+
+ Profiler() = default;
+ virtual ~Profiler() = default;
+
+ // support for the extra macro args (e.g. format strings) will come in a later PR
+ virtual void BeginRegion(const Budget* budget, const char* eventName) = 0;
+ virtual void EndRegion(const Budget* budget) = 0;
+ };
+
class ProfileScope
{
public:
diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.inl b/Code/Framework/AzCore/AzCore/Debug/Profiler.inl
index 8ca8368ce1..74c0f553c4 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Profiler.inl
+++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.inl
@@ -6,6 +6,8 @@
*
*/
+#include
+
namespace AZ::Debug
{
template
@@ -22,9 +24,11 @@ namespace AZ::Debug
PIXBeginEvent(PIX_COLOR_INDEX(budget->Crc() & 0xff), eventName, args...);
#endif
budget->BeginProfileRegion();
-// TODO: injecting instrumentation for other profilers
-// NOTE: external profiler registration won't occur inline in a header necessarily in this manner, but the exact mechanism
-// will be introduced in a future PR
+
+ if (auto profiler = AZ::Interface::Get(); profiler)
+ {
+ profiler->BeginRegion(budget, eventName);
+ }
#endif
}
@@ -39,6 +43,10 @@ namespace AZ::Debug
#if defined(USE_PIX)
PIXEndEvent();
#endif
+ if (auto profiler = AZ::Interface::Get(); profiler)
+ {
+ profiler->EndRegion(budget);
+ }
#endif
}
diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp
index 5cf854d49f..1ca6a7c4c7 100644
--- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp
+++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp
@@ -72,6 +72,7 @@ namespace AZ
{
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
+ bool fileFound = false;
if (AZ::IO::FixedMaxPath projectModulePath;
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
{
@@ -79,6 +80,23 @@ namespace AZ
if (AZ::IO::SystemFile::Exists(projectModulePath.c_str()))
{
m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size());
+ fileFound = true;
+ }
+ }
+ if (!fileFound)
+ {
+ if (AZ::IO::FixedMaxPath installedBinariesPath;
+ settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
+ {
+ if (AZ::IO::FixedMaxPath engineRootFolder;
+ settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
+ {
+ installedBinariesPath = engineRootFolder / installedBinariesPath / fullFilePath;
+ if (AZ::IO::SystemFile::Exists(installedBinariesPath.c_str()))
+ {
+ m_fileName.assign(installedBinariesPath.c_str(), installedBinariesPath.Native().size());
+ }
+ }
}
}
}
diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp
index 9aff67a00f..2e31936057 100644
--- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp
+++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp
@@ -9,6 +9,7 @@
#include
#include
+#include
namespace AZ
{
@@ -39,6 +40,14 @@ namespace AZ
AZ::IO::FixedMaxPath path{homePath};
return path.Native();
}
+
+ struct passwd* pass = getpwuid(getuid());
+ if (pass)
+ {
+ AZ::IO::FixedMaxPath path{pass->pw_dir};
+ return path.Native();
+ }
+
return {};
}
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
index c94d588a90..d2a81102dc 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
@@ -181,7 +181,7 @@ namespace AZ::IO::ArchiveInternal
return 0;
}
- nTotal = (AZStd::min)(nTotal, GetFileSize() - m_nCurSeek);
+ nTotal = AZStd::min(nTotal, GetFileSize() - m_nCurSeek);
int64_t nReadBytes = GetFile()->ReadData(pDest, m_nCurSeek, nTotal);
if (nReadBytes == -1)
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp
index b909689c22..1b3645630e 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp
@@ -9,8 +9,19 @@
#include
#include
+#include
+
namespace AzFramework
{
+ ClickDetector::ClickDetector()
+ {
+ m_timeNowFn = []
+ {
+ const auto now = AZStd::chrono::high_resolution_clock::now();
+ return AZStd::chrono::time_point_cast(now).time_since_epoch();
+ };
+ }
+
ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta)
{
const auto previousDetectionState = m_detectionState;
@@ -26,11 +37,13 @@ namespace AzFramework
if (clickEvent == ClickEvent::Down)
{
- const auto now = std::chrono::steady_clock::now();
+ const auto now = m_timeNowFn();
if (m_tryBeginTime)
{
- const std::chrono::duration diff = now - m_tryBeginTime.value();
- if (diff.count() < m_doubleClickInterval)
+ using FloatingPointSeconds = AZStd::chrono::duration;
+
+ const auto diff = now - m_tryBeginTime.value();
+ if (FloatingPointSeconds(diff).count() < m_doubleClickInterval)
{
return ClickOutcome::Nil;
}
@@ -43,7 +56,8 @@ namespace AzFramework
}
else if (clickEvent == ClickEvent::Up)
{
- const auto clickOutcome = [detectionState = m_detectionState] {
+ const auto clickOutcome = [detectionState = m_detectionState]
+ {
if (detectionState == DetectionState::WaitingForMove)
{
return ClickOutcome::Click;
@@ -66,4 +80,9 @@ namespace AzFramework
return ClickOutcome::Nil;
}
+
+ void ClickDetector::OverrideTimeNowFn(AZStd::function timeNowFn)
+ {
+ m_timeNowFn = AZStd::move(timeNowFn);
+ }
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h
index f95924550a..70bdeb4619 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h
@@ -8,6 +8,7 @@
#pragma once
+#include
#include
#include
@@ -21,10 +22,9 @@ namespace AzFramework
//! (mouse down with movement and then mouse up).
class ClickDetector
{
- //! Alias for recording time of mouse down events
- using Time = std::chrono::time_point;
-
public:
+ ClickDetector();
+
//! Internal representation of click event (map from external event for this when
//! calling DetectClick).
enum class ClickEvent
@@ -51,6 +51,10 @@ namespace AzFramework
void SetDoubleClickInterval(float doubleClickInterval);
//! Override the dead zone before a 'move' outcome will be triggered.
void SetDeadZone(float deadZone);
+ //! Override how the current time is retrieved.
+ //! This is helpful to override when it comes to simulating different passages of
+ //! time to avoid double click issues in tests for example.
+ void OverrideTimeNowFn(AZStd::function timeNowFn);
private:
//! Internal state of ClickDetector based on incoming events.
@@ -65,7 +69,9 @@ namespace AzFramework
float m_deadZone = 2.0f; //!< How far to move before a click is cancelled (when Move will fire).
float m_doubleClickInterval = 0.4f; //!< Default double click interval, can be overridden.
DetectionState m_detectionState; //!< Internal state of ClickDetector.
- AZStd::optional
diff --git a/Code/Tools/AssetProcessor/Platform/Mac/main_dummy.cpp b/Code/Tools/AssetProcessor/Platform/Mac/main_dummy.cpp
deleted file mode 100644
index 3eed37e555..0000000000
--- a/Code/Tools/AssetProcessor/Platform/Mac/main_dummy.cpp
+++ /dev/null
@@ -1,75 +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
-#include
-#include
-#include
-#include
-
-#include
-
-int main(int argc, char* argv[])
-{
- // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
- AZ::ComponentApplication::Descriptor desc;
- AZ::ComponentApplication application;
- application.Create(desc);
-
- AZStd::vector envVars;
-
- const char* homePath = std::getenv("HOME");
- envVars.push_back(AZStd::string::format("HOME=%s", homePath));
-
- if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
- {
- const char* dyldLibPathOrig = std::getenv("DYLD_LIBRARY_PATH");
- AZStd::string dyldSearchPath = AZStd::string::format("DYLD_LIBRARY_PATH=%s", dyldLibPathOrig);
- if (AZ::IO::FixedMaxPath projectModulePath;
- settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
- {
- dyldSearchPath.append(":");
- dyldSearchPath.append(projectModulePath.c_str());
- }
-
- if (AZ::IO::FixedMaxPath installedBinariesFolder;
- settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
- {
- if (AZ::IO::FixedMaxPath engineRootFolder;
- settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
- {
- installedBinariesFolder = engineRootFolder / installedBinariesFolder;
- dyldSearchPath.append(":");
- dyldSearchPath.append(installedBinariesFolder.c_str());
- }
- }
- envVars.push_back(dyldSearchPath);
- }
-
- AZStd::string commandArgs;
- for (int i = 1; i < argc; i++)
- {
- commandArgs.append(argv[i]);
- commandArgs.append(" ");
- }
-
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- AZ::IO::Path processPath{ AZ::IO::PathView(AZ::Utils::GetExecutableDirectory()) };
- processPath /= "AssetProcessor";
- processLaunchInfo.m_processExecutableString = AZStd::move(processPath.Native());
- processLaunchInfo.m_commandlineParameters = commandArgs;
- processLaunchInfo.m_environmentVariables = &envVars;
- processLaunchInfo.m_showWindow = true;
-
- AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
-
- application.Destroy();
-
- return 0;
-}
-
diff --git a/Code/Tools/BundleLauncher/CMakeLists.txt b/Code/Tools/BundleLauncher/CMakeLists.txt
new file mode 100644
index 0000000000..812cb21099
--- /dev/null
+++ b/Code/Tools/BundleLauncher/CMakeLists.txt
@@ -0,0 +1,24 @@
+#
+# 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
+#
+#
+
+# This is the launcher that will be used by the O3DE_SDK.app bundle
+# generated by the cmake install process for Mac.
+if(NOT ${PAL_PLATFORM_NAME} STREQUAL Mac)
+ return()
+endif()
+
+ly_add_target(
+ NAME O3DE_SDK EXECUTABLE
+ NAMESPACE AZ
+ FILES_CMAKE
+ O3DE_SDK_files.cmake
+ BUILD_DEPENDENCIES
+ PRIVATE
+ AZ::AzCore
+ AZ::AzFramework
+)
diff --git a/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp b/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp
new file mode 100644
index 0000000000..0c362ac829
--- /dev/null
+++ b/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+int main(int argc, char* argv[])
+{
+ // We need to pass in the engine path since we won't be able to find it by searching upwards.
+ // We can't use any containers that use our custom allocator till after the call to ComponentApplication::Create()
+ AZ::IO::FixedMaxPath processPath = AZ::Utils::GetExecutableDirectory();
+ AZ::IO::FixedMaxPath enginePath = (processPath / "../Engine").LexicallyNormal();
+ auto enginePathParam = AZ::SettingsRegistryInterface::FixedValueString::format(R"(--engine-path="%s")", enginePath.c_str());
+ // Uses the fixed_vector deduction guide to determine the type is AZStd::fixed_vector
+ AZStd::fixed_vector commandLineParams{ processPath.Native().data(), enginePathParam.data() };
+
+
+ // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
+ AZ::ComponentApplication application(static_cast(commandLineParams.size()), commandLineParams.data());
+ application.Create(AZ::ComponentApplication::Descriptor());
+
+ AZ::IO::FixedMaxPath installedBinariesFolder;
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ if (settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
+ {
+ installedBinariesFolder = enginePath / installedBinariesFolder;
+ }
+ }
+
+ AZ::IO::FixedMaxPath shellPath = "/bin/sh";
+ AZStd::string parameters = AZStd::string::format("-c \"export LY_CMAKE_PATH=/usr/local/bin && \"%s/python/get_python.sh\"\"", enginePath.c_str());
+ AzFramework::ProcessLauncher::ProcessLaunchInfo shellProcessLaunch;
+ shellProcessLaunch.m_processExecutableString = AZStd::move(shellPath.Native());
+ shellProcessLaunch.m_commandlineParameters = parameters;
+ shellProcessLaunch.m_showWindow = true;
+ shellProcessLaunch.m_workingDirectory = enginePath.String();
+ AZStd::unique_ptr shellProcess(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE));
+ shellProcess->WaitForProcessToExit(120);
+ shellProcess.reset();
+
+ AZ::IO::FixedMaxPath projectManagerPath = installedBinariesFolder/"o3de.app"/"Contents"/"MacOS"/"o3de";
+ AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
+ processLaunchInfo.m_processExecutableString = AZStd::move(projectManagerPath.Native());
+ processLaunchInfo.m_showWindow = true;
+ AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
+
+ application.Destroy();
+
+ return 0;
+}
+
diff --git a/Code/Tools/BundleLauncher/O3DE_SDK_files.cmake b/Code/Tools/BundleLauncher/O3DE_SDK_files.cmake
new file mode 100644
index 0000000000..04989c9df2
--- /dev/null
+++ b/Code/Tools/BundleLauncher/O3DE_SDK_files.cmake
@@ -0,0 +1,11 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(FILES
+ O3DE_SDK_Launcher.cpp
+)
diff --git a/Code/Tools/BundleLauncher/info.plist b/Code/Tools/BundleLauncher/info.plist
new file mode 100644
index 0000000000..5b3dd43b37
--- /dev/null
+++ b/Code/Tools/BundleLauncher/info.plist
@@ -0,0 +1,18 @@
+
+
+
+
+ CFBundleExecutable
+ O3DE_SDK
+ CFBundleIdentifier
+ org.O3DE.O3DE_SDK
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ NSHumanReadableCopyright
+ Copyright (c) Contributors to the Open 3D Engine Project.
+ NSPrincipalClass
+ NSApplication
+
+
diff --git a/Code/Tools/CMakeLists.txt b/Code/Tools/CMakeLists.txt
index 66c43e53e5..8107089433 100644
--- a/Code/Tools/CMakeLists.txt
+++ b/Code/Tools/CMakeLists.txt
@@ -20,3 +20,4 @@ add_subdirectory(GridHub)
add_subdirectory(Standalone)
add_subdirectory(TestImpactFramework)
add_subdirectory(ProjectManager)
+add_subdirectory(BundleLauncher)
diff --git a/Code/Tools/ProjectManager/Platform/Mac/PAL_mac.cmake b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac.cmake
index 7a325ca97e..5cd1fb5a22 100644
--- a/Code/Tools/ProjectManager/Platform/Mac/PAL_mac.cmake
+++ b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac.cmake
@@ -5,3 +5,4 @@
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
+
diff --git a/Code/Tools/ProjectManager/Resources/Delete.svg b/Code/Tools/ProjectManager/Resources/Delete.svg
new file mode 100644
index 0000000000..f932c71544
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Delete.svg
@@ -0,0 +1,4 @@
+
diff --git a/Code/Tools/ProjectManager/Resources/Edit.svg b/Code/Tools/ProjectManager/Resources/Edit.svg
new file mode 100644
index 0000000000..3ee9bbbfae
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Edit.svg
@@ -0,0 +1,7 @@
+
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
index 2e93e9eca9..30bcc1ace5 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
@@ -35,5 +35,8 @@
Backgrounds/DefaultBackground.jpg
Backgrounds/FtueBackground.jpg
FeatureTagClose.svg
+ Refresh.svg
+ Edit.svg
+ Delete.svg
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss
index 17c5077d83..30117d6636 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss
@@ -518,3 +518,82 @@ QProgressBar::chunk {
font-size: 12px;
font-weight: 600;
}
+
+/************** Engine **************/
+
+#engineTab::tab-bar {
+ left: 60px;
+}
+
+#engineTabBar::tab {
+ height: 50px;
+ background-color: transparent;
+ font-weight: 400;
+ font-size: 18px;
+ min-width: 160px;
+}
+
+#engineTabBar::tab:selected {
+ border-bottom: 3px solid #94D2FF;
+ color: #94D2FF;
+ font-weight: 600;
+}
+#engineTabBar::tab:hover {
+ color: #94D2FF;
+ font-weight: 600;
+}
+#engineTabBar::tab:pressed {
+ color: #66bcfa;
+}
+
+#engineTopFrame {
+ background-color:#1E252F;
+}
+
+/************** Gem Repo **************/
+
+#gemRepoHeaderLabel {
+ font-size: 12px;
+}
+
+#gemRepoHeaderRefreshButton {
+ background-color: transparent;
+ qproperty-flat: true;
+ qproperty-iconSize: 14px;
+}
+
+#gemRepoHeaderAddButton {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #888888, stop: 1.0 #555555);
+ qproperty-flat: true;
+ margin-right:30px;
+ min-width:120px;
+ max-width:120px;
+ min-height:24px;
+ max-height:24px;
+ border-radius: 3px;
+ text-align:center;
+ font-size:12px;
+ font-weight:600;
+}
+#gemRepoHeaderAddButton:hover {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #999999, stop: 1.0 #666666);
+}
+#gemRepoHeaderAddButton:pressed {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #555555, stop: 1.0 #777777);
+}
+
+#gemRepoHeaderTable {
+ background-color: transparent;
+ max-height: 30px;
+}
+
+#gemRepoListHeader {
+ background-color: transparent;
+}
+
+#gemRepoInspector {
+ background: #444444;
+}
diff --git a/Code/Tools/ProjectManager/Resources/Refresh.svg b/Code/Tools/ProjectManager/Resources/Refresh.svg
new file mode 100644
index 0000000000..80cc892c68
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Refresh.svg
@@ -0,0 +1,4 @@
+
diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp
new file mode 100644
index 0000000000..c78a9426db
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ EngineScreenCtrl::EngineScreenCtrl(QWidget* parent)
+ : ScreenWidget(parent)
+ {
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setContentsMargins(0, 0, 0, 0);
+
+ QFrame* topBarFrameWidget = new QFrame(this);
+ topBarFrameWidget->setObjectName("engineTopFrame");
+ QHBoxLayout* topBarHLayout = new QHBoxLayout();
+ topBarHLayout->setContentsMargins(0, 0, 0, 0);
+
+ topBarFrameWidget->setLayout(topBarHLayout);
+
+ QTabWidget* tabWidget = new QTabWidget();
+ tabWidget->setObjectName("engineTab");
+ tabWidget->tabBar()->setObjectName("engineTabBar");
+ tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus);
+
+ m_engineSettingsScreen = new EngineSettingsScreen();
+ m_gemRepoScreen = new GemRepoScreen();
+
+ tabWidget->addTab(m_engineSettingsScreen, tr("General"));
+ tabWidget->addTab(m_gemRepoScreen, tr("Gem Repositories"));
+ topBarHLayout->addWidget(tabWidget);
+
+ vLayout->addWidget(topBarFrameWidget);
+
+ setLayout(vLayout);
+ }
+
+ ProjectManagerScreen EngineScreenCtrl::GetScreenEnum()
+ {
+ return ProjectManagerScreen::UpdateProject;
+ }
+
+ QString EngineScreenCtrl::GetTabText()
+ {
+ return tr("Engine");
+ }
+
+ bool EngineScreenCtrl::IsTab()
+ {
+ return true;
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h
new file mode 100644
index 0000000000..9e799f13e7
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h
@@ -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
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(EngineSettingsScreen)
+ QT_FORWARD_DECLARE_CLASS(GemRepoScreen)
+
+ class EngineScreenCtrl
+ : public ScreenWidget
+ {
+ public:
+ explicit EngineScreenCtrl(QWidget* parent = nullptr);
+ ~EngineScreenCtrl() = default;
+ ProjectManagerScreen GetScreenEnum() override;
+
+ QString GetTabText() override;
+ bool IsTab() override;
+
+ EngineSettingsScreen* m_engineSettingsScreen = nullptr;
+ GemRepoScreen* m_gemRepoScreen = nullptr;
+ };
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
index 0c24aac9f1..dec1c9a257 100644
--- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
@@ -7,15 +7,16 @@
*/
#include
-#include
-#include
-#include
-#include
#include
#include
#include
#include
+#include
+#include
+#include
+#include
+
namespace O3DE::ProjectManager
{
EngineSettingsScreen::EngineSettingsScreen(QWidget* parent)
@@ -78,16 +79,6 @@ namespace O3DE::ProjectManager
return ProjectManagerScreen::EngineSettings;
}
- QString EngineSettingsScreen::GetTabText()
- {
- return tr("Engine");
- }
-
- bool EngineSettingsScreen::IsTab()
- {
- return true;
- }
-
void EngineSettingsScreen::OnTextChanged()
{
// save engine settings
diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h
index 9d212c44b1..2f16400405 100644
--- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h
+++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h
@@ -24,8 +24,6 @@ namespace O3DE::ProjectManager
~EngineSettingsScreen() = default;
ProjectManagerScreen GetScreenEnum() override;
- QString GetTabText() override;
- bool IsTab() override;
protected slots:
void OnTextChanged();
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp
new file mode 100644
index 0000000000..3e524d8ec8
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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
+
+namespace O3DE::ProjectManager
+{
+ GemRepoInfo::GemRepoInfo(
+ const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled = true)
+ : m_name(name)
+ , m_creator(creator)
+ , m_summary(summary)
+ , m_lastUpdated(lastUpdated)
+ , m_isEnabled(isEnabled)
+ {
+ }
+
+ bool GemRepoInfo::IsValid() const
+ {
+ return !m_name.isEmpty();
+ }
+
+ bool GemRepoInfo::operator<(const GemRepoInfo& gemRepoInfo) const
+ {
+ return (m_lastUpdated < gemRepoInfo.m_lastUpdated);
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h
new file mode 100644
index 0000000000..6f4f828951
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h
@@ -0,0 +1,37 @@
+/*
+ * 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
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoInfo
+ {
+ public:
+ GemRepoInfo() = default;
+ GemRepoInfo(const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled);
+
+ bool IsValid() const;
+
+ bool operator<(const GemRepoInfo& gemRepoInfo) const;
+
+ QString m_path;
+ QString m_name = "Unknown Gem Repo Name";
+ QString m_creator = "Unknown Creator";
+ bool m_isEnabled = false; //! Is the repo currently enabled for this engine?
+ QString m_summary = "No summary provided.";
+ QString m_directoryLink;
+ QString m_repoLink;
+ QDateTime m_lastUpdated;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
new file mode 100644
index 0000000000..88ccee2636
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoItemDelegate::GemRepoItemDelegate(QAbstractItemModel* model, QObject* parent)
+ : QStyledItemDelegate(parent)
+ , m_model(model)
+ {
+ m_refreshIcon = QIcon(":/Refresh.svg").pixmap(s_refreshIconSize, s_refreshIconSize);
+ m_editIcon = QIcon(":/Edit.svg").pixmap(s_iconSize, s_iconSize);
+ m_deleteIcon = QIcon(":/Delete.svg").pixmap(s_iconSize, s_iconSize);
+ }
+
+ void GemRepoItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
+ {
+ if (!modelIndex.isValid())
+ {
+ return;
+ }
+
+ QStyleOptionViewItem options(option);
+ initStyleOption(&options, modelIndex);
+
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ QRect fullRect, itemRect, contentRect;
+ CalcRects(options, fullRect, itemRect, contentRect);
+ QRect buttonRect = CalcButtonRect(contentRect);
+
+ QFont standardFont(options.font);
+ standardFont.setPixelSize(static_cast(s_fontSize));
+ QFontMetrics standardFontMetrics(standardFont);
+
+ painter->save();
+ painter->setClipping(true);
+ painter->setClipRect(fullRect);
+ painter->setFont(standardFont);
+ painter->setPen(m_textColor);
+
+ // Draw background
+ painter->fillRect(fullRect, m_backgroundColor);
+
+ // Draw item background
+ const QColor itemBackgroundColor = options.state & QStyle::State_MouseOver ? m_itemBackgroundColor.lighter(120) : m_itemBackgroundColor;
+ painter->fillRect(itemRect, itemBackgroundColor);
+
+ // Draw border
+ if (options.state & QStyle::State_Selected)
+ {
+ painter->save();
+ QPen borderPen(m_borderColor);
+ borderPen.setWidth(s_borderWidth);
+ painter->setPen(borderPen);
+ painter->drawRect(itemRect);
+
+ painter->restore();
+ }
+
+ // Repo enabled
+ DrawButton(painter, buttonRect, modelIndex);
+
+ // Repo name
+ QString repoName = GemRepoModel::GetName(modelIndex);
+ repoName = QFontMetrics(standardFont).elidedText(repoName, Qt::TextElideMode::ElideRight, s_nameMaxWidth);
+
+ QRect repoNameRect = GetTextRect(standardFont, repoName, s_fontSize);
+ int currentHorizontalOffset = buttonRect.left() + s_buttonWidth + s_buttonSpacing;
+ repoNameRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoNameRect.height() / 2);
+ repoNameRect = painter->boundingRect(repoNameRect, Qt::TextSingleLine, repoName);
+
+ painter->drawText(repoNameRect, Qt::TextSingleLine, repoName);
+
+ // Rem repo creator
+ QString repoCreator = GemRepoModel::GetCreator(modelIndex);
+ repoCreator = standardFontMetrics.elidedText(repoCreator, Qt::TextElideMode::ElideRight, s_creatorMaxWidth);
+
+ QRect repoCreatorRect = GetTextRect(standardFont, repoCreator, s_fontSize);
+ currentHorizontalOffset += s_nameMaxWidth + s_contentSpacing;
+ repoCreatorRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoCreatorRect.height() / 2);
+ repoCreatorRect = painter->boundingRect(repoCreatorRect, Qt::TextSingleLine, repoCreator);
+
+ painter->drawText(repoCreatorRect, Qt::TextSingleLine, repoCreator);
+
+ // Repo update
+ QString repoUpdatedDate = GemRepoModel::GetLastUpdated(modelIndex).toString("dd/MM/yyyy hh:mmap");
+ repoUpdatedDate = standardFontMetrics.elidedText(repoUpdatedDate, Qt::TextElideMode::ElideRight, s_updatedMaxWidth);
+
+ QRect repoUpdatedDateRect = GetTextRect(standardFont, repoUpdatedDate, s_fontSize);
+ currentHorizontalOffset += s_creatorMaxWidth + s_contentSpacing;
+ repoUpdatedDateRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoUpdatedDateRect.height() / 2);
+ repoUpdatedDateRect = painter->boundingRect(repoUpdatedDateRect, Qt::TextSingleLine, repoUpdatedDate);
+
+ painter->drawText(repoUpdatedDateRect, Qt::TextSingleLine, repoUpdatedDate);
+
+ // Draw refresh button
+ painter->drawPixmap(
+ repoUpdatedDateRect.left() + repoUpdatedDateRect.width() + s_refreshIconSpacing,
+ contentRect.center().y() - s_refreshIconSize / 3, // Dividing size by 3 centers much better
+ m_refreshIcon);
+
+ if (options.state & QStyle::State_MouseOver)
+ {
+ DrawEditButtons(painter, contentRect);
+ }
+
+ painter->restore();
+ }
+
+ QSize GemRepoItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
+ {
+ QStyleOptionViewItem options(option);
+ initStyleOption(&options, modelIndex);
+
+ int marginsHorizontal = s_itemMargins.left() + s_itemMargins.right() + s_contentMargins.left() + s_contentMargins.right();
+ return QSize(marginsHorizontal + s_buttonWidth + s_buttonSpacing + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 3, s_height);
+ }
+
+ bool GemRepoItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex)
+ {
+ if (!modelIndex.isValid())
+ {
+ return false;
+ }
+
+ if (event->type() == QEvent::KeyPress)
+ {
+ auto keyEvent = static_cast(event);
+ if (keyEvent->key() == Qt::Key_Space)
+ {
+ const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
+ GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
+ return true;
+ }
+ }
+
+ if (event->type() == QEvent::MouseButtonPress)
+ {
+ QMouseEvent* mouseEvent = static_cast(event);
+
+ QRect fullRect, itemRect, contentRect;
+ CalcRects(option, fullRect, itemRect, contentRect);
+ const QRect buttonRect = CalcButtonRect(contentRect);
+
+ if (buttonRect.contains(mouseEvent->pos()))
+ {
+ const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
+ GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
+ return true;
+ }
+ }
+
+ return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
+ }
+
+ void GemRepoItemDelegate::CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const
+ {
+ outFullRect = QRect(option.rect);
+ outItemRect = QRect(outFullRect.adjusted(s_itemMargins.left(), s_itemMargins.top(), -s_itemMargins.right(), -s_itemMargins.bottom()));
+ outContentRect = QRect(outItemRect.adjusted(s_contentMargins.left(), s_contentMargins.top(), -s_contentMargins.right(), -s_contentMargins.bottom()));
+ }
+
+ QRect GemRepoItemDelegate::GetTextRect(QFont& font, const QString& text, qreal fontSize) const
+ {
+ font.setPixelSize(static_cast(fontSize));
+ return QFontMetrics(font).boundingRect(text);
+ }
+
+ QRect GemRepoItemDelegate::CalcButtonRect(const QRect& contentRect) const
+ {
+ const QPoint topLeft = QPoint(contentRect.left(), contentRect.top() + contentRect.height() / 2 - s_buttonHeight / 2);
+ const QSize size = QSize(s_buttonWidth, s_buttonHeight);
+ return QRect(topLeft, size);
+ }
+
+ void GemRepoItemDelegate::DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const
+ {
+ painter->save();
+ QPoint circleCenter;
+
+ const bool isEnabled = GemRepoModel::IsEnabled(modelIndex);
+ if (isEnabled)
+ {
+ painter->setBrush(m_buttonEnabledColor);
+ painter->setPen(m_buttonEnabledColor);
+
+ circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
+ }
+ else
+ {
+ circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius + 1, 1);
+ }
+
+ // Rounded rect
+ painter->drawRoundedRect(buttonRect, s_buttonBorderRadius, s_buttonBorderRadius);
+
+ // Circle
+ painter->setBrush(m_textColor);
+ painter->drawEllipse(circleCenter, s_buttonCircleRadius, s_buttonCircleRadius);
+
+ painter->restore();
+ }
+
+ void GemRepoItemDelegate::DrawEditButtons(QPainter* painter, const QRect& contentRect) const
+ {
+ painter->drawPixmap(contentRect.right() - s_iconSize * 2 - s_iconSpacing, contentRect.center().y() - s_iconSize / 2, m_editIcon);
+ painter->drawPixmap(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2, m_deleteIcon);
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h
new file mode 100644
index 0000000000..08d1fdffae
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h
@@ -0,0 +1,82 @@
+/*
+ * 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
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
+QT_FORWARD_DECLARE_CLASS(QEvent)
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoItemDelegate
+ : public QStyledItemDelegate
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRepoItemDelegate(QAbstractItemModel* model, QObject* parent = nullptr);
+ ~GemRepoItemDelegate() = default;
+
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
+ bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
+ QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
+
+ // Colors
+ const QColor m_textColor = QColor("#FFFFFF");
+ const QColor m_backgroundColor = QColor("#333333"); // Outside of the actual repo item
+ const QColor m_itemBackgroundColor = QColor("#404040"); // Background color of the repo item
+ const QColor m_borderColor = QColor("#1E70EB");
+ const QColor m_buttonEnabledColor = QColor("#1E70EB");
+
+ // Item
+ inline constexpr static int s_height = 72; // Repo item total height
+ inline constexpr static qreal s_fontSize = 12.0;
+
+ // Margin and borders
+ inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/0, /*top=*/8, /*right=*/60, /*bottom=*/8); // Item border distances
+ inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/20, /*right=*/20, /*bottom=*/20); // Distances of the elements within an item to the item borders
+ inline constexpr static int s_borderWidth = 4;
+
+ // Content
+ inline constexpr static int s_contentSpacing = 5;
+ inline constexpr static int s_nameMaxWidth = 145;
+ inline constexpr static int s_creatorMaxWidth = 115;
+ inline constexpr static int s_updatedMaxWidth = 125;
+
+ // Button
+ inline constexpr static int s_buttonWidth = 32;
+ inline constexpr static int s_buttonHeight = 16;
+ inline constexpr static int s_buttonBorderRadius = 8;
+ inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
+ inline constexpr static int s_buttonSpacing = 20;
+
+ // Icon
+ inline constexpr static int s_iconSize = 24;
+ inline constexpr static int s_iconSpacing = 16;
+ inline constexpr static int s_refreshIconSize = 14;
+ inline constexpr static int s_refreshIconSpacing = 10;
+
+ protected:
+ void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
+ QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
+ QRect CalcButtonRect(const QRect& contentRect) const;
+ void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
+ void DrawEditButtons(QPainter* painter, const QRect& contentRect) const;
+
+ QAbstractItemModel* m_model = nullptr;
+
+ QPixmap m_refreshIcon;
+ QPixmap m_editIcon;
+ QPixmap m_deleteIcon;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp
new file mode 100644
index 0000000000..519d52cb35
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoListView::GemRepoListView(QAbstractItemModel* model, QWidget* parent)
+ : QListView(parent)
+ {
+ setObjectName("gemRepoListView");
+ setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+
+ setModel(model);
+ setItemDelegate(new GemRepoItemDelegate(model, this));
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h
new file mode 100644
index 0000000000..0fd5d5c180
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h
@@ -0,0 +1,28 @@
+/*
+ * 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
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoListView
+ : public QListView
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRepoListView(QAbstractItemModel* model, QWidget* parent = nullptr);
+ ~GemRepoListView() = default;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp
new file mode 100644
index 0000000000..7a42c135e9
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoModel::GemRepoModel(QObject* parent)
+ : QStandardItemModel(parent)
+ {
+ m_selectionModel = new QItemSelectionModel(this, parent);
+ }
+
+ QItemSelectionModel* GemRepoModel::GetSelectionModel() const
+ {
+ return m_selectionModel;
+ }
+
+ void GemRepoModel::AddGemRepo(const GemRepoInfo& gemRepoInfo)
+ {
+ QStandardItem* item = new QStandardItem();
+
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+
+ item->setData(gemRepoInfo.m_name, RoleName);
+ item->setData(gemRepoInfo.m_creator, RoleCreator);
+ item->setData(gemRepoInfo.m_summary, RoleSummary);
+ item->setData(gemRepoInfo.m_isEnabled, RoleIsEnabled);
+ item->setData(gemRepoInfo.m_directoryLink, RoleDirectoryLink);
+ item->setData(gemRepoInfo.m_repoLink, RoleRepoLink);
+ item->setData(gemRepoInfo.m_lastUpdated, RoleLastUpdated);
+ item->setData(gemRepoInfo.m_path, RolePath);
+
+ appendRow(item);
+ }
+
+ void GemRepoModel::Clear()
+ {
+ clear();
+ }
+
+ QString GemRepoModel::GetName(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleName).toString();
+ }
+
+ QString GemRepoModel::GetCreator(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleCreator).toString();
+ }
+
+ QString GemRepoModel::GetSummary(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleSummary).toString();
+ }
+
+ QString GemRepoModel::GetDirectoryLink(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleDirectoryLink).toString();
+ }
+
+ QString GemRepoModel::GetRepoLink(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleRepoLink).toString();
+ }
+
+ QDateTime GemRepoModel::GetLastUpdated(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleLastUpdated).toDateTime();
+ }
+
+ QString GemRepoModel::GetPath(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RolePath).toString();
+ }
+
+ bool GemRepoModel::IsEnabled(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleIsEnabled).toBool();
+ }
+
+ void GemRepoModel::SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled)
+ {
+ model.setData(modelIndex, isEnabled, RoleIsEnabled);
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h
new file mode 100644
index 0000000000..2f1537d339
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h
@@ -0,0 +1,58 @@
+/*
+ * 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
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoModel
+ : public QStandardItemModel
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRepoModel(QObject* parent = nullptr);
+ QItemSelectionModel* GetSelectionModel() const;
+
+ void AddGemRepo(const GemRepoInfo& gemInfo);
+ void Clear();
+
+ static QString GetName(const QModelIndex& modelIndex);
+ static QString GetCreator(const QModelIndex& modelIndex);
+ static QString GetSummary(const QModelIndex& modelIndex);
+ static QString GetDirectoryLink(const QModelIndex& modelIndex);
+ static QString GetRepoLink(const QModelIndex& modelIndex);
+ static QDateTime GetLastUpdated(const QModelIndex& modelIndex);
+ static QString GetPath(const QModelIndex& modelIndex);
+
+ static bool IsEnabled(const QModelIndex& modelIndex);
+ static void SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled);
+
+ private:
+ enum UserRole
+ {
+ RoleName = Qt::UserRole,
+ RoleCreator,
+ RoleSummary,
+ RoleIsEnabled,
+ RoleDirectoryLink,
+ RoleRepoLink,
+ RoleLastUpdated,
+ RolePath
+ };
+
+ QItemSelectionModel* m_selectionModel = nullptr;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
new file mode 100644
index 0000000000..82de53a0d0
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoScreen::GemRepoScreen(QWidget* parent)
+ : ScreenWidget(parent)
+ {
+ m_gemRepoModel = new GemRepoModel(this);
+
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setMargin(0);
+ vLayout->setSpacing(0);
+ setLayout(vLayout);
+
+ QHBoxLayout* hLayout = new QHBoxLayout();
+ hLayout->setMargin(0);
+ hLayout->setSpacing(0);
+ vLayout->addLayout(hLayout);
+
+ hLayout->addSpacing(60);
+
+ m_gemRepoInspector = new QFrame(this);
+ m_gemRepoInspector->setObjectName(tr("gemRepoInspector"));
+ m_gemRepoInspector->setFixedWidth(240);
+
+ QVBoxLayout* middleVLayout = new QVBoxLayout();
+ middleVLayout->setMargin(0);
+ middleVLayout->setSpacing(0);
+
+ middleVLayout->addSpacing(30);
+
+ QHBoxLayout* topMiddleHLayout = new QHBoxLayout();
+ topMiddleHLayout->setMargin(0);
+ topMiddleHLayout->setSpacing(0);
+
+ m_lastAllUpdateLabel = new QLabel(tr("Last Updated: Never"), this);
+ m_lastAllUpdateLabel->setObjectName("gemRepoHeaderLabel");
+ topMiddleHLayout->addWidget(m_lastAllUpdateLabel);
+
+ topMiddleHLayout->addSpacing(20);
+
+ m_AllUpdateButton = new QPushButton(QIcon(":/Refresh.svg"), tr("Update All"), this);
+ m_AllUpdateButton->setObjectName("gemRepoHeaderRefreshButton");
+ topMiddleHLayout->addWidget(m_AllUpdateButton);
+
+ topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
+
+ m_AddRepoButton = new QPushButton(tr("Add Repository"), this);
+ m_AddRepoButton->setObjectName("gemRepoHeaderAddButton");
+ topMiddleHLayout->addWidget(m_AddRepoButton);
+
+ middleVLayout->addLayout(topMiddleHLayout);
+
+ middleVLayout->addSpacing(30);
+
+ // Create a QTableWidget just for its header
+ // Using a seperate model allows the setup of a header exactly as needed
+ m_gemRepoHeaderTable = new QTableWidget(this);
+ m_gemRepoHeaderTable->setObjectName("gemRepoHeaderTable");
+ m_gemRepoListHeader = m_gemRepoHeaderTable->horizontalHeader();
+ m_gemRepoListHeader->setObjectName("gemRepoListHeader");
+ m_gemRepoListHeader->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
+
+ // Insert columns so the header labels will show up
+ m_gemRepoHeaderTable->insertColumn(0);
+ m_gemRepoHeaderTable->insertColumn(1);
+ m_gemRepoHeaderTable->insertColumn(2);
+ m_gemRepoHeaderTable->insertColumn(3);
+ m_gemRepoHeaderTable->setHorizontalHeaderLabels({ tr("Enabled"), tr("Repository Name"), tr("Creator"), tr("Updated") });
+
+ const int headerExtraMargin = 10;
+ m_gemRepoListHeader->resizeSection(0, GemRepoItemDelegate::s_buttonWidth + GemRepoItemDelegate::s_buttonSpacing - 3);
+ m_gemRepoListHeader->resizeSection(1, GemRepoItemDelegate::s_nameMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
+ m_gemRepoListHeader->resizeSection(2, GemRepoItemDelegate::s_creatorMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
+ m_gemRepoListHeader->resizeSection(3, GemRepoItemDelegate::s_updatedMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
+
+ // Required to set stylesheet in code as it will not be respected if set in qss
+ m_gemRepoHeaderTable->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color:transparent; color:white; font-size:12px; text-align:left; border-style:none; }");
+ middleVLayout->addWidget(m_gemRepoHeaderTable);
+
+ m_gemRepoListView = new GemRepoListView(m_gemRepoModel, this);
+ middleVLayout->addWidget(m_gemRepoListView);
+
+ hLayout->addLayout(middleVLayout);
+ hLayout->addWidget(m_gemRepoInspector);
+
+ Reinit();
+ }
+
+ void GemRepoScreen::Reinit()
+ {
+ m_gemRepoModel->clear();
+ FillModel();
+
+ // Select the first entry after everything got correctly sized
+ QTimer::singleShot(200, [=]{
+ QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0);
+ m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
+ });
+ }
+
+ void GemRepoScreen::FillModel()
+ {
+ AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos();
+ if (allGemRepoInfosResult.IsSuccess())
+ {
+ // Add all available repos to the model
+ const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue();
+ for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos)
+ {
+ m_gemRepoModel->AddGemRepo(gemRepoInfo);
+ }
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str()));
+ }
+ }
+
+ ProjectManagerScreen GemRepoScreen::GetScreenEnum()
+ {
+ return ProjectManagerScreen::GemRepos;
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h
new file mode 100644
index 0000000000..b5316db84f
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QLabel)
+QT_FORWARD_DECLARE_CLASS(QPushButton)
+QT_FORWARD_DECLARE_CLASS(QHeaderView)
+QT_FORWARD_DECLARE_CLASS(QTableWidget)
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(GemRepoListView)
+ QT_FORWARD_DECLARE_CLASS(GemRepoModel)
+
+ class GemRepoScreen
+ : public ScreenWidget
+ {
+ public:
+ explicit GemRepoScreen(QWidget* parent = nullptr);
+ ~GemRepoScreen() = default;
+ ProjectManagerScreen GetScreenEnum() override;
+
+ void Reinit();
+
+ GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; }
+
+ private:
+ void FillModel();
+
+ QTableWidget* m_gemRepoHeaderTable = nullptr;
+ QHeaderView* m_gemRepoListHeader = nullptr;
+ GemRepoListView* m_gemRepoListView = nullptr;
+ QFrame* m_gemRepoInspector = nullptr;
+ GemRepoModel* m_gemRepoModel = nullptr;
+
+ QLabel* m_lastAllUpdateLabel;
+ QPushButton* m_AllUpdateButton;
+ QPushButton* m_AddRepoButton;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
index a723ccb917..d2f2d969f1 100644
--- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
@@ -22,7 +22,7 @@ namespace O3DE::ProjectManager
QVector screenEnums =
{
ProjectManagerScreen::Projects,
- ProjectManagerScreen::EngineSettings,
+ ProjectManagerScreen::Engine,
ProjectManagerScreen::CreateProject,
ProjectManagerScreen::UpdateProject
};
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index 18901946f3..6f8ff9abce 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -912,4 +912,45 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(templates));
}
}
+
+ GemRepoInfo PythonBindings::GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath)
+ {
+ /* Placeholder Logic */
+ (void)path;
+ (void)pyEnginePath;
+
+ return GemRepoInfo();
+ }
+
+//#define MOCK_GEM_REPO_INFO true
+
+ AZ::Outcome, AZStd::string> PythonBindings::GetAllGemRepoInfos()
+ {
+ QVector gemRepos;
+
+#ifndef MOCK_GEM_REPO_INFO
+ auto result = ExecuteWithLockErrorHandling(
+ [&]
+ {
+ /* Placeholder Logic, o3de scripts need method added
+ *
+ for (auto path : m_manifest.attr("get_gem_repos")())
+ {
+ gemRepos.push_back(GemRepoInfoFromPath(path, pybind11::none()));
+ }
+ *
+ */
+ });
+ if (!result.IsSuccess())
+ {
+ return AZ::Failure(result.GetError().c_str());
+ }
+#else
+ gemRepos.push_back(GemRepoInfo("JohnCreates", "John Smith", "", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true));
+ gemRepos.push_back(GemRepoInfo("JanesGems", "Jane Doe", "", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false));
+#endif // MOCK_GEM_REPO_INFO
+
+ std::sort(gemRepos.begin(), gemRepos.end());
+ return AZ::Success(AZStd::move(gemRepos));
+ }
}
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h
index 8482ac56e7..3b766c3797 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.h
@@ -56,12 +56,16 @@ namespace O3DE::ProjectManager
// ProjectTemplate
AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) override;
+ // Gem Repos
+ AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override;
+
private:
AZ_DISABLE_COPY_MOVE(PythonBindings);
AZ::Outcome ExecuteWithLockErrorHandling(AZStd::function executionCallback);
bool ExecuteWithLock(AZStd::function executionCallback);
GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
+ GemRepoInfo GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath);
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
bool RegisterThisEngine();
diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
index ca14a54630..9fd3002f93 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -56,14 +57,14 @@ namespace O3DE::ProjectManager
/**
* Get info about a Gem
- * @param path the absolute path to the Gem
+ * @param projectPath the absolute path to the Gem
* @return an outcome with GemInfo on success
*/
virtual AZ::Outcome GetGemInfo(const QString& path, const QString& projectPath = {}) = 0;
/**
* Get all available gem infos. This concatenates gems registered by the engine and the project.
- * @param path The absolute path to the project.
+ * @param projectPath The absolute path to the project.
* @return A list of gem infos.
*/
virtual AZ::Outcome, AZStd::string> GetAllGemInfos(const QString& projectPath) = 0;
@@ -155,6 +156,14 @@ namespace O3DE::ProjectManager
* @return an outcome with ProjectTemplateInfos on success
*/
virtual AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) = 0;
+
+ // Gem Repos
+
+ /**
+ * Get all available gem repo infos. Gathers all repos registered with the engine.
+ * @return A list of gem repo infos.
+ */
+ virtual AZ::Outcome, AZStd::string> GetAllGemRepoInfos() = 0;
};
using PythonBindingsInterface = AZ::Interface;
diff --git a/Code/Tools/ProjectManager/Source/ScreenDefs.h b/Code/Tools/ProjectManager/Source/ScreenDefs.h
index 97ebe19751..2ced8c08c9 100644
--- a/Code/Tools/ProjectManager/Source/ScreenDefs.h
+++ b/Code/Tools/ProjectManager/Source/ScreenDefs.h
@@ -23,7 +23,9 @@ namespace O3DE::ProjectManager
Projects,
UpdateProject,
UpdateProjectSettings,
- EngineSettings
+ Engine,
+ EngineSettings,
+ GemRepos
};
static QHash s_ProjectManagerStringNames = {
@@ -34,7 +36,9 @@ namespace O3DE::ProjectManager
{ "Projects", ProjectManagerScreen::Projects},
{ "UpdateProject", ProjectManagerScreen::UpdateProject},
{ "UpdateProjectSettings", ProjectManagerScreen::UpdateProjectSettings},
- { "EngineSettings", ProjectManagerScreen::EngineSettings}
+ { "Engine", ProjectManagerScreen::Engine},
+ { "EngineSettings", ProjectManagerScreen::EngineSettings},
+ { "GemRepos", ProjectManagerScreen::GemRepos}
};
// need to define qHash for ProjectManagerScreen when using scoped enums
diff --git a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
index f3bddfdd27..44aa713e6a 100644
--- a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
+++ b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
@@ -13,7 +13,9 @@
#include
#include
#include
+#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -41,9 +43,15 @@ namespace O3DE::ProjectManager
case (ProjectManagerScreen::UpdateProjectSettings):
newScreen = new UpdateProjectSettingsScreen(parent);
break;
+ case (ProjectManagerScreen::Engine):
+ newScreen = new EngineScreenCtrl(parent);
+ break;
case (ProjectManagerScreen::EngineSettings):
newScreen = new EngineSettingsScreen(parent);
break;
+ case (ProjectManagerScreen::GemRepos):
+ newScreen = new GemRepoScreen(parent);
+ break;
case (ProjectManagerScreen::Empty):
default:
newScreen = new ScreenWidget(parent);
diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake
index 6d0f392e52..7a336972e0 100644
--- a/Code/Tools/ProjectManager/project_manager_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_files.cmake
@@ -56,6 +56,8 @@ set(FILES
Source/ProjectsScreen.cpp
Source/ProjectSettingsScreen.h
Source/ProjectSettingsScreen.cpp
+ Source/EngineScreenCtrl.h
+ Source/EngineScreenCtrl.cpp
Source/EngineSettingsScreen.h
Source/EngineSettingsScreen.cpp
Source/ProjectButtonWidget.h
@@ -98,4 +100,14 @@ set(FILES
Source/GemCatalog/GemRequirementListView.cpp
Source/GemCatalog/GemSortFilterProxyModel.h
Source/GemCatalog/GemSortFilterProxyModel.cpp
+ Source/GemRepo/GemRepoScreen.h
+ Source/GemRepo/GemRepoScreen.cpp
+ Source/GemRepo/GemRepoInfo.h
+ Source/GemRepo/GemRepoInfo.cpp
+ Source/GemRepo/GemRepoItemDelegate.h
+ Source/GemRepo/GemRepoItemDelegate.cpp
+ Source/GemRepo/GemRepoListView.h
+ Source/GemRepo/GemRepoListView.cpp
+ Source/GemRepo/GemRepoModel.h
+ Source/GemRepo/GemRepoModel.cpp
)
diff --git a/Gems/Atom/Feature/Common/Code/CMakeLists.txt b/Gems/Atom/Feature/Common/Code/CMakeLists.txt
index b8c414dcc6..9c4ffe5b5e 100644
--- a/Gems/Atom/Feature/Common/Code/CMakeLists.txt
+++ b/Gems/Atom/Feature/Common/Code/CMakeLists.txt
@@ -40,6 +40,8 @@ ly_add_target(
Gem::Atom_Feature_Common.Public
Gem::ImGui.imguilib
#3rdParty::lux_core # AZ_TRAIT_LUXCORE_SUPPORTED is disabled in every platform, Issue #3915 will remove
+ RUNTIME_DEPENDENCIES
+ Gem::ImGui.imguilib
)
ly_add_target(
diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp
index 214643505a..2057c596e5 100644
--- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp
@@ -565,7 +565,7 @@ namespace AZ
AuxGeomBufferData* AuxGeomDrawQueue::Commit()
{
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "AuxGeomDrawQueue: Commit");
+ AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: Commit");
// get a mutually exclusive lock and then switch to the next buffer, returning a pointer to the current buffer (before the switch)
// grab the lock
@@ -585,7 +585,7 @@ namespace AZ
void AuxGeomDrawQueue::ClearCurrentBufferData()
{
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "AuxGeomDrawQueue: ClearCurrentBufferData");
+ AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: ClearCurrentBufferData");
// no need for mutex here, this function is only called from a function holding a lock
AuxGeomBufferData& data = m_buffers[m_currentBufferIndex];
@@ -649,7 +649,7 @@ namespace AZ
AZ::u8 width,
int32_t viewProjOverrideIndex)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: DrawPrimitiveWithSharedVerticesCommon");
// grab a mutex lock for the rest of this function so that a commit cannot happen during it and
// other threads can't add geometry during it
@@ -720,8 +720,7 @@ namespace AZ
AZ::u8 width,
int32_t viewProjOverrideIndex)
{
- AZ_PROFILE_FUNCTION(AzRender);
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "AuxGeomDrawQueue: DrawPrimitiveWithSharedVerticesCommon");
+ AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: DrawPrimitiveWithSharedVerticesCommon");
AZ_Assert(indexCount >= verticesPerPrimitiveType && (indexCount % verticesPerPrimitiveType == 0),
"Index count must be at least %d and must be a multiple of %d",
diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp
index feeb1dedcc..ee6d3ba4a3 100644
--- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomFeatureProcessor.cpp
@@ -80,7 +80,7 @@ namespace AZ
void AuxGeomFeatureProcessor::Render(const FeatureProcessor::RenderPacket& fpPacket)
{
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "AuxGeomFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(AzRender, "AuxGeomFeatureProcessor: Render");
// Get the scene data and switch buffers so that other threads can continue to queue requests
AuxGeomBufferData* bufferData = static_cast(m_sceneDrawQueue.get())->Commit();
diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp
index f35809f148..9af6493413 100644
--- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp
@@ -70,7 +70,7 @@ namespace AZ
void DynamicPrimitiveProcessor::PrepareFrame()
{
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "DynamicPrimitiveProcessor: PrepareFrame");
+ AZ_PROFILE_SCOPE(AzRender, "DynamicPrimitiveProcessor: PrepareFrame");
m_drawPackets.clear();
m_processSrgs.clear();
@@ -88,7 +88,7 @@ namespace AZ
void DynamicPrimitiveProcessor::ProcessDynamicPrimitives(const AuxGeomBufferData* bufferData, const RPI::FeatureProcessor::RenderPacket& fpPacket)
{
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "DynamicPrimitiveProcessor: ProcessDynamicPrimitives");
+ AZ_PROFILE_SCOPE(AzRender, "DynamicPrimitiveProcessor: ProcessDynamicPrimitives");
RHI::DrawPacketBuilder drawPacketBuilder;
const DynamicPrimitiveData& srcPrimitives = bufferData->m_primitiveData;
diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp
index 0045311bef..8b5e439ca0 100644
--- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp
@@ -108,8 +108,8 @@ namespace AZ
}
void FixedShapeProcessor::PrepareFrame()
- {
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "FixedShapeProcessor: PrepareFrame");
+ {
+ AZ_PROFILE_SCOPE(AzRender, "FixedShapeProcessor: PrepareFrame");
m_processSrgs.clear();
m_drawPackets.clear();
@@ -127,8 +127,7 @@ namespace AZ
void FixedShapeProcessor::ProcessObjects(const AuxGeomBufferData* bufferData, const RPI::FeatureProcessor::RenderPacket& fpPacket)
{
- AZ_PROFILE_FUNCTION(AzRender);
- AZ_ATOM_PROFILE_FUNCTION("AuxGeom", "FixedShapeProcessor: ProcessObjects");
+ AZ_PROFILE_SCOPE(AzRender, "FixedShapeProcessor: ProcessObjects");
RHI::DrawPacketBuilder drawPacketBuilder;
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp
index 683295cf5b..849c930afd 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.cpp
@@ -102,7 +102,7 @@ namespace AZ
void CapsuleLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "CapsuleLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "CapsuleLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -114,7 +114,7 @@ namespace AZ
void CapsuleLightFeatureProcessor::Render(const CapsuleLightFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "CapsuleLightFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "CapsuleLightFeatureProcessor: Render");
for (const RPI::ViewPtr& view : packet.m_views)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
index c235f78595..702818dcd9 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
@@ -196,7 +196,7 @@ namespace AZ
void DirectionalLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket&)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "DirectionalLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "DirectionalLightFeatureProcessor: Simulate");
if (m_shadowingLightHandle.IsValid())
{
@@ -293,7 +293,7 @@ namespace AZ
void DirectionalLightFeatureProcessor::Render(const FeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "DirectionalLightFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "DirectionalLightFeatureProcessor: Render");
if (m_shadowingLightHandle.IsValid())
{
@@ -1232,7 +1232,7 @@ namespace AZ
void DirectionalLightFeatureProcessor::SetFilterParameterToPass(LightHandle handle, const RPI::View* cameraView)
{
- AZ_ATOM_PROFILE_FUNCTION("DirectionalLightFeatureProcessor", "DirectionalLightFeatureProcessor::SetFilterParameterToPass");
+ AZ_PROFILE_SCOPE(RPI, "DirectionalLightFeatureProcessor::SetFilterParameterToPass");
if (handle != m_shadowingLightHandle)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp
index dfbeea0ffe..ca2c038e46 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp
@@ -123,7 +123,7 @@ namespace AZ
void DiskLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "DiskLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "DiskLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -135,7 +135,7 @@ namespace AZ
void DiskLightFeatureProcessor::Render(const DiskLightFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "DiskLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "DiskLightFeatureProcessor: Simulate");
for (const RPI::ViewPtr& view : packet.m_views)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp
index af440e5040..bfb0b1252b 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp
@@ -119,7 +119,7 @@ namespace AZ
void PointLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PointLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "PointLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -131,7 +131,7 @@ namespace AZ
void PointLightFeatureProcessor::Render(const PointLightFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PointLightFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "PointLightFeatureProcessor: Render");
for (const RPI::ViewPtr& view : packet.m_views)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp
index 089adf4621..9dbf01ae26 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PolygonLightFeatureProcessor.cpp
@@ -132,7 +132,7 @@ namespace AZ::Render
void PolygonLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PolygonLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "PolygonLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -153,7 +153,7 @@ namespace AZ::Render
void PolygonLightFeatureProcessor::Render(const PolygonLightFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PolygonLightFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "PolygonLightFeatureProcessor: Render");
for (const RPI::ViewPtr& view : packet.m_views)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp
index e22174225d..aadc8c2020 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.cpp
@@ -107,7 +107,7 @@ namespace AZ
void QuadLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "QuadLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "QuadLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -119,7 +119,7 @@ namespace AZ
void QuadLightFeatureProcessor::Render(const QuadLightFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "QuadLightFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "QuadLightFeatureProcessor: Render");
for (const RPI::ViewPtr& view : packet.m_views)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp
index b8bbb03335..f49a5e94fc 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.cpp
@@ -102,7 +102,7 @@ namespace AZ
void SimplePointLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "SimplePointLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "SimplePointLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -114,7 +114,7 @@ namespace AZ
void SimplePointLightFeatureProcessor::Render(const SimplePointLightFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "SimplePointLightFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "SimplePointLightFeatureProcessor: Render");
for (const RPI::ViewPtr& view : packet.m_views)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp
index d4776faec6..277b5026d7 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.cpp
@@ -102,7 +102,7 @@ namespace AZ
void SimpleSpotLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "SimpleSpotLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "SimpleSpotLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -114,7 +114,7 @@ namespace AZ
void SimpleSpotLightFeatureProcessor::Render(const SimpleSpotLightFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "SimpleSpotLightFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "SimpleSpotLightFeatureProcessor: Render");
for (const RPI::ViewPtr& view : packet.m_views)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp
index 4954ffc01c..4ff718b5ad 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalFeatureProcessor.cpp
@@ -107,7 +107,7 @@ namespace AZ
void DecalFeatureProcessor::Simulate(const RPI::FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "DecalFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "DecalFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -131,7 +131,7 @@ namespace AZ
void DecalFeatureProcessor::Render(const RPI::FeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "DecalFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "DecalFeatureProcessor: Render");
AZStd::array_view> baseMaps = GetImagesFromDecalData<1>();
AZStd::array_view> opacityMaps = GetImagesFromDecalData<2>();
diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp
index 4ecfd7fc09..c0b8f3315a 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp
@@ -145,7 +145,7 @@ namespace AZ
void DecalTextureArrayFeatureProcessor::Simulate(const RPI::FeatureProcessor::SimulatePacket& packet)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: Simulate");
AZ_UNUSED(packet);
if (m_deviceBufferNeedsUpdate)
@@ -158,7 +158,7 @@ namespace AZ
void DecalTextureArrayFeatureProcessor::Render(const RPI::FeatureProcessor::RenderPacket& packet)
{
// Note that decals are rendered as part of the forward shading pipeline. We only need to bind the decal buffers/textures in here.
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: Render");
for (const RPI::ViewPtr& view : packet.m_views)
{
@@ -294,7 +294,7 @@ namespace AZ
void DecalTextureArrayFeatureProcessor::SetDecalMaterial(const DecalHandle handle, const AZ::Data::AssetId material)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: SetDecalMaterial");
if (handle.IsNull())
{
AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalMaterial().");
@@ -364,7 +364,7 @@ namespace AZ
void DecalTextureArrayFeatureProcessor::OnAssetReady(const Data::Asset asset)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: OnAssetReady");
const Data::AssetId& assetId = asset->GetId();
const RPI::MaterialAsset* materialAsset = asset.GetAs();
diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp
index 543851da0f..d79240d4f1 100644
--- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp
@@ -111,7 +111,7 @@ namespace AZ
void DiffuseProbeGridFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "DiffuseProbeGridFeatureProcessor: Simulate");
// update pipeline states
if (m_needUpdatePipelineStates)
diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp
index b6ca1191dd..1a68317532 100644
--- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp
@@ -577,8 +577,7 @@ namespace AZ
void ImGuiPass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
{
- AZ_PROFILE_FUNCTION(AzRender);
- AZ_ATOM_PROFILE_FUNCTION("Pass", "ImGuiPass: Execute");
+ AZ_PROFILE_SCOPE(AzRender, "ImGuiPass: BuildCommandListInternal");
context.GetCommandList()->SetViewport(m_viewportState);
@@ -607,8 +606,7 @@ namespace AZ
uint32_t ImGuiPass::UpdateImGuiResources()
{
- AZ_PROFILE_FUNCTION(AzRender);
- AZ_ATOM_PROFILE_FUNCTION("Pass", "ImGuiPass: UpdateImGuiResources");
+ AZ_PROFILE_SCOPE(AzRender, "ImGuiPass: UpdateImGuiResources");
auto imguiContextScope = ImguiContextScope(m_imguiContext);
diff --git a/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp
index 7c41379a14..9cdad34f17 100644
--- a/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/ImageBasedLights/ImageBasedLightFeatureProcessor.cpp
@@ -50,7 +50,7 @@ namespace AZ
void ImageBasedLightFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "ImageBasedLightFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "ImageBasedLightFeatureProcessor: Simulate");
AZ_UNUSED(packet);
m_sceneSrg->SetImage(m_specularEnvMapIndex, m_specular);
diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
index 8ab324cdf7..52019f8d2f 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
@@ -75,8 +75,7 @@ namespace AZ
void MeshFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_PROFILE_FUNCTION(AzRender);
- AZ_ATOM_PROFILE_FUNCTION("RPI", "MeshFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: Simulate");
AZ_UNUSED(packet);
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
@@ -149,7 +148,7 @@ namespace AZ
const MeshHandleDescriptor& descriptor,
const MaterialAssignmentMap& materials)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: AcquireMesh");
// don't need to check the concurrency during emplace() because the StableDynamicArray won't move the other elements during insertion
MeshHandle meshDataHandle = m_meshData.emplace();
@@ -984,7 +983,7 @@ namespace AZ
void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance:: UpdateDrawPackets");
for (auto& drawPacketList : m_drawPacketListsByLod)
{
for (auto& drawPacket : drawPacketList)
@@ -999,7 +998,7 @@ namespace AZ
void MeshDataInstance::BuildCullable()
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: BuildCullable");
AZ_Assert(m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@@ -1076,7 +1075,7 @@ namespace AZ
void MeshDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
{
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: UpdateCullBounds");
AZ_Assert(m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp
index 35294d7403..d5b3ebd63b 100644
--- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp
@@ -49,7 +49,7 @@ namespace AZ
void PostProcessFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PostProcessFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "PostProcessFeatureProcessor: Simulate");
AZ_UNUSED(packet);
UpdateTime();
diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp
index 56d413e84f..a795d88212 100644
--- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp
@@ -161,7 +161,7 @@ namespace AZ
void SMAAFeatureProcessor::Render([[maybe_unused]] const SMAAFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "SMAAFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "SMAAFeatureProcessor: Render");
UpdateConvertToPerceptualPass();
UpdateEdgeDetectionPass();
diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp
index 341d1a0274..91c72013dd 100644
--- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp
@@ -154,8 +154,7 @@ namespace AZ
void ReflectionProbeFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
{
- AZ_PROFILE_FUNCTION(AzRender);
- AZ_ATOM_PROFILE_FUNCTION("ReflectionProbe", "ReflectionProbeFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(AzRender, "ReflectionProbeFeatureProcessor: Simulate");
// update pipeline states
if (m_needUpdatePipelineStates)
@@ -194,7 +193,6 @@ namespace AZ
if (m_probeSortRequired)
{
AZ_PROFILE_SCOPE(AzRender, "Sort reflection probes");
- AZ_ATOM_PROFILE_FUNCTION("ReflectionProbe", "ReflectionProbeFeatureProcessor: Sort reflection probes");
// sort the probes by descending inner volume size, so the smallest volumes are rendered last
auto sortFn = [](AZStd::shared_ptr const& probe1, AZStd::shared_ptr const& probe2) -> bool
diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp
index 68c31bd859..8fb971f8f5 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp
@@ -486,7 +486,7 @@ namespace AZ::Render
void ProjectedShadowFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& /*packet*/)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "ProjectedShadowFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "ProjectedShadowFeatureProcessor: Simulate");
if (m_shadowmapPassNeedsUpdate)
{
@@ -581,7 +581,7 @@ namespace AZ::Render
void ProjectedShadowFeatureProcessor::Render(const ProjectedShadowFeatureProcessor::RenderPacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "ProjectedShadowFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(RPI, "ProjectedShadowFeatureProcessor: Render");
if (!m_projectedShadowmapsPasses.empty())
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
index 0aa72bf2ca..500eadf110 100644
--- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
@@ -69,8 +69,7 @@ namespace AZ
void SkinnedMeshFeatureProcessor::Render(const FeatureProcessor::RenderPacket& packet)
{
- AZ_PROFILE_FUNCTION(AzRender);
- AZ_ATOM_PROFILE_FUNCTION("SkinnedMesh", "SkinnedMeshFeatureProcessor: Render");
+ AZ_PROFILE_SCOPE(AzRender, "SkinnedMeshFeatureProcessor: Render");
#if 0 //[GFX_TODO][ATOM-13564] Temporarily disable skinning culling until we figure out how to hook up visibility & lod selection with skinning:
//Setup the culling workgroup (it will be re-used for each view)
diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp
index b84d4347a7..4146a669fe 100644
--- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp
@@ -534,7 +534,7 @@ namespace AZ
// lod0 Positions[^ ^] lod0Normals[^ ^] lod1Positions[^ ^] lod1Normals[^ ^]
// lod0 subMesh0+1 Positions[^ ^^ ^] lod0 subMesh0+1 Normals[^ ^^ ^] lod1 sm0+1 pos[^ ^^ ^] lod1 sm0+1 norm[^ ^^ ^]
- AZ_PROFILE_FUNCTION(AzRender);
+ AZ_PROFILE_SCOPE(AzRender, "SkinnedMeshInputBuffers: CreateSkinnedMeshInstance");
AZStd::intrusive_ptr instance = aznew SkinnedMeshInstance;
// Each model gets a unique, random ID, so if the same source model is used for multiple instances, multiple target models will be created.
diff --git a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp
index d0150fc0c2..d4fa3f52be 100644
--- a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp
@@ -105,7 +105,7 @@ namespace AZ
void SkyBoxFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "SkyBoxFeatureProcessor: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "SkyBoxFeatureProcessor: Simulate");
AZ_UNUSED(packet);
m_sceneSrg->SetConstant(m_skyboxEnableIndex, m_enable);
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h
index 3fedc99566..70c5771b57 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h
@@ -9,6 +9,7 @@
#pragma once
#include
+#include
#include
#include
#include
@@ -21,15 +22,15 @@ namespace AZ
//! Structure that is used to cache a timed region into the thread's local storage.
struct CachedTimeRegion
{
- //! Structure that the profiling macro utilizes to create statically initialized instance to create string
- //! literals in static memory
+ //! Structure used internally for caching assumed global string pointers (ideally literals) to the marker group/region
+ //! NOTE: When used in a separate shared library, the library mustn't be unloaded before the CpuProfiler is shutdown.
struct GroupRegionName
{
GroupRegionName() = delete;
GroupRegionName(const char* const group, const char* const region);
-
- const char* const m_groupName = nullptr;
- const char* const m_regionName = nullptr;
+
+ const char* m_groupName = nullptr;
+ const char* m_regionName = nullptr;
struct Hash
{
@@ -39,31 +40,16 @@ namespace AZ
};
CachedTimeRegion() = default;
- CachedTimeRegion(const GroupRegionName* groupRegionName);
- CachedTimeRegion(const GroupRegionName* groupRegionName, uint16_t stackDepth, uint64_t startTick, uint64_t endTick);
+ CachedTimeRegion(const GroupRegionName& groupRegionName);
+ CachedTimeRegion(const GroupRegionName& groupRegionName, uint16_t stackDepth, uint64_t startTick, uint64_t endTick);
- //! Pointer to the GroupRegionName static instance.
- //! NOTE: When used in a separate shared library, the library mustn't be unloaded before
- //! the CpuProfiler is shutdown.
- const GroupRegionName* m_groupRegionName = nullptr;
+ GroupRegionName m_groupRegionName{nullptr, nullptr};
uint16_t m_stackDepth = 0u;
AZStd::sys_time_t m_startTick = 0;
AZStd::sys_time_t m_endTick = 0;
};
- //! Helper class used as a RAII-style mechanism for the macros to begin and end a region.
- class TimeRegion : public CachedTimeRegion
- {
- public:
- TimeRegion() = delete;
- TimeRegion(const GroupRegionName* groupRegionName);
- ~TimeRegion();
-
- //! End region
- void EndRegion();
- };
-
//! Interface class of the CpuProfiler
class CpuProfiler
{
@@ -80,12 +66,6 @@ namespace AZ
static CpuProfiler* Get();
- //! Add a new time region
- virtual void BeginTimeRegion(TimeRegion& timeRegion) = 0;
-
- //! Ends a time region
- virtual void EndTimeRegion() = 0;
-
//! Get the last frame's TimeRegionMap
virtual const TimeRegionMap& GetTimeRegionMap() const = 0;
@@ -101,38 +81,7 @@ namespace AZ
virtual void SetProfilerEnabled(bool enabled) = 0;
virtual bool IsProfilerEnabled() const = 0 ;
-
- //! Used by AZ_ATOM_PROFILE_DYNAMIC to create GroupRegionNames with known lifetimes.
- virtual const CachedTimeRegion::GroupRegionName& InsertDynamicName(const char* groupName, const AZStd::string& regionName) = 0;
};
} // namespace RPI
} // namespace AZ
-
-//! Utility functions for timing a section of code and writing the timing (in cycles) to a new, named time region inside the
-//! provided statistics data.
-
-//! Supply a group and region to the time region
-#define AZ_ATOM_PROFILE_TIME_GROUP_REGION(groupName, regionName) \
- static const AZ::RHI::CachedTimeRegion::GroupRegionName AZ_JOIN(groupRegionName, __LINE__)(groupName, regionName); \
- AZ::RHI::TimeRegion AZ_JOIN(timeRegion, __LINE__)(&AZ_JOIN(groupRegionName, __LINE__));
-
-//! Supply a region to the time region; "Default" will be used for the group
-#define AZ_ATOM_PROFILE_TIME_REGION(regionName) \
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("Default", regionName)
-
-//! Used to create a time region; "Default" will be used for the group, and __FUNCTION__ macro for the region
-#define AZ_ATOM_PROFILE_TIME_FUNCTION() \
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("Default", AZ_FUNCTION_SIGNATURE)
-
-//! Macro that combines the AZ_TRACE_METHOD with time profiling macro
-#define AZ_ATOM_PROFILE_FUNCTION(groupName, regionName) \
- AZ_TRACE_METHOD(); \
- AZ_ATOM_PROFILE_TIME_GROUP_REGION(groupName, regionName) \
-
-//! Macro that allows for region names to be submitted at runtime. Use sparingly - this acquires a lock and allocates new objects within a map.
-#define AZ_ATOM_PROFILE_DYNAMIC(groupName, regionName) \
- static_assert(AZStd::is_convertible_v, "Runtime group names are not allowed, use a static string literal instead."); \
- const AZ::RHI::CachedTimeRegion::GroupRegionName& AZ_JOIN(groupRegionName, __LINE__) = \
- AZ::RHI::CpuProfiler::Get()->InsertDynamicName(groupName, regionName); \
- AZ::RHI::TimeRegion AZ_JOIN(timeRegion, __LINE__)(&AZ_JOIN(groupRegionName, __LINE__));
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h
index 92b56880b7..29886625ea 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h
@@ -43,13 +43,13 @@ namespace AZ
static constexpr uint32_t TimeRegionStackSize = 2048u;
// Adds a region to the stack, gets called each time a region begins
- void RegionStackPushBack(TimeRegion& timeRegion);
+ void RegionStackPushBack(CachedTimeRegion& timeRegion);
// Pops a region from the stack, gets called each time a region ends
void RegionStackPopBack();
// Add a new cached time region. If the stack is empty, flush all entries to the cached map
- void AddCachedRegion(CachedTimeRegion&& timeRegionCached);
+ void AddCachedRegion(const CachedTimeRegion& timeRegionCached);
// Tries to flush the map to the passed parameter, only if the thread's mutex is unlocked
void TryFlushCachedMap(CpuProfiler::ThreadTimeRegionMap& cachedRegionMap);
@@ -63,7 +63,7 @@ namespace AZ
// Use fixed vectors to avoid re-allocating new elements
// Keeps track of the regions that added and removed using the macro
- AZStd::fixed_vector m_timeRegionStack;
+ AZStd::fixed_vector m_timeRegionStack;
// Keeps track of regions that completed (i.e regions that was pushed and popped from the stack)
// Intermediate storage point for the CachedTimeRegions, when the stack is empty, all entries will be
@@ -85,7 +85,8 @@ namespace AZ
//! forwards the request to profile a region to the appropriate thread. The user is able to request all
//! cached regions, which are stored on a per thread frequency.
class CpuProfilerImpl final
- : public CpuProfiler
+ : public AZ::Debug::Profiler
+ , public CpuProfiler
, public SystemTickBus::Handler
{
friend class CpuTimingLocalStorage;
@@ -107,16 +108,17 @@ namespace AZ
// m_timeRegionMap so that the next frame has up-to-date profiling data.
void OnSystemTick() final override;
+ //! AZ::Debug::Profiler overrides...
+ void BeginRegion(const AZ::Debug::Budget* budget, const char* eventName) final override;
+ void EndRegion(const AZ::Debug::Budget* budget) final override;
+
//! CpuProfiler overrides...
- void BeginTimeRegion(TimeRegion& timeRegion) final override;
- void EndTimeRegion() final override;
const TimeRegionMap& GetTimeRegionMap() const final override;
bool BeginContinuousCapture() final override;
bool EndContinuousCapture(AZStd::ring_buffer& flushTarget) final override;
bool IsContinuousCaptureInProgress() const final override;
void SetProfilerEnabled(bool enabled) final override;
bool IsProfilerEnabled() const final override;
- const CachedTimeRegion::GroupRegionName& InsertDynamicName(const char* groupName, const AZStd::string& regionName) final override;
private:
static constexpr AZStd::size_t MaxFramesToSave = 2 * 60 * 120; // 2 minutes of 120fps
@@ -133,15 +135,6 @@ namespace AZ
AZStd::vector, AZ::OSStdAllocator> m_registeredThreads;
AZStd::mutex m_threadRegisterMutex;
- // Pool for GroupRegionNames that are generated at runtime through AZ_ATOM_PROFILE_DYNAMIC. Each unique
- // combination of group name and region name submitted will be stored in this pool to emulate static lifetime.
- AZStd::unordered_set m_dynamicGroupRegionNamePool;
-
- // String pool for storing region names submitted at runtime. Each call to AZ_ATOM_PROFILE_DYNAMIC will either construct
- // a string in this pool or use an already-existing entry.
- AZStd::unordered_set m_regionNameStringPool;
- AZStd::mutex m_dynamicNameMutex;
-
// Thread local storage, gets lazily allocated when a thread is created
static thread_local CpuTimingLocalStorage* ms_threadLocalStorage;
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h
index a10afd880f..bdeb252174 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/MemorySubAllocator.h
@@ -157,7 +157,7 @@ namespace AZ
template
void MemorySubAllocator::GarbageCollect()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "MemorySubAllocator: GarbageCollect");
+ AZ_PROFILE_SCOPE(RHI, "MemorySubAllocator: GarbageCollect");
for (PageContext& pageContext : m_pageContexts)
{
pageContext.m_allocator.GarbageCollect();
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h
index cd8a85a385..988416326e 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h
@@ -173,7 +173,7 @@ namespace AZ
template
void ObjectCollector::Collect(bool forceFlush)
{
- AZ_ATOM_PROFILE_FUNCTION("DX12", "ObjectCollector: Collect");
+ AZ_PROFILE_SCOPE(RHI, "ObjectCollector: Collect");
m_mutex.lock();
if (m_pendingObjects.size())
{
diff --git a/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp
index 52021fa736..a076bf3e58 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/AsyncWorkQueue.cpp
@@ -128,7 +128,7 @@ namespace AZ
return;
}
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncWorkQueue: WaitToFinish");
AZStd::unique_lock lock(m_waitWorkItemMutex);
m_waitWorkItemCondition.wait(lock, [&]() {return HasFinishedWork(workHandle); });
diff --git a/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp b/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp
index 9849db254e..5d06d02668 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/BufferPool.cpp
@@ -163,7 +163,7 @@ namespace AZ
return ResultCode::InvalidArgument;
}
- AZ_ATOM_PROFILE_FUNCTION("RHI", "BufferPool::OrphanBuffer");
+ AZ_PROFILE_SCOPE(RHI, "BufferPool::OrphanBuffer");
return OrphanBufferInternal(buffer);
}
diff --git a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp
index 15621c7f2b..0983d4db22 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp
@@ -22,7 +22,7 @@ namespace AZ
ResultCode CommandQueue::Init(Device& device, const CommandQueueDescriptor& descriptor)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandQueue: Init");
#if defined (AZ_RHI_ENABLE_VALIDATION)
if (IsInitialized())
@@ -83,7 +83,7 @@ namespace AZ
void CommandQueue::FlushCommands()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "CommandQueue: FlushCommands");
+ AZ_PROFILE_SCOPE(RHI, "CommandQueue: FlushCommands");
while (!m_isWorkQueueEmpty && !m_isQuitting)
{
AZStd::this_thread::yield();
diff --git a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp
index e16b89b5cd..1bc17adb22 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp
@@ -27,38 +27,14 @@ namespace AZ
return Interface::Get();
}
- // --- TimeRegion ---
-
- TimeRegion::TimeRegion(const GroupRegionName* groupRegionName) :
- CachedTimeRegion(groupRegionName)
- {
- if (CpuProfiler::Get())
- {
- CpuProfiler::Get()->BeginTimeRegion(*this);
- }
- }
-
- TimeRegion::~TimeRegion()
- {
- EndRegion();
- }
-
- void TimeRegion::EndRegion()
- {
- if (CpuProfiler::Get())
- {
- CpuProfiler::Get()->EndTimeRegion();
- }
- }
-
// --- CachedTimeRegion ---
- CachedTimeRegion::CachedTimeRegion(const GroupRegionName* groupRegionName)
+ CachedTimeRegion::CachedTimeRegion(const GroupRegionName& groupRegionName)
{
m_groupRegionName = groupRegionName;
}
- CachedTimeRegion::CachedTimeRegion(const GroupRegionName* groupRegionName, uint16_t stackDepth, uint64_t startTick, uint64_t endTick)
+ CachedTimeRegion::CachedTimeRegion(const GroupRegionName& groupRegionName, uint16_t stackDepth, uint64_t startTick, uint64_t endTick)
{
m_groupRegionName = groupRegionName;
m_stackDepth = stackDepth;
@@ -92,6 +68,7 @@ namespace AZ
void CpuProfilerImpl::Init()
{
+ Interface::Register(this);
Interface::Register(this);
m_initialized = true;
SystemTickBus::Handler::BusConnect();
@@ -106,6 +83,7 @@ namespace AZ
}
// When this call is made, no more thread profiling calls can be performed anymore
Interface::Unregister(this);
+ Interface::Unregister(this);
// Wait for the remaining threads that might still be processing its profiling calls
AZStd::unique_lock shutdownLock(m_shutdownMutex);
@@ -121,7 +99,7 @@ namespace AZ
SystemTickBus::Handler::BusDisconnect();
}
- void CpuProfilerImpl::BeginTimeRegion(TimeRegion& timeRegion)
+ void CpuProfilerImpl::BeginRegion(const AZ::Debug::Budget* budget, const char* eventName)
{
// Try to lock here, the shutdownMutex will only be contested when the CpuProfiler is shutting down.
if (m_shutdownMutex.try_lock_shared())
@@ -132,6 +110,7 @@ namespace AZ
RegisterThreadStorage();
// Push it to the stack
+ CachedTimeRegion timeRegion({budget->Name(), eventName});
ms_threadLocalStorage->RegionStackPushBack(timeRegion);
}
@@ -139,11 +118,12 @@ namespace AZ
}
}
- void CpuProfilerImpl::EndTimeRegion()
+ void CpuProfilerImpl::EndRegion([[maybe_unused]] const AZ::Debug::Budget* budget)
{
// Try to lock here, the shutdownMutex will only be contested when the CpuProfiler is shutting down.
if (m_shutdownMutex.try_lock_shared())
{
+ // guard against enabling mid-marker
if (m_enabled && ms_threadLocalStorage != nullptr)
{
ms_threadLocalStorage->RegionStackPopBack();
@@ -232,19 +212,6 @@ namespace AZ
return m_enabled;
}
- const CachedTimeRegion::GroupRegionName& CpuProfilerImpl::InsertDynamicName(const char* groupName, const AZStd::string& regionName)
- {
- AZStd::scoped_lock lock(m_dynamicNameMutex);
- AZ_Warning("CpuProfiler", m_regionNameStringPool.size() < MaxRegionStringPoolSize,
- "Stored dynamic region names are accumulating. Consider removing a AZ_ATOM_PROFILE_DYNAMIC invocation.");
- auto [regionNameItr, wasRegionInserted] = m_regionNameStringPool.insert(regionName);
-
- CachedTimeRegion::GroupRegionName newGroupRegionName(groupName, regionNameItr->c_str());
- auto [groupRegionNameItr, wasGroupRegionInserted] = m_dynamicGroupRegionNamePool.insert(newGroupRegionName);
-
- return *groupRegionNameItr;
- }
-
void CpuProfilerImpl::OnSystemTick()
{
if (!m_enabled)
@@ -307,7 +274,7 @@ namespace AZ
m_deleteFlag = true;
}
- void CpuTimingLocalStorage::RegionStackPushBack(TimeRegion& timeRegion)
+ void CpuTimingLocalStorage::RegionStackPushBack(CachedTimeRegion& timeRegion)
{
// If it was (re)enabled, clear the lists first
if (m_clearContainers)
@@ -323,13 +290,13 @@ namespace AZ
timeRegion.m_stackDepth = static_cast(m_stackLevel);
AZ_Assert(m_timeRegionStack.size() < TimeRegionStackSize, "Adding too many time regions to the stack. Increase the size of TimeRegionStackSize.");
- m_timeRegionStack.push_back(&timeRegion);
+ m_timeRegionStack.push_back(timeRegion);
// Increment the stack
m_stackLevel++;
// Set the starting time at the end, to avoid recording the minor overhead
- timeRegion.m_startTick = AZStd::GetTimeNowTicks();
+ m_timeRegionStack.back().m_startTick = AZStd::GetTimeNowTicks();
}
void CpuTimingLocalStorage::RegionStackPopBack()
@@ -344,23 +311,23 @@ namespace AZ
const AZStd::sys_time_t endRegionTime = AZStd::GetTimeNowTicks();
AZ_Assert(!m_timeRegionStack.empty(), "Trying to pop an element in the stack, but it's empty.");
- TimeRegion* back = m_timeRegionStack.back();
+ CachedTimeRegion back = m_timeRegionStack.back();
m_timeRegionStack.pop_back();
// Set the ending time
- back->m_endTick = endRegionTime;
+ back.m_endTick = endRegionTime;
// Decrement the stack
m_stackLevel--;
// Add an entry to the cached region
- AddCachedRegion(CachedTimeRegion(back->m_groupRegionName, back->m_stackDepth, back->m_startTick, back->m_endTick));
+ AddCachedRegion(back);
}
// Gets called when region ends and all data is set
- void CpuTimingLocalStorage::AddCachedRegion(CachedTimeRegion&& timeRegionCached)
+ void CpuTimingLocalStorage::AddCachedRegion(const CachedTimeRegion& timeRegionCached)
{
- if (m_hitSizeLimitMap[timeRegionCached.m_groupRegionName->m_regionName])
+ if (m_hitSizeLimitMap[timeRegionCached.m_groupRegionName.m_regionName])
{
return;
}
@@ -379,12 +346,12 @@ namespace AZ
// Add the cached regions to the map
for (auto& cachedTimeRegion : m_cachedTimeRegions)
{
- const AZStd::string regionName = cachedTimeRegion.m_groupRegionName->m_regionName;
+ const AZStd::string regionName = cachedTimeRegion.m_groupRegionName.m_regionName;
AZStd::vector& regionVec = m_cachedTimeRegionMap[regionName];
regionVec.push_back(cachedTimeRegion);
if (regionVec.size() >= TimeRegionStackSize)
{
- m_hitSizeLimitMap[cachedTimeRegion.m_groupRegionName->m_regionName] = true;
+ m_hitSizeLimitMap.insert_or_assign(AZStd::move(regionName), true);
}
}
@@ -448,8 +415,8 @@ namespace AZ
CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::CpuProfilingStatisticsSerializerEntry(
const RHI::CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId)
{
- m_groupName = cachedTimeRegion.m_groupRegionName->m_groupName;
- m_regionName = cachedTimeRegion.m_groupRegionName->m_regionName;
+ m_groupName = cachedTimeRegion.m_groupRegionName.m_groupName;
+ m_regionName = cachedTimeRegion.m_groupRegionName.m_regionName;
m_stackDepth = cachedTimeRegion.m_stackDepth;
m_startTick = cachedTimeRegion.m_startTick;
m_endTick = cachedTimeRegion.m_endTick;
diff --git a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp
index 3af09717df..9453ff79ee 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp
@@ -128,7 +128,7 @@ namespace AZ
{
if (ValidateIsInitialized() && ValidateIsInFrame())
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "Device: EndFrame");
+ AZ_PROFILE_SCOPE(RHI, "Device: EndFrame");
EndFrameInternal();
m_isInFrame = false;
return ResultCode::Success;
@@ -150,7 +150,7 @@ namespace AZ
{
if (ValidateIsInitialized() && ValidateIsNotInFrame())
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "Device: CompileMemoryStatistics");
+ AZ_PROFILE_SCOPE(RHI, "Device: CompileMemoryStatistics");
MemoryStatisticsBuilder builder;
builder.Begin(memoryStatistics, reportFlags);
CompileMemoryStatisticsInternal(builder);
diff --git a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp
index b35260caca..ca0493a52c 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/Fence.cpp
@@ -81,7 +81,7 @@ namespace AZ
return ResultCode::InvalidOperation;
}
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "Fence: WaitOnCpu");
WaitOnCpuInternal();
return ResultCode::Success;
}
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp
index ff6ecb4df5..b85fa88f34 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp
@@ -73,7 +73,7 @@ namespace AZ
void FrameGraph::Clear()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraph: Clear");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraph: Clear");
for (Scope* scope : m_scopes)
{
scope->Deactivate();
@@ -126,7 +126,7 @@ namespace AZ
ResultCode FrameGraph::End()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraph: End");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraph: End");
ResultCode resultCode = ValidateEnd();
if (resultCode != ResultCode::Success)
{
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp
index c4204a4a90..5c5691d975 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphCompiler.cpp
@@ -121,7 +121,7 @@ namespace AZ
*/
MessageOutcome FrameGraphCompiler::Compile(const FrameGraphCompileRequest& request)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: Compile");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: Compile");
MessageOutcome outcome = ValidateCompileRequest(request);
if (!outcome)
@@ -146,7 +146,7 @@ namespace AZ
/// [Phase 4] Compile platform-specific scope data after all attachments and views have been compiled.
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: Scope Compile");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: Scope Compile");
for (Scope* scope : frameGraph.GetScopes())
{
@@ -162,7 +162,7 @@ namespace AZ
FrameGraph& frameGraph,
FrameSchedulerCompileFlags compileFlags)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileQueueCentricScopeGraph");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileQueueCentricScopeGraph");
const bool disableAsyncQueues = CheckBitsAll(compileFlags, FrameSchedulerCompileFlags::DisableAsyncQueues);
if (disableAsyncQueues)
@@ -480,7 +480,7 @@ namespace AZ
return;
}
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileTransientAttachments");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileTransientAttachments");
ExtendTransientAttachmentAsyncQueueLifetimes(frameGraph, compileFlags);
@@ -769,7 +769,7 @@ namespace AZ
void FrameGraphCompiler::CompileResourceViews(const FrameGraphAttachmentDatabase& attachmentDatabase)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileResourceViews");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileResourceViews");
for (ImageFrameAttachment* imageAttachment : attachmentDatabase.GetImageAttachments())
{
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp
index 342e537993..429081cd2c 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp
@@ -71,14 +71,13 @@ namespace AZ
void FrameGraphExecuter::Begin(const FrameGraph& frameGraph)
{
- AZ_TRACE_METHOD();
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphExecuter: Begin");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphExecuter: Begin");
BeginInternal(frameGraph);
}
void FrameGraphExecuter::End()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphExecuter: End");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphExecuter: End");
AZ_Assert(m_pendingGroups.empty(), "Pending contexts in queue.");
m_groups.clear();
EndInternal();
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp
index fe69f56856..90218709fa 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp
@@ -137,7 +137,7 @@ namespace AZ
ResultCode FrameScheduler::ImportScopeProducer(ScopeProducer& scopeProducer)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: ImportScopeProducer");
if (!ValidateIsProcessing())
{
@@ -171,14 +171,14 @@ namespace AZ
MessageOutcome FrameScheduler::Compile(const FrameSchedulerCompileRequest& compileRequest)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: Compile");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: Compile");
PrepareProducers();
m_compileRequest = compileRequest;
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "FrameScheduler: Compile: OnFrameCompile");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: Compile: OnFrameCompile");
FrameEventBus::Broadcast(&FrameEventBus::Events::OnFrameCompile);
}
@@ -193,7 +193,7 @@ namespace AZ
if (outcome.IsSuccess())
{
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "FrameScheduler: Compile: OnFrameCompileEnd");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: Compile: OnFrameCompileEnd");
FrameEventBus::Broadcast(&FrameEventBus::Events::OnFrameCompileEnd, *m_frameGraph);
}
@@ -216,8 +216,7 @@ namespace AZ
void FrameScheduler::PrepareProducers()
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: PrepareProducers");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: PrepareProducers");
for (ScopeProducer* scopeProducer : m_scopeProducers)
{
@@ -237,8 +236,7 @@ namespace AZ
void FrameScheduler::CompileProducers()
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: CompileProducers");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: CompileProducers");
for (ScopeProducer* scopeProducer : m_scopeProducers)
{
@@ -249,8 +247,7 @@ namespace AZ
void FrameScheduler::CompileShaderResourceGroups()
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: CompileShaderResourceGroups");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: CompileShaderResourceGroups");
// Execute all queued resource invalidations, which will mark SRG's for compilation.
{
@@ -286,7 +283,7 @@ namespace AZ
const auto compileGroupsForIntervalLambda = [srgPool, interval]()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler : compileGroupsForIntervalLambda");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler : compileGroupsForIntervalLambda");
srgPool->CompileGroupsForInterval(interval);
};
@@ -322,8 +319,7 @@ namespace AZ
void FrameScheduler::BuildRayTracingShaderTables()
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: BuildRayTracingShaderTables");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: BuildRayTracingShaderTables");
for (auto rayTracingShaderTable : m_rayTracingShaderTablesToBuild)
{
@@ -341,8 +337,7 @@ namespace AZ
ResultCode FrameScheduler::BeginFrame()
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: BeginFrame");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: BeginFrame");
if (!ValidateIsInitialized())
{
@@ -376,8 +371,7 @@ namespace AZ
ResultCode FrameScheduler::EndFrame()
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: EndFrame");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: EndFrame");
if (Validation::IsEnabled())
{
@@ -404,7 +398,7 @@ namespace AZ
m_scopeProducerLookup.clear();
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "FrameScheduler: EndFrame: OnFrameEnd");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: EndFrame: OnFrameEnd");
FrameEventBus::Event(m_device, &FrameEventBus::Events::OnFrameEnd);
}
@@ -431,8 +425,7 @@ namespace AZ
void FrameScheduler::ExecuteGroupInternal(AZ::Job* parentJob, uint32_t groupIndex)
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: ExecuteGroupInternal");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: ExecuteGroupInternal");
FrameGraphExecuteGroup* executeGroup = m_frameGraphExecuter->BeginGroup(groupIndex);
const uint32_t contextCount = executeGroup->GetContextCount();
@@ -474,8 +467,7 @@ namespace AZ
void FrameScheduler::Execute(JobPolicy overrideJobPolicy)
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameScheduler: Execute");
+ AZ_PROFILE_SCOPE(RHI, "FrameScheduler: Execute");
const uint32_t groupCount = m_frameGraphExecuter->GetGroupCount();
const JobPolicy platformJobPolicy = m_frameGraphExecuter->GetJobPolicy();
diff --git a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp
index 6e98456933..868580f0c7 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp
@@ -212,7 +212,7 @@ namespace AZ
void PipelineStateCache::Compact()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "PipelineStateCache: Compact");
+ AZ_PROFILE_SCOPE(RHI, "PipelineStateCache: Compact");
AZStd::unique_lock lock(m_mutex);
// Merge the pending cache into the read-only cache.
diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp
index a381209d2b..69f7002435 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp
@@ -187,8 +187,7 @@ namespace AZ
void RHISystem::FrameUpdate(FrameGraphCallback frameGraphCallback)
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("RHI", "RHISystem: FrameUpdate");
+ AZ_PROFILE_SCOPE(RHI, "RHISystem: FrameUpdate");
{
AZ_PROFILE_SCOPE(RHI, "main per-frame work");
@@ -201,7 +200,7 @@ namespace AZ
* own RHI scopes to the frame scheduler. This happens prior to the RPI pass graph registration.
*/
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "RHISystem: FrameUpdate: OnFramePrepare");
+ AZ_PROFILE_SCOPE(RHI, "RHISystem: FrameUpdate: OnFramePrepare");
RHISystemNotificationBus::Broadcast(&RHISystemNotificationBus::Events::OnFramePrepare, m_frameScheduler);
}
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp
index 29b210e17e..cb9dac3864 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp
@@ -196,7 +196,7 @@ namespace AZ
AsyncUploadQueue::FramePacket* AsyncUploadQueue::BeginFramePacket()
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: BeginFramePacket");
AZ_Assert(!m_recordingFrame, "The previous frame packet isn't ended");
FramePacket* framePacket = &m_framePackets[m_frameIndex];
@@ -212,7 +212,7 @@ namespace AZ
void AsyncUploadQueue::EndFramePacket(ID3D12CommandQueue* commandQueue)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: EndFramePacket");
AZ_Assert(m_recordingFrame, "The frame packet wasn't started. You need to call StartFramePacket first.");
AssertSuccess(m_commandList->Close());
@@ -229,7 +229,7 @@ namespace AZ
// [GFX TODO][ATOM-4205] Stage/Upload 3D streaming images more efficiently.
uint64_t AsyncUploadQueue::QueueUpload(const RHI::StreamingImageExpandRequest& request, uint32_t residentMip)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: QueueUpload");
uint64_t fenceValue = m_uploadFence.Increment();
@@ -475,7 +475,7 @@ namespace AZ
void AsyncUploadQueue::WaitForUpload(uint64_t fenceValue)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: WaitForUpload");
if (!IsUploadFinished(fenceValue))
{
@@ -489,7 +489,7 @@ namespace AZ
void AsyncUploadQueue::ProcessCallbacks(uint64_t fenceValue)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: ProcessCallbacks");
AZStd::lock_guard lock(m_callbackMutex);
while (m_callbacks.size() > 0 && m_callbacks.front().second <= fenceValue)
{
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp
index c5c71a9f43..efa9518ee1 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp
@@ -33,7 +33,7 @@ namespace AZ
void CommandListBase::Reset(ID3D12CommandAllocator* commandAllocator)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandListBase: Reset");
AZ_Assert(m_queuedBarriers.empty(), "Unflushed barriers in command list.");
m_commandList->Reset(commandAllocator, nullptr);
@@ -95,7 +95,7 @@ namespace AZ
{
if (m_queuedBarriers.size())
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandListBase: FlushBarriers");
m_commandList->ResourceBarrier((UINT)m_queuedBarriers.size(), m_queuedBarriers.data());
m_queuedBarriers.clear();
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp
index c31fe8ada8..94262064da 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListPool.cpp
@@ -175,7 +175,7 @@ namespace AZ
void CommandListAllocator::Collect()
{
- AZ_ATOM_PROFILE_FUNCTION("DX12", "CommandListAllocator: Collect");
+ AZ_PROFILE_SCOPE(RHI, "CommandListAllocator: Collect(DX12)");
for (uint32_t queueIdx = 0; queueIdx < RHI::HardwareQueueClassCount; ++queueIdx)
{
m_commandListSubAllocators[queueIdx].ForEach([](Internal::CommandListSubAllocator& commandListSubAllocator)
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp
index 9d58217f01..0cde6aeb09 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp
@@ -195,7 +195,7 @@ namespace AZ
void CommandQueue::UpdateTileMappings(CommandList& commandList)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandQueue: UpdateTileMappings");
for (const CommandList::TileMapRequest& request : commandList.GetTileMapRequests())
{
const uint32_t tileCount = request.m_sourceRegionSize.NumTiles;
@@ -229,7 +229,7 @@ namespace AZ
void CommandQueue::WaitForIdle()
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandQueue: WaitForIdle");
Fence fence;
fence.Init(m_device.get(), RHI::FenceState::Reset);
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp
index 96d621df59..eee137026d 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp
@@ -101,7 +101,7 @@ namespace AZ
void CommandQueueContext::WaitForIdle()
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandQueueContext: WaitForIdle");
for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx)
{
if (m_commandQueues[hardwareQueueIdx])
@@ -113,7 +113,7 @@ namespace AZ
void CommandQueueContext::Begin()
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandQueueContext: Begin");
{
AZ_PROFILE_SCOPE(RHI, "Clearing Command Queue Timers");
@@ -131,8 +131,7 @@ namespace AZ
void CommandQueueContext::End()
{
- AZ_PROFILE_FUNCTION(RHI);
- AZ_ATOM_PROFILE_FUNCTION("DX12", "CommandQueueContext: End");
+ AZ_PROFILE_SCOPE(RHI, "CommandQueueContext: End");
QueueGpuSignals(m_frameFences[m_currentFrameIndex]);
@@ -146,7 +145,6 @@ namespace AZ
{
AZ_PROFILE_SCOPE(RHI, "Wait and Reset Fence");
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("DX12", "CommandQueueContext: Wait on Fences");
FenceEvent event("FrameFence");
m_frameFences[m_currentFrameIndex].Wait(event);
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp
index 942b514b97..816b904e16 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp
@@ -341,7 +341,7 @@ namespace AZ
void DescriptorContext::GarbageCollect()
{
- AZ_ATOM_PROFILE_FUNCTION("DX12", "DescriptorContext: GarbageCollect");
+ AZ_PROFILE_SCOPE(RHI, "DescriptorContext: GarbageCollect(DX12)");
for (const auto& itr : m_platformLimitsDescriptor->m_descriptorHeapLimits)
{
for (uint32_t shaderVisibleIdx = 0; shaderVisibleIdx < PlatformLimitsDescriptor::NumHeapFlags; ++shaderVisibleIdx)
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp
index 7eaafc3705..722d535cb1 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp
@@ -204,7 +204,7 @@ namespace AZ
RHI::MessageOutcome FrameGraphCompiler::CompileInternal(const RHI::FrameGraphCompileRequest& request)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileInternal(DX12)");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileInternal(DX12)");
RHI::FrameGraph& frameGraph = *request.m_frameGraph;
@@ -373,7 +373,7 @@ namespace AZ
void FrameGraphCompiler::CompileResourceBarriers(Scope* rootScope, const RHI::FrameGraphAttachmentDatabase& attachmentDatabase)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileResourceBarriers(DX12)");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileResourceBarriers(DX12)");
for (RHI::BufferFrameAttachment* bufferFrameAttachment : attachmentDatabase.GetBufferAttachments())
{
@@ -394,7 +394,7 @@ namespace AZ
ResourceTransitionLoggerNull logger(bufferFrameAttachment.GetId());
#endif
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileBufferBarriers(DX12)");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileBufferBarriers(DX12)");
Buffer& buffer = static_cast(*bufferFrameAttachment.GetBuffer());
RHI::BufferScopeAttachment* scopeAttachment = bufferFrameAttachment.GetFirstScopeAttachment();
@@ -469,7 +469,7 @@ namespace AZ
ResourceTransitionLoggerNull logger(imageFrameAttachment.GetId());
#endif
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileImageBarriers (DX12)");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileImageBarriers (DX12)");
Image& image = static_cast(*imageFrameAttachment.GetImage());
RHI::ImageScopeAttachment* scopeAttachment = imageFrameAttachment.GetFirstScopeAttachment();
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp
index 1a32f06fa2..337b25a793 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/StagingMemoryAllocator.cpp
@@ -55,7 +55,7 @@ namespace AZ
void StagingMemoryAllocator::GarbageCollect()
{
- AZ_ATOM_PROFILE_FUNCTION("DX12", "StagingMemoryAllocator: GarbageCollect");
+ AZ_PROFILE_SCOPE(RHI, "StagingMemoryAllocator: GarbageCollect(DX12)");
m_mediumBlockAllocators.ForEach([](MemoryLinearSubAllocator& subAllocator)
{
subAllocator.GarbageCollect();
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp
index 7f0c535383..fb11700e04 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp
@@ -79,8 +79,8 @@ namespace AZ
void CommandQueueContext::End()
{
- AZ_PROFILE_FUNCTION(RHI);
-
+ AZ_PROFILE_SCOPE(RHI, "CommandQueueContext: End");
+
QueueGpuSignals(m_frameFences[m_currentFrameIndex]);
for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx)
{
@@ -92,7 +92,6 @@ namespace AZ
{
AZ_PROFILE_SCOPE(RHI, "Wait and Reset Fence");
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "CommandQueueContext: Wait on Fences");
//Synchronize the CPU with the GPU by waiting on the fence until signalled by the GPU. CPU can only go upto
//RHI::Limits::Device::FrameCountMax frames ahead of the GPU
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp
index 520e417f6b..a347ed9b12 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/FrameGraphCompiler.cpp
@@ -33,7 +33,7 @@ namespace AZ
RHI::MessageOutcome FrameGraphCompiler::CompileInternal(const RHI::FrameGraphCompileRequest& request)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileInternal(Metal)");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileInternal(Metal)");
RHI::FrameGraph& frameGraph = *request.m_frameGraph;
if (!RHI::CheckBitsAny(request.m_compileFlags, RHI::FrameSchedulerCompileFlags::DisableAsyncQueues))
{
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp
index 90ba04c3db..567f89b6e0 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp
@@ -192,7 +192,7 @@ namespace AZ
id SwapChain::RequestDrawable(bool isFrameCaptureEnabled)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "SwapChain::RequestDrawable");
+ AZ_PROFILE_SCOPE(RHI, "SwapChain::RequestDrawable");
m_metalView.metalLayer.framebufferOnly = !isFrameCaptureEnabled;
const uint32_t currentImageIndex = GetCurrentImageIndex();
if(m_drawables[currentImageIndex])
diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp
index 7a8499ab9d..2c3958cb65 100644
--- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp
+++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp
@@ -451,7 +451,7 @@ namespace AZ
AsyncUploadQueue::FramePacket* AsyncUploadQueue::BeginFramePacket(Queue* queue)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: BeginFramePacket");
AZ_Assert(!m_recordingFrame, "The previous frame packet isn't ended.");
auto& device = static_cast(GetDevice());
@@ -471,7 +471,7 @@ namespace AZ
void AsyncUploadQueue::EndFramePacket(Queue* queue, Semaphore* semaphoreToSignal /*=nullptr*/)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: EndFramePacket");
AZ_Assert(m_recordingFrame, "The frame packet wasn't started. You need to call StartFramePacket first.");
m_commandList->EndCommandBuffer();
@@ -636,7 +636,7 @@ namespace AZ
void AsyncUploadQueue::ProcessCallback(const RHI::AsyncWorkHandle& handle)
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "AsyncUploadQueue: ProcessCallback");
AZStd::unique_lock lock(m_callbackListMutex);
auto findIter = m_callbackList.find(handle);
if (findIter != m_callbackList.end())
diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp
index 39f0ac9d58..c0d34e2bf9 100644
--- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp
+++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp
@@ -42,7 +42,7 @@ namespace AZ
void CommandQueueContext::End()
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandQueueContext: End");
for (auto& commandQueue : m_commandQueues)
{
@@ -55,7 +55,6 @@ namespace AZ
{
AZ_PROFILE_SCOPE(RHI, "Wait on Fences");
- AZ_ATOM_PROFILE_FUNCTION("RHI", "CommandQueueContext: Wait on Fences");
FencesPerQueue& nextFences = m_frameFences[m_currentFrameIndex];
for (auto& fence : nextFences)
@@ -79,7 +78,7 @@ namespace AZ
void CommandQueueContext::WaitForIdle()
{
- AZ_PROFILE_FUNCTION(RHI);
+ AZ_PROFILE_SCOPE(RHI, "CommandQueueContext: WaitForIdle");
for (auto& commandQueue : m_commandQueues)
{
commandQueue->WaitForIdle();
diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp
index 372ebc273d..2a30e36e04 100644
--- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp
+++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphCompiler.cpp
@@ -45,7 +45,7 @@ namespace AZ
RHI::MessageOutcome FrameGraphCompiler::CompileInternal(const RHI::FrameGraphCompileRequest& request)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileInternal(Vulkan)");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileInternal(Vulkan)");
AZ_Assert(request.m_frameGraph, "FrameGraph is null.");
RHI::FrameGraph& frameGraph = *request.m_frameGraph;
@@ -89,7 +89,7 @@ namespace AZ
void FrameGraphCompiler::CompileResourceBarriers(const RHI::FrameGraphAttachmentDatabase& attachmentDatabase)
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileResourceBarriers(Vulkan)");
+ AZ_PROFILE_SCOPE(RHI, "FrameGraphCompiler: CompileResourceBarriers(Vulkan)");
for (RHI::BufferFrameAttachment* bufferFrameAttachment : attachmentDatabase.GetBufferAttachments())
{
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialAsset.h
index 52af56ba0e..6ca3bca652 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialAsset.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialAsset.h
@@ -19,6 +19,11 @@
#include
+namespace UnitTest
+{
+ class MaterialTests;
+}
+
namespace AZ
{
class ReflectContext;
@@ -40,6 +45,7 @@ namespace AZ
friend class MaterialAssetCreator;
friend class MaterialAssetHandler;
friend class MaterialAssetCreatorCommon;
+ friend class UnitTest::MaterialTests;
public:
AZ_RTTI(MaterialAsset, "{522C7BE0-501D-463E-92C6-15184A2B7AD8}", AZ::Data::AssetData);
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp
index bedf4fe989..f67343faa1 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp
@@ -299,7 +299,7 @@ namespace AZ
//work function
void Process() override
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "AddObjectsToViewJob: Process");
const View::UsageFlags viewFlags = m_jobData->m_view->GetUsageFlags();
const RHI::DrawListMask drawListMask = m_jobData->m_view->GetDrawListMask();
@@ -645,7 +645,7 @@ namespace AZ
uint32_t AddLodDataToView(const Vector3& pos, const Cullable::LodData& lodData, RPI::View& view)
{
#ifdef AZ_CULL_PROFILE_DETAILED
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "AddLodDataToView");
#endif
const Matrix4x4& viewToClip = view.GetViewToClipMatrix();
@@ -725,7 +725,7 @@ namespace AZ
void CullingScene::BeginCulling(const AZStd::vector& views)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "CullingScene: BeginCulling");
+ AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCulling");
m_cullDataConcurrencyCheck.soft_lock();
m_debugCtx.ResetCullStats();
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp
index 257bb689ee..8077038ea7 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQuerySystem.cpp
@@ -75,7 +75,7 @@ namespace AZ
void GpuQuerySystem::Update()
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "GpuQuerySystem: Update");
+ AZ_PROFILE_SCOPE(RPI, "GpuQuerySystem: Update");
for (auto& queryPool : m_queryPoolArray)
{
if (queryPool)
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp
index d4a55d1c29..71e2eaa2f5 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp
@@ -34,6 +34,8 @@
#include
#include
+AZ_DECLARE_BUDGET(RPI);
+
namespace AZ
{
namespace RPI
@@ -171,7 +173,7 @@ namespace AZ
void ImageSystem::Update()
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "ImageSystem: Update");
+ AZ_PROFILE_SCOPE(RPI, "ImageSystem: Update");
AZStd::lock_guard lock(m_activeStreamingPoolMutex);
for (StreamingImagePool* imagePool : m_activeStreamingPools)
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp
index 2dcaa70deb..d44ed40c7b 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp
@@ -100,9 +100,15 @@ namespace AZ
ShaderReloadNotificationBus::MultiHandler::BusConnect(shaderItem.GetShaderAsset().GetId());
}
+ // If this Init() is actually a re-initialize, we need to re-apply any overridden property values
+ // after loading the property values from the asset, so we save that data here.
MaterialPropertyFlags prevOverrideFlags = m_propertyOverrideFlags;
AZStd::vector prevPropertyValues = m_propertyValues;
+ // The property values are cleared to their default state to ensure that SetPropertyValue() does not early-return
+ // when called below. This is important when Init() is actually a re-initialize.
+ m_propertyValues.clear();
+
// Initialize the shader runtime data like shader constant buffers and shader variants by applying the
// material's property values. This will feed through the normal runtime material value-change data flow, which may
// include custom property change handlers provided by the material type.
@@ -504,7 +510,7 @@ namespace AZ
MaterialPropertyValue& savedPropertyValue = m_propertyValues[index.GetIndex()];
- // If the property value didn't actually change, don't waste time running functors and compiling the changes
+ // If the property value didn't actually change, don't waste time running functors and compiling the changes.
if (savedPropertyValue == value)
{
return false;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp
index 6fd313e27f..50da470ec4 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp
@@ -42,7 +42,7 @@ namespace AZ
Data::Instance Model::CreateInternal(const Data::Asset& modelAsset)
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "Model: CreateInternal");
Data::Instance model = aznew Model();
const RHI::ResultCode resultCode = model->Init(modelAsset);
@@ -56,7 +56,7 @@ namespace AZ
RHI::ResultCode Model::Init(const Data::Asset& modelAsset)
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "Model: Init");
m_lods.resize(modelAsset->GetLodAssets().size());
@@ -128,7 +128,7 @@ namespace AZ
bool Model::LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "Model: LocalRayIntersection");
if (!GetModelAsset())
{
@@ -171,7 +171,7 @@ namespace AZ
float& distanceNormalized,
AZ::Vector3& normal) const
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "Model: RayIntersection");
const AZ::Vector3 clampedScale = nonUniformScale.GetMax(AZ::Vector3(AZ::MinTransformScale));
const AZ::Transform inverseTM = modelTransform.GetInverse();
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp
index ef9521d23c..a1651defbc 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLodUtils.cpp
@@ -27,7 +27,7 @@ namespace AZ
ModelLodIndex SelectLod(const View* view, const Vector3& position, const Model& model, ModelLodIndex lodOverride)
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "ModelLodUtils: SelectLod");
ModelLodIndex lodIndex;
if (model.GetLodCount() == 1)
{
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp
index a8feeb1047..34d72338dc 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp
@@ -169,7 +169,7 @@ namespace AZ
void PassSystem::RemovePasses()
{
m_state = PassSystemState::RemovingPasses;
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: RemovePasses");
+ AZ_PROFILE_SCOPE(RPI, "PassSystem: RemovePasses");
if (!m_removePassList.empty())
{
@@ -189,8 +189,7 @@ namespace AZ
void PassSystem::BuildPasses()
{
m_state = PassSystemState::BuildingPasses;
- AZ_PROFILE_FUNCTION(RPI);
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments");
+ AZ_PROFILE_SCOPE(RPI, "PassSystem: BuildPasses");
m_passHierarchyChanged = m_passHierarchyChanged || !m_buildPassList.empty();
@@ -239,8 +238,7 @@ namespace AZ
void PassSystem::InitializePasses()
{
m_state = PassSystemState::InitializingPasses;
- AZ_PROFILE_FUNCTION(RPI);
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments");
+ AZ_PROFILE_SCOPE(RPI, "PassSystem: InitializePasses");
m_passHierarchyChanged = m_passHierarchyChanged || !m_initializePassList.empty();
@@ -277,7 +275,6 @@ namespace AZ
void PassSystem::Validate()
{
m_state = PassSystemState::ValidatingPasses;
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: Validate");
if (PassValidation::IsEnabled())
{
@@ -286,7 +283,7 @@ namespace AZ
return;
}
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "PassSystem: Validate");
PassValidationResults validationResults;
m_rootPass->Validate(validationResults);
@@ -298,7 +295,7 @@ namespace AZ
void PassSystem::ProcessQueuedChanges()
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: ProcessQueuedChanges");
+ AZ_PROFILE_SCOPE(RPI, "PassSystem: ProcessQueuedChanges");
RemovePasses();
BuildPasses();
InitializePasses();
@@ -307,8 +304,7 @@ namespace AZ
void PassSystem::FrameUpdate(RHI::FrameGraphBuilder& frameGraphBuilder)
{
- AZ_PROFILE_FUNCTION(RPI);
- AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: FrameUpdate");
+ AZ_PROFILE_SCOPE(RPI, "PassSystem: FrameUpdate");
ResetFrameStatistics();
ProcessQueuedChanges();
@@ -317,14 +313,14 @@ namespace AZ
Pass::FramePrepareParams params{ &frameGraphBuilder };
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Pass: FrameBegin");
+ AZ_PROFILE_SCOPE(RPI, "Pass: FrameBegin");
m_rootPass->FrameBegin(params);
}
}
void PassSystem::FrameEnd()
{
- AZ_ATOM_PROFILE_FUNCTION("RHI", "PassSystem: FrameEnd");
+ AZ_PROFILE_SCOPE(RHI, "PassSystem: FrameEnd");
m_state = PassSystemState::FrameEnd;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp
index 4c923d4a1a..d9f98c11d3 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp
@@ -216,7 +216,7 @@ namespace AZ
void RasterPass::CompileResources(const RHI::FrameGraphCompileContext& context)
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "RasterPass: CompileResources");
if (m_shaderResourceGroup == nullptr)
{
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp
index 500bf21628..5df1c655d6 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp
@@ -233,7 +233,7 @@ namespace AZ
void RPISystem::OnSystemTick()
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "RPISystem: OnSystemTick");
+ AZ_PROFILE_SCOPE(RPI, "RPISystem: OnSystemTick");
// Image system update is using system tick but not game tick so it can stream images in background even game is pausing
m_imageSystem.Update();
@@ -245,7 +245,7 @@ namespace AZ
{
return;
}
- AZ_ATOM_PROFILE_FUNCTION("RPI", "RPISystem: SimulationTick");
+ AZ_PROFILE_SCOPE(RPI, "RPISystem: SimulationTick");
AssetInitBus::Broadcast(&AssetInitBus::Events::PostLoadInit);
@@ -273,8 +273,7 @@ namespace AZ
return;
}
- AZ_PROFILE_FUNCTION(RPI);
- AZ_ATOM_PROFILE_FUNCTION("RPI", "RPISystem: RenderTick");
+ AZ_PROFILE_SCOPE(RPI, "RPISystem: RenderTick");
// Query system update is to increment the frame count
m_querySystem.Update();
@@ -301,7 +300,7 @@ namespace AZ
});
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "RPISystem: FrameEnd");
+ AZ_PROFILE_SCOPE(RPI, "RPISystem: FrameEnd");
m_dynamicDraw.FrameEnd();
m_passSystem.FrameEnd();
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp
index 7f0ab9c8aa..409a084e4f 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp
@@ -397,7 +397,7 @@ namespace AZ
void RenderPipeline::OnStartFrame()
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
m_lastRenderStartTime = m_lastRenderRequestTime;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp
index 9fa49f7f2a..778548f14c 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp
@@ -350,7 +350,7 @@ namespace AZ
void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: Simulate");
+ AZ_PROFILE_SCOPE(RPI, "Scene: Simulate");
m_simulationTime = tickInfo.m_currentGameTime;
@@ -389,7 +389,7 @@ namespace AZ
{
if (completionJob)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: WaitAndCleanCompletionJob");
+ AZ_PROFILE_SCOPE(RPI, "Scene: WaitAndCleanCompletionJob");
//[GFX TODO]: the completion job should start earlier and wait for completion here
completionJob->StartAndWaitForCompletion();
delete completionJob;
@@ -422,11 +422,10 @@ namespace AZ
void Scene::PrepareRender([[maybe_unused]]const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: PrepareRender");
+ AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender");
{
AZ_PROFILE_SCOPE(RPI, "WaitForSimulationCompletion");
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "WaitForSimulationCompletion");
WaitAndCleanCompletionJob(m_simulationCompletion);
}
@@ -435,7 +434,7 @@ namespace AZ
// Get active pipelines which need to be rendered and notify them of an impending frame.
AZStd::vector activePipelines;
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnPrepareFrame");
+ AZ_PROFILE_SCOPE(RPI, "Scene: OnPrepareFrame");
for (auto& pipeline : m_pipelines)
{
pipeline->OnPrepareFrame();
@@ -449,7 +448,7 @@ namespace AZ
// Get active pipelines which need to be rendered and notify them frame started
for (const auto& pipeline : activePipelines)
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnStartFrame");
+ AZ_PROFILE_SCOPE(RPI, "Scene: OnStartFrame");
pipeline->OnStartFrame();
}
@@ -468,7 +467,7 @@ namespace AZ
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Setup Views");
+ AZ_PROFILE_SCOPE(RPI, "Setup Views");
// Collect persistent views from all pipelines to be rendered
AZStd::map persistentViews;
@@ -506,8 +505,7 @@ namespace AZ
}
{
- AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets");
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "CollectDrawPackets");
+ AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets");
AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion();
// Launch FeatureProcessor::Render() jobs
@@ -550,14 +548,13 @@ namespace AZ
// Add dynamic draw data for all the views
if (m_dynamicDrawSystem)
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "DynamicDraw SubmitDrawData");
+ AZ_PROFILE_SCOPE(RPI, "DynamicDraw SubmitDrawData");
m_dynamicDrawSystem->SubmitDrawData(this, m_renderPacket.m_views);
}
}
{
AZ_PROFILE_BEGIN(RPI, "FinalizeDrawLists");
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "FinalizeDrawLists");
if (jobPolicy == RHI::JobPolicy::Serial)
{
for (auto& view : m_renderPacket.m_views)
@@ -586,14 +583,14 @@ namespace AZ
}
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene OnEndPrepareRender");
+ AZ_PROFILE_SCOPE(RPI, "Scene OnEndPrepareRender");
SceneNotificationBus::Event(GetId(), &SceneNotification::OnEndPrepareRender);
}
}
void Scene::OnFrameEnd()
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: OnFrameEnd");
+ AZ_PROFILE_SCOPE(RPI, "Scene: OnFrameEnd");
bool didRender = false;
for (auto& pipeline : m_pipelines)
{
@@ -730,7 +727,7 @@ namespace AZ
void Scene::RebuildPipelineStatesLookup()
{
- AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: RebuildPipelineStatesLookup");
+ AZ_PROFILE_SCOPE(RPI, "Scene: RebuildPipelineStatesLookup");
m_pipelineStatesLookup.clear();
AZStd::queue parents;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp
index 9e633077e7..528d32e217 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp
@@ -113,7 +113,7 @@ namespace AZ
return;
}
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "ShaderMetricsSystem: RequestShaderVariant");
AZStd::lock_guard lock(m_metricsMutex);
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp
index bdb3ea8899..c2356cea45 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp
@@ -239,7 +239,7 @@ namespace AZ
void View::FinalizeDrawLists()
{
- AZ_PROFILE_FUNCTION(RPI);
+ AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists");
m_drawListContext.FinalizeLists();
if (m_passesByDrawList)
{
diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp
index d82a17e1f3..f202747bf6 100644
--- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp
+++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp
@@ -182,6 +182,13 @@ namespace UnitTest
EXPECT_EQ(srgData.GetImageView(srgData.FindShaderInputImageIndex(Name{ "m_image" }), 0), m_testImage->GetImageView());
EXPECT_EQ(srgData.GetConstant(srgData.FindShaderInputConstantIndex(Name{ "m_enum" })), 2u);
}
+
+ //! Provides write access to private material asset property values, primarily for simulating
+ //! MaterialAsset hot reload.
+ MaterialPropertyValue& AccessMaterialAssetPropertyValue(Data::Asset materialAsset, Name propertyName)
+ {
+ return materialAsset->m_propertyValues[materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyName).GetIndex()];
+ }
};
TEST_F(MaterialTests, TestCreateVsFindOrCreate)
@@ -313,6 +320,30 @@ namespace UnitTest
EXPECT_EQ(srgData.GetConstant(srgData.FindShaderInputConstantIndex(Name{ "m_uint" })), 42u);
}
+ TEST_F(MaterialTests, TestSetPropertyValueWhenValueIsUnchanged)
+ {
+ Data::Instance material = Material::FindOrCreate(m_testMaterialAsset);
+
+ EXPECT_TRUE(material->SetPropertyValue(material->FindPropertyIndex(Name{ "MyFloat" }), 2.5f));
+
+ ProcessQueuedSrgCompilations(m_testMaterialShaderAsset, m_testMaterialSrgLayout->GetName());
+ EXPECT_TRUE(material->Compile());
+
+ // Taint the SRG so we can check whether it was set by the SetPropertyValue() calls below.
+ const RHI::ShaderResourceGroup* srg = material->GetRHIShaderResourceGroup();
+ const RHI::ShaderResourceGroupData& srgData = srg->GetData();
+ const_cast(&srgData)->SetConstant(m_testMaterialSrgLayout->FindShaderInputConstantIndex(Name{"m_float"}), 0.0f);
+
+ // Set the properties to the same values as before
+ EXPECT_FALSE(material->SetPropertyValue(material->FindPropertyIndex(Name{ "MyFloat" }), 2.5f));
+
+ ProcessQueuedSrgCompilations(m_testMaterialShaderAsset, m_testMaterialSrgLayout->GetName());
+ EXPECT_FALSE(material->Compile());
+
+ // Make sure the SRG is still tainted, because the SetPropertyValue() functions weren't processed
+ EXPECT_EQ(srgData.GetConstant(srgData.FindShaderInputConstantIndex(Name{ "m_float" })), 0.0f);
+ }
+
TEST_F(MaterialTests, TestImageNotProvided)
{
Data::Asset materialAssetWithEmptyImage;
@@ -785,4 +816,45 @@ namespace UnitTest
EXPECT_EQ((float)inputColor.GetElement(i), (float)colorFromMaterial.GetElement(i));
}
}
+
+ TEST_F(MaterialTests, TestReinitializeForHotReload)
+ {
+ Data::Instance material = Material::FindOrCreate(m_testMaterialAsset);
+ const RHI::ShaderResourceGroupData* srgData = &material->GetRHIShaderResourceGroup()->GetData();
+ ProcessQueuedSrgCompilations(m_testMaterialShaderAsset, m_testMaterialSrgLayout->GetName());
+
+ // Check the default property value
+ EXPECT_EQ(material->GetPropertyValue(material->FindPropertyIndex(Name{ "MyFloat" })), 1.5f);
+ EXPECT_EQ(srgData->GetConstant(srgData->FindShaderInputConstantIndex(Name{ "m_float" })), 1.5f);
+ EXPECT_EQ(material->GetPropertyValue(material->FindPropertyIndex(Name{ "MyInt" })), -2);
+ EXPECT_EQ(srgData->GetConstant(srgData->FindShaderInputConstantIndex(Name{ "m_int" })), -2);
+
+ // Override a property value
+ EXPECT_TRUE(material->SetPropertyValue(material->FindPropertyIndex(Name{ "MyFloat" }), 5.5f));
+
+ // Apply the changes
+ EXPECT_TRUE(material->Compile());
+ ProcessQueuedSrgCompilations(m_testMaterialShaderAsset, m_testMaterialSrgLayout->GetName());
+
+ // Check the updated values with one overridden
+ EXPECT_EQ(material->GetPropertyValue(material->FindPropertyIndex(Name{ "MyFloat" })), 5.5f);
+ EXPECT_EQ(srgData->GetConstant(srgData->FindShaderInputConstantIndex(Name{ "m_float" })), 5.5f);
+ EXPECT_EQ(material->GetPropertyValue(material->FindPropertyIndex(Name{ "MyInt" })), -2);
+ EXPECT_EQ(srgData->GetConstant(srgData->FindShaderInputConstantIndex(Name{ "m_int" })), -2);
+
+ // Pretend there was a hot-reload with new default values
+ AccessMaterialAssetPropertyValue(m_testMaterialAsset, Name{"MyFloat"}) = 0.5f;
+ AccessMaterialAssetPropertyValue(m_testMaterialAsset, Name{"MyInt"}) = -7;
+ AZ::Data::AssetBus::Event(m_testMaterialAsset.GetId(), &AZ::Data::AssetBus::Handler::OnAssetReloaded, m_testMaterialAsset);
+ srgData = &material->GetRHIShaderResourceGroup()->GetData();
+ ProcessQueuedSrgCompilations(m_testMaterialShaderAsset, m_testMaterialSrgLayout->GetName());
+
+ // Make sure the override values are still there
+ EXPECT_EQ(srgData->GetConstant(srgData->FindShaderInputConstantIndex(Name{ "m_float" })), 5.5f);
+ EXPECT_EQ(material->GetPropertyValue(material->FindPropertyIndex(Name{ "MyFloat" })), 5.5f);
+
+ // Make sure the new default value is applied where it was not overridden
+ EXPECT_EQ(material->GetPropertyValue(material->FindPropertyIndex(Name{ "MyInt" })), -7);
+ EXPECT_EQ(srgData->GetConstant(srgData->FindShaderInputConstantIndex(Name{ "m_int" })), -7);
+ }
}
diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h
index ea4dd20250..a649fcf0f7 100644
--- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h
+++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h
@@ -174,7 +174,7 @@ namespace AZ
AZStd::unordered_map> m_savedData;
// Region color cache
- AZStd::unordered_map m_regionColorMap;
+ AZStd::unordered_map m_regionColorMap;
// Tracks the frame boundaries
AZStd::vector m_frameEndTicks = { INT64_MIN };
diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl
index 61f68197b6..a573e3019a 100644
--- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl
+++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl
@@ -124,7 +124,7 @@ namespace AZ
m_cpuTimingStatisticsWhenPause = currentCpuTimingStatistics;
CollectFrameData();
- CullFrameData(currentCpuTimingStatistics);
+ CullFrameData(currentCpuTimingStatistics);
// Only listen to system ticks when the profiler is active
if (!SystemTickBus::Handler::BusIsConnected())
@@ -148,7 +148,7 @@ namespace AZ
}
}
ImGui::End();
-
+
if (m_captureToFile)
{
AZStd::sys_time_t timeNow = AZStd::GetTimeNowSecond();
@@ -325,7 +325,7 @@ namespace AZ
{
const bool ascending = sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending;
const ImS16 columnToSort = sortSpecs->Specs->ColumnIndex;
-
+
switch (columnToSort)
{
case (0): // Sort by group name
@@ -343,7 +343,7 @@ namespace AZ
case (4): // Sort by invocations
AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_invocationsLastFrame, ascending));
break;
- case (5): // Sort by total time
+ case (5): // Sort by total time
AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_lastFrameTotalTicks, ascending));
break;
}
@@ -401,7 +401,7 @@ namespace AZ
}
DrawTable();
- }
+ }
}
inline void ImGuiCpuProfiler::DrawFilePicker()
@@ -460,17 +460,17 @@ namespace AZ
const auto [groupRegionNameItr, wasGroupRegionNameInserted] =
m_deserializedGroupRegionNamePool.emplace(groupNameItr->c_str(), regionNameItr->c_str());
- const RHI::CachedTimeRegion newRegion(&(*groupRegionNameItr), entry.m_stackDepth, entry.m_startTick, entry.m_endTick);
+ const RHI::CachedTimeRegion newRegion(*groupRegionNameItr, entry.m_stackDepth, entry.m_startTick, entry.m_endTick);
m_savedData[entry.m_threadId].push_back(newRegion);
- // Since we don't serialize the frame boundaries, we need to use the RPI's OnSystemTick event as a heuristic.
+ // Since we don't serialize the frame boundaries, we need to use the RPI's OnSystemTick event as a heuristic.
const static Name frameBoundaryName = Name("RPISystem: OnSystemTick");
if (entry.m_regionName == frameBoundaryName)
{
m_frameEndTicks.push_back(entry.m_endTick);
- }
+ }
- // Update running statistics
+ // Update running statistics
if (!m_groupRegionMap[*groupNameItr].contains(*regionNameItr))
{
m_groupRegionMap[*groupNameItr][*regionNameItr].m_groupName = *groupNameItr;
@@ -487,7 +487,7 @@ namespace AZ
// Invariant: each vector in m_savedData must be sorted so that we can efficiently cull region data.
for (auto& [threadId, singleThreadData] : m_savedData)
{
- AZStd::sort(singleThreadData.begin(), singleThreadData.end(),
+ AZStd::sort(singleThreadData.begin(), singleThreadData.end(),
[](const TimeRegion& lhs, const TimeRegion& rhs)
{
return lhs.m_startTick < rhs.m_startTick;
@@ -669,7 +669,7 @@ namespace AZ
// Iterate through the entire TimeRegionMap and copy the data since it will get deleted on the next frame
for (const auto& [threadId, singleThreadRegionMap] : timeRegionMap)
{
- const size_t threadIdHashed = AZStd::hash{}(threadId);
+ const size_t threadIdHashed = AZStd::hash{}(threadId);
// The profiler can sometime return threads without any profiling events when dropping threads, FIXME(ATOM-15949)
if (singleThreadRegionMap.size() == 0)
{
@@ -686,7 +686,7 @@ namespace AZ
newVisualizerData.push_back(region); // Copies
// Also update the statistical view's data
- const AZStd::string& groupName = region.m_groupRegionName->m_groupName;
+ const AZStd::string& groupName = region.m_groupRegionName.m_groupName;
if (!m_groupRegionMap[groupName].contains(regionName))
{
@@ -765,7 +765,7 @@ namespace AZ
inline void ImGuiCpuProfiler::DrawBlock(const TimeRegion& block, u64 targetRow)
{
// Don't draw anything if the user is searching for regions and this block doesn't pass the filter
- if (!m_visualizerHighlightFilter.PassFilter(block.m_groupRegionName->m_regionName))
+ if (!m_visualizerHighlightFilter.PassFilter(block.m_groupRegionName.m_regionName))
{
return;
}
@@ -798,7 +798,7 @@ namespace AZ
if (regionPixelWidth > maxCharWidth) // We can draw at least one character
{
const AZStd::string label =
- AZStd::string::format("%s/ %s", block.m_groupRegionName->m_groupName, block.m_groupRegionName->m_regionName);
+ AZStd::string::format("%s/ %s", block.m_groupRegionName.m_groupName, block.m_groupRegionName.m_regionName);
const float textWidth = ImGui::CalcTextSize(label.c_str()).x;
if (regionPixelWidth < textWidth) // Not enough space in the block to draw the whole name, draw clipped text.
@@ -809,7 +809,7 @@ namespace AZ
// so we must adjust for the scale manually.
const float scaleFactor = ImGui::GetIO().FontGlobalScale;
const float fontSize = ImGui::GetFont()->FontSize * scaleFactor;
-
+
ImGui::GetFont()->RenderText(drawList, fontSize, startPoint, IM_COL32_WHITE, clipRect, label.c_str(), 0);
}
else // We have enough space to draw the entire label, draw and center text.
@@ -828,7 +828,7 @@ namespace AZ
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
{
m_enableVisualizer = false;
- const auto newFilter = AZStd::string(block.m_groupRegionName->m_regionName);
+ const auto newFilter = AZStd::string(block.m_groupRegionName.m_regionName);
m_timedRegionFilter = ImGuiTextFilter(newFilter.c_str());
m_timedRegionFilter.Build();
}
@@ -836,7 +836,7 @@ namespace AZ
drawList->AddRect(startPoint, endPoint, ImGui::GetColorU32({ 1, 1, 1, 1 }), 0.0, 0, 1.5);
ImGui::BeginTooltip();
- ImGui::Text("%s::%s", block.m_groupRegionName->m_groupName, block.m_groupRegionName->m_regionName);
+ ImGui::Text("%s::%s", block.m_groupRegionName.m_groupName, block.m_groupRegionName.m_regionName);
ImGui::Text("Execution time: %.3f ms", CpuProfilerImGuiHelper::TicksToMs(block.m_endTick - block.m_startTick));
ImGui::Text("Ticks %lld => %lld", block.m_startTick, block.m_endTick);
ImGui::EndTooltip();
@@ -846,10 +846,10 @@ namespace AZ
inline ImU32 ImGuiCpuProfiler::GetBlockColor(const TimeRegion& block)
{
// Use the GroupRegionName pointer a key into the cache, equal regions will have equal pointers
- const GroupRegionName* key = block.m_groupRegionName;
- if (m_regionColorMap.contains(key)) // Cache hit
+ const GroupRegionName& key = block.m_groupRegionName;
+ if (auto iter = m_regionColorMap.find(key); iter != m_regionColorMap.end()) // Cache hit
{
- return ImGui::GetColorU32(m_regionColorMap[key]);
+ return ImGui::GetColorU32(iter->second);
}
// Cache miss, generate a new random color
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt
index bf28ed3f14..e68681315e 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt
+++ b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt
@@ -109,6 +109,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
RUNTIME_DEPENDENCIES
Gem::Atom_RPI.Editor
Gem::Atom_Feature_Common.Editor
+ Legacy::EditorCommon
)
# The AtomLyIntegration_CommonFeatures.Editor module is used for Builders and Tools
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp
index cbb30e6cd8..d8cae4564d 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp
+++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp
@@ -231,7 +231,7 @@ namespace SurfaceData
void SurfaceDataMeshComponent::UpdateMeshData()
{
- AZ_PROFILE_FUNCTION(Entity);
+ AZ_PROFILE_SCOPE(Entity, "SurfaceDataMeshComponent: UpdateMeshData");
bool meshValidBeforeUpdate = false;
bool meshValidAfterUpdate = false;
diff --git a/Gems/Camera/Code/CMakeLists.txt b/Gems/Camera/Code/CMakeLists.txt
index 3fbeec0908..138f0fda85 100644
--- a/Gems/Camera/Code/CMakeLists.txt
+++ b/Gems/Camera/Code/CMakeLists.txt
@@ -61,6 +61,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
Legacy::EditorCommon
AZ::AzToolsFramework
Gem::Camera.Static
+ RUNTIME_DEPENDENCIES
+ Legacy::EditorCommon
)
# tools and builders use the above module.
diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphCommands.cpp
index dbc25d7a60..bd5a14f772 100644
--- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphCommands.cpp
+++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphCommands.cpp
@@ -715,12 +715,15 @@ namespace CommandSystem
// restore the workspace dirty flag
GetCommandManager()->SetWorkspaceDirtyFlag(m_oldWorkspaceDirtyFlag);
- AZStd::string resultString;
- GetCommandManager()->ExecuteCommandInsideCommand("Unselect -animGraphIndex SELECT_ALL", resultString);
+ MCore::CommandGroup commandGroup;
+ commandGroup.AddCommandString("RecorderClear");
+ commandGroup.AddCommandString("Unselect -animGraphIndex SELECT_ALL");
if (animGraph)
{
- GetCommandManager()->ExecuteCommandInsideCommand(AZStd::string::format("Select -animGraphID %d", animGraph->GetID()), resultString);
+ commandGroup.AddCommandString(AZStd::string::format("Select -animGraphID %d", animGraph->GetID()));
}
+ AZStd::string resultString;
+ GetCommandManager()->ExecuteCommandGroupInsideCommand(commandGroup, resultString);
return true;
}
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h
index 65bac09726..d09de1ad0d 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h
@@ -35,7 +35,7 @@ namespace Multiplayer
using EntityMigrationStartEvent = AZ::Event;
using EntityMigrationEndEvent = AZ::Event<>;
using EntityServerMigrationEvent = AZ::Event;
- using EntityPreRenderEvent = AZ::Event;
+ using EntityPreRenderEvent = AZ::Event;
using EntityCorrectionEvent = AZ::Event<>;
//! @class NetBindComponent
@@ -118,7 +118,7 @@ namespace Multiplayer
void NotifyMigrationStart(ClientInputId migratedInputId);
void NotifyMigrationEnd();
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
- void NotifyPreRender(float deltaTime, float blendFactor);
+ void NotifyPreRender(float deltaTime);
void NotifyCorrection();
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h
index 914aeaadd3..a018279a79 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h
@@ -29,24 +29,9 @@ namespace Multiplayer
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
private:
- void OnPreRender(float deltaTime, float blendFactor);
+ void OnPreRender(float deltaTime);
void OnCorrection();
- void OnRotationChangedEvent(const AZ::Quaternion& rotation);
- void OnTranslationChangedEvent(const AZ::Vector3& translation);
- void OnScaleChangedEvent(float scale);
- void OnResetCountChangedEvent();
-
- void UpdateTargetHostFrameId();
-
- AZ::Transform m_previousTransform = AZ::Transform::CreateIdentity();
- AZ::Transform m_targetTransform = AZ::Transform::CreateIdentity();
-
- AZ::Event::Handler m_rotationEventHandler;
- AZ::Event::Handler m_translationEventHandler;
- AZ::Event::Handler m_scaleEventHandler;
- AZ::Event::Handler m_resetCountEventHandler;
-
EntityPreRenderEvent::Handler m_entityPreRenderEventHandler;
EntityCorrectionEvent::Handler m_entityCorrectionEventHandler;
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h
index 4f714068db..e32b6188eb 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h
@@ -193,15 +193,13 @@ namespace Multiplayer
m_previousHostFrameId = time->GetHostFrameId();
m_previousHostTimeMs = time->GetHostTimeMs();
m_previousRewindConnectionId = time->GetRewindingConnectionId();
- time->AlterTime(frameId, timeMs, connectionId);
m_previousBlendFactor = time->GetHostBlendFactor();
- time->AlterBlendFactor(blendFactor);
+ time->AlterTime(frameId, timeMs, blendFactor, connectionId);
}
inline ~ScopedAlterTime()
{
INetworkTime* time = GetNetworkTime();
- time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousRewindConnectionId);
- time->AlterBlendFactor(m_previousBlendFactor);
+ time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousBlendFactor, m_previousRewindConnectionId);
}
private:
HostFrameId m_previousHostFrameId = InvalidHostFrameId;
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h
index ae47aa8373..c12cbb660b 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h
@@ -52,12 +52,6 @@ namespace Multiplayer
//! @return the ConnectionId of the connection requesting the rewind operation
virtual AzNetworking::ConnectionId GetRewindingConnectionId() const = 0;
- //! Get the controlling connection that may be currently altering global game time.
- //! Note this abstraction is required at a relatively high level to allow for 'don't rewind the shooter' semantics
- //! @param rewindConnectionId if this parameter matches the current rewindConnectionId, it will return the unaltered hostFrameId
- //! @return the HostFrameId taking into account the provided rewinding connectionId
- virtual HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const = 0;
-
//! Forcibly sets the current network time to the provided frameId and game time in milliseconds.
//! @param frameId the new HostFrameId to use
//! @param timeMs the new HostTimeMs to use
@@ -66,12 +60,9 @@ namespace Multiplayer
//! Alters the current HostFrameId and binds that alteration to the provided ConnectionId.
//! @param frameId the new HostFrameId to use
//! @param timeMs the new HostTimeMs to use
+ //! @param blendFactor the factor used to blend between values at the current and previous HostFrameId
//! @param rewindConnectionId the rewinding ConnectionId
- virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) = 0;
-
- //! Alters the current Host blend factor. Used to drive interpolation in rewound states.
- //! @param blendFactor the blend factor to use
- virtual void AlterBlendFactor(float blendFactor) = 0;
+ virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, float blendFactor, AzNetworking::ConnectionId rewindConnectionId) = 0;
//! Syncs all entities contained within a volume to the current rewind state.
//! @param rewindVolume the volume to rewind entities within (needed for physics entities)
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h
index a8af564c15..152f6f47a7 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h
@@ -60,7 +60,7 @@ namespace Multiplayer
//! @return value in const base type form
const BASE_TYPE& Get() const;
- //! Const base type retriever for one host frame behind Get(). Only intended for use in SyncRewind contexts.
+ //! Const base type retriever for one host frame behind Get() when contextually appropriate, otherwise identical to Get().
//! @return value in const base type form
const BASE_TYPE& GetPrevious() const;
@@ -86,9 +86,13 @@ namespace Multiplayer
private:
//! Returns what the appropriate current time is for this rewindable property.
- //! @return the appropriate current time is for this rewindable property
+ //! @return the appropriate current time for this rewindable property
HostFrameId GetCurrentTimeForProperty() const;
+ //! Returns what the appropriate previous time is for this rewindable property.
+ //! @return the appropriate previous time for this rewindable property
+ HostFrameId GetPreviousTimeForProperty() const;
+
//! Updates the latest value for this object instance, if frameTime represents a current or future time.
//! Any attempts to set old values on the object will fail
//! @param value the new value to set in the object history
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl
index b0c9bc0c46..9183a1e9da 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl
@@ -69,7 +69,7 @@ namespace Multiplayer
template
inline const BASE_TYPE& RewindableObject::GetPrevious() const
{
- return GetValueForTime(GetCurrentTimeForProperty() - HostFrameId(1));
+ return GetValueForTime(GetPreviousTimeForProperty());
}
template
@@ -118,7 +118,22 @@ namespace Multiplayer
inline HostFrameId RewindableObject::GetCurrentTimeForProperty() const
{
INetworkTime* networkTime = Multiplayer::GetNetworkTime();
- return networkTime->GetHostFrameIdForRewindingConnection(m_owningConnectionId);
+ if (networkTime->IsTimeRewound() && (m_owningConnectionId == networkTime->GetRewindingConnectionId()))
+ {
+ return networkTime->GetUnalteredHostFrameId();
+ }
+ return networkTime->GetHostFrameId();
+ }
+
+ template
+ inline HostFrameId RewindableObject::GetPreviousTimeForProperty() const
+ {
+ INetworkTime* networkTime = Multiplayer::GetNetworkTime();
+ if (networkTime->IsTimeRewound() && (m_owningConnectionId == networkTime->GetRewindingConnectionId()))
+ {
+ return networkTime->GetUnalteredHostFrameId();
+ }
+ return networkTime->GetHostFrameId() - HostFrameId(1);
}
template
diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja
index 0f62da11f3..41f0fa1b02 100644
--- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja
+++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja
@@ -7,21 +7,21 @@
{% macro DeclareNetworkPropertyGetter(Property) %}
{% set PropertyName = UpperFirst(Property.attrib['Name']) %}
{% if Property.attrib['Container'] == 'Array' %}
-{% if Property.attrib['IsRewindable']|booleanTrue %}
+{% if Property.attrib['IsRewindable']|booleanTrue %}
const RewindableArray<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Array() const;
-{% else %}
+{% else %}
const AZStd::array<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Array() const;
-{% endif %}
+{% endif %}
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}(int32_t index) const;
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
void {{ PropertyName }}AddEvent(AZ::Event::Handler& handler);
{% endif %}
{% elif Property.attrib['Container'] == 'Vector' %}
-{% if Property.attrib['IsRewindable']|booleanTrue %}
+{% if Property.attrib['IsRewindable']|booleanTrue %}
const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Vector() const;
-{% else %}
+{% else %}
const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& Get{{ PropertyName }}Vector() const;
-{% endif %}
+{% endif %}
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}(int32_t index) const;
const {{ Property.attrib['Type'] }}& {{ PropertyName }}GetBack() const;
uint32_t {{ PropertyName }}GetSize() const;
@@ -31,6 +31,9 @@ void {{ PropertyName }}SizeChangedAddEvent(AZ::Event::Handler& handler
{% endif %}
{% else %}
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}() const;
+{% if Property.attrib['IsRewindable']|booleanTrue %}
+const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}Previous() const;
+{% endif %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
void {{ PropertyName }}AddEvent(AZ::Event<{{ Property.attrib['Type'] }}>::Handler& handler);
{% endif %}
diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja
index e57e8dad2f..eb4b81ea96 100644
--- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja
+++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja
@@ -3,11 +3,11 @@
{% macro LowerFirst(text) %}{{ text[0] | lower}}{{ text[1:] }}{% endmacro %}
{% macro DefineNetworkPropertyGet(ClassName, Property, Prefix = '') %}
{% if Property.attrib['Container'] == 'Array' %}
-{% if Property.attrib['IsRewindable']|booleanTrue %}
+{% if Property.attrib['IsRewindable']|booleanTrue %}
const RewindableArray<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Array() const
-{% else %}
+{% else %}
const AZStd::array<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Array() const
-{% endif %}
+{% endif %}
{
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }};
}
@@ -25,11 +25,11 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}AddEvent(AZ::Even
{% endif %}
{% elif Property.attrib['Container'] == 'Vector' %}
-{% if Property.attrib['IsRewindable']|booleanTrue %}
+{% if Property.attrib['IsRewindable']|booleanTrue %}
const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const
-{% else %}
+{% else %}
const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const
-{% endif %}
+{% endif %}
{
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }};
}
@@ -68,7 +68,12 @@ const {{ Property.attrib['Type'] }}& {{ ClassName }}::Get{{ UpperFirst(Property.
{
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }};
}
-
+{% if Property.attrib['IsRewindable']|booleanTrue %}
+const {{ Property.attrib['Type'] }}& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Previous() const
+{
+ return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }}.GetPrevious();
+}
+{% endif %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}AddEvent(AZ::Event<{{ Property.attrib['Type'] }}>::Handler& handler)
{
diff --git a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml
index 203750d761..c553bc5351 100644
--- a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml
+++ b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml
@@ -32,11 +32,11 @@
-
+
-
+
diff --git a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml
index cec005cc26..8ab2e61e5e 100644
--- a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml
+++ b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml
@@ -12,9 +12,9 @@
-
+
-
+
diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp
index 418bea79dd..c5f9b265f9 100644
--- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp
+++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp
@@ -185,12 +185,9 @@ namespace Multiplayer
// Discard move input events, client may be speed hacking
if (m_clientBankedTime < sv_MaxBankTimeWindowSec)
{
- // Client blends from previous frame to target so here we subtract blend factor to get to that state
- const float blendFactor = AZStd::min(AZStd::max(0.f, input.GetHostBlendFactor()), 1.0f);
- const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * (1.0f - blendFactor));
m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary
{
- ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, input.GetHostBlendFactor(), invokingConnection->GetConnectionId());
+ ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), input.GetHostBlendFactor(), invokingConnection->GetConnectionId());
GetNetBindComponent()->ProcessInput(input, static_cast(clientInputRateSec));
}
@@ -436,10 +433,13 @@ namespace Multiplayer
NetworkInputArray inputArray(GetEntityHandle());
NetworkInput& input = inputArray[0];
+ const float blendFactor = AZStd::min(AZStd::max(0.f, multiplayer->GetCurrentBlendFactor()), 1.0f);
+ const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * (1.0f - blendFactor));
input.SetClientInputId(m_clientInputId);
input.SetHostFrameId(networkTime->GetHostFrameId());
- input.SetHostTimeMs(multiplayer->GetCurrentHostTimeMs());
+ // Account for the client blending from previous frame to current
+ input.SetHostTimeMs(multiplayer->GetCurrentHostTimeMs() - blendMs);
input.SetHostBlendFactor(multiplayer->GetCurrentBlendFactor());
// Allow components to form the input for this frame
diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp
index 43577525c0..634cac74b2 100644
--- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp
+++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp
@@ -405,9 +405,9 @@ namespace Multiplayer
m_entityServerMigrationEvent.Signal(m_netEntityHandle, hostId, connectionId);
}
- void NetBindComponent::NotifyPreRender(float deltaTime, float blendFactor)
+ void NetBindComponent::NotifyPreRender(float deltaTime)
{
- m_entityPreRenderEvent.Signal(deltaTime, blendFactor);
+ m_entityPreRenderEvent.Signal(deltaTime);
}
void NetBindComponent::NotifyCorrection()
diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp
index fa08794c4d..1d9fee16e0 100644
--- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp
+++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp
@@ -26,11 +26,7 @@ namespace Multiplayer
}
NetworkTransformComponent::NetworkTransformComponent()
- : m_rotationEventHandler([this](const AZ::Quaternion& rotation) { OnRotationChangedEvent(rotation); })
- , m_translationEventHandler([this](const AZ::Vector3& translation) { OnTranslationChangedEvent(translation); })
- , m_scaleEventHandler([this](float scale) { OnScaleChangedEvent(scale); })
- , m_resetCountEventHandler([this](const uint8_t&) { OnResetCountChangedEvent(); })
- , m_entityPreRenderEventHandler([this](float deltaTime, float blendFactor) { OnPreRender(deltaTime, blendFactor); })
+ : m_entityPreRenderEventHandler([this](float deltaTime) { OnPreRender(deltaTime); })
, m_entityCorrectionEventHandler([this]() { OnCorrection(); })
{
;
@@ -43,15 +39,8 @@ namespace Multiplayer
void NetworkTransformComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
{
- RotationAddEvent(m_rotationEventHandler);
- TranslationAddEvent(m_translationEventHandler);
- ScaleAddEvent(m_scaleEventHandler);
- ResetCountAddEvent(m_resetCountEventHandler);
GetNetBindComponent()->AddEntityPreRenderEventHandler(m_entityPreRenderEventHandler);
GetNetBindComponent()->AddEntityCorrectionEventHandler(m_entityCorrectionEventHandler);
-
- // When coming into relevance, reset all blending factors so we don't interpolate to our start position
- OnResetCountChangedEvent();
}
void NetworkTransformComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
@@ -59,59 +48,31 @@ namespace Multiplayer
;
}
- void NetworkTransformComponent::OnRotationChangedEvent(const AZ::Quaternion& rotation)
- {
- m_previousTransform.SetRotation(m_targetTransform.GetRotation());
- m_targetTransform.SetRotation(rotation);
- UpdateTargetHostFrameId();
- }
-
- void NetworkTransformComponent::OnTranslationChangedEvent(const AZ::Vector3& translation)
- {
- m_previousTransform.SetTranslation(m_targetTransform.GetTranslation());
- m_targetTransform.SetTranslation(translation);
- UpdateTargetHostFrameId();
- }
-
- void NetworkTransformComponent::OnScaleChangedEvent(float scale)
- {
- m_previousTransform.SetUniformScale(m_targetTransform.GetUniformScale());
- m_targetTransform.SetUniformScale(scale);
- UpdateTargetHostFrameId();
- }
-
- void NetworkTransformComponent::OnResetCountChangedEvent()
- {
- m_targetTransform.SetRotation(GetRotation());
- m_targetTransform.SetTranslation(GetTranslation());
- m_targetTransform.SetUniformScale(GetScale());
- m_previousTransform = m_targetTransform;
- }
-
- void NetworkTransformComponent::UpdateTargetHostFrameId()
- {
- HostFrameId currentHostFrameId = Multiplayer::GetNetworkTime()->GetHostFrameId();
- if (currentHostFrameId > m_targetHostFrameId)
- {
- m_targetHostFrameId = currentHostFrameId;
- }
- }
-
- void NetworkTransformComponent::OnPreRender([[maybe_unused]] float deltaTime, float blendFactor)
+ void NetworkTransformComponent::OnPreRender([[maybe_unused]] float deltaTime)
{
if (!HasController())
{
AZ::Transform blendTransform;
- if (Multiplayer::GetNetworkTime() && Multiplayer::GetNetworkTime()->GetHostFrameId() > m_targetHostFrameId)
+ blendTransform.SetRotation(GetRotation());
+ blendTransform.SetTranslation(GetTranslation());
+ blendTransform.SetUniformScale(GetScale());
+
+ const float blendFactor = GetMultiplayer()->GetCurrentBlendFactor();
+ if (!AZ::IsClose(blendFactor, 1.0f))
{
- m_previousTransform = m_targetTransform;
- blendTransform = m_targetTransform;
- }
- else
- {
- blendTransform.SetRotation(m_previousTransform.GetRotation().Slerp(m_targetTransform.GetRotation(), blendFactor));
- blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor));
- blendTransform.SetUniformScale(AZ::Lerp(m_previousTransform.GetUniformScale(), m_targetTransform.GetUniformScale(), blendFactor));
+ AZ::Transform blendTransformPrevious;
+ blendTransformPrevious.SetRotation(GetRotationPrevious());
+ blendTransformPrevious.SetTranslation(GetTranslationPrevious());
+ blendTransformPrevious.SetUniformScale(GetScalePrevious());
+
+ if (!blendTransform.IsClose(blendTransformPrevious))
+ {
+ blendTransform.SetRotation(blendTransformPrevious.GetRotation().Slerp(blendTransform.GetRotation(), blendFactor));
+ blendTransform.SetTranslation(
+ blendTransformPrevious.GetTranslation().Lerp(blendTransform.GetTranslation(), blendFactor));
+ blendTransform.SetUniformScale(
+ AZ::Lerp(blendTransformPrevious.GetUniformScale(), blendTransform.GetUniformScale(), blendFactor));
+ }
}
if (!GetTransformComponent()->GetWorldTM().IsClose(blendTransform))
@@ -124,12 +85,15 @@ namespace Multiplayer
void NetworkTransformComponent::OnCorrection()
{
// Snap to latest
- OnResetCountChangedEvent();
+ AZ::Transform targetTransform;
+ targetTransform.SetRotation(GetRotation());
+ targetTransform.SetTranslation(GetTranslation());
+ targetTransform.SetUniformScale(GetScale());
// Hard set the entities transform
- if (!GetTransformComponent()->GetWorldTM().IsClose(m_targetTransform))
+ if (!GetTransformComponent()->GetWorldTM().IsClose(targetTransform))
{
- GetTransformComponent()->SetWorldTM(m_targetTransform);
+ GetTransformComponent()->SetWorldTM(targetTransform);
}
}
diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp
index 24f865194f..e66eb8d3a3 100644
--- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp
+++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp
@@ -922,7 +922,7 @@ namespace Multiplayer
for (NetBindComponent* netBindComponent : gatheredEntities)
{
- netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor);
+ netBindComponent->NotifyPreRender(deltaTime);
}
}
else
@@ -934,7 +934,7 @@ namespace Multiplayer
NetBindComponent* netBindComponent = entity->FindComponent();
if (netBindComponent != nullptr)
{
- netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor);
+ netBindComponent->NotifyPreRender(deltaTime);
}
}
}
diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp
index cd9c1737d6..b37f485ff4 100644
--- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp
+++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp
@@ -65,11 +65,6 @@ namespace Multiplayer
return m_rewindingConnectionId;
}
- HostFrameId NetworkTime::GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const
- {
- return (IsTimeRewound() && (rewindConnectionId == m_rewindingConnectionId)) ? m_unalteredFrameId : m_hostFrameId;
- }
-
void NetworkTime::ForceSetTime(HostFrameId frameId, AZ::TimeMs timeMs)
{
AZ_Assert(!IsTimeRewound(), "Forcibly setting network time is unsupported under a rewound time scope");
@@ -79,16 +74,12 @@ namespace Multiplayer
m_rewindingConnectionId = AzNetworking::InvalidConnectionId;
}
- void NetworkTime::AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId)
+ void NetworkTime::AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, float blendFactor, AzNetworking::ConnectionId rewindConnectionId)
{
m_hostFrameId = frameId;
m_hostTimeMs = timeMs;
- m_rewindingConnectionId = rewindConnectionId;
- }
-
- void NetworkTime::AlterBlendFactor(float blendFactor)
- {
m_hostBlendFactor = blendFactor;
+ m_rewindingConnectionId = rewindConnectionId;
}
void NetworkTime::SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume)
@@ -121,8 +112,15 @@ namespace Multiplayer
if (networkTransform != nullptr)
{
- // We're not presently factoring in interpolated position here
- const AZ::Vector3 rewindCenter = networkTransform->GetTranslation(); // Get the rewound position
+ // Get the rewound position for target host frame ID plus the one preceding it for potential lerp
+ AZ::Vector3 rewindCenter = networkTransform->GetTranslation();
+ const AZ::Vector3 rewindCenterPrevious = networkTransform->GetTranslationPrevious();
+ const float blendFactor = GetNetworkTime()->GetHostBlendFactor();
+ if (!AZ::IsClose(blendFactor, 1.0f) && !rewindCenter.IsClose(rewindCenterPrevious))
+ {
+ // If we have a blend factor, lerp the translation for accuracy
+ rewindCenter = rewindCenterPrevious.Lerp(rewindCenter, blendFactor);
+ }
const AZ::Vector3 rewindOffset = rewindCenter - currentCenter; // Compute offset between rewound and current positions
const AZ::Aabb rewoundAabb = currentBounds.GetTranslated(rewindOffset); // Apply offset to the entity aabb
diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h
index 0278ddd2b0..2bcf019623 100644
--- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h
+++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h
@@ -32,10 +32,8 @@ namespace Multiplayer
AZ::TimeMs GetHostTimeMs() const override;
float GetHostBlendFactor() const override;
AzNetworking::ConnectionId GetRewindingConnectionId() const override;
- HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override;
void ForceSetTime(HostFrameId frameId, AZ::TimeMs timeMs) override;
- void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) override;
- void AlterBlendFactor(float blendFactor) override;
+ void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, float blendFactor, AzNetworking::ConnectionId rewindConnectionId) override;
void SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) override;
void ClearRewoundEntities() override;
//! @}
diff --git a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp
index b8d60a94e8..04de971f0d 100644
--- a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp
+++ b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp
@@ -57,6 +57,35 @@ namespace UnitTest
}
}
+ TEST_F(RewindableObjectTests, CurrentPreviousTests)
+ {
+ Multiplayer::RewindableObject test(0);
+
+ for (uint32_t i = 0; i < RewindableBufferFrames; ++i)
+ {
+ test = i;
+ EXPECT_EQ(i, test);
+ Multiplayer::GetNetworkTime()->IncrementHostFrameId();
+ }
+
+ {
+ // Test that Get/GetPrevious return different value when not on the owning connection
+ Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames - 1), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId);
+ EXPECT_EQ(RewindableBufferFrames - 1, test.Get());
+ EXPECT_EQ(RewindableBufferFrames - 2, test.GetPrevious());
+ }
+
+ // Test that Get/GetPrevious return the unaltered frame on the owning conection
+ Multiplayer::GetNetworkTime()->AlterTime(static_cast(RewindableBufferFrames - 1), AZ::TimeMs{ 0 }, 1.f, AzNetworking::ConnectionId(0));
+ {
+ Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames - 1), AZ::TimeMs{ 0 }, 1.f, AzNetworking::ConnectionId(0));
+ test.SetOwningConnectionId(AzNetworking::ConnectionId(0));
+ EXPECT_EQ(RewindableBufferFrames - 1, test.Get());
+ EXPECT_EQ(RewindableBufferFrames - 1, test.GetPrevious());
+ }
+ Multiplayer::GetNetworkTime()->AlterTime(static_cast(RewindableBufferFrames), AZ::TimeMs(0), 1.f, AzNetworking::InvalidConnectionId);
+ }
+
TEST_F(RewindableObjectTests, OverflowTests)
{
Multiplayer::RewindableObject test(0);
diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake
index f70ed1aa02..4b7f929279 100644
--- a/cmake/3rdParty.cmake
+++ b/cmake/3rdParty.cmake
@@ -6,6 +6,17 @@
#
#
+define_property(TARGET PROPERTY LY_SYSTEM_LIBRARY
+ BRIEF_DOCS "Defines a 3rdParty library as a system library"
+ FULL_DOCS [[
+ Property which is set on third party targets that should be considered
+ as provided by the system. Such targets are excluded from the runtime
+ dependencies considerations, and are not distributed as part of the
+ O3DE SDK package. Instead, users of the SDK are expected to install
+ such a third party library themselves.
+ ]]
+)
+
# Do not overcomplicate searching for the 3rdParty path, if it is not easy to find,
# the user should define it.
@@ -79,9 +90,10 @@ endfunction()
# "fileA\nMy/Output/Subfolder/lib"
# "fileB\nMy/Output/Subfolder/bin"
#
+# \arg:SYSTEM If specified, the library is considered a system library, and is not copied to the build output directory
function(ly_add_external_target)
- set(options)
+ set(options SYSTEM)
set(oneValueArgs NAME VERSION 3RDPARTY_DIRECTORY PACKAGE 3RDPARTY_ROOT_DIRECTORY OUTPUT_SUBDIRECTORY)
set(multiValueArgs HEADER_CHECK COMPILE_DEFINITIONS INCLUDE_DIRECTORIES BUILD_DEPENDENCIES RUNTIME_DEPENDENCIES)
@@ -300,6 +312,10 @@ function(ly_add_external_target)
)
endif()
+ if(ly_add_external_target_SYSTEM)
+ set_target_properties(3rdParty::${NAME_WITH_NAMESPACE} PROPERTIES LY_SYSTEM_LIBRARY TRUE)
+ endif()
+
endif()
endfunction()
@@ -327,4 +343,4 @@ if(NOT INSTALLED_ENGINE)
ly_include_cmake_file_list(cmake/3rdParty/cmake_files.cmake)
ly_get_absolute_pal_filename(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME})
ly_include_cmake_file_list(${pal_3rdparty_dir}/cmake_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake)
-endif()
\ No newline at end of file
+endif()
diff --git a/cmake/Install.cmake b/cmake/Install.cmake
index 6f50c78fd7..adcd28fa37 100644
--- a/cmake/Install.cmake
+++ b/cmake/Install.cmake
@@ -152,3 +152,20 @@ function(ly_install_run_code CODE)
)
endfunction()
+
+#! ly_install_run_script: specifies path to script to be added to the install process (will run at install time)
+#
+# \notes:
+# - refer to cmake's install(SCRIPT documentation for more information
+#
+function(ly_install_run_script SCRIPT)
+
+ if(NOT LY_INSTALL_ENABLED)
+ return()
+ endif()
+
+ install(SCRIPT ${SCRIPT}
+ COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being
+ )
+
+endfunction()
\ No newline at end of file
diff --git a/cmake/LYPython.cmake b/cmake/LYPython.cmake
index eeb9f97a55..a8095fbc95 100644
--- a/cmake/LYPython.cmake
+++ b/cmake/LYPython.cmake
@@ -21,14 +21,17 @@ include(cmake/LySet.cmake)
# CMAKE_HOST_SYSTEM_NAME is "Windows", "Darwin", or "Linux" in our cases..
if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux" )
ly_set(LY_PYTHON_VERSION 3.7.10)
+ ly_set(LY_PYTHON_VERSION_MAJOR_MINOR 3.7)
ly_set(LY_PYTHON_PACKAGE_NAME python-3.7.10-rev2-linux)
ly_set(LY_PYTHON_PACKAGE_HASH 6b9cf455e6190ec38836194f4454bb9db6bfc6890b4baff185cc5520aa822f05)
elseif (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin" )
ly_set(LY_PYTHON_VERSION 3.7.10)
+ ly_set(LY_PYTHON_VERSION_MAJOR_MINOR 3.7)
ly_set(LY_PYTHON_PACKAGE_NAME python-3.7.10-rev1-darwin)
ly_set(LY_PYTHON_PACKAGE_HASH 3f65801894e4e44b5faa84dd85ef80ecd772dcf728cdd2d668a6e75978a32695)
elseif (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows" )
ly_set(LY_PYTHON_VERSION 3.7.10)
+ ly_set(LY_PYTHON_VERSION_MAJOR_MINOR 3.7)
ly_set(LY_PYTHON_PACKAGE_NAME python-3.7.10-rev2-windows)
ly_set(LY_PYTHON_PACKAGE_HASH 06d97488a2dbabe832ecfa832a42d3e8a7163ba95e975f032727331b0f49d280)
endif()
diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake
index fdd3256d78..8fb2effe29 100644
--- a/cmake/Platform/Common/Install_common.cmake
+++ b/cmake/Platform/Common/Install_common.cmake
@@ -21,15 +21,21 @@ define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET
ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core)
-cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory)
-cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory)
-
if(LY_MONOLITHIC_GAME)
set(LY_BUILD_PERMUTATION Monolithic)
else()
set(LY_BUILD_PERMUTATION Default)
endif()
+cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory)
+cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory)
+# Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target
+cmake_path(RELATIVE_PATH CMAKE_ARCHIVE_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE archive_output_directory)
+
+cmake_path(APPEND archive_output_directory "${PAL_PLATFORM_NAME}/$/${LY_BUILD_PERMUTATION}")
+cmake_path(APPEND library_output_directory "${PAL_PLATFORM_NAME}/$/${LY_BUILD_PERMUTATION}")
+cmake_path(APPEND runtime_output_directory "${PAL_PLATFORM_NAME}/$/${LY_BUILD_PERMUTATION}")
+
#! ly_setup_target: Setup the data needed to re-create the cmake target commands for a single target
function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_target_source_dir)
# De-alias target name
@@ -78,9 +84,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
endforeach()
endif()
- # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target
- cmake_path(RELATIVE_PATH CMAKE_ARCHIVE_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE archive_output_directory)
-
get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY)
if(target_runtime_output_directory)
cmake_path(RELATIVE_PATH target_runtime_output_directory BASE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_runtime_output_subdirectory)
@@ -91,10 +94,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
cmake_path(RELATIVE_PATH target_library_output_directory BASE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_library_output_subdirectory)
endif()
- cmake_path(APPEND archive_output_directory "${PAL_PLATFORM_NAME}/$/${LY_BUILD_PERMUTATION}")
- cmake_path(APPEND library_output_directory "${PAL_PLATFORM_NAME}/$/${LY_BUILD_PERMUTATION}")
- cmake_path(APPEND runtime_output_directory "${PAL_PLATFORM_NAME}/$/${LY_BUILD_PERMUTATION}")
-
if(COMMAND ly_install_target_override)
# Mac needs special handling because of a cmake issue
ly_install_target_override(TARGET ${TARGET_NAME}
@@ -372,6 +371,10 @@ function(ly_setup_o3de_install)
COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
)
+ if(COMMAND ly_post_install_steps)
+ ly_post_install_steps()
+ endif()
+
endfunction()
#! ly_setup_cmake_install: install the "cmake" folder
@@ -528,7 +531,7 @@ endfunction()"
# of baking the path. This is needed so `cmake --install --prefix ` works regardless of the CMAKE_INSTALL_PREFIX
# used to generate the solution.
# CMAKE_INSTALL_PREFIX is still used when building the INSTALL target
- set(install_output_folder "\${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${LY_BUILD_PERMUTATION}")
+ set(install_output_folder "\${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}")
set(target_file_dir "${install_output_folder}/${target_runtime_output_subdirectory}")
ly_get_runtime_dependencies(runtime_dependencies ${target})
foreach(runtime_dependency ${runtime_dependencies})
diff --git a/cmake/Platform/Common/RuntimeDependencies_common.cmake b/cmake/Platform/Common/RuntimeDependencies_common.cmake
index 95d91da7f7..60e55453f8 100644
--- a/cmake/Platform/Common/RuntimeDependencies_common.cmake
+++ b/cmake/Platform/Common/RuntimeDependencies_common.cmake
@@ -70,12 +70,23 @@ function(ly_get_runtime_dependencies ly_RUNTIME_DEPENDENCIES ly_TARGET)
# link dependencies are not runtime dependencies (we dont have anything to copy) however, we need to traverse
# them since them or some dependency downstream could have something to copy over
- foreach(link_dependency ${link_dependencies})
- if(NOT ${link_dependency} MATCHES "^::@") # Skip wraping produced when targets are not created in the same directory (https://cmake.org/cmake/help/latest/prop_tgt/LINK_LIBRARIES.html)
- unset(dependencies)
- ly_get_runtime_dependencies(dependencies ${link_dependency})
- list(APPEND all_runtime_dependencies ${dependencies})
+ foreach(link_dependency IN LISTS link_dependencies)
+ if(${link_dependency} MATCHES "^::@")
+ # Skip wraping produced when targets are not created in the same directory
+ # (https://cmake.org/cmake/help/latest/prop_tgt/LINK_LIBRARIES.html)
+ continue()
endif()
+
+ if(TARGET ${link_dependency} AND link_dependency MATCHES "^3rdParty::")
+ get_target_property(is_system_library ${link_dependency} LY_SYSTEM_LIBRARY)
+ if(is_system_library)
+ continue()
+ endif()
+ endif()
+
+ unset(dependencies)
+ ly_get_runtime_dependencies(dependencies ${link_dependency})
+ list(APPEND all_runtime_dependencies ${dependencies})
endforeach()
# For manual dependencies, we want to copy over the dependency and traverse them
diff --git a/cmake/Platform/Mac/Configurations_mac.cmake b/cmake/Platform/Mac/Configurations_mac.cmake
index 33a58dbbda..b1c50b751d 100644
--- a/cmake/Platform/Mac/Configurations_mac.cmake
+++ b/cmake/Platform/Mac/Configurations_mac.cmake
@@ -29,9 +29,7 @@ else()
endif()
# Signing
-# The "-o linker-signed" flag is required as a work-around for the following CMake issue:
-# https://gitlab.kitware.com/cmake/cmake/-/issues/21854
-ly_set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--deep -o linker-signed")
+ly_set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--deep")
# Generate scheme files for Xcode
ly_set(CMAKE_XCODE_GENERATE_SCHEME TRUE)
diff --git a/cmake/Platform/Mac/InstallUtils_mac.cmake.in b/cmake/Platform/Mac/InstallUtils_mac.cmake.in
new file mode 100644
index 0000000000..de6d9ddf65
--- /dev/null
+++ b/cmake/Platform/Mac/InstallUtils_mac.cmake.in
@@ -0,0 +1,168 @@
+#
+# 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
+#
+#
+
+function(fixup_qt_framework lib_name framework_path)
+
+ file(REMOVE_RECURSE
+ ${framework_path}/Headers
+ ${framework_path}/Resources
+ ${framework_path}/${lib_name}
+ ${framework_path}/Versions/Current
+ ${framework_path}/Versions/5/Headers
+ )
+
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink 5 Current
+ WORKING_DIRECTORY ${framework_path}/Versions
+ )
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/${lib_name} ${lib_name}
+ WORKING_DIRECTORY ${framework_path}
+ )
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Resources Resources
+ WORKING_DIRECTORY ${framework_path}
+ )
+
+endfunction()
+
+function(fixup_python_framework framework_path)
+
+ file(REMOVE_RECURSE
+ ${framework_path}/Versions/Current
+ ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/Headers
+ ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/Python
+ ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/python@LY_PYTHON_VERSION_MAJOR_MINOR@/test
+ ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/python@LY_PYTHON_VERSION_MAJOR_MINOR@/site-packages/scipy/io/tests
+ ${framework_path}/Python
+ ${framework_path}/Resources
+ ${framework_path}/Headers
+ )
+
+ file(GLOB_RECURSE exe_file_list "${framework_path}/**/*.exe")
+ if(exe_file_list)
+ file(REMOVE_RECURSE ${exe_file_list})
+ endif()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink include/python@LY_PYTHON_VERSION_MAJOR_MINOR@m Headers
+ WORKING_DIRECTORY ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@
+ )
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink @LY_PYTHON_VERSION_MAJOR_MINOR@ Current
+ WORKING_DIRECTORY ${framework_path}/Versions/
+ )
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Python Python
+ WORKING_DIRECTORY ${framework_path}
+ )
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Headers Headers
+ WORKING_DIRECTORY ${framework_path}
+ )
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Resources Resources
+ WORKING_DIRECTORY ${framework_path}
+ )
+ file(CHMOD ${framework_path}/Versions/Current/Python
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+ )
+
+endfunction()
+
+function(codesign_file file entitlement_file)
+
+ if (NOT @LY_ENABLE_HARDENED_RUNTIME@)
+ return()
+ endif()
+
+ if(EXISTS ${entitlement_file})
+
+ execute_process(COMMAND "/usr/bin/codesign" "--force" "--sign" "@LY_CODE_SIGN_IDENTITY@" "--deep" "-o" "runtime" "--timestamp" "--entitlements" "${entitlement_file}" "${file}"
+ TIMEOUT 300
+ OUTPUT_VARIABLE codesign_out
+ RESULT_VARIABLE codesign_ret
+ )
+ else()
+ execute_process(COMMAND "/usr/bin/codesign" "--force" "--sign" "@LY_CODE_SIGN_IDENTITY@" "--deep" "-o" "runtime" "--timestamp" "${file}"
+ TIMEOUT 300
+ OUTPUT_VARIABLE codesign_out
+ RESULT_VARIABLE codesign_ret
+ )
+ endif()
+
+ if(NOT ${codesign_ret} EQUAL "0")
+ message(FATAL_ERROR "Codesign operation for ${file_path} returned ${codesign_ret} with message ${codesign_out}")
+ endif()
+
+endfunction()
+
+function(codesign_python_framework_binaries framework_path)
+
+ if (NOT @LY_ENABLE_HARDENED_RUNTIME@)
+ return()
+ endif()
+
+ # The codesign "--deep" flag will only codesign binaries in folders with specific names.
+ # We need to codesign all the binaries that the "--deep" flag will miss.
+ file(GLOB_RECURSE files
+ LIST_DIRECTORIES false
+ "${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/bin/**"
+ "${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/**"
+ "${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/Resources/**")
+
+ foreach(file ${files})
+ if(NOT EXISTS ${file})
+ file(REMOVE ${file})
+ continue()
+ endif()
+ cmake_path(SET path_var "${file}")
+ cmake_path(GET path_var EXTENSION LAST_ONLY extension)
+ set(should_codesign FALSE)
+ set(extension_skip_list ".dylib" ".so" ".7m")
+ if (NOT extension)
+ set(should_codesign TRUE)
+ elseif(extension IN_LIST extension_skip_list)
+ set(should_codesign TRUE)
+ endif()
+ if(${should_codesign})
+ codesign_file("${file}" "@LY_ROOT_FOLDER@/python/Platform/Mac/PythonEntitlements.plist")
+ endif()
+ endforeach()
+
+endfunction()
+
+function(ly_copy source_file target_directory)
+
+ if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]")
+
+ # fixup origin to copy the whole Framework folder
+ string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}")
+
+ endif()
+ get_filename_component(target_filename "${source_file}" NAME)
+ file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN)
+
+ # Our Qt and Python frameworks aren't in the correct bundle format to be codesigned.
+ if("${target_filename}" MATCHES "(Qt[^.]+)\\.[Ff]ramework")
+ fixup_qt_framework(${CMAKE_MATCH_1} "${target_directory}/${target_filename}")
+ # For some Qt frameworks(QtCore), signing the bundle doesn't work because of bundle
+ # format issues(despite the fixes above). But once we've patched the framework above, there's
+ # only one executable that we need to sign so we can do it directly.
+ set(target_filename "${target_filename}/Versions/5/${CMAKE_MATCH_1}")
+ elseif("${target_filename}" MATCHES "Python.framework")
+ fixup_python_framework("${target_directory}/${target_filename}")
+ codesign_python_framework_binaries("${target_directory}/${target_filename}")
+ endif()
+ codesign_file("${target_directory}/${target_filename}" "none")
+
+endfunction()
+
+function(ly_download_and_codesign_sdk_python)
+ execute_process(COMMAND ${CMAKE_COMMAND} -DPAL_PLATFORM_NAME=Mac -DLY_3RDPARTY_PATH=${CMAKE_INSTALL_PREFIX}/python -P ${CMAKE_INSTALL_PREFIX}/python/get_python.cmake)
+ fixup_python_framework(${CMAKE_INSTALL_PREFIX}/python/runtime/@LY_PYTHON_PACKAGE_NAME@/Python.framework)
+ codesign_python_framework_binaries(${CMAKE_INSTALL_PREFIX}/python/runtime/@LY_PYTHON_PACKAGE_NAME@/Python.framework)
+ codesign_file(${CMAKE_INSTALL_PREFIX}/python/runtime/@LY_PYTHON_PACKAGE_NAME@/Python.framework @LY_ROOT_FOLDER@/python/Platform/Mac/PythonEntitlements.plist)
+endfunction()
+
+function(ly_codesign_sdk)
+ codesign_file(${LY_INSTALL_PATH_ORIGINAL}/O3DE_SDK.app "none")
+endfunction()
+
+
diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake
index 8f07b1bfde..bdc2300131 100644
--- a/cmake/Platform/Mac/Install_mac.cmake
+++ b/cmake/Platform/Mac/Install_mac.cmake
@@ -6,6 +6,8 @@
#
#
+include(cmake/Platform/Common/Install_common.cmake)
+
# This is used to generate a setreg file which will be placed inside the bundle
# for targets that request it(eg. AssetProcessor/Editor). This is the relative path
# to the bundle from the installed engine's root. This will be used to compute the
@@ -16,7 +18,7 @@ set(installed_binaries_path_template [[
"AzCore": {
"Runtime": {
"FilePaths": {
- "InstalledBinariesFolder": "bin/Mac/$"
+ "InstalledBinariesFolder": "@runtime_output_directory@"
}
}
}
@@ -24,15 +26,20 @@ set(installed_binaries_path_template [[
}]]
)
-unset(target_conf_dir)
-foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
- string(TOUPPER ${conf} UCONF)
- string(APPEND target_conf_dir $<$:${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${UCONF}}>)
-endforeach()
+# This setreg file will be used by all of our installed app bundles to locate installed
+# runtime dependencies. It contains the path to binary install directory relative to
+# the installed engine root.
+string(CONFIGURE "${installed_binaries_path_template}" configured_setreg_file)
+file(GENERATE
+ OUTPUT ${CMAKE_BINARY_DIR}/runtime_install/$/BinariesInstallPath.setreg
+ CONTENT "${configured_setreg_file}"
+)
-set(installed_binaries_setreg_path ${target_conf_dir}/Registry/installed_binaries_path.setreg)
-
-file(GENERATE OUTPUT ${installed_binaries_setreg_path} CONTENT ${installed_binaries_path_template})
+# ly_install_run_script isn't defined yet so we use install(SCRIPT) directly.
+# This needs to be done here because it needs to update the install prefix
+# before cmake does anything else in the install process.
+configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake @ONLY)
+install(SCRIPT ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})
#! ly_install_target_override: Mac specific target installation
function(ly_install_target_override)
@@ -70,33 +77,62 @@ function(ly_install_target_override)
COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
)
+ set(install_relative_binaries_path "${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR}")
+
if (${is_bundle})
set_property(TARGET ${ly_platform_install_target_TARGET} PROPERTY RESOURCE ${cached_resources_dir})
+ set(runtime_output_filename "$.app")
+ else()
+ set(runtime_output_filename "$")
+ endif()
+
+ get_target_property(target_type ${ly_platform_install_target_TARGET} TYPE)
+ if(target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS)
+ get_target_property(entitlement_file ${ly_platform_install_target_TARGET} ENTITLEMENT_FILE_PATH)
+ if (NOT entitlement_file)
+ set(entitlement_file "none")
+ endif()
+
+ ly_file_read(${LY_ROOT_FOLDER}/cmake/Platform/Mac/runtime_install_mac.cmake.in template_file)
+ string(CONFIGURE "${template_file}" configured_template_file @ONLY)
+ file(GENERATE
+ OUTPUT ${CMAKE_BINARY_DIR}/runtime_install/$/${ly_platform_install_target_TARGET}.cmake
+ CONTENT "${configured_template_file}"
+ )
endif()
-endfunction()
-
-#! ly_install_add_install_path_setreg: Adds the install path setreg file as a dependency
-function(ly_install_add_install_path_setreg NAME)
- set_property(TARGET ${NAME} APPEND PROPERTY INTERFACE_LY_TARGET_FILES "${installed_binaries_setreg_path}\nRegistry")
endfunction()
#! ly_install_code_function_override: Mac specific copy function to handle frameworks
function(ly_install_code_function_override)
- install(CODE
-"function(ly_copy source_file target_directory)
- if(\"\${source_file}\" MATCHES \"\\\\.[Ff]ramework[^\\\\.]\")
-
- # fixup origin to copy the whole Framework folder
- string(REGEX REPLACE \"(.*\\\\.[Ff]ramework).*\" \"\\\\1\" source_file \"\${source_file}\")
- get_filename_component(target_filename \"\${source_file}\" NAME)
-
- endif()
- file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS})
-endfunction()"
- COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
- )
+ configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/InstallUtils_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake @ONLY)
+ ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake)
+
+endfunction()
+
+#! ly_post_install_steps: Any additional platform specific post install steps
+function(ly_post_install_steps)
+
+ # On Mac, after CMake is done installing, the code signatures on all our built binaries will be invalid.
+ # We need to now codesign each dynamic library, executable, and app bundle. It's specific to each target
+ # because there could potentially be different entitlements for different targets.
+ get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS)
+ foreach(alias_target IN LISTS all_targets)
+ ly_de_alias_target(${alias_target} target)
+ # Exclude targets that dont produce runtime outputs
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS)
+ continue()
+ endif()
+
+ ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/$/${target}.cmake)
+ endforeach()
+
+ ly_install_run_code("
+ ly_download_and_codesign_sdk_python()
+ ly_codesign_sdk()
+ set(CMAKE_INSTALL_PREFIX ${LY_INSTALL_PATH_ORIGINAL})
+ ")
endfunction()
-include(cmake/Platform/Common/Install_common.cmake)
diff --git a/cmake/Platform/Mac/LYWrappers_mac.cmake b/cmake/Platform/Mac/LYWrappers_mac.cmake
index 578f6fe041..245d3bb7c1 100644
--- a/cmake/Platform/Mac/LYWrappers_mac.cmake
+++ b/cmake/Platform/Mac/LYWrappers_mac.cmake
@@ -6,6 +6,16 @@
#
#
+set(LY_ENABLE_HARDENED_RUNTIME OFF CACHE BOOL "Enable hardened runtime capability for Mac builds. This should be ON when building the engine for notarization/distribution.")
+
+define_property(TARGET PROPERTY ENTITLEMENT_FILE_PATH
+ BRIEF_DOCS "Path to the entitlement file"
+ FULL_DOCS [[
+ On MacOS, entitlements are used to grant certain privileges
+ to applications at runtime. Use this propery to specify the
+ path to a .plist file containing entitlements.
+ ]]
+)
function(ly_apply_platform_properties target)
@@ -14,6 +24,18 @@ function(ly_apply_platform_properties target)
INSTALL_RPATH "@executable_path/;@executable_path/../Frameworks"
)
+ get_property(is_imported TARGET ${target} PROPERTY IMPORTED)
+ if((NOT is_imported) AND (LY_ENABLE_HARDENED_RUNTIME))
+ get_property(target_type TARGET ${target} PROPERTY TYPE)
+ set(runtime_types_list "MODULE_LIBRARY" "SHARED_LIBRARY" "EXECUTABLE")
+ if (target_type IN_LIST runtime_types_list)
+ set_target_properties(${target} PROPERTIES
+ XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES
+ XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS NO
+ )
+ endif()
+ endif()
+
endfunction()
diff --git a/cmake/Platform/Mac/PAL_mac.cmake b/cmake/Platform/Mac/PAL_mac.cmake
index b415daf44a..065b35d69c 100644
--- a/cmake/Platform/Mac/PAL_mac.cmake
+++ b/cmake/Platform/Mac/PAL_mac.cmake
@@ -39,3 +39,6 @@ set(LY_ASSET_DEPLOY_ASSET_TYPE "mac" CACHE STRING "Set the asset type for deploy
# Set the python cmd tool
ly_set(LY_PYTHON_CMD ${CMAKE_CURRENT_SOURCE_DIR}/python/python.sh)
+
+# Only x86_64 is currently supported on Mac
+ly_set(CMAKE_OSX_ARCHITECTURES "x86_64")
diff --git a/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in b/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in
new file mode 100644
index 0000000000..5033aadd6e
--- /dev/null
+++ b/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in
@@ -0,0 +1,39 @@
+#
+# 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
+#
+#
+
+cmake_minimum_required(VERSION 3.20)
+
+# The O3DE SDK will be shipped as an app bundle. So we create an O3DE_SDK.app directory
+# and install SDK into the app's Contents/Engine directory.
+set(LY_INSTALL_PATH_ORIGINAL ${CMAKE_INSTALL_PREFIX})
+
+file(INSTALL @LY_ROOT_FOLDER@/Code/Tools/BundleLauncher/info.plist
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents
+)
+
+# This SDK launcher will install python site-packages and then launch the ProjectManager
+# when a user double clicks on the SDK from Finder. We're only going to need one version
+# of the SDK launcher regardless of what configs of the engine are installed.
+if (EXISTS @CMAKE_BINARY_DIR@/bin/profile/O3DE_SDK)
+ set(sdk_launcher_config profile)
+elseif (EXISTS @CMAKE_BINARY_DIR@/bin/debug/O3DE_SDK)
+ set(sdk_launcher_config debug)
+elseif (EXISTS @CMAKE_BINARY_DIR@/bin/release/O3DE_SDK)
+ set(sdk_launcher_config release)
+endif()
+file(INSTALL @CMAKE_BINARY_DIR@/bin/${sdk_launcher_config}/O3DE_SDK
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/MacOS
+ USE_SOURCE_PERMISSIONS
+)
+file(INSTALL @CMAKE_BINARY_DIR@/runtime_install/${sdk_launcher_config}/BinariesInstallPath.setreg
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/MacOS/Registry
+)
+
+# We need to update the CMAKE_INSTALL_PREFIX so that the engine is installed inside the app bundle.
+file(MAKE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/Engine)
+set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/Engine)
\ No newline at end of file
diff --git a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in
index d65578f82a..11551f608f 100644
--- a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in
+++ b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in
@@ -73,8 +73,8 @@ function(ly_copy source_file target_directory)
return()
endif()
- # fixup the destination so it ends up in Contents/Plugins
- string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/plugins" target_directory "${target_directory}")
+ # fixup the destination so it ends up in Contents/PlugIns
+ string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/PlugIns" target_directory "${target_directory}")
set(local_plugin_dirs ${plugin_dirs})
list(APPEND local_plugin_dirs "${target_directory}")
@@ -212,7 +212,6 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS")
file(REMOVE_RECURSE ${remove_file_list})
endif()
-
endif()
else() # Non-bundle case
diff --git a/cmake/Platform/Mac/runtime_install_mac.cmake.in b/cmake/Platform/Mac/runtime_install_mac.cmake.in
new file mode 100644
index 0000000000..65b1ede77b
--- /dev/null
+++ b/cmake/Platform/Mac/runtime_install_mac.cmake.in
@@ -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
+#
+#
+
+cmake_path(SET file_path "${CMAKE_INSTALL_PREFIX}/@install_relative_binaries_path@/@runtime_output_filename@")
+cmake_path(GET file_path EXTENSION LAST_ONLY file_ext)
+
+if(file_ext STREQUAL .app)
+
+ file(INSTALL @CMAKE_BINARY_DIR@/runtime_install/$/BinariesInstallPath.setreg
+ DESTINATION ${file_path}/Contents/MacOS/Registry
+ )
+
+ if(EXISTS "${file_path}/Contents/Frameworks/Python.framework")
+ codesign_python_framework_binaries("${file_path}/Contents/Frameworks/Python.framework")
+ endif()
+
+else()
+
+ find_program(LY_INSTALL_NAME_TOOL install_name_tool)
+ if (NOT LY_INSTALL_NAME_TOOL)
+ message(FATAL_ERROR "Unable to locate 'install_name_tool'")
+ endif()
+
+ execute_process(COMMAND
+ ${LY_INSTALL_NAME_TOOL} -add_rpath @loader_path ${file_path})
+
+endif()
+
+codesign_file("${file_path}" "@entitlement_file@")
diff --git a/python/Platform/Mac/PythonEntitlements.plist b/python/Platform/Mac/PythonEntitlements.plist
new file mode 100644
index 0000000000..ed4892befa
--- /dev/null
+++ b/python/Platform/Mac/PythonEntitlements.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.cs.disable-library-validation
+
+ com.apple.security.cs.allow-unsigned-executable-memory
+
+
+
diff --git a/python/get_python.sh b/python/get_python.sh
index 248a0790fc..e8d35a311e 100755
--- a/python/get_python.sh
+++ b/python/get_python.sh
@@ -30,7 +30,8 @@ cd $DIR
python_exitcode=$?
if [ $python_exitcode == 0 ]; then
echo get_python.sh: Python is already downloaded: $(./python.sh --version)
- $DIR/pip.sh install -r $DIR/requirements.txt --quiet --disable-pip-version-check
+ $DIR/pip.sh install -r $DIR/requirements.txt --disable-pip-version-check --no-warn-script-location
+ $DIR/pip.sh install -e $DIR/../scripts/o3de --no-deps --disable-pip-version-check --no-warn-script-location
exit 0
fi
if [[ "$OSTYPE" = *"darwin"* ]];
@@ -73,5 +74,6 @@ if [ $retVal -ne 0 ]; then
fi
echo installing via pip...
-$DIR/pip.sh install -r $DIR/requirements.txt --disable-pip-version-check
+$DIR/pip.sh install -r $DIR/requirements.txt --disable-pip-version-check --no-warn-script-location
+$DIR/pip.sh install -e $DIR/../scripts/o3de --no-deps --disable-pip-version-check --no-warn-script-location
exit $?
diff --git a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt
index 21c4755a2e..2cbbe58b38 100644
--- a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt
+++ b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt
@@ -13,6 +13,8 @@ libxcb-xinput0 # For Qt plugins at runtime
libfontconfig1-dev # For Qt plugins at runtime
libcurl4-openssl-dev # For HttpRequestor
libsdl2-dev # for WWise/Audio
-libxkbcommon-dev
+libxcb-xkb-dev # For xcb keyboard input
+libxkbcommon-x11-dev # For xcb keyboard input
+libxkbcommon-dev # For xcb keyboard input
zlib1g-dev
mesa-common-dev