diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index ed2d8a1d9f..a9bb7271ab 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include 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 e7b9825ecb..be7ac9e7a4 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 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ namespace AZ struct PassRequest; struct PassValidationResults; class AttachmentReadback; + class ImageAttachmentCopy; using SortedPipelineViewTags = AZStd::set; using PassesByDrawList = AZStd::map; @@ -94,6 +96,8 @@ namespace AZ { AZ_RPI_PASS(Pass); + friend class ImageAttachmentPreviewPass; + public: using ChildPassIndex = RHI::Handle; @@ -369,6 +373,9 @@ namespace AZ void UpdateReadbackAttachment(FramePrepareParams params, bool beforeAddScopes); + // Setup ImageAttachmentCopy + void UpdateAttachmentCopy(FramePrepareParams params); + // --- Protected Members --- const Name PassNameThis{"This"}; @@ -466,6 +473,9 @@ namespace AZ AZStd::shared_ptr m_attachmentReadback; PassAttachmentReadbackOption m_readbackOption; + // For image attachment preview + AZStd::weak_ptr m_attachmentCopy; + private: // Return the Timestamp result of this pass virtual TimestampResult GetTimestampResultInternal() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h index 5fb90d044e..ec51e34897 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h @@ -13,9 +13,7 @@ #include #include -#include #include -#include #include namespace AZ @@ -29,7 +27,6 @@ namespace AZ namespace RPI { - class ImageAttachmentCopy; class RenderPass; class Query; @@ -41,8 +38,6 @@ namespace AZ { AZ_RPI_PASS(RenderPass); - friend class ImageAttachmentPreviewPass; - using ScopeQuery = AZStd::array, static_cast(ScopeQueryType::Count)>; public: @@ -143,8 +138,6 @@ namespace AZ // Readback the results from the ScopeQueries void ReadbackScopeQueryResults(); - AZStd::weak_ptr m_attachmentCopy; - // Readback results from the Timestamp queries TimestampResult m_timestampResult; // Readback results from the PipelineStatistics queries diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h index 2e2b14a699..8ee7a44b6f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h @@ -78,7 +78,7 @@ namespace AZ ~ImageAttachmentPreviewPass(); //! Preview the PassAttachment of a pass' PassAttachmentBinding - void PreviewImageAttachmentForPass(RenderPass* pass, const PassAttachment* passAttachment); + void PreviewImageAttachmentForPass(Pass* pass, const PassAttachment* passAttachment); //! Set the output color attachment for this pass void SetOutputColorAttachment(RHI::Ptr outputImageAttachment); 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 3c1de28d6a..d04a35a10b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1215,6 +1216,12 @@ namespace AZ m_queueState = PassQueueState::NoQueue; InitializeInternal(); + + // Need to recreate the dest attachment because the source attachment might be changed + if (!m_attachmentCopy.expired()) + { + m_attachmentCopy.lock()->InvalidateDestImage(); + } m_state = PassState::Initialized; } @@ -1301,6 +1308,9 @@ namespace AZ // readback attachment with output state UpdateReadbackAttachment(params, false); + // update attachment copy for preview + UpdateAttachmentCopy(params); + UpdateConnectedOutputBindings(); } @@ -1489,6 +1499,14 @@ namespace AZ } } + void Pass::UpdateAttachmentCopy(FramePrepareParams params) + { + if (!m_attachmentCopy.expired()) + { + m_attachmentCopy.lock()->FrameBegin(params); + } + } + bool Pass::IsTimestampQueryEnabled() const { return m_flags.m_timestampQueryEnabled; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index b8115dff10..8353762c0f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -177,12 +177,6 @@ namespace AZ } } } - - // Need to recreate the dest attachment because the source attachment might be changed - if (!m_attachmentCopy.expired()) - { - m_attachmentCopy.lock()->InvalidateDestImage(); - } } void RenderPass::FrameBeginInternal(FramePrepareParams params) @@ -196,11 +190,7 @@ namespace AZ // Read back the ScopeQueries submitted from previous frames ReadbackScopeQueryResults(); - - if (!m_attachmentCopy.expired()) - { - m_attachmentCopy.lock()->FrameBegin(params); - } + CollectSrgs(); PassSystemInterface::Get()->IncrementFrameRenderPassCount(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp index 105936f64d..8f83e4efe1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -131,7 +131,7 @@ namespace AZ Data::AssetBus::Handler::BusDisconnect(); } - void ImageAttachmentPreviewPass::PreviewImageAttachmentForPass(RenderPass* pass, const PassAttachment* passAttachment) + void ImageAttachmentPreviewPass::PreviewImageAttachmentForPass(Pass* pass, const PassAttachment* passAttachment) { if (passAttachment->GetAttachmentType() != RHI::AttachmentType::Image) { diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h index 12e9776ae2..0e942bca58 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.h @@ -39,6 +39,8 @@ namespace AZ bool m_showAttachments = false; AZ::RPI::Pass* m_selectedPass = nullptr; + AZ::RPI::Pass* m_lastSelectedPass = nullptr; + AZ::Name m_selectedPassPath; AZ::RHI::AttachmentId m_attachmentId; AZ::Name m_slotName; bool m_selectedChanged = false; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl index fa649ed47b..55e457926a 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl @@ -31,7 +31,7 @@ namespace AZ::Render { - inline AZ::RPI::PassAttachment* FindPassAttachment(AZ::RPI::RenderPass* pass, AZ::RHI::AttachmentId attachmentId) + inline AZ::RPI::PassAttachment* FindPassAttachment(AZ::RPI::Pass* pass, AZ::RHI::AttachmentId attachmentId) { for (auto& binding : pass->GetAttachmentBindings()) { @@ -47,6 +47,10 @@ namespace AZ::Render { using namespace AZ; + // always set m_selectedPass to empty and use m_selectedPassPath to find it when render the pass tree + m_selectedPass = nullptr; + bool needSaveAttachment = false; + ImGui::SetNextWindowSize(ImVec2(200.f, 200.f), ImGuiCond_FirstUseEver); if (ImGui::Begin("PassTree View", &draw, ImGuiWindowFlags_None)) { @@ -83,60 +87,16 @@ namespace AZ::Render if (Scriptable_ImGui::Button("Save Attachment")) { - m_attachmentReadbackInfo = ""; - if (!m_readback) - { - m_readback = AZStd::make_shared(AZ::RHI::ScopeId{ "AttachmentReadback" }); - m_readback->SetCallback(AZStd::bind(&ImGuiPassTree::ReadbackCallback, this, AZStd::placeholders::_1)); - } - - if (m_selectedPass && !m_slotName.IsEmpty()) - { - bool readbackResult = m_selectedPass->ReadbackAttachment(m_readback, m_slotName); - if (!readbackResult) - { - AZ_Error("ImGuiPassTree", false, "Failed to readback attachment from pass [%s] slot [%s]", m_selectedPass->GetName().GetCStr(), m_slotName.GetCStr()); - } - } + needSaveAttachment = true; } ImGui::TextWrapped("%s", m_attachmentReadbackInfo.c_str()); } - if (m_previewAttachment && m_selectedChanged) - { - m_selectedChanged = false; - if (!m_attachmentId.IsEmpty() && m_selectedPass) - { - AZ::RPI::RenderPass* renderPass = azrtti_cast(m_selectedPass); - if (renderPass) - { - if (!m_previewPass->GetParent()) - { - RPI::PassSystemInterface::Get()->GetRootPass()->AddChild(m_previewPass); - } - AZ::RPI::PassAttachment* attachment = FindPassAttachment(renderPass, m_attachmentId); - if (attachment) - { - // Reset output attachment to empty so the preview will use pass's owner render pipeline's output - m_previewPass->SetOutputColorAttachment(nullptr); - m_previewPass->PreviewImageAttachmentForPass(renderPass, attachment); - } - } - else - { - m_previewPass->ClearPreviewAttachment(); - if (m_previewPass->GetParent()) - { - m_previewPass->QueueForRemoval(); - } - } - } - } - ImGui::End(); // Draw the hierarchical view + // It will assign m_seletedPass if there is a pass matches m_seletedPassPath ImGui::SetNextWindowPos(ImVec2(300, 60), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(300, 500), ImGuiCond_FirstUseEver); if (ImGui::Begin("PassTree", nullptr, ImGuiWindowFlags_None)) @@ -144,6 +104,63 @@ namespace AZ::Render DrawTreeView(rootPass); } ImGui::End(); + + // It's possible that the pass pointer changed but selected pass path wasn't changed + if (m_selectedPass != m_lastSelectedPass) + { + m_selectedChanged = true; + if (m_selectedPass == nullptr) + { + m_selectedPassPath = AZ::Name{}; + } + } + m_lastSelectedPass = m_selectedPass; + + if (m_previewAttachment && m_selectedChanged) + { + m_selectedChanged = false; + if (!m_attachmentId.IsEmpty() && m_selectedPass) + { + if (!m_previewPass->GetParent()) + { + RPI::PassSystemInterface::Get()->GetRootPass()->AddChild(m_previewPass); + } + AZ::RPI::PassAttachment* attachment = FindPassAttachment(m_selectedPass, m_attachmentId); + if (attachment) + { + // Reset output attachment to empty so the preview will use pass's owner render pipeline's output + m_previewPass->SetOutputColorAttachment(nullptr); + m_previewPass->PreviewImageAttachmentForPass(m_selectedPass, attachment); + } + } + else + { + m_previewPass->ClearPreviewAttachment(); + if (m_previewPass->GetParent()) + { + m_previewPass->QueueForRemoval(); + } + } + } + + if (needSaveAttachment) + { + m_attachmentReadbackInfo = ""; + if (!m_readback) + { + m_readback = AZStd::make_shared(AZ::RHI::ScopeId{ "AttachmentReadback" }); + m_readback->SetCallback(AZStd::bind(&ImGuiPassTree::ReadbackCallback, this, AZStd::placeholders::_1)); + } + + if (m_selectedPass && !m_slotName.IsEmpty()) + { + bool readbackResult = m_selectedPass->ReadbackAttachment(m_readback, m_slotName); + if (!readbackResult) + { + AZ_Error("ImGuiPassTree", false, "Failed to readback attachment from pass [%s] slot [%s]", m_selectedPass->GetName().GetCStr(), m_slotName.GetCStr()); + } + } + } } inline void ImGuiPassTree::DrawPassAttachments(AZ::RPI::Pass* pass) @@ -202,6 +219,7 @@ namespace AZ::Render if (Scriptable_ImGui::Selectable(label.c_str(), m_attachmentId == binding.m_attachment->GetAttachmentId())) { + m_selectedPassPath = pass->GetPathName(); m_selectedPass = pass; m_attachmentId = binding.m_attachment->GetAttachmentId(); m_slotName = binding.m_name; @@ -232,9 +250,9 @@ namespace AZ::Render if (!m_showAttachments) { // Only draw the leaf pass as selectable if we are not showing attachments as its children - if (Scriptable_ImGui::Selectable(pass->GetName().GetCStr(), m_selectedPass == pass)) + if (Scriptable_ImGui::Selectable(pass->GetName().GetCStr(), m_selectedPassPath == pass->GetPathName())) { - m_selectedPass = pass; + m_selectedPassPath = pass->GetPathName(); m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = true; @@ -244,13 +262,13 @@ namespace AZ::Render { // Draw the pass as a tree node which has attachments as its children ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_DefaultOpen - | ((m_selectedPass == pass) ? ImGuiTreeNodeFlags_Selected : 0); + | ((m_selectedPassPath == pass->GetPathName()) ? ImGuiTreeNodeFlags_Selected : 0); bool nodeOpen = Scriptable_ImGui::TreeNodeEx(pass->GetName().GetCStr(), flags); if (ImGui::IsItemClicked()) { - m_selectedPass = pass; + m_selectedPassPath = pass->GetPathName(); m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = true; @@ -259,7 +277,6 @@ namespace AZ::Render if (nodeOpen) { DrawPassAttachments(pass); - Scriptable_ImGui::TreePop(); } } @@ -268,13 +285,13 @@ namespace AZ::Render { // For a ParentPasse, draw it as a tree node ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_DefaultOpen - | ((m_selectedPass == pass) ? ImGuiTreeNodeFlags_Selected : 0); + | ((m_selectedPassPath == pass->GetPathName()) ? ImGuiTreeNodeFlags_Selected : 0); bool nodeOpen = ImGui::TreeNodeEx(pass->GetName().GetCStr(), flags); if (ImGui::IsItemClicked()) { - m_selectedPass = pass; + m_selectedPassPath = pass->GetPathName(); m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = true; @@ -282,7 +299,10 @@ namespace AZ::Render if (nodeOpen) { - DrawPassAttachments(pass); + if (m_showAttachments) + { + DrawPassAttachments(pass); + } for (const auto& child : asParent->GetChildren()) { DrawTreeView(child.get()); @@ -296,6 +316,12 @@ namespace AZ::Render { ImGui::PopStyleColor(); } + + // set m_selectedPass if pass path matches + if (pass->GetPathName() == m_selectedPassPath) + { + m_selectedPass = pass; + } } inline void ImGuiPassTree::ReadbackCallback(const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) @@ -364,7 +390,9 @@ namespace AZ::Render m_previewAttachment = false; m_showAttachments = false; + m_selectedPassPath = AZ::Name{}; m_selectedPass = nullptr; + m_lastSelectedPass = nullptr; m_attachmentId = AZ::RHI::AttachmentId{}; m_slotName = AZ::Name{}; m_selectedChanged = false;