From: Niklas Haas <g...@haasn.dev> This adds an internal API for ops backends, which are responsible for compiling op lists into executable functions. --- libswscale/ops.c | 62 ++++++++++++++++++++++ libswscale/ops_internal.h | 108 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 libswscale/ops_internal.h
diff --git a/libswscale/ops.c b/libswscale/ops.c index 004686147d..8491bd9cad 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -25,9 +25,22 @@ #include "libavutil/refstruct.h" #include "ops.h" +#include "ops_internal.h" + +const SwsOpBackend * const ff_sws_op_backends[] = { + NULL +}; + +const int ff_sws_num_op_backends = FF_ARRAY_ELEMS(ff_sws_op_backends) - 1; #define Q(N) ((AVRational) { N, 1 }) +#define RET(x) \ + do { \ + if ((ret = (x)) < 0) \ + return ret; \ + } while (0) + const char *ff_sws_pixel_type_name(SwsPixelType type) { switch (type) { @@ -520,3 +533,52 @@ void ff_sws_op_list_print(void *log, int lev, const SwsOpList *ops) av_log(log, lev, " (X = unused, + = exact, 0 = zero)\n"); } + +int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, + const SwsOpList *ops, SwsCompiledOp *out) +{ + SwsOpList *copy, rest; + int ret = 0; + + copy = ff_sws_op_list_duplicate(ops); + if (!copy) + return AVERROR(ENOMEM); + + /* Ensure these are always set during compilation */ + ff_sws_op_list_update_comps(copy); + + /* Make an on-stack copy of `ops` to ensure we can still properly clean up + * the copy afterwards */ + rest = *copy; + + ret = backend->compile(ctx, &rest, out); + if (ret == AVERROR(ENOTSUP)) { + av_log(ctx, AV_LOG_DEBUG, "Backend '%s' does not support operations:\n", backend->name); + ff_sws_op_list_print(ctx, AV_LOG_DEBUG, &rest); + } else if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to compile operations: %s\n", av_err2str(ret)); + ff_sws_op_list_print(ctx, AV_LOG_ERROR, &rest); + } + + ff_sws_op_list_free(©); + return ret; +} + +int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out) +{ + for (int n = 0; ff_sws_op_backends[n]; n++) { + const SwsOpBackend *backend = ff_sws_op_backends[n]; + if (ff_sws_ops_compile_backend(ctx, backend, ops, out) < 0) + continue; + + av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': " + "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n", + backend->name, out->block_size, out->over_read, out->over_write, + out->cpu_flags); + return 0; + } + + av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n"); + ff_sws_op_list_print(ctx, AV_LOG_WARNING, ops); + return AVERROR(ENOTSUP); +} diff --git a/libswscale/ops_internal.h b/libswscale/ops_internal.h new file mode 100644 index 0000000000..9fd866430b --- /dev/null +++ b/libswscale/ops_internal.h @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_OPS_INTERNAL_H +#define SWSCALE_OPS_INTERNAL_H + +#include "libavutil/mem_internal.h" + +#include "ops.h" + +/** + * Global execution context for all compiled functions. + * + * Note: This struct is hard-coded in assembly, so do not change the layout + * without updating the corresponding assembly definitions. + */ +typedef struct SwsOpExec { + /* The data pointers point to the first pixel to process */ + DECLARE_ALIGNED_32(const uint8_t, *in[4]); + DECLARE_ALIGNED_32(uint8_t, *out[4]); + + /* Separation between lines in bytes */ + DECLARE_ALIGNED_32(ptrdiff_t, in_stride[4]); + DECLARE_ALIGNED_32(ptrdiff_t, out_stride[4]); + + /* Extra metadata, may or may not be useful */ + int32_t width, height; /* Overall image dimensions */ + int32_t slice_y, slice_h; /* Start and height of current slice */ + int32_t pixel_bits_in; /* Bits per input pixel */ + int32_t pixel_bits_out; /* Bits per output pixel */ +} SwsOpExec; + +static_assert(sizeof(SwsOpExec) == 16 * sizeof(void *) + 8 * sizeof(int32_t), + "SwsOpExec layout mismatch"); + +/** + * Process a given range of pixel blocks. + * + * Note: `bx_start` and `bx_end` are in units of `SwsCompiledOp.block_size`. + */ +typedef void (*SwsOpFunc)(const SwsOpExec *exec, const void *priv, + int bx_start, int y_start, int bx_end, int y_end); + +#define SWS_DECL_FUNC(NAME) \ + void NAME(const SwsOpExec *, const void *, int, int, int, int) + +typedef struct SwsCompiledOp { + SwsOpFunc func; + + int block_size; /* number of pixels processed per iteration */ + int over_read; /* implementation over-reads input by this many bytes */ + int over_write; /* implementation over-writes output by this many bytes */ + int cpu_flags; /* active set of CPU flags (informative) */ + + /* Arbitrary private data */ + void *priv; + void (*free)(void *priv); +} SwsCompiledOp; + +typedef struct SwsOpBackend { + const char *name; /* Descriptive name for this backend */ + + /** + * Compile an operation list to an implementation chain. May modify `ops` + * freely; the original list will be freed automatically by the caller. + * + * Returns 0 or a negative error code. + */ + int (*compile)(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out); +} SwsOpBackend; + +/* List of all backends, terminated by NULL */ +extern const SwsOpBackend *const ff_sws_op_backends[]; +extern const int ff_sws_num_op_backends; /* excludes terminating NULL */ + +/** + * Attempt to compile a list of operations using a specific backend. + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, + const SwsOpList *ops, SwsCompiledOp *out); + +/** + * Compile a list of operations using the best available backend. + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out); + +#endif -- 2.49.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".