Vulkan: Area Readback of Framebuffer Textures #108418
|
@ -232,8 +232,8 @@ void VKFrameBuffer::attachment_set_loadstore_op(GPUAttachmentType /*type*/,
|
|||
|
||||
void VKFrameBuffer::read(eGPUFrameBufferBits plane,
|
||||
eGPUDataFormat format,
|
||||
const int /*area*/[4],
|
||||
int channel_len,
|
||||
const int area[4],
|
||||
int /*channel_len*/,
|
||||
int slot,
|
||||
void *r_data)
|
||||
{
|
||||
|
@ -243,30 +243,19 @@ void VKFrameBuffer::read(eGPUFrameBufferBits plane,
|
|||
texture = unwrap(unwrap(attachments_[GPU_FB_COLOR_ATTACHMENT0 + slot].tex));
|
||||
break;
|
||||
|
||||
case GPU_DEPTH_BIT:
|
||||
texture = unwrap(unwrap(attachments_[GPU_FB_DEPTH_ATTACHMENT].tex));
|
||||
break;
|
||||
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_assert_msg(texture,
|
||||
"Trying to read back color texture from framebuffer, but no color texture is "
|
||||
"available in requested slot.");
|
||||
void *data = texture->read(0, format);
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Add support for area.
|
||||
* - Add support for channel_len.
|
||||
* Best option would be to add this to VKTexture so we don't over-allocate and reduce number of
|
||||
* times copies are made.
|
||||
*/
|
||||
BLI_assert(format == GPU_DATA_FLOAT);
|
||||
BLI_assert(channel_len == 4);
|
||||
int mip_size[3] = {1, 1, 1};
|
||||
texture->mip_size_get(0, mip_size);
|
||||
const size_t mem_size = mip_size[0] * mip_size[1] * mip_size[2] * sizeof(float) * channel_len;
|
||||
memcpy(r_data, data, mem_size);
|
||||
MEM_freeN(data);
|
||||
"Trying to read back texture from framebuffer, but no texture is available in "
|
||||
"requested slot.");
|
||||
texture->read_sub(0, format, area, r_data);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -64,7 +64,7 @@ void VKTexture::swizzle_set(const char /*swizzle_mask*/[4]) {}
|
|||
|
||||
void VKTexture::mip_range_set(int /*min*/, int /*max*/) {}
|
||||
|
||||
void *VKTexture::read(int mip, eGPUDataFormat format)
|
||||
void VKTexture::read_sub(int mip, eGPUDataFormat format, const int area[4], void *r_data)
|
||||
{
|
||||
VKContext &context = *VKContext::get();
|
||||
layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
@ -72,20 +72,18 @@ void *VKTexture::read(int mip, eGPUDataFormat format)
|
|||
/* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */
|
||||
VKBuffer staging_buffer;
|
||||
|
||||
/* NOTE: mip_size_get() won't override any dimension that is equal to 0. */
|
||||
int extent[3] = {1, 1, 1};
|
||||
mip_size_get(mip, extent);
|
||||
size_t sample_len = extent[0] * extent[1] * extent[2];
|
||||
size_t sample_len = area[2] * area[3];
|
||||
size_t device_memory_size = sample_len * to_bytesize(format_);
|
||||
size_t host_memory_size = sample_len * to_bytesize(format_, format);
|
||||
|
||||
staging_buffer.create(
|
||||
device_memory_size, GPU_USAGE_DEVICE_ONLY, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageExtent.width = extent[0];
|
||||
region.imageExtent.height = extent[1];
|
||||
region.imageExtent.depth = extent[2];
|
||||
region.imageOffset.x = area[0];
|
||||
region.imageOffset.y = area[1];
|
||||
region.imageExtent.width = area[2];
|
||||
region.imageExtent.height = area[3];
|
||||
region.imageExtent.depth = 1;
|
||||
region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
||||
region.imageSubresource.mipLevel = mip;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
|
@ -94,8 +92,19 @@ void *VKTexture::read(int mip, eGPUDataFormat format)
|
|||
command_buffer.copy(staging_buffer, *this, Span<VkBufferImageCopy>(®ion, 1));
|
||||
command_buffer.submit();
|
||||
|
||||
convert_device_to_host(r_data, staging_buffer.mapped_memory_get(), sample_len, format, format_);
|
||||
}
|
||||
|
||||
void *VKTexture::read(int mip, eGPUDataFormat format)
|
||||
{
|
||||
int mip_size[3] = {1, 1, 1};
|
||||
mip_size_get(mip, mip_size);
|
||||
size_t sample_len = mip_size[0] * mip_size[1];
|
||||
size_t host_memory_size = sample_len * to_bytesize(format_, format);
|
||||
|
||||
void *data = MEM_mallocN(host_memory_size, __func__);
|
||||
convert_device_to_host(data, staging_buffer.mapped_memory_get(), sample_len, format, format_);
|
||||
int area[4] = {0, 0, mip_size[0], mip_size[1]};
|
||||
read_sub(mip, format, area, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ class VKTexture : public Texture {
|
|||
void swizzle_set(const char swizzle_mask[4]) override;
|
||||
void mip_range_set(int min, int max) override;
|
||||
void *read(int mip, eGPUDataFormat format) override;
|
||||
void read_sub(int mip, eGPUDataFormat format, const int area[4], void *r_data);
|
||||
void update_sub(
|
||||
int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) override;
|
||||
void update_sub(int offset[3],
|
||||
|
|
Loading…
Reference in New Issue