go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

rescaler.c (8304B)


      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@gmail.com)
     13 
     14 #include <assert.h>
     15 #include <stddef.h>
     16 
     17 #include "src/dsp/cpu.h"
     18 #include "src/webp/types.h"
     19 #include "src/dsp/dsp.h"
     20 #include "src/utils/rescaler_utils.h"
     21 
     22 //------------------------------------------------------------------------------
     23 // Implementations of critical functions ImportRow / ExportRow
     24 
     25 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
     26 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
     27 #define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
     28 
     29 //------------------------------------------------------------------------------
     30 // Row import
     31 
     32 void WebPRescalerImportRowExpand_C(WebPRescaler* WEBP_RESTRICT const wrk,
     33                                    const uint8_t* WEBP_RESTRICT src) {
     34   const int x_stride = wrk->num_channels;
     35   const int x_out_max = wrk->dst_width * wrk->num_channels;
     36   int channel;
     37   assert(!WebPRescalerInputDone(wrk));
     38   assert(wrk->x_expand);
     39   for (channel = 0; channel < x_stride; ++channel) {
     40     int x_in = channel;
     41     int x_out = channel;
     42     // simple bilinear interpolation
     43     int accum = wrk->x_add;
     44     rescaler_t left = (rescaler_t)src[x_in];
     45     rescaler_t right =
     46         (wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left;
     47     x_in += x_stride;
     48     while (1) {
     49       wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
     50       x_out += x_stride;
     51       if (x_out >= x_out_max) break;
     52       accum -= wrk->x_sub;
     53       if (accum < 0) {
     54         left = right;
     55         x_in += x_stride;
     56         assert(x_in < wrk->src_width * x_stride);
     57         right = (rescaler_t)src[x_in];
     58         accum += wrk->x_add;
     59       }
     60     }
     61     assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
     62   }
     63 }
     64 
     65 void WebPRescalerImportRowShrink_C(WebPRescaler* WEBP_RESTRICT const wrk,
     66                                    const uint8_t* WEBP_RESTRICT src) {
     67   const int x_stride = wrk->num_channels;
     68   const int x_out_max = wrk->dst_width * wrk->num_channels;
     69   int channel;
     70   assert(!WebPRescalerInputDone(wrk));
     71   assert(!wrk->x_expand);
     72   for (channel = 0; channel < x_stride; ++channel) {
     73     int x_in = channel;
     74     int x_out = channel;
     75     uint32_t sum = 0;
     76     int accum = 0;
     77     while (x_out < x_out_max) {
     78       uint32_t base = 0;
     79       accum += wrk->x_add;
     80       while (accum > 0) {
     81         accum -= wrk->x_sub;
     82         assert(x_in < wrk->src_width * x_stride);
     83         base = src[x_in];
     84         sum += base;
     85         x_in += x_stride;
     86       }
     87       {        // Emit next horizontal pixel.
     88         const rescaler_t frac = base * (-accum);
     89         wrk->frow[x_out] = sum * wrk->x_sub - frac;
     90         // fresh fractional start for next pixel
     91         sum = (int)MULT_FIX(frac, wrk->fx_scale);
     92       }
     93       x_out += x_stride;
     94     }
     95     assert(accum == 0);
     96   }
     97 }
     98 
     99 //------------------------------------------------------------------------------
    100 // Row export
    101 
    102 void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
    103   int x_out;
    104   uint8_t* const dst = wrk->dst;
    105   rescaler_t* const irow = wrk->irow;
    106   const int x_out_max = wrk->dst_width * wrk->num_channels;
    107   const rescaler_t* const frow = wrk->frow;
    108   assert(!WebPRescalerOutputDone(wrk));
    109   assert(wrk->y_accum <= 0);
    110   assert(wrk->y_expand);
    111   assert(wrk->y_sub != 0);
    112   if (wrk->y_accum == 0) {
    113     for (x_out = 0; x_out < x_out_max; ++x_out) {
    114       const uint32_t J = frow[x_out];
    115       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    116       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    117     }
    118   } else {
    119     const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
    120     const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
    121     for (x_out = 0; x_out < x_out_max; ++x_out) {
    122       const uint64_t I = (uint64_t)A * frow[x_out]
    123                        + (uint64_t)B * irow[x_out];
    124       const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
    125       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    126       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    127     }
    128   }
    129 }
    130 
    131 void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
    132   int x_out;
    133   uint8_t* const dst = wrk->dst;
    134   rescaler_t* const irow = wrk->irow;
    135   const int x_out_max = wrk->dst_width * wrk->num_channels;
    136   const rescaler_t* const frow = wrk->frow;
    137   const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
    138   assert(!WebPRescalerOutputDone(wrk));
    139   assert(wrk->y_accum <= 0);
    140   assert(!wrk->y_expand);
    141   if (yscale) {
    142     for (x_out = 0; x_out < x_out_max; ++x_out) {
    143       const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
    144       const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
    145       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    146       irow[x_out] = frac;   // new fractional start
    147     }
    148   } else {
    149     for (x_out = 0; x_out < x_out_max; ++x_out) {
    150       const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
    151       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    152       irow[x_out] = 0;
    153     }
    154   }
    155 }
    156 
    157 #undef MULT_FIX_FLOOR
    158 #undef MULT_FIX
    159 #undef ROUNDER
    160 
    161 //------------------------------------------------------------------------------
    162 // Main entry calls
    163 
    164 void WebPRescalerImportRow(WebPRescaler* WEBP_RESTRICT const wrk,
    165                            const uint8_t* WEBP_RESTRICT src) {
    166   assert(!WebPRescalerInputDone(wrk));
    167   if (!wrk->x_expand) {
    168     WebPRescalerImportRowShrink(wrk, src);
    169   } else {
    170     WebPRescalerImportRowExpand(wrk, src);
    171   }
    172 }
    173 
    174 void WebPRescalerExportRow(WebPRescaler* const wrk) {
    175   if (wrk->y_accum <= 0) {
    176     assert(!WebPRescalerOutputDone(wrk));
    177     if (wrk->y_expand) {
    178       WebPRescalerExportRowExpand(wrk);
    179     } else if (wrk->fxy_scale) {
    180       WebPRescalerExportRowShrink(wrk);
    181     } else {  // special case
    182       int i;
    183       assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1);
    184       assert(wrk->src_width == 1 && wrk->dst_width <= 2);
    185       for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
    186         wrk->dst[i] = wrk->irow[i];
    187         wrk->irow[i] = 0;
    188       }
    189     }
    190     wrk->y_accum += wrk->y_add;
    191     wrk->dst += wrk->dst_stride;
    192     ++wrk->dst_y;
    193   }
    194 }
    195 
    196 //------------------------------------------------------------------------------
    197 
    198 WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
    199 WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
    200 
    201 WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
    202 WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
    203 
    204 extern VP8CPUInfo VP8GetCPUInfo;
    205 extern void WebPRescalerDspInitSSE2(void);
    206 extern void WebPRescalerDspInitMIPS32(void);
    207 extern void WebPRescalerDspInitMIPSdspR2(void);
    208 extern void WebPRescalerDspInitMSA(void);
    209 extern void WebPRescalerDspInitNEON(void);
    210 
    211 WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
    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_HAVE_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_HAVE_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 }