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  default:
879  return AVERROR(ENOTSUP);
880  }
881  }
882 
883  /* Return and finalize */
884  spi_OpReturn(spi);
885  spi_OpFunctionEnd(spi);
886 
887  int len = spi_end(spi);
888  if (len < 0)
889  return AVERROR_INVALIDDATA;
890 
891  return ff_vk_shader_link(&s->vkctx, shd, spvbuf, len, "main");
892 }
893 #endif
894 
895 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
896 static void add_desc_read_write(FFVulkanDescriptorSetBinding *out_desc,
897  enum FFVkShaderRepFormat *out_rep,
898  const SwsOp *op)
899 {
900  const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f" :
901  op->type == SWS_PIXEL_U32 ? "rgba32ui" :
902  op->type == SWS_PIXEL_U16 ? "rgba16ui" :
903  "rgba8ui";
904 
905  *out_desc = (FFVulkanDescriptorSetBinding) {
906  .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img",
907  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
908  .mem_layout = img_type,
909  .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly",
910  .dimensions = 2,
911  .elems = 4,
912  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
913  };
914 
915  *out_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
916 }
917 
918 #define QSTR "(%i/%i%s)"
919 #define QTYPE(Q) (Q).num, (Q).den, cur_type == SWS_PIXEL_F32 ? ".0f" : ""
920 
921 static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
922  SwsOpList *ops, FFVulkanShader *shd)
923 {
924  int err;
925  uint8_t *spv_data;
926  size_t spv_len;
927  void *spv_opaque = NULL;
928 
929  /* Interlaced formats are not currently supported */
930  if (ops->src.interlaced || ops->dst.interlaced)
931  return AVERROR(ENOTSUP);
932 
933  err = ff_vk_shader_init(&s->vkctx, shd, "sws_pass",
934  VK_SHADER_STAGE_COMPUTE_BIT,
935  NULL, 0, 32, 32, 1, 0);
936  if (err < 0)
937  return err;
938 
939  int nb_desc = 0;
941 
942  const SwsOp *read = ff_sws_op_list_input(ops);
943  const SwsOp *write = ff_sws_op_list_output(ops);
944  if (read)
945  add_desc_read_write(&buf_desc[nb_desc++], &p->src_rep, read);
946  add_desc_read_write(&buf_desc[nb_desc++], &p->dst_rep, write);
947  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc, nb_desc, 0, 0);
948 
949  err = create_dither_bufs(s, p, ops);
950  if (err < 0)
951  return err;
952 
953  nb_desc = 0;
954  char dither_buf_name[MAX_DITHER_BUFS][64];
955  char dither_mat_name[MAX_DITHER_BUFS][64];
956  for (int n = 0; n < ops->num_ops; n++) {
957  const SwsOp *op = &ops->ops[n];
958  if (op->op != SWS_OP_DITHER)
959  continue;
960  int size = (1 << op->dither.size_log2);
961  av_assert0(size < 8192);
962  snprintf(dither_buf_name[nb_desc], 64, "dither_buf%i", n);
963  snprintf(dither_mat_name[nb_desc], 64, "float dither_mat%i[%i][%i];",
964  n, size, size);
966  .name = dither_buf_name[nb_desc],
967  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
968  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
969  .mem_layout = "scalar",
970  .buf_content = dither_mat_name[nb_desc],
971  };
972  nb_desc++;
973  }
974  if (nb_desc)
976  nb_desc, 1, 0);
977 
978  GLSLC(0, void main() );
979  GLSLC(0, { );
980  GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
981  GLSLC(1, ivec2 size = imageSize(src_img[0]); );
982  GLSLC(1, if (any(greaterThanEqual(pos, size))) );
983  GLSLC(2, return; );
984  GLSLC(0, );
985  GLSLC(1, u8vec4 u8; );
986  GLSLC(1, u16vec4 u16; );
987  GLSLC(1, u32vec4 u32; );
988  GLSLC(1, precise f32vec4 f32; );
989  GLSLC(1, precise f32vec4 tmp; );
990  GLSLC(0, );
991 
992  for (int n = 0; n < ops->num_ops; n++) {
993  const SwsOp *op = &ops->ops[n];
994  SwsPixelType cur_type = op->op == SWS_OP_CONVERT ? op->convert.to :
995  op->type;
996  const char *type_name = ff_sws_pixel_type_name(cur_type);
997  const char *type_v = cur_type == SWS_PIXEL_F32 ? "f32vec4" :
998  cur_type == SWS_PIXEL_U32 ? "u32vec4" :
999  cur_type == SWS_PIXEL_U16 ? "u16vec4" : "u8vec4";
1000  const char *type_s = cur_type == SWS_PIXEL_F32 ? "float" :
1001  cur_type == SWS_PIXEL_U32 ? "uint32_t" :
1002  cur_type == SWS_PIXEL_U16 ? "uint16_t" : "uint8_t";
1003  av_bprintf(&shd->src, " // %s\n", ff_sws_op_type_name(op->op));
1004 
1005  switch (op->op) {
1006  case SWS_OP_READ: {
1007  if (op->rw.frac || op->rw.filter) {
1008  return AVERROR(ENOTSUP);
1009  } else if (op->rw.packed) {
1010  GLSLF(1, %s = %s(imageLoad(src_img[%i], pos)); ,
1011  type_name, type_v, ops->plane_src[0]);
1012  } else {
1013  for (int i = 0; i < op->rw.elems; i++)
1014  GLSLF(1, %s.%c = %s(imageLoad(src_img[%i], pos)[0]); ,
1015  type_name, "xyzw"[i], type_s, ops->plane_src[i]);
1016  }
1017  break;
1018  }
1019  case SWS_OP_WRITE: {
1020  if (op->rw.frac || op->rw.filter) {
1021  return AVERROR(ENOTSUP);
1022  } else if (op->rw.packed) {
1023  GLSLF(1, imageStore(dst_img[%i], pos, %s(%s)); ,
1024  ops->plane_dst[0], type_v, type_name);
1025  } else {
1026  for (int i = 0; i < op->rw.elems; i++)
1027  GLSLF(1, imageStore(dst_img[%i], pos, %s(%s[%i])); ,
1028  ops->plane_dst[i], type_v, type_name, i);
1029  }
1030  break;
1031  }
1032  case SWS_OP_SWIZZLE: {
1033  av_bprintf(&shd->src, " %s = %s.", type_name, type_name);
1034  for (int i = 0; i < 4; i++)
1035  av_bprintf(&shd->src, "%c", "xyzw"[op->swizzle.in[i]]);
1036  av_bprintf(&shd->src, ";\n");
1037  break;
1038  }
1039  case SWS_OP_CLEAR: {
1040  for (int i = 0; i < 4; i++) {
1041  if (!SWS_COMP_TEST(op->clear.mask, i))
1042  continue;
1043  av_bprintf(&shd->src, " %s.%c = %s"QSTR";\n", type_name,
1044  "xyzw"[i], type_s, QTYPE(op->clear.value[i]));
1045  }
1046  break;
1047  }
1048  case SWS_OP_SCALE:
1049  av_bprintf(&shd->src, " %s = %s * "QSTR";\n",
1050  type_name, type_name, QTYPE(op->scale.factor));
1051  break;
1052  case SWS_OP_MIN:
1053  case SWS_OP_MAX:
1054  for (int i = 0; i < 4; i++) {
1055  if (!op->clamp.limit[i].den)
1056  continue;
1057  av_bprintf(&shd->src, " %s.%c = %s(%s.%c, "QSTR");\n",
1058  type_name, "xyzw"[i],
1059  op->op == SWS_OP_MIN ? "min" : "max",
1060  type_name, "xyzw"[i], QTYPE(op->clamp.limit[i]));
1061  }
1062  break;
1063  case SWS_OP_LSHIFT:
1064  case SWS_OP_RSHIFT:
1065  av_bprintf(&shd->src, " %s %s= %i;\n", type_name,
1066  op->op == SWS_OP_LSHIFT ? "<<" : ">>", op->shift.amount);
1067  break;
1068  case SWS_OP_CONVERT:
1069  if (ff_sws_pixel_type_is_int(cur_type) && op->convert.expand) {
1070  const AVRational sc = ff_sws_pixel_expand(op->type, op->convert.to);
1071  av_bprintf(&shd->src, " %s = %s((%s*%i)/%i);\n",
1072  type_name, type_v, ff_sws_pixel_type_name(op->type),
1073  sc.num, sc.den);
1074  } else {
1075  av_bprintf(&shd->src, " %s = %s(%s);\n",
1076  type_name, type_v, ff_sws_pixel_type_name(op->type));
1077  }
1078  break;
1079  case SWS_OP_DITHER: {
1080  int size = (1 << op->dither.size_log2);
1081  for (int i = 0; i < 4; i++) {
1082  if (op->dither.y_offset[i] < 0)
1083  continue;
1084  av_bprintf(&shd->src, " %s.%c += dither_mat%i[(pos.y + %i) & %i]"
1085  "[pos.x & %i];\n",
1086  type_name, "xyzw"[i], n,
1087  op->dither.y_offset[i], size - 1,
1088  size - 1);
1089  }
1090  break;
1091  }
1092  case SWS_OP_LINEAR:
1093  for (int i = 0; i < 4; i++) {
1094  if (op->lin.m[i][4].num)
1095  av_bprintf(&shd->src, " tmp.%c = "QSTR";\n", "xyzw"[i],
1096  QTYPE(op->lin.m[i][4]));
1097  else
1098  av_bprintf(&shd->src, " tmp.%c = 0;\n", "xyzw"[i]);
1099  for (int j = 0; j < 4; j++) {
1100  if (!op->lin.m[i][j].num)
1101  continue;
1102  av_bprintf(&shd->src, " tmp.%c += f32.%c*"QSTR";\n",
1103  "xyzw"[i], "xyzw"[j], QTYPE(op->lin.m[i][j]));
1104  }
1105  }
1106  av_bprintf(&shd->src, " f32 = tmp;\n");
1107  break;
1108  default:
1109  return AVERROR(ENOTSUP);
1110  }
1111  }
1112 
1113  GLSLC(0, } );
1114 
1115  err = s->spvc->compile_shader(&s->vkctx, s->spvc, shd,
1116  &spv_data, &spv_len, "main",
1117  &spv_opaque);
1118  if (err < 0)
1119  return err;
1120 
1121  err = ff_vk_shader_link(&s->vkctx, shd, spv_data, spv_len, "main");
1122 
1123  if (spv_opaque)
1124  s->spvc->free_shader(s->spvc, &spv_opaque);
1125 
1126  if (err < 0)
1127  return err;
1128 
1129  return 0;
1130 }
1131 #endif
1132 
1133 static int compile(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out, int glsl)
1134 {
1135  int err;
1136  SwsInternal *c = sws_internal(sws);
1137  FFVulkanOpsCtx *s = c->hw_priv;
1138  if (!s)
1139  return AVERROR(ENOTSUP);
1140 
1141  VulkanPriv *p = av_mallocz(sizeof(*p));
1142  if (!p)
1143  return AVERROR(ENOMEM);
1144  p->s = av_refstruct_ref(c->hw_priv);
1145 
1146  err = ff_vk_exec_pool_init(&s->vkctx, s->qf, &p->e, 1,
1147  0, 0, 0, NULL);
1148  if (err < 0)
1149  goto fail;
1150 
1151  if (ops->src.format == AV_PIX_FMT_BGR0 ||
1152  ops->src.format == AV_PIX_FMT_BGRA ||
1153  ops->dst.format == AV_PIX_FMT_BGR0 ||
1154  ops->dst.format == AV_PIX_FMT_BGRA) {
1155  VkFormatProperties2 prop = {
1156  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
1157  };
1158  FFVulkanFunctions *vk = &s->vkctx.vkfn;
1159  vk->GetPhysicalDeviceFormatProperties2(s->vkctx.hwctx->phys_dev,
1160  VK_FORMAT_B8G8R8A8_UNORM,
1161  &prop);
1162  if (!(prop.formatProperties.optimalTilingFeatures &
1163  VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT)) {
1164  err = AVERROR(ENOTSUP);
1165  goto fail;
1166  }
1167  }
1168 
1169  if (glsl) {
1170  err = AVERROR(ENOTSUP);
1171 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
1172  err = add_ops_glsl(p, s, ops, &p->shd);
1173 #endif
1174  } else {
1175  err = AVERROR(ENOTSUP);
1176 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
1177  err = add_ops_spirv(p, s, ops, &p->shd);
1178 #endif
1179  }
1180  if (err < 0)
1181  goto fail;
1182 
1183  err = ff_vk_shader_register_exec(&s->vkctx, &p->e, &p->shd);
1184  if (err < 0)
1185  goto fail;
1186 
1187  for (int i = 0; i < p->nb_dither_buf; i++)
1188  ff_vk_shader_update_desc_buffer(&s->vkctx, &p->e.contexts[0], &p->shd,
1189  1, i, 0, &p->dither_buf[i],
1190  0, VK_WHOLE_SIZE, VK_FORMAT_UNDEFINED);
1191 
1192  *out = (SwsCompiledOp) {
1193  .opaque = true,
1194  .func_opaque = process,
1195  .priv = p,
1196  .free = free_fn,
1197  };
1198 
1199  return 0;
1200 
1201 fail:
1202  free_fn(p);
1203  return err;
1204 }
1205 
1206 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
1207 static int compile_spirv(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out)
1208 {
1209  return compile(sws, ops, out, 0);
1210 }
1211 
1212 const SwsOpBackend backend_spirv = {
1213  .name = "spirv",
1214  .compile = compile_spirv,
1215  .hw_format = AV_PIX_FMT_VULKAN,
1216 };
1217 #endif
1218 
1219 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
1220 static int compile_glsl(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out)
1221 {
1222  return compile(sws, ops, out, 1);
1223 }
1224 
1225 const SwsOpBackend backend_glsl = {
1226  .name = "glsl",
1227  .compile = compile_glsl,
1228  .hw_format = AV_PIX_FMT_VULKAN,
1229 };
1230 #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
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:2820
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:2132
out
static FILE * out
Definition: movenc.c:55
compile
static int compile(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out, int glsl)
Definition: ops.c:1133
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:435
spi_OpFunctionEnd
static void spi_OpFunctionEnd(SPICtx *spi)
Definition: spvasm.h:531
AVFrame::width
int width
Definition: frame.h:507
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:2858
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:2846
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:2797
SwsOpBackend::name
const char * name
Definition: ops_internal.h:56
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:224
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:2748
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:2060
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:2613
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:193
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_internal.h:55
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
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:2386
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
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:436
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:2761
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:1080
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:1977
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:507
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:2513
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:2103
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