FFmpeg
vulkan.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "formats.h"
20 #include "vulkan.h"
21 #include "glslang.h"
22 
23 /* Generic macro for creating contexts which need to keep their addresses
24  * if another context is created. */
25 #define FN_CREATING(ctx, type, shortname, array, num) \
26 static av_always_inline type *create_ ##shortname(ctx *dctx) \
27 { \
28  type **array, *sctx = av_mallocz(sizeof(*sctx)); \
29  if (!sctx) \
30  return NULL; \
31  \
32  array = av_realloc_array(dctx->array, sizeof(*dctx->array), dctx->num + 1);\
33  if (!array) { \
34  av_free(sctx); \
35  return NULL; \
36  } \
37  \
38  dctx->array = array; \
39  dctx->array[dctx->num++] = sctx; \
40  \
41  return sctx; \
42 }
43 
44 const VkComponentMapping ff_comp_identity_map = {
45  .r = VK_COMPONENT_SWIZZLE_IDENTITY,
46  .g = VK_COMPONENT_SWIZZLE_IDENTITY,
47  .b = VK_COMPONENT_SWIZZLE_IDENTITY,
48  .a = VK_COMPONENT_SWIZZLE_IDENTITY,
49 };
50 
51 /* Converts return values to strings */
52 const char *ff_vk_ret2str(VkResult res)
53 {
54 #define CASE(VAL) case VAL: return #VAL
55  switch (res) {
56  CASE(VK_SUCCESS);
57  CASE(VK_NOT_READY);
58  CASE(VK_TIMEOUT);
59  CASE(VK_EVENT_SET);
60  CASE(VK_EVENT_RESET);
61  CASE(VK_INCOMPLETE);
62  CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
63  CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
64  CASE(VK_ERROR_INITIALIZATION_FAILED);
65  CASE(VK_ERROR_DEVICE_LOST);
66  CASE(VK_ERROR_MEMORY_MAP_FAILED);
67  CASE(VK_ERROR_LAYER_NOT_PRESENT);
68  CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
69  CASE(VK_ERROR_FEATURE_NOT_PRESENT);
70  CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
71  CASE(VK_ERROR_TOO_MANY_OBJECTS);
72  CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
73  CASE(VK_ERROR_FRAGMENTED_POOL);
74  CASE(VK_ERROR_SURFACE_LOST_KHR);
75  CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
76  CASE(VK_SUBOPTIMAL_KHR);
77  CASE(VK_ERROR_OUT_OF_DATE_KHR);
78  CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
79  CASE(VK_ERROR_VALIDATION_FAILED_EXT);
80  CASE(VK_ERROR_INVALID_SHADER_NV);
81  CASE(VK_ERROR_OUT_OF_POOL_MEMORY);
82  CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE);
83  CASE(VK_ERROR_NOT_PERMITTED_EXT);
84  default: return "Unknown error";
85  }
86 #undef CASE
87 }
88 
89 static int vk_alloc_mem(AVFilterContext *avctx, VkMemoryRequirements *req,
90  VkMemoryPropertyFlagBits req_flags, void *alloc_extension,
91  VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
92 {
93  VkResult ret;
94  int index = -1;
95  VkPhysicalDeviceProperties props;
96  VkPhysicalDeviceMemoryProperties mprops;
97  VulkanFilterContext *s = avctx->priv;
98 
99  VkMemoryAllocateInfo alloc_info = {
100  .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
101  .pNext = alloc_extension,
102  };
103 
104  vkGetPhysicalDeviceProperties(s->hwctx->phys_dev, &props);
105  vkGetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &mprops);
106 
107  /* Align if we need to */
108  if (req_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
109  req->size = FFALIGN(req->size, props.limits.minMemoryMapAlignment);
110 
111  alloc_info.allocationSize = req->size;
112 
113  /* The vulkan spec requires memory types to be sorted in the "optimal"
114  * order, so the first matching type we find will be the best/fastest one */
115  for (int i = 0; i < mprops.memoryTypeCount; i++) {
116  /* The memory type must be supported by the requirements (bitfield) */
117  if (!(req->memoryTypeBits & (1 << i)))
118  continue;
119 
120  /* The memory type flags must include our properties */
121  if ((mprops.memoryTypes[i].propertyFlags & req_flags) != req_flags)
122  continue;
123 
124  /* Found a suitable memory type */
125  index = i;
126  break;
127  }
128 
129  if (index < 0) {
130  av_log(avctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
131  req_flags);
132  return AVERROR(EINVAL);
133  }
134 
135  alloc_info.memoryTypeIndex = index;
136 
137  ret = vkAllocateMemory(s->hwctx->act_dev, &alloc_info,
138  s->hwctx->alloc, mem);
139  if (ret != VK_SUCCESS) {
140  av_log(avctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
141  ff_vk_ret2str(ret));
142  return AVERROR(ENOMEM);
143  }
144 
145  *mem_flags |= mprops.memoryTypes[index].propertyFlags;
146 
147  return 0;
148 }
149 
151  VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
152 {
153  int err;
154  VkResult ret;
155  VkMemoryRequirements req;
156  VulkanFilterContext *s = avctx->priv;
157 
158  VkBufferCreateInfo buf_spawn = {
159  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
160  .pNext = NULL,
161  .usage = usage,
162  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
163  .size = size, /* Gets FFALIGNED during alloc if host visible
164  but should be ok */
165  };
166 
167  ret = vkCreateBuffer(s->hwctx->act_dev, &buf_spawn, NULL, &buf->buf);
168  if (ret != VK_SUCCESS) {
169  av_log(avctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
170  ff_vk_ret2str(ret));
171  return AVERROR_EXTERNAL;
172  }
173 
174  vkGetBufferMemoryRequirements(s->hwctx->act_dev, buf->buf, &req);
175 
176  err = vk_alloc_mem(avctx, &req, flags, NULL, &buf->flags, &buf->mem);
177  if (err)
178  return err;
179 
180  ret = vkBindBufferMemory(s->hwctx->act_dev, buf->buf, buf->mem, 0);
181  if (ret != VK_SUCCESS) {
182  av_log(avctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
183  ff_vk_ret2str(ret));
184  return AVERROR_EXTERNAL;
185  }
186 
187  return 0;
188 }
189 
191  int nb_buffers, int invalidate)
192 {
193  VkResult ret;
194  VulkanFilterContext *s = avctx->priv;
195  VkMappedMemoryRange *inval_list = NULL;
196  int inval_count = 0;
197 
198  for (int i = 0; i < nb_buffers; i++) {
199  ret = vkMapMemory(s->hwctx->act_dev, buf[i].mem, 0,
200  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
201  if (ret != VK_SUCCESS) {
202  av_log(avctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
203  ff_vk_ret2str(ret));
204  return AVERROR_EXTERNAL;
205  }
206  }
207 
208  if (!invalidate)
209  return 0;
210 
211  for (int i = 0; i < nb_buffers; i++) {
212  const VkMappedMemoryRange ival_buf = {
213  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
214  .memory = buf[i].mem,
215  .size = VK_WHOLE_SIZE,
216  };
217  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
218  continue;
219  inval_list = av_fast_realloc(s->scratch, &s->scratch_size,
220  (++inval_count)*sizeof(*inval_list));
221  if (!inval_list)
222  return AVERROR(ENOMEM);
223  inval_list[inval_count - 1] = ival_buf;
224  }
225 
226  if (inval_count) {
227  ret = vkInvalidateMappedMemoryRanges(s->hwctx->act_dev, inval_count,
228  inval_list);
229  if (ret != VK_SUCCESS) {
230  av_log(avctx, AV_LOG_ERROR, "Failed to invalidate memory: %s\n",
231  ff_vk_ret2str(ret));
232  return AVERROR_EXTERNAL;
233  }
234  }
235 
236  return 0;
237 }
238 
239 int ff_vk_unmap_buffers(AVFilterContext *avctx, FFVkBuffer *buf, int nb_buffers,
240  int flush)
241 {
242  int err = 0;
243  VkResult ret;
244  VulkanFilterContext *s = avctx->priv;
245  VkMappedMemoryRange *flush_list = NULL;
246  int flush_count = 0;
247 
248  if (flush) {
249  for (int i = 0; i < nb_buffers; i++) {
250  const VkMappedMemoryRange flush_buf = {
251  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
252  .memory = buf[i].mem,
253  .size = VK_WHOLE_SIZE,
254  };
255  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
256  continue;
257  flush_list = av_fast_realloc(s->scratch, &s->scratch_size,
258  (++flush_count)*sizeof(*flush_list));
259  if (!flush_list)
260  return AVERROR(ENOMEM);
261  flush_list[flush_count - 1] = flush_buf;
262  }
263  }
264 
265  if (flush_count) {
266  ret = vkFlushMappedMemoryRanges(s->hwctx->act_dev, flush_count,
267  flush_list);
268  if (ret != VK_SUCCESS) {
269  av_log(avctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
270  ff_vk_ret2str(ret));
271  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
272  }
273  }
274 
275  for (int i = 0; i < nb_buffers; i++)
276  vkUnmapMemory(s->hwctx->act_dev, buf[i].mem);
277 
278  return err;
279 }
280 
282 {
283  VulkanFilterContext *s = avctx->priv;
284  if (!buf)
285  return;
286 
287  if (buf->buf != VK_NULL_HANDLE)
288  vkDestroyBuffer(s->hwctx->act_dev, buf->buf, s->hwctx->alloc);
289  if (buf->mem != VK_NULL_HANDLE)
290  vkFreeMemory(s->hwctx->act_dev, buf->mem, s->hwctx->alloc);
291 }
292 
294  int offset, int size, VkShaderStageFlagBits stage)
295 {
296  VkPushConstantRange *pc;
297 
298  pl->push_consts = av_realloc_array(pl->push_consts, sizeof(*pl->push_consts),
299  pl->push_consts_num + 1);
300  if (!pl->push_consts)
301  return AVERROR(ENOMEM);
302 
303  pc = &pl->push_consts[pl->push_consts_num++];
304  memset(pc, 0, sizeof(*pc));
305 
306  pc->stageFlags = stage;
307  pc->offset = offset;
308  pc->size = size;
309 
310  return 0;
311 }
312 
313 FN_CREATING(VulkanFilterContext, FFVkExecContext, exec_ctx, exec_ctx, exec_ctx_num)
315 {
316  VkResult ret;
317  FFVkExecContext *e;
318  VulkanFilterContext *s = avctx->priv;
319 
320  VkCommandPoolCreateInfo cqueue_create = {
321  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
322  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
323  .queueFamilyIndex = queue,
324  };
325  VkCommandBufferAllocateInfo cbuf_create = {
326  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
327  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
328  .commandBufferCount = 1,
329  };
330  VkFenceCreateInfo fence_spawn = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
331 
332  e = create_exec_ctx(s);
333  if (!e)
334  return AVERROR(ENOMEM);
335 
336  ret = vkCreateCommandPool(s->hwctx->act_dev, &cqueue_create,
337  s->hwctx->alloc, &e->pool);
338  if (ret != VK_SUCCESS) {
339  av_log(avctx, AV_LOG_ERROR, "Command pool creation failure: %s\n",
340  ff_vk_ret2str(ret));
341  return 1;
342  }
343 
344  cbuf_create.commandPool = e->pool;
345 
346  ret = vkAllocateCommandBuffers(s->hwctx->act_dev, &cbuf_create, &e->buf);
347  if (ret != VK_SUCCESS) {
348  av_log(avctx, AV_LOG_ERROR, "Command buffer alloc failure: %s\n",
349  ff_vk_ret2str(ret));
350  return 1;
351  }
352 
353  ret = vkCreateFence(s->hwctx->act_dev, &fence_spawn,
354  s->hwctx->alloc, &e->fence);
355  if (ret != VK_SUCCESS) {
356  av_log(avctx, AV_LOG_ERROR, "Failed to create frame fence: %s\n",
357  ff_vk_ret2str(ret));
358  return 1;
359  }
360 
361  vkGetDeviceQueue(s->hwctx->act_dev, queue, 0, &e->queue);
362 
363  *ctx = e;
364 
365  return 0;
366 }
367 
369 {
370  VkResult ret;
371  VkCommandBufferBeginInfo cmd_start = {
372  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
373  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
374  };
375 
376  e->sem_wait_cnt = 0;
377  e->sem_sig_cnt = 0;
378 
379  ret = vkBeginCommandBuffer(e->buf, &cmd_start);
380  if (ret != VK_SUCCESS) {
381  av_log(avctx, AV_LOG_ERROR, "Failed to start command recoding: %s\n",
382  ff_vk_ret2str(ret));
383  return AVERROR_EXTERNAL;
384  }
385 
386  return 0;
387 }
388 
390  AVFrame *frame, VkPipelineStageFlagBits in_wait_dst_flag)
391 {
392  AVVkFrame *f = (AVVkFrame *)frame->data[0];
394  int planes = av_pix_fmt_count_planes(fc->sw_format);
395 
396  for (int i = 0; i < planes; i++) {
398  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait));
399  if (!e->sem_wait)
400  return AVERROR(ENOMEM);
401 
403  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait_dst));
404  if (!e->sem_wait_dst)
405  return AVERROR(ENOMEM);
406 
408  (e->sem_sig_cnt + 1)*sizeof(*e->sem_sig));
409  if (!e->sem_sig)
410  return AVERROR(ENOMEM);
411 
412  e->sem_wait[e->sem_wait_cnt] = f->sem[i];
413  e->sem_wait_dst[e->sem_wait_cnt] = in_wait_dst_flag;
414  e->sem_wait_cnt++;
415 
416  e->sem_sig[e->sem_sig_cnt] = f->sem[i];
417  e->sem_sig_cnt++;
418  }
419 
420  return 0;
421 }
422 
424 {
425  VkResult ret;
426  VulkanFilterContext *s = avctx->priv;
427 
428  VkSubmitInfo s_info = {
429  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
430  .commandBufferCount = 1,
431  .pCommandBuffers = &e->buf,
432 
433  .pWaitSemaphores = e->sem_wait,
434  .pWaitDstStageMask = e->sem_wait_dst,
435  .waitSemaphoreCount = e->sem_wait_cnt,
436 
437  .pSignalSemaphores = e->sem_sig,
438  .signalSemaphoreCount = e->sem_sig_cnt,
439  };
440 
441  vkEndCommandBuffer(e->buf);
442 
443  ret = vkQueueSubmit(e->queue, 1, &s_info, e->fence);
444  if (ret != VK_SUCCESS) {
445  av_log(avctx, AV_LOG_ERROR, "Unable to submit command buffer: %s\n",
446  ff_vk_ret2str(ret));
447  return AVERROR_EXTERNAL;
448  }
449 
450  vkWaitForFences(s->hwctx->act_dev, 1, &e->fence, VK_TRUE, UINT64_MAX);
451  vkResetFences(s->hwctx->act_dev, 1, &e->fence);
452 
453  return 0;
454 }
455 
457 {
458  static const enum AVPixelFormat pixel_formats[] = {
460  };
461  AVFilterFormats *pix_fmts = ff_make_format_list(pixel_formats);
462  if (!pix_fmts)
463  return AVERROR(ENOMEM);
464 
465  return ff_set_common_formats(avctx, pix_fmts);
466 }
467 
469  AVBufferRef *device)
470 {
471  VulkanFilterContext *s = avctx->priv;
472 
474 
475  s->device_ref = av_buffer_ref(device);
476  if (!s->device_ref)
477  return AVERROR(ENOMEM);
478 
480  s->hwctx = s->device->hwctx;
481 
482  return 0;
483 }
484 
487 {
488  VulkanFilterContext *s = avctx->priv;
489 
491 
492  s->frames_ref = av_buffer_ref(frames);
493  if (!s->frames_ref)
494  return AVERROR(ENOMEM);
495 
496  return 0;
497 }
498 
500 {
501  int err;
502  AVFilterContext *avctx = inlink->dst;
503  VulkanFilterContext *s = avctx->priv;
504  AVHWFramesContext *input_frames;
505 
506  if (!inlink->hw_frames_ctx) {
507  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
508  "hardware frames context on the input.\n");
509  return AVERROR(EINVAL);
510  }
511 
512  /* Extract the device and default output format from the first input. */
513  if (avctx->inputs[0] != inlink)
514  return 0;
515 
516  input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
517  if (input_frames->format != AV_PIX_FMT_VULKAN)
518  return AVERROR(EINVAL);
519 
520  err = vulkan_filter_set_device(avctx, input_frames->device_ref);
521  if (err < 0)
522  return err;
523  err = vulkan_filter_set_frames(avctx, inlink->hw_frames_ctx);
524  if (err < 0)
525  return err;
526 
527  /* Default output parameters match input parameters. */
528  s->input_format = input_frames->sw_format;
529  if (s->output_format == AV_PIX_FMT_NONE)
530  s->output_format = input_frames->sw_format;
531  if (!s->output_width)
532  s->output_width = inlink->w;
533  if (!s->output_height)
534  s->output_height = inlink->h;
535 
536  return 0;
537 }
538 
540 {
541  int err;
542  AVFilterContext *avctx = outlink->src;
543  VulkanFilterContext *s = avctx->priv;
544 
545  av_buffer_unref(&outlink->hw_frames_ctx);
546 
547  if (!s->device_ref) {
548  if (!avctx->hw_device_ctx) {
549  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
550  "Vulkan device.\n");
551  return AVERROR(EINVAL);
552  }
553 
554  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
555  if (err < 0)
556  return err;
557  }
558 
559  outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref);
560  if (!outlink->hw_frames_ctx)
561  return AVERROR(ENOMEM);
562 
563  outlink->w = s->output_width;
564  outlink->h = s->output_height;
565 
566  return 0;
567 }
568 
570 {
571  int err;
572  AVFilterContext *avctx = outlink->src;
573  VulkanFilterContext *s = avctx->priv;
574  AVBufferRef *output_frames_ref;
575  AVHWFramesContext *output_frames;
576 
577  av_buffer_unref(&outlink->hw_frames_ctx);
578 
579  if (!s->device_ref) {
580  if (!avctx->hw_device_ctx) {
581  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
582  "Vulkan device.\n");
583  return AVERROR(EINVAL);
584  }
585 
586  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
587  if (err < 0)
588  return err;
589  }
590 
591  output_frames_ref = av_hwframe_ctx_alloc(s->device_ref);
592  if (!output_frames_ref) {
593  err = AVERROR(ENOMEM);
594  goto fail;
595  }
596  output_frames = (AVHWFramesContext*)output_frames_ref->data;
597 
598  output_frames->format = AV_PIX_FMT_VULKAN;
599  output_frames->sw_format = s->output_format;
600  output_frames->width = s->output_width;
601  output_frames->height = s->output_height;
602 
603  err = av_hwframe_ctx_init(output_frames_ref);
604  if (err < 0) {
605  av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
606  "frames: %d.\n", err);
607  goto fail;
608  }
609 
610  outlink->hw_frames_ctx = output_frames_ref;
611  outlink->w = s->output_width;
612  outlink->h = s->output_height;
613 
614  return 0;
615 fail:
616  av_buffer_unref(&output_frames_ref);
617  return err;
618 }
619 
621 {
622  VulkanFilterContext *s = avctx->priv;
623 
625 
626  if (glslang_init())
627  return AVERROR_EXTERNAL;
628 
629  return 0;
630 }
631 
632 FN_CREATING(VulkanFilterContext, VkSampler, sampler, samplers, samplers_num)
633 VkSampler *ff_vk_init_sampler(AVFilterContext *avctx, int unnorm_coords,
634  VkFilter filt)
635 {
636  VkResult ret;
637  VulkanFilterContext *s = avctx->priv;
638 
639  VkSamplerCreateInfo sampler_info = {
640  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
641  .magFilter = filt,
642  .minFilter = sampler_info.magFilter,
643  .mipmapMode = unnorm_coords ? VK_SAMPLER_MIPMAP_MODE_NEAREST :
644  VK_SAMPLER_MIPMAP_MODE_LINEAR,
645  .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
646  .addressModeV = sampler_info.addressModeU,
647  .addressModeW = sampler_info.addressModeU,
648  .anisotropyEnable = VK_FALSE,
649  .compareOp = VK_COMPARE_OP_NEVER,
650  .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
651  .unnormalizedCoordinates = unnorm_coords,
652  };
653 
654  VkSampler *sampler = create_sampler(s);
655  if (!sampler)
656  return NULL;
657 
658  ret = vkCreateSampler(s->hwctx->act_dev, &sampler_info,
659  s->hwctx->alloc, sampler);
660  if (ret != VK_SUCCESS) {
661  av_log(avctx, AV_LOG_ERROR, "Unable to init sampler: %s\n",
662  ff_vk_ret2str(ret));
663  return NULL;
664  }
665 
666  return sampler;
667 }
668 
670 {
671  if (pix_fmt == AV_PIX_FMT_ABGR || pix_fmt == AV_PIX_FMT_BGRA ||
672  pix_fmt == AV_PIX_FMT_RGBA || pix_fmt == AV_PIX_FMT_RGB24 ||
673  pix_fmt == AV_PIX_FMT_BGR24 || pix_fmt == AV_PIX_FMT_RGB48 ||
674  pix_fmt == AV_PIX_FMT_RGBA64 || pix_fmt == AV_PIX_FMT_RGB565 ||
675  pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_BGR0 ||
676  pix_fmt == AV_PIX_FMT_0BGR || pix_fmt == AV_PIX_FMT_RGB0)
677  return 1;
678  return 0;
679 }
680 
682 {
684  const int high = desc->comp[0].depth > 8;
685  return high ? "rgba16f" : "rgba8";
686 }
687 
688 int ff_vk_create_imageview(AVFilterContext *avctx, VkImageView *v, VkImage img,
689  VkFormat fmt, const VkComponentMapping map)
690 {
691  VulkanFilterContext *s = avctx->priv;
692  VkImageViewCreateInfo imgview_spawn = {
693  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
694  .pNext = NULL,
695  .image = img,
696  .viewType = VK_IMAGE_VIEW_TYPE_2D,
697  .format = fmt,
698  .components = map,
699  .subresourceRange = {
700  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
701  .baseMipLevel = 0,
702  .levelCount = 1,
703  .baseArrayLayer = 0,
704  .layerCount = 1,
705  },
706  };
707 
708  VkResult ret = vkCreateImageView(s->hwctx->act_dev, &imgview_spawn,
709  s->hwctx->alloc, v);
710  if (ret != VK_SUCCESS) {
711  av_log(s, AV_LOG_ERROR, "Failed to create imageview: %s\n",
712  ff_vk_ret2str(ret));
713  return AVERROR_EXTERNAL;
714  }
715 
716  return 0;
717 }
718 
719 void ff_vk_destroy_imageview(AVFilterContext *avctx, VkImageView *v)
720 {
721  VulkanFilterContext *s = avctx->priv;
722  if (v && *v) {
723  vkDestroyImageView(s->hwctx->act_dev, *v, s->hwctx->alloc);
724  *v = NULL;
725  }
726 }
727 
728 FN_CREATING(VulkanPipeline, SPIRVShader, shader, shaders, shaders_num)
730  const char *name, VkShaderStageFlags stage)
731 {
732  SPIRVShader *shd = create_shader(pl);
733  if (!shd)
734  return NULL;
735 
737 
738  shd->shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
739  shd->shader.stage = stage;
740 
741  shd->name = name;
742 
743  GLSLF(0, #version %i ,460);
744  GLSLC(0, #define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y)) );
745  GLSLC(0, );
746 
747  return shd;
748 }
749 
751  int local_size[3])
752 {
753  shd->local_size[0] = local_size[0];
754  shd->local_size[1] = local_size[1];
755  shd->local_size[2] = local_size[2];
756 
757  av_bprintf(&shd->src, "layout (local_size_x = %i, "
758  "local_size_y = %i, local_size_z = %i) in;\n\n",
759  shd->local_size[0], shd->local_size[1], shd->local_size[2]);
760 }
761 
762 static void print_shader(AVFilterContext *avctx, SPIRVShader *shd, int prio)
763 {
764  int line = 0;
765  const char *p = shd->src.str;
766  const char *start = p;
767 
768  AVBPrint buf;
770 
771  for (int i = 0; i < strlen(p); i++) {
772  if (p[i] == '\n') {
773  av_bprintf(&buf, "%i\t", ++line);
774  av_bprint_append_data(&buf, start, &p[i] - start + 1);
775  start = &p[i + 1];
776  }
777  }
778 
779  av_log(avctx, prio, "Shader %s: \n%s", shd->name, buf.str);
780  av_bprint_finalize(&buf, NULL);
781 }
782 
784  const char *entrypoint)
785 {
786  VkResult ret;
787  VulkanFilterContext *s = avctx->priv;
788  VkShaderModuleCreateInfo shader_create;
789  GLSlangResult *res;
790 
791  static const enum GLSlangStage emap[] = {
792  [VK_SHADER_STAGE_VERTEX_BIT] = GLSLANG_VERTEX,
793  [VK_SHADER_STAGE_FRAGMENT_BIT] = GLSLANG_FRAGMENT,
794  [VK_SHADER_STAGE_COMPUTE_BIT] = GLSLANG_COMPUTE,
795  };
796 
797  shd->shader.pName = entrypoint;
798 
799  res = glslang_compile(shd->src.str, emap[shd->shader.stage]);
800  if (!res)
801  return AVERROR(ENOMEM);
802 
803  if (res->rval) {
804  av_log(avctx, AV_LOG_ERROR, "Error compiling shader %s: %s!\n",
805  shd->name, av_err2str(res->rval));
806  print_shader(avctx, shd, AV_LOG_ERROR);
807  if (res->error_msg)
808  av_log(avctx, AV_LOG_ERROR, "%s", res->error_msg);
809  av_free(res->error_msg);
810  return res->rval;
811  }
812 
813  print_shader(avctx, shd, AV_LOG_VERBOSE);
814 
815  shader_create.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
816  shader_create.pNext = NULL;
817  shader_create.codeSize = res->size;
818  shader_create.flags = 0;
819  shader_create.pCode = res->data;
820 
821  ret = vkCreateShaderModule(s->hwctx->act_dev, &shader_create, NULL,
822  &shd->shader.module);
823 
824  /* Free the GLSlangResult struct */
825  av_free(res);
826 
827  if (ret != VK_SUCCESS) {
828  av_log(avctx, AV_LOG_ERROR, "Unable to create shader module: %s\n",
829  ff_vk_ret2str(ret));
830  return AVERROR_EXTERNAL;
831  }
832 
833  av_log(avctx, AV_LOG_VERBOSE, "Shader %s linked! Size: %zu bytes\n",
834  shd->name, shader_create.codeSize);
835 
836  return 0;
837 }
838 
839 static const struct descriptor_props {
840  size_t struct_size; /* Size of the opaque which updates the descriptor */
841  const char *type;
843  int mem_quali; /* Can use a memory qualifier */
844  int dim_needed; /* Must indicate dimension */
845  int buf_content; /* Must indicate buffer contents */
846 } descriptor_props[] = {
847  [VK_DESCRIPTOR_TYPE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 0, 0, },
848  [VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] = { sizeof(VkDescriptorImageInfo), "texture", 1, 0, 1, 0, },
849  [VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] = { sizeof(VkDescriptorImageInfo), "image", 1, 1, 1, 0, },
850  [VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] = { sizeof(VkDescriptorImageInfo), "subpassInput", 1, 0, 0, 0, },
851  [VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 1, 0, },
852  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
853  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
854  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
855  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
856  [VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] = { sizeof(VkBufferView), "samplerBuffer", 1, 0, 0, 0, },
857  [VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER] = { sizeof(VkBufferView), "imageBuffer", 1, 0, 0, 0, },
858 };
859 
862  int num, int only_print_to_shader)
863 {
864  VkResult ret;
865  VkDescriptorSetLayout *layout;
866  VulkanFilterContext *s = avctx->priv;
867 
868  if (only_print_to_shader)
869  goto print;
870 
871  pl->desc_layout = av_realloc_array(pl->desc_layout, sizeof(*pl->desc_layout),
872  pl->descriptor_sets_num + 1);
873  if (!pl->desc_layout)
874  return AVERROR(ENOMEM);
875 
876  layout = &pl->desc_layout[pl->descriptor_sets_num];
877  memset(layout, 0, sizeof(*layout));
878 
879  { /* Create descriptor set layout descriptions */
880  VkDescriptorSetLayoutCreateInfo desc_create_layout = { 0 };
881  VkDescriptorSetLayoutBinding *desc_binding;
882 
883  desc_binding = av_mallocz(sizeof(*desc_binding)*num);
884  if (!desc_binding)
885  return AVERROR(ENOMEM);
886 
887  for (int i = 0; i < num; i++) {
888  desc_binding[i].binding = i;
889  desc_binding[i].descriptorType = desc[i].type;
890  desc_binding[i].descriptorCount = FFMAX(desc[i].elems, 1);
891  desc_binding[i].stageFlags = desc[i].stages;
892  desc_binding[i].pImmutableSamplers = desc[i].samplers;
893  }
894 
895  desc_create_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
896  desc_create_layout.pBindings = desc_binding;
897  desc_create_layout.bindingCount = num;
898 
899  ret = vkCreateDescriptorSetLayout(s->hwctx->act_dev, &desc_create_layout,
900  s->hwctx->alloc, layout);
901  av_free(desc_binding);
902  if (ret != VK_SUCCESS) {
903  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
904  "layout: %s\n", ff_vk_ret2str(ret));
905  return AVERROR_EXTERNAL;
906  }
907  }
908 
909  { /* Pool each descriptor by type and update pool counts */
910  for (int i = 0; i < num; i++) {
911  int j;
912  for (j = 0; j < pl->pool_size_desc_num; j++)
913  if (pl->pool_size_desc[j].type == desc[i].type)
914  break;
915  if (j >= pl->pool_size_desc_num) {
917  sizeof(*pl->pool_size_desc),
918  ++pl->pool_size_desc_num);
919  if (!pl->pool_size_desc)
920  return AVERROR(ENOMEM);
921  memset(&pl->pool_size_desc[j], 0, sizeof(VkDescriptorPoolSize));
922  }
923  pl->pool_size_desc[j].type = desc[i].type;
924  pl->pool_size_desc[j].descriptorCount += FFMAX(desc[i].elems, 1);
925  }
926  }
927 
928  { /* Create template creation struct */
929  VkDescriptorUpdateTemplateCreateInfo *dt;
930  VkDescriptorUpdateTemplateEntry *des_entries;
931 
932  /* Freed after descriptor set initialization */
933  des_entries = av_mallocz(num*sizeof(VkDescriptorUpdateTemplateEntry));
934  if (!des_entries)
935  return AVERROR(ENOMEM);
936 
937  for (int i = 0; i < num; i++) {
938  des_entries[i].dstBinding = i;
939  des_entries[i].descriptorType = desc[i].type;
940  des_entries[i].descriptorCount = FFMAX(desc[i].elems, 1);
941  des_entries[i].dstArrayElement = 0;
942  des_entries[i].offset = ((uint8_t *)desc[i].updater) - (uint8_t *)s;
943  des_entries[i].stride = descriptor_props[desc[i].type].struct_size;
944  }
945 
947  sizeof(*pl->desc_template_info),
948  pl->descriptor_sets_num + 1);
949  if (!pl->desc_template_info)
950  return AVERROR(ENOMEM);
951 
953  memset(dt, 0, sizeof(*dt));
954 
955  dt->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO;
956  dt->templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
957  dt->descriptorSetLayout = *layout;
958  dt->pDescriptorUpdateEntries = des_entries;
959  dt->descriptorUpdateEntryCount = num;
960  }
961 
962  pl->descriptor_sets_num++;
963 
964 print:
965  /* Write shader info */
966  for (int i = 0; i < num; i++) {
967  const struct descriptor_props *prop = &descriptor_props[desc[i].type];
968  GLSLA("layout (set = %i, binding = %i", pl->descriptor_sets_num - 1, i);
969 
970  if (desc[i].mem_layout)
971  GLSLA(", %s", desc[i].mem_layout);
972  GLSLA(")");
973 
974  if (prop->is_uniform)
975  GLSLA(" uniform");
976 
977  if (prop->mem_quali && desc[i].mem_quali)
978  GLSLA(" %s", desc[i].mem_quali);
979 
980  if (prop->type)
981  GLSLA(" %s", prop->type);
982 
983  if (prop->dim_needed)
984  GLSLA("%iD", desc[i].dimensions);
985 
986  GLSLA(" %s", desc[i].name);
987 
988  if (prop->buf_content)
989  GLSLA(" {\n %s\n}", desc[i].buf_content);
990  else if (desc[i].elems > 0)
991  GLSLA("[%i]", desc[i].elems);
992 
993  GLSLA(";\n");
994  }
995  GLSLA("\n");
996 
997  return 0;
998 }
999 
1001  int set_id)
1002 {
1003  VulkanFilterContext *s = avctx->priv;
1004 
1005  vkUpdateDescriptorSetWithTemplate(s->hwctx->act_dev,
1006  pl->desc_set[set_id],
1007  pl->desc_template[set_id], s);
1008 }
1009 
1011  VkShaderStageFlagBits stage, int offset,
1012  size_t size, void *src)
1013 {
1014  vkCmdPushConstants(e->buf, e->bound_pl->pipeline_layout,
1015  stage, offset, size, src);
1016 }
1017 
1019 {
1020  VkResult ret;
1021  VulkanFilterContext *s = avctx->priv;
1022 
1023  { /* Init descriptor set pool */
1024  VkDescriptorPoolCreateInfo pool_create_info = {
1025  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1026  .poolSizeCount = pl->pool_size_desc_num,
1027  .pPoolSizes = pl->pool_size_desc,
1028  .maxSets = pl->descriptor_sets_num,
1029  };
1030 
1031  ret = vkCreateDescriptorPool(s->hwctx->act_dev, &pool_create_info,
1032  s->hwctx->alloc, &pl->desc_pool);
1033  av_freep(&pl->pool_size_desc);
1034  if (ret != VK_SUCCESS) {
1035  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
1036  "pool: %s\n", ff_vk_ret2str(ret));
1037  return AVERROR_EXTERNAL;
1038  }
1039  }
1040 
1041  { /* Allocate descriptor sets */
1042  VkDescriptorSetAllocateInfo alloc_info = {
1043  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1044  .descriptorPool = pl->desc_pool,
1045  .descriptorSetCount = pl->descriptor_sets_num,
1046  .pSetLayouts = pl->desc_layout,
1047  };
1048 
1049  pl->desc_set = av_malloc(pl->descriptor_sets_num*sizeof(*pl->desc_set));
1050  if (!pl->desc_set)
1051  return AVERROR(ENOMEM);
1052 
1053  ret = vkAllocateDescriptorSets(s->hwctx->act_dev, &alloc_info,
1054  pl->desc_set);
1055  if (ret != VK_SUCCESS) {
1056  av_log(avctx, AV_LOG_ERROR, "Unable to allocate descriptor set: %s\n",
1057  ff_vk_ret2str(ret));
1058  return AVERROR_EXTERNAL;
1059  }
1060  }
1061 
1062  { /* Finally create the pipeline layout */
1063  VkPipelineLayoutCreateInfo spawn_pipeline_layout = {
1064  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1065  .setLayoutCount = pl->descriptor_sets_num,
1066  .pSetLayouts = pl->desc_layout,
1067  .pushConstantRangeCount = pl->push_consts_num,
1068  .pPushConstantRanges = pl->push_consts,
1069  };
1070 
1071  ret = vkCreatePipelineLayout(s->hwctx->act_dev, &spawn_pipeline_layout,
1072  s->hwctx->alloc, &pl->pipeline_layout);
1073  av_freep(&pl->push_consts);
1074  pl->push_consts_num = 0;
1075  if (ret != VK_SUCCESS) {
1076  av_log(avctx, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n",
1077  ff_vk_ret2str(ret));
1078  return AVERROR_EXTERNAL;
1079  }
1080  }
1081 
1082  { /* Descriptor template (for tightly packed descriptors) */
1083  VkDescriptorUpdateTemplateCreateInfo *desc_template_info;
1084 
1085  pl->desc_template = av_malloc(pl->descriptor_sets_num*sizeof(*pl->desc_template));
1086  if (!pl->desc_template)
1087  return AVERROR(ENOMEM);
1088 
1089  /* Create update templates for the descriptor sets */
1090  for (int i = 0; i < pl->descriptor_sets_num; i++) {
1091  desc_template_info = &pl->desc_template_info[i];
1092  desc_template_info->pipelineLayout = pl->pipeline_layout;
1093  ret = vkCreateDescriptorUpdateTemplate(s->hwctx->act_dev,
1094  desc_template_info,
1095  s->hwctx->alloc,
1096  &pl->desc_template[i]);
1097  av_free((void *)desc_template_info->pDescriptorUpdateEntries);
1098  if (ret != VK_SUCCESS) {
1099  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor "
1100  "template: %s\n", ff_vk_ret2str(ret));
1101  return AVERROR_EXTERNAL;
1102  }
1103  }
1104 
1106  }
1107 
1108  return 0;
1109 }
1110 
1111 FN_CREATING(VulkanFilterContext, VulkanPipeline, pipeline, pipelines, pipelines_num)
1113 {
1114  return create_pipeline(avctx->priv);
1115 }
1116 
1118 {
1119  int i;
1120  VkResult ret;
1121  VulkanFilterContext *s = avctx->priv;
1122 
1123  VkComputePipelineCreateInfo pipe = {
1124  .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1125  .layout = pl->pipeline_layout,
1126  };
1127 
1128  for (i = 0; i < pl->shaders_num; i++) {
1129  if (pl->shaders[i]->shader.stage & VK_SHADER_STAGE_COMPUTE_BIT) {
1130  pipe.stage = pl->shaders[i]->shader;
1131  break;
1132  }
1133  }
1134  if (i == pl->shaders_num) {
1135  av_log(avctx, AV_LOG_ERROR, "Can't init compute pipeline, no shader\n");
1136  return AVERROR(EINVAL);
1137  }
1138 
1139  ret = vkCreateComputePipelines(s->hwctx->act_dev, VK_NULL_HANDLE, 1, &pipe,
1140  s->hwctx->alloc, &pl->pipeline);
1141  if (ret != VK_SUCCESS) {
1142  av_log(avctx, AV_LOG_ERROR, "Unable to init compute pipeline: %s\n",
1143  ff_vk_ret2str(ret));
1144  return AVERROR_EXTERNAL;
1145  }
1146 
1147  pl->bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
1148 
1149  return 0;
1150 }
1151 
1153  VulkanPipeline *pl)
1154 {
1155  vkCmdBindPipeline(e->buf, pl->bind_point, pl->pipeline);
1156 
1157  vkCmdBindDescriptorSets(e->buf, pl->bind_point, pl->pipeline_layout, 0,
1158  pl->descriptor_sets_num, pl->desc_set, 0, 0);
1159 
1160  e->bound_pl = pl;
1161 }
1162 
1164 {
1165  vkDestroyFence(s->hwctx->act_dev, e->fence, s->hwctx->alloc);
1166 
1167  if (e->buf != VK_NULL_HANDLE)
1168  vkFreeCommandBuffers(s->hwctx->act_dev, e->pool, 1, &e->buf);
1169  if (e->pool != VK_NULL_HANDLE)
1170  vkDestroyCommandPool(s->hwctx->act_dev, e->pool, s->hwctx->alloc);
1171 
1172  av_free(e->sem_wait);
1173  av_free(e->sem_wait_dst);
1174  av_free(e->sem_sig);
1175 
1176  av_free(e);
1177 }
1178 
1180 {
1181  for (int i = 0; i < pl->shaders_num; i++) {
1182  SPIRVShader *shd = pl->shaders[i];
1183  av_bprint_finalize(&shd->src, NULL);
1184  vkDestroyShaderModule(s->hwctx->act_dev, shd->shader.module,
1185  s->hwctx->alloc);
1186  av_free(shd);
1187  }
1188 
1189  vkDestroyPipeline(s->hwctx->act_dev, pl->pipeline, s->hwctx->alloc);
1190  vkDestroyPipelineLayout(s->hwctx->act_dev, pl->pipeline_layout,
1191  s->hwctx->alloc);
1192 
1193  for (int i = 0; i < pl->descriptor_sets_num; i++) {
1194  if (pl->desc_template && pl->desc_template[i])
1195  vkDestroyDescriptorUpdateTemplate(s->hwctx->act_dev, pl->desc_template[i],
1196  s->hwctx->alloc);
1197  if (pl->desc_layout && pl->desc_layout[i])
1198  vkDestroyDescriptorSetLayout(s->hwctx->act_dev, pl->desc_layout[i],
1199  s->hwctx->alloc);
1200  }
1201 
1202  /* Also frees the descriptor sets */
1203  if (pl->desc_pool)
1204  vkDestroyDescriptorPool(s->hwctx->act_dev, pl->desc_pool,
1205  s->hwctx->alloc);
1206 
1207  av_freep(&pl->desc_set);
1208  av_freep(&pl->shaders);
1209  av_freep(&pl->desc_layout);
1210  av_freep(&pl->desc_template);
1211  av_freep(&pl->push_consts);
1212  pl->push_consts_num = 0;
1213 
1214  /* Only freed in case of failure */
1215  av_freep(&pl->pool_size_desc);
1216  if (pl->desc_template_info) {
1217  for (int i = 0; i < pl->descriptor_sets_num; i++)
1218  av_free((void *)pl->desc_template_info[i].pDescriptorUpdateEntries);
1220  }
1221 
1222  av_free(pl);
1223 }
1224 
1226 {
1227  VulkanFilterContext *s = avctx->priv;
1228 
1229  glslang_uninit();
1230 
1231  for (int i = 0; i < s->samplers_num; i++)
1232  vkDestroySampler(s->hwctx->act_dev, *s->samplers[i], s->hwctx->alloc);
1233  av_freep(&s->samplers);
1234 
1235  for (int i = 0; i < s->pipelines_num; i++)
1236  free_pipeline(s, s->pipelines[i]);
1237  av_freep(&s->pipelines);
1238 
1239  for (int i = 0; i < s->exec_ctx_num; i++)
1240  free_exec_ctx(s, s->exec_ctx[i]);
1241  av_freep(&s->exec_ctx);
1242 
1243  av_freep(&s->scratch);
1244  s->scratch_size = 0;
1245 
1248 }
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
#define NULL
Definition: coverity.c:32
int ff_vk_add_exec_dep(AVFilterContext *avctx, FFVkExecContext *e, AVFrame *frame, VkPipelineStageFlagBits in_wait_dst_flag)
Adds a frame as a queue dependency.
Definition: vulkan.c:389
ptrdiff_t const GLvoid GLenum usage
Definition: opengl_enc.c:100
int sem_wait_cnt
Definition: vulkan.h:119
static enum AVPixelFormat pix_fmt
VkBuffer buf
Definition: vulkan.h:76
int ff_vk_init_pipeline_layout(AVFilterContext *avctx, VulkanPipeline *pl)
Initializes the pipeline layout after all shaders and descriptor sets have been finished.
Definition: vulkan.c:1018
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
version
Definition: libkvazaar.c:292
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:126
int ff_vk_add_descriptor_set(AVFilterContext *avctx, VulkanPipeline *pl, SPIRVShader *shd, VulkanDescriptorSetBinding *desc, int num, int only_print_to_shader)
Adds a descriptor set to the shader and registers them in the pipeline.
Definition: vulkan.c:860
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2549
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
void ff_vk_filter_uninit(AVFilterContext *avctx)
Definition: vulkan.c:1225
VkPipelineShaderStageCreateInfo shader
Definition: vulkan.h:59
static void flush(AVCodecContext *avctx)
VkSemaphore * sem_wait
Definition: vulkan.h:117
const char * ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt)
Gets the glsl format string for a pixel format.
Definition: vulkan.c:681
size_t struct_size
Definition: vulkan.c:840
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2589
int push_consts_num
Definition: vulkan.h:94
VkDescriptorPoolSize * pool_size_desc
Definition: vulkan.h:106
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
VkDescriptorUpdateTemplateCreateInfo * desc_template_info
Definition: vulkan.h:105
const char * desc
Definition: nvenc.c:68
int ff_vk_init_compute_pipeline(AVFilterContext *avctx, VulkanPipeline *pl)
Initializes a compute pipeline.
Definition: vulkan.c:1117
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:387
VkFence fence
Definition: vulkan.h:113
#define FN_CREATING(ctx, type, shortname, array, num)
Definition: vulkan.c:25
VkDescriptorUpdateTemplate * desc_template
Definition: vulkan.h:100
int sem_sig_cnt
Definition: vulkan.h:126
int ff_vk_filter_config_output(AVFilterLink *outlink)
Definition: vulkan.c:569
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
AVBufferRef * hw_device_ctx
For filters which will create hardware frames, sets the device the filter should create them in...
Definition: avfilter.h:394
VkDevice act_dev
Active device.
int ff_vk_start_exec_recording(AVFilterContext *avctx, FFVkExecContext *e)
Begin recording to the command buffer.
Definition: vulkan.c:368
VkCommandBuffer buf
Definition: vulkan.h:111
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:209
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:239
if it could not because there are no more frames
int shaders_num
Definition: vulkan.h:90
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame...
Definition: frame.h:634
VkPushConstantRange * push_consts
Definition: vulkan.h:93
size_t size
Definition: glslang.h:36
#define img
const char * name
Definition: vulkan.h:56
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
static int create_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, int queue_family_index)
VkPipelineStageFlagBits * sem_wait_dst
Definition: vulkan.h:121
int ff_vk_add_push_constant(AVFilterContext *avctx, VulkanPipeline *pl, int offset, int size, VkShaderStageFlagBits stage)
Define a push constant for a given stage into a pipeline.
Definition: vulkan.c:293
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
uint8_t
#define av_malloc(s)
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
#define f(width, name)
Definition: cbs_vp9.c:255
void ff_vk_set_compute_shader_sizes(AVFilterContext *avctx, SPIRVShader *shd, int local_size[3])
Writes the workgroup size for a shader.
Definition: vulkan.c:750
AVBPrint src
Definition: vulkan.h:57
AVBufferRef * frames_ref
Definition: vulkan.h:133
int sem_wait_dst_alloc
Definition: vulkan.h:122
int ff_vk_filter_init(AVFilterContext *avctx)
Definition: vulkan.c:620
static cqueue * cqueue_create(int size, int max_size)
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
VulkanPipeline * bound_pl
Definition: vulkan.h:115
ptrdiff_t size
Definition: opengl_enc.c:100
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:198
#define FFALIGN(x, a)
Definition: macros.h:48
#define av_log(a,...)
static int vk_alloc_mem(AVFilterContext *avctx, VkMemoryRequirements *req, VkMemoryPropertyFlagBits req_flags, void *alloc_extension, VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
Definition: vulkan.c:89
int ff_vk_unmap_buffers(AVFilterContext *avctx, FFVkBuffer *buf, int nb_buffers, int flush)
Unmaps the buffer from userspace.
Definition: vulkan.c:239
#define src
Definition: vp8dsp.c:254
#define fc(width, name, range_min, range_max)
Definition: cbs_av1.c:554
int sem_sig_alloc
Definition: vulkan.h:125
int ff_vk_filter_query_formats(AVFilterContext *avctx)
General lavfi IO functions.
Definition: vulkan.c:456
const VkSampler * samplers
Definition: vulkan.h:71
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
enum AVPixelFormat input_format
Definition: vulkan.h:141
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:569
#define AV_BPRINT_SIZE_UNLIMITED
const char * type
Definition: vulkan.c:841
int glslang_init(void)
Definition: glslang.cpp:224
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
void * priv
private data for use by the filter
Definition: avfilter.h:353
int ff_vk_create_buf(AVFilterContext *avctx, FFVkBuffer *buf, size_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
Create a VkBuffer with the specified parameters.
Definition: vulkan.c:150
Definition: graph2dot.c:48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:383
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:333
#define FFMAX(a, b)
Definition: common.h:94
unsigned int scratch_size
Definition: vulkan.h:156
#define fail()
Definition: checkasm.h:122
void glslang_uninit(void)
Definition: glslang.cpp:236
VulkanPipeline ** pipelines
Definition: vulkan.h:152
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
#define CASE(VAL)
static void free_pipeline(VulkanFilterContext *s, VulkanPipeline *pl)
Definition: vulkan.c:1179
int sem_wait_alloc
Definition: vulkan.h:118
AVBufferRef * device_ref
Definition: vulkan.h:132
VkSampler * ff_vk_init_sampler(AVFilterContext *avctx, int unnorm_coords, VkFilter filt)
Create a Vulkan sampler, will be auto-freed in ff_vk_filter_uninit()
Definition: vulkan.c:633
VkPipeline pipeline
Definition: vulkan.h:86
int ff_vk_submit_exec_queue(AVFilterContext *avctx, FFVkExecContext *e)
Submits a command buffer to the queue for execution.
Definition: vulkan.c:423
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
AVFormatContext * ctx
Definition: movenc.c:48
VkDescriptorSet * desc_set
Definition: vulkan.h:99
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
#define GLSLF(N, S,...)
Definition: vulkan.h:40
#define s(width, name)
Definition: cbs_vp9.c:257
void ff_vk_free_buf(AVFilterContext *avctx, FFVkBuffer *buf)
Frees a buffer.
Definition: vulkan.c:281
VkMemoryPropertyFlagBits flags
Definition: vulkan.h:78
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
Definition: mem.c:476
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
#define GLSLC(N, S)
Definition: vulkan.h:38
VkDescriptorType type
Definition: vulkan.h:64
void ff_vk_destroy_imageview(AVFilterContext *avctx, VkImageView *v)
Destroy an imageview.
Definition: vulkan.c:719
VkCommandPool pool
Definition: vulkan.h:110
void ff_vk_bind_pipeline_exec(AVFilterContext *avctx, FFVkExecContext *e, VulkanPipeline *pl)
Add a command to bind the completed pipeline and its descriptor sets.
Definition: vulkan.c:1152
if(ret)
GLSlangResult * glslang_compile(const char *glsl, enum GLSlangStage stage)
Definition: glslang.cpp:153
static int vulkan_filter_set_frames(AVFilterContext *avctx, AVBufferRef *frames)
Definition: vulkan.c:485
const VkComponentMapping ff_comp_identity_map
Definition: vulkan.c:44
GLuint shader
Definition: opengl_enc.c:115
static const struct @306 planes[]
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
int descriptor_sets_num
Definition: vulkan.h:101
int ff_vk_compile_shader(AVFilterContext *avctx, SPIRVShader *shd, const char *entrypoint)
Compiles the shader, entrypoint must be set to "main".
Definition: vulkan.c:783
uint8_t * data
The data buffer.
Definition: buffer.h:89
int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt)
Returns 1 if the image is any sort of supported RGB.
Definition: vulkan.c:669
const char * ff_vk_ret2str(VkResult res)
Converts Vulkan return values to strings.
Definition: vulkan.c:52
SPIRVShader * ff_vk_init_shader(AVFilterContext *avctx, VulkanPipeline *pl, const char *name, VkShaderStageFlags stage)
Inits a shader for a specific pipeline.
Definition: vulkan.c:729
VkDeviceMemory mem
Definition: vulkan.h:77
AVVulkanDeviceContext * hwctx
Definition: vulkan.h:135
#define GLSLA(...)
Definition: vulkan.h:39
int index
Definition: gxfenc.c:89
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
VulkanPipeline * ff_vk_create_pipeline(AVFilterContext *avctx)
Inits a pipeline.
Definition: vulkan.c:1112
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
VkShaderStageFlags stages
Definition: vulkan.h:70
const VDPAUPixFmtMap * map
VkPipelineLayout pipeline_layout
Definition: vulkan.h:85
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
#define AV_PIX_FMT_BGR565
Definition: pixfmt.h:389
static const int8_t filt[NUMTAPS]
Definition: af_earwax.c:39
#define flags(name, subs,...)
Definition: cbs_av1.c:564
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:141
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
void * data
Definition: glslang.h:35
A reference to a data buffer.
Definition: buffer.h:81
GLSlangStage
Definition: glslang.h:39
VkDescriptorSetLayout * desc_layout
Definition: vulkan.h:97
Vulkan hardware images.
Definition: pixfmt.h:356
int
VkSemaphore * sem_sig
Definition: vulkan.h:124
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Per-image semaphores.
int ff_vk_create_imageview(AVFilterContext *avctx, VkImageView *v, VkImage img, VkFormat fmt, const VkComponentMapping map)
Create an imageview.
Definition: vulkan.c:688
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:247
enum AVPixelFormat output_format
Definition: vulkan.h:140
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:94
int ff_vk_map_buffers(AVFilterContext *avctx, FFVkBuffer *buf, uint8_t *mem[], int nb_buffers, int invalidate)
Maps the buffer to userspace.
Definition: vulkan.c:190
void ff_vk_update_push_exec(AVFilterContext *avctx, FFVkExecContext *e, VkShaderStageFlagBits stage, int offset, size_t size, void *src)
Updates push constants.
Definition: vulkan.c:1010
int ff_vk_filter_config_output_inplace(AVFilterLink *outlink)
Definition: vulkan.c:539
#define av_free(p)
SPIRVShader ** shaders
Definition: vulkan.h:89
VkDescriptorPool desc_pool
Definition: vulkan.h:98
A list of supported formats for one end of a filter link.
Definition: formats.h:64
int ff_vk_filter_config_input(AVFilterLink *inlink)
Definition: vulkan.c:499
enum AVPixelFormat pixfmt
Definition: kmsgrab.c:202
VkPhysicalDevice phys_dev
Physical device.
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:384
An instance of a filter.
Definition: avfilter.h:338
VkQueue queue
Definition: vulkan.h:112
int ff_vk_create_exec_ctx(AVFilterContext *avctx, FFVkExecContext **ctx, int queue)
Init an execution context for command recording and queue submission.
Definition: vulkan.c:314
static void print_shader(AVFilterContext *avctx, SPIRVShader *shd, int prio)
Definition: vulkan.c:762
#define av_freep(p)
int pool_size_desc_num
Definition: vulkan.h:102
AVHWDeviceContext * device
Definition: vulkan.h:134
VkPipelineBindPoint bind_point
Definition: vulkan.h:82
int local_size[3]
Definition: vulkan.h:58
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
int depth
Number of bits in the component.
Definition: pixdesc.h:58
static void free_exec_ctx(VulkanFilterContext *s, FFVkExecContext *e)
Definition: vulkan.c:1163
FFVkExecContext ** exec_ctx
Definition: vulkan.h:148
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
VkSampler ** samplers
Definition: vulkan.h:144
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
static int vulkan_filter_set_device(AVFilterContext *avctx, AVBufferRef *device)
Definition: vulkan.c:468
static void print(AVTreeNode *t, int depth)
Definition: tree.c:44
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel layout
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
const char * name
Definition: opengl_enc.c:102
char * error_msg
Definition: glslang.h:33
void ff_vk_update_descriptor_set(AVFilterContext *avctx, VulkanPipeline *pl, int set_id)
Updates a descriptor set via the updaters defined.
Definition: vulkan.c:1000