1
This commit is contained in:
435
engine/vgui_vprofgraphpanel.cpp
Normal file
435
engine/vgui_vprofgraphpanel.cpp
Normal file
@ -0,0 +1,435 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "client_pch.h"
|
||||
|
||||
#include "ivideomode.h"
|
||||
#include "VGuiMatSurface/IMatSystemSurface.h"
|
||||
#include <vgui_controls/Panel.h>
|
||||
#include <vgui_controls/Controls.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <vgui/IScheme.h>
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/MaterialSystemUtil.h"
|
||||
#include "client.h"
|
||||
#include "gl_matsysiface.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef VPROF_ENABLED
|
||||
|
||||
static ConVar vprof_graph ( "vprof_graph","0", 0, "Draw the vprof graph." );
|
||||
static ConVar vprof_graphwidth ( "vprof_graphwidth", "512", FCVAR_ARCHIVE );
|
||||
static ConVar vprof_graphheight( "vprof_graphheight", "256", FCVAR_ARCHIVE );
|
||||
|
||||
#define TIMINGS 256 // Number of values to track (must be power of 2) b/c of masking
|
||||
|
||||
#define GRAPH_RED (0.9f * 255)
|
||||
#define GRAPH_GREEN (0.9f * 255)
|
||||
#define GRAPH_BLUE (0.7f * 255)
|
||||
|
||||
#define LERP_HEIGHT 24
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Displays the netgraph
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVProfGraphPanel : public vgui::Panel
|
||||
{
|
||||
typedef vgui::Panel BaseClass;
|
||||
private:
|
||||
|
||||
vgui::HFont m_hFont;
|
||||
|
||||
public:
|
||||
CVProfGraphPanel( vgui::VPANEL parent );
|
||||
virtual ~CVProfGraphPanel( void );
|
||||
|
||||
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
|
||||
virtual void Paint();
|
||||
virtual void OnTick( void );
|
||||
|
||||
virtual bool ShouldDraw( void );
|
||||
|
||||
|
||||
struct CLineSegment
|
||||
{
|
||||
int x1, y1, x2, y2;
|
||||
byte color[4];
|
||||
};
|
||||
|
||||
inline void DrawLine( vrect_t *rect, unsigned char *color, unsigned char alpha );
|
||||
|
||||
void DrawLineSegments();
|
||||
|
||||
void GraphGetXY( vrect_t *rect, int width, int *x, int *y );
|
||||
|
||||
private:
|
||||
|
||||
void PaintLineArt( int x, int y, int w );
|
||||
|
||||
CMaterialReference m_WhiteMaterial;
|
||||
|
||||
// VProf interface:
|
||||
float m_Samples[ TIMINGS ][3];
|
||||
CVProfNode* m_Components;
|
||||
|
||||
int m_CurrentSample;
|
||||
|
||||
void GetNextSample();
|
||||
|
||||
public:
|
||||
static CVProfNode* m_CurrentNode;
|
||||
};
|
||||
|
||||
CVProfNode* CVProfGraphPanel::m_CurrentNode = NULL;
|
||||
|
||||
|
||||
void IN_VProfPrevSibling(void)
|
||||
{
|
||||
CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetPrevSibling();
|
||||
if( n )
|
||||
CVProfGraphPanel::m_CurrentNode = n;
|
||||
}
|
||||
|
||||
void IN_VProfNextSibling(void)
|
||||
{
|
||||
CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetSibling();
|
||||
if( n )
|
||||
CVProfGraphPanel::m_CurrentNode = n;
|
||||
|
||||
}
|
||||
|
||||
void IN_VProfParent(void)
|
||||
{
|
||||
CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetParent();
|
||||
if( n )
|
||||
CVProfGraphPanel::m_CurrentNode = n;
|
||||
|
||||
}
|
||||
|
||||
void IN_VProfChild(void)
|
||||
{
|
||||
CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetChild();
|
||||
if( n )
|
||||
{
|
||||
// Find the largest child:
|
||||
CVProfGraphPanel::m_CurrentNode = n;
|
||||
|
||||
for( ; n; n = n->GetSibling() )
|
||||
{
|
||||
if( n->GetPrevTime() > CVProfGraphPanel::m_CurrentNode->GetPrevTime() )
|
||||
CVProfGraphPanel::m_CurrentNode = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ConCommand vprof_siblingprev ("vprof_prevsibling", IN_VProfPrevSibling);
|
||||
static ConCommand vprof_siblingnext ("vprof_nextsibling", IN_VProfNextSibling);
|
||||
static ConCommand vprof_parent ("vprof_parent", IN_VProfParent);
|
||||
static ConCommand vprof_child ("vprof_child", IN_VProfChild);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *parent -
|
||||
//-----------------------------------------------------------------------------
|
||||
CVProfGraphPanel::CVProfGraphPanel( vgui::VPANEL parent ) : BaseClass( NULL, "CVProfGraphPanel" )
|
||||
{
|
||||
SetParent( parent );
|
||||
SetSize( videomode->GetModeStereoWidth(), videomode->GetModeStereoHeight() );
|
||||
SetPos( 0, 0 );
|
||||
SetVisible( false );
|
||||
SetCursor( null );
|
||||
|
||||
m_hFont = 0;
|
||||
|
||||
SetFgColor( Color( 0, 0, 0, 255 ) );
|
||||
SetPaintBackgroundEnabled( false );
|
||||
|
||||
memset( m_Samples, 0, sizeof( m_Samples ) );
|
||||
m_CurrentSample = 0;
|
||||
m_CurrentNode = g_VProfCurrentProfile.GetRoot();
|
||||
|
||||
// Move down to an interesting node ( the render / sound / etc level)
|
||||
if( m_CurrentNode->GetChild() )
|
||||
{
|
||||
m_CurrentNode = m_CurrentNode->GetChild();
|
||||
|
||||
if( m_CurrentNode->GetChild() )
|
||||
{
|
||||
m_CurrentNode = m_CurrentNode->GetChild();
|
||||
}
|
||||
}
|
||||
|
||||
vgui::ivgui()->AddTickSignal( GetVPanel() );
|
||||
|
||||
m_WhiteMaterial.Init( "vgui/white", TEXTURE_GROUP_OTHER );
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CVProfGraphPanel::~CVProfGraphPanel( void )
|
||||
{
|
||||
}
|
||||
|
||||
void CVProfGraphPanel::ApplySchemeSettings(vgui::IScheme *pScheme)
|
||||
{
|
||||
BaseClass::ApplySchemeSettings(pScheme);
|
||||
|
||||
m_hFont = pScheme->GetFont( "DefaultVerySmall" );
|
||||
Assert( m_hFont );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Figure out x and y position for graph based on vprof_graphpos
|
||||
// value.
|
||||
// Input : *rect -
|
||||
// width -
|
||||
// *x -
|
||||
// *y -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVProfGraphPanel::GraphGetXY( vrect_t *rect, int width, int *x, int *y )
|
||||
{
|
||||
*x = rect->x + rect->width - 5 - width;
|
||||
*y = rect->y+rect->height - LERP_HEIGHT - 5;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVProfGraphPanel::OnTick( void )
|
||||
{
|
||||
SetVisible( ShouldDraw() );
|
||||
|
||||
}
|
||||
|
||||
bool CVProfGraphPanel::ShouldDraw( void )
|
||||
{
|
||||
return vprof_graph.GetBool();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVProfGraphPanel::Paint()
|
||||
{
|
||||
int x, y, w;
|
||||
vrect_t vrect;
|
||||
|
||||
if ( ( ShouldDraw() ) == false )
|
||||
return;
|
||||
|
||||
// Get screen rectangle
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = videomode->GetModeStereoWidth();
|
||||
vrect.height = videomode->GetModeStereoHeight();
|
||||
|
||||
// Determine graph width
|
||||
w = vprof_graphwidth.GetInt();
|
||||
if ( vrect.width < w + 10 )
|
||||
{
|
||||
w = vrect.width - 10;
|
||||
}
|
||||
|
||||
// Get the graph's location:
|
||||
GraphGetXY( &vrect, w, &x, &y );
|
||||
|
||||
PaintLineArt( x, y, w );
|
||||
|
||||
// Draw the text overlays:
|
||||
|
||||
// Print it out
|
||||
y -= vprof_graphheight.GetInt();
|
||||
|
||||
double RootTime = g_VProfCurrentProfile.GetRoot()->GetPrevTime();
|
||||
|
||||
char sz[256];
|
||||
if ( ( g_ClientGlobalVariables.absoluteframetime) > 0.f )
|
||||
{
|
||||
Q_snprintf( sz, sizeof( sz ), "%s - %0.1f%%%%", m_CurrentNode->GetName(), ( m_CurrentNode->GetPrevTime() / RootTime ) * 100.f);
|
||||
g_pMatSystemSurface->DrawColoredText( m_hFont, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, "%s", sz );
|
||||
}
|
||||
|
||||
byte color[3][3] =
|
||||
{
|
||||
{ 255, 0, 0 },
|
||||
{ 0, 0, 255 },
|
||||
{ 255, 255, 255 },
|
||||
};
|
||||
|
||||
const char *pTitles[3];
|
||||
pTitles[0] = m_CurrentNode->GetName();
|
||||
pTitles[1] = "Parent";
|
||||
pTitles[2] = "Total";
|
||||
|
||||
// Draw the legend:
|
||||
x += w / 2;
|
||||
for( int i = 3; --i >= 0; )
|
||||
{
|
||||
Q_snprintf( sz, sizeof( sz ), "%07.3f ms (%s)", m_Samples[m_CurrentSample][i], pTitles[i] );
|
||||
y -= 10;
|
||||
g_pMatSystemSurface->DrawColoredText( m_hFont, x, y, color[i][0], color[i][1], color[i][2], 180, "%s", sz );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// VProf interface:
|
||||
void CVProfGraphPanel::GetNextSample()
|
||||
{
|
||||
// Increment to the next sample:
|
||||
m_CurrentSample = ( m_CurrentSample + 1 ) % TIMINGS;
|
||||
m_Samples[m_CurrentSample][0] = m_CurrentNode->GetPrevTime();
|
||||
m_Samples[m_CurrentSample][1] = m_CurrentNode->GetParent() ? m_CurrentNode->GetParent()->GetPrevTime() : m_CurrentNode->GetPrevTime();
|
||||
m_Samples[m_CurrentSample][2] = g_VProfCurrentProfile.GetRoot()->GetPrevTime();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVProfGraphPanel::PaintLineArt( int x, int y, int w )
|
||||
{
|
||||
int nPanelHeight = vprof_graphheight.GetFloat() - LERP_HEIGHT - 2;
|
||||
int h, a;
|
||||
|
||||
// Update the sample graph:
|
||||
GetNextSample();
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
|
||||
IMesh* m_pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteMaterial );
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( m_pMesh, MATERIAL_LINES, 3 * w + 4 );
|
||||
|
||||
// Draw lines at 20, 30, 60 hz, and baseline
|
||||
int i;
|
||||
for ( i = 0; i < 4; ++i )
|
||||
{
|
||||
int nLineY = y - (nPanelHeight / 3) * i;
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
meshBuilder.Color4ub( 255, 255, 255, 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
meshBuilder.Color4ub( 128, 128, 128, 255 );
|
||||
}
|
||||
|
||||
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
|
||||
meshBuilder.Position3f( x, nLineY, 0 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
meshBuilder.Color4ub( 255, 255, 255, 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
meshBuilder.Color4ub( 128, 128, 128, 255 );
|
||||
}
|
||||
|
||||
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
|
||||
meshBuilder.Position3f( x + w, nLineY, 0 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
|
||||
byte color[3][4] =
|
||||
{
|
||||
{ 255, 0, 0, 255 },
|
||||
{ 0, 0, 255, 255 },
|
||||
{ 255, 255, 255, 255 },
|
||||
};
|
||||
|
||||
// 0.05f = 1/20 = 20Hz
|
||||
float flMsToPixel = nPanelHeight / 50.0f;
|
||||
float flDxDSample = (w <= TIMINGS) ? 1.0f : (float)w / (float)TIMINGS;
|
||||
|
||||
for( i = 3; --i >= 0; )
|
||||
{
|
||||
int sample = m_CurrentSample;
|
||||
for (a=w; a >= 0; a-- )
|
||||
{
|
||||
h = (int)(m_Samples[sample][i] * flMsToPixel + 0.5f);
|
||||
|
||||
// Clamp the height: (though it shouldn't need it)
|
||||
if ( h > nPanelHeight )
|
||||
{
|
||||
h = nPanelHeight;
|
||||
}
|
||||
|
||||
int px = (int)(x + (w - a - 1) * flDxDSample + 0.5f);
|
||||
int py = y - h;
|
||||
|
||||
meshBuilder.Color4ubv( color[i] );
|
||||
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
|
||||
meshBuilder.Position3f( px, py, 0 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
if ( ( a != w ) && ( a != 0 ) )
|
||||
{
|
||||
meshBuilder.Color4ubv( color[i] );
|
||||
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
|
||||
meshBuilder.Position3f( px, py, 0 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
|
||||
// Move on to the next sample:
|
||||
sample--;
|
||||
if ( sample < 0 )
|
||||
{
|
||||
sample = TIMINGS - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
meshBuilder.End();
|
||||
m_pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
#endif // VPROF_ENABLED
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates/destroys the vprof graph panel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef VPROF_ENABLED
|
||||
static CVProfGraphPanel *s_pVProfGraphPanel = NULL;
|
||||
#endif
|
||||
|
||||
void CreateVProfGraphPanel( vgui::Panel *pParent )
|
||||
{
|
||||
#ifdef VPROF_ENABLED
|
||||
s_pVProfGraphPanel = new CVProfGraphPanel( pParent->GetVPanel() );
|
||||
#endif
|
||||
}
|
||||
|
||||
void DestroyVProfGraphPanel()
|
||||
{
|
||||
#ifdef VPROF_ENABLED
|
||||
if ( s_pVProfGraphPanel )
|
||||
{
|
||||
s_pVProfGraphPanel->SetParent( (vgui::Panel *)NULL );
|
||||
delete s_pVProfGraphPanel;
|
||||
s_pVProfGraphPanel = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user