Commit b8510a4f77 for ffmpeg
commit b8510a4f7794d3b76f6b05ecd6db9fe8ae5a3472
Author: Niklas Haas <git@haasn.dev>
Date: Wed Oct 21 18:30:47 2026 +0200
swscale/vulkan/ops: define dither buffers at the point of use
Move the dither implementation into emit_dither(), which also creates the
buffer, its SPIR-V declarations and its descriptor binding, instead of
doing so across several separate passes that had to be kept in sync.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Niklas Haas <git@haasn.dev>
diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c
index c8752bf903..93bd997ff5 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -266,14 +266,7 @@ static int create_bufs(FFVulkanOpsCtx *s, VulkanPriv *p, const SwsOpList *ops)
p->nb_data_bufs = 0;
for (int n = 0; n < ops->num_ops; n++) {
const SwsOp *op = &ops->ops[n];
- if (op->op == SWS_OP_DITHER) {
- av_assert0(p->nb_data_bufs + 1 <= FF_ARRAY_ELEMS(p->data_bufs));
- err = create_dither_buf(s, &op->dither,
- &p->data_bufs[p->nb_data_bufs]);
- if (err < 0)
- goto fail;
- p->nb_data_bufs++;
- } else if (op->op == SWS_OP_READ && op->rw.filter.op) {
+ if (op->op == SWS_OP_READ && op->rw.filter.op) {
av_assert0(p->nb_data_bufs + 1 <= FF_ARRAY_ELEMS(p->data_bufs));
err = create_filter_buf(s, op->rw.filter.kernel,
&p->data_bufs[p->nb_data_bufs]);
@@ -291,17 +284,6 @@ fail:
return err;
}
-struct DitherData {
- int size;
- int arr_1d_id;
- int arr_2d_id;
- int struct_id;
- int struct_ptr_id;
- int id;
- int mask_id;
- int binding;
-};
-
struct FilterData {
SwsOpType filter;
int filter_size;
@@ -322,7 +304,7 @@ struct FilterData {
/* Buffers used by a single op */
typedef struct OpIDs {
- int buf; /* index into dither[] or filt[] */
+ int buf; /* index into filt[] */
} OpIDs;
typedef struct SPIRVIDs {
@@ -362,9 +344,7 @@ typedef struct SPIRVIDs {
OpIDs op[MAX_OPS];
- struct DitherData dither[MAX_DITHER_BUFS];
int dither_ptr_elem_id;
- int nb_dither_bufs;
struct FilterData filt[MAX_FILT_BUFS];
int filt_o_ptr_id;
@@ -392,6 +372,9 @@ typedef struct SPIRVIDs {
int push_const_var_id;
int field_i32;
+ VulkanPriv *priv;
+ FFVulkanDescriptorSetBinding buf_desc[MAX_DATA_BUFS]; /* set 1 */
+
/* Per-invocation state of the main function */
int in_img[4], out_img[4]; /* image handles, indexed by plane */
int gid, gi2; /* invocation position, as uvec2 and ivec2 */
@@ -496,18 +479,6 @@ static void define_shader_header(SPICtx *spi, SPIRVIDs *id)
/* Next section starts here */
spi_OpMemoryModel(spi, SpvAddressingModelLogical, SpvMemoryModelGLSL450);
- for (int i = 0; i < id->nb_dither_bufs; i++) {
- spi_OpDecorate(spi, id->dither[i].arr_1d_id, SpvDecorationArrayStride,
- sizeof(float));
- spi_OpDecorate(spi, id->dither[i].arr_2d_id, SpvDecorationArrayStride,
- id->dither[i].size*sizeof(float));
- spi_OpDecorate(spi, id->dither[i].struct_id, SpvDecorationBlock);
- spi_OpMemberDecorate(spi, id->dither[i].struct_id, 0, SpvDecorationOffset, 0);
- spi_OpDecorate(spi, id->dither[i].id, SpvDecorationDescriptorSet, 1);
- spi_OpDecorate(spi, id->dither[i].id, SpvDecorationBinding,
- id->dither[i].binding);
- }
-
for (int i = 0; i < id->nb_filter_bufs; i++) {
struct FilterData *f = &id->filt[i];
spi_OpDecorate(spi, f->arr_w_in_id, SpvDecorationArrayStride,
@@ -562,19 +533,6 @@ static void define_shader_bindings(const SwsOpList *ops, SPICtx *spi, SPIRVIDs *
id->dither_ptr_elem_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
id->f32_type);
- struct DitherData *dither = id->dither;
- for (int i = 0; i < id->nb_dither_bufs; i++) {
- int size_id = spi_OpConstantUInt(spi, id->u32_type, dither[i].size);
- dither[i].mask_id = spi_OpConstantUInt(spi, id->u32_type, dither[i].size - 1);
- spi_OpTypeArray(spi, id->f32_type, dither[i].arr_1d_id, size_id);
- spi_OpTypeArray(spi, dither[i].arr_1d_id, dither[i].arr_2d_id, size_id);
- spi_OpTypeStruct(spi, dither[i].struct_id, dither[i].arr_2d_id);
- dither[i].struct_ptr_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
- dither[i].struct_id);
- dither[i].id = spi_OpVariable(spi, dither[i].id, dither[i].struct_ptr_id,
- SpvStorageClassUniform, 0);
- }
-
/* Filter buffers: struct { float w[dst_size][filter_size]; int o[dst_size]; } */
id->filt_o_ptr_id = 0;
if (id->nb_filter_bufs)
@@ -862,10 +820,76 @@ static int rw_op_img_count(const SwsOp *op, const uint8_t *planes)
return count;
}
+static int emit_dither(SPICtx *spi, SPIRVIDs *id, const SwsOp *op, int *data)
+{
+ if (ff_sws_op_input_type(op) != SWS_PIXEL_F32)
+ return AVERROR(ENOTSUP);
+
+ VulkanPriv *p = id->priv;
+ const int binding = p->nb_data_bufs;
+ if (binding >= MAX_DATA_BUFS)
+ return AVERROR(ENOTSUP);
+
+ int err = create_dither_buf(p->s, &op->dither, &p->data_bufs[binding]);
+ if (err < 0)
+ return err;
+ p->nb_data_bufs++;
+ id->buf_desc[binding] = (FFVulkanDescriptorSetBinding) {
+ .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ };
+
+ /* Uniform buffer in descriptor set 1: struct { float m[size][size]; } */
+ const int size = 1 << op->dither.size_log2;
+ const int size_id = spi_OpConstantUInt(spi, id->u32_type, size);
+ const int mask_id = spi_OpConstantUInt(spi, id->u32_type, size - 1);
+
+ int arr_1d = spi_OpTypeArray(spi, id->f32_type, spi_get_id(spi), size_id);
+ spi_OpDecorate(spi, arr_1d, SpvDecorationArrayStride, sizeof(float));
+ int arr_2d = spi_OpTypeArray(spi, arr_1d, spi_get_id(spi), size_id);
+ spi_OpDecorate(spi, arr_2d, SpvDecorationArrayStride, size*sizeof(float));
+
+ int struct_id = spi_get_id(spi);
+ spi_OpTypeStruct(spi, struct_id, arr_2d);
+ spi_OpDecorate(spi, struct_id, SpvDecorationBlock);
+ spi_OpMemberDecorate(spi, struct_id, 0, SpvDecorationOffset, 0);
+
+ int ptr = spi_OpTypePointer(spi, SpvStorageClassUniform, struct_id);
+ int buf = spi_OpVariable(spi, spi_get_id(spi), ptr, SpvStorageClassUniform, 0);
+ spi_OpDecorate(spi, buf, SpvDecorationDescriptorSet, 1);
+ spi_OpDecorate(spi, buf, SpvDecorationBinding, binding);
+ id->iface[id->nb_iface++] = buf;
+
+ int x_id = spi_OpCompositeExtract(spi, id->u32_type, id->gid, 0);
+ int y_pos = spi_OpCompositeExtract(spi, id->u32_type, id->gid, 1);
+ x_id = spi_OpBitwiseAnd(spi, id->u32_type, x_id, mask_id);
+ for (int i = 0; i < 4; i++) {
+ if (op->dither.y_offset[i] < 0)
+ continue;
+
+ int y_off = spi_OpConstantUInt(spi, id->u32_type,
+ op->dither.y_offset[i]);
+ int y_id = spi_OpIAdd(spi, id->u32_type, y_pos, y_off);
+ y_id = spi_OpBitwiseAnd(spi, id->u32_type, y_id, mask_id);
+
+ int val_ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id, buf,
+ id->u32_cid[0], y_id, x_id);
+ int val = spi_OpLoad(spi, id->f32_type, val_ptr,
+ SpvMemoryAccessMaskNone, 0);
+
+ int tmp = spi_OpCompositeExtract(spi, id->f32_type, *data, i);
+ tmp = spi_OpFAdd(spi, id->f32_type, tmp, val);
+ *data = spi_OpCompositeInsert(spi, id->f32vec4_type, tmp, *data, i);
+ }
+
+ return 0;
+}
+
static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
const SwsOpList *ops, FFVulkanShader *shd, SPICtx *spi)
{
SPIRVIDs spid_data = { 0 }, *id = &spid_data;
+ id->priv = p;
if (ops->num_ops > MAX_OPS)
return AVERROR(ENOTSUP);
@@ -908,34 +932,19 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
};
ff_vk_shader_add_descriptor_set(&s->vkctx, shd, img_desc, 2, 0);
- /* Create dither buffers */
+ /* Create filter buffers */
err = create_bufs(s, p, ops);
if (err < 0)
return err;
- /* Create dither and filter buffer descriptor set. Both are collected in
- * op order, so the bindings match the buffer order from create_bufs().*/
- id->nb_dither_bufs = 0;
+ /* Collect the filter buffer bindings, in the same order as create_bufs() */
id->nb_filter_bufs = 0;
- FFVulkanDescriptorSetBinding buf_desc[MAX_DATA_BUFS];
int nb_data_bufs = 0;
for (int n = 0; n < ops->num_ops; n++) {
const SwsOp *op = &ops->ops[n];
int var_id = 0;
- if (op->op == SWS_OP_DITHER) {
- if (id->nb_dither_bufs >= MAX_DITHER_BUFS)
- return AVERROR(ENOTSUP);
- id->op[n].buf = id->nb_dither_bufs;
- struct DitherData *d = &id->dither[id->nb_dither_bufs++];
- d->size = 1 << op->dither.size_log2;
- d->arr_1d_id = spi_get_id(spi);
- d->arr_2d_id = spi_get_id(spi);
- d->struct_id = spi_get_id(spi);
- d->id = spi_get_id(spi);
- d->binding = nb_data_bufs;
- var_id = d->id;
- } else if (op->op == SWS_OP_READ && op->rw.filter.op) {
+ if (op->op == SWS_OP_READ && op->rw.filter.op) {
if (id->nb_filter_bufs >= MAX_FILT_BUFS)
return AVERROR(ENOTSUP);
const SwsFilterWeights *wd = op->rw.filter.kernel;
@@ -957,14 +966,11 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
}
id->iface[id->nb_iface++] = var_id;
- buf_desc[nb_data_bufs++] = (FFVulkanDescriptorSetBinding) {
+ id->buf_desc[nb_data_bufs++] = (FFVulkanDescriptorSetBinding) {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
};
}
- if (nb_data_bufs)
- ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc,
- nb_data_bufs, 1);
/* Define shader header sections */
define_shader_header(spi, id);
@@ -1157,33 +1163,11 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
data = spi_OpCompositeInsert(spi, type_v, tmp, data, i);
}
break;
- case SWS_OP_DITHER: {
- if (type_in != SWS_PIXEL_F32)
- return AVERROR(ENOTSUP);
- const struct DitherData *d = &id->dither[oid->buf];
- int x_id = spi_OpCompositeExtract(spi, id->u32_type, id->gid, 0);
- int y_pos = spi_OpCompositeExtract(spi, id->u32_type, id->gid, 1);
- x_id = spi_OpBitwiseAnd(spi, id->u32_type, x_id, d->mask_id);
- for (int i = 0; i < 4; i++) {
- if (op->dither.y_offset[i] < 0)
- continue;
-
- int y_off = spi_OpConstantUInt(spi, id->u32_type,
- op->dither.y_offset[i]);
- int y_id = spi_OpIAdd(spi, id->u32_type, y_pos, y_off);
- y_id = spi_OpBitwiseAnd(spi, id->u32_type, y_id, d->mask_id);
-
- int ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id, d->id,
- id->u32_cid[0], y_id, x_id);
- int val = spi_OpLoad(spi, id->f32_type, ptr,
- SpvMemoryAccessMaskNone, 0);
-
- int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
- tmp = spi_OpFAdd(spi, type_s, tmp, val);
- data = spi_OpCompositeInsert(spi, type_v, tmp, data, i);
- }
+ case SWS_OP_DITHER:
+ err = emit_dither(spi, id, op, &data);
+ if (err < 0)
+ return err;
break;
- }
case SWS_OP_LINEAR: {
if (type_in != SWS_PIXEL_F32)
return AVERROR(ENOTSUP);
@@ -1223,6 +1207,10 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
spi_OpReturn(spi);
spi_OpFunctionEnd(spi);
+ if (p->nb_data_bufs)
+ ff_vk_shader_add_descriptor_set(&s->vkctx, shd, id->buf_desc,
+ p->nb_data_bufs, 1);
+
define_entry_point(shd, spi, id);
return 0;
}