text: /*
   * Copyright 2009 The Android Open Source Project
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #include "SkBitmapProcState_opts_SSE2.h"
  #include "SkBitmapProcState_opts_SSSE3.h"
  #include "SkBlitMask.h"
  #include "SkBlitRow_opts_SSE2.h"
  #include "SkUtils_opts_SSE2.h"
  #include "SkUtils.h"
  
  /* This file must *not* be compiled with -msse or -msse2, otherwise
     gcc may generate sse2 even for scalar ops (and thus give an invalid
     instruction on Pentium3 on the code below).  Only files named *_SSE2.cpp
     in this directory should be compiled with -msse2. */
  
  
  #ifdef _MSC_VER
  static inline void getcpuid(int info_type, int info[4]) {
      __asm {
          mov    eax, [info_type]
          cpuid
          mov    edi, [info]
          mov    [edi], eax
          mov    [edi+4], ebx
          mov    [edi+8], ecx
          mov    [edi+12], edx
      }
  }
  #else
  #if defined(__x86_64__)
  static inline void getcpuid(int info_type, int info[4]) {
      asm volatile (
          "cpuid \n\t"
          : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
          : "a"(info_type)
      );
  }
  #else
  static inline void getcpuid(int info_type, int info[4]) {
      // We save and restore ebx, so this code can be compatible with -fPIC
      asm volatile (
          "pushl %%ebx      \n\t"
          "cpuid            \n\t"
          "movl %%ebx, %1   \n\t"
          "popl %%ebx       \n\t"
          : "=a"(info[0]), "=r"(info[1]), "=c"(info[2]), "=d"(info[3])
          : "a"(info_type)
      );
  }
  #endif
  #endif
  
  #if defined(__x86_64__) || defined(_WIN64)
  /* All x86_64 machines have SSE2, so don't even bother checking. */
  static inline bool hasSSE2() {
      return true;
  }
  #else
  
  static inline bool hasSSE2() {
      int cpu_info[4] = { 0 };
      getcpuid(1, cpu_info);
      return (cpu_info[3] & (1<<26)) != 0;
  }
  #endif
  
  static inline bool hasSSSE3() {
      int cpu_info[4] = { 0 };
      getcpuid(1, cpu_info);
      return (cpu_info[2] & 0x200) != 0;
  }
  
  static bool cachedHasSSE2() {
      static bool gHasSSE2 = hasSSE2();
      return gHasSSE2;
  }
  
  static bool cachedHasSSSE3() {
      static bool gHasSSSE3 = hasSSSE3();
      return gHasSSSE3;
  }
  
  void SkBitmapProcState::platformProcs() {
      if (cachedHasSSSE3()) {
          if (fSampleProc32 == S32_opaque_D32_filter_DX) {
              fSampleProc32 = S32_opaque_D32_filter_DX_SSSE3;
          } else if (fSampleProc32 == S32_alpha_D32_filter_DX) {
              fSampleProc32 = S32_alpha_D32_filter_DX_SSSE3;
          }
      } else if (cachedHasSSE2()) {
          if (fSampleProc32 == S32_opaque_D32_filter_DX) {
              fSampleProc32 = S32_opaque_D32_filter_DX_SSE2;
          } else if (fSampleProc32 == S32_alpha_D32_filter_DX) {
              fSampleProc32 = S32_alpha_D32_filter_DX_SSE2;
          }
      }
  
      if (cachedHasSSSE3() || cachedHasSSE2()) {
          if (fMatrixProc == ClampX_ClampY_filter_scale) {
              fMatrixProc = ClampX_ClampY_filter_scale_SSE2;
          } else if (fMatrixProc == ClampX_ClampY_nofilter_scale) {
              fMatrixProc = ClampX_ClampY_nofilter_scale_SSE2;
          }
  
          if (fMatrixProc == ClampX_ClampY_filter_affine) {
              fMatrixProc = ClampX_ClampY_filter_affine_SSE2;
          } else if (fMatrixProc == ClampX_ClampY_nofilter_affine) {
              fMatrixProc = ClampX_ClampY_nofilter_affine_SSE2;
          }
      }
  }
  
  static SkBlitRow::Proc32 platform_32_procs[] = {
      NULL,                               // S32_Opaque,
      S32_Blend_BlitRow32_SSE2,           // S32_Blend,
      S32A_Opaque_BlitRow32_SSE2,         // S32A_Opaque
      S32A_Blend_BlitRow32_SSE2,          // S32A_Blend,
  };
  
  SkBlitRow::Proc SkBlitRow::PlatformProcs4444(unsigned flags) {
      return NULL;
  }
  
  SkBlitRow::Proc SkBlitRow::PlatformProcs565(unsigned flags) {
      return NULL;
  }
  
  SkBlitRow::ColorProc SkBlitRow::PlatformColorProc() {
      if (cachedHasSSE2()) {
          return Color32_SSE2;
      } else {
          return NULL;
      }
  }
  
  SkBlitRow::Proc32 SkBlitRow::PlatformProcs32(unsigned flags) {
      if (cachedHasSSE2()) {
          return platform_32_procs[flags];
      } else {
          return NULL;
      }
  }
  
  
  SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig,
                                                       SkMask::Format maskFormat,
                                                       SkColor color) {
      if (SkMask::kA8_Format != maskFormat) {
          return NULL;
      }
      
      ColorProc proc = NULL;
      if (cachedHasSSE2()) {
          switch (dstConfig) {
              case SkBitmap::kARGB_8888_Config:
                  // The SSE2 version is not (yet) faster for black, so we check
                  // for that.
                  if (SK_ColorBLACK != color) {
                      proc = SkARGB32_A8_BlitMask_SSE2;
                  }
                  break;
              default:
                  break;
          }
      }
      return proc;
  }
  
  SkBlitMask::BlitLCD16RowProc SkBlitMask::PlatformBlitRowProcs16(bool isOpaque) {
      if (cachedHasSSE2()) {
          if (isOpaque) {
              return SkBlitLCD16OpaqueRow_SSE2;
          } else {
              return SkBlitLCD16Row_SSE2;
          }
      } else {
          return NULL;
      }
  
  }
  SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig,
                                                   SkMask::Format maskFormat,
                                                   RowFlags flags) {
      return NULL;
  }
  
  SkMemset16Proc SkMemset16GetPlatformProc() {
      if (cachedHasSSE2()) {
          return sk_memset16_SSE2;
      } else {
          return NULL;
      }
  }
  
  SkMemset32Proc SkMemset32GetPlatformProc() {
      if (cachedHasSSE2()) {
          return sk_memset32_SSE2;
      } else {
          return NULL;
      }
  }
  