Wwise Version
Target Platform(s):
Wwise SDK 2021.1.2
AkPlatformFuncs.h
Go to the documentation of this file.
1 /*******************************************************************************
2 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
3 released in source code form as part of the SDK installer package.
4 
5 Commercial License Usage
6 
7 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
8 may use this file in accordance with the end user license agreement provided
9 with the software or, alternatively, in accordance with the terms contained in a
10 written agreement between you and Audiokinetic Inc.
11 
12 Apache License Usage
13 
14 Alternatively, this file may be used under the Apache License, Version 2.0 (the
15 "Apache License"); you may not use this file except in compliance with the
16 Apache License. You may obtain a copy of the Apache License at
17 http://www.apache.org/licenses/LICENSE-2.0.
18 
19 Unless required by applicable law or agreed to in writing, software distributed
20 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
21 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
22 the specific language governing permissions and limitations under the License.
23 
24  Version: v2021.1.2 Build: 7629
25  Copyright (c) 2006-2021 Audiokinetic Inc.
26 *******************************************************************************/
27 
28 #pragma once
29 
32 #include <android/log.h>
33 
34 #if (defined(AK_CPU_X86_64) || defined(AK_CPU_X86))
35 #include <cpuid.h>
36 #endif
37 #include <time.h>
38 #include <stdlib.h>
39 
40 #define AK_THREAD_INIT_CODE(_threadProperties) syscall(__NR_sched_setaffinity, 0, sizeof(_threadProperties.dwAffinityMask), &_threadProperties.dwAffinityMask)
41 #define AK_SEC_TO_NANOSEC 1000000000ULL
42 
43 namespace AKPLATFORM
44 {
45  /// Platform Independent Helper
46  inline void PerformanceFrequency( AkInt64 * out_piFreq )
47  {
48  //Since Wall Clock is used, 1 NS is the frequency independent of the clock resolution
49  *out_piFreq = AK_SEC_TO_NANOSEC;
50  }
51 }
52 
53 #include <AK/Tools/POSIX/AkPlatformFuncs.h>
54 
55 #if (defined AK_LUMIN) && !(defined AK_OPTIMIZED)
56 #include <ml_logging.h>
57 #endif
58 
59 /// Stack allocations.
60 #define AkAlloca( _size_ ) __builtin_alloca( _size_ )
61 
62 namespace AKPLATFORM
63 {
64  /// Output a debug message on the console (Ansi string)
65 
66 #if defined(AK_OPTIMIZED)
67  inline void OutputDebugMsg( const char* ){}
68 
69  template <int MaxSize = 0> // Unused
70  inline void OutputDebugMsgV( const char* in_pszFmt, ... ) {}
71 #elif defined(AK_LUMIN)
72  inline void OutputDebugMsg( const char* in_pszMsg )
73  {
74  // To see output of this (mldb on lumin)
75  // mldb logcat ActivityManager:I YourApplication:D AKDEBUG:D *:S
76  ML_LOG_TAG(Info, "AKDEBUG", "%s", in_pszMsg);
77  }
78 
79  /// Output a debug message on the console (variadic function).
80  template <int MaxSize = 256>
81  inline void OutputDebugMsgV( const char* in_pszFmt, ... )
82  {
83  // magic leap doesn't have a log that takes a va_list
84 
85  int size = 0;
86  {
87  // Try with a reasonable guess first
88  char msg[MaxSize];
89  msg[MaxSize - 1] = '\0';
90 
91  va_list args;
92  va_start(args, in_pszFmt);
93  size = vsnprintf(msg, MaxSize, in_pszFmt, args);
94  va_end(args);
95 
96  // If it was enough, print to debug log
97  if (0 <= size && size <= MaxSize)
98  {
99  ML_LOG_TAG(Info, "AKDEBUG", in_pszFmt, args);
100  return;
101  }
102  }
103 
104  // Else, we need more memory to prevent truncation
105  {
106  // size + 1 more char for the last '\0'
107  size++;
108 
109  char* msg = (char*)AkAlloca((size) * sizeof(char));
110  msg[size - 1] = '\0';
111 
112  va_list args;
113  va_start(args, in_pszFmt);
114  vsnprintf(msg, size, in_pszFmt, args);
115  va_end(args);
116 
117  ML_LOG_TAG(Info, "AKDEBUG", in_pszFmt, args);
118  }
119  }
120 #else // AK_ANDROID
121  inline void OutputDebugMsg( const char* in_pszMsg )
122  {
123  // To see output of this
124  // adb logcat ActivityManager:I YourApplication:D AKDEBUG:D *:S
125  __android_log_print(ANDROID_LOG_INFO, "AKDEBUG", "%s", in_pszMsg);
126  }
127 
128  /// Output a debug message on the console (variadic function).
129  template <int MaxSize = 0> // Unused
130  inline void OutputDebugMsgV( const char* in_pszFmt, ...)
131  {
132  va_list args;
133  va_start(args, in_pszFmt);
134  __android_log_vprint(ANDROID_LOG_INFO, "AKDEBUG", in_pszFmt, args);
135  va_end(args);
136  }
137 #endif
138 
139  // Time functions
140  // ------------------------------------------------------------------
141 
142  /// Platform Independent Helper
143  inline void PerformanceCounter( AkInt64 * out_piLastTime )
144  {
145  struct timespec clockNow;
146  clock_gettime(CLOCK_MONOTONIC, &clockNow);
147  //This give the wallclock time in NS
148  *out_piLastTime = clockNow.tv_sec*AK_SEC_TO_NANOSEC + clockNow.tv_nsec;
149  }
150 
151 
152  template<class destType, class srcType>
153  inline size_t AkSimpleConvertString( destType* in_pdDest, const srcType* in_pSrc, size_t in_MaxSize, size_t destStrLen(const destType *), size_t srcStrLen(const srcType *) )
154  {
155  size_t i;
156  size_t lenToCopy = srcStrLen(in_pSrc);
157 
158  lenToCopy = (lenToCopy > in_MaxSize-1) ? in_MaxSize-1 : lenToCopy;
159  for(i = 0; i < lenToCopy; i++)
160  {
161  in_pdDest[i] = (destType) in_pSrc[i];
162  }
163  in_pdDest[lenToCopy] = (destType)0;
164 
165  return lenToCopy;
166  }
167 
168  #define CONVERT_UTF16_TO_CHAR( _astring_, _charstring_ ) \
169  _charstring_ = (char*)AkAlloca( (1 + AKPLATFORM::AkUtf16StrLen((const AkUtf16*)_astring_)) * sizeof(char) ); \
170  AK_UTF16_TO_CHAR( _charstring_, (const AkUtf16*)_astring_, AKPLATFORM::AkUtf16StrLen((const AkUtf16*)_astring_)+1 )
171 
172  #define AK_UTF8_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, strlen, strlen )
173  #define AK_UTF16_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, strlen, AKPLATFORM::AkUtf16StrLen )
174  #define AK_UTF16_TO_CHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, strlen, AKPLATFORM::AkUtf16StrLen )
175  #define AK_CHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, AKPLATFORM::AkUtf16StrLen, strlen)
176  #define AK_OSCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, AKPLATFORM::AkUtf16StrLen, strlen)
177 
178  #if __BIGGEST_ALIGNMENT__ < AK_SIMD_ALIGNMENT
179  #define AkAllocaSIMD( _size_ ) __builtin_alloca_with_align( _size_, AK_SIMD_ALIGNMENT*8 )
180  #endif
181 
182  /// Platform Independent Helper
183  inline void AkCreateThread(
184  AkThreadRoutine pStartRoutine, // Thread routine.
185  void * pParams, // Routine params.
186  const AkThreadProperties & in_threadProperties, // Properties. NULL for default.
187  AkThread * out_pThread, // Returned thread handle.
188  const char * /*in_szThreadName*/ ) // Opt thread name.
189  {
190  AKASSERT( out_pThread != NULL );
191 
192  pthread_attr_t attr;
193 
194  // Create the attr
195  AKVERIFY(!pthread_attr_init(&attr));
196  // Set the stack size
197  AKVERIFY(!pthread_attr_setstacksize(&attr,in_threadProperties.uStackSize));
198 
199  AKVERIFY(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
200 
201  // Create the tread
202  int threadError = pthread_create( out_pThread, &attr, pStartRoutine, pParams);
203  AKASSERT( threadError == 0 );
204  AKVERIFY(!pthread_attr_destroy(&attr));
205 
206  if( threadError != 0 )
207  {
208  AkClearThread( out_pThread );
209  return;
210  }
211 
212  // ::CreateThread() return NULL if it fails.
213  if ( !*out_pThread )
214  {
215  AkClearThread( out_pThread );
216  return;
217  }
218 
219  // Try to set the thread policy
220  int sched_policy = in_threadProperties.uSchedPolicy;
221 
222  // Get the priority for the policy
223  int minPriority, maxPriority;
224  minPriority = sched_get_priority_min(sched_policy);
225  maxPriority = sched_get_priority_max(sched_policy);
226 
227  // Set the thread priority if valid
228  sched_param schedParam;
229  schedParam.sched_priority = in_threadProperties.nPriority;
230  AKASSERT( in_threadProperties.nPriority >= minPriority && in_threadProperties.nPriority <= maxPriority );
231 
232  //pthread_setschedparam WILL fail on Android Lollipop when used with SCHED_FIFO (the default). Not allowed anymore. (ignore the error code).
233  int err = pthread_setschedparam(*out_pThread, sched_policy, &schedParam);
234  if (err != 0)
235  {
236  //Make sure the priority is well set, even if the policy could not.
237  sched_policy = SCHED_NORMAL;
238  minPriority = sched_get_priority_min(sched_policy);
239  maxPriority = sched_get_priority_max(sched_policy);
240  if (in_threadProperties.nPriority == AK_THREAD_PRIORITY_ABOVE_NORMAL)
241  schedParam.sched_priority = maxPriority;
242  else if (in_threadProperties.nPriority == AK_THREAD_PRIORITY_BELOW_NORMAL)
243  schedParam.sched_priority = minPriority;
244  else
245  schedParam.sched_priority = (maxPriority + minPriority) / 2;
246  err = pthread_setschedparam(*out_pThread, sched_policy, &schedParam);
247  AKASSERT(err == 0);
248  }
249  }
250 
251 #if (defined(AK_CPU_X86_64) || defined(AK_CPU_X86))
252  // Once our minimum compiler version supports __get_cpuid_count, these asm blocks can be replaced
253  #if defined(__i386__) && defined(__PIC__)
254  // %ebx may be the PIC register.
255  #define __ak_cpuid_count(level, count, a, b, c, d) \
256  __asm__ ("xchg{l}\t{%%}ebx, %k1\n\t" \
257  "cpuid\n\t" \
258  "xchg{l}\t{%%}ebx, %k1\n\t" \
259  : "=a" (a), "=&r" (b), "=c" (c), "=d" (d) \
260  : "0" (level), "2" (count))
261  #elif defined(__x86_64__) && defined(__PIC__)
262  // %rbx may be the PIC register.
263  #define __ak_cpuid_count(level, count, a, b, c, d) \
264  __asm__ ("xchg{q}\t{%%}rbx, %q1\n\t" \
265  "cpuid\n\t" \
266  "xchg{q}\t{%%}rbx, %q1\n\t" \
267  : "=a" (a), "=&r" (b), "=c" (c), "=d" (d) \
268  : "0" (level), "2" (count))
269  #else
270  #define __ak_cpuid_count(level, count, a, b, c, d) \
271  __asm__ ("cpuid\n\t" \
272  : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
273  : "0" (level), "2" (count))
274  #endif
275 
276  static __inline int __ak_get_cpuid_count(unsigned int __leaf,
277  unsigned int __subleaf,
278  unsigned int *__eax, unsigned int *__ebx,
279  unsigned int *__ecx, unsigned int *__edx)
280  {
281  unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0);
282 
283  if (__max_leaf == 0 || __max_leaf < __leaf)
284  return 0;
285 
286  __ak_cpuid_count(__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx);
287  return 1;
288  }
289 
290  /// Support to fetch the CPUID for the platform. Only valid for X86 targets
291  /// \remark Note that IAkProcessorFeatures should be preferred to fetch this data
292  /// as it will have already translated the feature bits into AK-relevant enums
293  inline void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
294  {
295  __ak_get_cpuid_count( in_uLeafOpcode, in_uSubLeafOpcode,
296  &out_uCPUFeatures[0],
297  &out_uCPUFeatures[1],
298  &out_uCPUFeatures[2],
299  &out_uCPUFeatures[3]);
300  }
301 #endif
302 }
static __inline int __ak_get_cpuid_count(unsigned int __leaf, unsigned int __subleaf, unsigned int *__eax, unsigned int *__ebx, unsigned int *__ecx, unsigned int *__edx)
Definition: AkPlatformFuncs.h:276
int nPriority
Thread priority.
Definition: AkPlatformFuncs.h:49
Platform-dependent helpers.
Definition: AkPlatformFuncs.h:157
#define __ak_cpuid_count(level, count, a, b, c, d)
Definition: AkPlatformFuncs.h:270
void OutputDebugMsg(const char *in_pszMsg)
Output a debug message on the console (Ansi string)
Definition: AkPlatformFuncs.h:121
void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
Definition: AkPlatformFuncs.h:293
#define NULL
Definition: AkTypes.h:47
#define AK_THREAD_PRIORITY_ABOVE_NORMAL
Definition: AkPlatformFuncs.h:79
void AkCreateThread(AkThreadRoutine pStartRoutine, void *pParams, const AkThreadProperties &in_threadProperties, AkThread *out_pThread, const char *)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:183
void OutputDebugMsgV(const char *in_pszFmt,...)
Output a debug message on the console (variadic function).
Definition: AkPlatformFuncs.h:130
void PerformanceCounter(AkInt64 *out_piLastTime)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:143
nn::os::ThreadFunction AkThreadRoutine
Thread routine.
Definition: AkTypes.h:99
int64_t AkInt64
Signed 64-bit integer.
Definition: AkTypes.h:91
#define AKASSERT(Condition)
Definition: AkAssert.h:76
#define AKVERIFY(x)
Definition: AkAssert.h:78
#define AkAlloca(_size_)
Stack allocations.
Definition: AkPlatformFuncs.h:60
#define AK_SEC_TO_NANOSEC
Definition: AkPlatformFuncs.h:41
AkForceInline void AkClearThread(AkThread *in_pThread)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:283
size_t uStackSize
Thread stack size.
Definition: AkPlatformFuncs.h:51
void PerformanceFrequency(AkInt64 *out_piFreq)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:46
int uSchedPolicy
Thread scheduling policy.
Definition: AkPlatformFuncs.h:52
#define AK_THREAD_PRIORITY_BELOW_NORMAL
Definition: AkPlatformFuncs.h:80
size_t AkSimpleConvertString(destType *in_pdDest, const srcType *in_pSrc, size_t in_MaxSize, size_t destStrLen(const destType *), size_t srcStrLen(const srcType *))
Definition: AkPlatformFuncs.h:153
Definition: AkTypes.h:104
uint32_t AkUInt32
Unsigned 32-bit integer.
Definition: AkTypes.h:77