FFmpeg
Loading...
Searching...
No Matches
vf_nlmeans_vulkan.c
Go to the documentation of this file.
1/*
2 * Copyright (c) Lynne
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "libavutil/mem.h"
22#include "libavutil/opt.h"
23#include "vulkan_filter.h"
24
25#include "filters.h"
26#include "video.h"
27
28extern const unsigned char ff_nlmeans_horizontal_comp_spv_data[];
29extern const unsigned int ff_nlmeans_horizontal_comp_spv_len;
30extern const unsigned char ff_nlmeans_vertical_comp_spv_data[];
31extern const unsigned int ff_nlmeans_vertical_comp_spv_len;
32extern const unsigned char ff_nlmeans_weights_comp_spv_data[];
33extern const unsigned int ff_nlmeans_weights_comp_spv_len;
34extern const unsigned char ff_nlmeans_denoise_comp_spv_data[];
35extern const unsigned int ff_nlmeans_denoise_comp_spv_len;
36
37/* Must be kept in sync with the definitions in the nlmeans_* shaders */
38#define TYPE_ELEMS 4
39#define TYPE_SIZE (TYPE_ELEMS*4)
40#define WG_SIZE 32
41
74
75typedef struct IntegralPushData {
76 uint32_t width[4];
77 uint32_t height[4];
78 float strength[4];
79 uint32_t comp_off[4];
80 uint32_t comp_plane[4];
81 VkDeviceAddress integral_base;
82 uint64_t integral_size;
83 uint64_t int_stride;
84 uint32_t xyoffs_start;
85 uint32_t nb_components;
87
89 FFVulkanShader *shd_horizontal,
90 FFVulkanShader *shd_vertical,
91 int planes)
92{
93 int err;
94 FFVulkanShader *shd;
95
96 /* Horizontal pass */
97 shd = shd_horizontal;
98 ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
99 (uint32_t []) { WG_SIZE, 1, 1 }, 0);
100
102 VK_SHADER_STAGE_COMPUTE_BIT);
103
104 RET(ff_vk_shader_link(vkctx, shd,
107
108 RET(ff_vk_shader_register_exec(vkctx, exec, shd));
109
110 /* Vertical pass */
111 shd = shd_vertical;
112 ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
113 (uint32_t []) { WG_SIZE, 1, 1 }, 0);
114
116 VK_SHADER_STAGE_COMPUTE_BIT);
117
118 const FFVulkanDescriptorSetBinding desc_set_img[] = {
119 { /* input_img */
120 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
121 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
122 .elems = planes,
123 },
124 };
125 ff_vk_shader_add_descriptor_set(vkctx, shd, desc_set_img, 1, 0);
126
127 const FFVulkanDescriptorSetBinding desc_set_xyoffsets[] = {
128 { /* xyoffsets_buffer */
129 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
130 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
131 },
132 };
133 ff_vk_shader_add_descriptor_set(vkctx, shd, desc_set_xyoffsets, 1, 1);
134
135 RET(ff_vk_shader_link(vkctx, shd,
138
139 RET(ff_vk_shader_register_exec(vkctx, exec, shd));
140
141fail:
142 return err;
143}
144
145typedef struct WeightsPushData {
146 uint32_t width[4];
147 uint32_t height[4];
148 uint32_t ws_offset[4];
149 uint32_t ws_stride[4];
151 float strength[4];
152 uint32_t comp_off[4];
153 uint32_t comp_plane[4];
154 VkDeviceAddress integral_base;
156 uint64_t int_stride;
157 uint32_t xyoffs_start;
158 uint32_t ws_count;
161
163 FFVulkanShader *shd, int planes)
164{
165 int err;
166
167 ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
168 (uint32_t []) { WG_SIZE, WG_SIZE, 1 }, 0);
169
171 VK_SHADER_STAGE_COMPUTE_BIT);
172
173 const FFVulkanDescriptorSetBinding desc_set[] = {
174 { /* input_img */
175 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
176 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
177 .elems = planes,
178 },
179 { /* weights_buffer */
180 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
181 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
182 },
183 { /* sums_buffer */
184 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
185 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
186 },
187 };
188 ff_vk_shader_add_descriptor_set(vkctx, shd, desc_set, 3, 0);
189
190 const FFVulkanDescriptorSetBinding desc_set_xyoffsets[] = {
191 { /* xyoffsets_buffer */
192 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
193 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
194 },
195 };
196 ff_vk_shader_add_descriptor_set(vkctx, shd, desc_set_xyoffsets, 1, 1);
197
198 RET(ff_vk_shader_link(vkctx, shd,
201
202 RET(ff_vk_shader_register_exec(vkctx, exec, shd));
203
204fail:
205 return err;
206}
207
208typedef struct DenoisePushData {
209 uint32_t comp_off[4];
210 uint32_t comp_plane[4];
211 uint32_t ws_offset[4];
212 uint32_t ws_stride[4];
213 uint32_t ws_count;
214 uint32_t t;
217
219 FFVulkanShader *shd, int planes)
220{
221 int err;
222
223 ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
224 (uint32_t []) { WG_SIZE, WG_SIZE, 1 }, 0);
225
227 VK_SHADER_STAGE_COMPUTE_BIT);
228
229 const FFVulkanDescriptorSetBinding desc_set_img[] = {
230 { /* input_img */
231 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
232 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
233 .elems = planes,
234 },
235 { /* output_img */
236 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
237 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
238 .elems = planes,
239 },
240 };
241 ff_vk_shader_add_descriptor_set(vkctx, shd, desc_set_img, 2, 0);
242
243 const FFVulkanDescriptorSetBinding desc_set_ws[] = {
244 { /* weights_buffer */
245 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
246 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
247 },
248 { /* sums_buffer */
249 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
250 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
251 },
252 };
253 ff_vk_shader_add_descriptor_set(vkctx, shd, desc_set_ws, 2, 0);
254
255 RET(ff_vk_shader_link(vkctx, shd,
258
259 RET(ff_vk_shader_register_exec(vkctx, exec, shd));
260
261fail:
262 return err;
263}
264
266{
267 int rad, err;
268 int xcnt = 0, ycnt = 0;
269 NLMeansVulkanContext *s = ctx->priv;
270 FFVulkanContext *vkctx = &s->vkctx;
271 const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
272 int *offsets_buf;
273 int offsets_dispatched = 0, nb_dispatches = 0;
274
275 if (!(s->opts.r & 1)) {
276 s->opts.r |= 1;
277 av_log(ctx, AV_LOG_WARNING, "Research size should be odd, setting to %i",
278 s->opts.r);
279 }
280
281 if (!(s->opts.p & 1)) {
282 s->opts.p |= 1;
283 av_log(ctx, AV_LOG_WARNING, "Patch size should be odd, setting to %i",
284 s->opts.p);
285 }
286
287 for (int i = 0; i < 4; i++) {
288 double str = !isnan(s->opts.sc[i]) ? s->opts.sc[i] : s->opts.s;
289 int ps = (s->opts.pc[i] ? s->opts.pc[i] : s->opts.p);
290 if (str == 0.0) {
291 s->strength[i] = 0.0;
292 } else {
293 str = 10.0f*str;
294 str *= -str;
295 str = 255.0*255.0 / str;
296 s->strength[i] = str;
297 }
298 if (!(ps & 1)) {
299 ps |= 1;
300 av_log(ctx, AV_LOG_WARNING, "Patch size should be odd, setting to %i",
301 ps);
302 }
303 s->patch[i] = ps / 2;
304 }
305
306 rad = s->opts.r/2;
307 s->nb_offsets = (2*rad + 1)*(2*rad + 1) - 1;
308 s->xoffsets = av_malloc(s->nb_offsets*sizeof(*s->xoffsets));
309 s->yoffsets = av_malloc(s->nb_offsets*sizeof(*s->yoffsets));
310 s->nb_offsets = 0;
311
312 for (int x = -rad; x <= rad; x++) {
313 for (int y = -rad; y <= rad; y++) {
314 if (!x && !y)
315 continue;
316
317 s->xoffsets[xcnt++] = x;
318 s->yoffsets[ycnt++] = y;
319 s->nb_offsets++;
320 }
321 }
322
323 RET(ff_vk_create_buf(&s->vkctx, &s->xyoffsets_buf, 2*s->nb_offsets*sizeof(int32_t), NULL, NULL,
324 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
325 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
326 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
327 RET(ff_vk_map_buffer(&s->vkctx, &s->xyoffsets_buf, (uint8_t **)&offsets_buf, 0));
328
329 for (int i = 0; i < 2*s->nb_offsets; i += 2) {
330 offsets_buf[i + 0] = s->xoffsets[i >> 1];
331 offsets_buf[i + 1] = s->yoffsets[i >> 1];
332 }
333
334 RET(ff_vk_unmap_buffer(&s->vkctx, &s->xyoffsets_buf, 1));
335
336 s->opts.t = FFMIN(s->opts.t, (FFALIGN(s->nb_offsets, TYPE_ELEMS) / TYPE_ELEMS));
337
338 s->qf = ff_vk_qf_find(vkctx, VK_QUEUE_COMPUTE_BIT, 0);
339 if (!s->qf) {
340 av_log(ctx, AV_LOG_ERROR, "Device has no compute queues\n");
341 err = AVERROR(ENOTSUP);
342 goto fail;
343 }
344
345 RET(ff_vk_exec_pool_init(vkctx, s->qf, &s->e, 1, 0, 0, 0, NULL));
346
347 RET(init_integral_pipeline(vkctx, &s->e, &s->shd_horizontal, &s->shd_vertical,
348 planes));
349
350 RET(init_weights_pipeline(vkctx, &s->e, &s->shd_weights, planes));
351
352 RET(init_denoise_pipeline(vkctx, &s->e, &s->shd_denoise, planes));
353
354 RET(ff_vk_shader_update_desc_buffer(vkctx, &s->e.contexts[0], &s->shd_vertical,
355 1, 0, 0,
356 &s->xyoffsets_buf, 0, s->xyoffsets_buf.size,
357 VK_FORMAT_UNDEFINED));
358
359 RET(ff_vk_shader_update_desc_buffer(vkctx, &s->e.contexts[0], &s->shd_weights,
360 1, 0, 0,
361 &s->xyoffsets_buf, 0, s->xyoffsets_buf.size,
362 VK_FORMAT_UNDEFINED));
363
364 do {
365 int wg_invoc = FFMIN((s->nb_offsets - offsets_dispatched)/TYPE_ELEMS, s->opts.t);
366 offsets_dispatched += wg_invoc * TYPE_ELEMS;
367 nb_dispatches++;
368 } while (offsets_dispatched < s->nb_offsets);
369
370 av_log(ctx, AV_LOG_VERBOSE, "Filter initialized, %i x/y offsets, %i dispatches\n",
371 s->nb_offsets, nb_dispatches);
372
373 s->initialized = 1;
374
375fail:
376 return err;
377}
378
380 FFVkBuffer *ws_vk, uint32_t comp_offs[4], uint32_t comp_planes[4],
381 uint32_t ws_offset[4], uint32_t ws_stride[4],
382 uint32_t ws_count, uint32_t t, uint32_t nb_components)
383{
384 FFVulkanContext *vkctx = &s->vkctx;
385 FFVulkanFunctions *vk = &vkctx->vkfn;
386
387 DenoisePushData pd = {
388 { comp_offs[0], comp_offs[1], comp_offs[2], comp_offs[3] },
389 { comp_planes[0], comp_planes[1], comp_planes[2], comp_planes[3] },
390 { ws_offset[0], ws_offset[1], ws_offset[2], ws_offset[3] },
391 { ws_stride[0], ws_stride[1], ws_stride[2], ws_stride[3] },
392 ws_count,
393 t,
394 nb_components,
395 };
396
397 /* Denoise pass pipeline */
398 ff_vk_exec_bind_shader(vkctx, exec, &s->shd_denoise);
399
400 /* Push data */
401 ff_vk_shader_update_push_const(vkctx, exec, &s->shd_denoise,
402 VK_SHADER_STAGE_COMPUTE_BIT,
403 0, sizeof(pd), &pd);
404
405 VkBufferMemoryBarrier2 buf_bar;
406 ff_vk_buf_barrier(buf_bar, ws_vk,
407 COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT,
408 SHADER_STORAGE_WRITE_BIT,
409 COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, NONE_KHR,
410 0, VK_WHOLE_SIZE);
411 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
412 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
413 .pBufferMemoryBarriers = &buf_bar,
414 .bufferMemoryBarrierCount = 1,
415 });
416
417 /* End of denoise pass */
418 vk->CmdDispatch(exec->buf,
419 FFALIGN(vkctx->output_width, s->shd_denoise.lg_size[0])/s->shd_denoise.lg_size[0],
420 FFALIGN(vkctx->output_height, s->shd_denoise.lg_size[1])/s->shd_denoise.lg_size[1],
421 av_pix_fmt_count_planes(s->vkctx.output_format));
422
423 return 0;
424}
425
427{
428 int err;
429 AVFrame *out = NULL;
430 AVFilterContext *ctx = link->dst;
431 NLMeansVulkanContext *s = ctx->priv;
432 AVFilterLink *outlink = ctx->outputs[0];
433 FFVulkanContext *vkctx = &s->vkctx;
434 FFVulkanFunctions *vk = &vkctx->vkfn;
435
437 int comp_offs[4];
438 int comp_planes[4];
439 int plane_widths[4];
440 int plane_heights[4];
441
442 int offsets_dispatched = 0;
443
444 /* Integral */
445 FFVkBuffer *integral_vk = NULL;
446 size_t int_stride;
447 size_t int_size;
448
449 /* Weights/sums */
450 FFVkBuffer *ws_vk = NULL;
451 uint32_t ws_count = 0;
452 uint32_t ws_offset[4];
453 uint32_t ws_stride[4];
454 size_t ws_size;
455
456 FFVkExecContext *exec;
457 VkImageView in_views[AV_NUM_DATA_POINTERS];
458 VkImageView out_views[AV_NUM_DATA_POINTERS];
459 VkImageMemoryBarrier2 img_bar[8];
460 int nb_img_bar = 0;
461 VkBufferMemoryBarrier2 buf_bar[2];
462 int nb_buf_bar = 0;
463
464 if (!s->initialized) {
465 err = init_filter(ctx);
466 if (err < 0) {
467 av_frame_free(&in);
468 return err;
469 }
470 }
471
472 /* Execution context */
473 exec = ff_vk_exec_get(&s->vkctx, &s->e);
474 err = ff_vk_exec_start(vkctx, exec);
475 if (err < 0) {
476 av_frame_free(&in);
477 return err;
478 }
479
481 if (!desc) {
482 err = AVERROR(EINVAL);
483 goto fail;
484 }
485
486 /* Integral image */
487 int_stride = FFALIGN(vkctx->output_width, s->shd_vertical.lg_size[0]) * TYPE_SIZE;
488 int_size = FFALIGN(vkctx->output_height, s->shd_horizontal.lg_size[0]) * int_stride;
489
490 /* Plane dimensions */
491 for (int i = 0; i < desc->nb_components; i++) {
492 plane_widths[i] = !i || (i == 3) ? vkctx->output_width : AV_CEIL_RSHIFT(vkctx->output_width, desc->log2_chroma_w);
493 plane_heights[i] = !i || (i == 3) ? vkctx->output_height : AV_CEIL_RSHIFT(vkctx->output_height, desc->log2_chroma_h);
494 plane_widths[i] = FFALIGN(plane_widths[i], s->shd_denoise.lg_size[0]);
495 plane_heights[i] = FFALIGN(plane_heights[i], s->shd_denoise.lg_size[1]);
496
497 comp_offs[i] = desc->comp[i].offset / (FFALIGN(desc->comp[i].depth, 8)/8);
498 comp_planes[i] = desc->comp[i].plane;
499
500 ws_stride[i] = plane_widths[i];
501 ws_offset[i] = ws_count;
502 ws_count += ws_stride[i] * plane_heights[i];
503 }
504
505 ws_size = ws_count * sizeof(float);
506
507 /* Buffers */
508 RET(ff_vk_get_pooled_buffer(&s->vkctx, &s->integral_buf_pool, &integral_vk,
509 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
510 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
511 NULL,
512 int_size * s->opts.t * desc->nb_components,
513 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
514 RET(ff_vk_get_pooled_buffer(&s->vkctx, &s->ws_buf_pool, &ws_vk,
515 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
516 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
517 NULL,
518 ws_size * s-> opts.t * 2,
519 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
520
521 /* Output frame */
522 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
523 if (!out) {
524 err = AVERROR(ENOMEM);
525 goto fail;
526 }
527
528 /* Dependencies */
529 RET(ff_vk_exec_add_dep_frame(vkctx, exec, in,
530 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
531 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
532 RET(ff_vk_exec_add_dep_frame(vkctx, exec, out,
533 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
534 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
535
536 /* Input frame prep */
537 RET(ff_vk_create_imageviews(vkctx, exec, in_views, in, FF_VK_REP_FLOAT));
538 ff_vk_frame_barrier(vkctx, exec, in, img_bar, &nb_img_bar,
539 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
540 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
541 VK_ACCESS_SHADER_READ_BIT,
542 VK_IMAGE_LAYOUT_GENERAL,
543 VK_QUEUE_FAMILY_IGNORED);
544
545 /* Output frame prep */
546 RET(ff_vk_create_imageviews(vkctx, exec, out_views, out, FF_VK_REP_FLOAT));
547 ff_vk_frame_barrier(vkctx, exec, out, img_bar, &nb_img_bar,
548 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
549 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
550 VK_ACCESS_SHADER_WRITE_BIT,
551 VK_IMAGE_LAYOUT_GENERAL,
552 VK_QUEUE_FAMILY_IGNORED);
553
554 ff_vk_buf_barrier(buf_bar[nb_buf_bar++], ws_vk,
555 ALL_COMMANDS_BIT, NONE_KHR, NONE_KHR,
556 TRANSFER_BIT, TRANSFER_WRITE_BIT, NONE_KHR,
557 0, VK_WHOLE_SIZE);
558 ff_vk_buf_barrier(buf_bar[nb_buf_bar++], integral_vk,
559 ALL_COMMANDS_BIT, NONE_KHR, NONE_KHR,
560 COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, NONE_KHR,
561 0, VK_WHOLE_SIZE);
562 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
563 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
564 .pImageMemoryBarriers = img_bar,
565 .imageMemoryBarrierCount = nb_img_bar,
566 .pBufferMemoryBarriers = buf_bar,
567 .bufferMemoryBarrierCount = nb_buf_bar,
568 });
569 nb_buf_bar = 0;
570 nb_img_bar = 0;
571
572 /* Buffer zeroing */
573 vk->CmdFillBuffer(exec->buf, ws_vk->buf, 0, ws_vk->size, 0x0);
574
575 /* Update integral descriptors */
576 ff_vk_shader_update_img_array(vkctx, exec, &s->shd_vertical, in, in_views, 0, 0,
577 VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
578 /* Update weights descriptors */
579 ff_vk_shader_update_img_array(vkctx, exec, &s->shd_weights, in, in_views, 0, 0,
580 VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
581 RET(ff_vk_shader_update_desc_buffer(&s->vkctx, exec, &s->shd_weights, 0, 1, 0,
582 ws_vk, 0, ws_size * s-> opts.t,
583 VK_FORMAT_UNDEFINED));
584 RET(ff_vk_shader_update_desc_buffer(&s->vkctx, exec, &s->shd_weights, 0, 2, 0,
585 ws_vk, ws_size * s-> opts.t, ws_size * s-> opts.t,
586 VK_FORMAT_UNDEFINED));
587
588 /* Update denoise descriptors */
589 ff_vk_shader_update_img_array(vkctx, exec, &s->shd_denoise, in, in_views, 0, 0,
590 VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
591 ff_vk_shader_update_img_array(vkctx, exec, &s->shd_denoise, out, out_views, 0, 1,
592 VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
593 RET(ff_vk_shader_update_desc_buffer(&s->vkctx, exec, &s->shd_denoise, 1, 0, 0,
594 ws_vk, 0, ws_size * s-> opts.t,
595 VK_FORMAT_UNDEFINED));
596 RET(ff_vk_shader_update_desc_buffer(&s->vkctx, exec, &s->shd_denoise, 1, 1, 0,
597 ws_vk, ws_size * s-> opts.t, ws_size * s-> opts.t,
598 VK_FORMAT_UNDEFINED));
599
600 VkPipelineStageFlagBits2 ws_stage = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
601 VkAccessFlagBits2 ws_access = VK_ACCESS_2_TRANSFER_WRITE_BIT;
602 do {
603 int wg_invoc = FFMIN((s->nb_offsets - offsets_dispatched)/TYPE_ELEMS, s->opts.t);
604 IntegralPushData pd = {
605 { plane_widths[0], plane_widths[1], plane_widths[2], plane_widths[3] },
606 { plane_heights[0], plane_heights[1], plane_heights[2], plane_heights[3] },
607 { s->strength[0], s->strength[1], s->strength[2], s->strength[3], },
608 { comp_offs[0], comp_offs[1], comp_offs[2], comp_offs[3] },
609 { comp_planes[0], comp_planes[1], comp_planes[2], comp_planes[3] },
610 integral_vk->address,
611 (uint64_t)int_size,
612 (uint64_t)int_stride,
613 offsets_dispatched,
614 desc->nb_components,
615 };
616
617 /* Vertical pass */
618 ff_vk_buf_barrier(buf_bar[nb_buf_bar++], integral_vk,
619 COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, NONE_KHR,
620 COMPUTE_SHADER_BIT, SHADER_STORAGE_WRITE_BIT, NONE_KHR,
621 0, VK_WHOLE_SIZE);
622 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
623 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
624 .pBufferMemoryBarriers = buf_bar,
625 .bufferMemoryBarrierCount = nb_buf_bar,
626 });
627 nb_buf_bar = 0;
628
629 ff_vk_exec_bind_shader(vkctx, exec, &s->shd_vertical);
630 ff_vk_shader_update_push_const(vkctx, exec, &s->shd_vertical,
631 VK_SHADER_STAGE_COMPUTE_BIT,
632 0, sizeof(pd), &pd);
633 vk->CmdDispatch(exec->buf,
634 FFALIGN(vkctx->output_width, s->shd_vertical.lg_size[0]) /
635 s->shd_vertical.lg_size[0],
636 desc->nb_components,
637 wg_invoc);
638
639 /* Horizontal pass */
640 ff_vk_buf_barrier(buf_bar[nb_buf_bar++], integral_vk,
641 COMPUTE_SHADER_BIT, SHADER_STORAGE_WRITE_BIT, NONE_KHR,
642 COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT,
643 SHADER_STORAGE_WRITE_BIT,
644 0, VK_WHOLE_SIZE);
645 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
646 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
647 .pBufferMemoryBarriers = buf_bar,
648 .bufferMemoryBarrierCount = nb_buf_bar,
649 });
650 nb_buf_bar = 0;
651
652 ff_vk_exec_bind_shader(vkctx, exec, &s->shd_horizontal);
653 ff_vk_shader_update_push_const(vkctx, exec, &s->shd_horizontal,
654 VK_SHADER_STAGE_COMPUTE_BIT,
655 0, sizeof(pd), &pd);
656 vk->CmdDispatch(exec->buf,
657 FFALIGN(vkctx->output_height, s->shd_horizontal.lg_size[0]) /
658 s->shd_horizontal.lg_size[0],
659 desc->nb_components,
660 wg_invoc);
661
662 /* Weights pass */
663 ff_vk_buf_barrier(buf_bar[nb_buf_bar++], integral_vk,
664 COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT,
665 SHADER_STORAGE_WRITE_BIT,
666 COMPUTE_SHADER_BIT, SHADER_STORAGE_READ_BIT, NONE_KHR,
667 0, VK_WHOLE_SIZE);
668 buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) {
669 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
670 .srcStageMask = ws_stage,
671 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
672 .srcAccessMask = ws_access,
673 .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
674 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
675 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
676 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
677 .buffer = ws_vk->buf,
678 .size = ws_vk->size,
679 .offset = 0,
680 };
681 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
682 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
683 .pBufferMemoryBarriers = buf_bar,
684 .bufferMemoryBarrierCount = nb_buf_bar,
685 });
686 nb_buf_bar = 0;
687 ws_stage = buf_bar[1].dstStageMask;
688 ws_access = buf_bar[1].dstAccessMask;
689
690 WeightsPushData wpd = {
691 { plane_widths[0], plane_widths[1], plane_widths[2], plane_widths[3] },
692 { plane_heights[0], plane_heights[1], plane_heights[2], plane_heights[3] },
693 { ws_offset[0], ws_offset[1], ws_offset[2], ws_offset[3] },
694 { ws_stride[0], ws_stride[1], ws_stride[2], ws_stride[3] },
695 { s->patch[0], s->patch[1], s->patch[2], s->patch[3] },
696 { s->strength[0], s->strength[1], s->strength[2], s->strength[3], },
697 { comp_offs[0], comp_offs[1], comp_offs[2], comp_offs[3] },
698 { comp_planes[0], comp_planes[1], comp_planes[2], comp_planes[3] },
699 integral_vk->address,
700 (uint64_t)int_size,
701 (uint64_t)int_stride,
702 offsets_dispatched,
703 ws_count,
704 desc->nb_components,
705 };
706 ff_vk_exec_bind_shader(vkctx, exec, &s->shd_weights);
707 ff_vk_shader_update_push_const(vkctx, exec, &s->shd_weights,
708 VK_SHADER_STAGE_COMPUTE_BIT,
709 0, sizeof(wpd), &wpd);
710 vk->CmdDispatch(exec->buf,
711 FFALIGN(vkctx->output_width, s->shd_weights.lg_size[0]) /
712 s->shd_weights.lg_size[0],
713 FFALIGN(vkctx->output_height, s->shd_weights.lg_size[1]) /
714 s->shd_weights.lg_size[1],
715 wg_invoc * desc->nb_components);
716
717 offsets_dispatched += wg_invoc * TYPE_ELEMS;
718 } while (offsets_dispatched < s->nb_offsets);
719
720 RET(denoise_pass(s, exec, ws_vk, comp_offs, comp_planes, ws_offset, ws_stride,
721 ws_count, s->opts.t, desc->nb_components));
722
723 ff_vk_exec_move_dep_refstruct(vkctx, exec, &integral_vk);
724 ff_vk_exec_move_dep_refstruct(vkctx, exec, &ws_vk);
725
726 err = av_frame_copy_props(out, in);
727 if (err < 0)
728 goto fail;
729
730 err = ff_vk_exec_submit(vkctx, exec);
731 if (err < 0) {
732 av_frame_free(&in);
734 return err;
735 }
736
737 av_frame_free(&in);
738
739 return ff_filter_frame(outlink, out);
740
741fail:
742 ff_vk_exec_discard(vkctx, exec);
743 av_refstruct_unref(&integral_vk);
744 av_refstruct_unref(&ws_vk);
745 av_frame_free(&in);
747 return err;
748}
749
751{
752 NLMeansVulkanContext *s = avctx->priv;
753 FFVulkanContext *vkctx = &s->vkctx;
754
755 ff_vk_exec_pool_free(vkctx, &s->e);
756 ff_vk_shader_free(vkctx, &s->shd_horizontal);
757 ff_vk_shader_free(vkctx, &s->shd_vertical);
758 ff_vk_shader_free(vkctx, &s->shd_weights);
759 ff_vk_shader_free(vkctx, &s->shd_denoise);
760
761 av_refstruct_pool_uninit(&s->integral_buf_pool);
762 av_refstruct_pool_uninit(&s->ws_buf_pool);
763
764 ff_vk_uninit(&s->vkctx);
765
766 av_freep(&s->xoffsets);
767 av_freep(&s->yoffsets);
768
769 s->initialized = 0;
770}
771
772#define OFFSET(x) offsetof(NLMeansVulkanContext, x)
773#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
775 { "s", "denoising strength for all components", OFFSET(opts.s), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 0.0, 100.0, FLAGS },
776 { "p", "patch size for all components", OFFSET(opts.p), AV_OPT_TYPE_INT, { .i64 = 3*2+1 }, 0, 99, FLAGS },
777 { "r", "research window size", OFFSET(opts.r), AV_OPT_TYPE_INT, { .i64 = 7*2+1 }, 0, 99, FLAGS },
778 { "t", "parallelism", OFFSET(opts.t), AV_OPT_TYPE_INT, { .i64 = 8 }, 1, 64, FLAGS },
779
780 { "s1", "denoising strength for component 1", OFFSET(opts.sc[0]), AV_OPT_TYPE_DOUBLE, { .dbl = NAN }, 0.0, 100.0, FLAGS },
781 { "s2", "denoising strength for component 2", OFFSET(opts.sc[1]), AV_OPT_TYPE_DOUBLE, { .dbl = NAN }, 0.0, 100.0, FLAGS },
782 { "s3", "denoising strength for component 3", OFFSET(opts.sc[2]), AV_OPT_TYPE_DOUBLE, { .dbl = NAN }, 0.0, 100.0, FLAGS },
783 { "s4", "denoising strength for component 4", OFFSET(opts.sc[3]), AV_OPT_TYPE_DOUBLE, { .dbl = NAN }, 0.0, 100.0, FLAGS },
784
785 { "p1", "patch size for component 1", OFFSET(opts.pc[0]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS },
786 { "p2", "patch size for component 2", OFFSET(opts.pc[1]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS },
787 { "p3", "patch size for component 3", OFFSET(opts.pc[2]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS },
788 { "p4", "patch size for component 4", OFFSET(opts.pc[3]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS },
789
790 { NULL }
791};
792
793AVFILTER_DEFINE_CLASS(nlmeans_vulkan);
794
796 {
797 .name = "default",
798 .type = AVMEDIA_TYPE_VIDEO,
799 .filter_frame = &nlmeans_vulkan_filter_frame,
800 .config_props = &ff_vk_filter_config_input,
801 },
802};
803
805 {
806 .name = "default",
807 .type = AVMEDIA_TYPE_VIDEO,
808 .config_props = &ff_vk_filter_config_output,
809 },
810};
811
813 .p.name = "nlmeans_vulkan",
814 .p.description = NULL_IF_CONFIG_SMALL("Non-local means denoiser (Vulkan)"),
815 .p.priv_class = &nlmeans_vulkan_class,
816 .p.flags = AVFILTER_FLAG_HWDEVICE,
817 .priv_size = sizeof(NLMeansVulkanContext),
823 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
824};
const FFFilter ff_vf_nlmeans_vulkan
static FILE * out
static AVFormatContext * ctx
static AVDictionary * opts
int32_t
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
#define AV_NUM_DATA_POINTERS
Definition frame.h:473
#define fail
Definition test.h:479
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
Definition opt.h:266
#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_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
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
void ff_vk_shader_update_img_array(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, AVFrame *f, VkImageView *views, int set, int binding, VkImageLayout layout, VkSampler sampler)
Update a descriptor in a buffer with an image array.
Definition vulkan.c:2719
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:2240
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:2550
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
Definition vulkan.c:331
int ff_vk_create_buf(FFVulkanContext *s, FFVkBuffer *buf, size_t size, void *pNext, void *alloc_pNext, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
Definition vulkan.c:1186
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:395
int ff_vk_shader_add_push_const(FFVulkanShader *shd, int offset, int size, VkShaderStageFlagBits stage)
Add/update push constants for execution.
Definition vulkan.c:1613
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
Definition vulkan.c:2815
void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e, AVFrame *pic, VkImageMemoryBarrier2 *bar, int *nb_bar, VkPipelineStageFlags2 src_stage, VkPipelineStageFlags2 dst_stage, VkAccessFlagBits2 new_access, VkImageLayout new_layout, uint32_t new_qf)
Definition vulkan.c:2197
int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e)
Start/submit/wait an execution.
Definition vulkan.c:660
int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e, VkImageView views[AV_NUM_DATA_POINTERS], AVFrame *f, enum FFVkShaderRepFormat rep_fmt)
Create an imageview and add it as a dependency to an execution.
Definition vulkan.c:2128
void ff_vk_shader_free(FFVulkanContext *s, FFVulkanShader *shd)
Free a shader.
Definition vulkan.c:2791
int ff_vk_shader_register_exec(FFVulkanContext *s, FFVkExecPool *pool, FFVulkanShader *shd)
Register a shader with an exec pool.
Definition vulkan.c:2584
FFVkExecContext * ff_vk_exec_get(FFVulkanContext *s, FFVkExecPool *pool)
Retrieve an execution pool.
Definition vulkan.c:622
int ff_vk_exec_submit(FFVulkanContext *s, FFVkExecContext *e)
Definition vulkan.c:969
void ff_vk_exec_bind_shader(FFVulkanContext *s, FFVkExecContext *e, const FFVulkanShader *shd)
Bind a shader.
Definition vulkan.c:2768
void ff_vk_exec_move_dep_refstruct(FFVulkanContext *s, FFVkExecContext *e, void *obj)
Definition vulkan.c:786
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:2732
AVVulkanDeviceQueueFamily * ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops)
Chooses an appropriate QF.
Definition vulkan.c:316
int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVRefStructPool **buf_pool, FFVkBuffer **buf, VkBufferUsageFlags usage, void *create_pNext, size_t size, VkMemoryPropertyFlagBits mem_props)
Initialize a pool and create AVBufferRefs containing FFVkBuffer.
Definition vulkan.c:1426
void ff_vk_exec_discard(FFVulkanContext *s, FFVkExecContext *e)
Definition vulkan.c:763
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:2444
int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, VkPipelineStageFlagBits2 wait_stage, VkPipelineStageFlagBits2 signal_stage)
Definition vulkan.c:867
void ff_vk_shader_update_push_const(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, VkShaderStageFlagBits stage, int offset, size_t size, void *src)
Update push constant in a shader.
Definition vulkan.c:2758
#define isnan(x)
Definition libm.h:342
const char * desc
Definition libsvtav1.c:83
static const struct @257111027162314367033347246032313251342043035002 planes[]
#define FFMIN(a, b)
Definition macros.h:49
#define FFALIGN(x, a)
Definition macros.h:78
#define NAN
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition pixfmt.h:379
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
Definition refstruct.c:120
static void av_refstruct_pool_uninit(AVRefStructPool **poolp)
Mark the pool as being available for freeing.
Definition refstruct.h:292
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
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
AVRefStructPool is an API for a thread-safe pool of objects managed via the RefStruct API.
Definition refstruct.c:183
VkBuffer buf
Definition vulkan.h:95
VkDeviceAddress address
Definition vulkan.h:99
size_t size
Definition vulkan.h:98
VkCommandBuffer buf
Definition vulkan.h:142
int output_height
Definition vulkan.h:351
FFVulkanFunctions vkfn
Definition vulkan.h:298
enum AVPixelFormat output_format
Definition vulkan.h:352
VkDeviceAddress integral_base
FFVulkanShader shd_vertical
AVRefStructPool * ws_buf_pool
FFVulkanShader shd_horizontal
FFVulkanShader shd_weights
AVVulkanDeviceQueueFamily * qf
AVRefStructPool * integral_buf_pool
FFVulkanShader shd_denoise
VkDeviceAddress integral_base
#define av_freep(p)
#define av_log(a,...)
static void nlmeans_vulkan_uninit(AVFilterContext *avctx)
static av_cold int init_denoise_pipeline(FFVulkanContext *vkctx, FFVkExecPool *exec, FFVulkanShader *shd, int planes)
static av_cold int init_weights_pipeline(FFVulkanContext *vkctx, FFVkExecPool *exec, FFVulkanShader *shd, int planes)
static av_cold int init_integral_pipeline(FFVulkanContext *vkctx, FFVkExecPool *exec, FFVulkanShader *shd_horizontal, FFVulkanShader *shd_vertical, int planes)
static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)
static const AVFilterPad nlmeans_vulkan_inputs[]
const unsigned int ff_nlmeans_vertical_comp_spv_len
const unsigned char ff_nlmeans_horizontal_comp_spv_data[]
static av_cold int init_filter(AVFilterContext *ctx)
#define WG_SIZE
const unsigned int ff_nlmeans_horizontal_comp_spv_len
#define TYPE_ELEMS
static int denoise_pass(NLMeansVulkanContext *s, FFVkExecContext *exec, FFVkBuffer *ws_vk, uint32_t comp_offs[4], uint32_t comp_planes[4], uint32_t ws_offset[4], uint32_t ws_stride[4], uint32_t ws_count, uint32_t t, uint32_t nb_components)
const unsigned char ff_nlmeans_vertical_comp_spv_data[]
const unsigned char ff_nlmeans_weights_comp_spv_data[]
static const AVOption nlmeans_vulkan_options[]
const unsigned int ff_nlmeans_weights_comp_spv_len
const unsigned int ff_nlmeans_denoise_comp_spv_len
#define OFFSET(x)
#define TYPE_SIZE
const unsigned char ff_nlmeans_denoise_comp_spv_data[]
static const AVFilterPad nlmeans_vulkan_outputs[]
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_buf_barrier(dst, vkb, s_stage, s_access, s_access2, d_stage, d_access, d_access2, offs, bsz)
Definition vulkan.h:575
@ FF_VK_REP_FLOAT
Definition vulkan.h:441
#define RET(x)
Definition vulkan.h:37
static int ff_vk_unmap_buffer(FFVulkanContext *s, FFVkBuffer *buf, int flush)
Definition vulkan.h:649
static int ff_vk_map_buffer(FFVulkanContext *s, FFVkBuffer *buf, uint8_t **mem, int invalidate)
Definition vulkan.h:642
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.