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  AVRational cv = op->clear.value[i];
402  if (cv.den && op->type == SWS_PIXEL_F32) {
403  float q = (float)cv.num/cv.den;
404  id->const_ids[id->nb_const_ids++] =
405  spi_OpConstantFloat(spi, f32_type, q);
406  } else if (op->clear.value[i].den) {
407  av_assert0(cv.den == 1);
408  id->const_ids[id->nb_const_ids++] =
409  spi_OpConstantUInt(spi, u32_type, cv.num);
410  }
411  }
412  break;
413  case SWS_OP_LSHIFT:
414  case SWS_OP_RSHIFT: {
415  int tmp = spi_OpConstantUInt(spi, u32_type, op->shift.amount);
416  tmp = spi_OpConstantComposite(spi, id->u32vec4_type,
417  tmp, tmp, tmp, tmp);
418  id->const_ids[id->nb_const_ids++] = tmp;
419  break;
420  }
421  case SWS_OP_SCALE: {
422  int tmp;
423  if (op->type == SWS_PIXEL_F32) {
424  float q = op->scale.factor.num/(float)op->scale.factor.den;
425  tmp = spi_OpConstantFloat(spi, f32_type, q);
426  tmp = spi_OpConstantComposite(spi, id->f32vec4_type,
427  tmp, tmp, tmp, tmp);
428  } else {
429  av_assert0(op->scale.factor.den == 1);
430  tmp = spi_OpConstantUInt(spi, u32_type, op->scale.factor.num);
431  tmp = spi_OpConstantComposite(spi, id->u32vec4_type,
432  tmp, tmp, tmp, tmp);
433  }
434  id->const_ids[id->nb_const_ids++] = tmp;
435  break;
436  }
437  case SWS_OP_MIN:
438  case SWS_OP_MAX:
439  for (int i = 0; i < 4; i++) {
440  int tmp;
441  AVRational cl = op->clamp.limit[i];
442  if (!op->clamp.limit[i].den) {
443  continue;
444  } else if (op->type == SWS_PIXEL_F32) {
445  float q = (float)cl.num/((float)cl.den);
446  tmp = spi_OpConstantFloat(spi, f32_type, q);
447  } else {
448  av_assert0(cl.den == 1);
449  tmp = spi_OpConstantUInt(spi, u32_type, cl.num);
450  }
451  id->const_ids[id->nb_const_ids++] = tmp;
452  }
453  break;
454  case SWS_OP_DITHER:
455  for (int i = 0; i < 4; i++) {
456  if (op->dither.y_offset[i] < 0)
457  continue;
458  int tmp = spi_OpConstantUInt(spi, u32_type, op->dither.y_offset[i]);
459  id->const_ids[id->nb_const_ids++] = tmp;
460  }
461  break;
462  case SWS_OP_LINEAR: {
463  for (int i = 0; i < 4; i++) {
464  float val;
465  if (op->lin.m[i][0].num) {
466  val = op->lin.m[i][0].num/(float)op->lin.m[i][0].den;
467  id->const_ids[id->nb_const_ids++] =
468  spi_OpConstantFloat(spi, f32_type, val);
469  }
470  if (op->lin.m[i][4].num) {
471  val = op->lin.m[i][4].num/(float)op->lin.m[i][4].den;
472  id->const_ids[id->nb_const_ids++] =
473  spi_OpConstantFloat(spi, f32_type, val);
474  }
475  for (int j = 1; j < 4; j++) {
476  if (!op->lin.m[i][j].num)
477  continue;
478  val = op->lin.m[i][j].num/(float)op->lin.m[i][j].den;
479  id->const_ids[id->nb_const_ids++] =
480  spi_OpConstantFloat(spi, f32_type, val);
481  }
482  }
483  break;
484  }
485  default:
486  break;
487  }
488  }
489 }
490 
491 /* Section 3: Define bindings */
492 static void define_shader_bindings(SwsOpList *ops, SPICtx *spi, SPIRVIDs *id,
493  int in_img_count, int out_img_count)
494 {
495  id->dither_ptr_elem_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
496  id->f32_type);
497 
498  struct DitherData *dither = id->dither;
499  for (int i = 0; i < id->nb_dither_bufs; i++) {
500  int size_id = spi_OpConstantUInt(spi, id->u32_type, dither[i].size);
501  dither[i].mask_id = spi_OpConstantUInt(spi, id->u32_type, dither[i].size - 1);
502  spi_OpTypeArray(spi, id->f32_type, dither[i].arr_1d_id, size_id);
503  spi_OpTypeArray(spi, dither[i].arr_1d_id, dither[i].arr_2d_id, size_id);
504  spi_OpTypeStruct(spi, dither[i].struct_id, dither[i].arr_2d_id);
505  dither[i].struct_ptr_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
506  dither[i].struct_id);
507  dither[i].id = spi_OpVariable(spi, dither[i].id, dither[i].struct_ptr_id,
508  SpvStorageClassUniform, 0);
509  }
510 
511  const SwsOp *op_w = ff_sws_op_list_output(ops);
512  const SwsOp *op_r = ff_sws_op_list_input(ops);
513 
514  /* Define image types for descriptors */
515  id->out_img_type = spi_OpTypeImage(spi,
516  op_w->type == SWS_PIXEL_F32 ?
517  id->f32_type : id->u32_type,
518  2, 0, 0, 0, 2, SpvImageFormatUnknown);
519  id->out_img_array_id = spi_OpTypeArray(spi, id->out_img_type, spi_get_id(spi),
520  id->u32_cid[out_img_count]);
521 
522  id->in_img_type = 0;
523  id->in_img_array_id = 0;
524  if (op_r) {
525  /* If the formats match, we have to reuse the types due to SPIR-V not
526  * allowing redundant type defines */
527  int match = ((op_w->type == SWS_PIXEL_F32) ==
528  (op_r->type == SWS_PIXEL_F32));
529  id->in_img_type = match ? id->out_img_type :
530  spi_OpTypeImage(spi,
531  op_r->type == SWS_PIXEL_F32 ?
532  id->f32_type : id->u32_type,
533  2, 0, 0, 0, 2, SpvImageFormatUnknown);
534  id->in_img_array_id = spi_OpTypeArray(spi, id->in_img_type, spi_get_id(spi),
535  id->u32_cid[in_img_count]);
536  }
537 
538  /* Pointer types for images */
539  id->u32vec3_tptr = spi_OpTypePointer(spi, SpvStorageClassInput,
540  id->u32vec3_type);
541  id->out_img_tptr = spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
542  id->out_img_array_id);
543  id->out_img_sptr = spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
544  id->out_img_type);
545 
546  id->in_img_tptr = 0;
547  id->in_img_sptr = 0;
548  if (op_r) {
549  id->in_img_tptr= spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
550  id->in_img_array_id);
551  id->in_img_sptr= spi_OpTypePointer(spi, SpvStorageClassUniformConstant,
552  id->in_img_type);
553  }
554 
555  /* Define inputs */
556  spi_OpVariable(spi, id->in_vars[0], id->u32vec3_tptr,
557  SpvStorageClassInput, 0);
558  if (op_r) {
559  spi_OpVariable(spi, id->in_vars[1], id->in_img_tptr,
560  SpvStorageClassUniformConstant, 0);
561  }
562  spi_OpVariable(spi, id->in_vars[2], id->out_img_tptr,
563  SpvStorageClassUniformConstant, 0);
564 }
565 
566 static int add_ops_spirv(VulkanPriv *p, FFVulkanOpsCtx *s,
567  SwsOpList *ops, FFVulkanShader *shd)
568 {
569  uint8_t spvbuf[1024*16];
570  SPICtx spi_context = { 0 }, *spi = &spi_context;
571  SPIRVIDs spid_data = { 0 }, *id = &spid_data;
572  spi_init(spi, spvbuf, sizeof(spvbuf));
573 
574  /* Interlaced formats are not currently supported */
575  if (ops->src.interlaced || ops->dst.interlaced)
576  return AVERROR(ENOTSUP);
577 
578  ff_vk_shader_load(shd, VK_SHADER_STAGE_COMPUTE_BIT, NULL,
579  (uint32_t []) { 32, 32, 1 }, 0);
580  shd->precompiled = 0;
581 
582  /* Image ops, to determine types */
583  const SwsOp *op_w = ff_sws_op_list_output(ops);
584  int out_img_count = op_w->rw.packed ? 1 : op_w->rw.elems;
585  p->dst_rep = op_w->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
586 
587  const SwsOp *op_r = ff_sws_op_list_input(ops);
588  int in_img_count = op_r ? op_r->rw.packed ? 1 : op_r->rw.elems : 0;
589  if (op_r)
590  p->src_rep = op_r->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
591 
593  {
594  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
595  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
596  .elems = 4,
597  },
598  {
599  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
600  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
601  .elems = 4,
602  },
603  };
604  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, desc_set, 2, 0, 0);
605 
606  /* Create dither buffers */
607  int err = create_dither_bufs(s, p, ops);
608  if (err < 0)
609  return err;
610 
611  /* Entrypoint inputs: gl_GlobalInvocationID, input and output images, dither */
612  id->in_vars[0] = spi_get_id(spi);
613  id->in_vars[1] = spi_get_id(spi);
614  id->in_vars[2] = spi_get_id(spi);
615 
616  /* Create dither buffer descriptor set */
617  id->nb_dither_bufs = 0;
618  for (int n = 0; n < ops->num_ops; n++) {
619  const SwsOp *op = &ops->ops[n];
620  if (op->op != SWS_OP_DITHER)
621  continue;
622 
623  id->dither[id->nb_dither_bufs].size = 1 << op->dither.size_log2;
624  id->dither[id->nb_dither_bufs].arr_1d_id = spi_get_id(spi);
625  id->dither[id->nb_dither_bufs].arr_2d_id = spi_get_id(spi);
626  id->dither[id->nb_dither_bufs].struct_id = spi_get_id(spi);
627  id->dither[id->nb_dither_bufs].id = spi_get_id(spi);
628  id->in_vars[3 + id->nb_dither_bufs] = id->dither[id->nb_dither_bufs].id;
629 
630  desc_set[id->nb_dither_bufs++] = (FFVulkanDescriptorSetBinding) {
631  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
632  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
633  };
634  }
635  if (id->nb_dither_bufs)
636  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, desc_set,
637  id->nb_dither_bufs, 1, 0);
638 
639  /* Define shader header sections */
640  define_shader_header(shd, ops, spi, id);
641  define_shader_consts(ops, spi, id);
642  define_shader_bindings(ops, spi, id, in_img_count, out_img_count);
643 
644  /* Main function starts here */
645  spi_OpFunction(spi, id->ep, id->void_type, 0, id->void_fn_type);
646  spi_OpLabel(spi, spi_get_id(spi));
647 
648  /* Load input image handles */
649  int in_img[4] = { 0 };
650  for (int i = 0; i < in_img_count; i++) {
651  /* Deref array and then the pointer */
652  int img = spi_OpAccessChain(spi, id->in_img_sptr,
653  id->in_vars[1], id->u32_cid[i]);
654  in_img[i] = spi_OpLoad(spi, id->in_img_type, img,
655  SpvMemoryAccessMaskNone, 0);
656  }
657 
658  /* Load output image handles */
659  int out_img[4];
660  for (int i = 0; i < out_img_count; i++) {
661  int img = spi_OpAccessChain(spi, id->out_img_sptr,
662  id->in_vars[2], id->u32_cid[i]);
663  out_img[i] = spi_OpLoad(spi, id->out_img_type, img,
664  SpvMemoryAccessMaskNone, 0);
665  }
666 
667  /* Load gl_GlobalInvocationID */
668  int gid = spi_OpLoad(spi, id->u32vec3_type, id->in_vars[0],
669  SpvMemoryAccessMaskNone, 0);
670 
671  /* ivec2(gl_GlobalInvocationID.xy) */
672  gid = spi_OpVectorShuffle(spi, id->u32vec2_type, gid, gid, 0, 1);
673  int gi2 = spi_OpBitcast(spi, id->i32vec2_type, gid);
674 
675  /* imageSize(out_img[0]); */
676  int img1_s = spi_OpImageQuerySize(spi, id->i32vec2_type, out_img[0]);
677  int scmp = spi_OpSGreaterThanEqual(spi, id->bvec2_type, gi2, img1_s);
678  scmp = spi_OpAny(spi, id->b_type, scmp);
679 
680  /* if (out of bounds) return */
681  int quit_label = spi_get_id(spi), merge_label = spi_get_id(spi);
682  spi_OpSelectionMerge(spi, merge_label, SpvSelectionControlMaskNone);
683  spi_OpBranchConditional(spi, scmp, quit_label, merge_label, 0);
684 
685  spi_OpLabel(spi, quit_label);
686  spi_OpReturn(spi); /* Quit if out of bounds here */
687  spi_OpLabel(spi, merge_label);
688 
689  /* Initialize main data state */
690  int data;
691  if (ops->ops[0].type == SWS_PIXEL_F32)
692  data = spi_OpCompositeConstruct(spi, id->f32vec4_type,
693  id->f32_p, id->f32_p,
694  id->f32_p, id->f32_p);
695  else
696  data = spi_OpCompositeConstruct(spi, id->u32vec4_type,
697  id->u32_p, id->u32_p,
698  id->u32_p, id->u32_p);
699 
700  /* Keep track of which constant/buffer to use */
701  int nb_const_ids = 0;
702  int nb_dither_bufs = 0;
703  int nb_linear_ops = 0;
704 
705  /* Operations */
706  for (int n = 0; n < ops->num_ops; n++) {
707  const SwsOp *op = &ops->ops[n];
708  SwsPixelType cur_type = op->op == SWS_OP_CONVERT ?
709  op->convert.to : op->type;
710  int type_v = cur_type == SWS_PIXEL_F32 ?
711  id->f32vec4_type : id->u32vec4_type;
712  int type_s = cur_type == SWS_PIXEL_F32 ?
713  id->f32_type : id->u32_type;
714  int uid = cur_type == SWS_PIXEL_F32 ?
715  id->f32_p : id->u32_p;
716 
717  switch (op->op) {
718  case SWS_OP_READ:
719  if (op->rw.frac || op->rw.filter) {
720  return AVERROR(ENOTSUP);
721  } else if (op->rw.packed) {
722  data = spi_OpImageRead(spi, type_v, in_img[ops->plane_src[0]],
723  gid, SpvImageOperandsMaskNone);
724  } else {
725  int tmp[4] = { uid, uid, uid, uid };
726  for (int i = 0; i < op->rw.elems; i++) {
727  tmp[i] = spi_OpImageRead(spi, type_v,
728  in_img[ops->plane_src[i]], gid,
729  SpvImageOperandsMaskNone);
730  tmp[i] = spi_OpCompositeExtract(spi, type_s, tmp[i], 0);
731  }
732  data = spi_OpCompositeConstruct(spi, type_v,
733  tmp[0], tmp[1], tmp[2], tmp[3]);
734  }
735  break;
736  case SWS_OP_WRITE:
737  if (op->rw.frac || op->rw.filter) {
738  return AVERROR(ENOTSUP);
739  } else if (op->rw.packed) {
740  spi_OpImageWrite(spi, out_img[ops->plane_dst[0]], gid, data,
741  SpvImageOperandsMaskNone);
742  } else {
743  for (int i = 0; i < op->rw.elems; i++) {
744  int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
745  tmp = spi_OpCompositeConstruct(spi, type_v, tmp, tmp, tmp, tmp);
746  spi_OpImageWrite(spi, out_img[ops->plane_dst[i]], gid, tmp,
747  SpvImageOperandsMaskNone);
748  }
749  }
750  break;
751  case SWS_OP_CLEAR:
752  for (int i = 0; i < 4; i++) {
753  if (!op->clear.value[i].den)
754  continue;
755  data = spi_OpCompositeInsert(spi, type_v,
756  id->const_ids[nb_const_ids++],
757  data, i);
758  }
759  break;
760  case SWS_OP_SWIZZLE:
761  data = spi_OpVectorShuffle(spi, type_v, data, data,
762  op->swizzle.in[0],
763  op->swizzle.in[1],
764  op->swizzle.in[2],
765  op->swizzle.in[3]);
766  break;
767  case SWS_OP_CONVERT:
768  if (ff_sws_pixel_type_is_int(cur_type) && op->convert.expand)
769  data = spi_OpIMul(spi, type_v, data, id->const_ids[nb_const_ids++]);
770  else if (op->type == SWS_PIXEL_F32 && type_s == id->u32_type)
771  data = spi_OpConvertFToU(spi, type_v, data);
772  else if (op->type != SWS_PIXEL_F32 && type_s == id->f32_type)
773  data = spi_OpConvertUToF(spi, type_v, data);
774  break;
775  case SWS_OP_LSHIFT:
776  data = spi_OpShiftLeftLogical(spi, type_v, data,
777  id->const_ids[nb_const_ids++]);
778  break;
779  case SWS_OP_RSHIFT:
780  data = spi_OpShiftRightLogical(spi, type_v, data,
781  id->const_ids[nb_const_ids++]);
782  break;
783  case SWS_OP_SCALE:
784  if (op->type == SWS_PIXEL_F32)
785  data = spi_OpFMul(spi, type_v, data,
786  id->const_ids[nb_const_ids++]);
787  else
788  data = spi_OpIMul(spi, type_v, data,
789  id->const_ids[nb_const_ids++]);
790  break;
791  case SWS_OP_MIN:
792  case SWS_OP_MAX: {
793  int t = op->type == SWS_PIXEL_F32 ?
794  op->op == SWS_OP_MIN ? GLSLstd450FMin : GLSLstd450FMax :
795  op->op == SWS_OP_MIN ? GLSLstd450UMin : GLSLstd450UMax;
796  for (int i = 0; i < 4; i++) {
797  if (!op->clamp.limit[i].den)
798  continue;
799  int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
800  tmp = spi_OpExtInst(spi, type_s, id->glfn, t,
801  tmp, id->const_ids[nb_const_ids++]);
802  data = spi_OpCompositeInsert(spi, type_v, tmp, data, i);
803  }
804  break;
805  }
806  case SWS_OP_DITHER: {
807  int did = nb_dither_bufs++;
808  int x_id = spi_OpCompositeExtract(spi, id->u32_type, gid, 0);
809  int y_pos = spi_OpCompositeExtract(spi, id->u32_type, gid, 1);
810  x_id = spi_OpBitwiseAnd(spi, id->u32_type, x_id,
811  id->dither[did].mask_id);
812  for (int i = 0; i < 4; i++) {
813  if (op->dither.y_offset[i] < 0)
814  continue;
815 
816  int y_id = spi_OpIAdd(spi, id->u32_type, y_pos,
817  id->const_ids[nb_const_ids++]);
818  y_id = spi_OpBitwiseAnd(spi, id->u32_type, y_id,
819  id->dither[did].mask_id);
820 
821  int ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id,
822  id->dither[did].id, id->u32_cid[0],
823  y_id, x_id);
824  int val = spi_OpLoad(spi, id->f32_type, ptr,
825  SpvMemoryAccessMaskNone, 0);
826 
827  int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
828  tmp = spi_OpFAdd(spi, type_s, tmp, val);
829  data = spi_OpCompositeInsert(spi, type_v, tmp, data, i);
830  }
831  break;
832  }
833  case SWS_OP_LINEAR: {
834  int tmp[4];
835  tmp[0] = spi_OpCompositeExtract(spi, type_s, data, 0);
836  tmp[1] = spi_OpCompositeExtract(spi, type_s, data, 1);
837  tmp[2] = spi_OpCompositeExtract(spi, type_s, data, 2);
838  tmp[3] = spi_OpCompositeExtract(spi, type_s, data, 3);
839 
840  int off = spi_reserve(spi, 0); /* Current offset */
841  spi->off = id->linear_deco_off[nb_linear_ops];
842  for (int i = 0; i < id->linear_deco_ops[nb_linear_ops]; i++)
843  spi_OpDecorate(spi, spi->id + i, SpvDecorationNoContraction);
844  spi->off = off;
845 
846  int res[4];
847  for (int j = 0; j < 4; j++) {
848  res[j] = op->type == SWS_PIXEL_F32 ? id->f32_0 : id->u32_cid[0];
849  if (op->lin.m[j][0].num)
850  res[j] = spi_OpFMul(spi, type_s, tmp[0],
851  id->const_ids[nb_const_ids++]);
852 
853  if (op->lin.m[j][0].num && op->lin.m[j][4].num)
854  res[j] = spi_OpFAdd(spi, type_s,
855  id->const_ids[nb_const_ids++], res[j]);
856  else if (op->lin.m[j][4].num)
857  res[j] = id->const_ids[nb_const_ids++];
858 
859  for (int i = 1; i < 4; i++) {
860  if (!op->lin.m[j][i].num)
861  continue;
862 
863  int v = spi_OpFMul(spi, type_s, tmp[i],
864  id->const_ids[nb_const_ids++]);
865  if (op->lin.m[j][0].num || op->lin.m[j][4].num)
866  res[j] = spi_OpFAdd(spi, type_s, res[j], v);
867  else
868  res[j] = v;
869  }
870  }
871  data = spi_OpCompositeConstruct(spi, type_v,
872  res[0], res[1], res[2], res[3]);
873  nb_linear_ops++;
874  break;
875  }
876  default:
877  return AVERROR(ENOTSUP);
878  }
879  }
880 
881  /* Return and finalize */
882  spi_OpReturn(spi);
883  spi_OpFunctionEnd(spi);
884 
885  int len = spi_end(spi);
886  if (len < 0)
887  return AVERROR_INVALIDDATA;
888 
889  return ff_vk_shader_link(&s->vkctx, shd, spvbuf, len, "main");
890 }
891 #endif
892 
893 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
894 static void add_desc_read_write(FFVulkanDescriptorSetBinding *out_desc,
895  enum FFVkShaderRepFormat *out_rep,
896  const SwsOp *op)
897 {
898  const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f" :
899  op->type == SWS_PIXEL_U32 ? "rgba32ui" :
900  op->type == SWS_PIXEL_U16 ? "rgba16ui" :
901  "rgba8ui";
902 
903  *out_desc = (FFVulkanDescriptorSetBinding) {
904  .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img",
905  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
906  .mem_layout = img_type,
907  .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly",
908  .dimensions = 2,
909  .elems = 4,
910  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
911  };
912 
913  *out_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT;
914 }
915 
916 #define QSTR "(%i/%i%s)"
917 #define QTYPE(Q) (Q).num, (Q).den, cur_type == SWS_PIXEL_F32 ? ".0f" : ""
918 
919 static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s,
920  SwsOpList *ops, FFVulkanShader *shd)
921 {
922  int err;
923  uint8_t *spv_data;
924  size_t spv_len;
925  void *spv_opaque = NULL;
926 
927  /* Interlaced formats are not currently supported */
928  if (ops->src.interlaced || ops->dst.interlaced)
929  return AVERROR(ENOTSUP);
930 
931  err = ff_vk_shader_init(&s->vkctx, shd, "sws_pass",
932  VK_SHADER_STAGE_COMPUTE_BIT,
933  NULL, 0, 32, 32, 1, 0);
934  if (err < 0)
935  return err;
936 
937  int nb_desc = 0;
938  FFVulkanDescriptorSetBinding buf_desc[8];
939 
940  const SwsOp *read = ff_sws_op_list_input(ops);
941  const SwsOp *write = ff_sws_op_list_output(ops);
942  if (read)
943  add_desc_read_write(&buf_desc[nb_desc++], &p->src_rep, read);
944  add_desc_read_write(&buf_desc[nb_desc++], &p->dst_rep, write);
945  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc, nb_desc, 0, 0);
946 
947  err = create_dither_bufs(s, p, ops);
948  if (err < 0)
949  return err;
950 
951  nb_desc = 0;
952  char dither_buf_name[MAX_DITHER_BUFS][64];
953  char dither_mat_name[MAX_DITHER_BUFS][64];
954  for (int n = 0; n < ops->num_ops; n++) {
955  const SwsOp *op = &ops->ops[n];
956  if (op->op != SWS_OP_DITHER)
957  continue;
958  int size = (1 << op->dither.size_log2);
959  av_assert0(size < 8192);
960  snprintf(dither_buf_name[nb_desc], 64, "dither_buf%i", n);
961  snprintf(dither_mat_name[nb_desc], 64, "float dither_mat%i[%i][%i];",
962  n, size, size);
963  buf_desc[nb_desc] = (FFVulkanDescriptorSetBinding) {
964  .name = dither_buf_name[nb_desc],
965  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
966  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
967  .mem_layout = "scalar",
968  .buf_content = dither_mat_name[nb_desc],
969  };
970  nb_desc++;
971  }
972  if (nb_desc)
973  ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc,
974  nb_desc, 1, 0);
975 
976  GLSLC(0, void main() );
977  GLSLC(0, { );
978  GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
979  GLSLC(1, ivec2 size = imageSize(src_img[0]); );
980  GLSLC(1, if (any(greaterThanEqual(pos, size))) );
981  GLSLC(2, return; );
982  GLSLC(0, );
983  GLSLC(1, u8vec4 u8; );
984  GLSLC(1, u16vec4 u16; );
985  GLSLC(1, u32vec4 u32; );
986  GLSLC(1, precise f32vec4 f32; );
987  GLSLC(1, precise f32vec4 tmp; );
988  GLSLC(0, );
989 
990  for (int n = 0; n < ops->num_ops; n++) {
991  const SwsOp *op = &ops->ops[n];
992  SwsPixelType cur_type = op->op == SWS_OP_CONVERT ? op->convert.to :
993  op->type;
994  const char *type_name = ff_sws_pixel_type_name(cur_type);
995  const char *type_v = cur_type == SWS_PIXEL_F32 ? "f32vec4" :
996  cur_type == SWS_PIXEL_U32 ? "u32vec4" :
997  cur_type == SWS_PIXEL_U16 ? "u16vec4" : "u8vec4";
998  const char *type_s = cur_type == SWS_PIXEL_F32 ? "float" :
999  cur_type == SWS_PIXEL_U32 ? "uint32_t" :
1000  cur_type == SWS_PIXEL_U16 ? "uint16_t" : "uint8_t";
1001  av_bprintf(&shd->src, " // %s\n", ff_sws_op_type_name(op->op));
1002 
1003  switch (op->op) {
1004  case SWS_OP_READ: {
1005  if (op->rw.frac || op->rw.filter) {
1006  return AVERROR(ENOTSUP);
1007  } else if (op->rw.packed) {
1008  GLSLF(1, %s = %s(imageLoad(src_img[%i], pos)); ,
1009  type_name, type_v, ops->plane_src[0]);
1010  } else {
1011  for (int i = 0; i < op->rw.elems; i++)
1012  GLSLF(1, %s.%c = %s(imageLoad(src_img[%i], pos)[0]); ,
1013  type_name, "xyzw"[i], type_s, ops->plane_src[i]);
1014  }
1015  break;
1016  }
1017  case SWS_OP_WRITE: {
1018  if (op->rw.frac || op->rw.filter) {
1019  return AVERROR(ENOTSUP);
1020  } else if (op->rw.packed) {
1021  GLSLF(1, imageStore(dst_img[%i], pos, %s(%s)); ,
1022  ops->plane_dst[0], type_v, type_name);
1023  } else {
1024  for (int i = 0; i < op->rw.elems; i++)
1025  GLSLF(1, imageStore(dst_img[%i], pos, %s(%s[%i])); ,
1026  ops->plane_dst[i], type_v, type_name, i);
1027  }
1028  break;
1029  }
1030  case SWS_OP_SWIZZLE: {
1031  av_bprintf(&shd->src, " %s = %s.", type_name, type_name);
1032  for (int i = 0; i < 4; i++)
1033  av_bprintf(&shd->src, "%c", "xyzw"[op->swizzle.in[i]]);
1034  av_bprintf(&shd->src, ";\n");
1035  break;
1036  }
1037  case SWS_OP_CLEAR: {
1038  for (int i = 0; i < 4; i++) {
1039  if (!op->clear.value[i].den)
1040  continue;
1041  av_bprintf(&shd->src, " %s.%c = %s"QSTR";\n", type_name,
1042  "xyzw"[i], type_s, QTYPE(op->clear.value[i]));
1043  }
1044  break;
1045  }
1046  case SWS_OP_SCALE:
1047  av_bprintf(&shd->src, " %s = %s * "QSTR";\n",
1048  type_name, type_name, QTYPE(op->scale.factor));
1049  break;
1050  case SWS_OP_MIN:
1051  case SWS_OP_MAX:
1052  for (int i = 0; i < 4; i++) {
1053  if (!op->clamp.limit[i].den)
1054  continue;
1055  av_bprintf(&shd->src, " %s.%c = %s(%s.%c, "QSTR");\n",
1056  type_name, "xyzw"[i],
1057  op->op == SWS_OP_MIN ? "min" : "max",
1058  type_name, "xyzw"[i], QTYPE(op->clamp.limit[i]));
1059  }
1060  break;
1061  case SWS_OP_LSHIFT:
1062  case SWS_OP_RSHIFT:
1063  av_bprintf(&shd->src, " %s %s= %i;\n", type_name,
1064  op->op == SWS_OP_LSHIFT ? "<<" : ">>", op->shift.amount);
1065  break;
1066  case SWS_OP_CONVERT:
1067  if (ff_sws_pixel_type_is_int(cur_type) && op->convert.expand) {
1068  const AVRational sc = ff_sws_pixel_expand(op->type, op->convert.to);
1069  av_bprintf(&shd->src, " %s = %s((%s*%i)/%i);\n",
1070  type_name, type_v, ff_sws_pixel_type_name(op->type),
1071  sc.num, sc.den);
1072  } else {
1073  av_bprintf(&shd->src, " %s = %s(%s);\n",
1074  type_name, type_v, ff_sws_pixel_type_name(op->type));
1075  }
1076  break;
1077  case SWS_OP_DITHER: {
1078  int size = (1 << op->dither.size_log2);
1079  for (int i = 0; i < 4; i++) {
1080  if (op->dither.y_offset[i] < 0)
1081  continue;
1082  av_bprintf(&shd->src, " %s.%c += dither_mat%i[(pos.y + %i) & %i]"
1083  "[pos.x & %i];\n",
1084  type_name, "xyzw"[i], n,
1085  op->dither.y_offset[i], size - 1,
1086  size - 1);
1087  }
1088  break;
1089  }
1090  case SWS_OP_LINEAR:
1091  for (int i = 0; i < 4; i++) {
1092  if (op->lin.m[i][4].num)
1093  av_bprintf(&shd->src, " tmp.%c = "QSTR";\n", "xyzw"[i],
1094  QTYPE(op->lin.m[i][4]));
1095  else
1096  av_bprintf(&shd->src, " tmp.%c = 0;\n", "xyzw"[i]);
1097  for (int j = 0; j < 4; j++) {
1098  if (!op->lin.m[i][j].num)
1099  continue;
1100  av_bprintf(&shd->src, " tmp.%c += f32.%c*"QSTR";\n",
1101  "xyzw"[i], "xyzw"[j], QTYPE(op->lin.m[i][j]));
1102  }
1103  }
1104  av_bprintf(&shd->src, " f32 = tmp;\n");
1105  break;
1106  default:
1107  return AVERROR(ENOTSUP);
1108  }
1109  }
1110 
1111  GLSLC(0, } );
1112 
1113  err = s->spvc->compile_shader(&s->vkctx, s->spvc, shd,
1114  &spv_data, &spv_len, "main",
1115  &spv_opaque);
1116  if (err < 0)
1117  return err;
1118 
1119  err = ff_vk_shader_link(&s->vkctx, shd, spv_data, spv_len, "main");
1120 
1121  if (spv_opaque)
1122  s->spvc->free_shader(s->spvc, &spv_opaque);
1123 
1124  if (err < 0)
1125  return err;
1126 
1127  return 0;
1128 }
1129 #endif
1130 
1131 static int compile(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out, int glsl)
1132 {
1133  int err;
1134  SwsInternal *c = sws_internal(sws);
1135  FFVulkanOpsCtx *s = c->hw_priv;
1136  if (!s)
1137  return AVERROR(ENOTSUP);
1138 
1139  VulkanPriv *p = av_mallocz(sizeof(*p));
1140  if (!p)
1141  return AVERROR(ENOMEM);
1142  p->s = av_refstruct_ref(c->hw_priv);
1143 
1144  err = ff_vk_exec_pool_init(&s->vkctx, s->qf, &p->e, 1,
1145  0, 0, 0, NULL);
1146  if (err < 0)
1147  goto fail;
1148 
1149  if (ops->src.format == AV_PIX_FMT_BGR0 ||
1150  ops->src.format == AV_PIX_FMT_BGRA ||
1151  ops->dst.format == AV_PIX_FMT_BGR0 ||
1152  ops->dst.format == AV_PIX_FMT_BGRA) {
1153  VkFormatProperties2 prop = {
1154  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
1155  };
1156  FFVulkanFunctions *vk = &s->vkctx.vkfn;
1157  vk->GetPhysicalDeviceFormatProperties2(s->vkctx.hwctx->phys_dev,
1158  VK_FORMAT_B8G8R8A8_UNORM,
1159  &prop);
1160  if (!(prop.formatProperties.optimalTilingFeatures &
1161  VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT)) {
1162  err = AVERROR(ENOTSUP);
1163  goto fail;
1164  }
1165  }
1166 
1167  if (glsl) {
1168  err = AVERROR(ENOTSUP);
1169 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
1170  err = add_ops_glsl(p, s, ops, &p->shd);
1171 #endif
1172  } else {
1173  err = AVERROR(ENOTSUP);
1174 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
1175  err = add_ops_spirv(p, s, ops, &p->shd);
1176 #endif
1177  }
1178  if (err < 0)
1179  goto fail;
1180 
1181  err = ff_vk_shader_register_exec(&s->vkctx, &p->e, &p->shd);
1182  if (err < 0)
1183  goto fail;
1184 
1185  for (int i = 0; i < p->nb_dither_buf; i++)
1186  ff_vk_shader_update_desc_buffer(&s->vkctx, &p->e.contexts[0], &p->shd,
1187  1, i, 0, &p->dither_buf[i],
1188  0, VK_WHOLE_SIZE, VK_FORMAT_UNDEFINED);
1189 
1190  *out = (SwsCompiledOp) {
1191  .opaque = true,
1192  .func_opaque = process,
1193  .priv = p,
1194  .free = free_fn,
1195  };
1196 
1197  return 0;
1198 
1199 fail:
1200  free_fn(p);
1201  return err;
1202 }
1203 
1204 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
1205 static int compile_spirv(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out)
1206 {
1207  return compile(sws, ops, out, 0);
1208 }
1209 
1210 const SwsOpBackend backend_spirv = {
1211  .name = "spirv",
1212  .compile = compile_spirv,
1213  .hw_format = AV_PIX_FMT_VULKAN,
1214 };
1215 #endif
1216 
1217 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
1218 static int compile_glsl(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out)
1219 {
1220  return compile(sws, ops, out, 1);
1221 }
1222 
1223 const SwsOpBackend backend_glsl = {
1224  .name = "glsl",
1225  .compile = compile_glsl,
1226  .hw_format = AV_PIX_FMT_VULKAN,
1227 };
1228 #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:1030
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:71
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:2486
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:2810
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:2122
out
static FILE * out
Definition: movenc.c:55
compile
static int compile(SwsContext *sws, SwsOpList *ops, SwsCompiledOp *out, int glsl)
Definition: ops.c:1131
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:643
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:223
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:427
spi_OpFunctionEnd
static void spi_OpFunctionEnd(SPICtx *spi)
Definition: spvasm.h:531
AVFrame::width
int width
Definition: frame.h:499
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:2848
ff_vk_exec_get
FFVkExecContext * ff_vk_exec_get(FFVulkanContext *s, FFVkExecPool *pool)
Retrieve an execution pool.
Definition: vulkan.c:548
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:2836
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:2787
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:780
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:271
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:38
fail
#define fail()
Definition: checkasm.h:223
SwsOpList::num_ops
int num_ops
Definition: ops.h:265
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:2738
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:2050
SPICtx
Definition: spvasm.h:52
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:2603
ff_sws_pixel_type_is_int
bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: ops.c:91
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:106
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:553
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:652
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
SwsOp::dither
SwsDitherOp dither
Definition: ops.h:231
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:2376
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:220
size
int size
Definition: twinvq_data.h:10344
AV_NUM_DATA_POINTERS
#define AV_NUM_DATA_POINTERS
Definition: frame.h:428
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:268
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:2751
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:1054
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:560
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:264
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:218
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:1244
SwsInternal
Definition: swscale_internal.h:334
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:1967
spi_OpTypeVoid
static int spi_OpTypeVoid(SPICtx *spi)
Definition: spvasm.h:422
SwsOpList::dst
SwsFormat dst
Definition: ops.h:268
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:549
spi_OpReturn
static void spi_OpReturn(SPICtx *spi)
Definition: spvasm.h:526
AVFrame::height
int height
Definition: frame.h:499
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:2503
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:110
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:61
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:108
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:905
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:78
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:271
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:263
ff_sws_op_type_name
const char * ff_sws_op_type_name(SwsOpType op)
Definition: ops.c:108
SwsContext
Main external API structure.
Definition: swscale.h:206
snprintf
#define snprintf
Definition: snprintf.h:34
FFVulkanFunctions
Definition: vulkan_functions.h:274
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:2093
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