diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ConstantsLayout.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ConstantsLayout.h index ea9ef23af0..653e8e4474 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ConstantsLayout.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ConstantsLayout.h @@ -82,6 +82,10 @@ namespace AZ //! If validation is disabled, true is always returned. bool ValidateAccess(ShaderInputConstantIndex inputIndex) const; + //! Prints to the console the shader input names specified by input list of indices + //! Will ignore any indices outside of the inputs array bounds + void DebugPrintNames(AZStd::array_view constantList) const; + protected: ConstantsLayout() = default; @@ -95,7 +99,6 @@ namespace AZ AZStd::vector m_inputs; IdReflectionMapForConstants m_idReflection; - AZStd::vector m_intervals; uint32_t m_sizeInBytes = 0; HashValue64 m_hash = InvalidHash; }; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/NameIdReflectionMap.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/NameIdReflectionMap.h index 7467c4d6b4..0dc0b30181 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/NameIdReflectionMap.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/NameIdReflectionMap.h @@ -69,6 +69,9 @@ namespace AZ /// Return the number of entries size_t Size() const; + // Returns true if size is zero + bool IsEmpty() const; + class NameIdReflectionMapSerializationEvents : public SerializeContext::IEventHandler { @@ -169,6 +172,12 @@ namespace AZ return m_reflectionMap.size(); } + template + bool NameIdReflectionMap::IsEmpty() const + { + return Size() == 0; + } + template void NameIdReflectionMap::Sort() { diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ConstantsData.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ConstantsData.h index dc5fb80435..ff1158e455 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ConstantsData.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ConstantsData.h @@ -85,6 +85,14 @@ namespace AZ //! Returns the constants layout. const ConstantsLayout* GetLayout() const; + //! Returns whether other constant data and this have the same value at the specified shader input index + bool ConstantIsEqual(const ConstantsData& other, ShaderInputConstantIndex inputIndex) const; + + //! Performs a diff between this and input constant data and returns a list of all the shader input indices + //! for which the constants are not the same between the two. If one of the two has more constants than the + //! other, these additional constants will be added to the end of the returned list. + AZStd::vector GetIndicesOfDifferingConstants(const ConstantsData& other) const; + private: enum class ValidateConstantAccessExpect : uint32_t { diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h index 5fe645be82..0ce43159f6 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h @@ -173,6 +173,9 @@ namespace AZ //! Different platforms might follow different packing rules for the internally-managed SRG constant buffer. AZStd::array_view GetConstantData() const; + //! Returns the underlying ConstantsData struct + const ConstantsData& GetConstantsData() const; + //! Returns the shader resource layout for this group. const ShaderResourceGroupLayout* GetLayout() const; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupDebug.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupDebug.h new file mode 100644 index 0000000000..d9ea77d823 --- /dev/null +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupDebug.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +namespace AZ +{ + namespace RHI + { + class ConstantsData; + struct DrawItem; + class ShaderResourceGroup; + + /// Given a ShaderResourceGroup and a reference ConstantsData input, this function will fetch the ConstantsData on the SRG and compare it + /// to the reference ConstantsData. It will print the names of any constants that are different between the two. + /// The parameter updateReferenceData can be used to set the reference data to the SRG's constant data after the comparison. This is + /// useful for keeping track of differences in between calls to the function, such as between frames. + void PrintConstantDataDiff(const ShaderResourceGroup& shaderResourceGroup, ConstantsData& referenceData, bool updateReferenceData = false); + + /// Given a DrawItem, an SRG binding slot on that draw item and a reference ConstantsData input, this function will fetch the ConstantsData + /// from the draw item's SRG at the binding slot and compare it to the reference ConstantsData. It will print the names of any constants + /// that are different between the two. + /// The parameter updateReferenceData can be used to set the reference data to the draw item's constant data after the comparison. This is + /// useful for keeping track of differences in between calls to the function, such as between frames. + void PrintConstantDataDiff(const DrawItem& drawItem, ConstantsData& referenceData, uint32_t srgBindingSlot, bool updateReferenceData = false); + + } +} diff --git a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ConstantsLayout.cpp b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ConstantsLayout.cpp index 956cc5be10..8be053e4ef 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ConstantsLayout.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ConstantsLayout.cpp @@ -18,10 +18,9 @@ namespace AZ if (SerializeContext* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) // Version 1: Adding debug helper functions to Shader Resource Groups ->Field("m_inputs", &ConstantsLayout::m_inputs) ->Field("m_idReflection", &ConstantsLayout::m_idReflection) - ->Field("m_intervals", &ConstantsLayout::m_intervals) ->Field("m_sizeInBytes", &ConstantsLayout::m_sizeInBytes) ->Field("m_hash", &ConstantsLayout::m_hash); } @@ -43,7 +42,6 @@ namespace AZ { m_inputs.clear(); m_idReflection.Clear(); - m_intervals.clear(); m_sizeInBytes = 0; m_hash = InvalidHash; } @@ -67,11 +65,8 @@ namespace AZ return false; } - // The constant data size is the maximum offset + size from the start of the struct. - constantDataSize = AZStd::max(constantDataSize, constantDescriptor.m_constantByteOffset + constantDescriptor.m_constantByteCount); - - // Add the [min, max) interval for the inline constant. - m_intervals.emplace_back(constantDescriptor.m_constantByteOffset, constantDescriptor.m_constantByteOffset + constantDescriptor.m_constantByteCount); + uint32_t end = constantDescriptor.m_constantByteOffset + constantDescriptor.m_constantByteCount; + constantDataSize = AZStd::max(constantDataSize, end); ++constantInputIndex; m_hash = TypeHash64(constantDescriptor.GetHash(), m_hash); @@ -100,7 +95,10 @@ namespace AZ Interval ConstantsLayout::GetInterval(ShaderInputConstantIndex inputIndex) const { - return m_intervals[inputIndex.GetIndex()]; + const ShaderInputConstantDescriptor& desc = GetShaderInput(inputIndex); + uint32_t start = desc.m_constantByteOffset; + uint32_t end = start + desc.m_constantByteCount; + return Interval(start, end); } const ShaderInputConstantDescriptor& ConstantsLayout::GetShaderInput(ShaderInputConstantIndex inputIndex) const @@ -139,8 +137,8 @@ namespace AZ { if (!m_sizeInBytes) { - AZ_Assert(m_intervals.empty(), "Constants size is not valid."); - return m_intervals.empty(); + AZ_Assert(m_idReflection.IsEmpty(), "Constants size is not valid."); + return m_idReflection.IsEmpty(); } } @@ -149,5 +147,20 @@ namespace AZ return true; } + + void ConstantsLayout::DebugPrintNames(AZStd::array_view constantList) const + { + AZStd::string output; + for (const ShaderInputConstantIndex& constantIdx : constantList) + { + if (constantIdx.GetIndex() < m_inputs.size()) + { + output += m_inputs[constantIdx.GetIndex()].m_name.GetCStr(); + output += " - "; + } + } + AZ_Printf("RHI", output.c_str()); + } + } } diff --git a/Gems/Atom/RHI/Code/Source/RHI/ConstantsData.cpp b/Gems/Atom/RHI/Code/Source/RHI/ConstantsData.cpp index 9144265a6d..1524883e54 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ConstantsData.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ConstantsData.cpp @@ -405,5 +405,71 @@ namespace AZ AZ_Assert(m_layout, "Constants layout is null"); return m_layout.get(); } + + bool ConstantsData::ConstantIsEqual(const ConstantsData& other, ShaderInputConstantIndex inputIndex) const + { + AZStd::array_view myConstant = GetConstantRaw(inputIndex); + AZStd::array_view otherConstant = other.GetConstantRaw(inputIndex); + + // If they point to the same data, they are equal + if (myConstant == otherConstant) + { + return true; + } + + // If they point to data of different size, they are not equal + if (myConstant.size() != otherConstant.size()) + { + return false; + } + + // If they point to differing data of same size, compare the data + // Note: due to small size of data this loop will be faster than a mem compare + for(uint32_t i = 0; i < myConstant.size(); ++i) + { + if (myConstant[i] != otherConstant[i]) + { + return false; + } + } + + // Arrays point to different locations in memory but all bytes match, return true + return true; + } + + AZStd::vector ConstantsData::GetIndicesOfDifferingConstants(const ConstantsData& other) const + { + AZStd::vector differingIndices; + + if (m_layout == nullptr || other.m_layout == nullptr) + { + return differingIndices; + } + + AZStd::array_view myShaderInputs = m_layout->GetShaderInputList(); + AZStd::array_view otherShaderInputs = other.m_layout->GetShaderInputList(); + + size_t minSize = AZStd::min(myShaderInputs.size(), otherShaderInputs.size()); + size_t maxSize = AZStd::max(myShaderInputs.size(), otherShaderInputs.size()); + + for (size_t idx = 0; idx < minSize; ++idx) + { + const ShaderInputConstantIndex inputIndex(idx); + if (!ConstantIsEqual(other, inputIndex)) + { + differingIndices.push_back(inputIndex); + } + } + + // If sizes are different, add difference at the end + for (size_t idx = minSize; idx < maxSize; ++idx) + { + const ShaderInputConstantIndex inputIndex(idx); + differingIndices.push_back(inputIndex); + } + + return differingIndices; + } + } } diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp index a9e08249c4..da7697d8f2 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp @@ -335,5 +335,10 @@ namespace AZ return m_constantsData.GetConstantData(); } + const ConstantsData& ShaderResourceGroupData::GetConstantsData() const + { + return m_constantsData; + } + } // namespace RHI } // namespace AZ diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupDebug.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupDebug.cpp new file mode 100644 index 0000000000..54399eba88 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupDebug.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AZ +{ + namespace RHI + { + + void PrintConstantDataDiff(const ShaderResourceGroup& shaderResourceGroup, ConstantsData& referenceData, bool updateReferenceData) + { + const RHI::ConstantsData& currentData = shaderResourceGroup.GetData().GetConstantsData(); + + AZStd::vector differingIndices = currentData.GetIndicesOfDifferingConstants(referenceData); + + if (differingIndices.size() > 0) + { + AZ_Printf("RHI", "Detected different SRG values for the following fields:\n"); + if (currentData.GetLayout()) + { + currentData.GetLayout()->DebugPrintNames(differingIndices); + } + } + + if (updateReferenceData) + { + referenceData = currentData; + } + } + + void PrintConstantDataDiff(const DrawItem& drawItem, ConstantsData& referenceData, uint32_t srgBindingSlot, bool updateReferenceData) + { + int srgIndex = -1; + for (uint32_t i = 0; i < drawItem.m_shaderResourceGroupCount; ++i) + { + if (drawItem.m_shaderResourceGroups[i]->GetBindingSlot() == srgBindingSlot) + { + srgIndex = i; + break; + } + } + + if (srgIndex != -1) + { + const ShaderResourceGroup& srg = *drawItem.m_shaderResourceGroups[srgIndex]; + PrintConstantDataDiff(srg, referenceData, updateReferenceData); + } + } + + } +} diff --git a/Gems/Atom/RHI/Code/atom_rhi_public_files.cmake b/Gems/Atom/RHI/Code/atom_rhi_public_files.cmake index a8c98c6674..338bae6386 100644 --- a/Gems/Atom/RHI/Code/atom_rhi_public_files.cmake +++ b/Gems/Atom/RHI/Code/atom_rhi_public_files.cmake @@ -157,10 +157,12 @@ set(FILES Source/RHI/ScopeAttachment.cpp Include/Atom/RHI/ShaderResourceGroup.h Include/Atom/RHI/ShaderResourceGroupData.h + Include/Atom/RHI/ShaderResourceGroupDebug.h Include/Atom/RHI/ShaderResourceGroupInvalidateRegistry.h Include/Atom/RHI/ShaderResourceGroupPool.h Source/RHI/ShaderResourceGroup.cpp Source/RHI/ShaderResourceGroupData.cpp + Source/RHI/ShaderResourceGroupDebug.cpp Source/RHI/ShaderResourceGroupInvalidateRegistry.cpp Source/RHI/ShaderResourceGroupPool.cpp Include/Atom/RHI/MemoryStatisticsBuilder.h 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 227fcb41d3..30fa27e64b 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 @@ -75,6 +75,12 @@ namespace AZ const AZ::Name& GetTargetedPassDebuggingName() const override; void ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) override; PassSystemState GetState() const override; + SwapChainPass* FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const override; + + // PassSystemInterface statistics related functions + void IncrementFrameDrawItemCount(u32 numDrawItems) override; + void IncrementFrameRenderPassCount() override; + PassSystemFrameStatistics GetFrameStatistics() override; // PassSystemInterface factory related functions... void AddPassCreator(Name className, PassCreator createFunction) override; @@ -93,7 +99,6 @@ namespace AZ void RegisterPass(Pass* pass) override; void UnregisterPass(Pass* pass) override; AZStd::vector FindPasses(const PassFilter& passFilter) const override; - SwapChainPass* FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const override; private: // Returns the root of the pass tree hierarchy @@ -116,6 +121,9 @@ namespace AZ void QueueForRemoval(Pass* pass) override; void QueueForInitialization(Pass* pass) override; + // Resets the frame statistic counters + void ResetFrameStatistics(); + // Lists for queuing passes for various function calls // Name of the list reflects the pass function it will call AZStd::vector< Ptr > m_buildPassList; @@ -141,13 +149,16 @@ namespace AZ AZ::Name m_targetedPassDebugName; // Counts the number of passes - int32_t m_passCounter = 0; + u32 m_passCounter = 0; // Events OnReadyLoadTemplatesEvent m_loadTemplatesEvent; // Used to track what phase of execution the pass system is in PassSystemState m_state = PassSystemState::Unitialized; + + // Counters used to gather statistics about the frame + PassSystemFrameStatistics m_frameStatistics; }; } // namespace RPI } // namespace AZ 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 2e51bc7bae..0e9386f3bb 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 @@ -67,6 +67,14 @@ namespace AZ FrameEnd, }; + //! Frame counters used for collecting statistics + struct PassSystemFrameStatistics + { + u32 m_numRenderPassesExecuted = 0; + u32 m_totalDrawItemsRendered = 0; + u32 m_maxDrawItemsRenderedInAPass = 0; + }; + class PassSystemInterface { friend class Pass; @@ -116,6 +124,27 @@ namespace AZ virtual void SetTargetedPassDebuggingName(const AZ::Name& targetPassName) = 0; virtual const AZ::Name& GetTargetedPassDebuggingName() const = 0; + //! Find the SwapChainPass associated with window Handle + virtual SwapChainPass* FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const = 0; + + using OnReadyLoadTemplatesEvent = AZ::Event<>; + //! Connect a handler to listen to the event that the pass system is ready to load pass templates + //! The event is triggered when pass system is initialized and asset system is ready. + //! The handler can add new pass templates or load pass template mappings from assets + virtual void ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) = 0; + + virtual PassSystemState GetState() const = 0; + + // Passes call this function to notify the pass system that they are drawing X draw items this frame + // Used for Pass System statistics + virtual void IncrementFrameDrawItemCount(u32 numDrawItems) = 0; + + // Increments the counter for the number of render passes executed this frame (does not include passes that are disabled) + virtual void IncrementFrameRenderPassCount() = 0; + + // Get frame statistics from the Pass System + virtual PassSystemFrameStatistics GetFrameStatistics() = 0; + // --- Pass Factory related functionality --- //! Directly creates a pass given a PassDescriptor @@ -172,17 +201,6 @@ namespace AZ //! Find matching passes from registered passes with specified filter virtual AZStd::vector FindPasses(const PassFilter& passFilter) const = 0; - //! Find the SwapChainPass associated with window Handle - virtual SwapChainPass* FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const = 0; - - using OnReadyLoadTemplatesEvent = AZ::Event<>; - //! Connect a handler to listen to the event that the pass system is ready to load pass templates - //! The event is triggered when pass system is initialized and asset system is ready. - //! The handler can add new pass templates or load pass template mappings from assets - virtual void ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) = 0; - - virtual PassSystemState GetState() const = 0; - private: // These functions are only meant to be used by the Pass class @@ -200,7 +218,6 @@ namespace AZ //! Unregisters the pass with the pass library. Called in the Pass destructor. virtual void UnregisterPass(Pass* pass) = 0; - }; namespace PassSystemEvents diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RasterPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RasterPass.h index 847fe36bd0..2c884ceedf 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RasterPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RasterPass.h @@ -38,11 +38,13 @@ namespace AZ void SetDrawListTag(Name drawListName); - void SetPipelineStateDataIndex(u32 index); + void SetPipelineStateDataIndex(uint32_t index); //! Expose shader resource group. ShaderResourceGroup* GetShaderResourceGroup(); + uint32_t GetDrawItemCount(); + protected: explicit RasterPass(const PassDescriptor& descriptor); @@ -76,6 +78,7 @@ namespace AZ RHI::Viewport m_viewportState; bool m_overrideScissorSate = false; bool m_overrideViewportState = false; + uint32_t m_drawItemCount = 0; }; } // 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 27e3612a4c..d73521763f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -310,6 +310,7 @@ namespace AZ AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: FrameUpdate"); + ResetFrameStatistics(); ProcessQueuedChanges(); m_state = PassSystemState::Rendering; @@ -398,6 +399,29 @@ namespace AZ handler.Connect(m_loadTemplatesEvent); } + void PassSystem::ResetFrameStatistics() + { + m_frameStatistics.m_numRenderPassesExecuted = 0; + m_frameStatistics.m_totalDrawItemsRendered = 0; + m_frameStatistics.m_maxDrawItemsRenderedInAPass = 0; + } + + PassSystemFrameStatistics PassSystem::GetFrameStatistics() + { + return m_frameStatistics; + } + + void PassSystem::IncrementFrameDrawItemCount(u32 numDrawItems) + { + m_frameStatistics.m_totalDrawItemsRendered += numDrawItems; + m_frameStatistics.m_maxDrawItemsRenderedInAPass = AZStd::max(m_frameStatistics.m_maxDrawItemsRenderedInAPass, numDrawItems); + } + + void PassSystem::IncrementFrameRenderPassCount() + { + ++m_frameStatistics.m_numRenderPassesExecuted; + } + // --- Pass Factory Functions --- void PassSystem::AddPassCreator(Name className, PassCreator createFunction) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp index 8890499cb7..ce02e1c570 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp @@ -104,7 +104,7 @@ namespace AZ m_flags.m_hasDrawListTag = true; } - void RasterPass::SetPipelineStateDataIndex(u32 index) + void RasterPass::SetPipelineStateDataIndex(uint32_t index) { m_pipelineStateDataIndex.m_index = index; } @@ -114,6 +114,11 @@ namespace AZ return m_shaderResourceGroup.get(); } + uint32_t RasterPass::GetDrawItemCount() + { + return m_drawItemCount; + } + // --- Pass behaviour overrides --- void RasterPass::Validate(PassValidationResults& validationResults) @@ -154,17 +159,21 @@ namespace AZ // Assert the view has our draw list (the view's DrawlistTags are collected from passes using its viewTag) AZ_Assert(view->HasDrawListTag(m_drawListTag), "View's DrawListTags out of sync with pass'. "); + // Draw List viewDrawList = view->GetDrawList(m_drawListTag); } // clean up data m_drawListView = {}; m_combinedDrawList.clear(); + m_drawItemCount = 0; // draw list from view was sorted and if it's the only draw list then we can use it directly if (viewDrawList.size() > 0 && drawLists.size() == 0) { m_drawListView = viewDrawList; + m_drawItemCount += static_cast(viewDrawList.size()); + PassSystemInterface::Get()->IncrementFrameDrawItemCount(m_drawItemCount); return; } @@ -172,12 +181,12 @@ namespace AZ drawLists.push_back(viewDrawList); // combine draw items from mutiple draw lists to one draw list and sort it. - size_t itemCount = 0; for (auto drawList : drawLists) { - itemCount += drawList.size(); + m_drawItemCount += static_cast(drawList.size()); } - m_combinedDrawList.resize(itemCount); + PassSystemInterface::Get()->IncrementFrameDrawItemCount(m_drawItemCount); + m_combinedDrawList.resize(m_drawItemCount); RHI::DrawItemProperties* currentBuffer = m_combinedDrawList.data(); for (auto drawList : drawLists) { @@ -202,7 +211,7 @@ namespace AZ void RasterPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) { RenderPass::SetupFrameGraphDependencies(frameGraph); - frameGraph.SetEstimatedItemCount(static_cast(m_drawListView.size())); + frameGraph.SetEstimatedItemCount(static_cast(m_drawListView.size())); } void RasterPass::CompileResources(const RHI::FrameGraphCompileContext& context) 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 913f83254e..9b182a3c4b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -201,6 +201,8 @@ namespace AZ m_attachmentCopy.lock()->FrameBegin(params); } CollectSrgs(); + + PassSystemInterface::Get()->IncrementFrameRenderPassCount(); } diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index 3e622e8994..40c4f8e48f 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -230,25 +230,20 @@ namespace AZ::Render AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); auto rootPass = viewportContext->GetCurrentPipeline()->GetRootPass(); const RPI::PipelineStatisticsResult stats = rootPass->GetLatestPipelineStatisticsResult(); - AZStd::function)> containingPassCount = [&containingPassCount](const AZ::RPI::Ptr pass) - { - int count = 1; - if (auto passAsParent = pass->AsParent()) - { - for (const auto& child : passAsParent->GetChildren()) - { - count += containingPassCount(child); - } - } - return count; - }; - const int numPasses = containingPassCount(rootPass); + + RPI::PassSystemFrameStatistics passSystemFrameStatistics = AZ::RPI::PassSystemInterface::Get()->GetFrameStatistics(); + DrawLine(AZStd::string::format( - "Total Passes: %d Vertex Count: %lld Primitive Count: %lld", - numPasses, + "RenderPasses: %d Vertex Count: %lld Primitive Count: %lld", + passSystemFrameStatistics.m_numRenderPassesExecuted, aznumeric_cast(stats.m_vertexCount), aznumeric_cast(stats.m_primitiveCount) )); + DrawLine(AZStd::string::format( + "Total Draw Item Count: %d Max Draw Items in a Pass: %d", + passSystemFrameStatistics.m_totalDrawItemsRendered, + passSystemFrameStatistics.m_maxDrawItemsRenderedInAPass + )); } void AtomViewportDisplayInfoSystemComponent::UpdateFramerate()