scale_test.cc 7.76 KB
Newer Older
1
/*
2
 *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 4 5 6
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS. All contributing project authors may
8 9 10 11 12 13
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdlib.h>
#include <time.h>

frkoenig@google.com's avatar
frkoenig@google.com committed
14 15
#include "libyuv/cpu_id.h"
#include "libyuv/scale.h"
16
#include "../unit_test/unit_test.h"
frkoenig@google.com's avatar
frkoenig@google.com committed
17

mikhal@webrtc.org's avatar
mikhal@webrtc.org committed
18
namespace libyuv {
19

20
// Test scaling with C vs Opt and return maximum pixel difference. 0 = exact.
21 22
static int TestFilter(int src_width, int src_height,
                      int dst_width, int dst_height,
23
                      FilterMode f, int benchmark_iterations) {
24
  int i, j;
25
  const int b = 128;
26 27
  int src_width_uv = (Abs(src_width) + 1) >> 1;
  int src_height_uv = (Abs(src_height) + 1) >> 1;
28

29
  int src_y_plane_size = (Abs(src_width) + b * 2) * (Abs(src_height) + b * 2);
30
  int src_uv_plane_size = (src_width_uv + b * 2) * (src_height_uv + b * 2);
31

fbarchard@google.com's avatar
fbarchard@google.com committed
32
  int src_stride_y = b * 2 + Abs(src_width);
33
  int src_stride_uv = b * 2 + src_width_uv;
34

35 36 37
  align_buffer_page_end(src_y, src_y_plane_size)
  align_buffer_page_end(src_u, src_uv_plane_size)
  align_buffer_page_end(src_v, src_uv_plane_size)
38 39 40 41
  srandom(time(NULL));
  MemRandomize(src_y, src_y_plane_size);
  MemRandomize(src_u, src_uv_plane_size);
  MemRandomize(src_v, src_uv_plane_size);
42

43 44
  int dst_width_uv = (dst_width + 1) >> 1;
  int dst_height_uv = (dst_height + 1) >> 1;
45

46 47
  int dst_y_plane_size = (dst_width + b * 2) * (dst_height + b * 2);
  int dst_uv_plane_size = (dst_width_uv + b * 2) * (dst_height_uv + b * 2);
48

49 50
  int dst_stride_y = b * 2 + dst_width;
  int dst_stride_uv = b * 2 + dst_width_uv;
51

52 53 54 55 56 57
  align_buffer_page_end(dst_y_c, dst_y_plane_size)
  align_buffer_page_end(dst_u_c, dst_uv_plane_size)
  align_buffer_page_end(dst_v_c, dst_uv_plane_size)
  align_buffer_page_end(dst_y_opt, dst_y_plane_size)
  align_buffer_page_end(dst_u_opt, dst_uv_plane_size)
  align_buffer_page_end(dst_v_opt, dst_uv_plane_size)
58

fbarchard@google.com's avatar
fbarchard@google.com committed
59 60

  MaskCpuFlags(0);  // Disable all CPU optimization.
61
  double c_time = get_time();
62 63 64 65 66 67 68 69 70
  I420Scale(src_y + (src_stride_y * b) + b, src_stride_y,
            src_u + (src_stride_uv * b) + b, src_stride_uv,
            src_v + (src_stride_uv * b) + b, src_stride_uv,
            src_width, src_height,
            dst_y_c + (dst_stride_y * b) + b, dst_stride_y,
            dst_u_c + (dst_stride_uv * b) + b, dst_stride_uv,
            dst_v_c + (dst_stride_uv * b) + b, dst_stride_uv,
            dst_width, dst_height, f);
  c_time = (get_time() - c_time);
71

fbarchard@google.com's avatar
fbarchard@google.com committed
72
  MaskCpuFlags(-1);  // Enable all CPU optimization.
73
  double opt_time = get_time();
74
  for (i = 0; i < benchmark_iterations; ++i) {
75 76 77 78 79 80 81
    I420Scale(src_y + (src_stride_y * b) + b, src_stride_y,
              src_u + (src_stride_uv * b) + b, src_stride_uv,
              src_v + (src_stride_uv * b) + b, src_stride_uv,
              src_width, src_height,
              dst_y_opt + (dst_stride_y * b) + b, dst_stride_y,
              dst_u_opt + (dst_stride_uv * b) + b, dst_stride_uv,
              dst_v_opt + (dst_stride_uv * b) + b, dst_stride_uv,
82
              dst_width, dst_height, f);
fbarchard@google.com's avatar
fbarchard@google.com committed
83
  }
84
  opt_time = (get_time() - opt_time) / benchmark_iterations;
fbarchard@google.com's avatar
fbarchard@google.com committed
85 86
  // Report performance of C vs OPT
  printf("filter %d - %8d us C - %8d us OPT\n",
87 88 89
         f,
         static_cast<int>(c_time * 1e6),
         static_cast<int>(opt_time * 1e6));
90

91 92
  // C version may be a little off from the optimized. Order of
  //  operations may introduce rounding somewhere. So do a difference
93 94 95 96 97
  //  of the buffers and look to see that the max difference isn't
  //  over 2.
  int max_diff = 0;
  for (i = b; i < (dst_height + b); ++i) {
    for (j = b; j < (dst_width + b); ++j) {
98
      int abs_diff = Abs(dst_y_c[(i * dst_stride_y) + j] -
99
                         dst_y_opt[(i * dst_stride_y) + j]);
fbarchard@google.com's avatar
fbarchard@google.com committed
100
      if (abs_diff > max_diff) {
101
        max_diff = abs_diff;
fbarchard@google.com's avatar
fbarchard@google.com committed
102
      }
103
    }
104
  }
105

106 107
  for (i = b; i < (dst_height_uv + b); ++i) {
    for (j = b; j < (dst_width_uv + b); ++j) {
108
      int abs_diff = Abs(dst_u_c[(i * dst_stride_uv) + j] -
109
                         dst_u_opt[(i * dst_stride_uv) + j]);
fbarchard@google.com's avatar
fbarchard@google.com committed
110
      if (abs_diff > max_diff) {
111
        max_diff = abs_diff;
fbarchard@google.com's avatar
fbarchard@google.com committed
112
      }
113
      abs_diff = Abs(dst_v_c[(i * dst_stride_uv) + j] -
114
                     dst_v_opt[(i * dst_stride_uv) + j]);
fbarchard@google.com's avatar
fbarchard@google.com committed
115
      if (abs_diff > max_diff) {
116
        max_diff = abs_diff;
fbarchard@google.com's avatar
fbarchard@google.com committed
117
      }
118
    }
119 120
  }

121 122 123 124 125 126
  free_aligned_buffer_page_end(dst_y_c)
  free_aligned_buffer_page_end(dst_u_c)
  free_aligned_buffer_page_end(dst_v_c)
  free_aligned_buffer_page_end(dst_y_opt)
  free_aligned_buffer_page_end(dst_u_opt)
  free_aligned_buffer_page_end(dst_v_opt)
127

128 129 130
  free_aligned_buffer_page_end(src_y)
  free_aligned_buffer_page_end(src_u)
  free_aligned_buffer_page_end(src_v)
131

fbarchard@google.com's avatar
fbarchard@google.com committed
132
  return max_diff;
133 134
}

135
#define TEST_FACTOR1(name, filter, hfactor, vfactor, max_diff)                 \
136 137
    TEST_F(libyuvTest, ScaleDownBy##name##_##filter) {                         \
      int diff = TestFilter(benchmark_width_, benchmark_height_,               \
138 139
                            Abs(benchmark_width_) * hfactor,                   \
                            Abs(benchmark_height_) * vfactor,                  \
140 141 142
                            kFilter##filter, benchmark_iterations_);           \
      EXPECT_LE(diff, max_diff);                                               \
    }
143

144 145
// Test a scale factor with all 3 filters.  Expect unfiltered to be exact, but
// filtering is different fixed point implementations for SSSE3, Neon and C.
146 147 148 149
#define TEST_FACTOR(name, hfactor, vfactor)                                    \
    TEST_FACTOR1(name, None, hfactor, vfactor, 0)                              \
    TEST_FACTOR1(name, Bilinear, hfactor, vfactor, 2)                          \
    TEST_FACTOR1(name, Box, hfactor, vfactor, 2)                               \
150 151

// TODO(fbarchard): ScaleDownBy1 should be lossless, but Box has error of 2.
152 153 154 155 156 157 158 159 160 161
TEST_FACTOR(1, 1 / 1, 1 / 1)
TEST_FACTOR(2, 1 / 2, 1 / 2)
TEST_FACTOR(4, 1 / 4, 1 / 4)
TEST_FACTOR(5, 1 / 5, 1 / 5)
TEST_FACTOR(8, 1 / 8, 1 / 8)
TEST_FACTOR(16, 1 / 16, 1 / 16)
TEST_FACTOR(2by3, 2 / 3, 2 / 3)
TEST_FACTOR(3by4, 3 / 4, 3 / 4)
TEST_FACTOR(3by8, 3 / 8, 3 / 8)
TEST_FACTOR(Vertical2by3, 1, 2 / 3)
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
#undef TEST_FACTOR1
#undef TEST_FACTOR

#define TEST_SCALETO1(width, height, filter, max_diff)                         \
    TEST_F(libyuvTest, ScaleTo##width##x##height##_##filter) {                 \
      int diff = TestFilter(benchmark_width_, benchmark_height_,               \
                            width, height,                                     \
                            kFilter##filter, benchmark_iterations_);           \
      EXPECT_LE(diff, max_diff);                                               \
    }                                                                          \
    TEST_F(libyuvTest, ScaleFrom##width##x##height##_##filter) {               \
      int diff = TestFilter(width, height,                                     \
                            Abs(benchmark_width_), Abs(benchmark_height_),     \
                            kFilter##filter, benchmark_iterations_);           \
      EXPECT_LE(diff, max_diff);                                               \
    }
178

179 180 181 182 183 184 185 186 187
// Test scale to a specified size with all 3 filters.
#define TEST_SCALETO(width, height)                                            \
    TEST_SCALETO1(width, height, None, 0)                                      \
    TEST_SCALETO1(width, height, Bilinear, 2)                                  \
    TEST_SCALETO1(width, height, Box, 2)                                       \

TEST_SCALETO(640, 360)
TEST_SCALETO(853, 480)
TEST_SCALETO(1280, 720)
188
TEST_SCALETO(1280, 800)
189
TEST_SCALETO(1366, 768)
190
TEST_SCALETO(1920, 1080)
191 192
#undef TEST_SCALETO1
#undef TEST_SCALETO
193

frkoenig@google.com's avatar
frkoenig@google.com committed
194
}  // namespace libyuv