]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/synchronizer.cpp
Don't create no-op barriers
[libs/gl.git] / source / backends / vulkan / synchronizer.cpp
1 #include <msp/core/algorithm.h>
2 #include "buffer.h"
3 #include "device.h"
4 #include "texture.h"
5 #include "synchronizer.h"
6 #include "vulkan.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace GL {
12
13 Synchronizer::Synchronizer(Device &d):
14         device(d)
15 { }
16
17 void Synchronizer::access(VkBuffer buffer, size_t offset, size_t size)
18 {
19         auto i = find_member(buffer_accesses, buffer, &BufferAccess::buffer);
20         if(i==buffer_accesses.end())
21         {
22                 i = buffer_accesses.emplace(buffer_accesses.end());
23                 i->buffer = buffer;
24                 i->offset = offset;
25                 i->size = size;
26         }
27         else
28         {
29                 size_t begin = min(offset, i->offset);
30                 size_t end = max(offset+size, i->offset+i->size);
31                 i->offset = begin;
32                 i->size = end-begin;
33         }
34
35         i->pending_write = true;
36 }
37
38 void Synchronizer::access(VkImage image, unsigned aspect, int layer, unsigned layout, bool discard)
39 {
40         auto i = find_member(image_accesses, image, &ImageAccess::image);
41         if(i==image_accesses.end())
42         {
43                 i = image_accesses.emplace(image_accesses.end());
44                 i->image = image;
45                 i->aspect = aspect;
46                 i->layer = layer;
47                 i->current_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
48         }
49
50         if(discard)
51                 i->current_layout = VK_IMAGE_LAYOUT_UNDEFINED;
52         if(layer!=i->layer)
53                 i->layer = -1;
54         i->pending_layout = layout;
55 }
56
57 void Synchronizer::reset()
58 {
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;
63 }
64
65 void Synchronizer::barrier(VkCommandBuffer command_buffer)
66 {
67         const VulkanFunctions &vk = device.get_functions();
68
69         if(buffer_accesses.empty() && image_accesses.empty())
70                 return;
71
72         VkPipelineStageFlags src_stage = 0;
73         VkPipelineStageFlags dst_stage = 0;
74
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;
78
79         vector<VkBufferMemoryBarrier> buffer_barriers;
80         buffer_barriers.reserve(buffer_accesses.size());
81         for(BufferAccess &b: buffer_accesses)
82         {
83                 if(b.pending_write==b.was_written)
84                         continue;
85
86                 buffer_barriers.emplace_back(VkBufferMemoryBarrier{ });
87                 VkBufferMemoryBarrier &barrier = buffer_barriers.back();
88
89                 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
90                 barrier.srcAccessMask = (b.was_written ? VK_ACCESS_MEMORY_WRITE_BIT : 0);
91                 barrier.dstAccessMask = (b.pending_write ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_MEMORY_READ_BIT);
92                 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
93                 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
94                 barrier.buffer = handle_cast<::VkBuffer>(b.buffer);
95                 barrier.offset = b.offset;
96                 barrier.size = b.size;
97
98                 src_stage |= (b.was_written ? buffer_write_stages : buffer_read_stages);
99                 dst_stage |= (b.pending_write ? buffer_write_stages : buffer_read_stages);
100         }
101
102         static constexpr VkPipelineStageFlags image_read_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT|VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT|
103                 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
104         static constexpr VkPipelineStageFlags image_write_stages = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT|
105                 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT|VK_PIPELINE_STAGE_TRANSFER_BIT;
106
107         vector<VkImageMemoryBarrier> image_barriers;
108         image_barriers.reserve(image_accesses.size());
109         for(const ImageAccess &i: image_accesses)
110         {
111                 if(i.pending_layout==i.current_layout)
112                         continue;
113
114                 image_barriers.emplace_back(VkImageMemoryBarrier{ });
115                 VkImageMemoryBarrier &barrier = image_barriers.back();
116
117                 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
118                 barrier.srcAccessMask = (is_write_layout(i.current_layout) ? VK_ACCESS_MEMORY_WRITE_BIT : 0);
119                 barrier.dstAccessMask = (is_write_layout(i.pending_layout) ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_MEMORY_READ_BIT);
120                 barrier.oldLayout = static_cast<VkImageLayout>(i.current_layout);
121                 barrier.newLayout = static_cast<VkImageLayout>(i.pending_layout);
122                 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
123                 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
124                 barrier.image = handle_cast<::VkImage>(i.image);
125                 barrier.subresourceRange.aspectMask = i.aspect;
126                 barrier.subresourceRange.baseMipLevel = 0;
127                 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
128                 if(i.layer>=0)
129                 {
130                         barrier.subresourceRange.baseArrayLayer = i.layer;
131                         barrier.subresourceRange.layerCount = 1;
132                 }
133                 else
134                 {
135                         barrier.subresourceRange.baseArrayLayer = 0;
136                         barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
137                 }
138
139                 if(i.current_layout!=VK_IMAGE_LAYOUT_UNDEFINED)
140                         src_stage |= (is_write_layout(i.current_layout) ? image_write_stages : image_read_stages);
141                 dst_stage |= (is_write_layout(i.pending_layout) ? image_write_stages : image_read_stages);
142         }
143
144         if(buffer_barriers.empty() && image_barriers.empty())
145                 return;
146
147         if(!src_stage)
148                 src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
149         if(!dst_stage)
150                 dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
151
152         vk.CmdPipelineBarrier(command_buffer, src_stage, dst_stage, 0, 0, 0,
153                 buffer_barriers.size(), buffer_barriers.data(), image_barriers.size(), image_barriers.data());
154
155         for(auto i=buffer_accesses.begin(); i!=buffer_accesses.end(); )
156         {
157                 if(!i->pending_write)
158                         i = buffer_accesses.erase(i);
159                 else
160                 {
161                         i->was_written = i->pending_write;
162                         ++i;
163                 }
164         }
165
166         for(auto i=image_accesses.begin(); i!=image_accesses.end(); )
167         {
168                 if(i->pending_layout==VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
169                         i = image_accesses.erase(i);
170                 else
171                 {
172                         i->current_layout = i->pending_layout;
173                         ++i;
174                 }
175         }
176 }
177
178 bool Synchronizer::is_write_layout(unsigned layout)
179 {
180         return layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || layout==VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
181                 layout==VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
182 }
183
184 } // namespace GL
185 } // namespace Msp