Revert "Refresh rate driven rendering tick logic (#3375)"

This reverts commit db63dcbcd9.

Signed-off-by: nvsickle <nvsickle@amazon.com>
This commit is contained in:
nvsickle
2021-09-21 16:44:19 -07:00
parent 39a4e05492
commit bcfe3d3878
25 changed files with 126 additions and 635 deletions
@@ -10,7 +10,6 @@
#include <QWidget>
#include <QElapsedTimer>
#include <QPointer>
#include <Atom/RPI.Public/Base.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/Input/QtEventToAzInputManager.h>
@@ -22,8 +21,6 @@
#include <AzFramework/Windowing/WindowBus.h>
#include <AzCore/Component/TickBus.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h>
namespace AtomToolsFramework
{
@@ -38,8 +35,6 @@ namespace AtomToolsFramework
, public AzFramework::WindowRequestBus::Handler
, protected AzFramework::InputChannelEventListener
, protected AZ::TickBus::Handler
, protected AZ::Render::Bootstrap::NotificationBus::Handler
, protected AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler
{
public:
//! Creates a RenderViewportWidget.
@@ -126,7 +121,6 @@ namespace AtomToolsFramework
// AZ::TickBus::Handler ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
int GetTickOrder() override;
// QWidget ...
void resizeEvent(QResizeEvent *event) override;
@@ -134,21 +128,9 @@ namespace AtomToolsFramework
void enterEvent(QEvent* event) override;
void leaveEvent(QEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void focusInEvent(QFocusEvent* event) override;
// AZ::Render::Bootstrap::NotificationBus::Handler ...
void OnFrameRateLimitChanged(float fpsLimit) override;
// AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler ...
void OnInactiveViewportFrameRateChanged(float fpsLimit) override;
private:
AzFramework::NativeWindowHandle GetNativeWindowHandle() const;
void UpdateFrameRate();
void SetScreen(QScreen* screen);
void SendWindowResizeEvent();
void NotifyUpdateRefreshRate();
// The underlying ViewportContext, our entry-point to the Atom RPI.
AZ::RPI::ViewportContextPtr m_viewportContext;
@@ -169,11 +151,5 @@ namespace AtomToolsFramework
AZ::ScriptTimePoint m_time;
// Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList.
AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr;
// Stores our current screen, used for tracking the current refresh rate.
QScreen* m_screen = nullptr;
// Stores the last RenderViewportWidget that has received user focus.
// This is used for optional framerate throtting for "inactive" viewports via the
// ed_inactive_viewport_fps_limit CVAR.
AZ::EnvironmentVariable<RenderViewportWidget*> m_lastFocusedViewport;
};
} //namespace AtomToolsFramework
@@ -1,35 +0,0 @@
/*
* 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
#include <AzCore/EBus/EBus.h>
namespace AtomToolsFramework
{
//! Provides an interface for providing notifications specific to RenderViewportWidget.
//! @note Most behaviors in RenderViewportWidget are handled by its underyling
//! ViewportContext, this bus is specifically for functionality exclusive to the
//! Qt layer provided by RenderViewportWidget.
class RenderViewportWidgetNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
//! Triggered when the idle frame rate limit for inactive viewports changed.
//! Controlled by the ed_inactive_viewport_fps_limit CVAR.
//! Active viewports are controlled by the r_fps_limit CVAR.
virtual void OnInactiveViewportFrameRateChanged([[maybe_unused]]float fpsLimit){}
protected:
~RenderViewportWidgetNotifications() = default;
};
using RenderViewportWidgetNotificationBus = AZ::EBus<RenderViewportWidgetNotifications>;
} // namespace AtomToolsFramework
@@ -6,42 +6,23 @@
*
*/
#include <Atom/Bootstrap/BootstrapRequestBus.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/View.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <AzCore/Console/Console.h>
#include <AzCore/Math/MathUtils.h>
#include <Atom/RPI.Public/View.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Viewport/ViewportControllerList.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
#include <AzCore/Math/MathUtils.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/Bootstrap/BootstrapRequestBus.h>
#include <QApplication>
#include <QBoxLayout>
#include <QCursor>
#include <QMouseEvent>
#include <QScreen>
#include <QTimer>
#include <QBoxLayout>
#include <QWindow>
static void OnInactiveViewportFrameRateChanged(const float& fpsLimit)
{
AtomToolsFramework::RenderViewportWidgetNotificationBus::Broadcast(
&AtomToolsFramework::RenderViewportWidgetNotificationBus::Events::OnInactiveViewportFrameRateChanged, fpsLimit);
}
AZ_CVAR(
float,
ed_inactive_viewport_fps_limit,
0,
OnInactiveViewportFrameRateChanged,
AZ::ConsoleFunctorFlags::Null,
"The maximum framerate to render viewports that don't have focus at");
static constexpr const char* LastFocusedViewportVariableName = "AtomToolsFramework::RenderViewportWidget::LastFocusedViewport";
#include <QMouseEvent>
namespace AtomToolsFramework
{
@@ -49,12 +30,6 @@ namespace AtomToolsFramework
: QWidget(parent)
, AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault())
{
m_lastFocusedViewport = AZ::Environment::FindVariable<RenderViewportWidget*>(LastFocusedViewportVariableName);
if (!m_lastFocusedViewport)
{
m_lastFocusedViewport = AZ::Environment::CreateVariable<RenderViewportWidget*>(LastFocusedViewportVariableName, nullptr);
}
if (shouldInitializeViewportContext)
{
InitializeViewportContext();
@@ -63,24 +38,13 @@ namespace AtomToolsFramework
setUpdatesEnabled(false);
setFocusPolicy(Qt::FocusPolicy::WheelFocus);
setMouseTracking(true);
// Wait a frame for our window handle to be constructed, then wire up our screen change signals.
QTimer::singleShot(
0,
[this]()
{
QObject::connect(windowHandle(), &QWindow::screenChanged, this, &RenderViewportWidget::SetScreen);
});
SetScreen(screen());
}
bool RenderViewportWidget::InitializeViewportContext(AzFramework::ViewportId id)
{
if (m_viewportContext != nullptr)
{
AZ_Assert(
id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id,
"Attempted to reinitialize RenderViewportWidget with a different ID");
AZ_Assert(id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id, "Attempted to reinitialize RenderViewportWidget with a different ID");
return true;
}
@@ -95,7 +59,7 @@ namespace AtomToolsFramework
// Before we do anything else, we must create a ViewportContext which will give us a ViewportId if we didn't manually specify one.
AZ::RPI::ViewportContextRequestsInterface::CreationParameters params;
params.device = AZ::RHI::RHISystemInterface::Get()->GetDevice();
params.windowHandle = GetNativeWindowHandle();
params.windowHandle = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
params.id = id;
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
m_viewportContext = viewportContextManager->CreateViewportContext(AZ::Name(), params);
@@ -116,46 +80,29 @@ namespace AtomToolsFramework
AzFramework::InputChannelEventListener::Connect();
AZ::TickBus::Handler::BusConnect();
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler::BusConnect();
m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, id);
// Forward input events to our controller list.
QObject::connect(
m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
QObject::connect(m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
[this](const AzFramework::InputChannel* inputChannel, QEvent* event)
{
const AzFramework::NativeWindowHandle windowId = GetNativeWindowHandle();
if (m_controllerList->HandleInputChannelEvent(
AzFramework::ViewportControllerInputEvent{ GetId(), windowId, *inputChannel }))
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
{
event->setAccepted(true);
}
}
});
// Update our target frame rate. If we're the only viewport, become active.
if (m_lastFocusedViewport.Get() == nullptr)
{
m_lastFocusedViewport.Set(this);
}
UpdateFrameRate();
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
if (m_controllerList->HandleInputChannelEvent(AzFramework::ViewportControllerInputEvent{GetId(), windowId, *inputChannel}))
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
{
event->setAccepted(true);
}
}
});
return true;
}
RenderViewportWidget::~RenderViewportWidget()
{
if (m_lastFocusedViewport.Get() == this)
{
m_lastFocusedViewport.Set(nullptr);
}
AzFramework::WindowRequestBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AzFramework::InputChannelEventListener::Disconnect();
@@ -234,22 +181,17 @@ namespace AtomToolsFramework
bool shouldConsumeEvent = true;
const bool eventHandled = m_controllerList->HandleInputChannelEvent({ GetId(), GetNativeWindowHandle(), inputChannel });
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
const bool eventHandled = m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel});
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might
// need), consume it.
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might need), consume it.
return eventHandled && shouldConsumeEvent;
}
void RenderViewportWidget::OnTick([[maybe_unused]] float deltaTime, AZ::ScriptTimePoint time)
void RenderViewportWidget::OnTick([[maybe_unused]]float deltaTime, AZ::ScriptTimePoint time)
{
m_time = time;
m_controllerList->UpdateViewport({ GetId(), AzFramework::FloatSeconds(deltaTime), m_time });
}
int RenderViewportWidget::GetTickOrder()
{
return AZ::ComponentTickBus::TICK_PRE_RENDER;
m_controllerList->UpdateViewport({GetId(), AzFramework::FloatSeconds(deltaTime), m_time});
}
void RenderViewportWidget::resizeEvent([[maybe_unused]] QResizeEvent* event)
@@ -277,75 +219,6 @@ namespace AtomToolsFramework
m_mousePosition = event->localPos();
}
void RenderViewportWidget::focusInEvent([[maybe_unused]] QFocusEvent* event)
{
RenderViewportWidget* lastFocusedViewport = m_lastFocusedViewport.Get();
if (lastFocusedViewport == this)
{
return;
}
RenderViewportWidget* previousFocusWidget = lastFocusedViewport;
m_lastFocusedViewport.Set(this);
// Ensure this viewport and whatever viewport last had focus (if any) respect
// the active / inactive viewport frame rate settings.
UpdateFrameRate();
if (previousFocusWidget != nullptr)
{
previousFocusWidget->UpdateFrameRate();
}
}
void RenderViewportWidget::OnFrameRateLimitChanged([[maybe_unused]] float fpsLimit)
{
UpdateFrameRate();
}
void RenderViewportWidget::OnInactiveViewportFrameRateChanged([[maybe_unused]] float fpsLimit)
{
UpdateFrameRate();
}
AzFramework::NativeWindowHandle RenderViewportWidget::GetNativeWindowHandle() const
{
return reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
}
void RenderViewportWidget::UpdateFrameRate()
{
if (ed_inactive_viewport_fps_limit > 0.f && m_lastFocusedViewport.Get() != this)
{
m_viewportContext->SetFpsLimit(ed_inactive_viewport_fps_limit);
}
else
{
float fpsLimit = 0.f;
AZ::Render::Bootstrap::RequestBus::BroadcastResult(fpsLimit, &AZ::Render::Bootstrap::RequestBus::Events::GetFrameRateLimit);
m_viewportContext->SetFpsLimit(fpsLimit);
}
}
void RenderViewportWidget::SetScreen(QScreen* screen)
{
if (m_screen != screen)
{
if (m_screen)
{
QObject::disconnect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate);
}
if (screen)
{
QObject::connect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate);
}
NotifyUpdateRefreshRate();
m_screen = screen;
}
}
void RenderViewportWidget::SendWindowResizeEvent()
{
// Scale the size by the DPI of the platform to
@@ -353,14 +226,8 @@ namespace AtomToolsFramework
const QSize uiWindowSize = size();
const QSize windowSize = uiWindowSize * devicePixelRatioF();
AzFramework::WindowNotificationBus::Event(
GetNativeWindowHandle(), &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
}
void RenderViewportWidget::NotifyUpdateRefreshRate()
{
AzFramework::WindowNotificationBus::Event(
GetNativeWindowHandle(), &AzFramework::WindowNotificationBus::Events::OnRefreshRateChanged, GetDisplayRefreshRate());
const AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
}
AZ::Name RenderViewportWidget::GetCurrentContextName() const
@@ -418,7 +285,9 @@ namespace AtomToolsFramework
// Build camera state from Atom camera transforms
AzFramework::CameraState cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix(
currentView->GetViewToWorldMatrix(), AZ::Vector2{ aznumeric_cast<float>(width()), aznumeric_cast<float>(height()) });
currentView->GetViewToWorldMatrix(),
AZ::Vector2{aznumeric_cast<float>(width()), aznumeric_cast<float>(height())}
);
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix());
// Convert from Z-up
@@ -430,7 +299,8 @@ namespace AtomToolsFramework
AzFramework::ScreenPoint RenderViewportWidget::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
{
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView(); currentView == nullptr)
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView();
currentView == nullptr)
{
return AzFramework::ScreenPoint(0, 0);
}
@@ -443,10 +313,12 @@ namespace AtomToolsFramework
const auto& cameraProjection = m_viewportContext->GetCameraProjectionMatrix();
const auto& cameraView = m_viewportContext->GetCameraViewMatrix();
const AZ::Vector4 normalizedScreenPosition{ screenPosition.m_x * 2.f / width() - 1.0f,
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f };
const AZ::Vector4 normalizedScreenPosition {
screenPosition.m_x * 2.f / width() - 1.0f,
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f
};
AZ::Matrix4x4 worldFromScreen = cameraProjection * cameraView;
worldFromScreen.InvertFull();
@@ -475,7 +347,7 @@ namespace AtomToolsFramework
AZ::Vector3 rayDirection = pos1.value() - pos0.value();
rayDirection.Normalize();
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection };
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection};
}
float RenderViewportWidget::DeviceScalingFactor()
@@ -505,12 +377,12 @@ namespace AtomToolsFramework
AzFramework::WindowSize RenderViewportWidget::GetClientAreaSize() const
{
return AzFramework::WindowSize{ aznumeric_cast<uint32_t>(width()), aznumeric_cast<uint32_t>(height()) };
return AzFramework::WindowSize{aznumeric_cast<uint32_t>(width()), aznumeric_cast<uint32_t>(height())};
}
void RenderViewportWidget::ResizeClientArea(AzFramework::WindowSize clientAreaSize)
{
const QSize targetSize = QSize{ aznumeric_cast<int>(clientAreaSize.m_width), aznumeric_cast<int>(clientAreaSize.m_height) };
const QSize targetSize = QSize{aznumeric_cast<int>(clientAreaSize.m_width), aznumeric_cast<int>(clientAreaSize.m_height)};
resize(targetSize);
}
@@ -520,7 +392,7 @@ namespace AtomToolsFramework
return false;
}
void RenderViewportWidget::SetFullScreenState([[maybe_unused]] bool fullScreenState)
void RenderViewportWidget::SetFullScreenState([[maybe_unused]]bool fullScreenState)
{
// The RenderViewportWidget does not currently support full screen.
}
@@ -543,20 +415,11 @@ namespace AtomToolsFramework
uint32_t RenderViewportWidget::GetDisplayRefreshRate() const
{
return static_cast<uint32_t>(screen()->refreshRate());
return 60;
}
uint32_t RenderViewportWidget::GetSyncInterval() const
{
uint32_t interval = 1;
// Get vsync_interval from AzFramework::NativeWindow, which owns it.
// NativeWindow also handles broadcasting OnVsyncIntervalChanged to all
// WindowNotificationBus listeners.
if (auto console = AZ::Interface<AZ::IConsole>::Get())
{
console->GetCvarValue<uint32_t>("vsync_interval", interval);
}
return interval;
return 1;
}
} // namespace AtomToolsFramework
} //namespace AtomToolsFramework
@@ -28,7 +28,6 @@ set(FILES
Include/AtomToolsFramework/Util/MaterialPropertyUtil.h
Include/AtomToolsFramework/Util/Util.h
Include/AtomToolsFramework/Viewport/RenderViewportWidget.h
Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h
Include/AtomToolsFramework/Window/AtomToolsMainWindow.h