]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/transferqueue.cpp
Align staging memory with an alignment suitable for image transfers
[libs/gl.git] / source / backends / vulkan / transferqueue.cpp
index d0ccb0d571c88419838faec234a7cd99e0f7fcd9..f6f3c6f5079f2c2a01812348616d8b1fb83ef367 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,7 +13,7 @@ TransferQueue::TransferQueue(Device &d):
        device(d)
 { }
 
-TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(size_t size)
+void TransferQueue::allocate_staging(PendingTransfer &transfer, size_t size)
 {
        auto i = find_if(buffers, [size](const StagingBuffer &b){ return b.used+size<=b.size; });
        if(i==buffers.end())
@@ -21,29 +22,92 @@ TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(size_t size)
                i = prev(buffers.end());
        }
 
-       PendingTransfer transfer;
        transfer.buffer_index = distance(buffers.begin(), i);
        transfer.offset = i->used;
        transfer.size = size;
-       transfers.push_back(transfer);
+       transfer.staging_address = static_cast<char *>(i->mapped_address)+transfer.offset;
+
+       i->used += size+47;
+       i->used -= i->used%48;
+       ++i->async_count;
+}
+
+TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(const void *object, bool ordered, size_t size)
+{
+       PendingTransfer transfer;
+       transfer.object = object;
+       transfer.order = ordered;
+
+       if(size)
+       {
+               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);
+
+       if(i->buffer_index>=0)
+               --buffers[i->buffer_index].async_count;
+       insert_transfer(move(*i));
+       async_transfers.erase(i);
+}
+
+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;
 
-       i->used += size;
+       order += ordered;
 
-       return transfers.back();
+       return *j;
 }
 
 void TransferQueue::dispatch_transfers(VkCommandBuffer command_buffer)
 {
-       if(!transfers.empty())
-               device.get_synchronizer().barrier(command_buffer);
+       if(transfers.empty())
+               return;
 
-       for(const PendingTransfer &t: transfers)
+       ++current_frame;
+       for(auto i=transfers.begin(); i!=transfers.end(); )
        {
-               VkBuffer buffer = buffers[t.buffer_index].buffer;
-               t.callback(command_buffer, buffer, t.offset);
+               auto j = i;
+               for(; (j!=transfers.end() && j->order==i->order); ++j)
+                       j->synchronize();
+
+               device.get_synchronizer().barrier(command_buffer);
+
+               for(; i!=j; ++i)
+               {
+                       VkBuffer buffer = (i->buffer_index>=0 ? buffers[i->buffer_index].buffer : 0);
+                       i->transfer(command_buffer, buffer, i->offset);
+                       if(i->buffer_index>=0)
+                               buffers[i->buffer_index].last_frame = current_frame;
+               }
        }
 
        transfers.clear();
+       next_orders.clear();
+
+       unsigned n_frames_in_flight = device.get_n_frames_in_flight();
+       for(StagingBuffer &b: buffers)
+               if(!b.async_count && b.last_frame+n_frames_in_flight<current_frame)
+                       b.used = 0;
 }
 
 
@@ -63,7 +127,7 @@ TransferQueue::StagingBuffer::StagingBuffer(Device &d, size_t s):
 
        MemoryAllocator &allocator = device.get_allocator();
        memory_id = allocator.allocate(buffer, STAGING_MEMORY);
-       mapped_address = allocator.map(memory_id, 0, size);
+       mapped_address = allocator.map(memory_id);
 }
 
 TransferQueue::StagingBuffer::StagingBuffer(StagingBuffer &&other):
@@ -86,7 +150,7 @@ TransferQueue::StagingBuffer::~StagingBuffer()
 
        if(mapped_address)
        {
-               allocator.unmap(mapped_address);
+               allocator.unmap(memory_id);
                allocator.release(memory_id);
        }
        if(buffer)