Home | History | Annotate | Download | only in simd
      1 // Copyright (c) 2012 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/cpu.h"
      6 #include "base/memory/scoped_ptr.h"
      7 #include "media/base/simd/convert_rgb_to_yuv.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 
     10 namespace {
     11 
     12 // Reference code that converts RGB pixels to YUV pixels.
     13 int ConvertRGBToY(const uint8* rgb) {
     14   int y = 25 * rgb[0] + 129 * rgb[1] + 66 * rgb[2];
     15   y = ((y + 128) >> 8) + 16;
     16   return std::max(0, std::min(255, y));
     17 }
     18 
     19 int ConvertRGBToU(const uint8* rgb, int size) {
     20   int u = 112 * rgb[0] - 74 * rgb[1] - 38 * rgb[2];
     21   u = ((u + 128) >> 8) + 128;
     22   return std::max(0, std::min(255, u));
     23 }
     24 
     25 int ConvertRGBToV(const uint8* rgb, int size) {
     26   int v = -18 * rgb[0] - 94 * rgb[1] + 112 * rgb[2];
     27   v = ((v + 128) >> 8) + 128;
     28   return std::max(0, std::min(255, v));
     29 }
     30 
     31 }  // namespace
     32 
     33 // Assembly code confuses MemorySanitizer. Do not run it in MSan builds.
     34 #if defined(MEMORY_SANITIZER)
     35 #define MAYBE_SideBySideRGB DISABLED_SideBySideRGB
     36 #else
     37 #define MAYBE_SideBySideRGB SideBySideRGB
     38 #endif
     39 
     40 // A side-by-side test that verifies our ASM functions that convert RGB pixels
     41 // to YUV pixels can output the expected results. This test converts RGB pixels
     42 // to YUV pixels with our ASM functions (which use SSE, SSE2, SSE3, and SSSE3)
     43 // and compare the output YUV pixels with the ones calculated with out reference
     44 // functions implemented in C++.
     45 TEST(YUVConvertTest, MAYBE_SideBySideRGB) {
     46   // We skip this test on PCs which does not support SSE3 because this test
     47   // needs it.
     48   base::CPU cpu;
     49   if (!cpu.has_ssse3())
     50     return;
     51 
     52   // This test checks a subset of all RGB values so this test does not take so
     53   // long time.
     54   const int kStep = 8;
     55   const int kWidth = 256 / kStep;
     56 
     57   for (int size = 3; size <= 4; ++size) {
     58     // Create the output buffers.
     59     scoped_ptr<uint8[]> rgb(new uint8[kWidth * size]);
     60     scoped_ptr<uint8[]> y(new uint8[kWidth]);
     61     scoped_ptr<uint8[]> u(new uint8[kWidth / 2]);
     62     scoped_ptr<uint8[]> v(new uint8[kWidth / 2]);
     63 
     64     // Choose the function that converts from RGB pixels to YUV ones.
     65     void (*convert)(const uint8*, uint8*, uint8*, uint8*,
     66                     int, int, int, int, int) = NULL;
     67     if (size == 3)
     68       convert = media::ConvertRGB24ToYUV_SSSE3;
     69     else
     70       convert = media::ConvertRGB32ToYUV_SSSE3;
     71 
     72     int total_error = 0;
     73     for (int r = 0; r < kWidth; ++r) {
     74       for (int g = 0; g < kWidth; ++g) {
     75 
     76         // Fill the input pixels.
     77         for (int b = 0; b < kWidth; ++b) {
     78           rgb[b * size + 0] = b * kStep;
     79           rgb[b * size + 1] = g * kStep;
     80           rgb[b * size + 2] = r * kStep;
     81           if (size == 4)
     82             rgb[b * size + 3] = 255;
     83         }
     84 
     85         // Convert the input RGB pixels to YUV ones.
     86         convert(rgb.get(), y.get(), u.get(), v.get(), kWidth, 1, kWidth * size,
     87                 kWidth, kWidth / 2);
     88 
     89         // Check the output Y pixels.
     90         for (int i = 0; i < kWidth; ++i) {
     91           const uint8* p = &rgb[i * size];
     92           int error = ConvertRGBToY(p) - y[i];
     93           total_error += error > 0 ? error : -error;
     94         }
     95 
     96         // Check the output U pixels.
     97         for (int i = 0; i < kWidth / 2; ++i) {
     98           const uint8* p = &rgb[i * 2 * size];
     99           int error = ConvertRGBToU(p, size) - u[i];
    100           total_error += error > 0 ? error : -error;
    101         }
    102 
    103         // Check the output V pixels.
    104         for (int i = 0; i < kWidth / 2; ++i) {
    105           const uint8* p = &rgb[i * 2 * size];
    106           int error = ConvertRGBToV(p, size) - v[i];
    107           total_error += error > 0 ? error : -error;
    108         }
    109       }
    110     }
    111 
    112     EXPECT_EQ(0, total_error);
    113   }
    114 }
    115