diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/vgui_vprofpanel.cpp | |
| download | archived-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.cpp | 1155 |
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 |