Home | History | Annotate | Download | only in dsp
      1 // Copyright 2014 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Rescaling functions
     11 //
     12 // Author: Skal (pascal.massimino (at) gmail.com)
     13 
     14 #include <assert.h>
     15 
     16 #include "./dsp.h"
     17 #include "../utils/rescaler_utils.h"
     18 
     19 //------------------------------------------------------------------------------
     20 // Implementations of critical functions ImportRow / ExportRow
     21 
     22 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
     23 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
     24 
     25 //------------------------------------------------------------------------------
     26 // Row import
     27 
     28 void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
     29   const int x_stride = wrk->num_channels;
     30   const int x_out_max = wrk->dst_width * wrk->num_channels;
     31   int channel;
     32   assert(!WebPRescalerInputDone(wrk));
     33   assert(wrk->x_expand);
     34   for (channel = 0; channel < x_stride; ++channel) {
     35     int x_in = channel;
     36     int x_out = channel;
     37     // simple bilinear interpolation
     38     int accum = wrk->x_add;
     39     int left = src[x_in];
     40     int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
     41     x_in += x_stride;
     42     while (1) {
     43       wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
     44       x_out += x_stride;
     45       if (x_out >= x_out_max) break;
     46       accum -= wrk->x_sub;
     47       if (accum < 0) {
     48         left = right;
     49         x_in += x_stride;
     50         assert(x_in < wrk->src_width * x_stride);
     51         right = src[x_in];
     52         accum += wrk->x_add;
     53       }
     54     }
     55     assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
     56   }
     57 }
     58 
     59 void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
     60   const int x_stride = wrk->num_channels;
     61   const int x_out_max = wrk->dst_width * wrk->num_channels;
     62   int channel;
     63   assert(!WebPRescalerInputDone(wrk));
     64   assert(!wrk->x_expand);
     65   for (channel = 0; channel < x_stride; ++channel) {
     66     int x_in = channel;
     67     int x_out = channel;
     68     uint32_t sum = 0;
     69     int accum = 0;
     70     while (x_out < x_out_max) {
     71       uint32_t base = 0;
     72       accum += wrk->x_add;
     73       while (accum > 0) {
     74         accum -= wrk->x_sub;
     75         assert(x_in < wrk->src_width * x_stride);
     76         base = src[x_in];
     77         sum += base;
     78         x_in += x_stride;
     79       }
     80       {        // Emit next horizontal pixel.
     81         const rescaler_t frac = base * (-accum);
     82         wrk->frow[x_out] = sum * wrk->x_sub - frac;
     83         // fresh fractional start for next pixel
     84         sum = (int)MULT_FIX(frac, wrk->fx_scale);
     85       }
     86       x_out += x_stride;
     87     }
     88     assert(accum == 0);
     89   }
     90 }
     91 
     92 //------------------------------------------------------------------------------
     93 // Row export
     94 
     95 void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) {
     96   int x_out;
     97   uint8_t* const dst = wrk->dst;
     98   rescaler_t* const irow = wrk->irow;
     99   const int x_out_max = wrk->dst_width * wrk->num_channels;
    100   const rescaler_t* const frow = wrk->frow;
    101   assert(!WebPRescalerOutputDone(wrk));
    102   assert(wrk->y_accum <= 0);
    103   assert(wrk->y_expand);
    104   assert(wrk->y_sub != 0);
    105   if (wrk->y_accum == 0) {
    106     for (x_out = 0; x_out < x_out_max; ++x_out) {
    107       const uint32_t J = frow[x_out];
    108       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    109       assert(v >= 0 && v <= 255);
    110       dst[x_out] = v;
    111     }
    112   } else {
    113     const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
    114     const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
    115     for (x_out = 0; x_out < x_out_max; ++x_out) {
    116       const uint64_t I = (uint64_t)A * frow[x_out]
    117                        + (uint64_t)B * irow[x_out];
    118       const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
    119       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    120       assert(v >= 0 && v <= 255);
    121       dst[x_out] = v;
    122     }
    123   }
    124 }
    125 
    126 void WebPRescalerExportRowShrinkC(WebPRescaler* const wrk) {
    127   int x_out;
    128   uint8_t* const dst = wrk->dst;
    129   rescaler_t* const irow = wrk->irow;
    130   const int x_out_max = wrk->dst_width * wrk->num_channels;
    131   const rescaler_t* const frow = wrk->frow;
    132   const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
    133   assert(!WebPRescalerOutputDone(wrk));
    134   assert(wrk->y_accum <= 0);
    135   assert(!wrk->y_expand);
    136   if (yscale) {
    137     for (x_out = 0; x_out < x_out_max; ++x_out) {
    138       const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
    139       const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
    140       assert(v >= 0 && v <= 255);
    141       dst[x_out] = v;
    142       irow[x_out] = frac;   // new fractional start
    143     }
    144   } else {
    145     for (x_out = 0; x_out < x_out_max; ++x_out) {
    146       const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
    147       assert(v >= 0 && v <= 255);
    148       dst[x_out] = v;
    149       irow[x_out] = 0;
    150     }
    151   }
    152 }
    153 
    154 #undef MULT_FIX
    155 #undef ROUNDER
    156 
    157 //------------------------------------------------------------------------------
    158 // Main entry calls
    159 
    160 void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
    161   assert(!WebPRescalerInputDone(wrk));
    162   if (!wrk->x_expand) {
    163     WebPRescalerImportRowShrink(wrk, src);
    164   } else {
    165     WebPRescalerImportRowExpand(wrk, src);
    166   }
    167 }
    168 
    169 void WebPRescalerExportRow(WebPRescaler* const wrk) {
    170   if (wrk->y_accum <= 0) {
    171     assert(!WebPRescalerOutputDone(wrk));
    172     if (wrk->y_expand) {
    173       WebPRescalerExportRowExpand(wrk);
    174     } else if (wrk->fxy_scale) {
    175       WebPRescalerExportRowShrink(wrk);
    176     } else {  // special case
    177       int i;
    178       assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1);
    179       assert(wrk->src_width == 1 && wrk->dst_width <= 2);
    180       for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
    181         wrk->dst[i] = wrk->irow[i];
    182         wrk->irow[i] = 0;
    183       }
    184     }
    185     wrk->y_accum += wrk->y_add;
    186     wrk->dst += wrk->dst_stride;
    187     ++wrk->dst_y;
    188   }
    189 }
    190 
    191 //------------------------------------------------------------------------------
    192 
    193 WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
    194 WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
    195 
    196 WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
    197 WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
    198 
    199 extern void WebPRescalerDspInitSSE2(void);
    200 extern void WebPRescalerDspInitMIPS32(void);
    201 extern void WebPRescalerDspInitMIPSdspR2(void);
    202 extern void WebPRescalerDspInitMSA(void);
    203 extern void WebPRescalerDspInitNEON(void);
    204 
    205 static volatile VP8CPUInfo rescaler_last_cpuinfo_used =
    206     (VP8CPUInfo)&rescaler_last_cpuinfo_used;
    207 
    208 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
    209   if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return;
    210 
    211   WebPRescalerImportRowExpand = WebPRescalerImportRowExpandC;
    212   WebPRescalerImportRowShrink = WebPRescalerImportRowShrinkC;
    213   WebPRescalerExportRowExpand = WebPRescalerExportRowExpandC;
    214   WebPRescalerExportRowShrink = WebPRescalerExportRowShrinkC;
    215 
    216   if (VP8GetCPUInfo != NULL) {
    217 #if defined(WEBP_USE_SSE2)
    218     if (VP8GetCPUInfo(kSSE2)) {
    219       WebPRescalerDspInitSSE2();
    220     }
    221 #endif
    222 #if defined(WEBP_USE_NEON)
    223     if (VP8GetCPUInfo(kNEON)) {
    224       WebPRescalerDspInitNEON();
    225     }
    226 #endif
    227 #if defined(WEBP_USE_MIPS32)
    228     if (VP8GetCPUInfo(kMIPS32)) {
    229       WebPRescalerDspInitMIPS32();
    230     }
    231 #endif
    232 #if defined(WEBP_USE_MIPS_DSP_R2)
    233     if (VP8GetCPUInfo(kMIPSdspR2)) {
    234       WebPRescalerDspInitMIPSdspR2();
    235     }
    236 #endif
    237 #if defined(WEBP_USE_MSA)
    238     if (VP8GetCPUInfo(kMSA)) {
    239       WebPRescalerDspInitMSA();
    240     }
    241 #endif
    242   }
    243   rescaler_last_cpuinfo_used = VP8GetCPUInfo;
    244 }
    245