blob: 0cb9f9498f389349529e01548aefb8920d13b148 [file] [edit]
/* Copyright (c) 2026 The Khronos Group Inc.
* Copyright (c) 2026 Valve Corporation
* Copyright (c) 2026 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "sync_barrier.h"
#include "sync_dynamic_rendering.h"
#include "containers/custom_containers.h"
#include "containers/span.h"
#include "generated/vk_object_types.h"
struct Location;
struct VulkanTypedHandle;
namespace vvl {
class Buffer;
class DescriptorSet;
class Image;
class ImageView;
class Pipeline;
class RenderPass;
enum class Func;
} // namespace vvl
namespace syncval {
class AccessContext;
class CommandBufferContext;
class RenderPassAccessContext;
struct CommandData;
struct SyncEnvironment;
enum class BufferName : uint8_t {
kDstBuffer,
kIndirect,
kDrawCount,
kTransformFeedbackCounter,
};
enum class CommandType : uint32_t {
kBufferCopy,
kBufferAccess,
kImageCopy,
kPipelineBarrier,
kBeginRendering,
kEndRendering,
kBeginRenderPass,
kNextSubpass,
kEndRenderPass,
kShaderAccess,
kDispatchIndirect,
kDrawIndirectCount,
kDrawMeshTasks,
};
struct BufferCopyRegion {
VkDeviceSize src_offset;
VkDeviceSize dst_offset;
VkDeviceSize size;
};
struct BufferCopyCommand {
const vvl::Buffer& src_buffer;
const vvl::Buffer& dst_buffer;
vvl::span<const BufferCopyRegion> regions;
uint32_t src_handle_index = vvl::kNoIndex32;
uint32_t dst_handle_index = vvl::kNoIndex32;
struct Storage {
uint32_t src_buffer_index;
uint32_t dst_buffer_index;
uint32_t first_region;
uint32_t region_count;
uint32_t src_handle_index;
uint32_t dst_handle_index;
BufferCopyCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct BufferAccessCommand {
const vvl::Buffer& buffer;
AccessRange range;
SyncAccessIndex access_index;
uint32_t handle_index = vvl::kNoIndex32;
SyncFlags flags = 0;
BufferName buffer_name = BufferName::kDstBuffer;
struct Storage {
AccessRange range;
uint32_t buffer_index;
SyncAccessIndex access_index;
uint32_t handle_index;
SyncFlags flags;
BufferName buffer_name;
BufferAccessCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct ImageCopyCommand {
const vvl::Image& src_image;
const vvl::Image& dst_image;
vvl::span<const VkImageCopy> regions;
uint32_t src_handle_index = vvl::kNoIndex32;
uint32_t dst_handle_index = vvl::kNoIndex32;
struct Storage {
uint32_t src_image_index;
uint32_t dst_image_index;
uint32_t first_region;
uint32_t region_count;
uint32_t src_handle_index;
uint32_t dst_handle_index;
ImageCopyCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct BarrierCommand {
const BarrierSet& barrier_set;
struct Storage {
uint32_t barrier_set_index;
BarrierCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct BeginRenderingCommand {
RenderingInstance rendering_instance;
uint32_t render_pass_instance_id;
struct Storage {
VkRenderingFlags flags;
VkRect2D render_area;
uint32_t view_mask;
uint32_t color_attachment_count;
uint32_t first_attachment;
uint32_t attachment_count;
uint32_t render_pass_instance_id;
BeginRenderingCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct EndRenderingCommand {
const RenderingInstance& rendering_instance;
uint32_t render_pass_instance_id;
struct Storage {};
Storage MakeStorage(CommandData&) const { return {}; }
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct BeginRenderPassCommand {
// Initial layout transition and loadOp tags
static constexpr uint32_t kTagCount = 2;
const vvl::RenderPass& render_pass;
vvl::span<const std::shared_ptr<const vvl::ImageView>> attachment_views;
VkRect2D render_area{};
uint32_t render_pass_instance_id = 0;
struct Storage {
uint32_t render_pass_index;
uint32_t first_attachment_view_index;
uint32_t attachment_count;
VkRect2D render_area;
uint32_t render_pass_instance_id;
BeginRenderPassCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, RenderPassAccessContext& rp_context) const;
};
struct NextSubpassCommand {
// Resolve, store, layout transition, load tags
static constexpr uint32_t kTagCount = 4;
struct Storage {
NextSubpassCommand MakeCommand(const CommandData&) const { return NextSubpassCommand{}; }
};
Storage MakeStorage(CommandData&) const { return Storage{}; }
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const RenderPassAccessContext& render_pass_context,
const CommandBufferContext& cb_context, ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, RenderPassAccessContext& rp_context) const;
};
struct EndRenderPassCommand {
// Store/resolve and final layout transition tags
static constexpr uint32_t kTagCount = 2;
struct Storage {
EndRenderPassCommand MakeCommand(const CommandData&) const { return EndRenderPassCommand{}; }
};
Storage MakeStorage(CommandData&) const { return Storage{}; }
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const RenderPassAccessContext& render_pass_context,
const CommandBufferContext& cb_context, ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, RenderPassAccessContext& rp_context,
AccessContext& external_context) const;
};
struct ShaderAccessCommand {
struct DescriptorInfo {
const vvl::DescriptorSet* descriptor_set;
VkDescriptorType descriptor_type;
uint32_t set;
uint32_t binding;
uint32_t array_element;
VkShaderStageFlagBits stage;
VulkanTypedHandle resource_handle;
};
struct BufferAccess {
DescriptorInfo info;
const vvl::Buffer* buffer;
AccessRange range;
SyncAccessIndex access_index;
uint32_t handle_index = vvl::kNoIndex32;
};
struct ImageViewAccess {
DescriptorInfo info;
const vvl::ImageView* image_view;
VkImageLayout image_layout;
SyncAccessIndex access_index;
uint32_t handle_index = vvl::kNoIndex32;
// Input attachments use the render area and render-pass attachment ordering
VkOffset3D offset{};
VkExtent3D extent{};
};
const vvl::Pipeline* pipeline = nullptr;
vvl::span<const BufferAccess> buffer_accesses;
vvl::span<const ImageViewAccess> image_accesses;
uint32_t render_pass_instance_id = vvl::kNoIndex32;
uint32_t subpass = vvl::kNoIndex32;
struct Storage {
const vvl::Pipeline* pipeline;
uint32_t first_buffer_access;
uint32_t buffer_access_count;
uint32_t first_image_access;
uint32_t image_access_count;
uint32_t render_pass_instance_id;
uint32_t subpass;
ShaderAccessCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
private:
bool ValidateBufferShaderAccess(const SyncEnvironment& env, const AccessContext& access_context,
const CommandBufferContext& cb_context, ResourceUsageTag replay_tag, const Location& loc,
const BufferAccess& buffer_access) const;
bool ValidateImageShaderAccess(const SyncEnvironment& env, const AccessContext& access_context,
const CommandBufferContext& cb_context, ResourceUsageTag replay_tag, const Location& loc,
const ImageViewAccess& image_access) const;
};
// Returned by CommandBufferContext::CollectDescriptorAccesses.
// The same data as ShaderAccessCommand, but owns the buffer/image access arrays
struct DescriptorAccesses {
const vvl::Pipeline* pipeline = nullptr;
std::vector<ShaderAccessCommand::BufferAccess> buffer_accesses;
std::vector<ShaderAccessCommand::ImageViewAccess> image_accesses;
uint32_t render_pass_instance_id = vvl::kNoIndex32;
uint32_t subpass = vvl::kNoIndex32;
// Registers a HandleRecord for each descriptor resource and initializes the
// handle_index fields of access structures. Call before MakeCommand. Record time only.
void RegisterResources(CommandBufferContext& cb_context, ResourceUsageTag tag);
ShaderAccessCommand MakeCommand() const {
return {pipeline, buffer_accesses, image_accesses, render_pass_instance_id, subpass};
}
};
struct DispatchIndirectCommand {
ShaderAccessCommand shader_accesses;
BufferAccessCommand indirect_access;
struct Storage {
ShaderAccessCommand::Storage shader_access_storage;
BufferAccessCommand::Storage indirect_access_storage;
DispatchIndirectCommand MakeCommand(const CommandData& command_data) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct DrawAttachmentCommand {
const vvl::Pipeline* pipeline;
RenderPassAccessContext* render_pass_context;
const RenderingInstance* rendering_instance;
uint32_t render_pass_instance_id;
bool depth_write;
bool stencil_write;
struct Storage {
const vvl::Pipeline* pipeline;
uint32_t render_pass_instance_id;
bool depth_write;
bool stencil_write;
DrawAttachmentCommand MakeCommand(RenderPassAccessContext* render_pass_context,
const RenderingInstance* rendering_instance) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct DrawIndirectCountCommand {
ShaderAccessCommand shader_accesses;
DrawAttachmentCommand attachment_accesses;
BufferAccessCommand count_access;
struct Storage {
ShaderAccessCommand::Storage shader_access_storage;
DrawAttachmentCommand::Storage attachment_access_storage;
BufferAccessCommand::Storage count_access_storage;
DrawIndirectCountCommand MakeCommand(const CommandData& command_data, RenderPassAccessContext* render_pass_context,
const RenderingInstance* rendering_instance) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct DrawMeshTasksCommand {
ShaderAccessCommand shader_accesses;
DrawAttachmentCommand attachment_accesses;
struct Storage {
ShaderAccessCommand::Storage shader_access_storage;
DrawAttachmentCommand::Storage attachment_access_storage;
DrawMeshTasksCommand MakeCommand(const CommandData& command_data, RenderPassAccessContext* render_pass_context,
const RenderingInstance* rendering_instance) const;
};
Storage MakeStorage(CommandData& command_data) const;
bool Validate(const CommandBufferContext& cb_context, const Location& loc) const;
bool Validate(const SyncEnvironment& env, const AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag replay_tag, const Location& loc) const;
void Apply(SyncEnvironment& env, ResourceUsageTag tag, AccessContext& access_context) const;
};
struct CommandRef {
CommandType type;
uint32_t index;
};
static_assert(sizeof(CommandRef) == 8);
struct CommandData {
// Command storage data.
// NOTE: NextSubpass, EndRenderPass, EndRendering - have no storage data
std::vector<BufferCopyCommand::Storage> buffer_copy_commands;
std::vector<BufferAccessCommand::Storage> buffer_access_commands;
std::vector<ImageCopyCommand::Storage> image_copy_commands;
std::vector<BarrierCommand::Storage> barrier_commands;
std::vector<BeginRenderingCommand::Storage> begin_rendering_commands;
std::vector<BeginRenderPassCommand::Storage> begin_render_pass_commands;
std::vector<ShaderAccessCommand::Storage> shader_access_commands;
std::vector<DispatchIndirectCommand::Storage> dispatch_indirect_commands;
std::vector<DrawIndirectCountCommand::Storage> draw_indirect_count_commands;
std::vector<DrawMeshTasksCommand::Storage> draw_mesh_tasks_commands;
// Resources and additional data used by the commands
std::vector<std::shared_ptr<const vvl::Buffer>> buffers;
std::vector<std::shared_ptr<const vvl::Image>> images;
std::vector<std::shared_ptr<const vvl::ImageView>> image_views;
std::vector<std::shared_ptr<const vvl::RenderPass>> render_passes;
std::vector<std::shared_ptr<const vvl::Pipeline>> pipelines;
std::vector<BufferCopyRegion> buffer_copy_regions;
std::vector<VkImageCopy> image_copy_regions;
std::vector<BarrierSet> barrier_sets;
std::vector<RenderingAttachment> rendering_attachments;
std::vector<ShaderAccessCommand::BufferAccess> descriptor_buffer_accesses;
std::vector<ShaderAccessCommand::ImageViewAccess> descriptor_image_accesses;
std::vector<std::shared_ptr<const vvl::DescriptorSet>> descriptor_sets;
vvl::unordered_set<const vvl::DescriptorSet*> descriptor_set_lookup;
void Reset(); // keeps capacity
uint32_t AddBuffer(const vvl::Buffer& buffer);
uint32_t AddImage(const vvl::Image& image);
uint32_t AddRenderPass(const vvl::RenderPass& render_pass);
void AddImageView(const vvl::ImageView& image_view);
void AddPipeline(const vvl::Pipeline& pipeline);
void AddDescriptorSet(const vvl::DescriptorSet& descriptor_set);
CommandRef Store(const BufferCopyCommand::Storage& storage) {
return Store(CommandType::kBufferCopy, buffer_copy_commands, storage);
}
CommandRef Store(const BufferAccessCommand::Storage& storage) {
return Store(CommandType::kBufferAccess, buffer_access_commands, storage);
}
CommandRef Store(const ImageCopyCommand::Storage& storage) {
return Store(CommandType::kImageCopy, image_copy_commands, storage);
}
CommandRef Store(const BarrierCommand::Storage& storage) {
return Store(CommandType::kPipelineBarrier, barrier_commands, storage);
}
CommandRef Store(const BeginRenderingCommand::Storage& storage) {
return Store(CommandType::kBeginRendering, begin_rendering_commands, storage);
}
CommandRef Store(const EndRenderingCommand::Storage&) {
// No storage data, return the command reference directly. The index is unused.
return {CommandType::kEndRendering, 0};
}
CommandRef Store(const BeginRenderPassCommand::Storage& storage) {
return Store(CommandType::kBeginRenderPass, begin_render_pass_commands, storage);
}
CommandRef Store(const NextSubpassCommand::Storage&) {
// No storage data, return the command reference directly. The index is unused.
return {CommandType::kNextSubpass, 0};
}
CommandRef Store(const EndRenderPassCommand::Storage&) {
// No storage data, return the command reference directly. The index is unused.
return {CommandType::kEndRenderPass, 0};
}
CommandRef Store(const ShaderAccessCommand::Storage& storage) {
return Store(CommandType::kShaderAccess, shader_access_commands, storage);
}
CommandRef Store(const DispatchIndirectCommand::Storage& storage) {
return Store(CommandType::kDispatchIndirect, dispatch_indirect_commands, storage);
}
CommandRef Store(const DrawIndirectCountCommand::Storage& storage) {
return Store(CommandType::kDrawIndirectCount, draw_indirect_count_commands, storage);
}
CommandRef Store(const DrawMeshTasksCommand::Storage& storage) {
return Store(CommandType::kDrawMeshTasks, draw_mesh_tasks_commands, storage);
}
private:
template <typename Storage>
static CommandRef Store(CommandType type, std::vector<Storage>& commands, const Storage& storage) {
const uint32_t index = static_cast<uint32_t>(commands.size());
commands.push_back(storage);
return {type, index};
}
};
// TODO: Revisit tag tracking after command conversion.
// Once tag and tag_count can be derived, store CommandRefs directly
struct CommandEntry {
CommandRef command_ref;
ResourceUsageTag tag;
uint32_t tag_count;
};
bool ReplayCommands(SyncEnvironment& env, AccessContext& access_context, const CommandBufferContext& cb_context,
ResourceUsageTag base_tag, const Location& loc);
} // namespace syncval