swscale/ops_chain: split generic setup helpers into op-specific helpers

This has the side benefit of not relying on the q2pixel macro to avoid division
by zero, since we can now explicitly avoid operating on undefined clear values.

Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
Niklas Haas
2026-03-28 18:01:25 +01:00
committed by Niklas Haas
parent 50793bc9bd
commit 32ba5c13de
6 changed files with 53 additions and 27 deletions

View File

@@ -143,12 +143,14 @@ static int aarch64_setup(SwsOpList *ops, int block_size, int n,
}
break;
case SWS_OP_CLEAR:
ff_sws_setup_clear(&(const SwsImplParams) { .op = op }, out);
break;
case SWS_OP_MIN:
case SWS_OP_MAX:
ff_sws_setup_q4(&(const SwsImplParams) { .op = op }, out);
ff_sws_setup_clamp(&(const SwsImplParams) { .op = op }, out);
break;
case SWS_OP_SCALE:
ff_sws_setup_q(&(const SwsImplParams) { .op = op }, out);
ff_sws_setup_scale(&(const SwsImplParams) { .op = op }, out);
break;
case SWS_OP_LINEAR:
return aarch64_setup_linear(p, op, out);

View File

@@ -263,33 +263,56 @@ int ff_sws_op_compile_tables(SwsContext *ctx, const SwsOpTable *const tables[],
#define q2pixel(type, q) ((q).den ? (type) (q).num / (q).den : 0)
int ff_sws_setup_u8(const SwsImplParams *params, SwsImplResult *out)
int ff_sws_setup_shift(const SwsImplParams *params, SwsImplResult *out)
{
out->priv.u8[0] = params->op->c.u;
return 0;
}
int ff_sws_setup_q(const SwsImplParams *params, SwsImplResult *out)
int ff_sws_setup_scale(const SwsImplParams *params, SwsImplResult *out)
{
const SwsOp *op = params->op;
const AVRational factor = op->c.q;
switch (op->type) {
case SWS_PIXEL_U8: out->priv.u8[0] = q2pixel(uint8_t, op->c.q); return 0;
case SWS_PIXEL_U16: out->priv.u16[0] = q2pixel(uint16_t, op->c.q); return 0;
case SWS_PIXEL_U32: out->priv.u32[0] = q2pixel(uint32_t, op->c.q); return 0;
case SWS_PIXEL_F32: out->priv.f32[0] = q2pixel(float, op->c.q); return 0;
case SWS_PIXEL_U8: out->priv.u8[0] = q2pixel(uint8_t, factor); break;
case SWS_PIXEL_U16: out->priv.u16[0] = q2pixel(uint16_t, factor); break;
case SWS_PIXEL_U32: out->priv.u32[0] = q2pixel(uint32_t, factor); break;
case SWS_PIXEL_F32: out->priv.f32[0] = q2pixel(float, factor); break;
default: return AVERROR(EINVAL);
}
return 0;
}
int ff_sws_setup_q4(const SwsImplParams *params, SwsImplResult *out)
int ff_sws_setup_clamp(const SwsImplParams *params, SwsImplResult *out)
{
const SwsOp *op = params->op;
for (int i = 0; i < 4; i++) {
const AVRational limit = op->c.q4[i];
switch (op->type) {
case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, op->c.q4[i]); break;
case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, op->c.q4[i]); break;
case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, op->c.q4[i]); break;
case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, op->c.q4[i]); break;
case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, limit); break;
case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, limit); break;
case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, limit); break;
case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, limit); break;
default: return AVERROR(EINVAL);
}
}
return 0;
}
int ff_sws_setup_clear(const SwsImplParams *params, SwsImplResult *out)
{
const SwsOp *op = params->op;
for (int i = 0; i < 4; i++) {
const AVRational value = op->c.q4[i];
if (!value.den)
continue;
switch (op->type) {
case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, value); break;
case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, value); break;
case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, value); break;
case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, value); break;
default: return AVERROR(EINVAL);
}
}

View File

@@ -140,10 +140,11 @@ typedef struct SwsOpEntry {
bool (*check)(const SwsImplParams *params); /* optional, return true if supported */
} SwsOpEntry;
/* Setup helpers */
int ff_sws_setup_u8(const SwsImplParams *params, SwsImplResult *out);
int ff_sws_setup_q(const SwsImplParams *params, SwsImplResult *out);
int ff_sws_setup_q4(const SwsImplParams *params, SwsImplResult *out);
/* Setup helpers for common/trivial operation types */
int ff_sws_setup_shift(const SwsImplParams *params, SwsImplResult *out);
int ff_sws_setup_scale(const SwsImplParams *params, SwsImplResult *out);
int ff_sws_setup_clamp(const SwsImplParams *params, SwsImplResult *out);
int ff_sws_setup_clear(const SwsImplParams *params, SwsImplResult *out);
static inline void ff_op_priv_free(SwsOpPriv *priv)
{

View File

@@ -85,7 +85,7 @@ DECL_IMPL(clear##_##X##Y##Z##W)
} \
\
DECL_ENTRY(clear##_##X##Y##Z##W, \
.setup = ff_sws_setup_q4, \
.setup = ff_sws_setup_clear, \
.op = SWS_OP_CLEAR, \
.flexible = true, \
.unused = { !X, !Y, !Z, !W }, \
@@ -141,13 +141,13 @@ DECL_PATTERN(max)
WRAP_COMMON_PATTERNS(min,
.op = SWS_OP_MIN,
.setup = ff_sws_setup_q4,
.setup = ff_sws_setup_clamp,
.flexible = true,
);
WRAP_COMMON_PATTERNS(max,
.op = SWS_OP_MAX,
.setup = ff_sws_setup_q4,
.setup = ff_sws_setup_clamp,
.flexible = true,
);
@@ -172,7 +172,7 @@ DECL_PATTERN(scale)
WRAP_COMMON_PATTERNS(scale,
.op = SWS_OP_SCALE,
.setup = ff_sws_setup_q,
.setup = ff_sws_setup_scale,
.flexible = true,
);

View File

@@ -383,13 +383,13 @@ DECL_PATTERN(rshift)
WRAP_COMMON_PATTERNS(lshift,
.op = SWS_OP_LSHIFT,
.setup = ff_sws_setup_u8,
.setup = ff_sws_setup_shift,
.flexible = true,
);
WRAP_COMMON_PATTERNS(rshift,
.op = SWS_OP_RSHIFT,
.setup = ff_sws_setup_u8,
.setup = ff_sws_setup_shift,
.flexible = true,
);
#endif /* BIT_DEPTH != 8 */

View File

@@ -185,20 +185,20 @@ static int setup_shift(const SwsImplParams *params, SwsImplResult *out)
#define DECL_MIN_MAX(EXT) \
DECL_COMMON_PATTERNS(F32, min##EXT, \
.op = SWS_OP_MIN, \
.setup = ff_sws_setup_q4, \
.setup = ff_sws_setup_clamp, \
.flexible = true, \
); \
\
DECL_COMMON_PATTERNS(F32, max##EXT, \
.op = SWS_OP_MAX, \
.setup = ff_sws_setup_q4, \
.setup = ff_sws_setup_clamp, \
.flexible = true, \
);
#define DECL_SCALE(EXT) \
DECL_COMMON_PATTERNS(F32, scale##EXT, \
.op = SWS_OP_SCALE, \
.setup = ff_sws_setup_q, \
.setup = ff_sws_setup_scale, \
.flexible = true, \
);
@@ -941,7 +941,7 @@ static void normalize_clear(SwsOp *op)
int i;
} c;
ff_sws_setup_q4(&(const SwsImplParams) { .op = op }, &res);
ff_sws_setup_clear(&(const SwsImplParams) { .op = op }, &res);
for (int i = 0; i < 4; i++) {
if (!op->c.q4[i].den)