summaryrefslogtreecommitdiff
path: root/engine/vgui_vprofgraphpanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/vgui_vprofgraphpanel.cpp')
-rw-r--r--engine/vgui_vprofgraphpanel.cpp435
1 files changed, 435 insertions, 0 deletions
diff --git a/engine/vgui_vprofgraphpanel.cpp b/engine/vgui_vprofgraphpanel.cpp
new file mode 100644
index 0000000..81efcc1
--- /dev/null
+++ b/engine/vgui_vprofgraphpanel.cpp
@@ -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
+}
+
+
+