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.

983 lines
28 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // CPU_PROFILE.CPP
  4. //
  5. // Cpu Profiling Display
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. #define PROFILE_MAXCOUNTERS 64
  9. #define PROFILE_MAXSAMPLES 512
  10. #define PROFILE_HISTORY_TIMINGHEIGHT 100
  11. #define PROFILE_HISTORY_NUMMINORTICKS 3
  12. #define PROFILE_HISTORY_LABELWIDTH 50
  13. #define PROFILE_HISTORY_SCALESTEPS 5
  14. #define PROFILE_HISTORY_MINSCALE 0.3f
  15. #define PROFILE_HISTORY_MAXSCALE 3.0f
  16. #define PROFILE_SAMPLES_ITEMHEIGHT 15
  17. #define PROFILE_SAMPLES_BARHEIGHT 10
  18. #define PROFILE_SAMPLES_TIMINGWIDTH 200
  19. #define PROFILE_SAMPLES_LABELWIDTH 150
  20. #define PROFILE_SAMPLES_LABELGAP 5
  21. #define PROFILE_SAMPLES_NUMMINORTICKS 3
  22. #define PROFILE_SAMPLES_PEAKHOLDTIME 3000
  23. #define PROFILE_SAMPLES_SCALESTEPS 10
  24. #define PROFILE_SAMPLES_MINSCALE 0.3f
  25. #define PROFILE_SAMPLES_MAXSCALE 3.0f
  26. #define ID_CPUPROFILE_SAMPLES 1
  27. #define ID_CPUPROFILE_HISTORY 2
  28. typedef struct
  29. {
  30. unsigned int samples[PROFILE_MAXSAMPLES];
  31. unsigned int peakSample;
  32. char label[64];
  33. COLORREF color;
  34. } profileCounter_t;
  35. HWND g_cpuProfile_hWndSamples;
  36. HWND g_cpuProfile_hWndHistory;
  37. int g_cpuProfile_numCounters;
  38. profileCounter_t g_cpuProfile_counters[PROFILE_MAXCOUNTERS];
  39. RECT g_cpuProfile_samplesWindowRect;
  40. RECT g_cpuProfile_historyWindowRect;
  41. DWORD g_cpuProfile_lastPeakTime;
  42. bool g_cpuProfile_history_tickMarks = true;
  43. bool g_cpuProfile_history_colors = true;
  44. int g_cpuProfile_history_scale;
  45. bool g_cpuProfile_samples_tickMarks = true;
  46. bool g_cpuProfile_samples_colors = true;
  47. int g_cpuProfile_samples_scale;
  48. int g_cpuProfile_numSamples;
  49. int g_cpuProfile_fpsLabels;
  50. //-----------------------------------------------------------------------------
  51. // CpuProfile_SaveConfig
  52. //
  53. //-----------------------------------------------------------------------------
  54. void CpuProfile_SaveConfig()
  55. {
  56. char buff[256];
  57. WINDOWPLACEMENT wp;
  58. // profile samples
  59. if ( g_cpuProfile_hWndSamples )
  60. {
  61. memset( &wp, 0, sizeof( wp ) );
  62. wp.length = sizeof( WINDOWPLACEMENT );
  63. GetWindowPlacement( g_cpuProfile_hWndSamples, &wp );
  64. g_cpuProfile_samplesWindowRect = wp.rcNormalPosition;
  65. sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom );
  66. Sys_SetRegistryString( "profileSamplesWindowRect", buff );
  67. }
  68. Sys_SetRegistryInteger( "profileSamplesScale", g_cpuProfile_samples_scale );
  69. // profile history
  70. if ( g_cpuProfile_hWndHistory )
  71. {
  72. memset( &wp, 0, sizeof( wp ) );
  73. wp.length = sizeof( WINDOWPLACEMENT );
  74. GetWindowPlacement( g_cpuProfile_hWndHistory, &wp );
  75. g_cpuProfile_historyWindowRect = wp.rcNormalPosition;
  76. sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom );
  77. Sys_SetRegistryString( "profileHistoryWindowRect", buff );
  78. }
  79. Sys_SetRegistryInteger( "profileHistoryScale", g_cpuProfile_history_scale );
  80. Sys_SetRegistryInteger( "cpuProfileFpsLabels", g_cpuProfile_fpsLabels );
  81. }
  82. //-----------------------------------------------------------------------------
  83. // CpuProfile_LoadConfig
  84. //
  85. //-----------------------------------------------------------------------------
  86. void CpuProfile_LoadConfig()
  87. {
  88. int numArgs;
  89. char buff[256];
  90. // profile samples
  91. Sys_GetRegistryString( "profileSamplesWindowRect", buff, "", sizeof( buff ) );
  92. numArgs = sscanf( buff, "%d %d %d %d", &g_cpuProfile_samplesWindowRect.left, &g_cpuProfile_samplesWindowRect.top, &g_cpuProfile_samplesWindowRect.right, &g_cpuProfile_samplesWindowRect.bottom );
  93. if ( numArgs != 4 )
  94. memset( &g_cpuProfile_samplesWindowRect, 0, sizeof( g_cpuProfile_samplesWindowRect ) );
  95. Sys_GetRegistryInteger( "profileSamplesScale", 0, g_cpuProfile_samples_scale );
  96. if ( g_cpuProfile_samples_scale < -PROFILE_SAMPLES_SCALESTEPS || g_cpuProfile_samples_scale > PROFILE_SAMPLES_SCALESTEPS )
  97. g_cpuProfile_samples_scale = 0;
  98. // profile history
  99. Sys_GetRegistryString( "profileHistoryWindowRect", buff, "", sizeof( buff ) );
  100. numArgs = sscanf( buff, "%d %d %d %d", &g_cpuProfile_historyWindowRect.left, &g_cpuProfile_historyWindowRect.top, &g_cpuProfile_historyWindowRect.right, &g_cpuProfile_historyWindowRect.bottom );
  101. if ( numArgs != 4 )
  102. memset( &g_cpuProfile_historyWindowRect, 0, sizeof( g_cpuProfile_historyWindowRect ) );
  103. Sys_GetRegistryInteger( "profileHistoryScale", 0, g_cpuProfile_history_scale );
  104. if ( g_cpuProfile_history_scale < -PROFILE_HISTORY_SCALESTEPS || g_cpuProfile_history_scale > PROFILE_HISTORY_SCALESTEPS )
  105. g_cpuProfile_history_scale = 0;
  106. Sys_GetRegistryInteger( "cpuProfileFpsLabels", 0, g_cpuProfile_fpsLabels );
  107. }
  108. //-----------------------------------------------------------------------------
  109. // CpuProfile_SetTitle
  110. //
  111. //-----------------------------------------------------------------------------
  112. void CpuProfile_SetTitle()
  113. {
  114. char titleBuff[128];
  115. if ( g_cpuProfile_hWndSamples )
  116. {
  117. strcpy( titleBuff, "CPU Usage Snapshot" );
  118. if ( VProf_GetState() == VPROF_CPU )
  119. strcat( titleBuff, " [ON]" );
  120. SetWindowText( g_cpuProfile_hWndSamples, titleBuff );
  121. }
  122. if ( g_cpuProfile_hWndHistory )
  123. {
  124. strcpy( titleBuff, "CPU Usage History" );
  125. if ( VProf_GetState() == VPROF_CPU )
  126. strcat( titleBuff, " [ON]" );
  127. SetWindowText( g_cpuProfile_hWndHistory, titleBuff );
  128. }
  129. }
  130. //-----------------------------------------------------------------------------
  131. // CpuProfile_UpdateWindow
  132. //
  133. //-----------------------------------------------------------------------------
  134. void CpuProfile_UpdateWindow()
  135. {
  136. if ( g_cpuProfile_hWndSamples && !IsIconic( g_cpuProfile_hWndSamples ) )
  137. {
  138. // visible - force a client repaint
  139. InvalidateRect( g_cpuProfile_hWndSamples, NULL, true );
  140. }
  141. if ( g_cpuProfile_hWndHistory && !IsIconic( g_cpuProfile_hWndHistory ) )
  142. {
  143. // visible - force a client repaint
  144. InvalidateRect( g_cpuProfile_hWndHistory, NULL, true );
  145. }
  146. }
  147. //-----------------------------------------------------------------------------
  148. // rc_SetCpuProfile
  149. //
  150. //-----------------------------------------------------------------------------
  151. int rc_SetCpuProfile( char* commandPtr )
  152. {
  153. int i;
  154. char* cmdToken;
  155. int retAddr;
  156. int errCode = -1;
  157. xrProfile_t* localList;
  158. int profileList;
  159. int numProfiles;
  160. int retVal;
  161. // get numProfiles
  162. cmdToken = GetToken( &commandPtr );
  163. if ( !cmdToken[0] )
  164. goto cleanUp;
  165. sscanf( cmdToken,"%x",&numProfiles );
  166. // get profile attributes
  167. cmdToken = GetToken( &commandPtr );
  168. if ( !cmdToken[0] )
  169. goto cleanUp;
  170. sscanf( cmdToken, "%x", &profileList );
  171. // get retAddr
  172. cmdToken = GetToken( &commandPtr );
  173. if ( !cmdToken[0] )
  174. goto cleanUp;
  175. sscanf( cmdToken,"%x",&retAddr );
  176. localList = new xrProfile_t[numProfiles];
  177. memset( localList, 0, numProfiles*sizeof( xrProfile_t ) );
  178. // get the caller's profile list
  179. DmGetMemory( ( void* )profileList, numProfiles*sizeof( xrProfile_t ), localList, NULL );
  180. g_cpuProfile_numCounters = numProfiles;
  181. if ( g_cpuProfile_numCounters > PROFILE_MAXCOUNTERS-1 )
  182. g_cpuProfile_numCounters = PROFILE_MAXCOUNTERS-1;
  183. for ( i=0; i<g_cpuProfile_numCounters; i++ )
  184. {
  185. // swap the structure
  186. localList[i].color = BigDWord( localList[i].color );
  187. // clear the old counter
  188. memset( &g_cpuProfile_counters[i], 0, sizeof( profileCounter_t ) );
  189. V_strncpy( g_cpuProfile_counters[i].label, localList[i].labelString, sizeof( g_cpuProfile_counters[i].label ) );
  190. g_cpuProfile_counters[i].color = localList[i].color;
  191. }
  192. // build out the reserved last counter as total count
  193. memset( &g_cpuProfile_counters[g_cpuProfile_numCounters], 0, sizeof( profileCounter_t ) );
  194. strcpy( g_cpuProfile_counters[g_cpuProfile_numCounters].label, "Total" );
  195. g_cpuProfile_counters[i].color = RGB( 255,255,255 );
  196. g_cpuProfile_numCounters++;
  197. // set the return code
  198. retVal = g_cpuProfile_numCounters-1;
  199. int xboxRetVal = BigDWord( retVal );
  200. DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL );
  201. DebugCommand( "0x%8.8x = SetCpuProfile( 0x%8.8x, 0x%8.8x )\n", retVal, numProfiles, profileList );
  202. delete [] localList;
  203. // success
  204. errCode = 0;
  205. cleanUp:
  206. return ( errCode );
  207. }
  208. //-----------------------------------------------------------------------------
  209. // rc_SetCpuProfileData
  210. //
  211. //-----------------------------------------------------------------------------
  212. int rc_SetCpuProfileData( char* commandPtr )
  213. {
  214. int i;
  215. int total;
  216. char* cmdToken;
  217. int errCode = -1;
  218. int counters;
  219. int currentSample;
  220. bool newPeaks;
  221. unsigned int localCounters[PROFILE_MAXCOUNTERS];
  222. DWORD newTime;
  223. // get profiles
  224. cmdToken = GetToken( &commandPtr );
  225. if ( !cmdToken[0] )
  226. {
  227. goto cleanUp;
  228. }
  229. sscanf( cmdToken, "%x", &counters );
  230. // get the caller's profile list
  231. if ( g_cpuProfile_numCounters )
  232. {
  233. DmGetMemory( ( void* )counters, ( g_cpuProfile_numCounters-1 )*sizeof( int ), localCounters, NULL );
  234. }
  235. // timeout peaks
  236. newTime = Sys_GetSystemTime();
  237. if ( newTime - g_cpuProfile_lastPeakTime > PROFILE_SAMPLES_PEAKHOLDTIME )
  238. {
  239. g_cpuProfile_lastPeakTime = newTime;
  240. newPeaks = true;
  241. }
  242. else
  243. {
  244. newPeaks = false;
  245. }
  246. // next sample
  247. currentSample = g_cpuProfile_numSamples % PROFILE_MAXSAMPLES;
  248. g_cpuProfile_numSamples++;
  249. total = 0;
  250. for ( i=0; i<g_cpuProfile_numCounters; i++ )
  251. {
  252. // swap
  253. localCounters[i] = BigDWord( localCounters[i] );
  254. if ( i != g_cpuProfile_numCounters-1 )
  255. {
  256. g_cpuProfile_counters[i].samples[currentSample] = localCounters[i];
  257. total += localCounters[i];
  258. }
  259. else
  260. {
  261. // reserved total counter
  262. g_cpuProfile_counters[i].samples[currentSample] = total;
  263. }
  264. if ( newPeaks || g_cpuProfile_counters[i].peakSample < g_cpuProfile_counters[i].samples[currentSample] )
  265. {
  266. g_cpuProfile_counters[i].peakSample = g_cpuProfile_counters[i].samples[currentSample];
  267. }
  268. }
  269. DebugCommand( "SetCpuProfileData( 0x%8.8x )\n", counters );
  270. CpuProfile_UpdateWindow();
  271. // success
  272. errCode = 0;
  273. cleanUp:
  274. return ( errCode );
  275. }
  276. //-----------------------------------------------------------------------------
  277. // CpuProfile_ZoomIn
  278. //
  279. //-----------------------------------------------------------------------------
  280. void CpuProfile_ZoomIn( int& scale, int numSteps )
  281. {
  282. scale++;
  283. if ( scale > numSteps )
  284. {
  285. scale = numSteps;
  286. return;
  287. }
  288. CpuProfile_UpdateWindow();
  289. }
  290. //-----------------------------------------------------------------------------
  291. // CpuProfile_ZoomOut
  292. //
  293. //-----------------------------------------------------------------------------
  294. void CpuProfile_ZoomOut( int& scale, int numSteps )
  295. {
  296. scale--;
  297. if ( scale < -numSteps )
  298. {
  299. scale = -numSteps;
  300. return;
  301. }
  302. CpuProfile_UpdateWindow();
  303. }
  304. //-----------------------------------------------------------------------------
  305. // CpuProfile_CalcScale
  306. //
  307. //-----------------------------------------------------------------------------
  308. float CpuProfile_CalcScale( int scale, int numSteps, float min, float max )
  309. {
  310. float t;
  311. // from integral scale [-numSteps..numSteps] to float scale [min..max]
  312. t = ( float )( scale + numSteps )/( float )( 2*numSteps );
  313. t = min + t*( max-min );
  314. return t;
  315. }
  316. //-----------------------------------------------------------------------------
  317. // ProfileSamples_Draw
  318. //
  319. //-----------------------------------------------------------------------------
  320. void ProfileSamples_Draw( HDC hdc, RECT* clientRect )
  321. {
  322. int i;
  323. int j;
  324. int x;
  325. int y;
  326. int x0;
  327. int y0;
  328. int w;
  329. float t;
  330. float scale;
  331. float sampleTime;
  332. char labelBuff[128];
  333. HPEN hBlackPen;
  334. HPEN hPenOld;
  335. HPEN hGreyPen;
  336. HBRUSH hColoredBrush;
  337. HBRUSH hbrushOld;
  338. HFONT hFontOld;
  339. RECT rect;
  340. int currentSample;
  341. int numTicks;
  342. int timingWidth;
  343. int windowWidth;
  344. int windowHeight;
  345. hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) );
  346. hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) );
  347. hPenOld = ( HPEN )SelectObject( hdc, hBlackPen );
  348. hFontOld = SelectFont( hdc, g_hProportionalFont );
  349. SetBkColor( hdc, g_backgroundColor );
  350. // zoom
  351. scale = CpuProfile_CalcScale( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS, PROFILE_SAMPLES_MINSCALE, PROFILE_SAMPLES_MAXSCALE );
  352. timingWidth = ( int )( PROFILE_SAMPLES_TIMINGWIDTH*scale );
  353. windowWidth = clientRect->right-clientRect->left;
  354. windowHeight = clientRect->bottom-clientRect->top;
  355. numTicks = ( windowWidth-PROFILE_SAMPLES_LABELWIDTH )/timingWidth + 1;
  356. if ( numTicks < 0 )
  357. numTicks = 1;
  358. rect.left = 0;
  359. rect.right = PROFILE_SAMPLES_LABELWIDTH;
  360. rect.top = 0;
  361. rect.bottom = PROFILE_SAMPLES_ITEMHEIGHT;
  362. DrawText( hdc, "Name", -1, &rect, DT_LEFT );
  363. // draw timing ticks
  364. x = PROFILE_SAMPLES_LABELWIDTH;
  365. y = 0;
  366. for ( i=0; i<numTicks; i++ )
  367. {
  368. // tick labels
  369. rect.left = x-40;
  370. rect.right = x+40;
  371. rect.top = y;
  372. rect.bottom = y+PROFILE_SAMPLES_ITEMHEIGHT;
  373. if ( !g_cpuProfile_fpsLabels )
  374. sprintf( labelBuff, "%.2fms", i*( 1000.0f/60.0f ) );
  375. else
  376. sprintf( labelBuff, "%.2ffps", i == 0 ? 0 : 60.0f/i );
  377. DrawText( hdc, labelBuff, -1, &rect, DT_CENTER );
  378. // major ticks
  379. x0 = x;
  380. y0 = y + PROFILE_SAMPLES_ITEMHEIGHT;
  381. SelectObject( hdc, hBlackPen );
  382. MoveToEx( hdc, x0, y0, NULL );
  383. LineTo( hdc, x0, y0+windowHeight );
  384. if ( g_cpuProfile_samples_tickMarks && g_cpuProfile_samples_scale > -PROFILE_SAMPLES_SCALESTEPS )
  385. {
  386. // minor ticks
  387. x0 = x;
  388. y0 = y + PROFILE_SAMPLES_ITEMHEIGHT;
  389. SelectObject( hdc, hGreyPen );
  390. for ( j=0; j<PROFILE_SAMPLES_NUMMINORTICKS; j++ )
  391. {
  392. x0 += timingWidth/( PROFILE_SAMPLES_NUMMINORTICKS+1 );
  393. MoveToEx( hdc, x0, y0, NULL );
  394. LineTo( hdc, x0, y0+windowHeight );
  395. }
  396. }
  397. x += timingWidth;
  398. }
  399. // seperator
  400. SelectObject( hdc, hBlackPen );
  401. MoveToEx( hdc, 0, PROFILE_SAMPLES_ITEMHEIGHT, NULL );
  402. LineTo( hdc, windowWidth, PROFILE_SAMPLES_ITEMHEIGHT );
  403. // draw labels
  404. x = 0;
  405. y = PROFILE_SAMPLES_ITEMHEIGHT;
  406. for ( i=0; i<g_cpuProfile_numCounters; i++ )
  407. {
  408. if ( !g_cpuProfile_counters[i].label )
  409. continue;
  410. rect.left = x;
  411. rect.right = x+PROFILE_SAMPLES_LABELWIDTH-PROFILE_SAMPLES_LABELGAP;
  412. rect.top = y;
  413. rect.bottom = y+PROFILE_SAMPLES_ITEMHEIGHT;
  414. DrawText( hdc, g_cpuProfile_counters[i].label, -1, &rect, DT_VCENTER|DT_RIGHT|DT_SINGLELINE|DT_END_ELLIPSIS|DT_MODIFYSTRING );
  415. // draw the under line
  416. MoveToEx( hdc, x, y+PROFILE_SAMPLES_ITEMHEIGHT, NULL );
  417. LineTo( hdc, x+PROFILE_SAMPLES_LABELWIDTH, y+PROFILE_SAMPLES_ITEMHEIGHT );
  418. y += PROFILE_SAMPLES_ITEMHEIGHT;
  419. }
  420. // draw bars
  421. SelectObject( hdc, hBlackPen );
  422. x = PROFILE_SAMPLES_LABELWIDTH;
  423. y = PROFILE_SAMPLES_ITEMHEIGHT;
  424. currentSample = g_cpuProfile_numSamples-1;
  425. if ( currentSample < 0 )
  426. currentSample = 0;
  427. else
  428. currentSample %= PROFILE_MAXSAMPLES;
  429. for ( i=0; i<g_cpuProfile_numCounters; i++ )
  430. {
  431. if ( !g_cpuProfile_counters[i].label )
  432. continue;
  433. hColoredBrush = CreateSolidBrush( g_cpuProfile_samples_colors ? g_cpuProfile_counters[i].color : g_backgroundColor );
  434. hbrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush );
  435. // bar - count is in us i.e. 1 major tick = 16667us
  436. t = ( float )g_cpuProfile_counters[i].samples[currentSample]/( 1000000.0f/60.0f );
  437. w = ( int )( t * ( float )timingWidth );
  438. if ( w > windowWidth )
  439. w = windowWidth;
  440. x0 = x;
  441. y0 = y + ( PROFILE_SAMPLES_ITEMHEIGHT-PROFILE_SAMPLES_BARHEIGHT )/2 + 1;
  442. Rectangle( hdc, x0, y0, x0 + w, y0 + PROFILE_SAMPLES_BARHEIGHT );
  443. // peak
  444. t = ( float )g_cpuProfile_counters[i].peakSample/( 1000000.0f/60.0f );
  445. w = ( int )( t * ( float )timingWidth );
  446. if ( w > windowWidth )
  447. w = windowWidth;
  448. x0 = x + w;
  449. y0 = y + PROFILE_SAMPLES_ITEMHEIGHT/2 + 1;
  450. POINT points[4];
  451. points[0].x = x0;
  452. points[0].y = y0-4;
  453. points[1].x = x0+4;
  454. points[1].y = y0;
  455. points[2].x = x0;
  456. points[2].y = y0+4;
  457. points[3].x = x0-4;
  458. points[3].y = y0;
  459. Polygon( hdc, points, 4 );
  460. SelectObject( hdc, hbrushOld );
  461. DeleteObject( hColoredBrush );
  462. // draw peak times
  463. sampleTime = ( float )g_cpuProfile_counters[i].peakSample/1000.0f;
  464. if ( sampleTime >= 0.01F )
  465. {
  466. sprintf( labelBuff, "%.2f", sampleTime );
  467. rect.left = x0 + 8;
  468. rect.right = x0 + 8 + 100;
  469. rect.top = y;
  470. rect.bottom = y + PROFILE_SAMPLES_ITEMHEIGHT;
  471. DrawText( hdc, labelBuff, -1, &rect, DT_VCENTER|DT_LEFT|DT_SINGLELINE );
  472. }
  473. y += PROFILE_SAMPLES_ITEMHEIGHT;
  474. }
  475. SelectObject( hdc, hFontOld );
  476. SelectObject( hdc, hPenOld );
  477. DeleteObject( hBlackPen );
  478. DeleteObject( hGreyPen );
  479. }
  480. //-----------------------------------------------------------------------------
  481. // ProfileHistory_Draw
  482. //
  483. //-----------------------------------------------------------------------------
  484. void ProfileHistory_Draw( HDC hdc, RECT* clientRect )
  485. {
  486. char labelBuff[128];
  487. HPEN hBlackPen;
  488. HPEN hPenOld;
  489. HPEN hNullPen;
  490. HPEN hGreyPen;
  491. HBRUSH hColoredBrush;
  492. HBRUSH hBrushOld;
  493. HFONT hFontOld;
  494. int currentSample;
  495. int numTicks;
  496. int timingHeight;
  497. int windowWidth;
  498. int windowHeight;
  499. int x;
  500. int y;
  501. int y0;
  502. int i;
  503. int j;
  504. int h;
  505. int numbars;
  506. RECT rect;
  507. float t;
  508. float scale;
  509. hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) );
  510. hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) );
  511. hNullPen = CreatePen( PS_NULL, 0, RGB( 0,0,0 ) );
  512. hPenOld = ( HPEN )SelectObject( hdc, hBlackPen );
  513. hFontOld = SelectFont( hdc, g_hProportionalFont );
  514. // zoom
  515. scale = CpuProfile_CalcScale( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS, PROFILE_HISTORY_MINSCALE, PROFILE_HISTORY_MAXSCALE );
  516. timingHeight = ( int )( PROFILE_HISTORY_TIMINGHEIGHT*scale );
  517. windowWidth = clientRect->right-clientRect->left;
  518. windowHeight = clientRect->bottom-clientRect->top;
  519. numTicks = windowHeight/timingHeight + 2;
  520. if ( numTicks < 0 )
  521. numTicks = 1;
  522. SetBkColor( hdc, g_backgroundColor );
  523. x = 0;
  524. y = windowHeight;
  525. for ( i=0; i<numTicks; i++ )
  526. {
  527. // major ticks
  528. SelectObject( hdc, hBlackPen );
  529. MoveToEx( hdc, 0, y, NULL );
  530. LineTo( hdc, windowWidth, y );
  531. if ( g_cpuProfile_history_tickMarks && g_cpuProfile_history_scale > -PROFILE_HISTORY_SCALESTEPS )
  532. {
  533. // minor ticks
  534. y0 = y;
  535. SelectObject( hdc, hGreyPen );
  536. for ( j=0; j<PROFILE_HISTORY_NUMMINORTICKS; j++ )
  537. {
  538. y0 += timingHeight/( PROFILE_SAMPLES_NUMMINORTICKS+1 );
  539. MoveToEx( hdc, 0, y0, NULL );
  540. LineTo( hdc, windowWidth, y0 );
  541. }
  542. }
  543. // tick labels
  544. if ( i )
  545. {
  546. rect.left = windowWidth-50;
  547. rect.right = windowWidth;
  548. rect.top = y-20;
  549. rect.bottom = y;
  550. if ( !g_cpuProfile_fpsLabels )
  551. sprintf( labelBuff, "%.2fms", i*( 1000.0f/60.0f ) );
  552. else
  553. sprintf( labelBuff, "%.2ffps", 60.0f/i );
  554. DrawText( hdc, labelBuff, -1, &rect, DT_RIGHT|DT_SINGLELINE|DT_BOTTOM );
  555. }
  556. y -= timingHeight;
  557. }
  558. // vertical bars
  559. if ( g_cpuProfile_numSamples )
  560. {
  561. SelectObject( hdc, hNullPen );
  562. numbars = windowWidth-PROFILE_HISTORY_LABELWIDTH;
  563. currentSample = g_cpuProfile_numSamples-1;
  564. for ( x=numbars-1; x>=0; x-=4 )
  565. {
  566. // all the counters at this sample
  567. y = windowHeight;
  568. for ( j=0; j<g_cpuProfile_numCounters-1; j++ )
  569. {
  570. if ( !g_cpuProfile_counters[j].label )
  571. continue;
  572. t = ( float )g_cpuProfile_counters[j].samples[currentSample % PROFILE_MAXSAMPLES]/( 1000000.0f/60.0f );
  573. h = ( int )( t * ( float )timingHeight );
  574. if ( h )
  575. {
  576. if ( h > windowHeight )
  577. h = windowHeight;
  578. hColoredBrush = CreateSolidBrush( g_cpuProfile_history_colors ? g_cpuProfile_counters[j].color : RGB( 80,80,80 ) );
  579. hBrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush );
  580. Rectangle( hdc, x-4, y-h, x, y+1 );
  581. y -= h;
  582. SelectObject( hdc, hBrushOld );
  583. DeleteObject( hColoredBrush );
  584. }
  585. }
  586. currentSample--;
  587. if ( currentSample < 0 )
  588. {
  589. // no data
  590. break;
  591. }
  592. }
  593. }
  594. SelectObject( hdc, hFontOld );
  595. SelectObject( hdc, hPenOld );
  596. DeleteObject( hBlackPen );
  597. DeleteObject( hGreyPen );
  598. }
  599. //-----------------------------------------------------------------------------
  600. // CpuProfile_WndProc
  601. //
  602. //-----------------------------------------------------------------------------
  603. LRESULT CALLBACK CpuProfile_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  604. {
  605. WORD wID = LOWORD( wParam );
  606. HDC hdc;
  607. PAINTSTRUCT ps;
  608. RECT rect;
  609. int id;
  610. bool bIsSamples;
  611. bool bIsHistory;
  612. CREATESTRUCT *createStructPtr;
  613. // identify window
  614. id = ( int )GetWindowLong( hwnd, GWL_USERDATA+0 );
  615. bIsSamples = ( id == ID_CPUPROFILE_SAMPLES );
  616. bIsHistory = ( id == ID_CPUPROFILE_HISTORY );
  617. switch ( message )
  618. {
  619. case WM_CREATE:
  620. // set the window identifier
  621. createStructPtr = ( CREATESTRUCT* )lParam;
  622. SetWindowLong( hwnd, GWL_USERDATA+0, ( LONG )createStructPtr->lpCreateParams );
  623. // reset peaks
  624. g_cpuProfile_lastPeakTime = 0;
  625. return 0L;
  626. case WM_DESTROY:
  627. CpuProfile_SaveConfig();
  628. if ( bIsSamples )
  629. g_cpuProfile_hWndSamples = NULL;
  630. else if ( bIsHistory )
  631. g_cpuProfile_hWndHistory = NULL;
  632. if ( VProf_GetState() == VPROF_CPU )
  633. {
  634. VProf_Enable( VPROF_OFF );
  635. }
  636. return 0L;
  637. case WM_INITMENU:
  638. if ( bIsSamples )
  639. {
  640. CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_cpuProfile_samples_tickMarks ? MF_CHECKED : MF_UNCHECKED ) );
  641. CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_COLORS, MF_BYCOMMAND | ( g_cpuProfile_samples_colors ? MF_CHECKED : MF_UNCHECKED ) );
  642. }
  643. else if ( bIsHistory )
  644. {
  645. CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_cpuProfile_history_tickMarks ? MF_CHECKED : MF_UNCHECKED ) );
  646. CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_COLORS, MF_BYCOMMAND | ( g_cpuProfile_history_colors ? MF_CHECKED : MF_UNCHECKED ) );
  647. }
  648. CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_FPSLABELS, MF_BYCOMMAND | ( g_cpuProfile_fpsLabels ? MF_CHECKED : MF_UNCHECKED ) );
  649. CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_ENABLE, MF_BYCOMMAND | ( VProf_GetState() == VPROF_CPU ? MF_CHECKED : MF_UNCHECKED ) );
  650. return 0L;
  651. case WM_PAINT:
  652. GetClientRect( hwnd, &rect );
  653. hdc = BeginPaint( hwnd, &ps );
  654. if ( bIsSamples )
  655. ProfileSamples_Draw( hdc, &rect );
  656. else if ( bIsHistory )
  657. ProfileHistory_Draw( hdc, &rect );
  658. EndPaint( hwnd, &ps );
  659. return 0L;
  660. case WM_SIZE:
  661. // force a redraw
  662. CpuProfile_UpdateWindow();
  663. return 0L;
  664. case WM_KEYDOWN:
  665. switch ( wParam )
  666. {
  667. case VK_INSERT:
  668. if ( bIsSamples )
  669. CpuProfile_ZoomIn( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS );
  670. else if ( bIsHistory )
  671. CpuProfile_ZoomIn( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS );
  672. return 0L;
  673. case VK_DELETE:
  674. if ( bIsSamples )
  675. CpuProfile_ZoomOut( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS );
  676. else if ( bIsHistory )
  677. CpuProfile_ZoomOut( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS );
  678. return 0L;
  679. }
  680. break;
  681. case WM_COMMAND:
  682. switch ( wID )
  683. {
  684. case IDM_CPUPROFILE_TICKMARKS:
  685. if ( bIsSamples )
  686. g_cpuProfile_samples_tickMarks ^= 1;
  687. else if ( bIsHistory )
  688. g_cpuProfile_history_tickMarks ^= 1;
  689. CpuProfile_UpdateWindow();
  690. return 0L;
  691. case IDM_CPUPROFILE_COLORS:
  692. if ( bIsSamples )
  693. g_cpuProfile_samples_colors ^= 1;
  694. else if ( bIsHistory )
  695. g_cpuProfile_history_colors ^= 1;
  696. CpuProfile_UpdateWindow();
  697. return 0L;
  698. case IDM_CPUPROFILE_FPSLABELS:
  699. g_cpuProfile_fpsLabels ^= 1;
  700. CpuProfile_UpdateWindow();
  701. return 0L;
  702. case IDM_CPUPROFILE_ZOOMIN:
  703. if ( bIsSamples )
  704. CpuProfile_ZoomIn( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS );
  705. else if ( bIsHistory )
  706. CpuProfile_ZoomIn( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS );
  707. return 0L;
  708. case IDM_CPUPROFILE_ZOOMOUT:
  709. if ( bIsSamples )
  710. CpuProfile_ZoomOut( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS );
  711. else if ( bIsHistory )
  712. CpuProfile_ZoomOut( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS );
  713. return 0L;
  714. case IDM_CPUPROFILE_ENABLE:
  715. bool bEnable = ( VProf_GetState() == VPROF_CPU );
  716. bEnable ^= 1;
  717. if ( !bEnable )
  718. VProf_Enable( VPROF_OFF );
  719. else
  720. VProf_Enable( VPROF_CPU );
  721. CpuProfile_SetTitle();
  722. return 0L;
  723. }
  724. break;
  725. }
  726. return ( DefWindowProc( hwnd, message, wParam, lParam ) );
  727. }
  728. //-----------------------------------------------------------------------------
  729. // CpuProfileHistory_Open
  730. //
  731. //-----------------------------------------------------------------------------
  732. void CpuProfileHistory_Open()
  733. {
  734. HWND hWnd;
  735. if ( g_cpuProfile_hWndHistory )
  736. {
  737. // only one profile instance
  738. if ( IsIconic( g_cpuProfile_hWndHistory ) )
  739. ShowWindow( g_cpuProfile_hWndHistory, SW_RESTORE );
  740. SetForegroundWindow( g_cpuProfile_hWndHistory );
  741. return;
  742. }
  743. if ( VProf_GetState() == VPROF_OFF )
  744. {
  745. VProf_Enable( VPROF_CPU );
  746. }
  747. hWnd = CreateWindowEx(
  748. WS_EX_CLIENTEDGE,
  749. "CPUPROFILEHISTORYCLASS",
  750. "",
  751. WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
  752. 0,
  753. 0,
  754. 600,
  755. 500,
  756. g_hDlgMain,
  757. NULL,
  758. g_hInstance,
  759. ( void* )ID_CPUPROFILE_HISTORY );
  760. g_cpuProfile_hWndHistory = hWnd;
  761. CpuProfile_SetTitle();
  762. if ( g_cpuProfile_historyWindowRect.right && g_cpuProfile_historyWindowRect.bottom )
  763. MoveWindow( g_cpuProfile_hWndHistory, g_cpuProfile_historyWindowRect.left, g_cpuProfile_historyWindowRect.top, g_cpuProfile_historyWindowRect.right-g_cpuProfile_historyWindowRect.left, g_cpuProfile_historyWindowRect.bottom-g_cpuProfile_historyWindowRect.top, FALSE );
  764. ShowWindow( g_cpuProfile_hWndHistory, SHOW_OPENWINDOW );
  765. }
  766. //-----------------------------------------------------------------------------
  767. // CpuProfileSamples_Open
  768. //
  769. //-----------------------------------------------------------------------------
  770. void CpuProfileSamples_Open()
  771. {
  772. HWND hWnd;
  773. if ( g_cpuProfile_hWndSamples )
  774. {
  775. // only one profile instance
  776. if ( IsIconic( g_cpuProfile_hWndSamples ) )
  777. ShowWindow( g_cpuProfile_hWndSamples, SW_RESTORE );
  778. SetForegroundWindow( g_cpuProfile_hWndSamples );
  779. return;
  780. }
  781. if ( VProf_GetState() == VPROF_OFF )
  782. {
  783. VProf_Enable( VPROF_CPU );
  784. }
  785. hWnd = CreateWindowEx(
  786. WS_EX_CLIENTEDGE,
  787. "CPUPROFILESAMPLESCLASS",
  788. "",
  789. WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
  790. 0,
  791. 0,
  792. 600,
  793. 500,
  794. g_hDlgMain,
  795. NULL,
  796. g_hInstance,
  797. ( void* )ID_CPUPROFILE_SAMPLES );
  798. g_cpuProfile_hWndSamples = hWnd;
  799. CpuProfile_SetTitle();
  800. if ( g_cpuProfile_samplesWindowRect.right && g_cpuProfile_samplesWindowRect.bottom )
  801. MoveWindow( g_cpuProfile_hWndSamples, g_cpuProfile_samplesWindowRect.left, g_cpuProfile_samplesWindowRect.top, g_cpuProfile_samplesWindowRect.right-g_cpuProfile_samplesWindowRect.left, g_cpuProfile_samplesWindowRect.bottom-g_cpuProfile_samplesWindowRect.top, FALSE );
  802. ShowWindow( g_cpuProfile_hWndSamples, SHOW_OPENWINDOW );
  803. }
  804. //-----------------------------------------------------------------------------
  805. // CpuProfile_Clear
  806. //
  807. //-----------------------------------------------------------------------------
  808. void CpuProfile_Clear()
  809. {
  810. // clear counters and history
  811. g_cpuProfile_numCounters = 0;
  812. g_cpuProfile_numSamples = 0;
  813. CpuProfile_UpdateWindow();
  814. }
  815. //-----------------------------------------------------------------------------
  816. // CpuProfile_Init
  817. //
  818. //-----------------------------------------------------------------------------
  819. bool CpuProfile_Init()
  820. {
  821. WNDCLASS wndclass;
  822. // set up our window class
  823. memset( &wndclass, 0, sizeof( wndclass ) );
  824. wndclass.style = 0;
  825. wndclass.lpfnWndProc = CpuProfile_WndProc;
  826. wndclass.cbClsExtra = 0;
  827. wndclass.cbWndExtra = 0;
  828. wndclass.hInstance = g_hInstance;
  829. wndclass.hIcon = g_hIcons[ICON_APPLICATION];
  830. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  831. wndclass.hbrBackground = g_hBackgroundBrush;
  832. wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_CPUPROFILE );
  833. wndclass.lpszClassName = "CPUPROFILESAMPLESCLASS";
  834. if ( !RegisterClass( &wndclass ) )
  835. return false;
  836. // set up our window class
  837. memset( &wndclass, 0, sizeof( wndclass ) );
  838. wndclass.style = 0;
  839. wndclass.lpfnWndProc = CpuProfile_WndProc;
  840. wndclass.cbClsExtra = 0;
  841. wndclass.cbWndExtra = 0;
  842. wndclass.hInstance = g_hInstance;
  843. wndclass.hIcon = g_hIcons[ICON_APPLICATION];
  844. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  845. wndclass.hbrBackground = g_hBackgroundBrush;
  846. wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_CPUPROFILE );
  847. wndclass.lpszClassName = "CPUPROFILEHISTORYCLASS";
  848. if ( !RegisterClass( &wndclass ) )
  849. return false;
  850. CpuProfile_LoadConfig();
  851. return true;
  852. }