[FFmpeg-devel] [PATCH 2/6] lavfi: add common Vulkan filtering code

Mark Thompson sw at jkqxz.net
Mon Sep 3 01:04:06 EEST 2018


On 21/06/18 17:55, Rostislav Pehlivanov wrote:
> This commit adds a common code for use in Vulkan filters. It attempts
> to ease the burden of writing Vulkan image filtering to a minimum,
> which is pretty much a requirement considering how verbose the API is.
> 
> It supports both compute and graphic pipelines and manages to abstract
> the API to such a level there's no need to call any Vulkan functions
> inside the init path of the code. Handling shader descriptors is probably
> the bulk of the code, and despite the abstraction, it loses none of the
> features for describing shader IO.
> 
> In order to produce linkable shaders, it depends on the libshaderc
> library (and depends on the latest stable version of it). This allows
> for greater performance and flexibility than static built-in shaders
> and also eliminates the cumbersome process of interfacing with glslang
> to compile GLSL to SPIR-V.
> 
> It's based off of the common opencl and provides similar interfaces for
> filter pad init and config, with the addition that it also supports
> in-place filtering.
> 
> Signed-off-by: Rostislav Pehlivanov <atomnuker at gmail.com>
> ---
>  configure            |   12 +-
>  libavfilter/vulkan.c | 1192 ++++++++++++++++++++++++++++++++++++++++++
>  libavfilter/vulkan.h |  223 ++++++++
>  3 files changed, 1425 insertions(+), 2 deletions(-)
>  create mode 100644 libavfilter/vulkan.c
>  create mode 100644 libavfilter/vulkan.h
> 
> diff --git a/configure b/configure
> index 7623a1205a..97bd4225dc 100755
> --- a/configure
> +++ b/configure
> @@ -252,6 +252,7 @@ External library support:
>    --enable-librsvg         enable SVG rasterization via librsvg [no]
>    --enable-librubberband   enable rubberband needed for rubberband filter [no]
>    --enable-librtmp         enable RTMP[E] support via librtmp [no]
> +  --enable-libshaderc      enable GLSL->SPIRV compilation via libshaderc [no]
>    --enable-libshine        enable fixed-point MP3 encoding via libshine [no]
>    --enable-libsmbclient    enable Samba protocol via libsmbclient [no]
>    --enable-libsnappy       enable Snappy compression, needed for hap encoding [no]
> @@ -1709,6 +1710,7 @@ EXTERNAL_LIBRARY_LIST="
>      libpulse
>      librsvg
>      librtmp
> +    libshaderc
>      libshine
>      libsmbclient
>      libsnappy
> @@ -2228,6 +2230,7 @@ HAVE_LIST="
>      opencl_dxva2
>      opencl_vaapi_beignet
>      opencl_vaapi_intel_media
> +    shaderc_opt_perf
>      vulkan_drm_mod
>      perl
>      pod2man
> @@ -3462,12 +3465,12 @@ avcodec_select="null_bsf"
>  avdevice_deps="avformat avcodec avutil"
>  avdevice_suggest="libm"
>  avfilter_deps="avutil"
> -avfilter_suggest="libm"
> +avfilter_suggest="libm libshaderc"
>  avformat_deps="avcodec avutil"
>  avformat_suggest="libm network zlib"
>  avresample_deps="avutil"
>  avresample_suggest="libm"
> -avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi videotoolbox corefoundation corevideo coremedia bcrypt"
> +avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl vulkan user32 vaapi videotoolbox corefoundation corevideo coremedia bcrypt"
>  postproc_deps="avutil gpl"
>  postproc_suggest="libm"
>  swresample_deps="avutil"
> @@ -6056,6 +6059,7 @@ enabled libpulse          && require_pkg_config libpulse libpulse pulse/pulseaud
>  enabled librsvg           && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo
>  enabled librtmp           && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket
>  enabled librubberband     && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++"
> +enabled libshaderc        && require libshaderc shaderc/shaderc.h shaderc_compiler_initialize -lshaderc_shared
>  enabled libshine          && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer
>  enabled libsmbclient      && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init ||
>                                 require libsmbclient libsmbclient.h smbc_init -lsmbclient; }
> @@ -6363,6 +6367,10 @@ enabled crystalhd && check_lib crystalhd "stdint.h libcrystalhd/libcrystalhd_if.
>  enabled vulkan &&
>      require_pkg_config vulkan "vulkan >= 1.1.73" "vulkan/vulkan.h" vkCreateInstance
>  
> +if enabled_all vulkan libshaderc ; then
> +    check_cc shaderc_opt_perf shaderc/shaderc.h "int t = shaderc_optimization_level_performance"
> +fi

Is there really no way to do this without a configure test?  A preprocessor version check?  (Or requiring a recent libshaderc, given that there is no compatibility to maintain.)

> +
>  if enabled_all vulkan libdrm ; then
>      check_cpp_condition vulkan_drm_mod vulkan/vulkan.h "defined VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME"
>  fi
> diff --git a/libavfilter/vulkan.c b/libavfilter/vulkan.c
> new file mode 100644
> index 0000000000..976e846fa3
> --- /dev/null
> +++ b/libavfilter/vulkan.c
> ...
> +int ff_vk_init_pipeline_layout(AVFilterContext *avctx)
> +{
> +    VkResult ret;
> +    VulkanFilterContext *s = avctx->priv;
> +
> +    { /* Init descriptor set pool */
> +        VkDescriptorPoolCreateInfo pool_create_info = {
> +            .sType         = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
> +            .poolSizeCount = s->pool_size_desc_num,
> +            .pPoolSizes    = s->pool_size_desc,
> +            .maxSets       = s->descriptor_sets_num,
> +        };
> +
> +        ret = vkCreateDescriptorPool(s->hwctx->act_dev, &pool_create_info,
> +                                     s->hwctx->alloc, &s->desc_pool);
> +        av_freep(&s->pool_size_desc);
> +        if (ret != VK_SUCCESS) {
> +            av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
> +                   "pool: %s\n", ff_vk_ret2str(ret));
> +            return AVERROR_EXTERNAL;
> +        }
> +    }
> +
> +    { /* Allocate descriptor sets */
> +        VkDescriptorSetAllocateInfo alloc_info = {
> +            .sType              = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
> +            .descriptorPool     = s->desc_pool,
> +            .descriptorSetCount = s->descriptor_sets_num,
> +            .pSetLayouts        = s->desc_layout,
> +        };
> +
> +        s->desc_set = av_malloc(s->descriptor_sets_num*sizeof(*s->desc_set));
> +        if (!s->desc_set)
> +            return AVERROR(ENOMEM);
> +
> +        ret = vkAllocateDescriptorSets(s->hwctx->act_dev, &alloc_info,
> +                                       s->desc_set);
> +        if (ret != VK_SUCCESS) {
> +            av_log(avctx, AV_LOG_ERROR, "Unable to allocate descriptor set: %s\n",
> +                   ff_vk_ret2str(ret));
> +            return AVERROR_EXTERNAL;
> +        }
> +    }
> +
> +    { /* Finally create the pipeline layout */
> +        VkPipelineLayoutCreateInfo spawn_pipeline_layout = {
> +            .sType                  = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
> +            .setLayoutCount         = s->descriptor_sets_num,
> +            .pSetLayouts            = s->desc_layout,
> +            .pushConstantRangeCount = s->push_consts_num,
> +            .pPushConstantRanges    = s->push_consts,
> +        };
> +
> +        ret = vkCreatePipelineLayout(s->hwctx->act_dev, &spawn_pipeline_layout,
> +                                     s->hwctx->alloc, &s->pipeline_layout);
> +        av_freep(&s->push_consts);
> +        s->push_consts_num = 0;
> +        if (ret != VK_SUCCESS) {
> +            av_log(avctx, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n",
> +                   ff_vk_ret2str(ret));
> +            return AVERROR_EXTERNAL;
> +        }
> +    }
> +
> +    { /* Descriptor template (for tightly packed descriptors) */
> +        VK_LOAD_PFN(s->hwctx->inst, vkCreateDescriptorUpdateTemplateKHR);
> +        VkDescriptorUpdateTemplateCreateInfo *desc_template_info;
> +
> +        s->desc_template = av_malloc(s->descriptor_sets_num*sizeof(*s->desc_template));
> +        if (!s->desc_template)
> +            return AVERROR(ENOMEM);
> +
> +        /* Create update templates for the descriptor sets */
> +        for (int i = 0; i < s->descriptor_sets_num; i++) {
> +            desc_template_info = &s->desc_template_info[i];
> +            desc_template_info->pipelineLayout = s->pipeline_layout;
> +            ret = pfn_vkCreateDescriptorUpdateTemplateKHR(s->hwctx->act_dev,
> +                                                          desc_template_info,
> +                                                          s->hwctx->alloc,
> +                                                          &s->desc_template[i]);
> +            av_free((void *)desc_template_info->pDescriptorUpdateEntries);
> +            if (ret != VK_SUCCESS) {
> +                av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor "
> +                       "template: %s\n", ff_vk_ret2str(ret));
> +                return AVERROR_EXTERNAL;
> +            }
> +        }
> +
> +        av_freep(&s->desc_template_info);
> +    }
> +
> +    return 0;
> +}

A number of the things here seem to leak - desc_sets, desc_template, and some of the Vulkan structures too.  I suggest going through this with valgrind to make sure you've cleaned up everything.


Not much else I can usefully comment on here, but looks generally ok.

Thanks,

- Mark


More information about the ffmpeg-devel mailing list