FFmpeg
Loading...
Searching...
No Matches
vf_gblur_vulkan.c
Go to the documentation of this file.
1/*
2 * copyright (c) 2021-2022 Wu Jianhua <jianhua.wu@intel.com>
3 * Copyright (c) Lynne
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "libavutil/mem.h"
23#include "libavutil/opt.h"
24#include "vulkan_filter.h"
25
26#include "filters.h"
27#include "video.h"
28
29#define GBLUR_MAX_KERNEL_SIZE 127
30
31extern const unsigned char ff_gblur_comp_spv_data[];
32extern const unsigned int ff_gblur_comp_spv_len;
33
52
53static inline float gaussian(float sigma, float x)
54{
55 return 1.0 / (sqrt(2.0 * M_PI) * sigma) *
56 exp(-(x * x) / (2.0 * sigma * sigma));
57}
58
59static inline float gaussian_simpson_integration(float sigma, float a, float b)
60{
61 return (b - a) * (1.0 / 6.0) * ((gaussian(sigma, a) +
62 4.0 * gaussian(sigma, (a + b) * 0.5) + gaussian(sigma, b)));
63}
64
65static void init_gaussian_kernel(float *kernel, float sigma, float kernel_size)
66{
67 int x;
68 float sum;
69
70 sum = 0;
71 for (x = 0; x < kernel_size; x++) {
72 kernel[x] = gaussian_simpson_integration(sigma, x - 0.5f, x + 0.5f);
73 if (!x)
74 sum += kernel[x];
75 else
76 sum += kernel[x] * 2.0;
77 }
78 /* Normalized */
79 sum = 1.0 / sum;
80 for (x = 0; x < kernel_size; x++) {
81 kernel[x] *= sum;
82 }
83}
84
85static inline void init_kernel_size(void *log_ctx, int *out_size)
86{
87 int size = *out_size;
88
89 if (!(size & 1)) {
90 av_log(log_ctx, AV_LOG_WARNING, "The kernel size should be odd\n");
91 size++;
92 }
93
94 *out_size = (size >> 1) + 1;
95}
96
98{
99 GBlurVulkanContext *s = ctx->priv;
100 if (s->sigmaV <= 0)
101 s->sigmaV = s->sigma;
102
103 init_kernel_size(ctx, &s->size);
104
105 if (s->sizeV <= 0)
106 s->sizeV = s->size;
107 else
108 init_kernel_size(ctx, &s->sizeV);
109}
110
112 FFVulkanShader *shd, FFVkBuffer *params_buf,
113 int ksize, float sigma)
114{
115 int err = 0;
116 uint8_t *kernel_mapped;
117
118 ff_vk_shader_add_push_const(shd, 0, sizeof(int),
119 VK_SHADER_STAGE_COMPUTE_BIT);
120
122 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
123 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
124 };
125 ff_vk_shader_add_descriptor_set(&s->vkctx, shd, &buf_desc, 1, 1);
126
127 RET(ff_vk_shader_link(&s->vkctx, shd,
129 ff_gblur_comp_spv_len, "main"));
130
131 RET(ff_vk_shader_register_exec(&s->vkctx, &s->e, shd));
132
133 RET(ff_vk_create_buf(&s->vkctx, params_buf, sizeof(float) * ksize, NULL, NULL,
134 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
135 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
136 RET(ff_vk_map_buffer(&s->vkctx, params_buf, &kernel_mapped, 0));
137
138 init_gaussian_kernel((float *)kernel_mapped, sigma, ksize);
139
140 RET(ff_vk_unmap_buffer(&s->vkctx, params_buf, 1));
141 RET(ff_vk_shader_update_desc_buffer(&s->vkctx, &s->e.contexts[0], shd, 1, 0, 0,
142 params_buf, 0, params_buf->size,
143 VK_FORMAT_UNDEFINED));
144
145fail:
146 return err;
147}
148
150{
151 int err = 0;
152 GBlurVulkanContext *s = ctx->priv;
153 FFVulkanContext *vkctx = &s->vkctx;
154 const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
155
156 s->qf = ff_vk_qf_find(vkctx, VK_QUEUE_COMPUTE_BIT, 0);
157 if (!s->qf) {
158 av_log(ctx, AV_LOG_ERROR, "Device has no compute queues\n");
159 err = AVERROR(ENOTSUP);
160 goto fail;
161 }
162
163 RET(ff_vk_exec_pool_init(vkctx, s->qf, &s->e, FF_VK_DEFAULT_EXEC_CONTEXTS, 0, 0, 0, NULL));
164
166 { /* input_img */
167 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
168 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
169 .elems = planes,
170 },
171 { /* output_img */
172 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
173 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
174 .elems = planes,
175 },
176 };
177
179
180 /* Horizontal */
181 ff_vk_shader_load(&s->shd_hor, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
182 (uint32_t []) { 32, 1, 1 }, 0);
183 ff_vk_shader_add_descriptor_set(vkctx, &s->shd_hor, desc, 2, 0);
184 RET(init_gblur_pipeline(s, &s->shd_hor, &s->params_hor, s->size, s->sigma));
185
186 /* Vertical */
187 ff_vk_shader_load(&s->shd_ver, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
188 (uint32_t []) { 1, 32, 1 }, 0);
189 ff_vk_shader_add_descriptor_set(vkctx, &s->shd_ver, desc, 2, 0);
190 RET(init_gblur_pipeline(s, &s->shd_ver, &s->params_ver, s->sizeV, s->sigmaV));
191
192 s->initialized = 1;
193
194fail:
195 return err;
196}
197
199{
200 GBlurVulkanContext *s = avctx->priv;
201 FFVulkanContext *vkctx = &s->vkctx;
202
203 ff_vk_exec_pool_free(vkctx, &s->e);
204 ff_vk_shader_free(vkctx, &s->shd_hor);
205 ff_vk_shader_free(vkctx, &s->shd_ver);
206 ff_vk_free_buf(vkctx, &s->params_hor);
207 ff_vk_free_buf(vkctx, &s->params_ver);
208
209 ff_vk_uninit(&s->vkctx);
210
211 s->initialized = 0;
212}
213
215{
216 int err;
217 AVFrame *tmp = NULL, *out = NULL;
218 AVFilterContext *ctx = link->dst;
219 GBlurVulkanContext *s = ctx->priv;
220 AVFilterLink *outlink = ctx->outputs[0];
221 const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
222
223 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
224 if (!out) {
225 err = AVERROR(ENOMEM);
226 goto fail;
227 }
228
229 tmp = ff_get_video_buffer(outlink, outlink->w, outlink->h);
230 if (!tmp) {
231 err = AVERROR(ENOMEM);
232 goto fail;
233 }
234
235 if (!s->initialized)
236 RET(init_filter(ctx, in));
237
238 RET(ff_vk_filter_process_2pass(&s->vkctx, &s->e,
239 (FFVulkanShader *[2]){ &s->shd_hor, &s->shd_ver },
240 out, tmp, in, VK_NULL_HANDLE,
241 planes, &s->planes, sizeof(int)));
242
243 err = av_frame_copy_props(out, in);
244 if (err < 0)
245 goto fail;
246
247 av_frame_free(&in);
249
250 return ff_filter_frame(outlink, out);
251
252fail:
253 av_frame_free(&in);
256 return err;
257}
258
259#define OFFSET(x) offsetof(GBlurVulkanContext, x)
260#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
262 { "sigma", "Set sigma", OFFSET(sigma), AV_OPT_TYPE_FLOAT, { .dbl = 0.5 }, 0.01, 1024.0, FLAGS },
263 { "sigmaV", "Set vertical sigma", OFFSET(sigmaV), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0.0, 1024.0, FLAGS },
264 { "planes", "Set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, { .i64 = 0xF }, 0, 0xF, FLAGS },
265 { "size", "Set kernel size", OFFSET(size), AV_OPT_TYPE_INT, { .i64 = 19 }, 1, GBLUR_MAX_KERNEL_SIZE, FLAGS },
266 { "sizeV", "Set vertical kernel size", OFFSET(sizeV), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, GBLUR_MAX_KERNEL_SIZE, FLAGS },
267 { NULL },
268};
269
271
273 {
274 .name = "default",
275 .type = AVMEDIA_TYPE_VIDEO,
276 .filter_frame = &gblur_vulkan_filter_frame,
277 .config_props = &ff_vk_filter_config_input,
278 }
279};
280
282 {
283 .name = "default",
284 .type = AVMEDIA_TYPE_VIDEO,
285 .config_props = &ff_vk_filter_config_output,
286 }
287};
288
290 .p.name = "gblur_vulkan",
291 .p.description = NULL_IF_CONFIG_SMALL("Gaussian Blur in Vulkan"),
292 .p.priv_class = &gblur_vulkan_class,
293 .p.flags = AVFILTER_FLAG_HWDEVICE,
294 .priv_size = sizeof(GBlurVulkanContext),
300 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
301};
const FFFilter ff_vf_gblur_vulkan
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
int8_t exp
Definition eval.c:76
#define fail
Definition test.h:479
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition avfilter.h:187
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
int a
#define b
Definition input.c:43
static av_cold void uninit(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition filters.h:208
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition filters.h:254
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
int ff_vk_shader_load(FFVulkanShader *shd, VkPipelineStageFlags stage, VkSpecializationInfo *spec, uint32_t wg_size[3], uint32_t required_subgroup_size)
Initialize a shader object.
Definition vulkan.c:2070
void ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd, const FFVulkanDescriptorSetBinding *desc, int nb, int singular)
Add descriptor to a shader.
Definition vulkan.c:2373
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
Definition vulkan.c:310
int ff_vk_create_buf(FFVulkanContext *s, FFVkBuffer *buf, size_t size, void *pNext, void *alloc_pNext, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
Definition vulkan.c:1016
int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext)
Allocates/frees an execution pool.
Definition vulkan.c:357
int ff_vk_shader_add_push_const(FFVulkanShader *shd, int offset, int size, VkShaderStageFlagBits stage)
Add/update push constants for execution.
Definition vulkan.c:1443
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
Definition vulkan.c:2638
void ff_vk_free_buf(FFVulkanContext *s, FFVkBuffer *buf)
Definition vulkan.c:1230
void ff_vk_shader_free(FFVulkanContext *s, FFVulkanShader *shd)
Free a shader.
Definition vulkan.c:2614
int ff_vk_shader_register_exec(FFVulkanContext *s, FFVkExecPool *pool, FFVulkanShader *shd)
Register a shader with an exec pool.
Definition vulkan.c:2407
int ff_vk_shader_update_desc_buffer(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, int set, int bind, int elem, FFVkBuffer *buf, VkDeviceSize offset, VkDeviceSize len, VkFormat fmt)
Update a descriptor in a buffer with a buffer.
Definition vulkan.c:2555
AVVulkanDeviceQueueFamily * ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops)
Chooses an appropriate QF.
Definition vulkan.c:297
int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd, const char *spirv, size_t spirv_len, const char *entrypoint)
Link a shader into an executable.
Definition vulkan.c:2267
const char * desc
Definition libsvtav1.c:83
static const struct @257111027162314367033347246032313251342043035002 planes[]
#define M_PI
Definition mathematics.h:67
Memory handling functions.
AVOptions.
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition pixfmt.h:379
An instance of a filter.
Definition avfilter.h:273
void * priv
private data for use by the filter
Definition avfilter.h:288
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
size_t size
Definition vulkan.h:98
AVVulkanDeviceQueueFamily * qf
FFVulkanShader shd_ver
FFVulkanShader shd_hor
FFVulkanContext vkctx
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
static FILE * out
Definition movenc.c:55
static int out_size
Definition movenc.c:56
static AVFormatContext * ctx
Definition movenc.c:49
int size
const unsigned char ff_gblur_comp_spv_data[]
static void init_gaussian_kernel(float *kernel, float sigma, float kernel_size)
static int init_gblur_pipeline(GBlurVulkanContext *s, FFVulkanShader *shd, FFVkBuffer *params_buf, int ksize, float sigma)
static void init_kernel_size(void *log_ctx, int *out_size)
static const AVFilterPad gblur_vulkan_outputs[]
static float gaussian(float sigma, float x)
static float gaussian_simpson_integration(float sigma, float a, float b)
static int gblur_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)
static const AVFilterPad gblur_vulkan_inputs[]
#define GBLUR_MAX_KERNEL_SIZE
static av_cold void gblur_vulkan_uninit(AVFilterContext *avctx)
const unsigned int ff_gblur_comp_spv_len
static av_cold void init_gaussian_params(AVFilterContext *ctx)
static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
#define OFFSET(x)
static const AVOption gblur_vulkan_options[]
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89
#define FF_VK_DEFAULT_EXEC_CONTEXTS
Definition vulkan.h:121
#define RET(x)
Definition vulkan.h:37
static int ff_vk_unmap_buffer(FFVulkanContext *s, FFVkBuffer *buf, int flush)
Definition vulkan.h:621
static int ff_vk_map_buffer(FFVulkanContext *s, FFVkBuffer *buf, uint8_t **mem, int invalidate)
Definition vulkan.h:614
int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e, FFVulkanShader *shd_list[2], AVFrame *out, AVFrame *tmp, AVFrame *in, VkSampler sampler, uint32_t wgc_z, 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_config_input(AVFilterLink *inlink)
int ff_vk_filter_config_output(AVFilterLink *outlink)
int ff_vk_filter_init(AVFilterContext *avctx)
General lavfi IO functions.