Add API for ViewportInfoDisplayState, add some minor RHI integration

This commit is contained in:
nvsickle
2021-05-12 15:58:28 -07:00
parent 559798251d
commit 84216f0479
4 changed files with 150 additions and 34 deletions
@@ -17,6 +17,8 @@ ly_add_target(
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
@@ -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 <AzCore/base.h>
#include <AzCore/EBus/EBus.h>
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<AtomViewportInfoDisplayRequests>;
//! 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<AtomViewportInfoDisplayNotifications>;
}
}
@@ -21,21 +21,30 @@
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/Pass/ParentPass.h>
#include <Atom/RHI/Factory.h>
#include <CrySystem/MemoryManager.h>
#include <CryCommon/ISystem.h>
#include <CryCommon/IConsole.h>
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<AtomBridge::ViewportInfoDisplayState>(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<AtomViewportDisplayInfoSystemComponent>("Viewport Display Info", "Manages debug viewport information through r_DisplayInfo")
ec->Class<AtomViewportDisplayInfoSystemComponent>("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<AzFramework::FontQueryInterface>::Get();
if (!fontQueryInterface)
{
return;
}
AzFramework::FontDrawInterface* fontDrawInterface =
AZ::Interface<AzFramework::FontQueryInterface>::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<AtomBridge::ViewportInfoDisplayState>(r_displayInfo.operator int());
}
void AtomViewportDisplayInfoSystemComponent::OnCrySystemShutdown([[maybe_unused]]ISystem& system)
void AtomViewportDisplayInfoSystemComponent::SetDisplayState(AtomBridge::ViewportInfoDisplayState state)
{
m_displayInfoCVar = nullptr;
r_displayInfo = static_cast<int>(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<int(const AZ::RPI::Ptr<AZ::RPI::Pass>)> containingPassCount = [&containingPassCount](const AZ::RPI::Ptr<AZ::RPI::Pass> 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<double> deltaTime = time.Get() - lastTime.value().Get();
if (deltaTime.count() == 0.0)
{
continue;
}
double fps = AZStd::chrono::seconds(1) / deltaTime;
if (!minFPS.has_value())
{
@@ -19,8 +19,7 @@
#include <AzFramework/Font/FontInterface.h>
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
struct ICVar;
#include <AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h>
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<AZ::ScriptTimePoint> m_fpsHistory;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_lastMemoryUpdate;
AZ::TickRequests* m_tickRequests = nullptr;
ICVar* m_displayInfoCVar = nullptr;
bool m_updateRootPassQuery = true;
};
} // namespace Render
} // namespace AZ