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