You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
5.3 KiB
254 lines
5.3 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#define WIN32_LEAN_AND_MEAN |
|
#include <windows.h> |
|
|
|
#include <assert.h> |
|
|
|
#pragma optimize( "", off ) |
|
|
|
#pragma pack( push, thing ) |
|
#pragma pack( 4 ) |
|
static long g_cw, g_single_cw, g_highchop_cw, g_full_cw, g_ceil_cw, g_pushed_cw; |
|
static struct |
|
{ |
|
long dummy[8]; |
|
} g_fpenv; |
|
#pragma pack( pop, thing ) |
|
|
|
|
|
void __declspec ( naked ) MaskExceptions() |
|
{ |
|
_asm |
|
{ |
|
fnstenv ds:dword ptr[g_fpenv] |
|
or ds:dword ptr[g_fpenv],03Fh |
|
fldenv ds:dword ptr[g_fpenv] |
|
ret |
|
} |
|
} |
|
|
|
void __declspec ( naked ) Sys_SetFPCW() |
|
{ |
|
_asm |
|
{ |
|
fnstcw ds:word ptr[g_cw] |
|
mov eax,ds:dword ptr[g_cw] |
|
and ah,0F0h |
|
or ah,003h |
|
mov ds:dword ptr[g_full_cw],eax |
|
mov ds:dword ptr[g_highchop_cw],eax |
|
and ah,0F0h |
|
or ah,00Ch |
|
mov ds:dword ptr[g_single_cw],eax |
|
and ah,0F0h |
|
or ah,008h |
|
mov ds:dword ptr[g_ceil_cw],eax |
|
ret |
|
} |
|
} |
|
|
|
void __declspec ( naked ) Sys_PushFPCW_SetHigh() |
|
{ |
|
_asm |
|
{ |
|
fnstcw ds:word ptr[g_pushed_cw] |
|
fldcw ds:word ptr[g_full_cw] |
|
ret |
|
} |
|
} |
|
|
|
void __declspec ( naked ) Sys_PopFPCW() |
|
{ |
|
_asm |
|
{ |
|
fldcw ds:word ptr[g_pushed_cw] |
|
ret |
|
} |
|
} |
|
|
|
#pragma optimize( "", on ) |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Implements high precision clock |
|
// TODO: Make into an interface? |
|
//----------------------------------------------------------------------------- |
|
class CSysClock |
|
{ |
|
public: |
|
// Construction |
|
CSysClock( void ); |
|
|
|
// Initialization |
|
void Init( void ); |
|
void SetStartTime( void ); |
|
|
|
// Sample the clock |
|
double GetTime( void ); |
|
|
|
private: |
|
// High performance clock frequency |
|
double m_dClockFrequency; |
|
// Current accumulated time |
|
double m_dCurrentTime; |
|
// How many bits to shift raw 64 bit sample count by |
|
int m_nTimeSampleShift; |
|
// Previous 32 bit sample count |
|
unsigned int m_uiPreviousTime; |
|
|
|
bool m_bInitialized; |
|
}; |
|
|
|
static CSysClock g_Clock; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CSysClock::CSysClock( void ) |
|
{ |
|
m_bInitialized = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Initialize the clock |
|
//----------------------------------------------------------------------------- |
|
void CSysClock::Init( void ) |
|
{ |
|
BOOL success; |
|
LARGE_INTEGER PerformanceFreq; |
|
unsigned int lowpart, highpart; |
|
|
|
MaskExceptions (); |
|
Sys_SetFPCW (); |
|
|
|
// Start clock at zero |
|
m_dCurrentTime = 0.0; |
|
|
|
success = QueryPerformanceFrequency( &PerformanceFreq ); |
|
assert( success ); |
|
|
|
// get 32 out of the 64 time bits such that we have around |
|
// 1 microsecond resolution |
|
lowpart = (unsigned int)PerformanceFreq.LowPart; |
|
highpart = (unsigned int)PerformanceFreq.HighPart; |
|
|
|
m_nTimeSampleShift = 0; |
|
|
|
while ( highpart || ( lowpart > 2000000.0 ) ) |
|
{ |
|
m_nTimeSampleShift++; |
|
lowpart >>= 1; |
|
lowpart |= (highpart & 1) << 31; |
|
highpart >>= 1; |
|
} |
|
|
|
m_dClockFrequency = 1.0 / (double)lowpart; |
|
|
|
// Get initial sample |
|
unsigned int temp; |
|
LARGE_INTEGER PerformanceCount; |
|
QueryPerformanceCounter( &PerformanceCount ); |
|
if ( !m_nTimeSampleShift ) |
|
{ |
|
temp = (unsigned int)PerformanceCount.LowPart; |
|
} |
|
else |
|
{ |
|
// Rotate counter to right by m_nTimeSampleShift places |
|
temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | |
|
((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); |
|
} |
|
|
|
// Set first time stamp |
|
m_uiPreviousTime = temp; |
|
|
|
m_bInitialized = true; |
|
|
|
SetStartTime(); |
|
} |
|
|
|
void CSysClock::SetStartTime( void ) |
|
{ |
|
GetTime(); |
|
|
|
m_dCurrentTime = 0.0; |
|
|
|
m_uiPreviousTime = ( unsigned int )m_dCurrentTime; |
|
} |
|
|
|
double CSysClock::GetTime( void ) |
|
{ |
|
LARGE_INTEGER PerformanceCount; |
|
unsigned int temp, t2; |
|
double time; |
|
|
|
if ( !m_bInitialized ) |
|
{ |
|
return 0.0; |
|
} |
|
|
|
Sys_PushFPCW_SetHigh(); |
|
|
|
// Get sample counter |
|
QueryPerformanceCounter( &PerformanceCount ); |
|
|
|
if ( !m_nTimeSampleShift ) |
|
{ |
|
temp = (unsigned int)PerformanceCount.LowPart; |
|
} |
|
else |
|
{ |
|
// Rotate counter to right by m_nTimeSampleShift places |
|
temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | |
|
((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); |
|
} |
|
|
|
// check for turnover or backward time |
|
if ( ( temp <= m_uiPreviousTime ) && |
|
( ( m_uiPreviousTime - temp ) < 0x10000000) ) |
|
{ |
|
m_uiPreviousTime = temp; // so we can't get stuck |
|
} |
|
else |
|
{ |
|
// gap in performance clocks |
|
t2 = temp - m_uiPreviousTime; |
|
|
|
// Convert to time using frequencey of clock |
|
time = (double)t2 * m_dClockFrequency; |
|
|
|
// Remember old time |
|
m_uiPreviousTime = temp; |
|
|
|
// Increment clock |
|
m_dCurrentTime += time; |
|
} |
|
|
|
Sys_PopFPCW(); |
|
|
|
// Convert to float |
|
return m_dCurrentTime; |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sample the high-precision clock |
|
// Output : double |
|
//----------------------------------------------------------------------------- |
|
double Sys_FloatTime( void ) |
|
{ |
|
return g_Clock.GetTime(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Initialize high-precision clock |
|
//----------------------------------------------------------------------------- |
|
void Sys_InitFloatTime( void ) |
|
{ |
|
g_Clock.Init(); |
|
}
|
|
|