]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/synchronizer.cpp
Add a synchronization helper class to the Vulkan backend
[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::reset()
39 {
40         for(BufferAccess &b: buffer_accesses)
41                 b.pending_write = false;
42 }
43
44 void Synchronizer::barrier(VkCommandBuffer command_buffer)
45 {
46         const VulkanFunctions &vk = device.get_functions();
47
48         if(buffer_accesses.empty())
49                 return;
50
51         VkPipelineStageFlags src_stage = 0;
52         VkPipelineStageFlags dst_stage = 0;
53
54         static constexpr VkPipelineStageFlags buffer_read_stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT|
55                 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT|VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
56         static constexpr VkPipelineStageFlags buffer_write_stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
57
58         vector<VkBufferMemoryBarrier> buffer_barriers;
59         buffer_barriers.reserve(buffer_accesses.size());
60         for(BufferAccess &b: buffer_accesses)
61         {
62                 buffer_barriers.emplace_back(VkBufferMemoryBarrier{ });
63                 VkBufferMemoryBarrier &barrier = buffer_barriers.back();
64
65                 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
66                 barrier.srcAccessMask = (b.was_written ? VK_ACCESS_MEMORY_WRITE_BIT : 0);
67                 barrier.dstAccessMask = (b.pending_write ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_MEMORY_READ_BIT);
68                 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
69                 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
70                 barrier.buffer = handle_cast<::VkBuffer>(b.buffer);
71                 barrier.offset = b.offset;
72                 barrier.size = b.size;
73
74                 src_stage |= (b.was_written ? buffer_write_stages : buffer_read_stages);
75                 dst_stage |= (b.pending_write ? buffer_write_stages : buffer_read_stages);
76         }
77
78         if(!src_stage)
79                 src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
80         if(!dst_stage)
81                 dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
82
83         vk.CmdPipelineBarrier(command_buffer, src_stage, dst_stage, 0, 0, 0,
84                 buffer_barriers.size(), buffer_barriers.data(), 0, 0);
85
86         for(auto i=buffer_accesses.begin(); i!=buffer_accesses.end(); )
87         {
88                 if(!i->pending_write)
89                         i = buffer_accesses.erase(i);
90                 else
91                 {
92                         i->was_written = i->pending_write;
93                         ++i;
94                 }
95         }
96 }
97
98 } // namespace GL
99 } // namespace Msp