1 #include <msp/core/algorithm.h>
5 #include "synchronizer.h"
13 Synchronizer::Synchronizer(Device &d):
17 void Synchronizer::access(VkBuffer buffer, size_t offset, size_t size)
19 auto i = find_member(buffer_accesses, buffer, &BufferAccess::buffer);
20 if(i==buffer_accesses.end())
22 i = buffer_accesses.emplace(buffer_accesses.end());
29 size_t begin = min(offset, i->offset);
30 size_t end = max(offset+size, i->offset+i->size);
35 i->pending_write = true;
38 void Synchronizer::access(VkImage image, unsigned aspect, int layer, unsigned layout, bool discard)
40 auto i = find_member(image_accesses, image, &ImageAccess::image);
41 if(i==image_accesses.end())
43 i = image_accesses.emplace(image_accesses.end());
47 i->current_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
51 i->current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
54 i->pending_layout = layout;
57 void Synchronizer::reset()
59 for(BufferAccess &b: buffer_accesses)
60 b.pending_write = false;
61 for(ImageAccess &i: image_accesses)
62 i.pending_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
65 void Synchronizer::barrier(VkCommandBuffer command_buffer)
67 const VulkanFunctions &vk = device.get_functions();
69 if(buffer_accesses.empty() && image_accesses.empty())
72 VkPipelineStageFlags src_stage = 0;
73 VkPipelineStageFlags dst_stage = 0;
75 static constexpr VkPipelineStageFlags buffer_read_stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT|
76 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT|VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
77 static constexpr VkPipelineStageFlags buffer_write_stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
79 vector<VkBufferMemoryBarrier> buffer_barriers;
80 buffer_barriers.reserve(buffer_accesses.size());
81 for(BufferAccess &b: buffer_accesses)
83 buffer_barriers.emplace_back(VkBufferMemoryBarrier{ });
84 VkBufferMemoryBarrier &barrier = buffer_barriers.back();
86 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
87 barrier.srcAccessMask = (b.was_written ? VK_ACCESS_MEMORY_WRITE_BIT : 0);
88 barrier.dstAccessMask = (b.pending_write ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_MEMORY_READ_BIT);
89 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
90 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
91 barrier.buffer = handle_cast<::VkBuffer>(b.buffer);
92 barrier.offset = b.offset;
93 barrier.size = b.size;
95 src_stage |= (b.was_written ? buffer_write_stages : buffer_read_stages);
96 dst_stage |= (b.pending_write ? buffer_write_stages : buffer_read_stages);
99 static constexpr VkPipelineStageFlags image_read_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT|VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT|
100 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
101 static constexpr VkPipelineStageFlags image_write_stages = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT|
102 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT|VK_PIPELINE_STAGE_TRANSFER_BIT;
104 vector<VkImageMemoryBarrier> image_barriers;
105 image_barriers.reserve(image_accesses.size());
106 for(const ImageAccess &i: image_accesses)
108 image_barriers.emplace_back(VkImageMemoryBarrier{ });
109 VkImageMemoryBarrier &barrier = image_barriers.back();
111 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
112 barrier.srcAccessMask = (is_write_layout(i.current_layout) ? VK_ACCESS_MEMORY_WRITE_BIT : 0);
113 barrier.dstAccessMask = (is_write_layout(i.pending_layout) ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_MEMORY_READ_BIT);
114 barrier.oldLayout = static_cast<VkImageLayout>(i.current_layout);
115 barrier.newLayout = static_cast<VkImageLayout>(i.pending_layout);
116 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
117 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
118 barrier.image = handle_cast<::VkImage>(i.image);
119 barrier.subresourceRange.aspectMask = i.aspect;
120 barrier.subresourceRange.baseMipLevel = 0;
121 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
124 barrier.subresourceRange.baseArrayLayer = i.layer;
125 barrier.subresourceRange.layerCount = 1;
129 barrier.subresourceRange.baseArrayLayer = 0;
130 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
133 if(i.current_layout!=VK_IMAGE_LAYOUT_UNDEFINED)
134 src_stage |= (is_write_layout(i.current_layout) ? image_write_stages : image_read_stages);
135 dst_stage |= (is_write_layout(i.pending_layout) ? image_write_stages : image_read_stages);
139 src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
141 dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
143 vk.CmdPipelineBarrier(command_buffer, src_stage, dst_stage, 0, 0, 0,
144 buffer_barriers.size(), buffer_barriers.data(), image_barriers.size(), image_barriers.data());
146 for(auto i=buffer_accesses.begin(); i!=buffer_accesses.end(); )
148 if(!i->pending_write)
149 i = buffer_accesses.erase(i);
152 i->was_written = i->pending_write;
157 for(auto i=image_accesses.begin(); i!=image_accesses.end(); )
159 if(i->pending_layout==VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
160 i = image_accesses.erase(i);
163 i->current_layout = i->pending_layout;
169 bool Synchronizer::is_write_layout(unsigned layout)
171 return layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || layout==VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
172 layout==VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;