swscale/uops: add SWS_UOP_FLAG_PUNNING

The current CPU-based backends don't suffer any penalty or consequence
of intermixing integers and float operations on the same registers. However,
this is not a universal assumption - in particular, SPIR-V expects fully
typed operations.

In theory, older x86 CPUs also have a penalty for switching from float to
int, but ENOCARE.

Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
Niklas Haas authored and Niklas Haas committed 2026-10-27 18:53:16 +00:00
1 parent 215351c1c3
commit 1c03b758a3
8 files changed
+25 -13

No files matched your search

+3 -1
View File
@@ -225,7 +225,9 @@ static int aarch64_compile(SwsContext *ctx, const SwsOpList *ops,
if (!uops)
return AVERROR(ENOMEM);
const SwsUOpFlags flags = (ctx->flags & SWS_BITEXACT) ? 0 : SWS_UOP_FLAG_FMA;
SwsUOpFlags flags = SWS_UOP_FLAG_PUNNING;
if (!(ctx->flags & SWS_BITEXACT))
flags |= SWS_UOP_FLAG_FMA;
int ret = ff_sws_ops_translate(ctx, ops, flags, uops);
if (ret < 0)
goto error;
+2 -1
View File
@@ -41,7 +41,8 @@ static int print_ops(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
const SwsUOpFlags flags = SWS_UOP_FLAG_EXPAND_BIT
| SWS_UOP_FLAG_READ_PALETTE
| SWS_UOP_FLAG_ADD;
| SWS_UOP_FLAG_ADD
| SWS_UOP_FLAG_PUNNING;
int ret = ff_sws_ops_translate(ctx, ops, flags, uops);
if (ret == AVERROR(ENOTSUP))
goto fail;
+3 -1
View File
@@ -201,7 +201,9 @@ static int collect_ops_compile(SwsContext *ctx, const SwsOpList *ops,
if (!uops)
return AVERROR(ENOMEM);
const SwsUOpFlags flags = (ctx->flags & SWS_BITEXACT) ? 0 : SWS_UOP_FLAG_FMA;
SwsUOpFlags flags = SWS_UOP_FLAG_PUNNING;
if (!(ctx->flags & SWS_BITEXACT))
flags |= SWS_UOP_FLAG_FMA;
ret = ff_sws_ops_translate(ctx, ops, flags, uops);
if (ret == AVERROR(ENOTSUP)) {
ret = 0;
+11 -7
View File
@@ -206,8 +206,12 @@ int ff_sws_dither_height(const SwsDitherUOp *dither)
return (1 << dither->size_log2) + max_offset;
}
static SwsPixelType pixel_type_to_int(const SwsPixelType type)
/* Conditionally promotes a pixel type to integer only if allowed by the flags */
static SwsPixelType pixel_type_to_int(SwsUOpFlags flags, const SwsPixelType type)
{
if (!(flags & SWS_UOP_FLAG_PUNNING))
return type;
switch (ff_sws_pixel_type_size(type)) {
case 1: return SWS_PIXEL_U8;
case 2: return SWS_PIXEL_U16;
@@ -274,7 +278,7 @@ static int translate_rw_op(SwsContext *ctx, SwsUOpList *ops, SwsUOpFlags flags,
/* Non-filtered reads don't care about the exact pixel contents */
if (!op->rw.filter.op)
uop.type = pixel_type_to_int(op->rw.type);
uop.type = pixel_type_to_int(flags, op->rw.type);
const bool is_read = op->op == SWS_OP_READ;
if (op->rw.filter.op) {
@@ -327,11 +331,11 @@ static int count_idx(const int *arr, size_t size, int val)
return num;
}
static int translate_swizzle(SwsUOpList *ops, const SwsOp *op)
static int translate_swizzle(SwsUOpList *ops, SwsUOpFlags flags, const SwsOp *op)
{
SwsUOp uop = {
.uop = SWS_UOP_PERMUTE,
.type = pixel_type_to_int(ff_sws_op_input_type(op)),
.type = pixel_type_to_int(flags, ff_sws_op_input_type(op)),
.mask = ff_sws_comp_mask_needed(op),
};
SwsMoveUOp *par = &uop.par.move;
@@ -524,7 +528,7 @@ static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags,
case SWS_OP_WRITE:
return translate_rw_op(ctx, uops, flags, op);
case SWS_OP_SWIZZLE:
return translate_swizzle(uops, op);
return translate_swizzle(uops, flags, op);
case SWS_OP_DITHER:
return translate_dither_op(uops, flags, op);
case SWS_OP_LINEAR:
@@ -573,7 +577,7 @@ static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags,
const AVRational64 v = op->clear.value[i];
const SwsPixelType type = op->clear.type[i];
const SwsPixel px = ff_sws_pixel_from_q64(type, v);
uop.type = pixel_type_to_int(type);
uop.type = pixel_type_to_int(flags, type);
uop.data.vec4[i] = px;
if (v.num == 0)
uop.par.clear.zero |= SWS_COMP(i);
@@ -596,7 +600,7 @@ static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags,
break;
case SWS_OP_SWAP_BYTES:
uop.uop = SWS_UOP_SWAP_BYTES;
uop.type = pixel_type_to_int(uop.type);
uop.type = pixel_type_to_int(flags, uop.type);
break;
case SWS_OP_LUT_3D:
uop.uop = SWS_UOP_LUT_3D;
+1
View File
@@ -152,6 +152,7 @@ typedef enum SwsUOpFlagBits {
SWS_UOP_FLAG_EXPAND_BIT = (1 << 2), /* backend implements SWS_UOP_EXPAND_BIT */
SWS_UOP_FLAG_READ_PALETTE = (1 << 3), /* backend implements SWS_UOP_READ_PALETTE */
SWS_UOP_FLAG_ADD = (1 << 4), /* backend implements SWS_UOP_ADD */
SWS_UOP_FLAG_PUNNING = (1 << 5), /* allow type punning float data as int */
} SwsUOpFlagBits;
typedef enum SwsUOpType {
+2 -1
View File
@@ -187,7 +187,8 @@ static int compile_c(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
const SwsUOpFlags flags = SWS_UOP_FLAG_EXPAND_BIT
| SWS_UOP_FLAG_READ_PALETTE
| SWS_UOP_FLAG_ADD;
| SWS_UOP_FLAG_ADD
| SWS_UOP_FLAG_PUNNING;
int ret = ff_sws_ops_translate(ctx, ops, flags, uops);
if (ret < 0)
goto fail;
+1 -1
View File
@@ -217,7 +217,7 @@ fail:
enum {
COMMON_FLAGS = SWS_UOP_FLAG_EXPAND_BIT | SWS_UOP_FLAG_READ_PALETTE |
SWS_UOP_FLAG_ADD,
SWS_UOP_FLAG_ADD | SWS_UOP_FLAG_PUNNING,
};
typedef struct Backend {
+2 -1
View File
@@ -726,7 +726,8 @@ static int compile_x86(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out
SwsUOpFlags flags = SWS_UOP_FLAG_PSHUFB
| SWS_UOP_FLAG_EXPAND_BIT
| SWS_UOP_FLAG_READ_PALETTE
| SWS_UOP_FLAG_ADD;
| SWS_UOP_FLAG_ADD
| SWS_UOP_FLAG_PUNNING;
if (EXTERNAL_FMA3(cpu_flags))
flags |= SWS_UOP_FLAG_FMA;