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.

1155 lines
29 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: VGUI scoreboard
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "client_pch.h"
  10. #include "vgui_vprofpanel.h"
  11. #include <KeyValues.h>
  12. #include "vgui_budgetpanel.h"
  13. #include "vprof_engine.h"
  14. #include "vprof_record.h"
  15. #include "ivideomode.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. using namespace vgui;
  19. // positions
  20. #define VPROF_INDENT_X XRES(20)
  21. #define VPROF_INDENT_Y YRES(10)
  22. // Scoreboard dimensions
  23. #define VPROF_TITLE_SIZE_Y YRES(22)
  24. #define X_BORDER XRES(4)
  25. #define Y_BORDER YRES(4)
  26. static ConVar vprof_verbose( "vprof_verbose", "1", FCVAR_ARCHIVE, "Set to one to show average and peak times" );
  27. static ConVar vprof_unaccounted_limit( "vprof_unaccounted_limit", "0.3", FCVAR_ARCHIVE,
  28. "number of milliseconds that a node must exceed to turn red in the vprof panel" );
  29. static ConVar vprof_warningmsec( "vprof_warningmsec", "10", FCVAR_ARCHIVE, "Above this many milliseconds render the label red to indicate slow code." );
  30. #ifdef VPROF_ENABLED
  31. //-----------------------------------------------------------------------------
  32. // Singleton accessor
  33. //-----------------------------------------------------------------------------
  34. static CVProfPanel *g_pVProfPanel = NULL;
  35. CVProfPanel *GetVProfPanel( void )
  36. {
  37. return g_pVProfPanel;
  38. }
  39. static void ClearNodeClientData( CVProfNode *pNode )
  40. {
  41. pNode->SetClientData( -1 );
  42. if( pNode->GetSibling() )
  43. {
  44. ClearNodeClientData( pNode->GetSibling() );
  45. }
  46. if( pNode->GetChild() )
  47. {
  48. ClearNodeClientData( pNode->GetChild() );
  49. }
  50. }
  51. void CVProfPanel::Reset()
  52. {
  53. m_pHierarchy->RemoveAll();
  54. m_RootItem = -1;
  55. ClearNodeClientData( m_pVProfile->GetRoot() );
  56. }
  57. CON_COMMAND( vprof_expand_all, "Expand the whole vprof tree" )
  58. {
  59. Msg("VProf expand all.\n");
  60. GetVProfPanel()->ExpandAll();
  61. }
  62. CON_COMMAND( vprof_collapse_all, "Collapse the whole vprof tree" )
  63. {
  64. Msg("VProf collapse all.\n");
  65. GetVProfPanel()->CollapseAll();
  66. }
  67. CON_COMMAND( vprof_expand_group, "Expand a budget group in the vprof tree by name" )
  68. {
  69. Msg("VProf expand group.\n");
  70. if ( args.ArgC() >= 2 )
  71. {
  72. GetVProfPanel()->ExpandGroup( args[ 1 ] );
  73. }
  74. }
  75. void IN_VProfDown(void)
  76. {
  77. GetVProfPanel()->UserCmd_ShowVProf();
  78. }
  79. void IN_VProfUp(void)
  80. {
  81. GetVProfPanel()->UserCmd_HideVProf();
  82. }
  83. static ConCommand startshowvprof("+showvprof", IN_VProfDown);
  84. static ConCommand endshowvprof("-showvprof", IN_VProfUp);
  85. void ChangeVProfScopeCallback( IConVar *pConVar, const char *pOldString, float flOldValue )
  86. {
  87. ConVarRef var( pConVar );
  88. Msg( "VProf setting scope to %s\n", var.GetString( ) );
  89. if ( g_pVProfPanel )
  90. {
  91. g_pVProfPanel->Reset();
  92. }
  93. }
  94. ConVar vprof_scope(
  95. "vprof_scope",
  96. "",
  97. 0,
  98. "Set a specific scope to start showing vprof tree",
  99. 0, 0, 0, 0,
  100. ChangeVProfScopeCallback );
  101. #define PROF_FONT "DefaultFixed"
  102. class CProfileTree : public TreeView
  103. {
  104. DECLARE_CLASS_SIMPLE( CProfileTree, TreeView );
  105. public:
  106. CProfileTree( CVProfPanel *parent, const char *panelName );
  107. ~CProfileTree();
  108. virtual void OnCommand( const char *cmd );
  109. virtual void InvalidateLayout( bool layoutNow = false, bool reloadScheme = false );
  110. virtual void ApplySchemeSettings( IScheme *pScheme )
  111. {
  112. BaseClass::ApplySchemeSettings( pScheme );
  113. SetFont( pScheme->GetFont( PROF_FONT ) );
  114. }
  115. virtual void SetBgColor( Color color )
  116. {
  117. BaseClass::SetBgColor( color );
  118. }
  119. private:
  120. Menu *m_pEditMenu;
  121. CVProfPanel *m_pParent;
  122. };
  123. CProfileTree::CProfileTree( CVProfPanel *parent, const char *panelName ) :
  124. BaseClass( (Panel *)parent, panelName ),
  125. m_pEditMenu( 0 ),
  126. m_pParent( parent )
  127. {
  128. }
  129. CProfileTree::~CProfileTree()
  130. {
  131. delete m_pEditMenu;
  132. }
  133. void CProfileTree::InvalidateLayout( bool layoutNow, bool reloadScheme )
  134. {
  135. BaseClass::InvalidateLayout( layoutNow, reloadScheme );
  136. if ( GetParent() )
  137. {
  138. GetParent()->InvalidateLayout( layoutNow, reloadScheme );
  139. }
  140. }
  141. void CProfileTree::OnCommand( const char *cmd )
  142. {
  143. // Relay to parent
  144. GetParent()->OnCommand( cmd );
  145. }
  146. CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t() :
  147. treeViewItem( -1 )
  148. {
  149. }
  150. CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t( const ColumnPanels_t& src )
  151. {
  152. treeViewItem = src.treeViewItem;
  153. int c = src.m_Columns.Count();
  154. for ( int i = 0; i < c; ++i )
  155. {
  156. PanelEntry_t pe;
  157. pe.dataname = src.m_Columns[ i ].dataname;
  158. pe.label = src.m_Columns[ i ].label;
  159. m_Columns.AddToTail( pe );
  160. }
  161. }
  162. void CProfileHierarchyPanel::ColumnPanels_t::AddColumn( int index, const char *name, vgui::Label *label )
  163. {
  164. m_Columns.EnsureCount( index + 1 );
  165. m_Columns[ index ].label = label;
  166. m_Columns[ index ].dataname = name;
  167. }
  168. void CProfileHierarchyPanel::ColumnPanels_t::Refresh( KeyValues *kv )
  169. {
  170. VPROF( "CProfileHierarchyPanel::ColumnPanels_t" );
  171. int c = m_Columns.Count();
  172. for ( int i = 0; i < c; ++i )
  173. {
  174. vgui::Label *label = m_Columns[ i ].label;
  175. if ( !label )
  176. continue;
  177. const char *name = m_Columns[ i ].dataname.String();
  178. if ( name && name[ 0 ] )
  179. {
  180. const char *value = kv->GetString( name, "" );
  181. if ( value )
  182. {
  183. if ( !value[ 0 ] )
  184. {
  185. label->SetText( "" );
  186. label->SetVisible( false );
  187. }
  188. else
  189. {
  190. label->SetVisible( true );
  191. label->SetText( value );
  192. }
  193. }
  194. else
  195. {
  196. label->SetVisible( false );
  197. }
  198. }
  199. }
  200. }
  201. CProfileHierarchyPanel::CProfileHierarchyPanel(vgui::Panel *parent, const char *panelName)
  202. : BaseClass(parent,panelName),
  203. m_Panels( 0, 0, PanelsLessFunc )
  204. {
  205. }
  206. CProfileHierarchyPanel::~CProfileHierarchyPanel()
  207. {
  208. }
  209. void CProfileHierarchyPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  210. {
  211. //SetProportional( true );
  212. BaseClass::ApplySchemeSettings( pScheme );
  213. m_itemFont = pScheme->GetFont( PROF_FONT );
  214. SetTitleBarInfo( m_itemFont, 20 );
  215. SetBgColor( Color(0, 0, 0, 176) );
  216. (( CProfileTree *)GetTree())->SetBgColor( Color( 0, 0, 0, 176 ) );
  217. }
  218. void CProfileHierarchyPanel::SetItemColors( int id, const Color& fg, const Color& bg )
  219. {
  220. VPROF( "CProfileHierarchyPanel::SetItemColors" );
  221. GetTree()->SetItemFgColor( id, fg );
  222. GetTree()->SetItemBgColor( id, bg );
  223. ColumnPanels_t search;
  224. search.treeViewItem = id;
  225. int idx = m_Panels.Find( search );
  226. if ( idx == m_Panels.InvalidIndex() )
  227. {
  228. return;
  229. }
  230. ColumnPanels_t& info = m_Panels[ idx ];
  231. int c = info.m_Columns.Count();
  232. for ( int i = 0; i < c; ++i )
  233. {
  234. Label *label = info.m_Columns[ i ].label;
  235. if ( !label )
  236. continue;
  237. label->SetFgColor( fg );
  238. label->SetBgColor( bg );
  239. }
  240. }
  241. void CProfileHierarchyPanel::SetItemColumnColors( int id, int col, const Color& fg, const Color& bg )
  242. {
  243. VPROF( "CProfileHierarchyPanel::SetItemColumnColors" );
  244. ColumnPanels_t search;
  245. search.treeViewItem = id;
  246. int idx = m_Panels.Find( search );
  247. if ( idx == m_Panels.InvalidIndex() )
  248. {
  249. return;
  250. }
  251. ColumnPanels_t& info = m_Panels[ idx ];
  252. int c = info.m_Columns.Count();
  253. if ( col < 0 || col >= c )
  254. return;
  255. Label *label = info.m_Columns[ col ].label;
  256. if ( !label )
  257. return;
  258. label->SetFgColor( fg );
  259. label->SetBgColor( bg );
  260. }
  261. void CProfileHierarchyPanel::ModifyItem( KeyValues *data, int itemIndex )
  262. {
  263. GetTree()->SetItemFgColor( itemIndex, GetFgColor() );
  264. GetTree()->SetItemBgColor( itemIndex, GetBgColor() );
  265. ColumnPanels_t search;
  266. search.treeViewItem = itemIndex;
  267. int idx = m_Panels.Find( search );
  268. if ( idx == m_Panels.InvalidIndex() )
  269. {
  270. Assert( 0 );
  271. return;
  272. }
  273. ColumnPanels_t& info = m_Panels[ idx ];
  274. info.Refresh( data );
  275. }
  276. int CProfileHierarchyPanel::AddItem( KeyValues *data, int parentItemIndex, ColumnPanels_t& columnPanels )
  277. {
  278. int itemIndex = GetTree()->AddItem( data, parentItemIndex );
  279. columnPanels.treeViewItem = itemIndex;
  280. ColumnPanels_t search;
  281. search.treeViewItem = itemIndex;
  282. int idx = m_Panels.Find( search );
  283. if ( idx == m_Panels.InvalidIndex() )
  284. {
  285. m_Panels.Insert( columnPanels );
  286. int c = columnPanels.m_Columns.Count();
  287. for ( int i = 0; i < c; ++i )
  288. {
  289. if ( columnPanels.m_Columns[ i ].label )
  290. {
  291. columnPanels.m_Columns[ i ].label->SetParent( this );
  292. }
  293. }
  294. }
  295. ModifyItem( data, itemIndex );
  296. return itemIndex;
  297. }
  298. void CProfileHierarchyPanel::PostChildPaint()
  299. {
  300. }
  301. void CProfileHierarchyPanel::PerformLayout()
  302. {
  303. VPROF( "CProfileHierarchyPanel::PerformLayout" );
  304. BaseClass::PerformLayout();
  305. // Assume all invisible at first
  306. HideAll();
  307. int tall = GetTall();
  308. int rowheight = GetTree()->GetRowHeight();
  309. int top, visitems;
  310. bool hbarVisible = false;
  311. GetTree()->GetVBarInfo( top, visitems, hbarVisible );
  312. int offset = -top * rowheight;
  313. int numColumns = GetNumColumns();
  314. // Now position column panels into the correct spot
  315. int rows = GetNumRows();
  316. for ( int row = 0; row < rows; ++row )
  317. {
  318. int tvi = GetTreeItemAtRow( row );
  319. for ( int col = 0; col < numColumns; ++col )
  320. {
  321. int left, right, bottom;
  322. GetGridElementBounds( col, row, left, top, right, bottom );
  323. ColumnPanels_t search;
  324. search.treeViewItem = tvi;
  325. int idx = m_Panels.Find( search );
  326. if ( idx != m_Panels.InvalidIndex() )
  327. {
  328. ColumnPanels_t& info = m_Panels[ idx ];
  329. if ( col >= info.m_Columns.Count() )
  330. continue;
  331. vgui::Label *p = info.m_Columns[ col ].label;
  332. if ( !p )
  333. {
  334. continue;
  335. }
  336. bool vis = ( top + offset - 20 ) >= 0 && ( bottom + offset ) < tall;
  337. p->SetParent( vis ? this : NULL );
  338. p->SetVisible( vis );
  339. p->SetBounds( left, top + offset, right - left, bottom - top );
  340. p->InvalidateLayout();
  341. }
  342. else
  343. {
  344. Assert( 0 );
  345. }
  346. }
  347. }
  348. }
  349. void CProfileHierarchyPanel::HideAll()
  350. {
  351. for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) )
  352. {
  353. ColumnPanels_t& info = m_Panels[ i ];
  354. int c = info.m_Columns.Count();
  355. for ( int j = 0 ; j < c; ++j )
  356. {
  357. Label *panel = info.m_Columns[ j ].label;
  358. if ( !panel )
  359. {
  360. continue;
  361. }
  362. panel->SetVisible( false );
  363. }
  364. }
  365. }
  366. void CProfileHierarchyPanel::RemoveAll()
  367. {
  368. GetTree()->RemoveAll();
  369. for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) )
  370. {
  371. ColumnPanels_t& info = m_Panels[ i ];
  372. int c = info.m_Columns.Count();
  373. for ( int j = 0 ; j < c; ++j )
  374. {
  375. delete info.m_Columns[ j ].label;
  376. }
  377. info.m_Columns.RemoveAll();
  378. }
  379. m_Panels.RemoveAll();
  380. InvalidateLayout();
  381. }
  382. void CProfileHierarchyPanel::ExpandItem(int itemIndex, bool bExpand)
  383. {
  384. GetTree()->ExpandItem( itemIndex, bExpand );
  385. }
  386. bool CProfileHierarchyPanel::IsItemExpanded( int itemIndex )
  387. {
  388. return GetTree()->IsItemExpanded( itemIndex );
  389. }
  390. KeyValues *CProfileHierarchyPanel::GetItemData(int itemIndex)
  391. {
  392. return GetTree()->GetItemData( itemIndex );
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Purpose: Create the VProf panel
  396. //-----------------------------------------------------------------------------
  397. CVProfPanel::CVProfPanel( vgui::Panel *pParent, const char *pElementName )
  398. : vgui::Frame( pParent, pElementName )
  399. {
  400. m_pVProfile = g_pVProfileForDisplay;
  401. Assert( g_pVProfPanel == NULL );
  402. g_pVProfPanel = this;
  403. m_RootItem = -1;
  404. m_fShowVprofHeld = false;
  405. int x = VPROF_INDENT_X;
  406. int y = VPROF_INDENT_Y;
  407. int wide = videomode->GetModeStereoWidth() - x * 2;
  408. int tall = videomode->GetModeStereoHeight() - y * 2;
  409. SetBgColor(Color(0, 0, 0, 175));
  410. // Initialize the top title.
  411. #ifdef VPROF_ENABLED
  412. SetTitle("VProf", false);
  413. #else
  414. SetTitle("** VProf is not enabled **", false);
  415. #endif
  416. SetZPos( 1002 );
  417. CProfileTree *profileTree = new CProfileTree( this, "ProfileTree" );
  418. m_pHierarchy = new CProfileHierarchyPanel( this, "Hierarchy" );
  419. m_pHierarchy->SetTreeView( profileTree );
  420. m_pHierarchy->SetNumColumns( 3 );
  421. int treewide = wide - 780;
  422. m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
  423. m_pHierarchy->SetColumnInfo( 1, "Group", 120 );
  424. m_pHierarchy->SetColumnInfo( 2, "Data", 180 );
  425. // Treeview of the hierarchical calls
  426. m_pHierarchy->SetBounds(X_BORDER, VPROF_TITLE_SIZE_Y, wide - X_BORDER*2, tall - Y_BORDER*2 - VPROF_TITLE_SIZE_Y);
  427. m_pHierarchy->SetParent(this);
  428. m_pHierarchy->SetPaintBorderEnabled( false );
  429. m_pHierarchy->SetPaintBackgroundEnabled( false );
  430. SETUP_PANEL( m_pHierarchy );
  431. SETUP_PANEL( profileTree );
  432. // Mode selection used to populate the tree view + lists
  433. m_pVProfCategory = new ComboBox(this, "CategoryCombo", 5, false);
  434. m_pVProfCategory->AddItem( "All Categories", NULL );
  435. m_pVProfCategory->AddActionSignalTarget( this );
  436. m_pVProfCategory->ActivateItem( 0 );
  437. m_pVProfSort = new ComboBox( this, "SortCombo", 5, false );
  438. m_pVProfSort->AddItem( "By Time", NULL );
  439. m_pVProfSort->AddItem( "By Name", NULL );
  440. m_pVProfSort->AddItem( "By Budget Group", NULL );
  441. m_pVProfSort->AddActionSignalTarget( this );
  442. m_pVProfSort->ActivateItem( 0 );
  443. m_nLastBudgetGroupCount = 0;
  444. m_nCurrentBudgetGroup = -1;
  445. m_pHierarchicalView = new vgui::CheckButton( this, "HierarchicalViewSelection", "" );
  446. m_pHierarchicalView->AddActionSignalTarget( this );
  447. m_pHierarchicalView->SetSelected( true );
  448. m_bHierarchicalView = true;
  449. m_pRedoSort = new vgui::Button( this, "RedoSorting", "", this, "redosort" );
  450. m_pVerbose = new vgui::CheckButton( this, "VerboseCheckbox", "" );
  451. m_pVerbose->AddActionSignalTarget( this );
  452. m_pVerbose->SetSelected( vprof_verbose.GetBool() );
  453. // Setup the playback controls.
  454. m_pPlaybackLabel = new vgui::Label( this, "PlaybackLabel", "" );
  455. m_pPlaybackLabel->SetBgColor( Color( 0, 0, 0, 200 ) );
  456. m_pPlaybackLabel->SetPaintBackgroundEnabled( true );
  457. m_pStepForward = new vgui::Button( this, "StepForward", "", this, "StepForward" );
  458. m_pStepBack = new vgui::Button( this, "StepBack", "", this, "StepBack" );
  459. m_pGotoButton = new vgui::Button( this, "GotoButton", "", this, "GotoButton" );
  460. m_pPlaybackScroll = new vgui::ScrollBar( this, "PlaybackScroll", false );
  461. m_pPlaybackScroll->SetRange( 0, 1000 );
  462. m_pPlaybackScroll->SetRangeWindow( 30 );
  463. m_pPlaybackScroll->AddActionSignalTarget( this );
  464. m_iLastPlaybackTick = -1;
  465. LoadControlSettings("Resource\\VProfPanel.res");
  466. SetBounds( x, y, wide, tall );
  467. vgui::ivgui()->AddTickSignal( GetVPanel() );
  468. }
  469. CVProfPanel::~CVProfPanel( void )
  470. {
  471. Assert( g_pVProfPanel == this );
  472. g_pVProfPanel = NULL;
  473. }
  474. #define DATA_FMT_STR "%-30.30s %-30.30s %-45.45s %-10.10s"
  475. void CVProfPanel::PerformLayout()
  476. {
  477. BaseClass::PerformLayout();
  478. int w, h;
  479. GetSize( w, h );
  480. int topoffset = 95;
  481. int inset = 10;
  482. m_pHierarchy->SetBounds( inset, topoffset, w - 2 * inset, h - inset - topoffset );
  483. int treewide = w - 900 - 20;
  484. treewide = max( treewide, 240 );
  485. m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
  486. m_pHierarchy->SetColumnInfo( 1, "Group", 125 );
  487. char header[ 512 ];
  488. Q_snprintf( header, sizeof( header ), DATA_FMT_STR,
  489. "Frame Calls + Time + NoChild",
  490. "Avg Calls + Time + NoChild",
  491. "Sum Calls + Time + NoChild + Peak",
  492. "L2Miss" );
  493. m_pHierarchy->SetColumnInfo( 2, header, 775, CTreeViewListControl::CI_HEADER_LEFTALIGN );
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Scheme settings!
  497. //-----------------------------------------------------------------------------
  498. void CVProfPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  499. {
  500. BaseClass::ApplySchemeSettings( pScheme );
  501. IBorder *border = pScheme->GetBorder( "ToolTipBorder" );
  502. SetBorder(border);
  503. SetBgColor(Color(0, 0, 0, 175));
  504. }
  505. //-----------------------------------------------------------------------------
  506. // Purpose:
  507. // Input : *command -
  508. //-----------------------------------------------------------------------------
  509. void CVProfPanel::Close()
  510. {
  511. UserCmd_HideVProf();
  512. BaseClass::Close();
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Is it visible?
  516. //-----------------------------------------------------------------------------
  517. void CVProfPanel::OnTick()
  518. {
  519. BaseClass::OnTick();
  520. // Did the CVProfile we're using switch behind our back?
  521. if ( g_pVProfileForDisplay != m_pVProfile )
  522. {
  523. Reset();
  524. m_pVProfile = g_pVProfileForDisplay;
  525. bool bVisible = false;
  526. #ifndef _XBOX
  527. if ( VProfRecord_IsPlayingBack() )
  528. {
  529. bVisible = true;
  530. m_iLastPlaybackTick = -1;
  531. }
  532. #endif
  533. m_pStepForward->SetVisible( bVisible );
  534. m_pStepBack->SetVisible( bVisible );
  535. m_pPlaybackLabel->SetVisible( bVisible );
  536. m_pPlaybackScroll->SetVisible( bVisible );
  537. m_pGotoButton->SetVisible( bVisible );
  538. }
  539. #ifndef _XBOX
  540. if ( VProfRecord_IsPlayingBack() )
  541. {
  542. // Update the playback tick.
  543. int iCur = VProfPlayback_GetCurrentTick();
  544. if ( iCur != m_iLastPlaybackTick )
  545. {
  546. char str[512];
  547. Q_snprintf( str, sizeof( str ), "VPROF playback (tick %d, %d%%)", iCur, (int)(VProfPlayback_GetCurrentPercent() * 100) );
  548. m_pPlaybackLabel->SetText( str );
  549. }
  550. }
  551. #endif
  552. SetVisible( m_fShowVprofHeld != 0 );
  553. m_pRedoSort->SetVisible( !m_bHierarchicalView );
  554. }
  555. // 0 = By Time
  556. // 1 = By "Text"
  557. // 2 = By "group" then by "text"
  558. static int g_nSortType = -1;
  559. //-----------------------------------------------------------------------------
  560. // Visualization changed
  561. //-----------------------------------------------------------------------------
  562. void CVProfPanel::OnTextChanged( KeyValues *data )
  563. {
  564. Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
  565. vgui::ComboBox *pBox = dynamic_cast<vgui::ComboBox *>( pPanel );
  566. if( pBox == m_pVProfCategory )
  567. {
  568. // The -1 here is for the 'All Categories' item
  569. m_nCurrentBudgetGroup = pBox->GetActiveItem() - 1;
  570. // NOTE: We have to reset the tree view so that it
  571. // is populated with only the ones we want (need to eliminate everything
  572. // that's not appropriate)
  573. Reset();
  574. return;
  575. }
  576. if ( pBox == m_pVProfSort )
  577. {
  578. g_nSortType = pBox->GetActiveItem();
  579. Reset();
  580. return;
  581. }
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Sort function for hierarchical data
  585. //-----------------------------------------------------------------------------
  586. bool ChildCostSortFunc(KeyValues *pNode1, KeyValues *pNode2)
  587. {
  588. switch ( g_nSortType )
  589. {
  590. default:
  591. case 0:
  592. case -1:
  593. {
  594. float flTime1 = pNode1->GetFloat( "Time", -1.0f );
  595. float flTime2 = pNode2->GetFloat( "Time", -1.0f );
  596. return (flTime1 > flTime2);
  597. }
  598. case 1:
  599. {
  600. const char *t1 = pNode1->GetString( "Text", "" );
  601. const char *t2 = pNode2->GetString( "Text", "" );
  602. if( Q_stricmp( t1, t2 ) <= 0 )
  603. return true;
  604. return false;
  605. }
  606. break;
  607. case 2:
  608. {
  609. const char *g1 = pNode1->GetString( "group", "" );
  610. const char *g2 = pNode2->GetString( "group", "" );
  611. int val = Q_stricmp( g1, g2 );
  612. if( val < 0 )
  613. return true;
  614. if ( val > 0 )
  615. return false;
  616. const char *t1 = pNode1->GetString( "Text", "" );
  617. const char *t2 = pNode2->GetString( "Text", "" );
  618. if( Q_stricmp( t1, t2 ) <= 0 )
  619. return true;
  620. return false;
  621. }
  622. }
  623. return false;
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Changes the visualization method for vprof data
  627. //-----------------------------------------------------------------------------
  628. void CVProfPanel::OnCheckButtonChecked(Panel *panel)
  629. {
  630. if ( panel == m_pHierarchicalView )
  631. {
  632. bool bSelected = m_pHierarchicalView->IsSelected() ? 1 : 0;
  633. if ( bSelected != m_bHierarchicalView )
  634. {
  635. m_bHierarchicalView = bSelected;
  636. m_pHierarchy->GetTree()->SetSortFunc( m_bHierarchicalView ? NULL : ChildCostSortFunc );
  637. m_pRedoSort->SetVisible( !m_bHierarchicalView );
  638. Reset();
  639. }
  640. return;
  641. }
  642. if ( panel == m_pVerbose )
  643. {
  644. vprof_verbose.SetValue( m_pVerbose->IsSelected() ? 1 : 0 );
  645. return;
  646. }
  647. }
  648. //-----------------------------------------------------------------------------
  649. // Methods related to expand/collapse in hierarchy
  650. //-----------------------------------------------------------------------------
  651. void CVProfPanel::ExpandAll( void )
  652. {
  653. int count = m_pHierarchy->GetTree()->GetHighestItemID();
  654. int i;
  655. for( i = 0; i < count; i++ )
  656. {
  657. if( m_pHierarchy->GetTree()->IsItemIDValid( i ) )
  658. {
  659. m_pHierarchy->GetTree()->ExpandItem( i, true );
  660. }
  661. }
  662. }
  663. void CVProfPanel::CollapseAll( void )
  664. {
  665. int count = m_pHierarchy->GetTree()->GetHighestItemID();
  666. int i;
  667. for( i = 1; i < count; i++ )
  668. {
  669. if( m_pHierarchy->GetTree()->IsItemIDValid( i ) )
  670. {
  671. m_pHierarchy->GetTree()->ExpandItem( i, false );
  672. }
  673. }
  674. }
  675. void CVProfPanel::ExpandGroupRecursive( int nBudgetGroupID, CVProfNode *pNode )
  676. {
  677. if( !pNode )
  678. {
  679. return;
  680. }
  681. if( pNode->GetBudgetGroupID() == nBudgetGroupID )
  682. {
  683. CVProfNode *pTempNode = pNode;
  684. while( pTempNode )
  685. {
  686. if( pTempNode->GetParent() )
  687. {
  688. int id = pTempNode->GetParent()->GetClientData();
  689. m_pHierarchy->ExpandItem( id, true );
  690. }
  691. pTempNode = pTempNode->GetParent();
  692. }
  693. }
  694. ExpandGroupRecursive( nBudgetGroupID, pNode->GetChild() );
  695. ExpandGroupRecursive( nBudgetGroupID, pNode->GetSibling() );
  696. }
  697. void CVProfPanel::ExpandGroup( const char *pGroupName )
  698. {
  699. int groupID = m_pVProfile->BudgetGroupNameToBudgetGroupID( pGroupName );
  700. ExpandGroupRecursive( groupID, m_pVProfile->GetRoot() );
  701. }
  702. class CVProfLabel : public Label
  703. {
  704. DECLARE_CLASS_SIMPLE( CVProfLabel, Label );
  705. public:
  706. CVProfLabel( Panel *parent, const char *panelName ) :
  707. BaseClass( parent, panelName, "" )
  708. {
  709. //SetPaintBackgroundEnabled( false );
  710. }
  711. virtual void ApplySchemeSettings( IScheme *pScheme )
  712. {
  713. BaseClass::ApplySchemeSettings( pScheme );
  714. SetFont( pScheme->GetFont( PROF_FONT ) );
  715. SetBgColor( Color( 0, 0, 0, 255 ) );
  716. }
  717. };
  718. Label *AllocateVprofLabel( const char *panelName )
  719. {
  720. CVProfLabel *l = new CVProfLabel( NULL, panelName );
  721. l->SetContentAlignment( Label::a_west );
  722. return l;
  723. }
  724. void CVProfPanel::AddColumns( CProfileHierarchyPanel::ColumnPanels_t& cp )
  725. {
  726. cp.AddColumn( 1, "group", AllocateVprofLabel( "group" ) );
  727. cp.AddColumn( 2, "data", AllocateVprofLabel( "data" ) );
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Populate the tree
  731. //-----------------------------------------------------------------------------
  732. int CVProfPanel::UpdateVProfTreeEntry( KeyValues *pKeyValues, CVProfNode *pNode, int parent )
  733. {
  734. VPROF( "UpdateVProfTreeEntry" );
  735. CFmtStrN<1024> msg;
  736. double curTimeLessChildren = pNode->GetCurTimeLessChildren();
  737. double avgLessChildren = ( pNode->GetTotalCalls() > 0 ) ? pNode->GetTotalTimeLessChildren() / (double)pNode->GetTotalCalls() : 0;
  738. pKeyValues->SetString( "Text", pNode->GetName() );
  739. pKeyValues->SetString( "group", m_pVProfile->GetBudgetGroupName( pNode->GetBudgetGroupID() ) );
  740. CFmtStrN< 256 > frame;
  741. CFmtStrN< 256 > avgstr;
  742. CFmtStrN< 256 > sum;
  743. CFmtStrN< 256 > l2miss;
  744. frame.sprintf( "[%4d] %7.2f %7.2f", pNode->GetCurCalls(), pNode->GetCurTime(), curTimeLessChildren );
  745. pKeyValues->SetString( "frame", msg );
  746. if( vprof_verbose.GetBool() )
  747. {
  748. double avgCalls = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalCalls() / (double)m_pVProfile->NumFramesSampled() : 0;
  749. double avg = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTime() / (double)m_pVProfile->NumFramesSampled() : 0;
  750. double avgLessChildrenVerbose = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTimeLessChildren() / (double)m_pVProfile->NumFramesSampled() : 0;
  751. avgstr.sprintf( "[%6.2f] %6.3f %6.3f", avgCalls, avg, avgLessChildrenVerbose );
  752. sum.sprintf( "[%7d] %9.2f %9.2f %8.2fp", pNode->GetTotalCalls(), pNode->GetTotalTime(), pNode->GetTotalTimeLessChildren(), pNode->GetPeakTime() );
  753. }
  754. if ( m_pVProfile->UsePME() )
  755. {
  756. l2miss.sprintf( "%5d", pNode->GetL2CacheMisses() );
  757. }
  758. msg.sprintf( DATA_FMT_STR,
  759. (const char *)frame,
  760. (const char *)avgstr,
  761. (const char *)sum,
  762. (const char *)l2miss );
  763. pKeyValues->SetString( "data", msg );
  764. pKeyValues->SetFloat( "Time", avgLessChildren );
  765. // Add or modify a line in the hierarchy
  766. int id = pNode->GetClientData();
  767. if ( id == -1 )
  768. {
  769. CProfileHierarchyPanel::ColumnPanels_t cp;
  770. AddColumns( cp );
  771. id = m_pHierarchy->AddItem( pKeyValues, parent, cp ) ;
  772. pNode->SetClientData( id );
  773. }
  774. else
  775. {
  776. VPROF( "UpdateVProfTreeEntry:Modify" );
  777. m_pHierarchy->ModifyItem( pKeyValues, id );
  778. }
  779. // Apply color to the item
  780. int r,g,b,a;
  781. m_pVProfile->GetBudgetGroupColor( pNode->GetBudgetGroupID(), r, g, b, a );
  782. m_pHierarchy->SetItemColors( id, Color( r, g, b, a ), Color( 0, 0, 0, 255 ) );
  783. if( pNode->GetBudgetGroupID() == VPROF_BUDGET_GROUP_ID_UNACCOUNTED )
  784. {
  785. if ( curTimeLessChildren > vprof_unaccounted_limit.GetFloat() )
  786. {
  787. m_pHierarchy->SetItemColors( id, Color( 255, 0, 0, 255 ), Color( 0, 0, 0, 255 ) );
  788. }
  789. }
  790. if ( pNode->GetCurTime() > vprof_warningmsec.GetFloat() ||
  791. curTimeLessChildren > vprof_warningmsec.GetFloat() )
  792. {
  793. m_pHierarchy->SetItemColumnColors( id, 2, Color( 255, 0, 0, 255 ), Color( 63, 0, 0, 255 ) );
  794. }
  795. return id;
  796. }
  797. //-----------------------------------------------------------------------------
  798. // Populate the tree
  799. //-----------------------------------------------------------------------------
  800. void CVProfPanel::FillTree( KeyValues *pKeyValues, CVProfNode *pNode, int parent )
  801. {
  802. #ifdef VPROF_ENABLED
  803. bool fIsRoot = ( pNode == m_pVProfile->GetRoot() );
  804. if ( fIsRoot )
  805. {
  806. if( pNode->GetChild() )
  807. {
  808. FillTree( pKeyValues, pNode->GetChild(), parent );
  809. }
  810. return;
  811. }
  812. int id = parent;
  813. if (( m_nCurrentBudgetGroup < 0 ) || ( pNode->GetBudgetGroupID() == m_nCurrentBudgetGroup ))
  814. {
  815. id = UpdateVProfTreeEntry( pKeyValues, pNode, parent );
  816. }
  817. if( pNode->GetSibling() )
  818. {
  819. FillTree( pKeyValues, pNode->GetSibling(), parent );
  820. }
  821. if( pNode->GetChild() )
  822. {
  823. FillTree( pKeyValues, pNode->GetChild(), m_bHierarchicalView ? id : parent );
  824. }
  825. #endif
  826. }
  827. //-----------------------------------------------------------------------------
  828. // Populates the budget group combo box
  829. //-----------------------------------------------------------------------------
  830. void CVProfPanel::PopulateBudgetGroupComboBox()
  831. {
  832. int nBudgetGroupCount = m_pVProfile->GetNumBudgetGroups();
  833. while( m_nLastBudgetGroupCount < nBudgetGroupCount )
  834. {
  835. m_pVProfCategory->AddItem( m_pVProfile->GetBudgetGroupName(m_nLastBudgetGroupCount), NULL );
  836. ++m_nLastBudgetGroupCount;
  837. }
  838. }
  839. //-----------------------------------------------------------------------------
  840. // Populates the tree
  841. //-----------------------------------------------------------------------------
  842. void CVProfPanel::UpdateProfile( float filteredtime )
  843. {
  844. #ifdef VPROF_ENABLED
  845. //ExecuteDeferredOp();
  846. if (IsVisible())
  847. {
  848. PopulateBudgetGroupComboBox();
  849. SetTitle( CFmtStr( "VProf (%s) -- %d frames sampled",
  850. m_pVProfile->IsEnabled() ? "running" : "not running",
  851. m_pVProfile->NumFramesSampled() ), false );
  852. // It's important to cache bEnabled since calling pause can disable.
  853. bool bEnabled = m_pVProfile->IsEnabled();
  854. if( bEnabled )
  855. {
  856. m_pVProfile->Pause();
  857. }
  858. KeyValues * pVal = new KeyValues("");
  859. if ( !m_pHierarchy->GetTree()->GetItemCount() )
  860. {
  861. pVal->SetString( "Text", "Call tree" );
  862. CProfileHierarchyPanel::ColumnPanels_t cp;
  863. AddColumns( cp );
  864. m_RootItem = m_pHierarchy->AddItem( pVal, -1, cp );
  865. m_pHierarchy->SetItemColors( m_RootItem, Color( 255, 255, 255, 255 ), Color( 0, 0, 0, 255 ) );
  866. m_pHierarchy->ExpandItem( m_RootItem, true );
  867. }
  868. m_pHierarchy->ExpandItem( m_RootItem, true );
  869. const char *pScope = vprof_scope.GetString();
  870. CVProfNode *pStartNode = ( pScope[0] == 0 ) ? m_pVProfile->GetRoot() : m_pVProfile->FindNode(m_pVProfile->GetRoot(), pScope );
  871. if ( pStartNode )
  872. {
  873. FillTree( pVal, pStartNode, m_RootItem );
  874. }
  875. pVal->deleteThis();
  876. if( bEnabled )
  877. {
  878. m_pVProfile->Resume();
  879. }
  880. }
  881. if ( m_pVProfile->IsEnabled() )
  882. {
  883. Assert( m_pVProfile->AtRoot() );
  884. if ( GetBudgetPanel()->IsBudgetPanelShown() )
  885. GetBudgetPanel()->SnapshotVProfHistory( filteredtime );
  886. WriteRemoteVProfData(); // send out the vprof data to remote endpoints
  887. }
  888. #endif
  889. }
  890. //-----------------------------------------------------------------------------
  891. // Purpose:
  892. //-----------------------------------------------------------------------------
  893. void CVProfPanel::UserCmd_ShowVProf( void )
  894. {
  895. m_fShowVprofHeld = true;
  896. SetVisible( true );
  897. // This is hacky . . need to at least remember the previous value to set it back.
  898. ConVarRef cl_mouseenable( "cl_mouseenable" );
  899. if ( cl_mouseenable.IsValid() )
  900. {
  901. cl_mouseenable.SetValue( 0 );
  902. }
  903. }
  904. //-----------------------------------------------------------------------------
  905. // Purpose:
  906. //-----------------------------------------------------------------------------
  907. void CVProfPanel::UserCmd_HideVProf( void )
  908. {
  909. m_fShowVprofHeld = false;
  910. SetVisible( false );
  911. // This is hacky . . need to at least remember the previous value to set it back.
  912. ConVarRef cl_mouseenable( "cl_mouseenable" );
  913. if ( cl_mouseenable.IsValid() )
  914. {
  915. cl_mouseenable.SetValue( 1 );
  916. }
  917. }
  918. //-----------------------------------------------------------------------------
  919. void CVProfPanel::Paint()
  920. {
  921. m_pVProfile->Pause();
  922. BaseClass::Paint();
  923. m_pVProfile->Resume();
  924. }
  925. void CVProfPanel::OnCommand( const char *pCommand )
  926. {
  927. #ifndef _XBOX
  928. if ( !Q_stricmp( pCommand, "StepForward" ) )
  929. {
  930. VProfPlayback_Step();
  931. }
  932. else if ( !Q_stricmp( pCommand, "StepBack" ) )
  933. {
  934. int shouldReset = VProfPlayback_StepBack();
  935. if ( shouldReset == 2 )
  936. {
  937. Reset();
  938. }
  939. }
  940. else if ( !Q_stricmp( pCommand, "GotoButton" ) )
  941. {
  942. int shouldReset = VProfPlayback_SeekToPercent( (float)m_pPlaybackScroll->GetValue() / 1000.0 );
  943. if ( shouldReset == 2 )
  944. {
  945. Reset();
  946. }
  947. }
  948. else if ( !Q_stricmp( pCommand, "redosort" ) )
  949. {
  950. //
  951. Assert( !m_bHierarchicalView );
  952. Reset();
  953. }
  954. #endif
  955. }
  956. #endif