Merge pull request #4426 from aws-lumberyard-dev/Atom/santorac/FixSceneSrgTime

Fixed potential render scene time precision issues.

The timestamp was simply converted from GetTimeAtCurrentTick to a float. Since this value is backed by QueryPerformanceCounter which is 0 at boot, you could see broken animations on the GPU when your system has been on for a long time. So I simplified the RPI's time API (removed unused code), and subtracted the application start time each frame before converting the time value to a float.

Also moved FindShaderInputConstantIndex("m_time") to be called only once, instead of every frame.

Testing:
Originally: I had a local material shader that did vertex animation and it wasn't working at all before, and now it works.
More recently, I made local changes to StandardPBR to add a simple sin wave animation. I also modified GetTimeNowMicroSecond() to artificially add 30 days to the clock. This showed choppy animation before my changes, and smooth animation after.
AtomSampleViewer passed dx12 and vulkan (other than pre-existing issues)
This commit is contained in:
santorac
2021-11-08 19:35:00 -08:00
committed by GitHub
6 changed files with 30 additions and 33 deletions
@@ -268,21 +268,23 @@ namespace AZ
AssetInitBus::Broadcast(&AssetInitBus::Events::PostLoadInit);
// Update tick time info
FillTickTimeInfo();
m_currentSimulationTime = GetCurrentTime();
for (auto& scene : m_scenes)
{
scene->Simulate(m_tickTime, m_simulationJobPolicy);
scene->Simulate(m_simulationJobPolicy, m_currentSimulationTime);
}
}
void RPISystem::FillTickTimeInfo()
float RPISystem::GetCurrentTime()
{
AZ::TickRequestBus::BroadcastResult(m_tickTime.m_gameDeltaTime, &AZ::TickRequestBus::Events::GetTickDeltaTime);
ScriptTimePoint currentTime;
AZ::TickRequestBus::BroadcastResult(currentTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
m_tickTime.m_currentGameTime = static_cast<float>(currentTime.GetSeconds());
ScriptTimePoint timeAtCurrentTick;
AZ::TickRequestBus::BroadcastResult(timeAtCurrentTick, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
// We subtract the start time to maximize precision of the time value, since we will be converting it to a float.
double currentTime = timeAtCurrentTick.GetSeconds() - m_startTime.GetSeconds();
return aznumeric_cast<float>(currentTime);
}
void RPISystem::RenderTick()
@@ -301,7 +303,7 @@ namespace AZ
// [GFX TODO] We may parallel scenes' prepare render.
for (auto& scenePtr : m_scenes)
{
scenePtr->PrepareRender(m_tickTime, m_prepareRenderJobPolicy);
scenePtr->PrepareRender(m_prepareRenderJobPolicy, m_currentSimulationTime);
}
m_rhiSystem.FrameUpdate(
@@ -375,7 +375,7 @@ namespace AZ
m_scene->RemoveRenderPipeline(m_nameId);
}
void RenderPipeline::OnStartFrame([[maybe_unused]] const TickTimeInfo& tick)
void RenderPipeline::OnStartFrame([[maybe_unused]] float time)
{
AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
@@ -44,6 +44,9 @@ namespace AZ
{
auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs();
scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName());
// Set value for constants defined in SceneTimeSrg.azsli
scene->m_timeInputIndex = scene->m_srg->FindShaderInputConstantIndex(Name{ "m_time" });
}
scene->m_name = sceneDescriptor.m_nameId;
@@ -410,11 +413,11 @@ namespace AZ
//[GFX TODO]: the completion job should start here
}
void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
void Scene::Simulate(RHI::JobPolicy jobPolicy, float simulationTime)
{
AZ_PROFILE_SCOPE(RPI, "Scene: Simulate");
m_simulationTime = tickInfo.m_currentGameTime;
m_simulationTime = simulationTime;
// If previous simulation job wasn't done, wait for it to finish.
if (m_taskGraphActive)
@@ -480,11 +483,9 @@ namespace AZ
{
if (m_srg)
{
// Set value for constants defined in SceneTimeSrg.azsli
RHI::ShaderInputConstantIndex timeIndex = m_srg->FindShaderInputConstantIndex(Name{ "m_time" });
if (timeIndex.IsValid())
if (m_timeInputIndex.IsValid())
{
m_srg->SetConstant(timeIndex, m_simulationTime);
m_srg->SetConstant(m_timeInputIndex, m_simulationTime);
}
// signal any handlers to update values for their partial scene srg
@@ -633,7 +634,7 @@ namespace AZ
WaitAndCleanCompletionJob(finalizeDrawListsCompletion);
}
void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
void Scene::PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime)
{
AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender");
@@ -657,7 +658,7 @@ namespace AZ
if (pipeline->NeedsRender())
{
activePipelines.push_back(pipeline);
pipeline->OnStartFrame(tickInfo);
pipeline->OnStartFrame(simulationTime);
}
}
}