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.
435 lines
10 KiB
435 lines
10 KiB
//========= 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 |
|
} |
|
|
|
|
|
|
|
|