1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 /* The global function contained in this file initializes SPL function
12  * pointers, currently only for ARM platforms.
13  *
14  * Some code came from common/rtcd.c in the WebM project.
15  */
16 
17 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
18 #include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
19 
20 /* Declare function pointers. */
21 MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
22 MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
23 MaxValueW16 WebRtcSpl_MaxValueW16;
24 MaxValueW32 WebRtcSpl_MaxValueW32;
25 MinValueW16 WebRtcSpl_MinValueW16;
26 MinValueW32 WebRtcSpl_MinValueW32;
27 CrossCorrelation WebRtcSpl_CrossCorrelation;
28 DownsampleFast WebRtcSpl_DownsampleFast;
29 ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound;
30 
31 #if (defined(WEBRTC_DETECT_ARM_NEON) || !defined(WEBRTC_ARCH_ARM_NEON)) && \
32     !defined(MIPS32_LE) && !defined(WEBRTC_ARCH_ARM64_NEON)
33 /* Initialize function pointers to the generic C version. */
InitPointersToC()34 static void InitPointersToC() {
35   WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C;
36   WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
37   WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C;
38   WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C;
39   WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C;
40   WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C;
41   WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC;
42   WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC;
43   WebRtcSpl_ScaleAndAddVectorsWithRound =
44       WebRtcSpl_ScaleAndAddVectorsWithRoundC;
45 }
46 #endif
47 
48 #if defined(WEBRTC_DETECT_ARM_NEON) || defined(WEBRTC_ARCH_ARM_NEON) || \
49   (defined WEBRTC_ARCH_ARM64_NEON)
50 /* Initialize function pointers to the Neon version. */
InitPointersToNeon()51 static void InitPointersToNeon() {
52   WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon;
53   WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon;
54   WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon;
55   WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon;
56   WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon;
57   WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon;
58   WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationNeon;
59   WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon;
60   /* TODO(henrik.lundin): re-enable NEON when the crash from bug 3243 is
61      understood. */
62   WebRtcSpl_ScaleAndAddVectorsWithRound =
63       WebRtcSpl_ScaleAndAddVectorsWithRoundC;
64 }
65 #endif
66 
67 #if defined(MIPS32_LE)
68 /* Initialize function pointers to the MIPS version. */
InitPointersToMIPS()69 static void InitPointersToMIPS() {
70   WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips;
71   WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips;
72   WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips;
73   WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips;
74   WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips;
75   WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelation_mips;
76   WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips;
77 #if defined(MIPS_DSP_R1_LE)
78   WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32_mips;
79   WebRtcSpl_ScaleAndAddVectorsWithRound =
80       WebRtcSpl_ScaleAndAddVectorsWithRound_mips;
81 #else
82   WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
83   WebRtcSpl_ScaleAndAddVectorsWithRound =
84       WebRtcSpl_ScaleAndAddVectorsWithRoundC;
85 #endif
86 }
87 #endif
88 
InitFunctionPointers(void)89 static void InitFunctionPointers(void) {
90 #if defined(WEBRTC_DETECT_ARM_NEON)
91   if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
92     InitPointersToNeon();
93   } else {
94     InitPointersToC();
95   }
96 #elif defined(WEBRTC_ARCH_ARM_NEON) || defined(WEBRTC_ARCH_ARM64_NEON)
97   InitPointersToNeon();
98 #elif defined(MIPS32_LE)
99   InitPointersToMIPS();
100 #else
101   InitPointersToC();
102 #endif  /* WEBRTC_DETECT_ARM_NEON */
103 }
104 
105 #if defined(WEBRTC_POSIX)
106 #include <pthread.h>
107 
once(void (* func)(void))108 static void once(void (*func)(void)) {
109   static pthread_once_t lock = PTHREAD_ONCE_INIT;
110   pthread_once(&lock, func);
111 }
112 
113 #elif defined(_WIN32)
114 #include <windows.h>
115 
once(void (* func)(void))116 static void once(void (*func)(void)) {
117   /* Didn't use InitializeCriticalSection() since there's no race-free context
118    * in which to execute it.
119    *
120    * TODO(kma): Change to different implementation (e.g.
121    * InterlockedCompareExchangePointer) to avoid issues similar to
122    * http://code.google.com/p/webm/issues/detail?id=467.
123    */
124   static CRITICAL_SECTION lock = {(void *)((size_t)-1), -1, 0, 0, 0, 0};
125   static int done = 0;
126 
127   EnterCriticalSection(&lock);
128   if (!done) {
129     func();
130     done = 1;
131   }
132   LeaveCriticalSection(&lock);
133 }
134 
135 /* There's no fallback version as an #else block here to ensure thread safety.
136  * In case of neither pthread for WEBRTC_POSIX nor _WIN32 is present, build
137  * system should pick it up.
138  */
139 #endif  /* WEBRTC_POSIX */
140 
WebRtcSpl_Init()141 void WebRtcSpl_Init() {
142   once(InitFunctionPointers);
143 }
144