Path: blob/master/thirdparty/libwebp/src/dsp/lossless.c
9913 views
// Copyright 2012 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// Image transforms and color space conversion methods for lossless decoder.10//11// Authors: Vikas Arora ([email protected])12// Jyrki Alakuijala ([email protected])13// Urvang Joshi ([email protected])1415#include "src/dsp/dsp.h"1617#include <assert.h>18#include <math.h>19#include <stdlib.h>20#include "src/dec/vp8li_dec.h"21#include "src/utils/endian_inl_utils.h"22#include "src/dsp/lossless.h"23#include "src/dsp/lossless_common.h"2425//------------------------------------------------------------------------------26// Image transforms.2728static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {29return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1);30}3132static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {33return Average2(Average2(a0, a2), a1);34}3536static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,37uint32_t a2, uint32_t a3) {38return Average2(Average2(a0, a1), Average2(a2, a3));39}4041static WEBP_INLINE uint32_t Clip255(uint32_t a) {42if (a < 256) {43return a;44}45// return 0, when a is a negative integer.46// return 255, when a is positive.47return ~a >> 24;48}4950static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) {51return Clip255((uint32_t)(a + b - c));52}5354static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,55uint32_t c2) {56const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24);57const int r = AddSubtractComponentFull((c0 >> 16) & 0xff,58(c1 >> 16) & 0xff,59(c2 >> 16) & 0xff);60const int g = AddSubtractComponentFull((c0 >> 8) & 0xff,61(c1 >> 8) & 0xff,62(c2 >> 8) & 0xff);63const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff);64return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;65}6667static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) {68return Clip255((uint32_t)(a + (a - b) / 2));69}7071static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,72uint32_t c2) {73const uint32_t ave = Average2(c0, c1);74const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24);75const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff);76const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff);77const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff);78return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;79}8081// gcc <= 4.9 on ARM generates incorrect code in Select() when Sub3() is82// inlined.83#if defined(__arm__) && defined(__GNUC__) && LOCAL_GCC_VERSION <= 0x40984# define LOCAL_INLINE __attribute__ ((noinline))85#else86# define LOCAL_INLINE WEBP_INLINE87#endif8889static LOCAL_INLINE int Sub3(int a, int b, int c) {90const int pb = b - c;91const int pa = a - c;92return abs(pb) - abs(pa);93}9495#undef LOCAL_INLINE9697static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {98const int pa_minus_pb =99Sub3((a >> 24) , (b >> 24) , (c >> 24) ) +100Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) +101Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) +102Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff);103return (pa_minus_pb <= 0) ? a : b;104}105106//------------------------------------------------------------------------------107// Predictors108109static uint32_t VP8LPredictor0_C(const uint32_t* const left,110const uint32_t* const top) {111(void)top;112(void)left;113return ARGB_BLACK;114}115static uint32_t VP8LPredictor1_C(const uint32_t* const left,116const uint32_t* const top) {117(void)top;118return *left;119}120uint32_t VP8LPredictor2_C(const uint32_t* const left,121const uint32_t* const top) {122(void)left;123return top[0];124}125uint32_t VP8LPredictor3_C(const uint32_t* const left,126const uint32_t* const top) {127(void)left;128return top[1];129}130uint32_t VP8LPredictor4_C(const uint32_t* const left,131const uint32_t* const top) {132(void)left;133return top[-1];134}135uint32_t VP8LPredictor5_C(const uint32_t* const left,136const uint32_t* const top) {137const uint32_t pred = Average3(*left, top[0], top[1]);138return pred;139}140uint32_t VP8LPredictor6_C(const uint32_t* const left,141const uint32_t* const top) {142const uint32_t pred = Average2(*left, top[-1]);143return pred;144}145uint32_t VP8LPredictor7_C(const uint32_t* const left,146const uint32_t* const top) {147const uint32_t pred = Average2(*left, top[0]);148return pred;149}150uint32_t VP8LPredictor8_C(const uint32_t* const left,151const uint32_t* const top) {152const uint32_t pred = Average2(top[-1], top[0]);153(void)left;154return pred;155}156uint32_t VP8LPredictor9_C(const uint32_t* const left,157const uint32_t* const top) {158const uint32_t pred = Average2(top[0], top[1]);159(void)left;160return pred;161}162uint32_t VP8LPredictor10_C(const uint32_t* const left,163const uint32_t* const top) {164const uint32_t pred = Average4(*left, top[-1], top[0], top[1]);165return pred;166}167uint32_t VP8LPredictor11_C(const uint32_t* const left,168const uint32_t* const top) {169const uint32_t pred = Select(top[0], *left, top[-1]);170return pred;171}172uint32_t VP8LPredictor12_C(const uint32_t* const left,173const uint32_t* const top) {174const uint32_t pred = ClampedAddSubtractFull(*left, top[0], top[-1]);175return pred;176}177uint32_t VP8LPredictor13_C(const uint32_t* const left,178const uint32_t* const top) {179const uint32_t pred = ClampedAddSubtractHalf(*left, top[0], top[-1]);180return pred;181}182183static void PredictorAdd0_C(const uint32_t* in, const uint32_t* upper,184int num_pixels, uint32_t* WEBP_RESTRICT out) {185int x;186(void)upper;187for (x = 0; x < num_pixels; ++x) out[x] = VP8LAddPixels(in[x], ARGB_BLACK);188}189static void PredictorAdd1_C(const uint32_t* in, const uint32_t* upper,190int num_pixels, uint32_t* WEBP_RESTRICT out) {191int i;192uint32_t left = out[-1];193(void)upper;194for (i = 0; i < num_pixels; ++i) {195out[i] = left = VP8LAddPixels(in[i], left);196}197}198GENERATE_PREDICTOR_ADD(VP8LPredictor2_C, PredictorAdd2_C)199GENERATE_PREDICTOR_ADD(VP8LPredictor3_C, PredictorAdd3_C)200GENERATE_PREDICTOR_ADD(VP8LPredictor4_C, PredictorAdd4_C)201GENERATE_PREDICTOR_ADD(VP8LPredictor5_C, PredictorAdd5_C)202GENERATE_PREDICTOR_ADD(VP8LPredictor6_C, PredictorAdd6_C)203GENERATE_PREDICTOR_ADD(VP8LPredictor7_C, PredictorAdd7_C)204GENERATE_PREDICTOR_ADD(VP8LPredictor8_C, PredictorAdd8_C)205GENERATE_PREDICTOR_ADD(VP8LPredictor9_C, PredictorAdd9_C)206GENERATE_PREDICTOR_ADD(VP8LPredictor10_C, PredictorAdd10_C)207GENERATE_PREDICTOR_ADD(VP8LPredictor11_C, PredictorAdd11_C)208GENERATE_PREDICTOR_ADD(VP8LPredictor12_C, PredictorAdd12_C)209GENERATE_PREDICTOR_ADD(VP8LPredictor13_C, PredictorAdd13_C)210211//------------------------------------------------------------------------------212213// Inverse prediction.214static void PredictorInverseTransform_C(const VP8LTransform* const transform,215int y_start, int y_end,216const uint32_t* in, uint32_t* out) {217const int width = transform->xsize_;218if (y_start == 0) { // First Row follows the L (mode=1) mode.219PredictorAdd0_C(in, NULL, 1, out);220PredictorAdd1_C(in + 1, NULL, width - 1, out + 1);221in += width;222out += width;223++y_start;224}225226{227int y = y_start;228const int tile_width = 1 << transform->bits_;229const int mask = tile_width - 1;230const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);231const uint32_t* pred_mode_base =232transform->data_ + (y >> transform->bits_) * tiles_per_row;233234while (y < y_end) {235const uint32_t* pred_mode_src = pred_mode_base;236int x = 1;237// First pixel follows the T (mode=2) mode.238PredictorAdd2_C(in, out - width, 1, out);239// .. the rest:240while (x < width) {241const VP8LPredictorAddSubFunc pred_func =242VP8LPredictorsAdd[((*pred_mode_src++) >> 8) & 0xf];243int x_end = (x & ~mask) + tile_width;244if (x_end > width) x_end = width;245pred_func(in + x, out + x - width, x_end - x, out + x);246x = x_end;247}248in += width;249out += width;250++y;251if ((y & mask) == 0) { // Use the same mask, since tiles are squares.252pred_mode_base += tiles_per_row;253}254}255}256}257258// Add green to blue and red channels (i.e. perform the inverse transform of259// 'subtract green').260void VP8LAddGreenToBlueAndRed_C(const uint32_t* src, int num_pixels,261uint32_t* dst) {262int i;263for (i = 0; i < num_pixels; ++i) {264const uint32_t argb = src[i];265const uint32_t green = ((argb >> 8) & 0xff);266uint32_t red_blue = (argb & 0x00ff00ffu);267red_blue += (green << 16) | green;268red_blue &= 0x00ff00ffu;269dst[i] = (argb & 0xff00ff00u) | red_blue;270}271}272273static WEBP_INLINE int ColorTransformDelta(int8_t color_pred,274int8_t color) {275return ((int)color_pred * color) >> 5;276}277278static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,279VP8LMultipliers* const m) {280m->green_to_red_ = (color_code >> 0) & 0xff;281m->green_to_blue_ = (color_code >> 8) & 0xff;282m->red_to_blue_ = (color_code >> 16) & 0xff;283}284285void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,286const uint32_t* src, int num_pixels,287uint32_t* dst) {288int i;289for (i = 0; i < num_pixels; ++i) {290const uint32_t argb = src[i];291const int8_t green = (int8_t)(argb >> 8);292const uint32_t red = argb >> 16;293int new_red = red & 0xff;294int new_blue = argb & 0xff;295new_red += ColorTransformDelta((int8_t)m->green_to_red_, green);296new_red &= 0xff;297new_blue += ColorTransformDelta((int8_t)m->green_to_blue_, green);298new_blue += ColorTransformDelta((int8_t)m->red_to_blue_, (int8_t)new_red);299new_blue &= 0xff;300dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);301}302}303304// Color space inverse transform.305static void ColorSpaceInverseTransform_C(const VP8LTransform* const transform,306int y_start, int y_end,307const uint32_t* src, uint32_t* dst) {308const int width = transform->xsize_;309const int tile_width = 1 << transform->bits_;310const int mask = tile_width - 1;311const int safe_width = width & ~mask;312const int remaining_width = width - safe_width;313const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);314int y = y_start;315const uint32_t* pred_row =316transform->data_ + (y >> transform->bits_) * tiles_per_row;317318while (y < y_end) {319const uint32_t* pred = pred_row;320VP8LMultipliers m = { 0, 0, 0 };321const uint32_t* const src_safe_end = src + safe_width;322const uint32_t* const src_end = src + width;323while (src < src_safe_end) {324ColorCodeToMultipliers(*pred++, &m);325VP8LTransformColorInverse(&m, src, tile_width, dst);326src += tile_width;327dst += tile_width;328}329if (src < src_end) { // Left-overs using C-version.330ColorCodeToMultipliers(*pred++, &m);331VP8LTransformColorInverse(&m, src, remaining_width, dst);332src += remaining_width;333dst += remaining_width;334}335++y;336if ((y & mask) == 0) pred_row += tiles_per_row;337}338}339340// Separate out pixels packed together using pixel-bundling.341// We define two methods for ARGB data (uint32_t) and alpha-only data (uint8_t).342#define COLOR_INDEX_INVERSE(FUNC_NAME, F_NAME, STATIC_DECL, TYPE, BIT_SUFFIX, \343GET_INDEX, GET_VALUE) \344static void F_NAME(const TYPE* src, const uint32_t* const color_map, \345TYPE* dst, int y_start, int y_end, int width) { \346int y; \347for (y = y_start; y < y_end; ++y) { \348int x; \349for (x = 0; x < width; ++x) { \350*dst++ = GET_VALUE(color_map[GET_INDEX(*src++)]); \351} \352} \353} \354STATIC_DECL void FUNC_NAME(const VP8LTransform* const transform, \355int y_start, int y_end, const TYPE* src, \356TYPE* dst) { \357int y; \358const int bits_per_pixel = 8 >> transform->bits_; \359const int width = transform->xsize_; \360const uint32_t* const color_map = transform->data_; \361if (bits_per_pixel < 8) { \362const int pixels_per_byte = 1 << transform->bits_; \363const int count_mask = pixels_per_byte - 1; \364const uint32_t bit_mask = (1 << bits_per_pixel) - 1; \365for (y = y_start; y < y_end; ++y) { \366uint32_t packed_pixels = 0; \367int x; \368for (x = 0; x < width; ++x) { \369/* We need to load fresh 'packed_pixels' once every */ \370/* 'pixels_per_byte' increments of x. Fortunately, pixels_per_byte */ \371/* is a power of 2, so can just use a mask for that, instead of */ \372/* decrementing a counter. */ \373if ((x & count_mask) == 0) packed_pixels = GET_INDEX(*src++); \374*dst++ = GET_VALUE(color_map[packed_pixels & bit_mask]); \375packed_pixels >>= bits_per_pixel; \376} \377} \378} else { \379VP8LMapColor##BIT_SUFFIX(src, color_map, dst, y_start, y_end, width); \380} \381}382383COLOR_INDEX_INVERSE(ColorIndexInverseTransform_C, MapARGB_C, static,384uint32_t, 32b, VP8GetARGBIndex, VP8GetARGBValue)385COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha_C, ,386uint8_t, 8b, VP8GetAlphaIndex, VP8GetAlphaValue)387388#undef COLOR_INDEX_INVERSE389390void VP8LInverseTransform(const VP8LTransform* const transform,391int row_start, int row_end,392const uint32_t* const in, uint32_t* const out) {393const int width = transform->xsize_;394assert(row_start < row_end);395assert(row_end <= transform->ysize_);396switch (transform->type_) {397case SUBTRACT_GREEN_TRANSFORM:398VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out);399break;400case PREDICTOR_TRANSFORM:401PredictorInverseTransform_C(transform, row_start, row_end, in, out);402if (row_end != transform->ysize_) {403// The last predicted row in this iteration will be the top-pred row404// for the first row in next iteration.405memcpy(out - width, out + (row_end - row_start - 1) * width,406width * sizeof(*out));407}408break;409case CROSS_COLOR_TRANSFORM:410ColorSpaceInverseTransform_C(transform, row_start, row_end, in, out);411break;412case COLOR_INDEXING_TRANSFORM:413if (in == out && transform->bits_ > 0) {414// Move packed pixels to the end of unpacked region, so that unpacking415// can occur seamlessly.416// Also, note that this is the only transform that applies on417// the effective width of VP8LSubSampleSize(xsize_, bits_). All other418// transforms work on effective width of xsize_.419const int out_stride = (row_end - row_start) * width;420const int in_stride = (row_end - row_start) *421VP8LSubSampleSize(transform->xsize_, transform->bits_);422uint32_t* const src = out + out_stride - in_stride;423memmove(src, out, in_stride * sizeof(*src));424ColorIndexInverseTransform_C(transform, row_start, row_end, src, out);425} else {426ColorIndexInverseTransform_C(transform, row_start, row_end, in, out);427}428break;429}430}431432//------------------------------------------------------------------------------433// Color space conversion.434435static int is_big_endian(void) {436static const union {437uint16_t w;438uint8_t b[2];439} tmp = { 1 };440return (tmp.b[0] != 1);441}442443void VP8LConvertBGRAToRGB_C(const uint32_t* WEBP_RESTRICT src,444int num_pixels, uint8_t* WEBP_RESTRICT dst) {445const uint32_t* const src_end = src + num_pixels;446while (src < src_end) {447const uint32_t argb = *src++;448*dst++ = (argb >> 16) & 0xff;449*dst++ = (argb >> 8) & 0xff;450*dst++ = (argb >> 0) & 0xff;451}452}453454void VP8LConvertBGRAToRGBA_C(const uint32_t* WEBP_RESTRICT src,455int num_pixels, uint8_t* WEBP_RESTRICT dst) {456const uint32_t* const src_end = src + num_pixels;457while (src < src_end) {458const uint32_t argb = *src++;459*dst++ = (argb >> 16) & 0xff;460*dst++ = (argb >> 8) & 0xff;461*dst++ = (argb >> 0) & 0xff;462*dst++ = (argb >> 24) & 0xff;463}464}465466void VP8LConvertBGRAToRGBA4444_C(const uint32_t* WEBP_RESTRICT src,467int num_pixels, uint8_t* WEBP_RESTRICT dst) {468const uint32_t* const src_end = src + num_pixels;469while (src < src_end) {470const uint32_t argb = *src++;471const uint8_t rg = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);472const uint8_t ba = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);473#if (WEBP_SWAP_16BIT_CSP == 1)474*dst++ = ba;475*dst++ = rg;476#else477*dst++ = rg;478*dst++ = ba;479#endif480}481}482483void VP8LConvertBGRAToRGB565_C(const uint32_t* WEBP_RESTRICT src,484int num_pixels, uint8_t* WEBP_RESTRICT dst) {485const uint32_t* const src_end = src + num_pixels;486while (src < src_end) {487const uint32_t argb = *src++;488const uint8_t rg = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);489const uint8_t gb = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);490#if (WEBP_SWAP_16BIT_CSP == 1)491*dst++ = gb;492*dst++ = rg;493#else494*dst++ = rg;495*dst++ = gb;496#endif497}498}499500void VP8LConvertBGRAToBGR_C(const uint32_t* WEBP_RESTRICT src,501int num_pixels, uint8_t* WEBP_RESTRICT dst) {502const uint32_t* const src_end = src + num_pixels;503while (src < src_end) {504const uint32_t argb = *src++;505*dst++ = (argb >> 0) & 0xff;506*dst++ = (argb >> 8) & 0xff;507*dst++ = (argb >> 16) & 0xff;508}509}510511static void CopyOrSwap(const uint32_t* WEBP_RESTRICT src, int num_pixels,512uint8_t* WEBP_RESTRICT dst, int swap_on_big_endian) {513if (is_big_endian() == swap_on_big_endian) {514const uint32_t* const src_end = src + num_pixels;515while (src < src_end) {516const uint32_t argb = *src++;517WebPUint32ToMem(dst, BSwap32(argb));518dst += sizeof(argb);519}520} else {521memcpy(dst, src, num_pixels * sizeof(*src));522}523}524525void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,526WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) {527switch (out_colorspace) {528case MODE_RGB:529VP8LConvertBGRAToRGB(in_data, num_pixels, rgba);530break;531case MODE_RGBA:532VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba);533break;534case MODE_rgbA:535VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba);536WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);537break;538case MODE_BGR:539VP8LConvertBGRAToBGR(in_data, num_pixels, rgba);540break;541case MODE_BGRA:542CopyOrSwap(in_data, num_pixels, rgba, 1);543break;544case MODE_bgrA:545CopyOrSwap(in_data, num_pixels, rgba, 1);546WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);547break;548case MODE_ARGB:549CopyOrSwap(in_data, num_pixels, rgba, 0);550break;551case MODE_Argb:552CopyOrSwap(in_data, num_pixels, rgba, 0);553WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0);554break;555case MODE_RGBA_4444:556VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba);557break;558case MODE_rgbA_4444:559VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba);560WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0);561break;562case MODE_RGB_565:563VP8LConvertBGRAToRGB565(in_data, num_pixels, rgba);564break;565default:566assert(0); // Code flow should not reach here.567}568}569570//------------------------------------------------------------------------------571572VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed;573VP8LPredictorAddSubFunc VP8LPredictorsAdd[16];574VP8LPredictorFunc VP8LPredictors[16];575576// exposed plain-C implementations577VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16];578579VP8LTransformColorInverseFunc VP8LTransformColorInverse;580581VP8LConvertFunc VP8LConvertBGRAToRGB;582VP8LConvertFunc VP8LConvertBGRAToRGBA;583VP8LConvertFunc VP8LConvertBGRAToRGBA4444;584VP8LConvertFunc VP8LConvertBGRAToRGB565;585VP8LConvertFunc VP8LConvertBGRAToBGR;586587VP8LMapARGBFunc VP8LMapColor32b;588VP8LMapAlphaFunc VP8LMapColor8b;589590extern VP8CPUInfo VP8GetCPUInfo;591extern void VP8LDspInitSSE2(void);592extern void VP8LDspInitSSE41(void);593extern void VP8LDspInitNEON(void);594extern void VP8LDspInitMIPSdspR2(void);595extern void VP8LDspInitMSA(void);596597#define COPY_PREDICTOR_ARRAY(IN, OUT) do { \598(OUT)[0] = IN##0_C; \599(OUT)[1] = IN##1_C; \600(OUT)[2] = IN##2_C; \601(OUT)[3] = IN##3_C; \602(OUT)[4] = IN##4_C; \603(OUT)[5] = IN##5_C; \604(OUT)[6] = IN##6_C; \605(OUT)[7] = IN##7_C; \606(OUT)[8] = IN##8_C; \607(OUT)[9] = IN##9_C; \608(OUT)[10] = IN##10_C; \609(OUT)[11] = IN##11_C; \610(OUT)[12] = IN##12_C; \611(OUT)[13] = IN##13_C; \612(OUT)[14] = IN##0_C; /* <- padding security sentinels*/ \613(OUT)[15] = IN##0_C; \614} while (0);615616WEBP_DSP_INIT_FUNC(VP8LDspInit) {617COPY_PREDICTOR_ARRAY(VP8LPredictor, VP8LPredictors)618COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd)619COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd_C)620621#if !WEBP_NEON_OMIT_C_CODE622VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;623624VP8LTransformColorInverse = VP8LTransformColorInverse_C;625626VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C;627VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;628VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;629#endif630631VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C;632VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C;633634VP8LMapColor32b = MapARGB_C;635VP8LMapColor8b = MapAlpha_C;636637// If defined, use CPUInfo() to overwrite some pointers with faster versions.638if (VP8GetCPUInfo != NULL) {639#if defined(WEBP_HAVE_SSE2)640if (VP8GetCPUInfo(kSSE2)) {641VP8LDspInitSSE2();642#if defined(WEBP_HAVE_SSE41)643if (VP8GetCPUInfo(kSSE4_1)) {644VP8LDspInitSSE41();645}646#endif647}648#endif649#if defined(WEBP_USE_MIPS_DSP_R2)650if (VP8GetCPUInfo(kMIPSdspR2)) {651VP8LDspInitMIPSdspR2();652}653#endif654#if defined(WEBP_USE_MSA)655if (VP8GetCPUInfo(kMSA)) {656VP8LDspInitMSA();657}658#endif659}660661#if defined(WEBP_HAVE_NEON)662if (WEBP_NEON_OMIT_C_CODE ||663(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {664VP8LDspInitNEON();665}666#endif667668assert(VP8LAddGreenToBlueAndRed != NULL);669assert(VP8LTransformColorInverse != NULL);670assert(VP8LConvertBGRAToRGBA != NULL);671assert(VP8LConvertBGRAToRGB != NULL);672assert(VP8LConvertBGRAToBGR != NULL);673assert(VP8LConvertBGRAToRGBA4444 != NULL);674assert(VP8LConvertBGRAToRGB565 != NULL);675assert(VP8LMapColor32b != NULL);676assert(VP8LMapColor8b != NULL);677}678#undef COPY_PREDICTOR_ARRAY679680//------------------------------------------------------------------------------681682683