| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include <stdint.h> | |
| 6 | |
| 7 #include <memory> | |
| 8 | |
| 9 #include "base/base_paths.h" | |
| 10 #include "base/cpu.h" | |
| 11 #include "base/files/file_util.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/macros.h" | |
| 14 #include "base/path_service.h" | |
| 15 #include "base/time/time.h" | |
| 16 #include "build/build_config.h" | |
| 17 #include "media/base/simd/convert_yuv_to_rgb.h" | |
| 18 #include "media/base/yuv_convert.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "testing/perf/perf_test.h" | |
| 21 #include "third_party/libyuv/include/libyuv/row.h" | |
| 22 | |
| 23 namespace media { | |
| 24 #if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) | |
| 25 // Size of raw image. | |
| 26 static const int kSourceWidth = 640; | |
| 27 static const int kSourceHeight = 360; | |
| 28 static const int kSourceYSize = kSourceWidth * kSourceHeight; | |
| 29 static const int kSourceUOffset = kSourceYSize; | |
| 30 static const int kSourceVOffset = kSourceYSize * 5 / 4; | |
| 31 static const int kBpp = 4; | |
| 32 | |
| 33 // Width of the row to convert. Odd so that we exercise the ending | |
| 34 // one-pixel-leftover case. | |
| 35 static const int kWidth = 639; | |
| 36 | |
| 37 // Surface sizes for various test files. | |
| 38 static const int kYUV12Size = kSourceYSize * 12 / 8; | |
| 39 static const int kRGBSize = kSourceYSize * kBpp; | |
| 40 | |
| 41 static const int kPerfTestIterations = 2000; | |
| 42 | |
| 43 class YUVConvertPerfTest : public testing::Test { | |
| 44 public: | |
| 45 YUVConvertPerfTest() | |
| 46 : yuv_bytes_(new uint8_t[kYUV12Size]), | |
| 47 rgb_bytes_converted_(new uint8_t[kRGBSize]) { | |
| 48 base::FilePath path; | |
| 49 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &path)); | |
| 50 path = path.Append(FILE_PATH_LITERAL("media")) | |
| 51 .Append(FILE_PATH_LITERAL("test")) | |
| 52 .Append(FILE_PATH_LITERAL("data")) | |
| 53 .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv")); | |
| 54 | |
| 55 // Verify file size is correct. | |
| 56 int64_t actual_size = 0; | |
| 57 base::GetFileSize(path, &actual_size); | |
| 58 CHECK_EQ(actual_size, kYUV12Size); | |
| 59 | |
| 60 // Verify bytes read are correct. | |
| 61 int bytes_read = base::ReadFile( | |
| 62 path, reinterpret_cast<char*>(yuv_bytes_.get()), kYUV12Size); | |
| 63 | |
| 64 CHECK_EQ(bytes_read, kYUV12Size); | |
| 65 } | |
| 66 | |
| 67 std::unique_ptr<uint8_t[]> yuv_bytes_; | |
| 68 std::unique_ptr<uint8_t[]> rgb_bytes_converted_; | |
| 69 | |
| 70 private: | |
| 71 DISALLOW_COPY_AND_ASSIGN(YUVConvertPerfTest); | |
| 72 }; | |
| 73 | |
| 74 TEST_F(YUVConvertPerfTest, ConvertYUVToRGB32Row_SSE) { | |
| 75 ASSERT_TRUE(base::CPU().has_sse()); | |
| 76 | |
| 77 base::TimeTicks start = base::TimeTicks::Now(); | |
| 78 for (int i = 0; i < kPerfTestIterations; ++i) { | |
| 79 for (int row = 0; row < kSourceHeight; ++row) { | |
| 80 int chroma_row = row / 2; | |
| 81 ConvertYUVToRGB32Row_SSE( | |
| 82 yuv_bytes_.get() + row * kSourceWidth, | |
| 83 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), | |
| 84 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), | |
| 85 rgb_bytes_converted_.get(), | |
| 86 kWidth, | |
| 87 GetLookupTable(YV12)); | |
| 88 } | |
| 89 } | |
| 90 media::EmptyRegisterState(); | |
| 91 double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); | |
| 92 perf_test::PrintResult( | |
| 93 "yuv_convert_perftest", "", "ConvertYUVToRGB32Row_SSE", | |
| 94 kPerfTestIterations / total_time_seconds, "runs/s", true); | |
| 95 } | |
| 96 | |
| 97 #ifdef HAS_I422TOARGBROW_SSSE3 | |
| 98 TEST_F(YUVConvertPerfTest, I422ToARGBRow_SSSE3) { | |
| 99 ASSERT_TRUE(base::CPU().has_ssse3()); | |
| 100 | |
| 101 base::TimeTicks start = base::TimeTicks::Now(); | |
| 102 for (int i = 0; i < kPerfTestIterations; ++i) { | |
| 103 for (int row = 0; row < kSourceHeight; ++row) { | |
| 104 int chroma_row = row / 2; | |
| 105 libyuv::I422ToARGBRow_SSSE3( | |
| 106 yuv_bytes_.get() + row * kSourceWidth, | |
| 107 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), | |
| 108 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), | |
| 109 rgb_bytes_converted_.get(), &libyuv::kYuvI601Constants, kWidth); | |
| 110 } | |
| 111 } | |
| 112 double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); | |
| 113 perf_test::PrintResult("yuv_convert_perftest", "", "I422ToARGBRow_SSSE3", | |
| 114 kPerfTestIterations / total_time_seconds, "runs/s", | |
| 115 true); | |
| 116 } | |
| 117 #endif | |
| 118 | |
| 119 TEST_F(YUVConvertPerfTest, ConvertYUVAToARGBRow_MMX) { | |
| 120 ASSERT_TRUE(base::CPU().has_sse()); | |
| 121 | |
| 122 base::TimeTicks start = base::TimeTicks::Now(); | |
| 123 for (int i = 0; i < kPerfTestIterations; ++i) { | |
| 124 for (int row = 0; row < kSourceHeight; ++row) { | |
| 125 int chroma_row = row / 2; | |
| 126 ConvertYUVAToARGBRow_MMX( | |
| 127 yuv_bytes_.get() + row * kSourceWidth, | |
| 128 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), | |
| 129 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), | |
| 130 yuv_bytes_.get() + row * kSourceWidth, // hack: use luma for alpha | |
| 131 rgb_bytes_converted_.get(), kWidth, GetLookupTable(YV12)); | |
| 132 } | |
| 133 } | |
| 134 media::EmptyRegisterState(); | |
| 135 double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); | |
| 136 perf_test::PrintResult("yuv_convert_perftest", "", "ConvertYUVAToARGBRow_MMX", | |
| 137 kPerfTestIterations / total_time_seconds, "runs/s", | |
| 138 true); | |
| 139 } | |
| 140 | |
| 141 #ifdef HAS_I422ALPHATOARGBROW_SSSE3 | |
| 142 TEST_F(YUVConvertPerfTest, I422AlphaToARGBRow_SSSE3) { | |
| 143 ASSERT_TRUE(base::CPU().has_ssse3()); | |
| 144 | |
| 145 base::TimeTicks start = base::TimeTicks::Now(); | |
| 146 for (int i = 0; i < kPerfTestIterations; ++i) { | |
| 147 for (int row = 0; row < kSourceHeight; ++row) { | |
| 148 int chroma_row = row / 2; | |
| 149 libyuv::I422AlphaToARGBRow_SSSE3( | |
| 150 yuv_bytes_.get() + row * kSourceWidth, | |
| 151 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), | |
| 152 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), | |
| 153 yuv_bytes_.get() + row * kSourceWidth, // hack: use luma for alpha | |
| 154 rgb_bytes_converted_.get(), &libyuv::kYuvI601Constants, kWidth); | |
| 155 } | |
| 156 } | |
| 157 double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); | |
| 158 perf_test::PrintResult("yuv_convert_perftest", "", "I422AlphaToARGBRow_SSSE3", | |
| 159 kPerfTestIterations / total_time_seconds, "runs/s", | |
| 160 true); | |
| 161 } | |
| 162 #endif | |
| 163 | |
| 164 // 64-bit release + component builds on Windows are too smart and optimizes | |
| 165 // away the function being tested. | |
| 166 #if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD)) | |
| 167 TEST_F(YUVConvertPerfTest, ScaleYUVToRGB32Row_SSE) { | |
| 168 ASSERT_TRUE(base::CPU().has_sse()); | |
| 169 | |
| 170 const int kSourceDx = 80000; // This value means a scale down. | |
| 171 | |
| 172 base::TimeTicks start = base::TimeTicks::Now(); | |
| 173 for (int i = 0; i < kPerfTestIterations; ++i) { | |
| 174 for (int row = 0; row < kSourceHeight; ++row) { | |
| 175 int chroma_row = row / 2; | |
| 176 ScaleYUVToRGB32Row_SSE( | |
| 177 yuv_bytes_.get() + row * kSourceWidth, | |
| 178 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), | |
| 179 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), | |
| 180 rgb_bytes_converted_.get(), | |
| 181 kWidth, | |
| 182 kSourceDx, | |
| 183 GetLookupTable(YV12)); | |
| 184 } | |
| 185 } | |
| 186 media::EmptyRegisterState(); | |
| 187 double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); | |
| 188 perf_test::PrintResult( | |
| 189 "yuv_convert_perftest", "", "ScaleYUVToRGB32Row_SSE", | |
| 190 kPerfTestIterations / total_time_seconds, "runs/s", true); | |
| 191 } | |
| 192 | |
| 193 TEST_F(YUVConvertPerfTest, LinearScaleYUVToRGB32Row_SSE) { | |
| 194 ASSERT_TRUE(base::CPU().has_sse()); | |
| 195 | |
| 196 const int kSourceDx = 80000; // This value means a scale down. | |
| 197 | |
| 198 base::TimeTicks start = base::TimeTicks::Now(); | |
| 199 for (int i = 0; i < kPerfTestIterations; ++i) { | |
| 200 for (int row = 0; row < kSourceHeight; ++row) { | |
| 201 int chroma_row = row / 2; | |
| 202 LinearScaleYUVToRGB32Row_SSE( | |
| 203 yuv_bytes_.get() + row * kSourceWidth, | |
| 204 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), | |
| 205 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), | |
| 206 rgb_bytes_converted_.get(), | |
| 207 kWidth, | |
| 208 kSourceDx, | |
| 209 GetLookupTable(YV12)); | |
| 210 } | |
| 211 } | |
| 212 media::EmptyRegisterState(); | |
| 213 double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); | |
| 214 perf_test::PrintResult( | |
| 215 "yuv_convert_perftest", "", "LinearScaleYUVToRGB32Row_SSE", | |
| 216 kPerfTestIterations / total_time_seconds, "runs/s", true); | |
| 217 } | |
| 218 #endif // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD) | |
| 219 | |
| 220 #endif // !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) | |
| 221 | |
| 222 } // namespace media | |
| OLD | NEW |