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 "base/base_paths.h" 6 #include "base/cpu.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 16 namespace media { 17 #if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) 18 // Size of raw image. 19 static const int kSourceWidth = 640; 20 static const int kSourceHeight = 360; 21 static const int kSourceYSize = kSourceWidth * kSourceHeight; 22 static const int kSourceUOffset = kSourceYSize; 23 static const int kSourceVOffset = kSourceYSize * 5 / 4; 24 static const int kBpp = 4; 25 26 // Width of the row to convert. Odd so that we exercise the ending 27 // one-pixel-leftover case. 28 static const int kWidth = 639; 29 30 // Surface sizes for various test files. 31 static const int kYUV12Size = kSourceYSize * 12 / 8; 32 static const int kRGBSize = kSourceYSize * kBpp; 33 34 static const int kPerfTestIterations = 2000; 35 36 class YUVConvertPerfTest : public testing::Test { 37 public: 38 YUVConvertPerfTest() 39 : yuv_bytes_(new uint8[kYUV12Size]), 40 rgb_bytes_converted_(new uint8[kRGBSize]) { 41 base::FilePath path; 42 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &path)); 43 path = path.Append(FILE_PATH_LITERAL("media")) 44 .Append(FILE_PATH_LITERAL("test")) 45 .Append(FILE_PATH_LITERAL("data")) 46 .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv")); 47 48 // Verify file size is correct. 49 int64 actual_size = 0; 50 base::GetFileSize(path, &actual_size); 51 CHECK_EQ(actual_size, kYUV12Size); 52 53 // Verify bytes read are correct. 54 int bytes_read = base::ReadFile( 55 path, reinterpret_cast<char*>(yuv_bytes_.get()), kYUV12Size); 56 57 CHECK_EQ(bytes_read, kYUV12Size); 58 } 59 60 scoped_ptr<uint8[]> yuv_bytes_; 61 scoped_ptr<uint8[]> rgb_bytes_converted_; 62 63 private: 64 DISALLOW_COPY_AND_ASSIGN(YUVConvertPerfTest); 65 }; 66 67 TEST_F(YUVConvertPerfTest, ConvertYUVToRGB32Row_SSE) { 68 ASSERT_TRUE(base::CPU().has_sse()); 69 70 base::TimeTicks start = base::TimeTicks::HighResNow(); 71 for (int i = 0; i < kPerfTestIterations; ++i) { 72 for (int row = 0; row < kSourceHeight; ++row) { 73 int chroma_row = row / 2; 74 ConvertYUVToRGB32Row_SSE( 75 yuv_bytes_.get() + row * kSourceWidth, 76 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), 77 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), 78 rgb_bytes_converted_.get(), 79 kWidth, 80 GetLookupTable(YV12)); 81 } 82 } 83 double total_time_seconds = 84 (base::TimeTicks::HighResNow() - start).InSecondsF(); 85 perf_test::PrintResult( 86 "yuv_convert_perftest", "", "ConvertYUVToRGB32Row_SSE", 87 kPerfTestIterations / total_time_seconds, "runs/s", true); 88 media::EmptyRegisterState(); 89 } 90 91 // 64-bit release + component builds on Windows are too smart and optimizes 92 // away the function being tested. 93 #if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD)) 94 TEST_F(YUVConvertPerfTest, ScaleYUVToRGB32Row_SSE) { 95 ASSERT_TRUE(base::CPU().has_sse()); 96 97 const int kSourceDx = 80000; // This value means a scale down. 98 99 base::TimeTicks start = base::TimeTicks::HighResNow(); 100 for (int i = 0; i < kPerfTestIterations; ++i) { 101 for (int row = 0; row < kSourceHeight; ++row) { 102 int chroma_row = row / 2; 103 ScaleYUVToRGB32Row_SSE( 104 yuv_bytes_.get() + row * kSourceWidth, 105 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), 106 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), 107 rgb_bytes_converted_.get(), 108 kWidth, 109 kSourceDx, 110 GetLookupTable(YV12)); 111 } 112 } 113 double total_time_seconds = 114 (base::TimeTicks::HighResNow() - start).InSecondsF(); 115 perf_test::PrintResult( 116 "yuv_convert_perftest", "", "ScaleYUVToRGB32Row_SSE", 117 kPerfTestIterations / total_time_seconds, "runs/s", true); 118 media::EmptyRegisterState(); 119 } 120 121 TEST_F(YUVConvertPerfTest, LinearScaleYUVToRGB32Row_SSE) { 122 ASSERT_TRUE(base::CPU().has_sse()); 123 124 const int kSourceDx = 80000; // This value means a scale down. 125 126 base::TimeTicks start = base::TimeTicks::HighResNow(); 127 for (int i = 0; i < kPerfTestIterations; ++i) { 128 for (int row = 0; row < kSourceHeight; ++row) { 129 int chroma_row = row / 2; 130 LinearScaleYUVToRGB32Row_SSE( 131 yuv_bytes_.get() + row * kSourceWidth, 132 yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), 133 yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), 134 rgb_bytes_converted_.get(), 135 kWidth, 136 kSourceDx, 137 GetLookupTable(YV12)); 138 } 139 } 140 double total_time_seconds = 141 (base::TimeTicks::HighResNow() - start).InSecondsF(); 142 perf_test::PrintResult( 143 "yuv_convert_perftest", "", "LinearScaleYUVToRGB32Row_SSE", 144 kPerfTestIterations / total_time_seconds, "runs/s", true); 145 media::EmptyRegisterState(); 146 } 147 #endif // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD) 148 149 #endif // !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) 150 151 } // namespace media 152