Version

menu_open
Target Platform(s):
Wwise SDK 2022.1.15
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  Copyright (c) 2024 Audiokinetic Inc.
25 *******************************************************************************/
26 
27 #pragma once
28 
31 #include <hilog/log.h>
32 
33 #if (defined(AK_CPU_X86_64) || defined(AK_CPU_X86))
34 #include <cpuid.h>
35 #endif
36 #include <time.h>
37 #include <stdlib.h>
38 
39 #define AK_THREAD_INIT_CODE(_threadProperties) syscall(__NR_sched_setaffinity, 0, sizeof(_threadProperties.dwAffinityMask), &_threadProperties.dwAffinityMask)
40 #define AK_SEC_TO_NANOSEC 1000000000ULL
41 
42 namespace AKPLATFORM
43 {
44  /// Platform Independent Helper
45  inline void PerformanceFrequency( AkInt64 * out_piFreq )
46  {
47  //Since Wall Clock is used, 1 NS is the frequency independent of the clock resolution
48  *out_piFreq = AK_SEC_TO_NANOSEC;
49  }
50 }
51 
52 #include <AK/Tools/POSIX/AkPlatformFuncs.h>
53 
54 /// Stack allocations.
55 #define AkAlloca( _size_ ) __builtin_alloca( _size_ )
56 
57 namespace AKPLATFORM
58 {
59  /// Output a debug message on the console (Ansi string)
60 
61 #if defined(AK_OPTIMIZED)
62  inline void OutputDebugMsg( const char* ){}
63 
64  template <int MaxSize = 0> // Unused
65  inline void OutputDebugMsgV( const char* in_pszFmt, ... ) {}
66 #else
67  inline void OutputDebugMsg( const char* in_pszMsg )
68  {
69  OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "Wwise", "%{public}s", in_pszMsg);
70  }
71 
72  /// Output a debug message on the console (variadic function).
73  template <int MaxSize = 256>
74  inline void OutputDebugMsgV( const char* in_pszFmt, ...)
75  {
76  // OpenHarmony hides the replacement tokens by default, so we have to do our own string formatting to avoid that.
77  char msg[MaxSize];
78  va_list args;
79  va_start(args, in_pszFmt);
80  vsnprintf(msg, MaxSize, in_pszFmt, args);
81  va_end(args);
82  OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "Wwise", "%{public}s", msg);
83  }
84 
85 #endif
86 
87  // Time functions
88  // ------------------------------------------------------------------
89 
90  /// Platform Independent Helper
91  inline void PerformanceCounter( AkInt64 * out_piLastTime )
92  {
93  struct timespec clockNow;
94  clock_gettime(CLOCK_MONOTONIC, &clockNow);
95  //This give the wallclock time in NS
96  *out_piLastTime = clockNow.tv_sec*AK_SEC_TO_NANOSEC + clockNow.tv_nsec;
97  }
98 
99 
100  template<class destType, class srcType>
101  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 *) )
102  {
103  size_t i;
104  size_t lenToCopy = srcStrLen(in_pSrc);
105 
106  lenToCopy = (lenToCopy > in_MaxSize-1) ? in_MaxSize-1 : lenToCopy;
107  for(i = 0; i < lenToCopy; i++)
108  {
109  in_pdDest[i] = (destType) in_pSrc[i];
110  }
111  in_pdDest[lenToCopy] = (destType)0;
112 
113  return lenToCopy;
114  }
115 
116  #define CONVERT_UTF16_TO_CHAR( _astring_, _charstring_ ) \
117  _charstring_ = (char*)AkAlloca( (1 + AKPLATFORM::AkUtf16StrLen((const AkUtf16*)_astring_)) * sizeof(char) ); \
118  AK_UTF16_TO_CHAR( _charstring_, (const AkUtf16*)_astring_, AKPLATFORM::AkUtf16StrLen((const AkUtf16*)_astring_)+1 )
119 
120  #define AK_UTF8_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, strlen, strlen )
121  #define AK_UTF16_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, strlen, AKPLATFORM::AkUtf16StrLen )
122  #define AK_UTF16_TO_CHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, strlen, AKPLATFORM::AkUtf16StrLen )
123  #define AK_CHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, AKPLATFORM::AkUtf16StrLen, strlen)
124  #define AK_OSCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkSimpleConvertString( in_pdDest, in_pSrc, in_MaxSize, AKPLATFORM::AkUtf16StrLen, strlen)
125 
126  #if __BIGGEST_ALIGNMENT__ < AK_SIMD_ALIGNMENT
127  #define AkAllocaSIMD( _size_ ) __builtin_alloca_with_align( _size_, AK_SIMD_ALIGNMENT*8 )
128  #endif
129 
130  /// Platform Independent Helper
131  inline void AkCreateThread(
132  AkThreadRoutine pStartRoutine, // Thread routine.
133  void * pParams, // Routine params.
134  const AkThreadProperties & in_threadProperties, // Properties. NULL for default.
135  AkThread * out_pThread, // Returned thread handle.
136  const char * /*in_szThreadName*/ ) // Opt thread name.
137  {
138  AKASSERT( out_pThread != NULL );
139 
140  pthread_attr_t attr;
141 
142  // Create the attr
143  AKVERIFY(!pthread_attr_init(&attr));
144  // Set the stack size
145  AKVERIFY(!pthread_attr_setstacksize(&attr,in_threadProperties.uStackSize));
146 
147  AKVERIFY(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
148 
149  // Create the tread
150  int threadError = pthread_create( out_pThread, &attr, pStartRoutine, pParams);
151  AKASSERT( threadError == 0 );
152  AKVERIFY(!pthread_attr_destroy(&attr));
153 
154  if( threadError != 0 )
155  {
156  AkClearThread( out_pThread );
157  return;
158  }
159 
160  // ::CreateThread() return NULL if it fails.
161  if ( !*out_pThread )
162  {
163  AkClearThread( out_pThread );
164  return;
165  }
166 
167  // Try to set the thread policy
168  int sched_policy = in_threadProperties.uSchedPolicy;
169 
170  // Get the priority for the policy
171  int minPriority, maxPriority;
172  minPriority = sched_get_priority_min(sched_policy);
173  maxPriority = sched_get_priority_max(sched_policy);
174 
175  // Set the thread priority if valid
176  sched_param schedParam;
177  schedParam.sched_priority = in_threadProperties.nPriority;
178  AKASSERT( in_threadProperties.nPriority >= minPriority && in_threadProperties.nPriority <= maxPriority );
179 
180  int err = pthread_setschedparam(*out_pThread, sched_policy, &schedParam);
181  if (err != 0)
182  {
183  //Make sure the priority is well set, even if the policy could not.
184  sched_policy = SCHED_OTHER;
185  minPriority = sched_get_priority_min(sched_policy);
186  maxPriority = sched_get_priority_max(sched_policy);
187  if (in_threadProperties.nPriority == AK_THREAD_PRIORITY_ABOVE_NORMAL)
188  schedParam.sched_priority = maxPriority;
189  else if (in_threadProperties.nPriority == AK_THREAD_PRIORITY_BELOW_NORMAL)
190  schedParam.sched_priority = minPriority;
191  else
192  schedParam.sched_priority = (maxPriority + minPriority) / 2;
193  err = pthread_setschedparam(*out_pThread, sched_policy, &schedParam);
194  AKASSERT(err == 0);
195  }
196  }
197 
198  #define AK_FILEHANDLE_TO_UINTPTR(_h) ((AkUIntPtr)_h)
199  #define AK_SET_FILEHANDLE_TO_UINTPTR(_h,_u) _h = (AkFileHandle)_u
200 
201 #if (defined(AK_CPU_X86_64) || defined(AK_CPU_X86))
202  // Once our minimum compiler version supports __get_cpuid_count, these asm blocks can be replaced
203  #if defined(__i386__) && defined(__PIC__)
204  // %ebx may be the PIC register.
205  #define __ak_cpuid_count(level, count, a, b, c, d) \
206  __asm__ ("xchg{l}\t{%%}ebx, %k1\n\t" \
207  "cpuid\n\t" \
208  "xchg{l}\t{%%}ebx, %k1\n\t" \
209  : "=a" (a), "=&r" (b), "=c" (c), "=d" (d) \
210  : "0" (level), "2" (count))
211  #elif defined(__x86_64__) && defined(__PIC__)
212  // %rbx may be the PIC register.
213  #define __ak_cpuid_count(level, count, a, b, c, d) \
214  __asm__ ("xchg{q}\t{%%}rbx, %q1\n\t" \
215  "cpuid\n\t" \
216  "xchg{q}\t{%%}rbx, %q1\n\t" \
217  : "=a" (a), "=&r" (b), "=c" (c), "=d" (d) \
218  : "0" (level), "2" (count))
219  #else
220  #define __ak_cpuid_count(level, count, a, b, c, d) \
221  __asm__ ("cpuid\n\t" \
222  : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
223  : "0" (level), "2" (count))
224  #endif
225 
226  static __inline int __ak_get_cpuid_count(unsigned int __leaf,
227  unsigned int __subleaf,
228  unsigned int *__eax, unsigned int *__ebx,
229  unsigned int *__ecx, unsigned int *__edx)
230  {
231  unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0);
232 
233  if (__max_leaf == 0 || __max_leaf < __leaf)
234  return 0;
235 
236  __ak_cpuid_count(__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx);
237  return 1;
238  }
239 
240  /// Support to fetch the CPUID for the platform. Only valid for X86 targets
241  /// \remark Note that IAkProcessorFeatures should be preferred to fetch this data
242  /// as it will have already translated the feature bits into AK-relevant enums
243  inline void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
244  {
245  __ak_get_cpuid_count( in_uLeafOpcode, in_uSubLeafOpcode,
246  &out_uCPUFeatures[0],
247  &out_uCPUFeatures[1],
248  &out_uCPUFeatures[2],
249  &out_uCPUFeatures[3]);
250  }
251 #endif
252 }
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)
int nPriority
Thread priority.
Platform-dependent helpers.
void OutputDebugMsg(const char *in_pszMsg)
Output a debug message on the console (Ansi string)
void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
#define NULL
Definition: AkTypes.h:46
#define AK_THREAD_PRIORITY_ABOVE_NORMAL
void AkCreateThread(AkThreadRoutine pStartRoutine, void *pParams, const AkThreadProperties &in_threadProperties, AkThread *out_pThread, const char *)
Platform Independent Helper.
void OutputDebugMsgV(const char *in_pszFmt,...)
Output a debug message on the console (variadic function).
void PerformanceCounter(AkInt64 *out_piLastTime)
Platform Independent Helper.
nn::os::ThreadFunction AkThreadRoutine
Thread routine.
Definition: AkTypes.h:90
#define AK_SEC_TO_NANOSEC
#define AKASSERT(Condition)
Definition: AkAssert.h:67
#define AKVERIFY(x)
Definition: AkAssert.h:69
#define __ak_cpuid_count(level, count, a, b, c, d)
AkForceInline void AkClearThread(AkThread *in_pThread)
Platform Independent Helper.
int64_t AkInt64
Signed 64-bit integer.
size_t uStackSize
Thread stack size.
void PerformanceFrequency(AkInt64 *out_piFreq)
Platform Independent Helper.
int uSchedPolicy
Thread scheduling policy.
uint32_t AkUInt32
Unsigned 32-bit integer.
#define AK_THREAD_PRIORITY_BELOW_NORMAL
size_t AkSimpleConvertString(destType *in_pdDest, const srcType *in_pSrc, size_t in_MaxSize, size_t destStrLen(const destType *), size_t srcStrLen(const srcType *))

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise