1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-08-04 22:03:09 +02:00

ffv1enc_vulkan: use ff_get_encode_buffer

We used to create our own buffer, but still used the DR1 flag,
which is not how it's supposed to work.

Instead, use ff_get_encode_buffer, and either host-map the buffer
before copying each slice via GPU transfers, or just copy each
slice manually if that fails or is unavailable.
This commit is contained in:
Lynne
2025-05-03 13:44:04 +02:00
parent 8a2d921627
commit f69db914ce

View File

@ -88,7 +88,6 @@ typedef struct VulkanEncodeFFv1Context {
/* Output data buffer */ /* Output data buffer */
AVBufferPool *out_data_pool; AVBufferPool *out_data_pool;
AVBufferPool *pkt_data_pool;
/* Slice results buffer */ /* Slice results buffer */
AVBufferPool *results_data_pool; AVBufferPool *results_data_pool;
@ -299,8 +298,11 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
NULL, maxsize, NULL, maxsize,
maxsize < fv->max_heap_size ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0x0)); (maxsize < fv->max_heap_size ?
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0x0) |
(!(fv->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) ?
VK_MEMORY_PROPERTY_HOST_CACHED_BIT : 0x0)));
out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; out_data_buf = (FFVkBuffer *)fd->out_data_ref->data;
ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 1); ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 1);
@ -583,10 +585,10 @@ fail:
return err; return err;
} }
static int download_slices(AVCodecContext *avctx, static int transfer_slices(AVCodecContext *avctx,
VkBufferCopy *buf_regions, int nb_regions, VkBufferCopy *buf_regions, int nb_regions,
VulkanEncodeFFv1FrameData *fd, VulkanEncodeFFv1FrameData *fd,
AVBufferRef *pkt_data_ref) uint8_t *dst, AVBufferRef *dst_ref)
{ {
int err; int err;
VulkanEncodeFFv1Context *fv = avctx->priv_data; VulkanEncodeFFv1Context *fv = avctx->priv_data;
@ -594,11 +596,20 @@ static int download_slices(AVCodecContext *avctx,
FFVkExecContext *exec; FFVkExecContext *exec;
FFVkBuffer *out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; FFVkBuffer *out_data_buf = (FFVkBuffer *)fd->out_data_ref->data;
FFVkBuffer *pkt_data_buf = (FFVkBuffer *)pkt_data_ref->data;
AVBufferRef *mapped_ref;
FFVkBuffer *mapped_buf;
VkBufferMemoryBarrier2 buf_bar[8]; VkBufferMemoryBarrier2 buf_bar[8];
int nb_buf_bar = 0; int nb_buf_bar = 0;
err = ff_vk_host_map_buffer(&fv->s, &mapped_ref, dst, dst_ref,
VK_BUFFER_USAGE_TRANSFER_DST_BIT);
if (err < 0)
return err;
mapped_buf = (FFVkBuffer *)mapped_ref->data;
/* Transfer the slices */ /* Transfer the slices */
exec = ff_vk_exec_get(&fv->s, &fv->transfer_exec_pool); exec = ff_vk_exec_get(&fv->s, &fv->transfer_exec_pool);
ff_vk_exec_start(&fv->s, exec); ff_vk_exec_start(&fv->s, exec);
@ -606,7 +617,8 @@ static int download_slices(AVCodecContext *avctx,
ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 0); ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 0);
fd->out_data_ref = NULL; /* Ownership passed */ fd->out_data_ref = NULL; /* Ownership passed */
ff_vk_exec_add_dep_buf(&fv->s, exec, &pkt_data_ref, 1, 1); ff_vk_exec_add_dep_buf(&fv->s, exec, &mapped_ref, 1, 0);
mapped_ref = NULL; /* Ownership passed */
/* Ensure the output buffer is finished */ /* Ensure the output buffer is finished */
buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) {
@ -630,8 +642,11 @@ static int download_slices(AVCodecContext *avctx,
out_data_buf->access = buf_bar[0].dstAccessMask; out_data_buf->access = buf_bar[0].dstAccessMask;
nb_buf_bar = 0; nb_buf_bar = 0;
for (int i = 0; i < nb_regions; i++)
buf_regions[i].dstOffset += mapped_buf->virtual_offset;
vk->CmdCopyBuffer(exec->buf, vk->CmdCopyBuffer(exec->buf,
out_data_buf->buf, pkt_data_buf->buf, out_data_buf->buf, mapped_buf->buf,
nb_regions, buf_regions); nb_regions, buf_regions);
/* Submit */ /* Submit */
@ -642,18 +657,6 @@ static int download_slices(AVCodecContext *avctx,
/* We need the encoded data immediately */ /* We need the encoded data immediately */
ff_vk_exec_wait(&fv->s, exec); ff_vk_exec_wait(&fv->s, exec);
/* Invalidate slice/output data if needed */
if (!(pkt_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
VkMappedMemoryRange invalidate_data = {
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
.memory = pkt_data_buf->mem,
.offset = 0,
.size = VK_WHOLE_SIZE,
};
vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev,
1, &invalidate_data);
}
return 0; return 0;
} }
@ -664,13 +667,9 @@ static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec,
VulkanEncodeFFv1Context *fv = avctx->priv_data; VulkanEncodeFFv1Context *fv = avctx->priv_data;
FFV1Context *f = &fv->ctx; FFV1Context *f = &fv->ctx;
FFVulkanFunctions *vk = &fv->s.vkfn; FFVulkanFunctions *vk = &fv->s.vkfn;
/* Packet data */
AVBufferRef *pkt_data_ref;
FFVkBuffer *pkt_data_buf;
VulkanEncodeFFv1FrameData *fd = exec->opaque; VulkanEncodeFFv1FrameData *fd = exec->opaque;
FFVkBuffer *out_data_buf = (FFVkBuffer *)fd->out_data_ref->data;
FFVkBuffer *results_data_buf = (FFVkBuffer *)fd->results_data_ref->data; FFVkBuffer *results_data_buf = (FFVkBuffer *)fd->results_data_ref->data;
uint64_t *sc; uint64_t *sc;
@ -707,20 +706,9 @@ static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec,
av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / (1024*1024)); av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / (1024*1024));
av_buffer_unref(&fd->results_data_ref); /* No need for this buffer anymore */ av_buffer_unref(&fd->results_data_ref); /* No need for this buffer anymore */
/* Allocate packet buffer */ /* Allocate packet */
err = ff_vk_get_pooled_buffer(&fv->s, &fv->pkt_data_pool, if ((err = ff_get_encode_buffer(avctx, pkt, pkt->size, 0)) < 0)
&pkt_data_ref,
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
NULL, pkt->size,
VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (err < 0)
return err; return err;
pkt_data_buf = (FFVkBuffer *)pkt_data_ref->data;
/* Setup packet data */
pkt->data = pkt_data_buf->mapped_mem;
pkt->buf = pkt_data_ref;
pkt->pts = fd->pts; pkt->pts = fd->pts;
pkt->dts = fd->pts; pkt->dts = fd->pts;
@ -733,8 +721,37 @@ static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec,
fd->frame_opaque_ref = NULL; fd->frame_opaque_ref = NULL;
} }
return download_slices(avctx, fv->buf_regions, f->slice_count, fd, /* Try using host mapped memory transfers first */
pkt_data_ref); if (fv->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) {
err = transfer_slices(avctx, fv->buf_regions, f->slice_count, fd,
pkt->data, pkt->buf);
if (err >= 0)
return err;
}
/* Invalidate slice/output data if needed */
if (!(out_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
VkMappedMemoryRange invalidate_data = {
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
.memory = out_data_buf->mem,
.offset = 0,
.size = VK_WHOLE_SIZE,
};
vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev,
1, &invalidate_data);
}
/* Copy each slice */
for (int i = 0; i < f->slice_count; i++) {
VkBufferCopy *region = &fv->buf_regions[i];
memcpy(pkt->data + region->dstOffset,
out_data_buf->mapped_mem + region->srcOffset,
region->size);
}
av_buffer_unref(&fd->out_data_ref);
return 0;
} }
static int vulkan_encode_ffv1_receive_packet(AVCodecContext *avctx, static int vulkan_encode_ffv1_receive_packet(AVCodecContext *avctx,
@ -1523,7 +1540,6 @@ static av_cold int vulkan_encode_ffv1_close(AVCodecContext *avctx)
av_buffer_pool_uninit(&fv->results_data_pool); av_buffer_pool_uninit(&fv->results_data_pool);
av_buffer_pool_uninit(&fv->out_data_pool); av_buffer_pool_uninit(&fv->out_data_pool);
av_buffer_pool_uninit(&fv->pkt_data_pool);
av_buffer_unref(&fv->keyframe_slice_data_ref); av_buffer_unref(&fv->keyframe_slice_data_ref);
av_buffer_pool_uninit(&fv->slice_data_pool); av_buffer_pool_uninit(&fv->slice_data_pool);