Atom Pass changes WIP: ASV screenshot tests passing now

This commit is contained in:
antonmic
2021-06-05 19:12:45 -07:00
parent 1e5a35ccfe
commit ed759612dd
14 changed files with 208 additions and 112 deletions
@@ -519,13 +519,13 @@ namespace AZ
io.Fonts->TexID = reinterpret_cast<ImTextureID>(m_fontAtlas.get());
}
void ImGuiPass::OnBuildFinishedInternal()
void ImGuiPass::InitializeInternal()
{
// Set output format and finalize pipeline state
m_pipelineState->SetOutputFromPass(this);
m_pipelineState->Finalize();
Base::OnBuildFinishedInternal();
Base::InitializeInternal();
}
void ImGuiPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
@@ -94,7 +94,7 @@ namespace AZ
explicit ImGuiPass(const RPI::PassDescriptor& descriptor);
// Pass Behaviour Overrides...
void OnBuildFinishedInternal() override;
void InitializeInternal() override;
void FrameBeginInternal(FramePrepareParams params) override;
// Scope producer functions
@@ -41,9 +41,9 @@ namespace AZ
return ParentPass::IsEnabled();
}
void SsaoParentPass::OnBuildFinishedInternal()
void SsaoParentPass::InitializeInternal()
{
ParentPass::OnBuildFinishedInternal();
ParentPass::InitializeInternal();
m_blurParentPass = FindChildPass(Name("SsaoBlur"))->AsParent();
AZ_Assert(m_blurParentPass, "[SsaoParentPass] Could not retrieve parent blur pass.");
@@ -36,7 +36,7 @@ namespace AZ
protected:
// Behavior functions override...
void OnBuildFinishedInternal() override;
void InitializeInternal() override;
void FrameBeginInternal(FramePrepareParams params) override;
private:
@@ -99,7 +99,7 @@ namespace AZ
void DecomposeExecute(const RHI::FrameGraphExecuteContext& context);
// copy data from the read back buffer (m_readbackBuffer) to the data buffer (m_dataBuffer)
void CopyBufferData(uint32_t readbackBufferIndex);
bool CopyBufferData(uint32_t readbackBufferIndex);
// Get read back data in a structure
ReadbackResult GetReadbackResult() const;
@@ -110,7 +110,7 @@ namespace AZ
void ResetInternal() override;
void BuildInternal() override;
void OnBuildFinishedInternal() override;
void OnInitializationFinishedInternal() override;
void InitializeInternal() override;
void FrameBeginInternal(FramePrepareParams params) override;
void FrameEndInternal() override;
@@ -320,12 +320,12 @@ namespace AZ
// Builds and sets up any attachments and input/output connections the pass needs.
// Called from PassSystem when pass is QueueForBuild.
void Build();
void Build(bool calledFromPassSystem = false);
virtual void BuildInternal() { }
// Called after the pass build phase has finished. Allows passes to reset build flags.
void OnBuildFinished();
virtual void OnBuildFinishedInternal() { };
void OnInitializationFinished();
virtual void OnInitializationFinishedInternal() { };
// Allows for additional pass initialization between building and rendering
// Can be queued independently of Build so as to only invoke Initialize without Build
@@ -395,6 +395,12 @@ namespace AZ
uint64_t m_initialized : 1;
uint64_t m_alreadyCreated : 1;
// OLD SCHOOL
uint64_t m_alreadyReset : 1;
uint64_t m_alreadyPrepared : 1;
uint64_t m_queuedForBuildAttachment : 1;
uint64_t m_partOfHierarchy : 1;
uint64_t m_hasDrawListTag : 1;
uint64_t m_hasPipelineViewTag : 1;
@@ -20,7 +20,7 @@
// Enables debugging of the pass system
// Set this to 1 locally on your machine to facilitate pass debugging and get extra information
// about passes in the output window. DO NOT SUBMIT with value set to 1
#define AZ_RPI_ENABLE_PASS_DEBUGGING 0
#define AZ_RPI_ENABLE_PASS_DEBUGGING 1
namespace AZ
{
@@ -31,9 +31,12 @@ namespace AZ
Uninitialized,
Queued,
Resetting,
Reset,
Building,
Built,
Initializing,
Initialized,
Idle,
Rendering
};
@@ -96,7 +96,7 @@ namespace AZ
void BindPassSrg(const RHI::FrameGraphCompileContext& context, Data::Instance<ShaderResourceGroup>& shaderResourceGroup);
// Pass behavior overrides...
void OnBuildFinishedInternal() override;
void InitializeInternal() override;
void FrameBeginInternal(FramePrepareParams params) override;
void FrameEndInternal() override;
@@ -320,8 +320,14 @@ namespace AZ
{
if (m_state == ReadbackState::Reading)
{
CopyBufferData(readbackBufferCurrentIndex);
m_state = ReadbackState::Success;
if (CopyBufferData(readbackBufferCurrentIndex))
{
m_state = ReadbackState::Success;
}
else
{
m_state = ReadbackState::Failed;
}
}
if (m_callback)
{
@@ -498,13 +504,13 @@ namespace AZ
return result;
}
void AttachmentReadback::CopyBufferData(uint32_t readbackBufferIndex)
bool AttachmentReadback::CopyBufferData(uint32_t readbackBufferIndex)
{
Data::Instance<Buffer> readbackBufferCurrent = m_readbackBufferArray[readbackBufferIndex];
if (!readbackBufferCurrent)
{
return;
return false;
}
auto bufferSize = readbackBufferCurrent->GetBufferSize();
@@ -537,6 +543,7 @@ namespace AZ
}
m_isReadbackComplete[readbackBufferIndex] = true;
return true;
}
} // namespace RPI
} // namespace AZ
@@ -270,10 +270,10 @@ namespace AZ
void ParentPass::ResetInternal()
{
for (const Ptr<Pass>& child : m_children)
{
child->Reset();
}
//for (const Ptr<Pass>& child : m_children)
//{
// child->Reset();
//}
}
void ParentPass::BuildInternal()
@@ -284,11 +284,11 @@ namespace AZ
}
}
void ParentPass::OnBuildFinishedInternal()
void ParentPass::OnInitializationFinishedInternal()
{
for (const Ptr<Pass>& child : m_children)
{
child->OnBuildFinished();
child->OnInitializationFinished();
}
}
@@ -37,10 +37,13 @@
#include <Atom/RPI.Reflect/Pass/PassName.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
namespace AZ
{
namespace RPI
{
#pragma optimize("", off)
// --- Constructors ---
Pass::Pass(const PassDescriptor& descriptor)
@@ -152,6 +155,7 @@ namespace AZ
AZ_RPI_PASS_ASSERT(m_parent != nullptr, "Trying to remove pass from parent but pointer to the parent pass is null.");
m_parent->RemoveChild(Ptr<Pass>(this));
m_queueState = PassQueueState::NoQueue;
m_state = PassState::Idle;
}
void Pass::OnOrphan()
@@ -354,53 +358,6 @@ namespace AZ
return nullptr;
}
// --- Queuing functions with PassSystem ---
void Pass::QueueForBuild()
{
// Don't queue if we're in building phase
if (m_state != PassState::Building &&
(m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization))
{
PassSystemInterface::Get()->QueueForBuild(this);
m_queueState = PassQueueState::QueuedForBuild;
if (m_state != PassState::Rendering)
{
m_state = PassState::Queued;
}
}
}
void Pass::QueueForInitialization()
{
// Don't queue if we're in initialization phase
if (m_queueState == PassQueueState::NoQueue)
{
PassSystemInterface::Get()->QueueForInitialization(this);
m_queueState = PassQueueState::QueuedForInitialization;
if(m_state != PassState::Rendering)
{
m_state = PassState::Queued;
}
}
}
void Pass::QueueForRemoval()
{
if (m_queueState != PassQueueState::QueuedForRemoval)
{
PassSystemInterface::Get()->QueueForRemoval(this);
m_queueState = PassQueueState::QueuedForRemoval;
if (m_state != PassState::Rendering)
{
m_state = PassState::Queued;
}
}
}
// --- PassTemplate related functions ---
void Pass::CreateBindingsFromTemplate()
@@ -430,7 +387,7 @@ namespace AZ
PassAttachmentBinding* localBinding = FindAttachmentBinding(slot);
if (!localBinding)
{
AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Pass %s failed to find slot %s.",
AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Pass [%s] failed to find slot [%s].",
m_path.GetCStr(), slot.GetCStr());
return;
}
@@ -440,7 +397,7 @@ namespace AZ
// handle the connected bindings
if (localBinding->m_attachment)
{
AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Slot %s already has attachment %s.",
AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Slot [%s] already has attachment [%s].",
slot.GetCStr(), localBinding->m_attachment->m_name.GetCStr());
return;
}
@@ -462,7 +419,7 @@ namespace AZ
PassAttachmentBinding* localBinding = FindAttachmentBinding(slot);
if (!localBinding)
{
AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Pass %s failed to find slot %s.",
AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Pass [%s] failed to find slot [%s].",
m_path.GetCStr(), slot.GetCStr());
return;
}
@@ -472,7 +429,7 @@ namespace AZ
// handle the connected bindings
if (localBinding->m_attachment)
{
AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Slot %s already has attachment %s.",
AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Slot [%s] already has attachment [%s].",
slot.GetCStr(), localBinding->m_attachment->m_name.GetCStr());
return;
}
@@ -495,7 +452,7 @@ namespace AZ
PassAttachmentBinding* localBinding = FindAttachmentBinding(connection.m_localSlot);
if (!localBinding)
{
AZ_RPI_PASS_ERROR(false, "Pass::ProcessConnection - Pass %s failed to find slot %s.",
AZ_RPI_PASS_ERROR(false, "Pass::ProcessConnection - Pass [%s] failed to find slot [%s].",
m_path.GetCStr(),
connection.m_localSlot.GetCStr());
return;
@@ -517,7 +474,7 @@ namespace AZ
{
foundPass = true;
const Ptr<PassAttachment> attachment = FindOwnedAttachment(connectedSlotName);
AZ_RPI_PASS_ERROR(attachment, "Pass::ProcessConnection - Pass %s doesn't own an attachment named %s.",
AZ_RPI_PASS_ERROR(attachment, "Pass::ProcessConnection - Pass [%s] doesn't own an attachment named [%s].",
m_path.GetCStr(),
connectedSlotName.GetCStr());
localBinding->SetAttachment(attachment);
@@ -628,10 +585,10 @@ namespace AZ
if (!outputBinding || !inputBinding)
{
AZ_RPI_PASS_ERROR(inputBinding, "Pass::ProcessFallbackConnection - Pass %s failed to find input slot %s.",
AZ_RPI_PASS_ERROR(inputBinding, "Pass::ProcessFallbackConnection - Pass [%s] failed to find input slot [%s].",
m_path.GetCStr(), connection.m_inputSlotName.GetCStr());
AZ_RPI_PASS_ERROR(outputBinding, "Pass::ProcessFallbackConnection - Pass %s failed to find output slot %s.",
AZ_RPI_PASS_ERROR(outputBinding, "Pass::ProcessFallbackConnection - Pass [%s] failed to find output slot [%s].",
m_path.GetCStr(), connection.m_outputSlotName.GetCStr());
return;
@@ -641,10 +598,10 @@ namespace AZ
if (!typesAreValid)
{
AZ_RPI_PASS_ERROR(inputBinding->m_slotType == PassSlotType::Input, "Pass::ProcessFallbackConnection - Pass %s specifies fallback connection input %s, which is not an input.",
AZ_RPI_PASS_ERROR(inputBinding->m_slotType == PassSlotType::Input, "Pass::ProcessFallbackConnection - Pass [%s] specifies fallback connection input [%s], which is not an input.",
m_path.GetCStr(), connection.m_inputSlotName.GetCStr());
AZ_RPI_PASS_ERROR(outputBinding->m_slotType == PassSlotType::Output, "Pass::ProcessFallbackConnection - Pass %s specifies fallback connection output %s, which is not an output.",
AZ_RPI_PASS_ERROR(outputBinding->m_slotType == PassSlotType::Output, "Pass::ProcessFallbackConnection - Pass [%s] specifies fallback connection output [%s], which is not an output.",
m_path.GetCStr(), connection.m_inputSlotName.GetCStr());
return;
@@ -1038,7 +995,7 @@ namespace AZ
// Check whether the template's slot allows this attachment
if (m_template && !m_template->AttachmentFitsSlot(targetAttachment->m_descriptor, binding.m_name))
{
AZ_RPI_PASS_ERROR(false, "Pass::UpdateConnectedBinding - Attachment %s did not match the filters of input slot %s on pass %s.",
AZ_RPI_PASS_ERROR(false, "Pass::UpdateConnectedBinding - Attachment [%s] did not match the filters of input slot [%s] on pass [%s].",
targetAttachment->m_name.GetCStr(),
binding.m_name.GetCStr(),
m_path.GetCStr());
@@ -1060,14 +1017,86 @@ namespace AZ
}
}
// --- Queuing functions with PassSystem ---
#define OLD_SCHOOL 1
void Pass::QueueForBuild()
{
#if OLD_SCHOOL
// Don't queue if we're in building phase
//if (PassSystemInterface::Get()->GetState() != RPI::PassSystemState::Building)
{
if (!m_flags.m_queuedForBuildAttachment)
{
PassSystemInterface::Get()->QueueForBuild(this);
m_flags.m_queuedForBuildAttachment = true;
// Set these two flags to false since when queue build attachments request, they should all be already be false except one use
// case that the pass system processed all queued requests when active a scene.
// m_flags.m_alreadyPrepared = false;
m_queueState = PassQueueState::QueuedForBuild;
if (m_state != PassState::Rendering)
{
m_state = PassState::Queued;
}
}
}
#else
// Don't queue if we're in building phase
if (m_state != PassState::Building &&
(m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization))
{
//if (PassSystemInterface::Get()->GetState() != RPI::PassSystemState::Building)
{
PassSystemInterface::Get()->QueueForBuild(this);
}
m_queueState = PassQueueState::QueuedForBuild;
if (m_state != PassState::Rendering)
{
m_state = PassState::Queued;
}
}
#endif
}
void Pass::QueueForInitialization()
{
// Only queue if the pass is not in any other queue
if (m_queueState == PassQueueState::NoQueue)
{
PassSystemInterface::Get()->QueueForInitialization(this);
m_queueState = PassQueueState::QueuedForInitialization;
if (m_state != PassState::Rendering && m_state != PassState::Built)
{
m_state = PassState::Queued;
}
}
}
void Pass::QueueForRemoval()
{
if (m_queueState != PassQueueState::QueuedForRemoval)
{
PassSystemInterface::Get()->QueueForRemoval(this);
m_queueState = PassQueueState::QueuedForRemoval;
if (m_state != PassState::Rendering)
{
m_state = PassState::Queued;
}
}
}
// --- Pass behavior functions ---
void Pass::Reset()
{
if (m_queueState != PassQueueState::QueuedForBuild || m_state != PassState::Queued)
{
return;
}
m_state = PassState::Resetting;
// Store references to imported attachments to underlying images and buffers aren't deleted during attachment building
@@ -1083,19 +1112,37 @@ namespace AZ
m_executeBeforePasses.clear();
ResetInternal();
m_state = PassState::Reset;
}
void Pass::Build()
void Pass::Build(bool calledFromPassSystem)
{
if (m_queueState != PassQueueState::QueuedForBuild || (m_state != PassState::Queued && m_state != PassState::Resetting))
AZ_RPI_BREAK_ON_TARGET_PASS;
bool execute = (m_state == PassState::Idle);
execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild);
execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization);
#if OLD_SCHOOL
AZ_Assert(!execute == m_flags.m_alreadyPrepared, "ANTON - EARLY OUT FLAGS do not match for pass BUILD!!");
if (m_flags.m_alreadyPrepared)
{
return;
}
m_flags.m_alreadyPrepared = true;
#else
if (!execute)
{
return;
}
#endif
Reset();
m_state = PassState::Building;
m_queueState = PassQueueState::NoQueue;
AZ_RPI_BREAK_ON_TARGET_PASS;
// Bindings, inputs and attachments
CreateBindingsFromTemplate();
SetupInputsFromRequest();
@@ -1116,32 +1163,51 @@ namespace AZ
UpdateOwnedAttachments();
UpdateAttachmentUsageIndices();
// Queue for Initialization
QueueForInitialization();
}
m_state = PassState::Built;
void Pass::OnBuildFinished()
{
AZ_RPI_BREAK_ON_TARGET_PASS;
m_flags.m_alreadyCreated = false;
m_importedAttachmentStore.clear();
OnBuildFinishedInternal();
// If this pass's Build() wasn't called from the Pass System, then it was called by it's parent pass
// In which case we don't need to queue for initialization because the parent will already be queued
if (calledFromPassSystem)
{
// Queue for Initialization
QueueForInitialization();
}
}
void Pass::Initialize()
{
if (m_queueState != PassQueueState::QueuedForInitialization || m_state != PassState::Queued)
AZ_RPI_BREAK_ON_TARGET_PASS;
bool execute = (m_state == PassState::Idle || m_state == PassState::Built);
execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization);
if (!execute)
{
return;
}
m_queueState = PassQueueState::NoQueue;
m_state = PassState::Initializing;
m_queueState = PassQueueState::NoQueue;
InitializeInternal();
m_state = PassState::Initialized;
}
void Pass::OnInitializationFinished()
{
AZ_RPI_BREAK_ON_TARGET_PASS;
m_flags.m_alreadyPrepared = false;
m_flags.m_queuedForBuildAttachment = false;
m_flags.m_alreadyCreated = false;
m_importedAttachmentStore.clear();
OnInitializationFinishedInternal();
m_state = PassState::Idle;
}
void Pass::Validate(PassValidationResults& validationResults)
{
if (PassValidation::IsEnabled())
@@ -1195,6 +1261,8 @@ namespace AZ
UpdateConnectedBindings();
return;
}
AZ_Assert(m_state == PassState::Idle, "Pass::FrameBegin - Pass [%s] is attempting to render, but is not in the Idle state.", m_path.GetCStr());
m_state = PassState::Rendering;
UpdateConnectedBindings();
@@ -1213,7 +1281,7 @@ namespace AZ
if (m_state == PassState::Rendering)
{
FrameEndInternal();
m_state = (m_queueState == PassQueueState::NoQueue) ? PassState::Initialized : PassState::Queued;
m_state = (m_queueState == PassQueueState::NoQueue) ? PassState::Idle : PassState::Queued;
}
}
@@ -1578,6 +1646,8 @@ namespace AZ
}
}
#pragma optimize("", on)
} // namespace RPI
} // namespace AZ
@@ -50,6 +50,8 @@ namespace AZ
{
namespace RPI
{
#pragma optimize("", off)
PassSystemInterface* PassSystemInterface::Get()
{
return Interface<PassSystemInterface>::Get();
@@ -101,6 +103,8 @@ namespace AZ
m_rootPass = CreatePass<ParentPass>(Name{"Root"});
m_rootPass->m_flags.m_partOfHierarchy = true;
//m_targetedPassDebugName = "RPISamplePipeline";
m_state = PassSystemState::Idle;
}
@@ -189,7 +193,8 @@ namespace AZ
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments");
m_passHierarchyChanged = !m_buildPassList.empty();
m_passHierarchyChanged = m_passHierarchyChanged || !m_buildPassList.empty();
u32 loopCounter = 0;
// While loop is for the event in which passes being built add more pass to m_buildPassList
while(!m_buildPassList.empty())
@@ -211,19 +216,13 @@ namespace AZ
for (const Ptr<Pass>& pass : buildListCopy)
{
pass->Reset();
}
for (const Ptr<Pass>& pass : buildListCopy)
{
pass->Build();
pass->Build(true);
}
loopCounter++;
}
if (m_passHierarchyChanged)
{
// Signal all passes that we have finished building
m_rootPass->OnBuildFinished();
#if AZ_RPI_ENABLE_PASS_DEBUGGING
if (!m_isHotReloading)
{
@@ -242,6 +241,9 @@ namespace AZ
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments");
m_passHierarchyChanged = m_passHierarchyChanged || !m_initializePassList.empty();
u32 loopCounter = 0;
while (!m_initializePassList.empty())
{
AZStd::vector< Ptr<Pass> > initListCopy = m_initializePassList;
@@ -261,6 +263,13 @@ namespace AZ
{
pass->Initialize();
}
loopCounter++;
}
if (m_passHierarchyChanged)
{
// Signal all passes that we have finished initialization
m_rootPass->OnInitializationFinished();
}
m_state = PassSystemState::Idle;
@@ -474,5 +483,6 @@ namespace AZ
return nullptr;
}
#pragma optimize("", on)
} // namespace RPI
} // namespace AZ
@@ -128,7 +128,7 @@ namespace AZ
}
void RenderPass::OnBuildFinishedInternal()
void RenderPass::InitializeInternal()
{
if (m_shaderResourceGroup != nullptr)
{