void VulkanBuffer::sub_data(size_t off, size_t sz, const void *d)
{
- device.get_synchronizer().write_buffer(handle, off, sz);
-
- void *staging = device.get_transfer_queue().prepare_transfer(sz, [this, off, sz](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
- const VulkanFunctions &vk = device.get_functions();
-
- VkBufferCopy region = { };
- region.srcOffset = src_off;
- region.dstOffset = off;
- region.size = sz;
- vk.CmdCopyBuffer(cmd_buf, staging_buf, handle, 1, ®ion);
- });
+ void *staging = device.get_transfer_queue().prepare_transfer(sz,
+ [this, off, sz](){
+ device.get_synchronizer().write_buffer(handle, off, sz);
+ },
+ [this, off, sz](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
+ const VulkanFunctions &vk = device.get_functions();
+
+ VkBufferCopy region = { };
+ region.srcOffset = src_off;
+ region.dstOffset = off;
+ region.size = sz;
+ vk.CmdCopyBuffer(cmd_buf, staging_buf, handle, 1, ®ion);
+ });
const char *src = static_cast<const char *>(d);
copy(src, src+sz, static_cast<char *>(staging));
const Texture1D &self = *static_cast<const Texture1D *>(this);
unsigned level_size = self.get_level_size(level);
- change_layout(self.levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (x==0 && wd==level_size));
+ 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,
+ [this, level, discard](){
+ unsigned n_levels = static_cast<const Texture1D *>(this)->levels;
+ change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
+ },
[this, level, x, wd](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
const Texture2D &self = *static_cast<const Texture2D *>(this);
auto level_size = self.get_level_size(level);
- change_layout(self.levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (x==0 && y==0 && wd==level_size.x && ht==level_size.y));
+ 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,
+ [this, level, discard](){
+ unsigned n_levels = static_cast<const Texture2D *>(this)->levels;
+ change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
+ },
[this, level, x, y, wd, ht](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
auto level_size = self.get_level_size(level);
bool discard = (x==0 && y==0 && z==0 && wd==level_size.x && ht==level_size.y && dp==level_size.z);
- change_layout(self.levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
size_t data_size = wd*ht*dp*get_pixel_size(storage_fmt);
void *staging = device.get_transfer_queue().prepare_transfer(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);
+ },
[this, level, x, y, z, wd, ht, dp](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
const TextureCube &self = *static_cast<const TextureCube *>(this);
unsigned level_size = self.get_level_size(level);
- change_layout(self.levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (x==0 && y==0 && wd==level_size && ht==level_size));
+ 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,
+ [this, level, discard](){
+ unsigned n_levels = static_cast<const TextureCube *>(this)->levels;
+ change_layout(n_levels, level, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, discard);
+ },
[this, face, level, x, y, wd, ht](VkCommandBuffer cmd_buf, VkBuffer staging_buf, size_t src_off){
const VulkanFunctions &vk = device.get_functions();
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)
+ t.synchronize();
+
+ device.get_synchronizer().barrier(command_buffer);
for(const PendingTransfer &t: transfers)
{
VkBuffer buffer = buffers[t.buffer_index].buffer;
- t.callback(command_buffer, buffer, t.offset);
+ t.transfer(command_buffer, buffer, t.offset);
}
transfers.clear();
~StagingBuffer();
};
- using TransferCallback = void(VkCommandBuffer, VkBuffer, std::size_t);
-
struct PendingTransfer
{
unsigned buffer_index = 0;
std::size_t offset = 0;
std::size_t size = 0;
- std::function<TransferCallback> callback;
+ std::function<void()> synchronize;
+ std::function<void(VkCommandBuffer, VkBuffer, std::size_t)> transfer;
};
Device &device;
public:
TransferQueue(Device &);
- template<typename T>
- void *prepare_transfer(std::size_t, T &&);
+ template<typename S, typename T>
+ void *prepare_transfer(std::size_t, S &&, T &&);
private:
PendingTransfer &prepare_transfer(std::size_t);
void dispatch_transfers(VkCommandBuffer);
};
-template<typename T>
-void *TransferQueue::prepare_transfer(std::size_t size, T &&callback)
+template<typename S, typename T>
+void *TransferQueue::prepare_transfer(std::size_t size, S &&synchronize, T &&transfer)
{
PendingTransfer &pt = prepare_transfer(size);
- pt.callback = std::forward<T>(callback);
+ pt.synchronize = std::forward<S>(synchronize);
+ pt.transfer = std::forward<T>(transfer);
return static_cast<char *>(buffers[pt.buffer_index].mapped_address)+pt.offset;
}