Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "client_pch.h"
  10. #include "ivideomode.h"
  11. #include "VGuiMatSurface/IMatSystemSurface.h"
  12. #include <vgui_controls/Panel.h>
  13. #include <vgui_controls/Controls.h>
  14. #include <vgui/ISurface.h>
  15. #include <vgui/IScheme.h>
  16. #include "materialsystem/imaterialsystem.h"
  17. #include "materialsystem/imesh.h"
  18. #include "materialsystem/imaterial.h"
  19. #include "materialsystem/MaterialSystemUtil.h"
  20. #include "client.h"
  21. #include "gl_matsysiface.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include "tier0/memdbgon.h"
  24. #ifdef VPROF_ENABLED
  25. static ConVar vprof_graph ( "vprof_graph","0", 0, "Draw the vprof graph." );
  26. static ConVar vprof_graphwidth ( "vprof_graphwidth", "512", FCVAR_ARCHIVE );
  27. static ConVar vprof_graphheight( "vprof_graphheight", "256", FCVAR_ARCHIVE );
  28. #define TIMINGS 256 // Number of values to track (must be power of 2) b/c of masking
  29. #define GRAPH_RED (0.9f * 255)
  30. #define GRAPH_GREEN (0.9f * 255)
  31. #define GRAPH_BLUE (0.7f * 255)
  32. #define LERP_HEIGHT 24
  33. //-----------------------------------------------------------------------------
  34. // Purpose: Displays the netgraph
  35. //-----------------------------------------------------------------------------
  36. class CVProfGraphPanel : public vgui::Panel
  37. {
  38. typedef vgui::Panel BaseClass;
  39. private:
  40. vgui::HFont m_hFont;
  41. public:
  42. CVProfGraphPanel( vgui::VPANEL parent );
  43. virtual ~CVProfGraphPanel( void );
  44. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  45. virtual void Paint();
  46. virtual void OnTick( void );
  47. virtual bool ShouldDraw( void );
  48. struct CLineSegment
  49. {
  50. int x1, y1, x2, y2;
  51. byte color[4];
  52. };
  53. inline void DrawLine( vrect_t *rect, unsigned char *color, unsigned char alpha );
  54. void DrawLineSegments();
  55. void GraphGetXY( vrect_t *rect, int width, int *x, int *y );
  56. private:
  57. void PaintLineArt( int x, int y, int w );
  58. CMaterialReference m_WhiteMaterial;
  59. // VProf interface:
  60. float m_Samples[ TIMINGS ][3];
  61. CVProfNode* m_Components;
  62. int m_CurrentSample;
  63. void GetNextSample();
  64. public:
  65. static CVProfNode* m_CurrentNode;
  66. };
  67. CVProfNode* CVProfGraphPanel::m_CurrentNode = NULL;
  68. void IN_VProfPrevSibling(void)
  69. {
  70. CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetPrevSibling();
  71. if( n )
  72. CVProfGraphPanel::m_CurrentNode = n;
  73. }
  74. void IN_VProfNextSibling(void)
  75. {
  76. CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetSibling();
  77. if( n )
  78. CVProfGraphPanel::m_CurrentNode = n;
  79. }
  80. void IN_VProfParent(void)
  81. {
  82. CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetParent();
  83. if( n )
  84. CVProfGraphPanel::m_CurrentNode = n;
  85. }
  86. void IN_VProfChild(void)
  87. {
  88. CVProfNode* n = CVProfGraphPanel::m_CurrentNode->GetChild();
  89. if( n )
  90. {
  91. // Find the largest child:
  92. CVProfGraphPanel::m_CurrentNode = n;
  93. for( ; n; n = n->GetSibling() )
  94. {
  95. if( n->GetPrevTime() > CVProfGraphPanel::m_CurrentNode->GetPrevTime() )
  96. CVProfGraphPanel::m_CurrentNode = n;
  97. }
  98. }
  99. }
  100. static ConCommand vprof_siblingprev ("vprof_prevsibling", IN_VProfPrevSibling);
  101. static ConCommand vprof_siblingnext ("vprof_nextsibling", IN_VProfNextSibling);
  102. static ConCommand vprof_parent ("vprof_parent", IN_VProfParent);
  103. static ConCommand vprof_child ("vprof_child", IN_VProfChild);
  104. //-----------------------------------------------------------------------------
  105. // Purpose:
  106. // Input : *parent -
  107. //-----------------------------------------------------------------------------
  108. CVProfGraphPanel::CVProfGraphPanel( vgui::VPANEL parent ) : BaseClass( NULL, "CVProfGraphPanel" )
  109. {
  110. SetParent( parent );
  111. SetSize( videomode->GetModeStereoWidth(), videomode->GetModeStereoHeight() );
  112. SetPos( 0, 0 );
  113. SetVisible( false );
  114. SetCursor( null );
  115. m_hFont = 0;
  116. SetFgColor( Color( 0, 0, 0, 255 ) );
  117. SetPaintBackgroundEnabled( false );
  118. memset( m_Samples, 0, sizeof( m_Samples ) );
  119. m_CurrentSample = 0;
  120. m_CurrentNode = g_VProfCurrentProfile.GetRoot();
  121. // Move down to an interesting node ( the render / sound / etc level)
  122. if( m_CurrentNode->GetChild() )
  123. {
  124. m_CurrentNode = m_CurrentNode->GetChild();
  125. if( m_CurrentNode->GetChild() )
  126. {
  127. m_CurrentNode = m_CurrentNode->GetChild();
  128. }
  129. }
  130. vgui::ivgui()->AddTickSignal( GetVPanel() );
  131. m_WhiteMaterial.Init( "vgui/white", TEXTURE_GROUP_OTHER );
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Purpose:
  135. //-----------------------------------------------------------------------------
  136. CVProfGraphPanel::~CVProfGraphPanel( void )
  137. {
  138. }
  139. void CVProfGraphPanel::ApplySchemeSettings(vgui::IScheme *pScheme)
  140. {
  141. BaseClass::ApplySchemeSettings(pScheme);
  142. m_hFont = pScheme->GetFont( "DefaultVerySmall" );
  143. Assert( m_hFont );
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose: Figure out x and y position for graph based on vprof_graphpos
  147. // value.
  148. // Input : *rect -
  149. // width -
  150. // *x -
  151. // *y -
  152. //-----------------------------------------------------------------------------
  153. void CVProfGraphPanel::GraphGetXY( vrect_t *rect, int width, int *x, int *y )
  154. {
  155. *x = rect->x + rect->width - 5 - width;
  156. *y = rect->y+rect->height - LERP_HEIGHT - 5;
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose:
  160. //-----------------------------------------------------------------------------
  161. void CVProfGraphPanel::OnTick( void )
  162. {
  163. SetVisible( ShouldDraw() );
  164. }
  165. bool CVProfGraphPanel::ShouldDraw( void )
  166. {
  167. return vprof_graph.GetBool();
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose:
  171. //-----------------------------------------------------------------------------
  172. void CVProfGraphPanel::Paint()
  173. {
  174. int x, y, w;
  175. vrect_t vrect;
  176. if ( ( ShouldDraw() ) == false )
  177. return;
  178. // Get screen rectangle
  179. vrect.x = 0;
  180. vrect.y = 0;
  181. vrect.width = videomode->GetModeStereoWidth();
  182. vrect.height = videomode->GetModeStereoHeight();
  183. // Determine graph width
  184. w = vprof_graphwidth.GetInt();
  185. if ( vrect.width < w + 10 )
  186. {
  187. w = vrect.width - 10;
  188. }
  189. // Get the graph's location:
  190. GraphGetXY( &vrect, w, &x, &y );
  191. PaintLineArt( x, y, w );
  192. // Draw the text overlays:
  193. // Print it out
  194. y -= vprof_graphheight.GetInt();
  195. double RootTime = g_VProfCurrentProfile.GetRoot()->GetPrevTime();
  196. char sz[256];
  197. if ( ( g_ClientGlobalVariables.absoluteframetime) > 0.f )
  198. {
  199. Q_snprintf( sz, sizeof( sz ), "%s - %0.1f%%%%", m_CurrentNode->GetName(), ( m_CurrentNode->GetPrevTime() / RootTime ) * 100.f);
  200. g_pMatSystemSurface->DrawColoredText( m_hFont, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, "%s", sz );
  201. }
  202. byte color[3][3] =
  203. {
  204. { 255, 0, 0 },
  205. { 0, 0, 255 },
  206. { 255, 255, 255 },
  207. };
  208. const char *pTitles[3];
  209. pTitles[0] = m_CurrentNode->GetName();
  210. pTitles[1] = "Parent";
  211. pTitles[2] = "Total";
  212. // Draw the legend:
  213. x += w / 2;
  214. for( int i = 3; --i >= 0; )
  215. {
  216. Q_snprintf( sz, sizeof( sz ), "%07.3f ms (%s)", m_Samples[m_CurrentSample][i], pTitles[i] );
  217. y -= 10;
  218. g_pMatSystemSurface->DrawColoredText( m_hFont, x, y, color[i][0], color[i][1], color[i][2], 180, "%s", sz );
  219. }
  220. }
  221. // VProf interface:
  222. void CVProfGraphPanel::GetNextSample()
  223. {
  224. // Increment to the next sample:
  225. m_CurrentSample = ( m_CurrentSample + 1 ) % TIMINGS;
  226. m_Samples[m_CurrentSample][0] = m_CurrentNode->GetPrevTime();
  227. m_Samples[m_CurrentSample][1] = m_CurrentNode->GetParent() ? m_CurrentNode->GetParent()->GetPrevTime() : m_CurrentNode->GetPrevTime();
  228. m_Samples[m_CurrentSample][2] = g_VProfCurrentProfile.GetRoot()->GetPrevTime();
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose:
  232. //-----------------------------------------------------------------------------
  233. void CVProfGraphPanel::PaintLineArt( int x, int y, int w )
  234. {
  235. int nPanelHeight = vprof_graphheight.GetFloat() - LERP_HEIGHT - 2;
  236. int h, a;
  237. // Update the sample graph:
  238. GetNextSample();
  239. CMatRenderContextPtr pRenderContext( materials );
  240. IMesh* m_pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteMaterial );
  241. CMeshBuilder meshBuilder;
  242. meshBuilder.Begin( m_pMesh, MATERIAL_LINES, 3 * w + 4 );
  243. // Draw lines at 20, 30, 60 hz, and baseline
  244. int i;
  245. for ( i = 0; i < 4; ++i )
  246. {
  247. int nLineY = y - (nPanelHeight / 3) * i;
  248. if ( i == 0 )
  249. {
  250. meshBuilder.Color4ub( 255, 255, 255, 255 );
  251. }
  252. else
  253. {
  254. meshBuilder.Color4ub( 128, 128, 128, 255 );
  255. }
  256. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  257. meshBuilder.Position3f( x, nLineY, 0 );
  258. meshBuilder.AdvanceVertex();
  259. if ( i == 0 )
  260. {
  261. meshBuilder.Color4ub( 255, 255, 255, 255 );
  262. }
  263. else
  264. {
  265. meshBuilder.Color4ub( 128, 128, 128, 255 );
  266. }
  267. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  268. meshBuilder.Position3f( x + w, nLineY, 0 );
  269. meshBuilder.AdvanceVertex();
  270. }
  271. byte color[3][4] =
  272. {
  273. { 255, 0, 0, 255 },
  274. { 0, 0, 255, 255 },
  275. { 255, 255, 255, 255 },
  276. };
  277. // 0.05f = 1/20 = 20Hz
  278. float flMsToPixel = nPanelHeight / 50.0f;
  279. float flDxDSample = (w <= TIMINGS) ? 1.0f : (float)w / (float)TIMINGS;
  280. for( i = 3; --i >= 0; )
  281. {
  282. int sample = m_CurrentSample;
  283. for (a=w; a >= 0; a-- )
  284. {
  285. h = (int)(m_Samples[sample][i] * flMsToPixel + 0.5f);
  286. // Clamp the height: (though it shouldn't need it)
  287. if ( h > nPanelHeight )
  288. {
  289. h = nPanelHeight;
  290. }
  291. int px = (int)(x + (w - a - 1) * flDxDSample + 0.5f);
  292. int py = y - h;
  293. meshBuilder.Color4ubv( color[i] );
  294. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  295. meshBuilder.Position3f( px, py, 0 );
  296. meshBuilder.AdvanceVertex();
  297. if ( ( a != w ) && ( a != 0 ) )
  298. {
  299. meshBuilder.Color4ubv( color[i] );
  300. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  301. meshBuilder.Position3f( px, py, 0 );
  302. meshBuilder.AdvanceVertex();
  303. }
  304. // Move on to the next sample:
  305. sample--;
  306. if ( sample < 0 )
  307. {
  308. sample = TIMINGS - 1;
  309. }
  310. }
  311. }
  312. meshBuilder.End();
  313. m_pMesh->Draw();
  314. }
  315. #endif // VPROF_ENABLED
  316. //-----------------------------------------------------------------------------
  317. // Creates/destroys the vprof graph panel
  318. //-----------------------------------------------------------------------------
  319. #ifdef VPROF_ENABLED
  320. static CVProfGraphPanel *s_pVProfGraphPanel = NULL;
  321. #endif
  322. void CreateVProfGraphPanel( vgui::Panel *pParent )
  323. {
  324. #ifdef VPROF_ENABLED
  325. s_pVProfGraphPanel = new CVProfGraphPanel( pParent->GetVPanel() );
  326. #endif
  327. }
  328. void DestroyVProfGraphPanel()
  329. {
  330. #ifdef VPROF_ENABLED
  331. if ( s_pVProfGraphPanel )
  332. {
  333. s_pVProfGraphPanel->SetParent( (vgui::Panel *)NULL );
  334. delete s_pVProfGraphPanel;
  335. s_pVProfGraphPanel = NULL;
  336. }
  337. #endif
  338. }