From 84216f04793e17c923b744e2531c3e7d0feca27d Mon Sep 17 00:00:00 2001 From: nvsickle Date: Wed, 12 May 2021 15:58:28 -0700 Subject: [PATCH] Add API for ViewportInfoDisplayState, add some minor RHI integration --- .../Code/CMakeLists.txt | 2 + .../AtomViewportInfoDisplayBus.h | 61 ++++++++++ ...AtomViewportDisplayInfoSystemComponent.cpp | 107 +++++++++++++----- .../AtomViewportDisplayInfoSystemComponent.h | 14 +-- 4 files changed, 150 insertions(+), 34 deletions(-) create mode 100644 Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Include/AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt index 395cc22d47..de4ee9b4b5 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt @@ -17,6 +17,8 @@ ly_add_target( INCLUDE_DIRECTORIES PRIVATE Source + PUBLIC + Include BUILD_DEPENDENCIES PRIVATE AZ::AzCore diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Include/AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Include/AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h new file mode 100644 index 0000000000..ae9359d9d3 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Include/AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h @@ -0,0 +1,61 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once +#include +#include + +namespace AZ +{ + namespace AtomBridge + { + //! The level of information to display in the viewport info display overlay. + enum class ViewportInfoDisplayState : int + { + NoInfo = 0, + NormalInfo = 1, + FullInfo = 2, + CompactInfo = 3, + Invalid + }; + + //! This bus is used to request changes to the viewport info display overlay. + class AtomViewportInfoDisplayRequests + : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; + + //! Gets the current viewport info overlay state. + virtual ViewportInfoDisplayState GetDisplayState() const = 0; + //! Sets the current viewport info overlay state. + //! The overlay will be drawn to the default viewport context every frame, if enabled. + virtual void SetDisplayState(ViewportInfoDisplayState state) = 0; + }; + + using AtomViewportInfoDisplayRequestBus = AZ::EBus; + + //! This bus is used to listen for state changes in the viewport info display overlay. + class AtomViewportInfoDisplayNotifications + : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; + + //! Called when the ViewportInfoDisplayState (via the r_displayInfo CVar) has changed. + virtual void OnViewportInfoDisplayStateChanged([[maybe_unused]]ViewportInfoDisplayState state){} + }; + + using AtomViewportInfoDisplayNotificationBus = AZ::EBus; + } +} diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index 394923071e..c9128c001f 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -21,21 +21,30 @@ #include #include #include +#include #include #include #include #include -AZ_CVAR(float, r_fpsInterval, 1.0f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, - "The time period over which to calculate the framerate for r_displayInfo"); - namespace AZ::Render { - static constexpr int DisplayInfoLevelNone = 0; - static constexpr int DisplayInfoLevelNormal = 1; - static constexpr int DisplayInfoLevelFull = 2; - static constexpr int DisplayInfoLevelCompact = 3; + AZ_CVAR(int, r_displayInfo, 1, [](const int& newDisplayInfoVal)->void + { + // Forward this event to the system component so it can update accordingly. + // This callback only gets triggered by console commands, so this will not recurse. + AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( + &AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, + static_cast(newDisplayInfoVal) + ); + }, AZ::ConsoleFunctorFlags::DontReplicate, + "Toggles debugging information display.\n" + "Usage: r_displayInfo [0=off/1=show/2=enhanced/3=compact]" + ); + AZ_CVAR(float, r_fpsCalcInterval, 1.0f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The time period over which to calculate the framerate for r_displayInfo." + ); void AtomViewportDisplayInfoSystemComponent::Reflect(AZ::ReflectContext* context) { @@ -47,7 +56,7 @@ namespace AZ::Render if (AZ::EditContext* ec = serialize->GetEditContext()) { - ec->Class("Viewport Display Info", "Manages debug viewport information through r_DisplayInfo") + ec->Class("Viewport Display Info", "Manages debug viewport information through r_displayInfo") ->ClassElement(Edit::ClassElements::EditorData, "") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) ->Attribute(Edit::Attributes::AutoExpand, true) @@ -83,15 +92,15 @@ namespace AZ::Render m_rendererDescription = AZStd::string::format("Atom using %s RHI", apiName.GetCStr()); } - CrySystemEventBus::Handler::BusConnect(); AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect( AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContextName()); + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler::BusConnect(); } void AtomViewportDisplayInfoSystemComponent::Deactivate() { + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler::BusDisconnect(); AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect(); - CrySystemEventBus::Handler::BusDisconnect(); } AZ::RPI::ViewportContextPtr AtomViewportDisplayInfoSystemComponent::GetViewportContext() const @@ -111,8 +120,13 @@ namespace AZ::Render void AtomViewportDisplayInfoSystemComponent::OnRenderTick() { + auto fontQueryInterface = AZ::Interface::Get(); + if (!fontQueryInterface) + { + return; + } AzFramework::FontDrawInterface* fontDrawInterface = - AZ::Interface::Get()->GetDefaultFontDrawInterface(); + fontQueryInterface->GetDefaultFontDrawInterface(); AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); if (!fontDrawInterface || !viewportContext || !viewportContext->GetRenderScene()) @@ -120,18 +134,23 @@ namespace AZ::Render return; } - m_fpsInterval = AZStd::chrono::seconds(r_fpsInterval); + m_fpsInterval = AZStd::chrono::seconds(r_fpsCalcInterval); UpdateFramerate(); - if (!m_displayInfoCVar) + const AtomBridge::ViewportInfoDisplayState displayLevel = GetDisplayState(); + if (displayLevel == AtomBridge::ViewportInfoDisplayState::NoInfo) { return; } - int displayLevel = m_displayInfoCVar->GetIVal(); - if (displayLevel == DisplayInfoLevelNone) + + if (m_updateRootPassQuery) { - return; + if (auto rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass()) + { + rootPass->SetPipelineStatisticsQueryEnabled(displayLevel == AtomBridge::ViewportInfoDisplayState::FullInfo); + m_updateRootPassQuery = false; + } } m_drawParams.m_drawViewportId = viewportContext->GetId(); @@ -152,22 +171,30 @@ namespace AZ::Render m_lineSpacing = lineHeight * m_drawParams.m_lineSpacing; DrawRendererInfo(); - if (displayLevel != DisplayInfoLevelCompact) + if (displayLevel == AtomBridge::ViewportInfoDisplayState::FullInfo) { DrawCameraInfo(); + DrawPassInfo(); + } + if (displayLevel != AtomBridge::ViewportInfoDisplayState::CompactInfo) + { DrawMemoryInfo(); } DrawFramerate(); } - void AtomViewportDisplayInfoSystemComponent::OnCrySystemInitialized(ISystem& system, [[maybe_unused]]const SSystemInitParams& initParams) + AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const { - m_displayInfoCVar = system.GetGlobalEnvironment()->pConsole->GetCVar("r_DisplayInfo"); + return static_cast(r_displayInfo.operator int()); } - void AtomViewportDisplayInfoSystemComponent::OnCrySystemShutdown([[maybe_unused]]ISystem& system) + void AtomViewportDisplayInfoSystemComponent::SetDisplayState(AtomBridge::ViewportInfoDisplayState state) { - m_displayInfoCVar = nullptr; + r_displayInfo = static_cast(state); + AtomBridge::AtomViewportInfoDisplayNotificationBus::Broadcast( + &AtomBridge::AtomViewportInfoDisplayNotificationBus::Events::OnViewportInfoDisplayStateChanged, + state); + m_updateRootPassQuery = true; } void AtomViewportDisplayInfoSystemComponent::DrawRendererInfo() @@ -198,6 +225,31 @@ namespace AZ::Render )); } + void AtomViewportDisplayInfoSystemComponent::DrawPassInfo() + { + auto rootPass = AZ::RPI::PassSystemInterface::Get()->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); + DrawLine(AZStd::string::format( + "Total Passes: %d Vertex Count: %d Primitive Count: %d", + numPasses, + stats.m_vertexCount, + stats.m_primitiveCount + )); + } + void AtomViewportDisplayInfoSystemComponent::DrawMemoryInfo() { static IMemoryManager::SProcessMemInfo processMemInfo; @@ -236,11 +288,16 @@ namespace AZ::Render AZ::ScriptTimePoint currentTime = m_tickRequests->GetTimeAtCurrentTick(); // Only keep as much sampling data is is required by our FPS history. - while (!m_fpsHistory.empty() && (currentTime.Get() - m_fpsHistory.front().Get() > m_fpsInterval)) + while (!m_fpsHistory.empty() && (currentTime.Get() - m_fpsHistory.front().Get()) > m_fpsInterval) { m_fpsHistory.pop_front(); } - m_fpsHistory.push_back(currentTime); + + // Discard entries with a zero time-delta (can happen when we don't have window focus). + if (m_fpsHistory.empty() || (currentTime.Get() - m_fpsHistory.back().Get()) != AZStd::chrono::seconds(0)) + { + m_fpsHistory.push_back(currentTime); + } } void AtomViewportDisplayInfoSystemComponent::DrawFramerate() @@ -254,10 +311,6 @@ namespace AZ::Render if (lastTime.has_value()) { AZStd::chrono::duration deltaTime = time.Get() - lastTime.value().Get(); - if (deltaTime.count() == 0.0) - { - continue; - } double fps = AZStd::chrono::seconds(1) / deltaTime; if (!minFPS.has_value()) { diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h index 5cb6ed3308..ac6c2bab65 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h @@ -19,8 +19,7 @@ #include #include #include - -struct ICVar; +#include namespace AZ { @@ -31,7 +30,7 @@ namespace AZ class AtomViewportDisplayInfoSystemComponent : public AZ::Component , public AZ::RPI::ViewportContextNotificationBus::Handler - , public CrySystemEventBus::Handler + , public AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler { public: AZ_COMPONENT(AtomViewportDisplayInfoSystemComponent, "{AC32F173-E7E2-4943-8E6C-7C3091978221}"); @@ -51,9 +50,9 @@ namespace AZ // AZ::RPI::ViewportContextNotificationBus::Handler overrides... void OnRenderTick() override; - // CrySystemEventBus::Handler overrides... - void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& initParams) override; - void OnCrySystemShutdown(ISystem& system) override; + // AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides... + AtomBridge::ViewportInfoDisplayState GetDisplayState() const override; + void SetDisplayState(AtomBridge::ViewportInfoDisplayState state) override; private: AZ::RPI::ViewportContextPtr GetViewportContext() const; @@ -63,6 +62,7 @@ namespace AZ void DrawRendererInfo(); void DrawCameraInfo(); + void DrawPassInfo(); void DrawMemoryInfo(); void DrawFramerate(); @@ -73,7 +73,7 @@ namespace AZ AZStd::deque m_fpsHistory; AZStd::optional m_lastMemoryUpdate; AZ::TickRequests* m_tickRequests = nullptr; - ICVar* m_displayInfoCVar = nullptr; + bool m_updateRootPassQuery = true; }; } // namespace Render } // namespace AZ