[FFmpeg-devel] [PATCH 4/4] avutil/hwcontext_vulkan: fully support customizable validation layers

Wu, Jianhua jianhua.wu at intel.com
Tue Nov 23 11:48:28 EET 2021



> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces at ffmpeg.org> On Behalf Of
> Lynne
> Sent: Tuesday, November 23, 2021 5:23 PM
> To: FFmpeg development discussions and patches <ffmpeg-
> devel at ffmpeg.org>
> Subject: Re: [FFmpeg-devel] [PATCH 4/4] avutil/hwcontext_vulkan: fully
> support customizable validation layers
> 
> 23 Nov 2021, 10:01 by jianhua.wu at intel.com:
> 
> > Validation layer is an indispensable part of developing on Vulkan.
> >
> > The following commands is on how to enable validation layers:
> >
> > ffmpeg -init_hw_device
> >
> vulkan=0,debug=1,validation_layers=VK_LAYER_KHRONOS_validation+VK_L
> AYE
> > R_LUNARG_api_dump
> >
> > Signed-off-by: Wu Jianhua <jianhua.wu at intel.com>
> > ---
> >  libavutil/hwcontext_vulkan.c | 110 ++++++++++++++++++++++++++++---
> ----
> >  libavutil/hwcontext_vulkan.h |   7 +++
> >  2 files changed, 97 insertions(+), 20 deletions(-)
> >
> > diff --git a/libavutil/hwcontext_vulkan.c
> > b/libavutil/hwcontext_vulkan.c index 644ed947f8..b808f8f76c 100644
> > --- a/libavutil/hwcontext_vulkan.c
> > +++ b/libavutil/hwcontext_vulkan.c
> > @@ -146,6 +146,13 @@ typedef struct AVVkFrameInternal {
> >  }                                                                      \
> >  } while(0)
> >
> > +#define RELEASE_PROPS(props, count)                                            \
> > +    if (props) {                                                               \
> > +        for (int i = 0; i < count; i++)                                        \
> > +            av_free((void *)((props)[i]));                                     \
> > +        av_free((void *)props);                                                \
> > +    }
> > +
> >  static const struct {
> >  enum AVPixelFormat pixfmt;
> >  const VkFormat vkfmts[4];
> > @@ -511,15 +518,83 @@ static int check_extensions(AVHWDeviceContext
> > *ctx, int dev, AVDictionary *opts,  return 0;
> >
> >  fail:
> > -    if (extension_names)
> > -        for (int i = 0; i < extensions_found; i++)
> > -            av_free((void *)extension_names[i]);
> > -    av_free(extension_names);
> > +    RELEASE_PROPS(extension_names, extensions_found);
> >  av_free(user_exts_str);
> >  av_free(sup_ext);
> >  return err;
> >  }
> >
> > +static int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary
> *opts,
> > +                                   const char * const **dst, uint32_t
> > +*num) {
> > +    int found, err = 0;
> > +    VulkanDevicePriv *priv = ctx->internal->priv;
> > +    FFVulkanFunctions *vk = &priv->vkfn;
> > +
> > +    uint32_t sup_layer_count;
> > +    VkLayerProperties *sup_layers;
> > +
> > +    AVDictionaryEntry *user_layers;
> > +    char *user_layers_str, *save, *token;
> > +
> > +    const char **enabled_layers = NULL;
> > +    uint32_t enabled_layers_count = 0;
> > +
> > +    user_layers = av_dict_get(opts, "validation_layers", NULL, 0);
> > +    if (!user_layers)
> > +        return 0;
> > +
> > +    user_layers_str = av_strdup(user_layers->value);
> > +    if (!user_layers_str) {
> > +        err = AVERROR(EINVAL);
> > +        goto fail;
> > +    }
> > +
> > +    vk->EnumerateInstanceLayerProperties(&sup_layer_count, NULL);
> > +    sup_layers = av_malloc_array(sup_layer_count,
> sizeof(VkLayerProperties));
> > +    if (!sup_layers)
> > +        return AVERROR(ENOMEM);
> > +    vk->EnumerateInstanceLayerProperties(&sup_layer_count,
> > + sup_layers);
> > +
> > +    av_log(ctx, AV_LOG_VERBOSE, "Supported Validation layers:\n");
> > +    for (int i = 0; i < sup_layer_count; i++)
> > +        av_log(ctx, AV_LOG_VERBOSE, "\t%s\n",
> > + sup_layers[i].layerName);
> > +
> > +    token = av_strtok(user_layers_str, "+", &save);
> > +    while (token) {
> > +        found = 0;
> > +        for (int j = 0; j < sup_layer_count; j++) {
> > +            if (!strcmp(token, sup_layers[j].layerName)) {
> > +                found = 1;
> > +                break;
> > +            }
> > +        }
> > +        if (found) {
> > +            av_log(ctx, AV_LOG_VERBOSE, "Requested Validation Layer: %s\n",
> token);
> > +            ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, token);
> > +        } else {
> > +            av_log(ctx, AV_LOG_ERROR,
> > +                   "Validation Layer \"%s\" not support.\n", token);
> > +            err = AVERROR(EINVAL);
> > +            goto fail;
> > +        }
> > +        token = av_strtok(NULL, "+", &save);
> > +    }
> > +
> > +    *dst = enabled_layers;
> > +    *num = enabled_layers_count;
> > +
> > +    av_free(sup_layers);
> > +    av_free(user_layers_str);
> > +    return 0;
> > +
> > +fail:
> > +    RELEASE_PROPS(enabled_layers, enabled_layers_count);
> > +    av_free(sup_layers);
> > +    av_free(user_layers_str);
> > +    return err;
> > +}
> > +
> >  /* Creates a VkInstance */
> >  static int create_instance(AVHWDeviceContext *ctx, AVDictionary
> > *opts)  { @@ -558,13 +633,18 @@ static int
> > create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
> >  /* Check for present/missing extensions */  err =
> > check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames,
> >  &inst_props.enabledExtensionCount, debug_mode);
> > +    hwctx->enabled_inst_extensions =
> inst_props.ppEnabledExtensionNames;
> > +    hwctx->nb_enabled_inst_extensions =
> > + inst_props.enabledExtensionCount;
> >  if (err < 0)
> >  return err;
> >
> >  if (debug_mode) {
> > -        static const char *layers[] = { "VK_LAYER_KHRONOS_validation" };
> > -        inst_props.ppEnabledLayerNames = layers;
> > -        inst_props.enabledLayerCount = FF_ARRAY_ELEMS(layers);
> > +        err = check_validation_layers(ctx, opts,
> &inst_props.ppEnabledLayerNames,
> > +                                      &inst_props.enabledLayerCount);
> > +        hwctx->enabled_validation_layers =
> inst_props.ppEnabledLayerNames;
> > +        hwctx->nb_enabled_validation_layers =
> inst_props.enabledLayerCount;
> > +        if (err)
> > +            return err;
> >  }
> >
> >  /* Try to create the instance */
> > @@ -574,9 +654,6 @@ static int create_instance(AVHWDeviceContext *ctx,
> > AVDictionary *opts)  if (ret != VK_SUCCESS) {  av_log(ctx,
> > AV_LOG_ERROR, "Instance creation failure: %s\n",  vk_ret2str(ret));
> > -        for (int i = 0; i < inst_props.enabledExtensionCount; i++)
> > -            av_free((void *)inst_props.ppEnabledExtensionNames[i]);
> > -        av_free((void *)inst_props.ppEnabledExtensionNames);
> >  return AVERROR_EXTERNAL;
> >  }
> >
> > @@ -604,9 +681,6 @@ static int create_instance(AVHWDeviceContext *ctx,
> > AVDictionary *opts)  hwctx->alloc, &p->debug_ctx);  }
> >
> > -    hwctx->enabled_inst_extensions =
> inst_props.ppEnabledExtensionNames;
> > -    hwctx->nb_enabled_inst_extensions =
> inst_props.enabledExtensionCount;
> > -
> >  return 0;
> >  }
> >
> > @@ -1163,13 +1237,9 @@ static void
> > vulkan_device_free(AVHWDeviceContext *ctx)  if (p->libvulkan)
> > dlclose(p->libvulkan);
> >
> > -    for (int i = 0; i < hwctx->nb_enabled_inst_extensions; i++)
> > -        av_free((void *)hwctx->enabled_inst_extensions[i]);
> > -    av_free((void *)hwctx->enabled_inst_extensions);
> > -
> > -    for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++)
> > -        av_free((void *)hwctx->enabled_dev_extensions[i]);
> > -    av_free((void *)hwctx->enabled_dev_extensions);
> > +    RELEASE_PROPS(hwctx->enabled_inst_extensions, hwctx-
> >nb_enabled_inst_extensions);
> > +    RELEASE_PROPS(hwctx->enabled_dev_extensions, hwctx-
> >nb_enabled_dev_extensions);
> > +    RELEASE_PROPS(hwctx->enabled_validation_layers,
> > + hwctx->nb_enabled_validation_layers);
> >  }
> >
> >  static int vulkan_device_create_internal(AVHWDeviceContext *ctx, diff
> > --git a/libavutil/hwcontext_vulkan.h b/libavutil/hwcontext_vulkan.h
> > index fdf2a60156..80c36d6f26 100644
> > --- a/libavutil/hwcontext_vulkan.h
> > +++ b/libavutil/hwcontext_vulkan.h
> > @@ -85,6 +85,13 @@ typedef struct AVVulkanDeviceContext {  const char
> > * const *enabled_inst_extensions;  int nb_enabled_inst_extensions;
> >
> > +    /**
> > +     * Enabled validation layers.
> > +     * If no layers are enabled, set these fields to NULL, and 0 respectively.
> > +     */
> > +    const char * const *enabled_validation_layers;
> > +    int nb_enabled_validation_layers;
> > +
> >
> 
> Why are you exposing them? Do API users really need to know this?
> 

It's okay. For it's only integrated in a really small separate function it
could be skipped by the status debug_mode as before. And validation
layers are embed by other specific drivers, platforms(such as those
specific layers in androids) or SDK, the FFmpeg is not need to do anything
more whatever the current is compiled with optimization mode or debug mode.
The use who only want to use filter is simply not able to know how to
enable the debug_mode. For me, as a user also, it is important to me, I
don't want to changed the code then compiling to use the specific validation
layers again and again.  And not only the developer need to use it, those
people who help us test could report a more detailed problem. I think it's
really benefit.

Thanks,
Jianhua


More information about the ffmpeg-devel mailing list