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.

274 lines
7.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <stdlib.h>
  7. #include <tier0/dbg.h>
  8. #include "interface.h"
  9. #include "istudiorender.h"
  10. #include "studio.h"
  11. #include "optimize.h"
  12. #include "cmdlib.h"
  13. #include "studiomdl.h"
  14. #include "perfstats.h"
  15. extern void MdlError( char const *pMsg, ... );
  16. static StudioRenderConfig_t s_StudioRenderConfig;
  17. class CStudioDataCache : public CBaseAppSystem<IStudioDataCache>
  18. {
  19. public:
  20. bool VerifyHeaders( studiohdr_t *pStudioHdr );
  21. vertexFileHeader_t *CacheVertexData( studiohdr_t *pStudioHdr );
  22. };
  23. static CStudioDataCache g_StudioDataCache;
  24. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CStudioDataCache, IStudioDataCache, STUDIO_DATA_CACHE_INTERFACE_VERSION, g_StudioDataCache );
  25. /*
  26. =================
  27. VerifyHeaders
  28. Minimal presence and header validation, no data loads
  29. Return true if successful, false otherwise.
  30. =================
  31. */
  32. bool CStudioDataCache::VerifyHeaders( studiohdr_t *pStudioHdr )
  33. {
  34. // default valid
  35. return true;
  36. }
  37. /*
  38. =================
  39. CacheVertexData
  40. Cache model's specified dynamic data
  41. =================
  42. */
  43. vertexFileHeader_t *CStudioDataCache::CacheVertexData( studiohdr_t *pStudioHdr )
  44. {
  45. // minimal implementation - return persisted data
  46. return (vertexFileHeader_t*)pStudioHdr->pVertexBase;
  47. }
  48. static void UpdateStudioRenderConfig( void )
  49. {
  50. memset( &s_StudioRenderConfig, 0, sizeof(s_StudioRenderConfig) );
  51. s_StudioRenderConfig.bEyeMove = true;
  52. s_StudioRenderConfig.fEyeShiftX = 0.0f;
  53. s_StudioRenderConfig.fEyeShiftY = 0.0f;
  54. s_StudioRenderConfig.fEyeShiftZ = 0.0f;
  55. s_StudioRenderConfig.fEyeSize = 10.0f;
  56. s_StudioRenderConfig.bSoftwareSkin = false;
  57. s_StudioRenderConfig.bNoHardware = false;
  58. s_StudioRenderConfig.bNoSoftware = false;
  59. s_StudioRenderConfig.bTeeth = true;
  60. s_StudioRenderConfig.drawEntities = true;
  61. s_StudioRenderConfig.bFlex = true;
  62. s_StudioRenderConfig.bEyes = true;
  63. s_StudioRenderConfig.bWireframe = false;
  64. s_StudioRenderConfig.bDrawNormals = false;
  65. s_StudioRenderConfig.skin = 0;
  66. s_StudioRenderConfig.maxDecalsPerModel = 0;
  67. s_StudioRenderConfig.bWireframeDecals = false;
  68. s_StudioRenderConfig.fullbright = false;
  69. s_StudioRenderConfig.bSoftwareLighting = false;
  70. s_StudioRenderConfig.bShowEnvCubemapOnly = false;
  71. g_pStudioRender->UpdateConfig( s_StudioRenderConfig );
  72. }
  73. static SpewOutputFunc_t s_pSavedSpewFunc;
  74. SpewRetval_t NullSpewOutputFunc( SpewType_t spewType, const tchar *pMsg )
  75. {
  76. switch( spewType )
  77. {
  78. case SPEW_WARNING:
  79. return SPEW_CONTINUE;
  80. case SPEW_MESSAGE:
  81. case SPEW_ASSERT:
  82. case SPEW_ERROR:
  83. case SPEW_LOG:
  84. Assert( s_pSavedSpewFunc );
  85. if( s_pSavedSpewFunc )
  86. {
  87. return s_pSavedSpewFunc( spewType, pMsg );
  88. }
  89. break;
  90. }
  91. Assert( 0 );
  92. return SPEW_CONTINUE;
  93. }
  94. void SpewPerfStats( studiohdr_t *pStudioHdr, const char *pFilename, unsigned int flags )
  95. {
  96. char fileName[260];
  97. vertexFileHeader_t *pNewVvdHdr;
  98. vertexFileHeader_t *pVvdHdr = 0;
  99. OptimizedModel::FileHeader_t *pVtxHdr = 0;
  100. studiohwdata_t studioHWData;
  101. int vvdSize = 0;
  102. const char *prefix[] = {".dx80.vtx", ".dx90.vtx", ".sw.vtx"};
  103. s_pSavedSpewFunc = NULL;
  104. if( !( flags & SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS ) )
  105. {
  106. s_pSavedSpewFunc = GetSpewOutputFunc();
  107. SpewOutputFunc( NullSpewOutputFunc );
  108. }
  109. // no stats on these
  110. if (!pStudioHdr->numbodyparts)
  111. return;
  112. // Need to update the render config to spew perf stats.
  113. UpdateStudioRenderConfig();
  114. // persist the vvd data
  115. Q_StripExtension( pFilename, fileName, sizeof( fileName ) );
  116. strcat( fileName, ".vvd" );
  117. if (FileExists( fileName ))
  118. {
  119. vvdSize = LoadFile( fileName, (void**)&pVvdHdr );
  120. }
  121. else
  122. {
  123. MdlError( "Could not open '%s'\n", fileName );
  124. }
  125. // validate header
  126. if (pVvdHdr->id != MODEL_VERTEX_FILE_ID)
  127. {
  128. MdlError( "Bad id for '%s' (got %d expected %d)\n", fileName, pVvdHdr->id, MODEL_VERTEX_FILE_ID);
  129. }
  130. if (pVvdHdr->version != MODEL_VERTEX_FILE_VERSION)
  131. {
  132. MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVvdHdr->version, MODEL_VERTEX_FILE_VERSION);
  133. }
  134. if (pVvdHdr->checksum != pStudioHdr->checksum)
  135. {
  136. MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVvdHdr->checksum, pStudioHdr->checksum);
  137. }
  138. if (pVvdHdr->numFixups)
  139. {
  140. // need to perform mesh relocation fixups
  141. // allocate a new copy
  142. pNewVvdHdr = (vertexFileHeader_t *)malloc( vvdSize );
  143. if (!pNewVvdHdr)
  144. {
  145. MdlError( "Error allocating %d bytes for Vertex File '%s'\n", vvdSize, fileName );
  146. }
  147. Studio_LoadVertexes( pVvdHdr, pNewVvdHdr, 0, true );
  148. // discard original
  149. free( pVvdHdr );
  150. pVvdHdr = pNewVvdHdr;
  151. }
  152. // iterate all ???.vtx files
  153. for (int j=0; j<sizeof(prefix)/sizeof(prefix[0]); j++)
  154. {
  155. // make vtx filename
  156. Q_StripExtension( pFilename, fileName, sizeof( fileName ) );
  157. strcat( fileName, prefix[j] );
  158. // persist the vtx data
  159. if (FileExists(fileName))
  160. {
  161. LoadFile( fileName, (void**)&pVtxHdr );
  162. }
  163. else
  164. {
  165. MdlError( "Could not open '%s'\n", fileName );
  166. }
  167. // validate header
  168. if (pVtxHdr->version != OPTIMIZED_MODEL_FILE_VERSION)
  169. {
  170. MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVtxHdr->version, OPTIMIZED_MODEL_FILE_VERSION );
  171. }
  172. if (pVtxHdr->checkSum != pStudioHdr->checksum)
  173. {
  174. MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVtxHdr->checkSum, pStudioHdr->checksum );
  175. }
  176. // studio render will request these through cache interface
  177. pStudioHdr->pVertexBase = (void *)pVvdHdr;
  178. pStudioHdr->pIndexBase = (void *)pVtxHdr;
  179. g_pStudioRender->LoadModel( pStudioHdr, pVtxHdr, &studioHWData );
  180. if( flags & SPEWPERFSTATS_SHOWPERF )
  181. {
  182. if( flags & SPEWPERFSTATS_SPREADSHEET )
  183. {
  184. printf( "%s,%s,%d,", fileName, prefix[j], studioHWData.m_NumLODs - studioHWData.m_RootLOD );
  185. }
  186. else
  187. {
  188. printf( "\n" );
  189. printf( "Performance Stats: %s\n", fileName );
  190. printf( "------------------\n" );
  191. }
  192. }
  193. int i;
  194. if( flags & SPEWPERFSTATS_SHOWPERF )
  195. {
  196. for( i = studioHWData.m_RootLOD; i < studioHWData.m_NumLODs; i++ )
  197. {
  198. DrawModelInfo_t drawModelInfo;
  199. drawModelInfo.m_Skin = 0;
  200. drawModelInfo.m_Body = 0;
  201. drawModelInfo.m_HitboxSet = 0;
  202. drawModelInfo.m_pClientEntity = 0;
  203. drawModelInfo.m_pColorMeshes = 0;
  204. drawModelInfo.m_pStudioHdr = pStudioHdr;
  205. drawModelInfo.m_pHardwareData = &studioHWData;
  206. CUtlBuffer statsOutput( 0, 0, CUtlBuffer::TEXT_BUFFER );
  207. if( !( flags & SPEWPERFSTATS_SPREADSHEET ) )
  208. {
  209. printf( "LOD:%d\n", i );
  210. }
  211. drawModelInfo.m_Lod = i;
  212. DrawModelResults_t results;
  213. g_pStudioRender->GetPerfStats( &results, drawModelInfo, &statsOutput );
  214. if( flags & SPEWPERFSTATS_SPREADSHEET )
  215. {
  216. printf( "%d,%d,%d,", results.m_ActualTriCount, results.m_NumBatches, results.m_NumMaterials );
  217. }
  218. else
  219. {
  220. printf( " actual tris:%d\n", ( int )results.m_ActualTriCount );
  221. printf( " texture memory bytes: %d (only valid in a rendering app)\n", ( int )results.m_TextureMemoryBytes );
  222. printf( ( char * )statsOutput.Base() );
  223. }
  224. }
  225. if( flags & SPEWPERFSTATS_SPREADSHEET )
  226. {
  227. printf( "\n" );
  228. }
  229. }
  230. g_pStudioRender->UnloadModel( &studioHWData );
  231. free(pVtxHdr);
  232. }
  233. if (pVvdHdr)
  234. free(pVvdHdr);
  235. if( !( flags & SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS ) )
  236. {
  237. SpewOutputFunc( s_pSavedSpewFunc );
  238. }
  239. }