Graphics/FrameGraph: Handle invalidation and flush barriers
This commit is contained in:
parent
38b143ce8f
commit
07199301df
|
|
@ -50,7 +50,7 @@ namespace Nz
|
||||||
|
|
||||||
BakedFrameGraph(std::vector<PassData> passes, std::vector<TextureData> textures, AttachmentIdToTextureId attachmentIdToTextureMapping, PassIdToPhysicalPassIndex passIdToPhysicalPassMapping);
|
BakedFrameGraph(std::vector<PassData> passes, std::vector<TextureData> textures, AttachmentIdToTextureId attachmentIdToTextureMapping, PassIdToPhysicalPassIndex passIdToPhysicalPassMapping);
|
||||||
|
|
||||||
struct TextureTransition
|
struct TextureBarrier
|
||||||
{
|
{
|
||||||
std::size_t textureId;
|
std::size_t textureId;
|
||||||
MemoryAccessFlags dstAccessMask;
|
MemoryAccessFlags dstAccessMask;
|
||||||
|
|
@ -75,7 +75,7 @@ namespace Nz
|
||||||
std::vector<std::size_t> outputTextureIndices;
|
std::vector<std::size_t> outputTextureIndices;
|
||||||
std::vector<CommandBufferBuilder::ClearValues> outputClearValues;
|
std::vector<CommandBufferBuilder::ClearValues> outputClearValues;
|
||||||
std::vector<SubpassData> subpasses;
|
std::vector<SubpassData> subpasses;
|
||||||
std::vector<TextureTransition> transitions;
|
std::vector<TextureBarrier> invalidationBarriers;
|
||||||
FramePass::ExecutionCallback executionCallback;
|
FramePass::ExecutionCallback executionCallback;
|
||||||
Recti renderRect;
|
Recti renderRect;
|
||||||
bool forceCommandBufferRegeneration = true;
|
bool forceCommandBufferRegeneration = true;
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ namespace Nz
|
||||||
using AttachmentIdToPassId = std::unordered_map<std::size_t /*attachmentId*/, std::size_t /*passId*/>;
|
using AttachmentIdToPassId = std::unordered_map<std::size_t /*attachmentId*/, std::size_t /*passId*/>;
|
||||||
using AttachmentIdToTextureId = std::unordered_map<std::size_t /*attachmentId*/, std::size_t /*textureId*/>;
|
using AttachmentIdToTextureId = std::unordered_map<std::size_t /*attachmentId*/, std::size_t /*textureId*/>;
|
||||||
using PassIdToPhysicalPassIndex = std::unordered_map<std::size_t /*passId*/, std::size_t /*physicalPassId*/>;
|
using PassIdToPhysicalPassIndex = std::unordered_map<std::size_t /*passId*/, std::size_t /*physicalPassId*/>;
|
||||||
using TextureTransition = BakedFrameGraph::TextureTransition;
|
using TextureBarrier = BakedFrameGraph::TextureBarrier;
|
||||||
|
|
||||||
struct AttachmentProxy
|
struct AttachmentProxy
|
||||||
{
|
{
|
||||||
|
|
@ -80,7 +80,7 @@ namespace Nz
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<TextureTransition> textureTransitions;
|
std::vector<TextureBarrier> textureBarrier;
|
||||||
std::vector<Subpass> passes;
|
std::vector<Subpass> passes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ namespace Nz
|
||||||
|
|
||||||
passData.commandBuffer = m_commandPool->BuildCommandBuffer([&](CommandBufferBuilder& builder)
|
passData.commandBuffer = m_commandPool->BuildCommandBuffer([&](CommandBufferBuilder& builder)
|
||||||
{
|
{
|
||||||
for (auto& textureTransition : passData.transitions)
|
for (auto& textureTransition : passData.invalidationBarriers)
|
||||||
{
|
{
|
||||||
const std::shared_ptr<Texture>& texture = m_textures[textureTransition.textureId].texture;
|
const std::shared_ptr<Texture>& texture = m_textures[textureTransition.textureId].texture;
|
||||||
builder.TextureBarrier(textureTransition.srcStageMask, textureTransition.dstStageMask, textureTransition.srcAccessMask, textureTransition.dstAccessMask, textureTransition.oldLayout, textureTransition.newLayout, *texture);
|
builder.TextureBarrier(textureTransition.srcStageMask, textureTransition.dstStageMask, textureTransition.srcAccessMask, textureTransition.dstAccessMask, textureTransition.oldLayout, textureTransition.newLayout, *texture);
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,8 @@ namespace Nz
|
||||||
AssignPhysicalTextures();
|
AssignPhysicalTextures();
|
||||||
AssignPhysicalPasses();
|
AssignPhysicalPasses();
|
||||||
BuildPhysicalPasses();
|
BuildPhysicalPasses();
|
||||||
//BuildBarriers();
|
BuildBarriers();
|
||||||
//BuildPhysicalBarriers();
|
BuildPhysicalBarriers();
|
||||||
|
|
||||||
std::vector<BakedFrameGraph::PassData> bakedPasses;
|
std::vector<BakedFrameGraph::PassData> bakedPasses;
|
||||||
bakedPasses.reserve(m_pending.physicalPasses.size());
|
bakedPasses.reserve(m_pending.physicalPasses.size());
|
||||||
|
|
@ -79,7 +79,7 @@ namespace Nz
|
||||||
auto& bakedPass = bakedPasses.emplace_back();
|
auto& bakedPass = bakedPasses.emplace_back();
|
||||||
bakedPass.name = std::move(physicalPass.name);
|
bakedPass.name = std::move(physicalPass.name);
|
||||||
bakedPass.renderPass = std::move(m_pending.renderPasses[renderPassIndex++]);
|
bakedPass.renderPass = std::move(m_pending.renderPasses[renderPassIndex++]);
|
||||||
bakedPass.transitions = std::move(physicalPass.textureTransitions);
|
bakedPass.invalidationBarriers = std::move(physicalPass.textureBarrier);
|
||||||
|
|
||||||
for (auto& subpass : physicalPass.passes)
|
for (auto& subpass : physicalPass.passes)
|
||||||
{
|
{
|
||||||
|
|
@ -274,7 +274,7 @@ namespace Nz
|
||||||
|
|
||||||
auto GetBarrier = [&](std::vector<Barrier>& barriers, std::size_t attachmentId) -> Barrier&
|
auto GetBarrier = [&](std::vector<Barrier>& barriers, std::size_t attachmentId) -> Barrier&
|
||||||
{
|
{
|
||||||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, ResolveAttachmentIndex(attachmentId));
|
||||||
|
|
||||||
auto it = std::find_if(barriers.begin(), barriers.end(), [&](const Barrier& barrier) { return barrier.textureId == textureId; });
|
auto it = std::find_if(barriers.begin(), barriers.end(), [&](const Barrier& barrier) { return barrier.textureId == textureId; });
|
||||||
if (it != barriers.end())
|
if (it != barriers.end())
|
||||||
|
|
@ -335,7 +335,7 @@ namespace Nz
|
||||||
invalidationBarrier.access = MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite;
|
invalidationBarrier.access = MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite;
|
||||||
invalidationBarrier.stages = PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
invalidationBarrier.stages = PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
|
||||||
auto& flushBarrier = GetInvalidationBarrier(dsOutputAttachement);
|
auto& flushBarrier = GetFlushBarrier(dsOutputAttachement);
|
||||||
flushBarrier.layout = TextureLayout::DepthStencilReadWrite;
|
flushBarrier.layout = TextureLayout::DepthStencilReadWrite;
|
||||||
flushBarrier.access = MemoryAccess::DepthStencilWrite;
|
flushBarrier.access = MemoryAccess::DepthStencilWrite;
|
||||||
flushBarrier.stages = PipelineStage::FragmentTestsLate;
|
flushBarrier.stages = PipelineStage::FragmentTestsLate;
|
||||||
|
|
@ -354,7 +354,7 @@ namespace Nz
|
||||||
else if (dsOutputAttachement != FramePass::InvalidAttachmentId)
|
else if (dsOutputAttachement != FramePass::InvalidAttachmentId)
|
||||||
{
|
{
|
||||||
// DS output-only
|
// DS output-only
|
||||||
auto& flushBarrier = GetInvalidationBarrier(dsOutputAttachement);
|
auto& flushBarrier = GetFlushBarrier(dsOutputAttachement);
|
||||||
if (flushBarrier.layout != TextureLayout::Undefined)
|
if (flushBarrier.layout != TextureLayout::Undefined)
|
||||||
throw std::runtime_error("layout mismatch");
|
throw std::runtime_error("layout mismatch");
|
||||||
|
|
||||||
|
|
@ -367,7 +367,7 @@ namespace Nz
|
||||||
|
|
||||||
void FrameGraph::BuildPhysicalBarriers()
|
void FrameGraph::BuildPhysicalBarriers()
|
||||||
{
|
{
|
||||||
struct TextureStates
|
struct PassTextureStates
|
||||||
{
|
{
|
||||||
MemoryAccessFlags invalidatedAccesses;
|
MemoryAccessFlags invalidatedAccesses;
|
||||||
MemoryAccessFlags flushedAccesses;
|
MemoryAccessFlags flushedAccesses;
|
||||||
|
|
@ -377,13 +377,21 @@ namespace Nz
|
||||||
TextureLayout finalLayout = TextureLayout::Undefined;
|
TextureLayout finalLayout = TextureLayout::Undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<TextureStates> textureStates;
|
struct TextureStates
|
||||||
|
{
|
||||||
|
MemoryAccessFlags flushedAccesses;
|
||||||
|
PipelineStageFlags flushedStages;
|
||||||
|
TextureLayout currentLayout = TextureLayout::Undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<TextureStates> textureStates(m_pending.textures.size());
|
||||||
|
std::vector<PassTextureStates> passTextureStates;
|
||||||
|
|
||||||
auto barriersIt = m_pending.barrierList.begin();
|
auto barriersIt = m_pending.barrierList.begin();
|
||||||
for (auto& physicalPass : m_pending.physicalPasses)
|
for (auto& physicalPass : m_pending.physicalPasses)
|
||||||
{
|
{
|
||||||
textureStates.clear();
|
passTextureStates.clear();
|
||||||
textureStates.resize(m_pending.textures.size());
|
passTextureStates.resize(m_pending.textures.size());
|
||||||
|
|
||||||
for (auto& subpass : physicalPass.passes)
|
for (auto& subpass : physicalPass.passes)
|
||||||
{
|
{
|
||||||
|
|
@ -391,9 +399,12 @@ namespace Nz
|
||||||
|
|
||||||
for (auto& invalidation : barriers.invalidationBarriers)
|
for (auto& invalidation : barriers.invalidationBarriers)
|
||||||
{
|
{
|
||||||
auto& states = textureStates[invalidation.textureId];
|
auto& states = passTextureStates[invalidation.textureId];
|
||||||
|
|
||||||
if (states.initialLayout == TextureLayout::Undefined)
|
if (states.initialLayout == TextureLayout::Undefined)
|
||||||
{
|
{
|
||||||
|
// First use in this pass
|
||||||
|
|
||||||
states.invalidatedAccesses |= invalidation.access;
|
states.invalidatedAccesses |= invalidation.access;
|
||||||
states.invalidatedStages |= invalidation.stages;
|
states.invalidatedStages |= invalidation.stages;
|
||||||
states.initialLayout = invalidation.layout;
|
states.initialLayout = invalidation.layout;
|
||||||
|
|
@ -406,7 +417,7 @@ namespace Nz
|
||||||
|
|
||||||
for (auto& flush : barriers.flushBarriers)
|
for (auto& flush : barriers.flushBarriers)
|
||||||
{
|
{
|
||||||
auto& states = textureStates[flush.textureId];
|
auto& states = passTextureStates[flush.textureId];
|
||||||
states.flushedAccesses |= flush.access;
|
states.flushedAccesses |= flush.access;
|
||||||
states.flushedStages |= flush.stages;
|
states.flushedStages |= flush.stages;
|
||||||
states.finalLayout = flush.layout;
|
states.finalLayout = flush.layout;
|
||||||
|
|
@ -418,6 +429,11 @@ namespace Nz
|
||||||
states.invalidatedAccesses = flush.access;
|
states.invalidatedAccesses = flush.access;
|
||||||
states.invalidatedStages = flush.stages;
|
states.invalidatedStages = flush.stages;
|
||||||
|
|
||||||
|
textureStates[flush.textureId].currentLayout = flush.layout;
|
||||||
|
|
||||||
|
if (states.invalidatedStages & PipelineStage::FragmentTestsLate)
|
||||||
|
states.invalidatedStages |= PipelineStage::FragmentTestsEarly;
|
||||||
|
|
||||||
if (states.invalidatedAccesses & MemoryAccess::ColorWrite)
|
if (states.invalidatedAccesses & MemoryAccess::ColorWrite)
|
||||||
states.invalidatedAccesses |= MemoryAccess::ColorRead;
|
states.invalidatedAccesses |= MemoryAccess::ColorRead;
|
||||||
|
|
||||||
|
|
@ -433,22 +449,33 @@ namespace Nz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (std::size_t textureId = 0; textureId < textureStates.size(); ++textureId)
|
for (std::size_t textureId = 0; textureId < passTextureStates.size(); ++textureId)
|
||||||
{
|
{
|
||||||
const auto& state = textureStates[textureId];
|
const auto& state = passTextureStates[textureId];
|
||||||
|
|
||||||
if (state.initialLayout == TextureLayout::Undefined && state.finalLayout == TextureLayout::Undefined)
|
if (state.initialLayout == TextureLayout::Undefined && state.finalLayout == TextureLayout::Undefined)
|
||||||
continue; //< Texture wasn't touched in this pass
|
continue; //< Texture wasn't touched in this pass
|
||||||
|
|
||||||
assert(state.finalLayout != TextureLayout::Undefined);
|
assert(state.finalLayout != TextureLayout::Undefined);
|
||||||
|
|
||||||
// TODO: Register invalidation
|
if (textureStates[textureId].flushedAccesses != 0)
|
||||||
|
{
|
||||||
|
auto& invalidationBarrier = physicalPass.textureBarrier.emplace_back();
|
||||||
|
invalidationBarrier.textureId = textureId;
|
||||||
|
invalidationBarrier.srcAccessMask = textureStates[textureId].flushedAccesses;
|
||||||
|
invalidationBarrier.srcStageMask = textureStates[textureId].flushedStages;
|
||||||
|
invalidationBarrier.dstAccessMask = state.invalidatedAccesses;
|
||||||
|
invalidationBarrier.dstStageMask = state.invalidatedStages;
|
||||||
|
invalidationBarrier.oldLayout = textureStates[textureId].currentLayout;
|
||||||
|
invalidationBarrier.newLayout = state.initialLayout;
|
||||||
|
|
||||||
if (state.flushedAccesses)
|
textureStates[textureId].flushedAccesses = 0;
|
||||||
; // TODO: Register flush
|
textureStates[textureId].flushedStages = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (state.invalidatedAccesses)
|
textureStates[textureId].currentLayout = state.finalLayout;
|
||||||
; // TODO: Register flush
|
textureStates[textureId].flushedAccesses |= state.flushedAccesses;
|
||||||
|
textureStates[textureId].flushedStages |= state.flushedStages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -645,7 +672,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
const std::shared_ptr<RenderDevice>& renderDevice = Graphics::Instance()->GetRenderDevice();
|
const std::shared_ptr<RenderDevice>& renderDevice = Graphics::Instance()->GetRenderDevice();
|
||||||
|
|
||||||
std::unordered_map<std::size_t /*textureId*/, TextureLayout> textureLayouts;
|
std::vector<TextureLayout> textureLayouts(m_pending.textures.size(), TextureLayout::Undefined);
|
||||||
|
|
||||||
std::size_t physicalPassIndex = 0;
|
std::size_t physicalPassIndex = 0;
|
||||||
for (auto& physicalPass : m_pending.physicalPasses)
|
for (auto& physicalPass : m_pending.physicalPasses)
|
||||||
|
|
@ -662,24 +689,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, input.attachmentId);
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, input.attachmentId);
|
||||||
|
|
||||||
auto it = textureLayouts.find(textureId);
|
TextureLayout& textureLayout = textureLayouts[textureId];
|
||||||
assert(it != textureLayouts.end());
|
assert(textureLayouts[textureId] != TextureLayout::Undefined);
|
||||||
|
|
||||||
TextureLayout& textureLayout = it->second;
|
|
||||||
if (textureLayout != TextureLayout::ColorInput)
|
|
||||||
{
|
|
||||||
auto& transition = physicalPass.textureTransitions.emplace_back();
|
|
||||||
transition.textureId = textureId;
|
|
||||||
|
|
||||||
transition.srcAccessMask = MemoryAccess::ColorWrite;
|
|
||||||
transition.srcStageMask = PipelineStage::ColorOutput;
|
|
||||||
|
|
||||||
transition.dstStageMask = PipelineStage::ColorOutput;
|
|
||||||
transition.dstAccessMask = MemoryAccess::ColorRead | MemoryAccess::ColorWrite;
|
|
||||||
|
|
||||||
transition.oldLayout = textureLayout;
|
|
||||||
transition.newLayout = TextureLayout::ColorInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
textureLayout = TextureLayout::ColorInput;
|
textureLayout = TextureLayout::ColorInput;
|
||||||
};
|
};
|
||||||
|
|
@ -688,15 +699,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, output.attachmentId);
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, output.attachmentId);
|
||||||
|
|
||||||
TextureLayout initialLayout = TextureLayout::Undefined;
|
TextureLayout initialLayout = textureLayouts[textureId];
|
||||||
auto layoutIt = textureLayouts.find(textureId);
|
textureLayouts[textureId] = TextureLayout::ColorOutput;
|
||||||
if (layoutIt != textureLayouts.end())
|
|
||||||
{
|
|
||||||
initialLayout = layoutIt->second;
|
|
||||||
layoutIt->second = TextureLayout::ColorOutput;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
textureLayouts.emplace(textureId, TextureLayout::ColorOutput);
|
|
||||||
|
|
||||||
auto it = usedTextureAttachments.find(textureId);
|
auto it = usedTextureAttachments.find(textureId);
|
||||||
if (it != usedTextureAttachments.end())
|
if (it != usedTextureAttachments.end())
|
||||||
|
|
@ -735,15 +739,8 @@ namespace Nz
|
||||||
|
|
||||||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
||||||
|
|
||||||
TextureLayout initialLayout = TextureLayout::Undefined;
|
TextureLayout initialLayout = textureLayouts[textureId];
|
||||||
auto layoutIt = textureLayouts.find(textureId);
|
textureLayouts[textureId] = textureLayout;
|
||||||
if (layoutIt != textureLayouts.end())
|
|
||||||
{
|
|
||||||
initialLayout = layoutIt->second;
|
|
||||||
layoutIt->second = textureLayout;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
textureLayouts.emplace(textureId, textureLayout);
|
|
||||||
|
|
||||||
depthStencilAttachmentId = attachmentId;
|
depthStencilAttachmentId = attachmentId;
|
||||||
depthStencilAttachmentIndex = renderPassAttachments.size();
|
depthStencilAttachmentIndex = renderPassAttachments.size();
|
||||||
|
|
@ -882,11 +879,8 @@ namespace Nz
|
||||||
// Assign final layout (TODO: Use this to perform layouts useful for future passes?)
|
// Assign final layout (TODO: Use this to perform layouts useful for future passes?)
|
||||||
for (const auto& [textureId, attachmentIndex] : usedTextureAttachments)
|
for (const auto& [textureId, attachmentIndex] : usedTextureAttachments)
|
||||||
{
|
{
|
||||||
auto layoutIt = textureLayouts.find(textureId);
|
|
||||||
assert(layoutIt != textureLayouts.end());
|
|
||||||
|
|
||||||
auto& attachment = renderPassAttachments[attachmentIndex];
|
auto& attachment = renderPassAttachments[attachmentIndex];
|
||||||
attachment.finalLayout = layoutIt->second;
|
attachment.finalLayout = textureLayouts[textureId];
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildPhysicalPassDependencies(colorAttachmentCount, depthStencilAttachmentIndex.has_value(), renderPassAttachments, subpassesDesc, subpassesDeps);
|
BuildPhysicalPassDependencies(colorAttachmentCount, depthStencilAttachmentIndex.has_value(), renderPassAttachments, subpassesDesc, subpassesDeps);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue