xref: /aosp_15_r20/external/libyuv/unit_test/scale_argb_test.cc (revision 4e366538070a3a6c5c163c31b791eab742e1657a)
1*4e366538SXin Li /*
2*4e366538SXin Li  *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
3*4e366538SXin Li  *
4*4e366538SXin Li  *  Use of this source code is governed by a BSD-style license
5*4e366538SXin Li  *  that can be found in the LICENSE file in the root of the source
6*4e366538SXin Li  *  tree. An additional intellectual property rights grant can be found
7*4e366538SXin Li  *  in the file PATENTS. All contributing project authors may
8*4e366538SXin Li  *  be found in the AUTHORS file in the root of the source tree.
9*4e366538SXin Li  */
10*4e366538SXin Li 
11*4e366538SXin Li #include <stdlib.h>
12*4e366538SXin Li #include <time.h>
13*4e366538SXin Li 
14*4e366538SXin Li #include "../unit_test/unit_test.h"
15*4e366538SXin Li #include "libyuv/convert_argb.h"
16*4e366538SXin Li #include "libyuv/cpu_id.h"
17*4e366538SXin Li #include "libyuv/scale_argb.h"
18*4e366538SXin Li #include "libyuv/video_common.h"
19*4e366538SXin Li 
20*4e366538SXin Li namespace libyuv {
21*4e366538SXin Li 
22*4e366538SXin Li #define STRINGIZE(line) #line
23*4e366538SXin Li #define FILELINESTR(file, line) file ":" STRINGIZE(line)
24*4e366538SXin Li 
25*4e366538SXin Li #if !defined(DISABLE_SLOW_TESTS) || defined(__x86_64__) || defined(__i386__)
26*4e366538SXin Li // SLOW TESTS are those that are unoptimized C code.
27*4e366538SXin Li // FULL TESTS are optimized but test many variations of the same code.
28*4e366538SXin Li #define ENABLE_FULL_TESTS
29*4e366538SXin Li #endif
30*4e366538SXin Li 
31*4e366538SXin Li // Test scaling with C vs Opt and return maximum pixel difference. 0 = exact.
ARGBTestFilter(int src_width,int src_height,int dst_width,int dst_height,FilterMode f,int benchmark_iterations,int disable_cpu_flags,int benchmark_cpu_info)32*4e366538SXin Li static int ARGBTestFilter(int src_width,
33*4e366538SXin Li                           int src_height,
34*4e366538SXin Li                           int dst_width,
35*4e366538SXin Li                           int dst_height,
36*4e366538SXin Li                           FilterMode f,
37*4e366538SXin Li                           int benchmark_iterations,
38*4e366538SXin Li                           int disable_cpu_flags,
39*4e366538SXin Li                           int benchmark_cpu_info) {
40*4e366538SXin Li   if (!SizeValid(src_width, src_height, dst_width, dst_height)) {
41*4e366538SXin Li     return 0;
42*4e366538SXin Li   }
43*4e366538SXin Li 
44*4e366538SXin Li   int i, j;
45*4e366538SXin Li   const int b = 0;  // 128 to test for padding/stride.
46*4e366538SXin Li   int64_t src_argb_plane_size =
47*4e366538SXin Li       (Abs(src_width) + b * 2) * (Abs(src_height) + b * 2) * 4LL;
48*4e366538SXin Li   int src_stride_argb = (b * 2 + Abs(src_width)) * 4;
49*4e366538SXin Li 
50*4e366538SXin Li   align_buffer_page_end(src_argb, src_argb_plane_size);
51*4e366538SXin Li   if (!src_argb) {
52*4e366538SXin Li     printf("Skipped.  Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n");
53*4e366538SXin Li     return 0;
54*4e366538SXin Li   }
55*4e366538SXin Li   MemRandomize(src_argb, src_argb_plane_size);
56*4e366538SXin Li 
57*4e366538SXin Li   int64_t dst_argb_plane_size =
58*4e366538SXin Li       (dst_width + b * 2) * (dst_height + b * 2) * 4LL;
59*4e366538SXin Li   int dst_stride_argb = (b * 2 + dst_width) * 4;
60*4e366538SXin Li 
61*4e366538SXin Li   align_buffer_page_end(dst_argb_c, dst_argb_plane_size);
62*4e366538SXin Li   align_buffer_page_end(dst_argb_opt, dst_argb_plane_size);
63*4e366538SXin Li   if (!dst_argb_c || !dst_argb_opt) {
64*4e366538SXin Li     printf("Skipped.  Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n");
65*4e366538SXin Li     return 0;
66*4e366538SXin Li   }
67*4e366538SXin Li   memset(dst_argb_c, 2, dst_argb_plane_size);
68*4e366538SXin Li   memset(dst_argb_opt, 3, dst_argb_plane_size);
69*4e366538SXin Li 
70*4e366538SXin Li   // Warm up both versions for consistent benchmarks.
71*4e366538SXin Li   MaskCpuFlags(disable_cpu_flags);  // Disable all CPU optimization.
72*4e366538SXin Li   ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
73*4e366538SXin Li             src_width, src_height, dst_argb_c + (dst_stride_argb * b) + b * 4,
74*4e366538SXin Li             dst_stride_argb, dst_width, dst_height, f);
75*4e366538SXin Li   MaskCpuFlags(benchmark_cpu_info);  // Enable all CPU optimization.
76*4e366538SXin Li   ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
77*4e366538SXin Li             src_width, src_height, dst_argb_opt + (dst_stride_argb * b) + b * 4,
78*4e366538SXin Li             dst_stride_argb, dst_width, dst_height, f);
79*4e366538SXin Li 
80*4e366538SXin Li   MaskCpuFlags(disable_cpu_flags);  // Disable all CPU optimization.
81*4e366538SXin Li   double c_time = get_time();
82*4e366538SXin Li   ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
83*4e366538SXin Li             src_width, src_height, dst_argb_c + (dst_stride_argb * b) + b * 4,
84*4e366538SXin Li             dst_stride_argb, dst_width, dst_height, f);
85*4e366538SXin Li 
86*4e366538SXin Li   c_time = (get_time() - c_time);
87*4e366538SXin Li 
88*4e366538SXin Li   MaskCpuFlags(benchmark_cpu_info);  // Enable all CPU optimization.
89*4e366538SXin Li   double opt_time = get_time();
90*4e366538SXin Li   for (i = 0; i < benchmark_iterations; ++i) {
91*4e366538SXin Li     ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
92*4e366538SXin Li               src_width, src_height,
93*4e366538SXin Li               dst_argb_opt + (dst_stride_argb * b) + b * 4, dst_stride_argb,
94*4e366538SXin Li               dst_width, dst_height, f);
95*4e366538SXin Li   }
96*4e366538SXin Li   opt_time = (get_time() - opt_time) / benchmark_iterations;
97*4e366538SXin Li 
98*4e366538SXin Li   // Report performance of C vs OPT
99*4e366538SXin Li   printf("filter %d - %8d us C - %8d us OPT\n", f,
100*4e366538SXin Li          static_cast<int>(c_time * 1e6), static_cast<int>(opt_time * 1e6));
101*4e366538SXin Li 
102*4e366538SXin Li   // C version may be a little off from the optimized. Order of
103*4e366538SXin Li   //  operations may introduce rounding somewhere. So do a difference
104*4e366538SXin Li   //  of the buffers and look to see that the max difference isn't
105*4e366538SXin Li   //  over 2.
106*4e366538SXin Li   int max_diff = 0;
107*4e366538SXin Li   for (i = b; i < (dst_height + b); ++i) {
108*4e366538SXin Li     for (j = b * 4; j < (dst_width + b) * 4; ++j) {
109*4e366538SXin Li       int abs_diff = Abs(dst_argb_c[(i * dst_stride_argb) + j] -
110*4e366538SXin Li                          dst_argb_opt[(i * dst_stride_argb) + j]);
111*4e366538SXin Li       if (abs_diff > max_diff) {
112*4e366538SXin Li         max_diff = abs_diff;
113*4e366538SXin Li       }
114*4e366538SXin Li     }
115*4e366538SXin Li   }
116*4e366538SXin Li 
117*4e366538SXin Li   free_aligned_buffer_page_end(dst_argb_c);
118*4e366538SXin Li   free_aligned_buffer_page_end(dst_argb_opt);
119*4e366538SXin Li   free_aligned_buffer_page_end(src_argb);
120*4e366538SXin Li   return max_diff;
121*4e366538SXin Li }
122*4e366538SXin Li 
123*4e366538SXin Li static const int kTileX = 64;
124*4e366538SXin Li static const int kTileY = 64;
125*4e366538SXin Li 
TileARGBScale(const uint8_t * src_argb,int src_stride_argb,int src_width,int src_height,uint8_t * dst_argb,int dst_stride_argb,int dst_width,int dst_height,FilterMode filtering)126*4e366538SXin Li static int TileARGBScale(const uint8_t* src_argb,
127*4e366538SXin Li                          int src_stride_argb,
128*4e366538SXin Li                          int src_width,
129*4e366538SXin Li                          int src_height,
130*4e366538SXin Li                          uint8_t* dst_argb,
131*4e366538SXin Li                          int dst_stride_argb,
132*4e366538SXin Li                          int dst_width,
133*4e366538SXin Li                          int dst_height,
134*4e366538SXin Li                          FilterMode filtering) {
135*4e366538SXin Li   for (int y = 0; y < dst_height; y += kTileY) {
136*4e366538SXin Li     for (int x = 0; x < dst_width; x += kTileX) {
137*4e366538SXin Li       int clip_width = kTileX;
138*4e366538SXin Li       if (x + clip_width > dst_width) {
139*4e366538SXin Li         clip_width = dst_width - x;
140*4e366538SXin Li       }
141*4e366538SXin Li       int clip_height = kTileY;
142*4e366538SXin Li       if (y + clip_height > dst_height) {
143*4e366538SXin Li         clip_height = dst_height - y;
144*4e366538SXin Li       }
145*4e366538SXin Li       int r = ARGBScaleClip(src_argb, src_stride_argb, src_width, src_height,
146*4e366538SXin Li                             dst_argb, dst_stride_argb, dst_width, dst_height, x,
147*4e366538SXin Li                             y, clip_width, clip_height, filtering);
148*4e366538SXin Li       if (r) {
149*4e366538SXin Li         return r;
150*4e366538SXin Li       }
151*4e366538SXin Li     }
152*4e366538SXin Li   }
153*4e366538SXin Li   return 0;
154*4e366538SXin Li }
155*4e366538SXin Li 
ARGBClipTestFilter(int src_width,int src_height,int dst_width,int dst_height,FilterMode f,int benchmark_iterations)156*4e366538SXin Li static int ARGBClipTestFilter(int src_width,
157*4e366538SXin Li                               int src_height,
158*4e366538SXin Li                               int dst_width,
159*4e366538SXin Li                               int dst_height,
160*4e366538SXin Li                               FilterMode f,
161*4e366538SXin Li                               int benchmark_iterations) {
162*4e366538SXin Li   if (!SizeValid(src_width, src_height, dst_width, dst_height)) {
163*4e366538SXin Li     return 0;
164*4e366538SXin Li   }
165*4e366538SXin Li 
166*4e366538SXin Li   const int b = 128;
167*4e366538SXin Li   int64_t src_argb_plane_size =
168*4e366538SXin Li       (Abs(src_width) + b * 2) * (Abs(src_height) + b * 2) * 4;
169*4e366538SXin Li   int src_stride_argb = (b * 2 + Abs(src_width)) * 4;
170*4e366538SXin Li 
171*4e366538SXin Li   align_buffer_page_end(src_argb, src_argb_plane_size);
172*4e366538SXin Li   if (!src_argb) {
173*4e366538SXin Li     printf("Skipped.  Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n");
174*4e366538SXin Li     return 0;
175*4e366538SXin Li   }
176*4e366538SXin Li   memset(src_argb, 1, src_argb_plane_size);
177*4e366538SXin Li 
178*4e366538SXin Li   int64_t dst_argb_plane_size = (dst_width + b * 2) * (dst_height + b * 2) * 4;
179*4e366538SXin Li   int dst_stride_argb = (b * 2 + dst_width) * 4;
180*4e366538SXin Li 
181*4e366538SXin Li   int i, j;
182*4e366538SXin Li   for (i = b; i < (Abs(src_height) + b); ++i) {
183*4e366538SXin Li     for (j = b; j < (Abs(src_width) + b) * 4; ++j) {
184*4e366538SXin Li       src_argb[(i * src_stride_argb) + j] = (fastrand() & 0xff);
185*4e366538SXin Li     }
186*4e366538SXin Li   }
187*4e366538SXin Li 
188*4e366538SXin Li   align_buffer_page_end(dst_argb_c, dst_argb_plane_size);
189*4e366538SXin Li   align_buffer_page_end(dst_argb_opt, dst_argb_plane_size);
190*4e366538SXin Li   if (!dst_argb_c || !dst_argb_opt) {
191*4e366538SXin Li     printf("Skipped.  Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n");
192*4e366538SXin Li     return 0;
193*4e366538SXin Li   }
194*4e366538SXin Li   memset(dst_argb_c, 2, dst_argb_plane_size);
195*4e366538SXin Li   memset(dst_argb_opt, 3, dst_argb_plane_size);
196*4e366538SXin Li 
197*4e366538SXin Li   // Do full image, no clipping.
198*4e366538SXin Li   double c_time = get_time();
199*4e366538SXin Li   ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
200*4e366538SXin Li             src_width, src_height, dst_argb_c + (dst_stride_argb * b) + b * 4,
201*4e366538SXin Li             dst_stride_argb, dst_width, dst_height, f);
202*4e366538SXin Li   c_time = (get_time() - c_time);
203*4e366538SXin Li 
204*4e366538SXin Li   // Do tiled image, clipping scale to a tile at a time.
205*4e366538SXin Li   double opt_time = get_time();
206*4e366538SXin Li   for (i = 0; i < benchmark_iterations; ++i) {
207*4e366538SXin Li     TileARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
208*4e366538SXin Li                   src_width, src_height,
209*4e366538SXin Li                   dst_argb_opt + (dst_stride_argb * b) + b * 4, dst_stride_argb,
210*4e366538SXin Li                   dst_width, dst_height, f);
211*4e366538SXin Li   }
212*4e366538SXin Li   opt_time = (get_time() - opt_time) / benchmark_iterations;
213*4e366538SXin Li 
214*4e366538SXin Li   // Report performance of Full vs Tiled.
215*4e366538SXin Li   printf("filter %d - %8d us Full - %8d us Tiled\n", f,
216*4e366538SXin Li          static_cast<int>(c_time * 1e6), static_cast<int>(opt_time * 1e6));
217*4e366538SXin Li 
218*4e366538SXin Li   // Compare full scaled image vs tiled image.
219*4e366538SXin Li   int max_diff = 0;
220*4e366538SXin Li   for (i = b; i < (dst_height + b); ++i) {
221*4e366538SXin Li     for (j = b * 4; j < (dst_width + b) * 4; ++j) {
222*4e366538SXin Li       int abs_diff = Abs(dst_argb_c[(i * dst_stride_argb) + j] -
223*4e366538SXin Li                          dst_argb_opt[(i * dst_stride_argb) + j]);
224*4e366538SXin Li       if (abs_diff > max_diff) {
225*4e366538SXin Li         max_diff = abs_diff;
226*4e366538SXin Li       }
227*4e366538SXin Li     }
228*4e366538SXin Li   }
229*4e366538SXin Li 
230*4e366538SXin Li   free_aligned_buffer_page_end(dst_argb_c);
231*4e366538SXin Li   free_aligned_buffer_page_end(dst_argb_opt);
232*4e366538SXin Li   free_aligned_buffer_page_end(src_argb);
233*4e366538SXin Li   return max_diff;
234*4e366538SXin Li }
235*4e366538SXin Li 
236*4e366538SXin Li // The following adjustments in dimensions ensure the scale factor will be
237*4e366538SXin Li // exactly achieved.
238*4e366538SXin Li #define DX(x, nom, denom) static_cast<int>((Abs(x) / nom) * nom)
239*4e366538SXin Li #define SX(x, nom, denom) static_cast<int>((x / nom) * denom)
240*4e366538SXin Li 
241*4e366538SXin Li #define TEST_FACTOR1(DISABLED_, name, filter, nom, denom, max_diff)          \
242*4e366538SXin Li   TEST_F(LibYUVScaleTest, ARGBScaleDownBy##name##_##filter) {                \
243*4e366538SXin Li     int diff = ARGBTestFilter(                                               \
244*4e366538SXin Li         SX(benchmark_width_, nom, denom), SX(benchmark_height_, nom, denom), \
245*4e366538SXin Li         DX(benchmark_width_, nom, denom), DX(benchmark_height_, nom, denom), \
246*4e366538SXin Li         kFilter##filter, benchmark_iterations_, disable_cpu_flags_,          \
247*4e366538SXin Li         benchmark_cpu_info_);                                                \
248*4e366538SXin Li     EXPECT_LE(diff, max_diff);                                               \
249*4e366538SXin Li   }                                                                          \
250*4e366538SXin Li   TEST_F(LibYUVScaleTest, DISABLED_##ARGBScaleDownClipBy##name##_##filter) { \
251*4e366538SXin Li     int diff = ARGBClipTestFilter(                                           \
252*4e366538SXin Li         SX(benchmark_width_, nom, denom), SX(benchmark_height_, nom, denom), \
253*4e366538SXin Li         DX(benchmark_width_, nom, denom), DX(benchmark_height_, nom, denom), \
254*4e366538SXin Li         kFilter##filter, benchmark_iterations_);                             \
255*4e366538SXin Li     EXPECT_LE(diff, max_diff);                                               \
256*4e366538SXin Li   }
257*4e366538SXin Li 
258*4e366538SXin Li // Test a scale factor with all 4 filters.  Expect unfiltered to be exact, but
259*4e366538SXin Li // filtering is different fixed point implementations for SSSE3, Neon and C.
260*4e366538SXin Li #ifndef DISABLE_SLOW_TESTS
261*4e366538SXin Li #define TEST_FACTOR(name, nom, denom)           \
262*4e366538SXin Li   TEST_FACTOR1(, name, None, nom, denom, 0)     \
263*4e366538SXin Li   TEST_FACTOR1(, name, Linear, nom, denom, 3)   \
264*4e366538SXin Li   TEST_FACTOR1(, name, Bilinear, nom, denom, 3) \
265*4e366538SXin Li   TEST_FACTOR1(, name, Box, nom, denom, 3)
266*4e366538SXin Li #else
267*4e366538SXin Li #if defined(ENABLE_FULL_TESTS)
268*4e366538SXin Li #define TEST_FACTOR(name, nom, denom)                    \
269*4e366538SXin Li   TEST_FACTOR1(DISABLED_, name, None, nom, denom, 0)     \
270*4e366538SXin Li   TEST_FACTOR1(DISABLED_, name, Linear, nom, denom, 3)   \
271*4e366538SXin Li   TEST_FACTOR1(DISABLED_, name, Bilinear, nom, denom, 3) \
272*4e366538SXin Li   TEST_FACTOR1(DISABLED_, name, Box, nom, denom, 3)
273*4e366538SXin Li #else
274*4e366538SXin Li #define TEST_FACTOR(name, nom, denom) \
275*4e366538SXin Li   TEST_FACTOR1(DISABLED_, name, Bilinear, nom, denom, 3)
276*4e366538SXin Li #endif
277*4e366538SXin Li #endif
278*4e366538SXin Li 
279*4e366538SXin Li TEST_FACTOR(2, 1, 2)
280*4e366538SXin Li TEST_FACTOR(4, 1, 4)
281*4e366538SXin Li #ifndef DISABLE_SLOW_TESTS
282*4e366538SXin Li TEST_FACTOR(8, 1, 8)
283*4e366538SXin Li #endif
284*4e366538SXin Li TEST_FACTOR(3by4, 3, 4)
285*4e366538SXin Li TEST_FACTOR(3by8, 3, 8)
286*4e366538SXin Li TEST_FACTOR(3, 1, 3)
287*4e366538SXin Li #undef TEST_FACTOR1
288*4e366538SXin Li #undef TEST_FACTOR
289*4e366538SXin Li #undef SX
290*4e366538SXin Li #undef DX
291*4e366538SXin Li 
292*4e366538SXin Li #define TEST_SCALETO1(DISABLED_, name, width, height, filter, max_diff)        \
293*4e366538SXin Li   TEST_F(LibYUVScaleTest, name##To##width##x##height##_##filter) {             \
294*4e366538SXin Li     int diff = ARGBTestFilter(benchmark_width_, benchmark_height_, width,      \
295*4e366538SXin Li                               height, kFilter##filter, benchmark_iterations_,  \
296*4e366538SXin Li                               disable_cpu_flags_, benchmark_cpu_info_);        \
297*4e366538SXin Li     EXPECT_LE(diff, max_diff);                                                 \
298*4e366538SXin Li   }                                                                            \
299*4e366538SXin Li   TEST_F(LibYUVScaleTest, name##From##width##x##height##_##filter) {           \
300*4e366538SXin Li     int diff = ARGBTestFilter(width, height, Abs(benchmark_width_),            \
301*4e366538SXin Li                               Abs(benchmark_height_), kFilter##filter,         \
302*4e366538SXin Li                               benchmark_iterations_, disable_cpu_flags_,       \
303*4e366538SXin Li                               benchmark_cpu_info_);                            \
304*4e366538SXin Li     EXPECT_LE(diff, max_diff);                                                 \
305*4e366538SXin Li   }                                                                            \
306*4e366538SXin Li   TEST_F(LibYUVScaleTest,                                                      \
307*4e366538SXin Li          DISABLED_##name##ClipTo##width##x##height##_##filter) {               \
308*4e366538SXin Li     int diff =                                                                 \
309*4e366538SXin Li         ARGBClipTestFilter(benchmark_width_, benchmark_height_, width, height, \
310*4e366538SXin Li                            kFilter##filter, benchmark_iterations_);            \
311*4e366538SXin Li     EXPECT_LE(diff, max_diff);                                                 \
312*4e366538SXin Li   }                                                                            \
313*4e366538SXin Li   TEST_F(LibYUVScaleTest,                                                      \
314*4e366538SXin Li          DISABLED_##name##ClipFrom##width##x##height##_##filter) {             \
315*4e366538SXin Li     int diff = ARGBClipTestFilter(width, height, Abs(benchmark_width_),        \
316*4e366538SXin Li                                   Abs(benchmark_height_), kFilter##filter,     \
317*4e366538SXin Li                                   benchmark_iterations_);                      \
318*4e366538SXin Li     EXPECT_LE(diff, max_diff);                                                 \
319*4e366538SXin Li   }
320*4e366538SXin Li 
321*4e366538SXin Li #ifndef DISABLE_SLOW_TESTS
322*4e366538SXin Li // Test scale to a specified size with all 4 filters.
323*4e366538SXin Li #define TEST_SCALETO(name, width, height)         \
324*4e366538SXin Li   TEST_SCALETO1(, name, width, height, None, 0)   \
325*4e366538SXin Li   TEST_SCALETO1(, name, width, height, Linear, 3) \
326*4e366538SXin Li   TEST_SCALETO1(, name, width, height, Bilinear, 3)
327*4e366538SXin Li #else
328*4e366538SXin Li #if defined(ENABLE_FULL_TESTS)
329*4e366538SXin Li #define TEST_SCALETO(name, width, height)                  \
330*4e366538SXin Li   TEST_SCALETO1(DISABLED_, name, width, height, None, 0)   \
331*4e366538SXin Li   TEST_SCALETO1(DISABLED_, name, width, height, Linear, 3) \
332*4e366538SXin Li   TEST_SCALETO1(DISABLED_, name, width, height, Bilinear, 3)
333*4e366538SXin Li #else
334*4e366538SXin Li #define TEST_SCALETO(name, width, height) \
335*4e366538SXin Li   TEST_SCALETO1(DISABLED_, name, width, height, Bilinear, 3)
336*4e366538SXin Li #endif
337*4e366538SXin Li #endif
338*4e366538SXin Li 
339*4e366538SXin Li TEST_SCALETO(ARGBScale, 1, 1)
340*4e366538SXin Li TEST_SCALETO(ARGBScale, 569, 480)
341*4e366538SXin Li TEST_SCALETO(ARGBScale, 640, 360)
342*4e366538SXin Li #ifndef DISABLE_SLOW_TESTS
343*4e366538SXin Li TEST_SCALETO(ARGBScale, 256, 144) /* 128x72 * 2 */
344*4e366538SXin Li TEST_SCALETO(ARGBScale, 320, 240)
345*4e366538SXin Li TEST_SCALETO(ARGBScale, 1280, 720)
346*4e366538SXin Li TEST_SCALETO(ARGBScale, 1920, 1080)
347*4e366538SXin Li #endif  // DISABLE_SLOW_TESTS
348*4e366538SXin Li #undef TEST_SCALETO1
349*4e366538SXin Li #undef TEST_SCALETO
350*4e366538SXin Li 
351*4e366538SXin Li #define TEST_SCALESWAPXY1(name, filter, max_diff)                       \
352*4e366538SXin Li   TEST_F(LibYUVScaleTest, name##SwapXY_##filter) {                      \
353*4e366538SXin Li     int diff = ARGBTestFilter(benchmark_width_, benchmark_height_,      \
354*4e366538SXin Li                               benchmark_height_, benchmark_width_,      \
355*4e366538SXin Li                               kFilter##filter, benchmark_iterations_,   \
356*4e366538SXin Li                               disable_cpu_flags_, benchmark_cpu_info_); \
357*4e366538SXin Li     EXPECT_LE(diff, max_diff);                                          \
358*4e366538SXin Li   }
359*4e366538SXin Li 
360*4e366538SXin Li #if defined(ENABLE_FULL_TESTS)
361*4e366538SXin Li // Test scale with swapped width and height with all 3 filters.
362*4e366538SXin Li TEST_SCALESWAPXY1(ARGBScale, None, 0)
363*4e366538SXin Li TEST_SCALESWAPXY1(ARGBScale, Linear, 0)
364*4e366538SXin Li TEST_SCALESWAPXY1(ARGBScale, Bilinear, 0)
365*4e366538SXin Li #else
366*4e366538SXin Li TEST_SCALESWAPXY1(ARGBScale, Bilinear, 0)
367*4e366538SXin Li #endif
368*4e366538SXin Li #undef TEST_SCALESWAPXY1
369*4e366538SXin Li 
370*4e366538SXin Li // Scale with YUV conversion to ARGB and clipping.
371*4e366538SXin Li // TODO(fbarchard): Add fourcc support.  All 4 ARGB formats is easy to support.
372*4e366538SXin Li LIBYUV_API
YUVToARGBScaleReference2(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint32_t,int src_width,int src_height,uint8_t * dst_argb,int dst_stride_argb,uint32_t,int dst_width,int dst_height,int clip_x,int clip_y,int clip_width,int clip_height,enum FilterMode filtering)373*4e366538SXin Li int YUVToARGBScaleReference2(const uint8_t* src_y,
374*4e366538SXin Li                              int src_stride_y,
375*4e366538SXin Li                              const uint8_t* src_u,
376*4e366538SXin Li                              int src_stride_u,
377*4e366538SXin Li                              const uint8_t* src_v,
378*4e366538SXin Li                              int src_stride_v,
379*4e366538SXin Li                              uint32_t /* src_fourcc */,
380*4e366538SXin Li                              int src_width,
381*4e366538SXin Li                              int src_height,
382*4e366538SXin Li                              uint8_t* dst_argb,
383*4e366538SXin Li                              int dst_stride_argb,
384*4e366538SXin Li                              uint32_t /* dst_fourcc */,
385*4e366538SXin Li                              int dst_width,
386*4e366538SXin Li                              int dst_height,
387*4e366538SXin Li                              int clip_x,
388*4e366538SXin Li                              int clip_y,
389*4e366538SXin Li                              int clip_width,
390*4e366538SXin Li                              int clip_height,
391*4e366538SXin Li                              enum FilterMode filtering) {
392*4e366538SXin Li   uint8_t* argb_buffer =
393*4e366538SXin Li       static_cast<uint8_t*>(malloc(src_width * src_height * 4));
394*4e366538SXin Li   int r;
395*4e366538SXin Li   I420ToARGB(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
396*4e366538SXin Li              argb_buffer, src_width * 4, src_width, src_height);
397*4e366538SXin Li 
398*4e366538SXin Li   r = ARGBScaleClip(argb_buffer, src_width * 4, src_width, src_height, dst_argb,
399*4e366538SXin Li                     dst_stride_argb, dst_width, dst_height, clip_x, clip_y,
400*4e366538SXin Li                     clip_width, clip_height, filtering);
401*4e366538SXin Li   free(argb_buffer);
402*4e366538SXin Li   return r;
403*4e366538SXin Li }
404*4e366538SXin Li 
FillRamp(uint8_t * buf,int width,int height,int v,int dx,int dy)405*4e366538SXin Li static void FillRamp(uint8_t* buf,
406*4e366538SXin Li                      int width,
407*4e366538SXin Li                      int height,
408*4e366538SXin Li                      int v,
409*4e366538SXin Li                      int dx,
410*4e366538SXin Li                      int dy) {
411*4e366538SXin Li   int rv = v;
412*4e366538SXin Li   for (int y = 0; y < height; ++y) {
413*4e366538SXin Li     for (int x = 0; x < width; ++x) {
414*4e366538SXin Li       *buf++ = v;
415*4e366538SXin Li       v += dx;
416*4e366538SXin Li       if (v < 0 || v > 255) {
417*4e366538SXin Li         dx = -dx;
418*4e366538SXin Li         v += dx;
419*4e366538SXin Li       }
420*4e366538SXin Li     }
421*4e366538SXin Li     v = rv + dy;
422*4e366538SXin Li     if (v < 0 || v > 255) {
423*4e366538SXin Li       dy = -dy;
424*4e366538SXin Li       v += dy;
425*4e366538SXin Li     }
426*4e366538SXin Li     rv = v;
427*4e366538SXin Li   }
428*4e366538SXin Li }
429*4e366538SXin Li 
430*4e366538SXin Li // Test scaling with C vs Opt and return maximum pixel difference. 0 = exact.
YUVToARGBTestFilter(int src_width,int src_height,int dst_width,int dst_height,FilterMode f,int benchmark_iterations)431*4e366538SXin Li static int YUVToARGBTestFilter(int src_width,
432*4e366538SXin Li                                int src_height,
433*4e366538SXin Li                                int dst_width,
434*4e366538SXin Li                                int dst_height,
435*4e366538SXin Li                                FilterMode f,
436*4e366538SXin Li                                int benchmark_iterations) {
437*4e366538SXin Li   int64_t src_y_plane_size = Abs(src_width) * Abs(src_height);
438*4e366538SXin Li   int64_t src_uv_plane_size =
439*4e366538SXin Li       ((Abs(src_width) + 1) / 2) * ((Abs(src_height) + 1) / 2);
440*4e366538SXin Li   int src_stride_y = Abs(src_width);
441*4e366538SXin Li   int src_stride_uv = (Abs(src_width) + 1) / 2;
442*4e366538SXin Li 
443*4e366538SXin Li   align_buffer_page_end(src_y, src_y_plane_size);
444*4e366538SXin Li   align_buffer_page_end(src_u, src_uv_plane_size);
445*4e366538SXin Li   align_buffer_page_end(src_v, src_uv_plane_size);
446*4e366538SXin Li 
447*4e366538SXin Li   int64_t dst_argb_plane_size = (dst_width) * (dst_height)*4LL;
448*4e366538SXin Li   int dst_stride_argb = (dst_width)*4;
449*4e366538SXin Li   align_buffer_page_end(dst_argb_c, dst_argb_plane_size);
450*4e366538SXin Li   align_buffer_page_end(dst_argb_opt, dst_argb_plane_size);
451*4e366538SXin Li   if (!dst_argb_c || !dst_argb_opt || !src_y || !src_u || !src_v) {
452*4e366538SXin Li     printf("Skipped.  Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n");
453*4e366538SXin Li     return 0;
454*4e366538SXin Li   }
455*4e366538SXin Li   // Fill YUV image with continuous ramp, which is less sensitive to
456*4e366538SXin Li   // subsampling and filtering differences for test purposes.
457*4e366538SXin Li   FillRamp(src_y, Abs(src_width), Abs(src_height), 128, 1, 1);
458*4e366538SXin Li   FillRamp(src_u, (Abs(src_width) + 1) / 2, (Abs(src_height) + 1) / 2, 3, 1, 1);
459*4e366538SXin Li   FillRamp(src_v, (Abs(src_width) + 1) / 2, (Abs(src_height) + 1) / 2, 4, 1, 1);
460*4e366538SXin Li   memset(dst_argb_c, 2, dst_argb_plane_size);
461*4e366538SXin Li   memset(dst_argb_opt, 3, dst_argb_plane_size);
462*4e366538SXin Li 
463*4e366538SXin Li   YUVToARGBScaleReference2(src_y, src_stride_y, src_u, src_stride_uv, src_v,
464*4e366538SXin Li                            src_stride_uv, libyuv::FOURCC_I420, src_width,
465*4e366538SXin Li                            src_height, dst_argb_c, dst_stride_argb,
466*4e366538SXin Li                            libyuv::FOURCC_I420, dst_width, dst_height, 0, 0,
467*4e366538SXin Li                            dst_width, dst_height, f);
468*4e366538SXin Li 
469*4e366538SXin Li   for (int i = 0; i < benchmark_iterations; ++i) {
470*4e366538SXin Li     YUVToARGBScaleClip(src_y, src_stride_y, src_u, src_stride_uv, src_v,
471*4e366538SXin Li                        src_stride_uv, libyuv::FOURCC_I420, src_width,
472*4e366538SXin Li                        src_height, dst_argb_opt, dst_stride_argb,
473*4e366538SXin Li                        libyuv::FOURCC_I420, dst_width, dst_height, 0, 0,
474*4e366538SXin Li                        dst_width, dst_height, f);
475*4e366538SXin Li   }
476*4e366538SXin Li   int max_diff = 0;
477*4e366538SXin Li   for (int i = 0; i < dst_height; ++i) {
478*4e366538SXin Li     for (int j = 0; j < dst_width * 4; ++j) {
479*4e366538SXin Li       int abs_diff = Abs(dst_argb_c[(i * dst_stride_argb) + j] -
480*4e366538SXin Li                          dst_argb_opt[(i * dst_stride_argb) + j]);
481*4e366538SXin Li       if (abs_diff > max_diff) {
482*4e366538SXin Li         printf("error %d at %d,%d c %d opt %d", abs_diff, j, i,
483*4e366538SXin Li                dst_argb_c[(i * dst_stride_argb) + j],
484*4e366538SXin Li                dst_argb_opt[(i * dst_stride_argb) + j]);
485*4e366538SXin Li         EXPECT_LE(abs_diff, 40);
486*4e366538SXin Li         max_diff = abs_diff;
487*4e366538SXin Li       }
488*4e366538SXin Li     }
489*4e366538SXin Li   }
490*4e366538SXin Li 
491*4e366538SXin Li   free_aligned_buffer_page_end(dst_argb_c);
492*4e366538SXin Li   free_aligned_buffer_page_end(dst_argb_opt);
493*4e366538SXin Li   free_aligned_buffer_page_end(src_y);
494*4e366538SXin Li   free_aligned_buffer_page_end(src_u);
495*4e366538SXin Li   free_aligned_buffer_page_end(src_v);
496*4e366538SXin Li   return max_diff;
497*4e366538SXin Li }
498*4e366538SXin Li 
TEST_F(LibYUVScaleTest,YUVToRGBScaleUp)499*4e366538SXin Li TEST_F(LibYUVScaleTest, YUVToRGBScaleUp) {
500*4e366538SXin Li   int diff =
501*4e366538SXin Li       YUVToARGBTestFilter(benchmark_width_, benchmark_height_,
502*4e366538SXin Li                           benchmark_width_ * 3 / 2, benchmark_height_ * 3 / 2,
503*4e366538SXin Li                           libyuv::kFilterBilinear, benchmark_iterations_);
504*4e366538SXin Li   EXPECT_LE(diff, 10);
505*4e366538SXin Li }
506*4e366538SXin Li 
TEST_F(LibYUVScaleTest,YUVToRGBScaleDown)507*4e366538SXin Li TEST_F(LibYUVScaleTest, YUVToRGBScaleDown) {
508*4e366538SXin Li   int diff = YUVToARGBTestFilter(
509*4e366538SXin Li       benchmark_width_ * 3 / 2, benchmark_height_ * 3 / 2, benchmark_width_,
510*4e366538SXin Li       benchmark_height_, libyuv::kFilterBilinear, benchmark_iterations_);
511*4e366538SXin Li   EXPECT_LE(diff, 10);
512*4e366538SXin Li }
513*4e366538SXin Li 
TEST_F(LibYUVScaleTest,ARGBTest3x)514*4e366538SXin Li TEST_F(LibYUVScaleTest, ARGBTest3x) {
515*4e366538SXin Li   const int kSrcStride = 480 * 4;
516*4e366538SXin Li   const int kDstStride = 160 * 4;
517*4e366538SXin Li   const int kSize = kSrcStride * 3;
518*4e366538SXin Li   align_buffer_page_end(orig_pixels, kSize);
519*4e366538SXin Li   for (int i = 0; i < 480 * 3; ++i) {
520*4e366538SXin Li     orig_pixels[i * 4 + 0] = i;
521*4e366538SXin Li     orig_pixels[i * 4 + 1] = 255 - i;
522*4e366538SXin Li     orig_pixels[i * 4 + 2] = i + 1;
523*4e366538SXin Li     orig_pixels[i * 4 + 3] = i + 10;
524*4e366538SXin Li   }
525*4e366538SXin Li   align_buffer_page_end(dest_pixels, kDstStride);
526*4e366538SXin Li 
527*4e366538SXin Li   int iterations160 = (benchmark_width_ * benchmark_height_ + (160 - 1)) / 160 *
528*4e366538SXin Li                       benchmark_iterations_;
529*4e366538SXin Li   for (int i = 0; i < iterations160; ++i) {
530*4e366538SXin Li     ARGBScale(orig_pixels, kSrcStride, 480, 3, dest_pixels, kDstStride, 160, 1,
531*4e366538SXin Li               kFilterBilinear);
532*4e366538SXin Li   }
533*4e366538SXin Li 
534*4e366538SXin Li   EXPECT_EQ(225, dest_pixels[0]);
535*4e366538SXin Li   EXPECT_EQ(255 - 225, dest_pixels[1]);
536*4e366538SXin Li   EXPECT_EQ(226, dest_pixels[2]);
537*4e366538SXin Li   EXPECT_EQ(235, dest_pixels[3]);
538*4e366538SXin Li 
539*4e366538SXin Li   ARGBScale(orig_pixels, kSrcStride, 480, 3, dest_pixels, kDstStride, 160, 1,
540*4e366538SXin Li             kFilterNone);
541*4e366538SXin Li 
542*4e366538SXin Li   EXPECT_EQ(225, dest_pixels[0]);
543*4e366538SXin Li   EXPECT_EQ(255 - 225, dest_pixels[1]);
544*4e366538SXin Li   EXPECT_EQ(226, dest_pixels[2]);
545*4e366538SXin Li   EXPECT_EQ(235, dest_pixels[3]);
546*4e366538SXin Li 
547*4e366538SXin Li   free_aligned_buffer_page_end(dest_pixels);
548*4e366538SXin Li   free_aligned_buffer_page_end(orig_pixels);
549*4e366538SXin Li }
550*4e366538SXin Li 
TEST_F(LibYUVScaleTest,ARGBTest4x)551*4e366538SXin Li TEST_F(LibYUVScaleTest, ARGBTest4x) {
552*4e366538SXin Li   const int kSrcStride = 640 * 4;
553*4e366538SXin Li   const int kDstStride = 160 * 4;
554*4e366538SXin Li   const int kSize = kSrcStride * 4;
555*4e366538SXin Li   align_buffer_page_end(orig_pixels, kSize);
556*4e366538SXin Li   for (int i = 0; i < 640 * 4; ++i) {
557*4e366538SXin Li     orig_pixels[i * 4 + 0] = i;
558*4e366538SXin Li     orig_pixels[i * 4 + 1] = 255 - i;
559*4e366538SXin Li     orig_pixels[i * 4 + 2] = i + 1;
560*4e366538SXin Li     orig_pixels[i * 4 + 3] = i + 10;
561*4e366538SXin Li   }
562*4e366538SXin Li   align_buffer_page_end(dest_pixels, kDstStride);
563*4e366538SXin Li 
564*4e366538SXin Li   int iterations160 = (benchmark_width_ * benchmark_height_ + (160 - 1)) / 160 *
565*4e366538SXin Li                       benchmark_iterations_;
566*4e366538SXin Li   for (int i = 0; i < iterations160; ++i) {
567*4e366538SXin Li     ARGBScale(orig_pixels, kSrcStride, 640, 4, dest_pixels, kDstStride, 160, 1,
568*4e366538SXin Li               kFilterBilinear);
569*4e366538SXin Li   }
570*4e366538SXin Li 
571*4e366538SXin Li   EXPECT_NEAR(66, dest_pixels[0], 4);
572*4e366538SXin Li   EXPECT_NEAR(255 - 66, dest_pixels[1], 4);
573*4e366538SXin Li   EXPECT_NEAR(67, dest_pixels[2], 4);
574*4e366538SXin Li   EXPECT_NEAR(76, dest_pixels[3], 4);
575*4e366538SXin Li 
576*4e366538SXin Li   ARGBScale(orig_pixels, kSrcStride, 640, 4, dest_pixels, kDstStride, 160, 1,
577*4e366538SXin Li             kFilterNone);
578*4e366538SXin Li 
579*4e366538SXin Li   EXPECT_EQ(2, dest_pixels[0]);
580*4e366538SXin Li   EXPECT_EQ(255 - 2, dest_pixels[1]);
581*4e366538SXin Li   EXPECT_EQ(3, dest_pixels[2]);
582*4e366538SXin Li   EXPECT_EQ(12, dest_pixels[3]);
583*4e366538SXin Li 
584*4e366538SXin Li   free_aligned_buffer_page_end(dest_pixels);
585*4e366538SXin Li   free_aligned_buffer_page_end(orig_pixels);
586*4e366538SXin Li }
587*4e366538SXin Li 
588*4e366538SXin Li }  // namespace libyuv
589