diff --git a/.clang-format b/.clang-format index 8c914ed21..308fb8e29 100644 --- a/.clang-format +++ b/.clang-format @@ -79,7 +79,7 @@ PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right -ReflowComments: true +ReflowComments: false SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: true diff --git a/ashura/include/ashura/gfx.h b/ashura/include/ashura/gfx.h index 592d00fea..704ce626e 100644 --- a/ashura/include/ashura/gfx.h +++ b/ashura/include/ashura/gfx.h @@ -586,25 +586,30 @@ enum class ImageUsages : u8 STX_DEFINE_ENUM_BIT_OPS(ImageUsages) -enum class BufferBindings : u8 +enum class BufferBindings : u16 { - None = 0x00, - Uniform = 0x01, - Storage = 0x02, - UniformTexel = 0x04, - StorageTexel = 0x08, - IndexBuffer = 0x10, - VertexBuffer = 0x20, + None = 0x0000, + ComputeShaderUniform = 0x0001, + ComputeShaderStorage = 0x0002, + ComputeShaderUniformTexel = 0x0004, + ComputeShaderStorageTexel = 0x0008, + FragmentShaderUniform = 0x0010, + FragmentShaderUniformTexel = 0x0020, + VertexShaderUniform = 0x0040, + VertexShaderUniformTexel = 0x0080, + GraphicsIndexBuffer = 0x0100, + GraphicsVertexBuffer = 0x0200, }; STX_DEFINE_ENUM_BIT_OPS(BufferBindings) enum class ImageBindings : u8 { - None = 0x00, - Sampled = 0x01, - Storage = 0x02, - InputAttachment = 0x04 + None = 0x00, + ComputeSampled = 0x01, + ComputeStorage = 0x02, + GraphicsSampled = 0x01, + GraphicsInputAttachment = 0x04 }; STX_DEFINE_ENUM_BIT_OPS(ImageBindings) @@ -622,47 +627,35 @@ enum class InputRate : u8 // // buffers have no transient accesses // -enum class MemoryAccess : u8 +enum class MemoryAccess : u32 { - None = 0, - Read = 1, - Write = 2, - TransientRead = 4, - TransientWrite = 8 + None = 0, + Read = 0x00008000, + Write = 0x00010000 }; STX_DEFINE_ENUM_BIT_OPS(MemoryAccess) -enum class Access : u64 -{ - None = 0x00000000ULL, - IndirectCommandRead = 0x00000001ULL, - IndexRead = 0x00000002ULL, - VertexAttributeRead = 0x00000004ULL, - UniformRead = 0x00000008ULL, - InputAttachmentRead = 0x00000010ULL, - ShaderRead = 0x00000020ULL, - ShaderWrite = 0x00000040ULL, - ColorAttachmentRead = 0x00000080ULL, - ColorAttachmentWrite = 0x00000100ULL, - DepthStencilAttachmentRead = 0x00000200ULL, - DepthStencilAttachmentWrite = 0x00000400ULL, - TransferRead = 0x00000800ULL, - TransferWrite = 0x00001000ULL, - HostRead = 0x00002000ULL, - HostWrite = 0x00004000ULL, - MemoryRead = 0x00008000ULL, - MemoryWrite = 0x00010000ULL, - VideoDecodeRead = 0x800000000ULL, - VideoDecodeWrite = 0x1000000000ULL, - VideoEncodeRead = 0x2000000000ULL, - VideoEncodeWrite = 0x4000000000ULL, - AccelerationStructureRead = 0x00200000ULL, - AccelerationStructureWrite = 0x00400000ULL, - FragmentDensityMapRead = 0x01000000ULL, - ColorAttachmentReadNonCoherent = 0x00080000ULL, - DescriptorBufferRead = 0x20000000000ULL, - ShaderBindingTableRead = 0x10000000000ULL +enum class Access : u32 +{ + None = 0x00000000, + IndirectCommandRead = 0x00000001, + IndexRead = 0x00000002, + VertexAttributeRead = 0x00000004, + UniformRead = 0x00000008, + InputAttachmentRead = 0x00000010, + ShaderRead = 0x00000020, + ShaderWrite = 0x00000040, + ColorAttachmentRead = 0x00000080, + ColorAttachmentWrite = 0x00000100, + DepthStencilAttachmentRead = 0x00000200, + DepthStencilAttachmentWrite = 0x00000400, + TransferRead = 0x00000800, + TransferWrite = 0x00001000, + HostRead = 0x00002000, + HostWrite = 0x00004000, + MemoryRead = 0x00008000, + MemoryWrite = 0x00010000 }; STX_DEFINE_ENUM_BIT_OPS(Access) @@ -848,6 +841,83 @@ struct RenderPassAttachment StoreOp store_op = StoreOp::Store; LoadOp stencil_load_op = LoadOp::Load; // how to use stencil components StoreOp stencil_store_op = StoreOp::Store; + + constexpr ImageAccess get_color_image_access() const + { + ImageLayout layout = ImageLayout::ColorAttachmentOptimal; + bool has_write = false; + bool has_read = false; + MemoryAccess access = MemoryAccess::None; + + if (load_op == LoadOp::Clear || load_op == LoadOp::DontCare || store_op == StoreOp::Store) + { + has_write = true; + } + + if (load_op == LoadOp::Load) + { + has_read = true; + } + + if (has_write) + { + access |= MemoryAccess::Write; + } + + if (has_read) + { + access |= MemoryAccess::Read; + } + + return ImageAccess{ + .layout = layout, .stages = PipelineStages::ColorAttachmentOutput, .access = access}; + } + + constexpr ImageAccess get_depth_stencil_image_access() const + { + ImageLayout layout = ImageLayout::Undefined; + bool has_write = false; + bool has_read = false; + MemoryAccess access = MemoryAccess::None; + + if (load_op == LoadOp::Clear || load_op == LoadOp::DontCare || store_op == StoreOp::Store || + store_op == StoreOp::DontCare || stencil_load_op == LoadOp::Clear || + stencil_load_op == LoadOp::DontCare || stencil_store_op == StoreOp::Store || + stencil_store_op == StoreOp::DontCare) + { + has_write = true; + } + + if (load_op == LoadOp::Load || stencil_load_op == LoadOp::Load) + { + has_read = true; + } + + if (has_write) + { + access |= MemoryAccess::Write; + } + + if (has_read) + { + access |= MemoryAccess::Read; + } + + if (has_write) + { + layout = ImageLayout::DepthStencilAttachmentOptimal; + } + else + { + layout = ImageLayout::DepthStencilReadOnlyOptimal; + } + + return ImageAccess{.layout = layout, + .stages = PipelineStages::EarlyFragmentTests | + PipelineStages::LateFragmentTests | + PipelineStages::ColorAttachmentOutput, + .access = access}; + } }; struct RenderPassDesc @@ -1163,19 +1233,59 @@ struct QueueImageMemoryBarrier Access dst_access = Access::None; }; +struct BufferAccess +{ + PipelineStages stages = PipelineStages::None; + MemoryAccess access = MemoryAccess::None; +}; + +struct ImageAccess +{ + ImageLayout layout = ImageLayout::Undefined; + PipelineStages stages = PipelineStages::None; + MemoryAccess access = MemoryAccess::None; +}; + struct BufferSyncScope { MemoryAccess access = MemoryAccess::None; - ImageLayout layout = ImageLayout::Undefined; BufferBindings bindings = BufferBindings::None; constexpr void reset() { - access = MemoryAccess::None; + access = MemoryAccess::None; + bindings = BufferBindings::None; } - u8 sync(MemoryAccess memory_access, Access access, PipelineStages stages, - QueueBufferMemoryBarrier barrier[2]); + constexpr bool sync(MemoryAccess new_access, PipelineStages new_stages, + QueueBufferMemoryBarrier &barrier) + { + if (access == MemoryAccess::None) + { + access |= new_access; + return false; + } + + // RAR needs no barrier + if ((new_access == MemoryAccess::Read || new_access == MemoryAccess::None) && + (access == MemoryAccess::Read || access == MemoryAccess::None)) + { + access |= new_access; + return false; + } + + bool const is_non_mutating = new_access == MemoryAccess::Read; + + // WAR, RAW, WAW + barrier.src_access = (Access) (is_non_mutating ? MemoryAccess::Write : access); + barrier.src_stages = PipelineStages::BottomOfPipe; + barrier.dst_access = (Access) new_access; + barrier.dst_stages = new_stages; + barrier.offset = 0; + barrier.size = WHOLE_SIZE; + access |= new_access; + return true; + } }; struct ImageSyncScope @@ -1186,11 +1296,129 @@ struct ImageSyncScope constexpr void reset() { - access = MemoryAccess::None; + access = MemoryAccess::None; + bindings = ImageBindings::None; + } + + constexpr bool sync(MemoryAccess new_access, PipelineStages new_stages, ImageLayout new_layout, + QueueImageMemoryBarrier &barrier) + { + if (layout == new_layout && access == MemoryAccess::None) + { + access |= new_access; + return false; + } + + if (layout == new_layout && + (new_access == MemoryAccess::Read || new_access == MemoryAccess::None) && + (access == MemoryAccess::Read || access == MemoryAccess::None)) + { + access |= new_access; + return false; + } + + // RAW, WAR, WAW + bool const is_non_mutating = new_access == MemoryAccess::Read && layout == new_layout; + barrier.first_mip_level = 0; + barrier.num_mip_levels = REMAINING_MIP_LEVELS; + barrier.first_array_layer = 0; + barrier.num_array_layers = REMAINING_ARRAY_LAYERS; + barrier.old_layout = layout; + barrier.new_layout = new_layout; + barrier.src_access = (Access) (is_non_mutating ? MemoryAccess::Write : access); + barrier.src_stages = PipelineStages::BottomOfPipe; + barrier.dst_access = (Access) new_access; + barrier.dst_stages = new_stages; + access |= is_non_mutating ? MemoryAccess::Read : new_access; + layout = new_layout; + return true; } - bool sync(MemoryAccess memory_access, Access access, PipelineStages stages, ImageLayout layout, - QueueImageMemoryBarrier &barrier); + BufferAccess to_pipeline_access(BufferBindings bindings, PipelineStages binding_stages) + { + Access access = Access::None; + PipelineStages stages = PipelineStages::None; + + if ((bindings & (BufferBindings::Uniform | BufferBindings::Storage | + BufferBindings::UniformTexel | BufferBindings::StorageTexel)) != + BufferBindings::None) + { + stages |= binding_stages; + } + + if ((bindings & (BufferBindings::IndexBuffer | BufferBindings::VertexBuffer)) != + BufferBindings::None) + { + stages |= PipelineStages::VertexInput; + } + + if ((bindings & BufferBindings::IndexBuffer) != BufferBindings::None) + { + access |= Access::IndexRead; + } + + if ((bindings & BufferBindings::VertexBuffer) != BufferBindings::None) + { + access |= Access::VertexAttributeRead; + } + + if ((bindings & (BufferBindings::Uniform | BufferBindings::UniformTexel)) != + BufferBindings::None) + { + access |= Access::ShaderRead; + } + + if ((bindings & (BufferBindings::Storage | BufferBindings::StorageTexel)) != + BufferBindings::None) + { + access |= Access::ShaderWrite; + } + + return BufferAccess{.stages = stages, .access = access}; + } + + ImageAccess to_pipeline_access(ImageBindings bindings, PipelineStages binding_stages) + { + Access access = Access::None; + ImageLayout layout = ImageLayout::Undefined; + PipelineStages stages = PipelineStages::None; + + if ((bindings & ImageBindings::InputAttachment) != ImageBindings::None) + { + access |= Access::InputAttachmentRead; + } + + if ((bindings & ImageBindings::Sampled) != ImageBindings::None) + { + access |= Access::ShaderRead; + } + + if ((bindings & ImageBindings::Storage) != ImageBindings::None) + { + access |= Access::ShaderWrite; + } + + if ((bindings & ImageBindings::Storage) != ImageBindings::None) + { + layout = ImageLayout::General; + } + else if ((bindings & (ImageBindings::Sampled | ImageBindings::InputAttachment)) != + ImageBindings::None) + { + layout = ImageLayout::ShaderReadOnlyOptimal; + } + + if (bindings == ImageBindings::InputAttachment) + { + stages = PipelineStages::FragmentShader; + } + else if (bindings != ImageBindings::None) + { + stages = binding_stages; + } + + return ImageAccess{.stages = stages, .access = access, .layout = layout}; + } }; struct StencilFaceState diff --git a/ashura/include/ashura/rcg.h b/ashura/include/ashura/rcg.h index 4b1e8b48c..3d38fff7c 100644 --- a/ashura/include/ashura/rcg.h +++ b/ashura/include/ashura/rcg.h @@ -113,26 +113,26 @@ struct GraphHook { Graph *graph = nullptr; - virtual void create(gfx::BufferDesc const &desc) = 0; - virtual void create(gfx::BufferViewDesc const &desc) = 0; - virtual void create(gfx::ImageDesc const &desc) = 0; - virtual void create(gfx::ImageViewDesc const &desc) = 0; - virtual void create(gfx::SamplerDesc const &sampler) = 0; - virtual void create(gfx::RenderPassDesc const &desc) = 0; - virtual void create(gfx::FramebufferDesc const &desc) = 0; - virtual void create(gfx::DescriptorSetDesc const &descriptor_set_layout) = 0; - virtual void create(gfx::ComputePipelineDesc const &desc) = 0; - virtual void create(gfx::GraphicsPipelineDesc const &desc) = 0; - virtual void release(gfx::Buffer buffer) = 0; - virtual void release(gfx::BufferView buffer_view) = 0; - virtual void release(gfx::Image image) = 0; - virtual void release(gfx::ImageView image_view) = 0; - virtual void release(gfx::Sampler sampler) = 0; - virtual void release(gfx::RenderPass render_pass) = 0; - virtual void release(gfx::Framebuffer framebuffer) = 0; - virtual void release(gfx::DescriptorSetLayout descriptor_set_layout) = 0; - virtual void release(gfx::ComputePipeline pipeline) = 0; - virtual void release(gfx::GraphicsPipeline pipeline) = 0; + virtual void create(gfx::BufferDesc const &desc) = 0; + virtual void create(gfx::BufferViewDesc const &desc) = 0; + virtual void create(gfx::ImageDesc const &desc) = 0; + virtual void create(gfx::ImageViewDesc const &desc) = 0; + virtual void create(gfx::SamplerDesc const &sampler) = 0; + virtual void create(gfx::RenderPassDesc const &desc) = 0; + virtual void create(gfx::FramebufferDesc const &desc) = 0; + virtual void create(stx::Span descriptor_set_desc) = 0; + virtual void create(gfx::ComputePipelineDesc const &desc) = 0; + virtual void create(gfx::GraphicsPipelineDesc const &desc) = 0; + virtual void release(gfx::Buffer buffer) = 0; + virtual void release(gfx::BufferView buffer_view) = 0; + virtual void release(gfx::Image image) = 0; + virtual void release(gfx::ImageView image_view) = 0; + virtual void release(gfx::Sampler sampler) = 0; + virtual void release(gfx::RenderPass render_pass) = 0; + virtual void release(gfx::Framebuffer framebuffer) = 0; + virtual void release(gfx::DescriptorSetLayout descriptor_set_layout) = 0; + virtual void release(gfx::ComputePipeline pipeline) = 0; + virtual void release(gfx::GraphicsPipeline pipeline) = 0; }; // interceptor that is used for validation and adding barriers @@ -173,7 +173,7 @@ struct Graph gfx::Sampler create(gfx::SamplerDesc const &sampler); gfx::RenderPass create(gfx::RenderPassDesc const &desc); gfx::Framebuffer create(gfx::FramebufferDesc const &desc); - gfx::DescriptorSetLayout create(gfx::DescriptorSetDesc const &descriptor_set_layout); + gfx::DescriptorSetLayout create(stx::Span descriptor_set_desc); gfx::ComputePipeline create(gfx::ComputePipelineDesc const &desc); gfx::GraphicsPipeline create(gfx::GraphicsPipelineDesc const &desc); void release(gfx::Buffer buffer); diff --git a/ashura/src/gfx.cc b/ashura/src/gfx.cc index dfd35ab1b..66138ee7d 100644 --- a/ashura/src/gfx.cc +++ b/ashura/src/gfx.cc @@ -5,240 +5,10 @@ namespace ash namespace gfx { -BufferAccess to_pipeline_access(BufferBindings bindings, PipelineStages binding_stages) -{ - Access access = Access::None; - PipelineStages stages = PipelineStages::None; - - if ((bindings & (BufferBindings::Uniform | BufferBindings::Storage | - BufferBindings::UniformTexel | BufferBindings::StorageTexel)) != - BufferBindings::None) - { - stages |= binding_stages; - } - - if ((bindings & (BufferBindings::IndexBuffer | BufferBindings::VertexBuffer)) != - BufferBindings::None) - { - stages |= PipelineStages::VertexInput; - } - - if ((bindings & BufferBindings::IndexBuffer) != BufferBindings::None) - { - access |= Access::IndexRead; - } - - if ((bindings & BufferBindings::VertexBuffer) != BufferBindings::None) - { - access |= Access::VertexAttributeRead; - } - - if ((bindings & (BufferBindings::Uniform | BufferBindings::UniformTexel)) != BufferBindings::None) - { - access |= Access::ShaderRead; - } - - if ((bindings & (BufferBindings::Storage | BufferBindings::StorageTexel)) != BufferBindings::None) - { - access |= Access::ShaderWrite; - } - - return BufferAccess{.stages = stages, .access = access}; -} - -ImageAccess to_pipeline_access(ImageBindings bindings, PipelineStages binding_stages) -{ - Access access = Access::None; - ImageLayout layout = ImageLayout::Undefined; - PipelineStages stages = PipelineStages::None; - - if ((bindings & ImageBindings::InputAttachment) != ImageBindings::None) - { - access |= Access::InputAttachmentRead; - } - - if ((bindings & ImageBindings::Sampled) != ImageBindings::None) - { - access |= Access::ShaderRead; - } - - if ((bindings & ImageBindings::Storage) != ImageBindings::None) - { - access |= Access::ShaderWrite; - } - - if ((bindings & ImageBindings::Storage) != ImageBindings::None) - { - layout = ImageLayout::General; - } - else if ((bindings & (ImageBindings::Sampled | ImageBindings::InputAttachment)) != - ImageBindings::None) - { - layout = ImageLayout::ShaderReadOnlyOptimal; - } - - if (bindings == ImageBindings::InputAttachment) - { - stages = PipelineStages::FragmentShader; - } - else if (bindings != ImageBindings::None) - { - stages = binding_stages; - } - - return ImageAccess{.stages = stages, .access = access, .layout = layout}; -} - -ImageAccess RenderPassAttachment::get_color_image_access() const -{ - ImageLayout layout = ImageLayout::ColorAttachmentOptimal; - bool has_write = false; - bool has_read = false; - Access access = Access::None; - - if (load_op == LoadOp::Clear || load_op == LoadOp::DontCare || store_op == StoreOp::Store) - { - has_write = true; - } - - if (load_op == LoadOp::Load) - { - has_read = true; - } - - if (has_write) - { - access |= Access::ColorAttachmentWrite; - } - - if (has_read) - { - access |= Access::ColorAttachmentRead; - } - - return ImageAccess{ - .stages = PipelineStages::ColorAttachmentOutput, .access = access, .layout = layout}; -} +bool BufferSyncScope::sync(MemoryAccess memory_access, PipelineStages stages, + QueueBufferMemoryBarrier &barrier) -ImageAccess RenderPassAttachment::get_depth_stencil_image_access() const -{ - ImageLayout layout = ImageLayout::Undefined; - bool has_write = false; - bool has_read = false; - Access access = Access::None; - - if (load_op == LoadOp::Clear || load_op == LoadOp::DontCare || store_op == StoreOp::Store || - store_op == StoreOp::DontCare || stencil_load_op == LoadOp::Clear || - stencil_load_op == LoadOp::DontCare || stencil_store_op == StoreOp::Store || - stencil_store_op == StoreOp::DontCare) - { - has_write = true; - } - - if (load_op == LoadOp::Load || stencil_load_op == LoadOp::Load) - { - has_read = true; - } - - if (has_write) - { - access |= Access::DepthStencilAttachmentWrite; - } - - if (has_read) - { - access |= Access::DepthStencilAttachmentRead; - } - - if (has_write) - { - layout = ImageLayout::DepthStencilAttachmentOptimal; - } - else - { - layout = ImageLayout::DepthStencilReadOnlyOptimal; - } - - return ImageAccess{.stages = PipelineStages::EarlyFragmentTests | - PipelineStages::LateFragmentTests | - PipelineStages::ColorAttachmentOutput, - .access = access, - .layout = layout}; -} -u8 BufferSyncScope::sync(MemoryAccess memory_access, Access access, PipelineStages stages, - QueueBufferMemoryBarrier barriers[2]) -{ - // TODO(lamarrr): upon write, clear all??? and reset to write, that way there will be no read | write case, since only trigger is write - u8 num_barriers = 0; - if (this->access == MemoryAccess::Write) - { - // RAW - if ((memory_access & MemoryAccess::Read) != MemoryAccess::None) - { - barriers[num_barriers].src_access = Access::MemoryWrite; - barriers[num_barriers].src_stages = PipelineStages::BottomOfPipe; - barriers[num_barriers].dst_access = Access::MemoryRead; - barriers[num_barriers].dst_stages = stages; - barriers[num_barriers].offset = 0; - barriers[num_barriers].size = WHOLE_SIZE; - num_barriers++; - } - - // WAW - if ((memory_access & MemoryAccess::Write) != MemoryAccess::None) - { - barriers[num_barriers].src_access = Access::MemoryWrite; - barriers[num_barriers].src_stages = PipelineStages::BottomOfPipe; - barriers[num_barriers].dst_access = Access::MemoryWrite; - barriers[num_barriers].dst_stages = stages; - barriers[num_barriers].offset = 0; - barriers[num_barriers].size = WHOLE_SIZE; - num_barriers++; - } - - this->access |= memory_access; - return num_barriers; - } - else if (this->access == MemoryAccess::Read) - { - if ((memory_access & MemoryAccess::Write) != MemoryAccess::None) - { - // WAR - barriers[num_barriers].src_access = Access::MemoryRead; - barriers[num_barriers].src_stages = PipelineStages::BottomOfPipe; - barriers[num_barriers].dst_access = access; - if((memory_access & MemoryAccess::Read)!= MemoryAccess::None){ - barriers[num_barriers].dst_stages = stages; - } else{ - barriers[num_barriers].dst_stages = stages; - } - barriers[num_barriers].offset = 0; - barriers[num_barriers].size = WHOLE_SIZE; - this->access |= memory_access; - } - else - { - // RAR - this->access |= memory_access; - return false; - } - } - else if (this->access == (MemoryAccess::Read | MemoryAccess::Write)) - { - - - } - else - { - return 0; - } -} - -bool ImageSyncScope::sync(MemoryAccess memory_access, Access access, PipelineStages stages, - ImageLayout layout, QueueImageMemoryBarrier &barrier) -{ -} // TODO(lamarrr): index buffer can be used from a generated compute stage, will our graph handle // this? we need to check for read/write compatibility diff --git a/ashura/src/rcg.cc b/ashura/src/rcg.cc index ec6c02838..c47b8c8e0 100644 --- a/ashura/src/rcg.cc +++ b/ashura/src/rcg.cc @@ -9,13 +9,21 @@ void CommandBuffer::fill_buffer(gfx::Buffer buffer, u64 offset, u64 size, u32 da { hook->fill_buffer(buffer, offset, size, data); - gfx::QueueBufferMemoryBarrier barriers[1] = {{.buffer = graph->buffers[buffer].handle}}; - if (graph->buffers[buffer].state.sync(gfx::BufferAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferWrite}, - barriers[0])) + gfx::QueueBufferMemoryBarrier barriers[1]; + u8 num_barriers = 0; + + if (graph->buffers[buffer].sync_scope.sync(gfx::MemoryAccess::Write, + gfx::PipelineStages::Transfer, barriers[0])) { - graph->driver->cmd_insert_barriers(handle, barriers, {}); + barriers[0].buffer = graph->buffers[buffer].handle; + num_barriers++; + } + + if (num_barriers > 0) + { + graph->driver->cmd_insert_barriers(handle, stx::Span{barriers, num_barriers}, {}); } + graph->driver->cmd_fill_buffer(handle, buffer, offset, size, data); } @@ -26,20 +34,31 @@ void CommandBuffer::copy_buffer(gfx::Buffer src, gfx::Buffer dst, gfx::QueueBufferMemoryBarrier barriers[2]; u8 num_barriers = 0; - if (graph->buffers[src].state.sync(gfx::BufferAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferRead}, - barriers[num_barriers])) + + if (src != dst) { - barriers[num_barriers].buffer = graph->buffers[src].handle; - num_barriers++; - } + if (graph->buffers[src].sync_scope.sync(gfx::MemoryAccess::Read, gfx::PipelineStages::Transfer, + barriers[num_barriers])) + { + barriers[num_barriers].buffer = graph->buffers[src].handle; + num_barriers++; + } - if (graph->buffers[dst].state.sync(gfx::BufferAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferWrite}, - barriers[num_barriers])) + if (graph->buffers[dst].sync_scope.sync(gfx::MemoryAccess::Write, gfx::PipelineStages::Transfer, + barriers[num_barriers])) + { + barriers[num_barriers].buffer = graph->buffers[dst].handle; + num_barriers++; + } + } + else { - barriers[num_barriers].buffer = graph->buffers[dst].handle; - num_barriers++; + if (graph->buffers[src].sync_scope.sync(gfx::MemoryAccess::Read | gfx::MemoryAccess::Write, + gfx::PipelineStages::Transfer, barriers[num_barriers])) + { + barriers[num_barriers].buffer = graph->buffers[src].handle; + num_barriers++; + } } if (num_barriers > 0) @@ -55,12 +74,18 @@ void CommandBuffer::update_buffer(stx::Span src, u64 dst_offset, gfx:: hook->update_buffer(src, dst_offset, dst); gfx::QueueBufferMemoryBarrier barriers[1]; - if (graph->buffers[dst].state.sync(gfx::BufferAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferWrite}, - barriers[0])) + u8 num_barriers = 0; + + if (graph->buffers[dst].sync_scope.sync(gfx::MemoryAccess::Write, gfx::PipelineStages::Transfer, + barriers[0])) { barriers[0].buffer = graph->buffers[dst].handle; - graph->driver->cmd_insert_barriers(handle, barriers, {}); + num_barriers++; + } + + if (num_barriers > 0) + { + graph->driver->cmd_insert_barriers(handle, stx::Span{barriers, num_barriers}, {}); } graph->driver->cmd_update_buffer(handle, src, dst_offset, dst); @@ -73,26 +98,37 @@ void CommandBuffer::copy_image(gfx::Image src, gfx::Image dst, gfx::QueueImageMemoryBarrier barriers[2]; u8 num_barriers = 0; - if (graph->images[src].state.sync( - gfx::ImageAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferRead, - .layout = gfx::ImageLayout::TransferSrcOptimal}, - barriers[num_barriers])) - { - barriers[num_barriers].image = graph->images[src].handle; - barriers[num_barriers].aspects = graph->images[src].desc.aspects; - num_barriers++; - } - if (graph->images[dst].state.sync( - gfx::ImageAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferWrite, - .layout = gfx::ImageLayout::TransferDstOptimal}, - barriers[num_barriers])) + if (src != dst) { - barriers[num_barriers].image = graph->images[dst].handle; - barriers[num_barriers].aspects = graph->images[dst].desc.aspects; - num_barriers++; + if (graph->images[src].sync_scope.sync(gfx::MemoryAccess::Read, gfx::PipelineStages::Transfer, + gfx::ImageLayout::TransferSrcOptimal, + barriers[num_barriers])) + { + barriers[num_barriers].image = graph->images[src].handle; + barriers[num_barriers].aspects = graph->images[src].desc.aspects; + num_barriers++; + } + + if (graph->images[dst].sync_scope.sync(gfx::MemoryAccess::Write, gfx::PipelineStages::Transfer, + gfx::ImageLayout::TransferDstOptimal, + barriers[num_barriers])) + { + barriers[num_barriers].image = graph->images[dst].handle; + barriers[num_barriers].aspects = graph->images[dst].desc.aspects; + num_barriers++; + } + } + else + { + if (graph->images[src].sync_scope.sync(gfx::MemoryAccess::Read | gfx::MemoryAccess::Write, + gfx::PipelineStages::Transfer, gfx::ImageLayout::General, + barriers[num_barriers])) + { + barriers[num_barriers].image = graph->images[src].handle; + barriers[num_barriers].aspects = graph->images[src].desc.aspects; + num_barriers++; + } } if (num_barriers > 0) @@ -107,23 +143,20 @@ void CommandBuffer::copy_buffer_to_image(gfx::Buffer src, gfx::Image dst, stx::Span copies) { gfx::QueueBufferMemoryBarrier buffer_memory_barriers[1]; - gfx::QueueImageMemoryBarrier image_memory_barriers[1]; u8 num_buffer_memory_barriers = 0; - u8 num_image_memory_barriers = 0; + gfx::QueueImageMemoryBarrier image_memory_barriers[1]; + u8 num_image_memory_barriers = 0; - if (graph->buffers[src].state.sync(gfx::BufferAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferRead}, - buffer_memory_barriers[num_buffer_memory_barriers])) + if (graph->buffers[src].sync_scope.sync(gfx::MemoryAccess::Read, gfx::PipelineStages::Transfer, + buffer_memory_barriers[num_buffer_memory_barriers])) { buffer_memory_barriers[num_buffer_memory_barriers].buffer = graph->buffers[src].handle; num_buffer_memory_barriers++; } - if (graph->images[dst].state.sync( - gfx::ImageAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferWrite, - .layout = gfx::ImageLayout::TransferDstOptimal}, - image_memory_barriers[num_image_memory_barriers])) + if (graph->images[dst].sync_scope.sync(gfx::MemoryAccess::Write, gfx::PipelineStages::Transfer, + gfx::ImageLayout::TransferDstOptimal, + image_memory_barriers[num_image_memory_barriers])) { image_memory_barriers[num_image_memory_barriers].image = graph->images[dst].handle; image_memory_barriers[num_image_memory_barriers].aspects = graph->images[dst].desc.aspects; @@ -147,26 +180,37 @@ void CommandBuffer::blit_image(gfx::Image src, gfx::Image dst, gfx::QueueImageMemoryBarrier barriers[2]; u8 num_barriers = 0; - if (graph->images[src].state.sync( - gfx::ImageAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferRead, - .layout = gfx::ImageLayout::TransferSrcOptimal}, - barriers[num_barriers])) - { - barriers[num_barriers].image = graph->images[src].handle; - barriers[num_barriers].aspects = graph->images[src].desc.aspects; - num_barriers++; - } - if (graph->images[dst].state.sync( - gfx::ImageAccess{.stages = gfx::PipelineStages::Transfer, - .access = gfx::Access::TransferWrite, - .layout = gfx::ImageLayout::TransferDstOptimal}, - barriers[num_barriers])) + if (src != dst) { - barriers[num_barriers].image = graph->images[dst].handle; - barriers[num_barriers].aspects = graph->images[dst].desc.aspects; - num_barriers++; + if (graph->images[src].sync_scope.sync(gfx::MemoryAccess::Read, gfx::PipelineStages::Transfer, + gfx::ImageLayout::TransferSrcOptimal, + barriers[num_barriers])) + { + barriers[num_barriers].image = graph->images[src].handle; + barriers[num_barriers].aspects = graph->images[src].desc.aspects; + num_barriers++; + } + + if (graph->images[dst].sync_scope.sync(gfx::MemoryAccess::Write, gfx::PipelineStages::Transfer, + gfx::ImageLayout::TransferDstOptimal, + barriers[num_barriers])) + { + barriers[num_barriers].image = graph->images[dst].handle; + barriers[num_barriers].aspects = graph->images[dst].desc.aspects; + num_barriers++; + } + } + else + { + if (graph->images[src].sync_scope.sync(gfx::MemoryAccess::Read | gfx::MemoryAccess::Write, + gfx::PipelineStages::Transfer, gfx::ImageLayout::General, + barriers[num_barriers])) + { + barriers[num_barriers].image = graph->images[src].handle; + barriers[num_barriers].aspects = graph->images[src].desc.aspects; + num_barriers++; + } } if (num_barriers > 0) @@ -186,7 +230,6 @@ void CommandBuffer::begin_render_pass( depth_stencil_attachments_clear_values); gfx::RenderPassDesc const &renderpass_desc = graph->render_passes[render_pass].desc; - gfx::QueueImageMemoryBarrier barrier; gfx::QueueImageMemoryBarrier barriers[gfx::MAX_COLOR_ATTACHMENTS + 1]; u32 num_barriers = 0; @@ -196,7 +239,7 @@ void CommandBuffer::begin_render_pass( graph->image_views[graph->framebuffers[framebuffer].desc.color_attachments[i]].desc.image; gfx::ImageResource const &resource = graph->images[image]; - if (graph->images[image].state.sync( + if (graph->images[image].sync_scope.sync( renderpass_desc.color_attachments[i].get_color_image_access(), barrier)) { barrier.image = resource.handle; @@ -222,7 +265,11 @@ void CommandBuffer::begin_render_pass( } } - graph->driver->cmd_insert_barriers(handle, {}, stx::Span{barriers, num_barriers}); + if (num_barriers > 0) + { + graph->driver->cmd_insert_barriers(handle, {}, stx::Span{barriers, num_barriers}); + } + graph->driver->cmd_begin_render_pass( handle, graph->framebuffers[framebuffer].handle, graph->render_passes[render_pass].handle, render_area, color_attachments_clear_values, depth_stencil_attachments_clear_values); @@ -234,7 +281,6 @@ void CommandBuffer::end_render_pass() graph->driver->cmd_end_render_pass(handle); } - inline void generate_descriptor_barriers(gfx::DescriptorSetBindings const &bindings, Graph &graph, stx::Vec &image_barriers, stx::Vec &buffer_barriers)