You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-11-23 21:54:53 +02:00
Add a shader-based Apple ProRes decoder. It supports all codec features for profiles up to the 4444 XQ profile, ie.: - 4:2:2 and 4:4:4 chroma subsampling - 10- and 12-bit component depth - Interlacing - Alpha The implementation consists in two shaders: the VLD kernel does entropy decoding for color/alpha, and the IDCT kernel performs the inverse transform on color components. Benchmarks for a 4k yuv422p10 sample: - AMD Radeon 6700XT: 178 fps - Intel i7 Tiger Lake: 37 fps - NVidia Orin Nano: 70 fps
542 lines
20 KiB
C
542 lines
20 KiB
C
/*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* FFmpeg is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "proresdec.h"
|
|
#include "vulkan_decode.h"
|
|
#include "hwaccel_internal.h"
|
|
#include "libavutil/mem.h"
|
|
#include "libavutil/vulkan.h"
|
|
#include "libavutil/vulkan_loader.h"
|
|
#include "libavutil/vulkan_spirv.h"
|
|
|
|
extern const char *ff_source_common_comp;
|
|
extern const char *ff_source_prores_reset_comp;
|
|
extern const char *ff_source_prores_vld_comp;
|
|
extern const char *ff_source_prores_idct_comp;
|
|
|
|
const FFVulkanDecodeDescriptor ff_vk_dec_prores_desc = {
|
|
.codec_id = AV_CODEC_ID_PRORES,
|
|
.queue_flags = VK_QUEUE_COMPUTE_BIT,
|
|
};
|
|
|
|
typedef struct ProresVulkanDecodePicture {
|
|
FFVulkanDecodePicture vp;
|
|
|
|
AVBufferRef *slice_offset_buf;
|
|
uint32_t slice_num;
|
|
|
|
uint32_t bitstream_start;
|
|
uint32_t bitstream_size;
|
|
} ProresVulkanDecodePicture;
|
|
|
|
typedef struct ProresVulkanDecodeContext {
|
|
struct ProresVulkanShaderVariants {
|
|
FFVulkanShader reset;
|
|
FFVulkanShader vld;
|
|
FFVulkanShader idct;
|
|
} shaders[2]; /* Progressive/interlaced */
|
|
|
|
AVBufferPool *slice_offset_pool;
|
|
} ProresVulkanDecodeContext;
|
|
|
|
typedef struct ProresVkParameters {
|
|
VkDeviceAddress slice_data;
|
|
uint32_t bitstream_size;
|
|
|
|
uint16_t width;
|
|
uint16_t height;
|
|
uint16_t mb_width;
|
|
uint16_t mb_height;
|
|
uint16_t slice_width;
|
|
uint16_t slice_height;
|
|
uint8_t log2_slice_width;
|
|
uint8_t log2_chroma_w;
|
|
uint8_t depth;
|
|
uint8_t alpha_info;
|
|
uint8_t bottom_field;
|
|
|
|
uint8_t qmat_luma [64];
|
|
uint8_t qmat_chroma[64];
|
|
} ProresVkParameters;
|
|
|
|
static int vk_prores_start_frame(AVCodecContext *avctx,
|
|
const AVBufferRef *buffer_ref,
|
|
av_unused const uint8_t *buffer,
|
|
av_unused uint32_t size)
|
|
{
|
|
ProresContext *pr = avctx->priv_data;
|
|
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
|
|
FFVulkanDecodeShared *ctx = dec->shared_ctx;
|
|
ProresVulkanDecodeContext *pv = ctx->sd_ctx;
|
|
ProresVulkanDecodePicture *pp = pr->hwaccel_picture_private;
|
|
FFVulkanDecodePicture *vp = &pp->vp;
|
|
|
|
int err;
|
|
|
|
/* Host map the input slices data if supported */
|
|
if (!vp->slices_buf && ctx->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY)
|
|
RET(ff_vk_host_map_buffer(&ctx->s, &vp->slices_buf, buffer_ref->data,
|
|
buffer_ref,
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT));
|
|
|
|
/* Allocate slice offsets buffer */
|
|
RET(ff_vk_get_pooled_buffer(&ctx->s, &pv->slice_offset_pool,
|
|
&pp->slice_offset_buf,
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
|
NULL, (pr->slice_count + 1) * sizeof(uint32_t),
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
|
|
|
|
/* Prepare frame to be used */
|
|
RET(ff_vk_decode_prepare_frame_sdr(dec, pr->frame, vp, 1,
|
|
FF_VK_REP_NATIVE, 0));
|
|
|
|
pp->slice_num = 0;
|
|
pp->bitstream_start = pp->bitstream_size = 0;
|
|
|
|
fail:
|
|
return err;
|
|
}
|
|
|
|
static int vk_prores_decode_slice(AVCodecContext *avctx,
|
|
const uint8_t *data,
|
|
uint32_t size)
|
|
{
|
|
ProresContext *pr = avctx->priv_data;
|
|
ProresVulkanDecodePicture *pp = pr->hwaccel_picture_private;
|
|
FFVulkanDecodePicture *vp = &pp->vp;
|
|
|
|
FFVkBuffer *slice_offset = (FFVkBuffer *)pp->slice_offset_buf->data;
|
|
FFVkBuffer *slices_buf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL;
|
|
|
|
/* Skip picture header */
|
|
if (slices_buf && slices_buf->host_ref && !pp->slice_num)
|
|
pp->bitstream_size = data - slices_buf->mapped_mem;
|
|
|
|
AV_WN32(slice_offset->mapped_mem + (pp->slice_num + 0) * sizeof(uint32_t),
|
|
pp->bitstream_size);
|
|
AV_WN32(slice_offset->mapped_mem + (pp->slice_num + 1) * sizeof(uint32_t),
|
|
pp->bitstream_size += size);
|
|
|
|
if (!slices_buf || !slices_buf->host_ref) {
|
|
int err = ff_vk_decode_add_slice(avctx, vp, data, size, 0,
|
|
&pp->slice_num, NULL);
|
|
if (err < 0)
|
|
return err;
|
|
} else {
|
|
pp->slice_num++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vk_prores_end_frame(AVCodecContext *avctx)
|
|
{
|
|
ProresContext *pr = avctx->priv_data;
|
|
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
|
|
FFVulkanDecodeShared *ctx = dec->shared_ctx;
|
|
FFVulkanFunctions *vk = &ctx->s.vkfn;
|
|
ProresVulkanDecodeContext *pv = ctx->sd_ctx;
|
|
ProresVulkanDecodePicture *pp = pr->hwaccel_picture_private;
|
|
FFVulkanDecodePicture *vp = &pp->vp;
|
|
|
|
ProresVkParameters pd;
|
|
FFVkBuffer *slice_data, *slice_offsets;
|
|
struct ProresVulkanShaderVariants *shaders;
|
|
VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
|
|
VkBufferMemoryBarrier2 buf_bar[2];
|
|
int nb_img_bar = 0, nb_buf_bar = 0, err;
|
|
const AVPixFmtDescriptor *pix_desc;
|
|
|
|
if (!pp->slice_num)
|
|
return 0;
|
|
|
|
pix_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
|
|
if (!pix_desc)
|
|
return AVERROR(EINVAL);
|
|
|
|
slice_data = (FFVkBuffer *)vp->slices_buf->data;
|
|
slice_offsets = (FFVkBuffer *)pp->slice_offset_buf->data;
|
|
|
|
shaders = &pv->shaders[pr->frame_type != 0];
|
|
|
|
pd = (ProresVkParameters) {
|
|
.slice_data = slice_data->address,
|
|
.bitstream_size = pp->bitstream_size,
|
|
|
|
.width = avctx->width,
|
|
.height = avctx->height,
|
|
.mb_width = pr->mb_width,
|
|
.mb_height = pr->mb_height,
|
|
.slice_width = pr->slice_count / pr->mb_height,
|
|
.slice_height = pr->mb_height,
|
|
.log2_slice_width = av_log2(pr->slice_mb_width),
|
|
.log2_chroma_w = pix_desc->log2_chroma_w,
|
|
.depth = avctx->bits_per_raw_sample,
|
|
.alpha_info = pr->alpha_info,
|
|
.bottom_field = pr->first_field ^ (pr->frame_type == 1),
|
|
};
|
|
|
|
memcpy(pd.qmat_luma, pr->qmat_luma, sizeof(pd.qmat_luma ));
|
|
memcpy(pd.qmat_chroma, pr->qmat_chroma, sizeof(pd.qmat_chroma));
|
|
|
|
FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool);
|
|
RET(ff_vk_exec_start(&ctx->s, exec));
|
|
|
|
/* Prepare deps */
|
|
RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, pr->frame,
|
|
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
|
|
|
|
RET(ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value,
|
|
pr->frame));
|
|
|
|
RET(ff_vk_exec_add_dep_buf(&ctx->s, exec,
|
|
(AVBufferRef *[]){ vp->slices_buf, pp->slice_offset_buf },
|
|
2, 0));
|
|
|
|
/* Transfer ownership to the exec context */
|
|
vp->slices_buf = pp->slice_offset_buf = NULL;
|
|
|
|
/* Input frame barrier */
|
|
ff_vk_frame_barrier(&ctx->s, exec, pr->frame, img_bar, &nb_img_bar,
|
|
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
|
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
VK_QUEUE_FAMILY_IGNORED);
|
|
|
|
vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
|
.pBufferMemoryBarriers = buf_bar,
|
|
.bufferMemoryBarrierCount = nb_buf_bar,
|
|
.pImageMemoryBarriers = img_bar,
|
|
.imageMemoryBarrierCount = nb_img_bar,
|
|
});
|
|
nb_img_bar = nb_buf_bar = 0;
|
|
|
|
/* Reset */
|
|
ff_vk_shader_update_img_array(&ctx->s, exec, &shaders->reset,
|
|
pr->frame, vp->view.out,
|
|
0, 0,
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
VK_NULL_HANDLE);
|
|
|
|
ff_vk_shader_update_push_const(&ctx->s, exec, &shaders->reset,
|
|
VK_SHADER_STAGE_COMPUTE_BIT,
|
|
0, sizeof(pd), &pd);
|
|
|
|
ff_vk_exec_bind_shader(&ctx->s, exec, &shaders->reset);
|
|
|
|
vk->CmdDispatch(exec->buf, pr->mb_width << 1, pr->mb_height << 1, 1);
|
|
|
|
/* Input frame barrier after reset */
|
|
ff_vk_frame_barrier(&ctx->s, exec, pr->frame, img_bar, &nb_img_bar,
|
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
|
VK_ACCESS_SHADER_WRITE_BIT,
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
VK_QUEUE_FAMILY_IGNORED);
|
|
|
|
vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
|
.pBufferMemoryBarriers = buf_bar,
|
|
.bufferMemoryBarrierCount = nb_buf_bar,
|
|
.pImageMemoryBarriers = img_bar,
|
|
.imageMemoryBarrierCount = nb_img_bar,
|
|
});
|
|
nb_img_bar = nb_buf_bar = 0;
|
|
|
|
/* Entropy decode */
|
|
ff_vk_shader_update_desc_buffer(&ctx->s, exec, &shaders->vld,
|
|
0, 0, 0,
|
|
slice_offsets,
|
|
0, (pp->slice_num + 1) * sizeof(uint32_t),
|
|
VK_FORMAT_UNDEFINED);
|
|
ff_vk_shader_update_img_array(&ctx->s, exec, &shaders->vld,
|
|
pr->frame, vp->view.out,
|
|
0, 1,
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
VK_NULL_HANDLE);
|
|
|
|
ff_vk_shader_update_push_const(&ctx->s, exec, &shaders->vld,
|
|
VK_SHADER_STAGE_COMPUTE_BIT,
|
|
0, sizeof(pd), &pd);
|
|
|
|
ff_vk_exec_bind_shader(&ctx->s, exec, &shaders->vld);
|
|
|
|
vk->CmdDispatch(exec->buf, AV_CEIL_RSHIFT(pr->slice_count / pr->mb_height, 3), AV_CEIL_RSHIFT(pr->mb_height, 3),
|
|
3 + !!pr->alpha_info);
|
|
|
|
/* Synchronize vld and idct shaders */
|
|
nb_img_bar = 0;
|
|
ff_vk_frame_barrier(&ctx->s, exec, pr->frame, img_bar, &nb_img_bar,
|
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
|
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
VK_QUEUE_FAMILY_IGNORED);
|
|
|
|
vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
|
.pBufferMemoryBarriers = buf_bar,
|
|
.bufferMemoryBarrierCount = nb_buf_bar,
|
|
.pImageMemoryBarriers = img_bar,
|
|
.imageMemoryBarrierCount = nb_img_bar,
|
|
});
|
|
nb_img_bar = nb_buf_bar = 0;
|
|
|
|
/* Inverse transform */
|
|
ff_vk_shader_update_img_array(&ctx->s, exec, &shaders->idct,
|
|
pr->frame, vp->view.out,
|
|
0, 0,
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
VK_NULL_HANDLE);
|
|
|
|
ff_vk_exec_bind_shader(&ctx->s, exec, &shaders->idct);
|
|
|
|
ff_vk_shader_update_push_const(&ctx->s, exec, &shaders->idct,
|
|
VK_SHADER_STAGE_COMPUTE_BIT,
|
|
0, sizeof(pd), &pd);
|
|
|
|
vk->CmdDispatch(exec->buf, AV_CEIL_RSHIFT(pr->mb_width, 1), pr->mb_height, 3);
|
|
|
|
RET(ff_vk_exec_submit(&ctx->s, exec));
|
|
|
|
fail:
|
|
return err;
|
|
}
|
|
|
|
static int add_push_data(FFVulkanShader *shd)
|
|
{
|
|
GLSLC(0, layout(push_constant, scalar) uniform pushConstants { );
|
|
GLSLC(1, u8buf slice_data; );
|
|
GLSLC(1, uint bitstream_size; );
|
|
GLSLC(0, );
|
|
GLSLC(1, uint16_t width; );
|
|
GLSLC(1, uint16_t height; );
|
|
GLSLC(1, uint16_t mb_width; );
|
|
GLSLC(1, uint16_t mb_height; );
|
|
GLSLC(1, uint16_t slice_width; );
|
|
GLSLC(1, uint16_t slice_height; );
|
|
GLSLC(1, uint8_t log2_slice_width; );
|
|
GLSLC(1, uint8_t log2_chroma_w; );
|
|
GLSLC(1, uint8_t depth; );
|
|
GLSLC(1, uint8_t alpha_info; );
|
|
GLSLC(1, uint8_t bottom_field; );
|
|
GLSLC(0, );
|
|
GLSLC(1, uint8_t qmat_luma [8*8]; );
|
|
GLSLC(1, uint8_t qmat_chroma[8*8]; );
|
|
GLSLC(0, }; );
|
|
|
|
return ff_vk_shader_add_push_const(shd, 0, sizeof(ProresVkParameters),
|
|
VK_SHADER_STAGE_COMPUTE_BIT);
|
|
}
|
|
|
|
static int init_shader(AVCodecContext *avctx, FFVulkanContext *s,
|
|
FFVkExecPool *pool, FFVkSPIRVCompiler *spv,
|
|
FFVulkanShader *shd, const char *name, const char *entrypoint,
|
|
FFVulkanDescriptorSetBinding *descs, int num_descs,
|
|
const char *source, int local_size, int interlaced)
|
|
{
|
|
uint8_t *spv_data;
|
|
size_t spv_len;
|
|
void *spv_opaque = NULL;
|
|
int err;
|
|
|
|
RET(ff_vk_shader_init(s, shd, name,
|
|
VK_SHADER_STAGE_COMPUTE_BIT,
|
|
(const char *[]) { "GL_EXT_buffer_reference",
|
|
"GL_EXT_buffer_reference2" }, 2,
|
|
local_size >> 16 & 0xff, local_size >> 8 & 0xff, local_size >> 0 & 0xff,
|
|
0));
|
|
|
|
/* Common code */
|
|
GLSLD(ff_source_common_comp);
|
|
|
|
/* Push constants layout */
|
|
RET(add_push_data(shd));
|
|
|
|
RET(ff_vk_shader_add_descriptor_set(s, shd, descs, num_descs, 0, 0));
|
|
|
|
if (interlaced)
|
|
av_bprintf(&shd->src, "#define INTERLACED\n");
|
|
|
|
/* Main code */
|
|
GLSLD(source);
|
|
|
|
RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, entrypoint,
|
|
&spv_opaque));
|
|
RET(ff_vk_shader_link(s, shd, spv_data, spv_len, entrypoint));
|
|
|
|
RET(ff_vk_shader_register_exec(s, pool, shd));
|
|
|
|
fail:
|
|
if (spv_opaque)
|
|
spv->free_shader(spv, &spv_opaque);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void vk_decode_prores_uninit(FFVulkanDecodeShared *ctx)
|
|
{
|
|
ProresVulkanDecodeContext *pv = ctx->sd_ctx;
|
|
int i;
|
|
|
|
for (i = 0; i < FF_ARRAY_ELEMS(pv->shaders); ++i) {
|
|
ff_vk_shader_free(&ctx->s, &pv->shaders[i].reset);
|
|
ff_vk_shader_free(&ctx->s, &pv->shaders[i].vld);
|
|
ff_vk_shader_free(&ctx->s, &pv->shaders[i].idct);
|
|
}
|
|
|
|
av_buffer_pool_uninit(&pv->slice_offset_pool);
|
|
|
|
av_freep(&pv);
|
|
}
|
|
|
|
static int vk_decode_prores_init(AVCodecContext *avctx)
|
|
{
|
|
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
|
|
FFVulkanDecodeShared *ctx = NULL;
|
|
|
|
AVHWFramesContext *out_frames_ctx;
|
|
ProresVulkanDecodeContext *pv;
|
|
FFVkSPIRVCompiler *spv;
|
|
FFVulkanDescriptorSetBinding *desc_set;
|
|
int max_num_slices, i, err;
|
|
|
|
max_num_slices = (avctx->coded_width >> 4) * (avctx->coded_height >> 4);
|
|
|
|
spv = ff_vk_spirv_init();
|
|
if (!spv) {
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
|
|
return AVERROR_EXTERNAL;
|
|
}
|
|
|
|
err = ff_vk_decode_init(avctx);
|
|
if (err < 0)
|
|
return err;
|
|
ctx = dec->shared_ctx;
|
|
|
|
pv = ctx->sd_ctx = av_mallocz(sizeof(*pv));
|
|
if (!pv) {
|
|
err = AVERROR(ENOMEM);
|
|
goto fail;
|
|
}
|
|
|
|
out_frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
|
|
|
|
ctx->sd_ctx_free = vk_decode_prores_uninit;
|
|
|
|
for (i = 0; i < FF_ARRAY_ELEMS(pv->shaders); ++i) { /* Progressive/interlaced */
|
|
struct ProresVulkanShaderVariants *shaders = &pv->shaders[i];
|
|
|
|
desc_set = (FFVulkanDescriptorSetBinding []) {
|
|
{
|
|
.name = "dst",
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
.dimensions = 2,
|
|
.mem_layout = ff_vk_shader_rep_fmt(out_frames_ctx->sw_format,
|
|
FF_VK_REP_NATIVE),
|
|
.mem_quali = "writeonly",
|
|
.elems = av_pix_fmt_count_planes(out_frames_ctx->sw_format),
|
|
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
},
|
|
};
|
|
RET(init_shader(avctx, &ctx->s, &ctx->exec_pool, spv, &shaders->reset,
|
|
"prores_dec_reset", "main", desc_set, 1,
|
|
ff_source_prores_reset_comp, 0x080801, i));
|
|
|
|
desc_set = (FFVulkanDescriptorSetBinding []) {
|
|
{
|
|
.name = "slice_offsets_buf",
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
.mem_quali = "readonly",
|
|
.buf_content = "uint32_t slice_offsets",
|
|
.buf_elems = max_num_slices + 1,
|
|
},
|
|
{
|
|
.name = "dst",
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
.dimensions = 2,
|
|
.mem_layout = ff_vk_shader_rep_fmt(out_frames_ctx->sw_format,
|
|
FF_VK_REP_NATIVE),
|
|
.mem_quali = "writeonly",
|
|
.elems = av_pix_fmt_count_planes(out_frames_ctx->sw_format),
|
|
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
},
|
|
};
|
|
RET(init_shader(avctx, &ctx->s, &ctx->exec_pool, spv, &shaders->vld,
|
|
"prores_dec_vld", "main", desc_set, 2,
|
|
ff_source_prores_vld_comp, 0x080801, i));
|
|
|
|
desc_set = (FFVulkanDescriptorSetBinding []) {
|
|
{
|
|
.name = "dst",
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
.dimensions = 2,
|
|
.mem_layout = ff_vk_shader_rep_fmt(out_frames_ctx->sw_format,
|
|
FF_VK_REP_NATIVE),
|
|
.elems = av_pix_fmt_count_planes(out_frames_ctx->sw_format),
|
|
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
},
|
|
};
|
|
RET(init_shader(avctx, &ctx->s, &ctx->exec_pool, spv, &shaders->idct,
|
|
"prores_dec_idct", "main", desc_set, 1,
|
|
ff_source_prores_idct_comp, 0x200201, i));
|
|
}
|
|
|
|
err = 0;
|
|
|
|
fail:
|
|
spv->uninit(&spv);
|
|
|
|
return err;
|
|
}
|
|
|
|
static void vk_prores_free_frame_priv(AVRefStructOpaque _hwctx, void *data)
|
|
{
|
|
AVHWDeviceContext *dev_ctx = _hwctx.nc;
|
|
ProresVulkanDecodePicture *pp = data;
|
|
|
|
ff_vk_decode_free_frame(dev_ctx, &pp->vp);
|
|
}
|
|
|
|
const FFHWAccel ff_prores_vulkan_hwaccel = {
|
|
.p.name = "prores_vulkan",
|
|
.p.type = AVMEDIA_TYPE_VIDEO,
|
|
.p.id = AV_CODEC_ID_PRORES,
|
|
.p.pix_fmt = AV_PIX_FMT_VULKAN,
|
|
.start_frame = &vk_prores_start_frame,
|
|
.decode_slice = &vk_prores_decode_slice,
|
|
.end_frame = &vk_prores_end_frame,
|
|
.free_frame_priv = &vk_prores_free_frame_priv,
|
|
.frame_priv_data_size = sizeof(ProresVulkanDecodePicture),
|
|
.init = &vk_decode_prores_init,
|
|
.update_thread_context = &ff_vk_update_thread_context,
|
|
.decode_params = &ff_vk_params_invalidate,
|
|
.flush = &ff_vk_decode_flush,
|
|
.uninit = &ff_vk_decode_uninit,
|
|
.frame_params = &ff_vk_frame_params,
|
|
.priv_data_size = sizeof(FFVulkanDecodeContext),
|
|
.caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE,
|
|
};
|