void VulkanBuffer::sub_data(size_t off, size_t sz, const void *d)
{
- void *staging = device.get_transfer_queue().prepare_transfer(sz,
+ void *staging = device.get_transfer_queue().prepare_transfer(this, false, sz,
[this, off, sz](){
device.get_synchronizer().write_buffer(handle, off, sz);
},
bool discard = (x==0 && wd==level_size);
size_t data_size = wd*get_pixel_size(storage_fmt);
- void *staging = device.get_transfer_queue().prepare_transfer(data_size,
+ void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
unsigned n_levels = static_cast<const Texture1D *>(this)->levels;
change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
bool discard = (x==0 && y==0 && wd==level_size.x && ht==level_size.y);
size_t data_size = wd*ht*get_pixel_size(storage_fmt);
- void *staging = device.get_transfer_queue().prepare_transfer(data_size,
+ void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
unsigned n_levels = static_cast<const Texture2D *>(this)->levels;
change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
bool discard = (x==0 && y==0 && z==0 && wd==level_size.x && ht==level_size.y && dp==level_size.z);
size_t data_size = wd*ht*dp*get_pixel_size(storage_fmt);
- void *staging = device.get_transfer_queue().prepare_transfer(data_size,
+ void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
unsigned n_levels = static_cast<const Texture3D *>(this)->levels;
change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
bool discard = (x==0 && y==0 && wd==level_size && ht==level_size);
size_t data_size = wd*ht*get_pixel_size(storage_fmt);
- void *staging = device.get_transfer_queue().prepare_transfer(data_size,
+ void *staging = device.get_transfer_queue().prepare_transfer(this, false, data_size,
[this, level, discard](){
unsigned n_levels = static_cast<const TextureCube *>(this)->levels;
change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
device(d)
{ }
-TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(size_t size)
+TransferQueue::PendingTransfer &TransferQueue::prepare_transfer(void *object, bool ordered, 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())
{
i = prev(buffers.end());
}
- PendingTransfer transfer;
transfer.buffer_index = distance(buffers.begin(), i);
transfer.offset = i->used;
transfer.size = size;
- transfers.push_back(transfer);
i->used += size;
- return transfers.back();
+ order += ordered;
+
+ return transfer;
}
void TransferQueue::dispatch_transfers(VkCommandBuffer command_buffer)
if(transfers.empty())
return;
- for(const PendingTransfer &t: transfers)
- t.synchronize();
+ for(auto i=transfers.begin(); i!=transfers.end(); )
+ {
+ auto j = i;
+ for(; (j!=transfers.end() && j->order==i->order); ++j)
+ j->synchronize();
- device.get_synchronizer().barrier(command_buffer);
+ device.get_synchronizer().barrier(command_buffer);
- for(const PendingTransfer &t: transfers)
- {
- VkBuffer buffer = buffers[t.buffer_index].buffer;
- t.transfer(command_buffer, buffer, t.offset);
+ for(; i!=j; ++i)
+ {
+ VkBuffer buffer = buffers[i->buffer_index].buffer;
+ i->transfer(command_buffer, buffer, i->offset);
+ }
}
transfers.clear();
+ next_orders.clear();
}
struct PendingTransfer
{
+ unsigned order = 0;
unsigned buffer_index = 0;
std::size_t offset = 0;
std::size_t size = 0;
std::size_t default_buffer_size = 16*1048576;
std::vector<StagingBuffer> buffers;
std::vector<PendingTransfer> transfers;
+ std::map<void *, unsigned> next_orders;
public:
TransferQueue(Device &);
template<typename S, typename T>
- void *prepare_transfer(std::size_t, S &&, T &&);
+ void *prepare_transfer(void *, bool, std::size_t, S &&, T &&);
private:
- PendingTransfer &prepare_transfer(std::size_t);
+ PendingTransfer &prepare_transfer(void *, bool, std::size_t);
public:
void dispatch_transfers(VkCommandBuffer);
};
template<typename S, typename T>
-void *TransferQueue::prepare_transfer(std::size_t size, S &&synchronize, T &&transfer)
+void *TransferQueue::prepare_transfer(void *object, bool ordered, std::size_t size, S &&synchronize, T &&transfer)
{
- PendingTransfer &pt = prepare_transfer(size);
+ PendingTransfer &pt = prepare_transfer(object, ordered, size);
pt.synchronize = std::forward<S>(synchronize);
pt.transfer = std::forward<T>(transfer);
return static_cast<char *>(buffers[pt.buffer_index].mapped_address)+pt.offset;