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

Lynne dev at lynne.ee
Tue Nov 23 12:13:34 EET 2021


23 Nov 2021, 10:48 by jianhua.wu at intel.com:

>
>
>> -----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.
>

Sorry, I didn't quite understand that.
I'm not objecting to being able to use custom debug layers and activating
them if they're requested from the user. We already do that for the
standard debug layer anyway. I'm just not sure I understand why filters
would need to know if a debug layer is ran, and which one it is, by exposing
them via the public API.


More information about the ffmpeg-devel mailing list