Home | History | Annotate | Download | only in unit_test
      1 /*
      2  *  Copyright 2011 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 <stdlib.h>
     12 #include <time.h>
     13 
     14 #include "libyuv/cpu_id.h"
     15 #include "libyuv/scale.h"
     16 #include "../unit_test/unit_test.h"
     17 
     18 namespace libyuv {
     19 
     20 static int TestFilter(int src_width, int src_height,
     21                       int dst_width, int dst_height,
     22                       FilterMode f, int rounding, int benchmark_iterations) {
     23   const int b = 128 * rounding;
     24   int src_width_uv = (src_width + rounding) >> 1;
     25   int src_height_uv = (src_height + rounding) >> 1;
     26 
     27   int src_y_plane_size = (src_width + b * 2) * (src_height + b * 2);
     28   int src_uv_plane_size = (src_width_uv + b * 2) * (src_height_uv + b * 2);
     29 
     30   int src_stride_y = b * 2 + src_width;
     31   int src_stride_uv = b * 2 + src_width_uv;
     32 
     33   align_buffer_page_end(src_y, src_y_plane_size)
     34   align_buffer_page_end(src_u, src_uv_plane_size)
     35   align_buffer_page_end(src_v, src_uv_plane_size)
     36 
     37   int dst_width_uv = (dst_width + rounding) >> 1;
     38   int dst_height_uv = (dst_height + rounding) >> 1;
     39 
     40   int dst_y_plane_size = (dst_width + b * 2) * (dst_height + b * 2);
     41   int dst_uv_plane_size = (dst_width_uv + b * 2) * (dst_height_uv + b * 2);
     42 
     43   int dst_stride_y = b * 2 + dst_width;
     44   int dst_stride_uv = b * 2 + dst_width_uv;
     45 
     46   srandom(time(NULL));
     47 
     48   int i, j;
     49   for (i = b; i < (src_height + b); ++i) {
     50     for (j = b; j < (src_width + b); ++j) {
     51       src_y[(i * src_stride_y) + j] = (random() & 0xff);
     52     }
     53   }
     54 
     55   for (i = b; i < (src_height_uv + b); ++i) {
     56     for (j = b; j < (src_width_uv + b); ++j) {
     57       src_u[(i * src_stride_uv) + j] = (random() & 0xff);
     58       src_v[(i * src_stride_uv) + j] = (random() & 0xff);
     59     }
     60   }
     61 
     62   align_buffer_page_end(dst_y_c, dst_y_plane_size)
     63   align_buffer_page_end(dst_u_c, dst_uv_plane_size)
     64   align_buffer_page_end(dst_v_c, dst_uv_plane_size)
     65   align_buffer_page_end(dst_y_opt, dst_y_plane_size)
     66   align_buffer_page_end(dst_u_opt, dst_uv_plane_size)
     67   align_buffer_page_end(dst_v_opt, dst_uv_plane_size)
     68 
     69   // Warm up both versions for consistent benchmarks.
     70   MaskCpuFlags(0);  // Disable all CPU optimization.
     71   I420Scale(src_y + (src_stride_y * b) + b, src_stride_y,
     72             src_u + (src_stride_uv * b) + b, src_stride_uv,
     73             src_v + (src_stride_uv * b) + b, src_stride_uv,
     74             src_width, src_height,
     75             dst_y_c + (dst_stride_y * b) + b, dst_stride_y,
     76             dst_u_c + (dst_stride_uv * b) + b, dst_stride_uv,
     77             dst_v_c + (dst_stride_uv * b) + b, dst_stride_uv,
     78             dst_width, dst_height, f);
     79   MaskCpuFlags(-1);  // Enable all CPU optimization.
     80   I420Scale(src_y + (src_stride_y * b) + b, src_stride_y,
     81             src_u + (src_stride_uv * b) + b, src_stride_uv,
     82             src_v + (src_stride_uv * b) + b, src_stride_uv,
     83             src_width, src_height,
     84             dst_y_opt + (dst_stride_y * b) + b, dst_stride_y,
     85             dst_u_opt + (dst_stride_uv * b) + b, dst_stride_uv,
     86             dst_v_opt + (dst_stride_uv * b) + b, dst_stride_uv,
     87             dst_width, dst_height, f);
     88 
     89   MaskCpuFlags(0);  // Disable all CPU optimization.
     90   double c_time = get_time();
     91   for (i = 0; i < benchmark_iterations; ++i) {
     92     I420Scale(src_y + (src_stride_y * b) + b, src_stride_y,
     93               src_u + (src_stride_uv * b) + b, src_stride_uv,
     94               src_v + (src_stride_uv * b) + b, src_stride_uv,
     95               src_width, src_height,
     96               dst_y_c + (dst_stride_y * b) + b, dst_stride_y,
     97               dst_u_c + (dst_stride_uv * b) + b, dst_stride_uv,
     98               dst_v_c + (dst_stride_uv * b) + b, dst_stride_uv,
     99               dst_width, dst_height, f);
    100   }
    101   c_time = (get_time() - c_time) / benchmark_iterations;
    102 
    103   MaskCpuFlags(-1);  // Enable all CPU optimization.
    104   double opt_time = get_time();
    105   for (i = 0; i < benchmark_iterations; ++i) {
    106     I420Scale(src_y + (src_stride_y * b) + b, src_stride_y,
    107               src_u + (src_stride_uv * b) + b, src_stride_uv,
    108               src_v + (src_stride_uv * b) + b, src_stride_uv,
    109               src_width, src_height,
    110               dst_y_opt + (dst_stride_y * b) + b, dst_stride_y,
    111               dst_u_opt + (dst_stride_uv * b) + b, dst_stride_uv,
    112               dst_v_opt + (dst_stride_uv * b) + b, dst_stride_uv,
    113               dst_width, dst_height, f);
    114   }
    115   opt_time = (get_time() - opt_time) / benchmark_iterations;
    116 
    117   // Report performance of C vs OPT
    118   printf("filter %d - %8d us C - %8d us OPT\n",
    119          f, static_cast<int>(c_time*1e6), static_cast<int>(opt_time*1e6));
    120 
    121   // C version may be a little off from the optimized. Order of
    122   //  operations may introduce rounding somewhere. So do a difference
    123   //  of the buffers and look to see that the max difference isn't
    124   //  over 2.
    125   int max_diff = 0;
    126   for (i = b; i < (dst_height + b); ++i) {
    127     for (j = b; j < (dst_width + b); ++j) {
    128       int abs_diff = abs(dst_y_c[(i * dst_stride_y) + j] -
    129                          dst_y_opt[(i * dst_stride_y) + j]);
    130       if (abs_diff > max_diff) {
    131         max_diff = abs_diff;
    132       }
    133     }
    134   }
    135 
    136   for (i = b; i < (dst_height_uv + b); ++i) {
    137     for (j = b; j < (dst_width_uv + b); ++j) {
    138       int abs_diff = abs(dst_u_c[(i * dst_stride_uv) + j] -
    139                          dst_u_opt[(i * dst_stride_uv) + j]);
    140       if (abs_diff > max_diff) {
    141         max_diff = abs_diff;
    142       }
    143       abs_diff = abs(dst_v_c[(i * dst_stride_uv) + j] -
    144                      dst_v_opt[(i * dst_stride_uv) + j]);
    145       if (abs_diff > max_diff) {
    146         max_diff = abs_diff;
    147       }
    148     }
    149   }
    150 
    151   free_aligned_buffer_page_end(dst_y_c)
    152   free_aligned_buffer_page_end(dst_u_c)
    153   free_aligned_buffer_page_end(dst_v_c)
    154   free_aligned_buffer_page_end(dst_y_opt)
    155   free_aligned_buffer_page_end(dst_u_opt)
    156   free_aligned_buffer_page_end(dst_v_opt)
    157 
    158   free_aligned_buffer_page_end(src_y)
    159   free_aligned_buffer_page_end(src_u)
    160   free_aligned_buffer_page_end(src_v)
    161 
    162   return max_diff;
    163 }
    164 
    165 TEST_F(libyuvTest, ScaleDownBy2) {
    166   const int src_width = 1280;
    167   const int src_height = 720;
    168   const int dst_width = src_width / 2;
    169   const int dst_height = src_height / 2;
    170 
    171   for (int f = 0; f < 3; ++f) {
    172     int max_diff = TestFilter(src_width, src_height,
    173                               dst_width, dst_height,
    174                               static_cast<FilterMode>(f), 1,
    175                               benchmark_iterations_);
    176     EXPECT_LE(max_diff, 1);
    177   }
    178 }
    179 
    180 TEST_F(libyuvTest, ScaleDownBy4) {
    181   const int src_width = 1280;
    182   const int src_height = 720;
    183   const int dst_width = src_width / 4;
    184   const int dst_height = src_height / 4;
    185 
    186   for (int f = 0; f < 3; ++f) {
    187     int max_diff = TestFilter(src_width, src_height,
    188                               dst_width, dst_height,
    189                               static_cast<FilterMode>(f), 1,
    190                               benchmark_iterations_);
    191     EXPECT_LE(max_diff, 2);  // This is the only scale factor with error of 2.
    192   }
    193 }
    194 
    195 TEST_F(libyuvTest, ScaleDownBy5) {
    196   const int src_width = 1280;
    197   const int src_height = 720;
    198   const int dst_width = src_width / 5;
    199   const int dst_height = src_height / 5;
    200 
    201   for (int f = 0; f < 3; ++f) {
    202     int max_diff = TestFilter(src_width, src_height,
    203                               dst_width, dst_height,
    204                               static_cast<FilterMode>(f), 1,
    205                               benchmark_iterations_);
    206     EXPECT_LE(max_diff, 1);
    207   }
    208 }
    209 
    210 TEST_F(libyuvTest, ScaleDownBy8) {
    211   const int src_width = 1280;
    212   const int src_height = 720;
    213   const int dst_width = src_width / 8;
    214   const int dst_height = src_height / 8;
    215 
    216   for (int f = 0; f < 3; ++f) {
    217     int max_diff = TestFilter(src_width, src_height,
    218                               dst_width, dst_height,
    219                               static_cast<FilterMode>(f), 1,
    220                               benchmark_iterations_);
    221     EXPECT_LE(max_diff, 1);
    222   }
    223 }
    224 
    225 TEST_F(libyuvTest, ScaleDownBy16) {
    226   const int src_width = 1280;
    227   const int src_height = 720;
    228   const int dst_width = src_width / 16;
    229   const int dst_height = src_height / 16;
    230 
    231   for (int f = 0; f < 3; ++f) {
    232     int max_diff = TestFilter(src_width, src_height,
    233                               dst_width, dst_height,
    234                               static_cast<FilterMode>(f), 1,
    235                               benchmark_iterations_);
    236     EXPECT_LE(max_diff, 1);
    237   }
    238 }
    239 
    240 TEST_F(libyuvTest, ScaleDownBy34) {
    241   const int src_width = 1280;
    242   const int src_height = 720;
    243   const int dst_width = src_width * 3 / 4;
    244   const int dst_height = src_height * 3 / 4;
    245 
    246   for (int f = 0; f < 3; ++f) {
    247     int max_diff = TestFilter(src_width, src_height,
    248                               dst_width, dst_height,
    249                               static_cast<FilterMode>(f), 1,
    250                               benchmark_iterations_);
    251     EXPECT_LE(max_diff, 1);
    252   }
    253 }
    254 
    255 TEST_F(libyuvTest, ScaleDownBy38) {
    256   int src_width = 1280;
    257   int src_height = 720;
    258   int dst_width = src_width * 3 / 8;
    259   int dst_height = src_height * 3 / 8;
    260 
    261   for (int f = 0; f < 3; ++f) {
    262     int max_diff = TestFilter(src_width, src_height,
    263                               dst_width, dst_height,
    264                               static_cast<FilterMode>(f), 1,
    265                               benchmark_iterations_);
    266     EXPECT_LE(max_diff, 1);
    267   }
    268 }
    269 
    270 TEST_F(libyuvTest, ScaleTo1366) {
    271   int src_width = 1280;
    272   int src_height = 720;
    273   int dst_width = 1366;
    274   int dst_height = 768;
    275 
    276   for (int f = 0; f < 3; ++f) {
    277     int max_diff = TestFilter(src_width, src_height,
    278                               dst_width, dst_height,
    279                               static_cast<FilterMode>(f), 1,
    280                               benchmark_iterations_);
    281     EXPECT_LE(max_diff, 1);
    282   }
    283 }
    284 
    285 TEST_F(libyuvTest, ScaleTo4074) {
    286   int src_width = 2880 * 2;
    287   int src_height = 1800;
    288   int dst_width = 4074;
    289   int dst_height = 1272;
    290 
    291   for (int f = 0; f < 3; ++f) {
    292     int max_diff = TestFilter(src_width, src_height,
    293                               dst_width, dst_height,
    294                               static_cast<FilterMode>(f), 1,
    295                               benchmark_iterations_);
    296     EXPECT_LE(max_diff, 1);
    297   }
    298 }
    299 
    300 TEST_F(libyuvTest, ScaleTo853) {
    301   int src_width = 1280;
    302   int src_height = 720;
    303   int dst_width = 853;
    304   int dst_height = 480;
    305 
    306   for (int f = 0; f < 3; ++f) {
    307     int max_diff = TestFilter(src_width, src_height,
    308                               dst_width, dst_height,
    309                               static_cast<FilterMode>(f), 1,
    310                               benchmark_iterations_);
    311     EXPECT_LE(max_diff, 1);
    312   }
    313 }
    314 
    315 TEST_F(libyuvTest, ScaleTo853Wrong) {
    316   int src_width = 1280;
    317   int src_height = 720;
    318   int dst_width = 853;
    319   int dst_height = 480;
    320 
    321   for (int f = 0; f < 3; ++f) {
    322     int max_diff = TestFilter(src_width, src_height,
    323                               dst_width, dst_height,
    324                               static_cast<FilterMode>(f), 0,
    325                               benchmark_iterations_);
    326     EXPECT_LE(max_diff, 1);
    327   }
    328 }
    329 
    330 // A one off test for a screen cast resolution scale.
    331 TEST_F(libyuvTest, ScaleTo684) {
    332   int src_width = 686;
    333   int src_height = 557;
    334   int dst_width = 684;
    335   int dst_height = 552;
    336 
    337   for (int f = 0; f < 3; ++f) {
    338     int max_diff = TestFilter(src_width, src_height,
    339                               dst_width, dst_height,
    340                               static_cast<FilterMode>(f), 1,
    341                               benchmark_iterations_);
    342     EXPECT_LE(max_diff, 1);
    343   }
    344 }
    345 
    346 TEST_F(libyuvTest, ScaleTo342) {
    347   int src_width = 686;
    348   int src_height = 557;
    349   int dst_width = 342;
    350   int dst_height = 276;
    351 
    352   for (int f = 0; f < 3; ++f) {
    353     int max_diff = TestFilter(src_width, src_height,
    354                               dst_width, dst_height,
    355                               static_cast<FilterMode>(f), 1,
    356                               benchmark_iterations_);
    357     EXPECT_LE(max_diff, 1);
    358   }
    359 }
    360 
    361 TEST_F(libyuvTest, ScaleToHalf342) {
    362   int src_width = 684;
    363   int src_height = 552;
    364   int dst_width = 342;
    365   int dst_height = 276;
    366 
    367   for (int f = 0; f < 3; ++f) {
    368     int max_diff = TestFilter(src_width, src_height,
    369                               dst_width, dst_height,
    370                               static_cast<FilterMode>(f), 1,
    371                               benchmark_iterations_);
    372     EXPECT_LE(max_diff, 1);
    373   }
    374 }
    375 
    376 }  // namespace libyuv
    377