Version
menu_open
link
Wwise SDK 2023.1.1
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 // AkPlatformFuncs.h
28 
29 /// \file
30 /// Platform-dependent functions definition.
31 
32 #ifndef _AK_TOOLS_COMMON_AKPLATFORMFUNCS_H
33 #define _AK_TOOLS_COMMON_AKPLATFORMFUNCS_H
34 
37 
38 // Uncomment the following to enable built-in platform profiler markers in the sound engine
39 //#define AK_ENABLE_INSTRUMENT
40 
41 #if defined(AK_WIN)
43 
44 #elif defined (AK_XBOX)
46 
47 #elif defined (AK_APPLE)
49 #include <AK/Tools/POSIX/AkPlatformFuncs.h>
50 
51 #elif defined( AK_ANDROID ) || defined ( AK_LINUX_AOSP )
53 
54 #elif defined (AK_PS4)
56 
57 #elif defined (AK_PS5)
59 
60 #elif defined (AK_EMSCRIPTEN)
62 
63 #elif defined (AK_LINUX)
65 #include <AK/Tools/POSIX/AkPlatformFuncs.h>
66 
67 #elif defined (AK_QNX)
68 #include <AK/Tools/QNX/AkPlatformFuncs.h>
69 #include <AK/Tools/POSIX/AkPlatformFuncs.h>
70 
71 #elif defined (AK_NX)
73 
74 #else
75 #error AkPlatformFuncs.h: Undefined platform
76 #endif
77 
78 #ifndef AkPrefetchZero
79 #define AkPrefetchZero(___Dest, ___Size)
80 #endif
81 
82 #ifndef AkPrefetchZeroAligned
83 #define AkPrefetchZeroAligned(___Dest, ___Size)
84 #endif
85 
86 #ifndef AkZeroMemAligned
87 #define AkZeroMemAligned(___Dest, ___Size) AKPLATFORM::AkMemSet(___Dest, 0, ___Size);
88 #endif
89 #ifndef AkZeroMemLarge
90 #define AkZeroMemLarge(___Dest, ___Size) AKPLATFORM::AkMemSet(___Dest, 0, ___Size);
91 #endif
92 #ifndef AkZeroMemSmall
93 #define AkZeroMemSmall(___Dest, ___Size) AKPLATFORM::AkMemSet(___Dest, 0, ___Size);
94 #endif
95 
96 #ifndef AkAllocaSIMD
97 #ifdef __clang__
98 #if __has_builtin( __builtin_alloca_with_align )
99 #define AkAllocaSIMD( _size_ ) __builtin_alloca_with_align( _size_, 128 )
100 #else
101 // work around alloca alignment issues in versions of clang before 4.0
102 #define AkAllocaSIMD( _size_ ) (void*)( ( ( uintptr_t )AkAlloca( _size_ + 16 ) + 0xF ) & ~0xF )
103 #endif
104 #else
105 #define AkAllocaSIMD( _size_ ) AkAlloca( _size_ )
106 #endif
107 #endif
108 
109 #ifndef AK_THREAD_INIT_CODE
110 #define AK_THREAD_INIT_CODE(_threadProperties)
111 #endif
112 
113 /// Platform-dependent helpers
114 namespace AKPLATFORM
115 {
117  {
118  AkGetDefaultThreadProperties(out_threadProperties);
119  out_threadProperties.nPriority = AK_THREAD_PRIORITY_ABOVE_NORMAL;
120  }
121 
122  // fallback implementations for when platform don't have their own implementation
123 #if !defined(AK_BIT_SCAN_INSTRUCTIONS)
124 
125  // AkPopCount returns how many set bits there are in the provided value
126 #if __clang__ || defined __GNUG__
128  {
129  return __builtin_popcount(in_bits);
130  }
131 #else
133  {
134  AkUInt32 num = 0;
135  while (in_bits) { ++num; in_bits &= in_bits - 1; }
136  return num;
137  }
138 #endif
139 
140 
141  // AkBitScanForward returns how many 0s there are until the least-significant-bit is set, or the length of the param if the value is zero
142 #if defined _MSC_VER && (defined AK_CPU_X86_64 || defined AK_CPU_ARM_64)
144  {
145  unsigned long ret = 0;
146  _BitScanForward64(&ret, in_bits);
147  return in_bits ? ret : 64;
148  }
149 #elif __clang__ || defined __GNUG__
151  {
152  return __builtin_ctzll(in_bits);
153  }
154 #else
156  {
157  if (in_bits == 0) return 64;
158  AkUInt32 ret = 0;
159  if ((in_bits & 0x00000000FFFFFFFFULL) == 0) { ret += 32; in_bits >>= 32; }
160  if ((in_bits & 0x000000000000FFFFULL) == 0) { ret += 16; in_bits >>= 16; }
161  if ((in_bits & 0x00000000000000FFULL) == 0) { ret += 8; in_bits >>= 8; }
162  if ((in_bits & 0x000000000000000FULL) == 0) { ret += 4; in_bits >>= 4; }
163  if ((in_bits & 0x0000000000000003ULL) == 0) { ret += 2; in_bits >>= 2; }
164  if ((in_bits & 0x0000000000000001ULL) == 0) { ret += 1; in_bits >>= 1; }
165  return ret;
166  }
167 #endif
168 
169 #if defined _MSC_VER
171  {
172  unsigned long ret = 0;
173  _BitScanForward(&ret, in_bits);
174  return in_bits ? ret : 32;
175  }
176 
177 #elif __clang__ || defined __GNUG__
179  {
180  return __builtin_ctzl(in_bits);
181  }
182 #else
184  {
185  if (in_bits == 0) return 32;
186  AkUInt32 ret = 0;
187  if ((in_bits & 0x0000FFFFULL) == 0) { ret += 16; in_bits >>= 16; }
188  if ((in_bits & 0x000000FFULL) == 0) { ret += 8; in_bits >>= 8; }
189  if ((in_bits & 0x0000000FULL) == 0) { ret += 4; in_bits >>= 4; }
190  if ((in_bits & 0x00000003ULL) == 0) { ret += 2; in_bits >>= 2; }
191  if ((in_bits & 0x00000001ULL) == 0) { ret += 1; in_bits >>= 1; }
192  return ret;
193  }
194 #endif
195 
196  // AkBitScanReverse returns how many 0s there are after the most-significant-bit is set, or the length of the param if the value is zero
197 #if defined _MSC_VER && (defined AK_CPU_X86_64 || defined AK_CPU_ARM_64)
199  {
200  unsigned long ret = 0;
201  _BitScanReverse64(&ret, in_bits);
202  return in_bits ? 63 - ret : 64;
203  }
204 #elif __clang__ || defined __GNUG__
206  {
207  return __builtin_clzll(in_bits);
208  }
209 #else
211  {
212  if (in_bits == 0) return 64;
213  int ret = 0;
214  if ((in_bits & 0xFFFFFFFF00000000ULL) == 0) { ret += 32; in_bits <<= 32; }
215  if ((in_bits & 0xFFFF000000000000ULL) == 0) { ret += 16; in_bits <<= 16; }
216  if ((in_bits & 0xFF00000000000000ULL) == 0) { ret += 8; in_bits <<= 8; }
217  if ((in_bits & 0xF000000000000000ULL) == 0) { ret += 4; in_bits <<= 4; }
218  if ((in_bits & 0xC000000000000000ULL) == 0) { ret += 2; in_bits <<= 2; }
219  if ((in_bits & 0x8000000000000000ULL) == 0) { ret += 1; in_bits <<= 1; }
220  return ret;
221  }
222 #endif
223 
224 #if defined _MSC_VER
226  {
227  unsigned long ret = 0;
228  _BitScanReverse(&ret, in_bits);
229  return in_bits ? 31 - ret : 32;
230  }
231 #elif __clang__ || defined __GNUG__
233  {
234  return __builtin_clzl(in_bits);
235  }
236 #else
238  {
239  if (in_bits == 0) return 32;
240  int ret = 0;
241  if ((in_bits & 0xFFFF0000ULL) == 0) { ret += 16; in_bits <<= 16; }
242  if ((in_bits & 0xFF000000ULL) == 0) { ret += 8; in_bits <<= 8; }
243  if ((in_bits & 0xF0000000ULL) == 0) { ret += 4; in_bits <<= 4; }
244  if ((in_bits & 0xC0000000ULL) == 0) { ret += 2; in_bits <<= 2; }
245  if ((in_bits & 0x80000000ULL) == 0) { ret += 1; in_bits <<= 1; }
246  return ret;
247  }
248 #endif
249 
250 #endif // !defined(AK_BIT_SCAN_INSTRUCTIONS)
251 
252  // fallback implementations for when platform don't have their own implementation
253 #if !defined(AK_LIMITEDSPINFORZERO)
254  // Waits for a limited amount of time for in_pVal to hit zero (without yielding the thread)
255  inline void AkLimitedSpinForZero(AkAtomic32* in_pVal)
256  {
257  AkInt64 endSpinTime = 0;
258  AkInt64 currentTime = 0;
259  PerformanceCounter(&endSpinTime);
260  endSpinTime += AkInt64(AK::g_fFreqRatio * 0.01); // only spin for about 10us
261  while (true)
262  {
263  // if pval is zero, skip out
264  if (AkAtomicLoad32(in_pVal) == 0)
265  {
266  break;
267  }
268  AkSpinHint();
269 
270  // Check if we've hit the deadline for the timeout
271  PerformanceCounter(&currentTime);
272  if (currentTime > endSpinTime)
273  {
274  break;
275  }
276  }
277  }
278 
279  // Waits for a limited amount of time for in_pVal to get atomically shift from the expected value to the proposed one
280  // returns true if acquisition succeeded
281  inline bool AkLimitedSpinToAcquire(AkAtomic32* in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
282  {
283  if (AkAtomicCas32(in_pVal, in_proposed, in_expected))
284  {
285  return true;
286  }
287 
288  // Cas failed, start the slower evaluation
289  AkInt64 endSpinTime = 0;
290  AkInt64 currentTime = 0;
291  PerformanceCounter(&endSpinTime);
292  endSpinTime += AkInt64(AK::g_fFreqRatio * 0.01); // only spin for about 10us
293  while (true)
294  {
295  // attempt cas to acquire and if successful, skip out
296  if (AkAtomicCas32(in_pVal, in_proposed, in_expected))
297  {
298  return true;
299  }
300  AkSpinHint();
301 
302  // Check if we've hit the deadline for the timeout
303  PerformanceCounter(&currentTime);
304  if (currentTime > endSpinTime)
305  {
306  return false;
307  }
308  }
309  }
310 #endif // !defined(AK_LIMITEDSPINFORZERO)
311 
312  inline void AkSpinWaitForZero(AkAtomic32* in_pVal)
313  {
314  if (AkAtomicLoad32(in_pVal) == 0)
315  {
316  return;
317  }
318 
319  // do a limited spin on-the-spot until in_pVal hits zero
320  AkLimitedSpinForZero(in_pVal);
321 
322  // if in_pVal is still non-zero, then the other thread is either blocked or waiting for us. Yield for real.
323  while (AkAtomicLoad32(in_pVal))
324  AkThreadYield();
325  }
326 
327  // Waits for a limited amount of time for in_pVal to get atomically shift from 0 to 1
328  inline void AkSpinToAcquire(AkAtomic32* in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
329  {
330  // do a limited spin on-the-spot until in_pVal can successfully hit 1
331  // or if it fails, then the other thread is either blocked or waiting for us. Yield for real.
332  while (!AkLimitedSpinToAcquire(in_pVal, in_proposed, in_expected))
333  {
334  AkThreadYield();
335  }
336  }
337 }
338 
339 
340 /// Utility functions
341 namespace AK
342 {
343  /// Count non-zero bits, e.g. to count # of channels in a channelmask
344  /// \return Number of channels.
346  {
347  return AKPLATFORM::AkPopCount(in_uWord);
348  }
349 
350  /// Computes the next power of two given a value.
351  /// \return next power of two.
353  {
354  in_uValue--;
355  in_uValue |= in_uValue >> 1;
356  in_uValue |= in_uValue >> 2;
357  in_uValue |= in_uValue >> 4;
358  in_uValue |= in_uValue >> 8;
359  in_uValue |= in_uValue >> 16;
360  in_uValue++;
361  return in_uValue;
362  }
363 
365  {
366  return (x << r) | (x >> (32 - r));
367  }
368 
370  {
371  return (x << r) | (x >> (64 - r));
372  }
373 }
374 
375 
376 #ifndef AK_PERF_RECORDING_RESET
377 #define AK_PERF_RECORDING_RESET()
378 #endif
379 #ifndef AK_PERF_RECORDING_START
380 #define AK_PERF_RECORDING_START( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )
381 #endif
382 #ifndef AK_PERF_RECORDING_STOP
383 #define AK_PERF_RECORDING_STOP( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )
384 #endif
385 
386 #endif // _AK_TOOLS_COMMON_AKPLATFORMFUNCS_H
void AkSpinHint()
Definition: AkAtomic.h:36
Audiokinetic namespace.
AkForceInline AkUInt32 AkBitScanReverse64(AkUInt64 in_bits)
int nPriority
Thread priority.
Platform-dependent helpers.
__forceinline int AkAtomicCas32(AkAtomic32 *pDest, long proposed, long expected)
Definition: AkAtomic.h:68
AkForceInline AkUInt32 ROTL32(AkUInt32 x, AkUInt32 r)
AkForceInline AkUInt32 AkPopCount(AkUInt32 in_bits)
#define AK_THREAD_PRIORITY_ABOVE_NORMAL
AkForceInline AkUInt32 AkBitScanForward64(AkUInt64 in_bits)
int32_t AkInt32
Signed 32-bit integer.
void PerformanceCounter(AkInt64 *out_piLastTime)
Platform Independent Helper.
volatile uint32_t AkAtomic32
Definition: AkAtomic.h:45
AkForceInline AkUInt32 AkBitScanReverse(AkUInt32 in_bits)
AkForceInline AkUInt32 GetNextPowerOfTwo(AkUInt32 in_uValue)
AkForceInline void AkGetDefaultThreadProperties(AkThreadProperties &out_threadProperties)
Platform Independent Helper.
void AkLimitedSpinForZero(AkAtomic32 *in_pVal)
AkForceInline AkUInt32 AkBitScanForward(AkUInt32 in_bits)
bool AkLimitedSpinToAcquire(AkAtomic32 *in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
AkReal32 g_fFreqRatio
void AkGetDefaultHighPriorityThreadProperties(AkThreadProperties &out_threadProperties)
int64_t AkInt64
Signed 64-bit integer.
AkForceInline AkUInt32 GetNumNonZeroBits(AkUInt32 in_uWord)
uint64_t AkUInt64
Unsigned 64-bit integer.
AkForceInline AkUInt64 ROTL64(AkUInt64 x, AkUInt64 r)
void AkSpinToAcquire(AkAtomic32 *in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
#define AkThreadYield()
Definition: AkAtomic.h:34
void AkSpinWaitForZero(AkAtomic32 *in_pVal)
uint32_t AkUInt32
Unsigned 32-bit integer.
#define AkForceInline
Definition: AkTypes.h:63
__forceinline long AkAtomicLoad32(AkAtomic32 *pSrc)
Definition: AkAtomic.h:58

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