1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/base_paths.h"
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/path_service.h"
10 #include "base/time/time.h"
11 #include "media/base/simd/convert_yuv_to_rgb.h"
12 #include "media/base/yuv_convert.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/perf/perf_test.h"
15 #include "third_party/libyuv/include/libyuv/row.h"
18 #if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY)
20 static const int kSourceWidth
= 640;
21 static const int kSourceHeight
= 360;
22 static const int kSourceYSize
= kSourceWidth
* kSourceHeight
;
23 static const int kSourceUOffset
= kSourceYSize
;
24 static const int kSourceVOffset
= kSourceYSize
* 5 / 4;
25 static const int kBpp
= 4;
27 // Width of the row to convert. Odd so that we exercise the ending
28 // one-pixel-leftover case.
29 static const int kWidth
= 639;
31 // Surface sizes for various test files.
32 static const int kYUV12Size
= kSourceYSize
* 12 / 8;
33 static const int kRGBSize
= kSourceYSize
* kBpp
;
35 static const int kPerfTestIterations
= 2000;
37 class YUVConvertPerfTest
: public testing::Test
{
40 : yuv_bytes_(new uint8
[kYUV12Size
]),
41 rgb_bytes_converted_(new uint8
[kRGBSize
]) {
43 CHECK(PathService::Get(base::DIR_SOURCE_ROOT
, &path
));
44 path
= path
.Append(FILE_PATH_LITERAL("media"))
45 .Append(FILE_PATH_LITERAL("test"))
46 .Append(FILE_PATH_LITERAL("data"))
47 .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
49 // Verify file size is correct.
50 int64 actual_size
= 0;
51 base::GetFileSize(path
, &actual_size
);
52 CHECK_EQ(actual_size
, kYUV12Size
);
54 // Verify bytes read are correct.
55 int bytes_read
= base::ReadFile(
56 path
, reinterpret_cast<char*>(yuv_bytes_
.get()), kYUV12Size
);
58 CHECK_EQ(bytes_read
, kYUV12Size
);
61 scoped_ptr
<uint8
[]> yuv_bytes_
;
62 scoped_ptr
<uint8
[]> rgb_bytes_converted_
;
65 DISALLOW_COPY_AND_ASSIGN(YUVConvertPerfTest
);
68 TEST_F(YUVConvertPerfTest
, I422ToARGBRow_SSSE3
) {
69 ASSERT_TRUE(base::CPU().has_ssse3());
71 base::TimeTicks start
= base::TimeTicks::Now();
72 for (int i
= 0; i
< kPerfTestIterations
; ++i
) {
73 for (int row
= 0; row
< kSourceHeight
; ++row
) {
74 int chroma_row
= row
/ 2;
75 libyuv::I422ToARGBRow_SSSE3(
76 yuv_bytes_
.get() + row
* kSourceWidth
,
77 yuv_bytes_
.get() + kSourceUOffset
+ (chroma_row
* kSourceWidth
/ 2),
78 yuv_bytes_
.get() + kSourceVOffset
+ (chroma_row
* kSourceWidth
/ 2),
79 rgb_bytes_converted_
.get(),
83 double total_time_seconds
= (base::TimeTicks::Now() - start
).InSecondsF();
84 perf_test::PrintResult(
85 "yuv_convert_perftest", "", "I422ToARGBRow_SSSE3",
86 kPerfTestIterations
/ total_time_seconds
, "runs/s", true);
89 TEST_F(YUVConvertPerfTest
, ConvertYUVToRGB32Row_SSE
) {
90 ASSERT_TRUE(base::CPU().has_sse());
92 base::TimeTicks start
= base::TimeTicks::Now();
93 for (int i
= 0; i
< kPerfTestIterations
; ++i
) {
94 for (int row
= 0; row
< kSourceHeight
; ++row
) {
95 int chroma_row
= row
/ 2;
96 ConvertYUVToRGB32Row_SSE(
97 yuv_bytes_
.get() + row
* kSourceWidth
,
98 yuv_bytes_
.get() + kSourceUOffset
+ (chroma_row
* kSourceWidth
/ 2),
99 yuv_bytes_
.get() + kSourceVOffset
+ (chroma_row
* kSourceWidth
/ 2),
100 rgb_bytes_converted_
.get(),
102 GetLookupTable(YV12
));
105 media::EmptyRegisterState();
106 double total_time_seconds
= (base::TimeTicks::Now() - start
).InSecondsF();
107 perf_test::PrintResult(
108 "yuv_convert_perftest", "", "ConvertYUVToRGB32Row_SSE",
109 kPerfTestIterations
/ total_time_seconds
, "runs/s", true);
112 TEST_F(YUVConvertPerfTest
, ConvertYUVAToARGBRow_MMX
) {
113 ASSERT_TRUE(base::CPU().has_sse());
115 base::TimeTicks start
= base::TimeTicks::Now();
116 for (int i
= 0; i
< kPerfTestIterations
; ++i
) {
117 for (int row
= 0; row
< kSourceHeight
; ++row
) {
118 int chroma_row
= row
/ 2;
119 ConvertYUVAToARGBRow_MMX(
120 yuv_bytes_
.get() + row
* kSourceWidth
,
121 yuv_bytes_
.get() + kSourceUOffset
+ (chroma_row
* kSourceWidth
/ 2),
122 yuv_bytes_
.get() + kSourceVOffset
+ (chroma_row
* kSourceWidth
/ 2),
123 yuv_bytes_
.get() + row
* kSourceWidth
, // hack: use luma for alpha
124 rgb_bytes_converted_
.get(),
126 GetLookupTable(YV12
));
129 media::EmptyRegisterState();
130 double total_time_seconds
= (base::TimeTicks::Now() - start
).InSecondsF();
131 perf_test::PrintResult(
132 "yuv_convert_perftest", "", "ConvertYUVAToARGBRow_MMX",
133 kPerfTestIterations
/ total_time_seconds
, "runs/s", true);
136 // 64-bit release + component builds on Windows are too smart and optimizes
137 // away the function being tested.
138 #if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD))
139 TEST_F(YUVConvertPerfTest
, ScaleYUVToRGB32Row_SSE
) {
140 ASSERT_TRUE(base::CPU().has_sse());
142 const int kSourceDx
= 80000; // This value means a scale down.
144 base::TimeTicks start
= base::TimeTicks::Now();
145 for (int i
= 0; i
< kPerfTestIterations
; ++i
) {
146 for (int row
= 0; row
< kSourceHeight
; ++row
) {
147 int chroma_row
= row
/ 2;
148 ScaleYUVToRGB32Row_SSE(
149 yuv_bytes_
.get() + row
* kSourceWidth
,
150 yuv_bytes_
.get() + kSourceUOffset
+ (chroma_row
* kSourceWidth
/ 2),
151 yuv_bytes_
.get() + kSourceVOffset
+ (chroma_row
* kSourceWidth
/ 2),
152 rgb_bytes_converted_
.get(),
155 GetLookupTable(YV12
));
158 media::EmptyRegisterState();
159 double total_time_seconds
= (base::TimeTicks::Now() - start
).InSecondsF();
160 perf_test::PrintResult(
161 "yuv_convert_perftest", "", "ScaleYUVToRGB32Row_SSE",
162 kPerfTestIterations
/ total_time_seconds
, "runs/s", true);
165 TEST_F(YUVConvertPerfTest
, LinearScaleYUVToRGB32Row_SSE
) {
166 ASSERT_TRUE(base::CPU().has_sse());
168 const int kSourceDx
= 80000; // This value means a scale down.
170 base::TimeTicks start
= base::TimeTicks::Now();
171 for (int i
= 0; i
< kPerfTestIterations
; ++i
) {
172 for (int row
= 0; row
< kSourceHeight
; ++row
) {
173 int chroma_row
= row
/ 2;
174 LinearScaleYUVToRGB32Row_SSE(
175 yuv_bytes_
.get() + row
* kSourceWidth
,
176 yuv_bytes_
.get() + kSourceUOffset
+ (chroma_row
* kSourceWidth
/ 2),
177 yuv_bytes_
.get() + kSourceVOffset
+ (chroma_row
* kSourceWidth
/ 2),
178 rgb_bytes_converted_
.get(),
181 GetLookupTable(YV12
));
184 media::EmptyRegisterState();
185 double total_time_seconds
= (base::TimeTicks::Now() - start
).InSecondsF();
186 perf_test::PrintResult(
187 "yuv_convert_perftest", "", "LinearScaleYUVToRGB32Row_SSE",
188 kPerfTestIterations
/ total_time_seconds
, "runs/s", true);
190 #endif // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD)
192 #endif // !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY)