1 /*
2  *  Copyright (c) 2017 The WebM 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 <assert.h>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include "third_party/googletest/src/include/gtest/gtest.h"
16 
17 #include "./vp9_rtcd.h"
18 #include "./vpx_config.h"
19 #include "./vpx_scale_rtcd.h"
20 #include "test/clear_system_state.h"
21 #include "test/register_state_check.h"
22 #include "test/vpx_scale_test.h"
23 #include "vpx_mem/vpx_mem.h"
24 #include "vpx_ports/vpx_timer.h"
25 #include "vpx_scale/yv12config.h"
26 
27 namespace libvpx_test {
28 
29 typedef void (*ScaleFrameFunc)(const YV12_BUFFER_CONFIG *src,
30                                YV12_BUFFER_CONFIG *dst,
31                                INTERP_FILTER filter_type, int phase_scaler);
32 
33 class ScaleTest : public VpxScaleBase,
34                   public ::testing::TestWithParam<ScaleFrameFunc> {
35  public:
~ScaleTest()36   virtual ~ScaleTest() {}
37 
38  protected:
SetUp()39   virtual void SetUp() { scale_fn_ = GetParam(); }
40 
ReferenceScaleFrame(INTERP_FILTER filter_type,int phase_scaler)41   void ReferenceScaleFrame(INTERP_FILTER filter_type, int phase_scaler) {
42     vp9_scale_and_extend_frame_c(&img_, &ref_img_, filter_type, phase_scaler);
43   }
44 
ScaleFrame(INTERP_FILTER filter_type,int phase_scaler)45   void ScaleFrame(INTERP_FILTER filter_type, int phase_scaler) {
46     ASM_REGISTER_STATE_CHECK(
47         scale_fn_(&img_, &dst_img_, filter_type, phase_scaler));
48   }
49 
RunTest(INTERP_FILTER filter_type)50   void RunTest(INTERP_FILTER filter_type) {
51     static const int kNumSizesToTest = 20;
52     static const int kNumScaleFactorsToTest = 4;
53     static const int kSizesToTest[] = {
54       2,  4,  6,  8,  10, 12, 14, 16, 18,  20,
55       22, 24, 26, 28, 30, 32, 34, 68, 128, 134
56     };
57     static const int kScaleFactors[] = { 1, 2, 3, 4 };
58     for (int phase_scaler = 0; phase_scaler < 16; ++phase_scaler) {
59       for (int h = 0; h < kNumSizesToTest; ++h) {
60         const int src_height = kSizesToTest[h];
61         for (int w = 0; w < kNumSizesToTest; ++w) {
62           const int src_width = kSizesToTest[w];
63           for (int sf_up_idx = 0; sf_up_idx < kNumScaleFactorsToTest;
64                ++sf_up_idx) {
65             const int sf_up = kScaleFactors[sf_up_idx];
66             for (int sf_down_idx = 0; sf_down_idx < kNumScaleFactorsToTest;
67                  ++sf_down_idx) {
68               const int sf_down = kScaleFactors[sf_down_idx];
69               const int dst_width = src_width * sf_up / sf_down;
70               const int dst_height = src_height * sf_up / sf_down;
71               if (sf_up == sf_down && sf_up != 1) {
72                 continue;
73               }
74               // I420 frame width and height must be even.
75               if (!dst_width || !dst_height || dst_width & 1 ||
76                   dst_height & 1) {
77                 continue;
78               }
79               // vpx_convolve8_c() has restriction on the step which cannot
80               // exceed 64 (ratio 1 to 4).
81               if (src_width > 4 * dst_width || src_height > 4 * dst_height) {
82                 continue;
83               }
84               ASSERT_NO_FATAL_FAILURE(ResetScaleImages(src_width, src_height,
85                                                        dst_width, dst_height));
86               ReferenceScaleFrame(filter_type, phase_scaler);
87               ScaleFrame(filter_type, phase_scaler);
88               if (memcmp(dst_img_.buffer_alloc, ref_img_.buffer_alloc,
89                          ref_img_.frame_size)) {
90                 printf(
91                     "filter_type = %d, phase_scaler = %d, src_width = %4d, "
92                     "src_height = %4d, dst_width = %4d, dst_height = %4d, "
93                     "scale factor = %d:%d\n",
94                     filter_type, phase_scaler, src_width, src_height, dst_width,
95                     dst_height, sf_down, sf_up);
96                 PrintDiff();
97               }
98               CompareImages(dst_img_);
99               DeallocScaleImages();
100             }
101           }
102         }
103       }
104     }
105   }
106 
PrintDiffComponent(const uint8_t * const ref,const uint8_t * const opt,const int stride,const int width,const int height,const int plane_idx) const107   void PrintDiffComponent(const uint8_t *const ref, const uint8_t *const opt,
108                           const int stride, const int width, const int height,
109                           const int plane_idx) const {
110     for (int y = 0; y < height; y++) {
111       for (int x = 0; x < width; x++) {
112         if (ref[y * stride + x] != opt[y * stride + x]) {
113           printf("Plane %d pixel[%d][%d] diff:%6d (ref),%6d (opt)\n", plane_idx,
114                  y, x, ref[y * stride + x], opt[y * stride + x]);
115           break;
116         }
117       }
118     }
119   }
120 
PrintDiff() const121   void PrintDiff() const {
122     assert(ref_img_.y_stride == dst_img_.y_stride);
123     assert(ref_img_.y_width == dst_img_.y_width);
124     assert(ref_img_.y_height == dst_img_.y_height);
125     assert(ref_img_.uv_stride == dst_img_.uv_stride);
126     assert(ref_img_.uv_width == dst_img_.uv_width);
127     assert(ref_img_.uv_height == dst_img_.uv_height);
128 
129     if (memcmp(dst_img_.buffer_alloc, ref_img_.buffer_alloc,
130                ref_img_.frame_size)) {
131       PrintDiffComponent(ref_img_.y_buffer, dst_img_.y_buffer,
132                          ref_img_.y_stride, ref_img_.y_width, ref_img_.y_height,
133                          0);
134       PrintDiffComponent(ref_img_.u_buffer, dst_img_.u_buffer,
135                          ref_img_.uv_stride, ref_img_.uv_width,
136                          ref_img_.uv_height, 1);
137       PrintDiffComponent(ref_img_.v_buffer, dst_img_.v_buffer,
138                          ref_img_.uv_stride, ref_img_.uv_width,
139                          ref_img_.uv_height, 2);
140     }
141   }
142 
143   ScaleFrameFunc scale_fn_;
144 };
145 
TEST_P(ScaleTest,ScaleFrame_EightTap)146 TEST_P(ScaleTest, ScaleFrame_EightTap) { RunTest(EIGHTTAP); }
TEST_P(ScaleTest,ScaleFrame_EightTapSmooth)147 TEST_P(ScaleTest, ScaleFrame_EightTapSmooth) { RunTest(EIGHTTAP_SMOOTH); }
TEST_P(ScaleTest,ScaleFrame_EightTapSharp)148 TEST_P(ScaleTest, ScaleFrame_EightTapSharp) { RunTest(EIGHTTAP_SHARP); }
TEST_P(ScaleTest,ScaleFrame_Bilinear)149 TEST_P(ScaleTest, ScaleFrame_Bilinear) { RunTest(BILINEAR); }
150 
TEST_P(ScaleTest,DISABLED_Speed)151 TEST_P(ScaleTest, DISABLED_Speed) {
152   static const int kCountSpeedTestBlock = 100;
153   static const int kNumScaleFactorsToTest = 4;
154   static const int kScaleFactors[] = { 1, 2, 3, 4 };
155   const int src_width = 1280;
156   const int src_height = 720;
157   for (INTERP_FILTER filter_type = 2; filter_type < 4; ++filter_type) {
158     for (int phase_scaler = 0; phase_scaler < 2; ++phase_scaler) {
159       for (int sf_up_idx = 0; sf_up_idx < kNumScaleFactorsToTest; ++sf_up_idx) {
160         const int sf_up = kScaleFactors[sf_up_idx];
161         for (int sf_down_idx = 0; sf_down_idx < kNumScaleFactorsToTest;
162              ++sf_down_idx) {
163           const int sf_down = kScaleFactors[sf_down_idx];
164           const int dst_width = src_width * sf_up / sf_down;
165           const int dst_height = src_height * sf_up / sf_down;
166           if (sf_up == sf_down && sf_up != 1) {
167             continue;
168           }
169           // I420 frame width and height must be even.
170           if (dst_width & 1 || dst_height & 1) {
171             continue;
172           }
173           ASSERT_NO_FATAL_FAILURE(
174               ResetScaleImages(src_width, src_height, dst_width, dst_height));
175           ASM_REGISTER_STATE_CHECK(
176               ReferenceScaleFrame(filter_type, phase_scaler));
177 
178           vpx_usec_timer timer;
179           vpx_usec_timer_start(&timer);
180           for (int i = 0; i < kCountSpeedTestBlock; ++i) {
181             ScaleFrame(filter_type, phase_scaler);
182           }
183           libvpx_test::ClearSystemState();
184           vpx_usec_timer_mark(&timer);
185           const int elapsed_time =
186               static_cast<int>(vpx_usec_timer_elapsed(&timer) / 1000);
187           CompareImages(dst_img_);
188           DeallocScaleImages();
189 
190           printf(
191               "filter_type = %d, phase_scaler = %d, src_width = %4d, "
192               "src_height = %4d, dst_width = %4d, dst_height = %4d, "
193               "scale factor = %d:%d, scale time: %5d ms\n",
194               filter_type, phase_scaler, src_width, src_height, dst_width,
195               dst_height, sf_down, sf_up, elapsed_time);
196         }
197       }
198     }
199   }
200 }
201 
202 INSTANTIATE_TEST_CASE_P(C, ScaleTest,
203                         ::testing::Values(vp9_scale_and_extend_frame_c));
204 
205 #if HAVE_SSSE3
206 INSTANTIATE_TEST_CASE_P(SSSE3, ScaleTest,
207                         ::testing::Values(vp9_scale_and_extend_frame_ssse3));
208 #endif  // HAVE_SSSE3
209 
210 #if HAVE_NEON
211 INSTANTIATE_TEST_CASE_P(NEON, ScaleTest,
212                         ::testing::Values(vp9_scale_and_extend_frame_neon));
213 #endif  // HAVE_NEON
214 
215 }  // namespace libvpx_test
216