• 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 "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 
WebPRescalerImportRowExpand_C(WebPRescaler * const wrk,const uint8_t * src)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 
WebPRescalerImportRowShrink_C(WebPRescaler * const wrk,const uint8_t * src)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 
WebPRescalerExportRowExpand_C(WebPRescaler * const wrk)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 
WebPRescalerExportRowShrink_C(WebPRescaler * const wrk)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 
WebPRescalerImportRow(WebPRescaler * const wrk,const uint8_t * src)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 
WebPRescalerExportRow(WebPRescaler * const wrk)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 
WebPRescalerDspInit(void)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