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 #include "libavutil/avassert.h"
25 
26 /* Generic macro for creating contexts which need to keep their addresses
27  * if another context is created. */
28 #define FN_CREATING(ctx, type, shortname, array, num) \
29 static av_always_inline type *create_ ##shortname(ctx *dctx) \
30 { \
31  type **array, *sctx = av_mallocz(sizeof(*sctx)); \
32  if (!sctx) \
33  return NULL; \
34  \
35  array = av_realloc_array(dctx->array, sizeof(*dctx->array), dctx->num + 1);\
36  if (!array) { \
37  av_free(sctx); \
38  return NULL; \
39  } \
40  \
41  dctx->array = array; \
42  dctx->array[dctx->num++] = sctx; \
43  \
44  return sctx; \
45 }
46 
47 const VkComponentMapping ff_comp_identity_map = {
48  .r = VK_COMPONENT_SWIZZLE_IDENTITY,
49  .g = VK_COMPONENT_SWIZZLE_IDENTITY,
50  .b = VK_COMPONENT_SWIZZLE_IDENTITY,
51  .a = VK_COMPONENT_SWIZZLE_IDENTITY,
52 };
53 
54 /* Converts return values to strings */
55 const char *ff_vk_ret2str(VkResult res)
56 {
57 #define CASE(VAL) case VAL: return #VAL
58  switch (res) {
59  CASE(VK_SUCCESS);
60  CASE(VK_NOT_READY);
61  CASE(VK_TIMEOUT);
62  CASE(VK_EVENT_SET);
63  CASE(VK_EVENT_RESET);
64  CASE(VK_INCOMPLETE);
65  CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
66  CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
67  CASE(VK_ERROR_INITIALIZATION_FAILED);
68  CASE(VK_ERROR_DEVICE_LOST);
69  CASE(VK_ERROR_MEMORY_MAP_FAILED);
70  CASE(VK_ERROR_LAYER_NOT_PRESENT);
71  CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
72  CASE(VK_ERROR_FEATURE_NOT_PRESENT);
73  CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
74  CASE(VK_ERROR_TOO_MANY_OBJECTS);
75  CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
76  CASE(VK_ERROR_FRAGMENTED_POOL);
77  CASE(VK_ERROR_SURFACE_LOST_KHR);
78  CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
79  CASE(VK_SUBOPTIMAL_KHR);
80  CASE(VK_ERROR_OUT_OF_DATE_KHR);
81  CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
82  CASE(VK_ERROR_VALIDATION_FAILED_EXT);
83  CASE(VK_ERROR_INVALID_SHADER_NV);
84  CASE(VK_ERROR_OUT_OF_POOL_MEMORY);
85  CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE);
86  CASE(VK_ERROR_NOT_PERMITTED_EXT);
87  default: return "Unknown error";
88  }
89 #undef CASE
90 }
91 
93  VkQueueFlagBits dev_family, int nb_queues)
94 {
95  FFVulkanContext *s = avctx->priv;
96 
97  switch (dev_family) {
98  case VK_QUEUE_GRAPHICS_BIT:
99  qf->queue_family = s->hwctx->queue_family_index;
100  qf->actual_queues = s->hwctx->nb_graphics_queues;
101  break;
102  case VK_QUEUE_COMPUTE_BIT:
103  qf->queue_family = s->hwctx->queue_family_comp_index;
104  qf->actual_queues = s->hwctx->nb_comp_queues;
105  break;
106  case VK_QUEUE_TRANSFER_BIT:
107  qf->queue_family = s->hwctx->queue_family_tx_index;
108  qf->actual_queues = s->hwctx->nb_tx_queues;
109  break;
110  case VK_QUEUE_VIDEO_ENCODE_BIT_KHR:
111  qf->queue_family = s->hwctx->queue_family_encode_index;
112  qf->actual_queues = s->hwctx->nb_encode_queues;
113  break;
114  case VK_QUEUE_VIDEO_DECODE_BIT_KHR:
115  qf->queue_family = s->hwctx->queue_family_decode_index;
116  qf->actual_queues = s->hwctx->nb_decode_queues;
117  break;
118  default:
119  av_assert0(0); /* Should never happen */
120  }
121 
122  if (!nb_queues)
123  qf->nb_queues = qf->actual_queues;
124  else
125  qf->nb_queues = nb_queues;
126 
127  return;
128 }
129 
131 {
132  qf->cur_queue = (qf->cur_queue + 1) % qf->nb_queues;
133 }
134 
135 static int vk_alloc_mem(AVFilterContext *avctx, VkMemoryRequirements *req,
136  VkMemoryPropertyFlagBits req_flags, void *alloc_extension,
137  VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
138 {
139  VkResult ret;
140  int index = -1;
141  FFVulkanContext *s = avctx->priv;
142  FFVulkanFunctions *vk = &s->vkfn;
143 
144  VkMemoryAllocateInfo alloc_info = {
145  .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
146  .pNext = alloc_extension,
147  };
148 
149  /* Align if we need to */
150  if (req_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
151  req->size = FFALIGN(req->size, s->props.limits.minMemoryMapAlignment);
152 
153  alloc_info.allocationSize = req->size;
154 
155  /* The vulkan spec requires memory types to be sorted in the "optimal"
156  * order, so the first matching type we find will be the best/fastest one */
157  for (int i = 0; i < s->mprops.memoryTypeCount; i++) {
158  /* The memory type must be supported by the requirements (bitfield) */
159  if (!(req->memoryTypeBits & (1 << i)))
160  continue;
161 
162  /* The memory type flags must include our properties */
163  if ((s->mprops.memoryTypes[i].propertyFlags & req_flags) != req_flags)
164  continue;
165 
166  /* Found a suitable memory type */
167  index = i;
168  break;
169  }
170 
171  if (index < 0) {
172  av_log(avctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
173  req_flags);
174  return AVERROR(EINVAL);
175  }
176 
177  alloc_info.memoryTypeIndex = index;
178 
179  ret = vk->AllocateMemory(s->hwctx->act_dev, &alloc_info,
180  s->hwctx->alloc, mem);
181  if (ret != VK_SUCCESS) {
182  av_log(avctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
183  ff_vk_ret2str(ret));
184  return AVERROR(ENOMEM);
185  }
186 
187  *mem_flags |= s->mprops.memoryTypes[index].propertyFlags;
188 
189  return 0;
190 }
191 
193  VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
194 {
195  int err;
196  VkResult ret;
197  int use_ded_mem;
198  FFVulkanContext *s = avctx->priv;
199  FFVulkanFunctions *vk = &s->vkfn;
200 
201  VkBufferCreateInfo buf_spawn = {
202  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
203  .pNext = NULL,
204  .usage = usage,
205  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
206  .size = size, /* Gets FFALIGNED during alloc if host visible
207  but should be ok */
208  };
209 
210  VkBufferMemoryRequirementsInfo2 req_desc = {
211  .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
212  };
213  VkMemoryDedicatedAllocateInfo ded_alloc = {
214  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
215  .pNext = NULL,
216  };
217  VkMemoryDedicatedRequirements ded_req = {
218  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
219  };
220  VkMemoryRequirements2 req = {
221  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
222  .pNext = &ded_req,
223  };
224 
225  ret = vk->CreateBuffer(s->hwctx->act_dev, &buf_spawn, NULL, &buf->buf);
226  if (ret != VK_SUCCESS) {
227  av_log(avctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
228  ff_vk_ret2str(ret));
229  return AVERROR_EXTERNAL;
230  }
231 
232  req_desc.buffer = buf->buf;
233 
234  vk->GetBufferMemoryRequirements2(s->hwctx->act_dev, &req_desc, &req);
235 
236  /* In case the implementation prefers/requires dedicated allocation */
237  use_ded_mem = ded_req.prefersDedicatedAllocation |
238  ded_req.requiresDedicatedAllocation;
239  if (use_ded_mem)
240  ded_alloc.buffer = buf->buf;
241 
242  err = vk_alloc_mem(avctx, &req.memoryRequirements, flags,
243  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
244  &buf->flags, &buf->mem);
245  if (err)
246  return err;
247 
248  ret = vk->BindBufferMemory(s->hwctx->act_dev, buf->buf, buf->mem, 0);
249  if (ret != VK_SUCCESS) {
250  av_log(avctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
251  ff_vk_ret2str(ret));
252  return AVERROR_EXTERNAL;
253  }
254 
255  return 0;
256 }
257 
258 int ff_vk_map_buffers(AVFilterContext *avctx, FFVkBuffer *buf, uint8_t *mem[],
259  int nb_buffers, int invalidate)
260 {
261  VkResult ret;
262  FFVulkanContext *s = avctx->priv;
263  FFVulkanFunctions *vk = &s->vkfn;
264  VkMappedMemoryRange *inval_list = NULL;
265  int inval_count = 0;
266 
267  for (int i = 0; i < nb_buffers; i++) {
268  ret = vk->MapMemory(s->hwctx->act_dev, buf[i].mem, 0,
269  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
270  if (ret != VK_SUCCESS) {
271  av_log(avctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
272  ff_vk_ret2str(ret));
273  return AVERROR_EXTERNAL;
274  }
275  }
276 
277  if (!invalidate)
278  return 0;
279 
280  for (int i = 0; i < nb_buffers; i++) {
281  const VkMappedMemoryRange ival_buf = {
282  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
283  .memory = buf[i].mem,
284  .size = VK_WHOLE_SIZE,
285  };
286  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
287  continue;
288  inval_list = av_fast_realloc(s->scratch, &s->scratch_size,
289  (++inval_count)*sizeof(*inval_list));
290  if (!inval_list)
291  return AVERROR(ENOMEM);
292  inval_list[inval_count - 1] = ival_buf;
293  }
294 
295  if (inval_count) {
296  ret = vk->InvalidateMappedMemoryRanges(s->hwctx->act_dev, inval_count,
297  inval_list);
298  if (ret != VK_SUCCESS) {
299  av_log(avctx, AV_LOG_ERROR, "Failed to invalidate memory: %s\n",
300  ff_vk_ret2str(ret));
301  return AVERROR_EXTERNAL;
302  }
303  }
304 
305  return 0;
306 }
307 
308 int ff_vk_unmap_buffers(AVFilterContext *avctx, FFVkBuffer *buf, int nb_buffers,
309  int flush)
310 {
311  int err = 0;
312  VkResult ret;
313  FFVulkanContext *s = avctx->priv;
314  FFVulkanFunctions *vk = &s->vkfn;
315  VkMappedMemoryRange *flush_list = NULL;
316  int flush_count = 0;
317 
318  if (flush) {
319  for (int i = 0; i < nb_buffers; i++) {
320  const VkMappedMemoryRange flush_buf = {
321  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
322  .memory = buf[i].mem,
323  .size = VK_WHOLE_SIZE,
324  };
325  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
326  continue;
327  flush_list = av_fast_realloc(s->scratch, &s->scratch_size,
328  (++flush_count)*sizeof(*flush_list));
329  if (!flush_list)
330  return AVERROR(ENOMEM);
331  flush_list[flush_count - 1] = flush_buf;
332  }
333  }
334 
335  if (flush_count) {
336  ret = vk->FlushMappedMemoryRanges(s->hwctx->act_dev, flush_count,
337  flush_list);
338  if (ret != VK_SUCCESS) {
339  av_log(avctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
340  ff_vk_ret2str(ret));
341  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
342  }
343  }
344 
345  for (int i = 0; i < nb_buffers; i++)
346  vk->UnmapMemory(s->hwctx->act_dev, buf[i].mem);
347 
348  return err;
349 }
350 
352 {
353  FFVulkanContext *s = avctx->priv;
354  FFVulkanFunctions *vk = &s->vkfn;
355 
356  if (!buf)
357  return;
358 
359  if (buf->buf != VK_NULL_HANDLE)
360  vk->DestroyBuffer(s->hwctx->act_dev, buf->buf, s->hwctx->alloc);
361  if (buf->mem != VK_NULL_HANDLE)
362  vk->FreeMemory(s->hwctx->act_dev, buf->mem, s->hwctx->alloc);
363 }
364 
366  int offset, int size, VkShaderStageFlagBits stage)
367 {
368  VkPushConstantRange *pc;
369 
370  pl->push_consts = av_realloc_array(pl->push_consts, sizeof(*pl->push_consts),
371  pl->push_consts_num + 1);
372  if (!pl->push_consts)
373  return AVERROR(ENOMEM);
374 
375  pc = &pl->push_consts[pl->push_consts_num++];
376  memset(pc, 0, sizeof(*pc));
377 
378  pc->stageFlags = stage;
379  pc->offset = offset;
380  pc->size = size;
381 
382  return 0;
383 }
384 
385 FN_CREATING(FFVulkanContext, FFVkExecContext, exec_ctx, exec_ctx, exec_ctx_num)
387  FFVkQueueFamilyCtx *qf)
388 {
389  VkResult ret;
390  FFVkExecContext *e;
391  FFVulkanContext *s = avctx->priv;
392  FFVulkanFunctions *vk = &s->vkfn;
393 
394  VkCommandPoolCreateInfo cqueue_create = {
395  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
396  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
397  .queueFamilyIndex = qf->queue_family,
398  };
399  VkCommandBufferAllocateInfo cbuf_create = {
400  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
401  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
402  .commandBufferCount = qf->nb_queues,
403  };
404 
405  e = create_exec_ctx(s);
406  if (!e)
407  return AVERROR(ENOMEM);
408 
409  e->qf = qf;
410 
411  e->queues = av_mallocz(qf->nb_queues * sizeof(*e->queues));
412  if (!e->queues)
413  return AVERROR(ENOMEM);
414 
415  e->bufs = av_mallocz(qf->nb_queues * sizeof(*e->bufs));
416  if (!e->bufs)
417  return AVERROR(ENOMEM);
418 
419  /* Create command pool */
420  ret = vk->CreateCommandPool(s->hwctx->act_dev, &cqueue_create,
421  s->hwctx->alloc, &e->pool);
422  if (ret != VK_SUCCESS) {
423  av_log(avctx, AV_LOG_ERROR, "Command pool creation failure: %s\n",
424  ff_vk_ret2str(ret));
425  return AVERROR_EXTERNAL;
426  }
427 
428  cbuf_create.commandPool = e->pool;
429 
430  /* Allocate command buffer */
431  ret = vk->AllocateCommandBuffers(s->hwctx->act_dev, &cbuf_create, e->bufs);
432  if (ret != VK_SUCCESS) {
433  av_log(avctx, AV_LOG_ERROR, "Command buffer alloc failure: %s\n",
434  ff_vk_ret2str(ret));
435  return AVERROR_EXTERNAL;
436  }
437 
438  for (int i = 0; i < qf->nb_queues; i++) {
439  FFVkQueueCtx *q = &e->queues[i];
440  vk->GetDeviceQueue(s->hwctx->act_dev, qf->queue_family,
441  i % qf->actual_queues, &q->queue);
442  }
443 
444  *ctx = e;
445 
446  return 0;
447 }
448 
450 {
451  FFVkQueueCtx *q = &e->queues[e->qf->cur_queue];
452 
453  for (int j = 0; j < q->nb_buf_deps; j++)
454  av_buffer_unref(&q->buf_deps[j]);
455  q->nb_buf_deps = 0;
456 
457  for (int j = 0; j < q->nb_frame_deps; j++)
458  av_frame_free(&q->frame_deps[j]);
459  q->nb_frame_deps = 0;
460 
461  e->sem_wait_cnt = 0;
462  e->sem_sig_cnt = 0;
463 }
464 
466 {
467  VkResult ret;
468  FFVulkanContext *s = avctx->priv;
469  FFVulkanFunctions *vk = &s->vkfn;
470  FFVkQueueCtx *q = &e->queues[e->qf->cur_queue];
471 
472  VkCommandBufferBeginInfo cmd_start = {
473  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
474  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
475  };
476 
477  /* Create the fence and don't wait for it initially */
478  if (!q->fence) {
479  VkFenceCreateInfo fence_spawn = {
480  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
481  };
482  ret = vk->CreateFence(s->hwctx->act_dev, &fence_spawn, s->hwctx->alloc,
483  &q->fence);
484  if (ret != VK_SUCCESS) {
485  av_log(avctx, AV_LOG_ERROR, "Failed to queue frame fence: %s\n",
486  ff_vk_ret2str(ret));
487  return AVERROR_EXTERNAL;
488  }
489  } else {
490  vk->WaitForFences(s->hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
491  vk->ResetFences(s->hwctx->act_dev, 1, &q->fence);
492  }
493 
494  /* Discard queue dependencies */
495  ff_vk_discard_exec_deps(avctx, e);
496 
497  ret = vk->BeginCommandBuffer(e->bufs[e->qf->cur_queue], &cmd_start);
498  if (ret != VK_SUCCESS) {
499  av_log(avctx, AV_LOG_ERROR, "Failed to start command recoding: %s\n",
500  ff_vk_ret2str(ret));
501  return AVERROR_EXTERNAL;
502  }
503 
504  return 0;
505 }
506 
508 {
509  return e->bufs[e->qf->cur_queue];
510 }
511 
513  AVFrame *frame, VkPipelineStageFlagBits in_wait_dst_flag)
514 {
515  AVFrame **dst;
516  AVVkFrame *f = (AVVkFrame *)frame->data[0];
517  FFVkQueueCtx *q = &e->queues[e->qf->cur_queue];
518  AVHWFramesContext *fc = (AVHWFramesContext *)frame->hw_frames_ctx->data;
519  int planes = av_pix_fmt_count_planes(fc->sw_format);
520 
521  for (int i = 0; i < planes; i++) {
523  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait));
524  if (!e->sem_wait) {
525  ff_vk_discard_exec_deps(avctx, e);
526  return AVERROR(ENOMEM);
527  }
528 
530  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait_dst));
531  if (!e->sem_wait_dst) {
532  ff_vk_discard_exec_deps(avctx, e);
533  return AVERROR(ENOMEM);
534  }
535 
537  (e->sem_wait_cnt + 1)*sizeof(*e->sem_wait_val));
538  if (!e->sem_wait_val) {
539  ff_vk_discard_exec_deps(avctx, e);
540  return AVERROR(ENOMEM);
541  }
542 
544  (e->sem_sig_cnt + 1)*sizeof(*e->sem_sig));
545  if (!e->sem_sig) {
546  ff_vk_discard_exec_deps(avctx, e);
547  return AVERROR(ENOMEM);
548  }
549 
551  (e->sem_sig_cnt + 1)*sizeof(*e->sem_sig_val));
552  if (!e->sem_sig_val) {
553  ff_vk_discard_exec_deps(avctx, e);
554  return AVERROR(ENOMEM);
555  }
556 
558  (e->sem_sig_cnt + 1)*sizeof(*e->sem_sig_val_dst));
559  if (!e->sem_sig_val_dst) {
560  ff_vk_discard_exec_deps(avctx, e);
561  return AVERROR(ENOMEM);
562  }
563 
564  e->sem_wait[e->sem_wait_cnt] = f->sem[i];
565  e->sem_wait_dst[e->sem_wait_cnt] = in_wait_dst_flag;
566  e->sem_wait_val[e->sem_wait_cnt] = f->sem_value[i];
567  e->sem_wait_cnt++;
568 
569  e->sem_sig[e->sem_sig_cnt] = f->sem[i];
570  e->sem_sig_val[e->sem_sig_cnt] = f->sem_value[i] + 1;
571  e->sem_sig_val_dst[e->sem_sig_cnt] = &f->sem_value[i];
572  e->sem_sig_cnt++;
573  }
574 
575  dst = av_fast_realloc(q->frame_deps, &q->frame_deps_alloc_size,
576  (q->nb_frame_deps + 1) * sizeof(*dst));
577  if (!dst) {
578  ff_vk_discard_exec_deps(avctx, e);
579  return AVERROR(ENOMEM);
580  }
581 
582  q->frame_deps = dst;
583  q->frame_deps[q->nb_frame_deps] = av_frame_clone(frame);
584  if (!q->frame_deps[q->nb_frame_deps]) {
585  ff_vk_discard_exec_deps(avctx, e);
586  return AVERROR(ENOMEM);
587  }
588  q->nb_frame_deps++;
589 
590  return 0;
591 }
592 
594 {
595  VkResult ret;
596  FFVulkanContext *s = avctx->priv;
597  FFVulkanFunctions *vk = &s->vkfn;
598  FFVkQueueCtx *q = &e->queues[e->qf->cur_queue];
599 
600  VkTimelineSemaphoreSubmitInfo s_timeline_sem_info = {
601  .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
602  .pWaitSemaphoreValues = e->sem_wait_val,
603  .pSignalSemaphoreValues = e->sem_sig_val,
604  .waitSemaphoreValueCount = e->sem_wait_cnt,
605  .signalSemaphoreValueCount = e->sem_sig_cnt,
606  };
607 
608  VkSubmitInfo s_info = {
609  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
610  .pNext = &s_timeline_sem_info,
611 
612  .commandBufferCount = 1,
613  .pCommandBuffers = &e->bufs[e->qf->cur_queue],
614 
615  .pWaitSemaphores = e->sem_wait,
616  .pWaitDstStageMask = e->sem_wait_dst,
617  .waitSemaphoreCount = e->sem_wait_cnt,
618 
619  .pSignalSemaphores = e->sem_sig,
620  .signalSemaphoreCount = e->sem_sig_cnt,
621  };
622 
623  ret = vk->EndCommandBuffer(e->bufs[e->qf->cur_queue]);
624  if (ret != VK_SUCCESS) {
625  av_log(avctx, AV_LOG_ERROR, "Unable to finish command buffer: %s\n",
626  ff_vk_ret2str(ret));
627  return AVERROR_EXTERNAL;
628  }
629 
630  ret = vk->QueueSubmit(q->queue, 1, &s_info, q->fence);
631  if (ret != VK_SUCCESS) {
632  av_log(avctx, AV_LOG_ERROR, "Unable to submit command buffer: %s\n",
633  ff_vk_ret2str(ret));
634  return AVERROR_EXTERNAL;
635  }
636 
637  for (int i = 0; i < e->sem_sig_cnt; i++)
638  *e->sem_sig_val_dst[i] += 1;
639 
640  return 0;
641 }
642 
644  AVBufferRef **deps, int nb_deps)
645 {
646  AVBufferRef **dst;
647  FFVkQueueCtx *q = &e->queues[e->qf->cur_queue];
648 
649  if (!deps || !nb_deps)
650  return 0;
651 
653  (q->nb_buf_deps + nb_deps) * sizeof(*dst));
654  if (!dst)
655  goto err;
656 
657  q->buf_deps = dst;
658 
659  for (int i = 0; i < nb_deps; i++) {
660  q->buf_deps[q->nb_buf_deps] = deps[i];
661  if (!q->buf_deps[q->nb_buf_deps])
662  goto err;
663  q->nb_buf_deps++;
664  }
665 
666  return 0;
667 
668 err:
669  ff_vk_discard_exec_deps(avctx, e);
670  return AVERROR(ENOMEM);
671 }
672 
674  AVBufferRef *device)
675 {
676  FFVulkanContext *s = avctx->priv;
677 
678  av_buffer_unref(&s->device_ref);
679 
680  s->device_ref = av_buffer_ref(device);
681  if (!s->device_ref)
682  return AVERROR(ENOMEM);
683 
684  s->device = (AVHWDeviceContext*)s->device_ref->data;
685  s->hwctx = s->device->hwctx;
686 
687  return 0;
688 }
689 
692 {
693  FFVulkanContext *s = avctx->priv;
694 
695  av_buffer_unref(&s->frames_ref);
696 
697  s->frames_ref = av_buffer_ref(frames);
698  if (!s->frames_ref)
699  return AVERROR(ENOMEM);
700 
701  return 0;
702 }
703 
705 {
706  int err;
707  AVFilterContext *avctx = inlink->dst;
708  FFVulkanContext *s = avctx->priv;
709  FFVulkanFunctions *vk = &s->vkfn;
710  AVHWFramesContext *input_frames;
711 
712  if (!inlink->hw_frames_ctx) {
713  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
714  "hardware frames context on the input.\n");
715  return AVERROR(EINVAL);
716  }
717 
718  /* Extract the device and default output format from the first input. */
719  if (avctx->inputs[0] != inlink)
720  return 0;
721 
722  input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
723  if (input_frames->format != AV_PIX_FMT_VULKAN)
724  return AVERROR(EINVAL);
725 
726  err = vulkan_filter_set_device(avctx, input_frames->device_ref);
727  if (err < 0)
728  return err;
729  err = vulkan_filter_set_frames(avctx, inlink->hw_frames_ctx);
730  if (err < 0)
731  return err;
732 
733  s->extensions = ff_vk_extensions_to_mask(s->hwctx->enabled_dev_extensions,
734  s->hwctx->nb_enabled_dev_extensions);
735 
736  err = ff_vk_load_functions(s->device, &s->vkfn, s->extensions, 1, 1);
737  if (err < 0)
738  return err;
739 
740  vk->GetPhysicalDeviceProperties(s->hwctx->phys_dev, &s->props);
741  vk->GetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &s->mprops);
742 
743  /* Default output parameters match input parameters. */
744  s->input_format = input_frames->sw_format;
745  if (s->output_format == AV_PIX_FMT_NONE)
746  s->output_format = input_frames->sw_format;
747  if (!s->output_width)
748  s->output_width = inlink->w;
749  if (!s->output_height)
750  s->output_height = inlink->h;
751 
752  return 0;
753 }
754 
756 {
757  int err;
758  AVFilterContext *avctx = outlink->src;
759  FFVulkanContext *s = avctx->priv;
760 
761  av_buffer_unref(&outlink->hw_frames_ctx);
762 
763  if (!s->device_ref) {
764  if (!avctx->hw_device_ctx) {
765  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
766  "Vulkan device.\n");
767  return AVERROR(EINVAL);
768  }
769 
770  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
771  if (err < 0)
772  return err;
773  }
774 
775  outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref);
776  if (!outlink->hw_frames_ctx)
777  return AVERROR(ENOMEM);
778 
779  outlink->w = s->output_width;
780  outlink->h = s->output_height;
781 
782  return 0;
783 }
784 
786 {
787  int err;
788  AVFilterContext *avctx = outlink->src;
789  FFVulkanContext *s = avctx->priv;
790  AVBufferRef *output_frames_ref;
791  AVHWFramesContext *output_frames;
792 
793  av_buffer_unref(&outlink->hw_frames_ctx);
794 
795  if (!s->device_ref) {
796  if (!avctx->hw_device_ctx) {
797  av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
798  "Vulkan device.\n");
799  return AVERROR(EINVAL);
800  }
801 
802  err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
803  if (err < 0)
804  return err;
805  }
806 
807  output_frames_ref = av_hwframe_ctx_alloc(s->device_ref);
808  if (!output_frames_ref) {
809  err = AVERROR(ENOMEM);
810  goto fail;
811  }
812  output_frames = (AVHWFramesContext*)output_frames_ref->data;
813 
814  output_frames->format = AV_PIX_FMT_VULKAN;
815  output_frames->sw_format = s->output_format;
816  output_frames->width = s->output_width;
817  output_frames->height = s->output_height;
818 
819  err = av_hwframe_ctx_init(output_frames_ref);
820  if (err < 0) {
821  av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
822  "frames: %d.\n", err);
823  goto fail;
824  }
825 
826  outlink->hw_frames_ctx = output_frames_ref;
827  outlink->w = s->output_width;
828  outlink->h = s->output_height;
829 
830  return 0;
831 fail:
832  av_buffer_unref(&output_frames_ref);
833  return err;
834 }
835 
837 {
838  FFVulkanContext *s = avctx->priv;
839 
840  s->output_format = AV_PIX_FMT_NONE;
841 
842  if (ff_vk_glslang_init())
843  return AVERROR_EXTERNAL;
844 
845  return 0;
846 }
847 
848 FN_CREATING(FFVulkanContext, FFVkSampler, sampler, samplers, samplers_num)
849 FFVkSampler *ff_vk_init_sampler(AVFilterContext *avctx, int unnorm_coords,
850  VkFilter filt)
851 {
852  VkResult ret;
853  FFVulkanContext *s = avctx->priv;
854  FFVulkanFunctions *vk = &s->vkfn;
855 
856  VkSamplerCreateInfo sampler_info = {
857  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
858  .magFilter = filt,
859  .minFilter = sampler_info.magFilter,
860  .mipmapMode = unnorm_coords ? VK_SAMPLER_MIPMAP_MODE_NEAREST :
861  VK_SAMPLER_MIPMAP_MODE_LINEAR,
862  .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
863  .addressModeV = sampler_info.addressModeU,
864  .addressModeW = sampler_info.addressModeU,
865  .anisotropyEnable = VK_FALSE,
866  .compareOp = VK_COMPARE_OP_NEVER,
867  .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
868  .unnormalizedCoordinates = unnorm_coords,
869  };
870 
871  FFVkSampler *sctx = create_sampler(s);
872  if (!sctx)
873  return NULL;
874 
875  ret = vk->CreateSampler(s->hwctx->act_dev, &sampler_info,
876  s->hwctx->alloc, &sctx->sampler[0]);
877  if (ret != VK_SUCCESS) {
878  av_log(avctx, AV_LOG_ERROR, "Unable to init sampler: %s\n",
879  ff_vk_ret2str(ret));
880  return NULL;
881  }
882 
883  for (int i = 1; i < 4; i++)
884  sctx->sampler[i] = sctx->sampler[0];
885 
886  return sctx;
887 }
888 
890 {
897  return 1;
898  return 0;
899 }
900 
902 {
904  const int high = desc->comp[0].depth > 8;
905  return high ? "rgba16f" : "rgba8";
906 }
907 
908 typedef struct ImageViewCtx {
909  VkImageView view;
910 } ImageViewCtx;
911 
912 static void destroy_imageview(void *opaque, uint8_t *data)
913 {
914  FFVulkanContext *s = opaque;
915  FFVulkanFunctions *vk = &s->vkfn;
916  ImageViewCtx *iv = (ImageViewCtx *)data;
917 
918  vk->DestroyImageView(s->hwctx->act_dev, iv->view, s->hwctx->alloc);
919  av_free(iv);
920 }
921 
923  VkImageView *v, VkImage img, VkFormat fmt,
924  const VkComponentMapping map)
925 {
926  int err;
927  AVBufferRef *buf;
928  FFVulkanContext *s = avctx->priv;
929  FFVulkanFunctions *vk = &s->vkfn;
930 
931  VkImageViewCreateInfo imgview_spawn = {
932  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
933  .pNext = NULL,
934  .image = img,
935  .viewType = VK_IMAGE_VIEW_TYPE_2D,
936  .format = fmt,
937  .components = map,
938  .subresourceRange = {
939  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
940  .baseMipLevel = 0,
941  .levelCount = 1,
942  .baseArrayLayer = 0,
943  .layerCount = 1,
944  },
945  };
946 
947  ImageViewCtx *iv = av_mallocz(sizeof(*iv));
948 
949  VkResult ret = vk->CreateImageView(s->hwctx->act_dev, &imgview_spawn,
950  s->hwctx->alloc, &iv->view);
951  if (ret != VK_SUCCESS) {
952  av_log(avctx, AV_LOG_ERROR, "Failed to create imageview: %s\n",
953  ff_vk_ret2str(ret));
954  return AVERROR_EXTERNAL;
955  }
956 
957  buf = av_buffer_create((uint8_t *)iv, sizeof(*iv), destroy_imageview, s, 0);
958  if (!buf) {
959  destroy_imageview(s, (uint8_t *)iv);
960  return AVERROR(ENOMEM);
961  }
962 
963  /* Add to queue dependencies */
964  err = ff_vk_add_dep_exec_ctx(avctx, e, &buf, 1);
965  if (err) {
966  av_buffer_unref(&buf);
967  return err;
968  }
969 
970  *v = iv->view;
971 
972  return 0;
973 }
974 
975 FN_CREATING(FFVulkanPipeline, FFSPIRVShader, shader, shaders, shaders_num)
977  const char *name, VkShaderStageFlags stage)
978 {
979  FFSPIRVShader *shd = create_shader(pl);
980  if (!shd)
981  return NULL;
982 
984 
985  shd->shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
986  shd->shader.stage = stage;
987 
988  shd->name = name;
989 
990  GLSLF(0, #version %i ,460);
991  GLSLC(0, #define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y)) );
992  GLSLC(0, );
993 
994  return shd;
995 }
996 
998  int local_size[3])
999 {
1000  shd->local_size[0] = local_size[0];
1001  shd->local_size[1] = local_size[1];
1002  shd->local_size[2] = local_size[2];
1003 
1004  av_bprintf(&shd->src, "layout (local_size_x = %i, "
1005  "local_size_y = %i, local_size_z = %i) in;\n\n",
1006  shd->local_size[0], shd->local_size[1], shd->local_size[2]);
1007 }
1008 
1010 {
1011  int line = 0;
1012  const char *p = shd->src.str;
1013  const char *start = p;
1014 
1015  AVBPrint buf;
1017 
1018  for (int i = 0; i < strlen(p); i++) {
1019  if (p[i] == '\n') {
1020  av_bprintf(&buf, "%i\t", ++line);
1021  av_bprint_append_data(&buf, start, &p[i] - start + 1);
1022  start = &p[i + 1];
1023  }
1024  }
1025 
1026  av_log(avctx, prio, "Shader %s: \n%s", shd->name, buf.str);
1027  av_bprint_finalize(&buf, NULL);
1028 }
1029 
1031  const char *entrypoint)
1032 {
1033  int err;
1034  VkResult ret;
1035  FFVulkanContext *s = avctx->priv;
1036  FFVulkanFunctions *vk = &s->vkfn;
1037  VkShaderModuleCreateInfo shader_create;
1038  uint8_t *spirv;
1039  size_t spirv_size;
1040  void *priv;
1041 
1042  shd->shader.pName = entrypoint;
1043 
1044  err = ff_vk_glslang_shader_compile(avctx, shd, &spirv, &spirv_size, &priv);
1045  if (err < 0)
1046  return err;
1047 
1048  ff_vk_print_shader(avctx, shd, AV_LOG_VERBOSE);
1049 
1050  av_log(avctx, AV_LOG_VERBOSE, "Shader %s compiled! Size: %zu bytes\n",
1051  shd->name, spirv_size);
1052 
1053  shader_create.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1054  shader_create.pNext = NULL;
1055  shader_create.codeSize = spirv_size;
1056  shader_create.flags = 0;
1057  shader_create.pCode = (void *)spirv;
1058 
1059  ret = vk->CreateShaderModule(s->hwctx->act_dev, &shader_create, NULL,
1060  &shd->shader.module);
1061 
1063 
1064  if (ret != VK_SUCCESS) {
1065  av_log(avctx, AV_LOG_ERROR, "Unable to create shader module: %s\n",
1066  ff_vk_ret2str(ret));
1067  return AVERROR_EXTERNAL;
1068  }
1069 
1070  return 0;
1071 }
1072 
1073 static const struct descriptor_props {
1074  size_t struct_size; /* Size of the opaque which updates the descriptor */
1075  const char *type;
1077  int mem_quali; /* Can use a memory qualifier */
1078  int dim_needed; /* Must indicate dimension */
1079  int buf_content; /* Must indicate buffer contents */
1080 } descriptor_props[] = {
1081  [VK_DESCRIPTOR_TYPE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 0, 0, },
1082  [VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] = { sizeof(VkDescriptorImageInfo), "texture", 1, 0, 1, 0, },
1083  [VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] = { sizeof(VkDescriptorImageInfo), "image", 1, 1, 1, 0, },
1084  [VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] = { sizeof(VkDescriptorImageInfo), "subpassInput", 1, 0, 0, 0, },
1085  [VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] = { sizeof(VkDescriptorImageInfo), "sampler", 1, 0, 1, 0, },
1086  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
1087  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
1088  [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), NULL, 1, 0, 0, 1, },
1089  [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), "buffer", 0, 1, 0, 1, },
1090  [VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] = { sizeof(VkBufferView), "samplerBuffer", 1, 0, 0, 0, },
1091  [VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER] = { sizeof(VkBufferView), "imageBuffer", 1, 0, 0, 0, },
1092 };
1093 
1096  int num, int only_print_to_shader)
1097 {
1098  VkResult ret;
1099  VkDescriptorSetLayout *layout;
1100  FFVulkanContext *s = avctx->priv;
1101  FFVulkanFunctions *vk = &s->vkfn;
1102 
1103  if (only_print_to_shader)
1104  goto print;
1105 
1106  pl->desc_layout = av_realloc_array(pl->desc_layout, sizeof(*pl->desc_layout),
1107  pl->desc_layout_num + pl->qf->nb_queues);
1108  if (!pl->desc_layout)
1109  return AVERROR(ENOMEM);
1110 
1112  sizeof(*pl->desc_set_initialized),
1113  pl->descriptor_sets_num + 1);
1114  if (!pl->desc_set_initialized)
1115  return AVERROR(ENOMEM);
1116 
1118  layout = &pl->desc_layout[pl->desc_layout_num];
1119 
1120  { /* Create descriptor set layout descriptions */
1121  VkDescriptorSetLayoutCreateInfo desc_create_layout = { 0 };
1122  VkDescriptorSetLayoutBinding *desc_binding;
1123 
1124  desc_binding = av_mallocz(sizeof(*desc_binding)*num);
1125  if (!desc_binding)
1126  return AVERROR(ENOMEM);
1127 
1128  for (int i = 0; i < num; i++) {
1129  desc_binding[i].binding = i;
1130  desc_binding[i].descriptorType = desc[i].type;
1131  desc_binding[i].descriptorCount = FFMAX(desc[i].elems, 1);
1132  desc_binding[i].stageFlags = desc[i].stages;
1133  desc_binding[i].pImmutableSamplers = desc[i].sampler ?
1134  desc[i].sampler->sampler :
1135  NULL;
1136  }
1137 
1138  desc_create_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
1139  desc_create_layout.pBindings = desc_binding;
1140  desc_create_layout.bindingCount = num;
1141 
1142  for (int i = 0; i < pl->qf->nb_queues; i++) {
1143  ret = vk->CreateDescriptorSetLayout(s->hwctx->act_dev, &desc_create_layout,
1144  s->hwctx->alloc, &layout[i]);
1145  if (ret != VK_SUCCESS) {
1146  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
1147  "layout: %s\n", ff_vk_ret2str(ret));
1148  av_free(desc_binding);
1149  return AVERROR_EXTERNAL;
1150  }
1151  }
1152 
1153  av_free(desc_binding);
1154  }
1155 
1156  { /* Pool each descriptor by type and update pool counts */
1157  for (int i = 0; i < num; i++) {
1158  int j;
1159  for (j = 0; j < pl->pool_size_desc_num; j++)
1160  if (pl->pool_size_desc[j].type == desc[i].type)
1161  break;
1162  if (j >= pl->pool_size_desc_num) {
1164  sizeof(*pl->pool_size_desc),
1165  ++pl->pool_size_desc_num);
1166  if (!pl->pool_size_desc)
1167  return AVERROR(ENOMEM);
1168  memset(&pl->pool_size_desc[j], 0, sizeof(VkDescriptorPoolSize));
1169  }
1170  pl->pool_size_desc[j].type = desc[i].type;
1171  pl->pool_size_desc[j].descriptorCount += FFMAX(desc[i].elems, 1)*pl->qf->nb_queues;
1172  }
1173  }
1174 
1175  { /* Create template creation struct */
1176  VkDescriptorUpdateTemplateCreateInfo *dt;
1177  VkDescriptorUpdateTemplateEntry *des_entries;
1178 
1179  /* Freed after descriptor set initialization */
1180  des_entries = av_mallocz(num*sizeof(VkDescriptorUpdateTemplateEntry));
1181  if (!des_entries)
1182  return AVERROR(ENOMEM);
1183 
1184  for (int i = 0; i < num; i++) {
1185  des_entries[i].dstBinding = i;
1186  des_entries[i].descriptorType = desc[i].type;
1187  des_entries[i].descriptorCount = FFMAX(desc[i].elems, 1);
1188  des_entries[i].dstArrayElement = 0;
1189  des_entries[i].offset = ((uint8_t *)desc[i].updater) - (uint8_t *)s;
1190  des_entries[i].stride = descriptor_props[desc[i].type].struct_size;
1191  }
1192 
1194  sizeof(*pl->desc_template_info),
1195  pl->total_descriptor_sets + pl->qf->nb_queues);
1196  if (!pl->desc_template_info)
1197  return AVERROR(ENOMEM);
1198 
1200  memset(dt, 0, sizeof(*dt)*pl->qf->nb_queues);
1201 
1202  for (int i = 0; i < pl->qf->nb_queues; i++) {
1203  dt[i].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO;
1204  dt[i].templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
1205  dt[i].descriptorSetLayout = layout[i];
1206  dt[i].pDescriptorUpdateEntries = des_entries;
1207  dt[i].descriptorUpdateEntryCount = num;
1208  }
1209  }
1210 
1211  pl->descriptor_sets_num++;
1212 
1213  pl->desc_layout_num += pl->qf->nb_queues;
1214  pl->total_descriptor_sets += pl->qf->nb_queues;
1215 
1216 print:
1217  /* Write shader info */
1218  for (int i = 0; i < num; i++) {
1219  const struct descriptor_props *prop = &descriptor_props[desc[i].type];
1220  GLSLA("layout (set = %i, binding = %i", pl->descriptor_sets_num - 1, i);
1221 
1222  if (desc[i].mem_layout)
1223  GLSLA(", %s", desc[i].mem_layout);
1224  GLSLA(")");
1225 
1226  if (prop->is_uniform)
1227  GLSLA(" uniform");
1228 
1229  if (prop->mem_quali && desc[i].mem_quali)
1230  GLSLA(" %s", desc[i].mem_quali);
1231 
1232  if (prop->type)
1233  GLSLA(" %s", prop->type);
1234 
1235  if (prop->dim_needed)
1236  GLSLA("%iD", desc[i].dimensions);
1237 
1238  GLSLA(" %s", desc[i].name);
1239 
1240  if (prop->buf_content)
1241  GLSLA(" {\n %s\n}", desc[i].buf_content);
1242  else if (desc[i].elems > 0)
1243  GLSLA("[%i]", desc[i].elems);
1244 
1245  GLSLA(";\n");
1246  }
1247  GLSLA("\n");
1248 
1249  return 0;
1250 }
1251 
1253  int set_id)
1254 {
1255  FFVulkanContext *s = avctx->priv;
1256  FFVulkanFunctions *vk = &s->vkfn;
1257 
1258  /* If a set has never been updated, update all queues' sets. */
1259  if (!pl->desc_set_initialized[set_id]) {
1260  for (int i = 0; i < pl->qf->nb_queues; i++) {
1261  int idx = set_id*pl->qf->nb_queues + i;
1262  vk->UpdateDescriptorSetWithTemplate(s->hwctx->act_dev,
1263  pl->desc_set[idx],
1264  pl->desc_template[idx],
1265  s);
1266  }
1267  pl->desc_set_initialized[set_id] = 1;
1268  return;
1269  }
1270 
1271  set_id = set_id*pl->qf->nb_queues + pl->qf->cur_queue;
1272 
1273  vk->UpdateDescriptorSetWithTemplate(s->hwctx->act_dev,
1274  pl->desc_set[set_id],
1275  pl->desc_template[set_id],
1276  s);
1277 }
1278 
1280  VkShaderStageFlagBits stage, int offset,
1281  size_t size, void *src)
1282 {
1283  FFVulkanContext *s = avctx->priv;
1284  FFVulkanFunctions *vk = &s->vkfn;
1285 
1286  vk->CmdPushConstants(e->bufs[e->qf->cur_queue], e->bound_pl->pipeline_layout,
1287  stage, offset, size, src);
1288 }
1289 
1291 {
1292  VkResult ret;
1293  FFVulkanContext *s = avctx->priv;
1294  FFVulkanFunctions *vk = &s->vkfn;
1295 
1296  pl->desc_staging = av_malloc(pl->descriptor_sets_num*sizeof(*pl->desc_staging));
1297  if (!pl->desc_staging)
1298  return AVERROR(ENOMEM);
1299 
1300  { /* Init descriptor set pool */
1301  VkDescriptorPoolCreateInfo pool_create_info = {
1302  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1303  .poolSizeCount = pl->pool_size_desc_num,
1304  .pPoolSizes = pl->pool_size_desc,
1305  .maxSets = pl->total_descriptor_sets,
1306  };
1307 
1308  ret = vk->CreateDescriptorPool(s->hwctx->act_dev, &pool_create_info,
1309  s->hwctx->alloc, &pl->desc_pool);
1310  av_freep(&pl->pool_size_desc);
1311  if (ret != VK_SUCCESS) {
1312  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor set "
1313  "pool: %s\n", ff_vk_ret2str(ret));
1314  return AVERROR_EXTERNAL;
1315  }
1316  }
1317 
1318  { /* Allocate descriptor sets */
1319  VkDescriptorSetAllocateInfo alloc_info = {
1320  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1321  .descriptorPool = pl->desc_pool,
1322  .descriptorSetCount = pl->total_descriptor_sets,
1323  .pSetLayouts = pl->desc_layout,
1324  };
1325 
1326  pl->desc_set = av_malloc(pl->total_descriptor_sets*sizeof(*pl->desc_set));
1327  if (!pl->desc_set)
1328  return AVERROR(ENOMEM);
1329 
1330  ret = vk->AllocateDescriptorSets(s->hwctx->act_dev, &alloc_info,
1331  pl->desc_set);
1332  if (ret != VK_SUCCESS) {
1333  av_log(avctx, AV_LOG_ERROR, "Unable to allocate descriptor set: %s\n",
1334  ff_vk_ret2str(ret));
1335  return AVERROR_EXTERNAL;
1336  }
1337  }
1338 
1339  { /* Finally create the pipeline layout */
1340  VkPipelineLayoutCreateInfo spawn_pipeline_layout = {
1341  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1342  .pSetLayouts = (VkDescriptorSetLayout *)pl->desc_staging,
1343  .pushConstantRangeCount = pl->push_consts_num,
1344  .pPushConstantRanges = pl->push_consts,
1345  };
1346 
1347  for (int i = 0; i < pl->total_descriptor_sets; i += pl->qf->nb_queues)
1348  pl->desc_staging[spawn_pipeline_layout.setLayoutCount++] = pl->desc_layout[i];
1349 
1350  ret = vk->CreatePipelineLayout(s->hwctx->act_dev, &spawn_pipeline_layout,
1351  s->hwctx->alloc, &pl->pipeline_layout);
1352  av_freep(&pl->push_consts);
1353  pl->push_consts_num = 0;
1354  if (ret != VK_SUCCESS) {
1355  av_log(avctx, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n",
1356  ff_vk_ret2str(ret));
1357  return AVERROR_EXTERNAL;
1358  }
1359  }
1360 
1361  { /* Descriptor template (for tightly packed descriptors) */
1362  VkDescriptorUpdateTemplateCreateInfo *dt;
1363 
1365  if (!pl->desc_template)
1366  return AVERROR(ENOMEM);
1367 
1368  /* Create update templates for the descriptor sets */
1369  for (int i = 0; i < pl->total_descriptor_sets; i++) {
1370  dt = &pl->desc_template_info[i];
1371  dt->pipelineLayout = pl->pipeline_layout;
1372  ret = vk->CreateDescriptorUpdateTemplate(s->hwctx->act_dev,
1373  dt, s->hwctx->alloc,
1374  &pl->desc_template[i]);
1375  if (ret != VK_SUCCESS) {
1376  av_log(avctx, AV_LOG_ERROR, "Unable to init descriptor "
1377  "template: %s\n", ff_vk_ret2str(ret));
1378  return AVERROR_EXTERNAL;
1379  }
1380  }
1381 
1382  /* Free the duplicated memory used for the template entries */
1383  for (int i = 0; i < pl->total_descriptor_sets; i += pl->qf->nb_queues) {
1384  dt = &pl->desc_template_info[i];
1385  av_free((void *)dt->pDescriptorUpdateEntries);
1386  }
1387 
1389  }
1390 
1391  return 0;
1392 }
1393 
1394 FN_CREATING(FFVulkanContext, FFVulkanPipeline, pipeline, pipelines, pipelines_num)
1396  FFVkQueueFamilyCtx *qf)
1397 {
1398  FFVulkanPipeline *pl = create_pipeline(avctx->priv);
1399  if (pl)
1400  pl->qf = qf;
1401 
1402  return pl;
1403 }
1404 
1406 {
1407  int i;
1408  VkResult ret;
1409  FFVulkanContext *s = avctx->priv;
1410  FFVulkanFunctions *vk = &s->vkfn;
1411 
1412  VkComputePipelineCreateInfo pipe = {
1413  .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1414  .layout = pl->pipeline_layout,
1415  };
1416 
1417  for (i = 0; i < pl->shaders_num; i++) {
1418  if (pl->shaders[i]->shader.stage & VK_SHADER_STAGE_COMPUTE_BIT) {
1419  pipe.stage = pl->shaders[i]->shader;
1420  break;
1421  }
1422  }
1423  if (i == pl->shaders_num) {
1424  av_log(avctx, AV_LOG_ERROR, "Can't init compute pipeline, no shader\n");
1425  return AVERROR(EINVAL);
1426  }
1427 
1428  ret = vk->CreateComputePipelines(s->hwctx->act_dev, VK_NULL_HANDLE, 1, &pipe,
1429  s->hwctx->alloc, &pl->pipeline);
1430  if (ret != VK_SUCCESS) {
1431  av_log(avctx, AV_LOG_ERROR, "Unable to init compute pipeline: %s\n",
1432  ff_vk_ret2str(ret));
1433  return AVERROR_EXTERNAL;
1434  }
1435 
1436  pl->bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
1437 
1438  return 0;
1439 }
1440 
1442  FFVulkanPipeline *pl)
1443 {
1444  FFVulkanContext *s = avctx->priv;
1445  FFVulkanFunctions *vk = &s->vkfn;
1446 
1447  vk->CmdBindPipeline(e->bufs[e->qf->cur_queue], pl->bind_point, pl->pipeline);
1448 
1449  for (int i = 0; i < pl->descriptor_sets_num; i++)
1450  pl->desc_staging[i] = pl->desc_set[i*pl->qf->nb_queues + pl->qf->cur_queue];
1451 
1452  vk->CmdBindDescriptorSets(e->bufs[e->qf->cur_queue], pl->bind_point,
1453  pl->pipeline_layout, 0,
1454  pl->descriptor_sets_num,
1455  (VkDescriptorSet *)pl->desc_staging,
1456  0, NULL);
1457 
1458  e->bound_pl = pl;
1459 }
1460 
1462 {
1463  FFVulkanFunctions *vk = &s->vkfn;
1464 
1465  /* Make sure all queues have finished executing */
1466  for (int i = 0; i < e->qf->nb_queues; i++) {
1467  FFVkQueueCtx *q = &e->queues[i];
1468 
1469  if (q->fence) {
1470  vk->WaitForFences(s->hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
1471  vk->ResetFences(s->hwctx->act_dev, 1, &q->fence);
1472  }
1473 
1474  /* Free the fence */
1475  if (q->fence)
1476  vk->DestroyFence(s->hwctx->act_dev, q->fence, s->hwctx->alloc);
1477 
1478  /* Free buffer dependencies */
1479  for (int j = 0; j < q->nb_buf_deps; j++)
1480  av_buffer_unref(&q->buf_deps[j]);
1481  av_free(q->buf_deps);
1482 
1483  /* Free frame dependencies */
1484  for (int j = 0; j < q->nb_frame_deps; j++)
1485  av_frame_free(&q->frame_deps[j]);
1486  av_free(q->frame_deps);
1487  }
1488 
1489  if (e->bufs)
1490  vk->FreeCommandBuffers(s->hwctx->act_dev, e->pool, e->qf->nb_queues, e->bufs);
1491  if (e->pool)
1492  vk->DestroyCommandPool(s->hwctx->act_dev, e->pool, s->hwctx->alloc);
1493 
1494  av_freep(&e->bufs);
1495  av_freep(&e->queues);
1496  av_freep(&e->sem_sig);
1497  av_freep(&e->sem_sig_val);
1499  av_freep(&e->sem_wait);
1500  av_freep(&e->sem_wait_dst);
1501  av_freep(&e->sem_wait_val);
1502  av_free(e);
1503 }
1504 
1506 {
1507  FFVulkanFunctions *vk = &s->vkfn;
1508 
1509  for (int i = 0; i < pl->shaders_num; i++) {
1510  FFSPIRVShader *shd = pl->shaders[i];
1511  av_bprint_finalize(&shd->src, NULL);
1512  vk->DestroyShaderModule(s->hwctx->act_dev, shd->shader.module,
1513  s->hwctx->alloc);
1514  av_free(shd);
1515  }
1516 
1517  vk->DestroyPipeline(s->hwctx->act_dev, pl->pipeline, s->hwctx->alloc);
1518  vk->DestroyPipelineLayout(s->hwctx->act_dev, pl->pipeline_layout,
1519  s->hwctx->alloc);
1520 
1521  for (int i = 0; i < pl->desc_layout_num; i++) {
1522  if (pl->desc_template && pl->desc_template[i])
1523  vk->DestroyDescriptorUpdateTemplate(s->hwctx->act_dev, pl->desc_template[i],
1524  s->hwctx->alloc);
1525  if (pl->desc_layout && pl->desc_layout[i])
1526  vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, pl->desc_layout[i],
1527  s->hwctx->alloc);
1528  }
1529 
1530  /* Also frees the descriptor sets */
1531  if (pl->desc_pool)
1532  vk->DestroyDescriptorPool(s->hwctx->act_dev, pl->desc_pool,
1533  s->hwctx->alloc);
1534 
1535  av_freep(&pl->desc_staging);
1536  av_freep(&pl->desc_set);
1537  av_freep(&pl->shaders);
1538  av_freep(&pl->desc_layout);
1539  av_freep(&pl->desc_template);
1541  av_freep(&pl->push_consts);
1542  pl->push_consts_num = 0;
1543 
1544  /* Only freed in case of failure */
1545  av_freep(&pl->pool_size_desc);
1546  if (pl->desc_template_info) {
1547  for (int i = 0; i < pl->total_descriptor_sets; i += pl->qf->nb_queues) {
1548  VkDescriptorUpdateTemplateCreateInfo *dt = &pl->desc_template_info[i];
1549  av_free((void *)dt->pDescriptorUpdateEntries);
1550  }
1552  }
1553 
1554  av_free(pl);
1555 }
1556 
1558 {
1559  FFVulkanContext *s = avctx->priv;
1560  FFVulkanFunctions *vk = &s->vkfn;
1561 
1563 
1564  for (int i = 0; i < s->exec_ctx_num; i++)
1565  free_exec_ctx(s, s->exec_ctx[i]);
1566  av_freep(&s->exec_ctx);
1567 
1568  for (int i = 0; i < s->samplers_num; i++) {
1569  vk->DestroySampler(s->hwctx->act_dev, s->samplers[i]->sampler[0],
1570  s->hwctx->alloc);
1571  av_free(s->samplers[i]);
1572  }
1573  av_freep(&s->samplers);
1574 
1575  for (int i = 0; i < s->pipelines_num; i++)
1576  free_pipeline(s, s->pipelines[i]);
1577  av_freep(&s->pipelines);
1578 
1579  av_freep(&s->scratch);
1580  s->scratch_size = 0;
1581 
1582  av_buffer_unref(&s->device_ref);
1583  av_buffer_unref(&s->frames_ref);
1584 }
FFVkExecContext::queues
FFVkQueueCtx * queues
Definition: vulkan.h:148
vulkan_loader.h
FFVulkanPipeline::bind_point
VkPipelineBindPoint bind_point
Definition: vulkan.h:96
ff_vk_print_shader
void ff_vk_print_shader(AVFilterContext *avctx, FFSPIRVShader *shd, int prio)
Pretty print shader, mainly used by shader compilers.
Definition: vulkan.c:1009
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:164
FFVkExecContext::sem_wait
VkSemaphore * sem_wait
Definition: vulkan.h:156
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
ff_vk_init_pipeline_layout
int ff_vk_init_pipeline_layout(AVFilterContext *avctx, FFVulkanPipeline *pl)
Initializes the pipeline layout after all shaders and descriptor sets have been finished.
Definition: vulkan.c:1290
FFVulkanPipeline::shaders_num
int shaders_num
Definition: vulkan.h:104
FFVkExecContext::qf
FFVkQueueFamilyCtx * qf
Definition: vulkan.h:144
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:234
ff_vk_glslang_uninit
void ff_vk_glslang_uninit(void)
Definition: glslang.c:250
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:68
FFVulkanPipeline::pipeline_layout
VkPipelineLayout pipeline_layout
Definition: vulkan.h:99
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2564
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
FFVkExecContext::sem_sig
VkSemaphore * sem_sig
Definition: vulkan.h:166
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:1076
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
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:310
index
fg index
Definition: ffmpeg_filter.c:168
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:889
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:643
data
const char data[16]
Definition: mxf.c:143
FFVkQueueCtx::buf_deps_alloc_size
int buf_deps_alloc_size
Definition: vulkan.h:135
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
free_pipeline
static void free_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl)
Definition: vulkan.c:1505
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:442
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
FFVulkanPipeline::desc_pool
VkDescriptorPool desc_pool
Definition: vulkan.h:112
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
ff_vk_create_exec_ctx
int ff_vk_create_exec_ctx(AVFilterContext *avctx, FFVkExecContext **ctx, FFVkQueueFamilyCtx *qf)
Init an execution context for command recording and queue submission.
Definition: vulkan.c:386
FFVulkanPipeline::desc_staging
void ** desc_staging
Definition: vulkan.h:114
FFVkExecContext::bound_pl
FFVulkanPipeline * bound_pl
Definition: vulkan.h:154
ff_vk_add_descriptor_set
int ff_vk_add_descriptor_set(AVFilterContext *avctx, FFVulkanPipeline *pl, FFSPIRVShader *shd, FFVulkanDescriptorSetBinding *desc, int num, int only_print_to_shader)
Adds a descriptor set to the shader and registers them in the pipeline.
Definition: vulkan.c:1094
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:346
ImageViewCtx::view
VkImageView view
Definition: vulkan.c:909
FFVkSampler
Definition: vulkan.h:63
descriptor_props::type
const char * type
Definition: vulkan.c:1075
FFVkBuffer::buf
VkBuffer buf
Definition: vulkan.h:81
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
formats.h
ImageViewCtx
Definition: vulkan.c:908
CASE
#define CASE(VAL)
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2604
ff_vk_update_descriptor_set
void ff_vk_update_descriptor_set(AVFilterContext *avctx, FFVulkanPipeline *pl, int set_id)
Updates a descriptor set via the updaters defined.
Definition: vulkan.c:1252
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:401
FFVkExecContext::sem_wait_dst
VkPipelineStageFlagBits * sem_wait_dst
Definition: vulkan.h:163
fail
#define fail()
Definition: checkasm.h:127
frames
if it could not because there are no more frames
Definition: filter_design.txt:266
FFVulkanPipeline::pipeline
VkPipeline pipeline
Definition: vulkan.h:100
FFSPIRVShader::name
const char * name
Definition: vulkan.h:57
FFVkExecContext::sem_sig_val_dst_alloc
int sem_sig_val_dst_alloc
Definition: vulkan.h:174
cqueue_create
static cqueue * cqueue_create(int size, int max_size)
Definition: af_dynaudnorm.c:136
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:512
descriptor_props::struct_size
size_t struct_size
Definition: vulkan.c:1074
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
FFVkQueueFamilyCtx::actual_queues
int actual_queues
Definition: vulkan.h:90
avassert.h
GLSLC
#define GLSLC(N, S)
Definition: vulkan.h:42
ff_vk_filter_uninit
void ff_vk_filter_uninit(AVFilterContext *avctx)
Definition: vulkan.c:1557
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
ff_vk_qf_init
void ff_vk_qf_init(AVFilterContext *avctx, FFVkQueueFamilyCtx *qf, VkQueueFlagBits dev_family, int nb_queues)
Initialize a queue family with a specific number of queues.
Definition: vulkan.c:92
FFVkQueueCtx::queue
VkQueue queue
Definition: vulkan.h:130
AVHWFramesContext::height
int height
Definition: hwcontext.h:229
vulkan_filter_set_device
static int vulkan_filter_set_device(AVFilterContext *avctx, AVBufferRef *device)
Definition: vulkan.c:673
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:138
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:704
ff_vk_qf_rotate
void ff_vk_qf_rotate(FFVkQueueFamilyCtx *qf)
Rotate through the queues in a queue family.
Definition: vulkan.c:130
FFVkExecContext::sem_sig_alloc
int sem_sig_alloc
Definition: vulkan.h:167
ff_comp_identity_map
const VkComponentMapping ff_comp_identity_map
Definition: vulkan.c:47
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:224
ff_vk_load_functions
static int ff_vk_load_functions(AVHWDeviceContext *ctx, FFVulkanFunctions *vk, uint64_t extensions_mask, int has_inst, int has_dev)
Function loader.
Definition: vulkan_loader.h:80
FFVulkanPipeline::desc_template
VkDescriptorUpdateTemplate * desc_template
Definition: vulkan.h:116
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
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:258
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
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demuxing_decoding.c:41
FFVkExecContext::sem_sig_val
uint64_t * sem_sig_val
Definition: vulkan.h:170
free_exec_ctx
static void free_exec_ctx(FFVulkanContext *s, FFVkExecContext *e)
Definition: vulkan.c:1461
f
#define f(width, name)
Definition: cbs_vp9.c:255
FFVulkanPipeline::desc_template_info
VkDescriptorUpdateTemplateCreateInfo * desc_template_info
Definition: vulkan.h:124
ff_vk_ret2str
const char * ff_vk_ret2str(VkResult res)
Converts Vulkan return values to strings.
Definition: vulkan.c:55
ff_vk_filter_config_output_inplace
int ff_vk_filter_config_output_inplace(AVFilterLink *outlink)
Definition: vulkan.c:755
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
FFVkSampler::sampler
VkSampler sampler[4]
Definition: vulkan.h:64
planes
static const struct @321 planes[]
if
if(ret)
Definition: filter_design.txt:179
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:381
descriptor_props::mem_quali
int mem_quali
Definition: vulkan.c:1077
FFVkQueueCtx
Definition: vulkan.h:128
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
ff_vk_add_push_constant
int ff_vk_add_push_constant(AVFilterContext *avctx, FFVulkanPipeline *pl, int offset, int size, VkShaderStageFlagBits stage)
Define a push constant for a given stage into a pipeline.
Definition: vulkan.c:365
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:157
FFVkExecContext::sem_sig_cnt
int sem_sig_cnt
Definition: vulkan.h:168
AVHWFramesContext::device_ref
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:141
AVFilterContext::inputs
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:394
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:507
descriptor_props::dim_needed
int dim_needed
Definition: vulkan.c:1078
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:230
FFVkExecContext::sem_sig_val_alloc
int sem_sig_val_alloc
Definition: vulkan.h:171
FFVulkanContext
Definition: vulkan.h:177
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
FFVulkanPipeline
Definition: vulkan.h:93
GLSLA
#define GLSLA(...)
Definition: vulkan.h:43
ff_vk_set_compute_shader_sizes
void ff_vk_set_compute_shader_sizes(AVFilterContext *avctx, FFSPIRVShader *shd, int local_size[3])
Writes the workgroup size for a shader.
Definition: vulkan.c:997
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:129
FFVulkanPipeline::desc_layout_num
int desc_layout_num
Definition: vulkan.h:118
FFVkExecContext::pool
VkCommandPool pool
Definition: vulkan.h:146
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
FFVulkanPipeline::total_descriptor_sets
int total_descriptor_sets
Definition: vulkan.h:120
FFVulkanDescriptorSetBinding
Definition: vulkan.h:67
AVVkFrame
Definition: hwcontext_vulkan.h:183
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:1279
vulkan.h
print
static void print(AVTreeNode *t, int depth)
Definition: tree.c:44
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:377
size
int size
Definition: twinvq_data.h:10344
FFVkQueueFamilyCtx
Definition: vulkan.h:86
FFVulkanPipeline::shaders
FFSPIRVShader ** shaders
Definition: vulkan.h:103
FFVkBuffer::flags
VkMemoryPropertyFlagBits flags
Definition: vulkan.h:83
img
#define img
Definition: vf_colormatrix.c:116
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:143
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
FFVulkanPipeline::desc_set
VkDescriptorSet * desc_set
Definition: vulkan.h:113
version
version
Definition: libkvazaar.c:307
FFSPIRVShader::shader
VkPipelineShaderStageCreateInfo shader
Definition: vulkan.h:60
ff_vk_glslang_shader_free
void ff_vk_glslang_shader_free(void *opaque)
Frees the shader-specific context.
Definition: glslang.c:233
ff_vk_filter_init
int ff_vk_filter_init(AVFilterContext *avctx)
General lavfi IO functions.
Definition: vulkan.c:836
create_exec_ctx
static int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, int queue_family_index, int num_queues)
Definition: hwcontext_vulkan.c:917
FFVkExecContext::sem_wait_cnt
int sem_wait_cnt
Definition: vulkan.h:158
FFVkQueueCtx::nb_buf_deps
int nb_buf_deps
Definition: vulkan.h:134
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
descriptor_props
Definition: vulkan.c:1073
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
FFVulkanPipeline::pool_size_desc
VkDescriptorPoolSize * pool_size_desc
Definition: vulkan.h:125
ff_vk_init_sampler
FFVkSampler * 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:849
FFVulkanPipeline::push_consts
VkPushConstantRange * push_consts
Definition: vulkan.h:107
ff_vk_glslang_init
int ff_vk_glslang_init(void)
Un/initialize glslang's global state.
Definition: glslang.c:238
FFSPIRVShader::src
AVBPrint src
Definition: vulkan.h:58
FFVulkanPipeline::qf
FFVkQueueFamilyCtx * qf
Definition: vulkan.h:94
FFVkBuffer::mem
VkDeviceMemory mem
Definition: vulkan.h:82
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:383
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:378
FN_CREATING
#define FN_CREATING(ctx, type, shortname, array, num)
Definition: vulkan.c:28
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
glslang.h
FFVulkanPipeline::desc_set_initialized
int * desc_set_initialized
Definition: vulkan.h:117
FFVulkanPipeline::push_consts_num
int push_consts_num
Definition: vulkan.h:108
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:912
ff_vk_start_exec_recording
int ff_vk_start_exec_recording(AVFilterContext *avctx, FFVkExecContext *e)
Begin recording to the command buffer.
Definition: vulkan.c:465
descriptor_props::buf_content
int buf_content
Definition: vulkan.c:1079
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:192
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:93
FFSPIRVShader::local_size
int local_size[3]
Definition: vulkan.h:59
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:593
vulkan_filter_set_frames
static int vulkan_filter_set_frames(AVFilterContext *avctx, AVBufferRef *frames)
Definition: vulkan.c:690
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:901
FFVkQueueFamilyCtx::nb_queues
int nb_queues
Definition: vulkan.h:88
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:135
ff_vk_free_buf
void ff_vk_free_buf(AVFilterContext *avctx, FFVkBuffer *buf)
Frees a buffer.
Definition: vulkan.c:351
FFVkQueueFamilyCtx::cur_queue
int cur_queue
Definition: vulkan.h:89
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:308
GLSLF
#define GLSLF(N, S,...)
Definition: vulkan.h:44
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
ff_vk_bind_pipeline_exec
void ff_vk_bind_pipeline_exec(AVFilterContext *avctx, FFVkExecContext *e, FFVulkanPipeline *pl)
Add a command to bind the completed pipeline and its descriptor sets.
Definition: vulkan.c:1441
AVFilterContext
An instance of a filter.
Definition: avfilter.h:386
desc
const char * desc
Definition: libsvtav1.c:79
FFVulkanPipeline::descriptor_sets_num
int descriptor_sets_num
Definition: vulkan.h:119
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
FFVkExecContext::bufs
VkCommandBuffer * bufs
Definition: vulkan.h:147
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_create_pipeline
FFVulkanPipeline * ff_vk_create_pipeline(AVFilterContext *avctx, FFVkQueueFamilyCtx *qf)
Inits a pipeline.
Definition: vulkan.c:1395
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
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:449
FFSPIRVShader
Definition: vulkan.h:56
FFVkBuffer
Definition: vulkan.h:80
FFVkExecContext::sem_wait_val
uint64_t * sem_wait_val
Definition: vulkan.h:160
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
ff_vk_extensions_to_mask
static uint64_t ff_vk_extensions_to_mask(const char *const *extensions, int nb_extensions)
Definition: vulkan_loader.h:34
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
ff_vk_init_shader
FFSPIRVShader * ff_vk_init_shader(AVFilterContext *avctx, FFVulkanPipeline *pl, const char *name, VkShaderStageFlags stage)
Inits a shader for a specific pipeline.
Definition: vulkan.c:976
FFVulkanPipeline::pool_size_desc_num
int pool_size_desc_num
Definition: vulkan.h:121
FFVkQueueCtx::nb_frame_deps
int nb_frame_deps
Definition: vulkan.h:139
FFVkExecContext::sem_sig_val_dst
uint64_t ** sem_sig_val_dst
Definition: vulkan.h:173
ff_vk_compile_shader
int ff_vk_compile_shader(AVFilterContext *avctx, FFSPIRVShader *shd, const char *entrypoint)
Compiles the shader, entrypoint must be set to "main".
Definition: vulkan.c:1030
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:922
FFVkExecContext::sem_wait_val_alloc
int sem_wait_val_alloc
Definition: vulkan.h:161
FFVkQueueCtx::buf_deps
AVBufferRef ** buf_deps
Definition: vulkan.h:133
FFVulkanPipeline::desc_layout
VkDescriptorSetLayout * desc_layout
Definition: vulkan.h:111
FFVulkanFunctions
Definition: vulkan_functions.h:168
ff_vk_glslang_shader_compile
int ff_vk_glslang_shader_compile(AVFilterContext *avctx, FFSPIRVShader *shd, uint8_t **data, size_t *size, void **opaque)
Compile GLSL into SPIR-V using glslang.
Definition: glslang.c:140
ff_vk_filter_config_output
int ff_vk_filter_config_output(AVFilterLink *outlink)
Definition: vulkan.c:785
FFVkQueueFamilyCtx::queue_family
int queue_family
Definition: vulkan.h:87
ff_vk_init_compute_pipeline
int ff_vk_init_compute_pipeline(AVFilterContext *avctx, FFVulkanPipeline *pl)
Initializes a compute pipeline.
Definition: vulkan.c:1405