27 #ifndef _AK_PLATFORM_FUNCS_H_
28 #define _AK_PLATFORM_FUNCS_H_
43 #if defined(AK_XBOXSERIESX)
44 #include <ammintrin.h>
53 #ifdef AK_WIN_UNIVERSAL_APP
54 PROCESSOR_NUMBER processorNumber;
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
88 #define AK_NULL_THREAD NULL
90 #define AK_INFINITE INFINITE
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)))
110 out_event = ::CreateEvent(
NULL,
122 ::CloseHandle( io_event );
129 AKVERIFY( ::WaitForSingleObject( in_event, INFINITE ) == WAIT_OBJECT_0 );
147 out_semaphore = ::CreateSemaphore(
158 ::CloseHandle(io_semaphore);
164 AKVERIFY(::WaitForSingleObject(in_semaphore, INFINITE) == WAIT_OBJECT_0);
170 AKVERIFY(ReleaseSemaphore(in_semaphore, in_count,
NULL) >= 0);
193 AKVERIFY( ::CloseHandle( *in_pThread ) );
197 #define AkExitThread( _result ) return _result;
204 #ifdef AK_WIN_UNIVERSAL_APP
205 out_threadProperties.processorNumber.Group = 0;
206 out_threadProperties.processorNumber.Number = MAXIMUM_PROCESSORS;
207 out_threadProperties.processorNumber.Reserved = 0;
216 const DWORD MS_VC_EXCEPTION=0x406D1388;
219 typedef struct tagTHREADNAME_INFO
228 THREADNAME_INFO info;
229 info.dwType = 0x1000;
230 info.szName = in_szThreadName;
231 info.dwThreadID = in_dwThreadID;
236 RaiseException( MS_VC_EXCEPTION, 0,
sizeof(info)/
sizeof(ULONG_PTR), (ULONG_PTR*)&info );
238 #pragma warning(suppress: 6312 6322)
239 __except(EXCEPTION_CONTINUE_EXECUTION)
243 #if defined(AK_XBOX) || defined(_GAMING_DESKTOP) // also applicable on Windows when Win7 support is dropped. SetThreadDescription is a Win10 only API
244 wchar_t wszThreadName[32];
245 AkUInt32 maxStrLen = (
sizeof(wszThreadName) /
sizeof(
wchar_t)) - 1;
246 AkUInt32 nameStrLen =
AkMin((
int)strlen(in_szThreadName), maxStrLen);
247 MultiByteToWideChar(CP_UTF8, 0, in_szThreadName, nameStrLen, wszThreadName, maxStrLen);
248 wszThreadName[nameStrLen] =
'\0';
249 SetThreadDescription(in_threadHnd, wszThreadName);
259 const char * in_szThreadName )
262 AKASSERT( (in_threadProperties.
nPriority >= THREAD_PRIORITY_LOWEST && in_threadProperties.
nPriority <= THREAD_PRIORITY_HIGHEST)
263 || ( in_threadProperties.
nPriority == THREAD_PRIORITY_TIME_CRITICAL )
264 || ( in_threadProperties.
nPriority == THREAD_MODE_BACKGROUND_BEGIN ) );
267 *out_pThread = ::CreateThread(
NULL,
288 if ( !::SetThreadPriority( *out_pThread, in_threadProperties.
nPriority ) &&
289 in_threadProperties.
nPriority != THREAD_MODE_BACKGROUND_BEGIN )
291 AKASSERT( !
"Failed setting thread priority" );
296 #ifdef AK_WIN_UNIVERSAL_APP
297 if ( in_threadProperties.processorNumber.Number != MAXIMUM_PROCESSORS)
299 if ( !SetThreadIdealProcessorEx( *out_pThread,
const_cast<PPROCESSOR_NUMBER
>(&in_threadProperties.processorNumber),
NULL) )
301 AKASSERT( !
"Failed setting thread ideal processor" );
311 DWORD_PTR procAffinity, sysAffinity;
312 if (::GetProcessAffinityMask(::GetCurrentProcess(), &procAffinity, &sysAffinity))
315 dwAffinityMask &= procAffinity;
317 if (!::SetThreadAffinityMask(*out_pThread, dwAffinityMask))
319 AKASSERT(!
"Failed setting thread affinity mask");
327 if (!::ResumeThread(*out_pThread))
329 AKASSERT(!
"Failed to start the thread");
341 ::WaitForSingleObject( *in_pThread, INFINITE );
347 return ::GetCurrentThreadId();
353 ::Sleep( in_ulMilliseconds );
362 ::QueryPerformanceCounter( (LARGE_INTEGER*)out_piLastTime );
368 ::QueryPerformanceFrequency( (LARGE_INTEGER*)out_piFreq );
388 char* io_pszAnsiString )
390 if(!io_pszAnsiString)
391 return WideCharToMultiByte(CP_UTF8, 0, in_pszUnicodeString, -1,
NULL, 0,
NULL,
NULL);
393 int iWritten = ::WideCharToMultiByte(CP_UTF8,
396 (
int)
AkMin( ( (
AkUInt32)wcslen( in_pszUnicodeString )), in_uiOutBufferSize-1 ),
401 io_pszAnsiString[iWritten] = 0;
408 void* io_pvUnicodeStringBuffer )
410 return ::MultiByteToWideChar( CP_UTF8,
414 (
wchar_t*)io_pvUnicodeStringBuffer,
421 void* io_pvUnicodeStringBuffer )
423 return ::MultiByteToWideChar( CP_UTF8,
427 (
wchar_t*)io_pvUnicodeStringBuffer,
432 inline void SafeStrCpy(
wchar_t * in_pDest,
const wchar_t* in_pSrc,
size_t in_uDestMaxNumChars )
434 size_t iSizeCopy =
AkMin( in_uDestMaxNumChars - 1, wcslen( in_pSrc ) + 1 );
435 wcsncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
436 in_pDest[iSizeCopy] =
'\0';
440 inline void SafeStrCpy(
char * in_pDest,
const char* in_pSrc,
size_t in_uDestMaxNumChars )
442 size_t iSizeCopy =
AkMin( in_uDestMaxNumChars - 1, strlen( in_pSrc ) + 1 );
443 strncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
444 in_pDest[iSizeCopy] =
'\0';
448 inline void SafeStrCat(
wchar_t * in_pDest,
const wchar_t* in_pSrc,
size_t in_uDestMaxNumChars )
450 int iAvailableSize = (int)( in_uDestMaxNumChars - wcslen( in_pDest ) - 1 );
451 wcsncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc,
AkMin( iAvailableSize, (
int)wcslen( in_pSrc ) ) );
455 inline void SafeStrCat(
char * in_pDest,
const char* in_pSrc,
size_t in_uDestMaxNumChars )
457 int iAvailableSize = (int)( in_uDestMaxNumChars - strlen( in_pDest ) - 1 );
458 strncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc,
AkMin( iAvailableSize, (
int)strlen( in_pSrc ) ) );
461 inline int SafeStrFormat(
wchar_t * in_pDest,
size_t in_uDestMaxNumChars,
const wchar_t* in_pszFmt, ...)
464 va_start(args, in_pszFmt);
465 int r = vswprintf(in_pDest, in_uDestMaxNumChars, in_pszFmt, args);
470 inline int SafeStrFormat(
char * in_pDest,
size_t in_uDestMaxNumChars,
const char* in_pszFmt, ...)
473 va_start(args, in_pszFmt);
474 int r = vsnprintf(in_pDest, in_uDestMaxNumChars, in_pszFmt, args);
480 #define AkAlloca( _size_ ) _alloca( _size_ )
483 #if ! defined(AK_OPTIMIZED)
486 OutputDebugStringW( in_pszMsg );
492 OutputDebugStringA( in_pszMsg );
499 template <
int MaxSize = 256>
506 wchar_t* msg = (
wchar_t*)
AkAlloca(MaxSize *
sizeof(
wchar_t));
507 msg[MaxSize - 1] =
'\0';
510 va_start(args, in_pszFmt);
511 vswprintf(msg, MaxSize, in_pszFmt, args);
521 template <
int MaxSize = 256>
528 msg[MaxSize - 1] =
'\0';
531 va_start(args, in_pszFmt);
532 size = vsnprintf(msg, MaxSize, in_pszFmt, args);
536 if (0 <= size && size <= MaxSize)
548 char* msg = (
char*)
AkAlloca((size) *
sizeof(char));
549 msg[size - 1] =
'\0';
552 va_start(args, in_pszFmt);
553 vsnprintf(msg, size, in_pszFmt, args);
564 template <
int MaxSize = 0>
567 template <
int MaxSize = 0>
579 #define CONVERT_WIDE_TO_OSCHAR( _wstring_, _oscharstring_ ) ( _oscharstring_ ) = (AkOSChar*)( _wstring_ )
589 #define CONVERT_CHAR_TO_OSCHAR( _astring_, _oscharstring_ ) \
590 _oscharstring_ = (AkOSChar*)AkAlloca( (1 + strlen( _astring_ )) * sizeof(AkOSChar)); \
591 AKPLATFORM::AkCharToWideChar( _astring_, (AkUInt32)(1 + strlen(_astring_ )), (AkOSChar*)( _oscharstring_ ) )
601 #define CONVERT_OSCHAR_TO_WIDE( _osstring_, _wstring_ ) _wstring_ = _osstring_
611 #define CONVERT_OSCHAR_TO_CHAR( _osstring_, _astring_ ) \
612 _astring_ = (char*)AkAlloca( 1 + AKPLATFORM::AkWideCharToChar( _osstring_, 0, NULL )); \
613 AKPLATFORM::AkWideCharToChar( _osstring_, AkUInt32(1 + AKPLATFORM::AkWideCharToChar( _osstring_, 0, NULL )), _astring_ );
619 return ( wcslen( in_pStr ) );
626 return ( wcslen( in_pszString ) );
630 #define AK_OSPRINTF swprintf_s
640 return ( wcscmp( in_pszString1, in_pszString2 ) );
651 return wcsncmp(in_pszString1, in_pszString2, in_MaxCountSize);
654 #define AK_UTF16_TO_WCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
655 #define AK_WCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
656 #define AK_UTF8_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
657 #define AK_UTF16_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
658 #define AK_UTF16_TO_CHAR( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkWideCharToChar( in_pSrc, in_MaxSize, in_pdDest )
659 #define AK_CHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
660 #define AK_OSCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize ) AKPLATFORM::SafeStrCpy( in_pdDest, in_pSrc, in_MaxSize )
666 (in_pathLen >= 3 && in_pszPath[1] ==
':' && in_pszPath[2] ==
'\\') ||
667 (in_pathLen >= 2 && in_pszPath[0] ==
'\\');
671 #define AK_PATH_SEPARATOR L"\\"
672 #define AK_LIBRARY_PREFIX L""
673 #define AK_DYNAMIC_LIBRARY_EXTENSION L".dll"
675 #define AK_FILEHANDLE_TO_UINTPTR(_h) ((AkUIntPtr)_h)
676 #define AK_SET_FILEHANDLE_TO_UINTPTR(_h,_u) _h = (AkFileHandle)_u
678 #if defined(AK_ENABLE_PERF_RECORDING)
680 static AkUInt32 g_uAkPerfRecExecCount = 0;
681 static AkReal32 g_fAkPerfRecExecTime = 0.f;
683 #define AK_PERF_RECORDING_RESET() \
684 AKPLATFORM::g_uAkPerfRecExecCount = 0;\
685 AKPLATFORM::g_fAkPerfRecExecTime = 0.f;
687 #define AK_PERF_RECORDING_START( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ ) \
688 AkInt64 iAkPerfRecTimeBefore; \
689 if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) ) \
690 AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeBefore );
692 #define AK_PERF_RECORDING_STOP( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ ) \
693 if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) ) \
695 AkInt64 iAkPerfRecTimeAfter; \
696 AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeAfter ); \
697 AKPLATFORM::g_fAkPerfRecExecTime += AKPLATFORM::Elapsed( iAkPerfRecTimeAfter, iAkPerfRecTimeBefore ); \
698 if ( AKPLATFORM::g_uAkPerfRecExecCount == (__uExecutionCountStop__) ) \
700 AkReal32 fAverageExecutionTime = AKPLATFORM::g_fAkPerfRecExecTime/((__uExecutionCountStop__)-(__uExecutionCountStart__)); \
702 swprintf_s(str, 256, AKTEXT("%s average execution time: %f\n"), AKTEXT(__StorageName__), fAverageExecutionTime);\
703 AKPLATFORM::OutputDebugMsg( str ); \
706 AKPLATFORM::g_uAkPerfRecExecCount++;
707 #endif // AK_ENABLE_PERF_RECORDING
709 #if (defined(AK_CPU_X86_64) || defined(AK_CPU_X86))
713 inline void CPUID(
AkUInt32 in_uLeafOpcode,
AkUInt32 in_uSubLeafOpcode,
unsigned int out_uCPUFeatures[4])
715 __cpuidex((
int*)out_uCPUFeatures, in_uLeafOpcode, in_uSubLeafOpcode);
720 #endif // _AK_PLATFORM_FUNCS_H_