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.
255 lines
5.3 KiB
255 lines
5.3 KiB
5 years ago
|
//========= 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();
|
||
|
}
|