]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/transferqueue.cpp
Refactor TransferQueue to require explicit finalization of transfers
[libs/gl.git] / source / backends / vulkan / transferqueue.cpp
index f356510e4b3a02d57dddb387825eb478ea88fa37..8db81020425ee5e705b15bee3e098002483cf728 100644 (file)
@@ -1,4 +1,5 @@
 #include <msp/core/algorithm.h>
+#include <msp/core/maputils.h>
 #include "device.h"
 #include "transferqueue.h"
 #include "vulkan.h"
@@ -12,36 +13,65 @@ TransferQueue::TransferQueue(Device &d):
        device(d)
 { }
 
-TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(const void *object, bool ordered, size_t size)
+void TransferQueue::allocate_staging(PendingTransfer &transfer, size_t size)
 {
-       unsigned &order = next_orders[object];
-       order += !order;
-       order += (order&1)|ordered;
+       auto i = find_if(buffers, [size](const StagingBuffer &b){ return b.used+size<=b.size; });
+       if(i==buffers.end())
+       {
+               buffers.emplace_back(device, max(default_buffer_size, size));
+               i = prev(buffers.end());
+       }
 
-       auto j = upper_bound_member(transfers, order, &PendingTransfer::order);
+       transfer.buffer_index = distance(buffers.begin(), i);
+       transfer.offset = i->used;
+       transfer.size = size;
+       transfer.staging_address = static_cast<char *>(i->mapped_address)+transfer.offset;
 
-       PendingTransfer &transfer = *transfers.emplace(j);
-       transfer.order = order;
+       i->used += size;
+}
+
+TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(const void *object, bool ordered, size_t size)
+{
+       PendingTransfer transfer;
+       transfer.object = object;
+       transfer.order = ordered;
 
        if(size)
        {
-               auto i = find_if(buffers, [size](const StagingBuffer &b){ return b.used+size<=b.size; });
-               if(i==buffers.end())
-               {
-                       buffers.emplace_back(device, max(default_buffer_size, size));
-                       i = prev(buffers.end());
-               }
+               allocate_staging(transfer, size);
+               auto i = lower_bound_member(async_transfers, transfer.staging_address, &PendingTransfer::staging_address);
+               i = async_transfers.emplace(i, move(transfer));
+               return *i;
+       }
+       else
+               return insert_transfer(move(transfer));
+}
+
+void TransferQueue::finalize_transfer(void *staging)
+{
+       auto i = lower_bound_member(async_transfers, staging, &PendingTransfer::staging_address);
+       if(i==async_transfers.end() || i->staging_address!=staging)
+               throw key_error(staging);
 
-               transfer.buffer_index = distance(buffers.begin(), i);
-               transfer.offset = i->used;
-               transfer.size = size;
+       insert_transfer(move(*i));
+       async_transfers.erase(i);
+}
 
-               i->used += size;
-       }
+TransferQueue::PendingTransfer &TransferQueue::insert_transfer(PendingTransfer &&pt)
+{
+       bool ordered = pt.order;
+
+       unsigned &order = next_orders[pt.object];
+       order += !order;
+       order += (order&1)|ordered;
+
+       auto j = upper_bound_member(transfers, order, &PendingTransfer::order);
+       j = transfers.emplace(j, move(pt));
+       j->order = order;
 
        order += ordered;
 
-       return transfer;
+       return *j;
 }
 
 void TransferQueue::dispatch_transfers(VkCommandBuffer command_buffer)