Version
menu_open
link
Wwise SDK 2022.1.12
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 #ifndef _AK_PLATFORM_FUNCS_H_
28 #define _AK_PLATFORM_FUNCS_H_
29 
31 #include <sce_atomic.h>
32 #include <sceerror.h>
33 #include <wchar.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <time.h>
37 #include <kernel/eventflag.h>
38 #include <unistd.h>
39 #include <sys/time.h>
40 #include <stdlib.h>
41 #include <cpuid.h>
42 #include <ajm.h>
43 #include <x86intrin.h>
44 
45 //-----------------------------------------------------------------------------
46 // Platform-specific thread properties definition.
47 //-----------------------------------------------------------------------------
48 struct AkThreadProperties
49 {
50  int nPriority; ///< Thread priority
51  SceKernelCpumask dwAffinityMask; ///< Affinity mask
52  size_t uStackSize; ///< Thread stack size
53  int uSchedPolicy; ///< Thread scheduling policy
54 };
55 
56 //-----------------------------------------------------------------------------
57 // External variables.
58 //-----------------------------------------------------------------------------
59 // These variables are declared and updated by the sound engine.
60 namespace AK
61 {
62  // used by time helpers to return time values in milliseconds.
64 }
65 
66 //-----------------------------------------------------------------------------
67 // Defines for PS5.
68 //-----------------------------------------------------------------------------
69 #define AK_DECLARE_THREAD_ROUTINE( FuncName ) void* FuncName(void* lpParameter)
70 #define AK_THREAD_RETURN( _param_ ) return (_param_);
71 #define AK_THREAD_ROUTINE_PARAMETER lpParameter
72 #define AK_GET_THREAD_ROUTINE_PARAMETER_PTR(type) reinterpret_cast<type*>( AK_THREAD_ROUTINE_PARAMETER )
73 
74 #define AK_RETURN_THREAD_OK 0x00000000
75 #define AK_RETURN_THREAD_ERROR 0x00000001
76 #define AK_DEFAULT_STACK_SIZE (128*1024)
77 #define AK_VM_PAGE_SIZE (64*1024)
78 #define AK_VM_HUGE_PAGE_SIZE (2*1024*1024)
79 #define AK_VM_DEVICE_PAGE_SIZE (64*1024)
80 #define AK_THREAD_DEFAULT_SCHED_POLICY SCE_KERNEL_SCHED_FIFO
81 #define AK_THREAD_PRIORITY_NORMAL SCE_KERNEL_PRIO_FIFO_DEFAULT
82 #define AK_THREAD_PRIORITY_ABOVE_NORMAL SCE_KERNEL_PRIO_FIFO_HIGHEST
83 #define AK_THREAD_PRIORITY_BELOW_NORMAL SCE_KERNEL_PRIO_FIFO_LOWEST
84 
85 #define AK_THREAD_AFFINITY_ALL 8191 // from 0b1'1111'1111'1111 -- 13 cores available
86 #define AK_THREAD_AFFINITY_DEFAULT 4095 // from 0b0'1111'1111'1111 -- Default to only the 12 fully-available cores. 13th core is half-available.
87 
88 // NULL objects
89 #define AK_NULL_THREAD NULL
90 
91 #define AK_INFINITE (AK_UINT_MAX)
92 
93 #define AkMax(x1, x2) (((x1) > (x2))? (x1): (x2))
94 #define AkMin(x1, x2) (((x1) < (x2))? (x1): (x2))
95 #define AkClamp(x, min, max) ((x) < (min)) ? (min) : (((x) > (max) ? (max) : (x)))
96 
97 namespace AKPLATFORM
98 {
99 #ifndef AK_OPTIMIZED
100  /// Output a debug message on the console (Ansi string)
101  AkForceInline void OutputDebugMsg( const char* in_pszMsg )
102  {
103  fputs( in_pszMsg, stderr );
104  }
105  /// Output a debug message on the console (Unicode string)
106  AkForceInline void OutputDebugMsg( const wchar_t* in_pszMsg )
107  {
108  fputws( in_pszMsg, stderr );
109  }
110 
111  /// Output a debug message on the console (Unicode string) (variadic function)
112  template <int MaxSize = 0> // Unused
113  AkForceInline void OutputDebugMsgV( const wchar_t* in_pszFmt, ... )
114  {
115  va_list args;
116  va_start(args, in_pszFmt);
117  vfwprintf(stderr, in_pszFmt, args);
118  va_end(args);
119  }
120 
121  /// Output a debug message on the console (Ansi string) (variadic function)
122  template <int MaxSize = 0> // Unused
123  AkForceInline void OutputDebugMsgV( const char* in_pszFmt, ... )
124  {
125  va_list args;
126  va_start(args, in_pszFmt);
127  vfprintf(stderr, in_pszFmt, args);
128  va_end(args);
129  }
130 #else
131  inline void OutputDebugMsg( const wchar_t* ){}
132  inline void OutputDebugMsg( const char* ){}
133 
134  template <int MaxSize = 0> // Unused
135  inline void OutputDebugMsgV( const wchar_t*, ... ){}
136 
137  template <int MaxSize = 0> // Unused
138  inline void OutputDebugMsgV( const char*, ... ){}
139 #endif
140 
141 
142  // Simple automatic event API
143  // ------------------------------------------------------------------
144 
145  /// Platform Independent Helper
146  AkForceInline void AkClearEvent( AkEvent & out_event )
147  {
148  out_event = NULL;
149  }
150 
151  AkForceInline AKRESULT AkCreateNamedEvent( AkEvent & out_event, const char* in_szName )
152  {
153  // NOTE: AkWaitForEvent uses the SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT flag
154  // to get the same behavior as an auto-reset Win32 event
155  int ret = sceKernelCreateEventFlag(
156  &out_event,
157  in_szName,
158  SCE_KERNEL_EVF_ATTR_MULTI,
159  0 /* not signalled by default */,
160  NULL /* No optional params */ );
161 
162  if( ret == SCE_OK )
163  return AK_Success;
164 
165  AkClearEvent( out_event );
166  return AK_Fail;
167  }
168 
169  /// Platform Independent Helper
171  {
172  return AkCreateNamedEvent( out_event, "AkEvent" );
173  }
174 
175  /// Platform Independent Helper
176  AkForceInline void AkDestroyEvent( AkEvent & io_event )
177  {
178  sceKernelDeleteEventFlag(io_event);
179  AkClearEvent( io_event );
180  }
181 
182  /// Platform Independent Helper
183  AkForceInline void AkWaitForEvent( AkEvent & in_event )
184  {
185  AKVERIFY( sceKernelWaitEventFlag(
186  in_event,
187  1,
188  SCE_KERNEL_EVF_WAITMODE_OR | SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL,
189  SCE_NULL,
190  SCE_NULL) == 0 );
191  }
192 
193  /// Platform Independent Helper
194  AkForceInline void AkSignalEvent( const AkEvent & in_event )
195  {
196  AKVERIFY( sceKernelSetEventFlag( in_event, 1 ) == 0 );
197  }
198 
199  /// Platform Independent Helper
200  AkForceInline void AkClearSemaphore(AkSemaphore& io_semaphore)
201  {
202  io_semaphore = NULL;
203  }
204 
205  /// Platform Independent Helper
206  inline AKRESULT AkCreateSemaphore( AkSemaphore& out_semaphore, AkUInt32 in_initialCount )
207  {
208  int ret = sceKernelCreateSema(
209  &out_semaphore,
210  "AkSemaphore",
211  0,
212  in_initialCount,
213  INT_MAX,
214  NULL );
215 
216  return ( ret == SCE_OK ) ? AK_Success : AK_Fail;
217  }
218 
219  /// Platform Independent Helper
220  inline void AkDestroySemaphore(AkSemaphore& io_semaphore)
221  {
222  AKVERIFY(sceKernelDeleteSema(io_semaphore) == SCE_OK);
223  }
224 
225  /// Platform Independent Helper - Semaphore wait, aka Operation P. Decrements value of semaphore, and, if the semaphore would be less than 0, waits for the semaphore to be released.
226  inline void AkWaitForSemaphore(AkSemaphore& in_semaphore)
227  {
228  AKVERIFY(sceKernelWaitSema(in_semaphore, 1, NULL) == SCE_OK);
229  }
230 
231  /// Platform Independent Helper - Semaphore signal, aka Operation V. Increments value of semaphore by an arbitrary count.
232  inline void AkReleaseSemaphore(AkSemaphore& in_semaphore, AkUInt32 in_count)
233  {
234  AKVERIFY(sceKernelSignalSema(in_semaphore, in_count) == SCE_OK);
235  }
236 
237  // Virtual Memory
238  // ------------------------------------------------------------------
239 
240  // In order to use ACM hardware accelerated functions, Wwise must have GPU-visible memory
241  const int kMemoryFlags = SCE_KERNEL_PROT_CPU_RW | SCE_KERNEL_PROT_GPU_RW | SCE_KERNEL_PROT_AMPR_ALL;
242  const int kDeviceMemoryFlags = SCE_KERNEL_PROT_CPU_RW | SCE_KERNEL_PROT_GPU_RW | SCE_KERNEL_PROT_AMPR_ALL | SCE_KERNEL_PROT_ACP_RW;
243 
244  AkForceInline void* AllocVM(size_t size, size_t* extra)
245  {
246  AKASSERT((size % AK_VM_PAGE_SIZE) == 0);
247  off_t directMemStart = 0;
248  void* ptr = NULL;
249 
250  int32_t err;
251  // if size lines up with huge pages, set alignment up similarly
252  int32_t alignment = (size % AK_VM_HUGE_PAGE_SIZE == 0) ? AK_VM_HUGE_PAGE_SIZE : AK_VM_PAGE_SIZE;
253  err = sceKernelAllocateMainDirectMemory(size, alignment, SCE_KERNEL_MTYPE_C_SHARED, &directMemStart);
254  if (err == SCE_OK)
255  {
256  err = sceKernelMapDirectMemory(&ptr, size, AKPLATFORM::kMemoryFlags, 0, directMemStart, alignment);
257  AKASSERT(ptr);
258  AKASSERT(err == SCE_OK);
259 
260  *extra = (size_t)directMemStart;
261  }
262  return ptr;
263  }
264 
265  AkForceInline void FreeVM(void* address, size_t size, size_t extra, size_t release)
266  {
267  if (release)
268  {
269  AKASSERT(extra);
270  off_t directMemStart = (off_t)extra;
271  int32_t err = sceKernelReleaseDirectMemory(directMemStart, release);
272  AKASSERT(err == SCE_OK);
273  }
274  }
275 
276  AkForceInline void* AllocDevice(size_t size, size_t* extra)
277  {
278  AKASSERT((size % AK_VM_DEVICE_PAGE_SIZE) == 0);
279  off_t directMemStart = 0;
280  void* ptr = NULL;
281 
282  int32_t err;
283  // if size lines up with huge pages, set alignment up similarly
284  int32_t alignment = (size % AK_VM_HUGE_PAGE_SIZE == 0) ? AK_VM_HUGE_PAGE_SIZE : AK_VM_DEVICE_PAGE_SIZE;
285  err = sceKernelAllocateMainDirectMemory(size, alignment, SCE_KERNEL_MTYPE_C_SHARED, &directMemStart);
286  if (err == SCE_OK)
287  {
288  err = sceKernelMapDirectMemory(&ptr, size, AKPLATFORM::kDeviceMemoryFlags, 0, directMemStart, alignment);
289  AKASSERT(ptr);
290  AKASSERT(err == SCE_OK);
291 
292  *extra = (size_t)directMemStart;
293  }
294  return ptr;
295  }
296 
297  AkForceInline void FreeDevice(void* address, size_t size, size_t extra, size_t release)
298  {
299  if (release)
300  {
301  AKASSERT(extra);
302  off_t directMemStart = (off_t)extra;
303  int32_t err = sceKernelReleaseDirectMemory(directMemStart, release);
304  AKASSERT(err == SCE_OK);
305  }
306  }
307 
308  AkForceInline bool CheckMemoryProtection(void* address, size_t size, int expectedProt)
309  {
310  void* pStart, * pEnd;
311  int prot;
312 
313  AkUIntPtr addressEnd = (AkUIntPtr)address + size - 1;
314 
315  // Check protection flags apply to the whole range
316  while ((AkUIntPtr)address < addressEnd)
317  {
318  int err = sceKernelQueryMemoryProtection(address, &pStart, &pEnd, &prot);
319  if (err != SCE_OK)
320  return false;
321 
322  // Check protection flags
323  if ((prot & expectedProt) != expectedProt)
324  return false;
325 
326  if ((AkUIntPtr)pStart > (AkUIntPtr)address)
327  return false;
328 
329  address = pEnd;
330  }
331 
332  return true;
333  }
334 
335  // Threads
336  // ------------------------------------------------------------------
337 
338  /// Platform Independent Helper
339  AkForceInline bool AkIsValidThread( AkThread * in_pThread )
340  {
341  return ( *in_pThread != AK_NULL_THREAD );
342  }
343 
344  /// Platform Independent Helper
345  AkForceInline void AkClearThread( AkThread * in_pThread )
346  {
347  *in_pThread = AK_NULL_THREAD;
348  }
349 
350  /// Platform Independent Helper
351  AkForceInline void AkCloseThread( AkThread * in_pThread )
352  {
353  AKASSERT( in_pThread );
354  AKASSERT( *in_pThread );
355 
356  // #define KILL_THREAD(t) do { void *ret; scePthreadJoin(t,&ret); } while(false)
357  // AKVERIFY( SCE_OK == sceKernelDeleteThread( *in_pThread ) );
358  AkClearThread( in_pThread );
359  }
360 
361  #define AkExitThread( _result ) return _result; // ?????
362 
363  /// Platform Independent Helper
364  AkForceInline void AkGetDefaultThreadProperties( AkThreadProperties & out_threadProperties )
365  {
366  out_threadProperties.uStackSize = AK_DEFAULT_STACK_SIZE;
367  out_threadProperties.uSchedPolicy = AK_THREAD_DEFAULT_SCHED_POLICY;
368  out_threadProperties.nPriority = AK_THREAD_PRIORITY_NORMAL;
369  out_threadProperties.dwAffinityMask = AK_THREAD_AFFINITY_DEFAULT;
370  }
371 
372  /// Platform Independent Helper
373  inline void AkCreateThread(
374  AkThreadRoutine pStartRoutine, // Thread routine.
375  void * pParams, // Routine params.
376  const AkThreadProperties & in_threadProperties, // Properties. NULL for default.
377  AkThread * out_pThread, // Returned thread handle.
378  const char * in_szThreadName ) // Opt thread name.
379  {
380  AKASSERT( out_pThread != NULL );
381 
382  ScePthreadAttr attr;
383 
384  // Create the attr
385  AKVERIFY(!scePthreadAttrInit(&attr));
386  // Set the stack size
387  AKVERIFY(!scePthreadAttrSetstacksize(&attr,in_threadProperties.uStackSize));
388  AKVERIFY(!scePthreadAttrSetdetachstate(&attr, SCE_PTHREAD_CREATE_JOINABLE));
389  AKVERIFY(!scePthreadAttrSetinheritsched(&attr, SCE_PTHREAD_EXPLICIT_SCHED));
390  AKVERIFY(!scePthreadAttrSetaffinity(&attr,in_threadProperties.dwAffinityMask));
391 
392  // Try to set the thread policy
393  int sched_policy = in_threadProperties.uSchedPolicy;
394  if( scePthreadAttrSetschedpolicy( &attr, sched_policy ) )
395  {
396  AKASSERT( !"AKCreateThread invalid sched policy, will automatically set it to FIFO scheduling" );
397  sched_policy = AK_THREAD_DEFAULT_SCHED_POLICY;
398  AKVERIFY( !scePthreadAttrSetschedpolicy( &attr, sched_policy ));
399  }
400 
401  int minPriority, maxPriority;
402  minPriority = SCE_KERNEL_PRIO_FIFO_HIGHEST;
403  maxPriority = SCE_KERNEL_PRIO_FIFO_LOWEST;
404 
405  // Set the thread priority if valid
406  AKASSERT( in_threadProperties.nPriority >= minPriority && in_threadProperties.nPriority <= maxPriority );
407  if( in_threadProperties.nPriority >= minPriority && in_threadProperties.nPriority <= maxPriority )
408  {
409  SceKernelSchedParam schedParam;
410  AKVERIFY( scePthreadAttrGetschedparam(&attr, &schedParam) == 0 );
411  schedParam.sched_priority = in_threadProperties.nPriority;
412  AKVERIFY( scePthreadAttrSetschedparam(&attr, &schedParam) == 0 );
413  }
414 
415  // Create the tread
416  int threadError = scePthreadCreate(out_pThread, &attr, pStartRoutine, pParams, in_szThreadName);
417  AKASSERT( threadError == 0 );
418  AKVERIFY(!scePthreadAttrDestroy(&attr));
419 
420  if( threadError != 0 )
421  {
422  AkClearThread( out_pThread );
423  return;
424  }
425 
426  // ::CreateThread() return NULL if it fails.
427  if ( !*out_pThread )
428  {
429  AkClearThread( out_pThread );
430  return;
431  }
432  }
433 
434  /// Platform Independent Helper
435  AkForceInline void AkWaitForSingleThread( AkThread * in_pThread )
436  {
437  AKASSERT( in_pThread );
438  AKASSERT( *in_pThread );
439  AKVERIFY(!scePthreadJoin( *in_pThread, NULL ));
440  }
441 
442  inline AkThreadID CurrentThread()
443  {
444  return scePthreadSelf();
445  }
446 
447  /// Platform Independent Helper
448  AkForceInline void AkSleep( AkUInt32 in_ulMilliseconds )
449  {
450  usleep( in_ulMilliseconds * 1000 );
451  }
452 
453  // Optimized memory functions
454  // --------------------------------------------------------------------
455 
456  /// Platform Independent Helper
457  AkForceInline void AkMemCpy( void * pDest, const void * pSrc, AkUInt32 uSize )
458  {
459  memcpy( pDest, pSrc, uSize );
460  }
461 
462  /// Platform Independent Helper
463  inline void AkMemMove( void* pDest, const void* pSrc, AkUInt32 uSize )
464  {
465  memmove( pDest, pSrc, uSize );
466  }
467 
468  /// Platform Independent Helper
469  AkForceInline void AkMemSet( void * pDest, AkInt32 iVal, AkUInt32 uSize )
470  {
471  memset( pDest, iVal, uSize );
472  }
473 
474  // Time functions
475  // ------------------------------------------------------------------
476 
477  /// Platform Independent Helper
478  AkForceInline void PerformanceCounter( AkInt64 * out_piLastTime )
479  {
480  uint64_t uTime = sceKernelGetProcessTimeCounter();
481  *out_piLastTime = (AkInt64)uTime;
482  }
483 
484  /// Frequency of the PerformanceCounter() (ticks per second)
485  AkForceInline void PerformanceFrequency( AkInt64 * out_piFreq )
486  {
487  *out_piFreq = (AkInt64)sceKernelGetProcessTimeCounterFrequency();
488  }
489 
490  /// Platform Independent Helper
492  {
493  AkInt64 iFreq;
494  PerformanceFrequency( &iFreq );
495  AK::g_fFreqRatio = (AkReal32)((AkReal64)iFreq / 1000);
496  }
497 
498  // Waits for a limited amount of time for in_pVal to hit zero (without yielding the thread)
499  inline void AkLimitedSpinForZero(AkAtomic32* in_pVal)
500  {
501  // monitorx and waitx are available on certain AMD CPUs, so we can have a custom impl of AkLimitedSpinForZero
502  AkInt64 endSpinTime = 0;
503  AkInt64 currentTime = 0;
504  PerformanceCounter(&endSpinTime);
505  endSpinTime += AkInt64(AK::g_fFreqRatio * 0.01); // only spin for about 10us
506  while (true)
507  {
508  // set up monitorx on pVal
509  _mm_monitorx((void*)in_pVal, 0U, 0U);
510  // if pval is zero, skip out
511  if (AkAtomicLoad32(in_pVal) == 0)
512  {
513  break;
514  }
515  // wait until a store to pVal occurs (or ~1us passes)
516  _mm_mwaitx(2U, 0U, 1000U);
517 
518  // Check if we've hit the deadline for the timeout
519  PerformanceCounter(&currentTime);
520  if (currentTime > endSpinTime)
521  {
522  break;
523  }
524  }
525  }
526 
527  // Waits for a limited amount of time for in_pVal to get atomically shift from the expected value to the proposed one
528  // returns true if acquisition succeeded
529  inline bool AkLimitedSpinToAcquire(AkAtomic32* in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
530  {
531  if (AkAtomicCas32(in_pVal, in_proposed, in_expected))
532  {
533  return true;
534  }
535 
536  // Cas failed, start the slower evaluation
537 
538  // monitorx and waitx are available on certain AMD CPUs, so we can use monitorx/waitx
539  AkInt64 endSpinTime = 0;
540  AkInt64 currentTime = 0;
541  PerformanceCounter(&endSpinTime);
542  endSpinTime += AkInt64(AK::g_fFreqRatio * 0.01); // only spin for about 10us
543  while (true)
544  {
545  // set up monitorx on pVal
546  _mm_monitorx((void*)in_pVal, 0U, 0U);
547  // attempt cas to acquire and if successful, skip out
548  if (AkAtomicCas32(in_pVal, in_proposed, in_expected))
549  {
550  return true;
551  }
552  // wait until a store to pVal occurs (or ~1us passes)
553  _mm_mwaitx(2U, 0U, 1000U);
554 
555  // Check if we've hit the deadline for the timeout
556  PerformanceCounter(&currentTime);
557  if (currentTime > endSpinTime)
558  {
559  return false;
560  }
561  }
562  }
563 
564 #define AK_LIMITEDSPINFORZERO // mark AkLimitedSpinForZero as defined to avoid duplicate definitions
565 
566  /// Returns a time range in milliseconds, using the sound engine's updated count->milliseconds ratio.
567  AkForceInline AkReal32 Elapsed( const AkInt64 & in_iNow, const AkInt64 & in_iStart )
568  {
569  return ( in_iNow - in_iStart ) / AK::g_fFreqRatio;
570  }
571 
572  /// String conversion helper
573  AkForceInline AkInt32 AkWideCharToChar( const wchar_t* in_pszUnicodeString,
574  AkUInt32 in_uiOutBufferSize,
575  char* io_pszAnsiString )
576  {
577  AKASSERT( io_pszAnsiString != NULL );
578 
579  mbstate_t state;
580  memset (&state, '\0', sizeof (state));
581 
582  return (AkInt32)wcsrtombs(io_pszAnsiString, // destination
583  &in_pszUnicodeString, // source
584  in_uiOutBufferSize, // destination length
585  &state); //
586 
587  }
588 
589  /// String conversion helper
590  AkForceInline AkInt32 AkCharToWideChar( const char* in_pszAnsiString,
591  AkUInt32 in_uiOutBufferSize,
592  void* io_pvUnicodeStringBuffer )
593  {
594  AKASSERT( io_pvUnicodeStringBuffer != NULL );
595 
596  mbstate_t state;
597  memset (&state, '\0', sizeof (state));
598 
599  return (AkInt32)mbsrtowcs((wchar_t*)io_pvUnicodeStringBuffer, // destination
600  &in_pszAnsiString, // source
601  in_uiOutBufferSize, // destination length
602  &state); //
603  }
604 
605  AkForceInline AkInt32 AkUtf8ToWideChar( const char* in_pszUtf8String,
606  AkUInt32 in_uiOutBufferSize,
607  void* io_pvUnicodeStringBuffer )
608  {
609  return AkCharToWideChar( in_pszUtf8String, in_uiOutBufferSize, (wchar_t*)io_pvUnicodeStringBuffer );
610  }
611 
612  /// Safe unicode string copy.
613  AkForceInline void SafeStrCpy( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
614  {
615  size_t uSizeCopy = AkMin( in_uDestMaxNumChars - 1, wcslen( in_pSrc ) + 1 );
616  wcsncpy( in_pDest, in_pSrc, uSizeCopy );
617  in_pDest[uSizeCopy] = '\0';
618  }
619 
620  /// Safe ansi string copy.
621  AkForceInline void SafeStrCpy( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
622  {
623  size_t uSizeCopy = AkMin( in_uDestMaxNumChars - 1, strlen( in_pSrc ) + 1 );
624  strncpy( in_pDest, in_pSrc, uSizeCopy );
625  in_pDest[uSizeCopy] = '\0';
626  }
627 
628  /// Safe unicode string concatenation.
629  AkForceInline void SafeStrCat( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
630  {
631  size_t uAvailableSize = ( in_uDestMaxNumChars - wcslen( in_pDest ) - 1 );
632  wcsncat( in_pDest, in_pSrc, AkMin( uAvailableSize, wcslen( in_pSrc ) ) );
633  }
634 
635  /// Safe ansi string concatenation.
636  AkForceInline void SafeStrCat( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
637  {
638  size_t uAvailableSize = ( in_uDestMaxNumChars - strlen( in_pDest ) - 1 );
639  strncat( in_pDest, in_pSrc, AkMin( uAvailableSize, strlen( in_pSrc ) ) );
640  }
641 
642  inline int SafeStrFormat(wchar_t * in_pDest, size_t in_uDestMaxNumChars, const wchar_t* in_pszFmt, ...)
643  {
644  va_list args;
645  va_start(args, in_pszFmt);
646  int r = vswprintf(in_pDest, in_uDestMaxNumChars, in_pszFmt, args);
647  va_end(args);
648  return r;
649  }
650 
651  inline int SafeStrFormat(char * in_pDest, size_t in_uDestMaxNumChars, const char* in_pszFmt, ...)
652  {
653  va_list args;
654  va_start(args, in_pszFmt);
655  int r = vsnprintf(in_pDest, in_uDestMaxNumChars, in_pszFmt, args);
656  va_end(args);
657  return r;
658  }
659 
660  /// Stack allocations.
661  #define AkAlloca( _size_ ) alloca( _size_ )
662 
663 
664 
665  /// Converts a wchar_t string to an AkOSChar string.
666  /// \remark On some platforms the AkOSChar string simply points to the same string,
667  /// on others a new buffer is allocated on the stack using AkAlloca. This means
668  /// you must make sure that:
669  /// - The source string stays valid and unmodified for as long as you need the
670  /// AkOSChar string (for cases where they point to the same string)
671  /// - The AkOSChar string is used within this scope only -- for example, do NOT
672  /// return that string from a function (for cases where it is allocated on the stack)
673  #define CONVERT_WIDE_TO_OSCHAR( _wstring_, _oscharstring_ ) \
674  _oscharstring_ = (AkOSChar*)AkAlloca( (1 + wcslen( _wstring_ )) * sizeof(AkOSChar) ); \
675  AKPLATFORM::AkWideCharToChar( _wstring_ , (AkUInt32)(1 + wcslen( _wstring_ )), (AkOSChar*)( _oscharstring_ ) )
676 
677 
678  /// Converts a char string to an AkOSChar string.
679  /// \remark On some platforms the AkOSChar string simply points to the same string,
680  /// on others a new buffer is allocated on the stack using AkAlloca. This means
681  /// you must make sure that:
682  /// - The source string stays valid and unmodified for as long as you need the
683  /// AkOSChar string (for cases where they point to the same string)
684  /// - The AkOSChar string is used within this scope only -- for example, do NOT
685  /// return that string from a function (for cases where it is allocated on the stack)
686  #define CONVERT_CHAR_TO_OSCHAR( _astring_, _oscharstring_ ) ( _oscharstring_ ) = (AkOSChar*)( _astring_ )
687 
688  /// Converts a AkOSChar string into wide char string.
689  /// \remark On some platforms the AkOSChar string simply points to the same string,
690  /// on others a new buffer is allocated on the stack using AkAlloca. This means
691  /// you must make sure that:
692  /// - The source string stays valid and unmodified for as long as you need the
693  /// AkOSChar string (for cases where they point to the same string)
694  /// - The AkOSChar string is used within this scope only -- for example, do NOT
695  /// return that string from a function (for cases where it is allocated on the stack)
696  #define CONVERT_OSCHAR_TO_WIDE( _osstring_, _wstring_ ) \
697  _wstring_ = (wchar_t*)AkAlloca((1+strlen(_osstring_)) * sizeof(wchar_t)); \
698  AKPLATFORM::AkCharToWideChar( _osstring_, (AkUInt32)(1 + strlen(_osstring_ )), _wstring_ )
699 
700  /// Converts a AkOSChar string into char string.
701  /// \remark On some platforms the AkOSChar string simply points to the same string,
702  /// on others a new buffer is allocated on the stack using AkAlloca. This means
703  /// you must make sure that:
704  /// - The source string stays valid and unmodified for as long as you need the
705  /// AkOSChar string (for cases where they point to the same string)
706  /// - The AkOSChar string is used within this scope only -- for example, do NOT
707  /// return that string from a function (for cases where it is allocated on the stack)
708  #define CONVERT_OSCHAR_TO_CHAR( _osstring_, _astring_ ) _astring_ = (char*)_osstring_
709 
710  /// Get the length, in characters, of a NULL-terminated AkUtf16 string
711  /// \return The length, in characters, of the specified string (excluding terminating NULL)
712  AkForceInline size_t AkUtf16StrLen( const AkUtf16* in_pStr )
713  {
714  return ( wcslen( in_pStr ) );
715  }
716 
717  /// Get the length, in characters, of a NULL-terminated AkOSChar string
718  /// \return The length, in characters, of the specified string (excluding terminating NULL)
719  AkForceInline size_t OsStrLen( const AkOSChar* in_pszString )
720  {
721  return ( strlen( in_pszString ) );
722  }
723 
724  /// AkOSChar version of sprintf().
725  #define AK_OSPRINTF snprintf
726 
727  /// Compare two NULL-terminated AkOSChar strings
728  /// \return
729  /// - < 0 if in_pszString1 < in_pszString2
730  /// - 0 if the two strings are identical
731  /// - > 0 if in_pszString1 > in_pszString2
732  /// \remark The comparison is case-sensitive
733  AkForceInline int OsStrCmp( const AkOSChar* in_pszString1, const AkOSChar* in_pszString2 )
734  {
735  return ( strcmp( in_pszString1, in_pszString2 ) );
736  }
737 
738  /// Compare two NULL-terminated AkOSChar strings up to the specified count of characters.
739  /// \return
740  /// - < 0 if in_pszString1 < in_pszString2
741  /// - 0 if the two strings are identical
742  /// - > 0 if in_pszString1 > in_pszString2
743  /// \remark The comparison is case-sensitive
744  inline int OsStrNCmp( const AkOSChar* in_pszString1, const AkOSChar* in_pszString2, size_t in_MaxCountSize )
745  {
746  return ( strncmp(in_pszString1, in_pszString2, in_MaxCountSize) );
747  }
748 
749  /// Detects whether the string represents an absolute path to a file
750  inline bool IsAbsolutePath(const AkOSChar* in_pszPath, size_t in_pathLen)
751  {
752  return in_pathLen >= 1 && in_pszPath[0] == '/';
753  }
754 
755  #define AK_UTF16_TO_WCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
756  #define AK_WCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
757  #define AK_UTF8_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
758  #define AK_UTF16_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkWideCharToChar( in_pSrc, in_MaxSize, in_pdDest )
759  #define AK_UTF16_TO_CHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkWideCharToChar( in_pSrc, in_MaxSize, in_pdDest )
760  #define AK_CHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
761  #define AK_OSCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
762 
763  // Use with AkOSChar.
764  #define AK_PATH_SEPARATOR ("/")
765  #define AK_LIBRARY_PREFIX ("")
766  #define AK_DYNAMIC_LIBRARY_EXTENSION (".prx")
767 
768  #define AK_FILEHANDLE_TO_UINTPTR(_h) ((AkUIntPtr)_h)
769  #define AK_SET_FILEHANDLE_TO_UINTPTR(_h,_u) _h = (AkFileHandle)_u
770 
771  /// Support to fetch the CPUID for the platform. Only valid for X86 targets
772  /// \remark Note that IAkProcessorFeatures should be preferred to fetch this data
773  /// as it will have already translated the feature bits into AK-relevant enums
774  inline void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
775  {
776  __get_cpuid_count( in_uLeafOpcode, in_uSubLeafOpcode,
777  &out_uCPUFeatures[0],
778  &out_uCPUFeatures[1],
779  &out_uCPUFeatures[2],
780  &out_uCPUFeatures[3]);
781  }
782 }
783 
784 #endif // _AK_PLATFORM_FUNCS_H_
AKRESULT AkCreateSemaphore(AkSemaphore &out_semaphore, AkUInt32 in_initialCount)
Platform Independent Helper.
size_t AkUtf16StrLen(const AkUtf16 *in_pStr)
Audiokinetic namespace.
@ AK_Fail
The operation failed.
Definition: AkTypes.h:202
semaphore_t AkEvent
Definition: AkTypes.h:84
AkForceInline void FreeVM(void *address, size_t size, size_t extra, size_t release)
#define AK_THREAD_DEFAULT_SCHED_POLICY
int nPriority
Thread priority.
void AkClearEvent(AkEvent &out_event)
Platform Independent Helper.
AkForceInline void AkClearSemaphore(AkSemaphore &io_semaphore)
Platform Independent Helper.
AkForceInline void FreeDevice(void *address, size_t size, size_t extra, size_t release)
Platform-dependent helpers.
void AkWaitForEvent(AkEvent &in_event)
Platform Independent Helper.
AkForceInline void UpdatePerformanceFrequency()
Platform Independent Helper.
int AkThreadID
Definition: AkTypes.h:69
AKRESULT
Standard function call result.
Definition: AkTypes.h:199
AkForceInline bool CheckMemoryProtection(void *address, size_t size, int expectedProt)
void OutputDebugMsg(const char *in_pszMsg)
Output a debug message on the console (Ansi string)
AkForceInline void * AllocVM(size_t size, size_t *extra)
__forceinline int AkAtomicCas32(AkAtomic32 *pDest, long proposed, long expected)
Definition: AkAtomic.h:67
void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
#define AK_NULL_THREAD
#define AK_VM_HUGE_PAGE_SIZE
char AkOSChar
Generic character string.
Definition: AkTypes.h:60
int SafeStrFormat(wchar_t *in_pDest, size_t in_uDestMaxNumChars, const wchar_t *in_pszFmt,...)
AkForceInline void * AllocDevice(size_t size, size_t *extra)
#define NULL
Definition: AkTypes.h:46
#define AK_THREAD_AFFINITY_DEFAULT
AkThreadID CurrentThread()
Returns the calling thread's ID.
bool IsAbsolutePath(const AkOSChar *in_pszPath, size_t in_pathLen)
Detects whether the string represents an absolute path to a file.
float AkReal32
32-bit floating point
@ AK_Success
The operation was successful.
Definition: AkTypes.h:201
int32_t AkInt32
Signed 32-bit integer.
void AkCreateThread(AkThreadRoutine pStartRoutine, void *pParams, const AkThreadProperties &in_threadProperties, AkThread *out_pThread, const char *)
Platform Independent Helper.
const int kMemoryFlags
AkUInt16 AkUtf16
Definition: AkTypes.h:61
uintptr_t AkUIntPtr
Integer (unsigned) type for pointers.
#define AK_VM_PAGE_SIZE
#define AK_THREAD_PRIORITY_NORMAL
void OutputDebugMsgV(const char *in_pszFmt,...)
Output a debug message on the console (variadic function).
void PerformanceCounter(AkInt64 *out_piLastTime)
Platform Independent Helper.
void AkDestroySemaphore(AkSemaphore &io_semaphore)
Platform Independent Helper.
void AkDestroyEvent(AkEvent &io_event)
Platform Independent Helper.
nn::os::ThreadFunction AkThreadRoutine
Thread routine.
Definition: AkTypes.h:87
AkForceInline bool AkIsValidThread(AkThread *in_pThread)
Platform Independent Helper.
#define AkMin(x1, x2)
AkForceInline void AkMemCpy(void *pDest, const void *pSrc, AkUInt32 uSize)
Platform Independent Helper.
#define AKASSERT(Condition)
Definition: AkAssert.h:67
#define AKVERIFY(x)
Definition: AkAssert.h:69
AkForceInline void AkSleep(AkUInt32 in_ulMilliseconds)
Platform Independent Helper.
AkForceInline void AkClearThread(AkThread *in_pThread)
Platform Independent Helper.
AkForceInline void AkGetDefaultThreadProperties(AkThreadProperties &out_threadProperties)
Platform Independent Helper.
int OsStrNCmp(const AkOSChar *in_pszString1, const AkOSChar *in_pszString2, size_t in_MaxCountSize)
void AkLimitedSpinForZero(AkAtomic32 *in_pVal)
bool AkLimitedSpinToAcquire(AkAtomic32 *in_pVal, AkInt32 in_proposed, AkInt32 in_expected)
AkForceInline void AkMemSet(void *pDest, AkInt32 iVal, AkUInt32 uSize)
Platform Independent Helper.
void AkMemMove(void *pDest, const void *pSrc, AkUInt32 uSize)
Platform Independent Helper.
SceKernelCpumask dwAffinityMask
Affinity mask.
AkReal32 g_fFreqRatio
double AkReal64
64-bit floating point
AKRESULT AkCreateEvent(AkEvent &out_event)
Platform Independent Helper.
AkForceInline void SafeStrCpy(wchar_t *in_pDest, const wchar_t *in_pSrc, size_t in_uDestMaxNumChars)
Safe unicode string copy.
const int kDeviceMemoryFlags
int64_t AkInt64
Signed 64-bit integer.
volatile long AkAtomic32
Definition: AkAtomic.h:42
void AkWaitForSemaphore(AkSemaphore &in_semaphore)
Platform Independent Helper - Semaphore wait, aka Operation P. Decrements value of semaphore,...
size_t uStackSize
Thread stack size.
void PerformanceFrequency(AkInt64 *out_piFreq)
Platform Independent Helper.
#define AK_DEFAULT_STACK_SIZE
int uSchedPolicy
Thread scheduling policy.
AkForceInline AkInt32 AkCharToWideChar(const char *in_pszAnsiString, AkUInt32 in_uiOutBufferSize, void *io_pvUnicodeStringBuffer)
String conversion helper.
uint32_t AkUInt32
Unsigned 32-bit integer.
void AkReleaseSemaphore(AkSemaphore &in_semaphore, AkUInt32 in_count)
Platform Independent Helper - Semaphore signal, aka Operation V. Increments value of semaphore by an ...
AkForceInline void SafeStrCat(wchar_t *in_pDest, const wchar_t *in_pSrc, size_t in_uDestMaxNumChars)
Safe unicode string concatenation.
AkForceInline AKRESULT AkCreateNamedEvent(AkEvent &out_event, const char *in_szName)
#define AK_VM_DEVICE_PAGE_SIZE
AkForceInline AkInt32 AkWideCharToChar(const wchar_t *in_pszUnicodeString, AkUInt32 in_uiOutBufferSize, char *io_pszAnsiString)
String conversion helper.
AkForceInline void AkWaitForSingleThread(AkThread *in_pThread)
Platform Independent Helper.
void AkSignalEvent(const AkEvent &in_event)
Platform Independent Helper.
AkForceInline AkInt32 AkUtf8ToWideChar(const char *in_pszUtf8String, AkUInt32 in_uiOutBufferSize, void *io_pvUnicodeStringBuffer)
String conversion helper.
semaphore_t AkSemaphore
Definition: AkTypes.h:85
AkForceInline void AkCloseThread(AkThread *in_pThread)
Platform Independent Helper.
AkForceInline int OsStrCmp(const AkOSChar *in_pszString1, const AkOSChar *in_pszString2)
#define AkForceInline
Definition: AkTypes.h:63
__forceinline long AkAtomicLoad32(AkAtomic32 *pSrc)
Definition: AkAtomic.h:57
AkForceInline size_t OsStrLen(const AkOSChar *in_pszString)
AkForceInline AkReal32 Elapsed(const AkInt64 &in_iNow, const AkInt64 &in_iStart)
Returns a time range in milliseconds, using the sound engine's updated count->milliseconds ratio.

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