From 41359681c3ea6975501381003dfe5ae32577beaf Mon Sep 17 00:00:00 2001 From: Themaister Date: Mon, 3 Sep 2012 00:48:00 +0200 Subject: [PATCH] Add special point scaler for optimal speed. --- gfx/scaler/filter.c | 3 +++ gfx/scaler/scaler.c | 44 ++++++++++++++++++++++++++++++++++++++--- gfx/scaler/scaler.h | 2 ++ gfx/scaler/scaler_int.c | 30 ++++++++++++++++++++++++++++ gfx/scaler/scaler_int.h | 6 ++++++ 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/gfx/scaler/filter.c b/gfx/scaler/filter.c index d6f58113e8..e235c6064f 100644 --- a/gfx/scaler/filter.c +++ b/gfx/scaler/filter.c @@ -15,6 +15,7 @@ #include "filter.h" +#include "scaler_int.h" #include #include #include @@ -57,6 +58,8 @@ static bool gen_filter_point(struct scaler_ctx *ctx) gen_filter_point_sub(&ctx->horiz, ctx->out_width, x_pos, x_step); gen_filter_point_sub(&ctx->vert, ctx->out_height, y_pos, y_step); + ctx->scaler_special = scaler_argb8888_point_special; + return true; } diff --git a/gfx/scaler/scaler.c b/gfx/scaler/scaler.c index 97e67ca9cb..52a93118ab 100644 --- a/gfx/scaler/scaler.c +++ b/gfx/scaler/scaler.c @@ -139,6 +139,8 @@ bool scaler_ctx_gen_filter(struct scaler_ctx *ctx) ctx->unscaled = false; } + ctx->scaler_special = NULL; + if (!allocate_frames(ctx)) return false; @@ -192,13 +194,50 @@ void scaler_ctx_scale(struct scaler_ctx *ctx, clock_gettime(CLOCK_MONOTONIC, &start_tv); #endif - if (ctx->unscaled) + if (ctx->unscaled) // Just perform straight pixel conversion. { ctx->direct_pixconv(output, input, ctx->out_width, ctx->out_height, ctx->out_stride, ctx->in_stride); } - else + else if (ctx->scaler_special) // Take some special, and (hopefully) more optimized path. + { + const void *inp = input; + int in_stride = ctx->in_stride; + + if (ctx->in_fmt != SCALER_FMT_ARGB8888) + { + ctx->in_pixconv(ctx->input.frame, input, + ctx->in_width, ctx->in_height, + ctx->input.stride, ctx->in_stride); + + inp = ctx->input.frame; + in_stride = ctx->input.stride; + } + + bool conv_out = ctx->out_fmt != SCALER_FMT_ARGB8888; + void *outp = output; + int out_stride = ctx->out_stride; + + if (conv_out) + { + outp = ctx->output.frame; + out_stride = ctx->output.stride; + } + + ctx->scaler_special(ctx, outp, inp, + ctx->out_width, ctx->out_height, + ctx->in_width, ctx->in_height, + out_stride, in_stride); + + if (conv_out) + { + ctx->out_pixconv(output, ctx->output.frame, + ctx->out_width, ctx->out_height, + ctx->out_stride, ctx->output.stride); + } + } + else // Take generic filter path. { if (ctx->in_fmt != SCALER_FMT_ARGB8888) { @@ -230,4 +269,3 @@ void scaler_ctx_scale(struct scaler_ctx *ctx, #endif } - diff --git a/gfx/scaler/scaler.h b/gfx/scaler/scaler.h index 1cf5872594..3a43b61f64 100644 --- a/gfx/scaler/scaler.h +++ b/gfx/scaler/scaler.h @@ -63,6 +63,8 @@ struct scaler_ctx const void*, int); void (*scaler_vert)(const struct scaler_ctx*, void*, int); + void (*scaler_special)(const struct scaler_ctx*, + void*, const void*, int, int, int, int, int, int); void (*in_pixconv)(void*, const void*, int, int, int, int); void (*out_pixconv)(void*, const void*, int, int, int, int); diff --git a/gfx/scaler/scaler_int.c b/gfx/scaler/scaler_int.c index b517f96b4c..2fc3a6ffc1 100644 --- a/gfx/scaler/scaler_int.c +++ b/gfx/scaler/scaler_int.c @@ -231,3 +231,33 @@ void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int } #endif +void scaler_argb8888_point_special(const struct scaler_ctx *ctx, + void *output_, const void *input_, + int out_width, int out_height, + int in_width, int in_height, + int out_stride, int in_stride) +{ + (void)ctx; + int x_pos = (1 << 15) * in_width / out_width - (1 << 15); + int x_step = (1 << 16) * in_width / out_width; + int y_pos = (1 << 15) * in_height / out_height - (1 << 15); + int y_step = (1 << 16) * in_height / out_height; + + if (x_pos < 0) + x_pos = 0; + if (y_pos < 0) + y_pos = 0; + + const uint32_t *input = (const uint32_t*)input_; + uint32_t *output = (uint32_t*)output_; + + for (int h = 0; h < out_height; h++, y_pos += y_step, output += out_stride >> 2) + { + int x = x_pos; + const uint32_t *inp = input + (y_pos >> 16) * (in_stride >> 2); + + for (int w = 0; w < out_width; w++, x += x_step) + output[w] = inp[x >> 16]; + } +} + diff --git a/gfx/scaler/scaler_int.h b/gfx/scaler/scaler_int.h index 99762f72d9..f785a3e29a 100644 --- a/gfx/scaler/scaler_int.h +++ b/gfx/scaler/scaler_int.h @@ -21,5 +21,11 @@ void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output, int stride); void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input, int stride); +void scaler_argb8888_point_special(const struct scaler_ctx *ctx, + void *output, const void *input, + int out_width, int out_height, + int in_width, int in_height, + int out_stride, int in_stride); + #endif