• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "./dsp.h"
17 #include "../utils/rescaler.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 
WebPRescalerImportRowExpandC(WebPRescaler * const wrk,const uint8_t * src)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 
WebPRescalerImportRowShrinkC(WebPRescaler * const wrk,const uint8_t * src)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 
WebPRescalerExportRowExpandC(WebPRescaler * const wrk)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 
WebPRescalerExportRowShrinkC(WebPRescaler * const wrk)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 
WebPRescalerImportRow(WebPRescaler * const wrk,const uint8_t * src)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 
WebPRescalerExportRow(WebPRescaler * const wrk)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 {  // very special case for src = dst = 1x1
177       int i;
178       assert(wrk->src_width == 1 && wrk->dst_width <= 2);
179       assert(wrk->src_height == 1 && wrk->dst_height == 1);
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 WebPRescalerDspInitNEON(void);
203 
204 static volatile VP8CPUInfo rescaler_last_cpuinfo_used =
205     (VP8CPUInfo)&rescaler_last_cpuinfo_used;
206 
WebPRescalerDspInit(void)207 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
208   if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return;
209 
210   WebPRescalerImportRowExpand = WebPRescalerImportRowExpandC;
211   WebPRescalerImportRowShrink = WebPRescalerImportRowShrinkC;
212   WebPRescalerExportRowExpand = WebPRescalerExportRowExpandC;
213   WebPRescalerExportRowShrink = WebPRescalerExportRowShrinkC;
214 
215   if (VP8GetCPUInfo != NULL) {
216 #if defined(WEBP_USE_SSE2)
217     if (VP8GetCPUInfo(kSSE2)) {
218       WebPRescalerDspInitSSE2();
219     }
220 #endif
221 #if defined(WEBP_USE_NEON)
222     if (VP8GetCPUInfo(kNEON)) {
223       WebPRescalerDspInitNEON();
224     }
225 #endif
226 #if defined(WEBP_USE_MIPS32)
227     if (VP8GetCPUInfo(kMIPS32)) {
228       WebPRescalerDspInitMIPS32();
229     }
230 #endif
231 #if defined(WEBP_USE_MIPS_DSP_R2)
232     if (VP8GetCPUInfo(kMIPSdspR2)) {
233       WebPRescalerDspInitMIPSdspR2();
234     }
235 #endif
236   }
237   rescaler_last_cpuinfo_used = VP8GetCPUInfo;
238 }
239