Line data Source code
1 : /*
2 : * Copyright 2013 The LibYuv Project Authors. All rights reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "libyuv/scale.h"
12 :
13 : #include <assert.h>
14 : #include <string.h>
15 :
16 : #include "libyuv/cpu_id.h"
17 : #include "libyuv/planar_functions.h" // For CopyARGB
18 : #include "libyuv/row.h"
19 : #include "libyuv/scale_row.h"
20 :
21 : #ifdef __cplusplus
22 : namespace libyuv {
23 : extern "C" {
24 : #endif
25 :
26 0 : static __inline int Abs(int v) {
27 0 : return v >= 0 ? v : -v;
28 : }
29 :
30 : // CPU agnostic row functions
31 0 : void ScaleRowDown2_C(const uint8* src_ptr,
32 : ptrdiff_t src_stride,
33 : uint8* dst,
34 : int dst_width) {
35 : int x;
36 : (void)src_stride;
37 0 : for (x = 0; x < dst_width - 1; x += 2) {
38 0 : dst[0] = src_ptr[1];
39 0 : dst[1] = src_ptr[3];
40 0 : dst += 2;
41 0 : src_ptr += 4;
42 : }
43 0 : if (dst_width & 1) {
44 0 : dst[0] = src_ptr[1];
45 : }
46 0 : }
47 :
48 0 : void ScaleRowDown2_16_C(const uint16* src_ptr,
49 : ptrdiff_t src_stride,
50 : uint16* dst,
51 : int dst_width) {
52 : int x;
53 : (void)src_stride;
54 0 : for (x = 0; x < dst_width - 1; x += 2) {
55 0 : dst[0] = src_ptr[1];
56 0 : dst[1] = src_ptr[3];
57 0 : dst += 2;
58 0 : src_ptr += 4;
59 : }
60 0 : if (dst_width & 1) {
61 0 : dst[0] = src_ptr[1];
62 : }
63 0 : }
64 :
65 0 : void ScaleRowDown2Linear_C(const uint8* src_ptr,
66 : ptrdiff_t src_stride,
67 : uint8* dst,
68 : int dst_width) {
69 0 : const uint8* s = src_ptr;
70 : int x;
71 : (void)src_stride;
72 0 : for (x = 0; x < dst_width - 1; x += 2) {
73 0 : dst[0] = (s[0] + s[1] + 1) >> 1;
74 0 : dst[1] = (s[2] + s[3] + 1) >> 1;
75 0 : dst += 2;
76 0 : s += 4;
77 : }
78 0 : if (dst_width & 1) {
79 0 : dst[0] = (s[0] + s[1] + 1) >> 1;
80 : }
81 0 : }
82 :
83 0 : void ScaleRowDown2Linear_16_C(const uint16* src_ptr,
84 : ptrdiff_t src_stride,
85 : uint16* dst,
86 : int dst_width) {
87 0 : const uint16* s = src_ptr;
88 : int x;
89 : (void)src_stride;
90 0 : for (x = 0; x < dst_width - 1; x += 2) {
91 0 : dst[0] = (s[0] + s[1] + 1) >> 1;
92 0 : dst[1] = (s[2] + s[3] + 1) >> 1;
93 0 : dst += 2;
94 0 : s += 4;
95 : }
96 0 : if (dst_width & 1) {
97 0 : dst[0] = (s[0] + s[1] + 1) >> 1;
98 : }
99 0 : }
100 :
101 0 : void ScaleRowDown2Box_C(const uint8* src_ptr,
102 : ptrdiff_t src_stride,
103 : uint8* dst,
104 : int dst_width) {
105 0 : const uint8* s = src_ptr;
106 0 : const uint8* t = src_ptr + src_stride;
107 : int x;
108 0 : for (x = 0; x < dst_width - 1; x += 2) {
109 0 : dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
110 0 : dst[1] = (s[2] + s[3] + t[2] + t[3] + 2) >> 2;
111 0 : dst += 2;
112 0 : s += 4;
113 0 : t += 4;
114 : }
115 0 : if (dst_width & 1) {
116 0 : dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
117 : }
118 0 : }
119 :
120 0 : void ScaleRowDown2Box_Odd_C(const uint8* src_ptr,
121 : ptrdiff_t src_stride,
122 : uint8* dst,
123 : int dst_width) {
124 0 : const uint8* s = src_ptr;
125 0 : const uint8* t = src_ptr + src_stride;
126 : int x;
127 0 : dst_width -= 1;
128 0 : for (x = 0; x < dst_width - 1; x += 2) {
129 0 : dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
130 0 : dst[1] = (s[2] + s[3] + t[2] + t[3] + 2) >> 2;
131 0 : dst += 2;
132 0 : s += 4;
133 0 : t += 4;
134 : }
135 0 : if (dst_width & 1) {
136 0 : dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
137 0 : dst += 1;
138 0 : s += 2;
139 0 : t += 2;
140 : }
141 0 : dst[0] = (s[0] + t[0] + 1) >> 1;
142 0 : }
143 :
144 0 : void ScaleRowDown2Box_16_C(const uint16* src_ptr,
145 : ptrdiff_t src_stride,
146 : uint16* dst,
147 : int dst_width) {
148 0 : const uint16* s = src_ptr;
149 0 : const uint16* t = src_ptr + src_stride;
150 : int x;
151 0 : for (x = 0; x < dst_width - 1; x += 2) {
152 0 : dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
153 0 : dst[1] = (s[2] + s[3] + t[2] + t[3] + 2) >> 2;
154 0 : dst += 2;
155 0 : s += 4;
156 0 : t += 4;
157 : }
158 0 : if (dst_width & 1) {
159 0 : dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
160 : }
161 0 : }
162 :
163 0 : void ScaleRowDown4_C(const uint8* src_ptr,
164 : ptrdiff_t src_stride,
165 : uint8* dst,
166 : int dst_width) {
167 : int x;
168 : (void)src_stride;
169 0 : for (x = 0; x < dst_width - 1; x += 2) {
170 0 : dst[0] = src_ptr[2];
171 0 : dst[1] = src_ptr[6];
172 0 : dst += 2;
173 0 : src_ptr += 8;
174 : }
175 0 : if (dst_width & 1) {
176 0 : dst[0] = src_ptr[2];
177 : }
178 0 : }
179 :
180 0 : void ScaleRowDown4_16_C(const uint16* src_ptr,
181 : ptrdiff_t src_stride,
182 : uint16* dst,
183 : int dst_width) {
184 : int x;
185 : (void)src_stride;
186 0 : for (x = 0; x < dst_width - 1; x += 2) {
187 0 : dst[0] = src_ptr[2];
188 0 : dst[1] = src_ptr[6];
189 0 : dst += 2;
190 0 : src_ptr += 8;
191 : }
192 0 : if (dst_width & 1) {
193 0 : dst[0] = src_ptr[2];
194 : }
195 0 : }
196 :
197 0 : void ScaleRowDown4Box_C(const uint8* src_ptr,
198 : ptrdiff_t src_stride,
199 : uint8* dst,
200 : int dst_width) {
201 0 : intptr_t stride = src_stride;
202 : int x;
203 0 : for (x = 0; x < dst_width - 1; x += 2) {
204 0 : dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
205 0 : src_ptr[stride + 0] + src_ptr[stride + 1] + src_ptr[stride + 2] +
206 0 : src_ptr[stride + 3] + src_ptr[stride * 2 + 0] +
207 0 : src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2] +
208 0 : src_ptr[stride * 2 + 3] + src_ptr[stride * 3 + 0] +
209 0 : src_ptr[stride * 3 + 1] + src_ptr[stride * 3 + 2] +
210 0 : src_ptr[stride * 3 + 3] + 8) >>
211 0 : 4;
212 0 : dst[1] = (src_ptr[4] + src_ptr[5] + src_ptr[6] + src_ptr[7] +
213 0 : src_ptr[stride + 4] + src_ptr[stride + 5] + src_ptr[stride + 6] +
214 0 : src_ptr[stride + 7] + src_ptr[stride * 2 + 4] +
215 0 : src_ptr[stride * 2 + 5] + src_ptr[stride * 2 + 6] +
216 0 : src_ptr[stride * 2 + 7] + src_ptr[stride * 3 + 4] +
217 0 : src_ptr[stride * 3 + 5] + src_ptr[stride * 3 + 6] +
218 0 : src_ptr[stride * 3 + 7] + 8) >>
219 0 : 4;
220 0 : dst += 2;
221 0 : src_ptr += 8;
222 : }
223 0 : if (dst_width & 1) {
224 0 : dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
225 0 : src_ptr[stride + 0] + src_ptr[stride + 1] + src_ptr[stride + 2] +
226 0 : src_ptr[stride + 3] + src_ptr[stride * 2 + 0] +
227 0 : src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2] +
228 0 : src_ptr[stride * 2 + 3] + src_ptr[stride * 3 + 0] +
229 0 : src_ptr[stride * 3 + 1] + src_ptr[stride * 3 + 2] +
230 0 : src_ptr[stride * 3 + 3] + 8) >>
231 0 : 4;
232 : }
233 0 : }
234 :
235 0 : void ScaleRowDown4Box_16_C(const uint16* src_ptr,
236 : ptrdiff_t src_stride,
237 : uint16* dst,
238 : int dst_width) {
239 0 : intptr_t stride = src_stride;
240 : int x;
241 0 : for (x = 0; x < dst_width - 1; x += 2) {
242 0 : dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
243 0 : src_ptr[stride + 0] + src_ptr[stride + 1] + src_ptr[stride + 2] +
244 0 : src_ptr[stride + 3] + src_ptr[stride * 2 + 0] +
245 0 : src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2] +
246 0 : src_ptr[stride * 2 + 3] + src_ptr[stride * 3 + 0] +
247 0 : src_ptr[stride * 3 + 1] + src_ptr[stride * 3 + 2] +
248 0 : src_ptr[stride * 3 + 3] + 8) >>
249 0 : 4;
250 0 : dst[1] = (src_ptr[4] + src_ptr[5] + src_ptr[6] + src_ptr[7] +
251 0 : src_ptr[stride + 4] + src_ptr[stride + 5] + src_ptr[stride + 6] +
252 0 : src_ptr[stride + 7] + src_ptr[stride * 2 + 4] +
253 0 : src_ptr[stride * 2 + 5] + src_ptr[stride * 2 + 6] +
254 0 : src_ptr[stride * 2 + 7] + src_ptr[stride * 3 + 4] +
255 0 : src_ptr[stride * 3 + 5] + src_ptr[stride * 3 + 6] +
256 0 : src_ptr[stride * 3 + 7] + 8) >>
257 0 : 4;
258 0 : dst += 2;
259 0 : src_ptr += 8;
260 : }
261 0 : if (dst_width & 1) {
262 0 : dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
263 0 : src_ptr[stride + 0] + src_ptr[stride + 1] + src_ptr[stride + 2] +
264 0 : src_ptr[stride + 3] + src_ptr[stride * 2 + 0] +
265 0 : src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2] +
266 0 : src_ptr[stride * 2 + 3] + src_ptr[stride * 3 + 0] +
267 0 : src_ptr[stride * 3 + 1] + src_ptr[stride * 3 + 2] +
268 0 : src_ptr[stride * 3 + 3] + 8) >>
269 0 : 4;
270 : }
271 0 : }
272 :
273 0 : void ScaleRowDown34_C(const uint8* src_ptr,
274 : ptrdiff_t src_stride,
275 : uint8* dst,
276 : int dst_width) {
277 : int x;
278 : (void)src_stride;
279 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
280 0 : for (x = 0; x < dst_width; x += 3) {
281 0 : dst[0] = src_ptr[0];
282 0 : dst[1] = src_ptr[1];
283 0 : dst[2] = src_ptr[3];
284 0 : dst += 3;
285 0 : src_ptr += 4;
286 : }
287 0 : }
288 :
289 0 : void ScaleRowDown34_16_C(const uint16* src_ptr,
290 : ptrdiff_t src_stride,
291 : uint16* dst,
292 : int dst_width) {
293 : int x;
294 : (void)src_stride;
295 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
296 0 : for (x = 0; x < dst_width; x += 3) {
297 0 : dst[0] = src_ptr[0];
298 0 : dst[1] = src_ptr[1];
299 0 : dst[2] = src_ptr[3];
300 0 : dst += 3;
301 0 : src_ptr += 4;
302 : }
303 0 : }
304 :
305 : // Filter rows 0 and 1 together, 3 : 1
306 0 : void ScaleRowDown34_0_Box_C(const uint8* src_ptr,
307 : ptrdiff_t src_stride,
308 : uint8* d,
309 : int dst_width) {
310 0 : const uint8* s = src_ptr;
311 0 : const uint8* t = src_ptr + src_stride;
312 : int x;
313 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
314 0 : for (x = 0; x < dst_width; x += 3) {
315 0 : uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
316 0 : uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
317 0 : uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
318 0 : uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
319 0 : uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
320 0 : uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
321 0 : d[0] = (a0 * 3 + b0 + 2) >> 2;
322 0 : d[1] = (a1 * 3 + b1 + 2) >> 2;
323 0 : d[2] = (a2 * 3 + b2 + 2) >> 2;
324 0 : d += 3;
325 0 : s += 4;
326 0 : t += 4;
327 : }
328 0 : }
329 :
330 0 : void ScaleRowDown34_0_Box_16_C(const uint16* src_ptr,
331 : ptrdiff_t src_stride,
332 : uint16* d,
333 : int dst_width) {
334 0 : const uint16* s = src_ptr;
335 0 : const uint16* t = src_ptr + src_stride;
336 : int x;
337 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
338 0 : for (x = 0; x < dst_width; x += 3) {
339 0 : uint16 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
340 0 : uint16 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
341 0 : uint16 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
342 0 : uint16 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
343 0 : uint16 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
344 0 : uint16 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
345 0 : d[0] = (a0 * 3 + b0 + 2) >> 2;
346 0 : d[1] = (a1 * 3 + b1 + 2) >> 2;
347 0 : d[2] = (a2 * 3 + b2 + 2) >> 2;
348 0 : d += 3;
349 0 : s += 4;
350 0 : t += 4;
351 : }
352 0 : }
353 :
354 : // Filter rows 1 and 2 together, 1 : 1
355 0 : void ScaleRowDown34_1_Box_C(const uint8* src_ptr,
356 : ptrdiff_t src_stride,
357 : uint8* d,
358 : int dst_width) {
359 0 : const uint8* s = src_ptr;
360 0 : const uint8* t = src_ptr + src_stride;
361 : int x;
362 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
363 0 : for (x = 0; x < dst_width; x += 3) {
364 0 : uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
365 0 : uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
366 0 : uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
367 0 : uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
368 0 : uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
369 0 : uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
370 0 : d[0] = (a0 + b0 + 1) >> 1;
371 0 : d[1] = (a1 + b1 + 1) >> 1;
372 0 : d[2] = (a2 + b2 + 1) >> 1;
373 0 : d += 3;
374 0 : s += 4;
375 0 : t += 4;
376 : }
377 0 : }
378 :
379 0 : void ScaleRowDown34_1_Box_16_C(const uint16* src_ptr,
380 : ptrdiff_t src_stride,
381 : uint16* d,
382 : int dst_width) {
383 0 : const uint16* s = src_ptr;
384 0 : const uint16* t = src_ptr + src_stride;
385 : int x;
386 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
387 0 : for (x = 0; x < dst_width; x += 3) {
388 0 : uint16 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
389 0 : uint16 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
390 0 : uint16 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
391 0 : uint16 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
392 0 : uint16 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
393 0 : uint16 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
394 0 : d[0] = (a0 + b0 + 1) >> 1;
395 0 : d[1] = (a1 + b1 + 1) >> 1;
396 0 : d[2] = (a2 + b2 + 1) >> 1;
397 0 : d += 3;
398 0 : s += 4;
399 0 : t += 4;
400 : }
401 0 : }
402 :
403 : // Scales a single row of pixels using point sampling.
404 0 : void ScaleCols_C(uint8* dst_ptr,
405 : const uint8* src_ptr,
406 : int dst_width,
407 : int x,
408 : int dx) {
409 : int j;
410 0 : for (j = 0; j < dst_width - 1; j += 2) {
411 0 : dst_ptr[0] = src_ptr[x >> 16];
412 0 : x += dx;
413 0 : dst_ptr[1] = src_ptr[x >> 16];
414 0 : x += dx;
415 0 : dst_ptr += 2;
416 : }
417 0 : if (dst_width & 1) {
418 0 : dst_ptr[0] = src_ptr[x >> 16];
419 : }
420 0 : }
421 :
422 0 : void ScaleCols_16_C(uint16* dst_ptr,
423 : const uint16* src_ptr,
424 : int dst_width,
425 : int x,
426 : int dx) {
427 : int j;
428 0 : for (j = 0; j < dst_width - 1; j += 2) {
429 0 : dst_ptr[0] = src_ptr[x >> 16];
430 0 : x += dx;
431 0 : dst_ptr[1] = src_ptr[x >> 16];
432 0 : x += dx;
433 0 : dst_ptr += 2;
434 : }
435 0 : if (dst_width & 1) {
436 0 : dst_ptr[0] = src_ptr[x >> 16];
437 : }
438 0 : }
439 :
440 : // Scales a single row of pixels up by 2x using point sampling.
441 0 : void ScaleColsUp2_C(uint8* dst_ptr,
442 : const uint8* src_ptr,
443 : int dst_width,
444 : int x,
445 : int dx) {
446 : int j;
447 : (void)x;
448 : (void)dx;
449 0 : for (j = 0; j < dst_width - 1; j += 2) {
450 0 : dst_ptr[1] = dst_ptr[0] = src_ptr[0];
451 0 : src_ptr += 1;
452 0 : dst_ptr += 2;
453 : }
454 0 : if (dst_width & 1) {
455 0 : dst_ptr[0] = src_ptr[0];
456 : }
457 0 : }
458 :
459 0 : void ScaleColsUp2_16_C(uint16* dst_ptr,
460 : const uint16* src_ptr,
461 : int dst_width,
462 : int x,
463 : int dx) {
464 : int j;
465 : (void)x;
466 : (void)dx;
467 0 : for (j = 0; j < dst_width - 1; j += 2) {
468 0 : dst_ptr[1] = dst_ptr[0] = src_ptr[0];
469 0 : src_ptr += 1;
470 0 : dst_ptr += 2;
471 : }
472 0 : if (dst_width & 1) {
473 0 : dst_ptr[0] = src_ptr[0];
474 : }
475 0 : }
476 :
477 : // (1-f)a + fb can be replaced with a + f(b-a)
478 : #if defined(__arm__) || defined(__aarch64__)
479 : #define BLENDER(a, b, f) \
480 : (uint8)((int)(a) + ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16))
481 : #else
482 : // Intel uses 7 bit math with rounding.
483 : #define BLENDER(a, b, f) \
484 : (uint8)((int)(a) + (((int)((f) >> 9) * ((int)(b) - (int)(a)) + 0x40) >> 7))
485 : #endif
486 :
487 0 : void ScaleFilterCols_C(uint8* dst_ptr,
488 : const uint8* src_ptr,
489 : int dst_width,
490 : int x,
491 : int dx) {
492 : int j;
493 0 : for (j = 0; j < dst_width - 1; j += 2) {
494 0 : int xi = x >> 16;
495 0 : int a = src_ptr[xi];
496 0 : int b = src_ptr[xi + 1];
497 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
498 0 : x += dx;
499 0 : xi = x >> 16;
500 0 : a = src_ptr[xi];
501 0 : b = src_ptr[xi + 1];
502 0 : dst_ptr[1] = BLENDER(a, b, x & 0xffff);
503 0 : x += dx;
504 0 : dst_ptr += 2;
505 : }
506 0 : if (dst_width & 1) {
507 0 : int xi = x >> 16;
508 0 : int a = src_ptr[xi];
509 0 : int b = src_ptr[xi + 1];
510 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
511 : }
512 0 : }
513 :
514 0 : void ScaleFilterCols64_C(uint8* dst_ptr,
515 : const uint8* src_ptr,
516 : int dst_width,
517 : int x32,
518 : int dx) {
519 0 : int64 x = (int64)(x32);
520 : int j;
521 0 : for (j = 0; j < dst_width - 1; j += 2) {
522 0 : int64 xi = x >> 16;
523 0 : int a = src_ptr[xi];
524 0 : int b = src_ptr[xi + 1];
525 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
526 0 : x += dx;
527 0 : xi = x >> 16;
528 0 : a = src_ptr[xi];
529 0 : b = src_ptr[xi + 1];
530 0 : dst_ptr[1] = BLENDER(a, b, x & 0xffff);
531 0 : x += dx;
532 0 : dst_ptr += 2;
533 : }
534 0 : if (dst_width & 1) {
535 0 : int64 xi = x >> 16;
536 0 : int a = src_ptr[xi];
537 0 : int b = src_ptr[xi + 1];
538 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
539 : }
540 0 : }
541 : #undef BLENDER
542 :
543 : // Same as 8 bit arm blender but return is cast to uint16
544 : #define BLENDER(a, b, f) \
545 : (uint16)((int)(a) + ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16))
546 :
547 0 : void ScaleFilterCols_16_C(uint16* dst_ptr,
548 : const uint16* src_ptr,
549 : int dst_width,
550 : int x,
551 : int dx) {
552 : int j;
553 0 : for (j = 0; j < dst_width - 1; j += 2) {
554 0 : int xi = x >> 16;
555 0 : int a = src_ptr[xi];
556 0 : int b = src_ptr[xi + 1];
557 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
558 0 : x += dx;
559 0 : xi = x >> 16;
560 0 : a = src_ptr[xi];
561 0 : b = src_ptr[xi + 1];
562 0 : dst_ptr[1] = BLENDER(a, b, x & 0xffff);
563 0 : x += dx;
564 0 : dst_ptr += 2;
565 : }
566 0 : if (dst_width & 1) {
567 0 : int xi = x >> 16;
568 0 : int a = src_ptr[xi];
569 0 : int b = src_ptr[xi + 1];
570 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
571 : }
572 0 : }
573 :
574 0 : void ScaleFilterCols64_16_C(uint16* dst_ptr,
575 : const uint16* src_ptr,
576 : int dst_width,
577 : int x32,
578 : int dx) {
579 0 : int64 x = (int64)(x32);
580 : int j;
581 0 : for (j = 0; j < dst_width - 1; j += 2) {
582 0 : int64 xi = x >> 16;
583 0 : int a = src_ptr[xi];
584 0 : int b = src_ptr[xi + 1];
585 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
586 0 : x += dx;
587 0 : xi = x >> 16;
588 0 : a = src_ptr[xi];
589 0 : b = src_ptr[xi + 1];
590 0 : dst_ptr[1] = BLENDER(a, b, x & 0xffff);
591 0 : x += dx;
592 0 : dst_ptr += 2;
593 : }
594 0 : if (dst_width & 1) {
595 0 : int64 xi = x >> 16;
596 0 : int a = src_ptr[xi];
597 0 : int b = src_ptr[xi + 1];
598 0 : dst_ptr[0] = BLENDER(a, b, x & 0xffff);
599 : }
600 0 : }
601 : #undef BLENDER
602 :
603 0 : void ScaleRowDown38_C(const uint8* src_ptr,
604 : ptrdiff_t src_stride,
605 : uint8* dst,
606 : int dst_width) {
607 : int x;
608 : (void)src_stride;
609 0 : assert(dst_width % 3 == 0);
610 0 : for (x = 0; x < dst_width; x += 3) {
611 0 : dst[0] = src_ptr[0];
612 0 : dst[1] = src_ptr[3];
613 0 : dst[2] = src_ptr[6];
614 0 : dst += 3;
615 0 : src_ptr += 8;
616 : }
617 0 : }
618 :
619 0 : void ScaleRowDown38_16_C(const uint16* src_ptr,
620 : ptrdiff_t src_stride,
621 : uint16* dst,
622 : int dst_width) {
623 : int x;
624 : (void)src_stride;
625 0 : assert(dst_width % 3 == 0);
626 0 : for (x = 0; x < dst_width; x += 3) {
627 0 : dst[0] = src_ptr[0];
628 0 : dst[1] = src_ptr[3];
629 0 : dst[2] = src_ptr[6];
630 0 : dst += 3;
631 0 : src_ptr += 8;
632 : }
633 0 : }
634 :
635 : // 8x3 -> 3x1
636 0 : void ScaleRowDown38_3_Box_C(const uint8* src_ptr,
637 : ptrdiff_t src_stride,
638 : uint8* dst_ptr,
639 : int dst_width) {
640 0 : intptr_t stride = src_stride;
641 : int i;
642 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
643 0 : for (i = 0; i < dst_width; i += 3) {
644 0 : dst_ptr[0] =
645 0 : (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[stride + 0] +
646 0 : src_ptr[stride + 1] + src_ptr[stride + 2] + src_ptr[stride * 2 + 0] +
647 0 : src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2]) *
648 0 : (65536 / 9) >>
649 0 : 16;
650 0 : dst_ptr[1] =
651 0 : (src_ptr[3] + src_ptr[4] + src_ptr[5] + src_ptr[stride + 3] +
652 0 : src_ptr[stride + 4] + src_ptr[stride + 5] + src_ptr[stride * 2 + 3] +
653 0 : src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5]) *
654 0 : (65536 / 9) >>
655 0 : 16;
656 0 : dst_ptr[2] =
657 0 : (src_ptr[6] + src_ptr[7] + src_ptr[stride + 6] + src_ptr[stride + 7] +
658 0 : src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7]) *
659 0 : (65536 / 6) >>
660 0 : 16;
661 0 : src_ptr += 8;
662 0 : dst_ptr += 3;
663 : }
664 0 : }
665 :
666 0 : void ScaleRowDown38_3_Box_16_C(const uint16* src_ptr,
667 : ptrdiff_t src_stride,
668 : uint16* dst_ptr,
669 : int dst_width) {
670 0 : intptr_t stride = src_stride;
671 : int i;
672 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
673 0 : for (i = 0; i < dst_width; i += 3) {
674 0 : dst_ptr[0] =
675 0 : (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[stride + 0] +
676 0 : src_ptr[stride + 1] + src_ptr[stride + 2] + src_ptr[stride * 2 + 0] +
677 0 : src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2]) *
678 0 : (65536 / 9) >>
679 0 : 16;
680 0 : dst_ptr[1] =
681 0 : (src_ptr[3] + src_ptr[4] + src_ptr[5] + src_ptr[stride + 3] +
682 0 : src_ptr[stride + 4] + src_ptr[stride + 5] + src_ptr[stride * 2 + 3] +
683 0 : src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5]) *
684 0 : (65536 / 9) >>
685 0 : 16;
686 0 : dst_ptr[2] =
687 0 : (src_ptr[6] + src_ptr[7] + src_ptr[stride + 6] + src_ptr[stride + 7] +
688 0 : src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7]) *
689 0 : (65536 / 6) >>
690 0 : 16;
691 0 : src_ptr += 8;
692 0 : dst_ptr += 3;
693 : }
694 0 : }
695 :
696 : // 8x2 -> 3x1
697 0 : void ScaleRowDown38_2_Box_C(const uint8* src_ptr,
698 : ptrdiff_t src_stride,
699 : uint8* dst_ptr,
700 : int dst_width) {
701 0 : intptr_t stride = src_stride;
702 : int i;
703 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
704 0 : for (i = 0; i < dst_width; i += 3) {
705 0 : dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[stride + 0] +
706 0 : src_ptr[stride + 1] + src_ptr[stride + 2]) *
707 0 : (65536 / 6) >>
708 0 : 16;
709 0 : dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + src_ptr[stride + 3] +
710 0 : src_ptr[stride + 4] + src_ptr[stride + 5]) *
711 0 : (65536 / 6) >>
712 0 : 16;
713 0 : dst_ptr[2] =
714 0 : (src_ptr[6] + src_ptr[7] + src_ptr[stride + 6] + src_ptr[stride + 7]) *
715 0 : (65536 / 4) >>
716 0 : 16;
717 0 : src_ptr += 8;
718 0 : dst_ptr += 3;
719 : }
720 0 : }
721 :
722 0 : void ScaleRowDown38_2_Box_16_C(const uint16* src_ptr,
723 : ptrdiff_t src_stride,
724 : uint16* dst_ptr,
725 : int dst_width) {
726 0 : intptr_t stride = src_stride;
727 : int i;
728 0 : assert((dst_width % 3 == 0) && (dst_width > 0));
729 0 : for (i = 0; i < dst_width; i += 3) {
730 0 : dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[stride + 0] +
731 0 : src_ptr[stride + 1] + src_ptr[stride + 2]) *
732 0 : (65536 / 6) >>
733 0 : 16;
734 0 : dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + src_ptr[stride + 3] +
735 0 : src_ptr[stride + 4] + src_ptr[stride + 5]) *
736 0 : (65536 / 6) >>
737 0 : 16;
738 0 : dst_ptr[2] =
739 0 : (src_ptr[6] + src_ptr[7] + src_ptr[stride + 6] + src_ptr[stride + 7]) *
740 0 : (65536 / 4) >>
741 0 : 16;
742 0 : src_ptr += 8;
743 0 : dst_ptr += 3;
744 : }
745 0 : }
746 :
747 0 : void ScaleAddRow_C(const uint8* src_ptr, uint16* dst_ptr, int src_width) {
748 : int x;
749 0 : assert(src_width > 0);
750 0 : for (x = 0; x < src_width - 1; x += 2) {
751 0 : dst_ptr[0] += src_ptr[0];
752 0 : dst_ptr[1] += src_ptr[1];
753 0 : src_ptr += 2;
754 0 : dst_ptr += 2;
755 : }
756 0 : if (src_width & 1) {
757 0 : dst_ptr[0] += src_ptr[0];
758 : }
759 0 : }
760 :
761 0 : void ScaleAddRow_16_C(const uint16* src_ptr, uint32* dst_ptr, int src_width) {
762 : int x;
763 0 : assert(src_width > 0);
764 0 : for (x = 0; x < src_width - 1; x += 2) {
765 0 : dst_ptr[0] += src_ptr[0];
766 0 : dst_ptr[1] += src_ptr[1];
767 0 : src_ptr += 2;
768 0 : dst_ptr += 2;
769 : }
770 0 : if (src_width & 1) {
771 0 : dst_ptr[0] += src_ptr[0];
772 : }
773 0 : }
774 :
775 0 : void ScaleARGBRowDown2_C(const uint8* src_argb,
776 : ptrdiff_t src_stride,
777 : uint8* dst_argb,
778 : int dst_width) {
779 0 : const uint32* src = (const uint32*)(src_argb);
780 0 : uint32* dst = (uint32*)(dst_argb);
781 : int x;
782 : (void)src_stride;
783 0 : for (x = 0; x < dst_width - 1; x += 2) {
784 0 : dst[0] = src[1];
785 0 : dst[1] = src[3];
786 0 : src += 4;
787 0 : dst += 2;
788 : }
789 0 : if (dst_width & 1) {
790 0 : dst[0] = src[1];
791 : }
792 0 : }
793 :
794 0 : void ScaleARGBRowDown2Linear_C(const uint8* src_argb,
795 : ptrdiff_t src_stride,
796 : uint8* dst_argb,
797 : int dst_width) {
798 : int x;
799 : (void)src_stride;
800 0 : for (x = 0; x < dst_width; ++x) {
801 0 : dst_argb[0] = (src_argb[0] + src_argb[4] + 1) >> 1;
802 0 : dst_argb[1] = (src_argb[1] + src_argb[5] + 1) >> 1;
803 0 : dst_argb[2] = (src_argb[2] + src_argb[6] + 1) >> 1;
804 0 : dst_argb[3] = (src_argb[3] + src_argb[7] + 1) >> 1;
805 0 : src_argb += 8;
806 0 : dst_argb += 4;
807 : }
808 0 : }
809 :
810 0 : void ScaleARGBRowDown2Box_C(const uint8* src_argb,
811 : ptrdiff_t src_stride,
812 : uint8* dst_argb,
813 : int dst_width) {
814 : int x;
815 0 : for (x = 0; x < dst_width; ++x) {
816 0 : dst_argb[0] = (src_argb[0] + src_argb[4] + src_argb[src_stride] +
817 0 : src_argb[src_stride + 4] + 2) >>
818 0 : 2;
819 0 : dst_argb[1] = (src_argb[1] + src_argb[5] + src_argb[src_stride + 1] +
820 0 : src_argb[src_stride + 5] + 2) >>
821 0 : 2;
822 0 : dst_argb[2] = (src_argb[2] + src_argb[6] + src_argb[src_stride + 2] +
823 0 : src_argb[src_stride + 6] + 2) >>
824 0 : 2;
825 0 : dst_argb[3] = (src_argb[3] + src_argb[7] + src_argb[src_stride + 3] +
826 0 : src_argb[src_stride + 7] + 2) >>
827 0 : 2;
828 0 : src_argb += 8;
829 0 : dst_argb += 4;
830 : }
831 0 : }
832 :
833 0 : void ScaleARGBRowDownEven_C(const uint8* src_argb,
834 : ptrdiff_t src_stride,
835 : int src_stepx,
836 : uint8* dst_argb,
837 : int dst_width) {
838 0 : const uint32* src = (const uint32*)(src_argb);
839 0 : uint32* dst = (uint32*)(dst_argb);
840 : (void)src_stride;
841 : int x;
842 0 : for (x = 0; x < dst_width - 1; x += 2) {
843 0 : dst[0] = src[0];
844 0 : dst[1] = src[src_stepx];
845 0 : src += src_stepx * 2;
846 0 : dst += 2;
847 : }
848 0 : if (dst_width & 1) {
849 0 : dst[0] = src[0];
850 : }
851 0 : }
852 :
853 0 : void ScaleARGBRowDownEvenBox_C(const uint8* src_argb,
854 : ptrdiff_t src_stride,
855 : int src_stepx,
856 : uint8* dst_argb,
857 : int dst_width) {
858 : int x;
859 0 : for (x = 0; x < dst_width; ++x) {
860 0 : dst_argb[0] = (src_argb[0] + src_argb[4] + src_argb[src_stride] +
861 0 : src_argb[src_stride + 4] + 2) >>
862 0 : 2;
863 0 : dst_argb[1] = (src_argb[1] + src_argb[5] + src_argb[src_stride + 1] +
864 0 : src_argb[src_stride + 5] + 2) >>
865 0 : 2;
866 0 : dst_argb[2] = (src_argb[2] + src_argb[6] + src_argb[src_stride + 2] +
867 0 : src_argb[src_stride + 6] + 2) >>
868 0 : 2;
869 0 : dst_argb[3] = (src_argb[3] + src_argb[7] + src_argb[src_stride + 3] +
870 0 : src_argb[src_stride + 7] + 2) >>
871 0 : 2;
872 0 : src_argb += src_stepx * 4;
873 0 : dst_argb += 4;
874 : }
875 0 : }
876 :
877 : // Scales a single row of pixels using point sampling.
878 0 : void ScaleARGBCols_C(uint8* dst_argb,
879 : const uint8* src_argb,
880 : int dst_width,
881 : int x,
882 : int dx) {
883 0 : const uint32* src = (const uint32*)(src_argb);
884 0 : uint32* dst = (uint32*)(dst_argb);
885 : int j;
886 0 : for (j = 0; j < dst_width - 1; j += 2) {
887 0 : dst[0] = src[x >> 16];
888 0 : x += dx;
889 0 : dst[1] = src[x >> 16];
890 0 : x += dx;
891 0 : dst += 2;
892 : }
893 0 : if (dst_width & 1) {
894 0 : dst[0] = src[x >> 16];
895 : }
896 0 : }
897 :
898 0 : void ScaleARGBCols64_C(uint8* dst_argb,
899 : const uint8* src_argb,
900 : int dst_width,
901 : int x32,
902 : int dx) {
903 0 : int64 x = (int64)(x32);
904 0 : const uint32* src = (const uint32*)(src_argb);
905 0 : uint32* dst = (uint32*)(dst_argb);
906 : int j;
907 0 : for (j = 0; j < dst_width - 1; j += 2) {
908 0 : dst[0] = src[x >> 16];
909 0 : x += dx;
910 0 : dst[1] = src[x >> 16];
911 0 : x += dx;
912 0 : dst += 2;
913 : }
914 0 : if (dst_width & 1) {
915 0 : dst[0] = src[x >> 16];
916 : }
917 0 : }
918 :
919 : // Scales a single row of pixels up by 2x using point sampling.
920 0 : void ScaleARGBColsUp2_C(uint8* dst_argb,
921 : const uint8* src_argb,
922 : int dst_width,
923 : int x,
924 : int dx) {
925 0 : const uint32* src = (const uint32*)(src_argb);
926 0 : uint32* dst = (uint32*)(dst_argb);
927 : int j;
928 : (void)x;
929 : (void)dx;
930 0 : for (j = 0; j < dst_width - 1; j += 2) {
931 0 : dst[1] = dst[0] = src[0];
932 0 : src += 1;
933 0 : dst += 2;
934 : }
935 0 : if (dst_width & 1) {
936 0 : dst[0] = src[0];
937 : }
938 0 : }
939 :
940 : // TODO(fbarchard): Replace 0x7f ^ f with 128-f. bug=607.
941 : // Mimics SSSE3 blender
942 : #define BLENDER1(a, b, f) ((a) * (0x7f ^ f) + (b)*f) >> 7
943 : #define BLENDERC(a, b, f, s) \
944 : (uint32)(BLENDER1(((a) >> s) & 255, ((b) >> s) & 255, f) << s)
945 : #define BLENDER(a, b, f) \
946 : BLENDERC(a, b, f, 24) | BLENDERC(a, b, f, 16) | BLENDERC(a, b, f, 8) | \
947 : BLENDERC(a, b, f, 0)
948 :
949 0 : void ScaleARGBFilterCols_C(uint8* dst_argb,
950 : const uint8* src_argb,
951 : int dst_width,
952 : int x,
953 : int dx) {
954 0 : const uint32* src = (const uint32*)(src_argb);
955 0 : uint32* dst = (uint32*)(dst_argb);
956 : int j;
957 0 : for (j = 0; j < dst_width - 1; j += 2) {
958 0 : int xi = x >> 16;
959 0 : int xf = (x >> 9) & 0x7f;
960 0 : uint32 a = src[xi];
961 0 : uint32 b = src[xi + 1];
962 0 : dst[0] = BLENDER(a, b, xf);
963 0 : x += dx;
964 0 : xi = x >> 16;
965 0 : xf = (x >> 9) & 0x7f;
966 0 : a = src[xi];
967 0 : b = src[xi + 1];
968 0 : dst[1] = BLENDER(a, b, xf);
969 0 : x += dx;
970 0 : dst += 2;
971 : }
972 0 : if (dst_width & 1) {
973 0 : int xi = x >> 16;
974 0 : int xf = (x >> 9) & 0x7f;
975 0 : uint32 a = src[xi];
976 0 : uint32 b = src[xi + 1];
977 0 : dst[0] = BLENDER(a, b, xf);
978 : }
979 0 : }
980 :
981 0 : void ScaleARGBFilterCols64_C(uint8* dst_argb,
982 : const uint8* src_argb,
983 : int dst_width,
984 : int x32,
985 : int dx) {
986 0 : int64 x = (int64)(x32);
987 0 : const uint32* src = (const uint32*)(src_argb);
988 0 : uint32* dst = (uint32*)(dst_argb);
989 : int j;
990 0 : for (j = 0; j < dst_width - 1; j += 2) {
991 0 : int64 xi = x >> 16;
992 0 : int xf = (x >> 9) & 0x7f;
993 0 : uint32 a = src[xi];
994 0 : uint32 b = src[xi + 1];
995 0 : dst[0] = BLENDER(a, b, xf);
996 0 : x += dx;
997 0 : xi = x >> 16;
998 0 : xf = (x >> 9) & 0x7f;
999 0 : a = src[xi];
1000 0 : b = src[xi + 1];
1001 0 : dst[1] = BLENDER(a, b, xf);
1002 0 : x += dx;
1003 0 : dst += 2;
1004 : }
1005 0 : if (dst_width & 1) {
1006 0 : int64 xi = x >> 16;
1007 0 : int xf = (x >> 9) & 0x7f;
1008 0 : uint32 a = src[xi];
1009 0 : uint32 b = src[xi + 1];
1010 0 : dst[0] = BLENDER(a, b, xf);
1011 : }
1012 0 : }
1013 : #undef BLENDER1
1014 : #undef BLENDERC
1015 : #undef BLENDER
1016 :
1017 : // Scale plane vertically with bilinear interpolation.
1018 0 : void ScalePlaneVertical(int src_height,
1019 : int dst_width,
1020 : int dst_height,
1021 : int src_stride,
1022 : int dst_stride,
1023 : const uint8* src_argb,
1024 : uint8* dst_argb,
1025 : int x,
1026 : int y,
1027 : int dy,
1028 : int bpp,
1029 : enum FilterMode filtering) {
1030 : // TODO(fbarchard): Allow higher bpp.
1031 0 : int dst_width_bytes = dst_width * bpp;
1032 : void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb,
1033 : ptrdiff_t src_stride, int dst_width,
1034 0 : int source_y_fraction) = InterpolateRow_C;
1035 0 : const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0;
1036 : int j;
1037 0 : assert(bpp >= 1 && bpp <= 4);
1038 0 : assert(src_height != 0);
1039 0 : assert(dst_width > 0);
1040 0 : assert(dst_height > 0);
1041 0 : src_argb += (x >> 16) * bpp;
1042 : #if defined(HAS_INTERPOLATEROW_SSSE3)
1043 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1044 0 : InterpolateRow = InterpolateRow_Any_SSSE3;
1045 0 : if (IS_ALIGNED(dst_width_bytes, 16)) {
1046 0 : InterpolateRow = InterpolateRow_SSSE3;
1047 : }
1048 : }
1049 : #endif
1050 : #if defined(HAS_INTERPOLATEROW_AVX2)
1051 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1052 0 : InterpolateRow = InterpolateRow_Any_AVX2;
1053 0 : if (IS_ALIGNED(dst_width_bytes, 32)) {
1054 0 : InterpolateRow = InterpolateRow_AVX2;
1055 : }
1056 : }
1057 : #endif
1058 : #if defined(HAS_INTERPOLATEROW_NEON)
1059 : if (TestCpuFlag(kCpuHasNEON)) {
1060 : InterpolateRow = InterpolateRow_Any_NEON;
1061 : if (IS_ALIGNED(dst_width_bytes, 16)) {
1062 : InterpolateRow = InterpolateRow_NEON;
1063 : }
1064 : }
1065 : #endif
1066 : #if defined(HAS_INTERPOLATEROW_DSPR2)
1067 : if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_argb, 4) &&
1068 : IS_ALIGNED(src_stride, 4) && IS_ALIGNED(dst_argb, 4) &&
1069 : IS_ALIGNED(dst_stride, 4)) {
1070 : InterpolateRow = InterpolateRow_Any_DSPR2;
1071 : if (IS_ALIGNED(dst_width_bytes, 4)) {
1072 : InterpolateRow = InterpolateRow_DSPR2;
1073 : }
1074 : }
1075 : #endif
1076 0 : for (j = 0; j < dst_height; ++j) {
1077 : int yi;
1078 : int yf;
1079 0 : if (y > max_y) {
1080 0 : y = max_y;
1081 : }
1082 0 : yi = y >> 16;
1083 0 : yf = filtering ? ((y >> 8) & 255) : 0;
1084 0 : InterpolateRow(dst_argb, src_argb + yi * src_stride, src_stride,
1085 0 : dst_width_bytes, yf);
1086 0 : dst_argb += dst_stride;
1087 0 : y += dy;
1088 : }
1089 0 : }
1090 0 : void ScalePlaneVertical_16(int src_height,
1091 : int dst_width,
1092 : int dst_height,
1093 : int src_stride,
1094 : int dst_stride,
1095 : const uint16* src_argb,
1096 : uint16* dst_argb,
1097 : int x,
1098 : int y,
1099 : int dy,
1100 : int wpp,
1101 : enum FilterMode filtering) {
1102 : // TODO(fbarchard): Allow higher wpp.
1103 0 : int dst_width_words = dst_width * wpp;
1104 : void (*InterpolateRow)(uint16 * dst_argb, const uint16* src_argb,
1105 : ptrdiff_t src_stride, int dst_width,
1106 0 : int source_y_fraction) = InterpolateRow_16_C;
1107 0 : const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0;
1108 : int j;
1109 0 : assert(wpp >= 1 && wpp <= 2);
1110 0 : assert(src_height != 0);
1111 0 : assert(dst_width > 0);
1112 0 : assert(dst_height > 0);
1113 0 : src_argb += (x >> 16) * wpp;
1114 : #if defined(HAS_INTERPOLATEROW_16_SSE2)
1115 : if (TestCpuFlag(kCpuHasSSE2)) {
1116 : InterpolateRow = InterpolateRow_Any_16_SSE2;
1117 : if (IS_ALIGNED(dst_width_bytes, 16)) {
1118 : InterpolateRow = InterpolateRow_16_SSE2;
1119 : }
1120 : }
1121 : #endif
1122 : #if defined(HAS_INTERPOLATEROW_16_SSSE3)
1123 : if (TestCpuFlag(kCpuHasSSSE3)) {
1124 : InterpolateRow = InterpolateRow_Any_16_SSSE3;
1125 : if (IS_ALIGNED(dst_width_bytes, 16)) {
1126 : InterpolateRow = InterpolateRow_16_SSSE3;
1127 : }
1128 : }
1129 : #endif
1130 : #if defined(HAS_INTERPOLATEROW_16_AVX2)
1131 : if (TestCpuFlag(kCpuHasAVX2)) {
1132 : InterpolateRow = InterpolateRow_Any_16_AVX2;
1133 : if (IS_ALIGNED(dst_width_bytes, 32)) {
1134 : InterpolateRow = InterpolateRow_16_AVX2;
1135 : }
1136 : }
1137 : #endif
1138 : #if defined(HAS_INTERPOLATEROW_16_NEON)
1139 : if (TestCpuFlag(kCpuHasNEON)) {
1140 : InterpolateRow = InterpolateRow_Any_16_NEON;
1141 : if (IS_ALIGNED(dst_width_bytes, 16)) {
1142 : InterpolateRow = InterpolateRow_16_NEON;
1143 : }
1144 : }
1145 : #endif
1146 : #if defined(HAS_INTERPOLATEROW_16_DSPR2)
1147 : if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_argb, 4) &&
1148 : IS_ALIGNED(src_stride, 4) && IS_ALIGNED(dst_argb, 4) &&
1149 : IS_ALIGNED(dst_stride, 4)) {
1150 : InterpolateRow = InterpolateRow_Any_16_DSPR2;
1151 : if (IS_ALIGNED(dst_width_bytes, 4)) {
1152 : InterpolateRow = InterpolateRow_16_DSPR2;
1153 : }
1154 : }
1155 : #endif
1156 0 : for (j = 0; j < dst_height; ++j) {
1157 : int yi;
1158 : int yf;
1159 0 : if (y > max_y) {
1160 0 : y = max_y;
1161 : }
1162 0 : yi = y >> 16;
1163 0 : yf = filtering ? ((y >> 8) & 255) : 0;
1164 0 : InterpolateRow(dst_argb, src_argb + yi * src_stride, src_stride,
1165 0 : dst_width_words, yf);
1166 0 : dst_argb += dst_stride;
1167 0 : y += dy;
1168 : }
1169 0 : }
1170 :
1171 : // Simplify the filtering based on scale factors.
1172 0 : enum FilterMode ScaleFilterReduce(int src_width,
1173 : int src_height,
1174 : int dst_width,
1175 : int dst_height,
1176 : enum FilterMode filtering) {
1177 0 : if (src_width < 0) {
1178 0 : src_width = -src_width;
1179 : }
1180 0 : if (src_height < 0) {
1181 0 : src_height = -src_height;
1182 : }
1183 0 : if (filtering == kFilterBox) {
1184 : // If scaling both axis to 0.5 or larger, switch from Box to Bilinear.
1185 0 : if (dst_width * 2 >= src_width && dst_height * 2 >= src_height) {
1186 0 : filtering = kFilterBilinear;
1187 : }
1188 : }
1189 0 : if (filtering == kFilterBilinear) {
1190 0 : if (src_height == 1) {
1191 0 : filtering = kFilterLinear;
1192 : }
1193 : // TODO(fbarchard): Detect any odd scale factor and reduce to Linear.
1194 0 : if (dst_height == src_height || dst_height * 3 == src_height) {
1195 0 : filtering = kFilterLinear;
1196 : }
1197 : // TODO(fbarchard): Remove 1 pixel wide filter restriction, which is to
1198 : // avoid reading 2 pixels horizontally that causes memory exception.
1199 0 : if (src_width == 1) {
1200 0 : filtering = kFilterNone;
1201 : }
1202 : }
1203 0 : if (filtering == kFilterLinear) {
1204 0 : if (src_width == 1) {
1205 0 : filtering = kFilterNone;
1206 : }
1207 : // TODO(fbarchard): Detect any odd scale factor and reduce to None.
1208 0 : if (dst_width == src_width || dst_width * 3 == src_width) {
1209 0 : filtering = kFilterNone;
1210 : }
1211 : }
1212 0 : return filtering;
1213 : }
1214 :
1215 : // Divide num by div and return as 16.16 fixed point result.
1216 0 : int FixedDiv_C(int num, int div) {
1217 0 : return (int)(((int64)(num) << 16) / div);
1218 : }
1219 :
1220 : // Divide num by div and return as 16.16 fixed point result.
1221 0 : int FixedDiv1_C(int num, int div) {
1222 0 : return (int)((((int64)(num) << 16) - 0x00010001) / (div - 1));
1223 : }
1224 :
1225 : #define CENTERSTART(dx, s) (dx < 0) ? -((-dx >> 1) + s) : ((dx >> 1) + s)
1226 :
1227 : // Compute slope values for stepping.
1228 0 : void ScaleSlope(int src_width,
1229 : int src_height,
1230 : int dst_width,
1231 : int dst_height,
1232 : enum FilterMode filtering,
1233 : int* x,
1234 : int* y,
1235 : int* dx,
1236 : int* dy) {
1237 0 : assert(x != NULL);
1238 0 : assert(y != NULL);
1239 0 : assert(dx != NULL);
1240 0 : assert(dy != NULL);
1241 0 : assert(src_width != 0);
1242 0 : assert(src_height != 0);
1243 0 : assert(dst_width > 0);
1244 0 : assert(dst_height > 0);
1245 : // Check for 1 pixel and avoid FixedDiv overflow.
1246 0 : if (dst_width == 1 && src_width >= 32768) {
1247 0 : dst_width = src_width;
1248 : }
1249 0 : if (dst_height == 1 && src_height >= 32768) {
1250 0 : dst_height = src_height;
1251 : }
1252 0 : if (filtering == kFilterBox) {
1253 : // Scale step for point sampling duplicates all pixels equally.
1254 0 : *dx = FixedDiv(Abs(src_width), dst_width);
1255 0 : *dy = FixedDiv(src_height, dst_height);
1256 0 : *x = 0;
1257 0 : *y = 0;
1258 0 : } else if (filtering == kFilterBilinear) {
1259 : // Scale step for bilinear sampling renders last pixel once for upsample.
1260 0 : if (dst_width <= Abs(src_width)) {
1261 0 : *dx = FixedDiv(Abs(src_width), dst_width);
1262 0 : *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
1263 0 : } else if (dst_width > 1) {
1264 0 : *dx = FixedDiv1(Abs(src_width), dst_width);
1265 0 : *x = 0;
1266 : }
1267 0 : if (dst_height <= src_height) {
1268 0 : *dy = FixedDiv(src_height, dst_height);
1269 0 : *y = CENTERSTART(*dy, -32768); // Subtract 0.5 (32768) to center filter.
1270 0 : } else if (dst_height > 1) {
1271 0 : *dy = FixedDiv1(src_height, dst_height);
1272 0 : *y = 0;
1273 : }
1274 0 : } else if (filtering == kFilterLinear) {
1275 : // Scale step for bilinear sampling renders last pixel once for upsample.
1276 0 : if (dst_width <= Abs(src_width)) {
1277 0 : *dx = FixedDiv(Abs(src_width), dst_width);
1278 0 : *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
1279 0 : } else if (dst_width > 1) {
1280 0 : *dx = FixedDiv1(Abs(src_width), dst_width);
1281 0 : *x = 0;
1282 : }
1283 0 : *dy = FixedDiv(src_height, dst_height);
1284 0 : *y = *dy >> 1;
1285 : } else {
1286 : // Scale step for point sampling duplicates all pixels equally.
1287 0 : *dx = FixedDiv(Abs(src_width), dst_width);
1288 0 : *dy = FixedDiv(src_height, dst_height);
1289 0 : *x = CENTERSTART(*dx, 0);
1290 0 : *y = CENTERSTART(*dy, 0);
1291 : }
1292 : // Negative src_width means horizontally mirror.
1293 0 : if (src_width < 0) {
1294 0 : *x += (dst_width - 1) * *dx;
1295 0 : *dx = -*dx;
1296 : // src_width = -src_width; // Caller must do this.
1297 : }
1298 0 : }
1299 : #undef CENTERSTART
1300 :
1301 : #ifdef __cplusplus
1302 : } // extern "C"
1303 : } // namespace libyuv
1304 : #endif
|