FFmpeg
ops.c
Go to the documentation of this file.
1 /**
2  * Copyright (C) 2026 Lynne
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "libavutil/mem.h"
22 #include "libavutil/refstruct.h"
23 
24 #include "../ops_internal.h"
25 #include "../swscale_internal.h"
26 
27 #include "ops.h"
28 
29 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
30 #include "spvasm.h"
31 #endif
32 
33 static void ff_sws_vk_uninit(AVRefStructOpaque opaque, void *obj)
34 {
35  FFVulkanOpsCtx *s = obj;
36 
37 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
38  if (s->spvc)
39  s->spvc->uninit(&s->spvc);
40 #endif
41  ff_vk_uninit(&s->vkctx);
42 }
43 
45 {
46  int err;
47  SwsInternal *c = sws_internal(sws);
48 
49  if (!c->hw_priv) {
50  c->hw_priv = av_refstruct_alloc_ext(sizeof(FFVulkanOpsCtx), 0, NULL,
52  if (!c->hw_priv)
53  return AVERROR(ENOMEM);
54  }
55 
56  FFVulkanOpsCtx *s = c->hw_priv;
57  if (s->vkctx.device_ref && s->vkctx.device_ref->data != dev_ref->data) {
58  /* Reinitialize with new context */
59  ff_vk_uninit(&s->vkctx);
60  } else if (s->vkctx.device_ref && s->vkctx.device_ref->data == dev_ref->data) {
61  return 0;
62  }
63 
64  err = ff_vk_init(&s->vkctx, sws, dev_ref, NULL);
65  if (err < 0)
66  return err;
67 
68  s->qf = ff_vk_qf_find(&s->vkctx, VK_QUEUE_COMPUTE_BIT, 0);
69  if (!s->qf) {
70  av_log(sws, AV_LOG_ERROR, "Device has no compute queues\n");
71  return AVERROR(ENOTSUP);
72  }
73 
74 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
75  if (!s->spvc) {
76  s->spvc = ff_vk_spirv_init();
77  if (!s->spvc)
78  return AVERROR(ENOMEM);
79  }
80 #endif
81 
82  return 0;
83 }
84 
85 #define MAX_DITHER_BUFS 4
86 
87 typedef struct VulkanPriv {
95 } VulkanPriv;
96 
97 static void process(const SwsFrame *dst, const SwsFrame *src, int y, int h,
98  const SwsPass *pass)
99 {
100  VulkanPriv *p = (VulkanPriv *) pass->priv;
101  FFVkExecContext *ec = ff_vk_exec_get(&p->s->vkctx, &p->e);
102  FFVulkanFunctions *vk = &p->s->vkctx.vkfn;
103  ff_vk_exec_start(&p->s->vkctx, ec);
104 
105  AVFrame *src_f = (AVFrame *) src->avframe;
106  AVFrame *dst_f = (AVFrame *) dst->avframe;
107  ff_vk_exec_add_dep_frame(&p->s->vkctx, ec, src_f,
108  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
109  VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
110  ff_vk_exec_add_dep_frame(&p->s->vkctx, ec, dst_f,
111  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
112  VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT);
113 
114  VkImageView src_views[AV_NUM_DATA_POINTERS];
115  VkImageView dst_views[AV_NUM_DATA_POINTERS];
116  ff_vk_create_imageviews(&p->s->vkctx, ec, src_views, src_f, p->src_rep);
117  ff_vk_create_imageviews(&p->s->vkctx, ec, dst_views, dst_f, p->dst_rep);
118 
119  ff_vk_shader_update_img_array(&p->s->vkctx, ec, &p->shd, src_f, src_views,
120  0, 0, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
121  ff_vk_shader_update_img_array(&p->s->vkctx, ec, &p->shd, dst_f, dst_views,
122  0, 1, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
123 
124  int nb_img_bar = 0;
125  VkImageMemoryBarrier2 img_bar[8];
126  ff_vk_frame_barrier(&p->s->vkctx, ec, src_f, img_bar, &nb_img_bar,
127  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
128  VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
129  VK_ACCESS_SHADER_READ_BIT,
130  VK_IMAGE_LAYOUT_GENERAL,
131  VK_QUEUE_FAMILY_IGNORED);
132  ff_vk_frame_barrier(&p->s->vkctx, ec, dst_f, img_bar, &nb_img_bar,
133  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
134  VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
135  VK_ACCESS_SHADER_WRITE_BIT,
136  VK_IMAGE_LAYOUT_GENERAL,
137  VK_QUEUE_FAMILY_IGNORED);
138  vk->CmdPipelineBarrier2(ec->buf, &(VkDependencyInfo) {
139  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
140  .pImageMemoryBarriers = img_bar,
141  .imageMemoryBarrierCount = nb_img_bar,
142  });
143 
144  ff_vk_exec_bind_shader(&p->s->vkctx, ec, &p->shd);
145 
146  vk->CmdDispatch(ec->buf,
147  FFALIGN(src_f->width, p->shd.lg_size[0])/p->shd.lg_size[0],
148  FFALIGN(src_f->height, p->shd.lg_size[1])/p->shd.lg_size[1],
149  1);
150 
151  ff_vk_exec_submit(&p->s->vkctx, ec);
152  ff_vk_exec_wait(&p->s->vkctx, ec);
153 }
154 
155 static void free_fn(void *priv)
156 {
157  VulkanPriv *p = priv;
158  ff_vk_exec_pool_free(&p->s->vkctx, &p->e);
159  ff_vk_shader_free(&p->s->vkctx, &p->shd);
160  for (int i = 0; i < p->nb_dither_buf; i++)
161  ff_vk_free_buf(&p->s->vkctx, &p->dither_buf[i]);
162  av_refstruct_unref(&p->s);
163  av_free(priv);
164 }
165 
167 {
168  int err;
169  p->nb_dither_buf = 0;
170  for (int n = 0; n < ops->num_ops; n++) {
171  const SwsOp *op = &ops->ops[n];
172  if (op->op != SWS_OP_DITHER)
173  continue;
174  av_assert0(p->nb_dither_buf + 1 <= MAX_DITHER_BUFS);
175 
176  int size = (1 << op->dither.size_log2);
177  int idx = p->nb_dither_buf;
178  err = ff_vk_create_buf(&s->vkctx, &p->dither_buf[idx],
179  size*size*sizeof(float), NULL, NULL,
180  VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
181  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
182  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
183  if (err < 0)
184  goto fail;
185  p->nb_dither_buf++;
186 
187  float *dither_data;
188  err = ff_vk_map_buffer(&s->vkctx, &p->dither_buf[idx],
189  (uint8_t **)&dither_data, 0);
190  if (err < 0)
191  goto fail;
192 
193  for (int i = 0; i < size; i++) {
194  for (int j = 0; j < size; j++) {
195  const AVRational r = op->dither.matrix[i*size + j];
196  dither_data[i*size + j] = r.num/(float)r.den;
197  }
198  }
199 
200  ff_vk_unmap_buffer(&s->vkctx, &p->dither_buf[idx], 1);
201  }
202 
203  return 0;
204 
205 fail:
206  for (int i = 0; i < p->nb_dither_buf; i++)
207  ff_vk_free_buf(&p->s->vkctx, &p->dither_buf[i]);
208  return err;
209 }
210 
211 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
212 struct DitherData {
213  int size;
214  int arr_1d_id;
215  int arr_2d_id;
216  int struct_id;
217  int struct_ptr_id;
218  int id;
219  int mask_id;
220 };
221 
222 typedef struct SPIRVIDs {
223  int in_vars[3 + MAX_DITHER_BUFS];
224 
225  int glfn;
226  int ep;
227 
228  /* Types */
229  int void_type;
230  int b_type;
231  int u32_type;
232  int i32_type;
233  int f32_type;
234  int void_fn_type;
235 
236  /* Define vector types */
237  int bvec2_type;
238  int u32vec2_type;
239  int i32vec2_type;
240 
241  int u32vec3_type;
242 
243  int u32vec4_type;
244  int f32vec4_type;
245 
246  /* Constants */
247  int u32_p;
248  int f32_p;
249  int f32_0;
250  int u32_cid[5];
251 
252  int const_ids[128];
253  int nb_const_ids;
254 
255  int linear_deco_off[16];
256  int linear_deco_ops[16];
257  int nb_linear_ops;
258 
259  struct DitherData dither[MAX_DITHER_BUFS];
260  int dither_ptr_elem_id;
261  int nb_dither_bufs;
262 
263  int out_img_type;
264  int out_img_array_id;
265 
266  int in_img_type;
267  int in_img_array_id;
268 
269  /* Pointer types for images */
270  int u32vec3_tptr;
271  int out_img_tptr;
272  int out_img_sptr;
273 
274  int in_img_tptr;
275  int in_img_sptr;
276 } SPIRVIDs;
277 
278 /* Section 1: Function to define all shader header data, and decorations */
279 static void define_shader_header(FFVulkanShader *shd, SwsOpList *ops,
280  SPICtx *spi, SPIRVIDs *id)
281 {
282  spi_OpCapability(spi, SpvCapabilityShader); /* Shader type */
283 
284  /* Declare required capabilities */
285  spi_OpCapability(spi, SpvCapabilityInt16);
286  spi_OpCapability(spi, SpvCapabilityInt8);
287  spi_OpCapability(spi, SpvCapabilityImageQuery);
288  spi_OpCapability(spi, SpvCapabilityStorageImageReadWithoutFormat);
289  spi_OpCapability(spi, SpvCapabilityStorageImageWriteWithoutFormat);
290  spi_OpCapability(spi, SpvCapabilityStorageBuffer8BitAccess);
291  /* Import the GLSL set of functions (used for min/max) */
292  id->glfn = spi_OpExtInstImport(spi, "GLSL.std.450");
293 
294  /* Next section starts here */
295  spi_OpMemoryModel(spi, SpvAddressingModelLogical, SpvMemoryModelGLSL450);
296 
297  /* Entrypoint */
298  id->ep = spi_OpEntryPoint(spi, SpvExecutionModelGLCompute, "main",
299  id->in_vars, 3 + id->nb_dither_bufs);
300  spi_OpExecutionMode(spi, id->ep, SpvExecutionModeLocalSize,
301  shd->lg_size, 3);
302 
303  /* gl_GlobalInvocationID descriptor decorations */
304  spi_OpDecorate(spi, id->in_vars[0], SpvDecorationBuiltIn,
305  SpvBuiltInGlobalInvocationId);
306 
307  /* Input image descriptor decorations */
308  spi_OpDecorate(spi, id->in_vars[1], SpvDecorationNonWritable);
309  spi_OpDecorate(spi, id->in_vars[1], SpvDecorationDescriptorSet, 0);
310  spi_OpDecorate(spi, id->in_vars[1], SpvDecorationBinding, 0);
311 
312  /* Output image descriptor decorations */
313  spi_OpDecorate(spi, id->in_vars[2], SpvDecorationNonReadable);
314  spi_OpDecorate(spi, id->in_vars[2], SpvDecorationDescriptorSet, 0);
315  spi_OpDecorate(spi, id->in_vars[2], SpvDecorationBinding, 1);
316 
317  for (int i = 0; i < id->nb_dither_bufs; i++) {
318  spi_OpDecorate(spi, id->dither[i].arr_1d_id, SpvDecorationArrayStride,
319  sizeof(float));
320  spi_OpDecorate(spi, id->dither[i].arr_2d_id, SpvDecorationArrayStride,
321  id->dither[i].size*sizeof(float));
322  spi_OpDecorate(spi, id->dither[i].struct_id, SpvDecorationBlock);
323  spi_OpMemberDecorate(spi, id->dither[i].struct_id, 0, SpvDecorationOffset, 0);
324  spi_OpDecorate(spi, id->dither[i].id, SpvDecorationDescriptorSet, 1);
325  spi_OpDecorate(spi, id->dither[i].id, SpvDecorationBinding, i);
326  }
327 
328  /* All linear arithmetic ops must be decorated with NoContraction */
329  for (int n = 0; n < ops->num_ops; n++) {
330  const SwsOp *op = &ops->ops[n];
331  if (op->op != SWS_OP_LINEAR)
332  continue;
333  av_assert0((id->nb_linear_ops + 1) <= FF_ARRAY_ELEMS(id->linear_deco_off));
334 
335  int nb_ops = 0;
336  for (int j = 0; j < 4; j++) {
337  nb_ops += !!op->lin.m[j][0].num;
338  nb_ops += op->lin.m[j][0].num && op->lin.m[j][4].num;
339  for (int i = 1; i < 4; i++) {
340  nb_ops += !!op->lin.m[j][i].num;
341  nb_ops += op->lin.m[j][i].num &&
342  (op->lin.m[j][0].num || op->lin.m[j][4].num);
343  }
344  }
345 
346  id->linear_deco_off[id->nb_linear_ops] = spi_reserve(spi, nb_ops*4*3);
347  id->linear_deco_ops[id->nb_linear_ops] = nb_ops;
348  id->nb_linear_ops++;
349  }
350 }
351 
352 /* Section 2: Define all types and constants */
353 static void define_shader_consts(SwsOpList *ops, SPICtx *spi, SPIRVIDs *id)
354 {
355  /* Define scalar types */
356  id->void_type = spi_OpTypeVoid(spi);
357  id->b_type = spi_OpTypeBool(spi);
358  int u32_type =
359  id->u32_type = spi_OpTypeInt(spi, 32, 0);
360  id->i32_type = spi_OpTypeInt(spi, 32, 1);
361  int f32_type =
362  id->f32_type = spi_OpTypeFloat(spi, 32);
363  id->void_fn_type = spi_OpTypeFunction(spi, id->void_type, NULL, 0);
364 
365  /* Define vector types */
366  id->bvec2_type = spi_OpTypeVector(spi, id->b_type, 2);
367  id->u32vec2_type = spi_OpTypeVector(spi, u32_type, 2);
368  id->i32vec2_type = spi_OpTypeVector(spi, id->i32_type, 2);
369 
370  id->u32vec3_type = spi_OpTypeVector(spi, u32_type, 3);
371 
372  id->u32vec4_type = spi_OpTypeVector(spi, u32_type, 4);
373  id->f32vec4_type = spi_OpTypeVector(spi, f32_type, 4);
374 
375  /* Constants */
376  id->u32_p = spi_OpUndef(spi, u32_type);
377  id->f32_p = spi_OpUndef(spi, f32_type);
378  id->f32_0 = spi_OpConstantFloat(spi, f32_type, 0);
379  for (int i = 0; i < 5; i++)
380  id->u32_cid[i] = spi_OpConstantUInt(spi, u32_type, i);
381 
382  /* Operation constants */
383  id->nb_const_ids = 0;
384  for (int n = 0; n < ops->num_ops; n++) {
385  /* Make sure there's always enough space for the maximum number of
386  * constants a single operation needs (currently linear, 20 consts). */
387  av_assert0((id->nb_const_ids + 20) <= FF_ARRAY_ELEMS(id->const_ids));
388  const SwsOp *op = &ops->ops[n];
389  switch (op->op) {
390  case SWS_OP_CONVERT:
391  if (ff_sws_pixel_type_is_int(op->convert.to) && op->convert.expand) {
392  AVRational m = ff_sws_pixel_expand(op->type, op->convert.to);
393  int tmp = spi_OpConstantUInt(spi, id->u32_type, m.num);
394  tmp = spi_OpConstantComposite(spi, id->u32vec4_type,
395  tmp, tmp, tmp, tmp);
396  id->const_ids[id->nb_const_ids++] = tmp;
397  }
398  break;
399  case SWS_OP_CLEAR:
400  for (int i = 0; i < 4; i++) {
401  if (!SWS_COMP_TEST(op->clear.mask, i))
402  continue;
403  AVRational cv = op->clear.value[i];
404  if (op->type == SWS_PIXEL_F32) {
405  float q = (float)cv.num/cv.den;
406  id->const_ids[id->nb_const_ids++] =
407  spi_OpConstantFloat(spi, f32_type, q);
408  } else {
409  av_assert0(cv.den == 1);
410  id->const_ids[id->nb_const_ids++] =
411  spi_OpConstantUInt(spi, u32_type, cv.num);
412  }
413  }
414  break;
415  case SWS_OP_LSHIFT:
416  case SWS_OP_RSHIFT: {
417  int tmp = spi_OpConstantUInt(spi, u32_type, op->shift.amount);
418  tmp = spi_OpConstantComposite(spi, id->u32vec4_type,
419  tmp, tmp, tmp, tmp);
420  id->const_ids[id->nb_const_ids++] = tmp;
421  break;
422  }
423  case SWS_OP_SCALE: {
424  int tmp;
425  if (op->type == SWS_PIXEL_F32) {
426  float q = op->scale.factor.num/(float)op->scale.factor.den;
427  tmp = spi_OpConstantFloat(spi, f32_type, q);
428  tmp = spi_OpConstantComposite(spi, id->f32vec4_type,
429  tmp, tmp, tmp, tmp);
430  } else {
431  av_assert0(op->scale.factor.den == 1);
432  tmp = spi_OpConstantUInt(spi, u32_type, op->scale.factor.num);
433  tmp = spi_OpConstantComposite(spi, id->u32vec4_type,
434  tmp, tmp, tmp, tmp);
435  }
436  id->const_ids[id->nb_const_ids++] = tmp;
437  break;
438  }
439  case SWS_OP_MIN:
440  case SWS_OP_MAX:
441  for (int i = 0; i < 4; i++) {
442  int tmp;
443  AVRational cl = op->clamp.limit[i];
444  if (!op->clamp.limit[i].den) {
445  continue;
446  } else if (op->type == SWS_PIXEL_F32) {
447  float q = (float)cl.num/((float)cl.den);
448  tmp = spi_OpConstantFloat(spi, f32_type, q);
449  } else {
450  av_assert0(cl.den == 1);
451  tmp = spi_OpConstantUInt(spi, u32_type, cl.num);
452  }
453  id->const_ids[id->nb_const_ids++] = tmp;
454  }
455  break;
456  case SWS_OP_DITHER:
457  for (int i = 0; i < 4; i++) {
458  if (op->dither.y_offset[i] < 0)
459  continue;
460  int tmp = spi_OpConstantUInt(spi, u32_type, op->dither.y_offset[i]);
461  id->const_ids[id->nb_const_ids++] = tmp;
462  }
463  break;
464  case SWS_OP_LINEAR: {
465  for (int i = 0; i < 4; i++) {
466  float val;
467  if (op->lin.m[i][0].num) {
468  val = op->lin.m[i][0].num/(float)op->lin.m[i][0].den;
469  id->const_ids[id->nb_const_ids++] =
470  spi_OpConstantFloat(spi, f32_type, val);
471  }
472  if (op->lin.m[i][4].num) {
473  val = op->lin.m[i][4].num/(float)op->lin.m[i][4].den;
474  id->const_ids[id->nb_const_ids++] =
475  spi_OpConstantFloat(spi, f32_type, val);
476  }
477  for (int j = 1; j < 4; j++) {
478  if (!op->lin.m[i][j].num)
479  continue;
480  val = op->lin.m[i][j].num/(float)op->lin.m[i][j].den;
481  id->const_ids[id->nb_const_ids++] =
482  spi_OpConstantFloat(spi, f32_type, val);
483  }
484  }
485  break;
486  }
487  default:
488  break;
489  }
490  }
491 }
492 
493 /* Section 3: Define bindings */
494 static void define_shader_bindings(SwsOpList *ops, SPICtx *spi, SPIRVIDs *id,
495  int in_img_count, int out_img_count)
496 {
497  id->dither_ptr_elem_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
498  id->f32_type);
499 
500  struct DitherData *dither = id->dither;
501  for (int i = 0; i < id->nb_dither_bufs; i++) {
502  int size_id = spi_OpConstantUInt(spi, id->u32_type, dither[i].size);
503  dither[i].mask_id = spi_OpConstantUInt(spi, id->u32_type, dither[i].size - 1);
504  spi_OpTypeArray(spi, id->f32_type, dither[i].arr_1d_id, size_id);
505  spi_OpTypeArray(spi, dither[i].arr_1d_id, dither[i].arr_2d_id, size_id);
506  spi_OpTypeStruct(spi, dither[i].struct_id, dither[i].arr_2d_id);
507  dither[i].struct_ptr_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
508  dither[i].struct_id);
509  dither[i].id = spi_OpVariable(spi, dither[i].id, dither[i].struct_ptr_id,
510  SpvStorageClassUniform, 0);
511  }
512 
513  const SwsOp *op_w = ff_sws_op_list_output(ops);
514  const SwsOp *op_r = ff_sws_op_list_input(ops);
515 
516  /* Define image types for descriptors */
517  id->out_img_type = spi_OpTypeImage(spi,
518  op_w->type == SWS_PIXEL_F32 ?
519  id->f32_type : id->u32_type,
520  2, 0, 0, 0, 2, SpvImageFormatUnknown);
521  id->out_img_array_id = spi_OpTypeArray(spi, id->out_img_type, spi_get_id(spi),
522  id->u32_cid[out_img_count]);
523 
524  id->in_img_type = 0;
525  id->in_img_array_id = 0;
526  if (op_r) {
527  /* If the formats match, we have to reuse the types due to SPIR-V not
528  * allowing redundant type defines */
529  int match = ((op_w->type == SWS_PIXEL_F32) ==
530  (op_r->type == SWS_PIXEL_F32));
531  id->in_img_type = match ? id->out_img_type :
532  spi_OpTypeImage(spi,
533  op_r->type == SWS_PIXEL_F32 ?
534  id->f32_type : id->u32_type,
535  2, 0, 0, 0, 2, SpvImageFormatUnknown);
536  id->in_img_array_id = spi_OpTypeArray(spi, id->in_img_type, spi_get_id(spi),
537  id->u32_cid[in_img_count]);
538  }
539 
540  /* Pointer types for images */
541  id->u32vec3_tptr = spi_OpTypePointer(spi, SpvStorageClassInput,
542  id->u32vec3_type);
543  id->out_img_tptr = spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
544  id->out_img_array_id);
545  id->out_img_sptr = spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
546  id->out_img_type);
547 
548  id->in_img_tptr = 0;
549  id->in_img_sptr = 0;
550  if (op_r) {
551  id->in_img_tptr= spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
552  id->in_img_array_id);
553  id->in_img_sptr= spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
554  id->in_img_type);
555  }
556 
557  /* Define inputs */
558  spi_OpVariable(spi, id->in_vars[0], id->u32vec3_tptr,
559  SpvStorageClassInput, 0);
560  if (op_r) {
561  spi_OpVariable(spi, id->in_vars[1], id->in_img_tptr,
562  SpvStorageClassUniformConstant, 0);
563  }
564  spi_OpVariable(spi, id->in_vars[2], id->out_img_tptr,
565  SpvStorageClassUniformConstant, 0);
566 }
567 
568 static int add_ops_spirv(VulkanPriv *p, FFVulkanOpsCtx *s,
569  SwsOpList *ops, FFVulkanShader *shd)
570 {
571  uint8_t spvbuf[1024*16];
572  SPICtx spi_context = { 0 }, *spi = &spi_context;
573  SPIRVIDs spid_data = { 0 }, *id = &spid_data;
574  spi_init(spi, spvbuf, sizeof(spvbuf));
575 
576  /* Interlaced formats are not currently supported */
577  if (ops->src.interlaced || ops->dst.interlaced)
578  return AVERROR(ENOTSUP);
579 
580  ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
581  (uint32_t []) { 32, 32, 1 }, 0);
582  shd->precompiled = 0;
583 
584  /* Image ops, to determine types */
585  const SwsOp *op_w = ff_sws_op_list_output(ops);
586  int out_img_count = op_w->rw.packed ? 1 : op_w->rw.elems;
587  p->dst_rep = op_w->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
588 
589  const SwsOp *op_r = ff_sws_op_list_input(ops);
590  int in_img_count = op_r ? op_r->rw.packed ? 1 : op_r->rw.elems : 0;
591  if (op_r)
592  p->src_rep = op_r->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
593 
595  {
596  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
597  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
598  .elems = 4,
599  },
600  {
601  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
602  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
603  .elems = 4,
604  },
605  };
606  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, desc_set, 2, 0, 0);
607 
608  /* Create dither buffers */
609  int err = create_dither_bufs(s, p, ops);
610  if (err < 0)
611  return err;
612 
613  /* Entrypoint inputs: gl_GlobalInvocationID, input and output images, dither */
614  id->in_vars[0] = spi_get_id(spi);
615  id->in_vars[1] = spi_get_id(spi);
616  id->in_vars[2] = spi_get_id(spi);
617 
618  /* Create dither buffer descriptor set */
619  id->nb_dither_bufs = 0;
620  for (int n = 0; n < ops->num_ops; n++) {
621  const SwsOp *op = &ops->ops[n];
622  if (op->op != SWS_OP_DITHER)
623  continue;
624 
625  id->dither[id->nb_dither_bufs].size = 1 << op->dither.size_log2;
626  id->dither[id->nb_dither_bufs].arr_1d_id = spi_get_id(spi);
627  id->dither[id->nb_dither_bufs].arr_2d_id = spi_get_id(spi);
628  id->dither[id->nb_dither_bufs].struct_id = spi_get_id(spi);
629  id->dither[id->nb_dither_bufs].id = spi_get_id(spi);
630  id->in_vars[3 + id->nb_dither_bufs] = id->dither[id->nb_dither_bufs].id;
631 
632  desc_set[id->nb_dither_bufs++] = (FFVulkanDescriptorSetBinding) {
633  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
634  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
635  };
636  }
637  if (id->nb_dither_bufs)
638  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, desc_set,
639  id->nb_dither_bufs, 1, 0);
640 
641  /* Define shader header sections */
642  define_shader_header(shd, ops, spi, id);
643  define_shader_consts(ops, spi, id);
644  define_shader_bindings(ops, spi, id, in_img_count, out_img_count);
645 
646  /* Main function starts here */
647  spi_OpFunction(spi, id->ep, id->void_type, 0, id->void_fn_type);
648  spi_OpLabel(spi, spi_get_id(spi));
649 
650  /* Load input image handles */
651  int in_img[4] = { 0 };
652  for (int i = 0; i < in_img_count; i++) {
653  /* Deref array and then the pointer */
654  int img = spi_OpAccessChain(spi, id->in_img_sptr,
655  id->in_vars[1], id->u32_cid[i]);
656  in_img[i] = spi_OpLoad(spi, id->in_img_type, img,
657  SpvMemoryAccessMaskNone, 0);
658  }
659 
660  /* Load output image handles */
661  int out_img[4];
662  for (int i = 0; i < out_img_count; i++) {
663  int img = spi_OpAccessChain(spi, id->out_img_sptr,
664  id->in_vars[2], id->u32_cid[i]);
665  out_img[i] = spi_OpLoad(spi, id->out_img_type, img,
666  SpvMemoryAccessMaskNone, 0);
667  }
668 
669  /* Load gl_GlobalInvocationID */
670  int gid = spi_OpLoad(spi, id->u32vec3_type, id->in_vars[0],
671  SpvMemoryAccessMaskNone, 0);
672 
673  /* ivec2(gl_GlobalInvocationID.xy) */
674  gid = spi_OpVectorShuffle(spi, id->u32vec2_type, gid, gid, 0, 1);
675  int gi2 = spi_OpBitcast(spi, id->i32vec2_type, gid);
676 
677  /* imageSize(out_img[0]); */
678  int img1_s = spi_OpImageQuerySize(spi, id->i32vec2_type, out_img[0]);
679  int scmp = spi_OpSGreaterThanEqual(spi, id->bvec2_type, gi2, img1_s);
680  scmp = spi_OpAny(spi, id->b_type, scmp);
681 
682  /* if (out of bounds) return */
683  int quit_label = spi_get_id(spi), merge_label = spi_get_id(spi);
684  spi_OpSelectionMerge(spi, merge_label, SpvSelectionControlMaskNone);
685  spi_OpBranchConditional(spi, scmp, quit_label, merge_label, 0);
686 
687  spi_OpLabel(spi, quit_label);
688  spi_OpReturn(spi); /* Quit if out of bounds here */
689  spi_OpLabel(spi, merge_label);
690 
691  /* Initialize main data state */
692  int data;
693  if (ops->ops[0].type == SWS_PIXEL_F32)
694  data = spi_OpCompositeConstruct(spi, id->f32vec4_type,
695  id->f32_p, id->f32_p,
696  id->f32_p, id->f32_p);
697  else
698  data = spi_OpCompositeConstruct(spi, id->u32vec4_type,
699  id->u32_p, id->u32_p,
700  id->u32_p, id->u32_p);
701 
702  /* Keep track of which constant/buffer to use */
703  int nb_const_ids = 0;
704  int nb_dither_bufs = 0;
705  int nb_linear_ops = 0;
706 
707  /* Operations */
708  for (int n = 0; n < ops->num_ops; n++) {
709  const SwsOp *op = &ops->ops[n];
710  SwsPixelType cur_type = op->op == SWS_OP_CONVERT ?
711  op->convert.to : op->type;
712  int type_v = cur_type == SWS_PIXEL_F32 ?
713  id->f32vec4_type : id->u32vec4_type;
714  int type_s = cur_type == SWS_PIXEL_F32 ?
715  id->f32_type : id->u32_type;
716  int uid = cur_type == SWS_PIXEL_F32 ?
717  id->f32_p : id->u32_p;
718 
719  switch (op->op) {
720  case SWS_OP_READ:
721  if (op->rw.frac || op->rw.filter) {
722  return AVERROR(ENOTSUP);
723  } else if (op->rw.packed) {
724  data = spi_OpImageRead(spi, type_v, in_img[ops->plane_src[0]],
725  gid, SpvImageOperandsMaskNone);
726  } else {
727  int tmp[4] = { uid, uid, uid, uid };
728  for (int i = 0; i < op->rw.elems; i++) {
729  tmp[i] = spi_OpImageRead(spi, type_v,
730  in_img[ops->plane_src[i]], gid,
731  SpvImageOperandsMaskNone);
732  tmp[i] = spi_OpCompositeExtract(spi, type_s, tmp[i], 0);
733  }
734  data = spi_OpCompositeConstruct(spi, type_v,
735  tmp[0], tmp[1], tmp[2], tmp[3]);
736  }
737  break;
738  case SWS_OP_WRITE:
739  if (op->rw.frac || op->rw.filter) {
740  return AVERROR(ENOTSUP);
741  } else if (op->rw.packed) {
742  spi_OpImageWrite(spi, out_img[ops->plane_dst[0]], gid, data,
743  SpvImageOperandsMaskNone);
744  } else {
745  for (int i = 0; i < op->rw.elems; i++) {
746  int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
747  tmp = spi_OpCompositeConstruct(spi, type_v, tmp, tmp, tmp, tmp);
748  spi_OpImageWrite(spi, out_img[ops->plane_dst[i]], gid, tmp,
749  SpvImageOperandsMaskNone);
750  }
751  }
752  break;
753  case SWS_OP_CLEAR:
754  for (int i = 0; i < 4; i++) {
755  if (!op->clear.value[i].den)
756  continue;
757  data = spi_OpCompositeInsert(spi, type_v,
758  id->const_ids[nb_const_ids++],
759  data, i);
760  }
761  break;
762  case SWS_OP_SWIZZLE:
763  data = spi_OpVectorShuffle(spi, type_v, data, data,
764  op->swizzle.in[0],
765  op->swizzle.in[1],
766  op->swizzle.in[2],
767  op->swizzle.in[3]);
768  break;
769  case SWS_OP_CONVERT:
770  if (ff_sws_pixel_type_is_int(cur_type) && op->convert.expand)
771  data = spi_OpIMul(spi, type_v, data, id->const_ids[nb_const_ids++]);
772  else if (op->type == SWS_PIXEL_F32 && type_s == id->u32_type)
773  data = spi_OpConvertFToU(spi, type_v, data);
774  else if (op->type != SWS_PIXEL_F32 && type_s == id->f32_type)
775  data = spi_OpConvertUToF(spi, type_v, data);
776  break;
777  case SWS_OP_LSHIFT:
778  data = spi_OpShiftLeftLogical(spi, type_v, data,
779  id->const_ids[nb_const_ids++]);
780  break;
781  case SWS_OP_RSHIFT:
782  data = spi_OpShiftRightLogical(spi, type_v, data,
783  id->const_ids[nb_const_ids++]);
784  break;
785  case SWS_OP_SCALE:
786  if (op->type == SWS_PIXEL_F32)
787  data = spi_OpFMul(spi, type_v, data,
788  id->const_ids[nb_const_ids++]);
789  else
790  data = spi_OpIMul(spi, type_v, data,
791  id->const_ids[nb_const_ids++]);
792  break;
793  case SWS_OP_MIN:
794  case SWS_OP_MAX: {
795  int t = op->type == SWS_PIXEL_F32 ?
796  op->op == SWS_OP_MIN ? GLSLstd450FMin : GLSLstd450FMax :
797  op->op == SWS_OP_MIN ? GLSLstd450UMin : GLSLstd450UMax;
798  for (int i = 0; i < 4; i++) {
799  if (!op->clamp.limit[i].den)
800  continue;
801  int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
802  tmp = spi_OpExtInst(spi, type_s, id->glfn, t,
803  tmp, id->const_ids[nb_const_ids++]);
804  data = spi_OpCompositeInsert(spi, type_v, tmp, data, i);
805  }
806  break;
807  }
808  case SWS_OP_DITHER: {
809  int did = nb_dither_bufs++;
810  int x_id = spi_OpCompositeExtract(spi, id->u32_type, gid, 0);
811  int y_pos = spi_OpCompositeExtract(spi, id->u32_type, gid, 1);
812  x_id = spi_OpBitwiseAnd(spi, id->u32_type, x_id,
813  id->dither[did].mask_id);
814  for (int i = 0; i < 4; i++) {
815  if (op->dither.y_offset[i] < 0)
816  continue;
817 
818  int y_id = spi_OpIAdd(spi, id->u32_type, y_pos,
819  id->const_ids[nb_const_ids++]);
820  y_id = spi_OpBitwiseAnd(spi, id->u32_type, y_id,
821  id->dither[did].mask_id);
822 
823  int ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id,
824  id->dither[did].id, id->u32_cid[0],
825  y_id, x_id);
826  int val = spi_OpLoad(spi, id->f32_type, ptr,
827  SpvMemoryAccessMaskNone, 0);
828 
829  int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
830  tmp = spi_OpFAdd(spi, type_s, tmp, val);
831  data = spi_OpCompositeInsert(spi, type_v, tmp, data, i);
832  }
833  break;
834  }
835  case SWS_OP_LINEAR: {
836  int tmp[4];
837  tmp[0] = spi_OpCompositeExtract(spi, type_s, data, 0);
838  tmp[1] = spi_OpCompositeExtract(spi, type_s, data, 1);
839  tmp[2] = spi_OpCompositeExtract(spi, type_s, data, 2);
840  tmp[3] = spi_OpCompositeExtract(spi, type_s, data, 3);
841 
842  int off = spi_reserve(spi, 0); /* Current offset */
843  spi->off = id->linear_deco_off[nb_linear_ops];
844  for (int i = 0; i < id->linear_deco_ops[nb_linear_ops]; i++)
845  spi_OpDecorate(spi, spi->id + i, SpvDecorationNoContraction);
846  spi->off = off;
847 
848  int res[4];
849  for (int j = 0; j < 4; j++) {
850  res[j] = op->type == SWS_PIXEL_F32 ? id->f32_0 : id->u32_cid[0];
851  if (op->lin.m[j][0].num)
852  res[j] = spi_OpFMul(spi, type_s, tmp[0],
853  id->const_ids[nb_const_ids++]);
854 
855  if (op->lin.m[j][0].num && op->lin.m[j][4].num)
856  res[j] = spi_OpFAdd(spi, type_s,
857  id->const_ids[nb_const_ids++], res[j]);
858  else if (op->lin.m[j][4].num)
859  res[j] = id->const_ids[nb_const_ids++];
860 
861  for (int i = 1; i < 4; i++) {
862  if (!op->lin.m[j][i].num)
863  continue;
864 
865  int v = spi_OpFMul(spi, type_s, tmp[i],
866  id->const_ids[nb_const_ids++]);
867  if (op->lin.m[j][0].num || op->lin.m[j][4].num)
868  res[j] = spi_OpFAdd(spi, type_s, res[j], v);
869  else
870  res[j] = v;
871  }
872  }
873  data = spi_OpCompositeConstruct(spi, type_v,
874  res[0], res[1], res[2], res[3]);
875  nb_linear_ops++;
876  break;
877  }
878  case SWS_OP_UNPACK:
879  if (ops->src.format == AV_PIX_FMT_X2BGR10)
880  data = spi_OpVectorShuffle(spi, type_v, data, data, 3, 2, 1, 0);
881  else
882  data = spi_OpVectorShuffle(spi, type_v, data, data, 3, 0, 1, 2);
883  break;
884  case SWS_OP_PACK:
885  if (ops->dst.format == AV_PIX_FMT_X2BGR10)
886  data = spi_OpVectorShuffle(spi, type_v, data, data, 3, 2, 1, 0);
887  else
888  data = spi_OpVectorShuffle(spi, type_v, data, data, 1, 2, 3, 0);
889  break;
890  default:
891  return AVERROR(ENOTSUP);
892  }
893  }
894 
895  /* Return and finalize */
896  spi_OpReturn(spi);
897  spi_OpFunctionEnd(spi);
898 
899  int len = spi_end(spi);
900  if (len < 0)
901  return AVERROR_INVALIDDATA;
902 
903  return ff_vk_shader_link(&s->vkctx, shd, spvbuf, len, "main");
904 }
905 #endif
906 
907 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
908 static void add_desc_read_write(FFVulkanDescriptorSetBinding *out_desc,
909  enum FFVkShaderRepFormat *out_rep,
910  const SwsOp *op)
911 {
912  const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f" :
913  op->type == SWS_PIXEL_U32 ? "rgba32ui" :
914  op->type == SWS_PIXEL_U16 ? "rgba16ui" :
915  "rgba8ui";
916 
917  *out_desc = (FFVulkanDescriptorSetBinding) {
918  .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img",
919  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
920  .mem_layout = img_type,
921  .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly",
922  .dimensions = 2,
923  .elems = 4,
924  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
925  };
926 
927  *out_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
928 }
929 
930 #define QSTR "(%i/%i%s)"
931 #define QTYPE(Q) (Q).num, (Q).den, cur_type == SWS_PIXEL_F32 ? ".0f" : ""
932 
933 static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
934  SwsOpList *ops, FFVulkanShader *shd)
935 {
936  int err;
937  uint8_t *spv_data;
938  size_t spv_len;
939  void *spv_opaque = NULL;
940 
941  /* Interlaced formats are not currently supported */
942  if (ops->src.interlaced || ops->dst.interlaced)
943  return AVERROR(ENOTSUP);
944 
945  err = ff_vk_shader_init(&s->vkctx, shd, "sws_pass",
946  VK_SHADER_STAGE_COMPUTE_BIT,
947  NULL, 0, 32, 32, 1, 0);
948  if (err < 0)
949  return err;
950 
951  int nb_desc = 0;
953 
954  const SwsOp *read = ff_sws_op_list_input(ops);
955  const SwsOp *write = ff_sws_op_list_output(ops);
956  if (read)
957  add_desc_read_write(&buf_desc[nb_desc++], &p->src_rep, read);
958  add_desc_read_write(&buf_desc[nb_desc++], &p->dst_rep, write);
959  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc, nb_desc, 0, 0);
960 
961  err = create_dither_bufs(s, p, ops);
962  if (err < 0)
963  return err;
964 
965  nb_desc = 0;
966  char dither_buf_name[MAX_DITHER_BUFS][64];
967  char dither_mat_name[MAX_DITHER_BUFS][64];
968  for (int n = 0; n < ops->num_ops; n++) {
969  const SwsOp *op = &ops->ops[n];
970  if (op->op != SWS_OP_DITHER)
971  continue;
972  int size = (1 << op->dither.size_log2);
973  av_assert0(size < 8192);
974  snprintf(dither_buf_name[nb_desc], 64, "dither_buf%i", n);
975  snprintf(dither_mat_name[nb_desc], 64, "float dither_mat%i[%i][%i];",
976  n, size, size);
978  .name = dither_buf_name[nb_desc],
979  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
980  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
981  .mem_layout = "scalar",
982  .buf_content = dither_mat_name[nb_desc],
983  };
984  nb_desc++;
985  }
986  if (nb_desc)
988  nb_desc, 1, 0);
989 
990  GLSLC(0, void main() );
991  GLSLC(0, { );
992  GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
993  GLSLC(1, ivec2 size = imageSize(src_img[0]); );
994  GLSLC(1, if (any(greaterThanEqual(pos, size))) );
995  GLSLC(2, return; );
996  GLSLC(0, );
997  GLSLC(1, u8vec4 u8; );
998  GLSLC(1, u16vec4 u16; );
999  GLSLC(1, u32vec4 u32; );
1000  GLSLC(1, precise f32vec4 f32; );
1001  GLSLC(1, precise f32vec4 tmp; );
1002  GLSLC(0, );
1003 
1004  for (int n = 0; n < ops->num_ops; n++) {
1005  const SwsOp *op = &ops->ops[n];
1006  SwsPixelType cur_type = op->op == SWS_OP_CONVERT ? op->convert.to :
1007  op->type;
1008  const char *type_name = ff_sws_pixel_type_name(cur_type);
1009  const char *type_v = cur_type == SWS_PIXEL_F32 ? "f32vec4" :
1010  cur_type == SWS_PIXEL_U32 ? "u32vec4" :
1011  cur_type == SWS_PIXEL_U16 ? "u16vec4" : "u8vec4";
1012  const char *type_s = cur_type == SWS_PIXEL_F32 ? "float" :
1013  cur_type == SWS_PIXEL_U32 ? "uint32_t" :
1014  cur_type == SWS_PIXEL_U16 ? "uint16_t" : "uint8_t";
1015  av_bprintf(&shd->src, " // %s\n", ff_sws_op_type_name(op->op));
1016 
1017  switch (op->op) {
1018  case SWS_OP_READ: {
1019  if (op->rw.frac || op->rw.filter) {
1020  return AVERROR(ENOTSUP);
1021  } else if (op->rw.packed) {
1022  GLSLF(1, %s = %s(imageLoad(src_img[%i], pos)); ,
1023  type_name, type_v, ops->plane_src[0]);
1024  } else {
1025  for (int i = 0; i < op->rw.elems; i++)
1026  GLSLF(1, %s.%c = %s(imageLoad(src_img[%i], pos)[0]); ,
1027  type_name, "xyzw"[i], type_s, ops->plane_src[i]);
1028  }
1029  break;
1030  }
1031  case SWS_OP_WRITE: {
1032  if (op->rw.frac || op->rw.filter) {
1033  return AVERROR(ENOTSUP);
1034  } else if (op->rw.packed) {
1035  GLSLF(1, imageStore(dst_img[%i], pos, %s(%s)); ,
1036  ops->plane_dst[0], type_v, type_name);
1037  } else {
1038  for (int i = 0; i < op->rw.elems; i++)
1039  GLSLF(1, imageStore(dst_img[%i], pos, %s(%s[%i])); ,
1040  ops->plane_dst[i], type_v, type_name, i);
1041  }
1042  break;
1043  }
1044  case SWS_OP_SWIZZLE: {
1045  av_bprintf(&shd->src, " %s = %s.", type_name, type_name);
1046  for (int i = 0; i < 4; i++)
1047  av_bprintf(&shd->src, "%c", "xyzw"[op->swizzle.in[i]]);
1048  av_bprintf(&shd->src, ";\n");
1049  break;
1050  }
1051  case SWS_OP_CLEAR: {
1052  for (int i = 0; i < 4; i++) {
1053  if (!SWS_COMP_TEST(op->clear.mask, i))
1054  continue;
1055  av_bprintf(&shd->src, " %s.%c = %s"QSTR";\n", type_name,
1056  "xyzw"[i], type_s, QTYPE(op->clear.value[i]));
1057  }
1058  break;
1059  }
1060  case SWS_OP_SCALE:
1061  av_bprintf(&shd->src, " %s = %s * "QSTR";\n",
1062  type_name, type_name, QTYPE(op->scale.factor));
1063  break;
1064  case SWS_OP_MIN:
1065  case SWS_OP_MAX:
1066  for (int i = 0; i < 4; i++) {
1067  if (!op->clamp.limit[i].den)
1068  continue;
1069  av_bprintf(&shd->src, " %s.%c = %s(%s.%c, "QSTR");\n",
1070  type_name, "xyzw"[i],
1071  op->op == SWS_OP_MIN ? "min" : "max",
1072  type_name, "xyzw"[i], QTYPE(op->clamp.limit[i]));
1073  }
1074  break;
1075  case SWS_OP_LSHIFT:
1076  case SWS_OP_RSHIFT:
1077  av_bprintf(&shd->src, " %s %s= %i;\n", type_name,
1078  op->op == SWS_OP_LSHIFT ? "<<" : ">>", op->shift.amount);
1079  break;
1080  case SWS_OP_CONVERT:
1081  if (ff_sws_pixel_type_is_int(cur_type) && op->convert.expand) {
1082  const AVRational sc = ff_sws_pixel_expand(op->type, op->convert.to);
1083  av_bprintf(&shd->src, " %s = %s((%s*%i)/%i);\n",
1084  type_name, type_v, ff_sws_pixel_type_name(op->type),
1085  sc.num, sc.den);
1086  } else {
1087  av_bprintf(&shd->src, " %s = %s(%s);\n",
1088  type_name, type_v, ff_sws_pixel_type_name(op->type));
1089  }
1090  break;
1091  case SWS_OP_DITHER: {
1092  int size = (1 << op->dither.size_log2);
1093  for (int i = 0; i < 4; i++) {
1094  if (op->dither.y_offset[i] < 0)
1095  continue;
1096  av_bprintf(&shd->src, " %s.%c += dither_mat%i[(pos.y + %i) & %i]"
1097  "[pos.x & %i];\n",
1098  type_name, "xyzw"[i], n,
1099  op->dither.y_offset[i], size - 1,
1100  size - 1);
1101  }
1102  break;
1103  }
1104  case SWS_OP_LINEAR:
1105  for (int i = 0; i < 4; i++) {
1106  if (op->lin.m[i][4].num)
1107  av_bprintf(&shd->src, " tmp.%c = "QSTR";\n", "xyzw"[i],
1108  QTYPE(op->lin.m[i][4]));
1109  else
1110  av_bprintf(&shd->src, " tmp.%c = 0;\n", "xyzw"[i]);
1111  for (int j = 0; j < 4; j++) {
1112  if (!op->lin.m[i][j].num)
1113  continue;
1114  av_bprintf(&shd->src, " tmp.%c += f32.%c*"QSTR";\n",
1115  "xyzw"[i], "xyzw"[j], QTYPE(op->lin.m[i][j]));
1116  }
1117  }
1118  av_bprintf(&shd->src, " f32 = tmp;\n");
1119  break;
1120  case SWS_OP_UNPACK:
1121  /* MSB->LSB indexing */
1122  av_bprintf(&shd->src, " %s = %s.%s;\n", type_name, type_name,
1123  ops->src.format == AV_PIX_FMT_X2BGR10 ? "wzyx" : "wxyz");
1124  break;
1125  case SWS_OP_PACK:
1126  /* LSB->MSB indexing */
1127  av_bprintf(&shd->src, " %s = %s.%s;\n", type_name, type_name,
1128  ops->dst.format == AV_PIX_FMT_X2BGR10 ? "wzyx" : "yzwx");
1129  break;
1130  default:
1131  return AVERROR(ENOTSUP);
1132  }
1133  }
1134 
1135  GLSLC(0, } );
1136 
1137  err = s->spvc->compile_shader(&s->vkctx, s->spvc, shd,
1138  &spv_data, &spv_len, "main",
1139  &spv_opaque);
1140  if (err < 0)
1141  return err;
1142 
1143  err = ff_vk_shader_link(&s->vkctx, shd, spv_data, spv_len, "main");
1144 
1145  if (spv_opaque)
1146  s->spvc->free_shader(s->spvc, &spv_opaque);
1147 
1148  if (err < 0)
1149  return err;
1150 
1151  return 0;
1152 }
1153 #endif
1154 
1155 static int compile(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out, int glsl)
1156 {
1157  int err;
1158  SwsInternal *c = sws_internal(sws);
1159  FFVulkanOpsCtx *s = c->hw_priv;
1160  if (!s)
1161  return AVERROR(ENOTSUP);
1162 
1163  VulkanPriv *p = av_mallocz(sizeof(*p));
1164  if (!p)
1165  return AVERROR(ENOMEM);
1166  p->s = av_refstruct_ref(c->hw_priv);
1167 
1168  err = ff_vk_exec_pool_init(&s->vkctx, s->qf, &p->e, 1,
1169  0, 0, 0, NULL);
1170  if (err < 0)
1171  goto fail;
1172 
1173  if (ops->src.format == AV_PIX_FMT_BGR0 ||
1174  ops->src.format == AV_PIX_FMT_BGRA ||
1175  ops->dst.format == AV_PIX_FMT_BGR0 ||
1176  ops->dst.format == AV_PIX_FMT_BGRA) {
1177  VkFormatProperties2 prop = {
1178  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
1179  };
1180  FFVulkanFunctions *vk = &s->vkctx.vkfn;
1181  vk->GetPhysicalDeviceFormatProperties2(s->vkctx.hwctx->phys_dev,
1182  VK_FORMAT_B8G8R8A8_UNORM,
1183  &prop);
1184  if (!(prop.formatProperties.optimalTilingFeatures &
1185  VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT)) {
1186  err = AVERROR(ENOTSUP);
1187  goto fail;
1188  }
1189  }
1190 
1191  if (glsl) {
1192  err = AVERROR(ENOTSUP);
1193 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
1194  err = add_ops_glsl(p, s, ops, &p->shd);
1195 #endif
1196  } else {
1197  err = AVERROR(ENOTSUP);
1198 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
1199  err = add_ops_spirv(p, s, ops, &p->shd);
1200 #endif
1201  }
1202  if (err < 0)
1203  goto fail;
1204 
1205  err = ff_vk_shader_register_exec(&s->vkctx, &p->e, &p->shd);
1206  if (err < 0)
1207  goto fail;
1208 
1209  for (int i = 0; i < p->nb_dither_buf; i++)
1210  ff_vk_shader_update_desc_buffer(&s->vkctx, &p->e.contexts[0], &p->shd,
1211  1, i, 0, &p->dither_buf[i],
1212  0, VK_WHOLE_SIZE, VK_FORMAT_UNDEFINED);
1213 
1214  *out = (SwsCompiledOp) {
1215  .opaque = true,
1216  .func_opaque = process,
1217  .priv = p,
1218  .free = free_fn,
1219  };
1220 
1221  return 0;
1222 
1223 fail:
1224  free_fn(p);
1225  return err;
1226 }
1227 
1228 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
1229 static int compile_spirv(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out)
1230 {
1231  return compile(sws, ops, out, 0);
1232 }
1233 
1234 const SwsOpBackend backend_spirv = {
1235  .name = "spirv",
1236  .compile = compile_spirv,
1237  .hw_format = AV_PIX_FMT_VULKAN,
1238 };
1239 #endif
1240 
1241 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
1242 static int compile_glsl(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out)
1243 {
1244  return compile(sws, ops, out, 1);
1245 }
1246 
1247 const SwsOpBackend backend_glsl = {
1248  .name = "glsl",
1249  .compile = compile_glsl,
1250  .hw_format = AV_PIX_FMT_VULKAN,
1251 };
1252 #endif
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:50
ff_vk_create_buf
int ff_vk_create_buf(FFVulkanContext *s, FFVkBuffer *buf, size_t size, void *pNext, void *alloc_pNext, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
Definition: vulkan.c:1040
spi_OpExecutionMode
static void spi_OpExecutionMode(SPICtx *spi, int entry_point_id, SpvExecutionMode mode, int *s, int nb_s)
Definition: spvasm.h:404
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: ops.h:36
VulkanPriv::e
FFVkExecPool e
Definition: ops.c:89
FFVulkanOpsCtx
Copyright (C) 2026 Lynne.
Definition: ops.h:31
SWS_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:53
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:75
VulkanPriv::src_rep
enum FFVkShaderRepFormat src_rep
Definition: ops.c:93
r
const char * r
Definition: vf_curves.c:127
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
uid
UID uid
Definition: mxfenc.c:2488
spi_end
static int spi_end(SPICtx *spi)
Definition: spvasm.h:100
SWS_OP_LSHIFT
@ SWS_OP_LSHIFT
Definition: ops.h:58
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:56
spi_OpVariable
static int spi_OpVariable(SPICtx *spi, int var_id, int ptr_type_id, SpvStorageClass storage_class, int initializer_id)
Definition: spvasm.h:536
ff_vk_shader_free
void ff_vk_shader_free(FFVulkanContext *s, FFVulkanShader *shd)
Free a shader.
Definition: vulkan.c:2835
ff_vk_shader_init
int ff_vk_shader_init(FFVulkanContext *s, FFVulkanShader *shd, const char *name, VkPipelineStageFlags stage, const char *extensions[], int nb_extensions, int lg_x, int lg_y, int lg_z, uint32_t required_subgroup_size)
Initialize a shader object, with a specific set of extensions, type+bind, local group size,...
Definition: vulkan.c:2147
out
static FILE * out
Definition: movenc.c:55
compile
static int compile(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out, int glsl)
Definition: ops.c:1155
MAX_DITHER_BUFS
#define MAX_DITHER_BUFS
Definition: ops.c:85
SwsFormat::interlaced
int interlaced
Definition: format.h:79
spi_OpTypeFunction
static int spi_OpTypeFunction(SPICtx *spi, int return_type_id, const int *args, int nb_args)
Definition: spvasm.h:497
ff_sws_op_list_input
const SwsOp * ff_sws_op_list_input(const SwsOpList *ops)
Returns the input operation for a given op list, or NULL if there is none (e.g.
Definition: ops.c:671
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:62
ff_vk_exec_pool_init
int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext)
Allocates/frees an execution pool.
Definition: vulkan.c:357
AVRefStructOpaque
RefStruct is an API for creating reference-counted objects with minimal overhead.
Definition: refstruct.h:58
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:243
spi_OpConstantUInt
static int spi_OpConstantUInt(SPICtx *spi, int type_id, uint32_t val)
Definition: spvasm.h:564
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:459
spi_OpFunctionEnd
static void spi_OpFunctionEnd(SPICtx *spi)
Definition: spvasm.h:531
AVFrame::width
int width
Definition: frame.h:531
ff_vk_map_buffer
static int ff_vk_map_buffer(FFVulkanContext *s, FFVkBuffer *buf, uint8_t **mem, int invalidate)
Definition: vulkan.h:603
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:70
FFVulkanShader::src
AVBPrint src
Definition: vulkan.h:234
data
const char data[16]
Definition: mxf.c:149
spi_OpDecorate
#define spi_OpDecorate(spi, target, deco,...)
Definition: spvasm.h:355
VulkanPriv::s
FFVulkanOpsCtx * s
Definition: ops.c:88
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:102
ff_vk_init
int ff_vk_init(FFVulkanContext *s, void *log_parent, AVBufferRef *device_ref, AVBufferRef *frames_ref)
Initializes the AVClass, in case this context is not used as the main user's context.
Definition: vulkan.c:2873
ff_vk_exec_get
FFVkExecContext * ff_vk_exec_get(FFVulkanContext *s, FFVkExecPool *pool)
Retrieve an execution pool.
Definition: vulkan.c:558
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: ops.h:37
ff_vk_uninit
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
Definition: vulkan.c:2861
spi_OpAccessChain
#define spi_OpAccessChain(spi, res_type, ptr_id,...)
Definition: spvasm.h:311
spi_OpCompositeExtract
#define spi_OpCompositeExtract(spi, res_type, src,...)
Definition: spvasm.h:319
ff_vk_exec_bind_shader
void ff_vk_exec_bind_shader(FFVulkanContext *s, FFVkExecContext *e, const FFVulkanShader *shd)
Bind a shader.
Definition: vulkan.c:2812
SwsOpBackend::name
const char * name
Definition: ops_dispatch.h:131
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:379
ff_vk_exec_add_dep_frame
int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, VkPipelineStageFlagBits2 wait_stage, VkPipelineStageFlagBits2 signal_stage)
Definition: vulkan.c:790
FFVkShaderRepFormat
FFVkShaderRepFormat
Returns the format to use for images in shaders.
Definition: vulkan.h:447
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:33
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:296
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:38
fail
#define fail()
Definition: checkasm.h:225
SwsOpList::num_ops
int num_ops
Definition: ops.h:290
ff_vk_shader_update_img_array
void ff_vk_shader_update_img_array(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, AVFrame *f, VkImageView *views, int set, int binding, VkImageLayout layout, VkSampler sampler)
Update a descriptor in a buffer with an image array.
Definition: vulkan.c:2763
ff_vk_frame_barrier
void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e, AVFrame *pic, VkImageMemoryBarrier2 *bar, int *nb_bar, VkPipelineStageFlags2 src_stage, VkPipelineStageFlags2 dst_stage, VkAccessFlagBits2 new_access, VkImageLayout new_layout, uint32_t new_qf)
Definition: vulkan.c:2075
SPICtx
Definition: spvasm.h:52
SWS_COMP_TEST
#define SWS_COMP_TEST(mask, X)
Definition: ops.h:89
ff_vk_shader_register_exec
int ff_vk_shader_register_exec(FFVulkanContext *s, FFVkExecPool *pool, FFVulkanShader *shd)
Register a shader with an exec pool.
Definition: vulkan.c:2628
ff_sws_pixel_type_is_int
bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: ops.c:92
val
static double val(void *priv, double ch)
Definition: aeval.c:77
spi_OpTypeBool
static int spi_OpTypeBool(SPICtx *spi)
Definition: spvasm.h:429
AVRational::num
int num
Numerator.
Definition: rational.h:59
spi_OpConstantComposite
#define spi_OpConstantComposite(spi, res_type, src,...)
Definition: spvasm.h:307
refstruct.h
spvasm.h
FFVulkanDescriptorSetBinding::type
VkDescriptorType type
Definition: vulkan.h:114
SwsFrame
Represents a view into a single field of frame data.
Definition: format.h:210
SWS_OP_SCALE
@ SWS_OP_SCALE
Definition: ops.h:66
GLSLC
#define GLSLC(N, S)
Definition: vulkan.h:45
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
main
int main
Definition: dovi_rpuenc.c:38
spi_reserve
static int spi_reserve(SPICtx *spi, int len)
Definition: spvasm.h:108
SwsPass::priv
void * priv
Definition: graph.h:110
float
float
Definition: af_crystalizer.c:122
ff_sws_vk_init
int ff_sws_vk_init(SwsContext *sws, AVBufferRef *dev_ref)
Definition: ops.c:44
dither
static const uint16_t dither[8][8]
Definition: vf_gradfun.c:46
s
#define s(width, name)
Definition: cbs_vp9.c:198
VulkanPriv::nb_dither_buf
int nb_dither_buf
Definition: ops.c:92
spi_init
static void spi_init(SPICtx *spi, uint8_t *spv_buf, int buf_len)
Definition: spvasm.h:86
spi_OpFunction
static void spi_OpFunction(SPICtx *spi, int fn_id, int result_type_id, SpvFunctionControlMask function_control, int function_type_id)
Definition: spvasm.h:508
op
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
Definition: anm.c:76
ops.h
spi_OpMemoryModel
static void spi_OpMemoryModel(SPICtx *spi, SpvAddressingModel addressing_model, SpvMemoryModel memory_model)
Definition: spvasm.h:125
ff_vk_exec_wait
void ff_vk_exec_wait(FFVulkanContext *s, FFVkExecContext *e)
Definition: vulkan.c:563
spi_OpLabel
static int spi_OpLabel(SPICtx *spi, int label_id)
Definition: spvasm.h:519
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
FF_VK_REP_FLOAT
@ FF_VK_REP_FLOAT
Definition: vulkan.h:451
av_refstruct_alloc_ext
static void * av_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque, void(*free_cb)(AVRefStructOpaque opaque, void *obj))
A wrapper around av_refstruct_alloc_ext_c() for the common case of a non-const qualified opaque.
Definition: refstruct.h:94
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:64
ff_sws_pixel_expand
static AVRational ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
Definition: ops_internal.h:31
SPICtx::id
int id
Definition: spvasm.h:59
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:69
ff_sws_op_list_output
const SwsOp * ff_sws_op_list_output(const SwsOpList *ops)
Returns the output operation for a given op list, or NULL if there is none.
Definition: ops.c:680
SPICtx::off
int off
Definition: spvasm.h:55
ff_vk_exec_pool_free
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
Definition: vulkan.c:299
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
SwsOpBackend
Definition: ops_dispatch.h:130
spi_OpUndef
static int spi_OpUndef(SPICtx *spi, int type_id)
Definition: spvasm.h:414
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
buf_desc
Definition: v4l2.c:128
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:57
SwsOp::dither
SwsDitherOp dither
Definition: ops.h:251
spi_OpBranchConditional
static void spi_OpBranchConditional(SPICtx *spi, int cond_id, int true_label, int false_label, uint32_t branch_weights)
Definition: spvasm.h:641
NULL
#define NULL
Definition: coverity.c:32
spi_OpExtInst
#define spi_OpExtInst(spi, res_type, instr_id, set_id,...)
Definition: spvasm.h:347
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
spi_OpTypeImage
static int spi_OpTypeImage(SPICtx *spi, int sampled_type_id, SpvDim dim, int depth, int arrayed, int ms, int sampled, SpvImageFormat image_format)
Definition: spvasm.h:452
ff_vk_shader_link
int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd, const char *spirv, size_t spirv_len, const char *entrypoint)
Link a shader into an executable.
Definition: vulkan.c:2401
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:265
spi_OpEntryPoint
static int spi_OpEntryPoint(SPICtx *spi, SpvExecutionModel execution_model, const char *name, const int *args, int nb_args)
Definition: spvasm.h:371
VulkanPriv::dither_buf
FFVkBuffer dither_buf[MAX_DITHER_BUFS]
Definition: ops.c:91
spi_OpTypeStruct
#define spi_OpTypeStruct(spi, id,...)
Definition: spvasm.h:351
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
spi_OpSelectionMerge
static void spi_OpSelectionMerge(SPICtx *spi, int merge_block, SpvSelectionControlMask selection_control)
Definition: spvasm.h:633
AV_PIX_FMT_X2BGR10
#define AV_PIX_FMT_X2BGR10
Definition: pixfmt.h:614
FFVulkanDescriptorSetBinding
Definition: vulkan.h:112
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
SwsOp::type
SwsPixelType type
Definition: ops.h:240
size
int size
Definition: twinvq_data.h:10344
AV_NUM_DATA_POINTERS
#define AV_NUM_DATA_POINTERS
Definition: frame.h:460
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:59
VulkanPriv::dst_rep
enum FFVkShaderRepFormat dst_rep
Definition: ops.c:94
SwsOpList::src
SwsFormat src
Definition: ops.h:293
FFVulkanShader
Definition: vulkan.h:225
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:51
av_refstruct_ref
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition: refstruct.c:140
img
#define img
Definition: vf_colormatrix.c:114
spi_OpTypeArray
static int spi_OpTypeArray(SPICtx *spi, int element_type_id, int id, int length_id)
Definition: spvasm.h:469
FFVkExecContext
Definition: vulkan.h:145
spi_OpExtInstImport
static int spi_OpExtInstImport(SPICtx *spi, const char *name)
Definition: spvasm.h:396
ff_vk_shader_update_desc_buffer
int ff_vk_shader_update_desc_buffer(FFVulkanContext *s, FFVkExecContext *e, FFVulkanShader *shd, int set, int bind, int elem, FFVkBuffer *buf, VkDeviceSize offset, VkDeviceSize len, VkFormat fmt)
Update a descriptor in a buffer with a buffer.
Definition: vulkan.c:2776
FFVulkanDescriptorSetBinding::name
const char * name
Definition: vulkan.h:113
av_refstruct_unref
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
Definition: refstruct.c:120
EnumOpaque::opaque
void * opaque
Definition: ops.c:1089
SwsFormat::format
enum AVPixelFormat format
Definition: format.h:80
ff_vk_exec_start
int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e)
Start/submit/wait an execution.
Definition: vulkan.c:570
spi_get_id
static int spi_get_id(SPICtx *spi)
Definition: spvasm.h:133
FF_VK_REP_UINT
@ FF_VK_REP_UINT
Definition: vulkan.h:455
process
static void process(const SwsFrame *dst, const SwsFrame *src, int y, int h, const SwsPass *pass)
Definition: ops.c:97
SwsOpList::ops
SwsOp * ops
Definition: ops.h:289
VulkanPriv
Definition: ops.c:87
ff_vk_unmap_buffer
static int ff_vk_unmap_buffer(FFVulkanContext *s, FFVkBuffer *buf, int flush)
Definition: vulkan.h:610
spi_OpCompositeConstruct
#define spi_OpCompositeConstruct(spi, res_type, src,...)
Definition: spvasm.h:315
spi_OpImageWrite
static void spi_OpImageWrite(SPICtx *spi, int img_id, int pos_id, int src_id, SpvImageOperandsMask image_operands)
Definition: spvasm.h:668
len
int len
Definition: vorbis_enc_data.h:426
SwsOp
Definition: ops.h:238
spi_OpVectorShuffle
#define spi_OpVectorShuffle(spi, res_type, src1, src2,...)
Definition: spvasm.h:363
ff_vk_free_buf
void ff_vk_free_buf(FFVulkanContext *s, FFVkBuffer *buf)
Definition: vulkan.c:1254
SwsInternal
Definition: swscale_internal.h:335
ff_vk_create_imageviews
int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e, VkImageView views[AV_NUM_DATA_POINTERS], AVFrame *f, enum FFVkShaderRepFormat rep_fmt)
Create an imageview and add it as a dependency to an execution.
Definition: vulkan.c:1992
spi_OpTypeVoid
static int spi_OpTypeVoid(SPICtx *spi)
Definition: spvasm.h:422
SwsOpList::dst
SwsFormat dst
Definition: ops.h:293
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:65
SwsCompiledOp
Definition: ops_dispatch.h:100
FFVkExecPool
Definition: vulkan.h:290
pos
unsigned int pos
Definition: spdifenc.c:414
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
ff_vk_qf_find
AVVulkanDeviceQueueFamily * ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops)
Chooses an appropriate QF.
Definition: vulkan.c:286
id
enum AVCodecID id
Definition: dts2pts.c:550
spi_OpReturn
static void spi_OpReturn(SPICtx *spi)
Definition: spvasm.h:526
AVFrame::height
int height
Definition: frame.h:531
ff_vk_shader_add_descriptor_set
int ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd, const FFVulkanDescriptorSetBinding *desc, int nb, int singular, int print_to_shader_only)
Add descriptor to a shader.
Definition: vulkan.c:2528
spi_OpImageRead
static int spi_OpImageRead(SPICtx *spi, int result_type_id, int img_id, int pos_id, SpvImageOperandsMask image_operands)
Definition: spvasm.h:655
FFVulkanShader::precompiled
int precompiled
Definition: vulkan.h:230
GLSLF
#define GLSLF(N, S,...)
Definition: vulkan.h:55
AVRational::den
int den
Denominator.
Definition: rational.h:60
SwsReadWriteOp::packed
bool packed
Definition: ops.h:128
spi_OpMemberDecorate
#define spi_OpMemberDecorate(spi, type, target, deco,...)
Definition: spvasm.h:359
ff_sws_pixel_type_name
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition: ops.c:62
spi_OpCapability
static void spi_OpCapability(SPICtx *spi, SpvCapability capability)
Definition: spvasm.h:119
create_dither_bufs
static int create_dither_bufs(FFVulkanOpsCtx *s, VulkanPriv *p, SwsOpList *ops)
Definition: ops.c:166
FFVulkanShader::lg_size
uint32_t lg_size[3]
Definition: vulkan.h:237
spi_OpConstantFloat
static int spi_OpConstantFloat(SPICtx *spi, int type_id, float val)
Definition: spvasm.h:595
VulkanPriv::shd
FFVulkanShader shd
Definition: ops.c:90
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
free_fn
static void free_fn(void *priv)
Definition: ops.c:155
SwsReadWriteOp::elems
uint8_t elems
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
Definition: ops.h:126
mem.h
spi_OpLoad
static int spi_OpLoad(SPICtx *spi, int result_type_id, int ptr_id, SpvMemoryAccessMask memory_access, int align)
Definition: spvasm.h:607
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
spi_OpTypePointer
static int spi_OpTypePointer(SPICtx *spi, SpvStorageClass storage_class, int type_id)
Definition: spvasm.h:487
spi_OpCompositeInsert
#define spi_OpCompositeInsert(spi, res_type, src1, src2,...)
Definition: spvasm.h:367
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:63
FFVkBuffer
Definition: vulkan.h:125
ff_sws_vk_uninit
static void ff_sws_vk_uninit(AVRefStructOpaque opaque, void *obj)
Copyright (C) 2026 Lynne.
Definition: ops.c:33
ff_vk_exec_submit
int ff_vk_exec_submit(FFVulkanContext *s, FFVkExecContext *e)
Definition: vulkan.c:915
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:79
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
h
h
Definition: vp9dsp_template.c:2070
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:296
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:288
ff_sws_op_type_name
const char * ff_sws_op_type_name(SwsOpType op)
Definition: ops.c:109
SwsContext
Main external API structure.
Definition: swscale.h:206
snprintf
#define snprintf
Definition: snprintf.h:34
FFVulkanFunctions
Definition: vulkan_functions.h:275
ff_vk_shader_load
int ff_vk_shader_load(FFVulkanShader *shd, VkPipelineStageFlags stage, VkSpecializationInfo *spec, uint32_t wg_size[3], uint32_t required_subgroup_size)
Initialize a shader object.
Definition: vulkan.c:2118
src
#define src
Definition: vp8dsp.c:248
read
static uint32_t BS_FUNC() read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
Definition: bitstream_template.h:239