#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(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)