1723 lines
53 KiB
C++
1723 lines
53 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//===========================================================================//
|
|
|
|
#ifndef PLATFORM_H
|
|
#define PLATFORM_H
|
|
|
|
#if defined(__x86_64__) || defined(_WIN64)
|
|
#define PLATFORM_64BITS 1
|
|
#endif
|
|
|
|
#if defined(__GCC__) || defined(__GNUC__)
|
|
#define COMPILER_GCC 1
|
|
#endif
|
|
|
|
#ifdef __clang__
|
|
#define COMPILER_CLANG 1
|
|
#endif
|
|
|
|
#if defined(_X360)
|
|
#define NO_STEAM
|
|
#define NO_VOICE
|
|
// for the 360, the ppc platform and the rtos are tightly coupled
|
|
// setup the 360 environment here !once! for much less leaf module include
|
|
// wackiness these are critical order and purposely appear *before* anything
|
|
// else
|
|
#define _XBOX
|
|
#include <xtl.h>
|
|
#include <xaudio2.h>
|
|
#include <xbdm.h>
|
|
#include <Xgraphics.h>
|
|
#include <xui.h>
|
|
#include <pmcpbsetup.h>
|
|
#include <XMAHardwareAbstraction.h>
|
|
#undef _XBOX
|
|
#endif
|
|
|
|
#include "basetypes.h"
|
|
#include "valve_off.h"
|
|
#include "wchartypes.h"
|
|
|
|
#ifdef _DEBUG
|
|
#if !defined(PLAT_COMPILE_TIME_ASSERT)
|
|
#define PLAT_COMPILE_TIME_ASSERT(pred) \
|
|
switch (0) { \
|
|
case 0: \
|
|
case pred:; \
|
|
}
|
|
#endif
|
|
#else
|
|
#if !defined(PLAT_COMPILE_TIME_ASSERT)
|
|
#define PLAT_COMPILE_TIME_ASSERT(pred)
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
// feature enables
|
|
#define NEW_SOFTWARE_LIGHTING
|
|
|
|
#ifdef F1_GCC
|
|
#undef POSIX
|
|
#undef LINUX
|
|
#undef _LINUX
|
|
|
|
// nasty hack i need to remove
|
|
// fixes windows.h errors under mingw with _MSC_VER defined
|
|
#undef __CRT_UUID_DECL
|
|
#define __CRT_UUID_DECL(type, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
|
extern "C++" { \
|
|
template <> \
|
|
inline const GUID &__mingw_uuidof<type>() { \
|
|
static const IID __uuid_inst = { \
|
|
l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}; \
|
|
return __uuid_inst; \
|
|
} \
|
|
template <> \
|
|
inline const GUID &__mingw_uuidof<type *>() { \
|
|
return __mingw_uuidof<type>(); \
|
|
} \
|
|
}
|
|
|
|
#undef __uuidof
|
|
#define __uuidof(type) __mingw_uuidof < __typeof(type)>()
|
|
#endif
|
|
|
|
#if defined(POSIX) && !defined(F1_GCC)
|
|
// need this for _alloca
|
|
#include <alloca.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <malloc.h>
|
|
#include <new>
|
|
|
|
// need this for memset
|
|
#include <string.h>
|
|
|
|
#include "valve_minmax_on.h" // GCC 4.2.2 headers screw up our min/max defs.
|
|
|
|
#ifdef _RETAIL
|
|
#define IsRetail() true
|
|
#else
|
|
#define IsRetail() false
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#define IsRelease() false
|
|
#define IsDebug() true
|
|
#else
|
|
#define IsRelease() true
|
|
#define IsDebug() false
|
|
#endif
|
|
|
|
// Deprecating, infavor of IsX360() which will revert to IsXbox()
|
|
// after confidence of xbox 1 code flush
|
|
#define IsXbox() false
|
|
|
|
#ifdef _WIN32
|
|
#define IsLinux() false
|
|
#define IsOSX() false
|
|
#define IsPosix() false
|
|
#define PLATFORM_WINDOWS 1 // Windows PC or Xbox 360
|
|
#ifndef _X360
|
|
#define IsWindows() true
|
|
#define IsPC() true
|
|
#define IsConsole() false
|
|
#define IsX360() false
|
|
#define IsPS3() false
|
|
#define IS_WINDOWS_PC
|
|
#define PLATFORM_WINDOWS_PC 1 // Windows PC
|
|
#ifdef _WIN64
|
|
#define IsPlatformWindowsPC64() true
|
|
#define IsPlatformWindowsPC32() false
|
|
#define PLATFORM_WINDOWS_PC64 1
|
|
#else
|
|
#define IsPlatformWindowsPC64() false
|
|
#define IsPlatformWindowsPC32() true
|
|
#define PLATFORM_WINDOWS_PC32 1
|
|
#endif
|
|
#else
|
|
#define PLATFORM_X360 1
|
|
#ifndef _CONSOLE
|
|
#define _CONSOLE
|
|
#endif
|
|
#define IsWindows() false
|
|
#define IsPC() false
|
|
#define IsConsole() true
|
|
#define IsX360() true
|
|
#define IsPS3() false
|
|
#endif
|
|
// Adding IsPlatformOpenGL() to help fix a bunch of code that was using
|
|
// IsPosix() to infer if the DX->GL translation layer was being used.
|
|
#if defined(DX_TO_GL_ABSTRACTION)
|
|
#define IsPlatformOpenGL() true
|
|
#else
|
|
#define IsPlatformOpenGL() false
|
|
#endif
|
|
#elif defined(POSIX)
|
|
#define IsPC() true
|
|
#define IsWindows() false
|
|
#define IsConsole() false
|
|
#define IsX360() false
|
|
#define IsPS3() false
|
|
#if defined(LINUX)
|
|
#define IsLinux() true
|
|
#else
|
|
#define IsLinux() false
|
|
#endif
|
|
|
|
#if defined(OSX)
|
|
#define IsOSX() true
|
|
#else
|
|
#define IsOSX() false
|
|
#endif
|
|
|
|
#define IsPosix() true
|
|
#define IsPlatformOpenGL() true
|
|
#else
|
|
#error
|
|
#endif
|
|
|
|
typedef unsigned char uint8;
|
|
typedef signed char int8;
|
|
|
|
#if defined(_WIN32)
|
|
|
|
typedef __int16 int16;
|
|
typedef unsigned __int16 uint16;
|
|
typedef __int32 int32;
|
|
typedef unsigned __int32 uint32;
|
|
typedef __int64 int64;
|
|
typedef unsigned __int64 uint64;
|
|
|
|
#ifdef PLATFORM_64BITS
|
|
typedef __int64 intp; // intp is an integer that can accomodate a pointer
|
|
typedef unsigned __int64 uintp; // (ie, sizeof(intp) >= sizeof(int) &&
|
|
// sizeof(intp) >= sizeof(void *)
|
|
#else
|
|
typedef __int32 intp;
|
|
typedef unsigned __int32 uintp;
|
|
#endif
|
|
|
|
#if defined(_X360)
|
|
#ifdef __m128
|
|
#undef __m128
|
|
#endif
|
|
#define __m128 __vector4
|
|
#endif
|
|
|
|
// Use this to specify that a function is an override of a virtual function.
|
|
// This lets the compiler catch cases where you meant to override a virtual
|
|
// function but you accidentally changed the function signature and created
|
|
// an overloaded function. Usage in function declarations is like this:
|
|
// int GetData() const OVERRIDE;
|
|
#define OVERRIDE override
|
|
|
|
#else // _WIN32
|
|
|
|
typedef short int16;
|
|
typedef unsigned short uint16;
|
|
typedef int int32;
|
|
typedef unsigned int uint32;
|
|
typedef long long int64;
|
|
typedef unsigned long long uint64;
|
|
#ifdef PLATFORM_64BITS
|
|
typedef long long intp;
|
|
typedef unsigned long long uintp;
|
|
#else
|
|
typedef int intp;
|
|
typedef unsigned int uintp;
|
|
#endif
|
|
typedef void *HWND;
|
|
|
|
// Avoid redefinition warnings if a previous header defines this.
|
|
#undef OVERRIDE
|
|
#if __cplusplus >= 201103L
|
|
#define OVERRIDE override
|
|
#if defined(__clang__)
|
|
// warning: 'override' keyword is a C++11 extension [-Wc++11-extensions]
|
|
// Disabling this warning is less intrusive than enabling C++11 extensions
|
|
#pragma GCC diagnostic ignored "-Wc++11-extensions"
|
|
#endif
|
|
#else
|
|
#define OVERRIDE
|
|
#endif
|
|
|
|
#endif // else _WIN32
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set up platform type defines.
|
|
//-----------------------------------------------------------------------------
|
|
#if defined(PLATFORM_X360) || defined(_PS3)
|
|
#if !defined(_GAMECONSOLE)
|
|
#define _GAMECONSOLE
|
|
#endif
|
|
#define IsPC() false
|
|
#define IsGameConsole() true
|
|
#else
|
|
#define IsPC() true
|
|
#define IsGameConsole() false
|
|
#endif
|
|
|
|
#ifdef PLATFORM_64BITS
|
|
#define IsPlatform64Bits() true
|
|
#else
|
|
#define IsPlatform64Bits() false
|
|
#endif
|
|
|
|
// From steam/steamtypes.h
|
|
// RTime32
|
|
// We use this 32 bit time representing real world time.
|
|
// It offers 1 second resolution beginning on January 1, 1970 (Unix time)
|
|
typedef uint32 RTime32;
|
|
|
|
typedef float float32;
|
|
typedef double float64;
|
|
|
|
// for when we don't care about how many bits we use
|
|
typedef unsigned int uint;
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma once
|
|
// Ensure that everybody has the right compiler version installed. The version
|
|
// number can be obtained by looking at the compiler output when you type 'cl'
|
|
// and removing the last two digits and the periods: 16.00.40219.01 becomes
|
|
// 160040219
|
|
#if _MSC_FULL_VER > 180000000
|
|
#if _MSC_FULL_VER < 180030723
|
|
#error You must install VS 2013 Update 3
|
|
#endif
|
|
#elif _MSC_FULL_VER > 160000000
|
|
#if _MSC_FULL_VER < 160040219
|
|
#error You must install VS 2010 SP1
|
|
#endif
|
|
#else
|
|
#if _MSC_FULL_VER < 140050727
|
|
#error You must install VS 2005 SP1
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
// This can be used to ensure the size of pointers to members when declaring
|
|
// a pointer type for a class that has only been forward declared
|
|
#if defined(_MSC_VER) && !defined(F1_GCC)
|
|
#define SINGLE_INHERITANCE __single_inheritance
|
|
#define MULTIPLE_INHERITANCE __multiple_inheritance
|
|
#else
|
|
#define SINGLE_INHERITANCE
|
|
#define MULTIPLE_INHERITANCE
|
|
#endif
|
|
|
|
#if defined(_MSC_VER) && !defined(F1_GCC)
|
|
#define NO_VTABLE __declspec(novtable)
|
|
#else
|
|
#define NO_VTABLE
|
|
#endif
|
|
|
|
#if defined(_MSC_VER) && !defined(F1_GCC)
|
|
// This indicates that a function never returns, which helps with
|
|
// generating accurate compiler warnings
|
|
#define NORETURN __declspec(noreturn)
|
|
#else
|
|
#define NORETURN
|
|
#endif
|
|
|
|
// This can be used to declare an abstract (interface only) class.
|
|
// Classes marked abstract should not be instantiated. If they are, and access
|
|
// violation will occur.
|
|
//
|
|
// Example of use:
|
|
//
|
|
// abstract_class CFoo
|
|
// {
|
|
// ...
|
|
// }
|
|
//
|
|
// MSDN __declspec(novtable) documentation:
|
|
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_langref_novtable.asp
|
|
//
|
|
// Note: NJS: This is not enabled for regular PC, due to not knowing the
|
|
// implications of exporting a class with no no vtable.
|
|
// It's probable that this shouldn't be an issue, but an experiment should
|
|
// be done to verify this.
|
|
//
|
|
#ifndef _X360
|
|
#define abstract_class class
|
|
#else
|
|
#define abstract_class class NO_VTABLE
|
|
#endif
|
|
|
|
// MSVC CRT uses 0x7fff while gcc uses MAX_INT, leading to mismatches between
|
|
// platforms As a result, we pick the least common denominator here. This
|
|
// should be used anywhere you might typically want to use RAND_MAX
|
|
#define VALVE_RAND_MAX 0x7fff
|
|
|
|
/*
|
|
FIXME: Enable this when we no longer fear change =)
|
|
|
|
// need these for the limits
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
|
|
// Maximum and minimum representable values
|
|
#define INT8_MAX SCHAR_MAX
|
|
#define INT16_MAX SHRT_MAX
|
|
#define INT32_MAX LONG_MAX
|
|
#define INT64_MAX (((int64)~0) >> 1)
|
|
|
|
#define INT8_MIN SCHAR_MIN
|
|
#define INT16_MIN SHRT_MIN
|
|
#define INT32_MIN LONG_MIN
|
|
#define INT64_MIN (((int64)1) << 63)
|
|
|
|
#define UINT8_MAX ((uint8)~0)
|
|
#define UINT16_MAX ((uint16)~0)
|
|
#define UINT32_MAX ((uint32)~0)
|
|
#define UINT64_MAX ((uint64)~0)
|
|
|
|
#define UINT8_MIN 0
|
|
#define UINT16_MIN 0
|
|
#define UINT32_MIN 0
|
|
#define UINT64_MIN 0
|
|
|
|
#ifndef UINT_MIN
|
|
#define UINT_MIN UINT32_MIN
|
|
#endif
|
|
|
|
#define FLOAT32_MAX FLT_MAX
|
|
#define FLOAT64_MAX DBL_MAX
|
|
|
|
#define FLOAT32_MIN FLT_MIN
|
|
#define FLOAT64_MIN DBL_MIN
|
|
*/
|
|
|
|
// portability / compiler settings
|
|
#if defined(_WIN32) && !defined(WINDED)
|
|
|
|
#if defined(_M_IX86)
|
|
#define __i386__ 1
|
|
#endif
|
|
|
|
#elif POSIX
|
|
#if defined(OSX) && defined(CARBON_WORKAROUND)
|
|
#define DWORD unsigned int
|
|
#else
|
|
typedef unsigned int DWORD;
|
|
#endif
|
|
typedef unsigned short WORD;
|
|
typedef void *HINSTANCE;
|
|
#define _MAX_PATH PATH_MAX
|
|
#define __cdecl
|
|
#define __stdcall
|
|
#define __declspec
|
|
|
|
#endif // defined(_WIN32) && !defined(WINDED)
|
|
|
|
// Defines MAX_PATH
|
|
#ifndef MAX_PATH
|
|
#define MAX_PATH 260
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#define MAX_UNICODE_PATH 32767
|
|
#else
|
|
#define MAX_UNICODE_PATH MAX_PATH
|
|
#endif
|
|
|
|
#define MAX_UNICODE_PATH_IN_UTF8 MAX_UNICODE_PATH * 4
|
|
|
|
#ifdef GNUC
|
|
#undef offsetof
|
|
//#define offsetof( type, var ) __builtin_offsetof( type, var )
|
|
#define offsetof(s, m) (size_t) & (((s *)0)->m)
|
|
#else
|
|
#undef offsetof
|
|
#define offsetof(s, m) (size_t) & (((s *)0)->m)
|
|
#endif
|
|
|
|
#define ALIGN_VALUE(val, alignment) \
|
|
((val + alignment - 1) & \
|
|
~(alignment - 1)) // need macro for constant expression
|
|
|
|
// Used to step into the debugger
|
|
#if defined(_WIN32) && !defined(_X360)
|
|
#define DebuggerBreak() __debugbreak()
|
|
#elif defined(_X360)
|
|
#define DebuggerBreak() DebugBreak()
|
|
#else
|
|
// On OSX, SIGTRAP doesn't really stop the thread cold when debugging.
|
|
// So if being debugged, use INT3 which is precise.
|
|
#ifdef OSX
|
|
#define DebuggerBreak() \
|
|
if (Plat_IsInDebugSession()) { \
|
|
__asm("int $3"); \
|
|
} else { \
|
|
raise(SIGTRAP); \
|
|
}
|
|
#else
|
|
#define DebuggerBreak() raise(SIGTRAP)
|
|
#endif
|
|
#endif
|
|
#define DebuggerBreakIfDebugging() \
|
|
if (!Plat_IsInDebugSession()) \
|
|
; \
|
|
else \
|
|
DebuggerBreak()
|
|
|
|
#ifdef STAGING_ONLY
|
|
#define DebuggerBreakIfDebugging_StagingOnly() \
|
|
if (!Plat_IsInDebugSession()) \
|
|
; \
|
|
else \
|
|
DebuggerBreak()
|
|
#else
|
|
#define DebuggerBreakIfDebugging_StagingOnly()
|
|
#endif
|
|
|
|
// Allows you to specify code that should only execute if we are in a staging
|
|
// build. Otherwise the code noops.
|
|
#ifdef STAGING_ONLY
|
|
#define STAGING_ONLY_EXEC(_exec) \
|
|
do { \
|
|
_exec; \
|
|
} while (0)
|
|
#else
|
|
#define STAGING_ONLY_EXEC(_exec) \
|
|
do { \
|
|
} while (0)
|
|
#endif
|
|
|
|
// C functions for external declarations that call the appropriate C++ methods
|
|
#ifndef EXPORT
|
|
#ifdef _WIN32
|
|
#define EXPORT _declspec(dllexport)
|
|
#else
|
|
#define EXPORT /* */
|
|
#endif
|
|
#endif
|
|
|
|
#if defined __i386__ && !defined __linux__
|
|
#define id386 1
|
|
#else
|
|
#define id386 0
|
|
#endif // __i386__
|
|
|
|
// decls for aligning data
|
|
#if defined(_WIN32) && !defined(F1_GCC)
|
|
#define DECL_ALIGN(x) __declspec(align(x))
|
|
|
|
#elif GNUC || defined(F1_GCC)
|
|
#define DECL_ALIGN(x) __attribute__((aligned(x)))
|
|
#else
|
|
#define DECL_ALIGN(x) /* */
|
|
#endif
|
|
|
|
#if defined(_MSC_VER) && !defined(F1_GCC)
|
|
// MSVC has the align at the start of the struct
|
|
#define ALIGN4 DECL_ALIGN(4)
|
|
#define ALIGN8 DECL_ALIGN(8)
|
|
#define ALIGN16 DECL_ALIGN(16)
|
|
#define ALIGN32 DECL_ALIGN(32)
|
|
#define ALIGN128 DECL_ALIGN(128)
|
|
|
|
#define ALIGN4_POST
|
|
#define ALIGN8_POST
|
|
#define ALIGN16_POST
|
|
#define ALIGN32_POST
|
|
#define ALIGN128_POST
|
|
#elif defined(GNUC) || defined(F1_GCC)
|
|
// gnuc has the align decoration at the end
|
|
#define ALIGN4
|
|
#define ALIGN8
|
|
#define ALIGN16
|
|
#define ALIGN32
|
|
#define ALIGN128
|
|
|
|
#define ALIGN4_POST DECL_ALIGN(4)
|
|
#define ALIGN8_POST DECL_ALIGN(8)
|
|
#define ALIGN16_POST DECL_ALIGN(16)
|
|
#define ALIGN32_POST DECL_ALIGN(32)
|
|
#define ALIGN128_POST DECL_ALIGN(128)
|
|
#else
|
|
#error
|
|
#endif
|
|
|
|
// Pull in the /analyze code annotations.
|
|
#include "annotations.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Convert int<-->pointer, avoiding 32/64-bit compiler warnings:
|
|
//-----------------------------------------------------------------------------
|
|
#define INT_TO_POINTER(i) (void *)((i) + (char *)NULL)
|
|
#define POINTER_TO_INT(p) ((int)(uintp)(p))
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Stack-based allocation related helpers
|
|
//-----------------------------------------------------------------------------
|
|
#if defined(GNUC)
|
|
#define stackalloc(_size) alloca(ALIGN_VALUE(_size, 16))
|
|
#ifdef _LINUX
|
|
#define mallocsize(_p) (malloc_usable_size(_p))
|
|
#elif defined(OSX)
|
|
#define mallocsize(_p) (malloc_size(_p))
|
|
#else
|
|
#error
|
|
#endif
|
|
#elif defined(_WIN32)
|
|
#define stackalloc(_size) _alloca(ALIGN_VALUE(_size, 16))
|
|
#define mallocsize(_p) (_msize(_p))
|
|
#endif
|
|
|
|
#define stackfree(_p) 0
|
|
|
|
// Linux had a few areas where it didn't construct objects in the same order
|
|
// that Windows does. So when CVProfile::CVProfile() would access g_pMemAlloc,
|
|
// it would crash because the allocator wasn't initalized yet.
|
|
#ifdef POSIX
|
|
#define CONSTRUCT_EARLY __attribute__((init_priority(101)))
|
|
#else
|
|
#define CONSTRUCT_EARLY
|
|
#endif
|
|
|
|
#if defined(_MSC_VER) && !defined(__clang__)
|
|
#define SELECTANY __declspec(selectany)
|
|
#define RESTRICT __restrict
|
|
#define RESTRICT_FUNC __declspec(restrict)
|
|
#define FMTFUNCTION(a, b)
|
|
#elif defined(GNUC)
|
|
#define SELECTANY __attribute__((weak))
|
|
#if defined(LINUX) && !defined(DEDICATED)
|
|
#define RESTRICT
|
|
#else
|
|
#define RESTRICT __restrict
|
|
#endif
|
|
#define RESTRICT_FUNC
|
|
// squirrel.h does a #define printf DevMsg which leads to warnings when we try
|
|
// to use printf as the prototype format function. Using __printf__ instead.
|
|
#define FMTFUNCTION(fmtargnumber, firstvarargnumber) \
|
|
__attribute__((format(__printf__, fmtargnumber, firstvarargnumber)))
|
|
#else
|
|
#define SELECTANY static
|
|
#define RESTRICT
|
|
#define RESTRICT_FUNC
|
|
#define FMTFUNCTION(a, b)
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
|
|
// Used for dll exporting and importing
|
|
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
|
#define DLL_IMPORT extern "C" __declspec(dllimport)
|
|
|
|
// Can't use extern "C" when DLL exporting a class
|
|
#define DLL_CLASS_EXPORT __declspec(dllexport)
|
|
#define DLL_CLASS_IMPORT __declspec(dllimport)
|
|
|
|
// Can't use extern "C" when DLL exporting a global
|
|
#define DLL_GLOBAL_EXPORT extern __declspec(dllexport)
|
|
#define DLL_GLOBAL_IMPORT extern __declspec(dllimport)
|
|
|
|
#define DLL_LOCAL
|
|
|
|
#elif defined GNUC
|
|
// Used for dll exporting and importing
|
|
#define DLL_EXPORT extern "C" __attribute__((visibility("default")))
|
|
#define DLL_IMPORT extern "C"
|
|
|
|
// Can't use extern "C" when DLL exporting a class
|
|
#define DLL_CLASS_EXPORT __attribute__((visibility("default")))
|
|
#define DLL_CLASS_IMPORT
|
|
|
|
// Can't use extern "C" when DLL exporting a global
|
|
#define DLL_GLOBAL_EXPORT extern __attribute((visibility("default")))
|
|
#define DLL_GLOBAL_IMPORT extern
|
|
|
|
#define DLL_LOCAL __attribute__((visibility("hidden")))
|
|
|
|
#else
|
|
#error "Unsupported Platform."
|
|
#endif
|
|
|
|
// Used for standard calling conventions
|
|
#if defined(_WIN32) && !defined(_X360)
|
|
#define STDCALL __stdcall
|
|
#define FASTCALL __fastcall
|
|
#define FORCEINLINE __forceinline
|
|
// GCC 3.4.1 has a bug in supporting forced inline of templated functions
|
|
// this macro lets us not force inlining in that case
|
|
#define FORCEINLINE_TEMPLATE __forceinline
|
|
#elif defined(_X360)
|
|
#define STDCALL __stdcall
|
|
#ifdef FORCEINLINE
|
|
#undef FORCEINLINE
|
|
#endif
|
|
#define FORCEINLINE __forceinline
|
|
#define FORCEINLINE_TEMPLATE __forceinline
|
|
#else
|
|
#define STDCALL
|
|
#define FASTCALL
|
|
#ifdef _LINUX_DEBUGGABLE
|
|
#define FORCEINLINE
|
|
#else
|
|
#define FORCEINLINE inline __attribute__((always_inline))
|
|
#endif
|
|
// GCC 3.4.1 has a bug in supporting forced inline of templated functions
|
|
// this macro lets us not force inlining in that case
|
|
#define FORCEINLINE_TEMPLATE inline
|
|
// #define __stdcall __attribute__ ((__stdcall__))
|
|
#endif
|
|
|
|
// Force a function call site -not- to inlined. (useful for profiling)
|
|
#define DONT_INLINE(a) (((int)(a) + 1) ? (a) : (a))
|
|
|
|
// Pass hints to the compiler to prevent it from generating unnessecary / stupid
|
|
// code in certain situations. Several compilers other than MSVC also have an
|
|
// equivilent construct.
|
|
//
|
|
// Essentially the 'Hint' is that the condition specified is assumed to be true
|
|
// at that point in the compilation. If '0' is passed, then the compiler
|
|
// assumes that any subsequent code in the same 'basic block' is unreachable,
|
|
// and thus usually removed.
|
|
#ifdef _MSC_VER
|
|
#define HINT(THE_HINT) __assume((THE_HINT))
|
|
#else
|
|
#define HINT(THE_HINT) 0
|
|
#endif
|
|
|
|
// Marks the codepath from here until the next branch entry point as
|
|
// unreachable, and asserts if any attempt is made to execute it.
|
|
#define UNREACHABLE() \
|
|
{ \
|
|
Assert(0); \
|
|
HINT(0); \
|
|
}
|
|
|
|
// In cases where no default is present or appropriate, this causes MSVC to
|
|
// generate as little code as possible, and throw an assertion in debug.
|
|
#define NO_DEFAULT \
|
|
default: \
|
|
UNREACHABLE();
|
|
|
|
#ifdef _WIN32
|
|
|
|
// Remove warnings from warning level 4.
|
|
#pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline
|
|
// function has been removed
|
|
#pragma warning( \
|
|
disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter
|
|
#pragma warning( \
|
|
disable : 4127) // warning C4127: conditional expression is constant
|
|
#pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment
|
|
// operator could not be generated
|
|
#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp'
|
|
// and C++ object destruction is non-portable
|
|
#pragma warning(disable : 4710) // warning C4710: function 'x' not inlined
|
|
#pragma warning(disable : 4702) // warning C4702: unreachable code
|
|
#pragma warning(disable : 4505) // unreferenced local function has been removed
|
|
#pragma warning( \
|
|
disable : 4239) // nonstandard extension used : 'argument' ( conversion
|
|
// from class Vector to class Vector& )
|
|
#pragma warning(disable : 4097) // typedef-name 'BaseClass' used as synonym for
|
|
// class-name 'CFlexCycler::CBaseFlex'
|
|
#pragma warning(disable : 4324) // Padding was added at the end of a structure
|
|
#pragma warning(disable : 4244) // type conversion warning.
|
|
#pragma warning(disable : 4305) // truncation from 'const double ' to 'float '
|
|
#pragma warning(disable : 4786) // Disable warnings about long symbol names
|
|
#pragma warning(disable : 4250) // 'X' : inherits 'Y::Z' via dominance
|
|
#pragma warning( \
|
|
disable : 4201) // nonstandard extension used : nameless struct/union
|
|
#pragma warning(disable : 4481) // warning C4481: nonstandard extension used:
|
|
// override specifier 'override'
|
|
#pragma warning( \
|
|
disable : 4748) // warning C4748: /GS can not protect parameters and local
|
|
// variables from local buffer overrun because
|
|
// optimizations are disabled in function
|
|
|
|
#if _MSC_VER >= 1300
|
|
#pragma warning( \
|
|
disable : 4511) // Disable warnings about private copy constructors
|
|
#pragma warning(disable : 4121) // warning C4121: 'symbol' : alignment of a
|
|
// member was sensitive to packing
|
|
#pragma warning( \
|
|
disable : 4530) // warning C4530: C++ exception handler used, but unwind
|
|
// semantics are not enabled. Specify /EHsc (disabled due
|
|
// to std headers having exception syntax)
|
|
#endif
|
|
|
|
#if _MSC_VER >= 1400
|
|
#pragma warning(disable : 4996) // functions declared deprecated
|
|
#endif
|
|
|
|
#endif // _WIN32
|
|
|
|
#if defined(LINUX) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
|
|
// based on some Jonathan Wakely macros on the net...
|
|
#define GCC_DIAG_STR(s) #s
|
|
#define GCC_DIAG_JOINSTR(x, y) GCC_DIAG_STR(x##y)
|
|
#define GCC_DIAG_DO_PRAGMA(x) _Pragma(#x)
|
|
#define GCC_DIAG_PRAGMA(x) GCC_DIAG_DO_PRAGMA(GCC diagnostic x)
|
|
|
|
#define GCC_DIAG_PUSH_OFF(x) \
|
|
GCC_DIAG_PRAGMA(push) GCC_DIAG_PRAGMA(ignored GCC_DIAG_JOINSTR(-W, x))
|
|
#define GCC_DIAG_POP() GCC_DIAG_PRAGMA(pop)
|
|
#else
|
|
#define GCC_DIAG_PUSH_OFF(x)
|
|
#define GCC_DIAG_POP()
|
|
#endif
|
|
|
|
#ifdef LINUX
|
|
#pragma GCC diagnostic ignored \
|
|
"-Wconversion-null" // passing NULL to non-pointer argument 1
|
|
#pragma GCC diagnostic ignored \
|
|
"-Wpointer-arith" // NULL used in arithmetic. Ie, vpanel == NULL where
|
|
// VPANEL is uint.
|
|
#pragma GCC diagnostic ignored \
|
|
"-Wswitch" // enumeration values not handled in switch
|
|
#endif
|
|
|
|
#ifdef OSX
|
|
#pragma GCC diagnostic ignored \
|
|
"-Wconversion-null" // passing NULL to non-pointer argument 1
|
|
#pragma GCC diagnostic ignored \
|
|
"-Wnull-arithmetic" // NULL used in arithmetic. Ie, vpanel == NULL where
|
|
// VPANEL is uint.
|
|
#pragma GCC diagnostic ignored \
|
|
"-Wswitch-enum" // enumeration values not handled in switch
|
|
#pragma GCC diagnostic ignored \
|
|
"-Wswitch" // enumeration values not handled in switch
|
|
#endif
|
|
|
|
// When we port to 64 bit, we'll have to resolve the int, ptr vs size_t 32/64
|
|
// bit problems...
|
|
#if !defined(_WIN64)
|
|
#pragma warning(disable : 4267) // conversion from 'size_t' to 'int', possible
|
|
// loss of data
|
|
#pragma warning(disable : 4311) // pointer truncation from 'char *' to 'int'
|
|
#pragma warning(disable : 4312) // conversion from 'unsigned int' to
|
|
// 'memhandle_t' of greater size
|
|
#endif
|
|
|
|
#ifdef POSIX
|
|
#define _stricmp stricmp
|
|
#define strcmpi stricmp
|
|
#define stricmp strcasecmp
|
|
#define _vsnprintf vsnprintf
|
|
#define _alloca alloca
|
|
#ifdef _snprintf
|
|
#undef _snprintf
|
|
#endif
|
|
#define _snprintf snprintf
|
|
#define GetProcAddress dlsym
|
|
#define _chdir chdir
|
|
#define _strnicmp strnicmp
|
|
#define strnicmp strncasecmp
|
|
#define _getcwd getcwd
|
|
#define _snwprintf swprintf
|
|
#define swprintf_s swprintf
|
|
#define wcsicmp _wcsicmp
|
|
#define _wcsicmp wcscmp
|
|
#define _finite finite
|
|
#define _tempnam tempnam
|
|
#define _unlink unlink
|
|
#define _access access
|
|
#define _mkdir(dir) mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO)
|
|
#define _wtoi(arg) wcstol(arg, NULL, 10)
|
|
#define _wtoi64(arg) wcstoll(arg, NULL, 10)
|
|
|
|
typedef uint32 HMODULE;
|
|
typedef void *HANDLE;
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// fsel
|
|
//-----------------------------------------------------------------------------
|
|
#ifndef _X360
|
|
|
|
static FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) {
|
|
return fComparand >= 0 ? fValGE : fLT;
|
|
}
|
|
static FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) {
|
|
return fComparand >= 0 ? fValGE : fLT;
|
|
}
|
|
|
|
#else
|
|
|
|
// __fsel(double fComparand, double fValGE, double fLT) == fComparand >= 0 ?
|
|
// fValGE : fLT this is much faster than if ( aFloat > 0 ) { x = .. }
|
|
#define fsel __fsel
|
|
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FP exception handling
|
|
//-----------------------------------------------------------------------------
|
|
//#define CHECK_FLOAT_EXCEPTIONS 1
|
|
|
|
#if !defined(_X360)
|
|
#if defined(_MSC_VER)
|
|
|
|
#if defined(PLATFORM_WINDOWS_PC64)
|
|
inline void SetupFPUControlWord() {}
|
|
#elif !defined(F1_GCC)
|
|
inline void SetupFPUControlWordForceExceptions() {
|
|
// use local to get and store control word
|
|
uint16 tmpCtrlW;
|
|
__asm
|
|
{
|
|
fnclex /* clear all current exceptions */
|
|
fnstcw word ptr [tmpCtrlW] /* get current control word */
|
|
and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */
|
|
or [tmpCtrlW], 0230h /* set to 53-bit, mask only inexact, underflow */
|
|
fldcw word ptr [tmpCtrlW] /* put new control word in FPU */
|
|
}
|
|
}
|
|
|
|
#ifdef CHECK_FLOAT_EXCEPTIONS
|
|
|
|
inline void SetupFPUControlWord() { SetupFPUControlWordForceExceptions(); }
|
|
|
|
#else
|
|
|
|
inline void SetupFPUControlWord() {
|
|
// use local to get and store control word
|
|
uint16 tmpCtrlW;
|
|
__asm
|
|
{
|
|
fnstcw word ptr [tmpCtrlW] /* get current control word */
|
|
and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */
|
|
or [tmpCtrlW], 023Fh /* set to 53-bit, mask only inexact, underflow */
|
|
fldcw word ptr [tmpCtrlW] /* put new control word in FPU */
|
|
}
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
#else
|
|
|
|
inline void SetupFPUControlWord() {
|
|
__volatile unsigned short int __cw;
|
|
__asm __volatile("fnstcw %0" : "=m"(__cw));
|
|
__cw = __cw & 0x0FCC0; // keep infinity control, keep rounding mode
|
|
__cw = __cw | 0x023F; // set 53-bit, no exceptions
|
|
__asm __volatile("fldcw %0" : : "m"(__cw));
|
|
}
|
|
|
|
#endif // _MSC_VER
|
|
|
|
#else
|
|
|
|
#ifdef _DEBUG
|
|
FORCEINLINE bool IsFPUControlWordSet() {
|
|
float f = 0.996f;
|
|
union {
|
|
double flResult;
|
|
int pResult[2];
|
|
};
|
|
flResult = __fctiw(f);
|
|
return (pResult[1] == 1);
|
|
}
|
|
#endif
|
|
|
|
inline void SetupFPUControlWord() {
|
|
// Set round-to-nearest in FPSCR
|
|
// (cannot assemble, must use op-code form)
|
|
__emit(0xFF80010C); // mtfsfi 7,0
|
|
|
|
// Favour compatibility over speed (make sure the VPU set to Java-compliant
|
|
// mode) NOTE: the VPU *always* uses round-to-nearest
|
|
__vector4 a = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
a; // Avoid compiler warning
|
|
__asm
|
|
{
|
|
mtvscr a; // Clear the Vector Status & Control Register to zero
|
|
}
|
|
}
|
|
|
|
#endif // _X360
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Standard functions for handling endian-ness
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-------------------------------------
|
|
// Basic swaps
|
|
//-------------------------------------
|
|
|
|
template <typename T>
|
|
inline T WordSwapC(T w) {
|
|
uint16 temp;
|
|
|
|
temp = ((*((uint16 *)&w) & 0xff00) >> 8);
|
|
temp |= ((*((uint16 *)&w) & 0x00ff) << 8);
|
|
|
|
return *((T *)&temp);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T DWordSwapC(T dw) {
|
|
uint32 temp;
|
|
|
|
temp = *((uint32 *)&dw) >> 24;
|
|
temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8);
|
|
temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8);
|
|
temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24);
|
|
|
|
return *((T *)&temp);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T QWordSwapC(T dw) {
|
|
// Assert sizes passed to this are already correct, otherwise
|
|
// the cast to uint64 * below is unsafe and may have wrong results
|
|
// or even crash.
|
|
PLAT_COMPILE_TIME_ASSERT(sizeof(dw) == sizeof(uint64));
|
|
|
|
uint64 temp;
|
|
|
|
temp = *((uint64 *)&dw) >> 56;
|
|
temp |= ((*((uint64 *)&dw) & 0x00FF000000000000ull) >> 40);
|
|
temp |= ((*((uint64 *)&dw) & 0x0000FF0000000000ull) >> 24);
|
|
temp |= ((*((uint64 *)&dw) & 0x000000FF00000000ull) >> 8);
|
|
temp |= ((*((uint64 *)&dw) & 0x00000000FF000000ull) << 8);
|
|
temp |= ((*((uint64 *)&dw) & 0x0000000000FF0000ull) << 24);
|
|
temp |= ((*((uint64 *)&dw) & 0x000000000000FF00ull) << 40);
|
|
temp |= ((*((uint64 *)&dw) & 0x00000000000000FFull) << 56);
|
|
|
|
return *((T *)&temp);
|
|
}
|
|
|
|
//-------------------------------------
|
|
// Fast swaps
|
|
//-------------------------------------
|
|
|
|
#if defined(_X360)
|
|
|
|
#define WordSwap WordSwap360Intr
|
|
#define DWordSwap DWordSwap360Intr
|
|
|
|
template <typename T>
|
|
inline T WordSwap360Intr(T w) {
|
|
T output;
|
|
__storeshortbytereverse(w, 0, &output);
|
|
return output;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T DWordSwap360Intr(T dw) {
|
|
T output;
|
|
__storewordbytereverse(dw, 0, &output);
|
|
return output;
|
|
}
|
|
|
|
#elif defined(_MSC_VER) && !defined(PLATFORM_WINDOWS_PC64) && !defined(F1_GCC)
|
|
|
|
#define WordSwap WordSwapAsm
|
|
#define DWordSwap DWordSwapAsm
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4035) // no return value
|
|
|
|
template <typename T>
|
|
inline T WordSwapAsm(T w) {
|
|
__asm
|
|
{
|
|
mov ax, w
|
|
xchg al, ah
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline T DWordSwapAsm(T dw) {
|
|
__asm
|
|
{
|
|
mov eax, dw
|
|
bswap eax
|
|
}
|
|
}
|
|
|
|
#pragma warning(pop)
|
|
|
|
#else
|
|
|
|
#define WordSwap WordSwapC
|
|
#define DWordSwap DWordSwapC
|
|
|
|
#endif
|
|
|
|
// No ASM implementation for this yet
|
|
#define QWordSwap QWordSwapC
|
|
|
|
//-------------------------------------
|
|
// The typically used methods.
|
|
//-------------------------------------
|
|
|
|
#if defined(__i386__) && !defined(VALVE_LITTLE_ENDIAN)
|
|
#define VALVE_LITTLE_ENDIAN 1
|
|
#endif
|
|
|
|
#if defined(_SGI_SOURCE) || defined(_X360)
|
|
#define VALVE_BIG_ENDIAN 1
|
|
#endif
|
|
|
|
// If a swapped float passes through the fpu, the bytes may get changed.
|
|
// Prevent this by swapping floats as DWORDs.
|
|
#define SafeSwapFloat(pOut, pIn) (*((uint *)pOut) = DWordSwap(*((uint *)pIn)))
|
|
|
|
#if defined(VALVE_LITTLE_ENDIAN)
|
|
|
|
#define BigShort(val) WordSwap(val)
|
|
#define BigWord(val) WordSwap(val)
|
|
#define BigLong(val) DWordSwap(val)
|
|
#define BigDWord(val) DWordSwap(val)
|
|
#define LittleShort(val) (val)
|
|
#define LittleWord(val) (val)
|
|
#define LittleLong(val) (val)
|
|
#define LittleDWord(val) (val)
|
|
#define LittleQWord(val) (val)
|
|
#define SwapShort(val) BigShort(val)
|
|
#define SwapWord(val) BigWord(val)
|
|
#define SwapLong(val) BigLong(val)
|
|
#define SwapDWord(val) BigDWord(val)
|
|
|
|
// Pass floats by pointer for swapping to avoid truncation in the fpu
|
|
#define BigFloat(pOut, pIn) SafeSwapFloat(pOut, pIn)
|
|
#define LittleFloat(pOut, pIn) (*pOut = *pIn)
|
|
#define SwapFloat(pOut, pIn) BigFloat(pOut, pIn)
|
|
|
|
#elif defined(VALVE_BIG_ENDIAN)
|
|
|
|
#define BigShort(val) (val)
|
|
#define BigWord(val) (val)
|
|
#define BigLong(val) (val)
|
|
#define BigDWord(val) (val)
|
|
#define LittleShort(val) WordSwap(val)
|
|
#define LittleWord(val) WordSwap(val)
|
|
#define LittleLong(val) DWordSwap(val)
|
|
#define LittleDWord(val) DWordSwap(val)
|
|
#define LittleQWord(val) QWordSwap(val)
|
|
#define SwapShort(val) LittleShort(val)
|
|
#define SwapWord(val) LittleWord(val)
|
|
#define SwapLong(val) LittleLong(val)
|
|
#define SwapDWord(val) LittleDWord(val)
|
|
|
|
// Pass floats by pointer for swapping to avoid truncation in the fpu
|
|
#define BigFloat(pOut, pIn) (*pOut = *pIn)
|
|
#define LittleFloat(pOut, pIn) SafeSwapFloat(pOut, pIn)
|
|
#define SwapFloat(pOut, pIn) LittleFloat(pOut, pIn)
|
|
|
|
#else
|
|
|
|
// @Note (toml 05-02-02): this technique expects the compiler to
|
|
// optimize the expression and eliminate the other path. On any new
|
|
// platform/compiler this should be tested.
|
|
inline short BigShort(short val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? WordSwap(val) : val;
|
|
}
|
|
inline uint16 BigWord(uint16 val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? WordSwap(val) : val;
|
|
}
|
|
inline long BigLong(long val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? DWordSwap(val) : val;
|
|
}
|
|
inline uint32 BigDWord(uint32 val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? DWordSwap(val) : val;
|
|
}
|
|
inline short LittleShort(short val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? val : WordSwap(val);
|
|
}
|
|
inline uint16 LittleWord(uint16 val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? val : WordSwap(val);
|
|
}
|
|
inline long LittleLong(long val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? val : DWordSwap(val);
|
|
}
|
|
inline uint32 LittleDWord(uint32 val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? val : DWordSwap(val);
|
|
}
|
|
inline uint64 LittleQWord(uint64 val) {
|
|
int test = 1;
|
|
return (*(char *)&test == 1) ? val : QWordSwap(val);
|
|
}
|
|
inline short SwapShort(short val) { return WordSwap(val); }
|
|
inline uint16 SwapWord(uint16 val) { return WordSwap(val); }
|
|
inline long SwapLong(long val) { return DWordSwap(val); }
|
|
inline uint32 SwapDWord(uint32 val) { return DWordSwap(val); }
|
|
|
|
// Pass floats by pointer for swapping to avoid truncation in the fpu
|
|
inline void BigFloat(float *pOut, const float *pIn) {
|
|
int test = 1;
|
|
(*(char *)&test == 1) ? SafeSwapFloat(pOut, pIn) : (*pOut = *pIn);
|
|
}
|
|
inline void LittleFloat(float *pOut, const float *pIn) {
|
|
int test = 1;
|
|
(*(char *)&test == 1) ? (*pOut = *pIn) : SafeSwapFloat(pOut, pIn);
|
|
}
|
|
inline void SwapFloat(float *pOut, const float *pIn) {
|
|
SafeSwapFloat(pOut, pIn);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _X360
|
|
FORCEINLINE unsigned long LoadLittleDWord(const unsigned long *base,
|
|
unsigned int dwordIndex) {
|
|
return __loadwordbytereverse(dwordIndex << 2, base);
|
|
}
|
|
|
|
FORCEINLINE void StoreLittleDWord(unsigned long *base, unsigned int dwordIndex,
|
|
unsigned long dword) {
|
|
__storewordbytereverse(dword, dwordIndex << 2, base);
|
|
}
|
|
#else
|
|
FORCEINLINE unsigned long LoadLittleDWord(const unsigned long *base,
|
|
unsigned int dwordIndex) {
|
|
return LittleDWord(base[dwordIndex]);
|
|
}
|
|
|
|
FORCEINLINE void StoreLittleDWord(unsigned long *base, unsigned int dwordIndex,
|
|
unsigned long dword) {
|
|
base[dwordIndex] = LittleDWord(dword);
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// DLL export for platform utilities
|
|
//-----------------------------------------------------------------------------
|
|
#ifndef STATIC_TIER0
|
|
|
|
#ifdef TIER0_DLL_EXPORT
|
|
#define PLATFORM_INTERFACE DLL_EXPORT
|
|
#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT
|
|
#define PLATFORM_CLASS DLL_CLASS_EXPORT
|
|
#else
|
|
#define PLATFORM_INTERFACE DLL_IMPORT
|
|
#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT
|
|
#define PLATFORM_CLASS DLL_CLASS_IMPORT
|
|
#endif
|
|
|
|
#else // BUILD_AS_DLL
|
|
|
|
#define PLATFORM_INTERFACE extern
|
|
#define PLATFORM_OVERLOAD
|
|
#define PLATFORM_CLASS
|
|
|
|
#endif // BUILD_AS_DLL
|
|
|
|
// When in benchmark mode, the timer returns a simple incremented value each
|
|
// time you call it.
|
|
//
|
|
// It should not be changed after startup unless you really know what you're
|
|
// doing. The only place that should do this is the benchmark code itself so it
|
|
// can output a legit duration.
|
|
PLATFORM_INTERFACE void Plat_SetBenchmarkMode(bool bBenchmarkMode);
|
|
PLATFORM_INTERFACE bool Plat_IsInBenchmarkMode();
|
|
|
|
PLATFORM_INTERFACE double
|
|
Plat_FloatTime(); // Returns time in seconds since the module was loaded.
|
|
PLATFORM_INTERFACE unsigned int Plat_MSTime(); // Time in milliseconds.
|
|
PLATFORM_INTERFACE char *Plat_ctime(const time_t *timep, char *buf,
|
|
size_t bufsize);
|
|
PLATFORM_INTERFACE struct tm *Plat_gmtime(const time_t *timep,
|
|
struct tm *result);
|
|
PLATFORM_INTERFACE time_t Plat_timegm(struct tm *timeptr);
|
|
PLATFORM_INTERFACE struct tm *Plat_localtime(const time_t *timep,
|
|
struct tm *result);
|
|
|
|
#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER >= 1400) && \
|
|
!defined(F1_GCC)
|
|
extern "C" unsigned __int64 __rdtsc();
|
|
#pragma intrinsic(__rdtsc)
|
|
#elif defined(F1_GCC)
|
|
#endif
|
|
|
|
inline uint64 Plat_Rdtsc() {
|
|
#if defined(_X360)
|
|
return (uint64)__mftb32();
|
|
#elif defined(_WIN64)
|
|
return (uint64)__rdtsc();
|
|
#elif defined(_WIN32) && !defined(F1_GCC)
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(F1_GCC)
|
|
return (uint64)__rdtsc();
|
|
#else
|
|
__asm rdtsc;
|
|
__asm ret;
|
|
#endif
|
|
#elif defined(__i386__)
|
|
uint64 val;
|
|
__asm__ __volatile__("rdtsc" : "=A"(val));
|
|
return val;
|
|
#elif defined(__x86_64__)
|
|
uint32 lo, hi;
|
|
__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
|
|
return (((uint64)hi) << 32) | lo;
|
|
#else
|
|
#error
|
|
#endif
|
|
}
|
|
|
|
// b/w compatibility
|
|
#define Sys_FloatTime Plat_FloatTime
|
|
|
|
// Protect against bad auto operator=
|
|
#define DISALLOW_OPERATOR_EQUAL(_classname) \
|
|
private: \
|
|
_classname &operator=(const _classname &); \
|
|
\
|
|
public:
|
|
|
|
// Define a reasonable operator=
|
|
#define IMPLEMENT_OPERATOR_EQUAL(_classname) \
|
|
public: \
|
|
_classname &operator=(const _classname &src) { \
|
|
memcpy(this, &src, sizeof(_classname)); \
|
|
return *this; \
|
|
}
|
|
|
|
// Processor Information:
|
|
struct CPUInformation {
|
|
int m_Size; // Size of this structure, for forward compatability.
|
|
|
|
bool m_bRDTSC : 1, // Is RDTSC supported?
|
|
m_bCMOV : 1, // Is CMOV supported?
|
|
m_bFCMOV : 1, // Is FCMOV supported?
|
|
m_bSSE : 1, // Is SSE supported?
|
|
m_bSSE2 : 1, // Is SSE2 Supported?
|
|
m_b3DNow : 1, // Is 3DNow! Supported?
|
|
m_bMMX : 1, // Is MMX supported?
|
|
m_bHT : 1; // Is HyperThreading supported?
|
|
|
|
uint8 m_nLogicalProcessors; // Number op logical processors.
|
|
uint8 m_nPhysicalProcessors; // Number of physical processors
|
|
|
|
bool m_bSSE3 : 1, m_bSSSE3 : 1, m_bSSE4a : 1, m_bSSE41 : 1, m_bSSE42 : 1;
|
|
|
|
int64 m_Speed; // In cycles per second.
|
|
|
|
tchar *m_szProcessorID; // Processor vendor Identification.
|
|
|
|
uint32 m_nModel;
|
|
uint32 m_nFeatures[3];
|
|
|
|
CPUInformation() : m_Size(0) {}
|
|
};
|
|
|
|
// Have to return a pointer, not a reference, because references are not
|
|
// compatible with the extern "C" implied by PLATFORM_INTERFACE.
|
|
PLATFORM_INTERFACE const CPUInformation *GetCPUInformation();
|
|
|
|
PLATFORM_INTERFACE float GetCPUUsage();
|
|
|
|
PLATFORM_INTERFACE void GetCurrentDate(int *pDay, int *pMonth, int *pYear);
|
|
|
|
// ----------------------------------------------------------------------------------
|
|
// // Performance Monitoring Events - L2 stats etc...
|
|
// ----------------------------------------------------------------------------------
|
|
// //
|
|
PLATFORM_INTERFACE void InitPME();
|
|
PLATFORM_INTERFACE void ShutdownPME();
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Thread related functions
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Sets a hardware data breakpoint on the given address. Currently Win32-only.
|
|
// Specify 1, 2, or 4 bytes for nWatchBytes; pass 0 to unregister the address.
|
|
PLATFORM_INTERFACE void Plat_SetHardwareDataBreakpoint(const void *pAddress,
|
|
int nWatchBytes,
|
|
bool bBreakOnRead);
|
|
|
|
// Apply current hardware data breakpoints to a newly created thread.
|
|
PLATFORM_INTERFACE void Plat_ApplyHardwareDataBreakpointsToNewThread(
|
|
unsigned long dwThreadID);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Process related functions
|
|
//-----------------------------------------------------------------------------
|
|
PLATFORM_INTERFACE const tchar *Plat_GetCommandLine();
|
|
#ifndef _WIN32
|
|
// helper function for OS's that don't have a ::GetCommandLine() call
|
|
PLATFORM_INTERFACE void Plat_SetCommandLine(const char *cmdLine);
|
|
#endif
|
|
PLATFORM_INTERFACE const char *Plat_GetCommandLineA();
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Security related functions
|
|
//-----------------------------------------------------------------------------
|
|
// Ensure that the hardware key's drivers have been installed.
|
|
PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver();
|
|
|
|
// Ok, so this isn't a very secure way to verify the hardware key for now. It
|
|
// is primarially depending on the fact that all the binaries have been wrapped
|
|
// with the secure wrapper provided by the hardware keys vendor.
|
|
PLATFORM_INTERFACE bool Plat_VerifyHardwareKey();
|
|
|
|
// The same as above, but notifies user with a message box when the key isn't in
|
|
// and gives him an opportunity to correct the situation.
|
|
PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt();
|
|
|
|
// Can be called in real time, doesn't perform the verify every frame. Mainly
|
|
// just here to allow the game to drop out quickly when the key is removed,
|
|
// rather than allowing the wrapper to pop up it's own blocking dialog, which
|
|
// the engine doesn't like much.
|
|
PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey();
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Just logs file and line to simple.log
|
|
//-----------------------------------------------------------------------------
|
|
PLATFORM_INTERFACE void *Plat_SimpleLog(const tchar *file, int line);
|
|
|
|
#if _X360
|
|
#define Plat_FastMemset XMemSet
|
|
#define Plat_FastMemcpy XMemCpy
|
|
#else
|
|
#define Plat_FastMemset memset
|
|
#define Plat_FastMemcpy memcpy
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns true if debugger attached, false otherwise
|
|
//-----------------------------------------------------------------------------
|
|
#if defined(_WIN32) || defined(LINUX) || defined(OSX)
|
|
PLATFORM_INTERFACE bool Plat_IsInDebugSession();
|
|
PLATFORM_INTERFACE void Plat_DebugString(const char *);
|
|
#else
|
|
inline bool Plat_IsInDebugSession(bool bForceRecheck = false) { return false; }
|
|
#define Plat_DebugString(s) ((void)0)
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns true if running on a 64 bit (windows) OS
|
|
//-----------------------------------------------------------------------------
|
|
PLATFORM_INTERFACE bool Is64BitOS();
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// XBOX Components valid in PC compilation space
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define XBOX_DVD_SECTORSIZE 2048
|
|
#define XBOX_DVD_ECC_SIZE 32768 // driver reads in quantum ECC blocks
|
|
#define XBOX_HDD_SECTORSIZE 512
|
|
|
|
// Custom windows messages for Xbox input
|
|
#define WM_XREMOTECOMMAND (WM_USER + 100)
|
|
#define WM_XCONTROLLER_KEY (WM_USER + 101)
|
|
#define WM_SYS_UI (WM_USER + 102)
|
|
#define WM_SYS_SIGNINCHANGED (WM_USER + 103)
|
|
#define WM_SYS_STORAGEDEVICESCHANGED (WM_USER + 104)
|
|
#define WM_SYS_PROFILESETTINGCHANGED (WM_USER + 105)
|
|
#define WM_SYS_MUTELISTCHANGED (WM_USER + 106)
|
|
#define WM_SYS_INPUTDEVICESCHANGED (WM_USER + 107)
|
|
#define WM_SYS_INPUTDEVICECONFIGCHANGED (WM_USER + 108)
|
|
#define WM_LIVE_CONNECTIONCHANGED (WM_USER + 109)
|
|
#define WM_LIVE_INVITE_ACCEPTED (WM_USER + 110)
|
|
#define WM_LIVE_LINK_STATE_CHANGED (WM_USER + 111)
|
|
#define WM_LIVE_CONTENT_INSTALLED (WM_USER + 112)
|
|
#define WM_LIVE_MEMBERSHIP_PURCHASED (WM_USER + 113)
|
|
#define WM_LIVE_VOICECHAT_AWAY (WM_USER + 114)
|
|
#define WM_LIVE_PRESENCE_CHANGED (WM_USER + 115)
|
|
#define WM_FRIENDS_PRESENCE_CHANGED (WM_USER + 116)
|
|
#define WM_FRIENDS_FRIEND_ADDED (WM_USER + 117)
|
|
#define WM_FRIENDS_FRIEND_REMOVED (WM_USER + 118)
|
|
#define WM_CUSTOM_GAMEBANNERPRESSED (WM_USER + 119)
|
|
#define WM_CUSTOM_ACTIONPRESSED (WM_USER + 120)
|
|
#define WM_XMP_STATECHANGED (WM_USER + 121)
|
|
#define WM_XMP_PLAYBACKBEHAVIORCHANGED (WM_USER + 122)
|
|
#define WM_XMP_PLAYBACKCONTROLLERCHANGED (WM_USER + 123)
|
|
|
|
inline const char *GetPlatformExt(void) { return IsX360() ? ".360" : ""; }
|
|
|
|
// flat view, 6 hw threads
|
|
#define XBOX_PROCESSOR_0 (1 << 0)
|
|
#define XBOX_PROCESSOR_1 (1 << 1)
|
|
#define XBOX_PROCESSOR_2 (1 << 2)
|
|
#define XBOX_PROCESSOR_3 (1 << 3)
|
|
#define XBOX_PROCESSOR_4 (1 << 4)
|
|
#define XBOX_PROCESSOR_5 (1 << 5)
|
|
|
|
// core view, 3 cores with 2 hw threads each
|
|
#define XBOX_CORE_0_HWTHREAD_0 XBOX_PROCESSOR_0
|
|
#define XBOX_CORE_0_HWTHREAD_1 XBOX_PROCESSOR_1
|
|
#define XBOX_CORE_1_HWTHREAD_0 XBOX_PROCESSOR_2
|
|
#define XBOX_CORE_1_HWTHREAD_1 XBOX_PROCESSOR_3
|
|
#define XBOX_CORE_2_HWTHREAD_0 XBOX_PROCESSOR_4
|
|
#define XBOX_CORE_2_HWTHREAD_1 XBOX_PROCESSOR_5
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Include additional dependant header components.
|
|
//-----------------------------------------------------------------------------
|
|
#include "fasttimer.h"
|
|
|
|
#if defined(_X360)
|
|
#include "xbox/xbox_core.h"
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Methods to invoke the constructor, copy constructor, and destructor
|
|
//-----------------------------------------------------------------------------
|
|
|
|
template <class T>
|
|
inline T *Construct(T *pMemory) {
|
|
return ::new (pMemory) T;
|
|
}
|
|
|
|
template <class T, typename ARG1>
|
|
inline T *Construct(T *pMemory, ARG1 a1) {
|
|
return ::new (pMemory) T(a1);
|
|
}
|
|
|
|
template <class T, typename ARG1, typename ARG2>
|
|
inline T *Construct(T *pMemory, ARG1 a1, ARG2 a2) {
|
|
return ::new (pMemory) T(a1, a2);
|
|
}
|
|
|
|
template <class T, typename ARG1, typename ARG2, typename ARG3>
|
|
inline T *Construct(T *pMemory, ARG1 a1, ARG2 a2, ARG3 a3) {
|
|
return ::new (pMemory) T(a1, a2, a3);
|
|
}
|
|
|
|
template <class T, typename ARG1, typename ARG2, typename ARG3, typename ARG4>
|
|
inline T *Construct(T *pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4) {
|
|
return ::new (pMemory) T(a1, a2, a3, a4);
|
|
}
|
|
|
|
template <class T, typename ARG1, typename ARG2, typename ARG3, typename ARG4,
|
|
typename ARG5>
|
|
inline T *Construct(T *pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4, ARG5 a5) {
|
|
return ::new (pMemory) T(a1, a2, a3, a4, a5);
|
|
}
|
|
|
|
template <class T, class P>
|
|
inline void ConstructOneArg(T *pMemory, P const &arg) {
|
|
::new (pMemory) T(arg);
|
|
}
|
|
|
|
template <class T, class P1, class P2>
|
|
inline void ConstructTwoArg(T *pMemory, P1 const &arg1, P2 const &arg2) {
|
|
::new (pMemory) T(arg1, arg2);
|
|
}
|
|
|
|
template <class T, class P1, class P2, class P3>
|
|
inline void ConstructThreeArg(T *pMemory, P1 const &arg1, P2 const &arg2,
|
|
P3 const &arg3) {
|
|
::new (pMemory) T(arg1, arg2, arg3);
|
|
}
|
|
|
|
template <class T>
|
|
inline T *CopyConstruct(T *pMemory, T const &src) {
|
|
return ::new (pMemory) T(src);
|
|
}
|
|
|
|
template <class T>
|
|
inline void Destruct(T *pMemory) {
|
|
pMemory->~T();
|
|
|
|
#ifdef _DEBUG
|
|
memset(reinterpret_cast<void *>(pMemory), 0xDD, sizeof(T));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// GET_OUTER()
|
|
//
|
|
// A platform-independent way for a contained class to get a pointer to its
|
|
// owner. If you know a class is exclusively used in the context of some
|
|
// "outer" class, this is a much more space efficient way to get at the outer
|
|
// class than having the inner class store a pointer to it.
|
|
//
|
|
// class COuter
|
|
// {
|
|
// class CInner // Note: this does not need to be a nested class to
|
|
//work
|
|
// {
|
|
// void PrintAddressOfOuter()
|
|
// {
|
|
// printf( "Outer is at 0x%x\n", GET_OUTER( COuter,
|
|
//m_Inner ) );
|
|
// }
|
|
// };
|
|
//
|
|
// CInner m_Inner;
|
|
// friend class CInner;
|
|
// };
|
|
|
|
#define GET_OUTER(OuterType, OuterMember) \
|
|
((OuterType *)((uint8 *)this - offsetof(OuterType, OuterMember)))
|
|
|
|
/* TEMPLATE_FUNCTION_TABLE()
|
|
|
|
(Note added to platform.h so platforms that correctly support templated
|
|
functions can handle portions as templated functions rather than
|
|
wrapped functions)
|
|
|
|
Helps automate the process of creating an array of function
|
|
templates that are all specialized by a single integer.
|
|
This sort of thing is often useful in optimization work.
|
|
|
|
For example, using TEMPLATE_FUNCTION_TABLE, this:
|
|
|
|
TEMPLATE_FUNCTION_TABLE(int, Function, ( int blah, int blah ), 10)
|
|
{
|
|
return argument * argument;
|
|
}
|
|
|
|
is equivilent to the following:
|
|
|
|
(NOTE: the function has to be wrapped in a class due to code
|
|
generation bugs involved with directly specializing a function
|
|
based on a constant.)
|
|
|
|
template<int argument>
|
|
class FunctionWrapper
|
|
{
|
|
public:
|
|
int Function( int blah, int blah )
|
|
{
|
|
return argument*argument;
|
|
}
|
|
}
|
|
|
|
typedef int (*FunctionType)( int blah, int blah );
|
|
|
|
class FunctionName
|
|
{
|
|
public:
|
|
enum { count = 10 };
|
|
FunctionType functions[10];
|
|
};
|
|
|
|
FunctionType FunctionName::functions[] =
|
|
{
|
|
FunctionWrapper<0>::Function,
|
|
FunctionWrapper<1>::Function,
|
|
FunctionWrapper<2>::Function,
|
|
FunctionWrapper<3>::Function,
|
|
FunctionWrapper<4>::Function,
|
|
FunctionWrapper<5>::Function,
|
|
FunctionWrapper<6>::Function,
|
|
FunctionWrapper<7>::Function,
|
|
FunctionWrapper<8>::Function,
|
|
FunctionWrapper<9>::Function
|
|
};
|
|
*/
|
|
|
|
PLATFORM_INTERFACE bool vtune(bool resume);
|
|
|
|
#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \
|
|
\
|
|
typedef RETURN_TYPE(FASTCALL *__Type_##NAME) ARGS; \
|
|
\
|
|
template <const int nArgument> \
|
|
struct __Function_##NAME { \
|
|
static RETURN_TYPE FASTCALL Run ARGS; \
|
|
}; \
|
|
\
|
|
template <const int i> \
|
|
struct __MetaLooper_##NAME : __MetaLooper_##NAME<i - 1> { \
|
|
__Type_##NAME func; \
|
|
inline __MetaLooper_##NAME() { func = __Function_##NAME<i>::Run; } \
|
|
}; \
|
|
\
|
|
template <> \
|
|
struct __MetaLooper_##NAME<0> { \
|
|
__Type_##NAME func; \
|
|
inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \
|
|
}; \
|
|
\
|
|
class NAME { \
|
|
private: \
|
|
static const __MetaLooper_##NAME<COUNT> m; \
|
|
\
|
|
public: \
|
|
enum { count = COUNT }; \
|
|
static const __Type_##NAME *functions; \
|
|
}; \
|
|
const __MetaLooper_##NAME<COUNT> NAME::m; \
|
|
const __Type_##NAME *NAME::functions = (__Type_##NAME *)&m; \
|
|
template <const int nArgument> \
|
|
RETURN_TYPE FASTCALL __Function_##NAME<nArgument>::Run ARGS
|
|
|
|
#define LOOP_INTERCHANGE(BOOLEAN, CODE) \
|
|
if ((BOOLEAN)) { \
|
|
CODE; \
|
|
} else { \
|
|
CODE; \
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Dynamic libs support
|
|
//-----------------------------------------------------------------------------
|
|
#if 0 // defined( PLATFORM_WINDOWS_PC )
|
|
|
|
PLATFORM_INTERFACE void *Plat_GetProcAddress( const char *pszModule, const char *pszName );
|
|
|
|
template <typename FUNCPTR_TYPE>
|
|
class CDynamicFunction
|
|
{
|
|
public:
|
|
CDynamicFunction( const char *pszModule, const char *pszName, FUNCPTR_TYPE pfnFallback = NULL )
|
|
{
|
|
m_pfn = pfnFallback;
|
|
void *pAddr = Plat_GetProcAddress( pszModule, pszName );
|
|
if ( pAddr )
|
|
{
|
|
m_pfn = (FUNCPTR_TYPE)pAddr;
|
|
}
|
|
}
|
|
|
|
operator bool() { return m_pfn != NULL; }
|
|
bool operator !() { return !m_pfn; }
|
|
operator FUNCPTR_TYPE() { return m_pfn; }
|
|
|
|
private:
|
|
FUNCPTR_TYPE m_pfn;
|
|
};
|
|
#endif
|
|
|
|
// Watchdog timer support. Call Plat_BeginWatchdogTimer( nn ) to kick the timer
|
|
// off. if you don't call Plat_EndWatchdogTimer within nn seconds, the program
|
|
// will kick off an exception. This is for making sure that hung dedicated
|
|
// servers abort (and restart) instead of staying hung. Calling
|
|
// Plat_EndWatchdogTimer more than once or when there is no active watchdog is
|
|
// fine. Only does anything under linux right now. It should be possible to
|
|
// implement this functionality in windows via a thread, if desired.
|
|
PLATFORM_INTERFACE void Plat_BeginWatchdogTimer(int nSecs);
|
|
PLATFORM_INTERFACE void Plat_EndWatchdogTimer(void);
|
|
PLATFORM_INTERFACE int Plat_GetWatchdogTime(void);
|
|
|
|
typedef void (*Plat_WatchDogHandlerFunction_t)(void);
|
|
PLATFORM_INTERFACE void Plat_SetWatchdogHandlerFunction(
|
|
Plat_WatchDogHandlerFunction_t function);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "valve_on.h"
|
|
|
|
#if defined(TIER0_DLL_EXPORT)
|
|
extern "C" int V_tier0_stricmp(const char *s1, const char *s2);
|
|
#undef stricmp
|
|
#undef strcmpi
|
|
#define stricmp(s1, s2) V_tier0_stricmp(s1, s2)
|
|
#define strcmpi(s1, s2) V_tier0_stricmp(s1, s2)
|
|
#endif
|
|
|
|
#endif /* PLATFORM_H */
|