1e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com/*
2e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com *  Copyright 2013 The LibYuv Project Authors. All rights reserved.
3e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com *
4e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com *  Use of this source code is governed by a BSD-style license
5e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com *  that can be found in the LICENSE file in the root of the source
6e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com *  tree. An additional intellectual property rights grant can be found
7e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com *  in the file PATENTS. All contributing project authors may
8e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com *  be found in the AUTHORS file in the root of the source tree.
9e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com */
10e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
1176f86067a26810e6d7f3f8e65f136d808d4f144dfbarchard@google.com#include "./psnr.h"  // NOLINT
12e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
13e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#ifdef _OPENMP
14e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#include <omp.h>
15e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
16e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#ifdef _MSC_VER
17e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#include <intrin.h>  // For __cpuid()
18e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
19e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
2033d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com#ifdef __cplusplus
2133d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.comextern "C" {
2233d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com#endif
2333d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com
2476f86067a26810e6d7f3f8e65f136d808d4f144dfbarchard@google.comtypedef unsigned int uint32;  // NOLINT
25e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#ifdef _MSC_VER
26e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comtypedef unsigned __int64 uint64;
27e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#else  // COMPILER_MSVC
28e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__)
29e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comtypedef unsigned long uint64;  // NOLINT
30e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#else  // defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__)
31e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comtypedef unsigned long long uint64;  // NOLINT
32e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif  // __LP64__
33e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif  // _MSC_VER
34e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
35b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com// libyuv provides this function when linking library for jpeg support.
36b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com#if !defined(HAVE_JPEG)
37b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com
38e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
39e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#define HAS_SUMSQUAREERROR_NEON
40e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comstatic uint32 SumSquareError_NEON(const uint8* src_a,
41e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com                                  const uint8* src_b, int count) {
42e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  volatile uint32 sse;
4333d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com  asm volatile (  // NOLINT
44e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmov.u8    q7, #0                         \n"
45e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmov.u8    q9, #0                         \n"
46e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmov.u8    q8, #0                         \n"
47e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmov.u8    q10, #0                        \n"
48e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
49e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "1:                                        \n"
50e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vld1.u8    {q0}, [%0]!                    \n"
51e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vld1.u8    {q1}, [%1]!                    \n"
52e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vsubl.u8   q2, d0, d2                     \n"
53e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vsubl.u8   q3, d1, d3                     \n"
54e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmlal.s16  q7, d4, d4                     \n"
55e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmlal.s16  q8, d6, d6                     \n"
56e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmlal.s16  q8, d5, d5                     \n"
57e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmlal.s16  q10, d7, d7                    \n"
58e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "subs       %2, %2, #16                    \n"
59e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "bhi        1b                             \n"
60e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
61e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vadd.u32   q7, q7, q8                     \n"
62e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vadd.u32   q9, q9, q10                    \n"
63e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vadd.u32   q10, q7, q9                    \n"
64e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vpaddl.u32 q1, q10                        \n"
65e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vadd.u64   d0, d2, d3                     \n"
66e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "vmov.32    %3, d0[0]                      \n"
67e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    : "+r"(src_a),
68e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com      "+r"(src_b),
69e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com      "+r"(count),
70e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com      "=r"(sse)
71e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    :
7233d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com    : "memory", "cc", "q0", "q1", "q2", "q3", "q7", "q8", "q9", "q10");
73e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  return sse;
74e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
75eed4149e10fdc63046262f44df6c5cfc5b364307fbarchard@google.com#elif !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER)
76e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#define HAS_SUMSQUAREERROR_SSE2
77e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com__declspec(naked)
78e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comstatic uint32 SumSquareError_SSE2(const uint8* /*src_a*/,
79e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com                                  const uint8* /*src_b*/, int /*count*/) {
80e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  __asm {
81e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    mov        eax, [esp + 4]    // src_a
82e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    mov        edx, [esp + 8]    // src_b
83e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    mov        ecx, [esp + 12]   // count
84e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    pxor       xmm0, xmm0
85e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    pxor       xmm5, xmm5
86e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    sub        edx, eax
87e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
88e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  wloop:
89e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    movdqu     xmm1, [eax]
90e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    movdqu     xmm2, [eax + edx]
91e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    lea        eax,  [eax + 16]
92e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    movdqu     xmm3, xmm1
93e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    psubusb    xmm1, xmm2
94e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    psubusb    xmm2, xmm3
95e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    por        xmm1, xmm2
96e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    movdqu     xmm2, xmm1
97e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    punpcklbw  xmm1, xmm5
98e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    punpckhbw  xmm2, xmm5
99e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    pmaddwd    xmm1, xmm1
100e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    pmaddwd    xmm2, xmm2
101e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    paddd      xmm0, xmm1
102e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    paddd      xmm0, xmm2
103e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    sub        ecx, 16
104e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    ja         wloop
105e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
106e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    pshufd     xmm1, xmm0, 0EEh
107e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    paddd      xmm0, xmm1
108e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    pshufd     xmm1, xmm0, 01h
109e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    paddd      xmm0, xmm1
110e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    movd       eax, xmm0
111e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    ret
112e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  }
113e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
114e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#elif !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
115e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#define HAS_SUMSQUAREERROR_SSE2
116e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comstatic uint32 SumSquareError_SSE2(const uint8* src_a,
117e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com                                  const uint8* src_b, int count) {
118e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  uint32 sse;
11933d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com  asm volatile (  // NOLINT
120e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "pxor      %%xmm0,%%xmm0                   \n"
121e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "pxor      %%xmm5,%%xmm5                   \n"
122e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "sub       %0,%1                           \n"
123e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
124e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  "1:                                          \n"
125e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "movdqu    (%0),%%xmm1                     \n"
126e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "movdqu    (%0,%1,1),%%xmm2                \n"
127e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "lea       0x10(%0),%0                     \n"
128e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "movdqu    %%xmm1,%%xmm3                   \n"
129e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "psubusb   %%xmm2,%%xmm1                   \n"
130e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "psubusb   %%xmm3,%%xmm2                   \n"
131e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "por       %%xmm2,%%xmm1                   \n"
132e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "movdqu    %%xmm1,%%xmm2                   \n"
133e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "punpcklbw %%xmm5,%%xmm1                   \n"
134e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "punpckhbw %%xmm5,%%xmm2                   \n"
135e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "pmaddwd   %%xmm1,%%xmm1                   \n"
136e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "pmaddwd   %%xmm2,%%xmm2                   \n"
137e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "paddd     %%xmm1,%%xmm0                   \n"
138e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "paddd     %%xmm2,%%xmm0                   \n"
139e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "sub       $0x10,%2                        \n"
140e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "ja        1b                              \n"
141e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
142e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "pshufd    $0xee,%%xmm0,%%xmm1             \n"
143e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "paddd     %%xmm1,%%xmm0                   \n"
144e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "pshufd    $0x1,%%xmm0,%%xmm1              \n"
145e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "paddd     %%xmm1,%%xmm0                   \n"
146e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "movd      %%xmm0,%3                       \n"
147e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
148e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  : "+r"(src_a),      // %0
149e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "+r"(src_b),      // %1
150e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "+r"(count),      // %2
151e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "=g"(sse)         // %3
152e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  :
153e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  : "memory", "cc"
154e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if defined(__SSE2__)
155b432b7da2d8dd78db1fb4621f1be1a3c12d49cb2fbarchard@google.com    , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
156e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
15733d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com  );  // NOLINT
158e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  return sse;
159e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
160e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif  // LIBYUV_DISABLE_X86 etc
161e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
162e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if defined(HAS_SUMSQUAREERROR_SSE2)
163e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__)
164e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comstatic __inline void __cpuid(int cpu_info[4], int info_type) {
16533d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com  asm volatile (  // NOLINT
166e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "mov %%ebx, %%edi                          \n"
167e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "cpuid                                     \n"
168e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "xchg %%edi, %%ebx                         \n"
169e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
17033d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com    : "a"(info_type));
171e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
172e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#elif defined(__i386__) || defined(__x86_64__)
173e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comstatic __inline void __cpuid(int cpu_info[4], int info_type) {
17433d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com  asm volatile (  // NOLINT
175e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    "cpuid                                     \n"
176e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
17733d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com    : "a"(info_type));
178e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
179e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
180e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
181e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comstatic int CpuHasSSE2() {
182e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)
183e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  int cpu_info[4];
184e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  __cpuid(cpu_info, 1);
185e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  if (cpu_info[3] & 0x04000000) {
186e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    return 1;
187e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  }
188e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
189e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  return 0;
190e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
191e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif  // HAS_SUMSQUAREERROR_SSE2
192e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
193e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comstatic uint32 SumSquareError_C(const uint8* src_a,
194e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com                               const uint8* src_b, int count) {
195e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  uint32 sse = 0u;
196e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  for (int x = 0; x < count; ++x) {
197e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    int diff = src_a[x] - src_b[x];
198e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    sse += static_cast<uint32>(diff * diff);
199e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  }
200e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  return sse;
201e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
202e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com
203e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.comdouble ComputeSumSquareError(const uint8* src_a,
204e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com                             const uint8* src_b, int count) {
205e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  uint32 (*SumSquareError)(const uint8* src_a,
206e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com                           const uint8* src_b, int count) = SumSquareError_C;
207e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if defined(HAS_SUMSQUAREERROR_NEON)
208e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  SumSquareError = SumSquareError_NEON;
209e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
210e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#if defined(HAS_SUMSQUAREERROR_SSE2)
211e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  if (CpuHasSSE2()) {
212e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    SumSquareError = SumSquareError_SSE2;
213e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  }
214e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
215e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  const int kBlockSize = 1 << 15;
216e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  uint64 sse = 0;
217e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#ifdef _OPENMP
218e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#pragma omp parallel for reduction(+: sse)
219e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com#endif
220e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  for (int i = 0; i < (count - (kBlockSize - 1)); i += kBlockSize) {
221e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    sse += SumSquareError(src_a + i, src_b + i, kBlockSize);
222e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  }
223e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  src_a += count & ~(kBlockSize - 1);
224e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  src_b += count & ~(kBlockSize - 1);
225e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  int remainder = count & (kBlockSize - 1) & ~15;
226e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  if (remainder) {
227e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    sse += SumSquareError(src_a, src_b, remainder);
228e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    src_a += remainder;
229e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    src_b += remainder;
230e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  }
231e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  remainder = count & 15;
232e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  if (remainder) {
233e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com    sse += SumSquareError_C(src_a, src_b, remainder);
234e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  }
235e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com  return static_cast<double>(sse);
236e424a9de7a97543aed7789bdec3795567288eafffbarchard@google.com}
237b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com#endif
238b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com
239b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com// PSNR formula: psnr = 10 * log10 (Peak Signal^2 * size / sse)
240b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com// Returns 128.0 (kMaxPSNR) if sse is 0 (perfect match).
241b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.comdouble ComputePSNR(double sse, double size) {
242b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com  const double kMINSSE = 255.0 * 255.0 * size / pow(10.0, kMaxPSNR / 10.0);
243b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com  if (sse <= kMINSSE)
244b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com    sse = kMINSSE;  // Produces max PSNR of 128
245b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com  return 10.0 * log10(255.0 * 255.0 * size / sse);
246b7d674e305f53c83145405a9721a9e822afde004fbarchard@google.com}
24733d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com
24833d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com#ifdef __cplusplus
24933d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com}  // extern "C"
25033d34eaad81ca9b3e05055f5a669c7ec3cd3fe61fbarchard@google.com#endif
251