]> git.tdb.fi Git - libs/gl.git/blob - source/backends/vulkan/transferqueue.cpp
Track the order of transfers involving the same objects
[libs/gl.git] / source / backends / vulkan / transferqueue.cpp
1 #include <msp/core/algorithm.h>
2 #include "device.h"
3 #include "transferqueue.h"
4 #include "vulkan.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace GL {
10
11 TransferQueue::TransferQueue(Device &d):
12         device(d)
13 { }
14
15 TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(void *object, bool ordered, size_t size)
16 {
17         unsigned &order = next_orders[object];
18         order += !order;
19         order += (order&1)|ordered;
20
21         auto j = upper_bound_member(transfers, order, &PendingTransfer::order);
22
23         PendingTransfer &transfer = *transfers.emplace(j);
24         transfer.order = order;
25
26         auto i = find_if(buffers, [size](const StagingBuffer &b){ return b.used+size<=b.size; });
27         if(i==buffers.end())
28         {
29                 buffers.emplace_back(device, max(default_buffer_size, size));
30                 i = prev(buffers.end());
31         }
32
33         transfer.buffer_index = distance(buffers.begin(), i);
34         transfer.offset = i->used;
35         transfer.size = size;
36
37         i->used += size;
38
39         order += ordered;
40
41         return transfer;
42 }
43
44 void TransferQueue::dispatch_transfers(VkCommandBuffer command_buffer)
45 {
46         if(transfers.empty())
47                 return;
48
49         for(auto i=transfers.begin(); i!=transfers.end(); )
50         {
51                 auto j = i;
52                 for(; (j!=transfers.end() && j->order==i->order); ++j)
53                         j->synchronize();
54
55                 device.get_synchronizer().barrier(command_buffer);
56
57                 for(; i!=j; ++i)
58                 {
59                         VkBuffer buffer = buffers[i->buffer_index].buffer;
60                         i->transfer(command_buffer, buffer, i->offset);
61                 }
62         }
63
64         transfers.clear();
65         next_orders.clear();
66 }
67
68
69 TransferQueue::StagingBuffer::StagingBuffer(Device &d, size_t s):
70         device(d),
71         size(s)
72 {
73         const VulkanFunctions &vk = device.get_functions();
74
75         VkBufferCreateInfo buffer_info = { };
76         buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
77         buffer_info.size = size;
78         buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
79         buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
80
81         vk.CreateBuffer(buffer_info, buffer);
82
83         MemoryAllocator &allocator = device.get_allocator();
84         memory_id = allocator.allocate(buffer, STAGING_MEMORY);
85         mapped_address = allocator.map(memory_id, 0, size);
86 }
87
88 TransferQueue::StagingBuffer::StagingBuffer(StagingBuffer &&other):
89         device(other.device),
90         buffer(other.buffer),
91         memory_id(other.memory_id),
92         size(other.size),
93         used(other.used),
94         mapped_address(other.mapped_address)
95 {
96         other.buffer = 0;
97         other.memory_id = 0;
98         other.mapped_address = 0;
99 }
100
101 TransferQueue::StagingBuffer::~StagingBuffer()
102 {
103         const VulkanFunctions &vk = device.get_functions();
104         MemoryAllocator &allocator = device.get_allocator();
105
106         if(mapped_address)
107         {
108                 allocator.unmap(mapped_address);
109                 allocator.release(memory_id);
110         }
111         if(buffer)
112                 vk.DestroyBuffer(buffer);
113 }
114
115 } // namespace GL
116 } // namespace Msp