diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
new file mode 100644
index 0000000000..b899d7dcde
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
@@ -0,0 +1,102 @@
+"""
+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
+
+Hydra script that is used to create a new level with a default rendering setup.
+After the level is setup, screenshots are diffed against golden images are used to verify pass/fail results of the test.
+
+See the run() function for more in-depth test info.
+"""
+
+import os
+import sys
+
+import azlmbr.legacy.general as general
+
+sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
+
+import editor_python_test_tools.hydra_editor_utils as hydra
+from editor_python_test_tools.editor_test_helper import EditorTestHelper
+from atom_renderer.atom_utils.benchmark_utils import BenchmarkHelper
+
+SCREEN_WIDTH = 1280
+SCREEN_HEIGHT = 720
+DEGREE_RADIAN_FACTOR = 0.0174533
+
+helper = EditorTestHelper(log_prefix="Test_Atom_BasicLevelSetup")
+
+
+def run():
+ """
+ 1. View -> Layouts -> Restore Default Layout, sets the viewport to ratio 16:9 @ 1280 x 720
+ 2. Runs console command r_DisplayInfo = 0
+ 3. Opens AtomFeatureIntegrationBenchmark level
+ 4. Initializes benchmark helper with benchmark name to capture benchmark metadata.
+ 5. Idles for 100 frames, then collects pass timings for 100 frames.
+ :return: None
+ """
+ def initial_viewport_setup(screen_width, screen_height):
+ general.set_viewport_size(screen_width, screen_height)
+ general.update_viewport()
+ helper.wait_for_condition(
+ function=lambda: helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1)
+ and helper.isclose(a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1),
+ timeout_in_seconds=4.0
+ )
+ result = helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) and helper.isclose(
+ a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1)
+ general.log(general.get_viewport_size().x)
+ general.log(general.get_viewport_size().y)
+ general.log(general.get_viewport_size().z)
+ general.log(f"Viewport is set to the expected size: {result}")
+ general.run_console("r_DisplayInfo = 0")
+
+ def after_level_load():
+ """Function to call after creating/opening a level to ensure it loads."""
+ # Give everything a second to initialize.
+ general.idle_enable(True)
+ general.idle_wait(1.0)
+ general.update_viewport()
+ general.idle_wait(0.5) # half a second is more than enough for updating the viewport.
+
+ # Close out problematic windows, FPS meters, and anti-aliasing.
+ if general.is_helpers_shown(): # Turn off the helper gizmos if visible
+ general.toggle_helpers()
+ general.idle_wait(1.0)
+ if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus.
+ general.close_pane("Error Report")
+ if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus.
+ general.close_pane("Error Log")
+ general.idle_wait(1.0)
+ general.run_console("r_displayInfo=0")
+ general.run_console("r_antialiasingmode=0")
+ general.idle_wait(1.0)
+
+ return True
+
+ # Wait for Editor idle loop before executing Python hydra scripts.
+ general.idle_enable(True)
+
+ general.open_level_no_prompt("AtomFeatureIntegrationBenchmark")
+
+ # Basic setup after opening level.
+ after_level_load()
+ initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT)
+
+ general.enter_game_mode()
+ general.idle_wait(1.0)
+ helper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=2.0)
+ benchmarker = BenchmarkHelper("AtomFeatureIntegrationBenchmark")
+ benchmarker.capture_benchmark_metadata()
+ general.idle_wait_frames(100)
+ for i in range(1, 101):
+ benchmarker.capture_pass_timestamp(i)
+ general.exit_game_mode()
+ helper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=2.0)
+ general.log("Capturing complete.")
+
+
+if __name__ == "__main__":
+ run()
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py
new file mode 100644
index 0000000000..21c7489ed3
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py
@@ -0,0 +1,84 @@
+"""
+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
+"""
+import azlmbr.atom
+import azlmbr.legacy.general as general
+
+FOLDER_PATH = '@user@/Scripts/PerformanceBenchmarks'
+METADATA_FILE = 'benchmark_metadata.json'
+
+class BenchmarkHelper(object):
+ """
+ A helper to capture benchmark data.
+ """
+ def __init__(self, benchmark_name):
+ super().__init__()
+ self.benchmark_name = benchmark_name
+ self.output_path = f'{FOLDER_PATH}/{benchmark_name}'
+ self.done = False
+ self.capturedData = False
+ self.max_frames_to_wait = 200
+
+ def capture_benchmark_metadata(self):
+ """
+ Capture benchmark metadata and block further execution until it has been written to the disk.
+ """
+ self.handler = azlmbr.atom.ProfilingCaptureNotificationBusHandler()
+ self.handler.connect()
+ self.handler.add_callback('OnCaptureBenchmarkMetadataFinished', self.on_data_captured)
+
+ self.done = False
+ self.capturedData = False
+ success = azlmbr.atom.ProfilingCaptureRequestBus(
+ azlmbr.bus.Broadcast, "CaptureBenchmarkMetadata", self.benchmark_name, f'{self.output_path}/{METADATA_FILE}'
+ )
+ if success:
+ self.wait_until_data()
+ general.log('Benchmark metadata captured.')
+ else:
+ general.log('Failed to capture benchmark metadata.')
+ return self.capturedData
+
+ def capture_pass_timestamp(self, frame_number):
+ """
+ Capture pass timestamps and block further execution until it has been written to the disk.
+ """
+ self.handler = azlmbr.atom.ProfilingCaptureNotificationBusHandler()
+ self.handler.connect()
+ self.handler.add_callback('OnCaptureQueryTimestampFinished', self.on_data_captured)
+
+ self.done = False
+ self.capturedData = False
+ success = azlmbr.atom.ProfilingCaptureRequestBus(
+ azlmbr.bus.Broadcast, "CapturePassTimestamp", f'{self.output_path}/frame{frame_number}_timestamps.json')
+ if success:
+ self.wait_until_data()
+ general.log('Pass timestamps captured.')
+ else:
+ general.log('Failed to capture pass timestamps.')
+ return self.capturedData
+
+ def on_data_captured(self, parameters):
+ # the parameters come in as a tuple
+ if parameters[0]:
+ general.log('Captured data successfully.')
+ self.capturedData = True
+ else:
+ general.log('Failed to capture data.')
+ self.done = True
+ self.handler.disconnect()
+
+ def wait_until_data(self):
+ frames_waited = 0
+ while self.done == False:
+ general.idle_wait_frames(1)
+ if frames_waited > self.max_frames_to_wait:
+ general.log('Timed out while waiting for the data to be captured')
+ self.handler.disconnect()
+ break
+ else:
+ frames_waited = frames_waited + 1
+ general.log(f'(waited {frames_waited} frames)')
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py
index dad92d0932..ede140c075 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py
+++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py
@@ -14,6 +14,7 @@ import pytest
import ly_test_tools.environment.file_system as file_system
from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
+from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator
import editor_python_test_tools.hydra_test_utils as hydra
logger = logging.getLogger(__name__)
@@ -83,3 +84,43 @@ class TestAllComponentsIndepthTests(object):
for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
compare_screenshots(test_screenshot, golden_screenshot)
+
+@pytest.mark.parametrize('rhi', ['dx12', 'vulkan'])
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+@pytest.mark.parametrize("launcher_platform", ["windows_editor"])
+@pytest.mark.parametrize("level", ["AtomFeatureIntegrationBenchmark"])
+class TestPerformanceBenchmarkSuite(object):
+ def test_AtomFeatureIntegrationBenchmark(
+ self, request, editor, workspace, rhi, project, launcher_platform, level):
+ """
+ Please review the hydra script run by this test for more specific test info.
+ Tests the performance of the Simple level.
+ """
+ expected_lines = [
+ "Benchmark metadata captured.",
+ "Pass timestamps captured.",
+ "Capturing complete.",
+ "Captured data successfully."
+ ]
+
+ unexpected_lines = [
+ "Failed to capture data.",
+ "Failed to capture pass timestamps.",
+ "Failed to capture benchmark metadata."
+ ]
+
+ hydra.launch_and_validate_results(
+ request,
+ TEST_DIRECTORY,
+ editor,
+ "hydra_GPUTest_AtomFeatureIntegrationBenchmark.py",
+ timeout=EDITOR_TIMEOUT,
+ expected_lines=expected_lines,
+ unexpected_lines=unexpected_lines,
+ halt_on_unexpected=True,
+ cfg_args=[level],
+ null_renderer=False,
+ )
+
+ aggregator = BenchmarkDataAggregator(workspace, logger, 'periodic')
+ aggregator.upload_metrics(rhi)
diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/AtomFeatureIntegrationBenchmark.ly b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/AtomFeatureIntegrationBenchmark.ly
new file mode 100644
index 0000000000..4fc96f242b
--- /dev/null
+++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/AtomFeatureIntegrationBenchmark.ly
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5232563c3ff322669808ac4daeda3d822e4ef8c9c87db0fa245f0f9c9c34aada
+size 23379
diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/filelist.xml b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/filelist.xml
new file mode 100644
index 0000000000..15b79f5e4f
--- /dev/null
+++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/filelist.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/level.pak b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/level.pak
new file mode 100644
index 0000000000..fecbc0b394
--- /dev/null
+++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/level.pak
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e075be2cb7cf5aa98e3503c1119b94c3098b35500c98c4db32d025c9e1afa52d
+size 5450
diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/tags.txt b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/tags.txt
new file mode 100644
index 0000000000..a5e0705349
--- /dev/null
+++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/tags.txt
@@ -0,0 +1,12 @@
+495.045,510.96,35.8437,-0.166,0,-1.82124
+4.79827,4.71364,64.7838,-1.41886,0,2.48964
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt
index fe694f165a..fca16a2093 100644
--- a/Code/Editor/CMakeLists.txt
+++ b/Code/Editor/CMakeLists.txt
@@ -163,6 +163,8 @@ ly_add_target(
editor_files.cmake
PLATFORM_INCLUDE_FILES
Platform/${PAL_PLATFORM_NAME}/editor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
+ TARGET_PROPERTIES
+ LY_INSTALL_GENERATE_RUN_TARGET TRUE
BUILD_DEPENDENCIES
PRIVATE
3rdParty::Qt::Core
diff --git a/Code/Editor/Core/QtEditorApplication.cpp b/Code/Editor/Core/QtEditorApplication.cpp
index 46e789cd7c..5a4763d8e8 100644
--- a/Code/Editor/Core/QtEditorApplication.cpp
+++ b/Code/Editor/Core/QtEditorApplication.cpp
@@ -415,33 +415,37 @@ namespace Editor
}
// Ensure that the Windows WM_INPUT messages get passed through to the AzFramework input system.
- // These events are now consumed both in and out of game mode.
- if (msg->message == WM_INPUT)
+ // These events are only broadcast in game mode. In Editor mode, RenderViewportWidget creates synthetic
+ // keyboard and mouse events via Qt.
+ if (GetIEditor()->IsInGameMode())
{
- UINT rawInputSize;
- const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER);
- GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, NULL, &rawInputSize, rawInputHeaderSize);
-
- AZStd::array rawInputBytesArray;
- LPBYTE rawInputBytes = rawInputBytesArray.data();
-
- const UINT bytesCopied = GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
- CRY_ASSERT(bytesCopied == rawInputSize);
-
- RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
- CRY_ASSERT(rawInput);
-
- AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput);
-
- return false;
- }
- else if (msg->message == WM_DEVICECHANGE)
- {
- if (msg->wParam == 0x0007) // DBT_DEVNODES_CHANGED
+ if (msg->message == WM_INPUT)
{
- AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputDeviceChangeEvent);
+ UINT rawInputSize;
+ const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER);
+ GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, NULL, &rawInputSize, rawInputHeaderSize);
+
+ AZStd::array rawInputBytesArray;
+ LPBYTE rawInputBytes = rawInputBytesArray.data();
+
+ const UINT bytesCopied = GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
+ CRY_ASSERT(bytesCopied == rawInputSize);
+
+ RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
+ CRY_ASSERT(rawInput);
+
+ AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput);
+
+ return false;
+ }
+ else if (msg->message == WM_DEVICECHANGE)
+ {
+ if (msg->wParam == 0x0007) // DBT_DEVNODES_CHANGED
+ {
+ AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputDeviceChangeEvent);
+ }
+ return true;
}
- return true;
}
return false;
diff --git a/Code/Editor/Util/AffineParts.h b/Code/Editor/Util/AffineParts.h
index cb2c609ecd..a2e3d2c79b 100644
--- a/Code/Editor/Util/AffineParts.h
+++ b/Code/Editor/Util/AffineParts.h
@@ -20,11 +20,11 @@ struct AffineParts
Vec3 scale; //!< Stretch factors.
float fDet; //!< Sign of determinant.
- /** Decompose matrix to its affnie parts.
+ /** Decompose matrix to its affine parts.
*/
void Decompose(const Matrix34& mat);
- /** Decompose matrix to its affnie parts.
+ /** Decompose matrix to its affine parts.
Assume there`s no stretch rotation.
*/
void SpectralDecompose(const Matrix34& mat);
diff --git a/Code/Framework/AzAutoGen/AzAutoGen.props b/Code/Framework/AzAutoGen/AzAutoGen.props
deleted file mode 100644
index 2f809d03a6..0000000000
--- a/Code/Framework/AzAutoGen/AzAutoGen.props
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
- True
-
-
diff --git a/Code/Framework/AzCore/AzCore/EBus/Internal/CallstackEntry.h b/Code/Framework/AzCore/AzCore/EBus/Internal/CallstackEntry.h
index 982040ee2f..bcda78aef8 100644
--- a/Code/Framework/AzCore/AzCore/EBus/Internal/CallstackEntry.h
+++ b/Code/Framework/AzCore/AzCore/EBus/Internal/CallstackEntry.h
@@ -84,7 +84,7 @@ namespace AZ
else
{
AZ::Debug::Trace::Instance().Assert(__FILE__, __LINE__, AZ_FUNCTION_SIGNATURE,
- "Bus has multiple threads in its callstack records. Configure MutexType on the bus, or don't send to it from multiple threads");
+ "Bus %s has multiple threads in its callstack records. Configure MutexType on the bus, or don't send to it from multiple threads", BusType::GetName());
}
}
diff --git a/Code/Framework/AzCore/AzCore/EBus/Policies.h b/Code/Framework/AzCore/AzCore/EBus/Policies.h
index 0217874416..db11043ef8 100644
--- a/Code/Framework/AzCore/AzCore/EBus/Policies.h
+++ b/Code/Framework/AzCore/AzCore/EBus/Policies.h
@@ -268,7 +268,7 @@ namespace AZ
m_messages.pop();
if (numMessages == 1)
{
- m_messages.get_container().clear(); // If it was the last message, free all memory.
+ m_messages = {};
}
}
//////////////////////////////////////////////////////////////////////////
@@ -280,7 +280,7 @@ namespace AZ
void Clear()
{
AZStd::lock_guard lock(m_messagesMutex);
- m_messages.get_container().clear();
+ m_messages = {};
}
void SetActive(bool isActive)
@@ -289,7 +289,7 @@ namespace AZ
m_isActive = isActive;
if (!m_isActive)
{
- m_messages.get_container().clear();
+ m_messages = {};
}
};
diff --git a/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl b/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl
index 35a2d64c0d..9eb65dec76 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl
+++ b/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl
@@ -42,8 +42,6 @@ namespace AZStd
class unordered_multiset;
template
class bitset;
- template*/ >
- class stack;
template
class intrusive_ptr;
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
index 74038c8aed..6b89b8c044 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
@@ -57,6 +57,7 @@ namespace AZ::Internal
// and avoid all this logic.
using namespace AZ::SettingsRegistryMergeUtils;
+ using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
AZ::IO::FixedMaxPath engineRoot;
if (auto engineManifestPath = AZ::Utils::GetEngineManifestPath(); !engineManifestPath.empty())
@@ -72,45 +73,16 @@ namespace AZ::Internal
struct EngineInfo
{
AZ::IO::FixedMaxPath m_path;
- AZ::SettingsRegistryInterface::FixedValueString m_moniker;
+ FixedValueString m_moniker;
};
struct EnginePathsVisitor : public AZ::SettingsRegistryInterface::Visitor
{
void Visit(
- [[maybe_unused]] AZStd::string_view path, [[maybe_unused]] AZStd::string_view valueName,
+ [[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName,
[[maybe_unused]] AZ::SettingsRegistryInterface::Type type, AZStd::string_view value) override
{
- m_enginePaths.emplace_back(EngineInfo{AZ::IO::FixedMaxPath{value}.LexicallyNormal(), {}});
- }
-
- AZ::SettingsRegistryInterface::VisitResponse Traverse(
- [[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName,
- AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type type) override
- {
- auto response = AZ::SettingsRegistryInterface::VisitResponse::Continue;
- if (action == AZ::SettingsRegistryInterface::VisitAction::Begin)
- {
- if (type == AZ::SettingsRegistryInterface::Type::Array)
- {
- if (valueName.compare("engines") != 0)
- {
- response = AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- }
- }
- else if (action == AZ::SettingsRegistryInterface::VisitAction::Value)
- {
- if (type == AZ::SettingsRegistryInterface::Type::String)
- {
- if (valueName.compare("path") != 0)
- {
- response = AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- }
- }
-
- return response;
+ m_enginePaths.emplace_back(EngineInfo{ AZ::IO::FixedMaxPath{value}.LexicallyNormal(), FixedValueString{valueName} });
}
AZStd::vector m_enginePaths{};
@@ -119,11 +91,11 @@ namespace AZ::Internal
EnginePathsVisitor pathVisitor;
if (manifestLoaded)
{
- auto enginePathsKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engines", EngineManifestRootKey);
+ auto enginePathsKey = FixedValueString::format("%s/engines_path", EngineManifestRootKey);
settingsRegistry.Visit(pathVisitor, enginePathsKey);
}
- const auto engineMonikerKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engine_name", EngineSettingsRootKey);
+ const auto engineMonikerKey = FixedValueString::format("%s/engine_name", EngineSettingsRootKey);
AZStd::set projectPathsNotFound;
@@ -135,7 +107,15 @@ namespace AZ::Internal
if (settingsRegistry.MergeSettingsFile(
engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, EngineSettingsRootKey))
{
- settingsRegistry.Get(engineInfo.m_moniker, engineMonikerKey);
+ FixedValueString engineName;
+ settingsRegistry.Get(engineName, engineMonikerKey);
+ AZ_Warning("SettingsRegistryMergeUtils",engineInfo.m_moniker == engineName,
+ R"(The engine name key "%s" mapped to engine path "%s" within the global manifest of "%s")"
+ R"( does not match the "engine_name" field "%s" in the engine.json)" "\n"
+ "This engine should be re-registered.",
+ engineInfo.m_moniker.c_str(), engineInfo.m_path.c_str(), engineManifestPath.c_str(),
+ engineName.c_str())
+ engineInfo.m_moniker = engineName;
}
}
diff --git a/Code/Framework/AzCore/AzCore/std/containers/queue.h b/Code/Framework/AzCore/AzCore/std/containers/queue.h
index f1df1dd787..8026ebe943 100644
--- a/Code/Framework/AzCore/AzCore/std/containers/queue.h
+++ b/Code/Framework/AzCore/AzCore/std/containers/queue.h
@@ -5,206 +5,17 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-#ifndef AZSTD_QUEUE_H
-#define AZSTD_QUEUE_H 1
+#pragma once
#include
#include
#include
+#include
namespace AZStd
{
- /**
- * FIFO queue complaint with \ref CStd (23.2.3.1)
- * The only extension we have is that we allow access
- * to the underlying container via: get_container function.
- * Check the queue \ref AZStdExamples.
- */
- template >
- class queue
- {
- enum
- {
- CONTAINER_VERSION = 1
- };
- public:
- typedef queue this_type;
- typedef Container container_type;
- typedef typename Container::value_type value_type;
- typedef typename Container::size_type size_type;
- typedef typename Container::reference reference;
- typedef typename Container::const_reference const_reference;
-
- AZ_FORCE_INLINE queue() {}
-
- AZ_FORCE_INLINE explicit queue(const container_type& container)
- : m_container(container) {}
- AZ_FORCE_INLINE bool empty() const { return m_container.empty(); }
- AZ_FORCE_INLINE size_type size() const { return m_container.size(); }
- AZ_FORCE_INLINE reference front() { return m_container.front(); }
- AZ_FORCE_INLINE const_reference front() const { return m_container.front(); }
- AZ_FORCE_INLINE reference back() { return m_container.back(); }
- AZ_FORCE_INLINE const_reference back() const { return m_container.back(); }
- AZ_FORCE_INLINE void push(const value_type& value) { m_container.push_back(value); }
- AZ_FORCE_INLINE void pop() { m_container.pop_front(); }
-
- AZ_FORCE_INLINE void push() { m_container.push_back(); }
-
- AZ_FORCE_INLINE queue(this_type&& rhs)
- : m_container(AZStd::move(rhs.m_container)) {}
- AZ_FORCE_INLINE explicit queue(Container&& container)
- : m_container(AZStd::move(container)) {}
- this_type& operator=(this_type&& rhs)
- {
- m_container = AZStd::move(rhs.m_container);
- return (*this);
- }
- void push(value_type&& value) { m_container.push_back(AZStd::move(value)); }
- template
- void emplace(Args&&... args) { m_container.emplace_back(AZStd::forward(args)...); }
- void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); }
-
- AZ_FORCE_INLINE Container& get_container() { return m_container; }
- AZ_FORCE_INLINE const Container& get_container() const { return m_container; }
-
- protected:
- Container m_container;
- };
-
- // queue TEMPLATE FUNCTIONS
- template
- AZ_FORCE_INLINE bool operator==(const AZStd::queue& left, const AZStd::queue& right)
- {
- return left.get_container() == right.get_container();
- }
-
- template
- AZ_FORCE_INLINE bool operator!=(const AZStd::queue& left, const AZStd::queue& right)
- {
- return left.get_container() != right.get_container();
- }
-
- /* template
- AZ_FORCE_INLINE bool operator<(const queue& left, const queue& right)
- {
- return left.get_container() < right.get_container();
- }
-
- template
- AZ_FORCE_INLINE bool operator>(const queue& left, const queue& right)
- {
- return left.get_container() > right.get_container();
- }
-
- template
- AZ_FORCE_INLINE operator<=(const queue& left, const queue& right)
- {
- return left.get_container() <= right.get_container();
- }
-
- template
- AZ_FORCE_INLINE bool operator>=(const queue& left, const queue& right)
- {
- return left.get_container() >= right.get_container();
- }*/
-
- /**
- * Priority queue is complaint with \ref CStd (23.2.3.2)
- * The only extension we have is that we allow access
- * to the underlying container via: get_container function.
- * Check the priority_queue \ref AZStdExamples.
- */
- template, class Predicate = AZStd::less >
- class priority_queue
- {
- enum
- {
- CONTAINER_VERSION = 1
- };
- public:
- typedef priority_queue this_type;
- typedef Container container_type;
- typedef typename Container::value_type value_type;
- typedef typename Container::size_type size_type;
- typedef typename Container::reference reference;
- typedef typename Container::const_reference const_reference;
-
- AZ_FORCE_INLINE priority_queue() {}
- AZ_FORCE_INLINE explicit priority_queue(const Predicate& comp)
- : m_comp(comp) {}
- AZ_FORCE_INLINE priority_queue(const Predicate& comp, const container_type& container)
- : m_container(container)
- , m_comp(comp)
- {
- // construct by copying specified container, comparator
- AZStd::make_heap(m_container.begin(), m_container.end(), comp);
- }
- template
- AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last)
- : m_container(first, last)
- , m_comp()
- {
- AZStd::make_heap(m_container.begin(), m_container.end(), m_comp);
- }
-
- template
- AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last, const Predicate& comp)
- : m_container(first, last)
- , m_comp(comp)
- { // construct by copying [_First, _Last), specified comparator
- AZStd::make_heap(m_container.begin(), m_container.end(), m_comp);
- }
-
- template
- AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last, const Predicate& comp, const container_type& container)
- : m_container(container)
- , m_comp(comp)
- { // construct by copying [_First, _Last), container, and comparator
- m_container.insert(m_container.end(), first, last);
- AZStd::make_heap(m_container.begin(), m_container.end(), m_comp);
- }
-
- AZ_FORCE_INLINE bool empty() const { return m_container.empty(); }
- AZ_FORCE_INLINE size_type size() const { return m_container.size(); }
- AZ_FORCE_INLINE const_reference top() const { return m_container.front(); }
- AZ_FORCE_INLINE reference top() { return m_container.front(); }
- AZ_FORCE_INLINE void push(const value_type& value)
- {
- m_container.push_back(value);
- AZStd::push_heap(m_container.begin(), m_container.end(), m_comp);
- }
-
- AZ_FORCE_INLINE void pop()
- {
- AZStd::pop_heap(m_container.begin(), m_container.end(), m_comp);
- m_container.pop_back();
- }
-
- AZ_FORCE_INLINE priority_queue(this_type&& rhs)
- : m_container(AZStd::move(rhs.m_container))
- , m_comp(AZStd::move(rhs.m_comp)) {}
- AZ_FORCE_INLINE explicit priority_queue(const Predicate& pred, Container&& container)
- : m_container(AZStd::move(container))
- , m_comp(pred) {}
- this_type& operator=(this_type&& rhs)
- {
- m_container = AZStd::move(rhs.m_container);
- m_comp = AZStd::move(rhs.m_comp);
- return (*this);
- }
- void push(value_type&& value) { m_container.push_back(AZStd::move(value)); AZStd::push_heap(m_container.begin(), m_container.end(), m_comp); }
- template
- void emplace(Args&& args) { m_container.emplace_back(AZStd::forward(args)); AZStd::push_heap(m_container.begin(), m_container.end(), m_comp); }
- void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); AZStd::swap(m_comp, rhs.m_comp); }
-
- AZ_FORCE_INLINE Container& get_container() { return m_container; }
- AZ_FORCE_INLINE const Container& get_container() const { return m_container; }
-
- protected:
- Container m_container;
- Predicate m_comp;
- };
+ template>
+ using queue = std::queue;
+ template, class Compare = AZStd::less>
+ using priority_queue = std::priority_queue;
}
-
-#endif // AZSTD_QUEUE_H
-#pragma once
diff --git a/Code/Framework/AzCore/AzCore/std/containers/stack.h b/Code/Framework/AzCore/AzCore/std/containers/stack.h
index 715d46c933..aa0d62d105 100644
--- a/Code/Framework/AzCore/AzCore/std/containers/stack.h
+++ b/Code/Framework/AzCore/AzCore/std/containers/stack.h
@@ -5,103 +5,13 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-#ifndef AZSTD_STACK_H
-#define AZSTD_STACK_H 1
+#pragma once
#include
+#include
namespace AZStd
{
- /**
- * Stack container is complaint with \ref CStd (23.2.3.3)
- * The only extension we have is that we allow access
- * to the underlying container via: get_container function.
- * Check the stack \ref AZStdExamples.
- */
- template >
- class stack
- {
- enum
- {
- CONTAINER_VERSION = 1
- };
- public:
- typedef stack this_type;
- typedef Container container_type;
- typedef typename Container::value_type value_type;
- typedef typename Container::size_type size_type;
- typedef typename Container::reference reference;
- typedef typename Container::const_reference const_reference;
-
- AZ_FORCE_INLINE stack() {}
- AZ_FORCE_INLINE explicit stack(const container_type& container)
- : m_container(container) {}
- AZ_FORCE_INLINE bool empty() const { return m_container.empty(); }
- AZ_FORCE_INLINE size_type size() const { return m_container.size(); }
- AZ_FORCE_INLINE reference top() { return m_container.back(); }
- AZ_FORCE_INLINE const_reference top() const { return m_container.back(); }
- AZ_FORCE_INLINE reference back() { return m_container.back(); }
- AZ_FORCE_INLINE const_reference back() const { return m_container.back(); }
- AZ_FORCE_INLINE void push(const value_type& value) { m_container.push_back(value); }
- AZ_FORCE_INLINE void pop() { m_container.pop_back(); }
- AZ_FORCE_INLINE void push() { m_container.push_back(); }
-
- AZ_FORCE_INLINE stack(this_type&& rhs)
- : m_container(AZStd::move(rhs.m_container)) {}
- AZ_FORCE_INLINE explicit stack(Container&& container)
- : m_container(AZStd::move(container)) {}
- this_type& operator=(this_type&& rhs) { m_container = AZStd::move(rhs.m_container); return *this; }
- void push(value_type&& value) { m_container.push_back(AZStd::move(value)); }
- template
- void emplace(Args&& args) { m_container.emplace_back(AZStd::forward(args)); }
- void swap(this_type&& rhs) { m_container.swap(AZStd::move(rhs.m_container)); }
-
- void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); }
-
- AZ_FORCE_INLINE Container& get_container() { return m_container; }
- AZ_FORCE_INLINE const Container& get_container() const { return m_container; }
-
- protected:
- Container m_container;
- };
-
- // queue TEMPLATE FUNCTIONS
- template
- AZ_FORCE_INLINE bool operator==(const AZStd::stack& left, const AZStd::stack& right)
- {
- return left.get_container() == right.get_container();
- }
-
- template
- AZ_FORCE_INLINE bool operator!=(const AZStd::stack& left, const AZStd::stack& right)
- {
- return left.get_container() != right.get_container();
- }
-
- /* template
- AZ_FORCE_INLINE bool operator<(const queue& left, const queue& right)
- {
- return left.get_container() < right.get_container();
- }
-
- template
- AZ_FORCE_INLINE bool operator>(const queue& left, const queue& right)
- {
- return left.get_container() > right.get_container();
- }
-
- template
- AZ_FORCE_INLINE operator<=(const queue& left, const queue& right)
- {
- return left.get_container() <= right.get_container();
- }
-
- template
- AZ_FORCE_INLINE bool operator>=(const queue& left, const queue& right)
- {
- return left.get_container() >= right.get_container();
- }*/
+ template>
+ using stack = std::stack;
}
-
-#endif // AZSTD_STACK_H
-#pragma once
diff --git a/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp b/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp
index 587d900b90..33a5d29b4f 100644
--- a/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp
+++ b/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp
@@ -298,7 +298,7 @@ namespace UnitTest
AZ_TEST_ASSERT(int_queue.empty());
AZ_TEST_ASSERT(int_queue.size() == 0);
- // Queue uses deque as default container, so try to contruct to queue from a deque.
+ // Queue uses deque as default container, so try to construct to queue from a deque.
deque container(40, 10);
int_queue_type int_queue2(container);
AZ_TEST_ASSERT(!int_queue2.empty());
@@ -324,7 +324,7 @@ namespace UnitTest
AZ_TEST_ASSERT(int_queue2.size() == 40);
AZ_TEST_ASSERT(int_queue2.back() == 20);
- int_queue.push();
+ int_queue.emplace();
AZ_TEST_ASSERT(!int_queue.empty());
AZ_TEST_ASSERT(int_queue.size() == 1);
@@ -423,7 +423,7 @@ namespace UnitTest
AZ_TEST_ASSERT(int_stack2.size() == 40);
AZ_TEST_ASSERT(int_stack2.top() == 10);
- int_stack.push();
+ int_stack.emplace();
AZ_TEST_ASSERT(!int_stack.empty());
AZ_TEST_ASSERT(int_stack.size() == 1);
// StackContainerTest-End
@@ -669,4 +669,19 @@ namespace UnitTest
++iteration;
}
}
+
+ using StackContainerTestFixture = ScopedAllocatorSetupFixture;
+
+ TEST_F(StackContainerTestFixture, StackEmplaceOperator_SupportsZeroOrMoreArguments)
+ {
+ using TestPairType = AZStd::pair;
+ AZStd::stack testStack;
+ testStack.emplace();
+ testStack.emplace(1);
+ testStack.emplace(2, 3);
+
+ using ContainerType = typename AZStd::stack::container_type;
+ AZStd::stack expectedStack(ContainerType{ TestPairType{ 0, 0 }, TestPairType{ 1, 0 }, TestPairType{ 2, 3 } });
+ EXPECT_EQ(expectedStack, testStack);
+ }
}
diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp
index a61f6a4845..cfea76f1d7 100644
--- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp
@@ -123,6 +123,12 @@ namespace AzPhysics
->Field("Kinematic", &RigidBodyConfiguration::m_kinematic)
->Field("CCD Enabled", &RigidBodyConfiguration::m_ccdEnabled)
->Field("Compute Mass", &RigidBodyConfiguration::m_computeMass)
+ ->Field("Lock Linear X", &RigidBodyConfiguration::m_lockLinearX)
+ ->Field("Lock Linear Y", &RigidBodyConfiguration::m_lockLinearY)
+ ->Field("Lock Linear Z", &RigidBodyConfiguration::m_lockLinearZ)
+ ->Field("Lock Angular X", &RigidBodyConfiguration::m_lockAngularX)
+ ->Field("Lock Angular Y", &RigidBodyConfiguration::m_lockAngularY)
+ ->Field("Lock Angular Z", &RigidBodyConfiguration::m_lockAngularZ)
->Field("Mass", &RigidBodyConfiguration::m_mass)
->Field("Compute COM", &RigidBodyConfiguration::m_computeCenterOfMass)
->Field("Centre of mass offset", &RigidBodyConfiguration::m_centerOfMassOffset)
diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h
index 59829e740c..51dcce842d 100644
--- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h
+++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h
@@ -62,6 +62,16 @@ namespace AzPhysics
bool m_computeInertiaTensor = true;
bool m_computeMass = true;
+ // Flags to restrict motion along specific world-space axes.
+ bool m_lockLinearX = false;
+ bool m_lockLinearY = false;
+ bool m_lockLinearZ = false;
+
+ // Flags to restrict rotation around specific world-space axes.
+ bool m_lockAngularX = false;
+ bool m_lockAngularY = false;
+ bool m_lockAngularZ = false;
+
//! If set, non-simulated shapes will also be included in the mass properties calculation.
bool m_includeAllShapesInMassCalculation = false;
diff --git a/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp b/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp
index cc663f36b8..ecbacd125b 100644
--- a/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp
+++ b/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp
@@ -32,7 +32,7 @@ namespace UnitTest
void TestDebugDisplayRequests::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max)
{
- const AZ::Transform& tm = m_transforms.back();
+ const AZ::Transform& tm = m_transforms.top();
m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), min.GetY(), min.GetZ())));
m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), min.GetY(), max.GetZ())));
m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), max.GetY(), min.GetZ())));
@@ -50,7 +50,7 @@ namespace UnitTest
void TestDebugDisplayRequests::DrawWireQuad(float width, float height)
{
- const AZ::Transform& tm = m_transforms.back();
+ const AZ::Transform& tm = m_transforms.top();
m_points.push_back(tm.TransformPoint(AZ::Vector3(-0.5f * width, 0.0f, -0.5f * height)));
m_points.push_back(tm.TransformPoint(AZ::Vector3(-0.5f * width, 0.0f, 0.5f * height)));
m_points.push_back(tm.TransformPoint(AZ::Vector3(0.5f * width, 0.0f, -0.5f * height)));
@@ -64,7 +64,7 @@ namespace UnitTest
void TestDebugDisplayRequests::DrawPoints(const AZStd::vector& points)
{
- const AZ::Transform& tm = m_transforms.back();
+ const AZ::Transform& tm = m_transforms.top();
for (const auto& point : points)
{
m_points.push_back(tm.TransformPoint(point));
@@ -100,7 +100,7 @@ namespace UnitTest
void TestDebugDisplayRequests::PushMatrix(const AZ::Transform& tm)
{
- m_transforms.push(m_transforms.back() * tm);
+ m_transforms.push(m_transforms.top() * tm);
}
void TestDebugDisplayRequests::PopMatrix()
diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp
index 5ef1cda30e..b4cad8511f 100644
--- a/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp
@@ -481,7 +481,7 @@ namespace AzFramework
if (!m_freeOctreeNodes.empty())
{
// Take a free block of child nodes from our free list
- ExtractPageAndOffsetFromIndex(m_freeOctreeNodes.back(), nextChildPage, nextChildOffset);
+ ExtractPageAndOffsetFromIndex(m_freeOctreeNodes.top(), nextChildPage, nextChildOffset);
m_freeOctreeNodes.pop();
}
else
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h b/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h
index 03c65ce0c3..9b57d1d49e 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h
+++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h
@@ -35,7 +35,7 @@ namespace AzFramework
class LinuxXcbConnectionManager
{
public:
- AZ_RTTI(LinuxXcbConnectionManager, "{649951316-3626-4C9D-9DCA-2E7ABF84C0A9}");
+ AZ_RTTI(LinuxXcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
virtual ~LinuxXcbConnectionManager() = default;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp
index c7bf72ff7b..8f93ebb6df 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp
@@ -177,7 +177,7 @@ namespace AzToolsFramework
PrefabDomUtils::ApplyPatches(templateDomReference, templateDomReference.GetAllocator(), providedPatch);
//trigger propagation
- if (result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Success)
+ if (result.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
{
AZ_Error("Prefab", false, "Patch was not successfully applied.");
return false;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
index 16db933192..a03e48062c 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
@@ -90,10 +90,11 @@ namespace AzToolsFramework
AZStd::unordered_map nestedInstanceLinkPatchesMap;
// Retrieve all entities affected and identify Instances
- if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances))
+ PrefabOperationResult retrieveEntitiesAndInstancesOutcome = RetrieveAndSortPrefabEntitiesAndInstances(
+ inputEntityList, commonRootEntityOwningInstance->get(), entities, instances);
+ if (!retrieveEntitiesAndInstancesOutcome.IsSuccess())
{
- return AZ::Failure(
- AZStd::string("Could not create a new prefab out of the entities provided - invalid selection."));
+ return retrieveEntitiesAndInstancesOutcome;
}
AZStd::unordered_map oldEntityAliases;
@@ -646,7 +647,12 @@ namespace AzToolsFramework
{
// Retrieve all nested instances that are part of the subtree under the current entity.
EntityList entities;
- RetrieveAndSortPrefabEntitiesAndInstances({ entity }, beforeOwningInstance->get(), entities, instancesInvolved);
+ PrefabOperationResult retrieveEntitiesAndInstancesOutcome = RetrieveAndSortPrefabEntitiesAndInstances(
+ { entity }, beforeOwningInstance->get(), entities, instancesInvolved);
+ if (!retrieveEntitiesAndInstancesOutcome.IsSuccess())
+ {
+ return retrieveEntitiesAndInstancesOutcome;
+ }
}
for (Instance* instance : instancesInvolved)
@@ -748,7 +754,9 @@ namespace AzToolsFramework
AZStd::vector instances;
// Retrieve all descendant entities and instances of this entity that belonged to the same owning instance.
- RetrieveAndSortPrefabEntitiesAndInstances({ entity }, beforeOwningInstance->get(), entities, instances);
+ PrefabOperationResult retrieveEntitiesAndInstancesOutcome = RetrieveAndSortPrefabEntitiesAndInstances(
+ { entity }, beforeOwningInstance->get(), entities, instances);
+ AZ_Error("Prefab", retrieveEntitiesAndInstancesOutcome.IsSuccess(), retrieveEntitiesAndInstancesOutcome.GetError().data());
AZStd::vector> instanceUniquePtrs;
AZStd::vector> instancePatches;
@@ -981,11 +989,12 @@ namespace AzToolsFramework
AZStd::vector instances;
EntityList inputEntityList = EntityIdSetToEntityList(duplicationSet);
- bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances);
+ PrefabOperationResult retrieveEntitiesAndInstancesOutcome =
+ RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances);
- if (!success)
+ if (!retrieveEntitiesAndInstancesOutcome.IsSuccess())
{
- return AZ::Failure(AZStd::string("Failed to retrieve entities and instances from the given list of entity ids for duplication"));
+ return AZStd::move(retrieveEntitiesAndInstancesOutcome);
}
// Take a snapshot of the instance DOM before we manipulate it
@@ -1128,11 +1137,12 @@ namespace AzToolsFramework
AZStd::vector entities;
AZStd::vector instances;
- bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances);
+ PrefabOperationResult retrieveEntitiesAndInstancesOutcome =
+ RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances);
- if (!success)
+ if (!retrieveEntitiesAndInstancesOutcome.IsSuccess())
{
- return AZ::Failure(AZStd::string("DeleteEntitiesAndAllDescendantsInInstance"));
+ return AZStd::move(retrieveEntitiesAndInstancesOutcome);
}
for (AZ::Entity* entity : entities)
@@ -1405,13 +1415,16 @@ namespace AzToolsFramework
return nullptr;
}
- bool PrefabPublicHandler::RetrieveAndSortPrefabEntitiesAndInstances(
- const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
- EntityList& outEntities, AZStd::vector& outInstances) const
+ PrefabOperationResult PrefabPublicHandler::RetrieveAndSortPrefabEntitiesAndInstances(
+ const EntityList& inputEntities,
+ Instance& commonRootEntityOwningInstance,
+ EntityList& outEntities,
+ AZStd::vector& outInstances) const
{
if (inputEntities.size() == 0)
{
- return false;
+ return AZ::Failure(
+ AZStd::string("An empty list of input entities is provided to retrieve the prefab entities and instances."));
}
AZStd::queue entityQueue;
@@ -1438,8 +1451,8 @@ namespace AzToolsFramework
AZ_Assert(
owningInstance.has_value(),
"An error occurred while retrieving entities and prefab instances : "
- "Owning instance of entity with id '%llu' couldn't be found",
- entity->GetId());
+ "Owning instance of entity with name '%s' and id '%llu' couldn't be found",
+ entity->GetName().c_str(), static_cast(entity->GetId()));
// Check if this entity is owned by the same instance owning the root.
if (&owningInstance->get() == &commonRootEntityOwningInstance)
@@ -1480,7 +1493,10 @@ namespace AzToolsFramework
else
{
// This can only happen if one entity does not share the common root!
- return false;
+ return AZ::Failure(AZStd::string::format(
+ "Entity with name '%s' and id '%llu' has an owning instance that doesn't belong to the instance "
+ "hierarchy of the selected entities.",
+ entity->GetName().c_str(), static_cast(entity->GetId())));
}
}
}
@@ -1501,7 +1517,12 @@ namespace AzToolsFramework
outInstances.push_back(instancePtr);
}
- return (outEntities.size() + outInstances.size()) > 0;
+ if ((outEntities.size() + outInstances.size()) == 0)
+ {
+ return AZ::Failure(
+ AZStd::string("An empty list of entities and prefab instances were retrieved from the selected entities"));
+ }
+ return AZ::Success();
}
EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutLevelInstance(
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
index f0c88a7a79..0e24b0841d 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
@@ -64,8 +64,11 @@ namespace AzToolsFramework
private:
PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants);
- bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
- EntityList& outEntities, AZStd::vector& outInstances) const;
+ PrefabOperationResult RetrieveAndSortPrefabEntitiesAndInstances(
+ const EntityList& inputEntities,
+ Instance& commonRootEntityOwningInstance,
+ EntityList& outEntities,
+ AZStd::vector& outInstances) const;
EntityIdList GenerateEntityIdListWithoutLevelInstance(const EntityIdList& entityIds) const;
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
diff --git a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp
index 2bc8d3e9f0..b8eea00871 100644
--- a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp
+++ b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp
@@ -1688,12 +1688,12 @@ namespace GridMate
return; //No connections to update
}
bool updateRate = false;
- AZ::u32 minRateBytesPerSecond = m_connByCongestionState.top().m_rate;
+ AZ::u32 minRateBytesPerSecond = m_connByCongestionState.front().m_rate;
//const AZ::u32 old = minRateBytesPerSecond; //For debugging
- auto connIt = AZStd::find(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end(), id);
+ auto connIt = AZStd::find(m_connByCongestionState.begin(), m_connByCongestionState.end(), id);
- if ( connIt == m_connByCongestionState.get_container().end())
+ if ( connIt == m_connByCongestionState.end())
{
return; //Already disconnected
}
@@ -1708,11 +1708,11 @@ namespace GridMate
//If new min or old min increased, rebuild the heap and send an update
if (bytesPerSecond < minRateBytesPerSecond
- || (id == m_connByCongestionState.top().m_connection && bytesPerSecond > minRateBytesPerSecond))
+ || (id == m_connByCongestionState.front().m_connection && bytesPerSecond > minRateBytesPerSecond))
{
updateRate = true;
minRateBytesPerSecond = bytesPerSecond;
- AZStd::make_heap(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end());
+ AZStd::make_heap(m_connByCongestionState.begin(), m_connByCongestionState.end());
}
}
diff --git a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h
index 93a46d8ad7..bd9f1a1ee9 100644
--- a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h
+++ b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h
@@ -459,7 +459,7 @@ namespace GridMate
}
};
static bool k_enableBackPressure;
- AZStd::priority_queue m_connByCongestionState; ///< Connections priority queue sorted by congestion window
+ AZStd::vector m_connByCongestionState; ///< Connections priority queue sorted by congestion window
/***
* Updates connection's rate in priority and updates send limit
*
@@ -479,7 +479,9 @@ namespace GridMate
}
AZ_Assert(carrier, "NULL carrier!");
- m_connByCongestionState.emplace(RateConnectionPair(AZ::u32(1500), id)); //default to 1500Bps (ex 1 Ethernet frame/second minimum)
+ m_connByCongestionState.emplace_back(AZ::u32(1500), id); //default to 1500Bps (ex 1 Ethernet frame/second minimum)
+ // Restore the heap property after pushing back another element
+ AZStd::push_heap(m_connByCongestionState.begin(), m_connByCongestionState.end());
}
void OnDisconnect(Carrier* carrier, ConnectionID id, CarrierDisconnectReason reason) override
{
@@ -490,17 +492,17 @@ namespace GridMate
}
AZ_Assert(carrier, "NULL carrier!");
- auto connIt = AZStd::find(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end(), id);
- if (connIt != m_connByCongestionState.get_container().end())
+ auto connIt = AZStd::find(m_connByCongestionState.begin(), m_connByCongestionState.end(), id);
+ if (connIt != m_connByCongestionState.end())
{
//Since we are using a weakly sorted heap, we need to re-generate when the top is removed
- bool remake = (connIt == m_connByCongestionState.get_container().begin());
+ bool remake = (connIt == m_connByCongestionState.begin());
- m_connByCongestionState.get_container().erase(connIt);
+ m_connByCongestionState.erase(connIt);
if (remake)
{
- AZStd::make_heap(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end());
+ AZStd::make_heap(m_connByCongestionState.begin(), m_connByCongestionState.end());
}
}
}
diff --git a/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua b/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua
new file mode 100644
index 0000000000..dda3974043
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua
@@ -0,0 +1,160 @@
+----------------------------------------------------------------------------------------------------
+--
+-- 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
+--
+--
+--
+----------------------------------------------------------------------------------------------------
+
+local FindMaterialAssignmentTest =
+{
+ Properties =
+ {
+ Textures =
+ {
+ "materials/presets/macbeth/05_blue_flower_srgb.tif.streamingimage",
+ "materials/presets/macbeth/06_bluish_green_srgb.tif.streamingimage",
+ "materials/presets/macbeth/09_moderate_red_srgb.tif.streamingimage",
+ "materials/presets/macbeth/11_yellow_green_srgb.tif.streamingimage",
+ "materials/presets/macbeth/12_orange_yellow_srgb.tif.streamingimage",
+ "materials/presets/macbeth/17_magenta_srgb.tif.streamingimage"
+ },
+ },
+}
+
+function randomColor()
+ return Color(math.random(), math.random(), math.random(), 1.0)
+end
+
+function randomDir()
+ dir = {}
+ for i = 1, 3 do
+ lerpDir = math.random()
+ if lerpDir < 0.5 then
+ table.insert(dir, -1.0)
+ else
+ table.insert(dir, 1.0)
+ end
+ end
+ return dir
+end
+
+function FindMaterialAssignmentTest:OnActivate()
+ self.timer = 0.0
+ self.totalTime = 0.0
+ self.totalTimeMax = 200.0
+ self.timeUpdate = 2.0
+ self.colors = {}
+ self.lerpDirs = {}
+
+ self.assignmentIds =
+ {
+ MaterialComponentRequestBus.Event.FindMaterialAssignmentId(self.entityId, -1, "lambert"),
+ }
+
+ for index = 1, #self.assignmentIds do
+ local id = self.assignmentIds[index]
+ if (id ~= nil) then
+ self.colors[index] = randomColor()
+ self.lerpDirs[index] = randomDir()
+ end
+ end
+ self.tickBusHandler = TickBus.Connect(self);
+end
+
+function FindMaterialAssignmentTest:UpdateFactor(assignmentId)
+ local propertyName = Name("baseColor.factor")
+ local propertyValue = math.random()
+ MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue);
+end
+
+function FindMaterialAssignmentTest:UpdateColor(assignmentId, color)
+ local propertyName = Name("baseColor.color")
+ local propertyValue = color
+ MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue);
+end
+
+function FindMaterialAssignmentTest:UpdateTexture(assignmentId)
+ if (#self.Properties.Textures > 0) then
+ local propertyName = Name("baseColor.textureMap")
+ local textureName = self.Properties.Textures[ math.random( #self.Properties.Textures ) ]
+ Debug.Log(textureName)
+ local textureAssetId = AssetCatalogRequestBus.Broadcast.GetAssetIdByPath(textureName, Uuid(), false)
+ MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, textureAssetId);
+ end
+end
+
+function FindMaterialAssignmentTest:UpdateProperties()
+ Debug.Log("Overriding properties...")
+ for index = 1, #self.assignmentIds do
+ local id = self.assignmentIds[index]
+ if (id ~= nil) then
+ self:UpdateFactor(id)
+ self:UpdateTexture(id)
+ end
+ end
+end
+
+function FindMaterialAssignmentTest:ClearProperties()
+ Debug.Log("Clearing properties...")
+ MaterialComponentRequestBus.Event.ClearAllPropertyOverrides(self.entityId);
+end
+
+function lerpColor(color, lerpDir, deltaTime)
+ local lerpSpeed = 0.5
+ color.r = color.r + deltaTime * lerpDir[1] * lerpSpeed
+ if color.r > 1.0 then
+ color.r = 1.0
+ lerpDir[1] = -1.0
+ elseif color.r < 0 then
+ color.r = 0
+ lerpDir[1] = 1.0
+ end
+
+ color.g = color.g + deltaTime * lerpDir[2] * lerpSpeed
+ if color.g > 1.0 then
+ color.g = 1.0
+ lerpDir[2] = -1.0
+ elseif color.g < 0 then
+ color.g = 0
+ lerpDir[2] = 1.0
+ end
+
+ color.b = color.b + deltaTime * lerpDir[3] * lerpSpeed
+ if color.b > 1.0 then
+ color.b = 1.0
+ lerpDir[3] = -1.0
+ elseif color.b < 0 then
+ color.b = 0
+ lerpDir[3] = 1.0
+ end
+end
+
+function FindMaterialAssignmentTest:lerpColors(deltaTime)
+ for index = 1, #self.assignmentIds do
+ local id = self.assignmentIds[index]
+ if (id ~= nil) then
+ lerpColor(self.colors[index], self.lerpDirs[index], deltaTime)
+ self:UpdateColor(id, self.colors[index])
+ end
+ end
+end
+
+function FindMaterialAssignmentTest:OnTick(deltaTime, timePoint)
+ self.timer = self.timer + deltaTime
+ self.totalTime = self.totalTime + deltaTime
+ self:lerpColors(deltaTime)
+
+ if (self.timer > self.timeUpdate and self.totalTime < self.totalTimeMax) then
+ self.timer = self.timer - self.timeUpdate
+ self:UpdateProperties()
+ elseif self.totalTime > self.totalTimeMax then
+ self:ClearProperties()
+ self.tickBusHandler:Disconnect(self);
+ end
+end
+
+return FindMaterialAssignmentTest
\ No newline at end of file
diff --git a/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua b/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua
index c470748801..685fd8310b 100644
--- a/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua
+++ b/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua
@@ -53,10 +53,9 @@ function PropertyOverrideTest:OnActivate()
self.originalAssignments = MaterialComponentRequestBus.Event.GetOriginalMaterialAssignments(self.entityId);
self.assignmentIds = self.originalAssignments:GetKeys()
- for index = 0, self.assignmentIds:Size() do
- local idOutcome = self.assignmentIds:At(index)
- if (idOutcome:IsSuccess()) then
- local id = idOutcome:GetValue()
+ for index = 1, self.assignmentIds:GetSize() do
+ local id = self.assignmentIds[index]
+ if (id ~= nil) then
self.colors[index] = randomColor()
self.lerpDirs[index] = randomDir()
end
@@ -88,10 +87,9 @@ end
function PropertyOverrideTest:UpdateProperties()
Debug.Log("Overriding properties...")
- for index = 0, self.assignmentIds:Size() do
- local idOutcome = self.assignmentIds:At(index)
- if (idOutcome:IsSuccess()) then
- local id = idOutcome:GetValue()
+ for index = 1, self.assignmentIds:GetSize() do
+ local id = self.assignmentIds[index]
+ if (id ~= nil) then
self:UpdateFactor(id)
self:UpdateTexture(id)
end
@@ -134,10 +132,9 @@ function lerpColor(color, lerpDir, deltaTime)
end
function PropertyOverrideTest:lerpColors(deltaTime)
- for index = 0, self.assignmentIds:Size() do
- local idOutcome = self.assignmentIds:At(index)
- if (idOutcome:IsSuccess()) then
- local id = idOutcome:GetValue()
+ for index = 1, self.assignmentIds:GetSize() do
+ local id = self.assignmentIds[index]
+ if (id ~= nil) then
lerpColor(self.colors[index], self.lerpDirs[index], deltaTime)
self:UpdateColor(id, self.colors[index])
end
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h
index 12a9c0fccc..907b1a1740 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
+
#pragma once
#include
@@ -63,5 +64,8 @@ namespace AZ
//! Utility function for generating a set of available material assignments in a model
MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model);
+ //! Find an assignment id corresponding to the lod and label substring filters
+ MaterialAssignmentId FindMaterialAssignmentIdInModel(
+ const Data::Instance model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter);
} // namespace Render
} // namespace AZ
diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp
index 8b617cfe0f..a9ee46dd2c 100644
--- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp
@@ -124,6 +124,18 @@ namespace AZ
->Field("AcesParameterOverrides", &DisplayMapperConfigurationDescriptor::m_acesParameterOverrides)
;
}
+
+ if (auto* behaviorContext = azrtti_cast(context))
+ {
+ behaviorContext->Class()
+ ->Enum<(uint32_t)DisplayMapperOperationType::Aces>("DisplayMapperOperationType_Aces")
+ ->Enum<(uint32_t)DisplayMapperOperationType::AcesLut>("DisplayMapperOperationType_AcesLut")
+ ->Enum<(uint32_t)DisplayMapperOperationType::Passthrough>("DisplayMapperOperationType_Passthrough")
+ ->Enum<(uint32_t)DisplayMapperOperationType::GammaSRGB>("DisplayMapperOperationType_GammaSRGB")
+ ->Enum<(uint32_t)DisplayMapperOperationType::Reinhard>("DisplayMapperOperationType_Reinhard")
+ ->Enum<(uint32_t)DisplayMapperOperationType::Invalid>("DisplayMapperOperationType_Invalid")
+ ;
+ }
}
void DisplayMapperPassData::Reflect(ReflectContext* context)
diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp
index ec48d57d1a..074d5c39e8 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp
@@ -166,5 +166,48 @@ namespace AZ
return materials;
}
+
+ MaterialAssignmentId FindMaterialAssignmentIdInLod(
+ const Data::Instance& lod, const MaterialAssignmentLodIndex lodIndex, const AZStd::string& labelFilter)
+ {
+ for (const AZ::RPI::ModelLod::Mesh& mesh : lod->GetMeshes())
+ {
+ if (mesh.m_material && mesh.m_material->GetAssetId().IsValid())
+ {
+ AZ::Data::AssetInfo assetInfo;
+ AZ::Data::AssetCatalogRequestBus::BroadcastResult(
+ assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, mesh.m_material->GetAssetId());
+ if (assetInfo.m_assetId.IsValid() && AZ::StringFunc::Contains(assetInfo.m_relativePath, labelFilter, true))
+ {
+ return MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId());
+ }
+ }
+ }
+ return MaterialAssignmentId();
+ }
+
+ MaterialAssignmentId FindMaterialAssignmentIdInModel(
+ const Data::Instance model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter)
+ {
+ if (model && !labelFilter.empty())
+ {
+ if (lodFilter < model->GetLodCount())
+ {
+ return FindMaterialAssignmentIdInLod(model->GetLods()[lodFilter], lodFilter, labelFilter);
+ }
+
+ for (size_t lodIndex = 0; lodIndex < model->GetLodCount(); ++lodIndex)
+ {
+ const MaterialAssignmentId result =
+ FindMaterialAssignmentIdInLod(model->GetLods()[lodIndex], MaterialAssignmentId::NonLodIndex, labelFilter);
+ if (!result.IsDefault())
+ {
+ return result;
+ }
+ }
+ }
+
+ return MaterialAssignmentId();
+ }
} // namespace Render
} // namespace AZ
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h
index 14e9968e42..c1fd4453d4 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h
@@ -81,6 +81,15 @@ namespace AZ
AZ_RTTI(SwapChain, "{888B64A5-D956-406F-9C33-CF6A54FC41B0}", Object);
+#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
+ // On Linux platforms that uses XCB, a resize may occur in the swap chain but the command queue may still
+ // reference the original surface. This flag is a temporary fix to make sure that all the swap chains
+ // have finished their resize events before presenting the command queue.
+
+ // [GFX TODO][GHI - 2678]
+ AZStd::atomic_bool m_resized{ false };
+#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+
protected:
SwapChain();
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp
index b670dc1234..d2298cda3f 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp
@@ -126,6 +126,7 @@ namespace AZ
ResultCode FrameGraph::End()
{
+ AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraph: End");
ResultCode resultCode = ValidateEnd();
if (resultCode != ResultCode::Success)
{
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp
index 3189acab49..342e537993 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp
@@ -72,6 +72,7 @@ namespace AZ
void FrameGraphExecuter::Begin(const FrameGraph& frameGraph)
{
AZ_TRACE_METHOD();
+ AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphExecuter: Begin");
BeginInternal(frameGraph);
}
diff --git a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp
index 1170b82d78..0210d941dc 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp
@@ -6,6 +6,7 @@
*
*/
+#include
#include
#include
#include
@@ -205,6 +206,7 @@ namespace AZ
void PipelineStateCache::Compact()
{
+ AZ_ATOM_PROFILE_FUNCTION("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 083fb87b93..49244f776f 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp
@@ -223,7 +223,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_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "RHISystem: FrameUpdate: OnFramePrepare");
RHISystemNotificationBus::Broadcast(&RHISystemNotificationBus::Events::OnFramePrepare, m_frameScheduler);
}
diff --git a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp
index b0501d937d..5fbb83fccf 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp
@@ -164,6 +164,10 @@ namespace AZ
m_currentImageIndex = 0;
}
+#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
+ m_resized.store(true);
+#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+
return resultCode;
}
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp
index c98fd51fbb..ba4aa76a60 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp
@@ -469,6 +469,8 @@ namespace AZ
ResourceTransitionLoggerNull logger(imageFrameAttachment.GetId());
#endif
+ AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileImageBarriers (DX12)");
+
Image& image = static_cast(*imageFrameAttachment.GetImage());
RHI::ImageScopeAttachment* scopeAttachment = imageFrameAttachment.GetFirstScopeAttachment();
diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp
index ca6c829cca..84b4964235 100644
--- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp
+++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp
@@ -42,6 +42,15 @@ namespace AZ
void CommandQueue::ExecuteWork(const RHI::ExecuteWorkRequest& rhiRequest)
{
+#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
+ for (RHI::SwapChain* swapChain : rhiRequest.m_swapChainsToPresent)
+ {
+ if (!swapChain->m_resized)
+ {
+ return;
+ }
+ }
+#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
const ExecuteWorkRequest& request = static_cast(rhiRequest);
QueueCommand([=](void* queue)
{
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp
index e192e71fc4..c630fe0e5d 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp
@@ -720,6 +720,7 @@ namespace AZ
void CullingScene::BeginCulling(const AZStd::vector& views)
{
+ AZ_ATOM_PROFILE_FUNCTION("RPI", "CullingScene: BeginCulling");
m_cullDataConcurrencyCheck.soft_lock();
m_debugCtx.ResetCullStats();
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 f62dfa1d70..27e3612a4c 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp
@@ -298,6 +298,7 @@ namespace AZ
void PassSystem::ProcessQueuedChanges()
{
+ AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: ProcessQueuedChanges");
RemovePasses();
BuildPasses();
InitializePasses();
@@ -313,7 +314,11 @@ namespace AZ
m_state = PassSystemState::Rendering;
Pass::FramePrepareParams params{ &frameGraphBuilder };
- m_rootPass->FrameBegin(params);
+
+ {
+ AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Pass: FrameBegin");
+ m_rootPass->FrameBegin(params);
+ }
}
void PassSystem::FrameEnd()
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp
index bc700dd24f..071a07ecda 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp
@@ -408,6 +408,7 @@ namespace AZ
{
AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "m_srgCallback");
+ AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "ShaderResourceGroupCallback: SrgCallback");
// Set values for scene srg
if (m_srg && m_srgCallback)
{
@@ -418,7 +419,7 @@ namespace AZ
// Get active pipelines which need to be rendered and notify them frame started
AZStd::vector activePipelines;
{
- AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "OnStartFrame");
+ AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnStartFrame");
for (auto& pipeline : m_pipelines)
{
if (pipeline->NeedsRender())
@@ -483,6 +484,7 @@ namespace AZ
{
AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "CollectDrawPackets");
+ AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "CollectDrawPackets");
AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion();
// Launch FeatureProcessor::Render() jobs
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h
new file mode 100644
index 0000000000..dc57179fcc
--- /dev/null
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+namespace AtomToolsFramework
+{
+ //! Base class for Atom tools to inherit from
+ class AtomToolsApplication
+ : public AzFramework::Application
+ , public AzQtComponents::AzQtApplication
+ , protected AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler
+ , protected AzFramework::AssetSystemStatusBus::Handler
+ , protected AzToolsFramework::EditorPythonConsoleNotificationBus::Handler
+ , protected AZ::UserSettingsOwnerRequestBus::Handler
+ {
+ public:
+ AZ_TYPE_INFO(AtomTools::AtomToolsApplication, "{A0DF25BA-6F74-4F11-9F85-0F99278D5986}");
+
+ using Base = AzFramework::Application;
+
+ AtomToolsApplication(int* argc, char*** argv);
+
+ //////////////////////////////////////////////////////////////////////////
+ // AzFramework::Application
+ void CreateReflectionManager() override;
+ void Reflect(AZ::ReflectContext* context) override;
+ void RegisterCoreComponents() override;
+ AZ::ComponentTypeList GetRequiredSystemComponents() const override;
+ void CreateStaticModules(AZStd::vector& outModules) override;
+ const char* GetCurrentConfigurationName() const override;
+ void StartCommon(AZ::Entity* systemEntity) override;
+ void Tick(float deltaOverride = -1.f) override;
+ void Stop() override;
+
+ protected:
+ //////////////////////////////////////////////////////////////////////////
+ // AssetDatabaseRequestsBus::Handler overrides...
+ bool GetAssetDatabaseLocation(AZStd::string& result) override;
+ //////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ // AzFramework::Application overrides...
+ void Destroy() override;
+ //////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ // AzFramework::AssetSystemStatusBus::Handler overrides...
+ void AssetSystemAvailable() override;
+ //////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ // AZ::ComponentApplication overrides...
+ void QueryApplicationType(AZ::ApplicationTypeQuery& appType) const override;
+ //////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ // AZ::UserSettingsOwnerRequestBus::Handler overrides...
+ void SaveSettings() override;
+ //////////////////////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////
+ // EditorPythonConsoleNotificationBus::Handler overrides...
+ void OnTraceMessage(AZStd::string_view message) override;
+ void OnErrorMessage(AZStd::string_view message) override;
+ void OnExceptionMessage(AZStd::string_view message) override;
+ ////////////////////////////////////////////////////////////////////////
+
+ //! Executable target name generally used as a prefix for logging and other saved files
+ virtual AZStd::string GetBuildTargetName() const;
+
+ //! List of filters for assets that need to be pre-built to run the application
+ virtual AZStd::vector GetCriticalAssetFilters() const;
+
+ virtual void LoadSettings();
+ virtual void UnloadSettings();
+ virtual void CompileCriticalAssets();
+ virtual void ProcessCommandLine(const AZ::CommandLine& commandLine);
+ virtual bool LaunchDiscoveryService();
+ virtual void StartInternal();
+
+ static void PyIdleWaitFrames(uint32_t frames);
+
+ AzToolsFramework::TraceLogger m_traceLogger;
+
+ //! Local user settings are used to store material browser tree expansion state
+ AZ::UserSettingsProvider m_localUserSettings;
+
+ //! Are local settings loaded
+ bool m_activatedLocalUserSettings = false;
+
+ QTimer m_timer;
+
+ AtomToolsFramework::LocalSocket m_socket;
+ AtomToolsFramework::LocalServer m_server;
+ };
+} // namespace AtomToolsFramework
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp
new file mode 100644
index 0000000000..3a542db1a4
--- /dev/null
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp
@@ -0,0 +1,512 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
+#include
+#include
+AZ_POP_DISABLE_WARNING
+
+namespace AtomToolsFramework
+{
+ AZStd::string AtomToolsApplication::GetBuildTargetName() const
+ {
+ return AZStd::string("AtomTools");
+ }
+
+ const char* AtomToolsApplication::GetCurrentConfigurationName() const
+ {
+#if defined(_RELEASE)
+ return "ReleaseAtomTools";
+#elif defined(_DEBUG)
+ return "DebugAtomTools";
+#else
+ return "ProfileAtomTools";
+#endif
+ }
+
+ AtomToolsApplication::AtomToolsApplication(int* argc, char*** argv)
+ : Application(argc, argv)
+ , AzQtApplication(*argc, *argv)
+ {
+ connect(&m_timer, &QTimer::timeout, this, [&]()
+ {
+ this->PumpSystemEventLoopUntilEmpty();
+ this->Tick();
+ });
+ }
+
+ void AtomToolsApplication::CreateReflectionManager()
+ {
+ Base::CreateReflectionManager();
+ GetSerializeContext()->CreateEditContext();
+ }
+
+ void AtomToolsApplication::Reflect(AZ::ReflectContext* context)
+ {
+ Base::Reflect(context);
+
+ AzToolsFramework::AssetBrowser::AssetBrowserEntry::Reflect(context);
+ AzToolsFramework::AssetBrowser::RootAssetBrowserEntry::Reflect(context);
+ AzToolsFramework::AssetBrowser::FolderAssetBrowserEntry::Reflect(context);
+ AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry::Reflect(context);
+ AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry::Reflect(context);
+
+ AzToolsFramework::QTreeViewWithStateSaving::Reflect(context);
+ AzToolsFramework::QWidgetSavedState::Reflect(context);
+
+ if (auto behaviorContext = azrtti_cast(context))
+ {
+ auto targetName = GetBuildTargetName();
+
+ // this will put these methods into the 'azlmbr.AtomTools.general' module
+ auto addGeneral = [targetName](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder)
+ {
+ methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
+ ->Attribute(AZ::Script::Attributes::Category, "Editor")
+ ->Attribute(AZ::Script::Attributes::Module, targetName);
+ };
+ // The reflection here is based on patterns in CryEditPythonHandler::Reflect
+ addGeneral(behaviorContext->Method(
+ "idle_wait_frames", &AtomToolsApplication::PyIdleWaitFrames, nullptr,
+ "Waits idling for a frames. Primarily used for auto-testing."));
+ }
+ }
+
+ void AtomToolsApplication::RegisterCoreComponents()
+ {
+ Base::RegisterCoreComponents();
+ RegisterComponentDescriptor(AzToolsFramework::AssetBrowser::AssetBrowserComponent::CreateDescriptor());
+ RegisterComponentDescriptor(AzToolsFramework::Thumbnailer::ThumbnailerComponent::CreateDescriptor());
+ RegisterComponentDescriptor(AzToolsFramework::Components::PropertyManagerComponent::CreateDescriptor());
+ RegisterComponentDescriptor(AzToolsFramework::AssetSystem::AssetSystemComponent::CreateDescriptor());
+ RegisterComponentDescriptor(AzToolsFramework::PerforceComponent::CreateDescriptor());
+ }
+
+ AZ::ComponentTypeList AtomToolsApplication::GetRequiredSystemComponents() const
+ {
+ AZ::ComponentTypeList components = Base::GetRequiredSystemComponents();
+
+ components.insert(
+ components.end(),
+ {
+ azrtti_typeid(),
+ azrtti_typeid(),
+ azrtti_typeid(),
+ azrtti_typeid(),
+ });
+
+ return components;
+ }
+
+ void AtomToolsApplication::CreateStaticModules(AZStd::vector& outModules)
+ {
+ Base::CreateStaticModules(outModules);
+ outModules.push_back(aznew AzToolsFramework::AzToolsFrameworkModule);
+ }
+
+ void AtomToolsApplication::StartCommon(AZ::Entity* systemEntity)
+ {
+ AzFramework::AssetSystemStatusBus::Handler::BusConnect();
+ AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect();
+
+ Base::StartCommon(systemEntity);
+
+ StartInternal();
+
+ m_timer.start();
+ }
+
+ void AtomToolsApplication::Destroy()
+ {
+ AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
+ AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect();
+
+ AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::StartDisconnectingAssetProcessor);
+ Base::Destroy();
+ }
+
+ AZStd::vector AtomToolsApplication::GetCriticalAssetFilters() const
+ {
+ return AZStd::vector({});
+ }
+
+ void AtomToolsApplication::AssetSystemAvailable()
+ {
+ bool connectedToAssetProcessor = false;
+
+ // When the AssetProcessor is already launched it should take less than a second to perform a connection
+ // but when the AssetProcessor needs to be launch it could take up to 15 seconds to have the AssetProcessor initialize
+ // and able to negotiate a connection when running a debug build
+ // and to negotiate a connection
+
+ auto targetName = GetBuildTargetName();
+
+ AzFramework::AssetSystem::ConnectionSettings connectionSettings;
+ AzFramework::AssetSystem::ReadConnectionSettingsFromSettingsRegistry(connectionSettings);
+ connectionSettings.m_connectionDirection =
+ AzFramework::AssetSystem::ConnectionSettings::ConnectionDirection::ConnectToAssetProcessor;
+ connectionSettings.m_connectionIdentifier = GetBuildTargetName();
+ connectionSettings.m_loggingCallback = [targetName]([[maybe_unused]] AZStd::string_view logData)
+ {
+ AZ_TracePrintf(targetName.c_str(), "%.*s", aznumeric_cast(logData.size()), logData.data());
+ };
+ AzFramework::AssetSystemRequestBus::BroadcastResult(
+ connectedToAssetProcessor, &AzFramework::AssetSystemRequestBus::Events::EstablishAssetProcessorConnection, connectionSettings);
+
+ if (connectedToAssetProcessor)
+ {
+ CompileCriticalAssets();
+ }
+
+ AzFramework::AssetSystemStatusBus::Handler::BusDisconnect();
+ }
+
+ void AtomToolsApplication::CompileCriticalAssets()
+ {
+ AZ_TracePrintf(GetBuildTargetName().c_str(), "Compiling critical assets.\n");
+
+ QStringList failedAssets;
+
+ // Forced asset processor to synchronously process all critical assets
+ // Note: with AssetManager's current implementation, a compiled asset won't be added in asset registry until next system tick.
+ // So the asset id won't be found right after CompileAssetSync call.
+ for (const AZStd::string& assetFilters : GetCriticalAssetFilters())
+ {
+ AZ_TracePrintf(GetBuildTargetName().c_str(), "Compiling critical asset matching: %s.\n", assetFilters.c_str());
+
+ // Wait for the asset be compiled
+ AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown;
+ AzFramework::AssetSystemRequestBus::BroadcastResult(
+ status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, assetFilters);
+ if (status != AzFramework::AssetSystem::AssetStatus_Compiled)
+ {
+ failedAssets.append(assetFilters.c_str());
+ }
+ }
+
+ if (!failedAssets.empty())
+ {
+ QMessageBox::critical(
+ activeWindow(), QString("Failed to compile critical assets"),
+ QString("Failed to compile the following critical assets:\n%1\n%2")
+ .arg(failedAssets.join(",\n"))
+ .arg("Make sure this is an Atom project."));
+ ExitMainLoop();
+ }
+ }
+
+ void AtomToolsApplication::SaveSettings()
+ {
+ if (m_activatedLocalUserSettings)
+ {
+ AZ::SerializeContext* context = nullptr;
+ AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext);
+ AZ_Assert(context, "No serialize context");
+
+ char resolvedPath[AZ_MAX_PATH_LEN] = "";
+ AZStd::string fileName = "@user@/" + GetBuildTargetName() + "UserSettings.xml";
+
+ AZ::IO::FileIOBase::GetInstance()->ResolvePath(
+ fileName.c_str(), resolvedPath, AZ_ARRAY_SIZE(resolvedPath));
+ m_localUserSettings.Save(resolvedPath, context);
+ }
+ }
+
+ void AtomToolsApplication::LoadSettings()
+ {
+ AZ::SerializeContext* context = nullptr;
+ AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext);
+ AZ_Assert(context, "No serialize context");
+
+ char resolvedPath[AZ_MAX_PATH_LEN] = "";
+ AZStd::string fileName = "@user@/" + GetBuildTargetName() + "UserSettings.xml";
+
+ AZ::IO::FileIOBase::GetInstance()->ResolvePath(fileName.c_str(), resolvedPath, AZ_MAX_PATH_LEN);
+
+ m_localUserSettings.Load(resolvedPath, context);
+ m_localUserSettings.Activate(AZ::UserSettings::CT_LOCAL);
+ AZ::UserSettingsOwnerRequestBus::Handler::BusConnect(AZ::UserSettings::CT_LOCAL);
+ m_activatedLocalUserSettings = true;
+ }
+
+ void AtomToolsApplication::UnloadSettings()
+ {
+ if (m_activatedLocalUserSettings)
+ {
+ SaveSettings();
+ m_localUserSettings.Deactivate();
+ AZ::UserSettingsOwnerRequestBus::Handler::BusDisconnect();
+ m_activatedLocalUserSettings = false;
+ }
+ }
+
+ void AtomToolsApplication::ProcessCommandLine(const AZ::CommandLine& commandLine)
+ {
+ const AZStd::string timeoputSwitchName = "timeout";
+ if (commandLine.HasSwitch(timeoputSwitchName))
+ {
+ const AZStd::string& timeoutValue = commandLine.GetSwitchValue(timeoputSwitchName, 0);
+ const uint32_t timeoutInMs = atoi(timeoutValue.c_str());
+ AZ_Printf(GetBuildTargetName().c_str(), "Timeout scheduled, shutting down in %u ms", timeoutInMs);
+ QTimer::singleShot(
+ timeoutInMs,
+ [this]
+ {
+ AZ_Printf(GetBuildTargetName().c_str(), "Timeout reached, shutting down");
+ ExitMainLoop();
+ });
+ }
+
+ // Process command line options for running one or more python scripts on startup
+ const AZStd::string runPythonScriptSwitchName = "runpython";
+ size_t runPythonScriptCount = commandLine.GetNumSwitchValues(runPythonScriptSwitchName);
+ for (size_t runPythonScriptIndex = 0; runPythonScriptIndex < runPythonScriptCount; ++runPythonScriptIndex)
+ {
+ const AZStd::string runPythonScriptPath = commandLine.GetSwitchValue(runPythonScriptSwitchName, runPythonScriptIndex);
+ AZStd::vector runPythonArgs;
+
+ AZ_Printf(GetBuildTargetName().c_str(), "Launching script: %s", runPythonScriptPath.c_str());
+ AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
+ &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, runPythonScriptPath, runPythonArgs);
+ }
+
+ const AZStd::string exitAfterCommandsSwitchName = "exitaftercommands";
+ if (commandLine.HasSwitch(exitAfterCommandsSwitchName))
+ {
+ ExitMainLoop();
+ }
+ }
+
+ bool AtomToolsApplication::LaunchDiscoveryService()
+ {
+ // Determine if this is the first launch of the tool by attempting to connect to a running server
+ if (m_socket.Connect(QApplication::applicationName()))
+ {
+ // If the server was located, the application is already running.
+ // Forward commandline options to other application instance.
+ QByteArray buffer;
+ buffer.append("ProcessCommandLine:");
+
+ // Add the command line options from this process to the message, skipping the executable path
+ for (int argi = 1; argi < m_argC; ++argi)
+ {
+ buffer.append(QString(m_argV[argi]).append("\n").toUtf8());
+ }
+
+ // Inject command line option to always bring the main window to the foreground
+ buffer.append("--activatewindow\n");
+
+ m_socket.Send(buffer);
+ m_socket.Disconnect();
+ return false;
+ }
+
+ // Setup server to handle basic commands
+ m_server.SetReadHandler(
+ [this](const QByteArray& buffer)
+ {
+ // Handle commmand line params from connected socket
+ if (buffer.startsWith("ProcessCommandLine:"))
+ {
+ // Remove header and parse commands
+ AZStd::string params(buffer.data(), buffer.size());
+ params = params.substr(strlen("ProcessCommandLine:"));
+
+ AZStd::vector tokens;
+ AZ::StringFunc::Tokenize(params, tokens, "\n");
+
+ if (!tokens.empty())
+ {
+ AZ::CommandLine commandLine;
+ commandLine.Parse(tokens);
+ ProcessCommandLine(commandLine);
+ }
+ }
+ });
+
+ // Launch local server
+ if (!m_server.Connect(QApplication::applicationName()))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void AtomToolsApplication::StartInternal()
+ {
+ if (WasExitMainLoopRequested())
+ {
+ return;
+ }
+
+ AZStd::string fileName = GetBuildTargetName() + ".log";
+
+ m_traceLogger.WriteStartupLog(fileName.c_str());
+
+ if (!LaunchDiscoveryService())
+ {
+ ExitMainLoop();
+ return;
+ }
+
+ AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect();
+ AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast(
+ &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized);
+
+ AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml");
+
+ AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets();
+
+ LoadSettings();
+
+ auto editorPythonEventsInterface = AZ::Interface::Get();
+ if (editorPythonEventsInterface)
+ {
+ // The PythonSystemComponent does not call StartPython to allow for lazy python initialization, so start it here
+ // The PythonSystemComponent will call StopPython when it deactivates, so we do not need our own corresponding call to
+ // StopPython
+ editorPythonEventsInterface->StartPython();
+ }
+
+ // Delay execution of commands and scripts post initialization
+ QTimer::singleShot(
+ 0,
+ [this]()
+ {
+ ProcessCommandLine(m_commandLine);
+ });
+ }
+
+ bool AtomToolsApplication::GetAssetDatabaseLocation(AZStd::string& result)
+ {
+ AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get();
+ AZ::IO::FixedMaxPath assetDatabaseSqlitePath;
+ if (settingsRegistry &&
+ settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder))
+ {
+ assetDatabaseSqlitePath /= "assetdb.sqlite";
+ result = AZStd::string_view(assetDatabaseSqlitePath.Native());
+ return true;
+ }
+
+ return false;
+ }
+
+ void AtomToolsApplication::Tick(float deltaOverride)
+ {
+ TickSystem();
+ Base::Tick(deltaOverride);
+
+ if (WasExitMainLoopRequested())
+ {
+ m_timer.disconnect();
+ quit();
+ }
+ }
+
+ void AtomToolsApplication::Stop()
+ {
+ UnloadSettings();
+ Base::Stop();
+ }
+
+ void AtomToolsApplication::QueryApplicationType(AZ::ApplicationTypeQuery& appType) const
+ {
+ appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Game;
+ }
+
+ void AtomToolsApplication::OnTraceMessage([[maybe_unused]] AZStd::string_view message)
+ {
+#if defined(AZ_ENABLE_TRACING)
+ AZStd::vector lines;
+ AzFramework::StringFunc::Tokenize(
+ message, lines, "\n",
+ false, // Keep empty strings
+ false // Keep space strings
+ );
+
+ for (auto& line : lines)
+ {
+ AZ_TracePrintf(GetBuildTargetName().c_str(), "Python: %s\n", line.c_str());
+ }
+#endif
+ }
+
+ void AtomToolsApplication::OnErrorMessage(AZStd::string_view message)
+ {
+ // Use AZ_TracePrintf instead of AZ_Error or AZ_Warning to avoid all the metadata noise
+ OnTraceMessage(message);
+ }
+
+ void AtomToolsApplication::OnExceptionMessage([[maybe_unused]] AZStd::string_view message)
+ {
+ AZ_Error(GetBuildTargetName().c_str(), false, "Python: " AZ_STRING_FORMAT, AZ_STRING_ARG(message));
+ }
+
+ // Copied from PyIdleWaitFrames in CryEdit.cpp
+ void AtomToolsApplication::PyIdleWaitFrames(uint32_t frames)
+ {
+ struct Ticker : public AZ::TickBus::Handler
+ {
+ Ticker(QEventLoop* loop, uint32_t targetFrames)
+ : m_loop(loop)
+ , m_targetFrames(targetFrames)
+ {
+ AZ::TickBus::Handler::BusConnect();
+ }
+ ~Ticker()
+ {
+ AZ::TickBus::Handler::BusDisconnect();
+ }
+
+ void OnTick(float deltaTime, AZ::ScriptTimePoint time) override
+ {
+ AZ_UNUSED(deltaTime);
+ AZ_UNUSED(time);
+ if (++m_elapsedFrames == m_targetFrames)
+ {
+ m_loop->quit();
+ }
+ }
+ QEventLoop* m_loop = nullptr;
+ uint32_t m_elapsedFrames = 0;
+ uint32_t m_targetFrames = 0;
+ };
+
+ QEventLoop loop;
+ Ticker ticker(&loop, frames);
+ loop.exec();
+ }
+} // namespace AtomToolsFramework
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake
index dfe222bfc5..86fc3f5f5e 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake
@@ -7,6 +7,7 @@
#
set(FILES
+ Include/AtomToolsFramework/Application/AtomToolsApplication.h
Include/AtomToolsFramework/Communication/LocalServer.h
Include/AtomToolsFramework/Communication/LocalSocket.h
Include/AtomToolsFramework/Debug/TraceRecorder.h
@@ -23,6 +24,7 @@ set(FILES
Include/AtomToolsFramework/Viewport/RenderViewportWidget.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h
+ Source/Application/AtomToolsApplication.cpp
Source/Communication/LocalServer.cpp
Source/Communication/LocalSocket.cpp
Source/Debug/TraceRecorder.cpp
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp
index 10ad1df5f3..0977694b90 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp
@@ -8,56 +8,53 @@
#include
#include
-#include
+#include
+#include
#include
#include
-#include
-
-#include
+#include
#include
#include
-#include
-#include
-#include
-#include
#include
#include
+#include
+#include
+#include
+#include
#include
#include
-#include
+#include
+#include
#include
+#include
#include
#include
-#include
+#include
+#include
+#include
+#include
+#include
+
+#include
#include
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
-#include
#include
+#include
AZ_POP_DISABLE_WARNING
namespace MaterialEditor
{
//! This function returns the build system target name of "MaterialEditor
- AZStd::string_view GetBuildTargetName()
+ AZStd::string MaterialEditorApplication::GetBuildTargetName() const
{
-#if !defined (LY_CMAKE_TARGET)
+#if !defined(LY_CMAKE_TARGET)
#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target"
#endif
- return AZStd::string_view{ LY_CMAKE_TARGET };
+ return AZStd::string{ LY_CMAKE_TARGET };
}
const char* MaterialEditorApplication::GetCurrentConfigurationName() const
@@ -72,19 +69,12 @@ namespace MaterialEditor
}
MaterialEditorApplication::MaterialEditorApplication(int* argc, char*** argv)
- : Application(argc, argv)
- , AzQtApplication(*argc, *argv)
+ : AtomToolsApplication(argc, argv)
{
QApplication::setApplicationName("O3DE Material Editor");
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(
*AZ::SettingsRegistry::Get(), GetBuildTargetName());
-
- connect(&m_timer, &QTimer::timeout, this, [&]()
- {
- this->PumpSystemEventLoopUntilEmpty();
- this->Tick();
- });
}
MaterialEditorApplication::~MaterialEditorApplication()
@@ -94,88 +84,14 @@ namespace MaterialEditor
AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
}
- void MaterialEditorApplication::CreateReflectionManager()
- {
- Application::CreateReflectionManager();
- GetSerializeContext()->CreateEditContext();
- }
-
- void MaterialEditorApplication::Reflect(AZ::ReflectContext* context)
- {
- Application::Reflect(context);
-
- AzToolsFramework::AssetBrowser::AssetBrowserEntry::Reflect(context);
- AzToolsFramework::AssetBrowser::RootAssetBrowserEntry::Reflect(context);
- AzToolsFramework::AssetBrowser::FolderAssetBrowserEntry::Reflect(context);
- AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry::Reflect(context);
- AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry::Reflect(context);
-
- AzToolsFramework::QTreeViewWithStateSaving::Reflect(context);
- AzToolsFramework::QWidgetSavedState::Reflect(context);
-
- if (auto behaviorContext = azrtti_cast(context))
- {
- // this will put these methods into the 'azlmbr.materialeditor.general' module
- auto addGeneral = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder)
- {
- methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
- ->Attribute(AZ::Script::Attributes::Category, "Editor")
- ->Attribute(AZ::Script::Attributes::Module, "materialeditor.general");
- };
- // The reflection here is based on patterns in CryEditPythonHandler::Reflect
- addGeneral(behaviorContext->Method("idle_wait_frames", &MaterialEditorApplication::PyIdleWaitFrames, nullptr, "Waits idling for a frames. Primarily used for auto-testing."));
- }
- }
-
- void MaterialEditorApplication::RegisterCoreComponents()
- {
- Application::RegisterCoreComponents();
- RegisterComponentDescriptor(AzToolsFramework::AssetBrowser::AssetBrowserComponent::CreateDescriptor());
- RegisterComponentDescriptor(AzToolsFramework::Thumbnailer::ThumbnailerComponent::CreateDescriptor());
- RegisterComponentDescriptor(AzToolsFramework::Components::PropertyManagerComponent::CreateDescriptor());
- RegisterComponentDescriptor(AzToolsFramework::AssetSystem::AssetSystemComponent::CreateDescriptor());
- RegisterComponentDescriptor(AzToolsFramework::PerforceComponent::CreateDescriptor());
- }
-
- AZ::ComponentTypeList MaterialEditorApplication::GetRequiredSystemComponents() const
- {
- AZ::ComponentTypeList components = Application::GetRequiredSystemComponents();
-
- components.insert(components.end(), {
- azrtti_typeid(),
- azrtti_typeid(),
- azrtti_typeid(),
- azrtti_typeid(),
- });
-
- return components;
- }
-
void MaterialEditorApplication::CreateStaticModules(AZStd::vector& outModules)
{
- Application::CreateStaticModules(outModules);
- outModules.push_back(aznew AzToolsFramework::AzToolsFrameworkModule);
+ Base::CreateStaticModules(outModules);
outModules.push_back(aznew MaterialDocumentModule);
outModules.push_back(aznew MaterialViewportModule);
outModules.push_back(aznew MaterialEditorWindowModule);
}
- void MaterialEditorApplication::StartCommon(AZ::Entity* systemEntity)
- {
- {
- //[GFX TODO][ATOM-408] This needs to be updated in some way to support the MaterialViewport render widget
- }
-
- AzFramework::AssetSystemStatusBus::Handler::BusConnect();
- AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect();
-
- AzFramework::Application::StartCommon(systemEntity);
-
- StartInternal();
-
- m_timer.start();
- }
-
void MaterialEditorApplication::OnMaterialEditorWindowClosing()
{
ExitMainLoop();
@@ -187,120 +103,14 @@ namespace MaterialEditor
MaterialEditor::MaterialEditorWindowFactoryRequestBus::Broadcast(
&MaterialEditor::MaterialEditorWindowFactoryRequestBus::Handler::DestroyMaterialEditorWindow);
- AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
- AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect();
MaterialEditorWindowNotificationBus::Handler::BusDisconnect();
- AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
- m_logFile = {};
- m_startupLogSink = {};
-
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::StartDisconnectingAssetProcessor);
- Application::Destroy();
+ Base::Destroy();
}
- void MaterialEditorApplication::AssetSystemAvailable()
+ AZStd::vector MaterialEditorApplication::GetCriticalAssetFilters() const
{
- bool connectedToAssetProcessor = false;
-
- // When the AssetProcessor is already launched it should take less than a second to perform a connection
- // but when the AssetProcessor needs to be launch it could take up to 15 seconds to have the AssetProcessor initialize
- // and able to negotiate a connection when running a debug build
- // and to negotiate a connection
-
- AzFramework::AssetSystem::ConnectionSettings connectionSettings;
- AzFramework::AssetSystem::ReadConnectionSettingsFromSettingsRegistry(connectionSettings);
- connectionSettings.m_connectionDirection = AzFramework::AssetSystem::ConnectionSettings::ConnectionDirection::ConnectToAssetProcessor;
- connectionSettings.m_connectionIdentifier = "MaterialEditor";
- connectionSettings.m_loggingCallback = []([[maybe_unused]] AZStd::string_view logData)
- {
- AZ_TracePrintf("Material Editor", "%.*s", aznumeric_cast(logData.size()), logData.data());
- };
- AzFramework::AssetSystemRequestBus::BroadcastResult(connectedToAssetProcessor,
- &AzFramework::AssetSystemRequestBus::Events::EstablishAssetProcessorConnection, connectionSettings);
- if (connectedToAssetProcessor)
- {
- CompileCriticalAssets();
- }
-
- AzFramework::AssetSystemStatusBus::Handler::BusDisconnect();
- }
-
-
- void MaterialEditorApplication::CompileCriticalAssets()
- {
- AZ_TracePrintf("MaterialEditor", "Compiling critical assets.\n");
-
- // List of common asset filters for things that need to be compiled to run the material editor
- // Some of these things will not be necessary once we have proper support for queued asset loading and reloading
- const AZStd::string assetFiltersArray[] =
- {
- "passes/",
- "config/",
- "MaterialEditor/",
- };
-
- QStringList failedAssets;
-
- // Forced asset processor to synchronously process all critical assets
- // Note: with AssetManager's current implementation, a compiled asset won't be added in asset registry until next system tick.
- // So the asset id won't be found right after CompileAssetSync call.
- for (const AZStd::string& assetFilters : assetFiltersArray)
- {
- AZ_TracePrintf("MaterialEditor", "Compiling critical asset matching: %s.\n", assetFilters.c_str());
-
- // Wait for the asset be compiled
- AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown;
- AzFramework::AssetSystemRequestBus::BroadcastResult(
- status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, assetFilters);
- if (status != AzFramework::AssetSystem::AssetStatus_Compiled)
- {
- failedAssets.append(assetFilters.c_str());
- }
- }
-
- if (!failedAssets.empty())
- {
- QMessageBox::critical(activeWindow(),
- QString("Failed to compile critical assets"),
- QString("Failed to compile the following critical assets:\n%1\n%2")
- .arg(failedAssets.join(",\n"))
- .arg("Make sure this is an Atom project."));
- ExitMainLoop();
- }
- }
-
- void MaterialEditorApplication::SaveSettings()
- {
- if (m_activatedLocalUserSettings)
- {
- AZ::SerializeContext* context = nullptr;
- AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext);
- AZ_Assert(context, "No serialize context");
-
- char resolvedPath[AZ_MAX_PATH_LEN] = "";
- AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/MaterialEditorUserSettings.xml", resolvedPath, AZ_ARRAY_SIZE(resolvedPath));
- m_localUserSettings.Save(resolvedPath, context);
- }
- }
-
- bool MaterialEditorApplication::OnOutput(const char* window, const char* message)
- {
- // Suppress spam from the Source Control system
- if (0 == strncmp(window, AzToolsFramework::SCC_WINDOW, AZ_ARRAY_SIZE(AzToolsFramework::SCC_WINDOW)))
- {
- return true;
- }
-
- if (m_logFile)
- {
- m_logFile->AppendLog(AzFramework::LogFile::SEV_NORMAL, window, message);
- }
- else
- {
- m_startupLogSink.push_back({ window, message });
- }
- return false;
+ return AZStd::vector({ "passes/", "config/", "MaterialEditor" });
}
void MaterialEditorApplication::ProcessCommandLine(const AZ::CommandLine& commandLine)
@@ -312,195 +122,27 @@ namespace MaterialEditor
&MaterialEditor::MaterialEditorWindowRequestBus::Handler::ActivateWindow);
}
- const AZStd::string timeoputSwitchName = "timeout";
- if (commandLine.HasSwitch(timeoputSwitchName))
- {
- const AZStd::string& timeoutValue = commandLine.GetSwitchValue(timeoputSwitchName, 0);
- const uint32_t timeoutInMs = atoi(timeoutValue.c_str());
- AZ_Printf("MaterialEditor", "Timeout scheduled, shutting down in %u ms", timeoutInMs);
- QTimer::singleShot(timeoutInMs, [this] {
- AZ_Printf("MaterialEditor", "Timeout reached, shutting down");
- ExitMainLoop();
- });
- }
-
- // Process command line options for running one or more python scripts on startup
- const AZStd::string runPythonScriptSwitchName = "runpython";
- size_t runPythonScriptCount = commandLine.GetNumSwitchValues(runPythonScriptSwitchName);
- for (size_t runPythonScriptIndex = 0; runPythonScriptIndex < runPythonScriptCount; ++runPythonScriptIndex)
- {
- const AZStd::string runPythonScriptPath = commandLine.GetSwitchValue(runPythonScriptSwitchName, runPythonScriptIndex);
- AZStd::vector runPythonArgs;
-
- AZ_Printf("MaterialEditor", "Launching script: %s", runPythonScriptPath.c_str());
- AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
- &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
- runPythonScriptPath,
- runPythonArgs);
- }
-
// Process command line options for opening one or more material documents on startup
size_t openDocumentCount = commandLine.GetNumMiscValues();
for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex)
{
const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex);
- AZ_Printf("MaterialEditor", "Opening document: %s", openDocumentPath.c_str());
+ AZ_Printf(GetBuildTargetName().c_str(), "Opening document: %s", openDocumentPath.c_str());
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
}
- const AZStd::string exitAfterCommandsSwitchName = "exitaftercommands";
- if (commandLine.HasSwitch(exitAfterCommandsSwitchName))
- {
- ExitMainLoop();
- }
- }
-
- void MaterialEditorApplication::LoadSettings()
- {
- AZ::SerializeContext* context = nullptr;
- AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext);
- AZ_Assert(context, "No serialize context");
-
- char resolvedPath[AZ_MAX_PATH_LEN] = "";
- AZ::IO::FileIOBase::GetInstance()->ResolvePath("@user@/EditorUserSettings.xml", resolvedPath, AZ_MAX_PATH_LEN);
-
- m_localUserSettings.Load(resolvedPath, context);
- m_localUserSettings.Activate(AZ::UserSettings::CT_LOCAL);
- AZ::UserSettingsOwnerRequestBus::Handler::BusConnect(AZ::UserSettings::CT_LOCAL);
- m_activatedLocalUserSettings = true;
- }
-
- void MaterialEditorApplication::UnloadSettings()
- {
- if (m_activatedLocalUserSettings)
- {
- SaveSettings();
- m_localUserSettings.Deactivate();
- AZ::UserSettingsOwnerRequestBus::Handler::BusDisconnect();
- m_activatedLocalUserSettings = false;
- }
- }
-
- bool MaterialEditorApplication::LaunchDiscoveryService()
- {
- // Determine if this is the first launch of the tool by attempting to connect to a running server
- if (m_socket.Connect(QApplication::applicationName()))
- {
- // If the server was located, the application is already running.
- // Forward commandline options to other application instance.
- QByteArray buffer;
- buffer.append("ProcessCommandLine:");
-
- // Add the command line options from this process to the message, skipping the executable path
- for (int argi = 1; argi < m_argC; ++argi)
- {
- buffer.append(QString(m_argV[argi]).append("\n").toUtf8());
- }
-
- // Inject command line option to always bring the main window to the foreground
- buffer.append("--activatewindow\n");
-
- m_socket.Send(buffer);
- m_socket.Disconnect();
- return false;
- }
-
- // Setup server to handle basic commands
- m_server.SetReadHandler([this](const QByteArray& buffer) {
- // Handle commmand line params from connected socket
- if (buffer.startsWith("ProcessCommandLine:"))
- {
- // Remove header and parse commands
- AZStd::string params(buffer.data(), buffer.size());
- params = params.substr(strlen("ProcessCommandLine:"));
-
- AZStd::vector tokens;
- AZ::StringFunc::Tokenize(params, tokens, "\n");
-
- if (!tokens.empty())
- {
- AZ::CommandLine commandLine;
- commandLine.Parse(tokens);
- ProcessCommandLine(commandLine);
- }
- }
- });
-
- // Launch local server
- if (!m_server.Connect(QApplication::applicationName()))
- {
- return false;
- }
-
- return true;
+ Base::ProcessCommandLine(commandLine);
}
void MaterialEditorApplication::StartInternal()
{
- if (WasExitMainLoopRequested())
- {
- return;
- }
-
- m_traceLogger.WriteStartupLog("MaterialEditor.log");
-
- if (!LaunchDiscoveryService())
- {
- ExitMainLoop();
- return;
- }
-
- AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect();
- AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast(&AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized);
-
- AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml");
-
- AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets();
-
- LoadSettings();
+ Base::StartInternal();
MaterialEditorWindowNotificationBus::Handler::BusConnect();
MaterialEditor::MaterialEditorWindowFactoryRequestBus::Broadcast(
&MaterialEditor::MaterialEditorWindowFactoryRequestBus::Handler::CreateMaterialEditorWindow);
-
- auto editorPythonEventsInterface = AZ::Interface::Get();
- if (editorPythonEventsInterface)
- {
- // The PythonSystemComponent does not call StartPython to allow for lazy python initialization, so start it here
- // The PythonSystemComponent will call StopPython when it deactivates, so we do not need our own corresponding call to StopPython
- editorPythonEventsInterface->StartPython();
- }
-
- // Delay execution of commands and scripts post initialization
- QTimer::singleShot(0, [this]() { ProcessCommandLine(m_commandLine); });
- }
-
- bool MaterialEditorApplication::GetAssetDatabaseLocation(AZStd::string& result)
- {
- AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get();
- AZ::IO::FixedMaxPath assetDatabaseSqlitePath;
- if (settingsRegistry && settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder))
- {
- assetDatabaseSqlitePath /= "assetdb.sqlite";
- result = AZStd::string_view(assetDatabaseSqlitePath.Native());
- return true;
- }
-
- return false;
- }
-
- void MaterialEditorApplication::Tick(float deltaOverride)
- {
- TickSystem();
- Application::Tick(deltaOverride);
-
- if (WasExitMainLoopRequested())
- {
- m_timer.disconnect();
- quit();
- }
}
void MaterialEditorApplication::Stop()
@@ -508,76 +150,6 @@ namespace MaterialEditor
MaterialEditor::MaterialEditorWindowFactoryRequestBus::Broadcast(
&MaterialEditor::MaterialEditorWindowFactoryRequestBus::Handler::DestroyMaterialEditorWindow);
- UnloadSettings();
- AzFramework::Application::Stop();
+ Base::Stop();
}
-
- void MaterialEditorApplication::QueryApplicationType(AZ::ApplicationTypeQuery& appType) const
- {
- appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Game;
- }
-
- void MaterialEditorApplication::OnTraceMessage([[maybe_unused]] AZStd::string_view message)
- {
-#if defined(AZ_ENABLE_TRACING)
- AZStd::vector lines;
- AzFramework::StringFunc::Tokenize(
- message,
- lines,
- "\n",
- false, // Keep empty strings
- false // Keep space strings
- );
-
- for (auto& line : lines)
- {
- AZ_TracePrintf("MaterialEditor", "Python: %s\n", line.c_str());
- }
-#endif
- }
-
- void MaterialEditorApplication::OnErrorMessage(AZStd::string_view message)
- {
- // Use AZ_TracePrintf instead of AZ_Error or AZ_Warning to avoid all the metadata noise
- OnTraceMessage(message);
- }
-
- void MaterialEditorApplication::OnExceptionMessage([[maybe_unused]] AZStd::string_view message)
- {
- AZ_Error("MaterialEditor", false, "Python: " AZ_STRING_FORMAT, AZ_STRING_ARG(message));
- }
-
- // Copied from PyIdleWaitFrames in CryEdit.cpp
- void MaterialEditorApplication::PyIdleWaitFrames(uint32_t frames)
- {
- struct Ticker : public AZ::TickBus::Handler
- {
- Ticker(QEventLoop* loop, uint32_t targetFrames) : m_loop(loop), m_targetFrames(targetFrames)
- {
- AZ::TickBus::Handler::BusConnect();
- }
- ~Ticker()
- {
- AZ::TickBus::Handler::BusDisconnect();
- }
-
- void OnTick(float deltaTime, AZ::ScriptTimePoint time) override
- {
- AZ_UNUSED(deltaTime);
- AZ_UNUSED(time);
- if (++m_elapsedFrames == m_targetFrames)
- {
- m_loop->quit();
- }
- }
- QEventLoop* m_loop = nullptr;
- uint32_t m_elapsedFrames = 0;
- uint32_t m_targetFrames = 0;
- };
-
- QEventLoop loop;
- Ticker ticker(&loop, frames);
- loop.exec();
- }
-
} // namespace MaterialEditor
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h
index e6fe9401f6..ec2a48288c 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h
@@ -10,19 +10,7 @@
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
#include
@@ -31,41 +19,24 @@ namespace MaterialEditor
class MaterialThumbnailRenderer;
class MaterialEditorApplication
- : public AzFramework::Application
- , public AzQtComponents::AzQtApplication
- , private AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler
+ : public AtomToolsFramework::AtomToolsApplication
, private MaterialEditorWindowNotificationBus::Handler
- , private AzFramework::AssetSystemStatusBus::Handler
- , private AZ::UserSettingsOwnerRequestBus::Handler
- , private AZ::Debug::TraceMessageBus::Handler
- , private AzToolsFramework::EditorPythonConsoleNotificationBus::Handler
{
public:
AZ_TYPE_INFO(MaterialEditor::MaterialEditorApplication, "{30F90CA5-1253-49B5-8143-19CEE37E22BB}");
- using Base = AzFramework::Application;
+ using Base = AtomToolsFramework::AtomToolsApplication;
MaterialEditorApplication(int* argc, char*** argv);
virtual ~MaterialEditorApplication();
//////////////////////////////////////////////////////////////////////////
// AzFramework::Application
- void CreateReflectionManager() override;
- void Reflect(AZ::ReflectContext* context) override;
- void RegisterCoreComponents() override;
- AZ::ComponentTypeList GetRequiredSystemComponents() const override;
void CreateStaticModules(AZStd::vector& outModules) override;
const char* GetCurrentConfigurationName() const override;
- void StartCommon(AZ::Entity* systemEntity) override;
- void Tick(float deltaOverride = -1.f) override;
void Stop() override;
private:
- //////////////////////////////////////////////////////////////////////////
- // AssetDatabaseRequestsBus::Handler overrides...
- bool GetAssetDatabaseLocation(AZStd::string& result) override;
- //////////////////////////////////////////////////////////////////////////
-
//////////////////////////////////////////////////////////////////////////
// MaterialEditorWindowNotificationBus::Handler overrides...
void OnMaterialEditorWindowClosing() override;
@@ -76,66 +47,9 @@ namespace MaterialEditor
void Destroy() override;
//////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // AZ::ComponentApplication overrides...
- void QueryApplicationType(AZ::ApplicationTypeQuery& appType) const override;
- //////////////////////////////////////////////////////////////////////////
-
- ////////////////////////////////////////////////////////////////////////
- // EditorPythonConsoleNotificationBus::Handler overrides...
- void OnTraceMessage(AZStd::string_view message) override;
- void OnErrorMessage(AZStd::string_view message) override;
- void OnExceptionMessage(AZStd::string_view message) override;
- ////////////////////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////////////////////
- // AzFramework::AssetSystemStatusBus::Handler overrides...
- void AssetSystemAvailable() override;
- //////////////////////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////////////////////
- // AZ::UserSettingsOwnerRequestBus::Handler overrides...
- void SaveSettings() override;
- //////////////////////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////////////////////
- // AZ::Debug::TraceMessageBus::Handler overrides...
- bool OnOutput(const char* window, const char* message) override;
- //////////////////////////////////////////////////////////////////////////
-
- void CompileCriticalAssets();
-
- void ProcessCommandLine(const AZ::CommandLine& commandLine);
-
- void LoadSettings();
- void UnloadSettings();
-
- bool LaunchDiscoveryService();
-
- void StartInternal();
-
- static void PyIdleWaitFrames(uint32_t frames);
-
- struct LogMessage
- {
- AZStd::string window;
- AZStd::string message;
- };
-
- AZStd::vector m_startupLogSink;
- AZStd::unique_ptr m_logFile;
-
- AzToolsFramework::TraceLogger m_traceLogger;
-
- //! Local user settings are used to store material browser tree expansion state
- AZ::UserSettingsProvider m_localUserSettings;
-
- //! Are local settings loaded
- bool m_activatedLocalUserSettings = false;
-
- QTimer m_timer;
-
- AtomToolsFramework::LocalSocket m_socket;
- AtomToolsFramework::LocalServer m_server;
- };
+ void ProcessCommandLine(const AZ::CommandLine& commandLine) override;
+ void StartInternal() override;
+ AZStd::string GetBuildTargetName() const override;
+ AZStd::vector GetCriticalAssetFilters() const override;
+ };
} // namespace MaterialEditor
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp
index 461beffd06..23e37b2f7c 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp
@@ -324,7 +324,7 @@ namespace MaterialEditor
{
if (!preset)
{
- AZ_Error("MaterialViewportRenderer", false, "Attempting to set invalid lighting preset.");
+ AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid lighting preset.");
return;
}
@@ -365,13 +365,13 @@ namespace MaterialEditor
{
if (!preset)
{
- AZ_Error("MaterialViewportRenderer", false, "Attempting to set invalid model preset.");
+ AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid model preset.");
return;
}
if (!preset->m_modelAsset.GetId().IsValid())
{
- AZ_Error("MaterialViewportRenderer", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str());
+ AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str());
return;
}
diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp
index a39480637b..7e09f88f4f 100644
--- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp
+++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp
@@ -6,51 +6,48 @@
*
*/
-#include
+#include
+#include
+#include
#include
#include
-
-#include
+#include