diff --git a/src/dsp/dsp.h b/src/dsp/dsp.h index 411c52ec..4008ccd8 100644 --- a/src/dsp/dsp.h +++ b/src/dsp/dsp.h @@ -284,6 +284,22 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void); // Must be called before using WebPYUV444Converters[] WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void); +//------------------------------------------------------------------------------ +// Rescaler + +struct WebPRescaler; + +// Import a row of data and save its contribution in the rescaler. +// 'channel' denotes the channel number to be imported. +extern void (*WebPRescalerImportRow)(struct WebPRescaler* const wrk, + const uint8_t* const src, int channel); + +// Export one row (starting at x_out position) from rescaler. +extern void (*WebPRescalerExportRow)(struct WebPRescaler* const wrk, int x_out); + +// Must be called first before using the above. +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void); + //------------------------------------------------------------------------------ // Utilities for processing transparent channel. diff --git a/src/dsp/rescaler.c b/src/dsp/rescaler.c index 65d6d531..60e6480f 100644 --- a/src/dsp/rescaler.c +++ b/src/dsp/rescaler.c @@ -15,12 +15,8 @@ //------------------------------------------------------------------------------ // Implementations of critical functions ImportRow / ExportRow -void (*WebPRescalerImportRow)(WebPRescaler* const wrk, - const uint8_t* const src, int channel) = NULL; -void (*WebPRescalerExportRow)(WebPRescaler* const wrk, int x_out) = NULL; - -#define RFIX 30 -#define MULT_FIX(x, y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) +#define ROUNDER (1 << (WEBP_RESCALER_RFIX - 1)) +#define MULT_FIX(x, y) (((int64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) static void ImportRowC(WebPRescaler* const wrk, const uint8_t* const src, int channel) { @@ -83,54 +79,37 @@ static void ExportRowC(WebPRescaler* const wrk, int x_out) { } } +#undef MULT_FIX +#undef ROUNDER + //------------------------------------------------------------------------------ +void (*WebPRescalerImportRow)(struct WebPRescaler* const wrk, + const uint8_t* const src, int channel); +void (*WebPRescalerExportRow)(struct WebPRescaler* const wrk, int x_out); + extern void WebPRescalerDspInitMIPS32(void); extern void WebPRescalerDspInitMIPSdspR2(void); -void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, - uint8_t* const dst, int dst_width, int dst_height, - int dst_stride, int num_channels, int x_add, int x_sub, - int y_add, int y_sub, int32_t* const work) { - wrk->x_expand = (src_width < dst_width); - wrk->src_width = src_width; - wrk->src_height = src_height; - wrk->dst_width = dst_width; - wrk->dst_height = dst_height; - wrk->dst = dst; - wrk->dst_stride = dst_stride; - wrk->num_channels = num_channels; - // for 'x_expand', we use bilinear interpolation - wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; - wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; - wrk->y_accum = y_add; - wrk->y_add = y_add; - wrk->y_sub = y_sub; - wrk->fx_scale = (1 << RFIX) / x_sub; - wrk->fy_scale = (1 << RFIX) / y_sub; - wrk->fxy_scale = wrk->x_expand ? - ((int64_t)dst_height << RFIX) / (x_sub * src_height) : - ((int64_t)dst_height << RFIX) / (x_add * src_height); - wrk->irow = work; - wrk->frow = work + num_channels * dst_width; +static volatile VP8CPUInfo rescaler_last_cpuinfo_used = + (VP8CPUInfo)&rescaler_last_cpuinfo_used; - if (WebPRescalerImportRow == NULL) { - WebPRescalerImportRow = ImportRowC; - WebPRescalerExportRow = ExportRowC; - if (VP8GetCPUInfo != NULL) { +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) { + if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return; + + WebPRescalerImportRow = ImportRowC; + WebPRescalerExportRow = ExportRowC; + if (VP8GetCPUInfo != NULL) { #if defined(WEBP_USE_MIPS32) - if (VP8GetCPUInfo(kMIPS32)) { - WebPRescalerDspInitMIPS32(); - } + if (VP8GetCPUInfo(kMIPS32)) { + WebPRescalerDspInitMIPS32(); + } #endif #if defined(WEBP_USE_MIPS_DSP_R2) - if (VP8GetCPUInfo(kMIPSdspR2)) { - WebPRescalerDspInitMIPSdspR2(); - } -#endif + if (VP8GetCPUInfo(kMIPSdspR2)) { + WebPRescalerDspInitMIPSdspR2(); } +#endif } + rescaler_last_cpuinfo_used = VP8GetCPUInfo; } - -#undef MULT_FIX -#undef RFIX diff --git a/src/utils/rescaler.c b/src/utils/rescaler.c index 9d5750ef..cd45ae8d 100644 --- a/src/utils/rescaler.c +++ b/src/utils/rescaler.c @@ -13,8 +13,40 @@ #include #include +#include "../dsp/dsp.h" #include "./rescaler.h" +//------------------------------------------------------------------------------ + +void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, + uint8_t* const dst, int dst_width, int dst_height, + int dst_stride, int num_channels, int x_add, int x_sub, + int y_add, int y_sub, int32_t* const work) { + wrk->x_expand = (src_width < dst_width); + wrk->src_width = src_width; + wrk->src_height = src_height; + wrk->dst_width = dst_width; + wrk->dst_height = dst_height; + wrk->dst = dst; + wrk->dst_stride = dst_stride; + wrk->num_channels = num_channels; + // for 'x_expand', we use bilinear interpolation + wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; + wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; + wrk->y_accum = y_add; + wrk->y_add = y_add; + wrk->y_sub = y_sub; + wrk->fx_scale = (1 << WEBP_RESCALER_RFIX) / x_sub; + wrk->fy_scale = (1 << WEBP_RESCALER_RFIX) / y_sub; + wrk->fxy_scale = wrk->x_expand ? + ((int64_t)dst_height << WEBP_RESCALER_RFIX) / (x_sub * src_height) : + ((int64_t)dst_height << WEBP_RESCALER_RFIX) / (x_add * src_height); + wrk->irow = work; + wrk->frow = work + num_channels * dst_width; + + WebPRescalerDspInit(); +} + //------------------------------------------------------------------------------ // all-in-one calls diff --git a/src/utils/rescaler.h b/src/utils/rescaler.h index a6f37871..dd138b1d 100644 --- a/src/utils/rescaler.h +++ b/src/utils/rescaler.h @@ -20,8 +20,11 @@ extern "C" { #include "../webp/types.h" +#define WEBP_RESCALER_RFIX 30 // fixed-point precision for multiplies + // Structure used for on-the-fly rescaling -typedef struct { +typedef struct WebPRescaler WebPRescaler; +struct WebPRescaler { int x_expand; // true if we're expanding in the x direction int num_channels; // bytes to jump between pixels int fy_scale, fx_scale; // fixed-point scaling factor @@ -35,7 +38,7 @@ typedef struct { uint8_t* dst; int dst_stride; int32_t* irow, *frow; // work buffer -} WebPRescaler; +}; // Initialize a rescaler given scratch area 'work' and dimensions of src & dst. void WebPRescalerInit(WebPRescaler* const rescaler, @@ -57,13 +60,6 @@ int WebPRescaleNeededLines(const WebPRescaler* const rescaler, int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows, const uint8_t* src, int src_stride); -// Import a row of data and save its contribution in the rescaler. -// 'channel' denotes the channel number to be imported. -extern void (*WebPRescalerImportRow)(WebPRescaler* const wrk, - const uint8_t* const src, int channel); -// Export one row (starting at x_out position) from rescaler. -extern void (*WebPRescalerExportRow)(WebPRescaler* const wrk, int x_out); - // Return true if there is pending output rows ready. static WEBP_INLINE int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {