Skip to content

Commit

Permalink
sync: Replace SyncOp factories with regular functions
Browse files Browse the repository at this point in the history
The code templated with factory class was hard read because of general
naming (e.g. MakeApplyFunctor) that was used to unite different
implementations. Also missing symbol navigation.
  • Loading branch information
artem-lunarg committed Jan 23, 2025
1 parent 7f8007a commit 1b453b3
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 126 deletions.
211 changes: 100 additions & 111 deletions layers/sync/sync_op.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2019-2024 Valve Corporation
* Copyright (c) 2019-2024 LunarG, Inc.
* Copyright (c) 2019-2025 Valve Corporation
* Copyright (c) 2019-2025 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -194,6 +194,98 @@ class FilteredGeneratorGenerator {

using EventImageRangeGenerator = FilteredGeneratorGenerator<AccessContext::ScopeMap, subresource_adapter::ImageRangeGenerator>;

// Helper functions for SyncOpPipelineBarrier::ReplayRecord
namespace PipelineBarrier {
namespace {
SingleRangeGenerator<ResourceAccessRange> 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 <typename Barriers>
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>(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<SyncBarrier> &barriers, QueueId queue_id, ResourceUsageTag tag,
AccessContext *access_context) {
auto barriers_functor = ApplyBarrierOpsFunctor<PipelineBarrierOp>(true, barriers.size(), tag);
for (const auto &barrier : barriers) {
barriers_functor.EmplaceBack(PipelineBarrierOp(queue_id, barrier, false));
}
auto range_gen = SingleRangeGenerator<ResourceAccessRange>(kFullRange);
access_context->UpdateMemoryAccessState(barriers_functor, range_gen);
}
} // namespace PipelineBarrier

// Helper functions for SyncOpWaitEvents::ReplayRecord
namespace Events {
namespace {
// Need to restrict to only valid exec and access scope for this event
SyncBarrier RestrictToEvent(const SyncBarrier &barrier, const SyncEventState &sync_event) {
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 vvl::Buffer &buffer, const ResourceAccessRange &range_arg,
const SyncEventState &sync_event) {
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 syncval_state::ImageState &image, const VkImageSubresourceRange &subresource_range,
const SyncEventState &sync_event) {
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 <typename Barriers>
void ApplyBarriers(const Barriers &barriers, QueueId queue_id, AccessContext *access_context, const SyncEventState &sync_event) {
for (const auto &barrier : barriers) {
const auto *state = barrier.GetState();
if (state) {
auto restricted_barrier = RestrictToEvent(barrier.barrier, sync_event);
auto update_action = ApplyBarrierFunctor<WaitEventBarrierOp>(
WaitEventBarrierOp(queue_id, sync_event.first_scope_tag, restricted_barrier, barrier.IsLayoutTransition()));
auto range_gen = MakeRangeGen(*state, barrier.Range(), sync_event);
access_context->UpdateMemoryAccessState(update_action, range_gen);
}
}
}

void ApplyGlobalBarriers(const std::vector<SyncBarrier> &barriers, QueueId queue_id, ResourceUsageTag tag,
AccessContext *access_context, const SyncEventState &sync_event) {
auto barriers_functor = ApplyBarrierOpsFunctor<WaitEventBarrierOp>(false, barriers.size(), tag);
for (const auto &barrier : barriers) {
auto restricted_barrier = RestrictToEvent(barrier, sync_event);
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,
Expand Down Expand Up @@ -280,61 +372,6 @@ bool SyncOpPipelineBarrier::Validate(const CommandBufferAccessContext &cb_contex
return skip;
}

struct SyncOpPipelineBarrierFunctorFactory {
using BarrierOpFunctor = PipelineBarrierOp;
using ApplyFunctor = ApplyBarrierFunctor<BarrierOpFunctor>;
using GlobalBarrierOpFunctor = PipelineBarrierOp;
using GlobalApplyFunctor = ApplyBarrierOpsFunctor<GlobalBarrierOpFunctor>;
using BufferRange = SingleRangeGenerator<ResourceAccessRange>;
using ImageRange = subresource_adapter::ImageRangeGenerator;
using GlobalRange = SingleRangeGenerator<ResourceAccessRange>;
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 <typename Barriers, typename FunctorFactory>
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 <typename Barriers, typename FunctorFactory>
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_) {
Expand All @@ -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];
Expand All @@ -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 {
Expand Down Expand Up @@ -680,52 +716,6 @@ bool SyncOpWaitEvents::DoValidate(const CommandExecutionContext &exec_context, c
return skip;
}

struct SyncOpWaitEventsFunctorFactory {
using BarrierOpFunctor = WaitEventBarrierOp;
using ApplyFunctor = ApplyBarrierFunctor<BarrierOpFunctor>;
using GlobalBarrierOpFunctor = WaitEventBarrierOp;
using GlobalApplyFunctor = ApplyBarrierOpsFunctor<GlobalBarrierOpFunctor>;
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_);

Expand Down Expand Up @@ -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(barrier_set.buffer_memory_barriers, queue_id, access_context, *sync_event);
Events::ApplyBarriers(barrier_set.image_memory_barriers, queue_id, access_context, *sync_event);
Events::ApplyGlobalBarriers(barrier_set.memory_barriers, queue_id, exec_tag, access_context, *sync_event);

// 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
Expand Down
18 changes: 3 additions & 15 deletions layers/sync/sync_op.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2019-2024 Valve Corporation
* Copyright (c) 2019-2024 LunarG, Inc.
* Copyright (c) 2019-2025 Valve Corporation
* Copyright (c) 2019-2025 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -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<const vvl::Event>;
Expand Down Expand Up @@ -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 <typename Barriers, typename FunctorFactory>
static void ApplyBarriers(const Barriers &barriers, const FunctorFactory &factory, QueueId queue_id, ResourceUsageTag tag,
AccessContext *context);
template <typename Barriers, typename FunctorFactory>
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,
Expand All @@ -198,7 +186,7 @@ class SyncOpBarriers : public SyncOpBase {
VkDependencyFlags dependency_flags;
SyncExecScope src_exec_scope;
SyncExecScope dst_exec_scope;
std::vector<SyncMemoryBarrier> memory_barriers;
std::vector<SyncBarrier> memory_barriers;
std::vector<SyncBufferMemoryBarrier> buffer_memory_barriers;
std::vector<SyncImageMemoryBarrier> image_memory_barriers;
bool single_exec_scope;
Expand Down

0 comments on commit 1b453b3

Please sign in to comment.