Commit 1a9e407365 for ffmpeg
commit 1a9e407365fe0a0444f5a2a2c05f6b30aaef233a
Author: Niklas Haas <git@haasn.dev>
Date: Wed Oct 21 18:52:59 2026 +0200
swscale/vulkan/ops: define filter buffers at the point of use
Same as for dither buffers, by merging the buffer setup and filtered read
into emit_read_filtered(). This also replaces the per-tap index constants,
which relied on being allocated consecutive IDs.
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 cccfa45239..f805f32e7f 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -260,53 +260,6 @@ fail:
return err;
}
-static int create_bufs(FFVulkanOpsCtx *s, VulkanPriv *p, const SwsOpList *ops)
-{
- int err;
- 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_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]);
- if (err < 0)
- goto fail;
- p->nb_data_bufs++;
- }
- }
-
- return 0;
-
-fail:
- for (int i = 0; i < p->nb_data_bufs; i++)
- ff_vk_free_buf(&p->s->vkctx, &p->data_bufs[i]);
- return err;
-}
-
-struct FilterData {
- SwsOpType filter;
- int filter_size;
- int dst_size;
- int num_weights;
-
- int arr_w_in_id;
- int arr_w_out_id;
- int arr_o_id;
- int struct_id;
- int struct_ptr_id;
-
- int id; /* buffer ID */
- int binding; /* descriptor idx in desc set 1 */
-
- int tap_const_base;
-};
-
-/* Buffers used by a single op */
-typedef struct OpIDs {
- int buf; /* index into filt[] */
-} OpIDs;
-
typedef struct SPIRVIDs {
/* Entrypoint interface variables */
int iface[3 + MAX_DATA_BUFS + 1];
@@ -342,14 +295,8 @@ typedef struct SPIRVIDs {
int f32_0;
int u32_cid[5];
- OpIDs op[MAX_OPS];
-
int dither_ptr_elem_id;
- struct FilterData filt[MAX_FILT_BUFS];
- int filt_o_ptr_id;
- int nb_filter_bufs;
-
int out_img_type;
int out_img_array_id;
@@ -374,6 +321,7 @@ typedef struct SPIRVIDs {
VulkanPriv *priv;
FFVulkanDescriptorSetBinding buf_desc[MAX_DATA_BUFS]; /* set 1 */
+ const SwsOpList *ops;
/* Per-invocation state of the main function */
int in_img[4], out_img[4]; /* image handles, indexed by plane */
@@ -478,22 +426,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_filter_bufs; i++) {
- struct FilterData *f = &id->filt[i];
- spi_OpDecorate(spi, f->arr_w_in_id, SpvDecorationArrayStride,
- sizeof(float));
- spi_OpDecorate(spi, f->arr_w_out_id, SpvDecorationArrayStride,
- f->filter_size*sizeof(float));
- spi_OpDecorate(spi, f->arr_o_id, SpvDecorationArrayStride,
- sizeof(int32_t));
- spi_OpDecorate(spi, f->struct_id, SpvDecorationBlock);
- spi_OpMemberDecorate(spi, f->struct_id, 0, SpvDecorationOffset, 0);
- spi_OpMemberDecorate(spi, f->struct_id, 1, SpvDecorationOffset,
- f->num_weights*sizeof(float));
- spi_OpDecorate(spi, f->id, SpvDecorationDescriptorSet, 1);
- spi_OpDecorate(spi, f->id, SpvDecorationBinding, f->binding);
- }
}
/* Section 2: Define all types and constants */
@@ -533,32 +465,6 @@ static void define_shader_bindings(const SwsOpList *ops, SPICtx *spi, SPIRVIDs *
id->dither_ptr_elem_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
id->f32_type);
- /* Filter buffers: struct { float w[dst_size][filter_size]; int o[dst_size]; } */
- id->filt_o_ptr_id = 0;
- if (id->nb_filter_bufs)
- id->filt_o_ptr_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
- id->i32_type);
-
- for (int i = 0; i < id->nb_filter_bufs; i++) {
- struct FilterData *f = &id->filt[i];
- int fs_id = spi_OpConstantUInt(spi, id->u32_type, f->filter_size);
- int ds_id = spi_OpConstantUInt(spi, id->u32_type, f->dst_size);
-
- spi_OpTypeArray(spi, id->f32_type, f->arr_w_in_id, fs_id);
- spi_OpTypeArray(spi, f->arr_w_in_id, f->arr_w_out_id, ds_id);
- spi_OpTypeArray(spi, id->i32_type, f->arr_o_id, ds_id);
- spi_OpTypeStruct(spi, f->struct_id, f->arr_w_out_id, f->arr_o_id);
- f->struct_ptr_id = spi_OpTypePointer(spi, SpvStorageClassUniform,
- f->struct_id);
- f->id = spi_OpVariable(spi, f->id, f->struct_ptr_id,
- SpvStorageClassUniform, 0);
-
- /* Signed tap-index constants 0..filter_size-1 (consecutive <id>s) */
- f->tap_const_base = spi_OpConstantInt(spi, id->i32_type, 0);
- for (int t = 1; t < f->filter_size; t++)
- spi_OpConstantInt(spi, id->i32_type, t);
- }
-
const SwsOp *op_w = ff_sws_op_list_output(ops);
const SwsOp *op_r = ff_sws_op_list_input(ops);
@@ -721,10 +627,49 @@ static int add_buf_binding(SPIRVIDs *id)
return p->nb_data_bufs++;
}
-static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
- const SwsOp *op, const struct FilterData *f)
+static int emit_read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOp *op,
+ int *data)
{
- const int is_h = f->filter == SWS_OP_FILTER_H;
+ const SwsOpList *ops = id->ops;
+ const SwsFilterWeights *wd = op->rw.filter.kernel;
+ VulkanPriv *p = id->priv;
+ if (p->nb_data_bufs >= MAX_DATA_BUFS)
+ return AVERROR(ENOTSUP);
+
+ int err = create_filter_buf(p->s, wd, &p->data_bufs[p->nb_data_bufs]);
+ if (err < 0)
+ return err;
+ const int binding = add_buf_binding(id);
+
+ /* Uniform buffer in descriptor set 1:
+ * struct { float w[dst_size][filter_size]; int o[dst_size]; } */
+ const int fs_id = spi_OpConstantUInt(spi, id->u32_type, wd->filter_size);
+ const int ds_id = spi_OpConstantUInt(spi, id->u32_type, wd->dst_size);
+
+ int arr_w_in = spi_OpTypeArray(spi, id->f32_type, spi_get_id(spi), fs_id);
+ spi_OpDecorate(spi, arr_w_in, SpvDecorationArrayStride, sizeof(float));
+ int arr_w_out = spi_OpTypeArray(spi, arr_w_in, spi_get_id(spi), ds_id);
+ spi_OpDecorate(spi, arr_w_out, SpvDecorationArrayStride,
+ wd->filter_size*sizeof(float));
+ int arr_o = spi_OpTypeArray(spi, id->i32_type, spi_get_id(spi), ds_id);
+ spi_OpDecorate(spi, arr_o, SpvDecorationArrayStride, sizeof(int32_t));
+
+ int struct_id = spi_get_id(spi);
+ spi_OpTypeStruct(spi, struct_id, arr_w_out, arr_o);
+ spi_OpDecorate(spi, struct_id, SpvDecorationBlock);
+ spi_OpMemberDecorate(spi, struct_id, 0, SpvDecorationOffset, 0);
+ spi_OpMemberDecorate(spi, struct_id, 1, SpvDecorationOffset,
+ wd->num_weights*sizeof(float));
+
+ 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;
+
+ const int o_ptr_type = spi_OpTypePointer(spi, SpvStorageClassUniform,
+ id->i32_type);
+ const int is_h = op->rw.filter.op == SWS_OP_FILTER_H;
const int src_interlaced = ops->src.interlaced;
const int read_vtype = type_vec4(id, op->rw.type);
@@ -733,8 +678,7 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
int axis = spi_OpCompositeExtract(spi, id->u32_type, id->gid, is_h ? 0 : 1);
/* int o = filter_o[axis]; */
- int o_ptr = spi_OpAccessChain(spi, id->filt_o_ptr_id, f->id,
- id->u32_cid[1], axis);
+ int o_ptr = spi_OpAccessChain(spi, o_ptr_type, buf, id->u32_cid[1], axis);
int o = spi_OpLoad(spi, id->i32_type, o_ptr, SpvMemoryAccessMaskNone, 0);
/* Signed pixel position, for the non-filtered coordinate axis */
@@ -751,16 +695,17 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
/* Accumulators, initialized to zero */
int acc[4] = { id->f32_0, id->f32_0, id->f32_0, id->f32_0 };
- for (int t = 0; t < f->filter_size; t++) {
+ for (int t = 0; t < wd->filter_size; t++) {
+ const int tap = spi_OpConstantInt(spi, id->i32_type, t);
+
/* float w = filter_w[axis][t]; */
- int w_ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id, f->id,
- id->u32_cid[0], axis,
- f->tap_const_base + t);
+ int w_ptr = spi_OpAccessChain(spi, id->dither_ptr_elem_id, buf,
+ id->u32_cid[0], axis, tap);
int w = spi_OpLoad(spi, id->f32_type, w_ptr,
SpvMemoryAccessMaskNone, 0);
/* Source coordinate, filtered axis offset by the tap index */
- int c = t ? spi_OpIAdd(spi, id->i32_type, o, f->tap_const_base + t) : o;
+ int c = t ? spi_OpIAdd(spi, id->i32_type, o, tap) : o;
/* For interlaced vertical filtering, the per-tap source row is
* field-local; map it to the actual image row. */
if (src_interlaced && !is_h) {
@@ -782,8 +727,9 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
}
}
- return spi_OpCompositeConstruct(spi, id->f32vec4_type,
- acc[0], acc[1], acc[2], acc[3]);
+ *data = spi_OpCompositeConstruct(spi, id->f32vec4_type,
+ acc[0], acc[1], acc[2], acc[3]);
+ return 0;
}
/* Sub-packed formats are accessed as a single raw word per pixel, which is
@@ -896,6 +842,7 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
{
SPIRVIDs spid_data = { 0 }, *id = &spid_data;
id->priv = p;
+ id->ops = ops;
if (ops->num_ops > MAX_OPS)
return AVERROR(ENOTSUP);
@@ -938,46 +885,6 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
};
ff_vk_shader_add_descriptor_set(&s->vkctx, shd, img_desc, 2, 0);
- /* Create filter buffers */
- err = create_bufs(s, p, ops);
- if (err < 0)
- return err;
-
- /* Collect the filter buffer bindings, in the same order as create_bufs() */
- id->nb_filter_bufs = 0;
- 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_READ && op->rw.filter.op) {
- if (id->nb_filter_bufs >= MAX_FILT_BUFS)
- return AVERROR(ENOTSUP);
- const SwsFilterWeights *wd = op->rw.filter.kernel;
- id->op[n].buf = id->nb_filter_bufs;
- struct FilterData *f = &id->filt[id->nb_filter_bufs++];
- f->filter = op->rw.filter.op;
- f->filter_size = wd->filter_size;
- f->dst_size = wd->dst_size;
- f->num_weights = wd->num_weights;
- f->arr_w_in_id = spi_get_id(spi);
- f->arr_w_out_id = spi_get_id(spi);
- f->arr_o_id = spi_get_id(spi);
- f->struct_id = spi_get_id(spi);
- f->id = spi_get_id(spi);
- f->binding = nb_data_bufs;
- var_id = f->id;
- } else {
- continue;
- }
-
- id->iface[id->nb_iface++] = var_id;
- id->buf_desc[nb_data_bufs++] = (FFVulkanDescriptorSetBinding) {
- .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
- .stages = VK_SHADER_STAGE_COMPUTE_BIT,
- };
- }
-
/* Define shader header sections */
define_shader_header(spi, id);
define_shader_consts(spi, id);
@@ -1072,7 +979,6 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
/* Operations */
for (int n = 0; n < ops->num_ops; n++) {
const SwsOp *op = &ops->ops[n];
- const OpIDs *oid = &id->op[n];
SwsPixelType type_in = ff_sws_op_input_type(op);
SwsPixelType type_out = ff_sws_op_output_type(op);
if (op->op == SWS_OP_WRITE)
@@ -1089,7 +995,9 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
if (op->rw.mode != SWS_RW_PLANAR ||
op->rw.filter.type != SWS_PIXEL_F32)
return AVERROR(ENOTSUP);
- data = read_filtered(spi, id, ops, op, &id->filt[oid->buf]);
+ err = emit_read_filtered(spi, id, op, &data);
+ if (err < 0)
+ return err;
} else if (op->rw.mode == SWS_RW_PACKED) {
data = spi_OpImageRead(spi, type_v, id->in_img[ops->plane_src[0]],
id->src_gid, SpvImageOperandsMaskNone);