swscale/ops_internal: add internal ops backend API

This adds an internal API for ops backends, which are responsible for
compiling op lists into executable functions.
This commit is contained in:
Niklas Haas
2025-05-18 16:50:13 +02:00
parent ea9ca3ff35
commit d3ca0e300d
2 changed files with 145 additions and 0 deletions
+64
View File
@@ -27,6 +27,16 @@
#include "ops.h"
#include "ops_internal.h"
const SwsOpBackend * const ff_sws_op_backends[] = {
NULL
};
#define RET(x) \
do { \
if ((ret = (x)) < 0) \
return ret; \
} while (0)
const char *ff_sws_pixel_type_name(SwsPixelType type)
{
switch (type) {
@@ -508,3 +518,57 @@ 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;
SwsCompiledOp compiled = {0};
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, &compiled);
if (ret < 0) {
int msg_lev = ret == AVERROR(ENOTSUP) ? AV_LOG_TRACE : AV_LOG_ERROR;
av_log(ctx, msg_lev, "Backend '%s' failed to compile operations: %s\n",
backend->name, av_err2str(ret));
if (rest.num_ops != ops->num_ops) {
av_log(ctx, msg_lev, "Uncompiled remainder:\n");
ff_sws_op_list_print(ctx, msg_lev, &rest);
}
} else {
*out = compiled;
}
ff_sws_op_list_free(&copy);
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);
}
+81
View File
@@ -21,6 +21,8 @@
#ifndef SWSCALE_OPS_INTERNAL_H
#define SWSCALE_OPS_INTERNAL_H
#include "libavutil/mem_internal.h"
#include "ops.h"
#define Q(N) ((AVRational) { N, 1 })
@@ -45,4 +47,83 @@ static inline void ff_sws_pack_op_decode(const SwsOp *op, uint64_t mask[4], int
}
}
/**
* 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[];
/**
* 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 /* SWSCALE_OPS_INTERNAL_H */