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 "src/dsp/dsp.h"
     17 #include "src/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 WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
     29                                    const uint8_t* src) {
     30   const int x_stride = wrk->num_channels;
     31   const int x_out_max = wrk->dst_width * wrk->num_channels;
     32   int channel;
     33   assert(!WebPRescalerInputDone(wrk));
     34   assert(wrk->x_expand);
     35   for (channel = 0; channel < x_stride; ++channel) {
     36     int x_in = channel;
     37     int x_out = channel;
     38     // simple bilinear interpolation
     39     int accum = wrk->x_add;
     40     int left = src[x_in];
     41     int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
     42     x_in += x_stride;
     43     while (1) {
     44       wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
     45       x_out += x_stride;
     46       if (x_out >= x_out_max) break;
     47       accum -= wrk->x_sub;
     48       if (accum < 0) {
     49         left = right;
     50         x_in += x_stride;
     51         assert(x_in < wrk->src_width * x_stride);
     52         right = src[x_in];
     53         accum += wrk->x_add;
     54       }
     55     }
     56     assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
     57   }
     58 }
     59 
     60 void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk,
     61                                    const uint8_t* src) {
     62   const int x_stride = wrk->num_channels;
     63   const int x_out_max = wrk->dst_width * wrk->num_channels;
     64   int channel;
     65   assert(!WebPRescalerInputDone(wrk));
     66   assert(!wrk->x_expand);
     67   for (channel = 0; channel < x_stride; ++channel) {
     68     int x_in = channel;
     69     int x_out = channel;
     70     uint32_t sum = 0;
     71     int accum = 0;
     72     while (x_out < x_out_max) {
     73       uint32_t base = 0;
     74       accum += wrk->x_add;
     75       while (accum > 0) {
     76         accum -= wrk->x_sub;
     77         assert(x_in < wrk->src_width * x_stride);
     78         base = src[x_in];
     79         sum += base;
     80         x_in += x_stride;
     81       }
     82       {        // Emit next horizontal pixel.
     83         const rescaler_t frac = base * (-accum);
     84         wrk->frow[x_out] = sum * wrk->x_sub - frac;
     85         // fresh fractional start for next pixel
     86         sum = (int)MULT_FIX(frac, wrk->fx_scale);
     87       }
     88       x_out += x_stride;
     89     }
     90     assert(accum == 0);
     91   }
     92 }
     93 
     94 //------------------------------------------------------------------------------
     95 // Row export
     96 
     97 void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
     98   int x_out;
     99   uint8_t* const dst = wrk->dst;
    100   rescaler_t* const irow = wrk->irow;
    101   const int x_out_max = wrk->dst_width * wrk->num_channels;
    102   const rescaler_t* const frow = wrk->frow;
    103   assert(!WebPRescalerOutputDone(wrk));
    104   assert(wrk->y_accum <= 0);
    105   assert(wrk->y_expand);
    106   assert(wrk->y_sub != 0);
    107   if (wrk->y_accum == 0) {
    108     for (x_out = 0; x_out < x_out_max; ++x_out) {
    109       const uint32_t J = frow[x_out];
    110       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    111       assert(v >= 0 && v <= 255);
    112       dst[x_out] = v;
    113     }
    114   } else {
    115     const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
    116     const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
    117     for (x_out = 0; x_out < x_out_max; ++x_out) {
    118       const uint64_t I = (uint64_t)A * frow[x_out]
    119                        + (uint64_t)B * irow[x_out];
    120       const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
    121       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    122       assert(v >= 0 && v <= 255);
    123       dst[x_out] = v;
    124     }
    125   }
    126 }
    127 
    128 void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
    129   int x_out;
    130   uint8_t* const dst = wrk->dst;
    131   rescaler_t* const irow = wrk->irow;
    132   const int x_out_max = wrk->dst_width * wrk->num_channels;
    133   const rescaler_t* const frow = wrk->frow;
    134   const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
    135   assert(!WebPRescalerOutputDone(wrk));
    136   assert(wrk->y_accum <= 0);
    137   assert(!wrk->y_expand);
    138   if (yscale) {
    139     for (x_out = 0; x_out < x_out_max; ++x_out) {
    140       const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
    141       const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
    142       assert(v >= 0 && v <= 255);
    143       dst[x_out] = v;
    144       irow[x_out] = frac;   // new fractional start
    145     }
    146   } else {
    147     for (x_out = 0; x_out < x_out_max; ++x_out) {
    148       const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
    149       assert(v >= 0 && v <= 255);
    150       dst[x_out] = v;
    151       irow[x_out] = 0;
    152     }
    153   }
    154 }
    155 
    156 #undef MULT_FIX
    157 #undef ROUNDER
    158 
    159 //------------------------------------------------------------------------------
    160 // Main entry calls
    161 
    162 void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
    163   assert(!WebPRescalerInputDone(wrk));
    164   if (!wrk->x_expand) {
    165     WebPRescalerImportRowShrink(wrk, src);
    166   } else {
    167     WebPRescalerImportRowExpand(wrk, src);
    168   }
    169 }
    170 
    171 void WebPRescalerExportRow(WebPRescaler* const wrk) {
    172   if (wrk->y_accum <= 0) {
    173     assert(!WebPRescalerOutputDone(wrk));
    174     if (wrk->y_expand) {
    175       WebPRescalerExportRowExpand(wrk);
    176     } else if (wrk->fxy_scale) {
    177       WebPRescalerExportRowShrink(wrk);
    178     } else {  // special case
    179       int i;
    180       assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1);
    181       assert(wrk->src_width == 1 && wrk->dst_width <= 2);
    182       for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
    183         wrk->dst[i] = wrk->irow[i];
    184         wrk->irow[i] = 0;
    185       }
    186     }
    187     wrk->y_accum += wrk->y_add;
    188     wrk->dst += wrk->dst_stride;
    189     ++wrk->dst_y;
    190   }
    191 }
    192 
    193 //------------------------------------------------------------------------------
    194 
    195 WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
    196 WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
    197 
    198 WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
    199 WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
    200 
    201 extern void WebPRescalerDspInitSSE2(void);
    202 extern void WebPRescalerDspInitMIPS32(void);
    203 extern void WebPRescalerDspInitMIPSdspR2(void);
    204 extern void WebPRescalerDspInitMSA(void);
    205 extern void WebPRescalerDspInitNEON(void);
    206 
    207 static volatile VP8CPUInfo rescaler_last_cpuinfo_used =
    208     (VP8CPUInfo)&rescaler_last_cpuinfo_used;
    209 
    210 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
    211   if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return;
    212 #if !defined(WEBP_REDUCE_SIZE)
    213 #if !WEBP_NEON_OMIT_C_CODE
    214   WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C;
    215   WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C;
    216 #endif
    217 
    218   WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C;
    219   WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
    220 
    221   if (VP8GetCPUInfo != NULL) {
    222 #if defined(WEBP_USE_SSE2)
    223     if (VP8GetCPUInfo(kSSE2)) {
    224       WebPRescalerDspInitSSE2();
    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 
    244 #if defined(WEBP_USE_NEON)
    245   if (WEBP_NEON_OMIT_C_CODE ||
    246       (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
    247     WebPRescalerDspInitNEON();
    248   }
    249 #endif
    250 
    251   assert(WebPRescalerExportRowExpand != NULL);
    252   assert(WebPRescalerExportRowShrink != NULL);
    253   assert(WebPRescalerImportRowExpand != NULL);
    254   assert(WebPRescalerImportRowShrink != NULL);
    255 #endif   // WEBP_REDUCE_SIZE
    256   rescaler_last_cpuinfo_used = VP8GetCPUInfo;
    257 }
    258