Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #define WIN32_LEAN_AND_MEAN
  8. #include <windows.h>
  9. #include <assert.h>
  10. #pragma optimize( "", off )
  11. #pragma pack( push, thing )
  12. #pragma pack( 4 )
  13. static long g_cw, g_single_cw, g_highchop_cw, g_full_cw, g_ceil_cw, g_pushed_cw;
  14. static struct
  15. {
  16. long dummy[8];
  17. } g_fpenv;
  18. #pragma pack( pop, thing )
  19. void __declspec ( naked ) MaskExceptions()
  20. {
  21. _asm
  22. {
  23. fnstenv ds:dword ptr[g_fpenv]
  24. or ds:dword ptr[g_fpenv],03Fh
  25. fldenv ds:dword ptr[g_fpenv]
  26. ret
  27. }
  28. }
  29. void __declspec ( naked ) Sys_SetFPCW()
  30. {
  31. _asm
  32. {
  33. fnstcw ds:word ptr[g_cw]
  34. mov eax,ds:dword ptr[g_cw]
  35. and ah,0F0h
  36. or ah,003h
  37. mov ds:dword ptr[g_full_cw],eax
  38. mov ds:dword ptr[g_highchop_cw],eax
  39. and ah,0F0h
  40. or ah,00Ch
  41. mov ds:dword ptr[g_single_cw],eax
  42. and ah,0F0h
  43. or ah,008h
  44. mov ds:dword ptr[g_ceil_cw],eax
  45. ret
  46. }
  47. }
  48. void __declspec ( naked ) Sys_PushFPCW_SetHigh()
  49. {
  50. _asm
  51. {
  52. fnstcw ds:word ptr[g_pushed_cw]
  53. fldcw ds:word ptr[g_full_cw]
  54. ret
  55. }
  56. }
  57. void __declspec ( naked ) Sys_PopFPCW()
  58. {
  59. _asm
  60. {
  61. fldcw ds:word ptr[g_pushed_cw]
  62. ret
  63. }
  64. }
  65. #pragma optimize( "", on )
  66. //-----------------------------------------------------------------------------
  67. // Purpose: Implements high precision clock
  68. // TODO: Make into an interface?
  69. //-----------------------------------------------------------------------------
  70. class CSysClock
  71. {
  72. public:
  73. // Construction
  74. CSysClock( void );
  75. // Initialization
  76. void Init( void );
  77. void SetStartTime( void );
  78. // Sample the clock
  79. double GetTime( void );
  80. private:
  81. // High performance clock frequency
  82. double m_dClockFrequency;
  83. // Current accumulated time
  84. double m_dCurrentTime;
  85. // How many bits to shift raw 64 bit sample count by
  86. int m_nTimeSampleShift;
  87. // Previous 32 bit sample count
  88. unsigned int m_uiPreviousTime;
  89. bool m_bInitialized;
  90. };
  91. static CSysClock g_Clock;
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. //-----------------------------------------------------------------------------
  95. CSysClock::CSysClock( void )
  96. {
  97. m_bInitialized = false;
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose: Initialize the clock
  101. //-----------------------------------------------------------------------------
  102. void CSysClock::Init( void )
  103. {
  104. BOOL success;
  105. LARGE_INTEGER PerformanceFreq;
  106. unsigned int lowpart, highpart;
  107. MaskExceptions ();
  108. Sys_SetFPCW ();
  109. // Start clock at zero
  110. m_dCurrentTime = 0.0;
  111. success = QueryPerformanceFrequency( &PerformanceFreq );
  112. assert( success );
  113. // get 32 out of the 64 time bits such that we have around
  114. // 1 microsecond resolution
  115. lowpart = (unsigned int)PerformanceFreq.LowPart;
  116. highpart = (unsigned int)PerformanceFreq.HighPart;
  117. m_nTimeSampleShift = 0;
  118. while ( highpart || ( lowpart > 2000000.0 ) )
  119. {
  120. m_nTimeSampleShift++;
  121. lowpart >>= 1;
  122. lowpart |= (highpart & 1) << 31;
  123. highpart >>= 1;
  124. }
  125. m_dClockFrequency = 1.0 / (double)lowpart;
  126. // Get initial sample
  127. unsigned int temp;
  128. LARGE_INTEGER PerformanceCount;
  129. QueryPerformanceCounter( &PerformanceCount );
  130. if ( !m_nTimeSampleShift )
  131. {
  132. temp = (unsigned int)PerformanceCount.LowPart;
  133. }
  134. else
  135. {
  136. // Rotate counter to right by m_nTimeSampleShift places
  137. temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) |
  138. ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift));
  139. }
  140. // Set first time stamp
  141. m_uiPreviousTime = temp;
  142. m_bInitialized = true;
  143. SetStartTime();
  144. }
  145. void CSysClock::SetStartTime( void )
  146. {
  147. GetTime();
  148. m_dCurrentTime = 0.0;
  149. m_uiPreviousTime = ( unsigned int )m_dCurrentTime;
  150. }
  151. double CSysClock::GetTime( void )
  152. {
  153. LARGE_INTEGER PerformanceCount;
  154. unsigned int temp, t2;
  155. double time;
  156. if ( !m_bInitialized )
  157. {
  158. return 0.0;
  159. }
  160. Sys_PushFPCW_SetHigh();
  161. // Get sample counter
  162. QueryPerformanceCounter( &PerformanceCount );
  163. if ( !m_nTimeSampleShift )
  164. {
  165. temp = (unsigned int)PerformanceCount.LowPart;
  166. }
  167. else
  168. {
  169. // Rotate counter to right by m_nTimeSampleShift places
  170. temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) |
  171. ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift));
  172. }
  173. // check for turnover or backward time
  174. if ( ( temp <= m_uiPreviousTime ) &&
  175. ( ( m_uiPreviousTime - temp ) < 0x10000000) )
  176. {
  177. m_uiPreviousTime = temp; // so we can't get stuck
  178. }
  179. else
  180. {
  181. // gap in performance clocks
  182. t2 = temp - m_uiPreviousTime;
  183. // Convert to time using frequencey of clock
  184. time = (double)t2 * m_dClockFrequency;
  185. // Remember old time
  186. m_uiPreviousTime = temp;
  187. // Increment clock
  188. m_dCurrentTime += time;
  189. }
  190. Sys_PopFPCW();
  191. // Convert to float
  192. return m_dCurrentTime;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: Sample the high-precision clock
  196. // Output : double
  197. //-----------------------------------------------------------------------------
  198. double Sys_FloatTime( void )
  199. {
  200. return g_Clock.GetTime();
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose: Initialize high-precision clock
  204. //-----------------------------------------------------------------------------
  205. void Sys_InitFloatTime( void )
  206. {
  207. g_Clock.Init();
  208. }