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