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  int queue_family = s->queue_family_idx;
321  int nb_queues = s->queue_count;
322 
323  VkCommandPoolCreateInfo cqueue_create = {
324  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
325  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
326  .queueFamilyIndex = queue_family,
327  };
328  VkCommandBufferAllocateInfo cbuf_create = {
329  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
330  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
331  .commandBufferCount = nb_queues,
332  };
333 
334  e = create_exec_ctx(s);
335  if (!e)
336  return AVERROR(ENOMEM);
337 
338  e->queues = av_mallocz(nb_queues * sizeof(*e->queues));
339  if (!e->queues)
340  return AVERROR(ENOMEM);
341 
342  e->bufs = av_mallocz(nb_queues * sizeof(*e->bufs));
343  if (!e->bufs)
344  return AVERROR(ENOMEM);
345 
346  /* Create command pool */
347  ret = vkCreateCommandPool(s->hwctx->act_dev, &cqueue_create,
348  s->hwctx->alloc, &e->pool);
349  if (ret != VK_SUCCESS) {
350  av_log(avctx, AV_LOG_ERROR, "Command pool creation failure: %s\n",
351  ff_vk_ret2str(ret));
352  return AVERROR_EXTERNAL;
353  }
354 
355  cbuf_create.commandPool = e->pool;
356 
357  /* Allocate command buffer */
358  ret = vkAllocateCommandBuffers(s->hwctx->act_dev, &cbuf_create, e->bufs);
359  if (ret != VK_SUCCESS) {
360  av_log(avctx, AV_LOG_ERROR, "Command buffer alloc failure: %s\n",
361  ff_vk_ret2str(ret));
362  return AVERROR_EXTERNAL;
363  }
364 
365  for (int i = 0; i < nb_queues; i++) {
366  FFVkQueueCtx *q = &e->queues[i];
367  vkGetDeviceQueue(s->hwctx->act_dev, queue_family, i, &q->queue);
368  }
369 
370  *ctx = e;
371 
372  return 0;
373 }
374 
376 {
377  VulkanFilterContext *s = avctx->priv;
378  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
379 
380  for (int j = 0; j < q->nb_buf_deps; j++)
381  av_buffer_unref(&q->buf_deps[j]);
382  q->nb_buf_deps = 0;
383 
384  for (int j = 0; j < q->nb_frame_deps; j++)
385  av_frame_free(&q->frame_deps[j]);
386  q->nb_frame_deps = 0;
387 
388  e->sem_wait_cnt = 0;
389  e->sem_sig_cnt = 0;
390 }
391 
393 {
394  VkResult ret;
395  VulkanFilterContext *s = avctx->priv;
396  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
397 
398  VkCommandBufferBeginInfo cmd_start = {
399  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
400  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
401  };
402 
403  /* Create the fence and don't wait for it initially */
404  if (!q->fence) {
405  VkFenceCreateInfo fence_spawn = {
406  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
407  };
408  ret = vkCreateFence(s->hwctx->act_dev, &fence_spawn, s->hwctx->alloc,
409  &q->fence);
410  if (ret != VK_SUCCESS) {
411  av_log(avctx, AV_LOG_ERROR, "Failed to queue frame fence: %s\n",
412  ff_vk_ret2str(ret));
413  return AVERROR_EXTERNAL;
414  }
415  } else {
416  vkWaitForFences(s->hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
417  vkResetFences(s->hwctx->act_dev, 1, &q->fence);
418  }
419 
420  /* Discard queue dependencies */
421  ff_vk_discard_exec_deps(avctx, e);
422 
423  ret = vkBeginCommandBuffer(e->bufs[s->cur_queue_idx], &cmd_start);
424  if (ret != VK_SUCCESS) {
425  av_log(avctx, AV_LOG_ERROR, "Failed to start command recoding: %s\n",
426  ff_vk_ret2str(ret));
427  return AVERROR_EXTERNAL;
428  }
429 
430  return 0;
431 }
432 
434 {
435  VulkanFilterContext *s = avctx->priv;
436  return e->bufs[s->cur_queue_idx];
437 }
438 
440  AVFrame *frame, VkPipelineStageFlagBits in_wait_dst_flag)
441 {
442  AVFrame **dst;
443  VulkanFilterContext *s = avctx->priv;
444  AVVkFrame *f = (AVVkFrame *)frame->data[0];
445  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
447  int planes = av_pix_fmt_count_planes(fc->sw_format);
448 
449  for (int i = 0; i < planes; i++) {
451  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait));
452  if (!e->sem_wait) {
453  ff_vk_discard_exec_deps(avctx, e);
454  return AVERROR(ENOMEM);
455  }
456 
458  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait_dst));
459  if (!e->sem_wait_dst) {
460  ff_vk_discard_exec_deps(avctx, e);
461  return AVERROR(ENOMEM);
462  }
463 
465  (e->sem_sig_cnt + 1)*sizeof(*e->sem_sig));
466  if (!e->sem_sig) {
467  ff_vk_discard_exec_deps(avctx, e);
468  return AVERROR(ENOMEM);
469  }
470 
471  e->sem_wait[e->sem_wait_cnt] = f->sem[i];
472  e->sem_wait_dst[e->sem_wait_cnt] = in_wait_dst_flag;
473  e->sem_wait_cnt++;
474 
475  e->sem_sig[e->sem_sig_cnt] = f->sem[i];
476  e->sem_sig_cnt++;
477  }
478 
479  dst = av_fast_realloc(q->frame_deps, &q->frame_deps_alloc_size,
480  (q->nb_frame_deps + 1) * sizeof(*dst));
481  if (!dst) {
482  ff_vk_discard_exec_deps(avctx, e);
483  return AVERROR(ENOMEM);
484  }
485 
486  q->frame_deps = dst;
487  q->frame_deps[q->nb_frame_deps] = av_frame_clone(frame);
488  if (!q->frame_deps[q->nb_frame_deps]) {
489  ff_vk_discard_exec_deps(avctx, e);
490  return AVERROR(ENOMEM);
491  }
492  q->nb_frame_deps++;
493 
494  return 0;
495 }
496 
498 {
499  VkResult ret;
500  VulkanFilterContext *s = avctx->priv;
501  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
502 
503  VkSubmitInfo s_info = {
504  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
505  .commandBufferCount = 1,
506  .pCommandBuffers = &e->bufs[s->cur_queue_idx],
507 
508  .pWaitSemaphores = e->sem_wait,
509  .pWaitDstStageMask = e->sem_wait_dst,
510  .waitSemaphoreCount = e->sem_wait_cnt,
511 
512  .pSignalSemaphores = e->sem_sig,
513  .signalSemaphoreCount = e->sem_sig_cnt,
514  };
515 
516  ret = vkEndCommandBuffer(e->bufs[s->cur_queue_idx]);
517  if (ret != VK_SUCCESS) {
518  av_log(avctx, AV_LOG_ERROR, "Unable to finish command buffer: %s\n",
519  ff_vk_ret2str(ret));
520  return AVERROR_EXTERNAL;
521  }
522 
523  ret = vkQueueSubmit(q->queue, 1, &s_info, q->fence);
524  if (ret != VK_SUCCESS) {
525  av_log(avctx, AV_LOG_ERROR, "Unable to submit command buffer: %s\n",
526  ff_vk_ret2str(ret));
527  return AVERROR_EXTERNAL;
528  }
529 
530  /* Rotate queues */
531  s->cur_queue_idx = (s->cur_queue_idx + 1) % s->queue_count;
532 
533  return 0;
534 }
535 
537  AVBufferRef **deps, int nb_deps)
538 {
539  AVBufferRef **dst;
540  VulkanFilterContext *s = avctx->priv;
541  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
542 
543  if (!deps || !nb_deps)
544  return 0;
545 
547  (q->nb_buf_deps + nb_deps) * sizeof(*dst));
548  if (!dst)
549  goto err;
550 
551  q->buf_deps = dst;
552 
553  for (int i = 0; i < nb_deps; i++) {
554  q->buf_deps[q->nb_buf_deps] = deps[i];
555  if (!q->buf_deps[q->nb_buf_deps])
556  goto err;
557  q->nb_buf_deps++;
558  }
559 
560  return 0;
561 
562 err:
563  ff_vk_discard_exec_deps(avctx, e);
564  return AVERROR(ENOMEM);
565 }
566 
568 {
569  static const enum AVPixelFormat pixel_formats[] = {
571  };
572  AVFilterFormats *pix_fmts = ff_make_format_list(pixel_formats);
573  if (!pix_fmts)
574  return AVERROR(ENOMEM);
575 
576  return ff_set_common_formats(avctx, pix_fmts);
577 }
578 
580  AVBufferRef *device)
581 {
582  VulkanFilterContext *s = avctx->priv;
583 
585 
586  s->device_ref = av_buffer_ref(device);
587  if (!s->device_ref)
588  return AVERROR(ENOMEM);
589 
591  s->hwctx = s->device->hwctx;
592 
593  return 0;
594 }
595 
598 {
599  VulkanFilterContext *s = avctx->priv;
600 
602 
603  s->frames_ref = av_buffer_ref(frames);
604  if (!s->frames_ref)
605  return AVERROR(ENOMEM);
606 
607  return 0;
608 }
609 
611 {
612  int err;
613  AVFilterContext *avctx = inlink->dst;
614  VulkanFilterContext *s = avctx->priv;
615  AVHWFramesContext *input_frames;
616 
617  if (!inlink->hw_frames_ctx) {
618  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
619  "hardware frames context on the input.\n");
620  return AVERROR(EINVAL);
621  }
622 
623  /* Extract the device and default output format from the first input. */
624  if (avctx->inputs[0] != inlink)
625  return 0;
626 
627  input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
628  if (input_frames->format != AV_PIX_FMT_VULKAN)
629  return AVERROR(EINVAL);
630 
631  err = vulkan_filter_set_device(avctx, input_frames->device_ref);
632  if (err < 0)
633  return err;
634  err = vulkan_filter_set_frames(avctx, inlink->hw_frames_ctx);
635  if (err < 0)
636  return err;
637 
638  /* Default output parameters match input parameters. */
639  s->input_format = input_frames->sw_format;
640  if (s->output_format == AV_PIX_FMT_NONE)
641  s->output_format = input_frames->sw_format;
642  if (!s->output_width)
643  s->output_width = inlink->w;
644  if (!s->output_height)
645  s->output_height = inlink->h;
646 
647  return 0;
648 }
649 
651 {
652  int err;
653  AVFilterContext *avctx = outlink->src;
654  VulkanFilterContext *s = avctx->priv;
655 
656  av_buffer_unref(&outlink->hw_frames_ctx);
657 
658  if (!s->device_ref) {
659  if (!avctx->hw_device_ctx) {
660  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
661  "Vulkan device.\n");
662  return AVERROR(EINVAL);
663  }
664 
665  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
666  if (err < 0)
667  return err;
668  }
669 
670  outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref);
671  if (!outlink->hw_frames_ctx)
672  return AVERROR(ENOMEM);
673 
674  outlink->w = s->output_width;
675  outlink->h = s->output_height;
676 
677  return 0;
678 }
679 
681 {
682  int err;
683  AVFilterContext *avctx = outlink->src;
684  VulkanFilterContext *s = avctx->priv;
685  AVBufferRef *output_frames_ref;
686  AVHWFramesContext *output_frames;
687 
688  av_buffer_unref(&outlink->hw_frames_ctx);
689 
690  if (!s->device_ref) {
691  if (!avctx->hw_device_ctx) {
692  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
693  "Vulkan device.\n");
694  return AVERROR(EINVAL);
695  }
696 
697  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
698  if (err < 0)
699  return err;
700  }
701 
702  output_frames_ref = av_hwframe_ctx_alloc(s->device_ref);
703  if (!output_frames_ref) {
704  err = AVERROR(ENOMEM);
705  goto fail;
706  }
707  output_frames = (AVHWFramesContext*)output_frames_ref->data;
708 
709  output_frames->format = AV_PIX_FMT_VULKAN;
710  output_frames->sw_format = s->output_format;
711  output_frames->width = s->output_width;
712  output_frames->height = s->output_height;
713 
714  err = av_hwframe_ctx_init(output_frames_ref);
715  if (err < 0) {
716  av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
717  "frames: %d.\n", err);
718  goto fail;
719  }
720 
721  outlink->hw_frames_ctx = output_frames_ref;
722  outlink->w = s->output_width;
723  outlink->h = s->output_height;
724 
725  return 0;
726 fail:
727  av_buffer_unref(&output_frames_ref);
728  return err;
729 }
730 
732 {
733  VulkanFilterContext *s = avctx->priv;
734 
736 
737  if (glslang_init())
738  return AVERROR_EXTERNAL;
739 
740  return 0;
741 }
742 
743 FN_CREATING(VulkanFilterContext, VkSampler, sampler, samplers, samplers_num)
744 VkSampler *ff_vk_init_sampler(AVFilterContext *avctx, int unnorm_coords,
745  VkFilter filt)
746 {
747  VkResult ret;
748  VulkanFilterContext *s = avctx->priv;
749 
750  VkSamplerCreateInfo sampler_info = {
751  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
752  .magFilter = filt,
753  .minFilter = sampler_info.magFilter,
754  .mipmapMode = unnorm_coords ? VK_SAMPLER_MIPMAP_MODE_NEAREST :
755  VK_SAMPLER_MIPMAP_MODE_LINEAR,
756  .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
757  .addressModeV = sampler_info.addressModeU,
758  .addressModeW = sampler_info.addressModeU,
759  .anisotropyEnable = VK_FALSE,
760  .compareOp = VK_COMPARE_OP_NEVER,
761  .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
762  .unnormalizedCoordinates = unnorm_coords,
763  };
764 
765  VkSampler *sampler = create_sampler(s);
766  if (!sampler)
767  return NULL;
768 
769  ret = vkCreateSampler(s->hwctx->act_dev, &sampler_info,
770  s->hwctx->alloc, sampler);
771  if (ret != VK_SUCCESS) {
772  av_log(avctx, AV_LOG_ERROR, "Unable to init sampler: %s\n",
773  ff_vk_ret2str(ret));
774  return NULL;
775  }
776 
777  return sampler;
778 }
779 
781 {
782  if (pix_fmt == AV_PIX_FMT_ABGR || pix_fmt == AV_PIX_FMT_BGRA ||
783  pix_fmt == AV_PIX_FMT_RGBA || pix_fmt == AV_PIX_FMT_RGB24 ||
784  pix_fmt == AV_PIX_FMT_BGR24 || pix_fmt == AV_PIX_FMT_RGB48 ||
785  pix_fmt == AV_PIX_FMT_RGBA64 || pix_fmt == AV_PIX_FMT_RGB565 ||
786  pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_BGR0 ||
787  pix_fmt == AV_PIX_FMT_0BGR || pix_fmt == AV_PIX_FMT_RGB0)
788  return 1;
789  return 0;
790 }
791 
793 {
795  const int high = desc->comp[0].depth > 8;
796  return high ? "rgba16f" : "rgba8";
797 }
798 
799 typedef struct ImageViewCtx {
800  VkImageView view;
801 } ImageViewCtx;
802 
803 static void destroy_imageview(void *opaque, uint8_t *data)
804 {
805  VulkanFilterContext *s = opaque;
806  ImageViewCtx *iv = (ImageViewCtx *)data;
807  vkDestroyImageView(s->hwctx->act_dev, iv->view, s->hwctx->alloc);
808  av_free(iv);
809 }
810 
812  VkImageView *v, VkImage img, VkFormat fmt,
813  const VkComponentMapping map)
814 {
815  int err;
816  AVBufferRef *buf;
817  VulkanFilterContext *s = avctx->priv;
818  VkImageViewCreateInfo imgview_spawn = {
819  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
820  .pNext = NULL,
821  .image = img,
822  .viewType = VK_IMAGE_VIEW_TYPE_2D,
823  .format = fmt,
824  .components = map,
825  .subresourceRange = {
826  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
827  .baseMipLevel = 0,
828  .levelCount = 1,
829  .baseArrayLayer = 0,
830  .layerCount = 1,
831  },
832  };
833 
834  ImageViewCtx *iv = av_mallocz(sizeof(*iv));
835 
836  VkResult ret = vkCreateImageView(s->hwctx->act_dev, &imgview_spawn,
837  s->hwctx->alloc, &iv->view);
838  if (ret != VK_SUCCESS) {
839  av_log(avctx, AV_LOG_ERROR, "Failed to create imageview: %s\n",
840  ff_vk_ret2str(ret));
841  return AVERROR_EXTERNAL;
842  }
843 
844  buf = av_buffer_create((uint8_t *)iv, sizeof(*iv), destroy_imageview, s, 0);
845  if (!buf) {
846  destroy_imageview(s, (uint8_t *)iv);
847  return AVERROR(ENOMEM);
848  }
849 
850  /* Add to queue dependencies */
851  err = ff_vk_add_dep_exec_ctx(avctx, e, &buf, 1);
852  if (err) {
853  av_buffer_unref(&buf);
854  return err;
855  }
856 
857  *v = iv->view;
858 
859  return 0;
860 }
861 
862 FN_CREATING(VulkanPipeline, SPIRVShader, shader, shaders, shaders_num)
864  const char *name, VkShaderStageFlags stage)
865 {
866  SPIRVShader *shd = create_shader(pl);
867  if (!shd)
868  return NULL;
869 
871 
872  shd->shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
873  shd->shader.stage = stage;
874 
875  shd->name = name;
876 
877  GLSLF(0, #version %i ,460);
878  GLSLC(0, #define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y)) );
879  GLSLC(0, );
880 
881  return shd;
882 }
883 
885  int local_size[3])
886 {
887  shd->local_size[0] = local_size[0];
888  shd->local_size[1] = local_size[1];
889  shd->local_size[2] = local_size[2];
890 
891  av_bprintf(&shd->src, "layout (local_size_x = %i, "
892  "local_size_y = %i, local_size_z = %i) in;\n\n",
893  shd->local_size[0], shd->local_size[1], shd->local_size[2]);
894 }
895 
896 static void print_shader(AVFilterContext *avctx, SPIRVShader *shd, int prio)
897 {
898  int line = 0;
899  const char *p = shd->src.str;
900  const char *start = p;
901 
902  AVBPrint buf;
904 
905  for (int i = 0; i < strlen(p); i++) {
906  if (p[i] == '\n') {
907  av_bprintf(&buf, "%i\t", ++line);
908  av_bprint_append_data(&buf, start, &p[i] - start + 1);
909  start = &p[i + 1];
910  }
911  }
912 
913  av_log(avctx, prio, "Shader %s: \n%s", shd->name, buf.str);
914  av_bprint_finalize(&buf, NULL);
915 }
916 
918  const char *entrypoint)
919 {
920  VkResult ret;
921  VulkanFilterContext *s = avctx->priv;
922  VkShaderModuleCreateInfo shader_create;
923  GLSlangResult *res;
924 
925  static const enum GLSlangStage emap[] = {
926  [VK_SHADER_STAGE_VERTEX_BIT] = GLSLANG_VERTEX,
927  [VK_SHADER_STAGE_FRAGMENT_BIT] = GLSLANG_FRAGMENT,
928  [VK_SHADER_STAGE_COMPUTE_BIT] = GLSLANG_COMPUTE,
929  };
930 
931  shd->shader.pName = entrypoint;
932 
933  res = glslang_compile(shd->src.str, emap[shd->shader.stage]);
934  if (!res)
935  return AVERROR(ENOMEM);
936 
937  if (res->rval) {
938  av_log(avctx, AV_LOG_ERROR, "Error compiling shader %s: %s!\n",
939  shd->name, av_err2str(res->rval));
940  print_shader(avctx, shd, AV_LOG_ERROR);
941  if (res->error_msg)
942  av_log(avctx, AV_LOG_ERROR, "%s", res->error_msg);
943  av_free(res->error_msg);
944  return res->rval;
945  }
946 
947  print_shader(avctx, shd, AV_LOG_VERBOSE);
948 
949  shader_create.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
950  shader_create.pNext = NULL;
951  shader_create.codeSize = res->size;
952  shader_create.flags = 0;
953  shader_create.pCode = res->data;
954 
955  ret = vkCreateShaderModule(s->hwctx->act_dev, &shader_create, NULL,
956  &shd->shader.module);
957 
958  /* Free the GLSlangResult struct */
959  av_free(res->data);
960  av_free(res);
961 
962  if (ret != VK_SUCCESS) {
963  av_log(avctx, AV_LOG_ERROR, "Unable to create shader module: %s\n",
964  ff_vk_ret2str(ret));
965  return AVERROR_EXTERNAL;
966  }
967 
968  av_log(avctx, AV_LOG_VERBOSE, "Shader %s linked! Size: %zu bytes\n",
969  shd->name, shader_create.codeSize);
970 
971  return 0;
972 }
973 
974 static const struct descriptor_props {
975  size_t struct_size; /* Size of the opaque which updates the descriptor */
976  const char *type;
978  int mem_quali; /* Can use a memory qualifier */
979  int dim_needed; /* Must indicate dimension */
980  int buf_content; /* Must indicate buffer contents */
981 } descriptor_props[] = {
982  [VK_DESCRIPTOR_TYPE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 0, 0, },
983  [VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] = { sizeof(VkDescriptorImageInfo), "texture", 1, 0, 1, 0, },
984  [VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] = { sizeof(VkDescriptorImageInfo), "image", 1, 1, 1, 0, },
985  [VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] = { sizeof(VkDescriptorImageInfo), "subpassInput", 1, 0, 0, 0, },
986  [VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 1, 0, },
987  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
988  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
989  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
990  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
991  [VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] = { sizeof(VkBufferView), "samplerBuffer", 1, 0, 0, 0, },
992  [VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER] = { sizeof(VkBufferView), "imageBuffer", 1, 0, 0, 0, },
993 };
994 
997  int num, int only_print_to_shader)
998 {
999  VkResult ret;
1000  VkDescriptorSetLayout *layout;
1001  VulkanFilterContext *s = avctx->priv;
1002 
1003  if (only_print_to_shader)
1004  goto print;
1005 
1006  pl->desc_layout = av_realloc_array(pl->desc_layout, sizeof(*pl->desc_layout),
1007  pl->desc_layout_num + 1);
1008  if (!pl->desc_layout)
1009  return AVERROR(ENOMEM);
1010 
1011  layout = &pl->desc_layout[pl->desc_layout_num];
1012  memset(layout, 0, sizeof(*layout));
1013 
1014  { /* Create descriptor set layout descriptions */
1015  VkDescriptorSetLayoutCreateInfo desc_create_layout = { 0 };
1016  VkDescriptorSetLayoutBinding *desc_binding;
1017 
1018  desc_binding = av_mallocz(sizeof(*desc_binding)*num);
1019  if (!desc_binding)
1020  return AVERROR(ENOMEM);
1021 
1022  for (int i = 0; i < num; i++) {
1023  desc_binding[i].binding = i;
1024  desc_binding[i].descriptorType = desc[i].type;
1025  desc_binding[i].descriptorCount = FFMAX(desc[i].elems, 1);
1026  desc_binding[i].stageFlags = desc[i].stages;
1027  desc_binding[i].pImmutableSamplers = desc[i].samplers;
1028  }
1029 
1030  desc_create_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
1031  desc_create_layout.pBindings = desc_binding;
1032  desc_create_layout.bindingCount = num;
1033 
1034  ret = vkCreateDescriptorSetLayout(s->hwctx->act_dev, &desc_create_layout,
1035  s->hwctx->alloc, layout);
1036  av_free(desc_binding);
1037  if (ret != VK_SUCCESS) {
1038  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
1039  "layout: %s\n", ff_vk_ret2str(ret));
1040  return AVERROR_EXTERNAL;
1041  }
1042  }
1043 
1044  { /* Pool each descriptor by type and update pool counts */
1045  for (int i = 0; i < num; i++) {
1046  int j;
1047  for (j = 0; j < pl->pool_size_desc_num; j++)
1048  if (pl->pool_size_desc[j].type == desc[i].type)
1049  break;
1050  if (j >= pl->pool_size_desc_num) {
1052  sizeof(*pl->pool_size_desc),
1053  ++pl->pool_size_desc_num);
1054  if (!pl->pool_size_desc)
1055  return AVERROR(ENOMEM);
1056  memset(&pl->pool_size_desc[j], 0, sizeof(VkDescriptorPoolSize));
1057  }
1058  pl->pool_size_desc[j].type = desc[i].type;
1059  pl->pool_size_desc[j].descriptorCount += FFMAX(desc[i].elems, 1);
1060  }
1061  }
1062 
1063  { /* Create template creation struct */
1064  VkDescriptorUpdateTemplateCreateInfo *dt;
1065  VkDescriptorUpdateTemplateEntry *des_entries;
1066 
1067  /* Freed after descriptor set initialization */
1068  des_entries = av_mallocz(num*sizeof(VkDescriptorUpdateTemplateEntry));
1069  if (!des_entries)
1070  return AVERROR(ENOMEM);
1071 
1072  for (int i = 0; i < num; i++) {
1073  des_entries[i].dstBinding = i;
1074  des_entries[i].descriptorType = desc[i].type;
1075  des_entries[i].descriptorCount = FFMAX(desc[i].elems, 1);
1076  des_entries[i].dstArrayElement = 0;
1077  des_entries[i].offset = ((uint8_t *)desc[i].updater) - (uint8_t *)s;
1078  des_entries[i].stride = descriptor_props[desc[i].type].struct_size;
1079  }
1080 
1082  sizeof(*pl->desc_template_info),
1083  pl->desc_layout_num + 1);
1084  if (!pl->desc_template_info)
1085  return AVERROR(ENOMEM);
1086 
1087  dt = &pl->desc_template_info[pl->desc_layout_num];
1088  memset(dt, 0, sizeof(*dt));
1089 
1090  dt->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO;
1091  dt->templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
1092  dt->descriptorSetLayout = *layout;
1093  dt->pDescriptorUpdateEntries = des_entries;
1094  dt->descriptorUpdateEntryCount = num;
1095  }
1096 
1097  pl->desc_layout_num++;
1098 
1099 print:
1100  /* Write shader info */
1101  for (int i = 0; i < num; i++) {
1102  const struct descriptor_props *prop = &descriptor_props[desc[i].type];
1103  GLSLA("layout (set = %i, binding = %i", pl->desc_layout_num - 1, i);
1104 
1105  if (desc[i].mem_layout)
1106  GLSLA(", %s", desc[i].mem_layout);
1107  GLSLA(")");
1108 
1109  if (prop->is_uniform)
1110  GLSLA(" uniform");
1111 
1112  if (prop->mem_quali && desc[i].mem_quali)
1113  GLSLA(" %s", desc[i].mem_quali);
1114 
1115  if (prop->type)
1116  GLSLA(" %s", prop->type);
1117 
1118  if (prop->dim_needed)
1119  GLSLA("%iD", desc[i].dimensions);
1120 
1121  GLSLA(" %s", desc[i].name);
1122 
1123  if (prop->buf_content)
1124  GLSLA(" {\n %s\n}", desc[i].buf_content);
1125  else if (desc[i].elems > 0)
1126  GLSLA("[%i]", desc[i].elems);
1127 
1128  GLSLA(";\n");
1129  }
1130  GLSLA("\n");
1131 
1132  return 0;
1133 }
1134 
1136  int set_id)
1137 {
1138  VulkanFilterContext *s = avctx->priv;
1139 
1140  vkUpdateDescriptorSetWithTemplate(s->hwctx->act_dev,
1141  pl->desc_set[set_id * s->cur_queue_idx],
1142  pl->desc_template[set_id],
1143  s);
1144 }
1145 
1147  VkShaderStageFlagBits stage, int offset,
1148  size_t size, void *src)
1149 {
1150  VulkanFilterContext *s = avctx->priv;
1151  vkCmdPushConstants(e->bufs[s->cur_queue_idx], e->bound_pl->pipeline_layout,
1152  stage, offset, size, src);
1153 }
1154 
1156 {
1157  VkResult ret;
1158  VulkanFilterContext *s = avctx->priv;
1159 
1160  int queues_count = 1;
1161 
1162  pl->descriptor_sets_num = pl->desc_layout_num * queues_count;
1163 
1164  { /* Init descriptor set pool */
1165  VkDescriptorPoolCreateInfo pool_create_info = {
1166  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1167  .poolSizeCount = pl->pool_size_desc_num,
1168  .pPoolSizes = pl->pool_size_desc,
1169  .maxSets = pl->descriptor_sets_num,
1170  };
1171 
1172  ret = vkCreateDescriptorPool(s->hwctx->act_dev, &pool_create_info,
1173  s->hwctx->alloc, &pl->desc_pool);
1174  av_freep(&pl->pool_size_desc);
1175  if (ret != VK_SUCCESS) {
1176  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
1177  "pool: %s\n", ff_vk_ret2str(ret));
1178  return AVERROR_EXTERNAL;
1179  }
1180  }
1181 
1182  { /* Allocate descriptor sets */
1183  VkDescriptorSetAllocateInfo alloc_info = {
1184  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1185  .descriptorPool = pl->desc_pool,
1186  .descriptorSetCount = pl->descriptor_sets_num,
1187  .pSetLayouts = pl->desc_layout,
1188  };
1189 
1190  pl->desc_set = av_malloc(pl->descriptor_sets_num*sizeof(*pl->desc_set));
1191  if (!pl->desc_set)
1192  return AVERROR(ENOMEM);
1193 
1194  ret = vkAllocateDescriptorSets(s->hwctx->act_dev, &alloc_info,
1195  pl->desc_set);
1196  if (ret != VK_SUCCESS) {
1197  av_log(avctx, AV_LOG_ERROR, "Unable to allocate descriptor set: %s\n",
1198  ff_vk_ret2str(ret));
1199  return AVERROR_EXTERNAL;
1200  }
1201  }
1202 
1203  { /* Finally create the pipeline layout */
1204  VkPipelineLayoutCreateInfo spawn_pipeline_layout = {
1205  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1206  .setLayoutCount = pl->desc_layout_num,
1207  .pSetLayouts = pl->desc_layout,
1208  .pushConstantRangeCount = pl->push_consts_num,
1209  .pPushConstantRanges = pl->push_consts,
1210  };
1211 
1212  ret = vkCreatePipelineLayout(s->hwctx->act_dev, &spawn_pipeline_layout,
1213  s->hwctx->alloc, &pl->pipeline_layout);
1214  av_freep(&pl->push_consts);
1215  pl->push_consts_num = 0;
1216  if (ret != VK_SUCCESS) {
1217  av_log(avctx, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n",
1218  ff_vk_ret2str(ret));
1219  return AVERROR_EXTERNAL;
1220  }
1221  }
1222 
1223  { /* Descriptor template (for tightly packed descriptors) */
1224  VkDescriptorUpdateTemplateCreateInfo *desc_template_info;
1225 
1226  pl->desc_template = av_malloc(pl->descriptor_sets_num*sizeof(*pl->desc_template));
1227  if (!pl->desc_template)
1228  return AVERROR(ENOMEM);
1229 
1230  /* Create update templates for the descriptor sets */
1231  for (int i = 0; i < pl->descriptor_sets_num; i++) {
1232  desc_template_info = &pl->desc_template_info[i % pl->desc_layout_num];
1233  desc_template_info->pipelineLayout = pl->pipeline_layout;
1234  ret = vkCreateDescriptorUpdateTemplate(s->hwctx->act_dev,
1235  desc_template_info,
1236  s->hwctx->alloc,
1237  &pl->desc_template[i]);
1238  av_free((void *)desc_template_info->pDescriptorUpdateEntries);
1239  if (ret != VK_SUCCESS) {
1240  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor "
1241  "template: %s\n", ff_vk_ret2str(ret));
1242  return AVERROR_EXTERNAL;
1243  }
1244  }
1245 
1247  }
1248 
1249  return 0;
1250 }
1251 
1252 FN_CREATING(VulkanFilterContext, VulkanPipeline, pipeline, pipelines, pipelines_num)
1254 {
1255  return create_pipeline(avctx->priv);
1256 }
1257 
1259 {
1260  int i;
1261  VkResult ret;
1262  VulkanFilterContext *s = avctx->priv;
1263 
1264  VkComputePipelineCreateInfo pipe = {
1265  .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1266  .layout = pl->pipeline_layout,
1267  };
1268 
1269  for (i = 0; i < pl->shaders_num; i++) {
1270  if (pl->shaders[i]->shader.stage & VK_SHADER_STAGE_COMPUTE_BIT) {
1271  pipe.stage = pl->shaders[i]->shader;
1272  break;
1273  }
1274  }
1275  if (i == pl->shaders_num) {
1276  av_log(avctx, AV_LOG_ERROR, "Can't init compute pipeline, no shader\n");
1277  return AVERROR(EINVAL);
1278  }
1279 
1280  ret = vkCreateComputePipelines(s->hwctx->act_dev, VK_NULL_HANDLE, 1, &pipe,
1281  s->hwctx->alloc, &pl->pipeline);
1282  if (ret != VK_SUCCESS) {
1283  av_log(avctx, AV_LOG_ERROR, "Unable to init compute pipeline: %s\n",
1284  ff_vk_ret2str(ret));
1285  return AVERROR_EXTERNAL;
1286  }
1287 
1288  pl->bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
1289 
1290  return 0;
1291 }
1292 
1294  VulkanPipeline *pl)
1295 {
1296  VulkanFilterContext *s = avctx->priv;
1297 
1298  vkCmdBindPipeline(e->bufs[s->cur_queue_idx], pl->bind_point, pl->pipeline);
1299 
1300  vkCmdBindDescriptorSets(e->bufs[s->cur_queue_idx], pl->bind_point,
1302  pl->desc_set, 0, 0);
1303 
1304  e->bound_pl = pl;
1305 }
1306 
1308 {
1309  /* Make sure all queues have finished executing */
1310  for (int i = 0; i < s->queue_count; i++) {
1311  FFVkQueueCtx *q = &e->queues[i];
1312 
1313  if (q->fence) {
1314  vkWaitForFences(s->hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
1315  vkResetFences(s->hwctx->act_dev, 1, &q->fence);
1316  }
1317 
1318  /* Free the fence */
1319  if (q->fence)
1320  vkDestroyFence(s->hwctx->act_dev, q->fence, s->hwctx->alloc);
1321 
1322  /* Free buffer dependencies */
1323  for (int j = 0; j < q->nb_buf_deps; j++)
1324  av_buffer_unref(&q->buf_deps[j]);
1325  av_free(q->buf_deps);
1326 
1327  /* Free frame dependencies */
1328  for (int j = 0; j < q->nb_frame_deps; j++)
1329  av_frame_free(&q->frame_deps[j]);
1330  av_free(q->frame_deps);
1331  }
1332 
1333  if (e->bufs)
1334  vkFreeCommandBuffers(s->hwctx->act_dev, e->pool, s->queue_count, e->bufs);
1335  if (e->pool)
1336  vkDestroyCommandPool(s->hwctx->act_dev, e->pool, s->hwctx->alloc);
1337 
1338  av_freep(&e->bufs);
1339  av_freep(&e->queues);
1340  av_freep(&e->sem_sig);
1341  av_freep(&e->sem_wait);
1342  av_freep(&e->sem_wait_dst);
1343  av_free(e);
1344 }
1345 
1347 {
1348  for (int i = 0; i < pl->shaders_num; i++) {
1349  SPIRVShader *shd = pl->shaders[i];
1350  av_bprint_finalize(&shd->src, NULL);
1351  vkDestroyShaderModule(s->hwctx->act_dev, shd->shader.module,
1352  s->hwctx->alloc);
1353  av_free(shd);
1354  }
1355 
1356  vkDestroyPipeline(s->hwctx->act_dev, pl->pipeline, s->hwctx->alloc);
1357  vkDestroyPipelineLayout(s->hwctx->act_dev, pl->pipeline_layout,
1358  s->hwctx->alloc);
1359 
1360  for (int i = 0; i < pl->desc_layout_num; i++) {
1361  if (pl->desc_template && pl->desc_template[i])
1362  vkDestroyDescriptorUpdateTemplate(s->hwctx->act_dev, pl->desc_template[i],
1363  s->hwctx->alloc);
1364  if (pl->desc_layout && pl->desc_layout[i])
1365  vkDestroyDescriptorSetLayout(s->hwctx->act_dev, pl->desc_layout[i],
1366  s->hwctx->alloc);
1367  }
1368 
1369  /* Also frees the descriptor sets */
1370  if (pl->desc_pool)
1371  vkDestroyDescriptorPool(s->hwctx->act_dev, pl->desc_pool,
1372  s->hwctx->alloc);
1373 
1374  av_freep(&pl->desc_set);
1375  av_freep(&pl->shaders);
1376  av_freep(&pl->desc_layout);
1377  av_freep(&pl->desc_template);
1378  av_freep(&pl->push_consts);
1379  pl->push_consts_num = 0;
1380 
1381  /* Only freed in case of failure */
1382  av_freep(&pl->pool_size_desc);
1383  if (pl->desc_template_info) {
1384  for (int i = 0; i < pl->descriptor_sets_num; i++)
1385  av_free((void *)pl->desc_template_info[i].pDescriptorUpdateEntries);
1387  }
1388 
1389  av_free(pl);
1390 }
1391 
1393 {
1394  VulkanFilterContext *s = avctx->priv;
1395 
1396  glslang_uninit();
1397 
1398  for (int i = 0; i < s->exec_ctx_num; i++)
1399  free_exec_ctx(s, s->exec_ctx[i]);
1400  av_freep(&s->exec_ctx);
1401 
1402  for (int i = 0; i < s->samplers_num; i++) {
1403  vkDestroySampler(s->hwctx->act_dev, *s->samplers[i], s->hwctx->alloc);
1404  av_free(s->samplers[i]);
1405  }
1406  av_freep(&s->samplers);
1407 
1408  for (int i = 0; i < s->pipelines_num; i++)
1409  free_pipeline(s, s->pipelines[i]);
1410  av_freep(&s->pipelines);
1411 
1412  av_freep(&s->scratch);
1413  s->scratch_size = 0;
1414 
1417 }
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:439
ptrdiff_t const GLvoid GLenum usage
Definition: opengl_enc.c:100
int sem_wait_cnt
Definition: vulkan.h:149
static enum AVPixelFormat pix_fmt
VkBuffer buf
Definition: vulkan.h:87
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:1155
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:995
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:300
void ff_vk_filter_uninit(AVFilterContext *avctx)
Definition: vulkan.c:1392
VkPipelineShaderStageCreateInfo shader
Definition: vulkan.h:70
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
static void flush(AVCodecContext *avctx)
VkSemaphore * sem_wait
Definition: vulkan.h:147
const char * ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt)
Gets the glsl format string for a pixel format.
Definition: vulkan.c:792
size_t struct_size
Definition: vulkan.c:975
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2589
int push_consts_num
Definition: vulkan.h:105
VkDescriptorPoolSize * pool_size_desc
Definition: vulkan.h:118
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
VkDescriptorUpdateTemplateCreateInfo * desc_template_info
Definition: vulkan.h:117
const char * desc
Definition: nvenc.c:78
int ff_vk_init_compute_pipeline(AVFilterContext *avctx, VulkanPipeline *pl)
Initializes a compute pipeline.
Definition: vulkan.c:1258
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:387
AVFrame ** frame_deps
Definition: vulkan.h:131
#define FN_CREATING(ctx, type, shortname, array, num)
Definition: vulkan.c:25
VkDescriptorUpdateTemplate * desc_template
Definition: vulkan.h:111
int sem_sig_cnt
Definition: vulkan.h:156
int ff_vk_create_imageview(AVFilterContext *avctx, FFVkExecContext *e, VkImageView *v, VkImage img, VkFormat fmt, const VkComponentMapping map)
Create an imageview.
Definition: vulkan.c:811
int ff_vk_filter_config_output(AVFilterLink *outlink)
Definition: vulkan.c:680
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:392
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:209
int nb_frame_deps
Definition: vulkan.h:132
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:239
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:101
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:639
VkPushConstantRange * push_consts
Definition: vulkan.h:104
size_t size
Definition: glslang.h:36
#define img
const char * name
Definition: vulkan.h:67
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
static void destroy_imageview(void *opaque, uint8_t *data)
Definition: vulkan.c:803
VkPipelineStageFlagBits * sem_wait_dst
Definition: vulkan.h:151
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:884
AVBPrint src
Definition: vulkan.h:68
AVBufferRef * frames_ref
Definition: vulkan.h:163
int sem_wait_dst_alloc
Definition: vulkan.h:152
int ff_vk_filter_init(AVFilterContext *avctx)
Definition: vulkan.c:731
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:145
ptrdiff_t size
Definition: opengl_enc.c:100
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:200
#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:155
int ff_vk_filter_query_formats(AVFilterContext *avctx)
General lavfi IO functions.
Definition: vulkan.c:567
const VkSampler * samplers
Definition: vulkan.h:82
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
enum AVPixelFormat input_format
Definition: vulkan.h:176
#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:600
#define AV_BPRINT_SIZE_UNLIMITED
const char * type
Definition: vulkan.c:976
int glslang_init(void)
Definition: glslang.cpp:224
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
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
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
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:191
#define fail()
Definition: checkasm.h:123
void glslang_uninit(void)
Definition: glslang.cpp:236
VulkanPipeline ** pipelines
Definition: vulkan.h:187
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:1346
static const struct @315 planes[]
int sem_wait_alloc
Definition: vulkan.h:148
AVBufferRef * device_ref
Definition: vulkan.h:162
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:744
int ff_vk_create_exec_ctx(AVFilterContext *avctx, FFVkExecContext **ctx)
Init an execution context for command recording and queue submission.
Definition: vulkan.c:314
VkPipeline pipeline
Definition: vulkan.h:97
int ff_vk_submit_exec_queue(AVFilterContext *avctx, FFVkExecContext *e)
Submits a command buffer to the queue for execution.
Definition: vulkan.c:497
#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:110
int buf_deps_alloc_size
Definition: vulkan.h:128
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:89
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:480
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
#define GLSLC(N, S)
Definition: vulkan.h:38
VkDescriptorType type
Definition: vulkan.h:75
VkCommandPool pool
Definition: vulkan.h:137
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:541
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:1293
VkImageView view
Definition: vulkan.c:800
if(ret)
VkFence fence
Definition: vulkan.h:122
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:596
const VkComponentMapping ff_comp_identity_map
Definition: vulkan.c:44
GLuint shader
Definition: opengl_enc.c:115
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:113
int ff_vk_compile_shader(AVFilterContext *avctx, SPIRVShader *shd, const char *entrypoint)
Compiles the shader, entrypoint must be set to "main".
Definition: vulkan.c:917
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:780
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:863
VkDeviceMemory mem
Definition: vulkan.h:88
AVVulkanDeviceContext * hwctx
Definition: vulkan.h:165
#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:1253
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
VkShaderStageFlags stages
Definition: vulkan.h:81
int nb_buf_deps
Definition: vulkan.h:127
const VDPAUPixFmtMap * map
VkPipelineLayout pipeline_layout
Definition: vulkan.h:96
VkCommandBuffer ff_vk_get_exec_buf(AVFilterContext *avctx, FFVkExecContext *e)
Gets the command buffer to use for this submission from the exe context.
Definition: vulkan.c:433
void ff_vk_discard_exec_deps(AVFilterContext *avctx, FFVkExecContext *e)
Discards all queue dependencies.
Definition: vulkan.c:375
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
#define AV_PIX_FMT_BGR565
Definition: pixfmt.h:389
int desc_layout_num
Definition: vulkan.h:112
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:314
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:108
Vulkan hardware images.
Definition: pixfmt.h:356
int
VkSemaphore * sem_sig
Definition: vulkan.h:154
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Synchronization semaphores.
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:175
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:1146
int ff_vk_filter_config_output_inplace(AVFilterLink *outlink)
Definition: vulkan.c:650
#define av_free(p)
SPIRVShader ** shaders
Definition: vulkan.h:100
VkDescriptorPool desc_pool
Definition: vulkan.h:109
FFVkQueueCtx * queues
Definition: vulkan.h:139
VkCommandBuffer * bufs
Definition: vulkan.h:138
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:610
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
static void print_shader(AVFilterContext *avctx, SPIRVShader *shd, int prio)
Definition: vulkan.c:896
#define av_freep(p)
int pool_size_desc_num
Definition: vulkan.h:114
AVHWDeviceContext * device
Definition: vulkan.h:164
VkPipelineBindPoint bind_point
Definition: vulkan.h:93
int local_size[3]
Definition: vulkan.h:69
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 int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, int queue_family_index, int num_queues)
static void free_exec_ctx(VulkanFilterContext *s, FFVkExecContext *e)
Definition: vulkan.c:1307
FFVkExecContext ** exec_ctx
Definition: vulkan.h:183
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:179
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
static int vulkan_filter_set_device(AVFilterContext *avctx, AVBufferRef *device)
Definition: vulkan.c:579
int ff_vk_add_dep_exec_ctx(AVFilterContext *avctx, FFVkExecContext *e, AVBufferRef **deps, int nb_deps)
Adds a generic AVBufferRef as a queue depenency.
Definition: vulkan.c:536
static void print(AVTreeNode *t, int depth)
Definition: tree.c:44
VkQueue queue
Definition: vulkan.h:123
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.
AVBufferRef ** buf_deps
Definition: vulkan.h:126
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:1135