#include <msp/core/algorithm.h>
+#include <msp/core/maputils.h>
#include "device.h"
#include "transferqueue.h"
#include "vulkan.h"
device(d)
{ }
-TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(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 j = upper_bound_member(transfers, order, &PendingTransfer::order);
-
- PendingTransfer &transfer = *transfers.emplace(j);
- transfer.order = order;
-
auto i = find_if(buffers, [size](const StagingBuffer &b){ return b.used+size<=b.size; });
if(i==buffers.end())
{
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;
+
+ 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;
- i->used += size;
+ 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)
if(transfers.empty())
return;
+ ++current_frame;
for(auto i=transfers.begin(); i!=transfers.end(); )
{
auto j = i;
for(; i!=j; ++i)
{
- VkBuffer buffer = buffers[i->buffer_index].buffer;
+ 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;
}
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):
if(mapped_address)
{
- allocator.unmap(mapped_address);
+ allocator.unmap(memory_id);
allocator.release(memory_id);
}
if(buffer)