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  int use_ded_mem;
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  VkBufferMemoryRequirementsInfo2 req_desc = {
168  .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
169  };
170  VkMemoryDedicatedAllocateInfo ded_alloc = {
171  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
172  .pNext = NULL,
173  };
174  VkMemoryDedicatedRequirements ded_req = {
175  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
176  };
177  VkMemoryRequirements2 req = {
178  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
179  .pNext = &ded_req,
180  };
181 
182  ret = vkCreateBuffer(s->hwctx->act_dev, &buf_spawn, NULL, &buf->buf);
183  if (ret != VK_SUCCESS) {
184  av_log(avctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
185  ff_vk_ret2str(ret));
186  return AVERROR_EXTERNAL;
187  }
188 
189  req_desc.buffer = buf->buf;
190 
191  vkGetBufferMemoryRequirements2(s->hwctx->act_dev, &req_desc, &req);
192 
193  /* In case the implementation prefers/requires dedicated allocation */
194  use_ded_mem = ded_req.prefersDedicatedAllocation |
195  ded_req.requiresDedicatedAllocation;
196  if (use_ded_mem)
197  ded_alloc.buffer = buf->buf;
198 
199  err = vk_alloc_mem(avctx, &req.memoryRequirements, flags,
200  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
201  &buf->flags, &buf->mem);
202  if (err)
203  return err;
204 
205  ret = vkBindBufferMemory(s->hwctx->act_dev, buf->buf, buf->mem, 0);
206  if (ret != VK_SUCCESS) {
207  av_log(avctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
208  ff_vk_ret2str(ret));
209  return AVERROR_EXTERNAL;
210  }
211 
212  return 0;
213 }
214 
215 int ff_vk_map_buffers(AVFilterContext *avctx, FFVkBuffer *buf, uint8_t *mem[],
216  int nb_buffers, int invalidate)
217 {
218  VkResult ret;
219  VulkanFilterContext *s = avctx->priv;
220  VkMappedMemoryRange *inval_list = NULL;
221  int inval_count = 0;
222 
223  for (int i = 0; i < nb_buffers; i++) {
224  ret = vkMapMemory(s->hwctx->act_dev, buf[i].mem, 0,
225  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
226  if (ret != VK_SUCCESS) {
227  av_log(avctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
228  ff_vk_ret2str(ret));
229  return AVERROR_EXTERNAL;
230  }
231  }
232 
233  if (!invalidate)
234  return 0;
235 
236  for (int i = 0; i < nb_buffers; i++) {
237  const VkMappedMemoryRange ival_buf = {
238  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
239  .memory = buf[i].mem,
240  .size = VK_WHOLE_SIZE,
241  };
242  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
243  continue;
244  inval_list = av_fast_realloc(s->scratch, &s->scratch_size,
245  (++inval_count)*sizeof(*inval_list));
246  if (!inval_list)
247  return AVERROR(ENOMEM);
248  inval_list[inval_count - 1] = ival_buf;
249  }
250 
251  if (inval_count) {
252  ret = vkInvalidateMappedMemoryRanges(s->hwctx->act_dev, inval_count,
253  inval_list);
254  if (ret != VK_SUCCESS) {
255  av_log(avctx, AV_LOG_ERROR, "Failed to invalidate memory: %s\n",
256  ff_vk_ret2str(ret));
257  return AVERROR_EXTERNAL;
258  }
259  }
260 
261  return 0;
262 }
263 
264 int ff_vk_unmap_buffers(AVFilterContext *avctx, FFVkBuffer *buf, int nb_buffers,
265  int flush)
266 {
267  int err = 0;
268  VkResult ret;
269  VulkanFilterContext *s = avctx->priv;
270  VkMappedMemoryRange *flush_list = NULL;
271  int flush_count = 0;
272 
273  if (flush) {
274  for (int i = 0; i < nb_buffers; i++) {
275  const VkMappedMemoryRange flush_buf = {
276  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
277  .memory = buf[i].mem,
278  .size = VK_WHOLE_SIZE,
279  };
280  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
281  continue;
282  flush_list = av_fast_realloc(s->scratch, &s->scratch_size,
283  (++flush_count)*sizeof(*flush_list));
284  if (!flush_list)
285  return AVERROR(ENOMEM);
286  flush_list[flush_count - 1] = flush_buf;
287  }
288  }
289 
290  if (flush_count) {
291  ret = vkFlushMappedMemoryRanges(s->hwctx->act_dev, flush_count,
292  flush_list);
293  if (ret != VK_SUCCESS) {
294  av_log(avctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
295  ff_vk_ret2str(ret));
296  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
297  }
298  }
299 
300  for (int i = 0; i < nb_buffers; i++)
301  vkUnmapMemory(s->hwctx->act_dev, buf[i].mem);
302 
303  return err;
304 }
305 
307 {
308  VulkanFilterContext *s = avctx->priv;
309  if (!buf)
310  return;
311 
312  if (buf->buf != VK_NULL_HANDLE)
313  vkDestroyBuffer(s->hwctx->act_dev, buf->buf, s->hwctx->alloc);
314  if (buf->mem != VK_NULL_HANDLE)
315  vkFreeMemory(s->hwctx->act_dev, buf->mem, s->hwctx->alloc);
316 }
317 
319  int offset, int size, VkShaderStageFlagBits stage)
320 {
321  VkPushConstantRange *pc;
322 
323  pl->push_consts = av_realloc_array(pl->push_consts, sizeof(*pl->push_consts),
324  pl->push_consts_num + 1);
325  if (!pl->push_consts)
326  return AVERROR(ENOMEM);
327 
328  pc = &pl->push_consts[pl->push_consts_num++];
329  memset(pc, 0, sizeof(*pc));
330 
331  pc->stageFlags = stage;
332  pc->offset = offset;
333  pc->size = size;
334 
335  return 0;
336 }
337 
338 FN_CREATING(VulkanFilterContext, FFVkExecContext, exec_ctx, exec_ctx, exec_ctx_num)
340 {
341  VkResult ret;
342  FFVkExecContext *e;
343  VulkanFilterContext *s = avctx->priv;
344 
345  int queue_family = s->queue_family_idx;
346  int nb_queues = s->queue_count;
347 
348  VkCommandPoolCreateInfo cqueue_create = {
349  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
350  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
351  .queueFamilyIndex = queue_family,
352  };
353  VkCommandBufferAllocateInfo cbuf_create = {
354  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
355  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
356  .commandBufferCount = nb_queues,
357  };
358 
359  e = create_exec_ctx(s);
360  if (!e)
361  return AVERROR(ENOMEM);
362 
363  e->queues = av_mallocz(nb_queues * sizeof(*e->queues));
364  if (!e->queues)
365  return AVERROR(ENOMEM);
366 
367  e->bufs = av_mallocz(nb_queues * sizeof(*e->bufs));
368  if (!e->bufs)
369  return AVERROR(ENOMEM);
370 
371  /* Create command pool */
372  ret = vkCreateCommandPool(s->hwctx->act_dev, &cqueue_create,
373  s->hwctx->alloc, &e->pool);
374  if (ret != VK_SUCCESS) {
375  av_log(avctx, AV_LOG_ERROR, "Command pool creation failure: %s\n",
376  ff_vk_ret2str(ret));
377  return AVERROR_EXTERNAL;
378  }
379 
380  cbuf_create.commandPool = e->pool;
381 
382  /* Allocate command buffer */
383  ret = vkAllocateCommandBuffers(s->hwctx->act_dev, &cbuf_create, e->bufs);
384  if (ret != VK_SUCCESS) {
385  av_log(avctx, AV_LOG_ERROR, "Command buffer alloc failure: %s\n",
386  ff_vk_ret2str(ret));
387  return AVERROR_EXTERNAL;
388  }
389 
390  for (int i = 0; i < nb_queues; i++) {
391  FFVkQueueCtx *q = &e->queues[i];
392  vkGetDeviceQueue(s->hwctx->act_dev, queue_family, i, &q->queue);
393  }
394 
395  *ctx = e;
396 
397  return 0;
398 }
399 
401 {
402  VulkanFilterContext *s = avctx->priv;
403  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
404 
405  for (int j = 0; j < q->nb_buf_deps; j++)
406  av_buffer_unref(&q->buf_deps[j]);
407  q->nb_buf_deps = 0;
408 
409  for (int j = 0; j < q->nb_frame_deps; j++)
410  av_frame_free(&q->frame_deps[j]);
411  q->nb_frame_deps = 0;
412 
413  e->sem_wait_cnt = 0;
414  e->sem_sig_cnt = 0;
415 }
416 
418 {
419  VkResult ret;
420  VulkanFilterContext *s = avctx->priv;
421  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
422 
423  VkCommandBufferBeginInfo cmd_start = {
424  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
425  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
426  };
427 
428  /* Create the fence and don't wait for it initially */
429  if (!q->fence) {
430  VkFenceCreateInfo fence_spawn = {
431  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
432  };
433  ret = vkCreateFence(s->hwctx->act_dev, &fence_spawn, s->hwctx->alloc,
434  &q->fence);
435  if (ret != VK_SUCCESS) {
436  av_log(avctx, AV_LOG_ERROR, "Failed to queue frame fence: %s\n",
437  ff_vk_ret2str(ret));
438  return AVERROR_EXTERNAL;
439  }
440  } else {
441  vkWaitForFences(s->hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
442  vkResetFences(s->hwctx->act_dev, 1, &q->fence);
443  }
444 
445  /* Discard queue dependencies */
446  ff_vk_discard_exec_deps(avctx, e);
447 
448  ret = vkBeginCommandBuffer(e->bufs[s->cur_queue_idx], &cmd_start);
449  if (ret != VK_SUCCESS) {
450  av_log(avctx, AV_LOG_ERROR, "Failed to start command recoding: %s\n",
451  ff_vk_ret2str(ret));
452  return AVERROR_EXTERNAL;
453  }
454 
455  return 0;
456 }
457 
459 {
460  VulkanFilterContext *s = avctx->priv;
461  return e->bufs[s->cur_queue_idx];
462 }
463 
465  AVFrame *frame, VkPipelineStageFlagBits in_wait_dst_flag)
466 {
467  AVFrame **dst;
468  VulkanFilterContext *s = avctx->priv;
469  AVVkFrame *f = (AVVkFrame *)frame->data[0];
470  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
471  AVHWFramesContext *fc = (AVHWFramesContext *)frame->hw_frames_ctx->data;
472  int planes = av_pix_fmt_count_planes(fc->sw_format);
473 
474  for (int i = 0; i < planes; i++) {
476  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait));
477  if (!e->sem_wait) {
478  ff_vk_discard_exec_deps(avctx, e);
479  return AVERROR(ENOMEM);
480  }
481 
483  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait_dst));
484  if (!e->sem_wait_dst) {
485  ff_vk_discard_exec_deps(avctx, e);
486  return AVERROR(ENOMEM);
487  }
488 
490  (e->sem_sig_cnt + 1)*sizeof(*e->sem_sig));
491  if (!e->sem_sig) {
492  ff_vk_discard_exec_deps(avctx, e);
493  return AVERROR(ENOMEM);
494  }
495 
496  e->sem_wait[e->sem_wait_cnt] = f->sem[i];
497  e->sem_wait_dst[e->sem_wait_cnt] = in_wait_dst_flag;
498  e->sem_wait_cnt++;
499 
500  e->sem_sig[e->sem_sig_cnt] = f->sem[i];
501  e->sem_sig_cnt++;
502  }
503 
504  dst = av_fast_realloc(q->frame_deps, &q->frame_deps_alloc_size,
505  (q->nb_frame_deps + 1) * sizeof(*dst));
506  if (!dst) {
507  ff_vk_discard_exec_deps(avctx, e);
508  return AVERROR(ENOMEM);
509  }
510 
511  q->frame_deps = dst;
512  q->frame_deps[q->nb_frame_deps] = av_frame_clone(frame);
513  if (!q->frame_deps[q->nb_frame_deps]) {
514  ff_vk_discard_exec_deps(avctx, e);
515  return AVERROR(ENOMEM);
516  }
517  q->nb_frame_deps++;
518 
519  return 0;
520 }
521 
523 {
524  VkResult ret;
525  VulkanFilterContext *s = avctx->priv;
526  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
527 
528  VkSubmitInfo s_info = {
529  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
530  .commandBufferCount = 1,
531  .pCommandBuffers = &e->bufs[s->cur_queue_idx],
532 
533  .pWaitSemaphores = e->sem_wait,
534  .pWaitDstStageMask = e->sem_wait_dst,
535  .waitSemaphoreCount = e->sem_wait_cnt,
536 
537  .pSignalSemaphores = e->sem_sig,
538  .signalSemaphoreCount = e->sem_sig_cnt,
539  };
540 
541  ret = vkEndCommandBuffer(e->bufs[s->cur_queue_idx]);
542  if (ret != VK_SUCCESS) {
543  av_log(avctx, AV_LOG_ERROR, "Unable to finish command buffer: %s\n",
544  ff_vk_ret2str(ret));
545  return AVERROR_EXTERNAL;
546  }
547 
548  ret = vkQueueSubmit(q->queue, 1, &s_info, q->fence);
549  if (ret != VK_SUCCESS) {
550  av_log(avctx, AV_LOG_ERROR, "Unable to submit command buffer: %s\n",
551  ff_vk_ret2str(ret));
552  return AVERROR_EXTERNAL;
553  }
554 
555  /* Rotate queues */
556  s->cur_queue_idx = (s->cur_queue_idx + 1) % s->queue_count;
557 
558  return 0;
559 }
560 
562  AVBufferRef **deps, int nb_deps)
563 {
564  AVBufferRef **dst;
565  VulkanFilterContext *s = avctx->priv;
566  FFVkQueueCtx *q = &e->queues[s->cur_queue_idx];
567 
568  if (!deps || !nb_deps)
569  return 0;
570 
572  (q->nb_buf_deps + nb_deps) * sizeof(*dst));
573  if (!dst)
574  goto err;
575 
576  q->buf_deps = dst;
577 
578  for (int i = 0; i < nb_deps; i++) {
579  q->buf_deps[q->nb_buf_deps] = deps[i];
580  if (!q->buf_deps[q->nb_buf_deps])
581  goto err;
582  q->nb_buf_deps++;
583  }
584 
585  return 0;
586 
587 err:
588  ff_vk_discard_exec_deps(avctx, e);
589  return AVERROR(ENOMEM);
590 }
591 
593 {
594  static const enum AVPixelFormat pixel_formats[] = {
596  };
597 
598  return ff_set_common_formats_from_list(avctx, pixel_formats);
599 }
600 
602  AVBufferRef *device)
603 {
604  VulkanFilterContext *s = avctx->priv;
605 
606  av_buffer_unref(&s->device_ref);
607 
608  s->device_ref = av_buffer_ref(device);
609  if (!s->device_ref)
610  return AVERROR(ENOMEM);
611 
612  s->device = (AVHWDeviceContext*)s->device_ref->data;
613  s->hwctx = s->device->hwctx;
614 
615  return 0;
616 }
617 
620 {
621  VulkanFilterContext *s = avctx->priv;
622 
623  av_buffer_unref(&s->frames_ref);
624 
625  s->frames_ref = av_buffer_ref(frames);
626  if (!s->frames_ref)
627  return AVERROR(ENOMEM);
628 
629  return 0;
630 }
631 
633 {
634  int err;
635  AVFilterContext *avctx = inlink->dst;
636  VulkanFilterContext *s = avctx->priv;
637  AVHWFramesContext *input_frames;
638 
639  if (!inlink->hw_frames_ctx) {
640  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
641  "hardware frames context on the input.\n");
642  return AVERROR(EINVAL);
643  }
644 
645  /* Extract the device and default output format from the first input. */
646  if (avctx->inputs[0] != inlink)
647  return 0;
648 
649  input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
650  if (input_frames->format != AV_PIX_FMT_VULKAN)
651  return AVERROR(EINVAL);
652 
653  err = vulkan_filter_set_device(avctx, input_frames->device_ref);
654  if (err < 0)
655  return err;
656  err = vulkan_filter_set_frames(avctx, inlink->hw_frames_ctx);
657  if (err < 0)
658  return err;
659 
660  /* Default output parameters match input parameters. */
661  s->input_format = input_frames->sw_format;
662  if (s->output_format == AV_PIX_FMT_NONE)
663  s->output_format = input_frames->sw_format;
664  if (!s->output_width)
665  s->output_width = inlink->w;
666  if (!s->output_height)
667  s->output_height = inlink->h;
668 
669  return 0;
670 }
671 
673 {
674  int err;
675  AVFilterContext *avctx = outlink->src;
676  VulkanFilterContext *s = avctx->priv;
677 
678  av_buffer_unref(&outlink->hw_frames_ctx);
679 
680  if (!s->device_ref) {
681  if (!avctx->hw_device_ctx) {
682  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
683  "Vulkan device.\n");
684  return AVERROR(EINVAL);
685  }
686 
687  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
688  if (err < 0)
689  return err;
690  }
691 
692  outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref);
693  if (!outlink->hw_frames_ctx)
694  return AVERROR(ENOMEM);
695 
696  outlink->w = s->output_width;
697  outlink->h = s->output_height;
698 
699  return 0;
700 }
701 
703 {
704  int err;
705  AVFilterContext *avctx = outlink->src;
706  VulkanFilterContext *s = avctx->priv;
707  AVBufferRef *output_frames_ref;
708  AVHWFramesContext *output_frames;
709 
710  av_buffer_unref(&outlink->hw_frames_ctx);
711 
712  if (!s->device_ref) {
713  if (!avctx->hw_device_ctx) {
714  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
715  "Vulkan device.\n");
716  return AVERROR(EINVAL);
717  }
718 
719  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
720  if (err < 0)
721  return err;
722  }
723 
724  output_frames_ref = av_hwframe_ctx_alloc(s->device_ref);
725  if (!output_frames_ref) {
726  err = AVERROR(ENOMEM);
727  goto fail;
728  }
729  output_frames = (AVHWFramesContext*)output_frames_ref->data;
730 
731  output_frames->format = AV_PIX_FMT_VULKAN;
732  output_frames->sw_format = s->output_format;
733  output_frames->width = s->output_width;
734  output_frames->height = s->output_height;
735 
736  err = av_hwframe_ctx_init(output_frames_ref);
737  if (err < 0) {
738  av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
739  "frames: %d.\n", err);
740  goto fail;
741  }
742 
743  outlink->hw_frames_ctx = output_frames_ref;
744  outlink->w = s->output_width;
745  outlink->h = s->output_height;
746 
747  return 0;
748 fail:
749  av_buffer_unref(&output_frames_ref);
750  return err;
751 }
752 
754 {
755  VulkanFilterContext *s = avctx->priv;
756 
757  s->output_format = AV_PIX_FMT_NONE;
758 
759  if (glslang_init())
760  return AVERROR_EXTERNAL;
761 
762  return 0;
763 }
764 
765 FN_CREATING(VulkanFilterContext, VkSampler, sampler, samplers, samplers_num)
766 VkSampler *ff_vk_init_sampler(AVFilterContext *avctx, int unnorm_coords,
767  VkFilter filt)
768 {
769  VkResult ret;
770  VulkanFilterContext *s = avctx->priv;
771 
772  VkSamplerCreateInfo sampler_info = {
773  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
774  .magFilter = filt,
775  .minFilter = sampler_info.magFilter,
776  .mipmapMode = unnorm_coords ? VK_SAMPLER_MIPMAP_MODE_NEAREST :
777  VK_SAMPLER_MIPMAP_MODE_LINEAR,
778  .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
779  .addressModeV = sampler_info.addressModeU,
780  .addressModeW = sampler_info.addressModeU,
781  .anisotropyEnable = VK_FALSE,
782  .compareOp = VK_COMPARE_OP_NEVER,
783  .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
784  .unnormalizedCoordinates = unnorm_coords,
785  };
786 
787  VkSampler *sampler = create_sampler(s);
788  if (!sampler)
789  return NULL;
790 
791  ret = vkCreateSampler(s->hwctx->act_dev, &sampler_info,
792  s->hwctx->alloc, sampler);
793  if (ret != VK_SUCCESS) {
794  av_log(avctx, AV_LOG_ERROR, "Unable to init sampler: %s\n",
795  ff_vk_ret2str(ret));
796  return NULL;
797  }
798 
799  return sampler;
800 }
801 
803 {
810  return 1;
811  return 0;
812 }
813 
815 {
817  const int high = desc->comp[0].depth > 8;
818  return high ? "rgba16f" : "rgba8";
819 }
820 
821 typedef struct ImageViewCtx {
822  VkImageView view;
823 } ImageViewCtx;
824 
825 static void destroy_imageview(void *opaque, uint8_t *data)
826 {
827  VulkanFilterContext *s = opaque;
828  ImageViewCtx *iv = (ImageViewCtx *)data;
829  vkDestroyImageView(s->hwctx->act_dev, iv->view, s->hwctx->alloc);
830  av_free(iv);
831 }
832 
834  VkImageView *v, VkImage img, VkFormat fmt,
835  const VkComponentMapping map)
836 {
837  int err;
838  AVBufferRef *buf;
839  VulkanFilterContext *s = avctx->priv;
840  VkImageViewCreateInfo imgview_spawn = {
841  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
842  .pNext = NULL,
843  .image = img,
844  .viewType = VK_IMAGE_VIEW_TYPE_2D,
845  .format = fmt,
846  .components = map,
847  .subresourceRange = {
848  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
849  .baseMipLevel = 0,
850  .levelCount = 1,
851  .baseArrayLayer = 0,
852  .layerCount = 1,
853  },
854  };
855 
856  ImageViewCtx *iv = av_mallocz(sizeof(*iv));
857 
858  VkResult ret = vkCreateImageView(s->hwctx->act_dev, &imgview_spawn,
859  s->hwctx->alloc, &iv->view);
860  if (ret != VK_SUCCESS) {
861  av_log(avctx, AV_LOG_ERROR, "Failed to create imageview: %s\n",
862  ff_vk_ret2str(ret));
863  return AVERROR_EXTERNAL;
864  }
865 
866  buf = av_buffer_create((uint8_t *)iv, sizeof(*iv), destroy_imageview, s, 0);
867  if (!buf) {
868  destroy_imageview(s, (uint8_t *)iv);
869  return AVERROR(ENOMEM);
870  }
871 
872  /* Add to queue dependencies */
873  err = ff_vk_add_dep_exec_ctx(avctx, e, &buf, 1);
874  if (err) {
875  av_buffer_unref(&buf);
876  return err;
877  }
878 
879  *v = iv->view;
880 
881  return 0;
882 }
883 
884 FN_CREATING(VulkanPipeline, SPIRVShader, shader, shaders, shaders_num)
886  const char *name, VkShaderStageFlags stage)
887 {
888  SPIRVShader *shd = create_shader(pl);
889  if (!shd)
890  return NULL;
891 
893 
894  shd->shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
895  shd->shader.stage = stage;
896 
897  shd->name = name;
898 
899  GLSLF(0, #version %i ,460);
900  GLSLC(0, #define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y)) );
901  GLSLC(0, );
902 
903  return shd;
904 }
905 
907  int local_size[3])
908 {
909  shd->local_size[0] = local_size[0];
910  shd->local_size[1] = local_size[1];
911  shd->local_size[2] = local_size[2];
912 
913  av_bprintf(&shd->src, "layout (local_size_x = %i, "
914  "local_size_y = %i, local_size_z = %i) in;\n\n",
915  shd->local_size[0], shd->local_size[1], shd->local_size[2]);
916 }
917 
918 static void print_shader(AVFilterContext *avctx, SPIRVShader *shd, int prio)
919 {
920  int line = 0;
921  const char *p = shd->src.str;
922  const char *start = p;
923 
924  AVBPrint buf;
926 
927  for (int i = 0; i < strlen(p); i++) {
928  if (p[i] == '\n') {
929  av_bprintf(&buf, "%i\t", ++line);
930  av_bprint_append_data(&buf, start, &p[i] - start + 1);
931  start = &p[i + 1];
932  }
933  }
934 
935  av_log(avctx, prio, "Shader %s: \n%s", shd->name, buf.str);
936  av_bprint_finalize(&buf, NULL);
937 }
938 
940  const char *entrypoint)
941 {
942  VkResult ret;
943  VulkanFilterContext *s = avctx->priv;
944  VkShaderModuleCreateInfo shader_create;
945  GLSlangResult *res;
946 
947  static const enum GLSlangStage emap[] = {
948  [VK_SHADER_STAGE_VERTEX_BIT] = GLSLANG_VERTEX,
949  [VK_SHADER_STAGE_FRAGMENT_BIT] = GLSLANG_FRAGMENT,
950  [VK_SHADER_STAGE_COMPUTE_BIT] = GLSLANG_COMPUTE,
951  };
952 
953  shd->shader.pName = entrypoint;
954 
955  res = glslang_compile(shd->src.str, emap[shd->shader.stage]);
956  if (!res)
957  return AVERROR(ENOMEM);
958 
959  if (res->rval) {
960  av_log(avctx, AV_LOG_ERROR, "Error compiling shader %s: %s!\n",
961  shd->name, av_err2str(res->rval));
962  print_shader(avctx, shd, AV_LOG_ERROR);
963  if (res->error_msg)
964  av_log(avctx, AV_LOG_ERROR, "%s", res->error_msg);
965  av_free(res->error_msg);
966  return res->rval;
967  }
968 
969  print_shader(avctx, shd, AV_LOG_VERBOSE);
970 
971  shader_create.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
972  shader_create.pNext = NULL;
973  shader_create.codeSize = res->size;
974  shader_create.flags = 0;
975  shader_create.pCode = res->data;
976 
977  ret = vkCreateShaderModule(s->hwctx->act_dev, &shader_create, NULL,
978  &shd->shader.module);
979 
980  /* Free the GLSlangResult struct */
981  av_free(res->data);
982  av_free(res);
983 
984  if (ret != VK_SUCCESS) {
985  av_log(avctx, AV_LOG_ERROR, "Unable to create shader module: %s\n",
986  ff_vk_ret2str(ret));
987  return AVERROR_EXTERNAL;
988  }
989 
990  av_log(avctx, AV_LOG_VERBOSE, "Shader %s linked! Size: %zu bytes\n",
991  shd->name, shader_create.codeSize);
992 
993  return 0;
994 }
995 
996 static const struct descriptor_props {
997  size_t struct_size; /* Size of the opaque which updates the descriptor */
998  const char *type;
1000  int mem_quali; /* Can use a memory qualifier */
1001  int dim_needed; /* Must indicate dimension */
1002  int buf_content; /* Must indicate buffer contents */
1003 } descriptor_props[] = {
1004  [VK_DESCRIPTOR_TYPE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 0, 0, },
1005  [VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] = { sizeof(VkDescriptorImageInfo), "texture", 1, 0, 1, 0, },
1006  [VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] = { sizeof(VkDescriptorImageInfo), "image", 1, 1, 1, 0, },
1007  [VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] = { sizeof(VkDescriptorImageInfo), "subpassInput", 1, 0, 0, 0, },
1008  [VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 1, 0, },
1009  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
1010  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
1011  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
1012  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
1013  [VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] = { sizeof(VkBufferView), "samplerBuffer", 1, 0, 0, 0, },
1014  [VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER] = { sizeof(VkBufferView), "imageBuffer", 1, 0, 0, 0, },
1015 };
1016 
1019  int num, int only_print_to_shader)
1020 {
1021  VkResult ret;
1022  VkDescriptorSetLayout *layout;
1023  VulkanFilterContext *s = avctx->priv;
1024 
1025  if (only_print_to_shader)
1026  goto print;
1027 
1028  pl->desc_layout = av_realloc_array(pl->desc_layout, sizeof(*pl->desc_layout),
1029  pl->desc_layout_num + 1);
1030  if (!pl->desc_layout)
1031  return AVERROR(ENOMEM);
1032 
1033  layout = &pl->desc_layout[pl->desc_layout_num];
1034  memset(layout, 0, sizeof(*layout));
1035 
1036  { /* Create descriptor set layout descriptions */
1037  VkDescriptorSetLayoutCreateInfo desc_create_layout = { 0 };
1038  VkDescriptorSetLayoutBinding *desc_binding;
1039 
1040  desc_binding = av_mallocz(sizeof(*desc_binding)*num);
1041  if (!desc_binding)
1042  return AVERROR(ENOMEM);
1043 
1044  for (int i = 0; i < num; i++) {
1045  desc_binding[i].binding = i;
1046  desc_binding[i].descriptorType = desc[i].type;
1047  desc_binding[i].descriptorCount = FFMAX(desc[i].elems, 1);
1048  desc_binding[i].stageFlags = desc[i].stages;
1049  desc_binding[i].pImmutableSamplers = desc[i].samplers;
1050  }
1051 
1052  desc_create_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
1053  desc_create_layout.pBindings = desc_binding;
1054  desc_create_layout.bindingCount = num;
1055 
1056  ret = vkCreateDescriptorSetLayout(s->hwctx->act_dev, &desc_create_layout,
1057  s->hwctx->alloc, layout);
1058  av_free(desc_binding);
1059  if (ret != VK_SUCCESS) {
1060  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
1061  "layout: %s\n", ff_vk_ret2str(ret));
1062  return AVERROR_EXTERNAL;
1063  }
1064  }
1065 
1066  { /* Pool each descriptor by type and update pool counts */
1067  for (int i = 0; i < num; i++) {
1068  int j;
1069  for (j = 0; j < pl->pool_size_desc_num; j++)
1070  if (pl->pool_size_desc[j].type == desc[i].type)
1071  break;
1072  if (j >= pl->pool_size_desc_num) {
1074  sizeof(*pl->pool_size_desc),
1075  ++pl->pool_size_desc_num);
1076  if (!pl->pool_size_desc)
1077  return AVERROR(ENOMEM);
1078  memset(&pl->pool_size_desc[j], 0, sizeof(VkDescriptorPoolSize));
1079  }
1080  pl->pool_size_desc[j].type = desc[i].type;
1081  pl->pool_size_desc[j].descriptorCount += FFMAX(desc[i].elems, 1);
1082  }
1083  }
1084 
1085  { /* Create template creation struct */
1086  VkDescriptorUpdateTemplateCreateInfo *dt;
1087  VkDescriptorUpdateTemplateEntry *des_entries;
1088 
1089  /* Freed after descriptor set initialization */
1090  des_entries = av_mallocz(num*sizeof(VkDescriptorUpdateTemplateEntry));
1091  if (!des_entries)
1092  return AVERROR(ENOMEM);
1093 
1094  for (int i = 0; i < num; i++) {
1095  des_entries[i].dstBinding = i;
1096  des_entries[i].descriptorType = desc[i].type;
1097  des_entries[i].descriptorCount = FFMAX(desc[i].elems, 1);
1098  des_entries[i].dstArrayElement = 0;
1099  des_entries[i].offset = ((uint8_t *)desc[i].updater) - (uint8_t *)s;
1100  des_entries[i].stride = descriptor_props[desc[i].type].struct_size;
1101  }
1102 
1104  sizeof(*pl->desc_template_info),
1105  pl->desc_layout_num + 1);
1106  if (!pl->desc_template_info)
1107  return AVERROR(ENOMEM);
1108 
1109  dt = &pl->desc_template_info[pl->desc_layout_num];
1110  memset(dt, 0, sizeof(*dt));
1111 
1112  dt->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO;
1113  dt->templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
1114  dt->descriptorSetLayout = *layout;
1115  dt->pDescriptorUpdateEntries = des_entries;
1116  dt->descriptorUpdateEntryCount = num;
1117  }
1118 
1119  pl->desc_layout_num++;
1120 
1121 print:
1122  /* Write shader info */
1123  for (int i = 0; i < num; i++) {
1124  const struct descriptor_props *prop = &descriptor_props[desc[i].type];
1125  GLSLA("layout (set = %i, binding = %i", pl->desc_layout_num - 1, i);
1126 
1127  if (desc[i].mem_layout)
1128  GLSLA(", %s", desc[i].mem_layout);
1129  GLSLA(")");
1130 
1131  if (prop->is_uniform)
1132  GLSLA(" uniform");
1133 
1134  if (prop->mem_quali && desc[i].mem_quali)
1135  GLSLA(" %s", desc[i].mem_quali);
1136 
1137  if (prop->type)
1138  GLSLA(" %s", prop->type);
1139 
1140  if (prop->dim_needed)
1141  GLSLA("%iD", desc[i].dimensions);
1142 
1143  GLSLA(" %s", desc[i].name);
1144 
1145  if (prop->buf_content)
1146  GLSLA(" {\n %s\n}", desc[i].buf_content);
1147  else if (desc[i].elems > 0)
1148  GLSLA("[%i]", desc[i].elems);
1149 
1150  GLSLA(";\n");
1151  }
1152  GLSLA("\n");
1153 
1154  return 0;
1155 }
1156 
1158  int set_id)
1159 {
1160  VulkanFilterContext *s = avctx->priv;
1161 
1162  vkUpdateDescriptorSetWithTemplate(s->hwctx->act_dev,
1163  pl->desc_set[s->cur_queue_idx * pl->desc_layout_num + set_id],
1164  pl->desc_template[set_id],
1165  s);
1166 }
1167 
1169  VkShaderStageFlagBits stage, int offset,
1170  size_t size, void *src)
1171 {
1172  VulkanFilterContext *s = avctx->priv;
1173  vkCmdPushConstants(e->bufs[s->cur_queue_idx], e->bound_pl->pipeline_layout,
1174  stage, offset, size, src);
1175 }
1176 
1178 {
1179  VkResult ret;
1180  VulkanFilterContext *s = avctx->priv;
1181 
1182  pl->descriptor_sets_num = pl->desc_layout_num * s->queue_count;
1183 
1184  { /* Init descriptor set pool */
1185  VkDescriptorPoolCreateInfo pool_create_info = {
1186  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1187  .poolSizeCount = pl->pool_size_desc_num,
1188  .pPoolSizes = pl->pool_size_desc,
1189  .maxSets = pl->descriptor_sets_num,
1190  };
1191 
1192  ret = vkCreateDescriptorPool(s->hwctx->act_dev, &pool_create_info,
1193  s->hwctx->alloc, &pl->desc_pool);
1194  av_freep(&pl->pool_size_desc);
1195  if (ret != VK_SUCCESS) {
1196  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
1197  "pool: %s\n", ff_vk_ret2str(ret));
1198  return AVERROR_EXTERNAL;
1199  }
1200  }
1201 
1202  { /* Allocate descriptor sets */
1203  VkDescriptorSetAllocateInfo alloc_info = {
1204  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1205  .descriptorPool = pl->desc_pool,
1206  .descriptorSetCount = pl->descriptor_sets_num,
1207  .pSetLayouts = pl->desc_layout,
1208  };
1209 
1210  pl->desc_set = av_malloc(pl->descriptor_sets_num*sizeof(*pl->desc_set));
1211  if (!pl->desc_set)
1212  return AVERROR(ENOMEM);
1213 
1214  ret = vkAllocateDescriptorSets(s->hwctx->act_dev, &alloc_info,
1215  pl->desc_set);
1216  if (ret != VK_SUCCESS) {
1217  av_log(avctx, AV_LOG_ERROR, "Unable to allocate descriptor set: %s\n",
1218  ff_vk_ret2str(ret));
1219  return AVERROR_EXTERNAL;
1220  }
1221  }
1222 
1223  { /* Finally create the pipeline layout */
1224  VkPipelineLayoutCreateInfo spawn_pipeline_layout = {
1225  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1226  .setLayoutCount = pl->desc_layout_num,
1227  .pSetLayouts = pl->desc_layout,
1228  .pushConstantRangeCount = pl->push_consts_num,
1229  .pPushConstantRanges = pl->push_consts,
1230  };
1231 
1232  ret = vkCreatePipelineLayout(s->hwctx->act_dev, &spawn_pipeline_layout,
1233  s->hwctx->alloc, &pl->pipeline_layout);
1234  av_freep(&pl->push_consts);
1235  pl->push_consts_num = 0;
1236  if (ret != VK_SUCCESS) {
1237  av_log(avctx, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n",
1238  ff_vk_ret2str(ret));
1239  return AVERROR_EXTERNAL;
1240  }
1241  }
1242 
1243  { /* Descriptor template (for tightly packed descriptors) */
1244  VkDescriptorUpdateTemplateCreateInfo *desc_template_info;
1245 
1246  pl->desc_template = av_malloc(pl->descriptor_sets_num*sizeof(*pl->desc_template));
1247  if (!pl->desc_template)
1248  return AVERROR(ENOMEM);
1249 
1250  /* Create update templates for the descriptor sets */
1251  for (int i = 0; i < pl->descriptor_sets_num; i++) {
1252  desc_template_info = &pl->desc_template_info[i % pl->desc_layout_num];
1253  desc_template_info->pipelineLayout = pl->pipeline_layout;
1254  ret = vkCreateDescriptorUpdateTemplate(s->hwctx->act_dev,
1255  desc_template_info,
1256  s->hwctx->alloc,
1257  &pl->desc_template[i]);
1258  av_free((void *)desc_template_info->pDescriptorUpdateEntries);
1259  if (ret != VK_SUCCESS) {
1260  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor "
1261  "template: %s\n", ff_vk_ret2str(ret));
1262  return AVERROR_EXTERNAL;
1263  }
1264  }
1265 
1267  }
1268 
1269  return 0;
1270 }
1271 
1272 FN_CREATING(VulkanFilterContext, VulkanPipeline, pipeline, pipelines, pipelines_num)
1274 {
1275  return create_pipeline(avctx->priv);
1276 }
1277 
1279 {
1280  int i;
1281  VkResult ret;
1282  VulkanFilterContext *s = avctx->priv;
1283 
1284  VkComputePipelineCreateInfo pipe = {
1285  .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1286  .layout = pl->pipeline_layout,
1287  };
1288 
1289  for (i = 0; i < pl->shaders_num; i++) {
1290  if (pl->shaders[i]->shader.stage & VK_SHADER_STAGE_COMPUTE_BIT) {
1291  pipe.stage = pl->shaders[i]->shader;
1292  break;
1293  }
1294  }
1295  if (i == pl->shaders_num) {
1296  av_log(avctx, AV_LOG_ERROR, "Can't init compute pipeline, no shader\n");
1297  return AVERROR(EINVAL);
1298  }
1299 
1300  ret = vkCreateComputePipelines(s->hwctx->act_dev, VK_NULL_HANDLE, 1, &pipe,
1301  s->hwctx->alloc, &pl->pipeline);
1302  if (ret != VK_SUCCESS) {
1303  av_log(avctx, AV_LOG_ERROR, "Unable to init compute pipeline: %s\n",
1304  ff_vk_ret2str(ret));
1305  return AVERROR_EXTERNAL;
1306  }
1307 
1308  pl->bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
1309 
1310  return 0;
1311 }
1312 
1314  VulkanPipeline *pl)
1315 {
1316  VulkanFilterContext *s = avctx->priv;
1317 
1318  vkCmdBindPipeline(e->bufs[s->cur_queue_idx], pl->bind_point, pl->pipeline);
1319 
1320  vkCmdBindDescriptorSets(e->bufs[s->cur_queue_idx], pl->bind_point,
1322  pl->desc_set, 0, 0);
1323 
1324  e->bound_pl = pl;
1325 }
1326 
1328 {
1329  /* Make sure all queues have finished executing */
1330  for (int i = 0; i < s->queue_count; i++) {
1331  FFVkQueueCtx *q = &e->queues[i];
1332 
1333  if (q->fence) {
1334  vkWaitForFences(s->hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
1335  vkResetFences(s->hwctx->act_dev, 1, &q->fence);
1336  }
1337 
1338  /* Free the fence */
1339  if (q->fence)
1340  vkDestroyFence(s->hwctx->act_dev, q->fence, s->hwctx->alloc);
1341 
1342  /* Free buffer dependencies */
1343  for (int j = 0; j < q->nb_buf_deps; j++)
1344  av_buffer_unref(&q->buf_deps[j]);
1345  av_free(q->buf_deps);
1346 
1347  /* Free frame dependencies */
1348  for (int j = 0; j < q->nb_frame_deps; j++)
1349  av_frame_free(&q->frame_deps[j]);
1350  av_free(q->frame_deps);
1351  }
1352 
1353  if (e->bufs)
1354  vkFreeCommandBuffers(s->hwctx->act_dev, e->pool, s->queue_count, e->bufs);
1355  if (e->pool)
1356  vkDestroyCommandPool(s->hwctx->act_dev, e->pool, s->hwctx->alloc);
1357 
1358  av_freep(&e->bufs);
1359  av_freep(&e->queues);
1360  av_freep(&e->sem_sig);
1361  av_freep(&e->sem_wait);
1362  av_freep(&e->sem_wait_dst);
1363  av_free(e);
1364 }
1365 
1367 {
1368  for (int i = 0; i < pl->shaders_num; i++) {
1369  SPIRVShader *shd = pl->shaders[i];
1370  av_bprint_finalize(&shd->src, NULL);
1371  vkDestroyShaderModule(s->hwctx->act_dev, shd->shader.module,
1372  s->hwctx->alloc);
1373  av_free(shd);
1374  }
1375 
1376  vkDestroyPipeline(s->hwctx->act_dev, pl->pipeline, s->hwctx->alloc);
1377  vkDestroyPipelineLayout(s->hwctx->act_dev, pl->pipeline_layout,
1378  s->hwctx->alloc);
1379 
1380  for (int i = 0; i < pl->desc_layout_num; i++) {
1381  if (pl->desc_template && pl->desc_template[i])
1382  vkDestroyDescriptorUpdateTemplate(s->hwctx->act_dev, pl->desc_template[i],
1383  s->hwctx->alloc);
1384  if (pl->desc_layout && pl->desc_layout[i])
1385  vkDestroyDescriptorSetLayout(s->hwctx->act_dev, pl->desc_layout[i],
1386  s->hwctx->alloc);
1387  }
1388 
1389  /* Also frees the descriptor sets */
1390  if (pl->desc_pool)
1391  vkDestroyDescriptorPool(s->hwctx->act_dev, pl->desc_pool,
1392  s->hwctx->alloc);
1393 
1394  av_freep(&pl->desc_set);
1395  av_freep(&pl->shaders);
1396  av_freep(&pl->desc_layout);
1397  av_freep(&pl->desc_template);
1398  av_freep(&pl->push_consts);
1399  pl->push_consts_num = 0;
1400 
1401  /* Only freed in case of failure */
1402  av_freep(&pl->pool_size_desc);
1403  if (pl->desc_template_info) {
1404  for (int i = 0; i < pl->descriptor_sets_num; i++)
1405  av_free((void *)pl->desc_template_info[i].pDescriptorUpdateEntries);
1407  }
1408 
1409  av_free(pl);
1410 }
1411 
1413 {
1414  VulkanFilterContext *s = avctx->priv;
1415 
1416  glslang_uninit();
1417 
1418  for (int i = 0; i < s->exec_ctx_num; i++)
1419  free_exec_ctx(s, s->exec_ctx[i]);
1420  av_freep(&s->exec_ctx);
1421 
1422  for (int i = 0; i < s->samplers_num; i++) {
1423  vkDestroySampler(s->hwctx->act_dev, *s->samplers[i], s->hwctx->alloc);
1424  av_free(s->samplers[i]);
1425  }
1426  av_freep(&s->samplers);
1427 
1428  for (int i = 0; i < s->pipelines_num; i++)
1429  free_pipeline(s, s->pipelines[i]);
1430  av_freep(&s->pipelines);
1431 
1432  av_freep(&s->scratch);
1433  s->scratch_size = 0;
1434 
1435  av_buffer_unref(&s->device_ref);
1436  av_buffer_unref(&s->frames_ref);
1437 }
FFVkExecContext::queues
FFVkQueueCtx * queues
Definition: vulkan.h:139
ff_vk_filter_query_formats
int ff_vk_filter_query_formats(AVFilterContext *avctx)
General lavfi IO functions.
Definition: vulkan.c:592
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
name
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 default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
FFVkExecContext::sem_wait_dst_alloc
int sem_wait_dst_alloc
Definition: vulkan.h:152
FFVkExecContext::sem_wait
VkSemaphore * sem_wait
Definition: vulkan.h:147
AVERROR
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
GLSlangResult
Definition: glslang.h:31
GLSlangResult::data
void * data
Definition: glslang.h:35
GLSlangStage
GLSlangStage
Definition: glslang.h:39
GLSlangResult::size
size_t size
Definition: glslang.h:36
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:234
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:68
VulkanPipeline::desc_template_info
VkDescriptorUpdateTemplateCreateInfo * desc_template_info
Definition: vulkan.h:117
VulkanPipeline::pipeline_layout
VkPipelineLayout pipeline_layout
Definition: vulkan.h:96
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2540
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
FFVkExecContext::sem_sig
VkSemaphore * sem_sig
Definition: vulkan.h:154
AVHWFramesContext::format
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:209
inlink
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
Definition: filter_design.txt:212
descriptor_props::is_uniform
int is_uniform
Definition: vulkan.c:999
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:112
av_hwframe_ctx_init
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:333
free_pipeline
static void free_pipeline(VulkanFilterContext *s, VulkanPipeline *pl)
Definition: vulkan.c:1366
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:303
index
fg index
Definition: ffmpeg_filter.c:168
GLSLANG_FRAGMENT
@ GLSLANG_FRAGMENT
Definition: glslang.h:41
av_hwframe_ctx_alloc
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:247
ff_vk_mt_is_np_rgb
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:802
VulkanDescriptorSetBinding
Definition: vulkan.h:73
ff_vk_add_dep_exec_ctx
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:561
free_exec_ctx
static void free_exec_ctx(VulkanFilterContext *s, FFVkExecContext *e)
Definition: vulkan.c:1327
data
const char data[16]
Definition: mxf.c:143
FFVkQueueCtx::buf_deps_alloc_size
int buf_deps_alloc_size
Definition: vulkan.h:128
glslang_compile
GLSlangResult * glslang_compile(const char *glsl, enum GLSlangStage stage)
Definition: glslang.cpp:152
ff_vk_init_sampler
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:766
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
fc
#define fc(width, name, range_min, range_max)
Definition: cbs_av1.c:551
AVFilterContext::hw_device_ctx
AVBufferRef * hw_device_ctx
For filters which will create hardware frames, sets the device the filter should create them in.
Definition: avfilter.h:402
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
av_bprint_append_data
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:157
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
SPIRVShader::local_size
int local_size[3]
Definition: vulkan.h:69
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:346
ImageViewCtx::view
VkImageView view
Definition: vulkan.c:822
descriptor_props::type
const char * type
Definition: vulkan.c:998
FFVkBuffer::buf
VkBuffer buf
Definition: vulkan.h:87
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
formats.h
ImageViewCtx
Definition: vulkan.c:821
CASE
#define CASE(VAL)
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2580
ff_vk_init_shader
SPIRVShader * ff_vk_init_shader(AVFilterContext *avctx, VulkanPipeline *pl, const char *name, VkShaderStageFlags stage)
Inits a shader for a specific pipeline.
Definition: vulkan.c:885
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:361
FFVkExecContext::sem_wait_dst
VkPipelineStageFlagBits * sem_wait_dst
Definition: vulkan.h:151
fail
#define fail()
Definition: checkasm.h:127
SPIRVShader
Definition: vulkan.h:66
frames
if it could not because there are no more frames
Definition: filter_design.txt:266
ff_vk_create_pipeline
VulkanPipeline * ff_vk_create_pipeline(AVFilterContext *avctx)
Inits a pipeline.
Definition: vulkan.c:1273
GLSLANG_COMPUTE
@ GLSLANG_COMPUTE
Definition: glslang.h:42
glslang_uninit
void glslang_uninit(void)
Definition: glslang.cpp:235
cqueue_create
static cqueue * cqueue_create(int size, int max_size)
Definition: af_dynaudnorm.c:153
ff_vk_add_exec_dep
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:464
ff_vk_compile_shader
int ff_vk_compile_shader(AVFilterContext *avctx, SPIRVShader *shd, const char *entrypoint)
Compiles the shader, entrypoint must be set to "main".
Definition: vulkan.c:939
descriptor_props::struct_size
size_t struct_size
Definition: vulkan.c:997
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
VulkanPipeline::push_consts
VkPushConstantRange * push_consts
Definition: vulkan.h:104
planes
static const struct @318 planes[]
GLSLC
#define GLSLC(N, S)
Definition: vulkan.h:38
ff_vk_filter_uninit
void ff_vk_filter_uninit(AVFilterContext *avctx)
Definition: vulkan.c:1412
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FFVkQueueCtx::queue
VkQueue queue
Definition: vulkan.h:123
AVHWFramesContext::height
int height
Definition: hwcontext.h:229
VulkanPipeline::desc_pool
VkDescriptorPool desc_pool
Definition: vulkan.h:109
vulkan_filter_set_device
static int vulkan_filter_set_device(AVFilterContext *avctx, AVBufferRef *device)
Definition: vulkan.c:601
VulkanPipeline::pipeline
VkPipeline pipeline
Definition: vulkan.h:97
av_fast_realloc
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:504
FFVkQueueCtx::frame_deps
AVFrame ** frame_deps
Definition: vulkan.h:131
s
#define s(width, name)
Definition: cbs_vp9.c:257
ff_vk_filter_config_input
int ff_vk_filter_config_input(AVFilterLink *inlink)
Definition: vulkan.c:632
FFVkExecContext::sem_sig_alloc
int sem_sig_alloc
Definition: vulkan.h:155
ff_comp_identity_map
const VkComponentMapping ff_comp_identity_map
Definition: vulkan.c:44
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:224
ff_set_common_formats_from_list
int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts)
Equivalent to ff_set_common_formats(ctx, ff_make_format_list(fmts))
Definition: formats.c:703
ctx
AVFormatContext * ctx
Definition: movenc.c:48
ff_vk_map_buffers
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:215
av_frame_clone
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:424
ff_vk_init_pipeline_layout
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:1177
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demuxing_decoding.c:41
ff_vk_add_descriptor_set
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:1017
VulkanPipeline
Definition: vulkan.h:92
f
#define f(width, name)
Definition: cbs_vp9.c:255
ff_vk_ret2str
const char * ff_vk_ret2str(VkResult res)
Converts Vulkan return values to strings.
Definition: vulkan.c:52
ff_vk_filter_config_output_inplace
int ff_vk_filter_config_output_inplace(AVFilterLink *outlink)
Definition: vulkan.c:672
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
ff_vk_set_compute_shader_sizes
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:906
ff_vk_bind_pipeline_exec
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:1313
if
if(ret)
Definition: filter_design.txt:179
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:379
GLSlangResult::error_msg
char * error_msg
Definition: glslang.h:33
descriptor_props::mem_quali
int mem_quali
Definition: vulkan.c:1000
FFVkQueueCtx
Definition: vulkan.h:121
flush
static void flush(AVCodecContext *avctx)
Definition: aacdec_template.c:593
NULL
#define NULL
Definition: coverity.c:32
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
av_buffer_unref
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:139
FFVkExecContext::sem_wait_alloc
int sem_wait_alloc
Definition: vulkan.h:148
FFVkExecContext::sem_sig_cnt
int sem_sig_cnt
Definition: vulkan.h:156
AVHWFramesContext::device_ref
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:141
print_shader
static void print_shader(AVFilterContext *avctx, SPIRVShader *shd, int prio)
Definition: vulkan.c:918
AVFilterContext::inputs
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:354
SPIRVShader::shader
VkPipelineShaderStageCreateInfo shader
Definition: vulkan.h:70
src
#define src
Definition: vp8dsp.c:255
ff_vk_get_exec_buf
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:458
descriptor_props::dim_needed
int dim_needed
Definition: vulkan.c:1001
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:230
VulkanPipeline::desc_layout
VkDescriptorSetLayout * desc_layout
Definition: vulkan.h:108
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
GLSLA
#define GLSLA(...)
Definition: vulkan.h:39
av_buffer_create
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:55
usage
const char * usage
Definition: floatimg_cmp.c:60
FFVkQueueCtx::fence
VkFence fence
Definition: vulkan.h:122
FFVkExecContext::pool
VkCommandPool pool
Definition: vulkan.h:137
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
VulkanPipeline::shaders
SPIRVShader ** shaders
Definition: vulkan.h:100
AVVkFrame
Definition: hwcontext_vulkan.h:168
ff_vk_update_push_exec
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:1168
vulkan.h
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
print
static void print(AVTreeNode *t, int depth)
Definition: tree.c:44
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:375
size
int size
Definition: twinvq_data.h:10344
FFVkExecContext::bound_pl
VulkanPipeline * bound_pl
Definition: vulkan.h:145
FFVkBuffer::flags
VkMemoryPropertyFlagBits flags
Definition: vulkan.h:89
img
#define img
Definition: vf_colormatrix.c:116
VulkanPipeline::push_consts_num
int push_consts_num
Definition: vulkan.h:105
VulkanPipeline::pool_size_desc
VkDescriptorPoolSize * pool_size_desc
Definition: vulkan.h:118
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
offset
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
Definition: writing_filters.txt:86
FFVkExecContext
Definition: vulkan.h:136
line
Definition: graph2dot.c:48
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:228
version
version
Definition: libkvazaar.c:307
ff_vk_filter_init
int ff_vk_filter_init(AVFilterContext *avctx)
Definition: vulkan.c:753
create_exec_ctx
static int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, int queue_family_index, int num_queues)
Definition: hwcontext_vulkan.c:996
ff_vk_update_descriptor_set
void ff_vk_update_descriptor_set(AVFilterContext *avctx, VulkanPipeline *pl, int set_id)
Updates a descriptor set via the updaters defined.
Definition: vulkan.c:1157
FFVkExecContext::sem_wait_cnt
int sem_wait_cnt
Definition: vulkan.h:149
FFVkQueueCtx::nb_buf_deps
int nb_buf_deps
Definition: vulkan.h:127
layout
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
Definition: filter_design.txt:18
i
int i
Definition: input.c:406
descriptor_props
Definition: vulkan.c:996
VulkanPipeline::desc_template
VkDescriptorUpdateTemplate * desc_template
Definition: vulkan.h:111
VulkanPipeline::shaders_num
int shaders_num
Definition: vulkan.h:101
VulkanPipeline::desc_set
VkDescriptorSet * desc_set
Definition: vulkan.h:110
FFVkBuffer::mem
VkDeviceMemory mem
Definition: vulkan.h:88
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:263
AV_PIX_FMT_BGR565
#define AV_PIX_FMT_BGR565
Definition: pixfmt.h:381
filt
static const int8_t filt[NUMTAPS *2]
Definition: af_earwax.c:39
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:376
GLSLANG_VERTEX
@ GLSLANG_VERTEX
Definition: glslang.h:40
FN_CREATING
#define FN_CREATING(ctx, type, shortname, array, num)
Definition: vulkan.c:25
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
glslang.h
SPIRVShader::src
AVBPrint src
Definition: vulkan.h:68
ret
ret
Definition: filter_design.txt:187
pixfmt
enum AVPixelFormat pixfmt
Definition: kmsgrab.c:365
AV_PIX_FMT_0BGR
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:229
frame
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
Definition: filter_design.txt:264
destroy_imageview
static void destroy_imageview(void *opaque, uint8_t *data)
Definition: vulkan.c:825
ff_vk_start_exec_recording
int ff_vk_start_exec_recording(AVFilterContext *avctx, FFVkExecContext *e)
Begin recording to the command buffer.
Definition: vulkan.c:417
descriptor_props::buf_content
int buf_content
Definition: vulkan.c:1002
ff_vk_create_buf
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
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:93
ff_vk_submit_exec_queue
int ff_vk_submit_exec_queue(AVFilterContext *avctx, FFVkExecContext *e)
Submits a command buffer to the queue for execution.
Definition: vulkan.c:522
vulkan_filter_set_frames
static int vulkan_filter_set_frames(AVFilterContext *avctx, AVBufferRef *frames)
Definition: vulkan.c:618
ff_vk_shader_rep_fmt
const char * ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt)
Gets the glsl format string for a pixel format.
Definition: vulkan.c:814
vk_alloc_mem
static int vk_alloc_mem(AVFilterContext *avctx, VkMemoryRequirements *req, VkMemoryPropertyFlagBits req_flags, void *alloc_extension, VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
Definition: vulkan.c:89
ff_vk_free_buf
void ff_vk_free_buf(AVFilterContext *avctx, FFVkBuffer *buf)
Frees a buffer.
Definition: vulkan.c:306
ff_vk_unmap_buffers
int ff_vk_unmap_buffers(AVFilterContext *avctx, FFVkBuffer *buf, int nb_buffers, int flush)
Unmaps the buffer from userspace.
Definition: vulkan.c:264
GLSLF
#define GLSLF(N, S,...)
Definition: vulkan.h:40
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
AVFilterContext
An instance of a filter.
Definition: avfilter.h:346
VulkanPipeline::desc_layout_num
int desc_layout_num
Definition: vulkan.h:112
desc
const char * desc
Definition: libsvtav1.c:79
ff_vk_create_exec_ctx
int ff_vk_create_exec_ctx(AVFilterContext *avctx, FFVkExecContext **ctx)
Init an execution context for command recording and queue submission.
Definition: vulkan.c:339
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
glslang_init
int glslang_init(void)
Definition: glslang.cpp:223
FFVkExecContext::bufs
VkCommandBuffer * bufs
Definition: vulkan.h:138
GLSlangResult::rval
int rval
Definition: glslang.h:32
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
ff_vk_add_push_constant
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:318
VulkanFilterContext
Definition: vulkan.h:159
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
SPIRVShader::name
const char * name
Definition: vulkan.h:67
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
ff_vk_discard_exec_deps
void ff_vk_discard_exec_deps(AVFilterContext *avctx, FFVkExecContext *e)
Discards all queue dependencies.
Definition: vulkan.c:400
FFVkBuffer
Definition: vulkan.h:86
VulkanPipeline::descriptor_sets_num
int descriptor_sets_num
Definition: vulkan.h:113
VulkanPipeline::pool_size_desc_num
int pool_size_desc_num
Definition: vulkan.h:114
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
ff_vk_init_compute_pipeline
int ff_vk_init_compute_pipeline(AVFilterContext *avctx, VulkanPipeline *pl)
Initializes a compute pipeline.
Definition: vulkan.c:1278
FFVkQueueCtx::nb_frame_deps
int nb_frame_deps
Definition: vulkan.h:132
int
int
Definition: ffmpeg_filter.c:156
ff_vk_create_imageview
int ff_vk_create_imageview(AVFilterContext *avctx, FFVkExecContext *e, VkImageView *v, VkImage img, VkFormat fmt, const VkComponentMapping map)
Create an imageview.
Definition: vulkan.c:833
FFVkQueueCtx::buf_deps
AVBufferRef ** buf_deps
Definition: vulkan.h:126
ff_vk_filter_config_output
int ff_vk_filter_config_output(AVFilterLink *outlink)
Definition: vulkan.c:702
VulkanPipeline::bind_point
VkPipelineBindPoint bind_point
Definition: vulkan.h:93