lavfi: add lavfi-only Vulkan infrastructure

pull/389/head
Lynne 2 years ago
parent 51b7fe81be
commit 05ce6473ac
No known key found for this signature in database
GPG Key ID: A2FEA5F03F034464
  1. 6
      libavfilter/Makefile
  2. 462
      libavfilter/vulkan_filter.c
  3. 33
      libavfilter/vulkan_filter.h
  4. 19
      libavfilter/vulkan_glslang.c
  5. 8
      libavfilter/vulkan_shaderc.c
  6. 45
      libavfilter/vulkan_spirv.h

@ -623,6 +623,10 @@ OBJS-$(CONFIG_AVSYNCTEST_FILTER) += src_avsynctest.o
OBJS-$(CONFIG_AMOVIE_FILTER) += src_movie.o OBJS-$(CONFIG_AMOVIE_FILTER) += src_movie.o
OBJS-$(CONFIG_MOVIE_FILTER) += src_movie.o OBJS-$(CONFIG_MOVIE_FILTER) += src_movie.o
# vulkan libs
OBJS-$(CONFIG_LIBGLSLANG) += vulkan_glslang.o
OBJS-$(CONFIG_LIBSHADERC) += vulkan_shaderc.o
# Objects duplicated from other libraries for shared builds # Objects duplicated from other libraries for shared builds
SHLIBOBJS += log2_tab.o SHLIBOBJS += log2_tab.o
@ -636,6 +640,8 @@ SKIPHEADERS-$(CONFIG_QSVVPP) += qsvvpp.h stack_internal.h
SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h
SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_vpp.h stack_internal.h SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_vpp.h stack_internal.h
SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_filter.h SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_filter.h
SKIPHEADERS-$(CONFIG_LIBSHADERC) += vulkan_spirv.h
SKIPHEADERS-$(CONFIG_LIBGLSLANG) += vulkan_spirv.h
TOOLS = graph2dot TOOLS = graph2dot
TESTPROGS = drawutils filtfmts formats integral TESTPROGS = drawutils filtfmts formats integral

@ -1,4 +1,6 @@
/* /*
* Copyright (c) Lynne
*
* This file is part of FFmpeg. * This file is part of FFmpeg.
* *
* FFmpeg is free software; you can redistribute it and/or * FFmpeg is free software; you can redistribute it and/or
@ -18,107 +20,186 @@
#include "vulkan_filter.h" #include "vulkan_filter.h"
static int vulkan_filter_set_device(AVFilterContext *avctx, int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s,
AVBufferRef *device) AVBufferRef *frames_ref,
int width, int height, enum AVPixelFormat sw_format)
{ {
FFVulkanContext *s = avctx->priv; int err;
AVHWFramesContext *frames_ctx;
AVHWDeviceContext *device_ctx;
AVVulkanFramesContext *vk_frames;
AVVulkanDeviceContext *vk_dev;
AVBufferRef *device_ref = avctx->hw_device_ctx;
/* Check if context is reusable as-is */
if (frames_ref) {
int no_storage = 0;
FFVulkanFunctions *vk;
const VkFormat *sub = av_vkfmt_from_pixfmt(sw_format);
frames_ctx = (AVHWFramesContext *)frames_ref->data;
device_ctx = (AVHWDeviceContext *)frames_ctx->device_ref->data;
vk_frames = frames_ctx->hwctx;
vk_dev = device_ctx->hwctx;
/* Basic format validation */
if (width != frames_ctx->width ||
height != frames_ctx->height ||
sw_format != frames_ctx->sw_format ||
(vk_frames->tiling != VK_IMAGE_TILING_LINEAR &&
vk_frames->tiling != VK_IMAGE_TILING_OPTIMAL) ||
!(vk_frames->usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
goto skip;
}
if (vk_frames->usage & VK_IMAGE_USAGE_STORAGE_BIT)
goto accept;
av_buffer_unref(&s->device_ref); s->extensions = ff_vk_extensions_to_mask(vk_dev->enabled_dev_extensions,
vk_dev->nb_enabled_dev_extensions);
err = ff_vk_load_functions(device_ctx, &s->vkfn, s->extensions, 1, 1);
if (err < 0)
return err;
vk = &s->vkfn;
/* Check if the subformats can do storage */
for (int i = 0; sub[i] != VK_FORMAT_UNDEFINED; i++) {
VkFormatProperties2 prop = {
.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
};
vk->GetPhysicalDeviceFormatProperties2(vk_dev->phys_dev, sub[i],
&prop);
if (vk_frames->tiling == VK_IMAGE_TILING_LINEAR) {
no_storage |= !(prop.formatProperties.linearTilingFeatures &
VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
} else {
no_storage |= !(prop.formatProperties.optimalTilingFeatures &
VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
}
}
s->device_ref = av_buffer_ref(device); /* Check if it's usable */
if (!s->device_ref) if (no_storage) {
skip:
device_ref = frames_ctx->device_ref;
frames_ref = NULL;
} else {
accept:
frames_ref = av_buffer_ref(frames_ref);
if (!frames_ref)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
}
}
s->device = (AVHWDeviceContext*)s->device_ref->data; if (!frames_ref) {
s->hwctx = s->device->hwctx; if (!device_ref) {
av_log(avctx, AV_LOG_ERROR,
"Vulkan filtering requires a device context!\n");
return AVERROR(EINVAL);
}
return 0; frames_ref = av_hwframe_ctx_alloc(device_ref);
frames_ctx = (AVHWFramesContext *)frames_ref->data;
frames_ctx->format = AV_PIX_FMT_VULKAN;
frames_ctx->sw_format = sw_format;
frames_ctx->width = width;
frames_ctx->height = height;
vk_frames = frames_ctx->hwctx;
vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL;
vk_frames->usage = VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
err = av_hwframe_ctx_init(frames_ref);
if (err < 0) {
av_buffer_unref(&frames_ref);
return err;
} }
static int vulkan_filter_set_frames(AVFilterContext *avctx, device_ctx = (AVHWDeviceContext *)frames_ctx->device_ref->data;
AVBufferRef *frames) vk_dev = device_ctx->hwctx;
{ }
FFVulkanContext *s = avctx->priv;
av_buffer_unref(&s->frames_ref); s->extensions = ff_vk_extensions_to_mask(vk_dev->enabled_dev_extensions,
vk_dev->nb_enabled_dev_extensions);
s->frames_ref = av_buffer_ref(frames); /**
if (!s->frames_ref) * libplacebo does not use descriptor buffers.
return AVERROR(ENOMEM); */
if (!(s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) &&
strcmp(avctx->filter->name, "libplacebo")) {
av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires that "
"the %s extension is supported!\n",
VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
av_buffer_unref(&frames_ref);
return AVERROR(EINVAL);
}
return 0; err = ff_vk_load_functions(device_ctx, &s->vkfn, s->extensions, 1, 1);
if (err < 0) {
av_buffer_unref(&frames_ref);
return err;
}
s->frames_ref = frames_ref;
s->frames = frames_ctx;
s->hwfc = vk_frames;
s->device = device_ctx;
s->hwctx = device_ctx->hwctx;
err = ff_vk_load_props(s);
if (err < 0)
av_buffer_unref(&s->frames_ref);
return err;
} }
int ff_vk_filter_config_input(AVFilterLink *inlink) int ff_vk_filter_config_input(AVFilterLink *inlink)
{ {
int err;
AVFilterContext *avctx = inlink->dst;
FFVulkanContext *s = avctx->priv;
FFVulkanFunctions *vk = &s->vkfn;
AVHWFramesContext *input_frames; AVHWFramesContext *input_frames;
AVFilterContext *avctx = inlink->dst;
FFVulkanContext *s = inlink->dst->priv;
if (!inlink->hw_frames_ctx) { if (!inlink->hw_frames_ctx) {
av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a " av_log(inlink->dst, AV_LOG_ERROR, "Vulkan filtering requires a "
"hardware frames context on the input.\n"); "hardware frames context on the input.\n");
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
/* Extract the device and default output format from the first input. */
if (avctx->inputs[0] != inlink)
return 0;
input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data; input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
if (input_frames->format != AV_PIX_FMT_VULKAN) if (input_frames->format != AV_PIX_FMT_VULKAN)
return AVERROR(EINVAL); return AVERROR(EINVAL);
err = vulkan_filter_set_device(avctx, input_frames->device_ref); /* Extract the device and default output format from the first input. */
if (err < 0) if (avctx->inputs[0] != inlink)
return err; return 0;
err = vulkan_filter_set_frames(avctx, inlink->hw_frames_ctx);
if (err < 0)
return err;
s->extensions = ff_vk_extensions_to_mask(s->hwctx->enabled_dev_extensions,
s->hwctx->nb_enabled_dev_extensions);
err = ff_vk_load_functions(s->device, &s->vkfn, s->extensions, 1, 1);
if (err < 0)
return err;
vk->GetPhysicalDeviceProperties(s->hwctx->phys_dev, &s->props); /* Save the ref, without reffing it */
vk->GetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &s->mprops); s->input_frames_ref = inlink->hw_frames_ctx;
/* Default output parameters match input parameters. */ /* Defaults */
s->input_format = input_frames->sw_format;
if (s->output_format == AV_PIX_FMT_NONE)
s->output_format = input_frames->sw_format; s->output_format = input_frames->sw_format;
if (!s->output_width)
s->output_width = inlink->w; s->output_width = inlink->w;
if (!s->output_height)
s->output_height = inlink->h; s->output_height = inlink->h;
return 0; return 0;
} }
int ff_vk_filter_config_output_inplace(AVFilterLink *outlink) int ff_vk_filter_config_output(AVFilterLink *outlink)
{ {
int err; int err;
AVFilterContext *avctx = outlink->src; FFVulkanContext *s = outlink->src->priv;
FFVulkanContext *s = avctx->priv;
av_buffer_unref(&outlink->hw_frames_ctx); av_buffer_unref(&outlink->hw_frames_ctx);
if (!s->device_ref) { err = ff_vk_filter_init_context(outlink->src, s, s->input_frames_ref,
if (!avctx->hw_device_ctx) { s->output_width, s->output_height,
av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a " s->output_format);
"Vulkan device.\n");
return AVERROR(EINVAL);
}
err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
if (err < 0) if (err < 0)
return err; return err;
}
outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref); outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref);
if (!outlink->hw_frames_ctx) if (!outlink->hw_frames_ctx)
@ -127,65 +208,246 @@ int ff_vk_filter_config_output_inplace(AVFilterLink *outlink)
outlink->w = s->output_width; outlink->w = s->output_width;
outlink->h = s->output_height; outlink->h = s->output_height;
return 0; return err;
} }
int ff_vk_filter_config_output(AVFilterLink *outlink) int ff_vk_filter_init(AVFilterContext *avctx)
{ {
int err;
AVFilterContext *avctx = outlink->src;
FFVulkanContext *s = avctx->priv; FFVulkanContext *s = avctx->priv;
AVBufferRef *output_frames_ref;
AVHWFramesContext *output_frames;
av_buffer_unref(&outlink->hw_frames_ctx); s->output_format = AV_PIX_FMT_NONE;
if (!s->device_ref) { return 0;
if (!avctx->hw_device_ctx) {
av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
"Vulkan device.\n");
return AVERROR(EINVAL);
} }
err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx); int ff_vk_filter_process_simple(FFVulkanContext *vkctx, FFVkExecPool *e,
if (err < 0) FFVulkanPipeline *pl, AVFrame *out_f, AVFrame *in_f,
return err; VkSampler sampler, void *push_src, size_t push_size)
{
int err = 0;
FFVulkanFunctions *vk = &vkctx->vkfn;
VkImageView in_views[AV_NUM_DATA_POINTERS];
VkImageView out_views[AV_NUM_DATA_POINTERS];
VkImageMemoryBarrier2 img_bar[37];
int nb_img_bar = 0;
/* Update descriptors and init the exec context */
FFVkExecContext *exec = ff_vk_exec_get(e);
ff_vk_exec_start(vkctx, exec);
ff_vk_exec_bind_pipeline(vkctx, exec, pl);
if (push_src)
ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
0, push_size, push_src);
if (in_f) {
RET(ff_vk_exec_add_dep_frame(vkctx, exec, in_f,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
RET(ff_vk_create_imageviews(vkctx, exec, in_views, in_f));
ff_vk_update_descriptor_img_array(vkctx, pl, exec, in_f, in_views, 0, 0,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
sampler);
ff_vk_frame_barrier(vkctx, exec, in_f, 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_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED);
} }
output_frames_ref = av_hwframe_ctx_alloc(s->device_ref); RET(ff_vk_exec_add_dep_frame(vkctx, exec, out_f,
if (!output_frames_ref) { VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
err = AVERROR(ENOMEM); VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
goto fail; RET(ff_vk_create_imageviews(vkctx, exec, out_views, out_f));
ff_vk_update_descriptor_img_array(vkctx, pl, exec, out_f, out_views, 0, !!in_f,
VK_IMAGE_LAYOUT_GENERAL,
VK_NULL_HANDLE);
ff_vk_frame_barrier(vkctx, exec, out_f, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_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,
.pImageMemoryBarriers = img_bar,
.imageMemoryBarrierCount = nb_img_bar,
});
vk->CmdDispatch(exec->buf,
FFALIGN(vkctx->output_width, pl->wg_size[0])/pl->wg_size[0],
FFALIGN(vkctx->output_height, pl->wg_size[1])/pl->wg_size[1],
pl->wg_size[2]);
return ff_vk_exec_submit(vkctx, exec);
fail:
ff_vk_exec_discard_deps(vkctx, exec);
return err;
} }
output_frames = (AVHWFramesContext*)output_frames_ref->data;
output_frames->format = AV_PIX_FMT_VULKAN;
output_frames->sw_format = s->output_format;
output_frames->width = s->output_width;
output_frames->height = s->output_height;
err = av_hwframe_ctx_init(output_frames_ref); int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e,
if (err < 0) { FFVulkanPipeline *pls[2],
av_log(avctx, AV_LOG_ERROR, "Failed to initialise output " AVFrame *out, AVFrame *tmp, AVFrame *in,
"frames: %d.\n", err); VkSampler sampler, void *push_src, size_t push_size)
goto fail; {
int err = 0;
FFVulkanFunctions *vk = &vkctx->vkfn;
VkImageView in_views[AV_NUM_DATA_POINTERS];
VkImageView tmp_views[AV_NUM_DATA_POINTERS];
VkImageView out_views[AV_NUM_DATA_POINTERS];
VkImageMemoryBarrier2 img_bar[37];
int nb_img_bar = 0;
/* Update descriptors and init the exec context */
FFVkExecContext *exec = ff_vk_exec_get(e);
ff_vk_exec_start(vkctx, exec);
RET(ff_vk_exec_add_dep_frame(vkctx, exec, in,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
RET(ff_vk_exec_add_dep_frame(vkctx, exec, tmp,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
RET(ff_vk_exec_add_dep_frame(vkctx, exec, out,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
RET(ff_vk_create_imageviews(vkctx, exec, in_views, in));
RET(ff_vk_create_imageviews(vkctx, exec, tmp_views, tmp));
RET(ff_vk_create_imageviews(vkctx, exec, out_views, out));
ff_vk_frame_barrier(vkctx, exec, in, 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_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED);
ff_vk_frame_barrier(vkctx, exec, tmp, 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);
ff_vk_frame_barrier(vkctx, exec, out, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_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,
.pImageMemoryBarriers = img_bar,
.imageMemoryBarrierCount = nb_img_bar,
});
for (int i = 0; i < 2; i++) {
FFVulkanPipeline *pl = pls[i];
AVFrame *src_f = !i ? in : tmp;
AVFrame *dst_f = !i ? tmp : out;
VkImageView *src_views = !i ? in_views : tmp_views;
VkImageView *dst_views = !i ? tmp_views : out_views;
ff_vk_exec_bind_pipeline(vkctx, exec, pl);
if (push_src)
ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
0, push_size, push_src);
ff_vk_update_descriptor_img_array(vkctx, pl, exec, src_f, src_views, 0, 0,
!i ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL :
VK_IMAGE_LAYOUT_GENERAL,
sampler);
ff_vk_update_descriptor_img_array(vkctx, pl, exec, dst_f, dst_views, 0, 1,
VK_IMAGE_LAYOUT_GENERAL,
VK_NULL_HANDLE);
vk->CmdDispatch(exec->buf,
FFALIGN(vkctx->output_width, pl->wg_size[0])/pl->wg_size[0],
FFALIGN(vkctx->output_height, pl->wg_size[1])/pl->wg_size[1],
pl->wg_size[2]);
} }
outlink->hw_frames_ctx = output_frames_ref; return ff_vk_exec_submit(vkctx, exec);
outlink->w = s->output_width;
outlink->h = s->output_height;
return 0;
fail: fail:
av_buffer_unref(&output_frames_ref); ff_vk_exec_discard_deps(vkctx, exec);
return err; return err;
} }
int ff_vk_filter_init(AVFilterContext *avctx) int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e,
FFVulkanPipeline *pl,
AVFrame *out, AVFrame *in[], int nb_in,
VkSampler sampler, void *push_src, size_t push_size)
{ {
FFVulkanContext *s = avctx->priv; int err = 0;
FFVulkanFunctions *vk = &vkctx->vkfn;
s->output_format = AV_PIX_FMT_NONE; VkImageView in_views[16][AV_NUM_DATA_POINTERS];
VkImageView out_views[AV_NUM_DATA_POINTERS];
VkImageMemoryBarrier2 img_bar[128];
int nb_img_bar = 0;
/* Update descriptors and init the exec context */
FFVkExecContext *exec = ff_vk_exec_get(e);
ff_vk_exec_start(vkctx, exec);
/* Inputs */
for (int i = 0; i < nb_in; i++) {
RET(ff_vk_exec_add_dep_frame(vkctx, exec, in[i],
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
RET(ff_vk_create_imageviews(vkctx, exec, in_views[i], in[i]));
ff_vk_frame_barrier(vkctx, exec, in[i], 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_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED);
}
return 0; /* Output */
RET(ff_vk_exec_add_dep_frame(vkctx, exec, out,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
RET(ff_vk_create_imageviews(vkctx, exec, out_views, out));
ff_vk_frame_barrier(vkctx, exec, out, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_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,
.pImageMemoryBarriers = img_bar,
.imageMemoryBarrierCount = nb_img_bar,
});
ff_vk_exec_bind_pipeline(vkctx, exec, pl);
if (push_src)
ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
0, push_size, push_src);
for (int i = 0; i < nb_in; i++)
ff_vk_update_descriptor_img_array(vkctx, pl, exec, in[i], in_views[i], 0, i,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
sampler);
ff_vk_update_descriptor_img_array(vkctx, pl, exec, out, out_views, 0, nb_in,
VK_IMAGE_LAYOUT_GENERAL,
VK_NULL_HANDLE);
vk->CmdDispatch(exec->buf,
FFALIGN(vkctx->output_width, pl->wg_size[0])/pl->wg_size[0],
FFALIGN(vkctx->output_height, pl->wg_size[1])/pl->wg_size[1],
pl->wg_size[2]);
return ff_vk_exec_submit(vkctx, exec);
fail:
ff_vk_exec_discard_deps(vkctx, exec);
return err;
} }

@ -1,4 +1,6 @@
/* /*
* Copyright (c) Lynne
*
* This file is part of FFmpeg. * This file is part of FFmpeg.
* *
* FFmpeg is free software; you can redistribute it and/or * FFmpeg is free software; you can redistribute it and/or
@ -29,6 +31,35 @@
int ff_vk_filter_init (AVFilterContext *avctx); int ff_vk_filter_init (AVFilterContext *avctx);
int ff_vk_filter_config_input (AVFilterLink *inlink); int ff_vk_filter_config_input (AVFilterLink *inlink);
int ff_vk_filter_config_output(AVFilterLink *outlink); int ff_vk_filter_config_output(AVFilterLink *outlink);
int ff_vk_filter_config_output_inplace(AVFilterLink *outlink);
/**
* Can be called manually, if not using ff_vk_filter_config_output.
*/
int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s,
AVBufferRef *frames_ref,
int width, int height, enum AVPixelFormat sw_format);
/**
* Submit a compute shader with a zero/one input and single out for execution.
*/
int ff_vk_filter_process_simple(FFVulkanContext *vkctx, FFVkExecPool *e,
FFVulkanPipeline *pl, AVFrame *out_f, AVFrame *in_f,
VkSampler sampler, void *push_src, size_t push_size);
/**
* Submit a compute shader with a single in and single out with 2 stages.
*/
int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e,
FFVulkanPipeline *pls[2],
AVFrame *out, AVFrame *tmp, AVFrame *in,
VkSampler sampler, void *push_src, size_t push_size);
/**
* Up to 16 inputs, one output
*/
int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e,
FFVulkanPipeline *pl,
AVFrame *out, AVFrame *in[], int nb_in,
VkSampler sampler, void *push_src, size_t push_size);
#endif /* AVFILTER_VULKAN_FILTER_H */ #endif /* AVFILTER_VULKAN_FILTER_H */

@ -21,8 +21,9 @@
#include <glslang/build_info.h> #include <glslang/build_info.h>
#include <glslang/Include/glslang_c_interface.h> #include <glslang/Include/glslang_c_interface.h>
#include "mem.h" #include "vulkan_spirv.h"
#include "avassert.h" #include "libavutil/mem.h"
#include "libavutil/avassert.h"
static pthread_mutex_t glslc_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t glslc_mutex = PTHREAD_MUTEX_INITIALIZER;
static int glslc_refcount = 0; static int glslc_refcount = 0;
@ -176,11 +177,13 @@ static int glslc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
av_assert0(glslc_refcount); av_assert0(glslc_refcount);
*opaque = NULL;
if (!(glslc_shader = glslang_shader_create(&glslc_input))) if (!(glslc_shader = glslang_shader_create(&glslc_input)))
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
if (!glslang_shader_preprocess(glslc_shader, &glslc_input)) { if (!glslang_shader_preprocess(glslc_shader, &glslc_input)) {
ff_vk_print_shader(avctx, shd, AV_LOG_WARNING); ff_vk_shader_print(avctx, shd, AV_LOG_WARNING);
av_log(avctx, AV_LOG_ERROR, "Unable to preprocess shader: %s (%s)!\n", av_log(avctx, AV_LOG_ERROR, "Unable to preprocess shader: %s (%s)!\n",
glslang_shader_get_info_log(glslc_shader), glslang_shader_get_info_log(glslc_shader),
glslang_shader_get_info_debug_log(glslc_shader)); glslang_shader_get_info_debug_log(glslc_shader));
@ -189,7 +192,7 @@ static int glslc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
} }
if (!glslang_shader_parse(glslc_shader, &glslc_input)) { if (!glslang_shader_parse(glslc_shader, &glslc_input)) {
ff_vk_print_shader(avctx, shd, AV_LOG_WARNING); ff_vk_shader_print(avctx, shd, AV_LOG_WARNING);
av_log(avctx, AV_LOG_ERROR, "Unable to parse shader: %s (%s)!\n", av_log(avctx, AV_LOG_ERROR, "Unable to parse shader: %s (%s)!\n",
glslang_shader_get_info_log(glslc_shader), glslang_shader_get_info_log(glslc_shader),
glslang_shader_get_info_debug_log(glslc_shader)); glslang_shader_get_info_debug_log(glslc_shader));
@ -206,7 +209,7 @@ static int glslc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
if (!glslang_program_link(glslc_program, GLSLANG_MSG_SPV_RULES_BIT | if (!glslang_program_link(glslc_program, GLSLANG_MSG_SPV_RULES_BIT |
GLSLANG_MSG_VULKAN_RULES_BIT)) { GLSLANG_MSG_VULKAN_RULES_BIT)) {
ff_vk_print_shader(avctx, shd, AV_LOG_WARNING); ff_vk_shader_print(avctx, shd, AV_LOG_WARNING);
av_log(avctx, AV_LOG_ERROR, "Unable to link shader: %s (%s)!\n", av_log(avctx, AV_LOG_ERROR, "Unable to link shader: %s (%s)!\n",
glslang_program_get_info_log(glslc_program), glslang_program_get_info_log(glslc_program),
glslang_program_get_info_debug_log(glslc_program)); glslang_program_get_info_debug_log(glslc_program));
@ -219,10 +222,10 @@ static int glslc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
messages = glslang_program_SPIRV_get_messages(glslc_program); messages = glslang_program_SPIRV_get_messages(glslc_program);
if (messages) { if (messages) {
ff_vk_print_shader(avctx, shd, AV_LOG_WARNING); ff_vk_shader_print(avctx, shd, AV_LOG_WARNING);
av_log(avctx, AV_LOG_WARNING, "%s\n", messages); av_log(avctx, AV_LOG_WARNING, "%s\n", messages);
} else { } else {
ff_vk_print_shader(avctx, shd, AV_LOG_VERBOSE); ff_vk_shader_print(avctx, shd, AV_LOG_VERBOSE);
} }
glslang_shader_delete(glslc_shader); glslang_shader_delete(glslc_shader);
@ -257,7 +260,7 @@ static void glslc_uninit(FFVkSPIRVCompiler **ctx)
av_freep(ctx); av_freep(ctx);
} }
static FFVkSPIRVCompiler *ff_vk_glslang_init(void) FFVkSPIRVCompiler *ff_vk_glslang_init(void)
{ {
FFVkSPIRVCompiler *ret = av_mallocz(sizeof(*ret)); FFVkSPIRVCompiler *ret = av_mallocz(sizeof(*ret));
if (!ret) if (!ret)

@ -18,7 +18,8 @@
#include <shaderc/shaderc.h> #include <shaderc/shaderc.h>
#include "mem.h" #include "libavutil/mem.h"
#include "vulkan_spirv.h"
static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx, static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
FFVkSPIRVShader *shd, uint8_t **data, FFVkSPIRVShader *shd, uint8_t **data,
@ -43,6 +44,7 @@ static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
}; };
shaderc_compile_options_t opts = shaderc_compile_options_initialize(); shaderc_compile_options_t opts = shaderc_compile_options_initialize();
*opaque = NULL;
if (!opts) if (!opts)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
@ -65,7 +67,7 @@ static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
loglevel = err ? AV_LOG_ERROR : warn ? AV_LOG_WARNING : AV_LOG_VERBOSE; loglevel = err ? AV_LOG_ERROR : warn ? AV_LOG_WARNING : AV_LOG_VERBOSE;
ff_vk_print_shader(avctx, shd, loglevel); ff_vk_shader_print(avctx, shd, loglevel);
if (message && (err || warn)) if (message && (err || warn))
av_log(avctx, loglevel, "%s\n", message); av_log(avctx, loglevel, "%s\n", message);
status = ret < FF_ARRAY_ELEMS(shdc_result) ? shdc_result[ret] : "unknown"; status = ret < FF_ARRAY_ELEMS(shdc_result) ? shdc_result[ret] : "unknown";
@ -104,7 +106,7 @@ static void shdc_uninit(FFVkSPIRVCompiler **ctx)
av_freep(ctx); av_freep(ctx);
} }
static FFVkSPIRVCompiler *ff_vk_shaderc_init(void) FFVkSPIRVCompiler *ff_vk_shaderc_init(void)
{ {
FFVkSPIRVCompiler *ret = av_mallocz(sizeof(*ret)); FFVkSPIRVCompiler *ret = av_mallocz(sizeof(*ret));
if (!ret) if (!ret)

@ -0,0 +1,45 @@
/*
* 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
*/
#ifndef AVFILTER_VULKAN_SPIRV_H
#define AVFILTER_VULKAN_SPIRV_H
#include "libavutil/vulkan.h"
#include "vulkan.h"
#include "config.h"
typedef struct FFVkSPIRVCompiler {
void *priv;
int (*compile_shader)(struct FFVkSPIRVCompiler *ctx, void *avctx,
struct FFVkSPIRVShader *shd, uint8_t **data,
size_t *size, const char *entrypoint, void **opaque);
void (*free_shader)(struct FFVkSPIRVCompiler *ctx, void **opaque);
void (*uninit)(struct FFVkSPIRVCompiler **ctx);
} FFVkSPIRVCompiler;
#if CONFIG_LIBGLSLANG
FFVkSPIRVCompiler *ff_vk_glslang_init(void);
#define ff_vk_spirv_init ff_vk_glslang_init
#endif
#if CONFIG_LIBSHADERC
FFVkSPIRVCompiler *ff_vk_shaderc_init(void);
#define ff_vk_spirv_init ff_vk_shaderc_init
#endif
#endif /* AVFILTER_VULKAN_H */
Loading…
Cancel
Save