diff --git a/libswscale/format.c b/libswscale/format.c index a26349585a..ad85f46cfa 100644 --- a/libswscale/format.c +++ b/libswscale/format.c @@ -931,10 +931,15 @@ static SwsClearOp fmt_clear(enum AVPixelFormat fmt) const bool has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA; SwsClearOp c = {0}; - if (!has_chroma) + if (!has_chroma) { + c.mask |= SWS_COMP(1) | SWS_COMP(2); c.value[1] = c.value[2] = Q0; - if (!has_alpha) + } + + if (!has_alpha) { + c.mask |= SWS_COMP(3); c.value[3] = Q0; + } return c; } @@ -1060,6 +1065,7 @@ int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt) RET(ff_sws_op_list_append(ops, &(SwsOp) { .op = SWS_OP_CLEAR, .type = pixel_type, + .clear.mask = SWS_COMP(3), .clear.value[3] = Q0, })); } diff --git a/libswscale/ops.c b/libswscale/ops.c index e2b6da25a8..c91c39d29a 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -217,7 +217,7 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4]) return; case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { - if (op->clear.value[i].den) + if (SWS_COMP_TEST(op->clear.mask, i)) x[i] = op->clear.value[i]; } return; @@ -446,7 +446,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops) } case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { - if (op->clear.value[i].den) { + if (SWS_COMP_TEST(op->clear.mask, i)) { op->comps.flags[i] = 0; if (op->clear.value[i].num == 0) op->comps.flags[i] |= SWS_COMP_ZERO; @@ -565,7 +565,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops) break; case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den) + if (!SWS_COMP_TEST(op->clear.mask, i)) need_in[i] = need_out[i]; } break; diff --git a/libswscale/ops.h b/libswscale/ops.h index fb5b9fab4e..4d908edba2 100644 --- a/libswscale/ops.h +++ b/libswscale/ops.h @@ -167,7 +167,8 @@ typedef struct SwsShiftOp { } SwsShiftOp; typedef struct SwsClearOp { - AVRational value[4]; /* value to set, or {0, 0} for no-op */ + SwsCompMask mask; /* mask of components to clear */ + AVRational value[4]; /* value to set */ } SwsClearOp; typedef struct SwsConvertOp { diff --git a/libswscale/ops_chain.c b/libswscale/ops_chain.c index 1730fdfe61..7072f8c437 100644 --- a/libswscale/ops_chain.c +++ b/libswscale/ops_chain.c @@ -117,7 +117,7 @@ static int op_match(const SwsOp *op, const SwsOpEntry *entry) for (int i = 0; i < 4; i++) { if (!SWS_OP_NEEDED(op, i)) continue; - if (entry->unused[i] != !!op->clear.value[i].den) + if (entry->unused[i] != SWS_COMP_TEST(op->clear.mask, i)) return 0; } } @@ -149,7 +149,7 @@ static int op_match(const SwsOp *op, const SwsOpEntry *entry) return score; case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den || !SWS_OP_NEEDED(op, i)) + if (!SWS_COMP_TEST(op->clear.mask, i) || !SWS_OP_NEEDED(op, i)) continue; if (av_cmp_q(op->clear.value[i], Q(entry->clear_value))) return 0; diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c index 1fec8b21c9..5ad12b87b6 100644 --- a/libswscale/ops_memcpy.c +++ b/libswscale/ops_memcpy.c @@ -99,7 +99,7 @@ static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den) + if (!SWS_COMP_TEST(op->clear.mask, i)) continue; if (op->clear.value[i].den != 1) return AVERROR(ENOTSUP); diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c index ec6581e9f7..8e0ceafa0b 100644 --- a/libswscale/ops_optimizer.c +++ b/libswscale/ops_optimizer.c @@ -53,11 +53,14 @@ static bool op_commute_clear(SwsOp *op, SwsOp *next) case SWS_OP_MAX: case SWS_OP_SCALE: case SWS_OP_READ: - case SWS_OP_SWIZZLE: case SWS_OP_FILTER_H: case SWS_OP_FILTER_V: ff_sws_apply_op_q(next, op->clear.value); return true; + case SWS_OP_SWIZZLE: + op->clear.mask = ff_sws_comp_mask_swizzle(op->clear.mask, next->swizzle); + ff_sws_apply_op_q(next, op->clear.value); + return true; case SWS_OP_SWAP_BYTES: switch (next->type) { case SWS_PIXEL_U16: @@ -65,7 +68,7 @@ static bool op_commute_clear(SwsOp *op, SwsOp *next) return true; case SWS_PIXEL_U32: for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den) + if (!SWS_COMP_TEST(op->clear.mask, i)) continue; uint32_t v = av_bswap32(op->clear.value[i].num); if (v > INT_MAX) @@ -277,6 +280,7 @@ static bool extract_constant_rows(SwsLinearOp *c, SwsComps prev, (prev.flags[j] & SWS_COMP_ZERO); /* input is zero */ } if (const_row && (c->mask & SWS_MASK_ROW(i))) { + clear.mask |= SWS_COMP(i); clear.value[i] = c->m[i][4]; for (int j = 0; j < 5; j++) c->m[i][j] = Q(i == j); @@ -444,7 +448,7 @@ retry: case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den) + if (!SWS_COMP_TEST(op->clear.mask, i)) continue; if ((prev->comps.flags[i] & SWS_COMP_ZERO) && @@ -452,11 +456,11 @@ retry: op->clear.value[i].num == 0) { /* Redundant clear-to-zero of zero component */ - op->clear.value[i].den = 0; + op->clear.mask ^= SWS_COMP(i); } else if (!SWS_OP_NEEDED(op, i)) { /* Unnecessary clear of unused component */ - op->clear.value[i] = (AVRational) {0, 0}; - } else if (op->clear.value[i].den) { + op->clear.mask ^= SWS_COMP(i); + } else { noop = false; } } @@ -469,9 +473,10 @@ retry: /* Transitive clear */ if (next->op == SWS_OP_CLEAR) { for (int i = 0; i < 4; i++) { - if (next->clear.value[i].den) + if (SWS_COMP_TEST(next->clear.mask, i)) op->clear.value[i] = next->clear.value[i]; } + op->clear.mask |= next->clear.mask; ff_sws_op_list_remove_at(ops, n + 1, 1); goto retry; } @@ -816,7 +821,7 @@ int ff_sws_solve_shuffle(const SwsOpList *const ops, uint8_t shuffle[], case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den) + if (!SWS_COMP_TEST(op->clear.mask, i)) continue; if (op->clear.value[i].num != 0 || !clear_val) return AVERROR(ENOTSUP); diff --git a/libswscale/tests/sws_ops.c b/libswscale/tests/sws_ops.c index 05378be18d..1256c73ec6 100644 --- a/libswscale/tests/sws_ops.c +++ b/libswscale/tests/sws_ops.c @@ -74,7 +74,7 @@ static int register_op(SwsContext *ctx, void *opaque, SwsOp *op) break; case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) - op->clear.value[i] = (AVRational) { 0, !!op->clear.value[i].den }; + op->clear.value[i] = (AVRational) { 0, SWS_COMP_TEST(op->clear.mask, i) }; break; case SWS_OP_DITHER: /* Strip arbitrary offset */ diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c index 49a3d7827c..cf128b00c1 100644 --- a/libswscale/vulkan/ops.c +++ b/libswscale/vulkan/ops.c @@ -398,12 +398,14 @@ static void define_shader_consts(SwsOpList *ops, SPICtx *spi, SPIRVIDs *id) break; case SWS_OP_CLEAR: for (int i = 0; i < 4; i++) { + if (!SWS_COMP_TEST(op->clear.mask, i)) + continue; AVRational cv = op->clear.value[i]; - if (cv.den && op->type == SWS_PIXEL_F32) { + if (op->type == SWS_PIXEL_F32) { float q = (float)cv.num/cv.den; id->const_ids[id->nb_const_ids++] = spi_OpConstantFloat(spi, f32_type, q); - } else if (op->clear.value[i].den) { + } else { av_assert0(cv.den == 1); id->const_ids[id->nb_const_ids++] = spi_OpConstantUInt(spi, u32_type, cv.num); @@ -1036,7 +1038,7 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s, } case SWS_OP_CLEAR: { for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den) + if (!SWS_COMP_TEST(op->clear.mask, i)) continue; av_bprintf(&shd->src, " %s.%c = %s"QSTR";\n", type_name, "xyzw"[i], type_s, QTYPE(op->clear.value[i])); diff --git a/libswscale/x86/ops.c b/libswscale/x86/ops.c index a87fa56f53..5e95e80eac 100644 --- a/libswscale/x86/ops.c +++ b/libswscale/x86/ops.c @@ -953,7 +953,7 @@ static void normalize_clear(SwsOp *op) ff_sws_setup_clear(&(const SwsImplParams) { .op = op }, &res); for (int i = 0; i < 4; i++) { - if (!op->clear.value[i].den) + if (!SWS_COMP_TEST(op->clear.mask, i)) continue; switch (ff_sws_pixel_type_size(op->type)) { case 1: c.u32 = 0x1010101U * res.priv.u8[i]; break; diff --git a/tests/checkasm/sw_ops.c b/tests/checkasm/sw_ops.c index dd993ffcfc..82415574f4 100644 --- a/tests/checkasm/sw_ops.c +++ b/tests/checkasm/sw_ops.c @@ -540,32 +540,34 @@ static void check_clear(void) const AVRational zero = (AVRational) { 0, 1}; const AVRational none = {0}; - const SwsClearOp patterns[] = { + const AVRational patterns[][4] = { /* Zero only */ - {{ none, none, none, zero }}, - {{ zero, none, none, none }}, + { none, none, none, zero }, + { zero, none, none, none }, /* Alpha only */ - {{ none, none, none, alpha }}, - {{ alpha, none, none, none }}, + { none, none, none, alpha }, + { alpha, none, none, none }, /* Chroma only */ - {{ chroma, chroma, none, none }}, - {{ none, chroma, chroma, none }}, - {{ none, none, chroma, chroma }}, - {{ chroma, none, chroma, none }}, - {{ none, chroma, none, chroma }}, + { chroma, chroma, none, none }, + { none, chroma, chroma, none }, + { none, none, chroma, chroma }, + { chroma, none, chroma, none }, + { none, chroma, none, chroma }, /* Alpha+chroma */ - {{ chroma, chroma, none, alpha }}, - {{ none, chroma, chroma, alpha }}, - {{ alpha, none, chroma, chroma }}, - {{ chroma, none, chroma, alpha }}, - {{ alpha, chroma, none, chroma }}, + { chroma, chroma, none, alpha }, + { none, chroma, chroma, alpha }, + { alpha, none, chroma, chroma }, + { chroma, none, chroma, alpha }, + { alpha, chroma, none, chroma }, }; for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { + SwsClearOp clear = { .mask = ff_sws_comp_mask_q4(patterns[i]) }; + memcpy(clear.value, patterns[i], sizeof(clear.value)); CHECK(FMT("clear_pattern_%s[%d]", type, i), 4, 4, t, t, { .op = SWS_OP_CLEAR, .type = t, - .clear = patterns[i], + .clear = clear, }); } } else if (!ff_sws_pixel_type_is_int(t)) { @@ -574,6 +576,7 @@ static void check_clear(void) .op = SWS_OP_CLEAR, .type = t, .clear.value[3] = { 0, 1 }, + .clear.mask = SWS_COMP(3), }); } }