From 36d02882b9ac773416fb3304fa7679bcdb45e7b9 Mon Sep 17 00:00:00 2001 From: EpEpDragon Date: Wed, 28 Dec 2022 10:37:42 +0200 Subject: [PATCH] Added optional offset and size parameter to RenderDevice buffer_get_data method --- doc/classes/RenderingDevice.xml | 3 +++ drivers/vulkan/rendering_device_vulkan.cpp | 20 ++++++++++++++------ drivers/vulkan/rendering_device_vulkan.h | 2 +- servers/rendering/rendering_device.cpp | 2 +- servers/rendering/rendering_device.h | 2 +- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index f3184306112c..a575ea80b004 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -26,7 +26,10 @@ + + + Returns a copy of the data of the specified [param buffer], optionally [param offset_bytes] and [param size_bytes] can be set to copy only a portion of the buffer. diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 425ca1c5161a..5c834be0b9cd 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -5926,7 +5926,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3 return OK; } -Vector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { +Vector RenderingDeviceVulkan::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) { _THREAD_SAFE_METHOD_ // It could be this buffer was just created. @@ -5943,12 +5943,20 @@ Vector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + // Size of buffer to retrieve. + if (!p_size) { + p_size = buffer->size; + } else { + ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, Vector(), + "Size is larger than the buffer."); + } + Buffer tmp_buffer; - _buffer_allocate(&tmp_buffer, buffer->size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT); + _buffer_allocate(&tmp_buffer, p_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT); VkBufferCopy region; - region.srcOffset = 0; + region.srcOffset = p_offset; region.dstOffset = 0; - region.size = buffer->size; + region.size = p_size; vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, ®ion); // Dst buffer is in CPU, but I wonder if src buffer needs a barrier for this. // Flush everything so memory can be safely mapped. _flush(true); @@ -5959,9 +5967,9 @@ Vector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { Vector buffer_data; { - buffer_data.resize(buffer->size); + buffer_data.resize(p_size); uint8_t *w = buffer_data.ptrw(); - memcpy(w, buffer_mem, buffer->size); + memcpy(w, buffer_mem, p_size); } vmaUnmapMemory(allocator, tmp_buffer.allocation); diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index b2c2a03a8724..5d81e20fe2ad 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -1122,7 +1122,7 @@ class RenderingDeviceVulkan : public RenderingDevice { virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); // Works for any buffer. virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual Vector buffer_get_data(RID p_buffer); + virtual Vector buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0); /*************************/ /**** RENDER PIPELINE ****/ diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 28f872761ab8..286d1b683fb5 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -746,7 +746,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); - ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data); + ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer", "offset_bytes", "size_bytes"), &RenderingDevice::buffer_get_data, DEFVAL(0), DEFVAL(0)); ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray())); ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 08ca25b64b07..9de21dcac663 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -828,7 +828,7 @@ class RenderingDevice : public Object { virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; - virtual Vector buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving + virtual Vector buffer_get_data(RID p_buffer, uint32_t p_offset = 0, uint32_t p_size = 0) = 0; // This causes stall, only use to retrieve large buffers for saving. /******************************************/ /**** PIPELINE SPECIALIZATION CONSTANT ****/