Refresh rate driven rendering tick logic (#3375)

* Implement sync interval and refresh rate API for RenderViewportWidget

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Measure actual frame timings in the viewport info overlay.

Takes the median of the sum of (frame end - frame begin) to provide more a more representative view of when frames begin and end.

Note: Until VSync is internally supported by the event loop, this will produce nearly identical frame timings as the frame will spend as much time as needed synchronously waiting on a vblank.

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Make frame timing per-pipeline, wire up refresh rate info to ViewportContext

Signed-off-by: nvsickle <nvsickle@amazon.com>

* POC: Frame limit pipeline rendering

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Switch Editor tick to every 0ms to allow better tick accumulation behavior

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Move RPISystemComponent to the tick bus, remove tick accumulation logic

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Add `AddToRenderTickAtInterval` to RenderPipeline API

This allows a pipeline to update at a set cadence, instead of rendering every frame or being directly told when to tick.

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Make ViewportContext enforce a target framerate

-Adds GetFpsLimit/SetFpsLimit for actively limiting FPS
-Calculates a render tick interval based on vsync and the vps limit and updates the current pipeline

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Add r_fps_limit and ed_inactive_viewport_fps_limit cvars

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Quick null check from a crash I bumped into

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Fix off-by-one on FPS calculation (shouldn't include the not-yet-rendered frame)

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Clarify frame time begin initialization

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Fix TrackView export.

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Address some reviewer feedback, revert RPISystem API change, fix CPU profiler.

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Add g_simulation_tick_rate

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Address review feedback, make frame limit updates event driven

Signed-off-by: nvsickle <nvsickle@amazon.com>

* Remove timestamp update from ComponentApplication::Tick

Signed-off-by: nvsickle <nvsickle@amazon.com>
This commit is contained in:
Nicholas Van Sickle
2021-09-13 17:57:42 -07:00
committed by GitHub
parent b2963f2bc1
commit db63dcbcd9
26 changed files with 633 additions and 124 deletions
@@ -74,6 +74,8 @@
#include <AzCore/Module/Environment.h>
#include <AzCore/std/string/conversions.h>
AZ_CVAR(float, g_simulation_tick_rate, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "The rate at which the game simulation tick loop runs, or 0 for as fast as possible");
static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments)
{
if (arguments.empty())
@@ -1392,6 +1394,23 @@ namespace AZ
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
// If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame,
// sleeping if there's still time remaining.
if (g_simulation_tick_rate > 0.f)
{
now = AZStd::chrono::system_clock::now();
// Work in microsecond durations here as that's the native measurement time for time_point
constexpr float microsecondsPerSecond = 1000.f * 1000.f;
const AZStd::chrono::microseconds timeBudgetPerTick(static_cast<int>(microsecondsPerSecond / g_simulation_tick_rate));
AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now;
if (timeUntilNextTick.count() > 0)
{
AZStd::this_thread::sleep_for(timeUntilNextTick);
}
}
}
}
@@ -46,6 +46,8 @@ namespace AZ
TICK_PRE_RENDER = 750, ///< Suggested tick handler position to update render-related data.
TICK_RENDER = 800, ///< Suggested tick handler position for rendering.
TICK_DEFAULT = 1000, ///< Default tick handler position when the handler is constructed.
TICK_UI = 2000, ///< Suggested tick handler position for UI components.