From 5fb114bfff27dba0aa9412cf152107cb6d8006f1 Mon Sep 17 00:00:00 2001 From: Artem Kharytoniuk Date: Thu, 23 Jan 2025 15:33:04 +0100 Subject: [PATCH] layers: Refactor SyncOp functor factories --- layers/sync/sync_op.cpp | 207 +++++++++++++++++++--------------------- layers/sync/sync_op.h | 14 +-- 2 files changed, 99 insertions(+), 122 deletions(-) diff --git a/layers/sync/sync_op.cpp b/layers/sync/sync_op.cpp index caf59b7743d..41855a92d1d 100644 --- a/layers/sync/sync_op.cpp +++ b/layers/sync/sync_op.cpp @@ -194,6 +194,98 @@ class FilteredGeneratorGenerator { using EventImageRangeGenerator = FilteredGeneratorGenerator; + +namespace PipelineBarrier { +namespace { +SingleRangeGenerator MakeRangeGen(const vvl::Buffer &buffer, const ResourceAccessRange &range) { + if (!SimpleBinding(buffer)) return ResourceAccessRange(); + const auto base_address = ResourceBaseAddress(buffer); + return (range + base_address); +} + +subresource_adapter::ImageRangeGenerator MakeRangeGen(const syncval_state::ImageState &image, + const VkImageSubresourceRange &subresource_range) { + return image.MakeImageRangeGen(subresource_range, false); +} +} // namespace + +template +void ApplyBarriers(const Barriers &barriers, QueueId queue_id, AccessContext *access_context) { + for (const auto &barrier : barriers) { + const auto *state = barrier.GetState(); + if (state) { + auto update_action = + ApplyBarrierFunctor(PipelineBarrierOp(queue_id, barrier.barrier, barrier.IsLayoutTransition())); + auto range_gen = MakeRangeGen(*state, barrier.Range()); + access_context->UpdateMemoryAccessState(update_action, range_gen); + } + } +} + +void ApplyGlobalBarriers(const std::vector &barriers, QueueId queue_id, ResourceUsageTag tag, + AccessContext *access_context) { + auto barriers_functor = ApplyBarrierOpsFunctor(true, barriers.size(), tag); + for (const auto &barrier : barriers) { + barriers_functor.EmplaceBack(PipelineBarrierOp(queue_id, barrier, false)); + } + auto range_gen = SingleRangeGenerator(kFullRange); + access_context->UpdateMemoryAccessState(barriers_functor, range_gen); +} +} // namespace PipelineBarrier + +namespace Events { +namespace { +// Need to restrict to only valid exec and access scope for this event +// Pass by value is intentional to get a copy we can change without modifying the passed barrier +SyncBarrier RestrictToEvent(const SyncEventState &sync_event, const SyncBarrier &barrier) { + SyncBarrier result = barrier; + result.src_exec_scope.exec_scope = sync_event.scope.exec_scope & barrier.src_exec_scope.exec_scope; + result.src_access_scope = sync_event.scope.valid_accesses & barrier.src_access_scope; + return result; +} + +EventSimpleRangeGenerator MakeRangeGen(const SyncEventState &sync_event, const vvl::Buffer &buffer, + const ResourceAccessRange &range_arg) { + const auto base_address = ResourceBaseAddress(buffer); + ResourceAccessRange range = SimpleBinding(buffer) ? (range_arg + base_address) : ResourceAccessRange(); + EventSimpleRangeGenerator filtered_range_gen(sync_event.FirstScope(), range); + return filtered_range_gen; +} + +EventImageRangeGenerator MakeRangeGen(const SyncEventState &sync_event, const syncval_state::ImageState &image, + const VkImageSubresourceRange &subresource_range) { + ImageRangeGen image_range_gen = image.MakeImageRangeGen(subresource_range, false); + EventImageRangeGenerator filtered_range_gen(sync_event.FirstScope(), image_range_gen); + return filtered_range_gen; +} +} // namespace + +template +void ApplyBarriers(const SyncEventState &sync_event, const Barriers &barriers, QueueId queue_id, AccessContext *access_context) { + for (const auto &barrier : barriers) { + const auto *state = barrier.GetState(); + if (state) { + auto restricted_barrier = RestrictToEvent(sync_event, barrier.barrier); + auto update_action = ApplyBarrierFunctor( + WaitEventBarrierOp(queue_id, sync_event.first_scope_tag, restricted_barrier, barrier.IsLayoutTransition())); + auto range_gen = MakeRangeGen(sync_event, *state, barrier.Range()); + access_context->UpdateMemoryAccessState(update_action, range_gen); + } + } +} + +void ApplyGlobalBarriers(const SyncEventState &sync_event, const std::vector &barriers, QueueId queue_id, + ResourceUsageTag tag, AccessContext *access_context) { + auto barriers_functor = ApplyBarrierOpsFunctor(false, barriers.size(), tag); + for (const auto &barrier : barriers) { + auto restricted_barrier = RestrictToEvent(sync_event, barrier); + barriers_functor.EmplaceBack(WaitEventBarrierOp(queue_id, sync_event.first_scope_tag, restricted_barrier, false)); + } + auto range_gen = EventSimpleRangeGenerator(sync_event.FirstScope(), kFullRange); + access_context->UpdateMemoryAccessState(barriers_functor, range_gen); +} +} // namespace Events + SyncOpBarriers::SyncOpBarriers(vvl::Func command, const SyncValidator &sync_state, VkQueueFlags queue_flags, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, @@ -280,61 +372,6 @@ bool SyncOpPipelineBarrier::Validate(const CommandBufferAccessContext &cb_contex return skip; } -struct SyncOpPipelineBarrierFunctorFactory { - using BarrierOpFunctor = PipelineBarrierOp; - using ApplyFunctor = ApplyBarrierFunctor; - using GlobalBarrierOpFunctor = PipelineBarrierOp; - using GlobalApplyFunctor = ApplyBarrierOpsFunctor; - using BufferRange = SingleRangeGenerator; - using ImageRange = subresource_adapter::ImageRangeGenerator; - using GlobalRange = SingleRangeGenerator; - using ImageState = syncval_state::ImageState; - - ApplyFunctor MakeApplyFunctor(QueueId queue_id, const SyncBarrier &barrier, bool layout_transition) const { - return ApplyFunctor(BarrierOpFunctor(queue_id, barrier, layout_transition)); - } - GlobalApplyFunctor MakeGlobalApplyFunctor(size_t size_hint, ResourceUsageTag tag) const { - return GlobalApplyFunctor(true /* resolve */, size_hint, tag); - } - GlobalBarrierOpFunctor MakeGlobalBarrierOpFunctor(QueueId queue_id, const SyncBarrier &barrier) const { - return GlobalBarrierOpFunctor(queue_id, barrier, false); - } - - BufferRange MakeRangeGen(const vvl::Buffer &buffer, const ResourceAccessRange &range) const { - if (!SimpleBinding(buffer)) return ResourceAccessRange(); - const auto base_address = ResourceBaseAddress(buffer); - return (range + base_address); - } - ImageRange MakeRangeGen(const ImageState &image, const VkImageSubresourceRange &subresource_range) const { - return image.MakeImageRangeGen(subresource_range, false); - } - GlobalRange MakeGlobalRangeGen() const { return kFullRange; } -}; - -template -void SyncOpBarriers::ApplyBarriers(const Barriers &barriers, const FunctorFactory &factory, const QueueId queue_id, - const ResourceUsageTag tag, AccessContext *access_context) { - for (const auto &barrier : barriers) { - const auto *state = barrier.GetState(); - if (state) { - auto update_action = factory.MakeApplyFunctor(queue_id, barrier.barrier, barrier.IsLayoutTransition()); - auto range_gen = factory.MakeRangeGen(*state, barrier.Range()); - access_context->UpdateMemoryAccessState(update_action, range_gen); - } - } -} - -template -void SyncOpBarriers::ApplyGlobalBarriers(const Barriers &barriers, const FunctorFactory &factory, const QueueId queue_id, - const ResourceUsageTag tag, AccessContext *access_context) { - auto barriers_functor = factory.MakeGlobalApplyFunctor(barriers.size(), tag); - for (const auto &barrier : barriers) { - barriers_functor.EmplaceBack(factory.MakeGlobalBarrierOpFunctor(queue_id, barrier)); - } - auto range_gen = factory.MakeGlobalRangeGen(); - access_context->UpdateMemoryAccessState(barriers_functor, range_gen); -} - ResourceUsageTag SyncOpPipelineBarrier::Record(CommandBufferAccessContext *cb_context) { const auto tag = cb_context->NextCommandTag(command_); for (const auto &barrier_set : barriers_) { @@ -350,7 +387,6 @@ ResourceUsageTag SyncOpPipelineBarrier::Record(CommandBufferAccessContext *cb_co } void SyncOpPipelineBarrier::ReplayRecord(CommandExecutionContext &exec_context, const ResourceUsageTag exec_tag) const { - SyncOpPipelineBarrierFunctorFactory factory; // Pipeline barriers only have a single barrier set, unlike WaitEvents2 assert(barriers_.size() == 1); const auto &barrier_set = barriers_[0]; @@ -359,9 +395,9 @@ void SyncOpPipelineBarrier::ReplayRecord(CommandExecutionContext &exec_context, SyncEventsContext *events_context = exec_context.GetCurrentEventsContext(); AccessContext *access_context = exec_context.GetCurrentAccessContext(); const auto queue_id = exec_context.GetQueueId(); - ApplyBarriers(barrier_set.buffer_memory_barriers, factory, queue_id, exec_tag, access_context); - ApplyBarriers(barrier_set.image_memory_barriers, factory, queue_id, exec_tag, access_context); - ApplyGlobalBarriers(barrier_set.memory_barriers, factory, queue_id, exec_tag, access_context); + PipelineBarrier::ApplyBarriers(barrier_set.buffer_memory_barriers, queue_id, access_context); + PipelineBarrier::ApplyBarriers(barrier_set.image_memory_barriers, queue_id, access_context); + PipelineBarrier::ApplyGlobalBarriers(barrier_set.memory_barriers, queue_id, exec_tag, access_context); if (barrier_set.single_exec_scope) { events_context->ApplyBarrier(barrier_set.src_exec_scope, barrier_set.dst_exec_scope, exec_tag); } else { @@ -680,52 +716,6 @@ bool SyncOpWaitEvents::DoValidate(const CommandExecutionContext &exec_context, c return skip; } -struct SyncOpWaitEventsFunctorFactory { - using BarrierOpFunctor = WaitEventBarrierOp; - using ApplyFunctor = ApplyBarrierFunctor; - using GlobalBarrierOpFunctor = WaitEventBarrierOp; - using GlobalApplyFunctor = ApplyBarrierOpsFunctor; - using BufferRange = EventSimpleRangeGenerator; - using ImageRange = EventImageRangeGenerator; - using GlobalRange = EventSimpleRangeGenerator; - using ImageState = syncval_state::ImageState; - - // Need to restrict to only valid exec and access scope for this event - // Pass by value is intentional to get a copy we can change without modifying the passed barrier - SyncBarrier RestrictToEvent(SyncBarrier barrier) const { - barrier.src_exec_scope.exec_scope = sync_event->scope.exec_scope & barrier.src_exec_scope.exec_scope; - barrier.src_access_scope = sync_event->scope.valid_accesses & barrier.src_access_scope; - return barrier; - } - ApplyFunctor MakeApplyFunctor(QueueId queue_id, const SyncBarrier &barrier_arg, bool layout_transition) const { - auto barrier = RestrictToEvent(barrier_arg); - return ApplyFunctor(BarrierOpFunctor(queue_id, sync_event->first_scope_tag, barrier, layout_transition)); - } - GlobalApplyFunctor MakeGlobalApplyFunctor(size_t size_hint, ResourceUsageTag tag) const { - return GlobalApplyFunctor(false /* don't resolve */, size_hint, tag); - } - GlobalBarrierOpFunctor MakeGlobalBarrierOpFunctor(const QueueId queue_id, const SyncBarrier &barrier_arg) const { - auto barrier = RestrictToEvent(barrier_arg); - return GlobalBarrierOpFunctor(queue_id, sync_event->first_scope_tag, barrier, false); - } - - BufferRange MakeRangeGen(const vvl::Buffer &buffer, const ResourceAccessRange &range_arg) const { - const auto base_address = ResourceBaseAddress(buffer); - ResourceAccessRange range = SimpleBinding(buffer) ? (range_arg + base_address) : ResourceAccessRange(); - EventSimpleRangeGenerator filtered_range_gen(sync_event->FirstScope(), range); - return filtered_range_gen; - } - ImageRange MakeRangeGen(const ImageState &image, const VkImageSubresourceRange &subresource_range) const { - ImageRangeGen image_range_gen = image.MakeImageRangeGen(subresource_range, false); - EventImageRangeGenerator filtered_range_gen(sync_event->FirstScope(), image_range_gen); - - return filtered_range_gen; - } - GlobalRange MakeGlobalRangeGen() const { return EventSimpleRangeGenerator(sync_event->FirstScope(), kFullRange); } - SyncOpWaitEventsFunctorFactory(SyncEventState *sync_event_) : sync_event(sync_event_) { assert(sync_event); } - SyncEventState *sync_event; -}; - ResourceUsageTag SyncOpWaitEvents::Record(CommandBufferAccessContext *cb_context) { const auto tag = cb_context->NextCommandTag(command_); @@ -760,10 +750,9 @@ void SyncOpWaitEvents::ReplayRecord(CommandExecutionContext &exec_context, Resou // These apply barriers one at a time as the are restricted to the resource ranges specified per each barrier, // but do not update the dependency chain information (but set the "pending" state) // s.t. the order independence // of the barriers is maintained. - SyncOpWaitEventsFunctorFactory factory(sync_event); - ApplyBarriers(barrier_set.buffer_memory_barriers, factory, queue_id, exec_tag, access_context); - ApplyBarriers(barrier_set.image_memory_barriers, factory, queue_id, exec_tag, access_context); - ApplyGlobalBarriers(barrier_set.memory_barriers, factory, queue_id, exec_tag, access_context); + Events::ApplyBarriers(*sync_event, barrier_set.buffer_memory_barriers, queue_id, access_context); + Events::ApplyBarriers(*sync_event, barrier_set.image_memory_barriers, queue_id, access_context); + Events::ApplyGlobalBarriers(*sync_event, barrier_set.memory_barriers, queue_id, exec_tag, access_context); // Apply the global barrier to the event itself (for race condition tracking) // Events don't happen at a stage, so we need to store the unexpanded ALL_COMMANDS if set for inter-event-calls diff --git a/layers/sync/sync_op.h b/layers/sync/sync_op.h index 774a82e48b2..e026ce59e9a 100644 --- a/layers/sync/sync_op.h +++ b/layers/sync/sync_op.h @@ -31,8 +31,6 @@ class RenderPass; class CommandBuffer; } // namespace vvl -using SyncMemoryBarrier = SyncBarrier; - struct SyncEventState { enum IgnoreReason { NotIgnored = 0, ResetWaitRace, Reset2WaitRace, SetRace, MissingStageBits, SetVsWait2, MissingSetEvent }; using EventPointer = std::shared_ptr; @@ -167,21 +165,11 @@ class SyncOpBase { virtual void ReplayRecord(CommandExecutionContext &exec_context, ResourceUsageTag exec_tag) const = 0; protected: - // Only non-null and valid for SyncOps within a render pass instance WIP -- think about how to manage for non RPI calls within - // RPI and 2ndarys... - uint32_t subpass_ = VK_SUBPASS_EXTERNAL; vvl::Func command_; }; class SyncOpBarriers : public SyncOpBase { protected: - template - static void ApplyBarriers(const Barriers &barriers, const FunctorFactory &factory, QueueId queue_id, ResourceUsageTag tag, - AccessContext *context); - template - static void ApplyGlobalBarriers(const Barriers &barriers, const FunctorFactory &factory, QueueId queue_id, ResourceUsageTag tag, - AccessContext *access_context); - SyncOpBarriers(vvl::Func command, const SyncValidator &sync_state, VkQueueFlags queue_flags, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, @@ -198,7 +186,7 @@ class SyncOpBarriers : public SyncOpBase { VkDependencyFlags dependency_flags; SyncExecScope src_exec_scope; SyncExecScope dst_exec_scope; - std::vector memory_barriers; + std::vector memory_barriers; std::vector buffer_memory_barriers; std::vector image_memory_barriers; bool single_exec_scope;