Removal and Replacement of the CryTimer (gEnv->pTimer) (#5409)

Replaced and removed the CryTimer (gEnv->pTimer). The new TimeSystem is a merger of the current time functionality found in the engine.

* Rename TimeSystemComponent.h/.cpp to TimeSystem.h/.cpp
* Adding New TimeSystem
* remove old timer cvars
* small improvements to the time system.
 - updated parts to use the time conversion functions.
 - in AdvanceTickDeltaTimes applying t_simulationTickScale is now uses doubles instead of floats.
* Replace gEnv->pTimer / ITimer usages with TimeSystem
* Updating usages of AZ::TimeMs{ 0 } and AZ::TimeUs{ 0 } to AZ::Time::ZeroTimeMs and AZ::Time::ZeroTimeUs
* red code the CryTimer
* using TimeUs instead of TimeMs is some cases + updating usages of old cvars to new

Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com>
This commit is contained in:
amzn-sean
2021-11-15 12:11:58 +00:00
committed by GitHub
parent 0ada8b335b
commit 38a03817bb
142 changed files with 1215 additions and 2090 deletions
@@ -19,7 +19,6 @@
#include <AzCore/Slice/SliceSystemComponent.h>
#include <AzCore/Slice/SliceMetadataInfoComponent.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzCore/Time/TimeSystemComponent.h>
#include <AzCore/Console/LoggerSystemComponent.h>
#include <AzCore/EBus/EventSchedulerSystemComponent.h>
#include <AzCore/Task/TaskGraphSystemComponent.h>
@@ -40,7 +39,6 @@ namespace AZ
SliceComponent::CreateDescriptor(),
SliceSystemComponent::CreateDescriptor(),
SliceMetadataInfoComponent::CreateDescriptor(),
TimeSystemComponent::CreateDescriptor(),
LoggerSystemComponent::CreateDescriptor(),
EventSchedulerSystemComponent::CreateDescriptor(),
TaskGraphSystemComponent::CreateDescriptor(),
@@ -59,7 +57,6 @@ namespace AZ
{
return AZ::ComponentTypeList
{
azrtti_typeid<TimeSystemComponent>(),
azrtti_typeid<LoggerSystemComponent>(),
azrtti_typeid<EventSchedulerSystemComponent>(),
azrtti_typeid<TaskGraphSystemComponent>(),
@@ -72,6 +72,7 @@
#include <AzCore/Module/Environment.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/Time/TimeSystem.h>
static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments)
{
@@ -416,6 +417,7 @@ namespace AZ
ComponentApplication::ComponentApplication(int argC, char** argV)
: m_eventLogger{}
, m_timeSystem(AZStd::make_unique<TimeSystem>())
{
if (Interface<ComponentApplicationRequests>::Get() == nullptr)
{
@@ -574,7 +576,6 @@ namespace AZ
DestroyAllocator();
}
void ReportBadEngineRoot()
{
AZStd::string errorMessage = {"Unable to determine a valid path to the engine.\n"
@@ -677,7 +678,6 @@ namespace AZ
ComponentApplicationBus::Handler::BusConnect();
m_currentTime = AZStd::chrono::system_clock::now();
TickRequestBus::Handler::BusConnect();
#if defined(AZ_ENABLE_DEBUG_TOOLS)
@@ -1413,31 +1413,23 @@ namespace AZ
#endif
}
void ComponentApplication::Tick(float deltaOverride /*= -1.f*/)
void ComponentApplication::Tick()
{
AZ_PROFILE_SCOPE(System, "Component application simulation tick");
{
AZ_PROFILE_SCOPE(System, "Component application simulation tick");
AZStd::chrono::system_clock::time_point now = AZStd::chrono::system_clock::now();
m_deltaTime = 0.0f;
if (now >= m_currentTime)
{
AZStd::chrono::duration<float> delta = now - m_currentTime;
m_deltaTime = deltaOverride >= 0.f ? deltaOverride : delta.count();
}
{
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:ExecuteQueuedEvents");
TickBus::ExecuteQueuedEvents();
}
m_currentTime = now;
{
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:ExecuteQueuedEvents");
TickBus::ExecuteQueuedEvents();
}
{
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
const AZ::TimeUs deltaTimeUs = m_timeSystem->AdvanceTickDeltaTimes();
const float deltaTimeSeconds = AZ::TimeUsToSeconds(deltaTimeUs);
AZ::TickBus::Broadcast(&TickEvents::OnTick, deltaTimeSeconds, GetTimeAtCurrentTick());
}
m_timeSystem->ApplyTickRateLimiterIfNeeded();
}
void ComponentApplication::TickSystem()
@@ -1519,13 +1511,10 @@ namespace AZ
appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Invalid;
}
//=========================================================================
// GetFrameTime
// [1/22/2016]
//=========================================================================
float ComponentApplication::GetTickDeltaTime()
{
return m_deltaTime;
const AZ::TimeUs gameTickTime = m_timeSystem->GetSimulationTickDeltaTimeUs();
return AZ::TimeUsToSeconds(gameTickTime);
}
//=========================================================================
@@ -1534,7 +1523,8 @@ namespace AZ
//=========================================================================
ScriptTimePoint ComponentApplication::GetTimeAtCurrentTick()
{
return ScriptTimePoint(m_currentTime);
const AZ::TimeUs lastGameTickTime = m_timeSystem->GetLastSimulationTickTime();
return ScriptTimePoint(AZ::TimeUsToChrono(lastGameTickTime));
}
//=========================================================================
@@ -30,12 +30,14 @@
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/string/osstring.h>
namespace AZ
{
class BehaviorContext;
class IConsole;
class Module;
class ModuleManager;
class TimeSystem;
}
namespace AZ::Debug
{
@@ -237,7 +239,7 @@ namespace AZ
/**
* Ticks all components using the \ref AZ::TickBus during simulation time. May not tick if the application is not active (i.e. not in focus)
*/
virtual void Tick(float deltaOverride = -1.f);
virtual void Tick();
/**
* Ticks all using the \ref AZ::SystemTickBus at all times. Should always tick even if the application is not active.
@@ -359,8 +361,6 @@ namespace AZ
}
}
AZStd::chrono::system_clock::time_point m_currentTime{ AZStd::chrono::system_clock::time_point::max() };
float m_deltaTime{ 0.0f };
AZStd::unique_ptr<ModuleManager> m_moduleManager;
AZStd::unique_ptr<SettingsRegistryInterface> m_settingsRegistry;
EntityAddedEvent m_entityAddedEvent;
@@ -381,6 +381,8 @@ namespace AZ
AZ::SettingsRegistryInterface::NotifyEventHandler m_projectNameChangedHandler;
AZ::SettingsRegistryInterface::NotifyEventHandler m_commandLineUpdatedHandler;
AZStd::unique_ptr<AZ::TimeSystem> m_timeSystem;
// ConsoleFunctorHandle is responsible for unregistering the Settings Registry Console
// from the m_console member when it goes out of scope
AZ::SettingsRegistryConsoleUtils::ConsoleFunctorHandle m_settingsRegistryConsoleFunctors;
@@ -60,7 +60,7 @@ namespace AZ
void EventSchedulerSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
TimeMs startTime = GetElapsedTimeMs();
TimeMs startTime = AZ::GetElapsedTimeMs();
bool usingTimeslice = bg_maxScheduledEventProcessTimeMs != TimeMs{ 0 };
while (!m_queue.empty())
@@ -76,7 +76,7 @@ namespace AZ
while (!m_pendingQueue.empty())
{
if (usingTimeslice && (GetElapsedTimeMs() - startTime > bg_maxScheduledEventProcessTimeMs))
if (usingTimeslice && (AZ::GetElapsedTimeMs() - startTime > bg_maxScheduledEventProcessTimeMs))
{
AZLOG_WARN("Failed to trigger all pending scheduled events, %u events remain on the pending queue", aznumeric_cast<uint32_t>(m_pendingQueue.size()));
break;
@@ -103,7 +103,7 @@ namespace AZ
durationMs = TimeMs{ 0 };
}
TimeMs currentMilliseconds = GetElapsedTimeMs();
TimeMs currentMilliseconds = AZ::GetElapsedTimeMs();
if (timedEvent->m_handle == nullptr)
{
timedEvent->m_handle = AllocateHandle();
@@ -122,7 +122,7 @@ namespace AZ
durationMs = TimeMs{ 0 };
}
TimeMs currentMilliseconds = GetElapsedTimeMs();
TimeMs currentMilliseconds = AZ::GetElapsedTimeMs();
ScheduledEvent* timedEvent = AllocateManagedEvent(callback, eventName);
const bool ownsScheduledEvent = true;
*(timedEvent->m_handle) = ScheduledEventHandle(TimeMs(currentMilliseconds + durationMs), durationMs, timedEvent, ownsScheduledEvent);
@@ -76,7 +76,7 @@ namespace AZ
TimeMs ScheduledEvent::TimeInQueueMs() const
{
return GetElapsedTimeMs() - m_timeInserted;
return AZ::GetElapsedTimeMs() - m_timeInserted;
}
TimeMs ScheduledEvent::RemainingTimeInQueueMs() const
+121 -9
View File
@@ -12,8 +12,8 @@
#include <AzCore/EBus/EBus.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/RTTI/TypeSafeIntegral.h>
#include <AzCore/std/time.h>
#include <AzCore/std/chrono/chrono.h>
#include <AzCore/std/time.h>
namespace AZ
{
@@ -24,15 +24,21 @@ namespace AZ
//! Using int64_t as the underlying type, this is good to represent approximately 292,471 years
AZ_TYPE_SAFE_INTEGRAL(TimeUs, int64_t);
namespace Time
{
static const AZ::TimeMs ZeroTimeMs = AZ::TimeMs{ 0 };
static const AZ::TimeUs ZeroTimeUs = AZ::TimeUs{ 0 };
}
//! @class ITime
//! @brief This is an AZ::Interface<> for managing time related operations.
//! AZ::ITime and associated types may not operate in realtime. These abstractions are to allow our application
//! simulation to operate both slower and faster than realtime in a well defined and user controllable manner
//! The rate at which time passes for AZ::ITime is controlled by the cvar t_scale
//! t_scale == 0 means simulation time should halt
//! 0 < t_scale < 1 will cause time to pass slower than realtime, with t_scale 0.1 being roughly 1/10th realtime
//! t_scale == 1 will cause time to pass at roughly realtime
//! t_scale > 1 will cause time to pass faster than normal, with t_scale 10 being roughly 10x realtime
//! The rate at which time passes for AZ::ITime is controlled by the cvar t_simulationTickScale
//! t_simulationTickScale == 0 means simulation time should halt
//! 0 < t_simulationTickScale < 1 will cause time to pass slower than realtime, with t_simulationTickScale 0.1 being roughly 1/10th realtime
//! t_simulationTickScale == 1 will cause time to pass at roughly realtime
//! t_simulationTickScale > 1 will cause time to pass faster than normal, with t_simulationTickScale 10 being roughly 10x realtime
class ITime
{
public:
@@ -41,15 +47,72 @@ namespace AZ
ITime() = default;
virtual ~ITime() = default;
//! Returns the number of milliseconds since application start.
//! @return the number of milliseconds that have elapsed since application start
//! Returns the number of milliseconds since application start scaled by t_simulationTickScale.
//! @return The number of milliseconds that have elapsed since application start.
virtual TimeMs GetElapsedTimeMs() const = 0;
//! Returns the number of microseconds since application start.
//! Returns the number of microseconds since application start scaled by t_simulationTickScale.
//! @return the number of microseconds that have elapsed since application start
virtual TimeUs GetElapsedTimeUs() const = 0;
//! Returns the number of milliseconds since application start.
//! This value is not affected by the t_simulationTickScale cvar.
//! @return The number of milliseconds that have elapsed since application start.
virtual TimeMs GetRealElapsedTimeMs() const = 0;
//! Returns the number of microseconds since application start.
//! This value is not affected by the t_simulationTickScale cvar.
//! @return The number of microseconds that have elapsed since application start.
virtual TimeUs GetRealElapsedTimeUs() const = 0;
//! Returns the current simulation tick delta time.
//! This is affected by the cvars t_simulationTickScale, t_simulationTickDeltaOverride, and t_maxGameTickDelta.
//! @return The number of microseconds elapsed since the last game tick.
virtual TimeUs GetSimulationTickDeltaTimeUs() const = 0;
//! Returns the non-manipulated tick time.
//! @return The number of microseconds elapsed since the last game tick.
virtual TimeUs GetRealTickDeltaTimeUs() const = 0;
//! Returns the time since application start of when the last simulation tick was updated.
virtual TimeUs GetLastSimulationTickTime() const = 0;
//! If > 0 this will override the simulation tick delta time with the provided value.
//! When enabled this will ignore any set simulation tick scale.
//! Setting to 0 disables the override.
//! @param timeMs The time in milliseconds to use for the tick delta.
virtual void SetSimulationTickDeltaOverride(TimeMs timeMs) = 0;
//! Returns the current simulation tick override.
//! 0 means disabled.
//! @returns The current simulation tick override in milliseconds.
virtual TimeMs GetSimulationTickDeltaOverride() const = 0;
//! A scalar amount to adjust the passage of time by, 1.0 == realtime, 0.5 == half realtime, 2.0 == doubletime.
//! @param scale The scalar value to apply to the simulation time.
virtual void SetSimulationTickScale(float scale) = 0;
//! Returns the current simulation tick scale.
//! 1.0 == realtime, 0.5 == half realtime, 2.0 == doubletime.
//! @returns The simulation tick scale value.
virtual float GetSimulationTickScale() const = 0;
//! The minimum rate to force the simulation tick to run.
//! 0 for as fast as possible. 30 = ~33ms, 60 = ~16ms.
//! Setting to 0 will disable rate limiting.
//! @note It is not guaranteed to hit the requested tick rate exactly.
//! @param rate The rate in frames per second.
virtual void SetSimulationTickRate(int rate) = 0;
//! Return the current simulation tick rate.
//! 0 means disabled.
//! @return The rate in frames per second.
virtual int32_t GetSimulationTickRate() const = 0;
AZ_DISABLE_COPY_MOVE(ITime);
static const AZ::TimeMs ZeroTimeMs = AZ::TimeMs{ 0 };
static const AZ::TimeUs ZeroTimeUs = AZ::TimeUs{ 0 };
};
// EBus wrapper for ScriptCanvas
@@ -74,6 +137,29 @@ namespace AZ
return AZ::Interface<ITime>::Get()->GetElapsedTimeUs();
}
inline TimeMs GetRealElapsedTimeMs()
{
return AZ::Interface<ITime>::Get()->GetRealElapsedTimeMs();
}
//! This is a simple convenience wrapper
inline TimeUs GetSimulationTickDeltaTimeUs()
{
return AZ::Interface<ITime>::Get()->GetSimulationTickDeltaTimeUs();
}
//! This is a simple convenience wrapper
inline TimeUs GetRealTickDeltaTimeUs()
{
return AZ::Interface<ITime>::Get()->GetRealTickDeltaTimeUs();
}
//! This is a simple convenience wrapper
inline TimeUs GetLastSimulationTickTime()
{
return AZ::Interface<ITime>::Get()->GetLastSimulationTickTime();
}
//! Converts from milliseconds to microseconds
inline TimeUs TimeMsToUs(TimeMs value)
{
@@ -92,12 +178,24 @@ namespace AZ
return static_cast<float>(value) / 1000.0f;
}
//! Converts from milliseconds to seconds
inline double TimeMsToSecondsDouble(TimeMs value)
{
return static_cast<double>(value) / 1000.0;
}
//! Converts from microseconds to seconds
inline float TimeUsToSeconds(TimeUs value)
{
return static_cast<float>(value) / 1000000.0f;
}
//! Converts from microseconds to seconds
inline double TimeUsToSecondsDouble(TimeUs value)
{
return static_cast<double>(value) / 1000000.0;
}
//! Converts from milliseconds to AZStd::chrono::time_point
inline auto TimeMsToChrono(TimeMs value)
{
@@ -113,6 +211,20 @@ namespace AZ
auto chronoValue = AZStd::chrono::microseconds(aznumeric_cast<int64_t>(value));
return epoch + chronoValue;
}
//! A utility function to convert from seconds to TimeMs
inline TimeMs SecondsToTimeMs(const double value)
{
const double valueMs = value * 1000.0;
return static_cast<TimeMs>(static_cast<int64_t>(valueMs));
}
//! A utility function to convert from seconds to TimeUs
inline TimeUs SecondsToTimeUs(const double value)
{
const double valueMs = value * 1000000.0;
return static_cast<TimeUs>(static_cast<int64_t>(valueMs));
}
} // namespace AZ
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(AZ::TimeMs);
@@ -0,0 +1,214 @@
/*
* 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 <AzCore/Time/TimeSystem.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
namespace
{
void cvar_t_simulationTickScale_Changed(const float& value)
{
if (auto* timeSystem = AZ::Interface<ITime>::Get())
{
timeSystem->SetSimulationTickScale(value);
}
}
void cvar_t_simulationTickDeltaOverride_Changed(const float& value)
{
if (auto* timeSystem = AZ::Interface<ITime>::Get())
{
timeSystem->SetSimulationTickDeltaOverride(AZ::SecondsToTimeMs(value));
}
}
void cvar_t_simulationTickRate_Changed(const int& rate)
{
AZ_Warning("tick", false, "Simulation tick rate limiting is currently disabled. Setting will not be applied.");
if (auto* timeSystem = AZ::Interface<ITime>::Get())
{
timeSystem->SetSimulationTickRate(rate);
}
}
} // namespace
AZ_CVAR(float, t_simulationTickScale, 1.0f, cvar_t_simulationTickScale_Changed, AZ::ConsoleFunctorFlags::Null,
"A scalar amount to adjust time passage by, 1.0 == realtime, 0.5 == half realtime, 2.0 == doubletime");
AZ_CVAR(float, t_simulationTickDeltaOverride, 0.0f, cvar_t_simulationTickDeltaOverride_Changed, AZ::ConsoleFunctorFlags::Null,
"If > 0, overrides the simulation tick delta time with the provided value (Seconds) and ignores any t_simulationTickScale value.");
AZ_CVAR(int, t_simulationTickRate, 0, cvar_t_simulationTickRate_Changed, AZ::ConsoleFunctorFlags::Null,
"The minimum rate to force the game simulation tick to run. 0 for as fast as possible. 30 = ~33ms, 60 = ~16ms");
void TimeSystem::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<TimeSystem, ITime>()
->Version(1);
}
}
TimeSystem::TimeSystem()
{
m_lastInvokedTimeUs = static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
AZ::Interface<ITime>::Register(this);
ITimeRequestBus::Handler::BusConnect();
}
TimeSystem::~TimeSystem()
{
AZ::Interface<ITime>::Unregister(this);
ITimeRequestBus::Handler::BusDisconnect();
}
TimeMs TimeSystem::GetElapsedTimeMs() const
{
return AZ::TimeUsToMs(GetElapsedTimeUs());
}
TimeUs TimeSystem::GetElapsedTimeUs() const
{
TimeUs currentTime = static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
TimeUs deltaTime = currentTime - m_lastInvokedTimeUs;
if (t_simulationTickScale != 1.0f)
{
const float floatDelta = AZStd::GetMax(static_cast<float>(deltaTime) * t_simulationTickScale, 1.0f);
deltaTime = static_cast<TimeUs>(static_cast<int64_t>(floatDelta));
}
m_accumulatedTimeUs += deltaTime;
m_lastInvokedTimeUs = currentTime;
return m_accumulatedTimeUs;
}
TimeMs TimeSystem::GetRealElapsedTimeMs() const
{
return AZ::TimeUsToMs(GetRealElapsedTimeUs());
}
TimeUs TimeSystem::GetRealElapsedTimeUs() const
{
return static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
}
TimeUs TimeSystem::GetSimulationTickDeltaTimeUs() const
{
return m_simulationTickDeltaTimeUs;
}
TimeUs TimeSystem::GetRealTickDeltaTimeUs() const
{
return m_realTickDeltaTimeUs;
}
TimeUs TimeSystem::GetLastSimulationTickTime() const
{
return m_lastSimulationTickTimeUs;
}
TimeUs TimeSystem::AdvanceTickDeltaTimes()
{
const TimeUs currentTimeUs = static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
//real time
m_realTickDeltaTimeUs = currentTimeUs - m_lastRealTickTimeUs;
m_lastRealTickTimeUs = currentTimeUs;
//game time
if (m_simulationTickDeltaOverride > AZ::Time::ZeroTimeUs)
{
m_simulationTickDeltaTimeUs = m_simulationTickDeltaOverride;
m_lastSimulationTickTimeUs = m_simulationTickDeltaTimeUs;
return m_simulationTickDeltaTimeUs;
}
m_simulationTickDeltaTimeUs = currentTimeUs - m_lastSimulationTickTimeUs;
if (!AZ::IsClose(t_simulationTickScale, 1.0f))
{
const double floatDelta = AZStd::GetMax(static_cast<double>(m_simulationTickDeltaTimeUs) * static_cast<double>(t_simulationTickScale), 1.0);
m_simulationTickDeltaTimeUs = static_cast<TimeUs>(static_cast<int64_t>(floatDelta));
}
m_lastSimulationTickTimeUs = currentTimeUs;
return m_simulationTickDeltaTimeUs;
}
void TimeSystem::ApplyTickRateLimiterIfNeeded()
{
// Currently disabling the Tick rate limiter as there are some reported issues when using it.
#ifdef ENABLE_TICK_RATE_LIMITER
// If tick rate limiting is on, ensure (1 / t_simulationTickRate) ms has elapsed since the last frame,
// sleeping if there's still time remaining.
if (t_simulationTickRate > 0)
{
const TimeUs currentTimeUs = AZ::GetRealElapsedTimeUs();
const TimeUs timeUntilNextTick = (m_lastSimulationTickTimeUs + m_simulationTickLimitTimeUs) - currentTimeUs;
if (timeUntilNextTick > AZ::Time::ZeroTimeUs)
{
AZ_TracePrintf("tick", "Sleeping for %.2f", AZ::TimeUsToSecondsDouble(timeUntilNextTick));
AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(static_cast<int64_t>(timeUntilNextTick)));
}
}
#endif // #ifdef ENABLE_TICK_RATE_LIMITER
}
void TimeSystem::SetSimulationTickDeltaOverride(TimeMs timeMs)
{
const TimeUs timeUs = AZ::TimeMsToUs(timeMs);
if (timeUs != m_simulationTickDeltaOverride)
{
m_simulationTickDeltaOverride = timeUs;
t_simulationTickDeltaOverride = AZ::TimeUsToSeconds(timeUs); //update the cvar
}
}
TimeMs TimeSystem::GetSimulationTickDeltaOverride() const
{
return AZ::TimeUsToMs(m_simulationTickDeltaOverride);
}
void TimeSystem::SetSimulationTickScale(float scale)
{
if (!AZ::IsClose(scale, t_simulationTickScale))
{
t_simulationTickScale = scale;
}
}
float TimeSystem::GetSimulationTickScale() const
{
return t_simulationTickScale;
}
void TimeSystem::SetSimulationTickRate(int rate)
{
m_simulationTickLimitRate = AZStd::abs(rate);
if (m_simulationTickLimitRate != 0)
{
m_simulationTickLimitTimeUs = AZ::SecondsToTimeUs(1.0f / m_simulationTickLimitRate);
}
else
{
m_simulationTickLimitTimeUs = AZ::Time::ZeroTimeUs;
}
}
int32_t TimeSystem::GetSimulationTickRate() const
{
return m_simulationTickLimitRate;
}
} // namespace AZ
@@ -0,0 +1,84 @@
/*
* 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/RTTI/RTTI.h>
#include <AzCore/Time/ITime.h>
namespace AZ
{
class ReflectContext;
//! Implementation of the ITime system interface.
class TimeSystem
: public ITimeRequestBus::Handler
{
public:
AZ_RTTI(AZ::TimeSystem, "{CE1C5E4F-7DC1-4248-B10C-AC55E8924A48}", AZ::ITime);
static void Reflect(AZ::ReflectContext* context);
TimeSystem();
virtual ~TimeSystem();
//! ITime overrides.
//! @{
TimeMs GetElapsedTimeMs() const override;
TimeUs GetElapsedTimeUs() const override;
TimeMs GetRealElapsedTimeMs() const override;
TimeUs GetRealElapsedTimeUs() const override;
TimeUs GetSimulationTickDeltaTimeUs() const override;
TimeUs GetRealTickDeltaTimeUs() const override;
TimeUs GetLastSimulationTickTime() const override;
void SetSimulationTickDeltaOverride(TimeMs timeMs) override;
TimeMs GetSimulationTickDeltaOverride() const override;
void SetSimulationTickScale(float scale) override;
float GetSimulationTickScale() const override;
void SetSimulationTickRate(int rate) override;
int32_t GetSimulationTickRate() const override;
//! @}
//! Advances the Simulation and Real tick delta time counters.
//! This is called from the owner of the TimeSystem, ComponentApplication in Tick().
//! @return The delta in microseconds from the last call to AdvanceTickDeltaTimes(). Value will be the same as GetSimulationTickDeltaTimeUs().
TimeUs AdvanceTickDeltaTimes();
//! If t_simulationTickRate is >0 this will try to have the game delta time run at a maximum of the rate set.
//! This is called from the owner of the TimeSystem, ComponentApplication in Tick().
//! example. If t_simulationTickRate is set to 60Fps, and the game tick delta is <17ms(60fps), this will add a sleep for the remaining time.
//! example. If t_simulationTickRate is set to 60Fps, and the game tick delta is >=17ms(60fps), this will not sleep at all.
//! @note It is not guaranteed to hit the requested tick rate exactly.
void ApplyTickRateLimiterIfNeeded();
private:
//! Used to calculate the delta time between calls to GetElapsedTimeMs/TimeUs().
//! Mutable to allow GetElapsedTimeMs/TimeUs() to be a const functions.
mutable TimeUs m_lastInvokedTimeUs = AZ::Time::ZeroTimeUs;
//! Accumulates the delta time of GetElapsedTimeMs/TimeUs() calls.
//! Mutable to allow GetElapsedTimeMs/TimeUs() to be a const functions.
mutable TimeUs m_accumulatedTimeUs = AZ::Time::ZeroTimeUs;
//! The current game tick delta time.
//! Can be affected by time system cvars.
//! Updated in AdvanceTickDeltaTimes().
TimeUs m_simulationTickDeltaTimeUs = AZ::Time::ZeroTimeUs;
//! The current real tick delta time.
//! Will not be affected by time system cvars.
//! Updated in AdvanceTickDeltaTimes().
TimeUs m_realTickDeltaTimeUs = AZ::Time::ZeroTimeUs;
TimeUs m_lastSimulationTickTimeUs = AZ::Time::ZeroTimeUs; //!< Used to determine the game tick delta time (affected by cvars).
TimeUs m_lastRealTickTimeUs = AZ::Time::ZeroTimeUs; //!< Used to determine the real game tick delta time (not affected by cvars).
TimeUs m_simulationTickDeltaOverride = AZ::Time::ZeroTimeUs; //<! Stores the TimeUs value of the t_simulationTickDeltaOverride cvar.
TimeUs m_simulationTickLimitTimeUs = AZ::Time::ZeroTimeUs; //<! Stores the TimeUs value of the t_simulationTickRate cvar.
int32_t m_simulationTickLimitRate = 0; //<! Stores the simulation rate limit in frames per second.
};
}
@@ -1,80 +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
*
*/
#include <AzCore/Time/TimeSystemComponent.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
AZ_CVAR(float, t_scale, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "A scalar amount to adjust time passage by, 1.0 == realtime, 0.5 == half realtime, 2.0 == doubletime");
void TimeSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<TimeSystemComponent, AZ::Component>()
->Version(1);
}
}
void TimeSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("TimeService"));
}
void TimeSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("TimeService"));
}
TimeSystemComponent::TimeSystemComponent()
{
m_lastInvokedTimeUs = static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
AZ::Interface<ITime>::Register(this);
ITimeRequestBus::Handler::BusConnect();
}
TimeSystemComponent::~TimeSystemComponent()
{
ITimeRequestBus::Handler::BusDisconnect();
AZ::Interface<ITime>::Unregister(this);
}
void TimeSystemComponent::Activate()
{
;
}
void TimeSystemComponent::Deactivate()
{
;
}
TimeMs TimeSystemComponent::GetElapsedTimeMs() const
{
return TimeUsToMs(GetElapsedTimeUs());
}
TimeUs TimeSystemComponent::GetElapsedTimeUs() const
{
TimeUs currentTime = static_cast<TimeUs>(AZStd::GetTimeNowMicroSecond());
TimeUs deltaTime = currentTime - m_lastInvokedTimeUs;
if (t_scale != 1.0f)
{
float floatDelta = static_cast<float>(deltaTime) * t_scale;
deltaTime = static_cast<TimeUs>(static_cast<int64_t>(floatDelta));
}
m_accumulatedTimeUs += deltaTime;
m_lastInvokedTimeUs = currentTime;
return m_accumulatedTimeUs;
}
}
@@ -1,50 +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/Time/ITime.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Console/IConsole.h>
namespace AZ
{
//! Implementation of the ITime system interface.
class TimeSystemComponent
: public AZ::Component
, public ITimeRequestBus::Handler
{
public:
AZ_COMPONENT(TimeSystemComponent, "{CE1C5E4F-7DC1-4248-B10C-AC55E8924A48}");
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
TimeSystemComponent();
virtual ~TimeSystemComponent();
//! AZ::Component overrides.
//! @{
void Activate() override;
void Deactivate() override;
//! @}
//! ITime overrides.
//! @{
TimeMs GetElapsedTimeMs() const override;
TimeUs GetElapsedTimeUs() const override;
//! @}
private:
mutable TimeUs m_lastInvokedTimeUs = TimeUs{0};
mutable TimeUs m_accumulatedTimeUs = TimeUs{0};
};
}
@@ -0,0 +1,119 @@
/*
* 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/Time/TimeSystem.h>
#include <gmock/gmock.h>
namespace AZ
{
class MockTimeSystem;
using NiceTimeSystemMock =::testing::NiceMock<MockTimeSystem>;
//used if you wish to mock any of the Get time functions.
class MockTimeSystem
: public ITimeRequestBus::Handler
{
public:
MockTimeSystem()
{
AZ::Interface<ITime>::Register(this);
ITimeRequestBus::Handler::BusConnect();
}
virtual ~MockTimeSystem()
{
AZ::Interface<ITime>::Unregister(this);
ITimeRequestBus::Handler::BusDisconnect();
}
MOCK_CONST_METHOD0(GetElapsedTimeMs, TimeMs());
MOCK_CONST_METHOD0(GetElapsedTimeUs, TimeUs());
MOCK_CONST_METHOD0(GetRealElapsedTimeMs, TimeMs());
MOCK_CONST_METHOD0(GetRealElapsedTimeUs, TimeUs());
MOCK_CONST_METHOD0(GetSimulationTickDeltaTimeUs, TimeUs());
MOCK_CONST_METHOD0(GetRealTickDeltaTimeUs, TimeUs());
MOCK_CONST_METHOD0(GetLastSimulationTickTime, TimeUs());
MOCK_METHOD1(SetSimulationTickDeltaOverride, void(TimeMs));
MOCK_CONST_METHOD0(GetSimulationTickDeltaOverride, TimeMs());
MOCK_METHOD1(SetSimulationTickScale, void(float));
MOCK_CONST_METHOD0(GetSimulationTickScale, float());
MOCK_METHOD1(SetSimulationTickRate, void(int));
MOCK_CONST_METHOD0(GetSimulationTickRate, int32_t());
};
//used if you wish to override any of the Get time functions with specific functionality.
class StubTimeSystem
: public AZ::TimeSystem
{
public:
AZ_RTTI(AZ::StubTimeSystem, "{DD5D5A6A-345F-49FD-A61E-A40E63C49CFA}", AZ::TimeSystem);
virtual AZ::TimeMs GetElapsedTimeMs() const override
{
return AZ::Time::ZeroTimeMs;
}
virtual AZ::TimeUs GetElapsedTimeUs() const override
{
return AZ::Time::ZeroTimeUs;
}
virtual AZ::TimeMs GetRealElapsedTimeMs() const override
{
return AZ::Time::ZeroTimeMs;
}
virtual AZ::TimeUs GetRealElapsedTimeUs() const override
{
return AZ::Time::ZeroTimeUs;
}
virtual AZ::TimeUs GetSimulationTickDeltaTimeUs() const override
{
return AZ::Time::ZeroTimeUs;
}
virtual AZ::TimeUs GetRealTickDeltaTimeUs() const override
{
return AZ::Time::ZeroTimeUs;
}
virtual AZ::TimeUs GetLastSimulationTickTime() const override
{
return AZ::Time::ZeroTimeUs;
}
virtual void SetSimulationTickDeltaOverride([[maybe_unused]]TimeMs timeMs) override
{
}
virtual TimeMs GetSimulationTickDeltaOverride() const override
{
return AZ::Time::ZeroTimeMs;
}
virtual void SetSimulationTickScale([[maybe_unused]] float scale) override
{
}
virtual float GetSimulationTickScale() const override
{
return 1.0f;
}
virtual void SetSimulationTickRate([[maybe_unused]] int rate) override
{
}
virtual int32_t GetSimulationTickRate() const override
{
return 0;
}
};
} // namespace AZ
@@ -654,8 +654,8 @@ set(FILES
Threading/ThreadUtils.h
Threading/ThreadUtils.cpp
Time/ITime.h
Time/TimeSystemComponent.cpp
Time/TimeSystemComponent.h
Time/TimeSystem.cpp
Time/TimeSystem.h
)
# Prevent the following files from being grouped in UNITY builds
@@ -12,5 +12,6 @@ set(FILES
UnitTest/UnitTest.h
UnitTest/TestTypes.h
UnitTest/Mocks/MockFileIOBase.h
UnitTest/Mocks/MockITime.h
UnitTest/Mocks/MockSettingsRegistry.h
)
-1
View File
@@ -6,7 +6,6 @@
*
*/
#include <AzCore/Debug/Timer.h>
#include <AzCore/Debug/StackTracer.h>
#include <AzCore/Debug/TraceMessagesDrillerBus.h>
#include <AzCore/Debug/Profiler.h>
@@ -11,7 +11,7 @@
#include <AzCore/EBus/ScheduledEvent.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Console/LoggerSystemComponent.h>
#include <AzCore/Time/TimeSystemComponent.h>
#include <AzCore/Time/TimeSystem.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/UnitTest/TestTypes.h>
@@ -26,22 +26,22 @@ namespace UnitTest
SetupAllocator();
AZ::NameDictionary::Create();
m_loggerComponent = new AZ::LoggerSystemComponent;
m_timeComponent = new AZ::TimeSystemComponent;
m_eventSchedulerComponent = new AZ::EventSchedulerSystemComponent;
m_loggerComponent = AZStd::make_unique<AZ::LoggerSystemComponent>();
m_timeSystem = AZStd::make_unique<AZ::TimeSystem>();
m_eventSchedulerComponent = AZStd::make_unique<AZ::EventSchedulerSystemComponent>();
m_testEvent = new AZ::ScheduledEvent([this] { TestBasicEvent(); }, AZ::Name("UnitTestEvent fire once event"));
m_testRequeue = new AZ::ScheduledEvent([this] { TestAutoRequeuedEvent(); }, AZ::Name("UnitTestEvent auto Requeue"));
m_testEvent = AZStd::make_unique<AZ::ScheduledEvent>([this] { TestBasicEvent(); }, AZ::Name("UnitTestEvent fire once event"));
m_testRequeue = AZStd::make_unique<AZ::ScheduledEvent>([this] { TestAutoRequeuedEvent(); }, AZ::Name("UnitTestEvent auto Requeue"));
}
void TearDown() override
{
delete m_testEvent;
delete m_testRequeue;
m_testEvent.reset();
m_testRequeue.reset();
delete m_eventSchedulerComponent;
delete m_timeComponent;
delete m_loggerComponent;
m_eventSchedulerComponent.reset();
m_timeSystem.reset();
m_loggerComponent.reset();
AZ::NameDictionary::Destroy();
TeardownAllocator();
@@ -60,12 +60,12 @@ namespace UnitTest
uint32_t m_basicEventTriggerCount = 0;
uint32_t m_requeuedEventTriggerCount = 0;
AZ::ScheduledEvent* m_testEvent = nullptr;
AZ::ScheduledEvent* m_testRequeue = nullptr;
AZStd::unique_ptr<AZ::ScheduledEvent> m_testEvent;
AZStd::unique_ptr<AZ::ScheduledEvent> m_testRequeue;
AZ::LoggerSystemComponent* m_loggerComponent = nullptr;
AZ::TimeSystemComponent* m_timeComponent = nullptr;
AZ::EventSchedulerSystemComponent* m_eventSchedulerComponent = nullptr;
AZStd::unique_ptr<AZ::LoggerSystemComponent> m_loggerComponent;
AZStd::unique_ptr<AZ::TimeSystem> m_timeSystem;
AZStd::unique_ptr<AZ::EventSchedulerSystemComponent> m_eventSchedulerComponent;
};
TEST_F(ScheduledEventTests, TestFireOnce)
+28 -4
View File
@@ -6,7 +6,7 @@
*
*/
#include <AzCore/Time/TimeSystemComponent.h>
#include <AzCore/Time/TimeSystem.h>
#include <AzCore/UnitTest/TestTypes.h>
namespace UnitTest
@@ -18,16 +18,16 @@ namespace UnitTest
void SetUp() override
{
SetupAllocator();
m_timeComponent = new AZ::TimeSystemComponent;
m_timeSystem = AZStd::make_unique<AZ::TimeSystem>();
}
void TearDown() override
{
delete m_timeComponent;
m_timeSystem.reset();
TeardownAllocator();
}
AZ::TimeSystemComponent* m_timeComponent = nullptr;
AZStd::unique_ptr<AZ::TimeSystem> m_timeSystem;
};
TEST_F(TimeTests, TestConversionUsToMs)
@@ -44,6 +44,30 @@ namespace UnitTest
EXPECT_EQ(timeUs, AZ::TimeUs{ 1000000 });
}
TEST_F(TimeTests, TestConversionTimeMsToSeconds)
{
AZ::TimeMs timeMs = AZ::TimeMs{ 1000 };
float timeSecondsFloat = AZ::TimeMsToSeconds(timeMs);
EXPECT_TRUE(AZ::IsClose(timeSecondsFloat, 1.0f));
double timeSecondsDouble = AZ::TimeMsToSecondsDouble(timeMs);
EXPECT_TRUE(AZ::IsClose(timeSecondsDouble, 1.0));
}
TEST_F(TimeTests, TestConversionSecondsToTimeUs)
{
double seconds = 1.0;
AZ::TimeUs timeUs = AZ::SecondsToTimeUs(seconds);
EXPECT_EQ(timeUs, AZ::TimeUs{ 1000000 });
}
TEST_F(TimeTests, TestConversionSecondsToTimeMs)
{
double seconds = 1.0;
AZ::TimeMs timeMs = AZ::SecondsToTimeMs(seconds);
EXPECT_EQ(timeMs, AZ::TimeMs{ 1000 });
}
TEST_F(TimeTests, TestClocks)
{
AZ::TimeUs timeUs = AZ::GetElapsedTimeUs();