Version
menu_open
link
Target Platform(s):
Wwise SDK 2022.1.4
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) 2023 Audiokinetic Inc.
25 *******************************************************************************/
26 
27 #ifndef _AK_PLATFORM_FUNCS_H_
28 #define _AK_PLATFORM_FUNCS_H_
29 
30 #include "malloc.h"
33 #include <windows.h>
34 #include <stdio.h>
35 
36 #if defined(_WIN64)
37 // on 64 bit, removes warning C4985: 'ceil': attributes not present on previous declaration.
38 // see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=294649
39 #include <math.h>
40 #endif // _WIN64
41 #include <intrin.h>
42 
43 #if defined(AK_XBOXSERIESX)
44 #include <ammintrin.h>
45 #endif
46 
47 //-----------------------------------------------------------------------------
48 // Platform-specific thread properties definition.
49 //-----------------------------------------------------------------------------
50 struct AkThreadProperties
51 {
52  int nPriority; ///< Thread priority
53 #ifdef AK_WIN_UNIVERSAL_APP
54  PROCESSOR_NUMBER processorNumber;///< Ideal processor (passed to SetThreadIdealProcessorEx)
55 #else
56  AkUInt32 dwAffinityMask; ///< Affinity mask
57 #endif
58  AkUInt32 uStackSize; ///< Thread stack size.
59 };
60 
61 //-----------------------------------------------------------------------------
62 // External variables.
63 //-----------------------------------------------------------------------------
64 // g_fFreqRatio is used by time helpers to return time values in milliseconds.
65 // It is declared and updated by the sound engine.
66 namespace AK
67 {
68  extern AkReal32 g_fFreqRatio;
69 }
70 
71 //-----------------------------------------------------------------------------
72 // Defines for Win32.
73 //-----------------------------------------------------------------------------
74 #define AK_DECLARE_THREAD_ROUTINE( FuncName ) DWORD WINAPI FuncName(LPVOID lpParameter)
75 #define AK_THREAD_RETURN( _param_ ) return (_param_);
76 #define AK_THREAD_ROUTINE_PARAMETER lpParameter
77 #define AK_GET_THREAD_ROUTINE_PARAMETER_PTR(type) reinterpret_cast<type*>( AK_THREAD_ROUTINE_PARAMETER )
78 #define AK_RETURN_THREAD_OK 0x00000000
79 #define AK_RETURN_THREAD_ERROR 0x00000001
80 #define AK_DEFAULT_STACK_SIZE (128*1024)
81 #define AK_THREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
82 #define AK_THREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_ABOVE_NORMAL
83 #define AK_THREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_BELOW_NORMAL
84 #define AK_THREAD_PRIORITY_TIME_CRITICAL THREAD_PRIORITY_TIME_CRITICAL
85 #define AK_THREAD_MODE_BACKGROUND_BEGIN THREAD_MODE_BACKGROUND_BEGIN
86 
87 // NULL objects
88 #define AK_NULL_THREAD NULL
89 
90 #define AK_INFINITE INFINITE
91 
92 #define AkMax(x1, x2) (((x1) > (x2))? (x1): (x2))
93 #define AkMin(x1, x2) (((x1) < (x2))? (x1): (x2))
94 #define AkClamp(x, min, max) ((x) < (min)) ? (min) : (((x) > (max) ? (max) : (x)))
95 
96 namespace AKPLATFORM
97 {
98  // Simple automatic event API
99  // ------------------------------------------------------------------
100 
101  /// Platform Independent Helper
102  inline void AkClearEvent( AkEvent & out_event )
103  {
104  out_event = NULL;
105  }
106 
107  /// Platform Independent Helper
108  inline AKRESULT AkCreateEvent( AkEvent & out_event )
109  {
110 #ifdef AK_USE_UWP_API
111  out_event = CreateEventEx(nullptr, nullptr, 0, STANDARD_RIGHTS_ALL|EVENT_MODIFY_STATE);
112 #else
113  out_event = ::CreateEvent( NULL, // No security attributes
114  false, // Reset type: automatic
115  false, // Initial signaled state: not signaled
116  NULL // No name
117  );
118 #endif
119  return ( out_event ) ? AK_Success : AK_Fail;
120  }
121 
122  /// Platform Independent Helper
123  inline void AkDestroyEvent( AkEvent & io_event )
124  {
125  if ( io_event )
126  ::CloseHandle( io_event );
127  io_event = NULL;
128  }
129 
130  /// Platform Independent Helper
131  inline void AkWaitForEvent( AkEvent & in_event )
132  {
133 #ifdef AK_USE_UWP_API
134  DWORD dwWaitResult = ::WaitForSingleObjectEx( in_event, INFINITE, FALSE );
135  AKASSERT( dwWaitResult == WAIT_OBJECT_0 );
136 #else
137  AKVERIFY( ::WaitForSingleObject( in_event, INFINITE ) == WAIT_OBJECT_0 );
138 #endif
139  }
140 
141  /// Platform Independent Helper
142  inline void AkSignalEvent( const AkEvent & in_event )
143  {
144  AKVERIFY( ::SetEvent( in_event ) );
145  }
146 
147  /// Platform Independent Helper
148  AkForceInline void AkClearSemaphore(AkSemaphore& io_semaphore)
149  {
150  io_semaphore = NULL;
151  }
152 
153  /// Platform Independent Helper
154  inline AKRESULT AkCreateSemaphore(AkSemaphore& out_semaphore, AkUInt32 in_initialCount)
155  {
156 #ifdef AK_USE_UWP_API
157  out_semaphore = ::CreateSemaphoreEx(
158  NULL, // no security attributes
159  in_initialCount, // initial count
160  INT_MAX, // no maximum -- matches posix semaphore behaviour
161  NULL, // no name
162  0, // reserved
163  STANDARD_RIGHTS_ALL | SEMAPHORE_MODIFY_STATE);
164 #else
165  out_semaphore = ::CreateSemaphore(
166  NULL, // no security attributes
167  in_initialCount, // initial count
168  INT_MAX, // no maximum -- matches posix semaphore behaviour
169  NULL); // no name
170 #endif
171  return (out_semaphore) ? AK_Success : AK_Fail;
172  }
173 
174  /// Platform Independent Helper
175  inline void AkDestroySemaphore(AkSemaphore& io_semaphore)
176  {
177  ::CloseHandle(io_semaphore);
178  }
179 
180  /// 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.
181  inline void AkWaitForSemaphore(AkSemaphore& in_semaphore)
182  {
183  AKVERIFY(::WaitForSingleObject(in_semaphore, INFINITE) == WAIT_OBJECT_0);
184  }
185 
186  /// Platform Independent Helper - Semaphore signal, aka Operation V. Increments value of semaphore by an arbitrary count.
187  inline void AkReleaseSemaphore(AkSemaphore& in_semaphore, AkUInt32 in_count)
188  {
189  AKVERIFY(ReleaseSemaphore(in_semaphore, in_count, NULL) >= 0);
190  }
191 
192  // Virtual Memory
193  // ------------------------------------------------------------------
194 
195 #if defined(AK_WIN)
196 #ifdef AK_WIN_UNIVERSAL_APP
197  AkForceInline void* AllocVM(size_t size, size_t* /*extra*/)
198  {
199  return VirtualAllocFromApp(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
200  }
201 #else
202  AkForceInline void* AllocVM(size_t size, size_t* /*extra*/)
203  {
204  return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
205  }
206 
207 #endif
208  AkForceInline void FreeVM(void* address, size_t size, size_t /*extra*/, size_t release)
209  {
210  VirtualFree(address, release ? 0 : size, release ? MEM_RELEASE : MEM_DECOMMIT);
211  }
212 #endif
213 
214  // Threads
215  // ------------------------------------------------------------------
216 
217  /// Platform Independent Helper
218  inline bool AkIsValidThread( AkThread * in_pThread )
219  {
220  return (*in_pThread != AK_NULL_THREAD);
221  }
222 
223  /// Platform Independent Helper
224  inline void AkClearThread( AkThread * in_pThread )
225  {
226  *in_pThread = AK_NULL_THREAD;
227  }
228 
229  /// Platform Independent Helper
230  inline void AkCloseThread( AkThread * in_pThread )
231  {
232  AKASSERT( in_pThread );
233  AKASSERT( *in_pThread );
234  AKVERIFY( ::CloseHandle( *in_pThread ) );
235  AkClearThread( in_pThread );
236  }
237 
238 #define AkExitThread( _result ) return _result;
239 
240  /// Platform Independent Helper
241  inline void AkGetDefaultThreadProperties( AkThreadProperties & out_threadProperties )
242  {
243  out_threadProperties.nPriority = AK_THREAD_PRIORITY_NORMAL;
244  out_threadProperties.uStackSize= AK_DEFAULT_STACK_SIZE;
245 #ifdef AK_WIN_UNIVERSAL_APP
246  out_threadProperties.processorNumber.Group = 0;
247  out_threadProperties.processorNumber.Number = MAXIMUM_PROCESSORS;
248  out_threadProperties.processorNumber.Reserved = 0;
249 #else
250  out_threadProperties.dwAffinityMask = 0;
251 #endif
252  }
253 
254  /// Set the name of a thread: see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
255  inline void AkSetThreadName( AkThread in_threadHnd, DWORD in_dwThreadID, LPCSTR in_szThreadName )
256  {
257  const DWORD MS_VC_EXCEPTION=0x406D1388;
258 
259 #pragma pack(push,8)
260  typedef struct tagTHREADNAME_INFO
261  {
262  DWORD dwType;
263  LPCSTR szName;
264  DWORD dwThreadID;
265  DWORD dwFlags;
266  } THREADNAME_INFO;
267 #pragma pack(pop)
268 
269  THREADNAME_INFO info;
270  info.dwType = 0x1000;
271  info.szName = in_szThreadName;
272  info.dwThreadID = in_dwThreadID;
273  info.dwFlags = 0;
274 
275  __try
276  {
277  RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
278  }
279 #pragma warning(suppress: 6312 6322)
280  __except(EXCEPTION_CONTINUE_EXECUTION)
281  {
282  }
283 
284 #if defined(AK_XBOX) || defined(_GAMING_DESKTOP) // also applicable on Windows when Win7 support is dropped. SetThreadDescription is a Win10 only API
285  wchar_t wszThreadName[32];
286  AkUInt32 maxStrLen = (sizeof(wszThreadName) / sizeof(wchar_t)) - 1;
287  AkUInt32 nameStrLen = AkMin((int)strlen(in_szThreadName), maxStrLen);
288  MultiByteToWideChar(CP_UTF8, 0, in_szThreadName, nameStrLen, wszThreadName, maxStrLen);
289  wszThreadName[nameStrLen] = '\0';
290  SetThreadDescription(in_threadHnd, wszThreadName);
291 #endif
292  }
293 
294  /// Platform Independent Helper
295  inline void AkCreateThread(
296  AkThreadRoutine pStartRoutine, // Thread routine.
297  void * pParams, // Routine params.
298  const AkThreadProperties & in_threadProperties, // Properties. NULL for default.
299  AkThread * out_pThread, // Returned thread handle.
300  const char * in_szThreadName ) // Opt thread name.
301  {
302  AKASSERT( out_pThread != NULL );
303  AKASSERT( (in_threadProperties.nPriority >= THREAD_PRIORITY_LOWEST && in_threadProperties.nPriority <= THREAD_PRIORITY_HIGHEST)
304  || ( in_threadProperties.nPriority == THREAD_PRIORITY_TIME_CRITICAL )
305  || ( in_threadProperties.nPriority == THREAD_MODE_BACKGROUND_BEGIN ) );
306 
307  DWORD dwThreadID;
308  *out_pThread = ::CreateThread( NULL, // No security attributes
309  in_threadProperties.uStackSize, // StackSize (0 uses system default)
310  pStartRoutine, // Thread start routine
311  pParams, // Thread function parameter
312  0, // Creation flags: create running
313  &dwThreadID );
314 
315  // ::CreateThread() return NULL if it fails.
316  if ( !*out_pThread )
317  {
318  AkClearThread( out_pThread );
319  return;
320  }
321 
322  // Set thread name.
323  if (in_szThreadName)
324  {
325  AkSetThreadName(*out_pThread, dwThreadID, in_szThreadName);
326  }
327 
328  // Set properties.
329  if ( !::SetThreadPriority( *out_pThread, in_threadProperties.nPriority ) &&
330  in_threadProperties.nPriority != THREAD_MODE_BACKGROUND_BEGIN )
331  {
332  AKASSERT( !"Failed setting thread priority" );
333  AkCloseThread( out_pThread );
334  return;
335  }
336 #ifdef AK_WIN_UNIVERSAL_APP
337  if ( in_threadProperties.processorNumber.Number != MAXIMUM_PROCESSORS)
338  {
339  if ( !SetThreadIdealProcessorEx( *out_pThread, const_cast<PPROCESSOR_NUMBER>(&in_threadProperties.processorNumber), NULL) )
340  {
341  AKASSERT( !"Failed setting thread ideal processor" );
342  AkCloseThread( out_pThread );
343  }
344  }
345 #else
346  if (in_threadProperties.dwAffinityMask)
347  {
348  if (!::SetThreadAffinityMask(*out_pThread, in_threadProperties.dwAffinityMask))
349  {
350  AKASSERT(!"Failed setting thread affinity mask");
351  AkCloseThread(out_pThread);
352  }
353  }
354 #endif
355  }
356 
357  /// Platform Independent Helper
358  inline void AkWaitForSingleThread( AkThread * in_pThread )
359  {
360  AKASSERT( in_pThread );
361  AKASSERT( *in_pThread );
362 #ifdef AK_USE_UWP_API
363  ::WaitForSingleObjectEx( *in_pThread, INFINITE, FALSE );
364 #else
365  ::WaitForSingleObject( *in_pThread, INFINITE );
366 #endif
367  }
368 
369  /// Returns the calling thread's ID.
370  inline AkThreadID CurrentThread()
371  {
372  return ::GetCurrentThreadId();
373  }
374 
375  /// Platform Independent Helper
376  inline void AkSleep( AkUInt32 in_ulMilliseconds )
377  {
378  ::Sleep( in_ulMilliseconds );
379  }
380 
381  // Optimized memory functions
382  // --------------------------------------------------------------------
383 
384  /// Platform Independent Helper
385  inline void AkMemCpy( void * pDest, const void * pSrc, AkUInt32 uSize )
386  {
387  memcpy( pDest, pSrc, uSize );
388  }
389 
390  /// Platform Independent Helper
391  inline void AkMemMove( void* pDest, const void* pSrc, AkUInt32 uSize )
392  {
393  memmove( pDest, pSrc, uSize );
394  }
395 
396  /// Platform Independent Helper
397  inline void AkMemSet( void * pDest, AkInt32 iVal, AkUInt32 uSize )
398  {
399  memset( pDest, iVal, uSize );
400  }
401 
402  // Time functions
403  // ------------------------------------------------------------------
404 
405  /// Platform Independent Helper
406  inline void PerformanceCounter( AkInt64 * out_piLastTime )
407  {
408  ::QueryPerformanceCounter( (LARGE_INTEGER*)out_piLastTime );
409  }
410 
411  /// Platform Independent Helper
412  inline void PerformanceFrequency( AkInt64 * out_piFreq )
413  {
414  ::QueryPerformanceFrequency( (LARGE_INTEGER*)out_piFreq );
415  }
416 
417  /// Platform Independent Helper
418  inline void UpdatePerformanceFrequency()
419  {
420  AkInt64 iFreq;
421  PerformanceFrequency( &iFreq );
422  AK::g_fFreqRatio = (AkReal32)((AkReal64)iFreq / 1000);
423  }
424 
425  /// Returns a time range in milliseconds, using the sound engine's updated count->milliseconds ratio.
426  inline AkReal32 Elapsed( const AkInt64 & in_iNow, const AkInt64 & in_iStart )
427  {
428  return ( in_iNow - in_iStart ) / AK::g_fFreqRatio;
429  }
430 
431 #if defined(AK_XBOXSERIESX)
432  // Waits for a limited amount of time for in_pVal to hit zero (without yielding the thread)
433  inline void AkLimitedSpinForZero(AkAtomic32* in_pVal)
434  {
435  // monitorx and waitx are available on certain AMD CPUs, so we can have a custom impl of AkLimitedSpinForZero
436  AkInt64 endSpinTime = 0;
437  AkInt64 currentTime = 0;
438  PerformanceCounter(&endSpinTime);
439  endSpinTime += AkInt64(AK::g_fFreqRatio * 0.01); // only spin for about 10us
440  while (true)
441  {
442  // set up monitorx on pVal
443  _mm_monitorx((void*)in_pVal, 0U, 0U);
444  // if pval is zero, skip out
445  if (AkAtomicLoad32(in_pVal) == 0)
446  {
447  break;
448  }
449  // wait until a store to pVal occurs (or ~1us passes)
450  _mm_mwaitx(2U, 0U, 1000U);
451 
452  // Check if we've hit the deadline for the timeout
453  PerformanceCounter(&currentTime);
454  if (currentTime > endSpinTime)
455  {
456  break;
457  }
458  }
459  }
460 #define AK_LIMITEDSPINFORZERO // mark AkLimitedSpinForZero as defined to avoid duplicate definitions
461 #endif
462 
463  /// String conversion helper. If io_pszAnsiString is null, the function returns the required size.
464  inline AkInt32 AkWideCharToChar( const wchar_t* in_pszUnicodeString,
465  AkUInt32 in_uiOutBufferSize,
466  char* io_pszAnsiString )
467  {
468  if(!io_pszAnsiString)
469  return WideCharToMultiByte(CP_UTF8, 0, in_pszUnicodeString, -1, NULL, 0, NULL, NULL);
470 
471  int iWritten = ::WideCharToMultiByte(CP_UTF8, // code page
472  0, // performance and mapping flags
473  in_pszUnicodeString, // wide-character string
474  (int)AkMin( ( (AkUInt32)wcslen( in_pszUnicodeString )), in_uiOutBufferSize-1 ), // number of chars in string : -1 = NULL terminated string.
475  io_pszAnsiString, // buffer for new string
476  in_uiOutBufferSize, // size of buffer
477  NULL, // default for unmappable chars
478  NULL); // set when default char used
479  io_pszAnsiString[iWritten] = 0;
480  return iWritten;
481  }
482 
483  /// String conversion helper
484  inline AkInt32 AkCharToWideChar( const char* in_pszAnsiString,
485  AkUInt32 in_uiOutBufferSize,
486  void* io_pvUnicodeStringBuffer )
487  {
488  return ::MultiByteToWideChar( CP_UTF8, // code page
489  0, // performance and mapping flags
490  in_pszAnsiString, // wide-character string
491  -1, // number of chars in string : -1 = NULL terminated string.
492  (wchar_t*)io_pvUnicodeStringBuffer, // buffer for new string
493  in_uiOutBufferSize); // size of buffer
494  }
495 
496  /// String conversion helper
497  inline AkInt32 AkUtf8ToWideChar( const char* in_pszUtf8String,
498  AkUInt32 in_uiOutBufferSize,
499  void* io_pvUnicodeStringBuffer )
500  {
501  return ::MultiByteToWideChar( CP_UTF8, // code page
502  0, // performance and mapping flags
503  in_pszUtf8String, // wide-character string
504  -1, // number of chars in string : -1 = NULL terminated string.
505  (wchar_t*)io_pvUnicodeStringBuffer, // buffer for new string
506  in_uiOutBufferSize); // size of buffer
507  }
508 
509  /// Safe unicode string copy.
510  inline void SafeStrCpy( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
511  {
512  size_t iSizeCopy = AkMin( in_uDestMaxNumChars - 1, wcslen( in_pSrc ) + 1 );
513  wcsncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
514  in_pDest[iSizeCopy] = '\0';
515  }
516 
517  /// Safe string copy.
518  inline void SafeStrCpy( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
519  {
520  size_t iSizeCopy = AkMin( in_uDestMaxNumChars - 1, strlen( in_pSrc ) + 1 );
521  strncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
522  in_pDest[iSizeCopy] = '\0';
523  }
524 
525  /// Safe unicode string concatenation.
526  inline void SafeStrCat( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
527  {
528  int iAvailableSize = (int)( in_uDestMaxNumChars - wcslen( in_pDest ) - 1 );
529  wcsncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc, AkMin( iAvailableSize, (int)wcslen( in_pSrc ) ) );
530  }
531 
532  /// Safe string concatenation.
533  inline void SafeStrCat( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
534  {
535  int iAvailableSize = (int)( in_uDestMaxNumChars - strlen( in_pDest ) - 1 );
536  strncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc, AkMin( iAvailableSize, (int)strlen( in_pSrc ) ) );
537  }
538 
539  inline int SafeStrFormat(wchar_t * in_pDest, size_t in_uDestMaxNumChars, const wchar_t* in_pszFmt, ...)
540  {
541  va_list args;
542  va_start(args, in_pszFmt);
543  int r = vswprintf(in_pDest, in_uDestMaxNumChars, in_pszFmt, args);
544  va_end(args);
545  return r;
546  }
547 
548  inline int SafeStrFormat(char * in_pDest, size_t in_uDestMaxNumChars, const char* in_pszFmt, ...)
549  {
550  va_list args;
551  va_start(args, in_pszFmt);
552  int r = vsnprintf(in_pDest, in_uDestMaxNumChars, in_pszFmt, args);
553  va_end(args);
554  return r;
555  }
556 
557  /// Stack allocations.
558  #define AkAlloca( _size_ ) _alloca( _size_ )
559 
560  /// Output a debug message on the console
561 #if ! defined(AK_OPTIMIZED)
562  inline void OutputDebugMsg( const wchar_t* in_pszMsg )
563  {
564  OutputDebugStringW( in_pszMsg );
565  }
566 
567  /// Output a debug message on the console
568  inline void OutputDebugMsg( const char* in_pszMsg )
569  {
570  OutputDebugStringA( in_pszMsg );
571  }
572 
573  /// Output a debug message on the console (variadic function).
574  /// Use MaxSize to specify the size to reserve for the message.
575  /// Warning: On Win32, OutputDebugMsgV with wchar_t will truncate the string
576  /// to MaxSize.
577  template <int MaxSize = 256>
578  inline void OutputDebugMsgV(const wchar_t* in_pszFmt, ...)
579  {
580  // No equivalent of snprintf for wide string so truncate if necessary
581  // vswprintf returns the number of characters written and not the numbers
582  // that would be written
583 
584  wchar_t* msg = (wchar_t*)AkAlloca(MaxSize * sizeof(wchar_t));
585  msg[MaxSize - 1] = '\0';
586 
587  va_list args;
588  va_start(args, in_pszFmt);
589  vswprintf(msg, MaxSize, in_pszFmt, args);
590  va_end(args);
591 
592  OutputDebugMsg(msg);
593  }
594 
595  /// Output a debug message on the console (variadic function).
596  /// Use MaxSize to specify the expected size of the message.
597  /// If the required size is superior to MaxSize, a new string
598  /// will be allocated on the stack with the required size.
599  template <int MaxSize = 256>
600  inline void OutputDebugMsgV(const char* in_pszFmt, ...)
601  {
602  int size = 0;
603  {
604  // Try with a reasonable guess first
605  char msg[MaxSize];
606  msg[MaxSize - 1] = '\0';
607 
608  va_list args;
609  va_start(args, in_pszFmt);
610  size = vsnprintf(msg, MaxSize, in_pszFmt, args);
611  va_end(args);
612 
613  // If it was enough, print to debug log
614  if (0 <= size && size <= MaxSize)
615  {
616  OutputDebugMsg(msg);
617  return;
618  }
619  }
620 
621  // Else, we need more memory to prevent truncation
622  {
623  // size + 1 more char for the last '\0'
624  size++;
625 
626  char* msg = (char*)AkAlloca((size) * sizeof(char));
627  msg[size - 1] = '\0';
628 
629  va_list args;
630  va_start(args, in_pszFmt);
631  vsnprintf(msg, size, in_pszFmt, args);
632  va_end(args);
633 
634  OutputDebugMsg(msg);
635  }
636  }
637 
638 #else
639  inline void OutputDebugMsg(const wchar_t*){}
640  inline void OutputDebugMsg(const char*){}
641 
642  template <int MaxSize = 0>
643  inline void OutputDebugMsgV(const wchar_t*, ...) {}
644 
645  template <int MaxSize = 0>
646  inline void OutputDebugMsgV(const char*, ...) {}
647 #endif
648 
649  /// Converts a wchar_t string to an AkOSChar string.
650  /// \remark On some platforms the AkOSChar string simply points to the same string,
651  /// on others a new buffer is allocated on the stack using AkAlloca. This means
652  /// you must make sure that:
653  /// - The source string stays valid and unmodified for as long as you need the
654  /// AkOSChar string (for cases where they point to the same string)
655  /// - The AkOSChar string is used within this scope only -- for example, do NOT
656  /// return that string from a function (for cases where it is allocated on the stack)
657  #define CONVERT_WIDE_TO_OSCHAR( _wstring_, _oscharstring_ ) ( _oscharstring_ ) = (AkOSChar*)( _wstring_ )
658 
659  /// Converts a char string to an AkOSChar string.
660  /// \remark On some platforms the AkOSChar string simply points to the same string,
661  /// on others a new buffer is allocated on the stack using AkAlloca. This means
662  /// you must make sure that:
663  /// - The source string stays valid and unmodified for as long as you need the
664  /// AkOSChar string (for cases where they point to the same string)
665  /// - The AkOSChar string is used within this scope only -- for example, do NOT
666  /// return that string from a function (for cases where it is allocated on the stack)
667  #define CONVERT_CHAR_TO_OSCHAR( _astring_, _oscharstring_ ) \
668  _oscharstring_ = (AkOSChar*)AkAlloca( (1 + strlen( _astring_ )) * sizeof(AkOSChar)); \
669  AKPLATFORM::AkCharToWideChar( _astring_, (AkUInt32)(1 + strlen(_astring_ )), (AkOSChar*)( _oscharstring_ ) )
670 
671  /// Converts a AkOSChar string into wide char string.
672  /// \remark On some platforms the AkOSChar string simply points to the same string,
673  /// on others a new buffer is allocated on the stack using AkAlloca. This means
674  /// you must make sure that:
675  /// - The source string stays valid and unmodified for as long as you need the
676  /// AkOSChar string (for cases where they point to the same string)
677  /// - The AkOSChar string is used within this scope only -- for example, do NOT
678  /// return that string from a function (for cases where it is allocated on the stack)
679  #define CONVERT_OSCHAR_TO_WIDE( _osstring_, _wstring_ ) _wstring_ = _osstring_
680 
681  /// Converts a AkOSChar string into char string.
682  /// \remark On some platforms the AkOSChar string simply points to the same string,
683  /// on others a new buffer is allocated on the stack using AkAlloca. This means
684  /// you must make sure that:
685  /// - The source string stays valid and unmodified for as long as you need the
686  /// AkOSChar string (for cases where they point to the same string)
687  /// - The AkOSChar string is used within this scope only -- for example, do NOT
688  /// return that string from a function (for cases where it is allocated on the stack)
689  #define CONVERT_OSCHAR_TO_CHAR( _osstring_, _astring_ ) \
690  _astring_ = (char*)AkAlloca( 1 + AKPLATFORM::AkWideCharToChar( _osstring_, 0, NULL )); \
691  AKPLATFORM::AkWideCharToChar( _osstring_, AkUInt32(1 + AKPLATFORM::AkWideCharToChar( _osstring_, 0, NULL )), _astring_ );
692 
693  /// Get the length, in characters, of a NULL-terminated AkUtf16 string
694  /// \return The length, in characters, of the specified string (excluding terminating NULL)
695  inline size_t AkUtf16StrLen( const AkUtf16* in_pStr )
696  {
697  return ( wcslen( in_pStr ) );
698  }
699 
700  /// Get the length, in characters, of a NULL-terminated AkOSChar string
701  /// \return The length, in characters, of the specified string (excluding terminating NULL)
702  inline size_t OsStrLen( const AkOSChar* in_pszString )
703  {
704  return ( wcslen( in_pszString ) );
705  }
706 
707  /// AkOSChar version of sprintf().
708  #define AK_OSPRINTF swprintf_s
709 
710  /// Compare two NULL-terminated AkOSChar strings
711  /// \return
712  /// - < 0 if in_pszString1 < in_pszString2
713  /// - 0 if the two strings are identical
714  /// - > 0 if in_pszString1 > in_pszString2
715  /// \remark The comparison is case-sensitive
716  inline int OsStrCmp( const AkOSChar* in_pszString1, const AkOSChar* in_pszString2 )
717  {
718  return ( wcscmp( in_pszString1, in_pszString2 ) );
719  }
720 
721  /// Compare two NULL-terminated AkOSChar strings up to the specified count of characters.
722  /// \return
723  /// - < 0 if in_pszString1 < in_pszString2
724  /// - 0 if the two strings are identical
725  /// - > 0 if in_pszString1 > in_pszString2
726  /// \remark The comparison is case-sensitive
727  inline int OsStrNCmp( const AkOSChar* in_pszString1, const AkOSChar* in_pszString2, size_t in_MaxCountSize)
728  {
729  return wcsncmp(in_pszString1, in_pszString2, in_MaxCountSize);
730  }
731 
732  #define AK_UTF16_TO_WCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
733  #define AK_WCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
734  #define AK_UTF8_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
735  #define AK_UTF16_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
736  #define AK_UTF16_TO_CHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkWideCharToChar( in_pSrc, in_MaxSize, in_pdDest )
737  #define AK_CHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
738  #define AK_OSCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
739 
740  /// Detects whether the string represents an absolute path to a file
741  inline bool IsAbsolutePath(const AkOSChar* in_pszPath, size_t in_pathLen)
742  {
743  return
744  (in_pathLen >= 3 && in_pszPath[1] == ':' && in_pszPath[2] == '\\') || // Classic "C:\..." DOS-style path
745  (in_pathLen >= 2 && in_pszPath[0] == '\\'); // Uncommon "\..." absolute path from current drive, or UNC "\\..."
746  }
747 
748  // Use with AkOSChar.
749  #define AK_PATH_SEPARATOR (L"\\")
750  #define AK_LIBRARY_PREFIX (L"")
751  #define AK_DYNAMIC_LIBRARY_EXTENSION (L".dll")
752 
753  #define AK_FILEHANDLE_TO_UINTPTR(_h) ((AkUIntPtr)_h)
754  #define AK_SET_FILEHANDLE_TO_UINTPTR(_h,_u) _h = (AkFileHandle)_u
755 
756  #if defined(AK_ENABLE_PERF_RECORDING)
757 
758  static AkUInt32 g_uAkPerfRecExecCount = 0;
759  static AkReal32 g_fAkPerfRecExecTime = 0.f;
760 
761  #define AK_PERF_RECORDING_RESET() \
762  AKPLATFORM::g_uAkPerfRecExecCount = 0;\
763  AKPLATFORM::g_fAkPerfRecExecTime = 0.f;
764 
765  #define AK_PERF_RECORDING_START( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ ) \
766  AkInt64 iAkPerfRecTimeBefore; \
767  if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) ) \
768  AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeBefore );
769 
770  #define AK_PERF_RECORDING_STOP( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ ) \
771  if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) ) \
772  { \
773  AkInt64 iAkPerfRecTimeAfter; \
774  AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeAfter ); \
775  AKPLATFORM::g_fAkPerfRecExecTime += AKPLATFORM::Elapsed( iAkPerfRecTimeAfter, iAkPerfRecTimeBefore ); \
776  if ( AKPLATFORM::g_uAkPerfRecExecCount == (__uExecutionCountStop__) ) \
777  { \
778  AkReal32 fAverageExecutionTime = AKPLATFORM::g_fAkPerfRecExecTime/((__uExecutionCountStop__)-(__uExecutionCountStart__)); \
779  AkOSChar str[256]; \
780  swprintf_s(str, 256, AKTEXT("%s average execution time: %f\n"), AKTEXT(__StorageName__), fAverageExecutionTime);\
781  AKPLATFORM::OutputDebugMsg( str ); \
782  } \
783  } \
784  AKPLATFORM::g_uAkPerfRecExecCount++;
785  #endif // AK_ENABLE_PERF_RECORDING
786 
787 #if (defined(AK_CPU_X86_64) || defined(AK_CPU_X86))
788  /// Support to fetch the CPUID for the platform. Only valid for X86 targets
789  /// \remark Note that IAkProcessorFeatures should be preferred to fetch this data
790  /// as it will have already translated the feature bits into AK-relevant enums
791  inline void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
792  {
793  __cpuidex((int*)out_uCPUFeatures, in_uLeafOpcode, in_uSubLeafOpcode);
794  }
795 #endif
796 }
797 
798 #endif // _AK_PLATFORM_FUNCS_H_
AKRESULT AkCreateSemaphore(AkSemaphore &out_semaphore, AkUInt32 in_initialCount)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:99
size_t AkUtf16StrLen(const AkUtf16 *in_pStr)
Definition: AkPlatformFuncs.h:582
Audiokinetic namespace.
@ AK_Fail
The operation failed.
Definition: AkTypes.h:196
#define AK_THREAD_PRIORITY_NORMAL
Definition: AkPlatformFuncs.h:81
semaphore_t AkEvent
Definition: AkTypes.h:73
#define AK_DEFAULT_STACK_SIZE
Definition: AkPlatformFuncs.h:80
AkForceInline void FreeVM(void *address, size_t size, size_t extra, size_t release)
Definition: AkPlatformFuncs.h:262
int nPriority
Thread priority.
Definition: AkPlatformFuncs.h:48
void AkClearEvent(AkEvent &out_event)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:51
AkForceInline void AkClearSemaphore(AkSemaphore &io_semaphore)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:93
Platform-dependent helpers.
Definition: AkPlatformFuncs.h:156
void AkWaitForEvent(AkEvent &in_event)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:79
AkForceInline void UpdatePerformanceFrequency()
Platform Independent Helper.
Definition: AkPlatformFuncs.h:429
int AkThreadID
Definition: AkTypes.h:69
AKRESULT
Standard function call result.
Definition: AkTypes.h:193
void OutputDebugMsg(const char *in_pszMsg)
Output a debug message on the console (Ansi string)
Definition: AkPlatformFuncs.h:120
AkForceInline void * AllocVM(size_t size, size_t *extra)
Definition: AkPlatformFuncs.h:243
void CPUID(AkUInt32 in_uLeafOpcode, AkUInt32 in_uSubLeafOpcode, unsigned int out_uCPUFeatures[4])
Definition: AkPlatformFuncs.h:295
char AkOSChar
Generic character string.
Definition: AkTypes.h:60
int SafeStrFormat(wchar_t *in_pDest, size_t in_uDestMaxNumChars, const wchar_t *in_pszFmt,...)
Definition: AkPlatformFuncs.h:512
#define NULL
Definition: AkTypes.h:46
AkThreadID CurrentThread()
Returns the calling thread's ID.
Definition: AkPlatformFuncs.h:380
bool IsAbsolutePath(const AkOSChar *in_pszPath, size_t in_pathLen)
Detects whether the string represents an absolute path to a file.
Definition: AkPlatformFuncs.h:620
float AkReal32
32-bit floating point
Definition: AkNumeralTypes.h:46
@ AK_Success
The operation was successful.
Definition: AkTypes.h:195
int32_t AkInt32
Signed 32-bit integer.
Definition: AkNumeralTypes.h:43
void AkCreateThread(AkThreadRoutine pStartRoutine, void *pParams, const AkThreadProperties &in_threadProperties, AkThread *out_pThread, const char *)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:182
AkUInt16 AkUtf16
Definition: AkTypes.h:61
void OutputDebugMsgV(const char *in_pszFmt,...)
Output a debug message on the console (variadic function).
Definition: AkPlatformFuncs.h:129
void PerformanceCounter(AkInt64 *out_piLastTime)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:142
AkUInt32 uStackSize
Thread stack size.
Definition: AkPlatformFuncs.h:58
void AkSetThreadName(AkThread in_threadHnd, DWORD in_dwThreadID, LPCSTR in_szThreadName)
Set the name of a thread: see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx.
Definition: AkPlatformFuncs.h:255
void AkDestroySemaphore(AkSemaphore &io_semaphore)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:111
void AkDestroyEvent(AkEvent &io_event)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:69
nn::os::ThreadFunction AkThreadRoutine
Thread routine.
Definition: AkTypes.h:85
AkForceInline bool AkIsValidThread(AkThread *in_pThread)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:277
AkForceInline void AkMemCpy(void *pDest, const void *pSrc, AkUInt32 uSize)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:395
#define AKASSERT(Condition)
Definition: AkAssert.h:67
#define AKVERIFY(x)
Definition: AkAssert.h:69
AkForceInline void AkSleep(AkUInt32 in_ulMilliseconds)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:386
AkForceInline void AkClearThread(AkThread *in_pThread)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:283
AkForceInline void AkGetDefaultThreadProperties(AkThreadProperties &out_threadProperties)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:302
#define AK_NULL_THREAD
Definition: AkPlatformFuncs.h:88
int OsStrNCmp(const AkOSChar *in_pszString1, const AkOSChar *in_pszString2, size_t in_MaxCountSize)
Definition: AkPlatformFuncs.h:614
void AkLimitedSpinForZero(AkAtomic32 *in_pVal)
Definition: AkPlatformFuncs.h:224
AkForceInline void AkMemSet(void *pDest, AkInt32 iVal, AkUInt32 uSize)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:407
void AkMemMove(void *pDest, const void *pSrc, AkUInt32 uSize)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:401
SceKernelCpumask dwAffinityMask
Affinity mask.
Definition: AkPlatformFuncs.h:49
AkReal32 g_fFreqRatio
Definition: AkPlatformFuncs.h:63
double AkReal64
64-bit floating point
Definition: AkNumeralTypes.h:47
#define AkMin(x1, x2)
Definition: AkPlatformFuncs.h:93
AKRESULT AkCreateEvent(AkEvent &out_event)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:57
AkForceInline void SafeStrCpy(wchar_t *in_pDest, const wchar_t *in_pSrc, size_t in_uDestMaxNumChars)
Safe unicode string copy.
Definition: AkPlatformFuncs.h:483
int64_t AkInt64
Signed 64-bit integer.
Definition: AkNumeralTypes.h:44
AkUInt32 dwAffinityMask
Affinity mask.
Definition: AkPlatformFuncs.h:56
volatile long AkAtomic32
Definition: AkAtomic.h:42
void AkWaitForSemaphore(AkSemaphore &in_semaphore)
Platform Independent Helper - Semaphore wait, aka Operation P. Decrements value of semaphore,...
Definition: AkPlatformFuncs.h:117
size_t uStackSize
Thread stack size.
Definition: AkPlatformFuncs.h:50
void PerformanceFrequency(AkInt64 *out_piFreq)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:45
AkForceInline AkInt32 AkCharToWideChar(const char *in_pszAnsiString, AkUInt32 in_uiOutBufferSize, void *io_pvUnicodeStringBuffer)
String conversion helper.
Definition: AkPlatformFuncs.h:460
uint32_t AkUInt32
Unsigned 32-bit integer.
Definition: AkNumeralTypes.h:38
void AkReleaseSemaphore(AkSemaphore &in_semaphore, AkUInt32 in_count)
Platform Independent Helper - Semaphore signal, aka Operation V. Increments value of semaphore by an ...
Definition: AkPlatformFuncs.h:123
AkForceInline void SafeStrCat(wchar_t *in_pDest, const wchar_t *in_pSrc, size_t in_uDestMaxNumChars)
Safe unicode string concatenation.
Definition: AkPlatformFuncs.h:499
AkForceInline AkInt32 AkWideCharToChar(const wchar_t *in_pszUnicodeString, AkUInt32 in_uiOutBufferSize, char *io_pszAnsiString)
String conversion helper.
Definition: AkPlatformFuncs.h:443
AkForceInline void AkWaitForSingleThread(AkThread *in_pThread)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:373
#define AkAlloca(_size_)
Stack allocations.
Definition: AkPlatformFuncs.h:558
void AkSignalEvent(const AkEvent &in_event)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:86
Definition: AkTypes.h:90
AkForceInline AkInt32 AkUtf8ToWideChar(const char *in_pszUtf8String, AkUInt32 in_uiOutBufferSize, void *io_pvUnicodeStringBuffer)
String conversion helper.
Definition: AkPlatformFuncs.h:475
semaphore_t AkSemaphore
Definition: AkTypes.h:74
AkForceInline void AkCloseThread(AkThread *in_pThread)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:289
AkForceInline int OsStrCmp(const AkOSChar *in_pszString1, const AkOSChar *in_pszString2)
Definition: AkPlatformFuncs.h:603
#define AkForceInline
Definition: AkTypes.h:61
__forceinline long AkAtomicLoad32(AkAtomic32 *pSrc)
Definition: AkAtomic.h:57
AkForceInline size_t OsStrLen(const AkOSChar *in_pszString)
Definition: AkPlatformFuncs.h:589
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.
Definition: AkPlatformFuncs.h:437

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