summaryrefslogtreecommitdiff
path: root/engine/vgui_vprofpanel.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/vgui_vprofpanel.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'engine/vgui_vprofpanel.cpp')
-rw-r--r--engine/vgui_vprofpanel.cpp1155
1 files changed, 1155 insertions, 0 deletions
diff --git a/engine/vgui_vprofpanel.cpp b/engine/vgui_vprofpanel.cpp
new file mode 100644
index 0000000..f4c9e8a
--- /dev/null
+++ b/engine/vgui_vprofpanel.cpp
@@ -0,0 +1,1155 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: VGUI scoreboard
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//===========================================================================//
+
+#include "client_pch.h"
+#include "vgui_vprofpanel.h"
+#include <KeyValues.h>
+#include "vgui_budgetpanel.h"
+#include "vprof_engine.h"
+#include "vprof_record.h"
+#include "ivideomode.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+// positions
+#define VPROF_INDENT_X XRES(20)
+#define VPROF_INDENT_Y YRES(10)
+
+// Scoreboard dimensions
+#define VPROF_TITLE_SIZE_Y YRES(22)
+
+#define X_BORDER XRES(4)
+#define Y_BORDER YRES(4)
+
+static ConVar vprof_verbose( "vprof_verbose", "1", FCVAR_ARCHIVE, "Set to one to show average and peak times" );
+static ConVar vprof_unaccounted_limit( "vprof_unaccounted_limit", "0.3", FCVAR_ARCHIVE,
+ "number of milliseconds that a node must exceed to turn red in the vprof panel" );
+static ConVar vprof_warningmsec( "vprof_warningmsec", "10", FCVAR_ARCHIVE, "Above this many milliseconds render the label red to indicate slow code." );
+
+#ifdef VPROF_ENABLED
+
+//-----------------------------------------------------------------------------
+// Singleton accessor
+//-----------------------------------------------------------------------------
+static CVProfPanel *g_pVProfPanel = NULL;
+CVProfPanel *GetVProfPanel( void )
+{
+ return g_pVProfPanel;
+}
+
+
+static void ClearNodeClientData( CVProfNode *pNode )
+{
+ pNode->SetClientData( -1 );
+ if( pNode->GetSibling() )
+ {
+ ClearNodeClientData( pNode->GetSibling() );
+ }
+
+ if( pNode->GetChild() )
+ {
+ ClearNodeClientData( pNode->GetChild() );
+ }
+}
+
+void CVProfPanel::Reset()
+{
+ m_pHierarchy->RemoveAll();
+ m_RootItem = -1;
+ ClearNodeClientData( m_pVProfile->GetRoot() );
+}
+
+
+CON_COMMAND( vprof_expand_all, "Expand the whole vprof tree" )
+{
+ Msg("VProf expand all.\n");
+ GetVProfPanel()->ExpandAll();
+}
+
+CON_COMMAND( vprof_collapse_all, "Collapse the whole vprof tree" )
+{
+ Msg("VProf collapse all.\n");
+ GetVProfPanel()->CollapseAll();
+}
+
+CON_COMMAND( vprof_expand_group, "Expand a budget group in the vprof tree by name" )
+{
+ Msg("VProf expand group.\n");
+ if ( args.ArgC() >= 2 )
+ {
+ GetVProfPanel()->ExpandGroup( args[ 1 ] );
+ }
+}
+
+void IN_VProfDown(void)
+{
+ GetVProfPanel()->UserCmd_ShowVProf();
+}
+
+void IN_VProfUp(void)
+{
+ GetVProfPanel()->UserCmd_HideVProf();
+}
+
+static ConCommand startshowvprof("+showvprof", IN_VProfDown);
+static ConCommand endshowvprof("-showvprof", IN_VProfUp);
+
+void ChangeVProfScopeCallback( IConVar *pConVar, const char *pOldString, float flOldValue )
+{
+ ConVarRef var( pConVar );
+ Msg( "VProf setting scope to %s\n", var.GetString( ) );
+
+ if ( g_pVProfPanel )
+ {
+ g_pVProfPanel->Reset();
+ }
+}
+
+ConVar vprof_scope(
+ "vprof_scope",
+ "",
+ 0,
+ "Set a specific scope to start showing vprof tree",
+ 0, 0, 0, 0,
+ ChangeVProfScopeCallback );
+
+#define PROF_FONT "DefaultFixed"
+
+class CProfileTree : public TreeView
+{
+ DECLARE_CLASS_SIMPLE( CProfileTree, TreeView );
+public:
+ CProfileTree( CVProfPanel *parent, const char *panelName );
+ ~CProfileTree();
+
+ virtual void OnCommand( const char *cmd );
+
+ virtual void InvalidateLayout( bool layoutNow = false, bool reloadScheme = false );
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+ SetFont( pScheme->GetFont( PROF_FONT ) );
+ }
+
+ virtual void SetBgColor( Color color )
+ {
+ BaseClass::SetBgColor( color );
+ }
+
+private:
+
+ Menu *m_pEditMenu;
+ CVProfPanel *m_pParent;
+};
+
+CProfileTree::CProfileTree( CVProfPanel *parent, const char *panelName ) :
+ BaseClass( (Panel *)parent, panelName ),
+ m_pEditMenu( 0 ),
+ m_pParent( parent )
+{
+}
+
+CProfileTree::~CProfileTree()
+{
+ delete m_pEditMenu;
+}
+
+void CProfileTree::InvalidateLayout( bool layoutNow, bool reloadScheme )
+{
+ BaseClass::InvalidateLayout( layoutNow, reloadScheme );
+ if ( GetParent() )
+ {
+ GetParent()->InvalidateLayout( layoutNow, reloadScheme );
+ }
+}
+
+void CProfileTree::OnCommand( const char *cmd )
+{
+ // Relay to parent
+ GetParent()->OnCommand( cmd );
+}
+
+CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t() :
+ treeViewItem( -1 )
+{
+}
+
+CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t( const ColumnPanels_t& src )
+{
+ treeViewItem = src.treeViewItem;
+ int c = src.m_Columns.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ PanelEntry_t pe;
+ pe.dataname = src.m_Columns[ i ].dataname;
+ pe.label = src.m_Columns[ i ].label;
+
+ m_Columns.AddToTail( pe );
+ }
+}
+
+void CProfileHierarchyPanel::ColumnPanels_t::AddColumn( int index, const char *name, vgui::Label *label )
+{
+ m_Columns.EnsureCount( index + 1 );
+
+ m_Columns[ index ].label = label;
+ m_Columns[ index ].dataname = name;
+}
+
+void CProfileHierarchyPanel::ColumnPanels_t::Refresh( KeyValues *kv )
+{
+ VPROF( "CProfileHierarchyPanel::ColumnPanels_t" );
+
+ int c = m_Columns.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ vgui::Label *label = m_Columns[ i ].label;
+ if ( !label )
+ continue;
+
+ const char *name = m_Columns[ i ].dataname.String();
+ if ( name && name[ 0 ] )
+ {
+ const char *value = kv->GetString( name, "" );
+ if ( value )
+ {
+ if ( !value[ 0 ] )
+ {
+ label->SetText( "" );
+ label->SetVisible( false );
+ }
+ else
+ {
+ label->SetVisible( true );
+ label->SetText( value );
+ }
+ }
+ else
+ {
+ label->SetVisible( false );
+ }
+ }
+ }
+}
+
+
+CProfileHierarchyPanel::CProfileHierarchyPanel(vgui::Panel *parent, const char *panelName)
+ : BaseClass(parent,panelName),
+ m_Panels( 0, 0, PanelsLessFunc )
+{
+}
+
+CProfileHierarchyPanel::~CProfileHierarchyPanel()
+{
+}
+
+void CProfileHierarchyPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ //SetProportional( true );
+ BaseClass::ApplySchemeSettings( pScheme );
+ m_itemFont = pScheme->GetFont( PROF_FONT );
+ SetTitleBarInfo( m_itemFont, 20 );
+ SetBgColor( Color(0, 0, 0, 176) );
+ (( CProfileTree *)GetTree())->SetBgColor( Color( 0, 0, 0, 176 ) );
+}
+
+void CProfileHierarchyPanel::SetItemColors( int id, const Color& fg, const Color& bg )
+{
+ VPROF( "CProfileHierarchyPanel::SetItemColors" );
+ GetTree()->SetItemFgColor( id, fg );
+ GetTree()->SetItemBgColor( id, bg );
+ ColumnPanels_t search;
+ search.treeViewItem = id;
+ int idx = m_Panels.Find( search );
+ if ( idx == m_Panels.InvalidIndex() )
+ {
+ return;
+ }
+ ColumnPanels_t& info = m_Panels[ idx ];
+ int c = info.m_Columns.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ Label *label = info.m_Columns[ i ].label;
+ if ( !label )
+ continue;
+ label->SetFgColor( fg );
+ label->SetBgColor( bg );
+ }
+}
+
+void CProfileHierarchyPanel::SetItemColumnColors( int id, int col, const Color& fg, const Color& bg )
+{
+ VPROF( "CProfileHierarchyPanel::SetItemColumnColors" );
+ ColumnPanels_t search;
+ search.treeViewItem = id;
+ int idx = m_Panels.Find( search );
+ if ( idx == m_Panels.InvalidIndex() )
+ {
+ return;
+ }
+ ColumnPanels_t& info = m_Panels[ idx ];
+ int c = info.m_Columns.Count();
+ if ( col < 0 || col >= c )
+ return;
+
+ Label *label = info.m_Columns[ col ].label;
+ if ( !label )
+ return;
+
+ label->SetFgColor( fg );
+ label->SetBgColor( bg );
+}
+
+void CProfileHierarchyPanel::ModifyItem( KeyValues *data, int itemIndex )
+{
+ GetTree()->SetItemFgColor( itemIndex, GetFgColor() );
+ GetTree()->SetItemBgColor( itemIndex, GetBgColor() );
+
+ ColumnPanels_t search;
+ search.treeViewItem = itemIndex;
+ int idx = m_Panels.Find( search );
+ if ( idx == m_Panels.InvalidIndex() )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ ColumnPanels_t& info = m_Panels[ idx ];
+ info.Refresh( data );
+}
+
+int CProfileHierarchyPanel::AddItem( KeyValues *data, int parentItemIndex, ColumnPanels_t& columnPanels )
+{
+ int itemIndex = GetTree()->AddItem( data, parentItemIndex );
+ columnPanels.treeViewItem = itemIndex;
+
+ ColumnPanels_t search;
+ search.treeViewItem = itemIndex;
+
+ int idx = m_Panels.Find( search );
+ if ( idx == m_Panels.InvalidIndex() )
+ {
+ m_Panels.Insert( columnPanels );
+
+ int c = columnPanels.m_Columns.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ if ( columnPanels.m_Columns[ i ].label )
+ {
+ columnPanels.m_Columns[ i ].label->SetParent( this );
+ }
+ }
+ }
+
+ ModifyItem( data, itemIndex );
+
+ return itemIndex;
+}
+
+void CProfileHierarchyPanel::PostChildPaint()
+{
+}
+
+void CProfileHierarchyPanel::PerformLayout()
+{
+ VPROF( "CProfileHierarchyPanel::PerformLayout" );
+ BaseClass::PerformLayout();
+
+ // Assume all invisible at first
+ HideAll();
+
+ int tall = GetTall();
+
+ int rowheight = GetTree()->GetRowHeight();
+ int top, visitems;
+ bool hbarVisible = false;
+ GetTree()->GetVBarInfo( top, visitems, hbarVisible );
+
+ int offset = -top * rowheight;
+
+ int numColumns = GetNumColumns();
+ // Now position column panels into the correct spot
+ int rows = GetNumRows();
+ for ( int row = 0; row < rows; ++row )
+ {
+ int tvi = GetTreeItemAtRow( row );
+
+ for ( int col = 0; col < numColumns; ++col )
+ {
+ int left, right, bottom;
+ GetGridElementBounds( col, row, left, top, right, bottom );
+
+ ColumnPanels_t search;
+ search.treeViewItem = tvi;
+
+ int idx = m_Panels.Find( search );
+ if ( idx != m_Panels.InvalidIndex() )
+ {
+ ColumnPanels_t& info = m_Panels[ idx ];
+
+ if ( col >= info.m_Columns.Count() )
+ continue;
+
+ vgui::Label *p = info.m_Columns[ col ].label;
+ if ( !p )
+ {
+ continue;
+ }
+
+ bool vis = ( top + offset - 20 ) >= 0 && ( bottom + offset ) < tall;
+
+ p->SetParent( vis ? this : NULL );
+ p->SetVisible( vis );
+ p->SetBounds( left, top + offset, right - left, bottom - top );
+ p->InvalidateLayout();
+ }
+ else
+ {
+ Assert( 0 );
+ }
+ }
+ }
+}
+
+void CProfileHierarchyPanel::HideAll()
+{
+ for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) )
+ {
+ ColumnPanels_t& info = m_Panels[ i ];
+ int c = info.m_Columns.Count();
+ for ( int j = 0 ; j < c; ++j )
+ {
+ Label *panel = info.m_Columns[ j ].label;
+ if ( !panel )
+ {
+ continue;
+ }
+ panel->SetVisible( false );
+ }
+ }
+}
+
+void CProfileHierarchyPanel::RemoveAll()
+{
+ GetTree()->RemoveAll();
+
+ for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) )
+ {
+ ColumnPanels_t& info = m_Panels[ i ];
+ int c = info.m_Columns.Count();
+ for ( int j = 0 ; j < c; ++j )
+ {
+ delete info.m_Columns[ j ].label;
+ }
+ info.m_Columns.RemoveAll();
+ }
+ m_Panels.RemoveAll();
+ InvalidateLayout();
+}
+
+void CProfileHierarchyPanel::ExpandItem(int itemIndex, bool bExpand)
+{
+ GetTree()->ExpandItem( itemIndex, bExpand );
+}
+
+bool CProfileHierarchyPanel::IsItemExpanded( int itemIndex )
+{
+ return GetTree()->IsItemExpanded( itemIndex );
+}
+
+KeyValues *CProfileHierarchyPanel::GetItemData(int itemIndex)
+{
+ return GetTree()->GetItemData( itemIndex );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create the VProf panel
+//-----------------------------------------------------------------------------
+CVProfPanel::CVProfPanel( vgui::Panel *pParent, const char *pElementName )
+ : vgui::Frame( pParent, pElementName )
+{
+ m_pVProfile = g_pVProfileForDisplay;
+
+ Assert( g_pVProfPanel == NULL );
+ g_pVProfPanel = this;
+
+ m_RootItem = -1;
+ m_fShowVprofHeld = false;
+
+ int x = VPROF_INDENT_X;
+ int y = VPROF_INDENT_Y;
+ int wide = videomode->GetModeStereoWidth() - x * 2;
+ int tall = videomode->GetModeStereoHeight() - y * 2;
+ SetBgColor(Color(0, 0, 0, 175));
+
+ // Initialize the top title.
+#ifdef VPROF_ENABLED
+ SetTitle("VProf", false);
+#else
+ SetTitle("** VProf is not enabled **", false);
+#endif
+
+ SetZPos( 1002 );
+
+ CProfileTree *profileTree = new CProfileTree( this, "ProfileTree" );
+
+ m_pHierarchy = new CProfileHierarchyPanel( this, "Hierarchy" );
+
+ m_pHierarchy->SetTreeView( profileTree );
+ m_pHierarchy->SetNumColumns( 3 );
+
+ int treewide = wide - 780;
+ m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
+
+ m_pHierarchy->SetColumnInfo( 1, "Group", 120 );
+ m_pHierarchy->SetColumnInfo( 2, "Data", 180 );
+
+ // Treeview of the hierarchical calls
+ m_pHierarchy->SetBounds(X_BORDER, VPROF_TITLE_SIZE_Y, wide - X_BORDER*2, tall - Y_BORDER*2 - VPROF_TITLE_SIZE_Y);
+ m_pHierarchy->SetParent(this);
+ m_pHierarchy->SetPaintBorderEnabled( false );
+ m_pHierarchy->SetPaintBackgroundEnabled( false );
+
+ SETUP_PANEL( m_pHierarchy );
+ SETUP_PANEL( profileTree );
+
+ // Mode selection used to populate the tree view + lists
+ m_pVProfCategory = new ComboBox(this, "CategoryCombo", 5, false);
+ m_pVProfCategory->AddItem( "All Categories", NULL );
+ m_pVProfCategory->AddActionSignalTarget( this );
+ m_pVProfCategory->ActivateItem( 0 );
+
+ m_pVProfSort = new ComboBox( this, "SortCombo", 5, false );
+ m_pVProfSort->AddItem( "By Time", NULL );
+ m_pVProfSort->AddItem( "By Name", NULL );
+ m_pVProfSort->AddItem( "By Budget Group", NULL );
+ m_pVProfSort->AddActionSignalTarget( this );
+ m_pVProfSort->ActivateItem( 0 );
+
+ m_nLastBudgetGroupCount = 0;
+ m_nCurrentBudgetGroup = -1;
+
+ m_pHierarchicalView = new vgui::CheckButton( this, "HierarchicalViewSelection", "" );
+ m_pHierarchicalView->AddActionSignalTarget( this );
+ m_pHierarchicalView->SetSelected( true );
+ m_bHierarchicalView = true;
+
+ m_pRedoSort = new vgui::Button( this, "RedoSorting", "", this, "redosort" );
+
+ m_pVerbose = new vgui::CheckButton( this, "VerboseCheckbox", "" );
+ m_pVerbose->AddActionSignalTarget( this );
+ m_pVerbose->SetSelected( vprof_verbose.GetBool() );
+
+
+ // Setup the playback controls.
+ m_pPlaybackLabel = new vgui::Label( this, "PlaybackLabel", "" );
+ m_pPlaybackLabel->SetBgColor( Color( 0, 0, 0, 200 ) );
+ m_pPlaybackLabel->SetPaintBackgroundEnabled( true );
+
+ m_pStepForward = new vgui::Button( this, "StepForward", "", this, "StepForward" );
+ m_pStepBack = new vgui::Button( this, "StepBack", "", this, "StepBack" );
+ m_pGotoButton = new vgui::Button( this, "GotoButton", "", this, "GotoButton" );
+
+ m_pPlaybackScroll = new vgui::ScrollBar( this, "PlaybackScroll", false );
+ m_pPlaybackScroll->SetRange( 0, 1000 );
+ m_pPlaybackScroll->SetRangeWindow( 30 );
+ m_pPlaybackScroll->AddActionSignalTarget( this );
+
+ m_iLastPlaybackTick = -1;
+
+
+ LoadControlSettings("Resource\\VProfPanel.res");
+
+ SetBounds( x, y, wide, tall );
+
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+}
+
+
+CVProfPanel::~CVProfPanel( void )
+{
+ Assert( g_pVProfPanel == this );
+ g_pVProfPanel = NULL;
+}
+
+#define DATA_FMT_STR "%-30.30s %-30.30s %-45.45s %-10.10s"
+void CVProfPanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+
+ int topoffset = 95;
+ int inset = 10;
+
+ m_pHierarchy->SetBounds( inset, topoffset, w - 2 * inset, h - inset - topoffset );
+
+ int treewide = w - 900 - 20;
+ treewide = max( treewide, 240 );
+ m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
+
+ m_pHierarchy->SetColumnInfo( 1, "Group", 125 );
+ char header[ 512 ];
+ Q_snprintf( header, sizeof( header ), DATA_FMT_STR,
+ "Frame Calls + Time + NoChild",
+ "Avg Calls + Time + NoChild",
+ "Sum Calls + Time + NoChild + Peak",
+ "L2Miss" );
+
+ m_pHierarchy->SetColumnInfo( 2, header, 775, CTreeViewListControl::CI_HEADER_LEFTALIGN );
+}
+
+//-----------------------------------------------------------------------------
+// Scheme settings!
+//-----------------------------------------------------------------------------
+void CVProfPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ IBorder *border = pScheme->GetBorder( "ToolTipBorder" );
+ SetBorder(border);
+
+ SetBgColor(Color(0, 0, 0, 175));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CVProfPanel::Close()
+{
+ UserCmd_HideVProf();
+ BaseClass::Close();
+}
+
+
+//-----------------------------------------------------------------------------
+// Is it visible?
+//-----------------------------------------------------------------------------
+void CVProfPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ // Did the CVProfile we're using switch behind our back?
+ if ( g_pVProfileForDisplay != m_pVProfile )
+ {
+ Reset();
+ m_pVProfile = g_pVProfileForDisplay;
+
+ bool bVisible = false;
+#ifndef _XBOX
+ if ( VProfRecord_IsPlayingBack() )
+ {
+ bVisible = true;
+ m_iLastPlaybackTick = -1;
+ }
+#endif
+ m_pStepForward->SetVisible( bVisible );
+ m_pStepBack->SetVisible( bVisible );
+ m_pPlaybackLabel->SetVisible( bVisible );
+ m_pPlaybackScroll->SetVisible( bVisible );
+ m_pGotoButton->SetVisible( bVisible );
+ }
+#ifndef _XBOX
+ if ( VProfRecord_IsPlayingBack() )
+ {
+ // Update the playback tick.
+ int iCur = VProfPlayback_GetCurrentTick();
+ if ( iCur != m_iLastPlaybackTick )
+ {
+ char str[512];
+ Q_snprintf( str, sizeof( str ), "VPROF playback (tick %d, %d%%)", iCur, (int)(VProfPlayback_GetCurrentPercent() * 100) );
+ m_pPlaybackLabel->SetText( str );
+ }
+ }
+#endif
+ SetVisible( m_fShowVprofHeld != 0 );
+
+ m_pRedoSort->SetVisible( !m_bHierarchicalView );
+}
+
+// 0 = By Time
+// 1 = By "Text"
+// 2 = By "group" then by "text"
+static int g_nSortType = -1;
+//-----------------------------------------------------------------------------
+// Visualization changed
+//-----------------------------------------------------------------------------
+void CVProfPanel::OnTextChanged( KeyValues *data )
+{
+ Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
+ vgui::ComboBox *pBox = dynamic_cast<vgui::ComboBox *>( pPanel );
+
+ if( pBox == m_pVProfCategory )
+ {
+ // The -1 here is for the 'All Categories' item
+ m_nCurrentBudgetGroup = pBox->GetActiveItem() - 1;
+
+ // NOTE: We have to reset the tree view so that it
+ // is populated with only the ones we want (need to eliminate everything
+ // that's not appropriate)
+ Reset();
+ return;
+ }
+ if ( pBox == m_pVProfSort )
+ {
+ g_nSortType = pBox->GetActiveItem();
+ Reset();
+ return;
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Sort function for hierarchical data
+//-----------------------------------------------------------------------------
+bool ChildCostSortFunc(KeyValues *pNode1, KeyValues *pNode2)
+{
+ switch ( g_nSortType )
+ {
+ default:
+ case 0:
+ case -1:
+ {
+ float flTime1 = pNode1->GetFloat( "Time", -1.0f );
+ float flTime2 = pNode2->GetFloat( "Time", -1.0f );
+ return (flTime1 > flTime2);
+ }
+ case 1:
+ {
+ const char *t1 = pNode1->GetString( "Text", "" );
+ const char *t2 = pNode2->GetString( "Text", "" );
+ if( Q_stricmp( t1, t2 ) <= 0 )
+ return true;
+ return false;
+ }
+ break;
+ case 2:
+ {
+ const char *g1 = pNode1->GetString( "group", "" );
+ const char *g2 = pNode2->GetString( "group", "" );
+ int val = Q_stricmp( g1, g2 );
+ if( val < 0 )
+ return true;
+
+ if ( val > 0 )
+ return false;
+
+ const char *t1 = pNode1->GetString( "Text", "" );
+ const char *t2 = pNode2->GetString( "Text", "" );
+ if( Q_stricmp( t1, t2 ) <= 0 )
+ return true;
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Changes the visualization method for vprof data
+//-----------------------------------------------------------------------------
+void CVProfPanel::OnCheckButtonChecked(Panel *panel)
+{
+ if ( panel == m_pHierarchicalView )
+ {
+ bool bSelected = m_pHierarchicalView->IsSelected() ? 1 : 0;
+ if ( bSelected != m_bHierarchicalView )
+ {
+ m_bHierarchicalView = bSelected;
+ m_pHierarchy->GetTree()->SetSortFunc( m_bHierarchicalView ? NULL : ChildCostSortFunc );
+ m_pRedoSort->SetVisible( !m_bHierarchicalView );
+ Reset();
+ }
+ return;
+ }
+
+ if ( panel == m_pVerbose )
+ {
+ vprof_verbose.SetValue( m_pVerbose->IsSelected() ? 1 : 0 );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to expand/collapse in hierarchy
+//-----------------------------------------------------------------------------
+void CVProfPanel::ExpandAll( void )
+{
+ int count = m_pHierarchy->GetTree()->GetHighestItemID();
+ int i;
+ for( i = 0; i < count; i++ )
+ {
+ if( m_pHierarchy->GetTree()->IsItemIDValid( i ) )
+ {
+ m_pHierarchy->GetTree()->ExpandItem( i, true );
+ }
+ }
+}
+
+void CVProfPanel::CollapseAll( void )
+{
+ int count = m_pHierarchy->GetTree()->GetHighestItemID();
+ int i;
+ for( i = 1; i < count; i++ )
+ {
+ if( m_pHierarchy->GetTree()->IsItemIDValid( i ) )
+ {
+ m_pHierarchy->GetTree()->ExpandItem( i, false );
+ }
+ }
+}
+
+void CVProfPanel::ExpandGroupRecursive( int nBudgetGroupID, CVProfNode *pNode )
+{
+ if( !pNode )
+ {
+ return;
+ }
+ if( pNode->GetBudgetGroupID() == nBudgetGroupID )
+ {
+ CVProfNode *pTempNode = pNode;
+ while( pTempNode )
+ {
+ if( pTempNode->GetParent() )
+ {
+ int id = pTempNode->GetParent()->GetClientData();
+ m_pHierarchy->ExpandItem( id, true );
+ }
+ pTempNode = pTempNode->GetParent();
+ }
+ }
+
+ ExpandGroupRecursive( nBudgetGroupID, pNode->GetChild() );
+ ExpandGroupRecursive( nBudgetGroupID, pNode->GetSibling() );
+}
+
+void CVProfPanel::ExpandGroup( const char *pGroupName )
+{
+ int groupID = m_pVProfile->BudgetGroupNameToBudgetGroupID( pGroupName );
+ ExpandGroupRecursive( groupID, m_pVProfile->GetRoot() );
+}
+
+class CVProfLabel : public Label
+{
+ DECLARE_CLASS_SIMPLE( CVProfLabel, Label );
+public:
+
+ CVProfLabel( Panel *parent, const char *panelName ) :
+ BaseClass( parent, panelName, "" )
+ {
+ //SetPaintBackgroundEnabled( false );
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+ SetFont( pScheme->GetFont( PROF_FONT ) );
+ SetBgColor( Color( 0, 0, 0, 255 ) );
+ }
+};
+
+Label *AllocateVprofLabel( const char *panelName )
+{
+ CVProfLabel *l = new CVProfLabel( NULL, panelName );
+ l->SetContentAlignment( Label::a_west );
+ return l;
+}
+
+void CVProfPanel::AddColumns( CProfileHierarchyPanel::ColumnPanels_t& cp )
+{
+ cp.AddColumn( 1, "group", AllocateVprofLabel( "group" ) );
+ cp.AddColumn( 2, "data", AllocateVprofLabel( "data" ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Populate the tree
+//-----------------------------------------------------------------------------
+int CVProfPanel::UpdateVProfTreeEntry( KeyValues *pKeyValues, CVProfNode *pNode, int parent )
+{
+ VPROF( "UpdateVProfTreeEntry" );
+
+ CFmtStrN<1024> msg;
+ double curTimeLessChildren = pNode->GetCurTimeLessChildren();
+ double avgLessChildren = ( pNode->GetTotalCalls() > 0 ) ? pNode->GetTotalTimeLessChildren() / (double)pNode->GetTotalCalls() : 0;
+
+ pKeyValues->SetString( "Text", pNode->GetName() );
+ pKeyValues->SetString( "group", m_pVProfile->GetBudgetGroupName( pNode->GetBudgetGroupID() ) );
+
+ CFmtStrN< 256 > frame;
+ CFmtStrN< 256 > avgstr;
+ CFmtStrN< 256 > sum;
+ CFmtStrN< 256 > l2miss;
+
+ frame.sprintf( "[%4d] %7.2f %7.2f", pNode->GetCurCalls(), pNode->GetCurTime(), curTimeLessChildren );
+
+
+ pKeyValues->SetString( "frame", msg );
+
+ if( vprof_verbose.GetBool() )
+ {
+ double avgCalls = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalCalls() / (double)m_pVProfile->NumFramesSampled() : 0;
+ double avg = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTime() / (double)m_pVProfile->NumFramesSampled() : 0;
+ double avgLessChildrenVerbose = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTimeLessChildren() / (double)m_pVProfile->NumFramesSampled() : 0;
+
+ avgstr.sprintf( "[%6.2f] %6.3f %6.3f", avgCalls, avg, avgLessChildrenVerbose );
+ sum.sprintf( "[%7d] %9.2f %9.2f %8.2fp", pNode->GetTotalCalls(), pNode->GetTotalTime(), pNode->GetTotalTimeLessChildren(), pNode->GetPeakTime() );
+ }
+
+ if ( m_pVProfile->UsePME() )
+ {
+ l2miss.sprintf( "%5d", pNode->GetL2CacheMisses() );
+ }
+
+ msg.sprintf( DATA_FMT_STR,
+ (const char *)frame,
+ (const char *)avgstr,
+ (const char *)sum,
+ (const char *)l2miss );
+ pKeyValues->SetString( "data", msg );
+
+ pKeyValues->SetFloat( "Time", avgLessChildren );
+
+ // Add or modify a line in the hierarchy
+ int id = pNode->GetClientData();
+ if ( id == -1 )
+ {
+ CProfileHierarchyPanel::ColumnPanels_t cp;
+ AddColumns( cp );
+ id = m_pHierarchy->AddItem( pKeyValues, parent, cp ) ;
+ pNode->SetClientData( id );
+ }
+ else
+ {
+ VPROF( "UpdateVProfTreeEntry:Modify" );
+ m_pHierarchy->ModifyItem( pKeyValues, id );
+ }
+
+ // Apply color to the item
+ int r,g,b,a;
+ m_pVProfile->GetBudgetGroupColor( pNode->GetBudgetGroupID(), r, g, b, a );
+ m_pHierarchy->SetItemColors( id, Color( r, g, b, a ), Color( 0, 0, 0, 255 ) );
+
+ if( pNode->GetBudgetGroupID() == VPROF_BUDGET_GROUP_ID_UNACCOUNTED )
+ {
+ if ( curTimeLessChildren > vprof_unaccounted_limit.GetFloat() )
+ {
+ m_pHierarchy->SetItemColors( id, Color( 255, 0, 0, 255 ), Color( 0, 0, 0, 255 ) );
+ }
+ }
+
+ if ( pNode->GetCurTime() > vprof_warningmsec.GetFloat() ||
+ curTimeLessChildren > vprof_warningmsec.GetFloat() )
+ {
+ m_pHierarchy->SetItemColumnColors( id, 2, Color( 255, 0, 0, 255 ), Color( 63, 0, 0, 255 ) );
+ }
+ return id;
+}
+
+//-----------------------------------------------------------------------------
+// Populate the tree
+//-----------------------------------------------------------------------------
+void CVProfPanel::FillTree( KeyValues *pKeyValues, CVProfNode *pNode, int parent )
+{
+#ifdef VPROF_ENABLED
+
+ bool fIsRoot = ( pNode == m_pVProfile->GetRoot() );
+ if ( fIsRoot )
+ {
+ if( pNode->GetChild() )
+ {
+ FillTree( pKeyValues, pNode->GetChild(), parent );
+ }
+ return;
+ }
+
+ int id = parent;
+ if (( m_nCurrentBudgetGroup < 0 ) || ( pNode->GetBudgetGroupID() == m_nCurrentBudgetGroup ))
+ {
+ id = UpdateVProfTreeEntry( pKeyValues, pNode, parent );
+ }
+
+ if( pNode->GetSibling() )
+ {
+ FillTree( pKeyValues, pNode->GetSibling(), parent );
+ }
+
+ if( pNode->GetChild() )
+ {
+ FillTree( pKeyValues, pNode->GetChild(), m_bHierarchicalView ? id : parent );
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Populates the budget group combo box
+//-----------------------------------------------------------------------------
+void CVProfPanel::PopulateBudgetGroupComboBox()
+{
+ int nBudgetGroupCount = m_pVProfile->GetNumBudgetGroups();
+ while( m_nLastBudgetGroupCount < nBudgetGroupCount )
+ {
+ m_pVProfCategory->AddItem( m_pVProfile->GetBudgetGroupName(m_nLastBudgetGroupCount), NULL );
+ ++m_nLastBudgetGroupCount;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Populates the tree
+//-----------------------------------------------------------------------------
+void CVProfPanel::UpdateProfile( float filteredtime )
+{
+#ifdef VPROF_ENABLED
+ //ExecuteDeferredOp();
+ if (IsVisible())
+ {
+ PopulateBudgetGroupComboBox();
+
+ SetTitle( CFmtStr( "VProf (%s) -- %d frames sampled",
+ m_pVProfile->IsEnabled() ? "running" : "not running",
+ m_pVProfile->NumFramesSampled() ), false );
+
+ // It's important to cache bEnabled since calling pause can disable.
+ bool bEnabled = m_pVProfile->IsEnabled();
+ if( bEnabled )
+ {
+ m_pVProfile->Pause();
+ }
+
+ KeyValues * pVal = new KeyValues("");
+
+ if ( !m_pHierarchy->GetTree()->GetItemCount() )
+ {
+ pVal->SetString( "Text", "Call tree" );
+ CProfileHierarchyPanel::ColumnPanels_t cp;
+ AddColumns( cp );
+ m_RootItem = m_pHierarchy->AddItem( pVal, -1, cp );
+ m_pHierarchy->SetItemColors( m_RootItem, Color( 255, 255, 255, 255 ), Color( 0, 0, 0, 255 ) );
+ m_pHierarchy->ExpandItem( m_RootItem, true );
+ }
+
+ m_pHierarchy->ExpandItem( m_RootItem, true );
+
+ const char *pScope = vprof_scope.GetString();
+ CVProfNode *pStartNode = ( pScope[0] == 0 ) ? m_pVProfile->GetRoot() : m_pVProfile->FindNode(m_pVProfile->GetRoot(), pScope );
+
+ if ( pStartNode )
+ {
+ FillTree( pVal, pStartNode, m_RootItem );
+ }
+
+ pVal->deleteThis();
+
+ if( bEnabled )
+ {
+ m_pVProfile->Resume();
+ }
+ }
+
+ if ( m_pVProfile->IsEnabled() )
+ {
+ Assert( m_pVProfile->AtRoot() );
+
+ if ( GetBudgetPanel()->IsBudgetPanelShown() )
+ GetBudgetPanel()->SnapshotVProfHistory( filteredtime );
+
+ WriteRemoteVProfData(); // send out the vprof data to remote endpoints
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVProfPanel::UserCmd_ShowVProf( void )
+{
+ m_fShowVprofHeld = true;
+
+ SetVisible( true );
+ // This is hacky . . need to at least remember the previous value to set it back.
+ ConVarRef cl_mouseenable( "cl_mouseenable" );
+ if ( cl_mouseenable.IsValid() )
+ {
+ cl_mouseenable.SetValue( 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVProfPanel::UserCmd_HideVProf( void )
+{
+ m_fShowVprofHeld = false;
+
+ SetVisible( false );
+
+ // This is hacky . . need to at least remember the previous value to set it back.
+ ConVarRef cl_mouseenable( "cl_mouseenable" );
+ if ( cl_mouseenable.IsValid() )
+ {
+ cl_mouseenable.SetValue( 1 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+
+void CVProfPanel::Paint()
+{
+ m_pVProfile->Pause();
+ BaseClass::Paint();
+ m_pVProfile->Resume();
+}
+
+
+void CVProfPanel::OnCommand( const char *pCommand )
+{
+#ifndef _XBOX
+ if ( !Q_stricmp( pCommand, "StepForward" ) )
+ {
+ VProfPlayback_Step();
+ }
+ else if ( !Q_stricmp( pCommand, "StepBack" ) )
+ {
+ int shouldReset = VProfPlayback_StepBack();
+ if ( shouldReset == 2 )
+ {
+ Reset();
+ }
+ }
+ else if ( !Q_stricmp( pCommand, "GotoButton" ) )
+ {
+ int shouldReset = VProfPlayback_SeekToPercent( (float)m_pPlaybackScroll->GetValue() / 1000.0 );
+ if ( shouldReset == 2 )
+ {
+ Reset();
+ }
+ }
+ else if ( !Q_stricmp( pCommand, "redosort" ) )
+ {
+ //
+ Assert( !m_bHierarchicalView );
+ Reset();
+ }
+#endif
+}
+
+#endif