Commit a32afbae68 for ffmpeg
commit a32afbae68162d090fe9c9f23b31ac34985c1cc5
Author: Niklas Haas <git@haasn.dev>
Date: Wed Oct 21 02:30:03 2026 +0200
swscale/vulkan/ops: keep main function state in SPIRVIDs
Avoids having to pass the image handles and invocation position around
explicitly.
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 cbf9e18482..e3886666e9 100644
--- a/libswscale/vulkan/ops.c
+++ b/libswscale/vulkan/ops.c
@@ -406,6 +406,11 @@ typedef struct SPIRVIDs {
int push_const_elem_ptr_id;
int push_const_var_id;
int field_i32;
+
+ /* 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 */
+ int src_gid, dst_gid; /* image position to read from / write to */
} SPIRVIDs;
/* All integer pixel types are represented as 32-bit unsigned integers */
@@ -868,8 +873,7 @@ static int insert_bitexact_linear(const SwsOp *op, SPICtx *spi, SPIRVIDs *id,
}
static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
- const SwsOp *op, const struct FilterData *f,
- const int *in_img, int gid, int gi2)
+ const SwsOp *op, const struct FilterData *f)
{
const int is_h = f->filter == SWS_OP_FILTER_H;
const int src_interlaced = ops->src.interlaced;
@@ -877,7 +881,7 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
const int read_vtype = type_vec4(id, op->rw.type);
/* Buffer array index along the filtered axis: pos.x (H) or pos.y (V) */
- int axis = spi_OpCompositeExtract(spi, id->u32_type, gid, is_h ? 0 : 1);
+ 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,
@@ -885,8 +889,8 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
int o = spi_OpLoad(spi, id->i32_type, o_ptr, SpvMemoryAccessMaskNone, 0);
/* Signed pixel position, for the non-filtered coordinate axis */
- int pos_x = spi_OpCompositeExtract(spi, id->i32_type, gi2, 0);
- int pos_y = spi_OpCompositeExtract(spi, id->i32_type, gi2, 1);
+ int pos_x = spi_OpCompositeExtract(spi, id->i32_type, id->gi2, 0);
+ int pos_y = spi_OpCompositeExtract(spi, id->i32_type, id->gi2, 1);
/* For interlaced horizontal filtering, the y coordinate of every tap is
* the (constant) destination y mapped into the source image. */
@@ -920,7 +924,7 @@ static int read_filtered(SPICtx *spi, SPIRVIDs *id, const SwsOpList *ops,
for (int e = 0; e < op->rw.elems; e++) {
int px = spi_OpImageRead(spi, read_vtype,
- in_img[ops->plane_src[e]], coord,
+ id->in_img[ops->plane_src[e]], coord,
SpvImageOperandsMaskNone);
px = spi_OpCompositeExtract(spi, type_scalar(id, op->rw.type), px, 0);
px = emit_convert(spi, op->rw.type, SWS_PIXEL_F32, id->f32_type, px);
@@ -1103,37 +1107,35 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
spi_OpLabel(spi, spi_get_id(spi));
/* Load input image handles */
- int in_img[4] = { 0 };
for (int i = 0; i < in_img_count; i++) {
/* Deref array and then the pointer */
int img = spi_OpAccessChain(spi, id->in_img_sptr,
id->in_img_var, id->u32_cid[i]);
- in_img[i] = spi_OpLoad(spi, id->in_img_type, img,
+ id->in_img[i] = spi_OpLoad(spi, id->in_img_type, img,
SpvMemoryAccessMaskNone, 0);
}
/* Load output image handles */
- int out_img[4] = { 0 };
for (int i = 0; i < out_img_count; i++) {
int img = spi_OpAccessChain(spi, id->out_img_sptr,
id->out_img_var, id->u32_cid[i]);
- out_img[i] = spi_OpLoad(spi, id->out_img_type, img,
+ id->out_img[i] = spi_OpLoad(spi, id->out_img_type, img,
SpvMemoryAccessMaskNone, 0);
}
/* Load gl_GlobalInvocationID */
- int gid = spi_OpLoad(spi, id->u32vec3_type, id->gid_var,
+ id->gid = spi_OpLoad(spi, id->u32vec3_type, id->gid_var,
SpvMemoryAccessMaskNone, 0);
/* ivec2(gl_GlobalInvocationID.xy) */
- gid = spi_OpVectorShuffle(spi, id->u32vec2_type, gid, gid, 0, 1);
- int gi2 = spi_OpBitcast(spi, id->i32vec2_type, gid);
+ id->gid = spi_OpVectorShuffle(spi, id->u32vec2_type, id->gid, id->gid, 0, 1);
+ id->gi2 = spi_OpBitcast(spi, id->i32vec2_type, id->gid);
/* For interlaced sources/destinations the shader operates on field-local
* coordinates, while images contain the full frame. Map the y axis to the
* actual image row: image_y = field_y * 2 + field. */
- int dst_gid = gid, dst_gi2 = gi2;
- int src_gid = gid;
+ int dst_gi2 = id->gi2;
+ id->dst_gid = id->src_gid = id->gid;
if (id->interlaced) {
int field_u32_ptr = spi_OpAccessChain(spi, id->push_const_elem_ptr_id,
id->push_const_var_id,
@@ -1143,25 +1145,25 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
id->field_i32 = spi_OpBitcast(spi, id->i32_type, field_u32);
int img_y_i32 = spi_OpShiftLeftLogical(spi, id->i32_type,
- spi_OpCompositeExtract(spi, id->i32_type, gi2, 1),
+ spi_OpCompositeExtract(spi, id->i32_type, id->gi2, 1),
id->u32_cid[1]);
img_y_i32 = spi_OpIAdd(spi, id->i32_type, img_y_i32, id->field_i32);
- int gi2_x = spi_OpCompositeExtract(spi, id->i32_type, gi2, 0);
+ int gi2_x = spi_OpCompositeExtract(spi, id->i32_type, id->gi2, 0);
int mapped_gi2 = spi_OpCompositeConstruct(spi, id->i32vec2_type,
gi2_x, img_y_i32);
int mapped_gid = spi_OpBitcast(spi, id->u32vec2_type, mapped_gi2);
if (ops->src.interlaced)
- src_gid = mapped_gid;
+ id->src_gid = mapped_gid;
if (ops->dst.interlaced) {
- dst_gid = mapped_gid;
+ id->dst_gid = mapped_gid;
dst_gi2 = mapped_gi2;
}
}
- /* imageSize(out_img[0]); */
- int img1_s = spi_OpImageQuerySize(spi, id->i32vec2_type, out_img[0]);
+ /* imageSize(id->out_img[0]); */
+ int img1_s = spi_OpImageQuerySize(spi, id->i32vec2_type, id->out_img[0]);
int scmp = spi_OpSGreaterThanEqual(spi, id->bvec2_type, dst_gi2, img1_s);
scmp = spi_OpAny(spi, id->b_type, scmp);
@@ -1205,17 +1207,15 @@ 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],
- in_img, gid, gi2);
+ data = read_filtered(spi, id, ops, op, &id->filt[oid->buf]);
} else if (op->rw.mode == SWS_RW_PACKED) {
- data = spi_OpImageRead(spi, type_v, in_img[ops->plane_src[0]],
- src_gid, SpvImageOperandsMaskNone);
+ data = spi_OpImageRead(spi, type_v, id->in_img[ops->plane_src[0]],
+ id->src_gid, SpvImageOperandsMaskNone);
} else if (op->rw.mode == SWS_RW_PLANAR) {
int tmp[4] = { uid, uid, uid, uid };
for (int i = 0; i < op->rw.elems; i++) {
tmp[i] = spi_OpImageRead(spi, type_v,
- in_img[ops->plane_src[i]], src_gid,
+ id->in_img[ops->plane_src[i]], id->src_gid,
SpvImageOperandsMaskNone);
tmp[i] = spi_OpCompositeExtract(spi, type_s, tmp[i], 0);
}
@@ -1229,13 +1229,13 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
if (op->rw.frac || op->rw.filter.op) {
return AVERROR(ENOTSUP);
} else if (op->rw.mode == SWS_RW_PACKED) {
- spi_OpImageWrite(spi, out_img[ops->plane_dst[0]], dst_gid, data,
+ spi_OpImageWrite(spi, id->out_img[ops->plane_dst[0]], id->dst_gid, data,
SpvImageOperandsMaskNone);
} else {
for (int i = 0; i < op->rw.elems; i++) {
int tmp = spi_OpCompositeExtract(spi, type_s, data, i);
tmp = spi_OpCompositeConstruct(spi, type_v, tmp, tmp, tmp, tmp);
- spi_OpImageWrite(spi, out_img[ops->plane_dst[i]], dst_gid, tmp,
+ spi_OpImageWrite(spi, id->out_img[ops->plane_dst[i]], id->dst_gid, tmp,
SpvImageOperandsMaskNone);
}
}
@@ -1283,8 +1283,8 @@ static int emit_shader(SwsContext *sws, VulkanPriv *p, FFVulkanOpsCtx *s,
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, gid, 0);
- int y_pos = spi_OpCompositeExtract(spi, id->u32_type, gid, 1);
+ 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)