AkPlatformFuncs.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. Commercial License Usage
  5. Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
  6. may use this file in accordance with the end user license agreement provided
  7. with the software or, alternatively, in accordance with the terms contained in a
  8. written agreement between you and Audiokinetic Inc.
  9. Apache License Usage
  10. Alternatively, this file may be used under the Apache License, Version 2.0 (the
  11. "Apache License"); you may not use this file except in compliance with the
  12. Apache License. You may obtain a copy of the Apache License at
  13. http://www.apache.org/licenses/LICENSE-2.0.
  14. Unless required by applicable law or agreed to in writing, software distributed
  15. under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
  16. OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
  17. the specific language governing permissions and limitations under the License.
  18. Copyright (c) 2023 Audiokinetic Inc.
  19. *******************************************************************************/
  20. // AkPlatformFuncs.h
  21. /// \file
  22. /// Platform-dependent functions definition.
  23. #ifndef _AK_TOOLS_COMMON_AKPLATFORMFUNCS_H
  24. #define _AK_TOOLS_COMMON_AKPLATFORMFUNCS_H
  25. #include <AK/SoundEngine/Common/AkTypes.h>
  26. #include <AK/SoundEngine/Common/AkAtomic.h>
  27. // Uncomment the following to enable built-in platform profiler markers in the sound engine
  28. //#define AK_ENABLE_INSTRUMENT
  29. #if defined(AK_WIN)
  30. #include <AK/Tools/Win32/AkPlatformFuncs.h>
  31. #elif defined (AK_XBOX)
  32. #include <AK/Tools/XboxGC/AkPlatformFuncs.h>
  33. #elif defined (AK_APPLE)
  34. #include <AK/Tools/Mac/AkPlatformFuncs.h>
  35. #include <AK/Tools/POSIX/AkPlatformFuncs.h>
  36. #elif defined( AK_ANDROID ) || defined ( AK_LINUX_AOSP )
  37. #include <AK/Tools/Android/AkPlatformFuncs.h>
  38. #elif defined (AK_PS4)
  39. #include <AK/Tools/PS4/AkPlatformFuncs.h>
  40. #elif defined (AK_PS5)
  41. #include <AK/Tools/PS5/AkPlatformFuncs.h>
  42. #elif defined (AK_EMSCRIPTEN)
  43. #include <AK/Tools/Emscripten/AkPlatformFuncs.h>
  44. #elif defined (AK_LINUX)
  45. #include <AK/Tools/Linux/AkPlatformFuncs.h>
  46. #include <AK/Tools/POSIX/AkPlatformFuncs.h>
  47. #elif defined (AK_QNX)
  48. #include <AK/Tools/QNX/AkPlatformFuncs.h>
  49. #include <AK/Tools/POSIX/AkPlatformFuncs.h>
  50. #elif defined (AK_NX)
  51. #include <AK/Tools/NX/AkPlatformFuncs.h>
  52. #else
  53. #error AkPlatformFuncs.h: Undefined platform
  54. #endif
  55. #ifndef AkPrefetchZero
  56. #define AkPrefetchZero(___Dest, ___Size)
  57. #endif
  58. #ifndef AkPrefetchZeroAligned
  59. #define AkPrefetchZeroAligned(___Dest, ___Size)
  60. #endif
  61. #ifndef AkZeroMemAligned
  62. #define AkZeroMemAligned(___Dest, ___Size) AKPLATFORM::AkMemSet(___Dest, 0, ___Size);
  63. #endif
  64. #ifndef AkZeroMemLarge
  65. #define AkZeroMemLarge(___Dest, ___Size) AKPLATFORM::AkMemSet(___Dest, 0, ___Size);
  66. #endif
  67. #ifndef AkZeroMemSmall
  68. #define AkZeroMemSmall(___Dest, ___Size) AKPLATFORM::AkMemSet(___Dest, 0, ___Size);
  69. #endif
  70. #ifndef AkAllocaSIMD
  71. #ifdef __clang__
  72. #if __has_builtin( __builtin_alloca_with_align )
  73. #define AkAllocaSIMD( _size_ ) __builtin_alloca_with_align( _size_, 128 )
  74. #else
  75. // work around alloca alignment issues in versions of clang before 4.0
  76. #define AkAllocaSIMD( _size_ ) (void*)( ( ( uintptr_t )AkAlloca( _size_ + 16 ) + 0xF ) & ~0xF )
  77. #endif
  78. #else
  79. #define AkAllocaSIMD( _size_ ) AkAlloca( _size_ )
  80. #endif
  81. #endif
  82. #ifndef AK_THREAD_INIT_CODE
  83. #define AK_THREAD_INIT_CODE(_threadProperties)
  84. #endif
  85. /// Platform-dependent helpers
  86. namespace AKPLATFORM
  87. {
  88. inline void AkGetDefaultHighPriorityThreadProperties(AkThreadProperties& out_threadProperties)
  89. {
  90. AkGetDefaultThreadProperties(out_threadProperties);
  91. out_threadProperties.nPriority = AK_THREAD_PRIORITY_ABOVE_NORMAL;
  92. }
  93. // fallback implementations for when platform don't have their own implementation
  94. #if !defined(AK_BIT_SCAN_INSTRUCTIONS)
  95. // AkPopCount returns how many set bits there are in the provided value
  96. #if __clang__ || defined __GNUG__
  97. AkForceInline AkUInt32 AkPopCount(AkUInt32 in_bits)
  98. {
  99. return __builtin_popcount(in_bits);
  100. }
  101. #else
  102. AkForceInline AkUInt32 AkPopCount(AkUInt32 in_bits)
  103. {
  104. AkUInt32 num = 0;
  105. while (in_bits) { ++num; in_bits &= in_bits - 1; }
  106. return num;
  107. }
  108. #endif
  109. // 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
  110. #if defined _MSC_VER && (defined AK_CPU_X86_64 || defined AK_CPU_ARM_64)
  111. AkForceInline AkUInt32 AkBitScanForward64(AkUInt64 in_bits)
  112. {
  113. unsigned long ret = 0;
  114. _BitScanForward64(&ret, in_bits);
  115. return in_bits ? ret : 64;
  116. }
  117. #elif __clang__ || defined __GNUG__
  118. AkForceInline AkUInt32 AkBitScanForward64(AkUInt64 in_bits)
  119. {
  120. return __builtin_ctzll(in_bits);
  121. }
  122. #else
  123. AkForceInline AkUInt32 AkBitScanForward64(AkUInt64 in_bits)
  124. {
  125. if (in_bits == 0) return 64;
  126. AkUInt32 ret = 0;
  127. if ((in_bits & 0x00000000FFFFFFFFULL) == 0) { ret += 32; in_bits >>= 32; }
  128. if ((in_bits & 0x000000000000FFFFULL) == 0) { ret += 16; in_bits >>= 16; }
  129. if ((in_bits & 0x00000000000000FFULL) == 0) { ret += 8; in_bits >>= 8; }
  130. if ((in_bits & 0x000000000000000FULL) == 0) { ret += 4; in_bits >>= 4; }
  131. if ((in_bits & 0x0000000000000003ULL) == 0) { ret += 2; in_bits >>= 2; }
  132. if ((in_bits & 0x0000000000000001ULL) == 0) { ret += 1; in_bits >>= 1; }
  133. return ret;
  134. }
  135. #endif
  136. #if defined _MSC_VER
  137. AkForceInline AkUInt32 AkBitScanForward(AkUInt32 in_bits)
  138. {
  139. unsigned long ret = 0;
  140. _BitScanForward(&ret, in_bits);
  141. return in_bits ? ret : 32;
  142. }
  143. #elif __clang__ || defined __GNUG__
  144. AkForceInline AkUInt32 AkBitScanForward(AkUInt32 in_bits)
  145. {
  146. return __builtin_ctzl(in_bits);
  147. }
  148. #else
  149. AkForceInline AkUInt32 AkBitScanForward(AkUInt32 in_bits)
  150. {
  151. if (in_bits == 0) return 32;
  152. AkUInt32 ret = 0;
  153. if ((in_bits & 0x0000FFFFULL) == 0) { ret += 16; in_bits >>= 16; }
  154. if ((in_bits & 0x000000FFULL) == 0) { ret += 8; in_bits >>= 8; }
  155. if ((in_bits & 0x0000000FULL) == 0) { ret += 4; in_bits >>= 4; }
  156. if ((in_bits & 0x00000003ULL) == 0) { ret += 2; in_bits >>= 2; }
  157. if ((in_bits & 0x00000001ULL) == 0) { ret += 1; in_bits >>= 1; }
  158. return ret;
  159. }
  160. #endif
  161. // 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
  162. #if defined _MSC_VER && (defined AK_CPU_X86_64 || defined AK_CPU_ARM_64)
  163. AkForceInline AkUInt32 AkBitScanReverse64(AkUInt64 in_bits)
  164. {
  165. unsigned long ret = 0;
  166. _BitScanReverse64(&ret, in_bits);
  167. return in_bits ? 63 - ret : 64;
  168. }
  169. #elif __clang__ || defined __GNUG__
  170. AkForceInline AkUInt32 AkBitScanReverse64(AkUInt64 in_bits)
  171. {
  172. return __builtin_clzll(in_bits);
  173. }
  174. #else
  175. AkForceInline AkUInt32 AkBitScanReverse64(AkUInt64 in_bits)
  176. {
  177. if (in_bits == 0) return 64;
  178. int ret = 0;
  179. if ((in_bits & 0xFFFFFFFF00000000ULL) == 0) { ret += 32; in_bits <<= 32; }
  180. if ((in_bits & 0xFFFF000000000000ULL) == 0) { ret += 16; in_bits <<= 16; }
  181. if ((in_bits & 0xFF00000000000000ULL) == 0) { ret += 8; in_bits <<= 8; }
  182. if ((in_bits & 0xF000000000000000ULL) == 0) { ret += 4; in_bits <<= 4; }
  183. if ((in_bits & 0xC000000000000000ULL) == 0) { ret += 2; in_bits <<= 2; }
  184. if ((in_bits & 0x8000000000000000ULL) == 0) { ret += 1; in_bits <<= 1; }
  185. return ret;
  186. }
  187. #endif
  188. #if defined _MSC_VER
  189. AkForceInline AkUInt32 AkBitScanReverse(AkUInt32 in_bits)
  190. {
  191. unsigned long ret = 0;
  192. _BitScanReverse(&ret, in_bits);
  193. return in_bits ? 31 - ret : 32;
  194. }
  195. #elif __clang__ || defined __GNUG__
  196. AkForceInline AkUInt32 AkBitScanReverse(AkUInt32 in_bits)
  197. {
  198. return __builtin_clzl(in_bits);
  199. }
  200. #else
  201. AkForceInline AkUInt32 AkBitScanReverse(AkUInt32 in_bits)
  202. {
  203. if (in_bits == 0) return 32;
  204. int ret = 0;
  205. if ((in_bits & 0xFFFF0000ULL) == 0) { ret += 16; in_bits <<= 16; }
  206. if ((in_bits & 0xFF000000ULL) == 0) { ret += 8; in_bits <<= 8; }
  207. if ((in_bits & 0xF0000000ULL) == 0) { ret += 4; in_bits <<= 4; }
  208. if ((in_bits & 0xC0000000ULL) == 0) { ret += 2; in_bits <<= 2; }
  209. if ((in_bits & 0x80000000ULL) == 0) { ret += 1; in_bits <<= 1; }
  210. return ret;
  211. }
  212. #endif
  213. #endif // !defined(AK_BIT_SCAN_INSTRUCTIONS)
  214. // fallback implementations for when platform don't have their own implementation
  215. #if !defined(AK_LIMITEDSPINFORZERO)
  216. // Waits for a limited amount of time for in_pVal to hit zero (without yielding the thread)
  217. inline void AkLimitedSpinForZero(AkAtomic32* in_pVal)
  218. {
  219. AkInt64 endSpinTime = 0;
  220. AkInt64 currentTime = 0;
  221. PerformanceCounter(&endSpinTime);
  222. endSpinTime += AkInt64(AK::g_fFreqRatio * 0.01); // only spin for about 10us
  223. while (true)
  224. {
  225. // if pval is zero, skip out
  226. if (AkAtomicLoad32(in_pVal) == 0)
  227. {
  228. break;
  229. }
  230. AkSpinHint();
  231. // Check if we've hit the deadline for the timeout
  232. PerformanceCounter(&currentTime);
  233. if (currentTime > endSpinTime)
  234. {
  235. break;
  236. }
  237. }
  238. }
  239. // Waits for a limited amount of time for in_pVal to get atomically shift from the expected value to the proposed one
  240. // returns true if acquisition succeeded
  241. inline bool AkLimitedSpinToAcquire(AkAtomic32* in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
  242. {
  243. if (AkAtomicCas32(in_pVal, in_proposed, in_expected))
  244. {
  245. return true;
  246. }
  247. // Cas failed, start the slower evaluation
  248. AkInt64 endSpinTime = 0;
  249. AkInt64 currentTime = 0;
  250. PerformanceCounter(&endSpinTime);
  251. endSpinTime += AkInt64(AK::g_fFreqRatio * 0.01); // only spin for about 10us
  252. while (true)
  253. {
  254. // attempt cas to acquire and if successful, skip out
  255. if (AkAtomicCas32(in_pVal, in_proposed, in_expected))
  256. {
  257. return true;
  258. }
  259. AkSpinHint();
  260. // Check if we've hit the deadline for the timeout
  261. PerformanceCounter(&currentTime);
  262. if (currentTime > endSpinTime)
  263. {
  264. return false;
  265. }
  266. }
  267. }
  268. #endif // !defined(AK_LIMITEDSPINFORZERO)
  269. inline void AkSpinWaitForZero(AkAtomic32* in_pVal)
  270. {
  271. if (AkAtomicLoad32(in_pVal) == 0)
  272. {
  273. return;
  274. }
  275. // do a limited spin on-the-spot until in_pVal hits zero
  276. AkLimitedSpinForZero(in_pVal);
  277. // if in_pVal is still non-zero, then the other thread is either blocked or waiting for us. Yield for real.
  278. while (AkAtomicLoad32(in_pVal))
  279. AkThreadYield();
  280. }
  281. // Waits for a limited amount of time for in_pVal to get atomically shift from 0 to 1
  282. inline void AkSpinToAcquire(AkAtomic32* in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
  283. {
  284. // do a limited spin on-the-spot until in_pVal can successfully hit 1
  285. // or if it fails, then the other thread is either blocked or waiting for us. Yield for real.
  286. while (!AkLimitedSpinToAcquire(in_pVal, in_proposed, in_expected))
  287. {
  288. AkThreadYield();
  289. }
  290. }
  291. }
  292. /// Utility functions
  293. namespace AK
  294. {
  295. /// Count non-zero bits, e.g. to count # of channels in a channelmask
  296. /// \return Number of channels.
  297. AkForceInline AkUInt32 GetNumNonZeroBits(AkUInt32 in_uWord)
  298. {
  299. return AKPLATFORM::AkPopCount(in_uWord);
  300. }
  301. /// Computes the next power of two given a value.
  302. /// \return next power of two.
  303. AkForceInline AkUInt32 GetNextPowerOfTwo(AkUInt32 in_uValue)
  304. {
  305. in_uValue--;
  306. in_uValue |= in_uValue >> 1;
  307. in_uValue |= in_uValue >> 2;
  308. in_uValue |= in_uValue >> 4;
  309. in_uValue |= in_uValue >> 8;
  310. in_uValue |= in_uValue >> 16;
  311. in_uValue++;
  312. return in_uValue;
  313. }
  314. AkForceInline AkUInt32 ROTL32(AkUInt32 x, AkUInt32 r)
  315. {
  316. return (x << r) | (x >> (32 - r));
  317. }
  318. AkForceInline AkUInt64 ROTL64(AkUInt64 x, AkUInt64 r)
  319. {
  320. return (x << r) | (x >> (64 - r));
  321. }
  322. }
  323. #ifndef AK_PERF_RECORDING_RESET
  324. #define AK_PERF_RECORDING_RESET()
  325. #endif
  326. #ifndef AK_PERF_RECORDING_START
  327. #define AK_PERF_RECORDING_START( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )
  328. #endif
  329. #ifndef AK_PERF_RECORDING_STOP
  330. #define AK_PERF_RECORDING_STOP( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )
  331. #endif
  332. #endif // _AK_TOOLS_COMMON_AKPLATFORMFUNCS_H