[FFmpeg-devel] [PATCH v4 04/16] vulkan: copy host-mapping buffer code from hwcontext
Lynne
dev at lynne.ee
Thu Mar 13 19:03:36 EET 2025
This is useful elsewhere.
---
libavutil/vulkan.c | 163 ++++++++++++++++++++++++++++++++++++++++++++-
libavutil/vulkan.h | 18 ++++-
2 files changed, 178 insertions(+), 3 deletions(-)
diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c
index 99c6af7e48..235c76d1d0 100644
--- a/libavutil/vulkan.c
+++ b/libavutil/vulkan.c
@@ -1088,6 +1088,8 @@ int ff_vk_unmap_buffers(FFVulkanContext *s, FFVkBuffer **buf, int nb_buffers,
.memory = buf[i]->mem,
.size = VK_WHOLE_SIZE,
};
+
+ av_assert0(!buf[i]->host_ref);
if (buf[i]->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
continue;
flush_list[flush_count++] = flush_buf;
@@ -1119,12 +1121,18 @@ void ff_vk_free_buf(FFVulkanContext *s, FFVkBuffer *buf)
if (!buf || !s->hwctx)
return;
- if (buf->mapped_mem)
+ if (buf->mapped_mem && !buf->host_ref)
ff_vk_unmap_buffer(s, buf, 0);
if (buf->buf != VK_NULL_HANDLE)
vk->DestroyBuffer(s->hwctx->act_dev, buf->buf, s->hwctx->alloc);
if (buf->mem != VK_NULL_HANDLE)
vk->FreeMemory(s->hwctx->act_dev, buf->mem, s->hwctx->alloc);
+ if (buf->host_ref)
+ av_buffer_unref(&buf->host_ref);
+
+ buf->buf = VK_NULL_HANDLE;
+ buf->mem = VK_NULL_HANDLE;
+ buf->mapped_mem = NULL;
}
static void free_data_buf(void *opaque, uint8_t *data)
@@ -1201,6 +1209,157 @@ int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVBufferPool **buf_pool,
return 0;
}
+static int create_mapped_buffer(FFVulkanContext *s,
+ FFVkBuffer *vkb, VkBufferUsageFlags usage,
+ size_t size,
+ VkExternalMemoryBufferCreateInfo *create_desc,
+ VkImportMemoryHostPointerInfoEXT *import_desc,
+ VkMemoryHostPointerPropertiesEXT props)
+{
+ int err;
+ VkResult ret;
+ FFVulkanFunctions *vk = &s->vkfn;
+
+ VkBufferCreateInfo buf_spawn = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .pNext = create_desc,
+ .usage = usage,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .size = size,
+ };
+ VkMemoryRequirements req = {
+ .size = size,
+ .alignment = s->hprops.minImportedHostPointerAlignment,
+ .memoryTypeBits = props.memoryTypeBits,
+ };
+
+ err = ff_vk_alloc_mem(s, &req,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
+ import_desc, &vkb->flags, &vkb->mem);
+ if (err < 0)
+ return err;
+
+ ret = vk->CreateBuffer(s->hwctx->act_dev, &buf_spawn, s->hwctx->alloc, &vkb->buf);
+ if (ret != VK_SUCCESS) {
+ vk->FreeMemory(s->hwctx->act_dev, vkb->mem, s->hwctx->alloc);
+ return AVERROR_EXTERNAL;
+ }
+
+ ret = vk->BindBufferMemory(s->hwctx->act_dev, vkb->buf, vkb->mem, 0);
+ if (ret != VK_SUCCESS) {
+ vk->FreeMemory(s->hwctx->act_dev, vkb->mem, s->hwctx->alloc);
+ vk->DestroyBuffer(s->hwctx->act_dev, vkb->buf, s->hwctx->alloc);
+ return AVERROR_EXTERNAL;
+ }
+
+ return 0;
+}
+
+static void destroy_avvkbuf(void *opaque, uint8_t *data)
+{
+ FFVulkanContext *s = opaque;
+ FFVkBuffer *buf = (FFVkBuffer *)data;
+ ff_vk_free_buf(s, buf);
+ av_free(buf);
+}
+
+int ff_vk_host_map_buffer(FFVulkanContext *s, AVBufferRef **dst,
+ uint8_t *src_data, AVBufferRef *src_buf,
+ VkBufferUsageFlags usage)
+{
+ int err;
+ VkResult ret;
+ FFVulkanFunctions *vk = &s->vkfn;
+
+ VkExternalMemoryBufferCreateInfo create_desc = {
+ .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
+ .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
+ };
+ VkMemoryAllocateFlagsInfo alloc_flags = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,
+ .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT,
+ };
+ VkImportMemoryHostPointerInfoEXT import_desc = {
+ .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
+ .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
+ .pNext = usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ? &alloc_flags : NULL,
+ };
+ VkMemoryHostPointerPropertiesEXT props;
+
+ AVBufferRef *ref;
+ FFVkBuffer *vkb;
+ size_t offs;
+ size_t buffer_size;
+
+ *dst = NULL;
+
+ /* Get the previous point at which mapping was possible and use it */
+ offs = (uintptr_t)src_data % s->hprops.minImportedHostPointerAlignment;
+ import_desc.pHostPointer = src_data - offs;
+
+ props = (VkMemoryHostPointerPropertiesEXT) {
+ VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
+ };
+ ret = vk->GetMemoryHostPointerPropertiesEXT(s->hwctx->act_dev,
+ import_desc.handleType,
+ import_desc.pHostPointer,
+ &props);
+ if (!(ret == VK_SUCCESS && props.memoryTypeBits))
+ return AVERROR(EINVAL);
+
+ /* Ref the source buffer */
+ ref = av_buffer_ref(src_buf);
+ if (!ref)
+ return AVERROR(ENOMEM);
+
+ /* Add the offset at the start, which gets ignored */
+ buffer_size = offs + src_buf->size;
+ buffer_size = FFALIGN(buffer_size, s->props.properties.limits.minMemoryMapAlignment);
+ buffer_size = FFALIGN(buffer_size, s->hprops.minImportedHostPointerAlignment);
+
+ /* Create a buffer struct */
+ vkb = av_mallocz(sizeof(*vkb));
+ if (!vkb) {
+ av_buffer_unref(&ref);
+ return AVERROR(ENOMEM);
+ }
+
+ err = create_mapped_buffer(s, vkb, usage,
+ buffer_size, &create_desc, &import_desc,
+ props);
+ if (err < 0) {
+ av_buffer_unref(&ref);
+ av_free(vkb);
+ return err;
+ }
+
+ if (usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) {
+ VkBufferDeviceAddressInfo address_info = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
+ .buffer = vkb->buf,
+ };
+ vkb->address = vk->GetBufferDeviceAddress(s->hwctx->act_dev, &address_info);
+ }
+
+ vkb->host_ref = ref;
+ vkb->virtual_offset = offs;
+ vkb->address += offs;
+ vkb->mapped_mem = src_data;
+ vkb->size = buffer_size - offs;
+ vkb->flags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+ /* Create a ref */
+ *dst = av_buffer_create((uint8_t *)vkb, sizeof(*vkb),
+ destroy_avvkbuf, s, 0);
+ if (!(*dst)) {
+ destroy_avvkbuf(s, (uint8_t *)vkb);
+ *dst = NULL;
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
int ff_vk_shader_add_push_const(FFVulkanShader *shd, int offset, int size,
VkShaderStageFlagBits stage)
{
@@ -2533,7 +2692,7 @@ int ff_vk_shader_update_desc_buffer(FFVulkanContext *s, FFVkExecContext *e,
} else {
VkDescriptorBufferInfo desc_pool_write_info_buf = {
.buffer = buf->buf,
- .offset = offset,
+ .offset = buf->virtual_offset + offset,
.range = len,
};
VkWriteDescriptorSet desc_pool_write_info = {
diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h
index baf9dc2009..29249fe95d 100644
--- a/libavutil/vulkan.h
+++ b/libavutil/vulkan.h
@@ -96,8 +96,17 @@ typedef struct FFVkBuffer {
VkPipelineStageFlags2 stage;
VkAccessFlags2 access;
- /* Only valid when allocated via ff_vk_get_pooled_buffer with HOST_VISIBLE */
+ /* Only valid when allocated via ff_vk_get_pooled_buffer with HOST_VISIBLE or
+ * via ff_vk_host_map_buffer */
uint8_t *mapped_mem;
+
+ /* Set by ff_vk_host_map_buffer. This is the offset at which the buffer data
+ * actually begins at.
+ * The address and mapped_mem fields will be offset by this amount. */
+ size_t virtual_offset;
+
+ /* If host mapping, reference to the backing host memory buffer */
+ AVBufferRef *host_ref;
} FFVkBuffer;
typedef struct FFVkExecContext {
@@ -520,6 +529,13 @@ int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVBufferPool **buf_pool,
void *create_pNext, size_t size,
VkMemoryPropertyFlagBits mem_props);
+/** Maps a system RAM buffer into a Vulkan buffer.
+ * References the source buffer.
+ */
+int ff_vk_host_map_buffer(FFVulkanContext *s, AVBufferRef **dst,
+ uint8_t *src_data, AVBufferRef *src_buf,
+ VkBufferUsageFlags usage);
+
/**
* Create a sampler.
*/
--
2.47.2
More information about the ffmpeg-devel
mailing list