From f92daf060bdd2ccd37ef095b6d3d388e4b5eb379 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 23 Sep 2021 12:41:26 -0700 Subject: [PATCH 01/33] Working on exposing the doubles-sided flag outside the Opacity property group. Before, the only way to set the double-sided flag was to enable a non-opaque mode, because the flag was hidden. We are moving the double-sided flag to the general property group instead of the opacity property group, so it is always available. In this particular commit, we just add the general.doubleSided property so we don't break existing data. In an upcoming commit I will remove opacity.doubleSided, once we have the material backward compatibility system ready. I also added another "default" texture map to the Common/Feature gem that is directional, so better for understanding UV/tangent space. These were copied from the AtomLyIntegration gem. This is being used for a screenshot test in AtomSampleViewer with the new 009_Opacity_Opaque_DoubleSided.material. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Materials/Types/EnhancedPBR.materialtype | 6 ++++++ .../Materials/Types/StandardPBR.materialtype | 6 ++++++ .../Types/StandardPBR_HandleOpacityDoubleSided.lua | 8 +++++--- .../Assets/Textures/Default/checker_basecolor.tif | 3 +++ .../Textures/Default/checker_uv_basecolor.png | 3 +++ .../009_Opacity_Opaque_DoubleSided.material | 14 ++++++++++++++ Gems/Atom/TestData/TestData/Objects/tube.fbx | 3 +++ 7 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Textures/Default/checker_basecolor.tif create mode 100644 Gems/Atom/Feature/Common/Assets/Textures/Default/checker_uv_basecolor.png create mode 100644 Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Opaque_DoubleSided.material create mode 100644 Gems/Atom/TestData/TestData/Objects/tube.fbx diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index 9b2c465352..66b88fddf9 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -92,6 +92,12 @@ ], "properties": { "general": [ + { + "id": "doubleSided", + "displayName": "Double-sided", + "description": "Whether to render back-faces or just front-faces.", + "type": "Bool" + }, { "id": "applySpecularAA", "displayName": "Apply Specular AA", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 8b7e4b1c7e..4038a2465d 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -72,6 +72,12 @@ ], "properties": { "general": [ + { + "id": "doubleSided", + "displayName": "Double-sided", + "description": "Whether to render back-faces or just front-faces.", + "type": "Bool" + }, { "id": "applySpecularAA", "displayName": "Apply Specular AA", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua index 2382f3f0f0..8b3bd2b91b 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua @@ -10,17 +10,19 @@ ---------------------------------------------------------------------------------------------------- function GetMaterialPropertyDependencies() - return {"opacity.doubleSided"} + return {"general.doubleSided", "opacity.doubleSided", "opacity.mode"} end ForwardPassIndex = 0 ForwardPassEdsIndex = 1 function Process(context) - local doubleSided = context:GetMaterialPropertyValue_bool("opacity.doubleSided") + local doubleSided = context:GetMaterialPropertyValue_bool("general.doubleSided") + local opacityDoubleSided = context:GetMaterialPropertyValue_bool("opacity.doubleSided") + local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") local lastShader = context:GetShaderCount() - 1; - if(doubleSided) then + if(doubleSided or (opacityDoubleSided and opacityMode ~= 0)) then for i=0,lastShader do context:GetShader(i):GetRenderStatesOverride():SetCullMode(CullMode_None) end diff --git a/Gems/Atom/Feature/Common/Assets/Textures/Default/checker_basecolor.tif b/Gems/Atom/Feature/Common/Assets/Textures/Default/checker_basecolor.tif new file mode 100644 index 0000000000..5abe5bbd49 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Textures/Default/checker_basecolor.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57d6744696768f9fb8a5fe5fee9aa36fee1eb87a9dbc1e60d4a35ed3c39d68e6 +size 810620 diff --git a/Gems/Atom/Feature/Common/Assets/Textures/Default/checker_uv_basecolor.png b/Gems/Atom/Feature/Common/Assets/Textures/Default/checker_uv_basecolor.png new file mode 100644 index 0000000000..07e240baf9 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Textures/Default/checker_uv_basecolor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:513f47f6fea5105f603170a8881b7e3b1cd2c4258636d64a6399c725032b500d +size 38689 diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Opaque_DoubleSided.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Opaque_DoubleSided.material new file mode 100644 index 0000000000..a26bf6e045 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Opaque_DoubleSided.material @@ -0,0 +1,14 @@ +{ + "description": "", + "materialType": "Materials/Types/StandardPBR.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 3, + "properties": { + "baseColor": { + "textureMap": "Textures/Default/checker_uv_basecolor.png" + }, + "general": { + "doubleSided": true + } + } +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Objects/tube.fbx b/Gems/Atom/TestData/TestData/Objects/tube.fbx new file mode 100644 index 0000000000..f9034e7641 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Objects/tube.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2ecc32cd3052f3cb5836c8be7bf5cba54d98f46e6a0eeac95aaef00a123411a +size 27340 From 720495748ef91d4af3d0542288855b526680c6b4 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 23 Sep 2021 12:42:10 -0700 Subject: [PATCH 02/33] Since I was already working with _dev_shaderball_00_basecolor.png from AtomLyIntegration gem, I went ahead and updated the one in MaterialEditor to match, because I noticed that the one from AtomLyIntegration was a bit nicer, having colored arrays instead of low contrast gray ones. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../ViewportModels/_dev_shaderball_00_basecolor.png | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/_dev_shaderball_00_basecolor.png b/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/_dev_shaderball_00_basecolor.png index 415ca3e521..07e240baf9 100644 --- a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/_dev_shaderball_00_basecolor.png +++ b/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/ViewportModels/_dev_shaderball_00_basecolor.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:93a7e033d9fb0fcac221647322bde03716643d789390f79078c4fcc37ecfd005 -size 68327 +oid sha256:513f47f6fea5105f603170a8881b7e3b1cd2c4258636d64a6399c725032b500d +size 38689 From 99b840652d22a67ce50c5f2312cd6d3c5cb9a76b Mon Sep 17 00:00:00 2001 From: John Date: Mon, 25 Oct 2021 13:40:12 +0100 Subject: [PATCH 03/33] Add Focus Mode integration tests. Signed-off-by: John --- .../Viewport/ViewportEditorModeTests.cpp | 130 +++++++++++++++++- 1 file changed, 125 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index db6a0b8571..31d8bfdcb1 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -187,10 +188,13 @@ namespace UnitTest ASSERT_NE(m_viewportEditorModeTracker, nullptr); m_viewportEditorModes = m_viewportEditorModeTracker->GetViewportEditorModes({AzToolsFramework::GetEntityContextId()}); ASSERT_NE(m_viewportEditorModes, nullptr); + m_focusModeInterface = AZ::Interface::Get(); + ASSERT_NE(m_focusModeInterface, nullptr); } ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; const ViewportEditorModesInterface* m_viewportEditorModes = nullptr; + AzToolsFramework::FocusModeInterface* m_focusModeInterface = nullptr; }; TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4) @@ -522,7 +526,8 @@ namespace UnitTest } TEST_F( - ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive) + ViewportEditorModeTrackerIntegrationTestFixture, + EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive) { // When component mode is entered AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( @@ -539,15 +544,35 @@ namespace UnitTest // Expect the default and component viewport editor modes to be active EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); - - // Do not expect the pick and focus viewport editor modes to be active EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); } TEST_F( ViewportEditorModeTrackerIntegrationTestFixture, - EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickModeActive) + ExitingComponentModeAfterEnteringFrominitialStateHasViewportEditorModesDefaultActive) + { + // When component mode is entered and exited + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, + AZStd::vector{}); + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode); + + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + + // Expect to not be in component mode + EXPECT_FALSE(inComponentMode); + + // Expect only the default viewport editor mode to be active + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickActive) { // When entering pick mode using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; @@ -563,6 +588,101 @@ namespace UnitTest ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Pick); } - // FocusMode integration tests will follow (LYN-6995) + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + EnteringEditorDefaultEntitySelectionFromEditorPickEntitySelectionHasOnlyViewportEditorModeDefaultActive) + { + // When pick mode is entered and exited + using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus; + EditorInteractionSystemViewportSelectionRequestBus::Event( + AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + { + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); + }); + EditorInteractionSystemViewportSelectionRequestBus::Event( + AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, + [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, + [[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker) + { + return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); + }); + // Expect only the default viewport editor mode to be active + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); + } + + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, EnteringFocusModeAfterInitialStateHasViewportEditorModeDefaultAndPickActive) + { + // When entering focus mode + m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 }); + + // Expect the default and focus viewport editor modes to be active + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + ExitingFocusModeAfterEnteringFromInitialStateHasOnlyViewportEditorModeDefaultActive) + { + // When entering and leaving focus mode + m_focusModeInterface->SetFocusRoot(AZ::EntityId(1)); + m_focusModeInterface->SetFocusRoot(AZ::EntityId()); + + // Expect only the default mode to be active + ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); + } + + TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeFromFocusModeStateHasViewportEditorModeDefaultAndFocusAndComponentActive) + { + // When entering component mode from focus mode + m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 }); + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, + AZStd::vector{}); + + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + + // Expect to be in component mode + EXPECT_TRUE(inComponentMode); + + // Expect the default, focus and component viewport editor modes to be active + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); + } + + TEST_F( + ViewportEditorModeTrackerIntegrationTestFixture, + ExitingComponentModeAfterEnteringFromFocusModeHasViewportEditorModeDefaultAndFocusActive) + { + // When entering and leaving component mode from focus mode + m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 }); + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, + AZStd::vector{}); + m_focusModeInterface->SetFocusRoot(AZ::EntityId(1)); + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode); + + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + + // Expect to not be in component mode + EXPECT_FALSE(inComponentMode); + + // Expect the default and focus viewport editor modes to be active + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); + EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component)); + EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick)); + } } // namespace UnitTest From f98d2e55aad36165953ee0f3359135629dd172cd Mon Sep 17 00:00:00 2001 From: John Date: Mon, 25 Oct 2021 13:48:36 +0100 Subject: [PATCH 04/33] Refactor component mode query. Signed-off-by: John --- .../Viewport/ViewportEditorModeTests.cpp | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 31d8bfdcb1..05d7a0d37d 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -72,6 +72,14 @@ namespace UnitTest } } + bool IsComponentModeActive() + { + bool inComponentMode = false; + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( + inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); + return inComponentMode; + } + // Fixture for testing editor mode states class ViewportEditorModesTestsFixture : public ::testing::Test @@ -534,12 +542,8 @@ namespace UnitTest &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, AZStd::vector{}); - bool inComponentMode = false; - AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( - inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); - // Expect to be in component mode - EXPECT_TRUE(inComponentMode); + EXPECT_TRUE(IsComponentModeActive()); // Expect the default and component viewport editor modes to be active EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); @@ -556,15 +560,14 @@ namespace UnitTest AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, AZStd::vector{}); + + EXPECT_TRUE(IsComponentModeActive()); + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode); - bool inComponentMode = false; - AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( - inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); - // Expect to not be in component mode - EXPECT_FALSE(inComponentMode); + EXPECT_FALSE(IsComponentModeActive()); // Expect only the default viewport editor mode to be active ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); @@ -601,6 +604,7 @@ namespace UnitTest { return AZStd::make_unique(entityDataCache, viewportEditorModeTracker); }); + EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler, [](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache, @@ -645,12 +649,8 @@ namespace UnitTest &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, AZStd::vector{}); - bool inComponentMode = false; - AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( - inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); - // Expect to be in component mode - EXPECT_TRUE(inComponentMode); + EXPECT_TRUE(IsComponentModeActive()); // Expect the default, focus and component viewport editor modes to be active EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); @@ -668,16 +668,14 @@ namespace UnitTest AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, AZStd::vector{}); - m_focusModeInterface->SetFocusRoot(AZ::EntityId(1)); + + EXPECT_TRUE(IsComponentModeActive()); + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode); - bool inComponentMode = false; - AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( - inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); - // Expect to not be in component mode - EXPECT_FALSE(inComponentMode); + EXPECT_FALSE(IsComponentModeActive()); // Expect the default and focus viewport editor modes to be active EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); From 06d5711db83bf1e66e9c2c0b943131eb9638eb29 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Mon, 25 Oct 2021 10:07:55 -0700 Subject: [PATCH 05/33] ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface (#4739) * ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface Introduced new PassSystemInterface::ForEachPass() funtion to replace PassSystemInterface::FindPasses(), PassSystemInterface::GetPassesByTemplateName and ParentPass::FindPassByNameRecursive() functions. Update all the places which were using those three functions. The new pass finding filter support any combination of pass name, pass template name, pass class type, pass hirechary, owner scene, owner render pipeline. Update unit tests. Signed-off-by: Qing Tao (cherry picked from commit fe8dac798977a2271a2a5775d947d7172949866e) --- .../Include/Atom/Feature/ImGui/ImGuiUtils.h | 6 +- .../Include/Atom/Feature/ImGui/SystemBus.h | 7 +- .../Atom/Feature/Utils/FrameCaptureBus.h | 2 +- .../DirectionalLightFeatureProcessor.cpp | 71 ++--- ...fuseGlobalIlluminationFeatureProcessor.cpp | 57 ++-- .../DiffuseProbeGridFeatureProcessor.cpp | 12 +- .../DisplayMapper/DisplayMapperPass.cpp | 25 +- .../Source/FrameCaptureSystemComponent.cpp | 37 +-- .../Source/ImGui/ImGuiSystemComponent.cpp | 48 +-- .../Code/Source/ImGui/ImGuiSystemComponent.h | 2 +- .../DepthOfField/DepthOfFieldSettings.cpp | 20 +- .../ExposureControlSettings.cpp | 27 +- .../LookModificationCompositePass.cpp | 14 +- .../PostProcessing/SMAAFeatureProcessor.cpp | 51 ++-- .../ProfilingCaptureSystemComponent.cpp | 31 +- .../Source/ProfilingCaptureSystemComponent.h | 2 - .../ReflectionCopyFrameBufferPass.cpp | 19 +- .../ReflectionScreenSpaceBlurPass.cpp | 2 +- .../ReflectionScreenSpaceCompositePass.cpp | 26 +- .../ProjectedShadowFeatureProcessor.cpp | 54 ++-- .../Shadows/ProjectedShadowFeatureProcessor.h | 4 +- .../SkinnedMeshFeatureProcessor.cpp | 13 +- .../SkinnedMesh/SkinnedMeshFeatureProcessor.h | 2 +- .../Include/Atom/RPI.Public/Pass/ParentPass.h | 3 - .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 4 + .../Include/Atom/RPI.Public/Pass/PassFilter.h | 136 ++++----- .../Atom/RPI.Public/Pass/PassLibrary.h | 4 +- .../Include/Atom/RPI.Public/Pass/PassSystem.h | 4 +- .../RPI.Public/Pass/PassSystemInterface.h | 21 +- .../Source/RPI.Public/Pass/ParentPass.cpp | 23 -- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 5 + .../Source/RPI.Public/Pass/PassFilter.cpp | 285 ++++++++++++++---- .../Source/RPI.Public/Pass/PassLibrary.cpp | 90 ++++-- .../Source/RPI.Public/Pass/PassSystem.cpp | 22 +- Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp | 159 ++++++++-- .../Code/Rendering/HairFeatureProcessor.cpp | 44 ++- .../Code/Rendering/HairFeatureProcessor.h | 2 + 37 files changed, 800 insertions(+), 534 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h index a200f30c98..52e272a9c4 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h @@ -50,12 +50,12 @@ namespace AZ return scope; } - //! Sets the active context based on the provided PassHierarchyFilter. If the filter doesn't match exactly one pass, then do nothing. - static ImGuiActiveContextScope FromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) + //! Sets the active context based on the provided pass hierarchy filter. If the filter doesn't match exactly one pass, then do nothing. + static ImGuiActiveContextScope FromPass(const AZStd::vector& passHierarchy) { ImGuiActiveContextScope scope; scope.ConnectToImguiNotificationBus(); - ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchyFilter); + ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchy); return scope; } diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h index 289cb178d4..78f71b39ba 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h @@ -15,11 +15,6 @@ namespace AZ { - namespace RPI - { - class PassHierarchyFilter; - } - namespace Render { class ImGuiPass; @@ -51,7 +46,7 @@ namespace AZ //! Pushes whichever ImGui pass is default on the top of the active context stack. Returns true/false for success/fail. virtual bool PushActiveContextFromDefaultPass() = 0; //! Pushes whichever ImGui pass is provided in passHierarchy on the top of the active context stack. Returns true/false for success/fail. - virtual bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) = 0; + virtual bool PushActiveContextFromPass(const AZStd::vector& passHierarchy) = 0; //! Pops the active context off the top of the active context stack. Returns true if there's a context to pop. virtual bool PopActiveContext() = 0; //! Gets the context at the top of the active context stack. Returns nullptr if the stack is emtpy. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h index 93600ec08f..c80926700e 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h @@ -50,7 +50,7 @@ namespace AZ virtual bool CaptureScreenshotWithPreview(const AZStd::string& outputFilePath) = 0; //! Save a buffer attachment or a image attachment binded to a pass's slot to a data file. - //! @param passHierarchy For finding the pass by using PassHierarchyFilter + //! @param passHierarchy For finding the pass by using a pass hierarchy filter. Check PassFilter::CreateWithPassHierarchy() function for detail //! @param slotName Name of the pass's slot. The attachment bound to this slot will be captured. //! @param option Only valid for an InputOutput attachment. Use PassAttachmentReadbackOption::Input to capture the input state //! and use PassAttachmentReadbackOption::Output to capture the output state diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 6c24b7d35b..b6c6910fd3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -647,54 +647,46 @@ namespace AZ UpdateViewsOfCascadeSegments(); } - void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() { - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("CascadedShadowmapsTemplate")); + void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() + { m_cascadedShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("CascadedShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { + RPI::RenderPipeline* pipeline = pass->GetRenderPipeline(); const RPI::RenderPipelineId pipelineId = pipeline->GetId(); - // This function can be called when the pipeline is not attached to the scene. - // So we check it is attached to the scene. - if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) + + CascadedShadowmapsPass* shadowPass = azrtti_cast(pass); + AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass."); + if (pipeline->GetDefaultView()) { - CascadedShadowmapsPass* shadowPass = azrtti_cast(pass); - AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass."); - if (pipeline->GetDefaultView()) - { - m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass); - } + m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DirectionalLightFeatureProcessor::CacheEsmShadowmapsPass() { - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); m_esmShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - const RPI::RenderPipelineId pipelineId = pipeline->GetId(); - // checking the render pipeline is just removed from the scene. - if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) + const RPI::RenderPipelineId pipelineId = pass->GetRenderPipeline()->GetId(); + + if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) { - if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) + EsmShadowmapsPass* esmPass = azrtti_cast(pass); + AZ_Assert(esmPass, "It is not an EsmShadowmapPass."); + if (esmPass->GetLightTypeName() == m_lightTypeName) { - EsmShadowmapsPass* esmPass = azrtti_cast(pass); - AZ_Assert(esmPass, "It is not an EsmShadowmapPass."); - if (m_cascadedShadowmapsPasses.find(esmPass->GetRenderPipeline()->GetId()) != m_cascadedShadowmapsPasses.end() && - esmPass->GetLightTypeName() == m_lightTypeName) - { - m_esmShadowmapsPasses[pipelineId].push_back(esmPass); - } + m_esmShadowmapsPasses[pipelineId].push_back(esmPass); } } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DirectionalLightFeatureProcessor::PrepareCameraViews() @@ -1063,12 +1055,13 @@ namespace AZ // if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view, // to filter out shadows from objects that are excluded from the cubemap - RPI::PassClassFilter passFilter; - AZStd::vector cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!cubeMapPasses.empty()) - { - usageFlags |= RPI::View::UsageReflectiveCubeMap; - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + usageFlags |= RPI::View::UsageReflectiveCubeMap; + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); segment.m_view = RPI::View::CreateView(viewName, usageFlags); } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp index c085b26e31..453dbbc0ab 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp @@ -80,35 +80,48 @@ namespace AZ } // update the size multiplier on the DiffuseProbeGridDownsamplePass output - AZStd::vector downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; - RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy); - const AZStd::vector& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter); - for (RPI::Pass* pass : downsamplePasses) + // NOTE: The ownerScene wasn't added to both filters. This is because the passes from the non-owner scene may have invalid SRG values which could lead to + // GPU error if the scene doesn't have this feature processor enabled. + // For example, the ASV MultiScene sample may have TDR. { - for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) - { - RPI::Ptr outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; - RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; + AZStd::vector downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; + RPI::PassFilter downsamplePassFilter = RPI::PassFilter::CreateWithPassHierarchy(downsamplePassHierarchy); + RPI::PassSystemInterface::Get()->ForEachPass( + downsamplePassFilter, + [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) + { + RPI::Ptr outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; + RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; - sizeMultipliers.m_widthMultiplier = sizeMultiplier; - sizeMultipliers.m_heightMultiplier = sizeMultiplier; - } + sizeMultipliers.m_widthMultiplier = sizeMultiplier; + sizeMultipliers.m_heightMultiplier = sizeMultiplier; + } - // set the output scale on the PassSrg - RPI::FullscreenTrianglePass* downsamplePass = static_cast(pass); - auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale")); - downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + // set the output scale on the PassSrg + RPI::FullscreenTrianglePass* downsamplePass = static_cast(pass); + RHI::ShaderInputNameIndex outputImageScaleShaderInput = "m_outputImageScale"; + downsamplePass->GetShaderResourceGroup()->SetConstant( + outputImageScaleShaderInput, aznumeric_cast(1.0f / sizeMultiplier)); + + // handle all downsample passes + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } // update the image scale on the DiffuseComposite pass - AZStd::vector compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") }; - RPI::PassHierarchyFilter compositePassFilter(compositePassHierarchy); - const AZStd::vector& compositePasses = RPI::PassSystemInterface::Get()->FindPasses(compositePassFilter); - for (RPI::Pass* pass : compositePasses) { - RPI::FullscreenTrianglePass* compositePass = static_cast(pass); - auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale")); - compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + AZStd::vector compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") }; + RPI::PassFilter compositePassFilter = RPI::PassFilter::CreateWithPassHierarchy(compositePassHierarchy); + RPI::PassSystemInterface::Get()->ForEachPass(compositePassFilter, [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + RPI::FullscreenTrianglePass* compositePass = static_cast(pass); + RHI::ShaderInputNameIndex imageScaleShaderInput = "m_imageScale"; + compositePass->GetShaderResourceGroup()->SetConstant(imageScaleShaderInput, aznumeric_cast(1.0f / sizeMultiplier)); + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } } } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index 4329fd556c..5ea4748fc9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -603,12 +603,12 @@ namespace AZ RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); if (device->GetFeatures().m_rayTracing == false) { - RPI::PassHierarchyFilter updatePassFilter(AZ::Name("DiffuseProbeGridUpdatePass")); - const AZStd::vector& updatePasses = RPI::PassSystemInterface::Get()->FindPasses(updatePassFilter); - for (RPI::Pass* pass : updatePasses) - { - pass->SetEnabled(false); - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(false); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index 3ec8840a1c..5b5599383e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -10,9 +10,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include @@ -66,22 +67,14 @@ namespace AZ { // Need to invalidate the CopyToSwapChain pass so that it updates the pipeline state in the event that // the swapchain format changed (for example, moving from LDR to HDR display) - auto* passSystem = RPI::PassSystemInterface::Get(); - const Name fullscreenCopyTemplateName("FullscreenCopyTemplate"); - - if (passSystem->HasPassesForTemplateName(fullscreenCopyTemplateName)) - { - const AZStd::vector& passes = passSystem->GetPassesForTemplateName(fullscreenCopyTemplateName); - for (RPI::Pass* pass : passes) + const Name copyToSwapChainPassName("CopyToSwapChain"); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(copyToSwapChainPassName, GetRenderPipeline()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - RPI::FullscreenTrianglePass* fullscreenTrianglePass = azrtti_cast(pass); - const Name& passName = fullscreenTrianglePass->GetName(); - if (passName.GetStringView() == "CopyToSwapChain") - { - fullscreenTrianglePass->QueueForInitialization(); - } - } - } + pass->QueueForInitialization(); + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); + ConfigureDisplayParameters(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 8c0360dec2..ed2d8a1d9f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -372,29 +372,25 @@ namespace AZ } m_latestCaptureInfo.clear(); - // Find the pass first - RPI::PassClassFilter passFilter; - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - - if (foundPasses.size() == 0) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast(RPI::PassSystemInterface::Get()->FindFirstPass(passFilter)); + if (!previewPass) { - AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass pass "); + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass"); return false; } - AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast(foundPasses[0]); bool result = previewPass->ReadbackOutput(m_readback); if (result) { m_state = State::Pending; m_result = FrameCaptureResult::None; SystemTickBus::Handler::BusConnect(); + return true; } - else - { - AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass");; - } - return result; + + AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass"); + return false; } bool FrameCaptureSystemComponent::CapturePassAttachment(const AZStd::vector& passHierarchy, const AZStd::string& slot, @@ -405,6 +401,12 @@ namespace AZ return false; } + if (passHierarchy.size() == 0) + { + AZ_Warning("FrameCaptureSystemComponent", false, "Empty data in passHierarchy"); + return false; + } + InitReadback(); if (m_state != State::Idle) @@ -426,17 +428,15 @@ namespace AZ } m_latestCaptureInfo.clear(); - // Find the pass first - AZ::RPI::PassHierarchyFilter passFilter(passHierarchy); - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchy); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); - if (foundPasses.size() == 0) + if (!pass) { - AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str()); + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passHierarchy[0].c_str()); return false; } - AZ::RPI::Pass* pass = foundPasses[0]; if (pass->ReadbackAttachment(m_readback, Name(slot), option)) { m_state = State::Pending; @@ -444,6 +444,7 @@ namespace AZ SystemTickBus::Handler::BusConnect(); return true; } + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to readback the attachment bound to pass [%s] slot [%s]", pass->GetName().GetCStr(), slot.c_str()); return false; } diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp index afca20c5cb..3783752e67 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp @@ -109,15 +109,15 @@ namespace AZ void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func) { ImGuiContext* contextToRestore = ImGui::GetCurrentContext(); - RPI::PassClassFilter filter; - auto imguiPasses = RPI::PassSystemInterface::Get()->FindPasses(filter); - - for (RPI::Pass* pass : imguiPasses) - { - ImGuiPass* imguiPass = azrtti_cast(pass); - ImGui::SetCurrentContext(imguiPass->GetContext()); - func(imguiPass); - } + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + ImGuiPass* imguiPass = azrtti_cast(pass); + ImGui::SetCurrentContext(imguiPass->GetContext()); + func(imguiPass); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); ImGui::SetCurrentContext(contextToRestore); } @@ -169,29 +169,37 @@ namespace AZ return false; } - bool ImGuiSystemComponent::PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) + bool ImGuiSystemComponent::PushActiveContextFromPass(const AZStd::vector& passHierarchyFilter) { - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passHierarchyFilter); + if (passHierarchyFilter.size() == 0) + { + AZ_Warning("ImGuiSystemComponent", false, "passHierarchyFilter is empty"); + return false; + } + AZStd::vector foundImGuiPasses; - for (RPI::Pass* pass : foundPasses) - { - ImGuiPass* imGuiPass = azrtti_cast(pass); - if (imGuiPass) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchyFilter); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundImGuiPasses](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - foundImGuiPasses.push_back(imGuiPass); - } - } + ImGuiPass* imGuiPass = azrtti_cast(pass); + if (imGuiPass) + { + foundImGuiPasses.push_back(imGuiPass); + } + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); if (foundImGuiPasses.size() == 0) { - AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter.ToString().c_str()); + AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter[0].c_str()); return false; } if (foundImGuiPasses.size() > 1) { - AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter.ToString().c_str()); + AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter[0].c_str()); } ImGuiContext* context = foundImGuiPasses.at(0)->GetContext(); diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h index 838cf0b3c2..d59124890f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h @@ -56,7 +56,7 @@ namespace AZ ImGuiPass* GetDefaultImGuiPass() override; bool PushActiveContextFromDefaultPass() override; - bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) override; + bool PushActiveContextFromPass(const AZStd::vector& passHierarchy) override; bool PopActiveContext() override; ImGuiContext* GetActiveContext() override; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp index fe1ce8a281..98b527868d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -259,24 +260,19 @@ namespace AZ // [GFX TODO][ATOM-3035]This function is temporary and will change with improvement to the draw list tag system void DepthOfFieldSettings::UpdateAutoFocusDepth(bool enabled) - { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); + { const Name TemplateNameReadBackFocusDepth = Name("DepthOfFieldReadBackFocusDepthTemplate"); - if (passSystem->HasPassesForTemplateName(TemplateNameReadBackFocusDepth)) - { - const AZStd::vector& dofPasses = passSystem->GetPassesForTemplateName(TemplateNameReadBackFocusDepth); - for (RPI::Pass* pass : dofPasses) + // [GFX TODO][ATOM-4908] multiple camera should be distingushed. + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(TemplateNameReadBackFocusDepth, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, enabled](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* dofPass = azrtti_cast(pass); - // Check this pass belongs to a render pipeline of the scene. - // [GFX TODO][ATOM-4908] multiple camera should be distingushed. - const RPI::RenderPipelineId pipelineId = dofPass->GetRenderPipeline()->GetId(); - if (enabled && GetParentScene()->GetRenderPipeline(pipelineId)) + if (enabled) { m_normalizedFocusDistanceForAutoFocus = dofPass->GetNormalizedFocusDistanceForAutoFocus(); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DepthOfFieldSettings::SetCameraEntityId(EntityId cameraEntityId) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp index 96ca424307..26c2a61d54 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -188,21 +189,21 @@ namespace AZ void ExposureControlSettings::UpdateLuminanceHeatmap() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - // [GFX-TODO][ATOM-13194] Support multiple views for the luminance heatmap - // [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass - const RPI::Ptr luminanceHeatmap = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHeatmapNameId); - if (luminanceHeatmap) - { - luminanceHeatmap->SetEnabled(m_heatmapEnabled); - } + // [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass + RPI::PassFilter heatmapPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHeatmapNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(heatmapPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(m_heatmapEnabled); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); - const RPI::Ptr histogramGenerator = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHistogramGeneratorNameId); - if (histogramGenerator) - { - histogramGenerator->SetEnabled(m_heatmapEnabled); - } + RPI::PassFilter histogramPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHistogramGeneratorNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(histogramPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(m_heatmapEnabled); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void ExposureControlSettings::UpdateBuffer() diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp index 85c45de96b..aac3d1d941 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp @@ -31,12 +31,14 @@ namespace AZ 0, [](const uint8_t& value) { - auto passes = RPI::PassSystem::Get()->FindPasses(RPI::PassClassFilter()); - for (auto* pass : passes) - { - LookModificationCompositePass* lookModPass = azrtti_cast(pass); - lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value)); - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [value](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + LookModificationCompositePass* lookModPass = azrtti_cast(pass); + lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value)); + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); }, ConsoleFunctorFlags::Null, "This can be increased to deal with particularly tricky luts. Range (0-2). 0 (default) - Standard linear sampling. 1 - 7 tap b-spline sampling. 2 - 19 tap b-spline sampling." diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp index eef0c51e95..ad059fbec0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -71,26 +72,18 @@ namespace AZ void SMAAFeatureProcessor::UpdateConvertToPerceptualPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId)) - { - const AZStd::vector& convertToPerceptualColorPasses = passSystem->GetPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId); - for (RPI::Pass* pass : convertToPerceptualColorPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_convertToPerceptualColorPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { pass->SetEnabled(m_data.m_enable); - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateEdgeDetectionPass() - { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_edgeDetectioPassTemplateNameId)) - { - const AZStd::vector& edgeDetectionPasses = passSystem->GetPassesForTemplateName(m_edgeDetectioPassTemplateNameId); - for (RPI::Pass* pass : edgeDetectionPasses) + { + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_edgeDetectioPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* edgeDetectionPass = azrtti_cast(pass); @@ -106,18 +99,14 @@ namespace AZ edgeDetectionPass->SetPredicationScale(m_data.m_predicationScale); edgeDetectionPass->SetPredicationStrength(m_data.m_predicationStrength); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateBlendingWeightCalculationPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId)) - { - const AZStd::vector& blendingWeightCalculationPasses = passSystem->GetPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId); - for (RPI::Pass* pass : blendingWeightCalculationPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_blendingWeightCalculationPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* blendingWeightCalculationPass = azrtti_cast(pass); @@ -130,18 +119,14 @@ namespace AZ blendingWeightCalculationPass->SetDiagonalDetectionEnable(m_data.m_enableDiagonalDetection); blendingWeightCalculationPass->SetCornerDetectionEnable(m_data.m_enableCornerDetection); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateNeighborhoodBlendingPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId)) - { - const AZStd::vector& neighborhoodBlendingPasses = passSystem->GetPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId); - for (RPI::Pass* pass : neighborhoodBlendingPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_neighborhoodBlendingPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* neighborhoodBlendingPass = azrtti_cast(pass); @@ -153,8 +138,8 @@ namespace AZ { neighborhoodBlendingPass->SetOutputMode(SMAAOutputMode::PassThrough); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::Render([[maybe_unused]] const SMAAFeatureProcessor::RenderPacket& packet) diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp index 66adfe9985..9bfb2b7e9e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp @@ -377,14 +377,7 @@ namespace AZ bool ProfilingCaptureSystemComponent::CapturePassTimestamp(const AZStd::string& outputFilePath) { - // Find the root pass. - AZStd::vector passes = FindPasses({ "Root" }); - if (passes.empty()) - { - return false; - } - - RPI::Pass* root = passes[0]; + RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get(); // Enable all the Timestamp queries in passes. root->SetTimestampQueryEnabled(true); @@ -465,14 +458,7 @@ namespace AZ bool ProfilingCaptureSystemComponent::CapturePassPipelineStatistics(const AZStd::string& outputFilePath) { - // Find the root pass. - AZStd::vector passes = FindPasses({ "Root" }); - if (passes.empty()) - { - return false; - } - - RPI::Pass* root = passes[0]; + RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get(); // Enable all the PipelineStatistics queries in passes. root->SetPipelineStatisticsQueryEnabled(true); @@ -572,19 +558,6 @@ namespace AZ return passes; } - AZStd::vector ProfilingCaptureSystemComponent::FindPasses(AZStd::vector&& passHierarchy) const - { - // Find the pass first. - RPI::PassHierarchyFilter passFilter(passHierarchy); - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (foundPasses.size() == 0) - { - AZ_Warning("ProfilingCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str()); - } - - return foundPasses; - } - void ProfilingCaptureSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { // Update the delayed captures diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h index a9bb8c585f..af1d2f5643 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h @@ -78,8 +78,6 @@ namespace AZ // Recursively collect all the passes from the root pass. AZStd::vector CollectPassesRecursively(const RPI::Pass* root) const; - AZStd::vector FindPasses(AZStd::vector&& passHierarchy) const; - DelayedQueryCaptureHelper m_timestampCapture; DelayedQueryCaptureHelper m_cpuFrameTimeStatisticsCapture; DelayedQueryCaptureHelper m_pipelineStatisticsCapture; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp index 37b1885ee3..a1858a7e9d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp @@ -28,16 +28,17 @@ namespace AZ void ReflectionCopyFrameBufferPass::BuildInternal() { - RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!passes.empty()) - { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); - Data::Instance& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment(); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); + Data::Instance& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment(); - RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); - AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); - } + RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); + AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); + + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); FullscreenTrianglePass::BuildInternal(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp index 394a6fd406..edd7ad1013 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp @@ -150,7 +150,7 @@ namespace AZ auto transientImageDesc = RHI::ImageDescriptor::Create2D(imageBindFlags, mipSize.m_width, mipSize.m_height, RHI::Format::R16G16B16A16_FLOAT); RPI::PassAttachment* transientPassAttachment = aznew RPI::PassAttachment(); - AZStd::string transientAttachmentName = AZStd::string::format("ReflectionScreenSpace_BlurImage%d", mip); + AZStd::string transientAttachmentName = AZStd::string::format("%s.ReflectionScreenSpace_BlurImage%d", GetPathName().GetCStr(), mip); transientPassAttachment->m_name = transientAttachmentName; transientPassAttachment->m_path = transientAttachmentName; transientPassAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp index 1cf227650c..1362191691 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp @@ -33,20 +33,22 @@ namespace AZ return; } - RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!passes.empty()) - { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); - // compute the max mip level based on the available mips in the previous frame image, and capping it - // to stay within a range that has reasonable data - const uint32_t MaxNumRoughnessMips = 8; - uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); - auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); - m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); - } + // compute the max mip level based on the available mips in the previous frame image, and capping it + // to stay within a range that has reasonable data + const uint32_t MaxNumRoughnessMips = 8; + uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; + + auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); + m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); + + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); FullscreenTrianglePass::CompileResources(context); } diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 7c0b3563c7..70ccaa5702 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -313,52 +313,38 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::CachePasses() { - const AZStd::vector validPipelineIds = CacheProjectedShadowmapsPass(); - CacheEsmShadowmapsPass(validPipelineIds); + CacheProjectedShadowmapsPass(); + CacheEsmShadowmapsPass(); m_shadowmapPassNeedsUpdate = true; } - AZStd::vector ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass() + void ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass() { - const AZStd::vector& renderPipelines = GetParentScene()->GetRenderPipelines(); - const auto* passSystem = RPI::PassSystemInterface::Get();; - const AZStd::vector& passes = passSystem->GetPassesForTemplateName(Name("ProjectedShadowmapsTemplate")); - - AZStd::vector validPipelineIds; m_projectedShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - ProjectedShadowmapsPass* shadowPass = static_cast(pass); - for (const RPI::RenderPipelinePtr& pipeline : renderPipelines) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("ProjectedShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - if (pipeline.get() == shadowPass->GetRenderPipeline()) - { - m_projectedShadowmapsPasses.emplace_back(shadowPass); - validPipelineIds.push_back(shadowPass->GetRenderPipeline()->GetId()); - } - } - } - return validPipelineIds; + ProjectedShadowmapsPass* shadowPass = static_cast(pass); + m_projectedShadowmapsPasses.emplace_back(shadowPass); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } - void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds) + void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass() { const Name LightTypeName = Name("projected"); - - const auto* passSystem = RPI::PassSystemInterface::Get(); - const AZStd::vector passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); - + m_esmShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - EsmShadowmapsPass* esmPass = static_cast(pass); - if (esmPass->GetRenderPipeline() && - AZStd::find(validPipelineIds.begin(), validPipelineIds.end(), esmPass->GetRenderPipeline()->GetId()) != validPipelineIds.end() && - esmPass->GetLightTypeName() == LightTypeName) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, LightTypeName](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - m_esmShadowmapsPasses.emplace_back(esmPass); - } - } + EsmShadowmapsPass* esmPass = static_cast(pass); + if (esmPass->GetLightTypeName() == LightTypeName) + { + m_esmShadowmapsPasses.emplace_back(esmPass); + } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void ProjectedShadowFeatureProcessor::UpdateFilterParameters() diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index fafcb25a08..8939f1845d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -97,8 +97,8 @@ namespace AZ::Render // Functions for caching the ProjectedShadowmapsPass and EsmShadowmapsPass. void CachePasses(); - AZStd::vector CacheProjectedShadowmapsPass(); - void CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds); + void CacheProjectedShadowmapsPass(); + void CacheEsmShadowmapsPass(); //! Functions to update the parameter of Gaussian filter used in ESM. void UpdateFilterParameters(); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index e0209702dc..4c379c4239 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -241,12 +242,12 @@ namespace AZ void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) { - InitSkinningAndMorphPass(pipeline->GetRootPass()); + InitSkinningAndMorphPass(pipeline.get()); } void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { - InitSkinningAndMorphPass(renderPipeline->GetRootPass()); + InitSkinningAndMorphPass(renderPipeline); } void SkinnedMeshFeatureProcessor::OnBeginPrepareRender() @@ -289,9 +290,10 @@ namespace AZ return false; } - void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(const RPI::Ptr pipelineRootPass) + void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline) { - RPI::Ptr skinningPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "SkinningPass" }); + RPI::PassFilter skinPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "SkinningPass" }, renderPipeline); + RPI::Ptr skinningPass = RPI::PassSystemInterface::Get()->FindFirstPass(skinPassFilter); if (skinningPass) { SkinnedMeshComputePass* skinnedMeshComputePass = azdynamic_cast(skinningPass.get()); @@ -310,7 +312,8 @@ namespace AZ } } - RPI::Ptr morphTargetPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "MorphTargetPass" }); + RPI::PassFilter morphPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "MorphTargetPass" }, renderPipeline); + RPI::Ptr morphTargetPass = RPI::PassSystemInterface::Get()->FindFirstPass(morphPassFilter); if (morphTargetPass) { MorphTargetComputePass* morphTargetComputePass = azdynamic_cast(morphTargetPass.get()); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h index 2e93acf2cd..5b7ab943e1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h @@ -66,7 +66,7 @@ namespace AZ private: AZ_DISABLE_COPY_MOVE(SkinnedMeshFeatureProcessor); - void InitSkinningAndMorphPass(const RPI::Ptr pipelineRootPass); + void InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline); SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) override; bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index 36994ec03b..6523f0a6d8 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -68,9 +68,6 @@ namespace AZ template Ptr FindChildPass() const; - //! Searches the tree for the first pass that has same pass name (Depth-first search). Return nullptr if none found. - Ptr FindPassByNameRecursive(const Name& passName) const; - //! Gets the list of children. Useful for validating hierarchies AZStd::array_view> GetChildren() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 34eaae4495..e7b9825ecb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -139,6 +139,10 @@ namespace AZ //! Returns the number of output attachment bindings uint32_t GetOutputCount() const; + //! Returns the pass template which was used for create this pass. + //! It may return nullptr if the pass wasn't create from a template + const PassTemplate* GetPassTemplate() const; + //! Enable/disable this pass //! If the pass is disabled, it (and any children if it's a ParentPass) won't be rendered. void SetEnabled(bool enabled); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h index c31f353adb..c42991725e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h @@ -16,95 +16,85 @@ namespace AZ { namespace RPI { - // A base class for a filter which can be used to filter passes + class Scene; + class RenderPipeline; + class PassFilter { public: - //! Whether the input pass matches with the filter - virtual bool Matches(const Pass* pass) const = 0; + static PassFilter CreateWithPassName(Name passName, const Scene* scene); + static PassFilter CreateWithPassName(Name passName, const RenderPipeline* renderPipeline); - //! Return the pass' name if a pass name is used for the filter. - //! Return nullptr if the filter doesn't have pass name used for matching - virtual const Name* GetPassName() const = 0; + //! Create a PassFilter with pass hierarchy information + //! Filter for passes which have a matching name and also with ordered parents. + //! For example, if the filter is initialized with + //! pass name: "ShadowPass1" + //! pass parents names: "MainPipeline", "Shadow" + //! Passes with these names match the filter: + //! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" + //! or "Root.MainPipeline.Shadow.ShadowPass1" + //! or "MainPipeline.Shadow.Group1.ShadowPass1" + //! + //! Passes with these names wont match: + //! "MainPipeline.ShadowPass1" + //! or "Shadow.MainPipeline.ShadowPass1" + static PassFilter CreateWithPassHierarchy(const AZStd::vector& passHierarchy); + static PassFilter CreateWithPassHierarchy(const AZStd::vector& passHierarchy); + static PassFilter CreateWithTemplateName(Name templateName, const Scene* scene); + static PassFilter CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline); + template + static PassFilter CreateWithPassClass(); - //! Return this filter's info as a string - virtual AZStd::string ToString() const = 0; - }; + enum FilterOptions : uint32_t + { + Empty = 0, + PassName = AZ_BIT(0), + PassTemplateName = AZ_BIT(1), + PassClass = AZ_BIT(2), + PassHierarchy = AZ_BIT(3), + OwnerScene = AZ_BIT(4), + OwnerRenderPipeline = AZ_BIT(5) + }; - //! Filter for passes which have a matching name and also with ordered parents. - //! For example, if the filter is initialized with - //! pass name: "ShadowPass1" - //! pass parents names: "MainPipeline", "Shadow" - //! Passes with these names match the filter: - //! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" - //! or "Root.MainPipeline.Shadow.ShadowPass1" - //! or "MainPipeline.Shadow.Group1.ShadowPass1" - //! - //! Passes with these names wont match: - //! "MainPipeline.ShadowPass1" - //! or "Shadow.MainPipeline.ShadowPass1" - class PassHierarchyFilter - : public PassFilter - { - public: - AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter); - AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0); + void SetOwenrScene(const Scene* scene); + void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline); + void SetPassName(Name passName); + void SetTemplateName(Name passTemplateName); + void SetPassClass(TypeId passClassTypeId); - //! Construct filter with only pass name. - PassHierarchyFilter(const Name& passName); + const Name& GetPassName() const; + const Name& GetPassTemplateName() const; - virtual ~PassHierarchyFilter() = default; + uint32_t GetEnabledFilterOptions() const; - //! Construct filter with pass name and its parents' names in the order of the hierarchy - //! This means k-th element is always an ancestor of the (k-1)-th element. - //! And the last element is the pass name. - PassHierarchyFilter(const AZStd::vector& passHierarchy); - PassHierarchyFilter(const AZStd::vector& passHierarchy); + //! Return true if the input pass matches the filter + bool Matches(const Pass* pass) const; - // PassFilter overrides... - bool Matches(const Pass* pass) const override; - const Name* GetPassName() const override; - AZStd::string ToString() const override; + //! Return true if the input pass matches the filter with selected filter options + //! The input filter options should be a subset of options returned by GetEnabledFilterOptions() + //! This function is used to avoid extra checks for passes which was already filtered. + //! Check PassLibrary::ForEachPass() function's implementation for more details + bool Matches(const Pass* pass, uint32_t options) const; private: - PassHierarchyFilter() = delete; + void UpdateFilterOptions(); - AZStd::vector m_parentNames; Name m_passName; + Name m_templateName; + TypeId m_passClassTypeId = TypeId::CreateNull(); + AZStd::vector m_parentNames; + const RenderPipeline* m_ownerRenderPipeline = nullptr; + const Scene* m_ownerScene = nullptr; + uint32_t m_filterOptions = 0; }; - //! Filter for passes based on their class. - template - class PassClassFilter - : public PassFilter - { - public: - AZ_RTTI(PassClassFilter, "{AF6E3AD5-433A-462A-997A-F36D8A551D02}", PassFilter); - AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0); - PassClassFilter() = default; - - // PassFilter overrides... - bool Matches(const Pass* pass) const override; - const Name* GetPassName() const override; - AZStd::string ToString() const override; - }; - - template - bool PassClassFilter::Matches(const Pass* pass) const - { - return pass->RTTI_IsTypeOf(PassClass::RTTI_Type()); - } - - template - const Name* PassClassFilter::GetPassName() const - { - return nullptr; - } - - template - AZStd::string PassClassFilter::ToString() const - { - return AZStd::string::format("PassClassFilter<%s>", PassClass::RTTI_TypeName()); + template + PassFilter PassFilter::CreateWithPassClass() + { + PassFilter filter; + filter.m_passClassTypeId = PassClass::RTTI_Type(); + filter.UpdateFilterOptions(); + return filter; } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h index 0a4b1c4399..66c3c205ab 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h @@ -84,8 +84,8 @@ namespace AZ bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath); bool LoadPassTemplateMappings(Data::Asset mappingAsset); - //! Returns a list of passes found in the pass name mapping using the provided pass filter - AZStd::vector FindPasses(const PassFilter& passFilter) const; + //! Visit each pass which matches the filter + void ForEachPass(const PassFilter& passFilter, AZStd::function passFunction); private: diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h index 30fa27e64b..8390b0f7e2 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h @@ -92,13 +92,13 @@ namespace AZ // PassSystemInterface library related functions... bool HasPassesForTemplateName(const Name& templateName) const override; - const AZStd::vector& GetPassesForTemplateName(const Name& templateName) const override; bool AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) override; const AZStd::shared_ptr GetPassTemplate(const Name& name) const override; void RemovePassFromLibrary(Pass* pass) override; void RegisterPass(Pass* pass) override; void UnregisterPass(Pass* pass) override; - AZStd::vector FindPasses(const PassFilter& passFilter) const override; + void ForEachPass(const PassFilter& filter, AZStd::function passFunction) override; + Pass* FindFirstPass(const PassFilter& filter) override; private: // Returns the root of the pass tree hierarchy diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 0e9386f3bb..7f944df88f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -75,6 +75,13 @@ namespace AZ u32 m_maxDrawItemsRenderedInAPass = 0; }; + + enum PassFilterExecutionFlow : uint8_t + { + StopVisitingPasses, + ContinueVisitingPasses, + }; + class PassSystemInterface { friend class Pass; @@ -186,9 +193,6 @@ namespace AZ //! Returns true if the pass factory contains passes created with the given template name virtual bool HasPassesForTemplateName(const Name& templateName) const = 0; - //! Get the passes created with the given template name. - virtual const AZStd::vector& GetPassesForTemplateName(const Name& templateName) const = 0; - //! Adds a PassTemplate to the library virtual bool AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) = 0; @@ -197,9 +201,16 @@ namespace AZ //! Removes all references to the given pass from the pass library virtual void RemovePassFromLibrary(Pass* pass) = 0; + + //! Visit the matching passes from registered passes with specified filter + //! The return value of the passFunction decides if the search continues or not + //! Note: this function will find all the passes which match the pass filter even they are for render pipelines which are not added to a scene + //! This function is fast if a pass name or a pass template name is specified. + virtual void ForEachPass(const PassFilter& filter, AZStd::function passFunction) = 0; - //! Find matching passes from registered passes with specified filter - virtual AZStd::vector FindPasses(const PassFilter& passFilter) const = 0; + //! Find the first matching pass from registered passes with specified filter + //! Note: this function SHOULD ONLY be used when you are certain you only need to handle the first pass found + virtual Pass* FindFirstPass(const PassFilter& filter) = 0; private: // These functions are only meant to be used by the Pass class diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 36c28877ea..dccf5dbc2e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -149,29 +149,6 @@ namespace AZ return index.IsValid() ? m_children[index.GetIndex()] : Ptr(nullptr); } - Ptr ParentPass::FindPassByNameRecursive(const Name& passName) const - { - for (const Ptr& child : m_children) - { - if (child->GetName() == passName) - { - return child.get(); - } - - ParentPass* asParent = child->AsParent(); - if (asParent) - { - auto pass = asParent->FindPassByNameRecursive(passName); - if (pass) - { - return pass; - } - } - } - - return nullptr; - } - const Pass* ParentPass::FindPass(RHI::DrawListTag drawListTag) const { if (HasDrawListTag() && GetDrawListTag() == drawListTag) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index a8d94e9a91..3c1de28d6a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -238,6 +238,11 @@ namespace AZ return m_attachmentBindings[bindingIndex]; } + const PassTemplate* Pass::GetPassTemplate() const + { + return m_template.get(); + } + void Pass::AddAttachmentBinding(PassAttachmentBinding attachmentBinding) { // Add the index of the binding to the input, output or input/output list based on the slot type diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp index 7bd1abc0a7..d9e458c615 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp @@ -8,101 +8,264 @@ #include #include +#include namespace AZ { namespace RPI { - PassHierarchyFilter::PassHierarchyFilter(const Name& passName) + PassFilter PassFilter::CreateWithPassName(Name passName, const Scene* scene) + { + PassFilter filter; + filter.m_passName = passName; + filter.m_ownerScene = scene; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassName(Name passName, const RenderPipeline* renderPipeline) + { + PassFilter filter; + filter.m_passName = passName; + filter.m_ownerRenderPipeline = renderPipeline; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithTemplateName(Name templateName, const Scene* scene) + { + PassFilter filter; + filter.m_templateName = templateName; + filter.m_ownerScene = scene; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline) + { + PassFilter filter; + filter.m_templateName = templateName; + filter.m_ownerRenderPipeline = renderPipeline; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector& passHierarchy) + { + PassFilter filter; + if (passHierarchy.size() == 0) + { + AZ_Assert(false, "passHierarchy should have at least one element"); + return filter; + } + + filter.m_passName = passHierarchy.back(); + + filter.m_parentNames.resize(passHierarchy.size() - 1); + for (uint32_t index = 0; index < filter.m_parentNames.size(); index++) + { + filter.m_parentNames[index] = passHierarchy[index]; + } + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector& passHierarchy) + { + PassFilter filter; + if (passHierarchy.size() == 0) + { + AZ_Assert(false, "passHierarchy should have at least one element"); + return filter; + } + + filter.m_passName = Name(passHierarchy.back()); + + filter.m_parentNames.resize(passHierarchy.size() - 1); + for (uint32_t index = 0; index < filter.m_parentNames.size(); index++) + { + filter.m_parentNames[index] = Name(passHierarchy[index]); + } + filter.UpdateFilterOptions(); + return filter; + } + + void PassFilter::SetOwenrScene(const Scene* scene) + { + m_ownerScene = scene; + UpdateFilterOptions(); + } + + void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline) + { + m_ownerRenderPipeline = renderPipeline; + UpdateFilterOptions(); + } + + void PassFilter::SetPassName(Name passName) { m_passName = passName; + UpdateFilterOptions(); } - PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector& passHierarchy) + void PassFilter::SetTemplateName(Name passTemplateName) { - if (passHierarchy.size() == 0) - { - AZ_Assert(false, "passHierarchy should have at least one element"); - return; - } - - m_passName = Name(passHierarchy.back()); - - m_parentNames.resize(passHierarchy.size() - 1); - for (uint32_t index = 0; index < m_parentNames.size(); index++) - { - m_parentNames[index] = Name(passHierarchy[index]); - } + m_templateName = passTemplateName; + UpdateFilterOptions(); } - PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector& passHierarchy) + void PassFilter::SetPassClass(TypeId passClassTypeId) { - if (passHierarchy.size() == 0) - { - AZ_Assert(false, "passHierarchy should have at least one element"); - return; - } - - m_passName = passHierarchy.back(); - - m_parentNames.resize(passHierarchy.size() - 1); - for (uint32_t index = 0; index < m_parentNames.size(); index++) - { - m_parentNames[index] = passHierarchy[index]; - } + m_passClassTypeId = passClassTypeId; + UpdateFilterOptions(); } - bool PassHierarchyFilter::Matches(const Pass* pass) const + const Name& PassFilter::GetPassName() const { - if (pass->GetName() != m_passName) + return m_passName; + } + + const Name& PassFilter::GetPassTemplateName() const + { + return m_templateName; + } + + uint32_t PassFilter::GetEnabledFilterOptions() const + { + return m_filterOptions; + } + + bool PassFilter::Matches(const Pass* pass) const + { + return Matches(pass, m_filterOptions); + } + + bool PassFilter::Matches(const Pass* pass, uint32_t options) const + { + AZ_Assert( (options&m_filterOptions) == options, "options should be a subset of m_filterOptions"); + + // return false if the pass doesn't have a pass template or the template's name is not matching + if (options & FilterOptions::PassTemplateName && (!pass->GetPassTemplate() || pass->GetPassTemplate()->m_name != m_templateName)) { return false; } - ParentPass* parent = pass->GetParent(); - - // search from the back of the array with the most close parent - for (int32_t index = static_cast(m_parentNames.size() - 1); index >= 0; index--) + if ((options & FilterOptions::PassName) && pass->GetName() != m_passName) { - const Name& parentName = m_parentNames[index]; - while (parent) - { - if (parent->GetName() == parentName) - { - break; - } - parent = parent->GetParent(); - } + return false; + } - // if parent is nullptr the it didn't find a parent has matching current parentName - if (!parent) + if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId) + { + return false; + } + + if ((options & FilterOptions::OwnerRenderPipeline) && m_ownerRenderPipeline != pass->GetRenderPipeline()) + { + return false; + } + + // If the owner render pipeline was checked, the owner scene check can be skipped + if (options & FilterOptions::OwnerScene) + { + if (pass->GetRenderPipeline()) { + // return false if the owner scene doesn't match + if (m_ownerScene != pass->GetRenderPipeline()->GetScene()) + { + return false; + } + } + else + { + // return false if the pass doesn't have an owner scene return false; } + } - // move to next parent - parent = parent->GetParent(); + if ((options & FilterOptions::PassHierarchy)) + { + // Filter for passes which have a matching name and also with ordered parents. + // For example, if the filter is initialized with + // pass name: "ShadowPass1" + // pass parents names: "MainPipeline", "Shadow" + // Passes with these names match the filter: + // "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" + // or "Root.MainPipeline.Shadow.ShadowPass1" + // or "MainPipeline.Shadow.Group1.ShadowPass1" + // + // Passes with these names wont match: + // "MainPipeline.ShadowPass1" + // or "Shadow.MainPipeline.ShadowPass1" + + ParentPass* parent = pass->GetParent(); + + // search from the back of the array with the most close parent + for (int32_t index = static_cast(m_parentNames.size() - 1); index >= 0; index--) + { + const Name& parentName = m_parentNames[index]; + while (parent) + { + if (parent->GetName() == parentName) + { + break; + } + parent = parent->GetParent(); + } + + // if parent is nullptr the it didn't find a parent has matching current parentName + if (!parent) + { + return false; + } + + // move to next parent + parent = parent->GetParent(); + } } return true; } - const Name* PassHierarchyFilter::GetPassName() const + void PassFilter::UpdateFilterOptions() { - return &m_passName; - } - - AZStd::string PassHierarchyFilter::ToString() const - { - AZStd::string result = "PassHierarchyFilter"; - for (uint32_t index = 0; index < m_parentNames.size(); index++) + m_filterOptions = FilterOptions::Empty; + if (!m_passName.IsEmpty()) { - result += AZStd::string::format(" [%s]", m_parentNames[index].GetCStr()); + m_filterOptions |= FilterOptions::PassName; + } + if (!m_templateName.IsEmpty()) + { + m_filterOptions |= FilterOptions::PassTemplateName; + } + if (m_parentNames.size() > 0) + { + m_filterOptions |= FilterOptions::PassHierarchy; + } + if (m_ownerRenderPipeline) + { + m_filterOptions |= FilterOptions::OwnerRenderPipeline; + } + if (m_ownerScene) + { + // If the OwnerRenderPipeline exists, we shouldn't need to filter owner scene + // Validate the owner render pipeline belongs to the owner scene + if (m_filterOptions & FilterOptions::OwnerRenderPipeline) + { + if (m_ownerRenderPipeline->GetScene() != m_ownerScene) + { + AZ_Warning("RPI", false, "The owner scene filter doesn't match owner render pipeline. It will be skipped."); + } + } + else + { + m_filterOptions |= FilterOptions::OwnerScene; + } + } + if (!m_passClassTypeId.IsNull()) + { + m_filterOptions |= FilterOptions::PassClass; } - - result += AZStd::string::format(" [%s]", m_passName.GetCStr()); - return result; } - } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp index c43edafd6b..6a6f5f3ff9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp @@ -85,47 +85,80 @@ namespace AZ return (GetPassesForTemplate(templateName).size() > 0); } - AZStd::vector PassLibrary::FindPasses(const PassFilter& passFilter) const + void PassLibrary::ForEachPass(const PassFilter& passFilter, AZStd::function passFunction) { - const Name* passName = passFilter.GetPassName(); + uint32_t filterOptions = passFilter.GetEnabledFilterOptions(); - AZStd::vector result; - - if (passName) + // A lambda function which visits each pass in a pass list, if the pass matches the pass filter, then call the pass function + auto visitList = [passFilter, passFunction](const AZStd::vector& passList, uint32_t options) -> PassFilterExecutionFlow { - // If the pass' name is known, find passes with matching names first - const auto constItr = m_passNameMapping.find(*passName); - if (constItr == m_passNameMapping.end()) + if (passList.size() == 0) { - return result; + return PassFilterExecutionFlow::ContinueVisitingPasses; } - - const AZStd::vector& passes = constItr->second; - - for (Pass* pass : passes) + // if there is not other filter options enabled, skip the filter and call pass functions directly + if (options == PassFilter::FilterOptions::Empty) { - if (passFilter.Matches(pass)) + for (Pass* pass : passList) { - result.push_back(pass); - } - } - } - else - { - // If the filter doesn't know matching pass' name, need to go through all registered passes - for (auto& namePasses : m_passNameMapping) - { - for (Pass* pass : namePasses.second) - { - if (passFilter.Matches(pass)) + // If user want to skip processing, return directly. + if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses) { - result.push_back(pass); + return PassFilterExecutionFlow::StopVisitingPasses; + } + } + return PassFilterExecutionFlow::ContinueVisitingPasses; + } + + // Check with the pass filter and call pass functions + for (Pass* pass : passList) + { + if (passFilter.Matches(pass, options)) + { + if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses) + { + return PassFilterExecutionFlow::StopVisitingPasses; } } } + return PassFilterExecutionFlow::ContinueVisitingPasses; + }; + + // Check pass template name first + if (filterOptions & PassFilter::FilterOptions::PassTemplateName) + { + auto entry = GetEntry(passFilter.GetPassTemplateName()); + if (!entry) + { + return; + } + + filterOptions &= ~(PassFilter::FilterOptions::PassTemplateName); + visitList(entry->m_passes, filterOptions); + return; + } + else if (filterOptions & PassFilter::FilterOptions::PassName) + { + const auto constItr = m_passNameMapping.find(passFilter.GetPassName()); + if (constItr == m_passNameMapping.end()) + { + return; + } + + filterOptions &= ~(PassFilter::FilterOptions::PassName); + visitList(constItr->second, filterOptions); + return; } - return result; + // check againest every passes. This might be slow + AZ_PROFILE_SCOPE(RPI, "PassLibrary::ForEachPass"); + for (auto& namePasses : m_passNameMapping) + { + if (visitList(namePasses.second, filterOptions) == PassFilterExecutionFlow::StopVisitingPasses) + { + return; + } + } } // Add Functions... @@ -419,3 +452,4 @@ namespace AZ } // namespace RPI } // namespace AZ + 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 f4f51f97b7..7f2948c13a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -456,11 +456,6 @@ namespace AZ return m_passLibrary.HasPassesForTemplate(templateName); } - const AZStd::vector& PassSystem::GetPassesForTemplateName(const Name& templateName) const - { - return m_passLibrary.GetPassesForTemplate(templateName); - } - bool PassSystem::AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) { return m_passLibrary.AddPassTemplate(name, passTemplate); @@ -487,10 +482,21 @@ namespace AZ RemovePassFromLibrary(pass); --m_passCounter; } - - AZStd::vector PassSystem::FindPasses(const PassFilter& passFilter) const + + void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function passFunction) { - return m_passLibrary.FindPasses(passFilter); + return m_passLibrary.ForEachPass(filter, passFunction); + } + + Pass* PassSystem::FindFirstPass(const PassFilter& filter) + { + Pass* foundPass = nullptr; + m_passLibrary.ForEachPass(filter, [&foundPass](RPI::Pass* pass) ->PassFilterExecutionFlow + { + foundPass = pass; + return PassFilterExecutionFlow::StopVisitingPasses; + }); + return foundPass; } SwapChainPass* PassSystem::FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const diff --git a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp index 420ab1798a..690f212ec7 100644 --- a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp @@ -19,6 +19,8 @@ #include #include +#include + #include #include @@ -573,7 +575,7 @@ namespace UnitTest EXPECT_TRUE(pass != nullptr); } - TEST_F(PassTests, PassHierarchyFilter) + TEST_F(PassTests, PassFilter_PassHierarchy) { m_data->AddPassTemplatesToLibrary(); @@ -587,62 +589,55 @@ namespace UnitTest parent2->AsParent()->AddChild(parent1); parent1->AsParent()->AddChild(pass); - { - // Filter with only pass name - PassHierarchyFilter filter(Name("pass1")); - EXPECT_TRUE(filter.Matches(pass.get())); - } - { // Filter with pass hierarchy which has only one element - PassHierarchyFilter filter({ Name("pass1") }); + PassFilter filter = PassFilter::CreateWithPassHierarchy({Name("pass1")}); EXPECT_TRUE(filter.Matches(pass.get())); } { - // Filter with empty pass hierarchy. Result one assert + // Filter with empty pass hierarchy, triggers one assert AZ_TEST_START_TRACE_SUPPRESSION; - PassHierarchyFilter filter(AZStd::vector{}); + PassFilter filter = PassFilter::CreateWithPassHierarchy(AZStd::vector{}); AZ_TEST_STOP_TRACE_SUPPRESSION(1); - EXPECT_FALSE(filter.Matches(pass.get())); } { // Filters with partial hierarchy by using string vector AZStd::vector passHierarchy1 = { "parent1", "pass1" }; - PassHierarchyFilter filter1(passHierarchy1); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1); EXPECT_TRUE(filter1.Matches(pass.get())); AZStd::vector passHierarchy2 = { "parent2", "pass1" }; - PassHierarchyFilter filter2(passHierarchy2); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2); EXPECT_TRUE(filter2.Matches(pass.get())); AZStd::vector passHierarchy3 = { "parent3", "parent2", "pass1" }; - PassHierarchyFilter filter3(passHierarchy3); + PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3); EXPECT_TRUE(filter3.Matches(pass.get())); } { // Filters with partial hierarchy by using Name vector AZStd::vector passHierarchy1 = { Name("parent1"), Name("pass1") }; - PassHierarchyFilter filter1(passHierarchy1); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1); EXPECT_TRUE(filter1.Matches(pass.get())); AZStd::vector passHierarchy2 = { Name("parent2"), Name("pass1")}; - PassHierarchyFilter filter2(passHierarchy2); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2); EXPECT_TRUE(filter2.Matches(pass.get())); AZStd::vector passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") }; - PassHierarchyFilter filter3(passHierarchy3); + PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3); EXPECT_TRUE(filter3.Matches(pass.get())); } { // Find non-leaf pass - PassHierarchyFilter filter1(AZStd::vector{"parent3", "parent1"}); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"parent3", "parent1"}); EXPECT_TRUE(filter1.Matches(parent1.get())); - - PassHierarchyFilter filter2(Name("parent1")); + + PassFilter filter2 = PassFilter::CreateWithPassHierarchy({ Name("parent1") }); EXPECT_TRUE(filter2.Matches(parent1.get())); EXPECT_FALSE(filter2.Matches(pass.get())); } @@ -650,11 +645,131 @@ namespace UnitTest { // Failed to find pass // Mis-matching hierarchy - PassHierarchyFilter filter1(AZStd::vector{"Parent1", "Parent3", "pass1"}); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"Parent1", "Parent3", "pass1"}); EXPECT_FALSE(filter1.Matches(pass.get())); // Mis-matching name - PassHierarchyFilter filter2(AZStd::vector{"Parent1", "pass1"}); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"Parent1", "pass1"}); EXPECT_FALSE(filter2.Matches(parent1.get())); } } + + TEST_F(PassTests, PassFilter_Empty_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + Ptr parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2")); + Ptr parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3")); + + parent3->AsParent()->AddChild(parent2); + parent2->AsParent()->AddChild(parent1); + parent1->AsParent()->AddChild(pass); + + PassFilter filter; + + // Any pass can match an empty filter + EXPECT_TRUE(filter.Matches(pass.get())); + EXPECT_TRUE(filter.Matches(parent1.get())); + EXPECT_TRUE(filter.Matches(parent2.get())); + EXPECT_TRUE(filter.Matches(parent3.get())); + } + + TEST_F(PassTests, PassFilter_PassClass_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr depthPass = m_passSystem->CreatePassFromTemplate(Name("DepthPrePass"), Name("depthPass")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + + parent1->AsParent()->AddChild(pass); + parent1->AsParent()->AddChild(depthPass); + + PassFilter filter1 = PassFilter::CreateWithPassClass(); + + EXPECT_TRUE(filter1.Matches(pass.get())); + EXPECT_FALSE(filter1.Matches(parent1.get())); + + PassFilter filter2 = PassFilter::CreateWithPassClass(); + EXPECT_FALSE(filter2.Matches(pass.get())); + EXPECT_TRUE(filter2.Matches(parent1.get())); + } + + TEST_F(PassTests, PassFilter_PassTemplate_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr childPass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + + PassFilter filter1 = PassFilter::CreateWithTemplateName(Name("Pass"), (Scene*) nullptr); + // childPass doesn't have a template + EXPECT_FALSE(filter1.Matches(childPass.get())); + + PassFilter filter2 = PassFilter::CreateWithTemplateName(Name("ParentPass"), (Scene*) nullptr); + EXPECT_TRUE(filter2.Matches(parent1.get())); + } + + TEST_F(PassTests, ForEachPass_PassTemplateFilter_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + Ptr parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2")); + Ptr parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3")); + + parent3->AsParent()->AddChild(parent2); + parent2->AsParent()->AddChild(parent1); + parent1->AsParent()->AddChild(pass); + + // Create render pipeline + const RPI::PipelineViewTag viewTag{ "viewTag1" }; + RPI::RenderPipelineDescriptor desc; + desc.m_mainViewTagName = viewTag.GetStringView(); + desc.m_name = "TestPipeline"; + RPI::RenderPipelinePtr pipeline = RPI::RenderPipeline::CreateRenderPipeline(desc); + Ptr parent4 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent4")); + pipeline->GetRootPass()->AddChild(parent4); + + Name templateName = Name("ParentPass"); + PassFilter filter1 = PassFilter::CreateWithTemplateName(templateName, (RenderPipeline*)nullptr); + + int count = 0; + m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow + { + EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName); + count++; + return PassFilterExecutionFlow::ContinueVisitingPasses; + }); + + // three from CreatePassFromTemplate() calls and one from Render Pipeline. + EXPECT_TRUE(count == 4); + + count = 0; + m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow + { + EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName); + count++; + return PassFilterExecutionFlow::StopVisitingPasses; + }); + EXPECT_TRUE(count == 1); + + PassFilter filter2 = PassFilter::CreateWithTemplateName(templateName, pipeline.get()); + count = 0; + m_passSystem->ForEachPass(filter2, [&count]([[maybe_unused]] RPI::Pass* pass) -> PassFilterExecutionFlow + { + count++; + return PassFilterExecutionFlow::ContinueVisitingPasses; + }); + + // only the ParentPass in the render pipeline was found + EXPECT_TRUE(count == 1); + + } } diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp index a0be18f0e2..161160e16f 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -142,12 +143,13 @@ namespace AZ EnablePasses(true); } - void HairFeatureProcessor::EnablePasses([[maybe_unused]] bool enable) + void HairFeatureProcessor::EnablePasses(bool enable) { - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName); - if (desiredPass) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); + if (pass) { - desiredPass->SetEnabled(enable); + pass->SetEnabled(enable); } } @@ -309,10 +311,17 @@ namespace AZ m_forceClearRenderData = true; } + bool HairFeatureProcessor::HasHairParentPass() + { + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); + return pass; + } + void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline.get()->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -323,10 +332,10 @@ namespace AZ m_forceRebuildRenderData = true; } - void HairFeatureProcessor::OnRenderPipelineRemoved(RPI::RenderPipeline* renderPipeline) + void HairFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -338,7 +347,7 @@ namespace AZ void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -457,7 +466,8 @@ namespace AZ { m_computePasses[passName] = nullptr; - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(passName); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(passName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_computePasses[passName] = static_cast(desiredPass.get()); @@ -478,8 +488,9 @@ namespace AZ bool HairFeatureProcessor::InitPPLLFillPass() { m_hairPPLLRasterPass = nullptr; // reset it to null, just in case it fails to load the assets properly - - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLRasterPassName); + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLRasterPassName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_hairPPLLRasterPass = static_cast(desiredPass.get()); @@ -497,7 +508,8 @@ namespace AZ { m_hairPPLLResolvePass = nullptr; // reset it to null, just in case it fails to load the assets properly - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLResolvePassName); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLResolvePassName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_hairPPLLResolvePass = static_cast(desiredPass.get()); @@ -518,8 +530,8 @@ namespace AZ m_hairShortCutGeometryDepthAlphaPass = nullptr; m_hairShortCutGeometryShadingPass = nullptr; - m_hairShortCutGeometryDepthAlphaPass = static_cast( - m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryDepthAlphaPassName).get()); + RPI::PassFilter depthAlphaPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryDepthAlphaPassName, m_renderPipeline); + m_hairShortCutGeometryDepthAlphaPass = static_cast(RPI::PassSystemInterface::Get()->FindFirstPass(depthAlphaPassFilter)); if (m_hairShortCutGeometryDepthAlphaPass) { m_hairShortCutGeometryDepthAlphaPass->SetFeatureProcessor(this); @@ -530,8 +542,8 @@ namespace AZ return false; } - m_hairShortCutGeometryShadingPass = static_cast( - m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryShadingPassName).get()); + RPI::PassFilter shaderingPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryShadingPassName, m_renderPipeline); + m_hairShortCutGeometryShadingPass = static_cast(RPI::PassSystemInterface::Get()->FindFirstPass(shaderingPassFilter)); if (m_hairShortCutGeometryShadingPass) { m_hairShortCutGeometryShadingPass->SetFeatureProcessor(this); diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h index 46660a6623..f810967824 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h @@ -165,6 +165,8 @@ namespace AZ void EnablePasses(bool enable); + bool HasHairParentPass(); + //! The following will serve to register the FP in the Thumbnail system AZStd::vector m_hairFeatureProcessorRegistryName; From a5694a5ac65093dcb7b713b97f7382d987a7feed Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Mon, 25 Oct 2021 12:49:57 -0700 Subject: [PATCH 06/33] ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface (#4739) (#4963) * ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface Introduced new PassSystemInterface::ForEachPass() funtion to replace PassSystemInterface::FindPasses(), PassSystemInterface::GetPassesByTemplateName and ParentPass::FindPassByNameRecursive() functions. Update all the places which were using those three functions. The new pass finding filter support any combination of pass name, pass template name, pass class type, pass hirechary, owner scene, owner render pipeline. Update unit tests. Signed-off-by: Qing Tao (cherry picked from commit fe8dac798977a2271a2a5775d947d7172949866e) --- .../Include/Atom/Feature/ImGui/ImGuiUtils.h | 6 +- .../Include/Atom/Feature/ImGui/SystemBus.h | 7 +- .../Atom/Feature/Utils/FrameCaptureBus.h | 2 +- .../DirectionalLightFeatureProcessor.cpp | 71 ++--- ...fuseGlobalIlluminationFeatureProcessor.cpp | 57 ++-- .../DiffuseProbeGridFeatureProcessor.cpp | 12 +- .../DisplayMapper/DisplayMapperPass.cpp | 25 +- .../Source/FrameCaptureSystemComponent.cpp | 37 +-- .../Source/ImGui/ImGuiSystemComponent.cpp | 48 +-- .../Code/Source/ImGui/ImGuiSystemComponent.h | 2 +- .../DepthOfField/DepthOfFieldSettings.cpp | 20 +- .../ExposureControlSettings.cpp | 27 +- .../LookModificationCompositePass.cpp | 14 +- .../PostProcessing/SMAAFeatureProcessor.cpp | 51 ++-- .../ProfilingCaptureSystemComponent.cpp | 31 +- .../Source/ProfilingCaptureSystemComponent.h | 2 - .../ReflectionCopyFrameBufferPass.cpp | 19 +- .../ReflectionScreenSpaceBlurPass.cpp | 2 +- .../ReflectionScreenSpaceCompositePass.cpp | 26 +- .../ProjectedShadowFeatureProcessor.cpp | 54 ++-- .../Shadows/ProjectedShadowFeatureProcessor.h | 4 +- .../SkinnedMeshFeatureProcessor.cpp | 13 +- .../SkinnedMesh/SkinnedMeshFeatureProcessor.h | 2 +- .../Include/Atom/RPI.Public/Pass/ParentPass.h | 3 - .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 4 + .../Include/Atom/RPI.Public/Pass/PassFilter.h | 136 ++++----- .../Atom/RPI.Public/Pass/PassLibrary.h | 4 +- .../Include/Atom/RPI.Public/Pass/PassSystem.h | 4 +- .../RPI.Public/Pass/PassSystemInterface.h | 21 +- .../Source/RPI.Public/Pass/ParentPass.cpp | 23 -- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 5 + .../Source/RPI.Public/Pass/PassFilter.cpp | 285 ++++++++++++++---- .../Source/RPI.Public/Pass/PassLibrary.cpp | 90 ++++-- .../Source/RPI.Public/Pass/PassSystem.cpp | 22 +- Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp | 159 ++++++++-- .../Code/Rendering/HairFeatureProcessor.cpp | 44 ++- .../Code/Rendering/HairFeatureProcessor.h | 2 + 37 files changed, 800 insertions(+), 534 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h index a200f30c98..52e272a9c4 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h @@ -50,12 +50,12 @@ namespace AZ return scope; } - //! Sets the active context based on the provided PassHierarchyFilter. If the filter doesn't match exactly one pass, then do nothing. - static ImGuiActiveContextScope FromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) + //! Sets the active context based on the provided pass hierarchy filter. If the filter doesn't match exactly one pass, then do nothing. + static ImGuiActiveContextScope FromPass(const AZStd::vector& passHierarchy) { ImGuiActiveContextScope scope; scope.ConnectToImguiNotificationBus(); - ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchyFilter); + ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchy); return scope; } diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h index 289cb178d4..78f71b39ba 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h @@ -15,11 +15,6 @@ namespace AZ { - namespace RPI - { - class PassHierarchyFilter; - } - namespace Render { class ImGuiPass; @@ -51,7 +46,7 @@ namespace AZ //! Pushes whichever ImGui pass is default on the top of the active context stack. Returns true/false for success/fail. virtual bool PushActiveContextFromDefaultPass() = 0; //! Pushes whichever ImGui pass is provided in passHierarchy on the top of the active context stack. Returns true/false for success/fail. - virtual bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) = 0; + virtual bool PushActiveContextFromPass(const AZStd::vector& passHierarchy) = 0; //! Pops the active context off the top of the active context stack. Returns true if there's a context to pop. virtual bool PopActiveContext() = 0; //! Gets the context at the top of the active context stack. Returns nullptr if the stack is emtpy. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h index 93600ec08f..c80926700e 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h @@ -50,7 +50,7 @@ namespace AZ virtual bool CaptureScreenshotWithPreview(const AZStd::string& outputFilePath) = 0; //! Save a buffer attachment or a image attachment binded to a pass's slot to a data file. - //! @param passHierarchy For finding the pass by using PassHierarchyFilter + //! @param passHierarchy For finding the pass by using a pass hierarchy filter. Check PassFilter::CreateWithPassHierarchy() function for detail //! @param slotName Name of the pass's slot. The attachment bound to this slot will be captured. //! @param option Only valid for an InputOutput attachment. Use PassAttachmentReadbackOption::Input to capture the input state //! and use PassAttachmentReadbackOption::Output to capture the output state diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 6c24b7d35b..b6c6910fd3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -647,54 +647,46 @@ namespace AZ UpdateViewsOfCascadeSegments(); } - void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() { - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("CascadedShadowmapsTemplate")); + void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() + { m_cascadedShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("CascadedShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { + RPI::RenderPipeline* pipeline = pass->GetRenderPipeline(); const RPI::RenderPipelineId pipelineId = pipeline->GetId(); - // This function can be called when the pipeline is not attached to the scene. - // So we check it is attached to the scene. - if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) + + CascadedShadowmapsPass* shadowPass = azrtti_cast(pass); + AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass."); + if (pipeline->GetDefaultView()) { - CascadedShadowmapsPass* shadowPass = azrtti_cast(pass); - AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass."); - if (pipeline->GetDefaultView()) - { - m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass); - } + m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DirectionalLightFeatureProcessor::CacheEsmShadowmapsPass() { - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); m_esmShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - const RPI::RenderPipelineId pipelineId = pipeline->GetId(); - // checking the render pipeline is just removed from the scene. - if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) + const RPI::RenderPipelineId pipelineId = pass->GetRenderPipeline()->GetId(); + + if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) { - if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) + EsmShadowmapsPass* esmPass = azrtti_cast(pass); + AZ_Assert(esmPass, "It is not an EsmShadowmapPass."); + if (esmPass->GetLightTypeName() == m_lightTypeName) { - EsmShadowmapsPass* esmPass = azrtti_cast(pass); - AZ_Assert(esmPass, "It is not an EsmShadowmapPass."); - if (m_cascadedShadowmapsPasses.find(esmPass->GetRenderPipeline()->GetId()) != m_cascadedShadowmapsPasses.end() && - esmPass->GetLightTypeName() == m_lightTypeName) - { - m_esmShadowmapsPasses[pipelineId].push_back(esmPass); - } + m_esmShadowmapsPasses[pipelineId].push_back(esmPass); } } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DirectionalLightFeatureProcessor::PrepareCameraViews() @@ -1063,12 +1055,13 @@ namespace AZ // if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view, // to filter out shadows from objects that are excluded from the cubemap - RPI::PassClassFilter passFilter; - AZStd::vector cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!cubeMapPasses.empty()) - { - usageFlags |= RPI::View::UsageReflectiveCubeMap; - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + usageFlags |= RPI::View::UsageReflectiveCubeMap; + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); segment.m_view = RPI::View::CreateView(viewName, usageFlags); } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp index c085b26e31..453dbbc0ab 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp @@ -80,35 +80,48 @@ namespace AZ } // update the size multiplier on the DiffuseProbeGridDownsamplePass output - AZStd::vector downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; - RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy); - const AZStd::vector& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter); - for (RPI::Pass* pass : downsamplePasses) + // NOTE: The ownerScene wasn't added to both filters. This is because the passes from the non-owner scene may have invalid SRG values which could lead to + // GPU error if the scene doesn't have this feature processor enabled. + // For example, the ASV MultiScene sample may have TDR. { - for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) - { - RPI::Ptr outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; - RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; + AZStd::vector downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; + RPI::PassFilter downsamplePassFilter = RPI::PassFilter::CreateWithPassHierarchy(downsamplePassHierarchy); + RPI::PassSystemInterface::Get()->ForEachPass( + downsamplePassFilter, + [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) + { + RPI::Ptr outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; + RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; - sizeMultipliers.m_widthMultiplier = sizeMultiplier; - sizeMultipliers.m_heightMultiplier = sizeMultiplier; - } + sizeMultipliers.m_widthMultiplier = sizeMultiplier; + sizeMultipliers.m_heightMultiplier = sizeMultiplier; + } - // set the output scale on the PassSrg - RPI::FullscreenTrianglePass* downsamplePass = static_cast(pass); - auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale")); - downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + // set the output scale on the PassSrg + RPI::FullscreenTrianglePass* downsamplePass = static_cast(pass); + RHI::ShaderInputNameIndex outputImageScaleShaderInput = "m_outputImageScale"; + downsamplePass->GetShaderResourceGroup()->SetConstant( + outputImageScaleShaderInput, aznumeric_cast(1.0f / sizeMultiplier)); + + // handle all downsample passes + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } // update the image scale on the DiffuseComposite pass - AZStd::vector compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") }; - RPI::PassHierarchyFilter compositePassFilter(compositePassHierarchy); - const AZStd::vector& compositePasses = RPI::PassSystemInterface::Get()->FindPasses(compositePassFilter); - for (RPI::Pass* pass : compositePasses) { - RPI::FullscreenTrianglePass* compositePass = static_cast(pass); - auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale")); - compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + AZStd::vector compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") }; + RPI::PassFilter compositePassFilter = RPI::PassFilter::CreateWithPassHierarchy(compositePassHierarchy); + RPI::PassSystemInterface::Get()->ForEachPass(compositePassFilter, [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + RPI::FullscreenTrianglePass* compositePass = static_cast(pass); + RHI::ShaderInputNameIndex imageScaleShaderInput = "m_imageScale"; + compositePass->GetShaderResourceGroup()->SetConstant(imageScaleShaderInput, aznumeric_cast(1.0f / sizeMultiplier)); + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } } } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index 4329fd556c..5ea4748fc9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -603,12 +603,12 @@ namespace AZ RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); if (device->GetFeatures().m_rayTracing == false) { - RPI::PassHierarchyFilter updatePassFilter(AZ::Name("DiffuseProbeGridUpdatePass")); - const AZStd::vector& updatePasses = RPI::PassSystemInterface::Get()->FindPasses(updatePassFilter); - for (RPI::Pass* pass : updatePasses) - { - pass->SetEnabled(false); - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(false); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index 3ec8840a1c..5b5599383e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -10,9 +10,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include @@ -66,22 +67,14 @@ namespace AZ { // Need to invalidate the CopyToSwapChain pass so that it updates the pipeline state in the event that // the swapchain format changed (for example, moving from LDR to HDR display) - auto* passSystem = RPI::PassSystemInterface::Get(); - const Name fullscreenCopyTemplateName("FullscreenCopyTemplate"); - - if (passSystem->HasPassesForTemplateName(fullscreenCopyTemplateName)) - { - const AZStd::vector& passes = passSystem->GetPassesForTemplateName(fullscreenCopyTemplateName); - for (RPI::Pass* pass : passes) + const Name copyToSwapChainPassName("CopyToSwapChain"); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(copyToSwapChainPassName, GetRenderPipeline()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - RPI::FullscreenTrianglePass* fullscreenTrianglePass = azrtti_cast(pass); - const Name& passName = fullscreenTrianglePass->GetName(); - if (passName.GetStringView() == "CopyToSwapChain") - { - fullscreenTrianglePass->QueueForInitialization(); - } - } - } + pass->QueueForInitialization(); + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); + ConfigureDisplayParameters(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 8c0360dec2..ed2d8a1d9f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -372,29 +372,25 @@ namespace AZ } m_latestCaptureInfo.clear(); - // Find the pass first - RPI::PassClassFilter passFilter; - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - - if (foundPasses.size() == 0) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast(RPI::PassSystemInterface::Get()->FindFirstPass(passFilter)); + if (!previewPass) { - AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass pass "); + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass"); return false; } - AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast(foundPasses[0]); bool result = previewPass->ReadbackOutput(m_readback); if (result) { m_state = State::Pending; m_result = FrameCaptureResult::None; SystemTickBus::Handler::BusConnect(); + return true; } - else - { - AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass");; - } - return result; + + AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass"); + return false; } bool FrameCaptureSystemComponent::CapturePassAttachment(const AZStd::vector& passHierarchy, const AZStd::string& slot, @@ -405,6 +401,12 @@ namespace AZ return false; } + if (passHierarchy.size() == 0) + { + AZ_Warning("FrameCaptureSystemComponent", false, "Empty data in passHierarchy"); + return false; + } + InitReadback(); if (m_state != State::Idle) @@ -426,17 +428,15 @@ namespace AZ } m_latestCaptureInfo.clear(); - // Find the pass first - AZ::RPI::PassHierarchyFilter passFilter(passHierarchy); - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchy); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); - if (foundPasses.size() == 0) + if (!pass) { - AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str()); + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passHierarchy[0].c_str()); return false; } - AZ::RPI::Pass* pass = foundPasses[0]; if (pass->ReadbackAttachment(m_readback, Name(slot), option)) { m_state = State::Pending; @@ -444,6 +444,7 @@ namespace AZ SystemTickBus::Handler::BusConnect(); return true; } + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to readback the attachment bound to pass [%s] slot [%s]", pass->GetName().GetCStr(), slot.c_str()); return false; } diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp index afca20c5cb..3783752e67 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp @@ -109,15 +109,15 @@ namespace AZ void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func) { ImGuiContext* contextToRestore = ImGui::GetCurrentContext(); - RPI::PassClassFilter filter; - auto imguiPasses = RPI::PassSystemInterface::Get()->FindPasses(filter); - - for (RPI::Pass* pass : imguiPasses) - { - ImGuiPass* imguiPass = azrtti_cast(pass); - ImGui::SetCurrentContext(imguiPass->GetContext()); - func(imguiPass); - } + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + ImGuiPass* imguiPass = azrtti_cast(pass); + ImGui::SetCurrentContext(imguiPass->GetContext()); + func(imguiPass); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); ImGui::SetCurrentContext(contextToRestore); } @@ -169,29 +169,37 @@ namespace AZ return false; } - bool ImGuiSystemComponent::PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) + bool ImGuiSystemComponent::PushActiveContextFromPass(const AZStd::vector& passHierarchyFilter) { - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passHierarchyFilter); + if (passHierarchyFilter.size() == 0) + { + AZ_Warning("ImGuiSystemComponent", false, "passHierarchyFilter is empty"); + return false; + } + AZStd::vector foundImGuiPasses; - for (RPI::Pass* pass : foundPasses) - { - ImGuiPass* imGuiPass = azrtti_cast(pass); - if (imGuiPass) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchyFilter); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundImGuiPasses](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - foundImGuiPasses.push_back(imGuiPass); - } - } + ImGuiPass* imGuiPass = azrtti_cast(pass); + if (imGuiPass) + { + foundImGuiPasses.push_back(imGuiPass); + } + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); if (foundImGuiPasses.size() == 0) { - AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter.ToString().c_str()); + AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter[0].c_str()); return false; } if (foundImGuiPasses.size() > 1) { - AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter.ToString().c_str()); + AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter[0].c_str()); } ImGuiContext* context = foundImGuiPasses.at(0)->GetContext(); diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h index 838cf0b3c2..d59124890f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h @@ -56,7 +56,7 @@ namespace AZ ImGuiPass* GetDefaultImGuiPass() override; bool PushActiveContextFromDefaultPass() override; - bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) override; + bool PushActiveContextFromPass(const AZStd::vector& passHierarchy) override; bool PopActiveContext() override; ImGuiContext* GetActiveContext() override; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp index fe1ce8a281..98b527868d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -259,24 +260,19 @@ namespace AZ // [GFX TODO][ATOM-3035]This function is temporary and will change with improvement to the draw list tag system void DepthOfFieldSettings::UpdateAutoFocusDepth(bool enabled) - { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); + { const Name TemplateNameReadBackFocusDepth = Name("DepthOfFieldReadBackFocusDepthTemplate"); - if (passSystem->HasPassesForTemplateName(TemplateNameReadBackFocusDepth)) - { - const AZStd::vector& dofPasses = passSystem->GetPassesForTemplateName(TemplateNameReadBackFocusDepth); - for (RPI::Pass* pass : dofPasses) + // [GFX TODO][ATOM-4908] multiple camera should be distingushed. + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(TemplateNameReadBackFocusDepth, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, enabled](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* dofPass = azrtti_cast(pass); - // Check this pass belongs to a render pipeline of the scene. - // [GFX TODO][ATOM-4908] multiple camera should be distingushed. - const RPI::RenderPipelineId pipelineId = dofPass->GetRenderPipeline()->GetId(); - if (enabled && GetParentScene()->GetRenderPipeline(pipelineId)) + if (enabled) { m_normalizedFocusDistanceForAutoFocus = dofPass->GetNormalizedFocusDistanceForAutoFocus(); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DepthOfFieldSettings::SetCameraEntityId(EntityId cameraEntityId) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp index 96ca424307..26c2a61d54 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -188,21 +189,21 @@ namespace AZ void ExposureControlSettings::UpdateLuminanceHeatmap() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - // [GFX-TODO][ATOM-13194] Support multiple views for the luminance heatmap - // [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass - const RPI::Ptr luminanceHeatmap = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHeatmapNameId); - if (luminanceHeatmap) - { - luminanceHeatmap->SetEnabled(m_heatmapEnabled); - } + // [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass + RPI::PassFilter heatmapPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHeatmapNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(heatmapPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(m_heatmapEnabled); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); - const RPI::Ptr histogramGenerator = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHistogramGeneratorNameId); - if (histogramGenerator) - { - histogramGenerator->SetEnabled(m_heatmapEnabled); - } + RPI::PassFilter histogramPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHistogramGeneratorNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(histogramPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(m_heatmapEnabled); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void ExposureControlSettings::UpdateBuffer() diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp index 85c45de96b..aac3d1d941 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp @@ -31,12 +31,14 @@ namespace AZ 0, [](const uint8_t& value) { - auto passes = RPI::PassSystem::Get()->FindPasses(RPI::PassClassFilter()); - for (auto* pass : passes) - { - LookModificationCompositePass* lookModPass = azrtti_cast(pass); - lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value)); - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [value](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + LookModificationCompositePass* lookModPass = azrtti_cast(pass); + lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value)); + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); }, ConsoleFunctorFlags::Null, "This can be increased to deal with particularly tricky luts. Range (0-2). 0 (default) - Standard linear sampling. 1 - 7 tap b-spline sampling. 2 - 19 tap b-spline sampling." diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp index eef0c51e95..ad059fbec0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -71,26 +72,18 @@ namespace AZ void SMAAFeatureProcessor::UpdateConvertToPerceptualPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId)) - { - const AZStd::vector& convertToPerceptualColorPasses = passSystem->GetPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId); - for (RPI::Pass* pass : convertToPerceptualColorPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_convertToPerceptualColorPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { pass->SetEnabled(m_data.m_enable); - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateEdgeDetectionPass() - { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_edgeDetectioPassTemplateNameId)) - { - const AZStd::vector& edgeDetectionPasses = passSystem->GetPassesForTemplateName(m_edgeDetectioPassTemplateNameId); - for (RPI::Pass* pass : edgeDetectionPasses) + { + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_edgeDetectioPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* edgeDetectionPass = azrtti_cast(pass); @@ -106,18 +99,14 @@ namespace AZ edgeDetectionPass->SetPredicationScale(m_data.m_predicationScale); edgeDetectionPass->SetPredicationStrength(m_data.m_predicationStrength); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateBlendingWeightCalculationPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId)) - { - const AZStd::vector& blendingWeightCalculationPasses = passSystem->GetPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId); - for (RPI::Pass* pass : blendingWeightCalculationPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_blendingWeightCalculationPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* blendingWeightCalculationPass = azrtti_cast(pass); @@ -130,18 +119,14 @@ namespace AZ blendingWeightCalculationPass->SetDiagonalDetectionEnable(m_data.m_enableDiagonalDetection); blendingWeightCalculationPass->SetCornerDetectionEnable(m_data.m_enableCornerDetection); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateNeighborhoodBlendingPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId)) - { - const AZStd::vector& neighborhoodBlendingPasses = passSystem->GetPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId); - for (RPI::Pass* pass : neighborhoodBlendingPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_neighborhoodBlendingPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* neighborhoodBlendingPass = azrtti_cast(pass); @@ -153,8 +138,8 @@ namespace AZ { neighborhoodBlendingPass->SetOutputMode(SMAAOutputMode::PassThrough); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::Render([[maybe_unused]] const SMAAFeatureProcessor::RenderPacket& packet) diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp index 66adfe9985..9bfb2b7e9e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp @@ -377,14 +377,7 @@ namespace AZ bool ProfilingCaptureSystemComponent::CapturePassTimestamp(const AZStd::string& outputFilePath) { - // Find the root pass. - AZStd::vector passes = FindPasses({ "Root" }); - if (passes.empty()) - { - return false; - } - - RPI::Pass* root = passes[0]; + RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get(); // Enable all the Timestamp queries in passes. root->SetTimestampQueryEnabled(true); @@ -465,14 +458,7 @@ namespace AZ bool ProfilingCaptureSystemComponent::CapturePassPipelineStatistics(const AZStd::string& outputFilePath) { - // Find the root pass. - AZStd::vector passes = FindPasses({ "Root" }); - if (passes.empty()) - { - return false; - } - - RPI::Pass* root = passes[0]; + RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get(); // Enable all the PipelineStatistics queries in passes. root->SetPipelineStatisticsQueryEnabled(true); @@ -572,19 +558,6 @@ namespace AZ return passes; } - AZStd::vector ProfilingCaptureSystemComponent::FindPasses(AZStd::vector&& passHierarchy) const - { - // Find the pass first. - RPI::PassHierarchyFilter passFilter(passHierarchy); - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (foundPasses.size() == 0) - { - AZ_Warning("ProfilingCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str()); - } - - return foundPasses; - } - void ProfilingCaptureSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { // Update the delayed captures diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h index a9bb8c585f..af1d2f5643 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h @@ -78,8 +78,6 @@ namespace AZ // Recursively collect all the passes from the root pass. AZStd::vector CollectPassesRecursively(const RPI::Pass* root) const; - AZStd::vector FindPasses(AZStd::vector&& passHierarchy) const; - DelayedQueryCaptureHelper m_timestampCapture; DelayedQueryCaptureHelper m_cpuFrameTimeStatisticsCapture; DelayedQueryCaptureHelper m_pipelineStatisticsCapture; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp index 37b1885ee3..a1858a7e9d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp @@ -28,16 +28,17 @@ namespace AZ void ReflectionCopyFrameBufferPass::BuildInternal() { - RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!passes.empty()) - { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); - Data::Instance& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment(); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); + Data::Instance& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment(); - RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); - AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); - } + RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); + AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); + + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); FullscreenTrianglePass::BuildInternal(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp index 394a6fd406..edd7ad1013 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp @@ -150,7 +150,7 @@ namespace AZ auto transientImageDesc = RHI::ImageDescriptor::Create2D(imageBindFlags, mipSize.m_width, mipSize.m_height, RHI::Format::R16G16B16A16_FLOAT); RPI::PassAttachment* transientPassAttachment = aznew RPI::PassAttachment(); - AZStd::string transientAttachmentName = AZStd::string::format("ReflectionScreenSpace_BlurImage%d", mip); + AZStd::string transientAttachmentName = AZStd::string::format("%s.ReflectionScreenSpace_BlurImage%d", GetPathName().GetCStr(), mip); transientPassAttachment->m_name = transientAttachmentName; transientPassAttachment->m_path = transientAttachmentName; transientPassAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp index 1cf227650c..1362191691 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp @@ -33,20 +33,22 @@ namespace AZ return; } - RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!passes.empty()) - { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); - // compute the max mip level based on the available mips in the previous frame image, and capping it - // to stay within a range that has reasonable data - const uint32_t MaxNumRoughnessMips = 8; - uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); - auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); - m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); - } + // compute the max mip level based on the available mips in the previous frame image, and capping it + // to stay within a range that has reasonable data + const uint32_t MaxNumRoughnessMips = 8; + uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; + + auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); + m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); + + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); FullscreenTrianglePass::CompileResources(context); } diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 7c0b3563c7..70ccaa5702 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -313,52 +313,38 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::CachePasses() { - const AZStd::vector validPipelineIds = CacheProjectedShadowmapsPass(); - CacheEsmShadowmapsPass(validPipelineIds); + CacheProjectedShadowmapsPass(); + CacheEsmShadowmapsPass(); m_shadowmapPassNeedsUpdate = true; } - AZStd::vector ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass() + void ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass() { - const AZStd::vector& renderPipelines = GetParentScene()->GetRenderPipelines(); - const auto* passSystem = RPI::PassSystemInterface::Get();; - const AZStd::vector& passes = passSystem->GetPassesForTemplateName(Name("ProjectedShadowmapsTemplate")); - - AZStd::vector validPipelineIds; m_projectedShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - ProjectedShadowmapsPass* shadowPass = static_cast(pass); - for (const RPI::RenderPipelinePtr& pipeline : renderPipelines) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("ProjectedShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - if (pipeline.get() == shadowPass->GetRenderPipeline()) - { - m_projectedShadowmapsPasses.emplace_back(shadowPass); - validPipelineIds.push_back(shadowPass->GetRenderPipeline()->GetId()); - } - } - } - return validPipelineIds; + ProjectedShadowmapsPass* shadowPass = static_cast(pass); + m_projectedShadowmapsPasses.emplace_back(shadowPass); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } - void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds) + void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass() { const Name LightTypeName = Name("projected"); - - const auto* passSystem = RPI::PassSystemInterface::Get(); - const AZStd::vector passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); - + m_esmShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - EsmShadowmapsPass* esmPass = static_cast(pass); - if (esmPass->GetRenderPipeline() && - AZStd::find(validPipelineIds.begin(), validPipelineIds.end(), esmPass->GetRenderPipeline()->GetId()) != validPipelineIds.end() && - esmPass->GetLightTypeName() == LightTypeName) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, LightTypeName](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - m_esmShadowmapsPasses.emplace_back(esmPass); - } - } + EsmShadowmapsPass* esmPass = static_cast(pass); + if (esmPass->GetLightTypeName() == LightTypeName) + { + m_esmShadowmapsPasses.emplace_back(esmPass); + } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void ProjectedShadowFeatureProcessor::UpdateFilterParameters() diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index fafcb25a08..8939f1845d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -97,8 +97,8 @@ namespace AZ::Render // Functions for caching the ProjectedShadowmapsPass and EsmShadowmapsPass. void CachePasses(); - AZStd::vector CacheProjectedShadowmapsPass(); - void CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds); + void CacheProjectedShadowmapsPass(); + void CacheEsmShadowmapsPass(); //! Functions to update the parameter of Gaussian filter used in ESM. void UpdateFilterParameters(); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index e0209702dc..4c379c4239 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -241,12 +242,12 @@ namespace AZ void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) { - InitSkinningAndMorphPass(pipeline->GetRootPass()); + InitSkinningAndMorphPass(pipeline.get()); } void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { - InitSkinningAndMorphPass(renderPipeline->GetRootPass()); + InitSkinningAndMorphPass(renderPipeline); } void SkinnedMeshFeatureProcessor::OnBeginPrepareRender() @@ -289,9 +290,10 @@ namespace AZ return false; } - void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(const RPI::Ptr pipelineRootPass) + void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline) { - RPI::Ptr skinningPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "SkinningPass" }); + RPI::PassFilter skinPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "SkinningPass" }, renderPipeline); + RPI::Ptr skinningPass = RPI::PassSystemInterface::Get()->FindFirstPass(skinPassFilter); if (skinningPass) { SkinnedMeshComputePass* skinnedMeshComputePass = azdynamic_cast(skinningPass.get()); @@ -310,7 +312,8 @@ namespace AZ } } - RPI::Ptr morphTargetPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "MorphTargetPass" }); + RPI::PassFilter morphPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "MorphTargetPass" }, renderPipeline); + RPI::Ptr morphTargetPass = RPI::PassSystemInterface::Get()->FindFirstPass(morphPassFilter); if (morphTargetPass) { MorphTargetComputePass* morphTargetComputePass = azdynamic_cast(morphTargetPass.get()); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h index 2e93acf2cd..5b7ab943e1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h @@ -66,7 +66,7 @@ namespace AZ private: AZ_DISABLE_COPY_MOVE(SkinnedMeshFeatureProcessor); - void InitSkinningAndMorphPass(const RPI::Ptr pipelineRootPass); + void InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline); SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) override; bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index 36994ec03b..6523f0a6d8 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -68,9 +68,6 @@ namespace AZ template Ptr FindChildPass() const; - //! Searches the tree for the first pass that has same pass name (Depth-first search). Return nullptr if none found. - Ptr FindPassByNameRecursive(const Name& passName) const; - //! Gets the list of children. Useful for validating hierarchies AZStd::array_view> GetChildren() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 34eaae4495..e7b9825ecb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -139,6 +139,10 @@ namespace AZ //! Returns the number of output attachment bindings uint32_t GetOutputCount() const; + //! Returns the pass template which was used for create this pass. + //! It may return nullptr if the pass wasn't create from a template + const PassTemplate* GetPassTemplate() const; + //! Enable/disable this pass //! If the pass is disabled, it (and any children if it's a ParentPass) won't be rendered. void SetEnabled(bool enabled); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h index c31f353adb..c42991725e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h @@ -16,95 +16,85 @@ namespace AZ { namespace RPI { - // A base class for a filter which can be used to filter passes + class Scene; + class RenderPipeline; + class PassFilter { public: - //! Whether the input pass matches with the filter - virtual bool Matches(const Pass* pass) const = 0; + static PassFilter CreateWithPassName(Name passName, const Scene* scene); + static PassFilter CreateWithPassName(Name passName, const RenderPipeline* renderPipeline); - //! Return the pass' name if a pass name is used for the filter. - //! Return nullptr if the filter doesn't have pass name used for matching - virtual const Name* GetPassName() const = 0; + //! Create a PassFilter with pass hierarchy information + //! Filter for passes which have a matching name and also with ordered parents. + //! For example, if the filter is initialized with + //! pass name: "ShadowPass1" + //! pass parents names: "MainPipeline", "Shadow" + //! Passes with these names match the filter: + //! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" + //! or "Root.MainPipeline.Shadow.ShadowPass1" + //! or "MainPipeline.Shadow.Group1.ShadowPass1" + //! + //! Passes with these names wont match: + //! "MainPipeline.ShadowPass1" + //! or "Shadow.MainPipeline.ShadowPass1" + static PassFilter CreateWithPassHierarchy(const AZStd::vector& passHierarchy); + static PassFilter CreateWithPassHierarchy(const AZStd::vector& passHierarchy); + static PassFilter CreateWithTemplateName(Name templateName, const Scene* scene); + static PassFilter CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline); + template + static PassFilter CreateWithPassClass(); - //! Return this filter's info as a string - virtual AZStd::string ToString() const = 0; - }; + enum FilterOptions : uint32_t + { + Empty = 0, + PassName = AZ_BIT(0), + PassTemplateName = AZ_BIT(1), + PassClass = AZ_BIT(2), + PassHierarchy = AZ_BIT(3), + OwnerScene = AZ_BIT(4), + OwnerRenderPipeline = AZ_BIT(5) + }; - //! Filter for passes which have a matching name and also with ordered parents. - //! For example, if the filter is initialized with - //! pass name: "ShadowPass1" - //! pass parents names: "MainPipeline", "Shadow" - //! Passes with these names match the filter: - //! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" - //! or "Root.MainPipeline.Shadow.ShadowPass1" - //! or "MainPipeline.Shadow.Group1.ShadowPass1" - //! - //! Passes with these names wont match: - //! "MainPipeline.ShadowPass1" - //! or "Shadow.MainPipeline.ShadowPass1" - class PassHierarchyFilter - : public PassFilter - { - public: - AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter); - AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0); + void SetOwenrScene(const Scene* scene); + void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline); + void SetPassName(Name passName); + void SetTemplateName(Name passTemplateName); + void SetPassClass(TypeId passClassTypeId); - //! Construct filter with only pass name. - PassHierarchyFilter(const Name& passName); + const Name& GetPassName() const; + const Name& GetPassTemplateName() const; - virtual ~PassHierarchyFilter() = default; + uint32_t GetEnabledFilterOptions() const; - //! Construct filter with pass name and its parents' names in the order of the hierarchy - //! This means k-th element is always an ancestor of the (k-1)-th element. - //! And the last element is the pass name. - PassHierarchyFilter(const AZStd::vector& passHierarchy); - PassHierarchyFilter(const AZStd::vector& passHierarchy); + //! Return true if the input pass matches the filter + bool Matches(const Pass* pass) const; - // PassFilter overrides... - bool Matches(const Pass* pass) const override; - const Name* GetPassName() const override; - AZStd::string ToString() const override; + //! Return true if the input pass matches the filter with selected filter options + //! The input filter options should be a subset of options returned by GetEnabledFilterOptions() + //! This function is used to avoid extra checks for passes which was already filtered. + //! Check PassLibrary::ForEachPass() function's implementation for more details + bool Matches(const Pass* pass, uint32_t options) const; private: - PassHierarchyFilter() = delete; + void UpdateFilterOptions(); - AZStd::vector m_parentNames; Name m_passName; + Name m_templateName; + TypeId m_passClassTypeId = TypeId::CreateNull(); + AZStd::vector m_parentNames; + const RenderPipeline* m_ownerRenderPipeline = nullptr; + const Scene* m_ownerScene = nullptr; + uint32_t m_filterOptions = 0; }; - //! Filter for passes based on their class. - template - class PassClassFilter - : public PassFilter - { - public: - AZ_RTTI(PassClassFilter, "{AF6E3AD5-433A-462A-997A-F36D8A551D02}", PassFilter); - AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0); - PassClassFilter() = default; - - // PassFilter overrides... - bool Matches(const Pass* pass) const override; - const Name* GetPassName() const override; - AZStd::string ToString() const override; - }; - - template - bool PassClassFilter::Matches(const Pass* pass) const - { - return pass->RTTI_IsTypeOf(PassClass::RTTI_Type()); - } - - template - const Name* PassClassFilter::GetPassName() const - { - return nullptr; - } - - template - AZStd::string PassClassFilter::ToString() const - { - return AZStd::string::format("PassClassFilter<%s>", PassClass::RTTI_TypeName()); + template + PassFilter PassFilter::CreateWithPassClass() + { + PassFilter filter; + filter.m_passClassTypeId = PassClass::RTTI_Type(); + filter.UpdateFilterOptions(); + return filter; } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h index 0a4b1c4399..66c3c205ab 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h @@ -84,8 +84,8 @@ namespace AZ bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath); bool LoadPassTemplateMappings(Data::Asset mappingAsset); - //! Returns a list of passes found in the pass name mapping using the provided pass filter - AZStd::vector FindPasses(const PassFilter& passFilter) const; + //! Visit each pass which matches the filter + void ForEachPass(const PassFilter& passFilter, AZStd::function passFunction); private: diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h index 30fa27e64b..8390b0f7e2 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h @@ -92,13 +92,13 @@ namespace AZ // PassSystemInterface library related functions... bool HasPassesForTemplateName(const Name& templateName) const override; - const AZStd::vector& GetPassesForTemplateName(const Name& templateName) const override; bool AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) override; const AZStd::shared_ptr GetPassTemplate(const Name& name) const override; void RemovePassFromLibrary(Pass* pass) override; void RegisterPass(Pass* pass) override; void UnregisterPass(Pass* pass) override; - AZStd::vector FindPasses(const PassFilter& passFilter) const override; + void ForEachPass(const PassFilter& filter, AZStd::function passFunction) override; + Pass* FindFirstPass(const PassFilter& filter) override; private: // Returns the root of the pass tree hierarchy diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 0e9386f3bb..7f944df88f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -75,6 +75,13 @@ namespace AZ u32 m_maxDrawItemsRenderedInAPass = 0; }; + + enum PassFilterExecutionFlow : uint8_t + { + StopVisitingPasses, + ContinueVisitingPasses, + }; + class PassSystemInterface { friend class Pass; @@ -186,9 +193,6 @@ namespace AZ //! Returns true if the pass factory contains passes created with the given template name virtual bool HasPassesForTemplateName(const Name& templateName) const = 0; - //! Get the passes created with the given template name. - virtual const AZStd::vector& GetPassesForTemplateName(const Name& templateName) const = 0; - //! Adds a PassTemplate to the library virtual bool AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) = 0; @@ -197,9 +201,16 @@ namespace AZ //! Removes all references to the given pass from the pass library virtual void RemovePassFromLibrary(Pass* pass) = 0; + + //! Visit the matching passes from registered passes with specified filter + //! The return value of the passFunction decides if the search continues or not + //! Note: this function will find all the passes which match the pass filter even they are for render pipelines which are not added to a scene + //! This function is fast if a pass name or a pass template name is specified. + virtual void ForEachPass(const PassFilter& filter, AZStd::function passFunction) = 0; - //! Find matching passes from registered passes with specified filter - virtual AZStd::vector FindPasses(const PassFilter& passFilter) const = 0; + //! Find the first matching pass from registered passes with specified filter + //! Note: this function SHOULD ONLY be used when you are certain you only need to handle the first pass found + virtual Pass* FindFirstPass(const PassFilter& filter) = 0; private: // These functions are only meant to be used by the Pass class diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 36c28877ea..dccf5dbc2e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -149,29 +149,6 @@ namespace AZ return index.IsValid() ? m_children[index.GetIndex()] : Ptr(nullptr); } - Ptr ParentPass::FindPassByNameRecursive(const Name& passName) const - { - for (const Ptr& child : m_children) - { - if (child->GetName() == passName) - { - return child.get(); - } - - ParentPass* asParent = child->AsParent(); - if (asParent) - { - auto pass = asParent->FindPassByNameRecursive(passName); - if (pass) - { - return pass; - } - } - } - - return nullptr; - } - const Pass* ParentPass::FindPass(RHI::DrawListTag drawListTag) const { if (HasDrawListTag() && GetDrawListTag() == drawListTag) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index a8d94e9a91..3c1de28d6a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -238,6 +238,11 @@ namespace AZ return m_attachmentBindings[bindingIndex]; } + const PassTemplate* Pass::GetPassTemplate() const + { + return m_template.get(); + } + void Pass::AddAttachmentBinding(PassAttachmentBinding attachmentBinding) { // Add the index of the binding to the input, output or input/output list based on the slot type diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp index 7bd1abc0a7..d9e458c615 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp @@ -8,101 +8,264 @@ #include #include +#include namespace AZ { namespace RPI { - PassHierarchyFilter::PassHierarchyFilter(const Name& passName) + PassFilter PassFilter::CreateWithPassName(Name passName, const Scene* scene) + { + PassFilter filter; + filter.m_passName = passName; + filter.m_ownerScene = scene; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassName(Name passName, const RenderPipeline* renderPipeline) + { + PassFilter filter; + filter.m_passName = passName; + filter.m_ownerRenderPipeline = renderPipeline; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithTemplateName(Name templateName, const Scene* scene) + { + PassFilter filter; + filter.m_templateName = templateName; + filter.m_ownerScene = scene; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline) + { + PassFilter filter; + filter.m_templateName = templateName; + filter.m_ownerRenderPipeline = renderPipeline; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector& passHierarchy) + { + PassFilter filter; + if (passHierarchy.size() == 0) + { + AZ_Assert(false, "passHierarchy should have at least one element"); + return filter; + } + + filter.m_passName = passHierarchy.back(); + + filter.m_parentNames.resize(passHierarchy.size() - 1); + for (uint32_t index = 0; index < filter.m_parentNames.size(); index++) + { + filter.m_parentNames[index] = passHierarchy[index]; + } + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector& passHierarchy) + { + PassFilter filter; + if (passHierarchy.size() == 0) + { + AZ_Assert(false, "passHierarchy should have at least one element"); + return filter; + } + + filter.m_passName = Name(passHierarchy.back()); + + filter.m_parentNames.resize(passHierarchy.size() - 1); + for (uint32_t index = 0; index < filter.m_parentNames.size(); index++) + { + filter.m_parentNames[index] = Name(passHierarchy[index]); + } + filter.UpdateFilterOptions(); + return filter; + } + + void PassFilter::SetOwenrScene(const Scene* scene) + { + m_ownerScene = scene; + UpdateFilterOptions(); + } + + void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline) + { + m_ownerRenderPipeline = renderPipeline; + UpdateFilterOptions(); + } + + void PassFilter::SetPassName(Name passName) { m_passName = passName; + UpdateFilterOptions(); } - PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector& passHierarchy) + void PassFilter::SetTemplateName(Name passTemplateName) { - if (passHierarchy.size() == 0) - { - AZ_Assert(false, "passHierarchy should have at least one element"); - return; - } - - m_passName = Name(passHierarchy.back()); - - m_parentNames.resize(passHierarchy.size() - 1); - for (uint32_t index = 0; index < m_parentNames.size(); index++) - { - m_parentNames[index] = Name(passHierarchy[index]); - } + m_templateName = passTemplateName; + UpdateFilterOptions(); } - PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector& passHierarchy) + void PassFilter::SetPassClass(TypeId passClassTypeId) { - if (passHierarchy.size() == 0) - { - AZ_Assert(false, "passHierarchy should have at least one element"); - return; - } - - m_passName = passHierarchy.back(); - - m_parentNames.resize(passHierarchy.size() - 1); - for (uint32_t index = 0; index < m_parentNames.size(); index++) - { - m_parentNames[index] = passHierarchy[index]; - } + m_passClassTypeId = passClassTypeId; + UpdateFilterOptions(); } - bool PassHierarchyFilter::Matches(const Pass* pass) const + const Name& PassFilter::GetPassName() const { - if (pass->GetName() != m_passName) + return m_passName; + } + + const Name& PassFilter::GetPassTemplateName() const + { + return m_templateName; + } + + uint32_t PassFilter::GetEnabledFilterOptions() const + { + return m_filterOptions; + } + + bool PassFilter::Matches(const Pass* pass) const + { + return Matches(pass, m_filterOptions); + } + + bool PassFilter::Matches(const Pass* pass, uint32_t options) const + { + AZ_Assert( (options&m_filterOptions) == options, "options should be a subset of m_filterOptions"); + + // return false if the pass doesn't have a pass template or the template's name is not matching + if (options & FilterOptions::PassTemplateName && (!pass->GetPassTemplate() || pass->GetPassTemplate()->m_name != m_templateName)) { return false; } - ParentPass* parent = pass->GetParent(); - - // search from the back of the array with the most close parent - for (int32_t index = static_cast(m_parentNames.size() - 1); index >= 0; index--) + if ((options & FilterOptions::PassName) && pass->GetName() != m_passName) { - const Name& parentName = m_parentNames[index]; - while (parent) - { - if (parent->GetName() == parentName) - { - break; - } - parent = parent->GetParent(); - } + return false; + } - // if parent is nullptr the it didn't find a parent has matching current parentName - if (!parent) + if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId) + { + return false; + } + + if ((options & FilterOptions::OwnerRenderPipeline) && m_ownerRenderPipeline != pass->GetRenderPipeline()) + { + return false; + } + + // If the owner render pipeline was checked, the owner scene check can be skipped + if (options & FilterOptions::OwnerScene) + { + if (pass->GetRenderPipeline()) { + // return false if the owner scene doesn't match + if (m_ownerScene != pass->GetRenderPipeline()->GetScene()) + { + return false; + } + } + else + { + // return false if the pass doesn't have an owner scene return false; } + } - // move to next parent - parent = parent->GetParent(); + if ((options & FilterOptions::PassHierarchy)) + { + // Filter for passes which have a matching name and also with ordered parents. + // For example, if the filter is initialized with + // pass name: "ShadowPass1" + // pass parents names: "MainPipeline", "Shadow" + // Passes with these names match the filter: + // "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" + // or "Root.MainPipeline.Shadow.ShadowPass1" + // or "MainPipeline.Shadow.Group1.ShadowPass1" + // + // Passes with these names wont match: + // "MainPipeline.ShadowPass1" + // or "Shadow.MainPipeline.ShadowPass1" + + ParentPass* parent = pass->GetParent(); + + // search from the back of the array with the most close parent + for (int32_t index = static_cast(m_parentNames.size() - 1); index >= 0; index--) + { + const Name& parentName = m_parentNames[index]; + while (parent) + { + if (parent->GetName() == parentName) + { + break; + } + parent = parent->GetParent(); + } + + // if parent is nullptr the it didn't find a parent has matching current parentName + if (!parent) + { + return false; + } + + // move to next parent + parent = parent->GetParent(); + } } return true; } - const Name* PassHierarchyFilter::GetPassName() const + void PassFilter::UpdateFilterOptions() { - return &m_passName; - } - - AZStd::string PassHierarchyFilter::ToString() const - { - AZStd::string result = "PassHierarchyFilter"; - for (uint32_t index = 0; index < m_parentNames.size(); index++) + m_filterOptions = FilterOptions::Empty; + if (!m_passName.IsEmpty()) { - result += AZStd::string::format(" [%s]", m_parentNames[index].GetCStr()); + m_filterOptions |= FilterOptions::PassName; + } + if (!m_templateName.IsEmpty()) + { + m_filterOptions |= FilterOptions::PassTemplateName; + } + if (m_parentNames.size() > 0) + { + m_filterOptions |= FilterOptions::PassHierarchy; + } + if (m_ownerRenderPipeline) + { + m_filterOptions |= FilterOptions::OwnerRenderPipeline; + } + if (m_ownerScene) + { + // If the OwnerRenderPipeline exists, we shouldn't need to filter owner scene + // Validate the owner render pipeline belongs to the owner scene + if (m_filterOptions & FilterOptions::OwnerRenderPipeline) + { + if (m_ownerRenderPipeline->GetScene() != m_ownerScene) + { + AZ_Warning("RPI", false, "The owner scene filter doesn't match owner render pipeline. It will be skipped."); + } + } + else + { + m_filterOptions |= FilterOptions::OwnerScene; + } + } + if (!m_passClassTypeId.IsNull()) + { + m_filterOptions |= FilterOptions::PassClass; } - - result += AZStd::string::format(" [%s]", m_passName.GetCStr()); - return result; } - } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp index c43edafd6b..6a6f5f3ff9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp @@ -85,47 +85,80 @@ namespace AZ return (GetPassesForTemplate(templateName).size() > 0); } - AZStd::vector PassLibrary::FindPasses(const PassFilter& passFilter) const + void PassLibrary::ForEachPass(const PassFilter& passFilter, AZStd::function passFunction) { - const Name* passName = passFilter.GetPassName(); + uint32_t filterOptions = passFilter.GetEnabledFilterOptions(); - AZStd::vector result; - - if (passName) + // A lambda function which visits each pass in a pass list, if the pass matches the pass filter, then call the pass function + auto visitList = [passFilter, passFunction](const AZStd::vector& passList, uint32_t options) -> PassFilterExecutionFlow { - // If the pass' name is known, find passes with matching names first - const auto constItr = m_passNameMapping.find(*passName); - if (constItr == m_passNameMapping.end()) + if (passList.size() == 0) { - return result; + return PassFilterExecutionFlow::ContinueVisitingPasses; } - - const AZStd::vector& passes = constItr->second; - - for (Pass* pass : passes) + // if there is not other filter options enabled, skip the filter and call pass functions directly + if (options == PassFilter::FilterOptions::Empty) { - if (passFilter.Matches(pass)) + for (Pass* pass : passList) { - result.push_back(pass); - } - } - } - else - { - // If the filter doesn't know matching pass' name, need to go through all registered passes - for (auto& namePasses : m_passNameMapping) - { - for (Pass* pass : namePasses.second) - { - if (passFilter.Matches(pass)) + // If user want to skip processing, return directly. + if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses) { - result.push_back(pass); + return PassFilterExecutionFlow::StopVisitingPasses; + } + } + return PassFilterExecutionFlow::ContinueVisitingPasses; + } + + // Check with the pass filter and call pass functions + for (Pass* pass : passList) + { + if (passFilter.Matches(pass, options)) + { + if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses) + { + return PassFilterExecutionFlow::StopVisitingPasses; } } } + return PassFilterExecutionFlow::ContinueVisitingPasses; + }; + + // Check pass template name first + if (filterOptions & PassFilter::FilterOptions::PassTemplateName) + { + auto entry = GetEntry(passFilter.GetPassTemplateName()); + if (!entry) + { + return; + } + + filterOptions &= ~(PassFilter::FilterOptions::PassTemplateName); + visitList(entry->m_passes, filterOptions); + return; + } + else if (filterOptions & PassFilter::FilterOptions::PassName) + { + const auto constItr = m_passNameMapping.find(passFilter.GetPassName()); + if (constItr == m_passNameMapping.end()) + { + return; + } + + filterOptions &= ~(PassFilter::FilterOptions::PassName); + visitList(constItr->second, filterOptions); + return; } - return result; + // check againest every passes. This might be slow + AZ_PROFILE_SCOPE(RPI, "PassLibrary::ForEachPass"); + for (auto& namePasses : m_passNameMapping) + { + if (visitList(namePasses.second, filterOptions) == PassFilterExecutionFlow::StopVisitingPasses) + { + return; + } + } } // Add Functions... @@ -419,3 +452,4 @@ namespace AZ } // namespace RPI } // namespace AZ + 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 f4f51f97b7..7f2948c13a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -456,11 +456,6 @@ namespace AZ return m_passLibrary.HasPassesForTemplate(templateName); } - const AZStd::vector& PassSystem::GetPassesForTemplateName(const Name& templateName) const - { - return m_passLibrary.GetPassesForTemplate(templateName); - } - bool PassSystem::AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) { return m_passLibrary.AddPassTemplate(name, passTemplate); @@ -487,10 +482,21 @@ namespace AZ RemovePassFromLibrary(pass); --m_passCounter; } - - AZStd::vector PassSystem::FindPasses(const PassFilter& passFilter) const + + void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function passFunction) { - return m_passLibrary.FindPasses(passFilter); + return m_passLibrary.ForEachPass(filter, passFunction); + } + + Pass* PassSystem::FindFirstPass(const PassFilter& filter) + { + Pass* foundPass = nullptr; + m_passLibrary.ForEachPass(filter, [&foundPass](RPI::Pass* pass) ->PassFilterExecutionFlow + { + foundPass = pass; + return PassFilterExecutionFlow::StopVisitingPasses; + }); + return foundPass; } SwapChainPass* PassSystem::FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const diff --git a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp index 420ab1798a..690f212ec7 100644 --- a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp @@ -19,6 +19,8 @@ #include #include +#include + #include #include @@ -573,7 +575,7 @@ namespace UnitTest EXPECT_TRUE(pass != nullptr); } - TEST_F(PassTests, PassHierarchyFilter) + TEST_F(PassTests, PassFilter_PassHierarchy) { m_data->AddPassTemplatesToLibrary(); @@ -587,62 +589,55 @@ namespace UnitTest parent2->AsParent()->AddChild(parent1); parent1->AsParent()->AddChild(pass); - { - // Filter with only pass name - PassHierarchyFilter filter(Name("pass1")); - EXPECT_TRUE(filter.Matches(pass.get())); - } - { // Filter with pass hierarchy which has only one element - PassHierarchyFilter filter({ Name("pass1") }); + PassFilter filter = PassFilter::CreateWithPassHierarchy({Name("pass1")}); EXPECT_TRUE(filter.Matches(pass.get())); } { - // Filter with empty pass hierarchy. Result one assert + // Filter with empty pass hierarchy, triggers one assert AZ_TEST_START_TRACE_SUPPRESSION; - PassHierarchyFilter filter(AZStd::vector{}); + PassFilter filter = PassFilter::CreateWithPassHierarchy(AZStd::vector{}); AZ_TEST_STOP_TRACE_SUPPRESSION(1); - EXPECT_FALSE(filter.Matches(pass.get())); } { // Filters with partial hierarchy by using string vector AZStd::vector passHierarchy1 = { "parent1", "pass1" }; - PassHierarchyFilter filter1(passHierarchy1); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1); EXPECT_TRUE(filter1.Matches(pass.get())); AZStd::vector passHierarchy2 = { "parent2", "pass1" }; - PassHierarchyFilter filter2(passHierarchy2); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2); EXPECT_TRUE(filter2.Matches(pass.get())); AZStd::vector passHierarchy3 = { "parent3", "parent2", "pass1" }; - PassHierarchyFilter filter3(passHierarchy3); + PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3); EXPECT_TRUE(filter3.Matches(pass.get())); } { // Filters with partial hierarchy by using Name vector AZStd::vector passHierarchy1 = { Name("parent1"), Name("pass1") }; - PassHierarchyFilter filter1(passHierarchy1); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1); EXPECT_TRUE(filter1.Matches(pass.get())); AZStd::vector passHierarchy2 = { Name("parent2"), Name("pass1")}; - PassHierarchyFilter filter2(passHierarchy2); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2); EXPECT_TRUE(filter2.Matches(pass.get())); AZStd::vector passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") }; - PassHierarchyFilter filter3(passHierarchy3); + PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3); EXPECT_TRUE(filter3.Matches(pass.get())); } { // Find non-leaf pass - PassHierarchyFilter filter1(AZStd::vector{"parent3", "parent1"}); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"parent3", "parent1"}); EXPECT_TRUE(filter1.Matches(parent1.get())); - - PassHierarchyFilter filter2(Name("parent1")); + + PassFilter filter2 = PassFilter::CreateWithPassHierarchy({ Name("parent1") }); EXPECT_TRUE(filter2.Matches(parent1.get())); EXPECT_FALSE(filter2.Matches(pass.get())); } @@ -650,11 +645,131 @@ namespace UnitTest { // Failed to find pass // Mis-matching hierarchy - PassHierarchyFilter filter1(AZStd::vector{"Parent1", "Parent3", "pass1"}); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"Parent1", "Parent3", "pass1"}); EXPECT_FALSE(filter1.Matches(pass.get())); // Mis-matching name - PassHierarchyFilter filter2(AZStd::vector{"Parent1", "pass1"}); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"Parent1", "pass1"}); EXPECT_FALSE(filter2.Matches(parent1.get())); } } + + TEST_F(PassTests, PassFilter_Empty_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + Ptr parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2")); + Ptr parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3")); + + parent3->AsParent()->AddChild(parent2); + parent2->AsParent()->AddChild(parent1); + parent1->AsParent()->AddChild(pass); + + PassFilter filter; + + // Any pass can match an empty filter + EXPECT_TRUE(filter.Matches(pass.get())); + EXPECT_TRUE(filter.Matches(parent1.get())); + EXPECT_TRUE(filter.Matches(parent2.get())); + EXPECT_TRUE(filter.Matches(parent3.get())); + } + + TEST_F(PassTests, PassFilter_PassClass_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr depthPass = m_passSystem->CreatePassFromTemplate(Name("DepthPrePass"), Name("depthPass")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + + parent1->AsParent()->AddChild(pass); + parent1->AsParent()->AddChild(depthPass); + + PassFilter filter1 = PassFilter::CreateWithPassClass(); + + EXPECT_TRUE(filter1.Matches(pass.get())); + EXPECT_FALSE(filter1.Matches(parent1.get())); + + PassFilter filter2 = PassFilter::CreateWithPassClass(); + EXPECT_FALSE(filter2.Matches(pass.get())); + EXPECT_TRUE(filter2.Matches(parent1.get())); + } + + TEST_F(PassTests, PassFilter_PassTemplate_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr childPass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + + PassFilter filter1 = PassFilter::CreateWithTemplateName(Name("Pass"), (Scene*) nullptr); + // childPass doesn't have a template + EXPECT_FALSE(filter1.Matches(childPass.get())); + + PassFilter filter2 = PassFilter::CreateWithTemplateName(Name("ParentPass"), (Scene*) nullptr); + EXPECT_TRUE(filter2.Matches(parent1.get())); + } + + TEST_F(PassTests, ForEachPass_PassTemplateFilter_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + Ptr parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2")); + Ptr parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3")); + + parent3->AsParent()->AddChild(parent2); + parent2->AsParent()->AddChild(parent1); + parent1->AsParent()->AddChild(pass); + + // Create render pipeline + const RPI::PipelineViewTag viewTag{ "viewTag1" }; + RPI::RenderPipelineDescriptor desc; + desc.m_mainViewTagName = viewTag.GetStringView(); + desc.m_name = "TestPipeline"; + RPI::RenderPipelinePtr pipeline = RPI::RenderPipeline::CreateRenderPipeline(desc); + Ptr parent4 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent4")); + pipeline->GetRootPass()->AddChild(parent4); + + Name templateName = Name("ParentPass"); + PassFilter filter1 = PassFilter::CreateWithTemplateName(templateName, (RenderPipeline*)nullptr); + + int count = 0; + m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow + { + EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName); + count++; + return PassFilterExecutionFlow::ContinueVisitingPasses; + }); + + // three from CreatePassFromTemplate() calls and one from Render Pipeline. + EXPECT_TRUE(count == 4); + + count = 0; + m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow + { + EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName); + count++; + return PassFilterExecutionFlow::StopVisitingPasses; + }); + EXPECT_TRUE(count == 1); + + PassFilter filter2 = PassFilter::CreateWithTemplateName(templateName, pipeline.get()); + count = 0; + m_passSystem->ForEachPass(filter2, [&count]([[maybe_unused]] RPI::Pass* pass) -> PassFilterExecutionFlow + { + count++; + return PassFilterExecutionFlow::ContinueVisitingPasses; + }); + + // only the ParentPass in the render pipeline was found + EXPECT_TRUE(count == 1); + + } } diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp index a0be18f0e2..161160e16f 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -142,12 +143,13 @@ namespace AZ EnablePasses(true); } - void HairFeatureProcessor::EnablePasses([[maybe_unused]] bool enable) + void HairFeatureProcessor::EnablePasses(bool enable) { - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName); - if (desiredPass) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); + if (pass) { - desiredPass->SetEnabled(enable); + pass->SetEnabled(enable); } } @@ -309,10 +311,17 @@ namespace AZ m_forceClearRenderData = true; } + bool HairFeatureProcessor::HasHairParentPass() + { + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); + return pass; + } + void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline.get()->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -323,10 +332,10 @@ namespace AZ m_forceRebuildRenderData = true; } - void HairFeatureProcessor::OnRenderPipelineRemoved(RPI::RenderPipeline* renderPipeline) + void HairFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -338,7 +347,7 @@ namespace AZ void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -457,7 +466,8 @@ namespace AZ { m_computePasses[passName] = nullptr; - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(passName); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(passName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_computePasses[passName] = static_cast(desiredPass.get()); @@ -478,8 +488,9 @@ namespace AZ bool HairFeatureProcessor::InitPPLLFillPass() { m_hairPPLLRasterPass = nullptr; // reset it to null, just in case it fails to load the assets properly - - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLRasterPassName); + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLRasterPassName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_hairPPLLRasterPass = static_cast(desiredPass.get()); @@ -497,7 +508,8 @@ namespace AZ { m_hairPPLLResolvePass = nullptr; // reset it to null, just in case it fails to load the assets properly - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLResolvePassName); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLResolvePassName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_hairPPLLResolvePass = static_cast(desiredPass.get()); @@ -518,8 +530,8 @@ namespace AZ m_hairShortCutGeometryDepthAlphaPass = nullptr; m_hairShortCutGeometryShadingPass = nullptr; - m_hairShortCutGeometryDepthAlphaPass = static_cast( - m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryDepthAlphaPassName).get()); + RPI::PassFilter depthAlphaPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryDepthAlphaPassName, m_renderPipeline); + m_hairShortCutGeometryDepthAlphaPass = static_cast(RPI::PassSystemInterface::Get()->FindFirstPass(depthAlphaPassFilter)); if (m_hairShortCutGeometryDepthAlphaPass) { m_hairShortCutGeometryDepthAlphaPass->SetFeatureProcessor(this); @@ -530,8 +542,8 @@ namespace AZ return false; } - m_hairShortCutGeometryShadingPass = static_cast( - m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryShadingPassName).get()); + RPI::PassFilter shaderingPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryShadingPassName, m_renderPipeline); + m_hairShortCutGeometryShadingPass = static_cast(RPI::PassSystemInterface::Get()->FindFirstPass(shaderingPassFilter)); if (m_hairShortCutGeometryShadingPass) { m_hairShortCutGeometryShadingPass->SetFeatureProcessor(this); diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h index 46660a6623..f810967824 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h @@ -165,6 +165,8 @@ namespace AZ void EnablePasses(bool enable); + bool HasHairParentPass(); + //! The following will serve to register the FP in the Thumbnail system AZStd::vector m_hairFeatureProcessorRegistryName; From 0f60d37fec8a8378fe1ca698706d099e1ab2fe2c Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 25 Oct 2021 13:32:32 -0700 Subject: [PATCH 07/33] Fixed a bug where material version updates didn't support moving a property from one group to another. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialSourceData.cpp | 15 ++-- .../Material/MaterialTypeSourceData.cpp | 28 +++---- .../Material/MaterialSourceDataTests.cpp | 73 +++++++++++++++++++ .../Material/MaterialTypeSourceDataTests.cpp | 13 +++- 4 files changed, 103 insertions(+), 26 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 5aed6b2993..1467b017d5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -93,31 +93,28 @@ namespace AZ // Note that the only kind of property update currently supported is rename... + PropertyGroupMap newPropertyGroups; for (auto& groupPair : m_properties) { PropertyMap& propertyMap = groupPair.second; - PropertyMap newPropertyMap; - for (auto& propertyPair : propertyMap) { MaterialPropertyId propertyId{groupPair.first, propertyPair.first}; + if (materialTypeSourceData.ApplyPropertyRenames(propertyId, m_materialTypeVersion)) { - newPropertyMap[propertyId.GetPropertyName().GetStringView()] = propertyPair.second; changesWereApplied = true; } - else - { - newPropertyMap[propertyPair.first] = propertyPair.second; - } + + newPropertyGroups[propertyId.GetGroupName().GetStringView()][propertyId.GetPropertyName().GetStringView()] = propertyPair.second; } - - propertyMap = newPropertyMap; } if (changesWereApplied) { + m_properties = AZStd::move(newPropertyGroups); + AZ_Warning("MaterialSourceData", false, "This material is based on version '%u' of '%s', but the material type is now at version '%u'. " "Automatic updates are available. Consider updating the .material source file.", diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 74250647c3..08f57c7cd3 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -164,16 +164,14 @@ namespace AZ const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view groupName, AZStd::string_view propertyName, uint32_t materialTypeVersion) const { auto groupIter = m_propertyLayout.m_properties.find(groupName); - if (groupIter == m_propertyLayout.m_properties.end()) + if (groupIter != m_propertyLayout.m_properties.end()) { - return nullptr; - } - - for (const PropertyDefinition& property : groupIter->second) - { - if (property.m_name == propertyName) + for (const PropertyDefinition& property : groupIter->second) { - return &property; + if (property.m_name == propertyName) + { + return &property; + } } } @@ -185,16 +183,14 @@ namespace AZ // Do the search again with the new names groupIter = m_propertyLayout.m_properties.find(propertyId.GetGroupName().GetStringView()); - if (groupIter == m_propertyLayout.m_properties.end()) + if (groupIter != m_propertyLayout.m_properties.end()) { - return nullptr; - } - - for (const PropertyDefinition& property : groupIter->second) - { - if (property.m_name == propertyId.GetPropertyName().GetStringView()) + for (const PropertyDefinition& property : groupIter->second) { - return &property; + if (property.m_name == propertyId.GetPropertyName().GetStringView()) + { + return &property; + } } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index acce52ae8e..fa8eed35de 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -105,6 +105,13 @@ namespace UnitTest {"op": "rename", "from": "general.testColorNameB", "to": "general.testColorNameC"} ] }, + { + "toVersion": 6, + "actions": [ + {"op": "rename", "from": "oldGroup.MyFloat", "to": "general.MyFloat"}, + {"op": "rename", "from": "oldGroup.MyIntOldName", "to": "general.MyInt"} + ] + }, { "toVersion": 10, "actions": [ @@ -751,6 +758,72 @@ namespace UnitTest material.ApplyVersionUpdates(); } + TEST_F(MaterialSourceDataTests, Load_MaterialTypeVersionUpdate_MovePropertiesToAnotherGroup) + { + const AZStd::string inputJson = R"( + { + "materialType": "@exefolder@/Temp/test.materialtype", + "materialTypeVersion": 3, + "properties": { + "oldGroup": { + "MyFloat": 1.2, + "MyIntOldName": 5 + } + } + } + )"; + + MaterialSourceData material; + JsonTestResult loadResult = LoadTestDataFromJson(material, inputJson); + + EXPECT_EQ(AZ::JsonSerializationResult::Tasks::ReadField, loadResult.m_jsonResultCode.GetTask()); + EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); + + // Initially, the loaded material data will match the .material file exactly. This gives us the accurate representation of + // what's actually saved on disk. + + EXPECT_NE(material.m_properties["oldGroup"].find("MyFloat"), material.m_properties["oldGroup"].end()); + EXPECT_NE(material.m_properties["oldGroup"].find("MyIntOldName"), material.m_properties["oldGroup"].end()); + EXPECT_EQ(material.m_properties["general"].find("MyFloat"), material.m_properties["general"].end()); + EXPECT_EQ(material.m_properties["general"].find("MyInt"), material.m_properties["general"].end()); + + float myFloat = material.m_properties["oldGroup"]["MyFloat"].m_value.GetValue(); + EXPECT_EQ(myFloat, 1.2f); + + int32_t myInt = material.m_properties["oldGroup"]["MyIntOldName"].m_value.GetValue(); + EXPECT_EQ(myInt, 5); + + EXPECT_EQ(3, material.m_materialTypeVersion); + + // Then we force the material data to update to the latest material type version specification + ErrorMessageFinder warningFinder; // Note this finds errors and warnings, and we're looking for a warning. + warningFinder.AddExpectedErrorMessage("Automatic updates are available. Consider updating the .material source file"); + warningFinder.AddExpectedErrorMessage("This material is based on version '3'"); + warningFinder.AddExpectedErrorMessage("material type is now at version '10'"); + material.ApplyVersionUpdates(); + warningFinder.CheckExpectedErrorsFound(); + + // Now the material data should match the latest material type. + // Look for the property under the latest name in the material type, not the name used in the .material file. + + EXPECT_EQ(material.m_properties["oldGroup"].find("MyFloat"), material.m_properties["oldGroup"].end()); + EXPECT_EQ(material.m_properties["oldGroup"].find("MyIntOldName"), material.m_properties["oldGroup"].end()); + EXPECT_NE(material.m_properties["general"].find("MyFloat"), material.m_properties["general"].end()); + EXPECT_NE(material.m_properties["general"].find("MyInt"), material.m_properties["general"].end()); + + myFloat = material.m_properties["general"]["MyFloat"].m_value.GetValue(); + EXPECT_EQ(myFloat, 1.2f); + + myInt = material.m_properties["general"]["MyInt"].m_value.GetValue(); + EXPECT_EQ(myInt, 5); + + EXPECT_EQ(10, material.m_materialTypeVersion); + + // Calling ApplyVersionUpdates() again should not report the warning again, since the material has already been updated. + warningFinder.Reset(); + material.ApplyVersionUpdates(); + } + TEST_F(MaterialSourceDataTests, Load_MaterialTypeVersionPartialUpdate) { // This case is similar to Load_MaterialTypeVersionUpdate but we start at a later diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index b811e630d0..2fe7b1dbe5 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -1346,7 +1346,8 @@ namespace UnitTest { "toVersion": 7, "actions": [ - { "op": "rename", "from": "general.bazA", "to": "otherGroup.bazB" } + { "op": "rename", "from": "general.bazA", "to": "otherGroup.bazB" }, + { "op": "rename", "from": "onlyOneProperty.bopA", "to": "otherGroup.bopB" } // This tests a group 'onlyOneProperty' that no longer exists in the material type ] } ], @@ -1370,6 +1371,10 @@ namespace UnitTest { "name": "bazB", "type": "Float" + }, + { + "name": "bopB", + "type": "Float" } ] } @@ -1386,13 +1391,16 @@ namespace UnitTest const MaterialTypeSourceData::PropertyDefinition* foo = materialType.FindProperty("general", "fooC"); const MaterialTypeSourceData::PropertyDefinition* bar = materialType.FindProperty("general", "barC"); const MaterialTypeSourceData::PropertyDefinition* baz = materialType.FindProperty("otherGroup", "bazB"); + const MaterialTypeSourceData::PropertyDefinition* bop = materialType.FindProperty("otherGroup", "bopB"); EXPECT_TRUE(foo); EXPECT_TRUE(bar); EXPECT_TRUE(baz); + EXPECT_TRUE(bop); EXPECT_EQ(foo->m_name, "fooC"); EXPECT_EQ(bar->m_name, "barC"); EXPECT_EQ(baz->m_name, "bazB"); + EXPECT_EQ(bop->m_name, "bopB"); // Now try doing the property lookup using old versions of the name and make sure the same property can be found @@ -1401,12 +1409,15 @@ namespace UnitTest EXPECT_EQ(bar, materialType.FindProperty("general", "barA")); EXPECT_EQ(bar, materialType.FindProperty("general", "barB")); EXPECT_EQ(baz, materialType.FindProperty("general", "bazA")); + EXPECT_EQ(bop, materialType.FindProperty("onlyOneProperty", "bopA")); EXPECT_EQ(nullptr, materialType.FindProperty("general", "fooX")); EXPECT_EQ(nullptr, materialType.FindProperty("general", "barX")); EXPECT_EQ(nullptr, materialType.FindProperty("general", "bazX")); EXPECT_EQ(nullptr, materialType.FindProperty("general", "bazB")); EXPECT_EQ(nullptr, materialType.FindProperty("otherGroup", "bazA")); + EXPECT_EQ(nullptr, materialType.FindProperty("onlyOneProperty", "bopB")); + EXPECT_EQ(nullptr, materialType.FindProperty("otherGroup", "bopA")); } TEST_F(MaterialTypeSourceDataTests, FindPropertyUsingOldName_Error_UnsupportedVersionUpdate) From 59da09c68b6a2476d72e839bf70a85a745b5b12c Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 25 Oct 2021 13:35:00 -0700 Subject: [PATCH 08/33] Now that we have material version auto update support, I remove the old opacity.doubleSided property and added a rename versionUpdate step to rename it to general.doubleSided. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Materials/Types/EnhancedPBR.materialtype | 16 +++++++++------- .../Materials/Types/StandardPBR.materialtype | 16 +++++++++------- .../StandardPBR_HandleOpacityDoubleSided.lua | 6 ++---- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index 384ad75260..d36213694b 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -1,6 +1,14 @@ { "description": "Material Type with properties used to define Enhanced PBR, a metallic-roughness Physically-Based Rendering (PBR) material shading model, with advanced features like subsurface scattering, transmission, and anisotropy.", - "version": 3, + "version": 4, + "versionUpdates": [ + { + "toVersion": 4, + "actions": [ + {"op": "rename", "from": "opacity.doubleSided", "to": "general.doubleSided"} + ] + } + ], "propertyLayout": { "groups": [ { @@ -715,12 +723,6 @@ "name": "m_opacityFactor" } }, - { - "name": "doubleSided", - "displayName": "Double-sided", - "description": "Whether to render back-faces or just front-faces.", - "type": "Bool" - }, { "name": "alphaAffectsSpecular", "displayName": "Alpha affects specular", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index a64e97516d..e0b1949058 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -1,6 +1,14 @@ { "description": "Material Type with properties used to define Standard PBR, a metallic-roughness Physically-Based Rendering (PBR) material shading model.", - "version": 3, + "version": 4, + "versionUpdates": [ + { + "toVersion": 4, + "actions": [ + {"op": "rename", "from": "opacity.doubleSided", "to": "general.doubleSided"} + ] + } + ], "propertyLayout": { "groups": [ { @@ -656,12 +664,6 @@ "name": "m_opacityFactor" } }, - { - "name": "doubleSided", - "displayName": "Double-sided", - "description": "Whether to render back-faces or just front-faces.", - "type": "Bool" - }, { "name": "alphaAffectsSpecular", "displayName": "Alpha affects specular", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua index 8b3bd2b91b..9584698532 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua @@ -10,7 +10,7 @@ ---------------------------------------------------------------------------------------------------- function GetMaterialPropertyDependencies() - return {"general.doubleSided", "opacity.doubleSided", "opacity.mode"} + return {"general.doubleSided"} end ForwardPassIndex = 0 @@ -18,11 +18,9 @@ ForwardPassEdsIndex = 1 function Process(context) local doubleSided = context:GetMaterialPropertyValue_bool("general.doubleSided") - local opacityDoubleSided = context:GetMaterialPropertyValue_bool("opacity.doubleSided") - local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") local lastShader = context:GetShaderCount() - 1; - if(doubleSided or (opacityDoubleSided and opacityMode ~= 0)) then + if(doubleSided) then for i=0,lastShader do context:GetShader(i):GetRenderStatesOverride():SetCullMode(CullMode_None) end From 3b4b8c354903f6c0fb9b579b13ae5d336c761382 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 25 Oct 2021 15:12:34 -0700 Subject: [PATCH 09/33] Move the initialization of m_editorEntityUiInterface higher so that it's initialized when the interface is set up. (#4972) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../UI/Outliner/EntityOutlinerWidget.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 3e97f967fc..d6e9cac754 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -153,6 +153,9 @@ namespace AzToolsFramework { initEntityOutlinerWidgetResources(); + m_editorEntityUiInterface = AZ::Interface::Get(); + AZ_Assert(m_editorEntityUiInterface != nullptr, "EntityOutlinerWidget requires a EditorEntityUiInterface instance on Initialize."); + m_gui = new Ui::EntityOutlinerWidgetUI(); m_gui->setupUi(this); @@ -282,12 +285,6 @@ namespace AzToolsFramework m_listModel->Initialize(); - m_editorEntityUiInterface = AZ::Interface::Get(); - - AZ_Assert( - m_editorEntityUiInterface != nullptr, - "EntityOutlinerWidget requires a EditorEntityUiInterface instance on Initialize."); - EditorPickModeNotificationBus::Handler::BusConnect(GetEntityContextId()); EntityHighlightMessages::Bus::Handler::BusConnect(); EntityOutlinerModelNotificationBus::Handler::BusConnect(); From bec24a85bf4ca837fb7af22182856eae6409b3bd Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Mon, 25 Oct 2021 15:59:30 -0700 Subject: [PATCH 10/33] Fix old references to gem_list Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/repo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index 9c26658a30..32c2cba428 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -115,14 +115,14 @@ def get_gem_json_paths_from_cached_repo(repo_uri: str) -> set: file_name = pathlib.Path(cache_filename).resolve() if not file_name.is_file(): logger.error(f'Could not find cached repo json file for {repo_uri}') - return gem_list + return gem_set with file_name.open('r') as f: try: repo_data = json.load(f) except json.JSONDecodeError as e: logger.error(f'{file_name} failed to load: {str(e)}') - return gem_list + return gem_set # Get list of gems, then add all json paths to the list if they exist in the cache repo_gems = [] From 4e6f1981b92ff2ea8801915b528590503dbe1429 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Mon, 25 Oct 2021 15:59:31 -0700 Subject: [PATCH 11/33] Hold arrow keys to move selected element in UI editor (#4968) * Hold arrow keys to move selected element in UI editor Signed-off-by: chiyteng * Fix nits Signed-off-by: chiyteng * Hold arrow keys to move selected element in UI editor Signed-off-by: chiyteng * undo enum changes Signed-off-by: chiyteng * remove extra spaces Signed-off-by: chiyteng * fix comments Signed-off-by: chiyteng * refactor key event code Signed-off-by: chiyteng --- .../Code/Editor/ViewportInteraction.cpp | 22 ++- Gems/LyShine/Code/Editor/ViewportWidget.cpp | 159 ++++-------------- Gems/LyShine/Code/Editor/ViewportWidget.h | 7 +- 3 files changed, 55 insertions(+), 133 deletions(-) diff --git a/Gems/LyShine/Code/Editor/ViewportInteraction.cpp b/Gems/LyShine/Code/Editor/ViewportInteraction.cpp index e6bdb4d8d5..a39a7b9cac 100644 --- a/Gems/LyShine/Code/Editor/ViewportInteraction.cpp +++ b/Gems/LyShine/Code/Editor/ViewportInteraction.cpp @@ -739,14 +739,32 @@ void ViewportInteraction::MouseWheelEvent(QWheelEvent* ev) bool ViewportInteraction::KeyPressEvent(QKeyEvent* ev) { - if (ev->key() == Qt::Key_Space) + switch (ev->key()) { + case Qt::Key_Space: if (!ev->isAutoRepeat()) { ActivateSpaceBar(); } - return true; + case Qt::Key_Up: + Nudge(ViewportInteraction::NudgeDirection::Up, + (ev->modifiers() & Qt::ShiftModifier) ? ViewportInteraction::NudgeSpeed::Fast : ViewportInteraction::NudgeSpeed::Slow); + return true; + case Qt::Key_Down: + Nudge(ViewportInteraction::NudgeDirection::Down, + (ev->modifiers() & Qt::ShiftModifier) ? ViewportInteraction::NudgeSpeed::Fast : ViewportInteraction::NudgeSpeed::Slow); + return true; + case Qt::Key_Left: + Nudge(ViewportInteraction::NudgeDirection::Left, + (ev->modifiers() & Qt::ShiftModifier) ? ViewportInteraction::NudgeSpeed::Fast : ViewportInteraction::NudgeSpeed::Slow); + return true; + case Qt::Key_Right: + Nudge(ViewportInteraction::NudgeDirection::Right, + (ev->modifiers() & Qt::ShiftModifier) ? ViewportInteraction::NudgeSpeed::Fast : ViewportInteraction::NudgeSpeed::Slow); + return true; + default: + break; } return false; diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.cpp b/Gems/LyShine/Code/Editor/ViewportWidget.cpp index e172d43b60..bf7447585c 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.cpp +++ b/Gems/LyShine/Code/Editor/ViewportWidget.cpp @@ -220,6 +220,7 @@ ViewportWidget::ViewportWidget(EditorWindow* parent) InitUiRenderer(); SetupShortcuts(); + installEventFilter(m_editorWindow); // Setup a timer for the maximum refresh rate we want. // Refresh is actually triggered by interaction events and by the IdleUpdate. This avoids the UI @@ -258,6 +259,8 @@ ViewportWidget::~ViewportWidget() LyShinePassDataRequestBus::Handler::BusDisconnect(); AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect(); + removeEventFilter(m_editorWindow); + m_uiRenderer.reset(); // Notify LyShine that this is no longer a valid UiRenderer. @@ -688,9 +691,9 @@ void ViewportWidget::wheelEvent(QWheelEvent* ev) Refresh(); } -bool ViewportWidget::event(QEvent* ev) +bool ViewportWidget::eventFilter([[maybe_unused]] QObject* watched, QEvent* event) { - if (ev->type() == QEvent::ShortcutOverride) + if (event->type() == QEvent::ShortcutOverride) { // When a shortcut is matched, Qt's event processing sends out a shortcut override event // to allow other systems to override it. If it's not overridden, then the key events @@ -698,40 +701,48 @@ bool ViewportWidget::event(QEvent* ev) // handler. In our case this causes a problem in preview mode for the Key_Delete event. // So, if we are preview mode avoid treating Key_Delete as a shortcut. - QKeyEvent* keyEvent = static_cast(ev); + QKeyEvent* keyEvent = static_cast(event); int key = keyEvent->key(); // Override the space bar shortcut so that the key gets handled by the viewport's KeyPress/KeyRelease // events when the viewport has the focus. The space bar is set up as a shortcut in order to give the // viewport the focus and activate the space bar when another widget has the focus. Once the shortcut // is pressed and focus is given to the viewport, the viewport takes over handling the space bar via - // the KeyPress/KeyRelease events - if (key == Qt::Key_Space) + // the KeyPress/KeyRelease events. + // Also ignore nudge shortcuts in edit/preview mode so that the KeyPressEvent will be sent. + switch (key) { - ev->accept(); + case Qt::Key_Space: + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_Left: + case Qt::Key_Right: + { + event->accept(); return true; } + default: + { + break; + } + } UiEditorMode editorMode = m_editorWindow->GetEditorMode(); if (editorMode == UiEditorMode::Preview) { - switch (key) + if (key == Qt::Key_Delete) { - case Qt::Key_Delete: - // Ignore nudge shortcuts in preview mode so that the KeyPressEvent will be sent - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_Left: - case Qt::Key_Right: - { - ev->accept(); + event->accept(); return true; } - break; - }; } } - + + return false; +} + +bool ViewportWidget::event(QEvent* ev) +{ bool result = RenderViewportWidget::event(ev); return result; } @@ -742,8 +753,7 @@ void ViewportWidget::keyPressEvent(QKeyEvent* event) if (editorMode == UiEditorMode::Edit) { // in Edit mode just send input to ViewportInteraction - bool handled = m_viewportInteraction->KeyPressEvent(event); - if (!handled) + if (!m_viewportInteraction->KeyPressEvent(event)) { RenderViewportWidget::keyPressEvent(event); } @@ -1246,115 +1256,6 @@ void ViewportWidget::SetupShortcuts() { // Actions with shortcuts are created instead of direct shortcuts because the shortcut dispatcher only looks for matching actions - // Create nudge shortcuts that are active across the entire UI Editor window. Any widgets (such as the spin box widget) that - // handle the same keys and want the shortcut to be ignored need to handle that with a shortcut override event. - // In preview mode, the nudge shortcuts are ignored via the shortcut override event. KeyPressEvents are sent instead, - // and passed along to the canvas - - // Nudge up - { - QAction* action = new QAction("Up", this); - action->setShortcut(QKeySequence(Qt::Key_Up)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Up, ViewportInteraction::NudgeSpeed::Slow); - }); - addAction(action); - } - - // Nudge up fast - { - QAction* action = new QAction("Up Fast", this); - action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Up)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Up, ViewportInteraction::NudgeSpeed::Fast); - }); - addAction(action); - } - - // Nudge down - { - QAction* action = new QAction("Down", this); - action->setShortcut(QKeySequence(Qt::Key_Down)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Down, ViewportInteraction::NudgeSpeed::Slow); - }); - addAction(action); - } - - // Nudge down fast - { - QAction* action = new QAction("Down Fast", this); - action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Down)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Down, ViewportInteraction::NudgeSpeed::Fast); - }); - addAction(action); - } - - // Nudge left - { - QAction* action = new QAction("Left", this); - action->setShortcut(QKeySequence(Qt::Key_Left)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Left, ViewportInteraction::NudgeSpeed::Slow); - }); - addAction(action); - } - - // Nudge left fast - { - QAction* action = new QAction("Left Fast", this); - action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Left)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Left, ViewportInteraction::NudgeSpeed::Fast); - }); - addAction(action); - } - - // Nudge right - { - QAction* action = new QAction("Right", this); - action->setShortcut(QKeySequence(Qt::Key_Right)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Right, ViewportInteraction::NudgeSpeed::Slow); - }); - addAction(action); - } - - // Nudge right fast - { - QAction* action = new QAction("Right Fast", this); - action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Right)); - QObject::connect(action, - &QAction::triggered, - [this]() - { - m_viewportInteraction->Nudge(ViewportInteraction::NudgeDirection::Right, ViewportInteraction::NudgeSpeed::Fast); - }); - addAction(action); - } - // Give the viewport focus and activate the space bar { QAction* action = new QAction("Viewport Focus", this); diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.h b/Gems/LyShine/Code/Editor/ViewportWidget.h index 620cb8fb35..722335aa93 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.h +++ b/Gems/LyShine/Code/Editor/ViewportWidget.h @@ -122,12 +122,15 @@ protected: void wheelEvent(QWheelEvent* ev) override; //! Prevents shortcuts from interfering with preview mode. + bool eventFilter(QObject* watched, QEvent* event) override; + + //! Handle events from Qt. bool event(QEvent* ev) override; - //! Key press event from Qt + //! Key press event from Qt. void keyPressEvent(QKeyEvent* event) override; - //! Key release event from Qt + //! Key release event from Qt. void keyReleaseEvent(QKeyEvent* event) override; void focusOutEvent(QFocusEvent* ev) override; From 144af200bf561ae0b16da97d4fdbd7fe11b5d2e8 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 25 Oct 2021 16:02:55 -0700 Subject: [PATCH 12/33] Fixed potential unused variable 'originalVersion' with 'maybe_unused' attribute. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp index e9d8a42641..36f4947e3d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp @@ -208,7 +208,7 @@ namespace AZ return; } - const uint32_t originalVersion = m_materialTypeVersion; + [[maybe_unused]] const uint32_t originalVersion = m_materialTypeVersion; bool changesWereApplied = false; From 423693d16b13a6589f8cda4ec0127ce83226cefc Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Mon, 25 Oct 2021 16:05:19 -0700 Subject: [PATCH 13/33] Re-add call used to initiate gem download Signed-off-by: AMZN-Phil --- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index bc667db4b4..b3d0ab83ed 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -166,6 +166,10 @@ namespace O3DE::ProjectManager { notification += " " + tr("and") + " "; } + if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) + { + m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); + } } if (numChangedDependencies == 1 ) From 1bc2968330c7f700759d68b4b4a8e59d81007027 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 25 Oct 2021 17:47:54 -0700 Subject: [PATCH 14/33] Resolve minor hover state bugs on the Entity Outlier (branches detect hover state separately from the rest of the columns) (#4977) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp index d94ced392c..0609f8113d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp @@ -72,7 +72,7 @@ namespace AzToolsFramework void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event) { - m_mousePosition = QPoint(); + m_mousePosition = QPoint(-1, -1); m_currentHoveredIndex = QModelIndex(); update(); } @@ -200,7 +200,7 @@ namespace AzToolsFramework const bool isEnabled = (this->model()->flags(index) & Qt::ItemIsEnabled); const bool isSelected = selectionModel()->isSelected(index); - const bool isHovered = (index == indexAt(m_mousePosition)) && isEnabled; + const bool isHovered = (index == indexAt(m_mousePosition).siblingAtColumn(0)) && isEnabled; // Paint the branch Selection/Hover Rect PaintBranchSelectionHoverRect(painter, rect, isSelected, isHovered); From 057c8e0d4e77c6ede25359a86324791ac313b548 Mon Sep 17 00:00:00 2001 From: moraaar Date: Tue, 26 Oct 2021 13:58:21 +0100 Subject: [PATCH 15/33] Fixed error: unused variable 'physxMaximumMaterialIndex' (#4989) Signed-off-by: moraaar --- Gems/PhysX/Code/Source/Utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/PhysX/Code/Source/Utils.cpp b/Gems/PhysX/Code/Source/Utils.cpp index b4e1e768c3..3e77ef257a 100644 --- a/Gems/PhysX/Code/Source/Utils.cpp +++ b/Gems/PhysX/Code/Source/Utils.cpp @@ -102,7 +102,7 @@ namespace PhysX const float scaleFactor = (maxHeightBounds <= minHeightBounds) ? 1.0f : AZStd::numeric_limits::max() / halfBounds; const float heightScale{ 1.0f / scaleFactor }; - const uint8_t physxMaximumMaterialIndex = 0x7f; + [[maybe_unused]] const uint8_t physxMaximumMaterialIndex = 0x7f; // Delete the cached heightfield object if it is there, and create a new one and save in the shape configuration heightfieldConfig.SetCachedNativeHeightfield(nullptr); From 75ebf77b590e5a987f36924f584105ee3b06da7c Mon Sep 17 00:00:00 2001 From: nggieber Date: Tue, 26 Oct 2021 07:22:47 -0700 Subject: [PATCH 16/33] Added warning message when adding repositories Signed-off-by: nggieber --- .../ProjectManager/Resources/ProjectManager.qss | 6 ++++++ .../Source/GemRepo/GemRepoAddDialog.cpp | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 6694168f2b..e755964a7f 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -691,6 +691,12 @@ QProgressBar::chunk { #gemRepoAddDialogInstructionTitleLabel { font-size:14px; + font-weight:bold; +} + +#gemRepoAddDialogWarningLabel { + font-size:12px; + font-style:italic; } #addGemRepoDialog #formFrame { diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp index 601c62d6e1..05a14b48d3 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -27,6 +27,7 @@ namespace O3DE::ProjectManager QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setContentsMargins(30, 30, 25, 10); vLayout->setSpacing(0); + vLayout->setAlignment(Qt::AlignTop); setLayout(vLayout); QLabel* instructionTitleLabel = new QLabel(tr("Enter a valid path to add a new user repository")); @@ -41,9 +42,18 @@ namespace O3DE::ProjectManager vLayout->addWidget(instructionContextLabel); m_repoPath = new FormFolderBrowseEditWidget(tr("Repository Path"), "", this); - m_repoPath->setFixedWidth(600); + m_repoPath->setFixedSize(QSize(600, 100)); vLayout->addWidget(m_repoPath); + vLayout->addSpacing(10); + + QLabel* warningLabel = new QLabel(tr("Online repositories may contain files that could potentially harm your computer," + " please ensure you understand the risks before downloading Gems from third-party sources.")); + warningLabel->setObjectName("gemRepoAddDialogWarningLabel"); + warningLabel->setWordWrap(true); + warningLabel->setAlignment(Qt::AlignLeft); + vLayout->addWidget(warningLabel); + vLayout->addSpacing(40); QDialogButtonBox* dialogButtons = new QDialogButtonBox(); From c2105b0631e6dbc1bd8962a210e08da6f5d68258 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 26 Oct 2021 15:30:08 +0100 Subject: [PATCH 17/33] Address PR comments. Signed-off-by: John --- ...ViewportEditorModeTrackerNotificationBus.h | 2 ++ .../Viewport/ViewportEditorModeTests.cpp | 22 ++++++------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index 966b9f8478..2d25dbbafc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -43,6 +43,8 @@ namespace AzToolsFramework }; //! Provides a bus to notify when the different editor modes are entered/exit. + //! @note The editor modes are not discrete states but rather each progression of mode retain the active the parent + //! mode that the new mode progressed from. class ViewportEditorModeNotifications : public AZ::EBusTraits { public: diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp index 05d7a0d37d..85b65f3edf 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportEditorModeTests.cpp @@ -72,14 +72,6 @@ namespace UnitTest } } - bool IsComponentModeActive() - { - bool inComponentMode = false; - AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult( - inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode); - return inComponentMode; - } - // Fixture for testing editor mode states class ViewportEditorModesTestsFixture : public ::testing::Test @@ -543,7 +535,7 @@ namespace UnitTest AZStd::vector{}); // Expect to be in component mode - EXPECT_TRUE(IsComponentModeActive()); + EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode()); // Expect the default and component viewport editor modes to be active EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); @@ -561,13 +553,13 @@ namespace UnitTest &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, AZStd::vector{}); - EXPECT_TRUE(IsComponentModeActive()); + EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode()); AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode); // Expect to not be in component mode - EXPECT_FALSE(IsComponentModeActive()); + EXPECT_FALSE(AzToolsFramework::ComponentModeFramework::InComponentMode()); // Expect only the default viewport editor mode to be active ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default); @@ -634,7 +626,7 @@ namespace UnitTest ExitingFocusModeAfterEnteringFromInitialStateHasOnlyViewportEditorModeDefaultActive) { // When entering and leaving focus mode - m_focusModeInterface->SetFocusRoot(AZ::EntityId(1)); + m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 }); m_focusModeInterface->SetFocusRoot(AZ::EntityId()); // Expect only the default mode to be active @@ -650,7 +642,7 @@ namespace UnitTest AZStd::vector{}); // Expect to be in component mode - EXPECT_TRUE(IsComponentModeActive()); + EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode()); // Expect the default, focus and component viewport editor modes to be active EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); @@ -669,13 +661,13 @@ namespace UnitTest &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode, AZStd::vector{}); - EXPECT_TRUE(IsComponentModeActive()); + EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode()); AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode); // Expect to not be in component mode - EXPECT_FALSE(IsComponentModeActive()); + EXPECT_FALSE(AzToolsFramework::ComponentModeFramework::InComponentMode()); // Expect the default and focus viewport editor modes to be active EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default)); From f3499011ac52f801ab5bf5f27791f56039e0a7d1 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 26 Oct 2021 08:30:51 -0700 Subject: [PATCH 18/33] [Mac] Fix QtEditorApplication_mac include (#4978) Commit 8e03d6f3065105f53a171345a2cf4a661cec4eb0 missed updating the platform-specific mac QApplication implementation file to include the class declaration from the new header. Signed-off-by: Chris Burel --- Code/Editor/Platform/Mac/Editor/Core/QtEditorApplication_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Editor/Platform/Mac/Editor/Core/QtEditorApplication_mac.mm b/Code/Editor/Platform/Mac/Editor/Core/QtEditorApplication_mac.mm index a7f59b7ac8..c664d13c79 100644 --- a/Code/Editor/Platform/Mac/Editor/Core/QtEditorApplication_mac.mm +++ b/Code/Editor/Platform/Mac/Editor/Core/QtEditorApplication_mac.mm @@ -9,7 +9,7 @@ #import #include "EditorDefs.h" -#include "QtEditorApplication.h" +#include "QtEditorApplication_mac.h" // AzFramework #include From 3ff469c55e4d8be1b45e343731324b78014252d6 Mon Sep 17 00:00:00 2001 From: nggieber Date: Tue, 26 Oct 2021 08:42:22 -0700 Subject: [PATCH 19/33] Fix issue with project still displaying when last project is removed Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/ScreensCtrl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp index 314765def0..fd8fbc970a 100644 --- a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp @@ -133,6 +133,11 @@ namespace O3DE::ProjectManager return true; } + else + { + // If we are already on this screen still notify we are on this screen to refresh it + newScreen->NotifyCurrentScreen(); + } } return false; From 22a287d046c606ccb79ff19c1c15075d8cd71dbc Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Tue, 26 Oct 2021 08:56:37 -0700 Subject: [PATCH 20/33] Fix to set the Taskbar name and Game Launcher window title to the name of the Project (#4986) Signed-off-by: Steve Pham --- .../Common/Xcb/AzFramework/XcbNativeWindow.cpp | 11 +++++++++-- .../Code/Source/BootstrapSystemComponent.cpp | 5 ++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp index 79a6333612..c7663dc1ab 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp @@ -258,10 +258,17 @@ namespace AzFramework //////////////////////////////////////////////////////////////////////////////////////////////// void XcbNativeWindow::SetWindowTitle(const AZStd::string& title) { + // Set the title of both the window and the task bar by using + // a buffer to hold the title twice, separated by a null-terminator + auto doubleTitleSize = (title.size() + 1) * 2; + AZStd::string doubleTitle(doubleTitleSize, '\0'); + azstrncpy(doubleTitle.data(), doubleTitleSize, title.c_str(), title.size()); + azstrncpy(&doubleTitle.data()[title.size() + 1], title.size(), title.c_str(), title.size()); + xcb_void_cookie_t xcbCheckResult; xcbCheckResult = xcb_change_property( - m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, static_cast(title.size()), - title.c_str()); + m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, static_cast(doubleTitle.size()), + doubleTitle.c_str()); AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set window title."); } diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index 8f2ff264e5..3f5761270a 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -115,7 +116,9 @@ namespace AZ { // GFX TODO - investigate window creation being part of the GameApplication. - m_nativeWindow = AZStd::make_unique("O3DELauncher", AzFramework::WindowGeometry(0, 0, 1920, 1080)); + auto projectTitle = AZ::Utils::GetProjectName(); + + m_nativeWindow = AZStd::make_unique(projectTitle.c_str(), AzFramework::WindowGeometry(0, 0, 1920, 1080)); AZ_Assert(m_nativeWindow, "Failed to create the game window\n"); m_nativeWindow->Activate(); From 866fd8a420e98ba871a49da8dec59b2a5971e36a Mon Sep 17 00:00:00 2001 From: nggieber Date: Tue, 26 Oct 2021 09:46:54 -0700 Subject: [PATCH 21/33] Fix selected gem filtering Signed-off-by: nggieber --- .../Source/GemCatalog/GemFilterWidget.cpp | 58 +++++++++++-------- .../GemCatalog/GemSortFilterProxyModel.cpp | 23 ++++++-- .../GemCatalog/GemSortFilterProxyModel.h | 3 +- 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp index b425c15dee..4f737d8629 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -225,21 +225,22 @@ namespace O3DE::ProjectManager QVector elementNames; QVector elementCounts; const int totalGems = m_gemModel->rowCount(); - const int selectedGemTotal = m_gemModel->TotalAddedGems(); + const int selectedGemTotal = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true).size(); + const int unselectedGemTotal = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true).size(); const int enabledGemTotal = m_gemModel->TotalAddedGems(/*includeDependencies=*/true); - elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Unselected)); - elementCounts.push_back(totalGems - selectedGemTotal); - elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Selected)); elementCounts.push_back(selectedGemTotal); - elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Inactive)); - elementCounts.push_back(totalGems - enabledGemTotal); + elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Unselected)); + elementCounts.push_back(unselectedGemTotal); elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Active)); elementCounts.push_back(enabledGemTotal); + elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Inactive)); + elementCounts.push_back(totalGems - enabledGemTotal); + bool wasCollapsed = false; if (m_statusFilter) { @@ -262,44 +263,51 @@ namespace O3DE::ProjectManager const QList buttons = m_statusFilter->GetButtonGroup()->buttons(); - QAbstractButton* unselectedButton = buttons[0]; - QAbstractButton* selectedButton = buttons[1]; - unselectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Unselected); - selectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Selected); + QAbstractButton* selectedButton = buttons[0]; + QAbstractButton* unselectedButton = buttons[1]; + selectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Selected); + unselectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Unselected); auto updateGemSelection = [=]([[maybe_unused]] bool checked) { - if (unselectedButton->isChecked() && !selectedButton->isChecked()) - { - m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Unselected); - } - else if (!unselectedButton->isChecked() && selectedButton->isChecked()) + if (!unselectedButton->isChecked() && selectedButton->isChecked()) { m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Selected); } + else if (unselectedButton->isChecked() && !selectedButton->isChecked()) + { + m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Unselected); + } else { - m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::NoFilter); + if (unselectedButton->isChecked() && selectedButton->isChecked()) + { + m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Both); + } + else + { + m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::NoFilter); + } } }; connect(unselectedButton, &QAbstractButton::toggled, this, updateGemSelection); connect(selectedButton, &QAbstractButton::toggled, this, updateGemSelection); - QAbstractButton* inactiveButton = buttons[2]; - QAbstractButton* activeButton = buttons[3]; - inactiveButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Inactive); - activeButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Active); + QAbstractButton* activeButton = buttons[2]; + QAbstractButton* inactiveButton = buttons[3]; + activeButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Active); + inactiveButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Inactive); auto updateGemActive = [=]([[maybe_unused]] bool checked) { - if (inactiveButton->isChecked() && !activeButton->isChecked()) - { - m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Inactive); - } - else if (!inactiveButton->isChecked() && activeButton->isChecked()) + if (!inactiveButton->isChecked() && activeButton->isChecked()) { m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Active); } + else if (inactiveButton->isChecked() && !activeButton->isChecked()) + { + m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Inactive); + } else { m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::NoFilter); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp index 199692f200..7ec45ac721 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp @@ -50,11 +50,26 @@ namespace O3DE::ProjectManager } } - // Gem selected - if (m_gemSelectedFilter != GemSelected::NoFilter) + // Gem selected + if (m_gemSelectedFilter == GemSelected::Selected) { - const GemSelected sourceGemStatus = static_cast(GemModel::IsAdded(sourceIndex)); - if (m_gemSelectedFilter != sourceGemStatus) + if (!GemModel::NeedsToBeAdded(sourceIndex, true)) + { + return false; + } + } + // Gem unselected + else if (m_gemSelectedFilter == GemSelected::Unselected) + { + if (!GemModel::NeedsToBeRemoved(sourceIndex, true)) + { + return false; + } + } + // Gem selected or unselected + else if (m_gemSelectedFilter == GemSelected::Both) + { + if (!GemModel::NeedsToBeAdded(sourceIndex, true) && !GemModel::NeedsToBeRemoved(sourceIndex, true)) { return false; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h index 74b1e915eb..ab739e62f9 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h @@ -29,7 +29,8 @@ namespace O3DE::ProjectManager { NoFilter = -1, Unselected, - Selected + Selected, + Both }; enum class GemActive { From b541d69efc1b1476eaa929a7cb81e09a3cf4185a Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Tue, 26 Oct 2021 12:19:12 -0500 Subject: [PATCH 22/33] DXC Validation Error Difficult to See in AP Window (#4982) * DXC Validation Error Difficult to See in AP Window Renamed ReportErrorMessages() as ReportMessages() All the message will be printed as a single AZ_Error() or AZ_Warning() instead of mingled AZ_Error/AZ_Warning/AZ_TRacePrintf which was making the output hard to read. Signed-off-by: garrieta --- .../Code/Source/Editor/ShaderAssetBuilder.cpp | 4 +-- .../RHI/Code/Include/Atom/RHI.Edit/Utils.h | 11 +++--- Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp | 36 +++++++------------ 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp index a0205efa72..89e202a4bc 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp @@ -477,8 +477,8 @@ namespace AZ preprocessorOptions.m_predefinedMacros.end(), macroDefinitionsToAdd.begin(), macroDefinitionsToAdd.end()); // Run the preprocessor. PreprocessorData output; - PreprocessFile(prependedAzslFilePath, output, preprocessorOptions, true, true); - RHI::ReportErrorMessages(ShaderAssetBuilderName, output.diagnostics); + const bool preprocessorSuccess = PreprocessFile(prependedAzslFilePath, output, preprocessorOptions, true, true); + RHI::ReportMessages(ShaderAssetBuilderName, output.diagnostics, !preprocessorSuccess); // Dump the preprocessed string as a flat AZSL file with extension .azslin, which will be given to AZSLc to generate the HLSL file. AZStd::string superVariantAzslinStemName = shaderFileName; if (!supervariantInfo.m_name.IsEmpty()) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h index 0624dce5f8..d648f05b46 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h @@ -83,11 +83,12 @@ namespace AZ const AZStd::string& shaderSourcePathForDebug, const char* toolNameForLog); - //! Reports error messages to AZ_Error and/or AZ_Warning, given a text blob that potentially contains many lines of errors and warnings. - //! @param window Debug window name used for AZ Trace functions - //! @param errorMessages String that may contain many lines of errors and warnings - //! @param return true if Errors were detected and reported (Warnings don't count) - bool ReportErrorMessages(AZStd::string_view window, AZStd::string_view errorMessages); + //! Reports messages with AZ_Error or AZ_Warning (See @reportAsErrors). + //! @param window Debug window name used for AZ Trace functions. + //! @param errorMessages Message string. + //! @param reportAsErrors If true, messages are traced with AZ_Error, otherwise AZ_Warning is used. + //! @returns true If the input text blob contains at least one line with the "error" string. + bool ReportMessages(AZStd::string_view window, AZStd::string_view errorMessages, bool reportAsErrors); //! Converts from a RHI::ShaderHardwareStage to an RHI::ShaderStage ShaderStage ToRHIShaderStage(ShaderHardwareStage stageType); diff --git a/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp b/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp index b4c68b3f75..dc203ef731 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp @@ -330,7 +330,7 @@ namespace AZ // Pump one last time to make sure the streams have been flushed pumpOuputStreams(); - const bool reportedErrors = ReportErrorMessages(toolNameForLog, errorMessages); + const bool reportedErrors = ReportMessages(toolNameForLog, errorMessages, exitCode != 0); if (timedOut) { @@ -367,32 +367,20 @@ namespace AZ return true; } - bool ReportErrorMessages([[maybe_unused]] AZStd::string_view window, AZStd::string_view errorMessages) + bool ReportMessages([[maybe_unused]] AZStd::string_view window, AZStd::string_view errorMessages, bool reportAsErrors) { - // There are more efficient ways to do this, but this approach is simple and gets us moving for now. - AZStd::vector lines; - AzFramework::StringFunc::Tokenize(errorMessages.data(), lines, "\n\r"); - - bool foundErrors = false; - - for (auto& line : lines) + if (reportAsErrors) { - if (AZStd::string::npos != AzFramework::StringFunc::Find(line, "error")) - { - AZ_Error(window.data(), false, "%s", line.data()); - foundErrors = true; - } - else if (AZStd::string::npos != AzFramework::StringFunc::Find(line, "warning")) - { - AZ_Warning(window.data(), false, "%s", line.data()); - } - else - { - AZ_TracePrintf(window.data(), "%s", line.data()); - } + AZ_Error(window.data(), false, "%.*s", aznumeric_cast(errorMessages.size()), errorMessages.data()); } - - return foundErrors; + else + { + // Using AZ_Warning instead of AZ_TracePrintf because this function is commonly + // used to report messages from stderr when executing applications. Applications + // when ran successfully, only output to stderr for errors or warnings. + AZ_Warning(window.data(), false, "%.*s", aznumeric_cast(errorMessages.size()), errorMessages.data()); + } + return AZStd::string::npos != AzFramework::StringFunc::Find(errorMessages, "error"); } ShaderStage ToRHIShaderStage(ShaderHardwareStage stageType) From a945fd9f1bc885af48bd7c3172f1e46d24588eb5 Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Tue, 26 Oct 2021 12:27:40 -0500 Subject: [PATCH 23/33] Removed ShaderAsset related unncessary warning (#5008) Removed ShaderAsset related unncessary warning that pollutes the logs. Signed-off-by: garrieta --- Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp index 692087d93b..84757d58ab 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp @@ -264,7 +264,6 @@ namespace AZ { // When rebuilding shaders we may be in a state where the ShaderAsset and root ShaderVariantAsset have been rebuilt and reloaded, but some (or all) // shader variants haven't been built yet. Since we want to use the latest version of the shader code, ignore the old variants and fall back to the newer root variant instead. - AZ_Warning("ShaderAsset", false, "ShaderAsset and ShaderVariantAsset are out of sync; defaulting to root shader variant. (This is common while reloading shaders)."); return GetRootVariant(supervariantIndex); } } From e9b5a51d9fec3126660bdd9a8626ab09c8807072 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 26 Oct 2021 18:39:39 +0100 Subject: [PATCH 24/33] Fix console warning when adding TerrainWorldRendererComponent (#4964) * Fix console warning when adding TerrainWorldRendererComponent Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * Change default value Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Code/Source/Components/TerrainWorldRendererComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h index 354b2fde34..140b830da1 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h @@ -46,7 +46,7 @@ namespace Terrain WorldSizeCount, }; - WorldSize m_worldSize; + WorldSize m_worldSize = WorldSize::_1024Meters; }; From e22235ec5b850541d6a186a80b44050ebfd24d89 Mon Sep 17 00:00:00 2001 From: hershey5045 <43485729+hershey5045@users.noreply.github.com> Date: Tue, 26 Oct 2021 10:40:30 -0700 Subject: [PATCH 25/33] Add OpenImageIO as runtime dependency in AtomLyIntegration. (#4987) * Add OpenImageIO as runtime dependency in AtomLyIntegration. Signed-off-by: rbarrand * Place 3rdparty import inside if block. Signed-off-by: rbarrand * Add platform cmake files for other platforms to prevent compile errors. Signed-off-by: rbarrand Co-authored-by: rbarrand --- .../Source/Platform/Windows/platform_windows.cmake | 9 --------- .../CommonFeatures/Code/CMakeLists.txt | 2 ++ .../Source/Platform/Android/platform_android.cmake | 7 +++++++ .../Source/Platform/AppleTV/platform_appletv.cmake | 8 ++++++++ .../Code/Source/Platform/Linux/platform_linux.cmake | 7 +++++++ .../Code/Source/Platform/Mac/platform_mac.cmake | 7 +++++++ .../Source/Platform/Windows/platform_windows.cmake | 13 +++++++++++++ .../Code/Source/Platform/iOS/platform_ios.cmake | 7 +++++++ 8 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Android/platform_android.cmake create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/AppleTV/platform_appletv.cmake create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Linux/platform_linux.cmake create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Mac/platform_mac.cmake create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Windows/platform_windows.cmake create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/iOS/platform_ios.cmake diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake index 7c594fc945..7a325ca97e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake +++ b/Gems/Atom/Feature/Common/Code/Source/Platform/Windows/platform_windows.cmake @@ -5,12 +5,3 @@ # SPDX-License-Identifier: Apache-2.0 OR MIT # # - -if(LY_MONOLITHIC_GAME) # Do not use OpenImageIO in monolithic game - return() -endif() - -set(LY_BUILD_DEPENDENCIES - PRIVATE - 3rdParty::ilmbase -) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt index e68681315e..95331a2f3f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt @@ -86,6 +86,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) FILES_CMAKE atomlyintegration_commonfeatures_editor_files.cmake ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + PLATFORM_INCLUDE_FILES + ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake INCLUDE_DIRECTORIES PRIVATE . diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Android/platform_android.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Android/platform_android.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Android/platform_android.cmake @@ -0,0 +1,7 @@ +# +# 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 +# +# diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/AppleTV/platform_appletv.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/AppleTV/platform_appletv.cmake new file mode 100644 index 0000000000..5cd1fb5a22 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/AppleTV/platform_appletv.cmake @@ -0,0 +1,8 @@ +# +# 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 +# +# + diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Linux/platform_linux.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Linux/platform_linux.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Linux/platform_linux.cmake @@ -0,0 +1,7 @@ +# +# 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 +# +# diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Mac/platform_mac.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Mac/platform_mac.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Mac/platform_mac.cmake @@ -0,0 +1,7 @@ +# +# 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 +# +# diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Windows/platform_windows.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Windows/platform_windows.cmake new file mode 100644 index 0000000000..3beda63de7 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/Windows/platform_windows.cmake @@ -0,0 +1,13 @@ +# +# 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 +# +# + +if(NOT LY_MONOLITHIC_GAME) # Do not use OpenImageIO in monolithic game + set(LY_RUNTIME_DEPENDENCIES + 3rdParty::OpenImageIO + ) +endif() diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/iOS/platform_ios.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/iOS/platform_ios.cmake new file mode 100644 index 0000000000..7a325ca97e --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Platform/iOS/platform_ios.cmake @@ -0,0 +1,7 @@ +# +# 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 +# +# From 707730ebbc1cedeea3bcb785251474401a0e76dd Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Tue, 26 Oct 2021 15:26:54 -0400 Subject: [PATCH 26/33] Hair - bug fix resulted from change in pass fetch using the new pipeline filter (#5013) Signed-off-by: Adi-Amazon Co-authored-by: Adi-Amazon --- .../Code/Rendering/HairFeatureProcessor.cpp | 13 +++++++------ .../Code/Rendering/HairFeatureProcessor.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp index 161160e16f..74ba99c26c 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp @@ -311,17 +311,17 @@ namespace AZ m_forceClearRenderData = true; } - bool HairFeatureProcessor::HasHairParentPass() + bool HairFeatureProcessor::HasHairParentPass(RPI::RenderPipeline* renderPipeline) { - RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, renderPipeline); RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); - return pass; + return pass ? true : false; } void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!HasHairParentPass()) + if (!HasHairParentPass(renderPipeline.get())) { return; } @@ -335,7 +335,7 @@ namespace AZ void HairFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!HasHairParentPass()) + if (!HasHairParentPass(renderPipeline)) { return; } @@ -347,7 +347,7 @@ namespace AZ void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!HasHairParentPass()) + if (!HasHairParentPass(renderPipeline)) { return; } @@ -623,3 +623,4 @@ namespace AZ } // namespace Hair } // namespace Render } // namespace AZ + diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h index f810967824..70e37a7863 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h @@ -165,7 +165,7 @@ namespace AZ void EnablePasses(bool enable); - bool HasHairParentPass(); + bool HasHairParentPass(RPI::RenderPipeline* renderPipeline); //! The following will serve to register the FP in the Thumbnail system AZStd::vector m_hairFeatureProcessorRegistryName; From 78b0683313fe37f87c0a2f9990d4b32f04456111 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Tue, 26 Oct 2021 15:47:17 -0500 Subject: [PATCH 27/33] Added GetComponentTypeEditorIcon API and replaced old macro style ebus calls. Signed-off-by: Chris Galvan --- .../ComponentEntityEditorPlugin/SandboxIntegration.cpp | 5 +++++ .../ComponentEntityEditorPlugin/SandboxIntegration.h | 1 + .../UI/ComponentPalette/ComponentDataModel.cpp | 2 +- Code/Editor/TrackView/TrackViewNodes.cpp | 2 +- .../AzToolsFramework/API/ToolsApplicationAPI.h | 4 ++++ .../AzToolsFramework/Application/ToolsApplication.cpp | 9 ++++++++- .../UI/ComponentPalette/ComponentPaletteUtil.cpp | 2 +- .../UI/PropertyEditor/ComponentEditor.cpp | 2 +- 8 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 41e950a058..5b849dcbe7 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -1788,6 +1788,11 @@ AZStd::string SandboxIntegrationManager::GetComponentEditorIcon(const AZ::Uuid& return iconPath; } +AZStd::string SandboxIntegrationManager::GetComponentTypeEditorIcon(const AZ::Uuid& componentType) +{ + return GetComponentEditorIcon(componentType, nullptr); +} + AZStd::string SandboxIntegrationManager::GetComponentIconPath(const AZ::Uuid& componentType, AZ::Crc32 componentIconAttrib, AZ::Component* component) { diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index 40962409a3..9afa944438 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -233,6 +233,7 @@ private: } AZStd::string GetComponentEditorIcon(const AZ::Uuid& componentType, AZ::Component* component) override; + AZStd::string GetComponentTypeEditorIcon(const AZ::Uuid& componentType) override; AZStd::string GetComponentIconPath(const AZ::Uuid& componentType, AZ::Crc32 componentIconAttrib, AZ::Component* component) override; ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/ComponentDataModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/ComponentDataModel.cpp index cd0fba350f..dcae6abfeb 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/ComponentDataModel.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/ComponentDataModel.cpp @@ -139,7 +139,7 @@ ComponentDataModel::ComponentDataModel(QObject* parent) if (element.m_elementId == AZ::Edit::ClassElements::EditorData) { AZStd::string iconPath; - EBUS_EVENT_RESULT(iconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, classData->m_typeId, nullptr); + AzToolsFramework::EditorRequestBus::BroadcastResult(iconPath, &AzToolsFramework::EditorRequests::GetComponentTypeEditorIcon, classData->m_typeId); if (!iconPath.empty()) { m_componentIcons[classData->m_typeId] = QIcon(iconPath.c_str()); diff --git a/Code/Editor/TrackView/TrackViewNodes.cpp b/Code/Editor/TrackView/TrackViewNodes.cpp index 2a2d584e46..db65abf9d2 100644 --- a/Code/Editor/TrackView/TrackViewNodes.cpp +++ b/Code/Editor/TrackView/TrackViewNodes.cpp @@ -408,7 +408,7 @@ CTrackViewNodesCtrl::CTrackViewNodesCtrl(QWidget* hParentWnd, CTrackViewDialog* serializeContext->EnumerateDerived([this](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid&) -> bool { AZStd::string iconPath; - EBUS_EVENT_RESULT(iconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, classData->m_typeId, nullptr); + AzToolsFramework::EditorRequestBus::BroadcastResult(iconPath, &AzToolsFramework::EditorRequests::GetComponentTypeEditorIcon, classData->m_typeId); if (!iconPath.empty()) { m_componentTypeToIconMap[classData->m_typeId] = QIcon(iconPath.c_str()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index 9e29b9813c..fd4196a296 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -826,6 +826,10 @@ namespace AzToolsFramework /// Path will be empty if component should have no icon. virtual AZStd::string GetComponentEditorIcon(const AZ::Uuid& /*componentType*/, AZ::Component* /*component*/) { return AZStd::string(); } + //! Return path to icon for component type. + //! Path will be empty if component type should have no icon. + virtual AZStd::string GetComponentTypeEditorIcon(const AZ::Uuid& /*componentType*/) { return AZStd::string(); } + /** * Return the icon image path based on the component type and where it is used. * \param componentType component type diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index fbd066ec6e..cdafa63eba 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -175,7 +175,7 @@ namespace AzToolsFramework , public AZ::BehaviorEBusHandler { AZ_EBUS_BEHAVIOR_BINDER(ToolsApplicationNotificationBusHandler, "{7EB67956-FF86-461A-91E2-7B08279CFACF}", AZ::SystemAllocator, - EntityRegistered, EntityDeregistered); + EntityRegistered, EntityDeregistered, AfterEntitySelectionChanged); void EntityRegistered(AZ::EntityId entityId) override { @@ -186,6 +186,11 @@ namespace AzToolsFramework { Call(FN_EntityDeregistered, entityId); } + + void AfterEntitySelectionChanged(const EntityIdList& newlySelectedEntities, const EntityIdList& newlyDeselectedEntities) override + { + Call(FN_AfterEntitySelectionChanged, newlySelectedEntities, newlyDeselectedEntities); + } }; struct ViewPaneCallbackBusHandler final @@ -408,6 +413,7 @@ namespace AzToolsFramework ->Handler() ->Event("EntityRegistered", &ToolsApplicationEvents::EntityRegistered) ->Event("EntityDeregistered", &ToolsApplicationEvents::EntityDeregistered) + ->Event("AfterEntitySelectionChanged", &ToolsApplicationEvents::AfterEntitySelectionChanged) ; behaviorContext->Class() @@ -426,6 +432,7 @@ namespace AzToolsFramework ->Attribute(AZ::Script::Attributes::Module, "editor") ->Event("RegisterCustomViewPane", &EditorRequests::RegisterCustomViewPane) ->Event("UnregisterViewPane", &EditorRequests::UnregisterViewPane) + ->Event("GetComponentTypeEditorIcon", &EditorRequests::GetComponentTypeEditorIcon) ; behaviorContext->EBus("EditorEventBus") diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp index b6f5b41b65..888554d065 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.cpp @@ -90,7 +90,7 @@ namespace AzToolsFramework } AZStd::string componentIconPath; - EBUS_EVENT_RESULT(componentIconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, componentClass->m_typeId, nullptr); + AzToolsFramework::EditorRequestBus::BroadcastResult(componentIconPath, &AzToolsFramework::EditorRequests::GetComponentTypeEditorIcon, componentClass->m_typeId); componentIconTable[componentClass] = QString::fromUtf8(componentIconPath.c_str()); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.cpp index 91d2359ca6..48dec6f225 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.cpp @@ -583,7 +583,7 @@ namespace AzToolsFramework } AZStd::string iconPath; - EBUS_EVENT_RESULT(iconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, componentType, const_cast(&componentInstance)); + AzToolsFramework::EditorRequestBus::BroadcastResult(iconPath, &AzToolsFramework::EditorRequests::GetComponentEditorIcon, componentType, const_cast(&componentInstance)); GetHeader()->SetIcon(QIcon(iconPath.c_str())); bool isExpanded = true; From 8fd34618636b922033441044b7937286e1ac2745 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Tue, 26 Oct 2021 15:38:09 -0700 Subject: [PATCH 28/33] Removed reference to opacity.doubleSided property that no longer exists. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua index c86fbfe0b7..9315131e44 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua @@ -81,7 +81,6 @@ function ProcessEditor(context) context:SetMaterialPropertyVisibility("opacity.textureMap", mainVisibility) context:SetMaterialPropertyVisibility("opacity.textureMapUv", mainVisibility) context:SetMaterialPropertyVisibility("opacity.factor", mainVisibility) - context:SetMaterialPropertyVisibility("opacity.doubleSided", mainVisibility) if(opacityMode == OpacityMode_Blended or opacityMode == OpacityMode_TintedTransparent) then context:SetMaterialPropertyVisibility("opacity.alphaAffectsSpecular", MaterialPropertyVisibility_Enabled) From 42a14079f2dd41f01048e9169daac282802b98c1 Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Tue, 26 Oct 2021 17:48:28 -0500 Subject: [PATCH 29/33] Fix naming for DisableOptimizations vs DxcDisableOptimizations (#5016) Signed-off-by: garrieta --- .../Shaders/ScreenSpace/DeferredFog.shader | 4 +-- .../Atom/RHI.Edit/ShaderCompilerArguments.h | 19 ++++++---- .../RHI.Edit/ShaderCompilerArguments.cpp | 36 +++++++++---------- .../RHI.Builders/ShaderPlatformInterface.cpp | 4 +-- .../RHI.Builders/ShaderPlatformInterface.cpp | 2 +- .../RHI.Builders/ShaderPlatformInterface.cpp | 2 +- .../Types/AutoBrick_ForwardPass.shader | 2 +- .../Types/MinimalPBR_ForwardPass.shader | 2 +- 8 files changed, 39 insertions(+), 32 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/ScreenSpace/DeferredFog.shader b/Gems/Atom/Feature/Common/Assets/Shaders/ScreenSpace/DeferredFog.shader index 5e2ca9bff5..06c991400e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/ScreenSpace/DeferredFog.shader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/ScreenSpace/DeferredFog.shader @@ -23,8 +23,8 @@ "DrawList" : "forward", "CompilerHints" : { - "DxcDisableOptimizations" : false, - "DxcGenerateDebugInfo" : false + "DisableOptimizations" : false, + "GenerateDebugInfo" : false }, "ProgramSettings": diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderCompilerArguments.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderCompilerArguments.h index d0960a7fde..83a868ab65 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderCompilerArguments.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderCompilerArguments.h @@ -57,12 +57,19 @@ namespace AZ AZStd::string m_azslcAdditionalFreeArguments; // note: if you add new sort of arguments here, don't forget to update HasDifferentAzslcArguments() - //! DXC - bool m_dxcDisableWarnings = false; - bool m_dxcWarningAsError = false; - bool m_dxcDisableOptimizations = false; - bool m_dxcGenerateDebugInfo = false; - uint8_t m_dxcOptimizationLevel = LevelUnset; + //! Remark: To the user, the following parameters are exposed without the + //! "Dxc" prefix because these are common options for the "main" compiler + //! for the given RHI. At the moment the only "main" compiler is Dxc, but in + //! the future AZSLc may transpile from AZSL to some other proprietary language + //! and in that case the "main" compiler won't be DXC + bool m_disableWarnings = false; + bool m_warningAsError = false; + bool m_disableOptimizations = false; + bool m_generateDebugInfo = false; + uint8_t m_optimizationLevel = LevelUnset; + //! "DxcAdditionalFreeArguments" keeps the "Dxc" prefix because these arguments + //! are specific to DXC, and it will be relevant only if DXC is the "main" compiler + //! for a given RHI, otherwise this parameter won't matter. AZStd::string m_dxcAdditionalFreeArguments; //! both diff --git a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp index ef330e7902..5411e6655e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp @@ -33,17 +33,17 @@ namespace AZ RegisterEnumerators(serializeContext); serializeContext->Class() - ->Version(2) + ->Version(3) ->Field("AzslcWarningLevel", &ShaderCompilerArguments::m_azslcWarningLevel) ->Field("AzslcWarningAsError", &ShaderCompilerArguments::m_azslcWarningAsError) ->Field("AzslcAdditionalFreeArguments", &ShaderCompilerArguments::m_azslcAdditionalFreeArguments) - ->Field("DxcDisableWarnings", &ShaderCompilerArguments::m_dxcDisableWarnings) - ->Field("DxcWarningAsError", &ShaderCompilerArguments::m_dxcWarningAsError) - ->Field("DxcDisableOptimizations", &ShaderCompilerArguments::m_dxcDisableOptimizations) - ->Field("DxcGenerateDebugInfo", &ShaderCompilerArguments::m_dxcGenerateDebugInfo) - ->Field("DxcOptimizationLevel", &ShaderCompilerArguments::m_dxcOptimizationLevel) - ->Field("DxcAdditionalFreeArguments", &ShaderCompilerArguments::m_dxcAdditionalFreeArguments) + ->Field("DisableWarnings", &ShaderCompilerArguments::m_disableWarnings) + ->Field("WarningAsError", &ShaderCompilerArguments::m_warningAsError) + ->Field("DisableOptimizations", &ShaderCompilerArguments::m_disableOptimizations) + ->Field("GenerateDebugInfo", &ShaderCompilerArguments::m_generateDebugInfo) + ->Field("OptimizationLevel", &ShaderCompilerArguments::m_optimizationLevel) ->Field("DefaultMatrixOrder", &ShaderCompilerArguments::m_defaultMatrixOrder) + ->Field("DxcAdditionalFreeArguments", &ShaderCompilerArguments::m_dxcAdditionalFreeArguments) ; } } @@ -62,13 +62,13 @@ namespace AZ } m_azslcWarningAsError = m_azslcWarningAsError || right.m_azslcWarningAsError; m_azslcAdditionalFreeArguments = CommandLineArgumentUtils::MergeCommandLineArguments(m_azslcAdditionalFreeArguments, right.m_azslcAdditionalFreeArguments); - m_dxcDisableWarnings = m_dxcDisableWarnings || right.m_dxcDisableWarnings; - m_dxcWarningAsError = m_dxcWarningAsError || right.m_dxcWarningAsError; - m_dxcDisableOptimizations = m_dxcDisableOptimizations || right.m_dxcDisableOptimizations; - m_dxcGenerateDebugInfo = m_dxcGenerateDebugInfo || right.m_dxcGenerateDebugInfo; - if (right.m_dxcOptimizationLevel != LevelUnset) + m_disableWarnings = m_disableWarnings || right.m_disableWarnings; + m_warningAsError = m_warningAsError || right.m_warningAsError; + m_disableOptimizations = m_disableOptimizations || right.m_disableOptimizations; + m_generateDebugInfo = m_generateDebugInfo || right.m_generateDebugInfo; + if (right.m_optimizationLevel != LevelUnset) { - m_dxcOptimizationLevel = right.m_dxcOptimizationLevel; + m_optimizationLevel = right.m_optimizationLevel; } m_dxcAdditionalFreeArguments = CommandLineArgumentUtils::MergeCommandLineArguments(m_dxcAdditionalFreeArguments, right.m_dxcAdditionalFreeArguments); if (right.m_defaultMatrixOrder != MatrixOrder::Default) @@ -131,21 +131,21 @@ namespace AZ AZStd::string ShaderCompilerArguments::MakeAdditionalDxcCommandLineString() const { AZStd::string arguments; - if (m_dxcDisableWarnings) + if (m_disableWarnings) { arguments += " -no-warnings"; } - else if (m_dxcWarningAsError) + else if (m_warningAsError) { arguments += " -WX"; } - if (m_dxcDisableOptimizations) + if (m_disableOptimizations) { arguments += " -Od"; } - else if (m_dxcOptimizationLevel <= 3) + else if (m_optimizationLevel <= 3) { - arguments = " -O" + AZStd::to_string(m_dxcOptimizationLevel); + arguments = " -O" + AZStd::to_string(m_optimizationLevel); } if (m_defaultMatrixOrder == MatrixOrder::Column) { diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp index f30fc72ace..ee293292e1 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp @@ -114,7 +114,7 @@ namespace AZ } } - if (shaderCompilerArguments.m_dxcDisableOptimizations) + if (shaderCompilerArguments.m_disableOptimizations) { // When optimizations are disabled (-Od), all resources declared in the source file are available to all stages // (when enabled only the resources which are referenced in a stage are bound to the stage) @@ -195,7 +195,7 @@ namespace AZ bool ShaderPlatformInterface::BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return shaderCompilerArguments.m_dxcGenerateDebugInfo; + return shaderCompilerArguments.m_generateDebugInfo; } const char* ShaderPlatformInterface::GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp index 7e41e50892..d43d88a7e1 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp @@ -167,7 +167,7 @@ namespace AZ bool ShaderPlatformInterface::BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return shaderCompilerArguments.m_dxcGenerateDebugInfo; + return shaderCompilerArguments.m_generateDebugInfo; } const char* ShaderPlatformInterface::GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp index 8b99b7b510..c5f1060ca3 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp @@ -109,7 +109,7 @@ namespace AZ bool ShaderPlatformInterface::BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return shaderCompilerArguments.m_dxcGenerateDebugInfo; + return shaderCompilerArguments.m_generateDebugInfo; } const char* ShaderPlatformInterface::GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const diff --git a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.shader b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.shader index 4f1c45d235..6418cc392e 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.shader +++ b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.shader @@ -24,7 +24,7 @@ }, "CompilerHints" : { - "DxcDisableOptimizations" : false + "DisableOptimizations" : false }, "ProgramSettings": diff --git a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.shader b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.shader index 13ba0ce547..f87a56daa2 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.shader +++ b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.shader @@ -24,7 +24,7 @@ }, "CompilerHints" : { - "DxcDisableOptimizations" : false + "DisableOptimizations" : false }, "ProgramSettings": From e4c69a29fa83e0a2dfff2581f5fe0e542cf0e7e1 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 26 Oct 2021 16:45:33 -0700 Subject: [PATCH 30/33] [Linux] Update Qt package to include xcb GL integration plugin (#4976) Fixes #3132. Signed-off-by: Chris Burel --- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 6210b9cc18..af7afff5dc 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -33,7 +33,7 @@ ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-linux ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-linux TARGETS googletest PACKAGE_HASH 7b7ad330f369450c316a4c4592d17fbb4c14c731c95bd8f37757203e8c2bbc1b) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-linux TARGETS GoogleBenchmark PACKAGE_HASH 4038878f337fc7e0274f0230f71851b385b2e0327c495fc3dd3d1c18a807928d) ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux TARGETS unwind PACKAGE_HASH 3453265fb056e25432f611a61546a25f60388e315515ad39007b5925dd054a77) -ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-linux TARGETS Qt PACKAGE_HASH 76b395897b941a173002845c7219a5f8a799e44b269ffefe8091acc048130f28) +ly_associate_package(PACKAGE_NAME qt-5.15.2-rev6-linux TARGETS Qt PACKAGE_HASH a37bd9989f1e8fe57d94b98cbf9bd5c3caaea740e2f314e5162fa77300551531) ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-linux TARGETS libpng PACKAGE_HASH 896451999f1de76375599aec4b34ae0573d8d34620d9ab29cc30b8739c265ba6) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux TARGETS libsamplerate PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc) From a29623e5f0d5d1bd83bcc7fa043f70e4c84e1123 Mon Sep 17 00:00:00 2001 From: moraaar Date: Wed, 27 Oct 2021 13:34:43 +0100 Subject: [PATCH 31/33] Fixed editor crash using cylinder shape component (#5037) Fixed cylinder shape by considering shape config list to be empty. The crash came from clearing shape config list when cylinder height is zero, but when the height is restored to zero it was expecting an element in the list. The code to set the shape configuration was the same for many shape types, so it has been refactored to a helper function. Fixes #4999 --- .../Source/EditorShapeColliderComponent.cpp | 56 ++----------------- .../Source/EditorShapeColliderComponent.h | 32 ++++++++++- .../Tests/ShapeColliderComponentTests.cpp | 40 ++++++++++++- 3 files changed, 73 insertions(+), 55 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index 832145d016..59b659a0bf 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -348,19 +348,7 @@ namespace PhysX LmbrCentral::BoxShapeComponentRequestsBus::EventResult(boxDimensions, GetEntityId(), &LmbrCentral::BoxShapeComponentRequests::GetBoxDimensions); - if (m_shapeType != ShapeType::Box) - { - m_shapeConfigs.clear(); - m_shapeConfigs.emplace_back(AZStd::make_shared(boxDimensions)); - - m_shapeType = ShapeType::Box; - } - else - { - Physics::BoxShapeConfiguration& configuration = - static_cast(*m_shapeConfigs.back()); - configuration = Physics::BoxShapeConfiguration(boxDimensions); - } + SetShapeConfig(ShapeType::Box, Physics::BoxShapeConfiguration(boxDimensions)); m_shapeConfigs.back()->m_scale = scale; m_geometryCache.m_boxDimensions = scale * boxDimensions; @@ -374,19 +362,7 @@ namespace PhysX const Physics::CapsuleShapeConfiguration& capsuleShapeConfig = Utils::ConvertFromLmbrCentralCapsuleConfig(lmbrCentralCapsuleShapeConfig); - if (m_shapeType != ShapeType::Capsule) - { - m_shapeConfigs.clear(); - m_shapeConfigs.emplace_back(AZStd::make_shared(capsuleShapeConfig)); - - m_shapeType = ShapeType::Capsule; - } - else - { - Physics::CapsuleShapeConfiguration& configuration = - static_cast(*m_shapeConfigs.back()); - configuration = capsuleShapeConfig; - } + SetShapeConfig(ShapeType::Capsule, capsuleShapeConfig); m_shapeConfigs.back()->m_scale = scale; const float scalarScale = scale.GetMaxElement(); @@ -400,19 +376,7 @@ namespace PhysX LmbrCentral::SphereShapeComponentRequestsBus::EventResult(radius, GetEntityId(), &LmbrCentral::SphereShapeComponentRequests::GetRadius); - if (m_shapeType != ShapeType::Sphere) - { - m_shapeConfigs.clear(); - m_shapeConfigs.emplace_back(AZStd::make_shared(radius)); - - m_shapeType = ShapeType::Sphere; - } - else - { - Physics::SphereShapeConfiguration& configuration = - static_cast(*m_shapeConfigs.back()); - configuration = Physics::SphereShapeConfiguration(radius); - } + SetShapeConfig(ShapeType::Sphere, Physics::SphereShapeConfiguration(radius)); m_shapeConfigs.back()->m_scale = scale; m_geometryCache.m_radius = scale.GetMaxElement() * radius; @@ -455,19 +419,7 @@ namespace PhysX if (shapeConfig.has_value()) { - if (m_shapeType != ShapeType::Cylinder) - { - m_shapeConfigs.clear(); - m_shapeConfigs.push_back(AZStd::make_shared(shapeConfig.value())); - - m_shapeType = ShapeType::Cylinder; - } - else - { - Physics::CookedMeshShapeConfiguration& configuration = - static_cast(*m_shapeConfigs.back()); - configuration = Physics::CookedMeshShapeConfiguration(shapeConfig.value()); - } + SetShapeConfig(ShapeType::Cylinder, shapeConfig.value()); CreateStaticEditorCollider(); } diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h index 431b34b1ae..3422d4959f 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -90,12 +91,15 @@ namespace PhysX void UpdateBoxConfig(const AZ::Vector3& scale); void UpdateCapsuleConfig(const AZ::Vector3& scale); void UpdateSphereConfig(const AZ::Vector3& scale); + void UpdateCylinderConfig(const AZ::Vector3& scale); void UpdatePolygonPrismDecomposition(); void UpdatePolygonPrismDecomposition(const AZ::PolygonPrismPtr polygonPrismPtr); - void RefreshUiProperties(); + // Helper function to set a specific shape configuration + template + void SetShapeConfig(ShapeType shapeType, const ConfigType& shapeConfig); - void UpdateCylinderConfig(const AZ::Vector3& scale); + void RefreshUiProperties(); AZ::u32 OnSubdivisionCountChange(); AZ::Crc32 SubdivisionCountVisibility(); @@ -154,4 +158,28 @@ namespace PhysX AZ::NonUniformScaleChangedEvent::Handler m_nonUniformScaleChangedHandler; //!< Responds to changes in non-uniform scale. AZ::Vector3 m_currentNonUniformScale = AZ::Vector3::CreateOne(); //!< Caches the current non-uniform scale. }; + + template + void EditorShapeColliderComponent::SetShapeConfig(ShapeType shapeType, const ConfigType& shapeConfig) + { + if (m_shapeType != shapeType) + { + m_shapeConfigs.clear(); + m_shapeType = shapeType; + } + + if (m_shapeConfigs.empty()) + { + m_shapeConfigs.emplace_back(AZStd::make_shared(shapeConfig)); + } + else + { + AZ_Assert(m_shapeConfigs.back()->GetShapeType() == shapeConfig.GetShapeType(), + "Expected Physics shape configuration with shape type %d but found one with shape type %d.", + static_cast(shapeConfig.GetShapeType()), static_cast(m_shapeConfigs.back()->GetShapeType())); + ConfigType& configuration = + static_cast(*m_shapeConfigs.back()); + configuration = shapeConfig; + } + } } // namespace PhysX diff --git a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp index fce427d9d3..06ba4f3e9c 100644 --- a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp +++ b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp @@ -320,7 +320,7 @@ namespace PhysXEditorTests TEST_F(PhysXEditorFixture, EditorShapeColliderComponent_ShapeColliderWithCylinderWithNullHeight_HandledGracefully) { - ValidateInvalidEditorShapeColliderComponentParams(0.f, 1.f); + ValidateInvalidEditorShapeColliderComponentParams(1.f, 0.f); } TEST_F(PhysXEditorFixture, EditorShapeColliderComponent_ShapeColliderWithCylinderWithNullRadiusAndNullHeight_HandledGracefully) @@ -338,6 +338,44 @@ namespace PhysXEditorTests ValidateInvalidEditorShapeColliderComponentParams(0.f, -1.f); } + TEST_F(PhysXEditorFixture, EditorShapeColliderComponent_ShapeColliderWithCylinderSwitchingFromNullHeightToValidHeight_HandledGracefully) + { + // create an editor entity with a shape collider component and a cylinder shape component + EntityPtr editorEntity = CreateInactiveEditorEntity("ShapeColliderComponentEditorEntity"); + editorEntity->CreateComponent(); + editorEntity->CreateComponent(LmbrCentral::EditorCylinderShapeComponentTypeId); + editorEntity->Activate(); + + const float validRadius = 1.0f; + const float nullHeight = 0.0f; + const float validHeight = 1.0f; + + LmbrCentral::CylinderShapeComponentRequestsBus::Event(editorEntity->GetId(), + &LmbrCentral::CylinderShapeComponentRequests::SetRadius, validRadius); + + { + UnitTest::ErrorHandler dimensionWarningHandler("Negative or zero cylinder dimensions are invalid"); + UnitTest::ErrorHandler colliderWarningHandler("No Collider or Shape information found when creating Rigid body"); + + LmbrCentral::CylinderShapeComponentRequestsBus::Event(editorEntity->GetId(), + &LmbrCentral::CylinderShapeComponentRequests::SetHeight, nullHeight); + + EXPECT_EQ(dimensionWarningHandler.GetExpectedWarningCount(), 1); + EXPECT_EQ(colliderWarningHandler.GetExpectedWarningCount(), 1); + } + + { + UnitTest::ErrorHandler dimensionWarningHandler("Negative or zero cylinder dimensions are invalid"); + UnitTest::ErrorHandler colliderWarningHandler("No Collider or Shape information found when creating Rigid body"); + + LmbrCentral::CylinderShapeComponentRequestsBus::Event(editorEntity->GetId(), + &LmbrCentral::CylinderShapeComponentRequests::SetHeight, validHeight); + + EXPECT_EQ(dimensionWarningHandler.GetExpectedWarningCount(), 0); + EXPECT_EQ(colliderWarningHandler.GetExpectedWarningCount(), 0); + } + } + TEST_F(PhysXEditorFixture, EditorShapeColliderComponent_ShapeColliderWithBoxAndRigidBody_CorrectRuntimeComponents) { // create an editor entity with a shape collider component and a box shape component From cf90d7a59466295ada9223751d4f0020a1d6336d Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Wed, 27 Oct 2021 10:05:26 -0500 Subject: [PATCH 32/33] ShaderVariantAssetBuilder: Provide registry property to disable (#5029) The registry property name is: "/O3DE/Atom/Shaders/BuildVariants" Default value is . Signed-off-by: garrieta --- .../AzslShaderBuilderSystemComponent.cpp | 42 +++++++++++++------ .../Editor/AzslShaderBuilderSystemComponent.h | 10 +++++ .../Asset/Shader/Registry/atom_shaders.setreg | 10 +++++ 3 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 Gems/Atom/Asset/Shader/Registry/atom_shaders.setreg diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp index 56f2fdec62..e41c04a0be 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -91,19 +92,31 @@ namespace AZ m_shaderAssetBuilder.BusConnect(shaderAssetBuilderDescriptor.m_busId); AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBus::Handler::RegisterBuilderInformation, shaderAssetBuilderDescriptor); - // Register Shader Variant Asset Builder - AssetBuilderSDK::AssetBuilderDesc shaderVariantAssetBuilderDescriptor; - shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder"; - // Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update - // ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder". - shaderVariantAssetBuilderDescriptor.m_version = 26; // [AZSL] Changing inlineConstant to rootConstant keyword work. - shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); - shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid(); - shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - shaderVariantAssetBuilderDescriptor.m_processJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::ProcessJob, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); + // If, either the SettingsRegistry doesn't exist, or the property @EnableShaderVariantAssetBuilderRegistryKey is not found, + // the default is to enable the ShaderVariantAssetBuilder. + m_enableShaderVariantAssetBuilder = true; + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry) + { + settingsRegistry->Get(m_enableShaderVariantAssetBuilder, EnableShaderVariantAssetBuilderRegistryKey); + } - m_shaderVariantAssetBuilder.BusConnect(shaderVariantAssetBuilderDescriptor.m_busId); - AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBus::Handler::RegisterBuilderInformation, shaderVariantAssetBuilderDescriptor); + if (m_enableShaderVariantAssetBuilder) + { + // Register Shader Variant Asset Builder + AssetBuilderSDK::AssetBuilderDesc shaderVariantAssetBuilderDescriptor; + shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder"; + // Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update + // ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder". + shaderVariantAssetBuilderDescriptor.m_version = 26; // [AZSL] Changing inlineConstant to rootConstant keyword work. + shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); + shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid(); + shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); + shaderVariantAssetBuilderDescriptor.m_processJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::ProcessJob, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); + + m_shaderVariantAssetBuilder.BusConnect(shaderVariantAssetBuilderDescriptor.m_busId); + AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBus::Handler::RegisterBuilderInformation, shaderVariantAssetBuilderDescriptor); + } // Register Precompiled Shader Builder AssetBuilderSDK::AssetBuilderDesc precompiledShaderBuilderDescriptor; @@ -121,7 +134,10 @@ namespace AZ void AzslShaderBuilderSystemComponent::Deactivate() { m_shaderAssetBuilder.BusDisconnect(); - m_shaderVariantAssetBuilder.BusDisconnect(); + if (m_enableShaderVariantAssetBuilder) + { + m_shaderVariantAssetBuilder.BusDisconnect(); + } m_precompiledShaderBuilder.BusDisconnect(); RHI::ShaderPlatformInterfaceRegisterBus::Handler::BusDisconnect(); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.h b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.h index 9ff5bd8282..f502e4c329 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.h @@ -61,7 +61,17 @@ namespace AZ private: ShaderAssetBuilder m_shaderAssetBuilder; + + // The ShaderVariantAssetBuilder can be disabled with this registry key. + // By default it is enabled. A user might want to disable it when doing look development + // work with shaders or doing lots of iterative changes to shaders. In these cases + // GPU performance doesn't matter at all so it is important to not waste time + // building ShaderVariantAssets (Other than the Root ShaderVariantAsset, of course.). + static constexpr char EnableShaderVariantAssetBuilderRegistryKey[] = "/O3DE/Atom/Shaders/BuildVariants"; + bool m_enableShaderVariantAssetBuilder = true; + ShaderVariantAssetBuilder m_shaderVariantAssetBuilder; + PrecompiledShaderBuilder m_precompiledShaderBuilder; /// Contains the ShaderPlatformInterface for all registered RHIs diff --git a/Gems/Atom/Asset/Shader/Registry/atom_shaders.setreg b/Gems/Atom/Asset/Shader/Registry/atom_shaders.setreg new file mode 100644 index 0000000000..31d108f47a --- /dev/null +++ b/Gems/Atom/Asset/Shader/Registry/atom_shaders.setreg @@ -0,0 +1,10 @@ +{ + "O3DE": { + "Atom": { + "Shaders": { + "BuildVariants": true + } + } + } + } +} From 30c366366ed9892fa79a47ec6b7a44dc81cb4dc3 Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Wed, 27 Oct 2021 09:56:30 -0700 Subject: [PATCH 33/33] Improve gamelift unit test by checking handler invocation (#5030) Signed-off-by: onecent1101 --- .../Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp index be72de555e..bc147fe7f6 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp @@ -108,7 +108,7 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithoutClientSe MatchmakingNotificationsHandlerMock matchmakingHandlerMock; AZ_TEST_START_TRACE_SUPPRESSION; m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); - WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; }); + WaitForProcessFinish([&](){ return matchmakingHandlerMock.m_numMatchError == 1; }); AZ_TEST_STOP_TRACE_SUPPRESSION(1); ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1); ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle()); @@ -122,7 +122,7 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_MultipleCallsWithou AZ_TEST_START_TRACE_SUPPRESSION; m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); - WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; }); + WaitForProcessFinish([&](){ return matchmakingHandlerMock.m_numMatchError == 1; }); AZ_TEST_STOP_TRACE_SUPPRESSION(1); ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1); ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle()); @@ -140,7 +140,7 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButWithFailedOu MatchmakingNotificationsHandlerMock matchmakingHandlerMock; AZ_TEST_START_TRACE_SUPPRESSION; m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); - WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; }); + WaitForProcessFinish([&](){ return matchmakingHandlerMock.m_numMatchError == 1; }); AZ_TEST_STOP_TRACE_SUPPRESSION(1); ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1); ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle()); @@ -160,7 +160,7 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithMoreThanOne MatchmakingNotificationsHandlerMock matchmakingHandlerMock; AZ_TEST_START_TRACE_SUPPRESSION; m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); - WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; }); + WaitForProcessFinish([&](){ return matchmakingHandlerMock.m_numMatchError == 1; }); AZ_TEST_STOP_TRACE_SUPPRESSION(1); ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1); ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle());