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.

5547 lines
180 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "pch_materialsystem.h"
  7. #define MATSYS_INTERNAL
  8. #include "cmaterialsystem.h"
  9. #include "colorspace.h"
  10. #include "materialsystem/materialsystem_config.h"
  11. #include "IHardwareConfigInternal.h"
  12. #include "shadersystem.h"
  13. #include "texturemanager.h"
  14. #include "shaderlib/ShaderDLL.h"
  15. #include "tier1/callqueue.h"
  16. #include "vstdlib/jobthread.h"
  17. #include "cmatnullrendercontext.h"
  18. #include "filesystem/IQueuedLoader.h"
  19. #include "datacache/idatacache.h"
  20. #include "materialsystem/imaterialproxy.h"
  21. #include "vstdlib/IKeyValuesSystem.h"
  22. #include "ctexturecompositor.h"
  23. #if defined( _X360 )
  24. #include "xbox/xbox_console.h"
  25. #include "xbox/xbox_win32stubs.h"
  26. #endif
  27. // NOTE: This must be the last file included!!!
  28. #include "tier0/memdbgon.h"
  29. #ifdef POSIX
  30. #define _finite finite
  31. #endif
  32. // this is hooked into the engines convar
  33. ConVar mat_debugalttab( "mat_debugalttab", "0", FCVAR_CHEAT );
  34. ConVar mat_forcemanagedtextureintohardware( "mat_forcemanagedtextureintohardware", "1", FCVAR_HIDDEN | FCVAR_ALLOWED_IN_COMPETITIVE );
  35. ConVar mat_supportflashlight( "mat_supportflashlight", "-1", FCVAR_HIDDEN, "0 - do not support flashlight (don't load flashlight shader combos), 1 - flashlight is supported" );
  36. #ifdef OSX
  37. #define CV_FRAME_SWAP_WORKAROUND_DEFAULT "1"
  38. #else
  39. #define CV_FRAME_SWAP_WORKAROUND_DEFAULT "0"
  40. #endif
  41. ConVar mat_texture_reload_frame_swap_workaround( "mat_texture_reload_frame_swap_workaround", CV_FRAME_SWAP_WORKAROUND_DEFAULT, FCVAR_INTERNAL_USE,
  42. "Workaround certain GL drivers holding unnecessary amounts of data when loading many materials by forcing synthetic frame swaps" );
  43. // This ConVar allows us to skip ~40% of our map load time, but it doesn't work on GPUs older
  44. // than ~2005. We set it automatically and don't expose it to players.
  45. ConVar mat_requires_rt_alloc_first( "mat_requires_rt_alloc_first", "0", FCVAR_HIDDEN );
  46. // Make sure this convar gets created before videocfg.lib is initialized, so it can be driven by dxsupport.cfg
  47. static ConVar mat_tonemapping_occlusion_use_stencil( "mat_tonemapping_occlusion_use_stencil", "0" );
  48. #ifdef DX_TO_GL_ABSTRACTION
  49. // In GL mode, we currently require mat_dxlevel to be between 90-92
  50. static ConVar mat_dxlevel( "mat_dxlevel", "92", 0, "", true, 90, true, 92, NULL );
  51. #else
  52. static ConVar mat_dxlevel( "mat_dxlevel", "0", 0, "Current DirectX Level. Competitive play requires at least mat_dxlevel 90", false, 0, false, 0, true, 90, false, 0, NULL );
  53. #endif
  54. IMaterialInternal *g_pErrorMaterial = NULL;
  55. CreateInterfaceFn g_fnMatSystemConnectCreateInterface = NULL;
  56. static int ReadListFromFile(CUtlVector<char*>* outReplacementMaterials, const char *pszPathName);
  57. //#define PERF_TESTING 1
  58. //-----------------------------------------------------------------------------
  59. // Implementational structures
  60. //-----------------------------------------------------------------------------
  61. //-----------------------------------------------------------------------------
  62. // Singleton instance exposed to the engine
  63. //-----------------------------------------------------------------------------
  64. CMaterialSystem g_MaterialSystem;
  65. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMaterialSystem, IMaterialSystem,
  66. MATERIAL_SYSTEM_INTERFACE_VERSION, g_MaterialSystem );
  67. // Expose this to the external shader DLLs
  68. MaterialSystem_Config_t g_config;
  69. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( MaterialSystem_Config_t, MaterialSystem_Config_t, MATERIALSYSTEM_CONFIG_VERSION, g_config );
  70. //-----------------------------------------------------------------------------
  71. CThreadFastMutex g_MatSysMutex;
  72. //-----------------------------------------------------------------------------
  73. // Purpose: additional materialsystem information, internal use only
  74. //-----------------------------------------------------------------------------
  75. #ifndef _X360
  76. struct MaterialSystem_Config_Internal_t
  77. {
  78. int r_waterforceexpensive;
  79. };
  80. MaterialSystem_Config_Internal_t g_config_internal;
  81. #endif
  82. //-----------------------------------------------------------------------------
  83. // Necessary to allow the shader DLLs to get ahold of IMaterialSystemHardwareConfig
  84. //-----------------------------------------------------------------------------
  85. IHardwareConfigInternal* g_pHWConfig = 0;
  86. static void *GetHardwareConfig()
  87. {
  88. if ( g_pHWConfig )
  89. return (IMaterialSystemHardwareConfig*)g_pHWConfig;
  90. // can't call QueryShaderAPI here because it calls a factory function
  91. // and we end up in an infinite recursion
  92. return NULL;
  93. }
  94. EXPOSE_INTERFACE_FN( GetHardwareConfig, IMaterialSystemHardwareConfig, MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION );
  95. //-----------------------------------------------------------------------------
  96. // Necessary to allow the shader DLLs to get ahold of ICvar
  97. //-----------------------------------------------------------------------------
  98. static void *GetICVar()
  99. {
  100. return g_pCVar;
  101. }
  102. EXPOSE_INTERFACE_FN( GetICVar, ICVar, CVAR_INTERFACE_VERSION );
  103. //-----------------------------------------------------------------------------
  104. // Accessor to get at the material system
  105. //-----------------------------------------------------------------------------
  106. IMaterialSystemInternal *g_pInternalMaterialSystem = &g_MaterialSystem;
  107. IShaderUtil *g_pShaderUtil = &g_MaterialSystem;
  108. #if defined(USE_SDL)
  109. #include "appframework/ilaunchermgr.h"
  110. ILauncherMgr *g_pLauncherMgr = NULL; // set in CMaterialSystem::Connect
  111. #endif
  112. //-----------------------------------------------------------------------------
  113. // Factory used to get at internal interfaces (used by shaderapi + shader dlls)
  114. //-----------------------------------------------------------------------------
  115. void *ShaderFactory( const char *pName, int *pReturnCode )
  116. {
  117. if (pReturnCode)
  118. {
  119. *pReturnCode = IFACE_OK;
  120. }
  121. if ( !Q_stricmp( pName, FILESYSTEM_INTERFACE_VERSION ))
  122. return g_pFullFileSystem;
  123. if ( !Q_stricmp( pName, QUEUEDLOADER_INTERFACE_VERSION ))
  124. return g_pQueuedLoader;
  125. if ( !Q_stricmp( pName, SHADER_UTIL_INTERFACE_VERSION ))
  126. return g_pShaderUtil;
  127. #ifdef USE_SDL
  128. if ( !Q_stricmp( pName, "SDLMgrInterface001" /*SDLMGR_INTERFACE_VERSION*/ ))
  129. return g_pLauncherMgr;
  130. #endif
  131. void * pInterface = g_MaterialSystem.QueryInterface( pName );
  132. if ( pInterface )
  133. return pInterface;
  134. if ( pReturnCode )
  135. {
  136. *pReturnCode = IFACE_FAILED;
  137. }
  138. return NULL;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Resource preloading for materials.
  142. //-----------------------------------------------------------------------------
  143. class CResourcePreloadMaterial : public CResourcePreload
  144. {
  145. virtual bool CreateResource( const char *pName )
  146. {
  147. IMaterial *pMaterial = g_MaterialSystem.FindMaterial( pName, TEXTURE_GROUP_WORLD, false );
  148. IMaterialInternal *pMatInternal = static_cast< IMaterialInternal * >( pMaterial );
  149. if ( pMatInternal )
  150. {
  151. // always work with the realtime material internally
  152. pMatInternal = pMatInternal->GetRealTimeVersion();
  153. // tag these for later identification (prevents an unwanted purge)
  154. pMatInternal->MarkAsPreloaded( true );
  155. if ( !pMatInternal->IsErrorMaterial() )
  156. {
  157. // force material's textures to create now
  158. pMatInternal->Precache();
  159. return true;
  160. }
  161. else
  162. {
  163. if ( IsPosix() )
  164. {
  165. printf("\n ##### CResourcePreloadMaterial::CreateResource can't find material %s\n", pName);
  166. }
  167. }
  168. }
  169. return false;
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Called before queued loader i/o jobs are actually performed. Must free up memory
  173. // to ensure i/o requests have enough memory to succeed. The materials that were
  174. // touched by the CreateResource() are inhibited from purging (as is their textures,
  175. // by virtue of ref counts), all others are candidates. The preloaded materials
  176. // are by definition zero ref'd until owned by the normal loading process. Any material
  177. // that stays zero ref'd is a candidate for the post load purge.
  178. //-----------------------------------------------------------------------------
  179. virtual void PurgeUnreferencedResources()
  180. {
  181. bool bSpew = ( g_pQueuedLoader->GetSpewDetail() & LOADER_DETAIL_PURGES ) != 0;
  182. bool bDidUncacheMaterial = false;
  183. MaterialHandle_t hNext;
  184. for ( MaterialHandle_t hMaterial = g_MaterialSystem.FirstMaterial(); hMaterial != g_MaterialSystem.InvalidMaterial(); hMaterial = hNext )
  185. {
  186. hNext = g_MaterialSystem.NextMaterial( hMaterial );
  187. IMaterialInternal *pMatInternal = g_MaterialSystem.GetMaterialInternal( hMaterial );
  188. Assert( pMatInternal->GetReferenceCount() >= 0 );
  189. // preloaded materials are safe from this pre-purge
  190. if ( !pMatInternal->IsPreloaded() )
  191. {
  192. // undo any possible artifical ref count
  193. pMatInternal->ArtificialRelease();
  194. if ( pMatInternal->GetReferenceCount() <= 0 )
  195. {
  196. if ( bSpew )
  197. {
  198. Msg( "CResourcePreloadMaterial: Purging: %s (%d)\n", pMatInternal->GetName(), pMatInternal->GetReferenceCount() );
  199. }
  200. bDidUncacheMaterial = true;
  201. pMatInternal->Uncache();
  202. pMatInternal->DeleteIfUnreferenced();
  203. }
  204. }
  205. else
  206. {
  207. // clear the bit
  208. pMatInternal->MarkAsPreloaded( false );
  209. }
  210. }
  211. // purged materials unreference their textures
  212. // purge any zero ref'd textures
  213. TextureManager()->RemoveUnusedTextures();
  214. // fixup any excluded textures, may cause some new batch requests
  215. MaterialSystem()->UpdateExcludedTextures();
  216. }
  217. virtual void PurgeAll()
  218. {
  219. bool bSpew = ( g_pQueuedLoader->GetSpewDetail() & LOADER_DETAIL_PURGES ) != 0;
  220. bool bDidUncacheMaterial = false;
  221. MaterialHandle_t hNext;
  222. for ( MaterialHandle_t hMaterial = g_MaterialSystem.FirstMaterial(); hMaterial != g_MaterialSystem.InvalidMaterial(); hMaterial = hNext )
  223. {
  224. hNext = g_MaterialSystem.NextMaterial( hMaterial );
  225. IMaterialInternal *pMatInternal = g_MaterialSystem.GetMaterialInternal( hMaterial );
  226. Assert( pMatInternal->GetReferenceCount() >= 0 );
  227. pMatInternal->MarkAsPreloaded( false );
  228. // undo any possible artifical ref count
  229. pMatInternal->ArtificialRelease();
  230. if ( pMatInternal->GetReferenceCount() <= 0 )
  231. {
  232. if ( bSpew )
  233. {
  234. Msg( "CResourcePreloadMaterial: Purging: %s (%d)\n", pMatInternal->GetName(), pMatInternal->GetReferenceCount() );
  235. }
  236. bDidUncacheMaterial = true;
  237. pMatInternal->Uncache();
  238. pMatInternal->DeleteIfUnreferenced();
  239. }
  240. }
  241. // purged materials unreference their textures
  242. // purge any zero ref'd textures
  243. TextureManager()->RemoveUnusedTextures();
  244. }
  245. };
  246. static CResourcePreloadMaterial s_ResourcePreloadMaterial;
  247. //-----------------------------------------------------------------------------
  248. // Resource preloading for cubemaps.
  249. //-----------------------------------------------------------------------------
  250. class CResourcePreloadCubemap : public CResourcePreload
  251. {
  252. virtual bool CreateResource( const char *pName )
  253. {
  254. ITexture *pTexture = g_MaterialSystem.FindTexture( pName, TEXTURE_GROUP_CUBE_MAP, true );
  255. ITextureInternal *pTexInternal = static_cast< ITextureInternal * >( pTexture );
  256. if ( pTexInternal )
  257. {
  258. // There can be cubemaps that are unbound by materials. To prevent an unwanted purge,
  259. // mark and increase the ref count. Otherwise the pre-purge discards these zero
  260. // ref'd textures, and then the normal loading process hitches on the miss.
  261. // The zombie cubemaps DO get discarded after the normal loading process completes
  262. // if no material references them.
  263. pTexInternal->MarkAsPreloaded( true );
  264. pTexInternal->IncrementReferenceCount();
  265. if ( !IsErrorTexture( pTexInternal ) )
  266. {
  267. return true;
  268. }
  269. }
  270. return false;
  271. }
  272. //-----------------------------------------------------------------------------
  273. // All valid cubemaps should have been owned by their materials. Undo the preloaded
  274. // cubemap locks. Any zero ref'd cubemaps will be purged by the normal loading path conclusion.
  275. //-----------------------------------------------------------------------------
  276. virtual void OnEndMapLoading( bool bAbort )
  277. {
  278. int iIndex = -1;
  279. for ( ;; )
  280. {
  281. ITextureInternal *pTexInternal;
  282. iIndex = TextureManager()->FindNext( iIndex, &pTexInternal );
  283. if ( iIndex == -1 || !pTexInternal )
  284. {
  285. // end of list
  286. break;
  287. }
  288. if ( pTexInternal->IsPreloaded() )
  289. {
  290. // undo the artificial increase
  291. pTexInternal->MarkAsPreloaded( false );
  292. pTexInternal->DecrementReferenceCount();
  293. }
  294. }
  295. }
  296. };
  297. static CResourcePreloadCubemap s_ResourcePreloadCubemap;
  298. //-----------------------------------------------------------------------------
  299. // Creates the debugging materials
  300. //-----------------------------------------------------------------------------
  301. void CMaterialSystem::CreateDebugMaterials()
  302. {
  303. if ( !m_pDrawFlatMaterial )
  304. {
  305. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  306. pVMTKeyValues->SetInt( "$model", 1 );
  307. pVMTKeyValues->SetFloat( "$decalscale", 0.05f );
  308. pVMTKeyValues->SetString( "$basetexture", "error" ); // This is the "error texture"
  309. g_pErrorMaterial = static_cast<IMaterialInternal*>(CreateMaterial( "___error.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  310. pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  311. pVMTKeyValues->SetInt( "$flat", 1 );
  312. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  313. m_pDrawFlatMaterial = static_cast<IMaterialInternal*>(CreateMaterial( "___flat.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  314. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  315. pVMTKeyValues->SetInt( "$nocull", 1 );
  316. m_pBufferClearObeyStencil[BUFFER_CLEAR_NONE] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil0.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  317. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  318. pVMTKeyValues->SetInt( "$nocull", 1 );
  319. pVMTKeyValues->SetInt( "$clearcolor", 1 );
  320. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  321. m_pBufferClearObeyStencil[BUFFER_CLEAR_COLOR] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil1.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  322. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  323. pVMTKeyValues->SetInt( "$nocull", 1 );
  324. pVMTKeyValues->SetInt( "$clearalpha", 1 );
  325. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  326. m_pBufferClearObeyStencil[BUFFER_CLEAR_ALPHA] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil2.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  327. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  328. pVMTKeyValues->SetInt( "$nocull", 1 );
  329. pVMTKeyValues->SetInt( "$clearcolor", 1 );
  330. pVMTKeyValues->SetInt( "$clearalpha", 1 );
  331. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  332. m_pBufferClearObeyStencil[BUFFER_CLEAR_COLOR_AND_ALPHA] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil3.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  333. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  334. pVMTKeyValues->SetInt( "$nocull", 1 );
  335. pVMTKeyValues->SetInt( "$cleardepth", 1 );
  336. m_pBufferClearObeyStencil[BUFFER_CLEAR_DEPTH] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil4.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  337. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  338. pVMTKeyValues->SetInt( "$nocull", 1 );
  339. pVMTKeyValues->SetInt( "$cleardepth", 1 );
  340. pVMTKeyValues->SetInt( "$clearcolor", 1 );
  341. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  342. m_pBufferClearObeyStencil[BUFFER_CLEAR_COLOR_AND_DEPTH] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil5.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  343. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  344. pVMTKeyValues->SetInt( "$nocull", 1 );
  345. pVMTKeyValues->SetInt( "$cleardepth", 1 );
  346. pVMTKeyValues->SetInt( "$clearalpha", 1 );
  347. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  348. m_pBufferClearObeyStencil[BUFFER_CLEAR_ALPHA_AND_DEPTH] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil6.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  349. pVMTKeyValues = new KeyValues( "BufferClearObeyStencil" );
  350. pVMTKeyValues->SetInt( "$nocull", 1 );
  351. pVMTKeyValues->SetInt( "$cleardepth", 1 );
  352. pVMTKeyValues->SetInt( "$clearcolor", 1 );
  353. pVMTKeyValues->SetInt( "$clearalpha", 1 );
  354. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  355. m_pBufferClearObeyStencil[BUFFER_CLEAR_COLOR_AND_ALPHA_AND_DEPTH] = static_cast<IMaterialInternal*>(CreateMaterial( "___buffer_clear_obey_stencil7.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  356. if ( IsX360() )
  357. {
  358. pVMTKeyValues = new KeyValues( "RenderTargetBlit_X360" );
  359. m_pRenderTargetBlitMaterial = static_cast<IMaterialInternal*>(CreateMaterial( "___renderTargetBlit.vmt", pVMTKeyValues ))->GetRealTimeVersion();
  360. }
  361. ShaderSystem()->CreateDebugMaterials();
  362. }
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Creates compositor materials
  366. //-----------------------------------------------------------------------------
  367. void CMaterialSystem::CreateCompositorMaterials()
  368. {
  369. // precache composite materials
  370. for ( int i = ECO_FirstPrecacheMaterial; i < ECO_LastPrecacheMaterial; i++ )
  371. {
  372. const char *pszMaterial = GetCombinedMaterialName( ( ECombineOperation ) i );
  373. if ( pszMaterial[ 0 ] == '\0' )
  374. continue;
  375. IMaterialInternal *pMatqf = assert_cast< IMaterialInternal* >( FindMaterial( pszMaterial, TEXTURE_GROUP_RUNTIME_COMPOSITE ) );
  376. Assert( pMatqf );
  377. Assert( !pMatqf->IsErrorMaterial() );
  378. IMaterialInternal *pMatrt = pMatqf->GetRealTimeVersion();
  379. Assert( pMatrt );
  380. pMatrt->IncrementReferenceCount(); // Hold a ref.
  381. m_pCompositorMaterials.AddToTail( pMatrt );
  382. }
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Cleanup compositor materials
  386. //-----------------------------------------------------------------------------
  387. void CMaterialSystem::CleanUpCompositorMaterials()
  388. {
  389. FOR_EACH_VEC( m_pCompositorMaterials, i )
  390. {
  391. if ( m_pCompositorMaterials[ i ] == NULL )
  392. continue;
  393. m_pCompositorMaterials[ i ]->DecrementReferenceCount();
  394. RemoveMaterial( m_pCompositorMaterials[ i ] );
  395. }
  396. m_pCompositorMaterials.RemoveAll();
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Creates the debugging materials
  400. //-----------------------------------------------------------------------------
  401. void CMaterialSystem::CleanUpDebugMaterials()
  402. {
  403. if ( m_pDrawFlatMaterial )
  404. {
  405. m_pDrawFlatMaterial->DecrementReferenceCount();
  406. RemoveMaterial( m_pDrawFlatMaterial );
  407. m_pDrawFlatMaterial = NULL;
  408. for ( int i = BUFFER_CLEAR_NONE; i < BUFFER_CLEAR_TYPE_COUNT; ++i )
  409. {
  410. m_pBufferClearObeyStencil[i]->DecrementReferenceCount();
  411. RemoveMaterial( m_pBufferClearObeyStencil[i] );
  412. m_pBufferClearObeyStencil[i] = NULL;
  413. }
  414. if ( IsX360() )
  415. {
  416. m_pRenderTargetBlitMaterial->DecrementReferenceCount();
  417. RemoveMaterial( m_pRenderTargetBlitMaterial );
  418. m_pRenderTargetBlitMaterial = NULL;
  419. }
  420. ShaderSystem()->CleanUpDebugMaterials();
  421. }
  422. }
  423. void CMaterialSystem::CleanUpErrorMaterial()
  424. {
  425. // Destruction of g_pErrorMaterial is deferred until after CMaterialDict::Shutdown.
  426. // The global g_pErrorMaterial is set to NULL so that IsErrorMaterial() will return false and
  427. // RemoveMaterial() / DestroyMaterial() will delete it.
  428. IMaterialInternal *pErrorMaterial = g_pErrorMaterial;
  429. g_pErrorMaterial = NULL;
  430. pErrorMaterial->DecrementReferenceCount();
  431. RemoveMaterial( pErrorMaterial );
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Constructor
  435. //-----------------------------------------------------------------------------
  436. CMaterialSystem::CMaterialSystem()
  437. {
  438. m_nRenderThreadID = 0xFFFFFFFF;
  439. m_hAsyncLoadFileCache = NULL;
  440. m_ShaderHInst = 0;
  441. m_pMaterialProxyFactory = NULL;
  442. m_nAdapter = 0;
  443. m_nAdapterFlags = 0;
  444. m_bRequestedEditorMaterials = false;
  445. m_bCanUseEditorMaterials = false;
  446. m_StandardTexturesAllocated = false;
  447. m_bInFrame = false;
  448. m_bThreadHasOwnership = false;
  449. m_ThreadOwnershipID = 0;
  450. m_pShaderDLL = NULL;
  451. m_FullbrightLightmapTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  452. m_FullbrightBumpedLightmapTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  453. m_BlackTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  454. m_FlatNormalTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  455. m_GreyTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  456. m_GreyAlphaZeroTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  457. m_WhiteTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  458. m_LinearToGammaTableTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  459. m_LinearToGammaIdentityTableTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  460. m_MaxDepthTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  461. m_bInStubMode = false;
  462. m_pForcedTextureLoadPathID = NULL;
  463. m_bAllocatingRenderTargets = false;
  464. m_pRenderContext.Set( &m_HardwareRenderContext );
  465. m_iCurQueuedContext = 0;
  466. #if defined(DEDICATED)
  467. m_bThreadingNotAvailable = true;
  468. m_bForcedSingleThreaded = true;
  469. m_bAllowQueuedRendering = false;
  470. #else
  471. m_bThreadingNotAvailable = false;
  472. m_bForcedSingleThreaded = false;
  473. m_bAllowQueuedRendering = true;
  474. #endif
  475. m_bGeneratedConfig = false;
  476. m_pActiveAsyncJob = NULL;
  477. m_pMatQueueThreadPool = NULL;
  478. m_IdealThreadMode = m_ThreadMode = MATERIAL_SINGLE_THREADED;
  479. m_nServiceThread = 0;
  480. m_nRenderTargetFrameBufferHeightOverride = m_nRenderTargetFrameBufferWidthOverride = 0;
  481. m_bReplacementFilesValid = false;
  482. }
  483. CMaterialSystem::~CMaterialSystem()
  484. {
  485. if (m_pShaderDLL)
  486. {
  487. delete[] m_pShaderDLL;
  488. }
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Creates/destroys the shader implementation for the selected API
  492. //-----------------------------------------------------------------------------
  493. CreateInterfaceFn CMaterialSystem::CreateShaderAPI( char const* pShaderDLL )
  494. {
  495. if ( !pShaderDLL )
  496. return 0;
  497. // Clean up the old shader
  498. DestroyShaderAPI();
  499. // Load the new shader
  500. m_ShaderHInst = Sys_LoadModule( pShaderDLL );
  501. // Error loading the shader
  502. if ( !m_ShaderHInst )
  503. return 0;
  504. // Get our class factory methods...
  505. return Sys_GetFactory( m_ShaderHInst );
  506. }
  507. void CMaterialSystem::DestroyShaderAPI()
  508. {
  509. if (m_ShaderHInst)
  510. {
  511. // NOTE: By unloading the library, this will destroy m_pShaderAPI
  512. Sys_UnloadModule( m_ShaderHInst );
  513. g_pShaderAPI = 0;
  514. g_pHWConfig = 0;
  515. g_pShaderShadow = 0;
  516. m_ShaderHInst = 0;
  517. }
  518. }
  519. //-----------------------------------------------------------------------------
  520. // Sets which shader we should be using. Has to be done before connect!
  521. //-----------------------------------------------------------------------------
  522. void CMaterialSystem::SetShaderAPI( char const *pShaderAPIDLL )
  523. {
  524. if ( m_ShaderAPIFactory )
  525. {
  526. Error( "Cannot set the shader API twice!\n" );
  527. }
  528. if ( !pShaderAPIDLL )
  529. {
  530. pShaderAPIDLL = "shaderapidx9";
  531. }
  532. // m_pShaderDLL is needed to spew driver info
  533. Assert( pShaderAPIDLL );
  534. int len = Q_strlen( pShaderAPIDLL ) + 1;
  535. m_pShaderDLL = new char[len];
  536. memcpy( m_pShaderDLL, pShaderAPIDLL, len );
  537. m_ShaderAPIFactory = CreateShaderAPI( pShaderAPIDLL );
  538. if ( !m_ShaderAPIFactory )
  539. {
  540. DestroyShaderAPI();
  541. }
  542. }
  543. //-----------------------------------------------------------------------------
  544. // Connect/disconnect
  545. //-----------------------------------------------------------------------------
  546. bool CMaterialSystem::Connect( CreateInterfaceFn factory )
  547. {
  548. // __stop__();
  549. if ( !factory )
  550. return false;
  551. if ( !BaseClass::Connect( factory ) )
  552. return false;
  553. if ( !g_pFullFileSystem )
  554. {
  555. Warning( "The material system requires the filesystem to run!\n" );
  556. return false;
  557. }
  558. // Get at the interfaces exported by the shader DLL
  559. g_pShaderDeviceMgr = (IShaderDeviceMgr*)m_ShaderAPIFactory( SHADER_DEVICE_MGR_INTERFACE_VERSION, 0 );
  560. if ( !g_pShaderDeviceMgr )
  561. return false;
  562. g_pHWConfig = (IHardwareConfigInternal*)m_ShaderAPIFactory( MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION, 0 );
  563. if ( !g_pHWConfig )
  564. return false;
  565. #if !defined(DEDICATED)
  566. #if defined( USE_SDL )
  567. g_pLauncherMgr = (ILauncherMgr *)factory( "SDLMgrInterface001" /*SDL_MGR_INTERFACE_VERSION*/, NULL );
  568. if ( !g_pLauncherMgr )
  569. {
  570. return false;
  571. }
  572. #endif // USE_SDL
  573. #endif // !DEDICATED
  574. // FIXME: ShaderAPI, ShaderDevice, and ShaderShadow should only come in after setting mode
  575. g_pShaderAPI = (IShaderAPI*)m_ShaderAPIFactory( SHADERAPI_INTERFACE_VERSION, 0 );
  576. if ( !g_pShaderAPI )
  577. return false;
  578. g_pShaderDevice = (IShaderDevice*)m_ShaderAPIFactory( SHADER_DEVICE_INTERFACE_VERSION, 0 );
  579. if ( !g_pShaderDevice )
  580. return false;
  581. g_pShaderShadow = (IShaderShadow*)m_ShaderAPIFactory( SHADERSHADOW_INTERFACE_VERSION, 0 );
  582. if ( !g_pShaderShadow )
  583. return false;
  584. // Remember the factory for connect
  585. g_fnMatSystemConnectCreateInterface = factory;
  586. return g_pShaderDeviceMgr->Connect( ShaderFactory );
  587. }
  588. void CMaterialSystem::Disconnect()
  589. {
  590. // Forget the factory for connect
  591. g_fnMatSystemConnectCreateInterface = NULL;
  592. if ( g_pShaderDeviceMgr )
  593. {
  594. g_pShaderDeviceMgr->Disconnect();
  595. g_pShaderDeviceMgr = NULL;
  596. // Unload the DLL
  597. DestroyShaderAPI();
  598. }
  599. g_pShaderAPI = NULL;
  600. g_pHWConfig = NULL;
  601. g_pShaderShadow = NULL;
  602. g_pShaderDevice = NULL;
  603. BaseClass::Disconnect();
  604. }
  605. //-----------------------------------------------------------------------------
  606. // Used to enable editor materials. Must be called before Init.
  607. //-----------------------------------------------------------------------------
  608. void CMaterialSystem::EnableEditorMaterials()
  609. {
  610. m_bRequestedEditorMaterials = true;
  611. }
  612. //-----------------------------------------------------------------------------
  613. // Method to get at interfaces supported by the SHADDERAPI
  614. //-----------------------------------------------------------------------------
  615. void *CMaterialSystem::QueryShaderAPI( const char *pInterfaceName )
  616. {
  617. // Returns various interfaces supported by the shader API dll
  618. void *pInterface = NULL;
  619. if (m_ShaderAPIFactory)
  620. {
  621. pInterface = m_ShaderAPIFactory( pInterfaceName, NULL );
  622. }
  623. return pInterface;
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Method to get at different interfaces supported by the material system
  627. //-----------------------------------------------------------------------------
  628. void *CMaterialSystem::QueryInterface( const char *pInterfaceName )
  629. {
  630. // Returns various interfaces supported by the shader API dll
  631. void *pInterface = QueryShaderAPI( pInterfaceName );
  632. if ( pInterface )
  633. return pInterface;
  634. CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary
  635. return factory( pInterfaceName, NULL ); // to prevent the LTCG compiler from crashing.
  636. }
  637. //-----------------------------------------------------------------------------
  638. // Must be called before Init(), if you're going to call it at all...
  639. //-----------------------------------------------------------------------------
  640. void CMaterialSystem::SetAdapter( int nAdapter, int nAdapterFlags )
  641. {
  642. m_nAdapter = nAdapter;
  643. m_nAdapterFlags = nAdapterFlags;
  644. }
  645. //-----------------------------------------------------------------------------
  646. // Initializes the color correction terms
  647. //-----------------------------------------------------------------------------
  648. void CMaterialSystem::InitColorCorrection( )
  649. {
  650. if ( ColorCorrectionSystem() )
  651. {
  652. ColorCorrectionSystem()->Init();
  653. }
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Initialization + shutdown of the material system
  657. //-----------------------------------------------------------------------------
  658. InitReturnVal_t CMaterialSystem::Init()
  659. {
  660. InitReturnVal_t nRetVal = BaseClass::Init();
  661. if ( nRetVal != INIT_OK )
  662. return nRetVal;
  663. // NOTE! : Overbright is 1.0 so that Hammer will work properly with the white bumped and unbumped lightmaps.
  664. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
  665. g_pShaderDeviceMgr->SetAdapter( m_nAdapter, m_nAdapterFlags );
  666. if ( g_pShaderDeviceMgr->Init( ) != INIT_OK )
  667. {
  668. DestroyShaderAPI();
  669. return INIT_FAILED;
  670. }
  671. // Texture manager...
  672. TextureManager()->Init( m_nAdapterFlags );
  673. // Shader system!
  674. ShaderSystem()->Init();
  675. #if defined( WIN32 ) && !defined( _X360 )
  676. // HACKHACK: <sigh> This horrible hack is possibly the only way to reliably detect an old
  677. // version of hammer initializing the material system. We need to know this so that we set
  678. // up the editor materials properly. If we don't do this, we never allocate the white lightmap,
  679. // for example. We can remove this when we update the SDK!!
  680. char szExeName[_MAX_PATH];
  681. if ( ::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), szExeName, sizeof( szExeName ) ) )
  682. {
  683. char szRight[20];
  684. Q_StrRight( szExeName, 11, szRight, sizeof( szRight ) );
  685. if ( !Q_stricmp( szRight, "\\hammer.exe" ) )
  686. {
  687. m_bRequestedEditorMaterials = true;
  688. }
  689. }
  690. #endif // WIN32
  691. m_bCanUseEditorMaterials = m_bRequestedEditorMaterials;
  692. InitColorCorrection();
  693. // Set up debug materials...
  694. CreateDebugMaterials();
  695. #if !defined(DEDICATED)
  696. CreateCompositorMaterials();
  697. #endif
  698. if ( IsX360() )
  699. {
  700. g_pQueuedLoader->InstallLoader( RESOURCEPRELOAD_MATERIAL, &s_ResourcePreloadMaterial );
  701. g_pQueuedLoader->InstallLoader( RESOURCEPRELOAD_CUBEMAP, &s_ResourcePreloadCubemap );
  702. }
  703. // Set up a default material system config
  704. // GenerateConfigFromConfigKeyValues( &g_config, false );
  705. // UpdateConfig( false );
  706. // JAY: Added this command line parameter to force creating <32x32 mips
  707. // to test for reported performance regressions on some systems
  708. if ( CommandLine()->FindParm("-forceallmips") )
  709. {
  710. extern bool g_bForceTextureAllMips;
  711. g_bForceTextureAllMips = true;
  712. }
  713. #if defined(DEDICATED)
  714. m_bThreadingNotAvailable = true;
  715. #else
  716. for ( int i = 0; i < ARRAYSIZE( m_QueuedRenderContexts ); i++ )
  717. {
  718. if ( !m_QueuedRenderContexts[i].IsInitialized() )
  719. {
  720. if ( !m_QueuedRenderContexts[i].Init( this, &m_HardwareRenderContext ) )
  721. {
  722. m_bThreadingNotAvailable = true;
  723. break;
  724. }
  725. }
  726. }
  727. #endif
  728. return m_HardwareRenderContext.Init( this );
  729. }
  730. //-----------------------------------------------------------------------------
  731. // For backwards compatability
  732. //-----------------------------------------------------------------------------
  733. static CreateInterfaceFn s_TempCVarFactory;
  734. static CreateInterfaceFn s_TempFileSystemFactory;
  735. void* TempCreateInterface( const char *pName, int *pReturnCode )
  736. {
  737. void *pRetVal = NULL;
  738. if ( s_TempCVarFactory )
  739. {
  740. pRetVal = s_TempCVarFactory( pName, pReturnCode );
  741. if (pRetVal)
  742. return pRetVal;
  743. }
  744. pRetVal = s_TempFileSystemFactory( pName, pReturnCode );
  745. if (pRetVal)
  746. return pRetVal;
  747. return NULL;
  748. }
  749. //-----------------------------------------------------------------------------
  750. // Initializes and shuts down the shader API
  751. //-----------------------------------------------------------------------------
  752. CreateInterfaceFn CMaterialSystem::Init( char const* pShaderAPIDLL,
  753. IMaterialProxyFactory *pMaterialProxyFactory,
  754. CreateInterfaceFn fileSystemFactory,
  755. CreateInterfaceFn cvarFactory )
  756. {
  757. SetShaderAPI( pShaderAPIDLL );
  758. s_TempCVarFactory = cvarFactory;
  759. s_TempFileSystemFactory = fileSystemFactory;
  760. if ( !Connect( TempCreateInterface ) )
  761. return 0;
  762. if (Init() != INIT_OK)
  763. return NULL;
  764. // save the proxy factory
  765. m_pMaterialProxyFactory = pMaterialProxyFactory;
  766. return m_ShaderAPIFactory;
  767. }
  768. void CMaterialSystem::Shutdown( )
  769. {
  770. DestroyMatQueueThreadPool();
  771. m_HardwareRenderContext.Shutdown();
  772. // Clean up standard textures
  773. ReleaseStandardTextures();
  774. CleanUpCompositorMaterials();
  775. // Clean up the debug materials
  776. CleanUpDebugMaterials();
  777. g_pMorphMgr->FreeMaterials();
  778. g_pOcclusionQueryMgr->FreeOcclusionQueryObjects();
  779. GetLightmaps()->Shutdown();
  780. m_MaterialDict.Shutdown();
  781. CleanUpErrorMaterial();
  782. // Shader system!
  783. ShaderSystem()->Shutdown();
  784. // Texture manager...
  785. TextureManager()->Shutdown();
  786. if (g_pShaderDeviceMgr)
  787. {
  788. g_pShaderDeviceMgr->Shutdown();
  789. }
  790. BaseClass::Shutdown();
  791. }
  792. void CMaterialSystem::ModInit()
  793. {
  794. // Set up a default material system config
  795. GenerateConfigFromConfigKeyValues( &g_config, false );
  796. UpdateConfig( false );
  797. // Shader system!
  798. ShaderSystem()->ModInit();
  799. }
  800. void CMaterialSystem::ModShutdown()
  801. {
  802. // Shader system!
  803. ShaderSystem()->ModShutdown();
  804. // HACK - this is here to unhook ourselves from the client interface, since we're not actually notified when it happens
  805. m_pMaterialProxyFactory = NULL;
  806. }
  807. //-----------------------------------------------------------------------------
  808. // Returns the current adapter in use
  809. //-----------------------------------------------------------------------------
  810. IMaterialSystemHardwareConfig *CMaterialSystem::GetHardwareConfig( const char *pVersion, int *returnCode )
  811. {
  812. return ( IMaterialSystemHardwareConfig * )m_ShaderAPIFactory( pVersion, returnCode );
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Returns the current adapter in use
  816. //-----------------------------------------------------------------------------
  817. int CMaterialSystem::GetCurrentAdapter() const
  818. {
  819. return g_pShaderDevice->GetCurrentAdapter();
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Returns the device name for the current adapter
  823. //-----------------------------------------------------------------------------
  824. char *CMaterialSystem::GetDisplayDeviceName() const
  825. {
  826. return g_pShaderDevice->GetDisplayDeviceName();
  827. }
  828. //-----------------------------------------------------------------------------
  829. //
  830. //-----------------------------------------------------------------------------
  831. void CMaterialSystem::SetThreadMode( MaterialThreadMode_t nextThreadMode, int nServiceThread )
  832. {
  833. m_IdealThreadMode = nextThreadMode;
  834. m_nServiceThread = nServiceThread;
  835. }
  836. MaterialThreadMode_t CMaterialSystem::GetThreadMode()
  837. {
  838. return m_ThreadMode;
  839. }
  840. bool CMaterialSystem::IsRenderThreadSafe( )
  841. {
  842. return ( m_ThreadMode != MATERIAL_QUEUED_THREADED && ThreadInMainThread() ) ||
  843. ( m_ThreadMode == MATERIAL_QUEUED_THREADED && m_nRenderThreadID == ThreadGetCurrentId() );
  844. }
  845. bool CMaterialSystem::AllowThreading( bool bAllow, int nServiceThread )
  846. {
  847. #if defined(DEDICATED)
  848. return false;
  849. #else
  850. if ( CommandLine()->ParmValue( "-threads", 2 ) < 2 ) // if -threads specified on command line to restrict all the pools then obey and not turn on QMS
  851. bAllow = false;
  852. bool bOldAllow = m_bAllowQueuedRendering;
  853. if ( GetCPUInformation()->m_nPhysicalProcessors >= 2 )
  854. {
  855. m_bAllowQueuedRendering = bAllow;
  856. bool bQueued = m_IdealThreadMode != MATERIAL_SINGLE_THREADED;
  857. if ( bAllow && !bQueued )
  858. {
  859. // go into queued mode
  860. DevMsg( "Queued Material System: ENABLED!\n" );
  861. SetThreadMode( MATERIAL_QUEUED_THREADED, nServiceThread );
  862. }
  863. else if ( !bAllow && bQueued )
  864. {
  865. // disabling queued mode just needs to stop the queuing of drawing
  866. // but still allow other threaded access to the Material System
  867. // flush the queue
  868. DevMsg( "Queued Material System: DISABLED!\n" );
  869. ForceSingleThreaded();
  870. MaterialLock_t hMaterialLock = Lock();
  871. SetThreadMode( MATERIAL_SINGLE_THREADED, -1 );
  872. Unlock( hMaterialLock );
  873. }
  874. }
  875. else
  876. {
  877. m_bAllowQueuedRendering = false;
  878. }
  879. return bOldAllow;
  880. #endif // !DEDICATED
  881. }
  882. void CMaterialSystem::ExecuteQueued()
  883. {
  884. }
  885. //-----------------------------------------------------------------------------
  886. //
  887. //-----------------------------------------------------------------------------
  888. IMatRenderContext *CMaterialSystem::GetRenderContext()
  889. {
  890. IMatRenderContext *pResult = m_pRenderContext.Get();
  891. if ( !pResult )
  892. {
  893. pResult = &m_HardwareRenderContext;
  894. m_pRenderContext.Set( &m_HardwareRenderContext );
  895. }
  896. return RetAddRef( pResult );
  897. }
  898. //-----------------------------------------------------------------------------
  899. //
  900. //-----------------------------------------------------------------------------
  901. IMatRenderContext *CMaterialSystem::CreateRenderContext( MaterialContextType_t type )
  902. {
  903. switch ( type )
  904. {
  905. case MATERIAL_HARDWARE_CONTEXT:
  906. return NULL;
  907. case MATERIAL_QUEUED_CONTEXT:
  908. {
  909. CMatQueuedRenderContext *pQueuedContext = new CMatQueuedRenderContext;
  910. pQueuedContext->Init( this, &m_HardwareRenderContext );
  911. pQueuedContext->BeginQueue( &m_HardwareRenderContext );
  912. return pQueuedContext;
  913. }
  914. case MATERIAL_NULL_CONTEXT:
  915. {
  916. CMatRenderContextBase *pNullContext = CreateNullRenderContext();
  917. pNullContext->Init();
  918. pNullContext->InitializeFrom( &m_HardwareRenderContext );
  919. return pNullContext;
  920. }
  921. }
  922. Assert(0);
  923. return NULL;
  924. }
  925. //-----------------------------------------------------------------------------
  926. //
  927. //-----------------------------------------------------------------------------
  928. IMatRenderContext *CMaterialSystem::SetRenderContext( IMatRenderContext *pNewContext )
  929. {
  930. IMatRenderContext *pOldContext = m_pRenderContext.Get();
  931. if ( pNewContext )
  932. {
  933. pNewContext->AddRef();
  934. m_pRenderContext.Set( assert_cast<IMatRenderContextInternal *>(pNewContext) );
  935. }
  936. else
  937. {
  938. m_pRenderContext.Set( NULL );
  939. }
  940. return pOldContext;
  941. }
  942. //-----------------------------------------------------------------------------
  943. // Get/Set Material proxy factory
  944. //-----------------------------------------------------------------------------
  945. IMaterialProxyFactory* CMaterialSystem::GetMaterialProxyFactory()
  946. {
  947. return m_pMaterialProxyFactory;
  948. }
  949. void CMaterialSystem::SetMaterialProxyFactory( IMaterialProxyFactory* pFactory )
  950. {
  951. // Changing the factory requires an uncaching of all materials
  952. // since the factory may contain different proxies
  953. UncacheAllMaterials();
  954. m_pMaterialProxyFactory = pFactory;
  955. }
  956. //-----------------------------------------------------------------------------
  957. // Can we use editor materials?
  958. //-----------------------------------------------------------------------------
  959. bool CMaterialSystem::CanUseEditorMaterials() const
  960. {
  961. return m_bCanUseEditorMaterials;
  962. }
  963. //-----------------------------------------------------------------------------
  964. // Methods related to mode setting...
  965. //-----------------------------------------------------------------------------
  966. // Gets the number of adapters...
  967. int CMaterialSystem::GetDisplayAdapterCount() const
  968. {
  969. return g_pShaderDeviceMgr->GetAdapterCount( );
  970. }
  971. // Returns info about each adapter
  972. void CMaterialSystem::GetDisplayAdapterInfo( int adapter, MaterialAdapterInfo_t& info ) const
  973. {
  974. g_pShaderDeviceMgr->GetAdapterInfo( adapter, info );
  975. }
  976. // Returns the number of modes
  977. int CMaterialSystem::GetModeCount( int adapter ) const
  978. {
  979. return g_pShaderDeviceMgr->GetModeCount( adapter );
  980. }
  981. //-----------------------------------------------------------------------------
  982. // Compatability function, should go away eventually
  983. //-----------------------------------------------------------------------------
  984. static void ConvertModeStruct( ShaderDeviceInfo_t *pMode, const MaterialSystem_Config_t &config )
  985. {
  986. pMode->m_DisplayMode.m_nWidth = config.m_VideoMode.m_Width;
  987. pMode->m_DisplayMode.m_nHeight = config.m_VideoMode.m_Height;
  988. pMode->m_DisplayMode.m_Format = config.m_VideoMode.m_Format;
  989. pMode->m_DisplayMode.m_nRefreshRateNumerator = config.m_VideoMode.m_RefreshRate;
  990. pMode->m_DisplayMode.m_nRefreshRateDenominator = config.m_VideoMode.m_RefreshRate ? 1 : 0;
  991. pMode->m_nBackBufferCount = 1;
  992. pMode->m_nAASamples = config.m_nAASamples;
  993. pMode->m_nAAQuality = config.m_nAAQuality;
  994. pMode->m_nDXLevel = MAX( ABSOLUTE_MINIMUM_DXLEVEL, config.dxSupportLevel );
  995. pMode->m_nWindowedSizeLimitWidth = (int)config.m_WindowedSizeLimitWidth;
  996. pMode->m_nWindowedSizeLimitHeight = (int)config.m_WindowedSizeLimitHeight;
  997. pMode->m_bWindowed = config.Windowed();
  998. pMode->m_bResizing = config.Resizing();
  999. pMode->m_bUseStencil = config.Stencil();
  1000. pMode->m_bLimitWindowedSize = config.LimitWindowedSize();
  1001. pMode->m_bWaitForVSync = config.WaitForVSync();
  1002. pMode->m_bScaleToOutputResolution = config.ScaleToOutputResolution();
  1003. pMode->m_bUsingMultipleWindows = config.UsingMultipleWindows();
  1004. }
  1005. static void ConvertModeStruct( MaterialVideoMode_t *pMode, const ShaderDisplayMode_t &info )
  1006. {
  1007. pMode->m_Width = info.m_nWidth;
  1008. pMode->m_Height = info.m_nHeight;
  1009. pMode->m_Format = info.m_Format;
  1010. pMode->m_RefreshRate = info.m_nRefreshRateDenominator ? ( info.m_nRefreshRateNumerator / info.m_nRefreshRateDenominator ) : 0;
  1011. }
  1012. //-----------------------------------------------------------------------------
  1013. // Returns mode information..
  1014. //-----------------------------------------------------------------------------
  1015. void CMaterialSystem::GetModeInfo( int nAdapter, int nMode, MaterialVideoMode_t& info ) const
  1016. {
  1017. ShaderDisplayMode_t shaderInfo;
  1018. g_pShaderDeviceMgr->GetModeInfo( &shaderInfo, nAdapter, nMode );
  1019. ConvertModeStruct( &info, shaderInfo );
  1020. }
  1021. //-----------------------------------------------------------------------------
  1022. // Returns the mode info for the current display device
  1023. //-----------------------------------------------------------------------------
  1024. void CMaterialSystem::GetDisplayMode( MaterialVideoMode_t& info ) const
  1025. {
  1026. ShaderDisplayMode_t shaderInfo;
  1027. g_pShaderDeviceMgr->GetCurrentModeInfo( &shaderInfo, m_nAdapter );
  1028. ConvertModeStruct( &info, shaderInfo );
  1029. }
  1030. void CMaterialSystem::ForceSingleThreaded()
  1031. {
  1032. if ( !ThreadInMainThread() )
  1033. {
  1034. Error("Can't force single thread from within thread!\n");
  1035. }
  1036. if ( GetThreadMode() != MATERIAL_SINGLE_THREADED )
  1037. {
  1038. if ( m_pActiveAsyncJob && !m_pActiveAsyncJob->IsFinished() )
  1039. {
  1040. m_pActiveAsyncJob->WaitForFinish();
  1041. }
  1042. SafeRelease( m_pActiveAsyncJob );
  1043. ThreadRelease();
  1044. g_pShaderAPI->EnableShaderShaderMutex( false );
  1045. m_HardwareRenderContext.InitializeFrom(&m_QueuedRenderContexts[m_iCurQueuedContext]);
  1046. m_pRenderContext.Set( &m_HardwareRenderContext );
  1047. for ( int i = 0; i < ARRAYSIZE( m_QueuedRenderContexts ); i++ )
  1048. {
  1049. Assert( m_QueuedRenderContexts[i].IsInitialized() );
  1050. m_QueuedRenderContexts[i].EndQueue(true);
  1051. }
  1052. if( mat_debugalttab.GetBool() )
  1053. {
  1054. Warning("Forcing queued mode off!\n");
  1055. }
  1056. // NOTE: Must happen after EndQueue or proxies get bound again, which is bad.
  1057. m_ThreadMode = MATERIAL_SINGLE_THREADED;
  1058. m_bForcedSingleThreaded = true;
  1059. }
  1060. }
  1061. //-----------------------------------------------------------------------------
  1062. // Sets the mode...
  1063. //-----------------------------------------------------------------------------
  1064. bool CMaterialSystem::SetMode( void* hwnd, const MaterialSystem_Config_t &config )
  1065. {
  1066. Assert( m_bGeneratedConfig );
  1067. ForceSingleThreaded();
  1068. ShaderDeviceInfo_t info;
  1069. ConvertModeStruct( &info, config );
  1070. bool bPreviouslyUsingGraphics = g_pShaderDevice->IsUsingGraphics();
  1071. if( config.m_nVRModeAdapter != -1 && config.m_nVRModeAdapter < GetDisplayAdapterCount() && !bPreviouslyUsingGraphics )
  1072. {
  1073. // if this is init-time, we need to override the adapter with the
  1074. // VR mode adapter
  1075. m_nAdapter = config.m_nVRModeAdapter;
  1076. }
  1077. bool bOk = g_pShaderAPI->SetMode( hwnd, m_nAdapter, info );
  1078. if ( !bOk )
  1079. return false;
  1080. #if defined( USE_SDL )
  1081. uint width = info.m_DisplayMode.m_nWidth;
  1082. uint height = info.m_DisplayMode.m_nHeight;
  1083. g_pLauncherMgr->RenderedSize( width, height, true ); // true = set
  1084. #endif
  1085. TextureManager()->FreeStandardRenderTargets();
  1086. TextureManager()->AllocateStandardRenderTargets();
  1087. // FIXME: There's gotta be a better way of doing this?
  1088. // After the first mode set, make sure to download any textures created
  1089. // before the first mode set. After the first mode set, all textures
  1090. // will be reloaded via the reaquireresources call. Same goes for procedural materials
  1091. if ( !bPreviouslyUsingGraphics )
  1092. {
  1093. if ( IsPC() )
  1094. {
  1095. TextureManager()->RestoreRenderTargets();
  1096. TextureManager()->RestoreNonRenderTargetTextures();
  1097. if ( MaterialSystem()->CanUseEditorMaterials() )
  1098. {
  1099. // We are in Hammer. Allocate these here since we aren't going to allocate
  1100. // lightmaps.
  1101. // HACK!
  1102. // NOTE! : Overbright is 1.0 so that Hammer will work properly with the white bumped and unbumped lightmaps.
  1103. MathLib_Init( 2.2f, 2.2f, 0.0f, OVERBRIGHT );
  1104. }
  1105. AllocateStandardTextures();
  1106. TextureManager()->WarmTextureCache();
  1107. }
  1108. if ( IsX360() )
  1109. {
  1110. // shaderapi was not viable at init time, it is now
  1111. TextureManager()->ReloadTextures();
  1112. AllocateStandardTextures();
  1113. }
  1114. }
  1115. g_pShaderDevice->SetHardwareGammaRamp( config.m_fMonitorGamma, config.m_fGammaTVRangeMin, config.m_fGammaTVRangeMax,
  1116. config.m_fGammaTVExponent, config.m_bGammaTVEnabled );
  1117. // Copy over that state which isn't stored currently in convars
  1118. g_config.m_VideoMode = config.m_VideoMode;
  1119. g_config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, config.Windowed() );
  1120. g_config.SetFlag( MATSYS_VIDCFG_FLAGS_STENCIL, config.Stencil() );
  1121. g_config.SetFlag( MATSYS_VIDCFG_FLAGS_VR_MODE, config.VRMode() );
  1122. WriteConfigIntoConVars( config );
  1123. extern void SetupDirtyDiskReportFunc();
  1124. SetupDirtyDiskReportFunc();
  1125. return true;
  1126. }
  1127. // Creates/ destroys a child window
  1128. bool CMaterialSystem::AddView( void* hwnd )
  1129. {
  1130. return g_pShaderDevice->AddView( hwnd );
  1131. }
  1132. void CMaterialSystem::RemoveView( void* hwnd )
  1133. {
  1134. g_pShaderDevice->RemoveView( hwnd );
  1135. }
  1136. // Activates a view
  1137. void CMaterialSystem::SetView( void* hwnd )
  1138. {
  1139. g_pShaderDevice->SetView( hwnd );
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Installs a function to be called when we need to release vertex buffers
  1143. //-----------------------------------------------------------------------------
  1144. void CMaterialSystem::AddReleaseFunc( MaterialBufferReleaseFunc_t func )
  1145. {
  1146. // Shouldn't have two copies in our list
  1147. Assert( m_ReleaseFunc.Find( func ) == -1 );
  1148. m_ReleaseFunc.AddToTail( func );
  1149. }
  1150. void CMaterialSystem::RemoveReleaseFunc( MaterialBufferReleaseFunc_t func )
  1151. {
  1152. int i = m_ReleaseFunc.Find( func );
  1153. if( i != -1 )
  1154. m_ReleaseFunc.Remove(i);
  1155. }
  1156. //-----------------------------------------------------------------------------
  1157. // Installs a function to be called when we need to restore vertex buffers
  1158. //-----------------------------------------------------------------------------
  1159. void CMaterialSystem::AddRestoreFunc( MaterialBufferRestoreFunc_t func )
  1160. {
  1161. // Shouldn't have two copies in our list
  1162. Assert( m_RestoreFunc.Find( func ) == -1 );
  1163. m_RestoreFunc.AddToTail( func );
  1164. }
  1165. void CMaterialSystem::RemoveRestoreFunc( MaterialBufferRestoreFunc_t func )
  1166. {
  1167. int i = m_RestoreFunc.Find( func );
  1168. Assert( i != -1 );
  1169. m_RestoreFunc.Remove(i);
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. // Called by the shader API when it's just about to lose video memory
  1173. //-----------------------------------------------------------------------------
  1174. void CMaterialSystem::ReleaseShaderObjects()
  1175. {
  1176. if( mat_debugalttab.GetBool() )
  1177. {
  1178. Warning( "mat_debugalttab: CMaterialSystem::ReleaseShaderObjects\n" );
  1179. }
  1180. m_HardwareRenderContext.OnReleaseShaderObjects();
  1181. g_pOcclusionQueryMgr->FreeOcclusionQueryObjects();
  1182. TextureManager()->ReleaseTextures();
  1183. ReleaseStandardTextures();
  1184. GetLightmaps()->ReleaseLightmapPages();
  1185. for (int i = 0; i < m_ReleaseFunc.Count(); ++i)
  1186. {
  1187. m_ReleaseFunc[i]();
  1188. }
  1189. }
  1190. void CMaterialSystem::RestoreShaderObjects( CreateInterfaceFn shaderFactory, int nChangeFlags )
  1191. {
  1192. if ( shaderFactory )
  1193. {
  1194. g_pShaderAPI = (IShaderAPI*)shaderFactory( SHADERAPI_INTERFACE_VERSION, NULL );
  1195. g_pShaderDevice = (IShaderDevice*)shaderFactory( SHADER_DEVICE_INTERFACE_VERSION, NULL );
  1196. g_pShaderShadow = (IShaderShadow*)shaderFactory( SHADERSHADOW_INTERFACE_VERSION, NULL );
  1197. }
  1198. for( MaterialHandle_t i = m_MaterialDict.FirstMaterial(); i != m_MaterialDict.InvalidMaterial(); i = m_MaterialDict.NextMaterial( i ) )
  1199. {
  1200. IMaterialInternal *pMat = m_MaterialDict.GetMaterialInternal( i );
  1201. if ( pMat )
  1202. pMat->ReportVarChanged( NULL );
  1203. }
  1204. if ( mat_debugalttab.GetBool() )
  1205. {
  1206. Warning( "mat_debugalttab: CMaterialSystem::RestoreShaderObjects\n" );
  1207. }
  1208. // Shader API sets this to the max value the card supports when it resets
  1209. // the state, so restore this value.
  1210. g_pShaderAPI->SetAnisotropicLevel( GetCurrentConfigForVideoCard().m_nForceAnisotropicLevel );
  1211. // NOTE: render targets must be restored first, then vb/ibs, then managed textures
  1212. // FIXME: Gotta restore lightmap pages + standard textures before restore funcs are called
  1213. // because they use them both.
  1214. TextureManager()->RestoreRenderTargets();
  1215. AllocateStandardTextures();
  1216. GetLightmaps()->RestoreLightmapPages();
  1217. g_pOcclusionQueryMgr->AllocOcclusionQueryObjects();
  1218. for (int i = 0; i < m_RestoreFunc.Count(); ++i)
  1219. {
  1220. m_RestoreFunc[i]( nChangeFlags );
  1221. }
  1222. TextureManager()->RestoreNonRenderTargetTextures( );
  1223. }
  1224. //-----------------------------------------------------------------------------
  1225. // Use this to spew information about the 3D layer
  1226. //-----------------------------------------------------------------------------
  1227. void CMaterialSystem::SpewDriverInfo() const
  1228. {
  1229. Warning( "ShaderAPI: %s\n", m_pShaderDLL );
  1230. g_pShaderDevice->SpewDriverInfo();
  1231. }
  1232. //-----------------------------------------------------------------------------
  1233. // Color converting blitter
  1234. //-----------------------------------------------------------------------------
  1235. bool CMaterialSystem::ConvertImageFormat( unsigned char *src, enum ImageFormat srcImageFormat,
  1236. unsigned char *dst, enum ImageFormat dstImageFormat,
  1237. int width, int height, int srcStride, int dstStride )
  1238. {
  1239. return ImageLoader::ConvertImageFormat( src, srcImageFormat,
  1240. dst, dstImageFormat, width, height, srcStride, dstStride );
  1241. }
  1242. //-----------------------------------------------------------------------------
  1243. // Figures out the amount of memory needed by a bitmap
  1244. //-----------------------------------------------------------------------------
  1245. int CMaterialSystem::GetMemRequired( int width, int height, int depth, ImageFormat format, bool mipmap )
  1246. {
  1247. return ImageLoader::GetMemRequired( width, height, depth, format, mipmap );
  1248. }
  1249. //-----------------------------------------------------------------------------
  1250. // Method to allow clients access to the MaterialSystem_Config
  1251. //-----------------------------------------------------------------------------
  1252. MaterialSystem_Config_t& CMaterialSystem::GetConfig()
  1253. {
  1254. //hushed Assert( m_bGeneratedConfig );
  1255. return g_config;
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. // Gets image format info
  1259. //-----------------------------------------------------------------------------
  1260. ImageFormatInfo_t const& CMaterialSystem::ImageFormatInfo( ImageFormat fmt) const
  1261. {
  1262. return ImageLoader::ImageFormatInfo(fmt);
  1263. }
  1264. //-----------------------------------------------------------------------------
  1265. // Reads keyvalues for information
  1266. //-----------------------------------------------------------------------------
  1267. static void ReadInt( KeyValues *pGroup, const char *pName, int nDefaultVal, int nUndefinedVal, int *pDest )
  1268. {
  1269. *pDest = pGroup->GetInt( pName, nDefaultVal );
  1270. // Warning( "\t%s = %d\n", pName, *pDest );
  1271. Assert( *pDest != nUndefinedVal );
  1272. }
  1273. static void ReadFlt( KeyValues *pGroup, const char *pName, float flDefaultVal, float flUndefinedVal, float *pDest )
  1274. {
  1275. *pDest = pGroup->GetFloat( pName, flDefaultVal );
  1276. // Warning( "\t%s = %f\n", pName, *pDest );
  1277. Assert( *pDest != flUndefinedVal );
  1278. }
  1279. static void LoadFlags( KeyValues *pGroup, const char *pName, bool bDefaultValue, unsigned int nFlag, unsigned int *pFlags )
  1280. {
  1281. int nValue = pGroup->GetInt( pName, bDefaultValue ? 1 : 0 );
  1282. // Warning( "\t%s = %s\n", pName, nValue ? "true" : "false" );
  1283. if ( nValue )
  1284. {
  1285. *pFlags |= nFlag;
  1286. }
  1287. }
  1288. #define ASPECT_4x3 0
  1289. #define ASPECT_16x9 1
  1290. #define ASPECT_16x10 2
  1291. //-----------------------------------------------------------------------------
  1292. // Purpose: aspect ratio mappings (for normal/widescreen combo)
  1293. //-----------------------------------------------------------------------------
  1294. struct RatioToAspectMode_t
  1295. {
  1296. int nAspectCode;
  1297. float flAspectRatio;
  1298. };
  1299. RatioToAspectMode_t g_RatioToAspectModes[] =
  1300. {
  1301. { ASPECT_4x3, 4.0f / 3.0f },
  1302. { ASPECT_16x9, 16.0f / 9.0f },
  1303. { ASPECT_16x10, 16.0f / 10.0f },
  1304. { ASPECT_16x10, 1.0f },
  1305. };
  1306. //-----------------------------------------------------------------------------
  1307. // Purpose: returns the aspect ratio mode number for the given resolution
  1308. //-----------------------------------------------------------------------------
  1309. int GetScreenAspectMode( int width, int height )
  1310. {
  1311. float flAspectRatio = (float)width / (float)height;
  1312. // Just find the closest ratio
  1313. float flClosestAspectRatioDist = 99999.0f;
  1314. int nClosestAspectCode = ASPECT_4x3;
  1315. for ( int i = 0; i < ARRAYSIZE(g_RatioToAspectModes); i++ )
  1316. {
  1317. float flDist = fabs( g_RatioToAspectModes[i].flAspectRatio - flAspectRatio );
  1318. if ( flDist < flClosestAspectRatioDist )
  1319. {
  1320. flClosestAspectRatioDist = flDist;
  1321. nClosestAspectCode = g_RatioToAspectModes[i].nAspectCode;
  1322. }
  1323. }
  1324. return nClosestAspectCode;
  1325. }
  1326. // Heuristic similar to one we put into L4D
  1327. bool BetterResolution( int nRecommendedNumPixels, int nBestNumPixels, int nNewNumPixels )
  1328. {
  1329. float flRecommendedNumPixels = (float) nRecommendedNumPixels;
  1330. float flBestNumPixels = (float) nBestNumPixels;
  1331. float flNewNumPixels = (float) nNewNumPixels;
  1332. // Give ourselves a little head room
  1333. float flTooBig = flRecommendedNumPixels * 1.1f;
  1334. // If our best is too big and the new resolution is no bigger, pick it
  1335. if ( ( flBestNumPixels > flTooBig ) && ( flNewNumPixels < flBestNumPixels ) )
  1336. return true;
  1337. // Don't allow resolutions which are too big
  1338. if ( flNewNumPixels > flTooBig )
  1339. return false;
  1340. // Finally, just check for nearness to desired number of pixels
  1341. float flDelta = fabs( flRecommendedNumPixels - flNewNumPixels );
  1342. float flBestDelta = fabs( flRecommendedNumPixels - flBestNumPixels );
  1343. if ( flDelta >= flBestDelta )
  1344. return false;
  1345. return true;
  1346. }
  1347. //-----------------------------------------------------------------------------
  1348. // This is called when the config changes
  1349. //-----------------------------------------------------------------------------
  1350. void CMaterialSystem::GenerateConfigFromConfigKeyValues( MaterialSystem_Config_t *pConfig, bool bOverwriteCommandLineValues )
  1351. {
  1352. if ( !g_pShaderDeviceMgr || !pConfig )
  1353. return;
  1354. // Look for the default recommended dx support level
  1355. MaterialAdapterInfo_t adapterInfo;
  1356. g_pShaderDeviceMgr->GetAdapterInfo( m_nAdapter, adapterInfo );
  1357. pConfig->dxSupportLevel = MAX( ABSOLUTE_MINIMUM_DXLEVEL, adapterInfo.m_nDXSupportLevel );
  1358. KeyValues *pKeyValues = new KeyValues( "config" );
  1359. if ( !GetRecommendedConfigurationInfo( pConfig->dxSupportLevel, pKeyValues ) )
  1360. {
  1361. pKeyValues->deleteThis();
  1362. return;
  1363. }
  1364. pConfig->m_Flags = 0;
  1365. #ifdef LINUX
  1366. uint width = 0;
  1367. uint height = 0;
  1368. uint refreshHz = 0; // Not used
  1369. #ifdef USE_SDL
  1370. // query backbuffer size (window size whether FS or windowed)
  1371. if( g_pLauncherMgr )
  1372. {
  1373. g_pLauncherMgr->GetNativeDisplayInfo( -1, width, height, refreshHz );
  1374. }
  1375. #endif
  1376. pConfig->m_VideoMode.m_Width = width;
  1377. pConfig->m_VideoMode.m_Height = height;
  1378. #else
  1379. // Get the recommended resolution from dxsupport.cfg, this assumes a 4:3 aspect ratio
  1380. int nRecommendedWidth, nRecommendedHeight;
  1381. ReadInt( pKeyValues, "DefaultRes", 640, -1, &nRecommendedWidth );
  1382. nRecommendedHeight = ( nRecommendedWidth * 3 ) / 4;
  1383. int nRecommendedPixels = nRecommendedHeight * nRecommendedWidth;
  1384. // Get the desktop resolution and aspect ratio
  1385. ShaderDisplayMode_t displayMode;
  1386. g_pShaderDeviceMgr->GetCurrentModeInfo( &displayMode, 0 );
  1387. int nCurrentScreenAspect = GetScreenAspectMode( displayMode.m_nWidth, displayMode.m_nHeight );
  1388. // Let's see what the device supports and pick the most appropriate mode
  1389. g_pShaderDeviceMgr->GetModeInfo( &displayMode, 0, 0 );
  1390. int nBestMode, nBestWidth, nBestHeight;
  1391. nBestMode = nBestWidth = nBestHeight = -1;
  1392. int nBestPixels = displayMode.m_nHeight * displayMode.m_nWidth;
  1393. int nNumVideoModes = g_pShaderDeviceMgr->GetModeCount( 0 );
  1394. // Pick the resolution with the right aspect ratio which matches the recommended resolution most closely
  1395. for ( int i=0; i<nNumVideoModes; i++ )
  1396. {
  1397. g_pShaderDeviceMgr->GetModeInfo( &displayMode, 0, i );
  1398. if ( nCurrentScreenAspect == GetScreenAspectMode( displayMode.m_nWidth, displayMode.m_nHeight ) )
  1399. {
  1400. int nNumPixels = displayMode.m_nWidth * displayMode.m_nHeight;
  1401. // Initially select the first mode we find of the correct aspect ratio for the display
  1402. if ( ( nBestMode == -1) || BetterResolution( nRecommendedPixels, nBestPixels, nNumPixels ) )
  1403. {
  1404. nBestMode = i;
  1405. nBestPixels = nNumPixels;
  1406. nBestWidth = displayMode.m_nWidth;
  1407. nBestHeight = displayMode.m_nHeight;
  1408. }
  1409. }
  1410. }
  1411. // We found a good mode
  1412. if ( nBestMode != -1 )
  1413. {
  1414. pConfig->m_VideoMode.m_Width = nBestWidth;
  1415. pConfig->m_VideoMode.m_Height = nBestHeight;
  1416. }
  1417. else // Fall back to 4:3 mode from the cfg file. This should never happen
  1418. {
  1419. pConfig->m_VideoMode.m_Width = nRecommendedWidth;
  1420. pConfig->m_VideoMode.m_Height = nRecommendedHeight;
  1421. }
  1422. #if defined( _X360 )
  1423. pConfig->m_VideoMode.m_Width = GetSystemMetrics( SM_CXSCREEN );
  1424. pConfig->m_VideoMode.m_Height = GetSystemMetrics( SM_CYSCREEN );
  1425. #endif
  1426. pKeyValues->deleteThis();
  1427. #endif // LINUX
  1428. WriteConfigurationInfoToConVars( bOverwriteCommandLineValues );
  1429. m_bGeneratedConfig = true;
  1430. }
  1431. //-----------------------------------------------------------------------------
  1432. // If mat_proxy goes to 0, we need to reload all materials, because their shader
  1433. // params might have been messed with.
  1434. //-----------------------------------------------------------------------------
  1435. static void MatProxyCallback( IConVar *pConVar, const char *old, float flOldValue )
  1436. {
  1437. ConVarRef var( pConVar );
  1438. int oldVal = (int)flOldValue;
  1439. if ( var.GetInt() == 0 && oldVal != 0 )
  1440. {
  1441. g_MaterialSystem.ReloadMaterials();
  1442. }
  1443. }
  1444. //-----------------------------------------------------------------------------
  1445. // Convars that control the config record
  1446. //-----------------------------------------------------------------------------
  1447. static ConVar mat_vsync( "mat_vsync", "0", FCVAR_ALLOWED_IN_COMPETITIVE, "Force sync to vertical retrace", true, 0.0, true, 1.0 );
  1448. static ConVar mat_forcehardwaresync( "mat_forcehardwaresync", IsPC() ? "1" : "0", FCVAR_ALLOWED_IN_COMPETITIVE );
  1449. // Texture-related
  1450. static ConVar mat_trilinear( "mat_trilinear", "0", FCVAR_ALLOWED_IN_COMPETITIVE );
  1451. #ifdef _X360 // The code that reads this out of moddefaults.txt is #if'd out for the 360, so force aniso to 2 here.
  1452. static ConVar mat_forceaniso( "mat_forceaniso", "2", FCVAR_ARCHIVE ); // 0 = Bilinear, 1 = Trilinear, 2+ = Aniso
  1453. #elif defined ( OSX )
  1454. static ConVar mat_forceaniso( "mat_forceaniso", "1", FCVAR_ARCHIVE, "Filtering level", true, 0, true, 8 ); // 0 = Bilinear, 1 = Trilinear, 2+ = Aniso
  1455. #else
  1456. static ConVar mat_forceaniso( "mat_forceaniso", "1", FCVAR_ARCHIVE ); // 0 = Bilinear, 1 = Trilinear, 2+ = Aniso
  1457. #endif
  1458. static ConVar mat_filterlightmaps( "mat_filterlightmaps", "1" );
  1459. static ConVar mat_filtertextures( "mat_filtertextures", "1" );
  1460. static ConVar mat_mipmaptextures( "mat_mipmaptextures", "1" );
  1461. static ConVar mat_vrmode_adapter( "mat_vrmode_adapter", "-1" );
  1462. static void mat_showmiplevels_Callback_f( IConVar *var, const char *pOldValue, float flOldValue )
  1463. {
  1464. // turn off texture filtering if we are showing mip levels.
  1465. mat_filtertextures.SetValue( ( ( ConVar * )var )->GetInt() == 0 );
  1466. }
  1467. // Debugging textures
  1468. static ConVar mat_showmiplevels( "mat_showmiplevels", "0", FCVAR_CHEAT, "color-code miplevels 2: normalmaps, 1: everything else", mat_showmiplevels_Callback_f );
  1469. static ConVar mat_specular( "mat_specular", "1", FCVAR_ALLOWED_IN_COMPETITIVE, "Enable/Disable specularity for perf testing. Will cause a material reload upon change." );
  1470. static ConVar mat_bumpmap( "mat_bumpmap", "1", FCVAR_ALLOWED_IN_COMPETITIVE );
  1471. static ConVar mat_phong( "mat_phong", "1" );
  1472. static ConVar mat_parallaxmap( "mat_parallaxmap", "1", FCVAR_HIDDEN | FCVAR_ALLOWED_IN_COMPETITIVE );
  1473. static ConVar mat_reducefillrate( "mat_reducefillrate", "0", FCVAR_ALLOWED_IN_COMPETITIVE );
  1474. #if defined( OSX ) && !defined( STAGING_ONLY ) && !defined( _DEBUG )
  1475. // OSX users are currently running OOM. We limit them to texture quality high here, which avoids the problem while we come up with a real solution.
  1476. static ConVar mat_picmip( "mat_picmip", "1", FCVAR_ARCHIVE, "", true, 0, true, 4 );
  1477. #else
  1478. static ConVar mat_picmip( "mat_picmip", "0", FCVAR_ARCHIVE, "", true, -1, true, 4 );
  1479. #endif
  1480. static ConVar mat_slopescaledepthbias_normal( "mat_slopescaledepthbias_normal", "0.0f", FCVAR_CHEAT );
  1481. static ConVar mat_depthbias_normal( "mat_depthbias_normal", "0.0f", FCVAR_CHEAT | FCVAR_ALLOWED_IN_COMPETITIVE );
  1482. static ConVar mat_slopescaledepthbias_decal( "mat_slopescaledepthbias_decal", "-0.5", FCVAR_CHEAT ); // Reciprocals of these biases sent to API
  1483. static ConVar mat_depthbias_decal( "mat_depthbias_decal", "-262144", FCVAR_CHEAT | FCVAR_ALLOWED_IN_COMPETITIVE ); //
  1484. static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT );
  1485. static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT );
  1486. static ConVar mat_monitorgamma( "mat_monitorgamma", "2.2", FCVAR_ARCHIVE, "monitor gamma (typically 2.2 for CRT and 1.7 for LCD)", true, 1.6f, true, 2.6f );
  1487. static ConVar mat_monitorgamma_tv_range_min( "mat_monitorgamma_tv_range_min", "16" );
  1488. static ConVar mat_monitorgamma_tv_range_max( "mat_monitorgamma_tv_range_max", "255" );
  1489. // TV's generally have a 2.5 gamma, so we need to convert our 2.2 frame buffer into a 2.5 frame buffer for display on a TV
  1490. static ConVar mat_monitorgamma_tv_exp( "mat_monitorgamma_tv_exp", "2.5", 0, "", true, 1.0f, true, 4.0f );
  1491. #ifdef _X360
  1492. static ConVar mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled", "1", FCVAR_ARCHIVE, "" );
  1493. #else
  1494. static ConVar mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled", "0", FCVAR_ARCHIVE, "" );
  1495. #endif
  1496. static ConVar mat_antialias( "mat_antialias", "0", FCVAR_ARCHIVE );
  1497. static ConVar mat_aaquality( "mat_aaquality", "0", FCVAR_ARCHIVE );
  1498. static ConVar mat_diffuse( "mat_diffuse", "1", FCVAR_CHEAT );
  1499. //=============================================================================
  1500. // HPE_BEGIN:
  1501. // [Forrest] Make this a cheat variable because low res textures makes enemy
  1502. // players and bullet impacts stand out more.
  1503. //=============================================================================
  1504. static ConVar mat_showlowresimage( "mat_showlowresimage", "0", FCVAR_CHEAT );
  1505. //=============================================================================
  1506. // HPE_END
  1507. //=============================================================================
  1508. static ConVar mat_fullbright( "mat_fullbright","0", FCVAR_CHEAT );
  1509. static ConVar mat_normalmaps( "mat_normalmaps", "0", FCVAR_CHEAT );
  1510. static ConVar mat_measurefillrate( "mat_measurefillrate", "0", FCVAR_CHEAT );
  1511. static ConVar mat_fillrate( "mat_fillrate", "0", FCVAR_CHEAT );
  1512. static ConVar mat_reversedepth( "mat_reversedepth", "0", FCVAR_CHEAT );
  1513. #ifdef DX_TO_GL_ABSTRACTION
  1514. static ConVar mat_bufferprimitives( "mat_bufferprimitives", "0" ); // I'm not seeing any benefit speed wise for buffered primitives on GLM/POSIX (checked via TF2 timedemo) - default to zero
  1515. #else
  1516. static ConVar mat_bufferprimitives( "mat_bufferprimitives", "1" );
  1517. #endif
  1518. static ConVar mat_drawflat( "mat_drawflat","0", FCVAR_CHEAT );
  1519. static ConVar mat_softwarelighting( "mat_softwarelighting", "0", FCVAR_ALLOWED_IN_COMPETITIVE );
  1520. static ConVar mat_proxy( "mat_proxy", "0", FCVAR_CHEAT, "", MatProxyCallback );
  1521. static ConVar mat_norendering( "mat_norendering", "0", FCVAR_CHEAT );
  1522. static ConVar mat_compressedtextures( "mat_compressedtextures", "1" );
  1523. static ConVar mat_fastspecular( "mat_fastspecular", "1", 0, "Enable/Disable specularity for visual testing. Will not reload materials and will not affect perf." );
  1524. static ConVar mat_fastnobump( "mat_fastnobump", "0", FCVAR_CHEAT ); // Binds 1-texel normal map for quick internal testing
  1525. // These are not controlled by the material system, but are limited by settings in the material system
  1526. static ConVar r_shadowrendertotexture( "r_shadowrendertotexture", "0", FCVAR_ARCHIVE );
  1527. static ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1" );
  1528. #ifndef _X360
  1529. static ConVar r_waterforceexpensive( "r_waterforceexpensive", "0", FCVAR_ARCHIVE );
  1530. #endif
  1531. static ConVar r_waterforcereflectentities( "r_waterforcereflectentities", "0", FCVAR_ALLOWED_IN_COMPETITIVE );
  1532. static ConVar mat_motion_blur_enabled( "mat_motion_blur_enabled", "0", FCVAR_ARCHIVE );
  1533. uint32 g_nDebugVarsSignature = 0;
  1534. //-----------------------------------------------------------------------------
  1535. // This is called when the config changes
  1536. //-----------------------------------------------------------------------------
  1537. void CMaterialSystem::ReadConfigFromConVars( MaterialSystem_Config_t *pConfig )
  1538. {
  1539. if ( !g_pCVar )
  1540. return;
  1541. // video panel config items
  1542. #ifndef CSS_PERF_TEST
  1543. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, !mat_vsync.GetBool() );
  1544. #endif
  1545. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR, mat_trilinear.GetBool() );
  1546. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR, !mat_specular.GetBool() );
  1547. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP, !mat_bumpmap.GetBool() );
  1548. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_PHONG, !mat_phong.GetBool() );
  1549. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING, mat_parallaxmap.GetBool() );
  1550. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE, mat_reducefillrate.GetBool() );
  1551. pConfig->m_nForceAnisotropicLevel = max( mat_forceaniso.GetInt(), 1 );
  1552. pConfig->dxSupportLevel = MAX( ABSOLUTE_MINIMUM_DXLEVEL, mat_dxlevel.GetInt() );
  1553. pConfig->skipMipLevels = mat_picmip.GetInt();
  1554. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC, mat_forcehardwaresync.GetBool() );
  1555. pConfig->m_SlopeScaleDepthBias_Decal = mat_slopescaledepthbias_decal.GetFloat();
  1556. pConfig->m_DepthBias_Decal = mat_depthbias_decal.GetFloat();
  1557. pConfig->m_SlopeScaleDepthBias_Normal = mat_slopescaledepthbias_normal.GetFloat();
  1558. pConfig->m_DepthBias_Normal = mat_depthbias_normal.GetFloat();
  1559. pConfig->m_SlopeScaleDepthBias_ShadowMap = mat_slopescaledepthbias_shadowmap.GetFloat();
  1560. pConfig->m_DepthBias_ShadowMap = mat_depthbias_shadowmap.GetFloat();
  1561. pConfig->m_fMonitorGamma = mat_monitorgamma.GetFloat();
  1562. pConfig->m_fGammaTVRangeMin = mat_monitorgamma_tv_range_min.GetFloat();
  1563. pConfig->m_fGammaTVRangeMax = mat_monitorgamma_tv_range_max.GetFloat();
  1564. pConfig->m_fGammaTVExponent = mat_monitorgamma_tv_exp.GetFloat();
  1565. pConfig->m_bGammaTVEnabled = mat_monitorgamma_tv_enabled.GetBool();
  1566. pConfig->m_nAASamples = mat_antialias.GetInt();
  1567. pConfig->m_nAAQuality = mat_aaquality.GetInt();
  1568. pConfig->bShowDiffuse = mat_diffuse.GetInt() ? true : false;
  1569. // pConfig->bAllowCheats = false; // hack
  1570. pConfig->bShowNormalMap = mat_normalmaps.GetInt() ? true : false;
  1571. pConfig->bShowLowResImage = mat_showlowresimage.GetInt() ? true : false;
  1572. pConfig->bMeasureFillRate = mat_measurefillrate.GetInt() ? true : false;
  1573. pConfig->bVisualizeFillRate = mat_fillrate.GetInt() ? true : false;
  1574. pConfig->bFilterLightmaps = mat_filterlightmaps.GetInt() ? true : false;
  1575. pConfig->bFilterTextures = mat_filtertextures.GetInt() ? true : false;
  1576. pConfig->bMipMapTextures = mat_mipmaptextures.GetInt() ? true : false;
  1577. pConfig->nShowMipLevels = mat_showmiplevels.GetInt();
  1578. pConfig->bReverseDepth = mat_reversedepth.GetInt() ? true : false;
  1579. pConfig->bBufferPrimitives = mat_bufferprimitives.GetInt() ? true : false;
  1580. pConfig->bDrawFlat = mat_drawflat.GetInt() ? true : false;
  1581. pConfig->bSoftwareLighting = mat_softwarelighting.GetInt() ? true : false;
  1582. pConfig->proxiesTestMode = mat_proxy.GetInt();
  1583. pConfig->m_bSuppressRendering = mat_norendering.GetInt() != 0;
  1584. pConfig->bCompressedTextures = mat_compressedtextures.GetBool();
  1585. pConfig->bShowSpecular = mat_fastspecular.GetInt() ? true : false;
  1586. pConfig->nFullbright = mat_fullbright.GetInt();
  1587. pConfig->m_bFastNoBump = mat_fastnobump.GetInt() != 0;
  1588. pConfig->m_bMotionBlur = mat_motion_blur_enabled.GetBool();
  1589. pConfig->m_bSupportFlashlight = mat_supportflashlight.GetInt() != 0;
  1590. pConfig->m_bShadowDepthTexture = r_flashlightdepthtexture.GetBool();
  1591. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_ENABLE_HDR, HardwareConfig() && HardwareConfig()->GetHDREnabled() );
  1592. // Render-to-texture shadows are disabled for dxlevel 70 because of material issues
  1593. if ( pConfig->dxSupportLevel < 80 )
  1594. {
  1595. r_shadowrendertotexture.SetValue( 0 );
  1596. #ifndef _X360
  1597. r_waterforceexpensive.SetValue( 0 );
  1598. #endif
  1599. r_waterforcereflectentities.SetValue( 0 );
  1600. }
  1601. if ( pConfig->dxSupportLevel < 90 )
  1602. {
  1603. mat_requires_rt_alloc_first.SetValue( 1 );
  1604. r_flashlightdepthtexture.SetValue( 0 );
  1605. mat_motion_blur_enabled.SetValue( 0 );
  1606. pConfig->m_bShadowDepthTexture = false;
  1607. pConfig->m_bMotionBlur = false;
  1608. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_ENABLE_HDR, false );
  1609. }
  1610. // VR mode adapter will generally be -1 if VR mode is not disabled
  1611. pConfig->m_nVRModeAdapter = mat_vrmode_adapter.GetInt();
  1612. if( pConfig->m_nVRModeAdapter != -1 )
  1613. {
  1614. // we must always be windowed in the config in VR mode
  1615. // so that we will start up on the main display. Once
  1616. // VR overrides the adapter the only place we can go
  1617. // full screen is on the HMD.
  1618. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true );
  1619. }
  1620. }
  1621. //-----------------------------------------------------------------------------
  1622. // Was the convar specified on the command-line?
  1623. //-----------------------------------------------------------------------------
  1624. static bool WasConVarSpecifiedOnCommandLine( const char *pConfigName )
  1625. {
  1626. // mat_dxlevel cannot be used on the command-line. Use -dxlevel instead.
  1627. if ( !Q_stricmp( pConfigName, "mat_dxlevel" ) )
  1628. return false;
  1629. return ( g_pCVar->GetCommandLineValue( pConfigName ) != NULL);
  1630. }
  1631. static const char *pConvarsAllowedInDXSupport[]={
  1632. "cl_detaildist",
  1633. "cl_detailfade",
  1634. "cl_ejectbrass",
  1635. "dsp_off",
  1636. "dsp_slow_cpu",
  1637. "mat_antialias",
  1638. "mat_aaquality",
  1639. "mat_bumpmap",
  1640. "mat_colorcorrection",
  1641. "mat_depthbias_decal",
  1642. "mat_depthbias_normal",
  1643. "mat_disable_ps_patch",
  1644. "mat_forceaniso",
  1645. "mat_forcehardwaresync",
  1646. "mat_forcemanagedtextureintohardware",
  1647. "mat_hdr_level",
  1648. "mat_parallaxmap",
  1649. "mat_picmip",
  1650. "mat_reducefillrate",
  1651. "mat_reduceparticles",
  1652. "mat_slopescaledepthbias_decal",
  1653. "mat_slopescaledepthbias_normal",
  1654. "mat_softwarelighting",
  1655. "mat_specular",
  1656. "mat_trilinear",
  1657. "mat_vsync",
  1658. "props_break_max_pieces",
  1659. "r_VehicleViewDampen",
  1660. "r_decal_cullsize",
  1661. "r_dopixelvisibility",
  1662. "r_drawdetailprops",
  1663. "r_drawflecks",
  1664. "r_drawmodeldecals",
  1665. "r_dynamic",
  1666. "r_lightcache_zbuffercache",
  1667. "r_fastzreject",
  1668. "r_overlayfademax",
  1669. "r_overlayfademin",
  1670. "r_rootlod",
  1671. "r_screenfademaxsize",
  1672. "r_screenfademinsize",
  1673. "r_shadowrendertotexture",
  1674. "r_shadows",
  1675. "r_waterforceexpensive",
  1676. "r_waterforcereflectentities",
  1677. "sv_alternateticks",
  1678. "mat_dxlevel",
  1679. "mat_fallbackEyeRefract20",
  1680. "r_shader_srgb",
  1681. "mat_motion_blur_enabled",
  1682. "r_flashlightdepthtexture",
  1683. "mat_disablehwmorph",
  1684. "r_portal_stencil_depth",
  1685. "cl_blobbyshadows",
  1686. "r_flex",
  1687. "r_drawropes",
  1688. "props_break_max_pieces",
  1689. "cl_ragdoll_fade_time",
  1690. "cl_ragdoll_forcefade",
  1691. "tf_impactwatertimeenable",
  1692. "fx_drawimpactdebris",
  1693. "fx_drawimpactdust",
  1694. "fx_drawmetalspark",
  1695. "mem_min_heapsize",
  1696. "mem_max_heapsize",
  1697. "mem_max_heapsize_dedicated",
  1698. "snd_spatialize_roundrobin",
  1699. "snd_cull_duplicates",
  1700. "cl_particle_retire_cost",
  1701. "mat_phong"
  1702. };
  1703. //-----------------------------------------------------------------------------
  1704. // Write dxsupport info to configvars
  1705. //-----------------------------------------------------------------------------
  1706. void CMaterialSystem::WriteConfigurationInfoToConVars( bool bOverwriteCommandLineValues )
  1707. {
  1708. if ( !g_pCVar )
  1709. return;
  1710. KeyValues *pKeyValues = new KeyValues( "config" );
  1711. if ( !GetRecommendedConfigurationInfo( g_config.dxSupportLevel, pKeyValues ) )
  1712. {
  1713. pKeyValues->deleteThis();
  1714. return;
  1715. }
  1716. for( KeyValues *pKey = pKeyValues->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey() )
  1717. {
  1718. const char *pConfigName = pKey->GetName();
  1719. if ( Q_strnicmp( pConfigName, "convar.", 7 ))
  1720. continue;
  1721. pConfigName += 7;
  1722. // check if legal
  1723. bool bLegalVar = false;
  1724. for(int i=0; i< NELEMS( pConvarsAllowedInDXSupport ) ; i++)
  1725. {
  1726. if (! stricmp( pConvarsAllowedInDXSupport[i], pConfigName ) )
  1727. {
  1728. bLegalVar = true;
  1729. break;
  1730. }
  1731. }
  1732. if (! bLegalVar )
  1733. {
  1734. Msg(" Bad convar found in dxsupport - %s\n", pConfigName );
  1735. continue;
  1736. }
  1737. if ( bOverwriteCommandLineValues || !WasConVarSpecifiedOnCommandLine( pConfigName ) )
  1738. {
  1739. ConVar *pConVar = g_pCVar->FindVar( pConfigName );
  1740. if ( !pConVar )
  1741. {
  1742. // NOTE: This is essential for dealing with convars that
  1743. // are not specified in either the app that uses the materialsystem
  1744. // or the materialsystem itself
  1745. // Yes, this causes a memory leak. Too bad!
  1746. int nLen = Q_strlen( pConfigName ) + 1;
  1747. char *pString = new char[nLen];
  1748. Q_strncpy( pString, pConfigName, nLen );
  1749. // Actually, we need two memory leaks, or we lose the default string.
  1750. int nDefaultLen = Q_strlen( pKey->GetString() ) + 1;
  1751. char *pDefaultString = new char[nDefaultLen];
  1752. Q_strncpy( pDefaultString, pKey->GetString(), nDefaultLen );
  1753. pConVar = new ConVar( pString, pDefaultString );
  1754. }
  1755. pConVar->SetValue( pKey->GetString() );
  1756. }
  1757. }
  1758. pKeyValues->deleteThis();
  1759. }
  1760. //-----------------------------------------------------------------------------
  1761. // This is called when the config changes
  1762. //-----------------------------------------------------------------------------
  1763. void CMaterialSystem::WriteConfigIntoConVars( const MaterialSystem_Config_t &config )
  1764. {
  1765. if ( !g_pCVar )
  1766. return;
  1767. mat_vsync.SetValue( config.WaitForVSync() );
  1768. mat_trilinear.SetValue( config.ForceTrilinear() );
  1769. mat_specular.SetValue( config.UseSpecular() );
  1770. mat_bumpmap.SetValue( config.UseBumpmapping() );
  1771. mat_phong.SetValue( config.UsePhong() );
  1772. mat_parallaxmap.SetValue( config.UseParallaxMapping() );
  1773. mat_reducefillrate.SetValue( config.ReduceFillrate() );
  1774. mat_forceaniso.SetValue( config.m_nForceAnisotropicLevel );
  1775. mat_dxlevel.SetValue( MAX( ABSOLUTE_MINIMUM_DXLEVEL, config.dxSupportLevel ) );
  1776. mat_picmip.SetValue( config.skipMipLevels );
  1777. mat_forcehardwaresync.SetValue( config.ForceHWSync() );
  1778. mat_slopescaledepthbias_normal.SetValue( config.m_SlopeScaleDepthBias_Normal );
  1779. mat_depthbias_normal.SetValue( config.m_DepthBias_Normal );
  1780. mat_slopescaledepthbias_decal.SetValue( config.m_SlopeScaleDepthBias_Decal );
  1781. mat_depthbias_decal.SetValue( config.m_DepthBias_Decal );
  1782. mat_slopescaledepthbias_shadowmap.SetValue( config.m_SlopeScaleDepthBias_ShadowMap );
  1783. mat_depthbias_shadowmap.SetValue( config.m_DepthBias_ShadowMap );
  1784. mat_monitorgamma.SetValue( config.m_fMonitorGamma );
  1785. mat_monitorgamma_tv_range_min.SetValue( config.m_fGammaTVRangeMin );
  1786. mat_monitorgamma_tv_range_max.SetValue( config.m_fGammaTVRangeMax );
  1787. mat_monitorgamma_tv_exp.SetValue( config.m_fGammaTVExponent );
  1788. mat_monitorgamma_tv_enabled.SetValue( config.m_bGammaTVEnabled );
  1789. mat_antialias.SetValue( config.m_nAASamples );
  1790. mat_aaquality.SetValue( config.m_nAAQuality );
  1791. mat_diffuse.SetValue( config.bShowDiffuse ? 1 : 0 );
  1792. // config.bAllowCheats = false; // hack
  1793. mat_normalmaps.SetValue( config.bShowNormalMap ? 1 : 0 );
  1794. mat_showlowresimage.SetValue( config.bShowLowResImage ? 1 : 0 );
  1795. mat_measurefillrate.SetValue( config.bMeasureFillRate ? 1 : 0 );
  1796. mat_fillrate.SetValue( config.bVisualizeFillRate ? 1 : 0 );
  1797. mat_filterlightmaps.SetValue( config.bFilterLightmaps ? 1 : 0 );
  1798. mat_filtertextures.SetValue( config.bFilterTextures ? 1 : 0 );
  1799. mat_mipmaptextures.SetValue( config.bMipMapTextures ? 1 : 0 );
  1800. mat_showmiplevels.SetValue( config.nShowMipLevels );
  1801. mat_reversedepth.SetValue( config.bReverseDepth ? 1 : 0 );
  1802. mat_bufferprimitives.SetValue( config.bBufferPrimitives ? 1 : 0 );
  1803. mat_drawflat.SetValue( config.bDrawFlat ? 1 : 0 );
  1804. mat_softwarelighting.SetValue( config.bSoftwareLighting ? 1 : 0 );
  1805. mat_proxy.SetValue( config.proxiesTestMode );
  1806. mat_norendering.SetValue( config.m_bSuppressRendering ? 1 : 0 );
  1807. mat_compressedtextures.SetValue( config.bCompressedTextures ? 1 : 0 );
  1808. mat_fastspecular.SetValue( config.bShowSpecular ? 1 : 0 );
  1809. mat_fullbright.SetValue( config.nFullbright );
  1810. mat_fastnobump.SetValue( config.m_bFastNoBump ? 1 : 0 );
  1811. bool hdre = config.HDREnabled();
  1812. HardwareConfig()->SetHDREnabled( hdre );
  1813. r_flashlightdepthtexture.SetValue( config.m_bShadowDepthTexture ? 1 : 0 );
  1814. mat_motion_blur_enabled.SetValue( config.m_bMotionBlur ? 1 : 0 );
  1815. mat_supportflashlight.SetValue( config.m_bSupportFlashlight ? 1 : 0 );
  1816. }
  1817. //-----------------------------------------------------------------------------
  1818. // This is called constantly to catch for config changes
  1819. //-----------------------------------------------------------------------------
  1820. bool CMaterialSystem::OverrideConfig( const MaterialSystem_Config_t &_config, bool forceUpdate )
  1821. {
  1822. Assert( m_bGeneratedConfig );
  1823. if ( memcmp( &_config, &g_config, sizeof(_config) ) == 0 )
  1824. {
  1825. return false;
  1826. }
  1827. MaterialLock_t hLock = Lock();
  1828. MaterialSystem_Config_t config = _config;
  1829. bool bRedownloadLightmaps = false;
  1830. bool bRedownloadTextures = false;
  1831. bool recomputeSnapshots = false;
  1832. bool dxSupportLevelChanged = false;
  1833. bool bReloadMaterials = false;
  1834. bool bResetAnisotropy = false;
  1835. bool bSetStandardVertexShaderConstants = false;
  1836. bool bMonitorGammaChanged = false;
  1837. bool bVideoModeChange = false;
  1838. bool bResetTextureFilter = false;
  1839. bool bForceAltTab = false;
  1840. // internal config settings
  1841. #ifndef _X360
  1842. MaterialSystem_Config_Internal_t config_internal;
  1843. config_internal.r_waterforceexpensive = r_waterforceexpensive.GetInt();
  1844. #endif
  1845. if ( !g_pShaderDevice->IsUsingGraphics() )
  1846. {
  1847. g_config = config;
  1848. #ifndef _X360
  1849. g_config_internal = config_internal;
  1850. #endif
  1851. // Shouldn't call this more than once.
  1852. ColorSpace::SetGamma( 2.2f, 2.2f, OVERBRIGHT, g_config.bAllowCheats, false );
  1853. Unlock( hLock );
  1854. return bRedownloadLightmaps;
  1855. }
  1856. // set the default state since we might be changing the number of
  1857. // texture units, etc. (i.e. we don't want to leave unit 2 in overbright mode
  1858. // if it isn't going to be reset upon each SetDefaultState because there is
  1859. // effectively only one texture unit.)
  1860. g_pShaderAPI->SetDefaultState();
  1861. // toggle dx emulation level
  1862. if ( config.dxSupportLevel != g_config.dxSupportLevel )
  1863. {
  1864. if ( mat_debugalttab.GetBool() )
  1865. {
  1866. Warning( "mat_debugalttab: Setting dxSupportLevelChanged, bResetAnisotropy, and bReloadMaterials because new dxlevel = %d and old dxlevel = %d\n",
  1867. ( int )config.dxSupportLevel, g_config.dxSupportLevel );
  1868. }
  1869. dxSupportLevelChanged = true;
  1870. bResetAnisotropy = true;
  1871. // Necessary for DXSupportLevelChanged to work
  1872. g_config.dxSupportLevel = config.dxSupportLevel;
  1873. // This will reset config to match whatever the dxlevel wants
  1874. // and slam to convars to match
  1875. g_pShaderAPI->DXSupportLevelChanged( );
  1876. WriteConfigurationInfoToConVars();
  1877. ReadConfigFromConVars( &config );
  1878. bReloadMaterials = true;
  1879. }
  1880. if ( config.HDREnabled() != g_config.HDREnabled() )
  1881. {
  1882. if ( mat_debugalttab.GetBool() )
  1883. {
  1884. Warning( "mat_debugalttab: Setting forceUpdate, bReloadMaterials, and bForceAltTab because new hdr level = %d and old hdr level = %d\n",
  1885. ( int )config.HDREnabled(), g_config.HDREnabled() );
  1886. }
  1887. forceUpdate = true;
  1888. bReloadMaterials = true;
  1889. bForceAltTab = true;
  1890. }
  1891. if ( config.ShadowDepthTexture() != g_config.ShadowDepthTexture() )
  1892. {
  1893. if ( mat_debugalttab.GetBool() )
  1894. {
  1895. Warning( "mat_debugalttab: Setting forceUpdate, bReloadMaterials and recomputeSnapshots (ShadowDepthTexture changed: %d -> %d)\n",
  1896. g_config.ShadowDepthTexture() ? 1 : 0, config.ShadowDepthTexture() ? 1 : 0 );
  1897. }
  1898. forceUpdate = true;
  1899. bReloadMaterials = true;
  1900. recomputeSnapshots = true;
  1901. }
  1902. if ( config.VRMode() != g_config.VRMode() || config.m_nVRModeAdapter != g_config.m_nVRModeAdapter )
  1903. {
  1904. bVideoModeChange = true;
  1905. }
  1906. // Don't use compressed textures for the moment if we don't support them
  1907. if ( HardwareConfig() && !HardwareConfig()->SupportsCompressedTextures() )
  1908. {
  1909. config.bCompressedTextures = false;
  1910. }
  1911. if ( forceUpdate )
  1912. {
  1913. if ( mat_debugalttab.GetBool() )
  1914. {
  1915. Warning( "mat_debugalttab: forceUpdate is true, therefore setting recomputeSnapshots, bRedownloadLightmaps, bRedownloadTextures, bResetAnisotropy, and bSetStandardVertexShaderConstants\n" );
  1916. }
  1917. GetLightmaps()->EnableLightmapFiltering( config.bFilterLightmaps );
  1918. recomputeSnapshots = true;
  1919. bRedownloadLightmaps = true;
  1920. bRedownloadTextures = true;
  1921. bResetAnisotropy = true;
  1922. bSetStandardVertexShaderConstants = true;
  1923. }
  1924. // toggle bump mapping
  1925. if ( config.UseBumpmapping() != g_config.UseBumpmapping() || config.UsePhong() != g_config.UsePhong() )
  1926. {
  1927. if( mat_debugalttab.GetBool() )
  1928. {
  1929. Warning( "mat_debugalttab: forceUpdate is true, therefore setting recomputeSnapshots, bRedownloadLightmaps, bRedownloadTextures, bResetAnisotropy, and bSetStandardVertexShaderConstants\n" );
  1930. }
  1931. recomputeSnapshots = true;
  1932. bReloadMaterials = true;
  1933. bResetAnisotropy = true;
  1934. }
  1935. // toggle specularity
  1936. if ( config.UseSpecular() != g_config.UseSpecular() )
  1937. {
  1938. if( mat_debugalttab.GetBool() )
  1939. {
  1940. Warning( "mat_debugalttab: new usespecular=%d, old usespecular=%d, setting recomputeSnapshots, bReloadMaterials, and bResetAnisotropy\n",
  1941. ( int )config.UseSpecular(), ( int )g_config.UseSpecular() );
  1942. }
  1943. recomputeSnapshots = true;
  1944. bReloadMaterials = true;
  1945. bResetAnisotropy = true;
  1946. }
  1947. // toggle parallax mapping
  1948. if ( config.UseParallaxMapping() != g_config.UseParallaxMapping() )
  1949. {
  1950. if ( mat_debugalttab.GetBool() )
  1951. {
  1952. Warning( "mat_debugalttab: new UseParallaxMapping=%d, old UseParallaxMapping=%d, setting bReloadMaterials\n",
  1953. ( int )config.UseParallaxMapping(), ( int )g_config.UseParallaxMapping() );
  1954. }
  1955. bReloadMaterials = true;
  1956. }
  1957. // Reload materials if we want reduced fillrate
  1958. if ( config.ReduceFillrate() != g_config.ReduceFillrate() )
  1959. {
  1960. if ( mat_debugalttab.GetBool() )
  1961. {
  1962. Warning( "mat_debugalttab: new ReduceFillrate=%d, old ReduceFillrate=%d, setting bReloadMaterials\n",
  1963. ( int )config.ReduceFillrate(), ( int )g_config.ReduceFillrate() );
  1964. }
  1965. bReloadMaterials = true;
  1966. }
  1967. // toggle reverse depth
  1968. if ( config.bReverseDepth != g_config.bReverseDepth )
  1969. {
  1970. if( mat_debugalttab.GetBool() )
  1971. {
  1972. Warning( "mat_debugalttab: new ReduceFillrate=%d, old ReduceFillrate=%d, setting bReloadMaterials\n",
  1973. ( int )config.ReduceFillrate(), ( int )g_config.ReduceFillrate() );
  1974. }
  1975. recomputeSnapshots = true;
  1976. bResetAnisotropy = true;
  1977. }
  1978. // toggle no transparency
  1979. if ( config.bNoTransparency != g_config.bNoTransparency )
  1980. {
  1981. if ( mat_debugalttab.GetBool() )
  1982. {
  1983. Warning( "mat_debugalttab: new bNoTransparency=%d, old bNoTransparency=%d, setting recomputeSnapshots and bResetAnisotropy\n",
  1984. ( int )config.bNoTransparency, ( int )g_config.bNoTransparency );
  1985. }
  1986. recomputeSnapshots = true;
  1987. bResetAnisotropy = true;
  1988. }
  1989. // toggle lightmap filtering
  1990. if ( config.bFilterLightmaps != g_config.bFilterLightmaps )
  1991. {
  1992. if ( mat_debugalttab.GetBool() )
  1993. {
  1994. Warning( "mat_debugalttab: new bFilterLightmaps=%d, old bFilterLightmaps=%d, setting EnableLightmapFiltering\n",
  1995. ( int )config.bFilterLightmaps, ( int )g_config.bFilterLightmaps );
  1996. }
  1997. GetLightmaps()->EnableLightmapFiltering( config.bFilterLightmaps );
  1998. }
  1999. // toggle software lighting
  2000. if ( config.bSoftwareLighting != g_config.bSoftwareLighting )
  2001. {
  2002. if( mat_debugalttab.GetBool() )
  2003. {
  2004. Warning( "mat_debugalttab: new bSoftwareLighting=%d, old bSoftwareLighting=%d, setting bReloadMaterials\n",
  2005. ( int )config.bFilterLightmaps, ( int )g_config.bFilterLightmaps );
  2006. }
  2007. bReloadMaterials = true;
  2008. }
  2009. #ifndef _X360
  2010. if ( config_internal.r_waterforceexpensive != g_config_internal.r_waterforceexpensive )
  2011. {
  2012. if ( mat_debugalttab.GetBool() )
  2013. {
  2014. Warning( "mat_debugalttab: new r_waterforceexpensive=%d, old r_waterforceexpensive=%d, setting bReloadMaterials\n",
  2015. ( int )config_internal.r_waterforceexpensive, ( int )g_config_internal.r_waterforceexpensive );
  2016. }
  2017. bReloadMaterials = true;
  2018. }
  2019. #endif
  2020. // generic things that cause us to redownload lightmaps
  2021. if ( config.bAllowCheats != g_config.bAllowCheats )
  2022. {
  2023. if ( mat_debugalttab.GetBool() )
  2024. {
  2025. Warning( "mat_debugalttab: new bAllowCheats=%d, old bAllowCheats=%d, setting bRedownloadLightmaps\n",
  2026. ( int )config.bAllowCheats, ( int )g_config.bAllowCheats );
  2027. }
  2028. bRedownloadLightmaps = true;
  2029. }
  2030. // generic things that cause us to redownload textures
  2031. if ( config.bAllowCheats != g_config.bAllowCheats ||
  2032. config.skipMipLevels != g_config.skipMipLevels ||
  2033. config.nShowMipLevels != g_config.nShowMipLevels ||
  2034. ((config.bCompressedTextures != g_config.bCompressedTextures) && HardwareConfig()->SupportsCompressedTextures())||
  2035. config.bShowLowResImage != g_config.bShowLowResImage
  2036. )
  2037. {
  2038. if ( mat_debugalttab.GetBool() )
  2039. {
  2040. Warning( "mat_debugalttab: setting bRedownloadTextures, recomputeSnapshots, and bResetAnisotropy\n" );
  2041. }
  2042. bRedownloadTextures = true;
  2043. recomputeSnapshots = true;
  2044. bResetAnisotropy = true;
  2045. }
  2046. if ( config.ForceTrilinear() != g_config.ForceTrilinear() )
  2047. {
  2048. if ( mat_debugalttab.GetBool() )
  2049. {
  2050. Warning( "mat_debugalttab: new forcetrilinear: %d, old forcetrilinear: %d, setting bResetTextureFilter\n",
  2051. ( int )config.ForceTrilinear(), ( int )g_config.ForceTrilinear() );
  2052. }
  2053. bResetTextureFilter = true;
  2054. }
  2055. if ( config.m_nForceAnisotropicLevel != g_config.m_nForceAnisotropicLevel )
  2056. {
  2057. if( mat_debugalttab.GetBool() )
  2058. {
  2059. Warning( "mat_debugalttab: new m_nForceAnisotropicLevel: %d, old m_nForceAnisotropicLevel: %d, setting bResetAnisotropy and bResetTextureFilter\n",
  2060. ( int )config.ForceTrilinear(), ( int )g_config.ForceTrilinear() );
  2061. }
  2062. bResetAnisotropy = true;
  2063. bResetTextureFilter = true;
  2064. }
  2065. if ( config.m_fMonitorGamma != g_config.m_fMonitorGamma || config.m_fGammaTVRangeMin != g_config.m_fGammaTVRangeMin ||
  2066. config.m_fGammaTVRangeMax != g_config.m_fGammaTVRangeMax || config.m_fGammaTVExponent != g_config.m_fGammaTVExponent ||
  2067. config.m_bGammaTVEnabled != g_config.m_bGammaTVEnabled )
  2068. {
  2069. if( mat_debugalttab.GetBool() )
  2070. {
  2071. Warning( "mat_debugalttab: new monitorgamma: %f, old monitorgamma: %f, setting bMonitorGammaChanged\n",
  2072. config.m_fMonitorGamma, g_config.m_fMonitorGamma );
  2073. }
  2074. bMonitorGammaChanged = true;
  2075. }
  2076. if ( config.m_VideoMode.m_Width != g_config.m_VideoMode.m_Width ||
  2077. config.m_VideoMode.m_Height != g_config.m_VideoMode.m_Height ||
  2078. config.m_VideoMode.m_RefreshRate != g_config.m_VideoMode.m_RefreshRate ||
  2079. config.m_nAASamples != g_config.m_nAASamples ||
  2080. config.m_nAAQuality != g_config.m_nAAQuality ||
  2081. config.Windowed() != g_config.Windowed() ||
  2082. config.Stencil() != g_config.Stencil() )
  2083. {
  2084. if( mat_debugalttab.GetBool() )
  2085. {
  2086. Warning( "mat_debugalttab: video mode changed for one of various reasons\n" );
  2087. }
  2088. bVideoModeChange = true;
  2089. }
  2090. // toggle wait for vsync
  2091. // In GL, we just check this and it's just a function call--no need for device shenanigans.
  2092. #if !defined( DX_TO_GL_ABSTRACTION )
  2093. if ( (IsX360() || !config.Windowed()) && (config.WaitForVSync() != g_config.WaitForVSync()) )
  2094. {
  2095. # if ( !defined( _X360 ) )
  2096. {
  2097. if ( mat_debugalttab.GetBool() )
  2098. {
  2099. Warning( "mat_debugalttab: video mode changed due to toggle of wait for vsync\n" );
  2100. }
  2101. bVideoModeChange = true;
  2102. }
  2103. # else
  2104. {
  2105. g_pShaderAPI->EnableVSync_360( config.WaitForVSync() );
  2106. }
  2107. # endif
  2108. }
  2109. #endif
  2110. g_config = config;
  2111. #ifndef _X360
  2112. g_config_internal = config_internal;
  2113. #endif
  2114. if ( dxSupportLevelChanged )
  2115. {
  2116. if ( mat_debugalttab.GetBool() )
  2117. {
  2118. Warning( "mat_debugalttab: dx support level changed, clearing snapshots\n" );
  2119. }
  2120. // All snapshots have basically become invalid;
  2121. g_pShaderAPI->ClearSnapshots();
  2122. }
  2123. if ( bRedownloadTextures || bRedownloadLightmaps )
  2124. {
  2125. // Get rid of this?
  2126. ColorSpace::SetGamma( 2.2f, 2.2f, OVERBRIGHT, g_config.bAllowCheats, false );
  2127. }
  2128. // 360 does not support various configuration changes and cannot reload materials
  2129. if ( !IsX360() )
  2130. {
  2131. if ( bResetAnisotropy || recomputeSnapshots || bRedownloadLightmaps ||
  2132. bRedownloadTextures || bResetAnisotropy || bVideoModeChange ||
  2133. bSetStandardVertexShaderConstants || bResetTextureFilter )
  2134. {
  2135. Unlock( hLock );
  2136. ForceSingleThreaded();
  2137. hLock = Lock();
  2138. }
  2139. }
  2140. if ( bReloadMaterials && !IsX360() )
  2141. {
  2142. if ( mat_debugalttab.GetBool() )
  2143. {
  2144. Warning( "mat_debugalttab: ReloadMaterials\n" );
  2145. }
  2146. ReloadMaterials();
  2147. }
  2148. // 360 does not support various configuration changes and cannot reload textures
  2149. // 360 has no reason to reload textures, it's unnecessary and massively expensive
  2150. // 360 does not use this path as an init affect to get its textures into memory
  2151. if ( bRedownloadTextures && !IsX360() )
  2152. {
  2153. if ( mat_debugalttab.GetBool() )
  2154. {
  2155. Warning( "mat_debugalttab: redownloading textures\n" );
  2156. }
  2157. if ( g_pShaderAPI->CanDownloadTextures() )
  2158. {
  2159. TextureManager()->RestoreRenderTargets();
  2160. TextureManager()->RestoreNonRenderTargetTextures();
  2161. }
  2162. }
  2163. else if ( bResetTextureFilter )
  2164. {
  2165. if( mat_debugalttab.GetBool() )
  2166. {
  2167. Warning( "mat_debugalttab: ResetTextureFilteringState\n" );
  2168. }
  2169. TextureManager()->ResetTextureFilteringState();
  2170. }
  2171. // Recompute all state snapshots
  2172. if ( recomputeSnapshots )
  2173. {
  2174. if( mat_debugalttab.GetBool() )
  2175. {
  2176. Warning( "mat_debugalttab: RecomputeAllStateSnapshots\n" );
  2177. }
  2178. RecomputeAllStateSnapshots();
  2179. }
  2180. if ( bResetAnisotropy )
  2181. {
  2182. if( mat_debugalttab.GetBool() )
  2183. {
  2184. Warning( "mat_debugalttab: SetAnisotropicLevel\n" );
  2185. }
  2186. g_pShaderAPI->SetAnisotropicLevel( config.m_nForceAnisotropicLevel );
  2187. }
  2188. if ( bSetStandardVertexShaderConstants )
  2189. {
  2190. if ( mat_debugalttab.GetBool() )
  2191. {
  2192. Warning( "mat_debugalttab: SetStandardVertexShaderConstants\n" );
  2193. }
  2194. g_pShaderAPI->SetStandardVertexShaderConstants( OVERBRIGHT );
  2195. }
  2196. if ( bMonitorGammaChanged )
  2197. {
  2198. if( mat_debugalttab.GetBool() )
  2199. {
  2200. Warning( "mat_debugalttab: SetHardwareGammaRamp\n" );
  2201. }
  2202. g_pShaderDevice->SetHardwareGammaRamp( config.m_fMonitorGamma, config.m_fGammaTVRangeMin, config.m_fGammaTVRangeMax,
  2203. config.m_fGammaTVExponent, config.m_bGammaTVEnabled );
  2204. }
  2205. if ( bVideoModeChange )
  2206. {
  2207. if ( mat_debugalttab.GetBool() )
  2208. {
  2209. Warning( "mat_debugalttab: ChangeVideoMode\n" );
  2210. }
  2211. ShaderDeviceInfo_t info;
  2212. ConvertModeStruct( &info, config );
  2213. g_pShaderAPI->ChangeVideoMode( info );
  2214. #if defined( USE_SDL )
  2215. uint width = info.m_DisplayMode.m_nWidth;
  2216. uint height = info.m_DisplayMode.m_nHeight;
  2217. g_pLauncherMgr->RenderedSize( width, height, true ); // true = set
  2218. #endif
  2219. }
  2220. if ( bForceAltTab )
  2221. {
  2222. // Simulate an Alt-Tab
  2223. // g_pShaderAPI->ReleaseResources();
  2224. // g_pShaderAPI->ReacquireResources();
  2225. }
  2226. Unlock( hLock );
  2227. if ( bVideoModeChange )
  2228. {
  2229. ForceSingleThreaded();
  2230. }
  2231. return bRedownloadLightmaps;
  2232. }
  2233. //-----------------------------------------------------------------------------
  2234. // This is called when the config changes
  2235. //-----------------------------------------------------------------------------
  2236. bool CMaterialSystem::UpdateConfig( bool forceUpdate )
  2237. {
  2238. int nUpdateFlags = 0;
  2239. if ( g_pCVar && g_pCVar->HasQueuedMaterialThreadConVarSets() )
  2240. {
  2241. ForceSingleThreaded();
  2242. nUpdateFlags = g_pCVar->ProcessQueuedMaterialThreadConVarSets();
  2243. }
  2244. MaterialSystem_Config_t config = g_config;
  2245. ReadConfigFromConVars( &config );
  2246. return OverrideConfig( config, forceUpdate );
  2247. }
  2248. void CMaterialSystem::ReleaseResources()
  2249. {
  2250. if( mat_debugalttab.GetBool() )
  2251. {
  2252. Warning( "mat_debugalttab: CMaterialSystem::ReleaseResources\n" );
  2253. }
  2254. g_pShaderAPI->FlushBufferedPrimitives();
  2255. g_pShaderDevice->ReleaseResources();
  2256. }
  2257. void CMaterialSystem::ReacquireResources()
  2258. {
  2259. if( mat_debugalttab.GetBool() )
  2260. {
  2261. Warning( "mat_debugalttab: CMaterialSystem::ReacquireResources\n" );
  2262. }
  2263. g_pShaderDevice->ReacquireResources();
  2264. }
  2265. //-----------------------------------------------------------------------------
  2266. //
  2267. //-----------------------------------------------------------------------------
  2268. bool CMaterialSystem::OnDrawMesh( IMesh *pMesh, int firstIndex, int numIndices )
  2269. {
  2270. if ( IsInStubMode() )
  2271. {
  2272. return false;
  2273. }
  2274. return GetRenderContextInternal()->OnDrawMesh( pMesh, firstIndex, numIndices );
  2275. }
  2276. bool CMaterialSystem::OnDrawMesh( IMesh *pMesh, CPrimList *pLists, int nLists )
  2277. {
  2278. if ( IsInStubMode() )
  2279. {
  2280. return false;
  2281. }
  2282. return GetRenderContextInternal()->OnDrawMesh( pMesh, pLists, nLists );
  2283. }
  2284. void CMaterialSystem::OnThreadEvent( uint32 threadEvent )
  2285. {
  2286. m_threadEvents.AddToTail( threadEvent );
  2287. }
  2288. ShaderAPITextureHandle_t CMaterialSystem::GetShaderAPITextureBindHandle( ITexture *pTexture, int nFrame, int nTextureChannel )
  2289. {
  2290. return ShaderSystem()->GetShaderAPITextureBindHandle( pTexture, nFrame, nTextureChannel );
  2291. }
  2292. //-----------------------------------------------------------------------------
  2293. // Creates a procedural texture
  2294. //-----------------------------------------------------------------------------
  2295. ITexture *CMaterialSystem::CreateProceduralTexture(
  2296. const char *pTextureName,
  2297. const char *pTextureGroupName,
  2298. int w,
  2299. int h,
  2300. ImageFormat fmt,
  2301. int nFlags )
  2302. {
  2303. ITextureInternal* pTex = TextureManager()->CreateProceduralTexture( pTextureName, pTextureGroupName, w, h, 1, fmt, nFlags );
  2304. return pTex;
  2305. }
  2306. //-----------------------------------------------------------------------------
  2307. // Create new materials (currently only used by the editor!)
  2308. //-----------------------------------------------------------------------------
  2309. IMaterial *CMaterialSystem::CreateMaterial( const char *pMaterialName, KeyValues *pVMTKeyValues )
  2310. {
  2311. // For not, just create a material with no default settings
  2312. IMaterialInternal* pMaterial = IMaterialInternal::CreateMaterial( pMaterialName, TEXTURE_GROUP_OTHER, pVMTKeyValues );
  2313. pMaterial->IncrementReferenceCount();
  2314. AddMaterialToMaterialList( pMaterial );
  2315. return pMaterial->GetQueueFriendlyVersion();
  2316. }
  2317. //-----------------------------------------------------------------------------
  2318. // Finds or creates a procedural material
  2319. //-----------------------------------------------------------------------------
  2320. IMaterial *CMaterialSystem::FindProceduralMaterial( const char *pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues )
  2321. {
  2322. // We need lower-case symbols for this to work
  2323. int nLen = Q_strlen( pMaterialName ) + 1;
  2324. char *pTemp = (char*)stackalloc( nLen );
  2325. Q_strncpy( pTemp, pMaterialName, nLen );
  2326. Q_strlower( pTemp );
  2327. Q_FixSlashes( pTemp, '/' );
  2328. // 'true' causes the search to find procedural materials
  2329. IMaterialInternal *pMaterial = m_MaterialDict.FindMaterial( pTemp, true );
  2330. if ( pMaterial )
  2331. {
  2332. pVMTKeyValues->deleteThis();
  2333. }
  2334. else
  2335. {
  2336. pMaterial = IMaterialInternal::CreateMaterial( pMaterialName, pTextureGroupName, pVMTKeyValues );
  2337. AddMaterialToMaterialList( static_cast<IMaterialInternal*>( pMaterial ) );
  2338. }
  2339. return pMaterial->GetQueueFriendlyVersion();
  2340. }
  2341. //-----------------------------------------------------------------------------
  2342. // Search by name
  2343. //-----------------------------------------------------------------------------
  2344. bool CMaterialSystem::IsMaterialLoaded( char const *pMaterialName )
  2345. {
  2346. // We need lower-case symbols for this to work
  2347. int nLen = Q_strlen( pMaterialName ) + 1;
  2348. char *pFixedNameTemp = (char*)stackalloc( nLen );
  2349. char *pTemp = (char*)stackalloc( nLen );
  2350. Q_strncpy( pFixedNameTemp, pMaterialName, nLen );
  2351. Q_strlower( pFixedNameTemp );
  2352. #ifdef POSIX
  2353. // strip extensions needs correct slashing for the OS, so fix it up early for Posix
  2354. Q_FixSlashes( pFixedNameTemp, '/' );
  2355. #endif
  2356. Q_StripExtension( pFixedNameTemp, pTemp, nLen );
  2357. #ifndef POSIX
  2358. Q_FixSlashes( pTemp, '/' );
  2359. #endif
  2360. Assert( nLen >= Q_strlen( pTemp ) + 1 );
  2361. return m_MaterialDict.FindMaterial( pTemp, false ) != NULL; // 'false' causes the search to find only file-created materials
  2362. }
  2363. //-----------------------------------------------------------------------------
  2364. // Search by name
  2365. //-----------------------------------------------------------------------------
  2366. IMaterial* CMaterialSystem::FindMaterial( char const *pMaterialName, const char *pTextureGroupName, bool bComplain, const char *pComplainPrefix )
  2367. {
  2368. return FindMaterialEx( pMaterialName, pTextureGroupName, MATERIAL_FINDCONTEXT_NONE, bComplain, pComplainPrefix );
  2369. }
  2370. //-----------------------------------------------------------------------------
  2371. // Search by name
  2372. //-----------------------------------------------------------------------------
  2373. IMaterial* CMaterialSystem::FindMaterialEx( char const* pMaterialName, const char *pTextureGroupName, int nContext, bool bComplain, const char *pComplainPrefix )
  2374. {
  2375. // We need lower-case symbols for this to work
  2376. int nLen = Q_strlen( pMaterialName ) + 1;
  2377. char *pFixedNameTemp = (char*)stackalloc( nLen );
  2378. char *pTemp = (char*)stackalloc( nLen );
  2379. Q_strncpy( pFixedNameTemp, pMaterialName, nLen );
  2380. Q_strlower( pFixedNameTemp );
  2381. #ifdef POSIX
  2382. // strip extensions needs correct slashing for the OS, so fix it up early for Posix
  2383. Q_FixSlashes( pFixedNameTemp, '/' );
  2384. #endif
  2385. Q_StripExtension( pFixedNameTemp, pTemp, nLen );
  2386. #ifndef POSIX
  2387. Q_FixSlashes( pTemp, '/' );
  2388. #endif
  2389. Assert( nLen >= Q_strlen( pTemp ) + 1 );
  2390. IMaterialInternal *pExistingMaterial = m_MaterialDict.FindMaterial( pTemp, false ); // 'false' causes the search to find only file-created materials
  2391. if ( pExistingMaterial )
  2392. return pExistingMaterial->GetQueueFriendlyVersion();
  2393. // It hasn't been seen yet, so let's check to see if it's in the filesystem.
  2394. nLen = Q_strlen( "materials/" ) + Q_strlen( pTemp ) + Q_strlen( ".vmt" ) + 1;
  2395. char *vmtName = (char *)stackalloc( nLen );
  2396. // Check to see if this is a UNC-specified material name
  2397. bool bIsUNC = pTemp[0] == '/' && pTemp[1] == '/' && pTemp[2] != '/';
  2398. if ( !bIsUNC )
  2399. {
  2400. Q_strncpy( vmtName, "materials/", nLen );
  2401. Q_strncat( vmtName, pTemp, nLen, COPY_ALL_CHARACTERS );
  2402. V_FixDoubleSlashes( vmtName );
  2403. }
  2404. else
  2405. {
  2406. Q_strncpy( vmtName, pTemp, nLen );
  2407. }
  2408. //Q_strncat( vmtName, ".vmt", nLen, COPY_ALL_CHARACTERS );
  2409. Assert( nLen >= (int)Q_strlen( vmtName ) + 1 );
  2410. CUtlVector<FileNameHandle_t> includes;
  2411. KeyValues *pKeyValues = new KeyValues("vmt");
  2412. KeyValues *pPatchKeyValues = new KeyValues( "vmt_patches" );
  2413. if ( !LoadVMTFile( *pKeyValues, *pPatchKeyValues, vmtName, true, &includes ) )
  2414. {
  2415. pKeyValues->deleteThis();
  2416. pKeyValues = NULL;
  2417. pPatchKeyValues->deleteThis();
  2418. pPatchKeyValues = NULL;
  2419. }
  2420. else
  2421. {
  2422. char *matNameWithExtension;
  2423. nLen = Q_strlen( pTemp ) + Q_strlen( ".vmt" ) + 1;
  2424. matNameWithExtension = (char *)stackalloc( nLen );
  2425. Q_strncpy( matNameWithExtension, pTemp, nLen );
  2426. Q_strncat( matNameWithExtension, ".vmt", nLen, COPY_ALL_CHARACTERS );
  2427. IMaterialInternal *pMat = NULL;
  2428. if ( !Q_stricmp( pKeyValues->GetName(), "subrect" ) )
  2429. {
  2430. pMat = m_MaterialDict.AddMaterialSubRect( matNameWithExtension, pTextureGroupName, pKeyValues, pPatchKeyValues );
  2431. }
  2432. else
  2433. {
  2434. pMat = m_MaterialDict.AddMaterial( matNameWithExtension, pTextureGroupName );
  2435. if ( g_pShaderDevice->IsUsingGraphics() )
  2436. {
  2437. if ( !bIsUNC )
  2438. {
  2439. m_pForcedTextureLoadPathID = "GAME";
  2440. }
  2441. pMat->PrecacheVars( pKeyValues, pPatchKeyValues, &includes, nContext );
  2442. m_pForcedTextureLoadPathID = NULL;
  2443. }
  2444. }
  2445. pKeyValues->deleteThis();
  2446. pPatchKeyValues->deleteThis();
  2447. return pMat->GetQueueFriendlyVersion();
  2448. }
  2449. if ( bComplain )
  2450. {
  2451. Assert( pTemp );
  2452. // convert to lowercase
  2453. nLen = Q_strlen(pTemp) + 1 ;
  2454. char *name = (char*)stackalloc( nLen );
  2455. Q_strncpy( name, pTemp, nLen );
  2456. Q_strlower( name );
  2457. if ( m_MaterialDict.NoteMissing( name ) )
  2458. {
  2459. if ( pComplainPrefix )
  2460. {
  2461. DevWarning( "%s", pComplainPrefix );
  2462. }
  2463. DevWarning( "material \"%s\" not found.\n", name );
  2464. }
  2465. }
  2466. return g_pErrorMaterial->GetRealTimeVersion();
  2467. }
  2468. void CMaterialSystem::SetAsyncTextureLoadCache( void* h )
  2469. {
  2470. Assert( !h || !m_hAsyncLoadFileCache );
  2471. m_hAsyncLoadFileCache = ( FileCacheHandle_t ) h;
  2472. }
  2473. static char const *TextureAliases[] =
  2474. {
  2475. // this table is only here for backwards compatibility where a render target change was made,
  2476. // and we wish to redirect an existing old client.dll for hl2 to reference this texture. It's
  2477. // not meant as a general texture aliasing system.
  2478. "_rt_FullFrameFB1", "_rt_FullScreen"
  2479. };
  2480. ITexture *CMaterialSystem::FindTexture( char const *pTextureName, const char *pTextureGroupName, bool bComplain /* = false */, int nAdditionalCreationFlags /* = 0 */ )
  2481. {
  2482. if ( m_hAsyncLoadFileCache && !TextureManager()->IsTextureLoaded( pTextureName ) )
  2483. {
  2484. bool bIsUNCName = ( pTextureName[0] == '/' && pTextureName[1] == '/' && pTextureName[2] != '/' );
  2485. if ( !bIsUNCName )
  2486. {
  2487. const char* pPathID = "GAME";
  2488. char buf[MAX_PATH];
  2489. V_snprintf( buf, MAX_PATH, "materials/%s", pTextureName );
  2490. V_SetExtension( buf, ".vtf", sizeof( buf ) );
  2491. const char *pbuf = buf;
  2492. g_pFullFileSystem->AddFilesToFileCache( m_hAsyncLoadFileCache, &pbuf, 1, pPathID );
  2493. return TextureManager()->ErrorTexture();
  2494. }
  2495. }
  2496. ITextureInternal *pTexture = TextureManager()->FindOrLoadTexture( pTextureName, pTextureGroupName, nAdditionalCreationFlags );
  2497. Assert( pTexture );
  2498. if ( pTexture->IsError() )
  2499. {
  2500. if ( IsPC() )
  2501. {
  2502. for ( int i=0; i<NELEMS( TextureAliases ); i+=2 )
  2503. {
  2504. if ( !Q_stricmp( pTextureName, TextureAliases[i] ) )
  2505. {
  2506. return FindTexture( TextureAliases[i+1], pTextureGroupName, bComplain, nAdditionalCreationFlags );
  2507. }
  2508. }
  2509. }
  2510. if ( bComplain )
  2511. {
  2512. DevWarning( "Texture '%s' not found.\n", pTextureName );
  2513. }
  2514. }
  2515. return pTexture;
  2516. }
  2517. bool CMaterialSystem::IsTextureLoaded( char const* pTextureName ) const
  2518. {
  2519. return TextureManager()->IsTextureLoaded( pTextureName );
  2520. }
  2521. void CMaterialSystem::AddTextureAlias( const char *pAlias, const char *pRealName )
  2522. {
  2523. TextureManager()->AddTextureAlias( pAlias, pRealName );
  2524. }
  2525. void CMaterialSystem::RemoveTextureAlias( const char *pAlias )
  2526. {
  2527. TextureManager()->RemoveTextureAlias( pAlias );
  2528. }
  2529. void CMaterialSystem::SetExcludedTextures( const char *pScriptName )
  2530. {
  2531. TextureManager()->SetExcludedTextures( pScriptName );
  2532. }
  2533. void CMaterialSystem::UpdateExcludedTextures( void )
  2534. {
  2535. TextureManager()->UpdateExcludedTextures();
  2536. // Have to re-setup the representative textures since they may have been removed out from under us by the queued loader.
  2537. for (MaterialHandle_t i = FirstMaterial(); i != InvalidMaterial(); i = NextMaterial(i) )
  2538. {
  2539. GetMaterialInternal(i)->FindRepresentativeTexture();
  2540. GetMaterialInternal(i)->PrecacheMappingDimensions();
  2541. }
  2542. }
  2543. //-----------------------------------------------------------------------------
  2544. // Recomputes state snapshots for all materials
  2545. //-----------------------------------------------------------------------------
  2546. void CMaterialSystem::RecomputeAllStateSnapshots()
  2547. {
  2548. g_pShaderAPI->ClearSnapshots();
  2549. for (MaterialHandle_t i = FirstMaterial(); i != InvalidMaterial(); i = NextMaterial(i) )
  2550. {
  2551. GetMaterialInternal(i)->RecomputeStateSnapshots();
  2552. }
  2553. g_pShaderAPI->ResetRenderState();
  2554. }
  2555. //-----------------------------------------------------------------------------
  2556. // Suspend texture streaming operations, for abormal periods such as loading
  2557. //-----------------------------------------------------------------------------
  2558. void CMaterialSystem::SuspendTextureStreaming()
  2559. {
  2560. TextureManager()->SuspendTextureStreaming();
  2561. }
  2562. //-----------------------------------------------------------------------------
  2563. // Inverse of SuspendTextureStreaming
  2564. //-----------------------------------------------------------------------------
  2565. void CMaterialSystem::ResumeTextureStreaming()
  2566. {
  2567. TextureManager()->ResumeTextureStreaming();
  2568. }
  2569. //-----------------------------------------------------------------------------
  2570. // Uncache all materials
  2571. //-----------------------------------------------------------------------------
  2572. void CMaterialSystem::UncacheAllMaterials()
  2573. {
  2574. MaterialLock_t hLock = Lock();
  2575. Flush( true );
  2576. m_bReplacementFilesValid = false;
  2577. for ( MaterialHandle_t i = FirstMaterial(); i != InvalidMaterial(); i = NextMaterial( i ) )
  2578. {
  2579. Assert( GetMaterialInternal(i)->GetReferenceCount() >= 0 );
  2580. GetMaterialInternal(i)->Uncache();
  2581. }
  2582. TextureManager()->RemoveUnusedTextures();
  2583. Unlock( hLock );
  2584. }
  2585. //-----------------------------------------------------------------------------
  2586. // Uncache unused materials
  2587. //-----------------------------------------------------------------------------
  2588. void CMaterialSystem::UncacheUnusedMaterials( bool bRecomputeStateSnapshots )
  2589. {
  2590. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2591. MaterialLock_t hLock = Lock();
  2592. Flush( true );
  2593. // We need two loops to make sure we don't reset the snapshots if nothing got removed,
  2594. // otherwise the snapshot recomputation is expensive and avoided at load time
  2595. bool bDidUncacheMaterial = false;
  2596. for ( MaterialHandle_t i = FirstMaterial(); i != InvalidMaterial(); i = NextMaterial(i) )
  2597. {
  2598. IMaterialInternal *pMatInternal = GetMaterialInternal( i );
  2599. Assert( pMatInternal->GetReferenceCount() >= 0 );
  2600. if ( pMatInternal->GetReferenceCount() <= 0 )
  2601. {
  2602. bDidUncacheMaterial = true;
  2603. pMatInternal->Uncache();
  2604. }
  2605. }
  2606. if ( IsX360() && bRecomputeStateSnapshots )
  2607. {
  2608. // Always recompute snapshots because the queued loading process skips it during pre-purge,
  2609. // allowing it to happen just once, here.
  2610. bDidUncacheMaterial = true;
  2611. }
  2612. if ( bDidUncacheMaterial && bRecomputeStateSnapshots )
  2613. {
  2614. // Clear the state snapshots since we are going to rebuild all of them.
  2615. g_pShaderAPI->ClearSnapshots();
  2616. g_pShaderAPI->ClearVertexAndPixelShaderRefCounts();
  2617. for ( MaterialHandle_t i = FirstMaterial(); i != InvalidMaterial(); i = NextMaterial(i) )
  2618. {
  2619. IMaterialInternal *pMatInternal = GetMaterialInternal(i);
  2620. if ( pMatInternal->GetReferenceCount() > 0 )
  2621. {
  2622. // Recompute the state snapshots for the materials that we are keeping
  2623. // since we blew all of them away above.
  2624. pMatInternal->RecomputeStateSnapshots();
  2625. }
  2626. }
  2627. g_pShaderAPI->PurgeUnusedVertexAndPixelShaders();
  2628. }
  2629. if ( bRecomputeStateSnapshots )
  2630. {
  2631. // kick out all per material context datas
  2632. for( MaterialHandle_t i = m_MaterialDict.FirstMaterial(); i != m_MaterialDict.InvalidMaterial(); i = m_MaterialDict.NextMaterial( i ) )
  2633. {
  2634. GetMaterialInternal(i)->ClearContextData();
  2635. }
  2636. }
  2637. TextureManager()->RemoveUnusedTextures();
  2638. Unlock( hLock );
  2639. }
  2640. //-----------------------------------------------------------------------------
  2641. // Release temporary HW memory...
  2642. //-----------------------------------------------------------------------------
  2643. void CMaterialSystem::ResetTempHWMemory( bool bExitingLevel )
  2644. {
  2645. g_pShaderAPI->DestroyVertexBuffers( bExitingLevel );
  2646. TextureManager()->ReleaseTempRenderTargetBits();
  2647. }
  2648. //-----------------------------------------------------------------------------
  2649. // Cache used materials
  2650. //-----------------------------------------------------------------------------
  2651. void CMaterialSystem::CacheUsedMaterials( )
  2652. {
  2653. g_pShaderAPI->EvictManagedResources();
  2654. size_t count = 0;
  2655. for (MaterialHandle_t i = FirstMaterial(); i != InvalidMaterial(); i = NextMaterial(i) )
  2656. {
  2657. // Some (mac) drivers (amd) seem to keep extra resources around on uploads until the next frame swap. This
  2658. // injects pointless synthetic swaps (between already-static load frames)
  2659. if ( mat_texture_reload_frame_swap_workaround.GetBool() )
  2660. {
  2661. if ( count++ % 20 == 0 )
  2662. {
  2663. Flush(true);
  2664. SwapBuffers(); // Not the right thing to call
  2665. }
  2666. }
  2667. IMaterialInternal* pMat = GetMaterialInternal(i);
  2668. Assert( pMat->GetReferenceCount() >= 0 );
  2669. if( pMat->GetReferenceCount() > 0 )
  2670. {
  2671. pMat->Precache();
  2672. }
  2673. }
  2674. if ( mat_forcemanagedtextureintohardware.GetBool() )
  2675. {
  2676. TextureManager()->ForceAllTexturesIntoHardware();
  2677. }
  2678. }
  2679. //-----------------------------------------------------------------------------
  2680. // Reloads textures + materials
  2681. //-----------------------------------------------------------------------------
  2682. void CMaterialSystem::ReloadTextures( void )
  2683. {
  2684. // Add by jay in changelist 621420.
  2685. ForceSingleThreaded();
  2686. // 360 should not have gotten here
  2687. Assert( !IsX360() );
  2688. KeyValuesSystem()->InvalidateCache();
  2689. TextureManager()->RestoreRenderTargets();
  2690. TextureManager()->RestoreNonRenderTargetTextures();
  2691. }
  2692. void CMaterialSystem::ReloadMaterials( const char *pSubString )
  2693. {
  2694. bool bDeviceReady = g_pShaderAPI->CanDownloadTextures();
  2695. if ( !bDeviceReady )
  2696. {
  2697. //$ TODO: Merge m_bDeferredMaterialReload from cs:go?
  2698. Msg( "%s bDeviceReady false\n", __FUNCTION__ );
  2699. }
  2700. // Add by jay in changelist 621420.
  2701. ForceSingleThreaded();
  2702. KeyValuesSystem()->InvalidateCache();
  2703. bool bVertexFormatChanged = false;
  2704. if( pSubString == NULL )
  2705. {
  2706. bVertexFormatChanged = true;
  2707. UncacheAllMaterials();
  2708. CacheUsedMaterials();
  2709. }
  2710. else
  2711. {
  2712. Flush( false );
  2713. char const chMultiDelim = '*';
  2714. CUtlVector< char > arrSearchSubString;
  2715. CUtlVector< char const * > arrSearchItems;
  2716. if ( strchr( pSubString, chMultiDelim ) )
  2717. {
  2718. arrSearchSubString.SetCount( strlen( pSubString ) + 1 );
  2719. strcpy( arrSearchSubString.Base(), pSubString );
  2720. for ( char * pch = arrSearchSubString.Base(); pch; )
  2721. {
  2722. char *pchEnd = strchr( pch, chMultiDelim );
  2723. pchEnd ? *( pchEnd ++ ) = 0 : 0;
  2724. arrSearchItems.AddToTail( pch );
  2725. pch = pchEnd;
  2726. }
  2727. }
  2728. for (MaterialHandle_t i = FirstMaterial(); i != InvalidMaterial(); i = NextMaterial(i) )
  2729. {
  2730. if( GetMaterialInternal(i)->GetReferenceCount() <= 0 )
  2731. continue;
  2732. char const *szMatName = GetMaterialInternal(i)->GetName();
  2733. if ( arrSearchItems.Count() > 1 )
  2734. {
  2735. bool bMatched = false;
  2736. for ( int k = 0; !bMatched && ( k < arrSearchItems.Count() ); ++ k )
  2737. if( Q_stristr( szMatName, arrSearchItems[k] ) )
  2738. bMatched = true;
  2739. if ( !bMatched )
  2740. continue;
  2741. }
  2742. else
  2743. {
  2744. if( !Q_stristr( szMatName, pSubString ) )
  2745. continue;
  2746. }
  2747. if ( !GetMaterialInternal(i)->IsPrecached() )
  2748. {
  2749. if ( GetMaterialInternal(i)->IsPrecachedVars() )
  2750. {
  2751. GetMaterialInternal(i)->Uncache( );
  2752. }
  2753. }
  2754. else
  2755. {
  2756. VertexFormat_t oldVertexFormat = GetMaterialInternal(i)->GetVertexFormat();
  2757. GetMaterialInternal(i)->Uncache();
  2758. GetMaterialInternal(i)->Precache();
  2759. GetMaterialInternal(i)->ReloadTextures();
  2760. if( GetMaterialInternal(i)->GetVertexFormat() != oldVertexFormat )
  2761. {
  2762. bVertexFormatChanged = true;
  2763. }
  2764. }
  2765. }
  2766. }
  2767. if( bVertexFormatChanged && bDeviceReady )
  2768. {
  2769. // Reloading materials could cause a vertex format change, so
  2770. // we need to release and restore
  2771. ReleaseShaderObjects();
  2772. RestoreShaderObjects( NULL, MATERIAL_RESTORE_VERTEX_FORMAT_CHANGED );
  2773. }
  2774. }
  2775. //-----------------------------------------------------------------------------
  2776. // Allocates the standard textures used by the material system
  2777. //-----------------------------------------------------------------------------
  2778. void CMaterialSystem::AllocateStandardTextures()
  2779. {
  2780. if ( m_StandardTexturesAllocated )
  2781. return;
  2782. m_StandardTexturesAllocated = true;
  2783. float nominal_lightmap_value = 1.0;
  2784. if ( HardwareConfig()->GetHDRType() == HDR_TYPE_INTEGER )
  2785. nominal_lightmap_value = 1.0/16.0;
  2786. unsigned char texel[4];
  2787. texel[3] = 255;
  2788. int tcFlags = TEXTURE_CREATE_MANAGED;
  2789. int tcFlagsSRGB = TEXTURE_CREATE_MANAGED | TEXTURE_CREATE_SRGB;
  2790. if ( IsX360() )
  2791. {
  2792. tcFlags |= TEXTURE_CREATE_CANCONVERTFORMAT;
  2793. tcFlagsSRGB |= TEXTURE_CREATE_CANCONVERTFORMAT;
  2794. }
  2795. // allocate a white, single texel texture for the fullbright lightmap
  2796. // note: make sure and redo this when changing gamma, etc.
  2797. // don't mipmap lightmaps
  2798. m_FullbrightLightmapTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_BGRX8888, 1, 1, tcFlags, "[FULLBRIGHT_LIGHTMAP_TEXID]", TEXTURE_GROUP_LIGHTMAP );
  2799. g_pShaderAPI->ModifyTexture( m_FullbrightLightmapTextureHandle );
  2800. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2801. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2802. float tmpVect[3] = { nominal_lightmap_value, nominal_lightmap_value, nominal_lightmap_value };
  2803. ColorSpace::LinearToLightmap( texel, tmpVect );
  2804. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_BGRX8888, 0, 1, 1, IMAGE_FORMAT_BGRX8888, false, texel );
  2805. // allocate a black single texel texture
  2806. #if !defined( _X360 )
  2807. m_BlackTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_BGRX8888, 1, 1, tcFlagsSRGB, "[BLACK_TEXID]", TEXTURE_GROUP_OTHER );
  2808. g_pShaderAPI->ModifyTexture( m_BlackTextureHandle );
  2809. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2810. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2811. texel[0] = texel[1] = texel[2] = 0;
  2812. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_BGRX8888, 0, 1, 1, IMAGE_FORMAT_BGRX8888, false, texel );
  2813. #else
  2814. m_BlackTextureHandle = ((ITextureInternal*)FindTexture( "black", TEXTURE_GROUP_OTHER, true ))->GetTextureHandle( 0 );
  2815. #endif
  2816. g_pShaderAPI->SetStandardTextureHandle( TEXTURE_BLACK, m_BlackTextureHandle );
  2817. // allocate a fully white single texel texture
  2818. #if !defined( _X360 )
  2819. m_WhiteTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_BGRX8888, 1, 1, tcFlagsSRGB, "[WHITE_TEXID]", TEXTURE_GROUP_OTHER );
  2820. g_pShaderAPI->ModifyTexture( m_WhiteTextureHandle );
  2821. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2822. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2823. texel[0] = texel[1] = texel[2] = 255;
  2824. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_BGRX8888, 0, 1, 1, IMAGE_FORMAT_BGRX8888, false, texel );
  2825. #else
  2826. m_WhiteTextureHandle = ((ITextureInternal*)FindTexture( "white", TEXTURE_GROUP_OTHER, true ))->GetTextureHandle( 0 );
  2827. #endif
  2828. g_pShaderAPI->SetStandardTextureHandle( TEXTURE_WHITE, m_WhiteTextureHandle );
  2829. // allocate a grey single texel texture with an alpha of zero (for mat_fullbright 2)
  2830. #if !defined( _X360 )
  2831. m_GreyTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_BGRX8888, 1, 1, tcFlagsSRGB, "[GREY_TEXID]", TEXTURE_GROUP_OTHER );
  2832. g_pShaderAPI->ModifyTexture( m_GreyTextureHandle );
  2833. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2834. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2835. texel[0] = texel[1] = texel[2] = 128;
  2836. texel[3] = 255; // needs to be 255 so that mat_fullbright 2 stuff isn't translucent.
  2837. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_BGRX8888, 0, 1, 1, IMAGE_FORMAT_BGRX8888, false, texel );
  2838. #else
  2839. m_GreyTextureHandle = ((ITextureInternal*)FindTexture( "grey", TEXTURE_GROUP_OTHER, true ))->GetTextureHandle( 0 );
  2840. #endif
  2841. g_pShaderAPI->SetStandardTextureHandle( TEXTURE_GREY, m_GreyTextureHandle );
  2842. // allocate a grey single texel texture with an alpha of zero (for mat_fullbright 2)
  2843. #if !defined( _X360 )
  2844. m_GreyAlphaZeroTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_RGBA8888, 1, 1, tcFlagsSRGB, "[GREYALPHAZERO_TEXID]", TEXTURE_GROUP_OTHER );
  2845. g_pShaderAPI->ModifyTexture( m_GreyAlphaZeroTextureHandle );
  2846. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2847. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2848. texel[0] = texel[1] = texel[2] = 128;
  2849. texel[3] = 0; // needs to be 0 so that self-illum doens't affect mat_fullbright 2
  2850. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_RGBA8888, 0, 1, 1, IMAGE_FORMAT_RGBA8888, false, texel );
  2851. texel[3] = 255; // set back to default value so we don't affect the rest of this code.'
  2852. #else
  2853. m_GreyAlphaZeroTextureHandle = ((ITextureInternal*)FindTexture( "greyalphazero", TEXTURE_GROUP_OTHER, true ))->GetTextureHandle( 0 );
  2854. #endif
  2855. g_pShaderAPI->SetStandardTextureHandle( TEXTURE_GREY_ALPHA_ZERO, m_GreyAlphaZeroTextureHandle );
  2856. // allocate a single texel flat normal texture lightmap
  2857. m_FlatNormalTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_BGRX8888, 1, 1, tcFlags, "[FLAT_NORMAL_TEXTURE]", TEXTURE_GROUP_OTHER );
  2858. g_pShaderAPI->ModifyTexture( m_FlatNormalTextureHandle );
  2859. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2860. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2861. texel[0] = 255; // B
  2862. texel[1] = 127; // G
  2863. texel[2] = 127; // R
  2864. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_BGRX8888, 0, 1, 1, IMAGE_FORMAT_BGRX8888, false, texel );
  2865. g_pShaderAPI->SetStandardTextureHandle( TEXTURE_NORMALMAP_FLAT, m_FlatNormalTextureHandle );
  2866. // allocate a single texel fullbright 1 lightmap for use with bump textures
  2867. m_FullbrightBumpedLightmapTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_BGRX8888, 1, 1, tcFlags, "[FULLBRIGHT_BUMPED_LIGHTMAP_TEXID]", TEXTURE_GROUP_LIGHTMAP );
  2868. g_pShaderAPI->ModifyTexture( m_FullbrightBumpedLightmapTextureHandle );
  2869. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2870. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2871. float linearColor[3] = { nominal_lightmap_value, nominal_lightmap_value, nominal_lightmap_value };
  2872. unsigned char dummy[3];
  2873. ColorSpace::LinearToBumpedLightmap( linearColor, linearColor, linearColor, linearColor,
  2874. dummy, texel, dummy, dummy );
  2875. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_BGRX8888, 0, 1, 1, IMAGE_FORMAT_BGRX8888, false, texel );
  2876. g_pShaderAPI->SetStandardTextureHandle( TEXTURE_LIGHTMAP_BUMPED_FULLBRIGHT, m_FullbrightBumpedLightmapTextureHandle );
  2877. {
  2878. int iGammaLookupFlags = tcFlags;
  2879. ImageFormat gammalookupfmt;
  2880. gammalookupfmt = IMAGE_FORMAT_I8;
  2881. // generate the linear->gamma conversion table texture.
  2882. {
  2883. const int LINEAR_TO_GAMMA_TABLE_WIDTH = 512;
  2884. m_LinearToGammaTableTextureHandle = g_pShaderAPI->CreateTexture( LINEAR_TO_GAMMA_TABLE_WIDTH, 1, 1, gammalookupfmt, 1, 1, iGammaLookupFlags, "[LINEAR_TO_GAMMA_LOOKUP_SRGBON_TEXID]", TEXTURE_GROUP_PIXEL_SHADERS );
  2885. g_pShaderAPI->ModifyTexture( m_LinearToGammaTableTextureHandle );
  2886. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2887. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2888. g_pShaderAPI->TexWrap( SHADER_TEXCOORD_S, SHADER_TEXWRAPMODE_CLAMP );
  2889. g_pShaderAPI->TexWrap( SHADER_TEXCOORD_T, SHADER_TEXWRAPMODE_CLAMP );
  2890. g_pShaderAPI->TexWrap( SHADER_TEXCOORD_U, SHADER_TEXWRAPMODE_CLAMP );
  2891. float pixelData[LINEAR_TO_GAMMA_TABLE_WIDTH]; //sometimes used as float, sometimes as uint8, sizeof(float) > sizeof(uint8)
  2892. for( int i = 0; i != LINEAR_TO_GAMMA_TABLE_WIDTH; ++i )
  2893. {
  2894. float fLookupResult = ((float)i) / ((float)(LINEAR_TO_GAMMA_TABLE_WIDTH - 1));
  2895. fLookupResult = g_pShaderAPI->LinearToGamma_HardwareSpecific( fLookupResult );
  2896. //do an extra srgb conversion because we'll be converting back on texture read
  2897. fLookupResult = g_pShaderAPI->LinearToGamma_HardwareSpecific( fLookupResult ); //that's right, linear->gamma->gamma2x so that that gamma->linear srgb read still ends up in gamma
  2898. int iColor = RoundFloatToInt( fLookupResult * 255.0f );
  2899. if( iColor > 255 )
  2900. iColor = 255;
  2901. ((uint8 *)pixelData)[i] = (uint8)iColor;
  2902. }
  2903. g_pShaderAPI->TexImage2D( 0, 0, gammalookupfmt, 0, LINEAR_TO_GAMMA_TABLE_WIDTH, 1, gammalookupfmt, false, (void *)pixelData );
  2904. }
  2905. // generate the identity conversion table texture.
  2906. {
  2907. const int LINEAR_TO_GAMMA_IDENTITY_TABLE_WIDTH = 256;
  2908. m_LinearToGammaIdentityTableTextureHandle = g_pShaderAPI->CreateTexture( LINEAR_TO_GAMMA_IDENTITY_TABLE_WIDTH, 1, 1, gammalookupfmt, 1, 1, tcFlags, "[LINEAR_TO_GAMMA_LOOKUP_SRGBOFF_TEXID]", TEXTURE_GROUP_PIXEL_SHADERS );
  2909. g_pShaderAPI->ModifyTexture( m_LinearToGammaIdentityTableTextureHandle );
  2910. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2911. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2912. g_pShaderAPI->TexWrap( SHADER_TEXCOORD_S, SHADER_TEXWRAPMODE_CLAMP );
  2913. g_pShaderAPI->TexWrap( SHADER_TEXCOORD_T, SHADER_TEXWRAPMODE_CLAMP );
  2914. g_pShaderAPI->TexWrap( SHADER_TEXCOORD_U, SHADER_TEXWRAPMODE_CLAMP );
  2915. float pixelData[LINEAR_TO_GAMMA_IDENTITY_TABLE_WIDTH]; //sometimes used as float, sometimes as uint8, sizeof(float) > sizeof(uint8)
  2916. for( int i = 0; i != LINEAR_TO_GAMMA_IDENTITY_TABLE_WIDTH; ++i )
  2917. {
  2918. float fLookupResult = ((float)i) / ((float)(LINEAR_TO_GAMMA_IDENTITY_TABLE_WIDTH - 1));
  2919. //do an extra srgb conversion because we'll be converting back on texture read
  2920. fLookupResult = g_pShaderAPI->LinearToGamma_HardwareSpecific( fLookupResult );
  2921. int iColor = RoundFloatToInt( fLookupResult * 255.0f );
  2922. if ( iColor > 255 )
  2923. iColor = 255;
  2924. ((uint8 *)pixelData)[i] = (uint8)iColor;
  2925. }
  2926. g_pShaderAPI->TexImage2D( 0, 0, gammalookupfmt, 0, LINEAR_TO_GAMMA_IDENTITY_TABLE_WIDTH, 1, gammalookupfmt, false, (void *)pixelData );
  2927. }
  2928. }
  2929. //create the maximum depth texture
  2930. {
  2931. m_MaxDepthTextureHandle = g_pShaderAPI->CreateTexture( 1, 1, 1, IMAGE_FORMAT_RGBA8888, 1, 1, tcFlags, "[MAXDEPTH_TEXID]", TEXTURE_GROUP_OTHER );
  2932. g_pShaderAPI->ModifyTexture( m_MaxDepthTextureHandle );
  2933. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2934. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2935. //360 gets depth out of the red channel (which doubles as depth in D24S8) and may be 0/1 depending on REVERSE_DEPTH_ON_X360
  2936. //PC gets depth out of the alpha channel
  2937. texel[0] = texel[1] = texel[2] = ReverseDepthOnX360() ? 0 : 255;
  2938. texel[3] = 255;
  2939. g_pShaderAPI->TexImage2D( 0, 0, IMAGE_FORMAT_RGBA8888, 0, 1, 1, IMAGE_FORMAT_RGBA8888, false, texel );
  2940. }
  2941. //only the shaderapi can handle switching between textures correctly, so pass off the textures to it.
  2942. g_pShaderAPI->SetLinearToGammaConversionTextures( m_LinearToGammaTableTextureHandle, m_LinearToGammaIdentityTableTextureHandle );
  2943. }
  2944. void CMaterialSystem::ReleaseStandardTextures()
  2945. {
  2946. if ( m_StandardTexturesAllocated )
  2947. {
  2948. if ( IsPC() )
  2949. {
  2950. g_pShaderAPI->DeleteTexture( m_BlackTextureHandle );
  2951. g_pShaderAPI->DeleteTexture( m_WhiteTextureHandle );
  2952. g_pShaderAPI->DeleteTexture( m_GreyTextureHandle );
  2953. g_pShaderAPI->DeleteTexture( m_GreyAlphaZeroTextureHandle );
  2954. }
  2955. g_pShaderAPI->DeleteTexture( m_FullbrightLightmapTextureHandle );
  2956. g_pShaderAPI->DeleteTexture( m_FlatNormalTextureHandle );
  2957. g_pShaderAPI->DeleteTexture( m_FullbrightBumpedLightmapTextureHandle );
  2958. g_pShaderAPI->DeleteTexture( m_LinearToGammaTableTextureHandle );
  2959. g_pShaderAPI->DeleteTexture( m_LinearToGammaIdentityTableTextureHandle );
  2960. g_pShaderAPI->SetLinearToGammaConversionTextures( INVALID_SHADERAPI_TEXTURE_HANDLE, INVALID_SHADERAPI_TEXTURE_HANDLE );
  2961. g_pShaderAPI->DeleteTexture( m_MaxDepthTextureHandle );
  2962. m_StandardTexturesAllocated = false;
  2963. }
  2964. }
  2965. //-----------------------------------------------------------------------------
  2966. //
  2967. //-----------------------------------------------------------------------------
  2968. void CMaterialSystem::BeginFrame( float frameTime )
  2969. {
  2970. // Safety measure (calls should only come from the main thread, also check correct pairing)
  2971. if ( !ThreadInMainThread() || IsInFrame() )
  2972. return;
  2973. // check debug vars. we will use these to setup g_nDebugVarsSignature so that materials will
  2974. // rebuild their draw lists when debug modes changed.
  2975. g_nDebugVarsSignature = (
  2976. (mat_specular.GetInt() != 0 ) + ( mat_normalmaps.GetInt() << 1 ) +
  2977. ( mat_fullbright.GetInt() << 2 ) + (mat_fastnobump.GetInt() << 4 ) ) << 24;
  2978. Assert( m_bGeneratedConfig );
  2979. VPROF_BUDGET( "CMaterialSystem::BeginFrame", VPROF_BUDGETGROUP_SWAP_BUFFERS );
  2980. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  2981. IMatRenderContextInternal *pRenderContext = GetRenderContextInternal();
  2982. if ( g_config.ForceHWSync() && (IsPC() || m_ThreadMode != MATERIAL_QUEUED_THREADED) )
  2983. {
  2984. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "ForceHardwareSync" );
  2985. pRenderContext->ForceHardwareSync();
  2986. }
  2987. pRenderContext->MarkRenderDataUnused( true );
  2988. pRenderContext->BeginFrame();
  2989. pRenderContext->SetFrameTime( frameTime );
  2990. pRenderContext->SetToneMappingScaleLinear( Vector( 1,1,1) );
  2991. Assert( !m_bInFrame );
  2992. m_bInFrame = true;
  2993. }
  2994. bool CMaterialSystem::IsInFrame( ) const
  2995. {
  2996. return m_bInFrame;
  2997. }
  2998. #ifdef RAD_TELEMETRY_ENABLED
  2999. static const char *GetMatString( enum MaterialThreadMode_t ThreadMode )
  3000. {
  3001. switch( ThreadMode )
  3002. {
  3003. case MATERIAL_SINGLE_THREADED: return "single";
  3004. case MATERIAL_QUEUED_SINGLE_THREADED: return "queued_single";
  3005. case MATERIAL_QUEUED_THREADED: return "queued_threaded";
  3006. default: return "???";
  3007. }
  3008. }
  3009. #endif
  3010. ConVar mat_queue_mode( "mat_queue_mode", "-1", FCVAR_ARCHIVE, "The queue/thread mode the material system should use: -1=default, 0=synchronous single thread"
  3011. #ifdef MAT_QUEUE_MODE_PROFILE
  3012. ", 1=queued single thread"
  3013. #endif
  3014. ", 2=queued multithreaded" );
  3015. ConVar mat_queue_report( "mat_queue_report", "0", FCVAR_ARCHIVE, "Report thread stalls. Positive number will filter by stalls >= time in ms. -1 reports all locks." );
  3016. void CMaterialSystem::ThreadExecuteQueuedContext( CMatQueuedRenderContext *pContext )
  3017. {
  3018. #ifdef RAD_TELEMETRY_ENABLED
  3019. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s-%s", __FUNCTION__, GetMatString( m_ThreadMode ) );
  3020. CTelemetrySpikeDetector Spike( "ThreadExecuteQueuedContext", 1 );
  3021. #endif
  3022. Assert( m_bThreadHasOwnership );
  3023. m_nRenderThreadID = ThreadGetCurrentId();
  3024. IMatRenderContextInternal* pSavedRenderContext = m_pRenderContext.Get();
  3025. m_pRenderContext.Set( &m_HardwareRenderContext );
  3026. pContext->EndQueue( true );
  3027. m_pRenderContext.Set( pSavedRenderContext );
  3028. m_nRenderThreadID = 0xFFFFFFFF;
  3029. }
  3030. IThreadPool *CMaterialSystem::CreateMatQueueThreadPool()
  3031. {
  3032. if( IsX360() )
  3033. {
  3034. return g_pThreadPool;
  3035. }
  3036. else if( !m_pMatQueueThreadPool )
  3037. {
  3038. ThreadPoolStartParams_t startParams;
  3039. startParams.nThreads = 1;
  3040. startParams.nStackSize = 256*1024;
  3041. startParams.fDistribute = TRS_TRUE;
  3042. // The rendering thread has the GL context and the main thread is coming in and
  3043. // "helping" finish jobs - that breaks OpenGL, which requires TLS. This flag states
  3044. // that only the threadpool threads should execute these jobs.
  3045. startParams.bExecOnThreadPoolThreadsOnly = true;
  3046. m_pMatQueueThreadPool = CreateThreadPool();
  3047. m_pMatQueueThreadPool->Start( startParams, "MatQueue" );
  3048. }
  3049. return m_pMatQueueThreadPool;
  3050. }
  3051. void CMaterialSystem::DestroyMatQueueThreadPool()
  3052. {
  3053. if( m_pMatQueueThreadPool )
  3054. {
  3055. m_pMatQueueThreadPool->Stop();
  3056. delete m_pMatQueueThreadPool;
  3057. m_pMatQueueThreadPool = NULL;
  3058. }
  3059. }
  3060. //-----------------------------------------------------------------------------------------------------
  3061. //
  3062. //-----------------------------------------------------------------------------------------------------
  3063. class CThreadAcquire : public CJob
  3064. {
  3065. virtual JobStatus_t DoExecute()
  3066. {
  3067. g_pShaderAPI->AcquireThreadOwnership();
  3068. return JOB_OK;
  3069. }
  3070. };
  3071. void CMaterialSystem::EndFrame( void )
  3072. {
  3073. // Safety measure (calls should only come from the main thread, also check correct pairing)
  3074. if ( !ThreadInMainThread() || !IsInFrame() )
  3075. return;
  3076. Assert( m_bGeneratedConfig );
  3077. VPROF_BUDGET( "CMaterialSystem::EndFrame", VPROF_BUDGETGROUP_SWAP_BUFFERS );
  3078. GetRenderContextInternal()->EndFrame();
  3079. TextureManager()->Update();
  3080. while ( !m_scheduledComposites.IsEmpty() )
  3081. {
  3082. // We hold a ref, so if there's only one count left, it's us. Let it go and move on.
  3083. if ( m_scheduledComposites[ 0 ]->GetRefCount() == 1 )
  3084. {
  3085. m_scheduledComposites[ 0 ]->Release();
  3086. m_scheduledComposites.Remove( 0 );
  3087. continue;
  3088. }
  3089. m_scheduledComposites[ 0 ]->Resolve();
  3090. m_pendingComposites.AddToTail( m_scheduledComposites[ 0 ] );
  3091. m_scheduledComposites.Remove( 0 );
  3092. // Only do one per frame, because these can actually be fairly expensive.
  3093. break;
  3094. }
  3095. FOR_EACH_VEC( m_pendingComposites, i )
  3096. {
  3097. CTextureCompositor* comp = m_pendingComposites[ i ];
  3098. // We hold a ref, so if there's only one count left, it's us. Let it go and move on.
  3099. if ( comp->GetRefCount() == 1 )
  3100. {
  3101. comp->Release();
  3102. m_pendingComposites.Remove( i );
  3103. // Back up one
  3104. --i;
  3105. continue;
  3106. }
  3107. comp->Update();
  3108. if ( comp->GetResolveStatus() == ECRS_Complete || comp->GetResolveStatus() == ECRS_Error )
  3109. {
  3110. comp->Release();
  3111. m_pendingComposites.Remove( i );
  3112. // Stop after the first one reports that it was completed, these can take awhile and
  3113. // we don't want to hammer anyone's framerate.
  3114. break;
  3115. }
  3116. }
  3117. //-------------------------------------------------------------
  3118. int iConVarThreadMode = mat_queue_mode.GetInt();
  3119. // For this testing release, -2 is equivalent to 0 (off). When we release, we'll make -2 equivalent to -1 (on)
  3120. if ( iConVarThreadMode == -2 )
  3121. {
  3122. iConVarThreadMode = MATERIAL_QUEUED_THREADED;
  3123. }
  3124. #ifndef MAT_QUEUE_MODE_PROFILE
  3125. if ( iConVarThreadMode == MATERIAL_QUEUED_SINGLE_THREADED )
  3126. {
  3127. iConVarThreadMode = MATERIAL_SINGLE_THREADED;
  3128. }
  3129. #endif
  3130. MaterialThreadMode_t nextThreadMode = ( iConVarThreadMode >= 0 ) ? (MaterialThreadMode_t)iConVarThreadMode : m_IdealThreadMode;
  3131. // note: This is a hack because there is no explicit query for the device being deactivated due to device lost.
  3132. // however, that is all the current implementation of CanDownloadTextures actually does.
  3133. bool bDeviceReady = g_pShaderAPI->CanDownloadTextures();
  3134. if ( !bDeviceReady || !m_bAllowQueuedRendering )
  3135. {
  3136. nextThreadMode = MATERIAL_SINGLE_THREADED;
  3137. }
  3138. if ( m_bForcedSingleThreaded || m_bThreadingNotAvailable )
  3139. {
  3140. nextThreadMode = MATERIAL_SINGLE_THREADED;
  3141. m_bForcedSingleThreaded = false;
  3142. }
  3143. switch ( m_ThreadMode )
  3144. {
  3145. case MATERIAL_SINGLE_THREADED:
  3146. OnRenderingAsyncComplete();
  3147. break;
  3148. case MATERIAL_QUEUED_THREADED:
  3149. {
  3150. VPROF_BUDGET( "Mat_ThreadedEndframe", "Mat_ThreadedEndframe" );
  3151. if ( !m_bThreadHasOwnership )
  3152. {
  3153. ThreadAcquire( true );
  3154. }
  3155. if ( m_pActiveAsyncJob && !m_pActiveAsyncJob->IsFinished() )
  3156. {
  3157. m_pActiveAsyncJob->WaitForFinish();
  3158. if ( !IsPC() && g_config.ForceHWSync() )
  3159. {
  3160. g_pShaderAPI->ForceHardwareSync();
  3161. }
  3162. }
  3163. SafeRelease( m_pActiveAsyncJob );
  3164. OnRenderingAsyncComplete();
  3165. CMatQueuedRenderContext *pPrevContext = &m_QueuedRenderContexts[m_iCurQueuedContext];
  3166. m_iCurQueuedContext = ( ( m_iCurQueuedContext + 1 ) % ARRAYSIZE( m_QueuedRenderContexts) );
  3167. m_QueuedRenderContexts[m_iCurQueuedContext].BeginQueue( pPrevContext );
  3168. m_pRenderContext.Set( &m_QueuedRenderContexts[m_iCurQueuedContext] );
  3169. m_pActiveAsyncJob = new CFunctorJob( CreateFunctor( this, &CMaterialSystem::ThreadExecuteQueuedContext, pPrevContext ), "ThreadExecuteQueuedContext" );
  3170. if ( IsX360() )
  3171. {
  3172. if ( m_nServiceThread >= 0 )
  3173. {
  3174. m_pActiveAsyncJob->SetServiceThread( m_nServiceThread );
  3175. }
  3176. }
  3177. IThreadPool *pThreadPool = CreateMatQueueThreadPool();
  3178. pThreadPool->AddJob( m_pActiveAsyncJob );
  3179. break;
  3180. }
  3181. case MATERIAL_QUEUED_SINGLE_THREADED:
  3182. OnRenderingAsyncComplete();
  3183. break;
  3184. #ifdef MAT_QUEUE_MODE_PROFILE
  3185. {
  3186. VPROF_BUDGET( "Mat_ThreadedEndframe", "Mat_QueuedEndframe" );
  3187. g_pShaderAPI->SetDisallowAccess( false );
  3188. m_pRenderContext.Set( &m_HardwareRenderContext );
  3189. m_QueuedRenderContexts[m_iCurQueuedContext].CallQueued();
  3190. m_pRenderContext.Set( &m_QueuedRenderContexts[m_iCurQueuedContext] );
  3191. g_pShaderAPI->SetDisallowAccess( true );
  3192. break;
  3193. }
  3194. #endif
  3195. }
  3196. bool bRelease = false;
  3197. if ( !bDeviceReady )
  3198. {
  3199. if ( nextThreadMode != MATERIAL_SINGLE_THREADED )
  3200. {
  3201. Assert( nextThreadMode == MATERIAL_SINGLE_THREADED );
  3202. bRelease = true;
  3203. nextThreadMode = MATERIAL_SINGLE_THREADED;
  3204. if( mat_debugalttab.GetBool() )
  3205. {
  3206. Warning("Handling alt-tab in queued mode!\n");
  3207. }
  3208. }
  3209. }
  3210. if ( m_threadEvents.Count() )
  3211. {
  3212. nextThreadMode = MATERIAL_SINGLE_THREADED;
  3213. }
  3214. if ( m_ThreadMode != nextThreadMode )
  3215. {
  3216. // Shut down the current mode & set new mode
  3217. switch ( m_ThreadMode )
  3218. {
  3219. case MATERIAL_SINGLE_THREADED:
  3220. break;
  3221. case MATERIAL_QUEUED_THREADED:
  3222. {
  3223. if ( m_pActiveAsyncJob )
  3224. {
  3225. m_pActiveAsyncJob->WaitForFinish();
  3226. SafeRelease( m_pActiveAsyncJob );
  3227. }
  3228. // probably have a queued context set here, need hardware to flush the queue if the job isn't active
  3229. m_HardwareRenderContext.InitializeFrom(&m_QueuedRenderContexts[m_iCurQueuedContext]);
  3230. m_pRenderContext.Set( &m_HardwareRenderContext );
  3231. m_QueuedRenderContexts[m_iCurQueuedContext].EndQueue( true );
  3232. ThreadRelease();
  3233. }
  3234. break;
  3235. #ifdef MAT_QUEUE_MODE_PROFILE
  3236. case MATERIAL_QUEUED_SINGLE_THREADED:
  3237. {
  3238. g_pShaderAPI->SetDisallowAccess( false );
  3239. // We have a queued context set here, need hardware to flush the queue if the job isn't active
  3240. m_pRenderContext.Set( &m_HardwareRenderContext );
  3241. m_QueuedRenderContexts[m_iCurQueuedContext].EndQueue( true );
  3242. break;
  3243. }
  3244. #endif
  3245. }
  3246. m_ThreadMode = nextThreadMode;
  3247. Assert( g_MatSysMutex.GetOwnerId() == 0 );
  3248. g_pShaderAPI->EnableShaderShaderMutex( m_ThreadMode != MATERIAL_SINGLE_THREADED ); // use mutex even for queued to allow "disalow access" to function properly
  3249. g_pShaderAPI->EnableBuffer2FramesAhead( true );
  3250. switch ( m_ThreadMode )
  3251. {
  3252. case MATERIAL_SINGLE_THREADED:
  3253. m_pRenderContext.Set( &m_HardwareRenderContext );
  3254. for ( int i = 0; i < ARRAYSIZE( m_QueuedRenderContexts ); i++ )
  3255. {
  3256. Assert( m_QueuedRenderContexts[i].IsInitialized() );
  3257. m_QueuedRenderContexts[i].EndQueue( true );
  3258. }
  3259. break;
  3260. #ifdef MAT_QUEUE_MODE_PROFILE
  3261. case MATERIAL_QUEUED_SINGLE_THREADED:
  3262. #endif
  3263. case MATERIAL_QUEUED_THREADED:
  3264. {
  3265. m_iCurQueuedContext = 0;
  3266. m_QueuedRenderContexts[m_iCurQueuedContext].BeginQueue( &m_HardwareRenderContext );
  3267. m_pRenderContext.Set( &m_QueuedRenderContexts[m_iCurQueuedContext] );
  3268. #ifdef MAT_QUEUE_MODE_PROFILE
  3269. if ( m_ThreadMode == MATERIAL_QUEUED_SINGLE_THREADED )
  3270. {
  3271. g_pShaderAPI->SetDisallowAccess( true );
  3272. }
  3273. else
  3274. #endif
  3275. {
  3276. g_pShaderAPI->ReleaseThreadOwnership();
  3277. CJob *pActiveAsyncJob = new CThreadAcquire();
  3278. IThreadPool *pThreadPool = CreateMatQueueThreadPool();
  3279. pThreadPool->AddJob( pActiveAsyncJob );
  3280. SafeRelease( pActiveAsyncJob );
  3281. m_bThreadHasOwnership = true;
  3282. m_ThreadOwnershipID = ThreadGetCurrentId();
  3283. }
  3284. }
  3285. break;
  3286. }
  3287. }
  3288. if ( m_ThreadMode == MATERIAL_SINGLE_THREADED )
  3289. {
  3290. for ( int i = 0; i < m_threadEvents.Count(); i++ )
  3291. {
  3292. g_pShaderDevice->HandleThreadEvent(m_threadEvents[i]);
  3293. }
  3294. m_threadEvents.RemoveAll();
  3295. }
  3296. Assert( m_bInFrame );
  3297. m_bInFrame = false;
  3298. }
  3299. void CMaterialSystem::SetInStubMode( bool bInStubMode )
  3300. {
  3301. m_bInStubMode = bInStubMode;
  3302. }
  3303. bool CMaterialSystem::IsInStubMode()
  3304. {
  3305. return m_bInStubMode;
  3306. }
  3307. void CMaterialSystem::Flush( bool flushHardware )
  3308. {
  3309. GetRenderContextInternal()->Flush( flushHardware );
  3310. }
  3311. //-----------------------------------------------------------------------------
  3312. // Flushes managed textures from the texture cacher
  3313. //-----------------------------------------------------------------------------
  3314. void CMaterialSystem::EvictManagedResources()
  3315. {
  3316. g_pShaderAPI->EvictManagedResources();
  3317. }
  3318. int __cdecl MaterialNameCompareFunc( const void *elem1, const void *elem2 )
  3319. {
  3320. IMaterialInternal *pMaterialA = g_MaterialSystem.GetMaterialInternal( *(MaterialHandle_t *)elem1 );
  3321. IMaterialInternal *pMaterialB = g_MaterialSystem.GetMaterialInternal( *(MaterialHandle_t *)elem2 );
  3322. // case insensitive to group similar named materials
  3323. return stricmp( pMaterialA->GetName(), pMaterialB->GetName() );
  3324. }
  3325. void CMaterialSystem::DebugPrintUsedMaterials( const char *pSearchSubString, bool bVerbose )
  3326. {
  3327. MaterialHandle_t h;
  3328. int i;
  3329. int nNumCached;
  3330. int nRefCount;
  3331. int nSortedMaterials;
  3332. int nNumErrors;
  3333. // build a mapping to sort the material names
  3334. MaterialHandle_t *pSorted = (MaterialHandle_t*)stackalloc( GetNumMaterials() * sizeof(MaterialHandle_t) );
  3335. nSortedMaterials = 0;
  3336. for (h = FirstMaterial(); h != InvalidMaterial(); h = NextMaterial(h) )
  3337. {
  3338. pSorted[nSortedMaterials++] = h;
  3339. }
  3340. qsort( pSorted, nSortedMaterials, sizeof(MaterialHandle_t), MaterialNameCompareFunc );
  3341. nNumCached = 0;
  3342. nNumErrors = 0;
  3343. for (i = 0; i < nSortedMaterials; i++)
  3344. {
  3345. // iterate using sort mapping
  3346. IMaterialInternal *pMaterial = GetMaterialInternal(pSorted[i]);
  3347. nRefCount = pMaterial->GetReferenceCount();
  3348. if ( nRefCount < 0 )
  3349. {
  3350. nNumErrors++;
  3351. }
  3352. else if (!nRefCount)
  3353. {
  3354. if (pMaterial->IsPrecached() || pMaterial->IsPrecachedVars())
  3355. {
  3356. nNumErrors++;
  3357. }
  3358. }
  3359. else
  3360. {
  3361. // nonzero reference count
  3362. // tally the valid ones
  3363. nNumCached++;
  3364. if( pSearchSubString )
  3365. {
  3366. if( !Q_stristr( pMaterial->GetName(), pSearchSubString ) &&
  3367. (!pMaterial->GetShader() || !Q_stristr( pMaterial->GetShader()->GetName(), pSearchSubString )) )
  3368. {
  3369. continue;
  3370. }
  3371. }
  3372. DevMsg( "%s (shader: %s) refCount: %d.\n", pMaterial->GetName(),
  3373. pMaterial->GetShader() ? pMaterial->GetShader()->GetName() : "unknown\n", nRefCount );
  3374. if( !bVerbose )
  3375. {
  3376. continue;
  3377. }
  3378. if( pMaterial->IsPrecached() )
  3379. {
  3380. if( pMaterial->GetShader() )
  3381. {
  3382. for( int j = 0; j < pMaterial->GetShader()->GetNumParams(); j++ )
  3383. {
  3384. IMaterialVar *var;
  3385. var = pMaterial->GetShaderParams()[j];
  3386. if( var )
  3387. {
  3388. switch( var->GetType() )
  3389. {
  3390. case MATERIAL_VAR_TYPE_TEXTURE:
  3391. {
  3392. ITextureInternal *texture = static_cast<ITextureInternal *>( var->GetTextureValue() );
  3393. if( !texture )
  3394. {
  3395. DevWarning( "Programming error: CMaterialSystem::DebugPrintUsedMaterialsCallback: NULL texture\n" );
  3396. continue;
  3397. }
  3398. if( IsTextureInternalEnvCubemap( texture ) )
  3399. {
  3400. DevMsg( " \"%s\" \"env_cubemap\"\n", var->GetName() );
  3401. }
  3402. else
  3403. {
  3404. DevMsg( " \"%s\" \"%s\"\n",
  3405. var->GetName(),
  3406. texture->GetName() );
  3407. DevMsg( " %dx%d refCount: %d numframes: %d\n", texture->GetActualWidth(), texture->GetActualHeight(),
  3408. texture->GetReferenceCount(), texture->GetNumAnimationFrames() );
  3409. }
  3410. }
  3411. break;
  3412. case MATERIAL_VAR_TYPE_UNDEFINED:
  3413. break;
  3414. default:
  3415. DevMsg( " \"%s\" \"%s\"\n", var->GetName(), var->GetStringValue() );
  3416. break;
  3417. }
  3418. }
  3419. }
  3420. }
  3421. }
  3422. }
  3423. }
  3424. // list the critical errors after, otherwise the console log scrolls them away
  3425. if (nNumErrors)
  3426. {
  3427. for (i = 0; i < nSortedMaterials; i++)
  3428. {
  3429. // iterate using sort mapping
  3430. IMaterialInternal *pMaterial = GetMaterialInternal(pSorted[i]);
  3431. nRefCount = pMaterial->GetReferenceCount();
  3432. if ( nRefCount < 0 )
  3433. {
  3434. // reference counts should not be negative
  3435. DevWarning( "DebugPrintUsedMaterials: refCount (%d) < 0 for material: \"%s\"\n",
  3436. nRefCount, pMaterial->GetName() );
  3437. }
  3438. else if (!nRefCount)
  3439. {
  3440. // ensure that it stayed uncached after the post loading uncache
  3441. // this is effectively a coding bug thats needs to be fixed
  3442. // a material is being precached without incrementing its reference
  3443. if (pMaterial->IsPrecached() || pMaterial->IsPrecachedVars())
  3444. {
  3445. DevWarning( "DebugPrintUsedMaterials: material: \"%s\" didn't unache\n",
  3446. pMaterial->GetName() );
  3447. }
  3448. }
  3449. }
  3450. DevWarning( "%d Errors\n", nNumErrors );
  3451. }
  3452. if (!pSearchSubString)
  3453. {
  3454. DevMsg( "%d Cached, %d Total Materials\n", nNumCached, GetNumMaterials() );
  3455. }
  3456. }
  3457. void CMaterialSystem::DebugPrintUsedTextures( void )
  3458. {
  3459. TextureManager()->DebugPrintUsedTextures();
  3460. }
  3461. #if defined( _X360 )
  3462. void CMaterialSystem::ListUsedMaterials( void )
  3463. {
  3464. int numMaterials = GetNumMaterials();
  3465. xMaterialList_t* pMaterialList = (xMaterialList_t *)stackalloc( numMaterials * sizeof( xMaterialList_t ) );
  3466. numMaterials = 0;
  3467. for ( MaterialHandle_t hMaterial = FirstMaterial(); hMaterial != InvalidMaterial(); hMaterial = NextMaterial( hMaterial ) )
  3468. {
  3469. IMaterialInternal *pMaterial = GetMaterialInternal( hMaterial );
  3470. pMaterialList[numMaterials].pName = pMaterial->GetName();
  3471. pMaterialList[numMaterials].pShaderName = pMaterial->GetShader() ? pMaterial->GetShader()->GetName() : "???";
  3472. pMaterialList[numMaterials].refCount = pMaterial->GetReferenceCount();
  3473. numMaterials++;
  3474. }
  3475. XBX_rMaterialList( numMaterials, pMaterialList );
  3476. }
  3477. #endif
  3478. void CMaterialSystem::ToggleSuppressMaterial( char const* pMaterialName )
  3479. {
  3480. /*
  3481. // This version suppresses all but the material
  3482. IMaterial *pMaterial = GetFirstMaterial();
  3483. while (pMaterial)
  3484. {
  3485. if (stricmp(pMaterial->GetName(), pMaterialName))
  3486. {
  3487. IMaterialInternal* pMatInt = static_cast<IMaterialInternal*>(pMaterial);
  3488. pMatInt->ToggleSuppression();
  3489. }
  3490. pMaterial = GetNextMaterial();
  3491. }
  3492. */
  3493. // Note: if we use this function a lot, we'll want to do something else, like have them
  3494. // pass in a texture group or reuse whatever texture group the material already had.
  3495. // As it is, this is rarely used, so if it's not in TEXTURE_GROUP_OTHER, it'll go in
  3496. // TEXTURE_GROUP_SHARED.
  3497. IMaterial* pMaterial = FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER, true, NULL );
  3498. if ( !IsErrorMaterial( pMaterial ) )
  3499. {
  3500. IMaterialInternal* pMatInt = static_cast<IMaterialInternal*>(pMaterial);
  3501. pMatInt = pMatInt->GetRealTimeVersion(); //always work with the realtime material internally
  3502. pMatInt->ToggleSuppression();
  3503. }
  3504. }
  3505. void CMaterialSystem::ToggleDebugMaterial( char const* pMaterialName )
  3506. {
  3507. // Note: if we use this function a lot, we'll want to do something else, like have them
  3508. // pass in a texture group or reuse whatever texture group the material already had.
  3509. // As it is, this is rarely used, so if it's not in TEXTURE_GROUP_OTHER, it'll go in
  3510. // TEXTURE_GROUP_SHARED.
  3511. IMaterial* pMaterial = FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER, false, NULL );
  3512. if ( !IsErrorMaterial( pMaterial ) )
  3513. {
  3514. IMaterialInternal* pMatInt = static_cast<IMaterialInternal*>(pMaterial);
  3515. pMatInt = pMatInt->GetRealTimeVersion(); //always work with the realtime material internally
  3516. pMatInt->ToggleDebugTrace();
  3517. }
  3518. else
  3519. {
  3520. Warning("Unknown material %s\n", pMaterialName );
  3521. }
  3522. }
  3523. //-----------------------------------------------------------------------------
  3524. // Used to iterate over all shaders for editing purposes
  3525. //-----------------------------------------------------------------------------
  3526. int CMaterialSystem::ShaderCount() const
  3527. {
  3528. return ShaderSystem()->ShaderCount();
  3529. }
  3530. int CMaterialSystem::GetShaders( int nFirstShader, int nMaxCount, IShader **ppShaderList ) const
  3531. {
  3532. return ShaderSystem()->GetShaders( nFirstShader, nMaxCount, ppShaderList );
  3533. }
  3534. //-----------------------------------------------------------------------------
  3535. // FIXME: Is there a better way of doing this?
  3536. // Returns shader flag names for editors to be able to edit them
  3537. //-----------------------------------------------------------------------------
  3538. int CMaterialSystem::ShaderFlagCount() const
  3539. {
  3540. return ShaderSystem()->ShaderStateCount( );
  3541. }
  3542. const char *CMaterialSystem::ShaderFlagName( int nIndex ) const
  3543. {
  3544. return ShaderSystem()->ShaderStateString( nIndex );
  3545. }
  3546. //-----------------------------------------------------------------------------
  3547. // Returns the currently active shader fallback for a particular shader
  3548. //-----------------------------------------------------------------------------
  3549. void CMaterialSystem::GetShaderFallback( const char *pShaderName, char *pFallbackShader, int nFallbackLength )
  3550. {
  3551. // FIXME: This is pretty much a hack. We need a better way for the
  3552. // editor to get ahold of shader fallbacks
  3553. int nCount = ShaderCount();
  3554. IShader** ppShaderList = (IShader**)_alloca( nCount * sizeof(IShader) );
  3555. GetShaders( 0, nCount, ppShaderList );
  3556. do
  3557. {
  3558. int i;
  3559. for ( i = 0; i < nCount; ++i )
  3560. {
  3561. if ( !Q_stricmp( pShaderName, ppShaderList[i]->GetName() ) )
  3562. break;
  3563. }
  3564. // Didn't find a match!
  3565. if ( i == nCount )
  3566. {
  3567. Q_strncpy( pFallbackShader, "wireframe", nFallbackLength );
  3568. return;
  3569. }
  3570. // Found a match
  3571. // FIXME: Theoretically, getting fallbacks should require a param list
  3572. // In practice, it looks rare or maybe even neved done
  3573. const char *pFallback = ppShaderList[i]->GetFallbackShader( NULL );
  3574. if ( !pFallback )
  3575. {
  3576. Q_strncpy( pFallbackShader, pShaderName, nFallbackLength );
  3577. return;
  3578. }
  3579. else
  3580. {
  3581. pShaderName = pFallback;
  3582. }
  3583. } while (true);
  3584. }
  3585. //-----------------------------------------------------------------------------
  3586. // Triggers OpenGL shader preloading at game startup
  3587. //-----------------------------------------------------------------------------
  3588. #ifdef DX_TO_GL_ABSTRACTION
  3589. void CMaterialSystem::DoStartupShaderPreloading( void )
  3590. {
  3591. GetRenderContextInternal()->DoStartupShaderPreloading();
  3592. }
  3593. #endif
  3594. void CMaterialSystem::SwapBuffers( void )
  3595. {
  3596. VPROF_BUDGET( "CMaterialSystem::SwapBuffers", VPROF_BUDGETGROUP_SWAP_BUFFERS );
  3597. GetRenderContextInternal()->SwapBuffers();
  3598. g_FrameNum++;
  3599. }
  3600. bool CMaterialSystem::InEditorMode() const
  3601. {
  3602. Assert( m_bGeneratedConfig );
  3603. return g_config.bEditMode && CanUseEditorMaterials();
  3604. }
  3605. void CMaterialSystem::NoteAnisotropicLevel( int currentLevel )
  3606. {
  3607. Assert( m_bGeneratedConfig );
  3608. g_config.m_nForceAnisotropicLevel = currentLevel;
  3609. }
  3610. // Get the current config for this video card (as last set by control panel or the default if not)
  3611. const MaterialSystem_Config_t &CMaterialSystem::GetCurrentConfigForVideoCard() const
  3612. {
  3613. Assert( m_bGeneratedConfig );
  3614. return g_config;
  3615. }
  3616. // Does the device support the given MSAA level?
  3617. bool CMaterialSystem::SupportsMSAAMode( int nNumSamples )
  3618. {
  3619. return g_pShaderAPI->SupportsMSAAMode( nNumSamples );
  3620. }
  3621. void CMaterialSystem::ReloadFilesInList( IFileList *pFilesToReload )
  3622. {
  3623. if ( !IsPC() )
  3624. return;
  3625. // We have to flush the materials in 2 steps because they have recursive dependencies. The problem case
  3626. // is if you have two materials, A and B, that depend on C. You tell A to reload and it also reloads C. Then
  3627. // the filesystem thinks C doesn't need to be reloaded anymore. So when you get to B, it decides not to reload
  3628. // either since C doesn't need to be reloaded. To fix this, we ask all materials if they want to reload in
  3629. // one stage, then in the next stage we actually reload the appropriate ones.
  3630. MaterialHandle_t hNext;
  3631. for ( MaterialHandle_t h=m_MaterialDict.FirstMaterial(); h != m_MaterialDict.InvalidMaterial(); h=hNext )
  3632. {
  3633. hNext = m_MaterialDict.NextMaterial( h );
  3634. IMaterialInternal *pMat = m_MaterialDict.GetMaterialInternal( h );
  3635. pMat->DecideShouldReloadFromWhitelist( pFilesToReload );
  3636. }
  3637. // Now reload the materials that wanted to be reloaded.
  3638. for ( MaterialHandle_t h=m_MaterialDict.FirstMaterial(); h != m_MaterialDict.InvalidMaterial(); h=hNext )
  3639. {
  3640. hNext = m_MaterialDict.NextMaterial( h );
  3641. IMaterialInternal *pMat = m_MaterialDict.GetMaterialInternal( h );
  3642. pMat->ReloadFromWhitelistIfMarked();
  3643. }
  3644. // Flush out necessary textures.
  3645. TextureManager()->ReloadFilesInList( pFilesToReload );
  3646. }
  3647. // Does the device support the given CSAA level?
  3648. bool CMaterialSystem::SupportsCSAAMode( int nNumSamples, int nQualityLevel )
  3649. {
  3650. return g_pShaderAPI->SupportsCSAAMode( nNumSamples, nQualityLevel );
  3651. }
  3652. // Does the device support shadow depth texturing?
  3653. bool CMaterialSystem::SupportsShadowDepthTextures( void )
  3654. {
  3655. return g_pShaderAPI->SupportsShadowDepthTextures();
  3656. }
  3657. // Does the device support Fetch4
  3658. bool CMaterialSystem::SupportsFetch4( void )
  3659. {
  3660. return g_pShaderAPI->SupportsFetch4();
  3661. }
  3662. // Vendor-dependent shadow depth texture format
  3663. ImageFormat CMaterialSystem::GetShadowDepthTextureFormat( void )
  3664. {
  3665. return g_pShaderAPI->GetShadowDepthTextureFormat();
  3666. }
  3667. // Vendor-dependent slim texture format
  3668. ImageFormat CMaterialSystem::GetNullTextureFormat( void )
  3669. {
  3670. return g_pShaderAPI->GetNullTextureFormat();
  3671. }
  3672. void CMaterialSystem::SetShadowDepthBiasFactors( float fShadowSlopeScaleDepthBias, float fShadowDepthBias )
  3673. {
  3674. g_pShaderAPI->SetShadowDepthBiasFactors( fShadowSlopeScaleDepthBias, fShadowDepthBias );
  3675. }
  3676. bool CMaterialSystem::SupportsHDRMode( HDRType_t nHDRMode )
  3677. {
  3678. return HardwareConfig()->SupportsHDRMode( nHDRMode );
  3679. }
  3680. bool CMaterialSystem::UsesSRGBCorrectBlending( void ) const
  3681. {
  3682. return HardwareConfig()->UsesSRGBCorrectBlending();
  3683. }
  3684. // Get video card identitier
  3685. const MaterialSystemHardwareIdentifier_t &CMaterialSystem::GetVideoCardIdentifier( void ) const
  3686. {
  3687. static MaterialSystemHardwareIdentifier_t foo;
  3688. Assert( 0 );
  3689. return foo;
  3690. }
  3691. void CMaterialSystem::AddModeChangeCallBack( ModeChangeCallbackFunc_t func )
  3692. {
  3693. g_pShaderDeviceMgr->AddModeChangeCallback( func );
  3694. }
  3695. void CMaterialSystem::RemoveModeChangeCallBack( ModeChangeCallbackFunc_t func )
  3696. {
  3697. g_pShaderDeviceMgr->RemoveModeChangeCallback( func );
  3698. }
  3699. //-----------------------------------------------------------------------------
  3700. // Gets configuration information associated with the display card, and optionally for a particular DX level.
  3701. // It will return a list of ConVars and values to set.
  3702. //-----------------------------------------------------------------------------
  3703. bool CMaterialSystem::GetRecommendedConfigurationInfo( int nDXLevel, KeyValues *pKeyValues )
  3704. {
  3705. MaterialLock_t hLock = Lock();
  3706. bool bResult = g_pShaderDeviceMgr->GetRecommendedConfigurationInfo( m_nAdapter, nDXLevel, pKeyValues );
  3707. Unlock( hLock );
  3708. return bResult;
  3709. }
  3710. //-----------------------------------------------------------------------------
  3711. // For dealing with device lost in cases where SwapBuffers isn't called all the time (Hammer)
  3712. //-----------------------------------------------------------------------------
  3713. void CMaterialSystem::HandleDeviceLost()
  3714. {
  3715. if ( IsX360() )
  3716. return;
  3717. g_pShaderAPI->HandleDeviceLost();
  3718. }
  3719. bool CMaterialSystem::UsingFastClipping( void )
  3720. {
  3721. return (HardwareConfig()->UseFastClipping() || (HardwareConfig()->MaxUserClipPlanes() < 1));
  3722. };
  3723. int CMaterialSystem::StencilBufferBits( void )
  3724. {
  3725. return HardwareConfig()->StencilBufferBits();
  3726. }
  3727. ITexture* CMaterialSystem::CreateRenderTargetTexture(
  3728. int w,
  3729. int h,
  3730. RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change).
  3731. ImageFormat format,
  3732. MaterialRenderTargetDepth_t depth )
  3733. {
  3734. return CreateNamedRenderTargetTextureEx( NULL, w, h, sizeMode, format, depth, TEXTUREFLAGS_CLAMPS|TEXTUREFLAGS_CLAMPT, 0 );
  3735. }
  3736. ITexture* CMaterialSystem::CreateNamedRenderTargetTexture(
  3737. const char *pRTName,
  3738. int w,
  3739. int h,
  3740. RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change).
  3741. ImageFormat format,
  3742. MaterialRenderTargetDepth_t depth,
  3743. bool bClampTexCoords,
  3744. bool bAutoMipMap )
  3745. {
  3746. unsigned int textureFlags = 0;
  3747. if ( bClampTexCoords )
  3748. {
  3749. textureFlags |= TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT;
  3750. }
  3751. unsigned int renderTargetFlags = 0;
  3752. if ( bAutoMipMap )
  3753. {
  3754. renderTargetFlags |= CREATERENDERTARGETFLAGS_AUTOMIPMAP;
  3755. }
  3756. return CreateNamedRenderTargetTextureEx( pRTName, w, h, sizeMode, format, depth, textureFlags, renderTargetFlags );
  3757. }
  3758. ITexture* CMaterialSystem::CreateNamedRenderTargetTextureEx(
  3759. const char *pRTName,
  3760. int w,
  3761. int h,
  3762. RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change).
  3763. ImageFormat format,
  3764. MaterialRenderTargetDepth_t depth,
  3765. unsigned int textureFlags,
  3766. unsigned int renderTargetFlags )
  3767. {
  3768. RenderTargetType_t rtType;
  3769. bool gl_canMixTargetSizes = (HardwareConfig() && HardwareConfig()->SupportsGLMixedSizeTargets());
  3770. // On GL, the depth buffer for a render target must be the same size (until we pick up mixed-sized attachments in 10.6.3)
  3771. if ( (!gl_canMixTargetSizes && IsPosix()) || IsEmulatingGL() )
  3772. {
  3773. if ( depth != MATERIAL_RT_DEPTH_SEPARATE && depth != MATERIAL_RT_DEPTH_NONE )
  3774. {
  3775. int fbWidth, fbHeight;
  3776. g_pShaderAPI->GetBackBufferDimensions( fbWidth, fbHeight );
  3777. if ( sizeMode != RT_SIZE_FULL_FRAME_BUFFER )
  3778. {
  3779. if ( w != fbWidth || h != fbHeight )
  3780. {
  3781. depth = MATERIAL_RT_DEPTH_SEPARATE;
  3782. }
  3783. }
  3784. }
  3785. }
  3786. // Determine RT type based on depth buffer requirements
  3787. switch ( depth )
  3788. {
  3789. case MATERIAL_RT_DEPTH_SEPARATE:
  3790. // using own depth buffer
  3791. rtType = RENDER_TARGET_WITH_DEPTH;
  3792. break;
  3793. case MATERIAL_RT_DEPTH_NONE:
  3794. // no depth buffer
  3795. rtType = RENDER_TARGET_NO_DEPTH;
  3796. break;
  3797. case MATERIAL_RT_DEPTH_ONLY:
  3798. // only depth buffer
  3799. rtType = RENDER_TARGET_ONLY_DEPTH;
  3800. break;
  3801. case MATERIAL_RT_DEPTH_SHARED:
  3802. default:
  3803. // using shared depth buffer
  3804. rtType = RENDER_TARGET;
  3805. break;
  3806. }
  3807. ITextureInternal* pTex = TextureManager()->CreateRenderTargetTexture( pRTName, w, h, sizeMode, format, rtType, textureFlags, renderTargetFlags );
  3808. pTex->IncrementReferenceCount();
  3809. #if defined( _X360 )
  3810. if ( !( renderTargetFlags & CREATERENDERTARGETFLAGS_NOEDRAM ) )
  3811. {
  3812. // create the EDRAM surface that is bound to the RT Texture
  3813. pTex->CreateRenderTargetSurface( 0, 0, IMAGE_FORMAT_UNKNOWN, true );
  3814. }
  3815. #endif
  3816. // If we're not in a BeginRenderTargetAllocation-EndRenderTargetAllocation block
  3817. // because we're being called by a legacy path (i.e. a mod), force an Alt-Tab after every
  3818. // RT allocation to ensure that all RTs get priority during allocation
  3819. if ( !m_bAllocatingRenderTargets )
  3820. {
  3821. EndRenderTargetAllocation();
  3822. }
  3823. return pTex;
  3824. }
  3825. //-----------------------------------------------------------------------------------------------------
  3826. // New version which must be called inside BeginRenderTargetAllocation-EndRenderTargetAllocation block
  3827. //-----------------------------------------------------------------------------------------------------
  3828. ITexture *CMaterialSystem::CreateNamedRenderTargetTextureEx2(
  3829. const char *pRTName,
  3830. int w,
  3831. int h,
  3832. RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change).
  3833. ImageFormat format,
  3834. MaterialRenderTargetDepth_t depth,
  3835. unsigned int textureFlags,
  3836. unsigned int renderTargetFlags )
  3837. {
  3838. // Only proceed if we are between BeginRenderTargetAllocation and EndRenderTargetAllocation
  3839. if ( !m_bAllocatingRenderTargets )
  3840. {
  3841. Warning( "Tried to create render target outside of CMaterialSystem::BeginRenderTargetAllocation/EndRenderTargetAllocation block\n" );
  3842. return NULL;
  3843. }
  3844. ITexture* pTexture = CreateNamedRenderTargetTextureEx( pRTName, w, h, sizeMode, format, depth, textureFlags, renderTargetFlags );
  3845. pTexture->DecrementReferenceCount(); // Follow the same convention as CTextureManager::LoadTexture (return refcount of 0).
  3846. return pTexture;
  3847. }
  3848. class CTextureBitsRegenerator : public ITextureRegenerator
  3849. {
  3850. public:
  3851. CTextureBitsRegenerator( int w, int h, int mips, ImageFormat fmt, int srcBufferSize, byte* srcBits )
  3852. : m_nWidth( w )
  3853. , m_nHeight( h )
  3854. , m_nMipmaps( mips )
  3855. , m_ImageFormat( fmt )
  3856. {
  3857. Assert( srcBits );
  3858. Assert( srcBufferSize > 0 );
  3859. Assert( m_nMipmaps != 0 );
  3860. // If these fail, we'll crash later, so look to before here for the problem.
  3861. Assert( ImageLoader::GetMemRequired( w, h, 1, fmt, m_nMipmaps > 1 ? true : false ) <= srcBufferSize );
  3862. Assert( m_nMipmaps == 1 || m_nMipmaps == ImageLoader::GetNumMipMapLevels( m_nWidth, m_nHeight, 1 ) );
  3863. m_ImageData.EnsureCapacity( srcBufferSize );
  3864. Q_memcpy( m_ImageData.Base(), srcBits, srcBufferSize );
  3865. }
  3866. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
  3867. {
  3868. Assert( pVTFTexture->FrameCount() == 1 );
  3869. Assert( pVTFTexture->FaceCount() == 1 );
  3870. int destWidth, destHeight, destDepth;
  3871. pVTFTexture->ComputeMipLevelDimensions( 0, &destWidth, &destHeight, &destDepth );
  3872. Assert( destDepth == 1 );
  3873. Assert( destWidth <= m_nWidth && destHeight <= m_nHeight );
  3874. unsigned char* pDest = pVTFTexture->ImageData();
  3875. ImageFormat destFmt = pVTFTexture->Format();
  3876. if ( destFmt == m_ImageFormat && destWidth == m_nWidth && destHeight == m_nHeight )
  3877. {
  3878. Q_memcpy( pDest, m_ImageData.Base(), m_ImageData.NumAllocated() );
  3879. }
  3880. else
  3881. {
  3882. int srcResX = m_nWidth;
  3883. int srcResY = m_nHeight;
  3884. int srcOffset = 0;
  3885. int dstOffset = 0;
  3886. int mip = 0;
  3887. // Skip the mips we're not including.
  3888. while ( mip < m_nMipmaps && ( srcResX > destWidth || srcResY > destHeight ) )
  3889. {
  3890. srcOffset += ImageLoader::GetMemRequired( srcResX, srcResY, 1, m_ImageFormat, false );
  3891. srcResX = Max( 1, ( srcResX >> 1 ) );
  3892. srcResY = Max( 1, ( srcResY >> 1 ) );
  3893. mip++;
  3894. }
  3895. // Assert we're where we expect to be now.
  3896. Assert( srcResX == destWidth && srcResY == destHeight );
  3897. for ( ; mip < m_nMipmaps; ++mip )
  3898. {
  3899. // Convert this mipmap level.
  3900. ImageLoader::ConvertImageFormat( m_ImageData.Base() + srcOffset, m_ImageFormat, pDest + dstOffset, destFmt, srcResX, srcResY );
  3901. // Then update offsets for the next mipmap level.
  3902. srcOffset += ImageLoader::GetMemRequired( srcResX, srcResY, 1, m_ImageFormat, false );
  3903. dstOffset += ImageLoader::GetMemRequired( srcResX, srcResY, 1, destFmt, false );
  3904. srcResX = Max( 1, ( srcResX >> 1 ) );
  3905. srcResY = Max( 1, ( srcResY >> 1 ) );
  3906. }
  3907. }
  3908. }
  3909. virtual void Release()
  3910. {
  3911. delete this;
  3912. }
  3913. private:
  3914. int m_nWidth;
  3915. int m_nHeight;
  3916. int m_nMipmaps;
  3917. ImageFormat m_ImageFormat;
  3918. CUtlMemory<byte> m_ImageData;
  3919. };
  3920. ITexture* CMaterialSystem::CreateTextureFromBits(int w, int h, int mips, ImageFormat fmt, int srcBufferSize, byte* srcBits)
  3921. {
  3922. int flags = TEXTUREFLAGS_SINGLECOPY
  3923. | ( mips > 1
  3924. ? TEXTUREFLAGS_ALL_MIPS
  3925. : TEXTUREFLAGS_NOMIP )
  3926. ;
  3927. return CreateNamedTextureFromBitsEx( "frombits", TEXTURE_GROUP_OTHER, w, h, mips, fmt, srcBufferSize, srcBits, flags );
  3928. }
  3929. void CMaterialSystem::OverrideRenderTargetAllocation( bool rtAlloc )
  3930. {
  3931. m_bAllocatingRenderTargets = rtAlloc;
  3932. }
  3933. ITextureCompositor* CMaterialSystem::NewTextureCompositor( int w, int h, const char* pCompositeName, int nTeamNum, uint64 randomSeed, KeyValues* stageDesc, uint32 texCompositeCreateFlags )
  3934. {
  3935. return CreateTextureCompositor( w, h, pCompositeName, nTeamNum, randomSeed, stageDesc, texCompositeCreateFlags );
  3936. }
  3937. void CMaterialSystem::ScheduleTextureComposite( CTextureCompositor* _texCompositor )
  3938. {
  3939. Assert( _texCompositor != NULL );
  3940. _texCompositor->AddRef();
  3941. m_scheduledComposites.AddToTail( _texCompositor );
  3942. }
  3943. void CMaterialSystem::AsyncFindTexture( const char* pFilename, const char *pTextureGroupName, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs, bool bComplain, int nAdditionalCreationFlags )
  3944. {
  3945. Assert( pFilename != NULL );
  3946. Assert( pTextureGroupName != NULL );
  3947. Assert( pRecipient != NULL );
  3948. // Bump the ref count on the recipient before handing it off. This ensures the receiver won't go away before we have completed our work.
  3949. pRecipient->AddRef();
  3950. TextureManager()->AsyncFindOrLoadTexture( pFilename, pTextureGroupName, pRecipient, pExtraArgs, bComplain, nAdditionalCreationFlags );
  3951. }
  3952. // creates a texture suitable for use with materials from a raw stream of bits.
  3953. // The bits will be retained by the material system and can be freed upon return.
  3954. ITexture *CMaterialSystem::CreateNamedTextureFromBitsEx( const char* pName, const char *pTextureGroupName, int w, int h, int mips, ImageFormat fmt, int srcBufferSize, byte* srcBits, int nFlags )
  3955. {
  3956. Assert( srcBits );
  3957. CTextureBitsRegenerator* regen = new CTextureBitsRegenerator( w, h, mips, fmt, srcBufferSize, srcBits );
  3958. ITextureInternal* tex = TextureManager()->CreateProceduralTexture( pName, pTextureGroupName, w, h, 1, fmt, nFlags, regen );
  3959. return tex;
  3960. }
  3961. bool CMaterialSystem::AddTextureCompositorTemplate( const char* pName, KeyValues* pTmplDesc, int /* nTexCompositeTemplateFlags */ )
  3962. {
  3963. // Flags are currently unused, but added for futureproofing.
  3964. return TextureManager()->AddTextureCompositorTemplate( pName, pTmplDesc );
  3965. }
  3966. bool CMaterialSystem::VerifyTextureCompositorTemplates()
  3967. {
  3968. return TextureManager()->VerifyTextureCompositorTemplates();
  3969. }
  3970. void CMaterialSystem::BeginRenderTargetAllocation( void )
  3971. {
  3972. g_pShaderAPI->FlushBufferedPrimitives();
  3973. m_bAllocatingRenderTargets = true;
  3974. }
  3975. void CMaterialSystem::EndRenderTargetAllocation( void )
  3976. {
  3977. // Any GPU newer than 2005 doesn't need to do this, and it eats up ~40% of our level load time!
  3978. const bool cbRequiresRenderTargetAllocationFirst = mat_requires_rt_alloc_first.GetBool();
  3979. g_pShaderAPI->FlushBufferedPrimitives();
  3980. m_bAllocatingRenderTargets = false;
  3981. if ( IsPC() && cbRequiresRenderTargetAllocationFirst && g_pShaderAPI->CanDownloadTextures() )
  3982. {
  3983. // Simulate an Alt-Tab...will cause RTs to be allocated first
  3984. g_pShaderDevice->ReleaseResources();
  3985. g_pShaderDevice->ReacquireResources();
  3986. }
  3987. TextureManager()->CacheExternalStandardRenderTargets();
  3988. }
  3989. void CMaterialSystem::SetRenderTargetFrameBufferSizeOverrides( int nWidth, int nHeight )
  3990. {
  3991. m_nRenderTargetFrameBufferWidthOverride = nWidth;
  3992. m_nRenderTargetFrameBufferHeightOverride = nHeight;
  3993. }
  3994. void CMaterialSystem::GetRenderTargetFrameBufferDimensions( int & nWidth, int & nHeight )
  3995. {
  3996. if( m_nRenderTargetFrameBufferHeightOverride && m_nRenderTargetFrameBufferWidthOverride )
  3997. {
  3998. nWidth = m_nRenderTargetFrameBufferWidthOverride;
  3999. nHeight = m_nRenderTargetFrameBufferHeightOverride;
  4000. }
  4001. else
  4002. {
  4003. GetBackBufferDimensions( nWidth, nHeight );
  4004. }
  4005. }
  4006. //-----------------------------------------------------------------------------------------------------
  4007. //
  4008. //-----------------------------------------------------------------------------------------------------
  4009. void CMaterialSystem::UpdateLightmap( int lightmapPageID, int lightmapSize[2],
  4010. int offsetIntoLightmapPage[2],
  4011. float *pFloatImage, float *pFloatImageBump1,
  4012. float *pFloatImageBump2, float *pFloatImageBump3 )
  4013. {
  4014. CMatCallQueue *pCallQueue = GetRenderCallQueue();
  4015. if ( !pCallQueue )
  4016. {
  4017. m_Lightmaps.UpdateLightmap( lightmapPageID, lightmapSize, offsetIntoLightmapPage, pFloatImage, pFloatImageBump1, pFloatImageBump2, pFloatImageBump3 );
  4018. }
  4019. else
  4020. {
  4021. ExecuteOnce( DebuggerBreakIfDebugging() );
  4022. }
  4023. }
  4024. //-----------------------------------------------------------------------------------------------------
  4025. // 360 TTF Font Support
  4026. //-----------------------------------------------------------------------------------------------------
  4027. #if defined( _X360 )
  4028. HXUIFONT CMaterialSystem::OpenTrueTypeFont( const char *pFontname, int tall, int style )
  4029. {
  4030. MaterialLock_t hLock = Lock();
  4031. HXUIFONT result = g_pShaderAPI->OpenTrueTypeFont( pFontname, tall, style );
  4032. Unlock( hLock );
  4033. return result;
  4034. }
  4035. void CMaterialSystem::CloseTrueTypeFont( HXUIFONT hFont )
  4036. {
  4037. MaterialLock_t hLock = Lock();
  4038. g_pShaderAPI->CloseTrueTypeFont( hFont );
  4039. Unlock( hLock );
  4040. }
  4041. bool CMaterialSystem::GetTrueTypeFontMetrics( HXUIFONT hFont, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] )
  4042. {
  4043. MaterialLock_t hLock = Lock();
  4044. bool result = g_pShaderAPI->GetTrueTypeFontMetrics( hFont, pFontMetrics, charMetrics );
  4045. Unlock( hLock );
  4046. return result;
  4047. }
  4048. bool CMaterialSystem::GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset )
  4049. {
  4050. MaterialLock_t hLock = Lock();
  4051. bool result = g_pShaderAPI->GetTrueTypeGlyphs( hFont, numChars, pWch, pOffsetX, pOffsetY, pWidth, pHeight, pRGBA, pRGBAOffset );
  4052. Unlock( hLock );
  4053. return result;
  4054. }
  4055. #endif
  4056. //-----------------------------------------------------------------------------------------------------
  4057. // 360 Back Buffer access. Due to hardware, RT data must be blitted from EDRAM
  4058. // and converted.
  4059. //-----------------------------------------------------------------------------------------------------
  4060. #if defined( _X360 )
  4061. void CMaterialSystem::ReadBackBuffer( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pDstData, ImageFormat dstFormat, int dstStride )
  4062. {
  4063. Assert( pSrcRect && pDstRect && pDstData );
  4064. int fbWidth, fbHeight;
  4065. g_pShaderAPI->GetBackBufferDimensions( fbWidth, fbHeight );
  4066. if ( pDstRect->width > fbWidth || pDstRect->height > fbHeight )
  4067. {
  4068. Assert( 0 );
  4069. return;
  4070. }
  4071. // intermediate results will be placed at (0,0)
  4072. Rect_t rect;
  4073. rect.x = 0;
  4074. rect.y = 0;
  4075. rect.width = pDstRect->width;
  4076. rect.height = pDstRect->height;
  4077. ITexture *pTempRT;
  4078. bool bStretch = ( pSrcRect->width != pDstRect->width || pSrcRect->height != pDstRect->height );
  4079. if ( !bStretch )
  4080. {
  4081. // hijack an unused RT (no surface required) for 1:1 resolve work, fastest path
  4082. pTempRT = FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  4083. }
  4084. else
  4085. {
  4086. // hijack an unused RT (with surface abilities) for stretch work, slower path
  4087. pTempRT = FindTexture( "_rt_WaterReflection", TEXTURE_GROUP_RENDER_TARGET );
  4088. }
  4089. Assert( !pTempRT->IsError() && pDstRect->width <= pTempRT->GetActualWidth() && pDstRect->height <= pTempRT->GetActualHeight() );
  4090. GetRenderContextInternal()->CopyRenderTargetToTextureEx( pTempRT, 0, pSrcRect, &rect );
  4091. // access the RT bits
  4092. CPixelWriter writer;
  4093. g_pShaderAPI->ModifyTexture( ((ITextureInternal*)pTempRT)->GetTextureHandle( 0 ) );
  4094. if ( !g_pShaderAPI->TexLock( 0, 0, 0, 0, pTempRT->GetActualWidth(), pTempRT->GetActualHeight(), writer ) )
  4095. return;
  4096. // this will be adequate for non-block formats
  4097. int srcStride = pTempRT->GetActualWidth() * ImageLoader::SizeInBytes( pTempRT->GetImageFormat() );
  4098. // untile intermediate RT in place to achieve linear access
  4099. XGUntileTextureLevel(
  4100. pTempRT->GetActualWidth(),
  4101. pTempRT->GetActualHeight(),
  4102. 0,
  4103. XGGetGpuFormat( ImageLoader::ImageFormatToD3DFormat( pTempRT->GetImageFormat() ) ),
  4104. 0,
  4105. (char*)writer.GetPixelMemory(),
  4106. srcStride,
  4107. NULL,
  4108. writer.GetPixelMemory(),
  4109. NULL );
  4110. // swap back to x86 order as expected by image conversion
  4111. ImageLoader::ByteSwapImageData( (unsigned char*)writer.GetPixelMemory(), srcStride*pTempRT->GetActualHeight(), pTempRT->GetImageFormat() );
  4112. // convert to callers format
  4113. Assert( dstFormat == IMAGE_FORMAT_RGB888 );
  4114. ImageLoader::ConvertImageFormat( (unsigned char*)writer.GetPixelMemory(), pTempRT->GetImageFormat(), pDstData, dstFormat, pDstRect->width, pDstRect->height, srcStride, dstStride );
  4115. g_pShaderAPI->TexUnlock();
  4116. }
  4117. #endif
  4118. #if defined( _X360 )
  4119. void CMaterialSystem::PersistDisplay()
  4120. {
  4121. g_pShaderAPI->PersistDisplay();
  4122. }
  4123. #endif
  4124. #if defined( _X360 )
  4125. void *CMaterialSystem::GetD3DDevice()
  4126. {
  4127. return g_pShaderAPI->GetD3DDevice();
  4128. }
  4129. #endif
  4130. #if defined( _X360 )
  4131. bool CMaterialSystem::OwnGPUResources( bool bEnable )
  4132. {
  4133. return g_pShaderAPI->OwnGPUResources( bEnable );
  4134. }
  4135. #endif
  4136. //-----------------------------------------------------------------------------------------------------
  4137. //
  4138. //-----------------------------------------------------------------------------------------------------
  4139. class CThreadRelease : public CJob
  4140. {
  4141. virtual JobStatus_t DoExecute()
  4142. {
  4143. g_pShaderAPI->ReleaseThreadOwnership();
  4144. return JOB_OK;
  4145. }
  4146. };
  4147. void CMaterialSystem::ThreadRelease( )
  4148. {
  4149. if ( !m_bThreadHasOwnership )
  4150. {
  4151. return;
  4152. }
  4153. double flStartTime, flEndThreadRelease, flEndTime;
  4154. int do_report = mat_queue_report.GetInt();
  4155. if ( do_report )
  4156. {
  4157. flStartTime = Plat_FloatTime();
  4158. }
  4159. CJob *pActiveAsyncJob = new CThreadRelease();
  4160. IThreadPool *pThreadPool = CreateMatQueueThreadPool();
  4161. pThreadPool->AddJob( pActiveAsyncJob );
  4162. pActiveAsyncJob->WaitForFinish();
  4163. SafeRelease( pActiveAsyncJob );
  4164. if ( do_report )
  4165. {
  4166. flEndThreadRelease = Plat_FloatTime();
  4167. }
  4168. g_pShaderAPI->AcquireThreadOwnership();
  4169. m_bThreadHasOwnership = false;
  4170. m_ThreadOwnershipID = 0;
  4171. if ( do_report )
  4172. {
  4173. flEndTime = Plat_FloatTime();
  4174. double flResult = ( flEndTime - flStartTime ) * 1000.0;
  4175. if ( do_report == -1 || flResult > mat_queue_report.GetFloat() )
  4176. {
  4177. Color red( 200, 20, 20, 255 );
  4178. ConColorMsg( red, "CMaterialSystem::ThreadRelease: %0.2fms = Release:%0.2fms + Acquire:%0.2fms\n", flResult, ( flEndThreadRelease - flStartTime ) * 1000.0, ( flEndTime - flEndThreadRelease ) * 1000.0 );
  4179. }
  4180. }
  4181. }
  4182. void CMaterialSystem::ThreadAcquire( bool bForce )
  4183. {
  4184. if ( !bForce )
  4185. {
  4186. return;
  4187. }
  4188. double flStartTime, flEndTime;
  4189. int do_report = mat_queue_report.GetInt();
  4190. if ( do_report )
  4191. {
  4192. flStartTime = Plat_FloatTime();
  4193. }
  4194. g_pShaderAPI->ReleaseThreadOwnership();
  4195. CJob *pActiveAsyncJob = new CThreadAcquire();
  4196. IThreadPool *pThreadPool = CreateMatQueueThreadPool();
  4197. pThreadPool->AddJob( pActiveAsyncJob );
  4198. // while we could wait for this job to finish, there's no reason too
  4199. // pActiveAsyncJob->WaitForFinish();
  4200. SafeRelease( pActiveAsyncJob );
  4201. m_bThreadHasOwnership = true;
  4202. m_ThreadOwnershipID = ThreadGetCurrentId();
  4203. if ( do_report )
  4204. {
  4205. flEndTime = Plat_FloatTime();
  4206. double flResult = ( flEndTime - flStartTime ) * 1000.0;
  4207. if ( do_report == -1 || flResult > mat_queue_report.GetFloat() )
  4208. {
  4209. Color red( 200, 20, 20, 255 );
  4210. ConColorMsg( red, "CMaterialSystem::ThreadAcquire: %0.2fms\n", flResult );
  4211. }
  4212. }
  4213. }
  4214. //-----------------------------------------------------------------------------------------------------
  4215. //
  4216. //-----------------------------------------------------------------------------------------------------
  4217. MaterialLock_t CMaterialSystem::Lock()
  4218. {
  4219. double flStartTime;
  4220. int do_report = mat_queue_report.GetInt();
  4221. if ( do_report )
  4222. {
  4223. flStartTime = Plat_FloatTime();
  4224. }
  4225. IMatRenderContextInternal *pCurContext = GetRenderContextInternal();
  4226. #if 1 // Rick's optimization: not sure this is needed anymore
  4227. if ( pCurContext != &m_HardwareRenderContext && m_pActiveAsyncJob )
  4228. {
  4229. m_pActiveAsyncJob->WaitForFinish();
  4230. // threadsafety note: not releasing or nulling pointer.
  4231. }
  4232. if ( m_ThreadMode != MATERIAL_SINGLE_THREADED )
  4233. {
  4234. TelemetrySetLockName( TELEMETRY_LEVEL0, (char const *)&g_MatSysMutex, "MatSysMutex" );
  4235. tmTryLock( TELEMETRY_LEVEL0, (char const *)&g_MatSysMutex, "CMaterialSystem" );
  4236. g_MatSysMutex.Lock();
  4237. tmEndTryLock( TELEMETRY_LEVEL0, (char const *)&g_MatSysMutex, TMLR_SUCCESS );
  4238. tmSetLockState( TELEMETRY_LEVEL0, (char const *)&g_MatSysMutex, TMLS_LOCKED, "CMaterialSystem" );
  4239. }
  4240. #endif
  4241. MaterialLock_t hMaterialLock = (MaterialLock_t)pCurContext;
  4242. m_pRenderContext.Set( &m_HardwareRenderContext );
  4243. if ( m_ThreadMode != MATERIAL_SINGLE_THREADED )
  4244. {
  4245. g_pShaderAPI->SetDisallowAccess( false );
  4246. if ( pCurContext->GetCallQueueInternal() )
  4247. {
  4248. ThreadRelease();
  4249. }
  4250. }
  4251. g_pShaderAPI->ShaderLock();
  4252. if ( do_report )
  4253. {
  4254. double flEndTime = Plat_FloatTime();
  4255. double flResult = ( flEndTime - flStartTime ) * 1000.0;
  4256. if ( do_report == -1 || flResult > mat_queue_report.GetFloat() )
  4257. {
  4258. Color red( 200, 20, 20, 255 );
  4259. ConColorMsg( red, "*CMaterialSystem::Lock: %0.2fms\n", flResult );
  4260. }
  4261. }
  4262. return hMaterialLock;
  4263. }
  4264. //-----------------------------------------------------------------------------------------------------
  4265. //
  4266. //-----------------------------------------------------------------------------------------------------
  4267. void CMaterialSystem::Unlock( MaterialLock_t hMaterialLock )
  4268. {
  4269. double flStartTime;
  4270. int do_report = mat_queue_report.GetInt();
  4271. if ( do_report )
  4272. {
  4273. flStartTime = Plat_FloatTime();
  4274. }
  4275. IMatRenderContextInternal *pRenderContext = (IMatRenderContextInternal *)hMaterialLock;
  4276. m_pRenderContext.Set( pRenderContext );
  4277. g_pShaderAPI->ShaderUnlock();
  4278. #ifdef MAT_QUEUE_MODE_PROFILE
  4279. if ( m_ThreadMode == MATERIAL_QUEUED_SINGLE_THREADED )
  4280. {
  4281. g_pShaderAPI->SetDisallowAccess( true );
  4282. }
  4283. else
  4284. #endif
  4285. if ( m_ThreadMode == MATERIAL_QUEUED_THREADED )
  4286. {
  4287. if ( pRenderContext->GetCallQueueInternal() )
  4288. {
  4289. ThreadAcquire();
  4290. }
  4291. }
  4292. #if 1 // Rick's optimization: not sure this is needed anymore
  4293. if ( m_ThreadMode != MATERIAL_SINGLE_THREADED )
  4294. {
  4295. g_MatSysMutex.Unlock();
  4296. tmSetLockState( TELEMETRY_LEVEL0, (char const *)&g_MatSysMutex, TMLS_RELEASED, "CMaterialSystem" );
  4297. }
  4298. #endif
  4299. if ( do_report )
  4300. {
  4301. double flEndTime = Plat_FloatTime();
  4302. double flResult = ( flEndTime - flStartTime ) * 1000.0;
  4303. if ( do_report || flResult > mat_queue_report.GetFloat() )
  4304. {
  4305. Color red( 200, 20, 20, 255 );
  4306. ConColorMsg( red, "*CMaterialSystem::Unlock: %0.2fms\n", flResult );
  4307. }
  4308. }
  4309. }
  4310. //-----------------------------------------------------------------------------------------------------
  4311. //
  4312. //-----------------------------------------------------------------------------------------------------
  4313. CMatCallQueue *CMaterialSystem::GetRenderCallQueue()
  4314. {
  4315. IMatRenderContextInternal *pRenderContext = m_pRenderContext.Get();
  4316. return pRenderContext ? pRenderContext->GetCallQueueInternal() : NULL;
  4317. }
  4318. void CMaterialSystem::UnbindMaterial( IMaterial *pMaterial )
  4319. {
  4320. Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
  4321. if ( m_HardwareRenderContext.GetCurrentMaterial() == pMaterial )
  4322. {
  4323. m_HardwareRenderContext.Bind( g_pErrorMaterial, NULL );
  4324. }
  4325. }
  4326. class CReplacementProxy : public IMaterialProxy
  4327. {
  4328. public:
  4329. CReplacementProxy( void );
  4330. virtual ~CReplacementProxy( void );
  4331. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  4332. virtual void OnBind( void * );
  4333. virtual void Release( );
  4334. virtual IMaterial * GetMaterial( );
  4335. private:
  4336. IMaterial *m_pReplaceMaterial;
  4337. };
  4338. #define REPLACEMENT_NAME "_replacement"
  4339. //-----------------------------------------------------------------------------
  4340. // Purpose:
  4341. //-----------------------------------------------------------------------------
  4342. CReplacementProxy::CReplacementProxy( void ) : m_pReplaceMaterial ( NULL )
  4343. {
  4344. }
  4345. //-----------------------------------------------------------------------------
  4346. // Purpose:
  4347. //-----------------------------------------------------------------------------
  4348. CReplacementProxy::~CReplacementProxy( void )
  4349. {
  4350. }
  4351. //-----------------------------------------------------------------------------
  4352. // Purpose: Get pointer to the color value
  4353. // Input : *pMaterial -
  4354. //-----------------------------------------------------------------------------
  4355. bool CReplacementProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  4356. {
  4357. const char *pszFileName = pMaterial->GetName();
  4358. char szNewName[ MAX_PATH ];
  4359. V_sprintf_safe( szNewName, "%s" REPLACEMENT_NAME, pszFileName );
  4360. m_pReplaceMaterial = materials->CreateMaterial( szNewName, pKeyValues );
  4361. return true;
  4362. }
  4363. //-----------------------------------------------------------------------------
  4364. // Purpose:
  4365. // Input :
  4366. //-----------------------------------------------------------------------------
  4367. void CReplacementProxy::OnBind( void * )
  4368. {
  4369. }
  4370. void CReplacementProxy::Release( )
  4371. {
  4372. m_pReplaceMaterial->DecrementReferenceCount();
  4373. // Since we have a material-holding-a-material situation here, we need to nuke these if unreferenced to prevent the
  4374. // engine needing to double-call UncacheUnusedMaterials to actually get rid of all materials.
  4375. m_pReplaceMaterial->DeleteIfUnreferenced();
  4376. m_pReplaceMaterial = NULL;
  4377. }
  4378. IMaterial *CReplacementProxy::GetMaterial()
  4379. {
  4380. static ConVarRef localplayer_visionflags( "localplayer_visionflags" );
  4381. bool bVisionOverride = ( localplayer_visionflags.IsValid() && ( localplayer_visionflags.GetInt() & ( 0x01 ) ) ); // Pyro-vision Goggles
  4382. if ( bVisionOverride )
  4383. {
  4384. return m_pReplaceMaterial;
  4385. }
  4386. return NULL;
  4387. }
  4388. EXPOSE_INTERFACE( CReplacementProxy, IMaterialProxy, "replace_proxy" IMATERIAL_PROXY_INTERFACE_VERSION );
  4389. static const char *pszReplacementForceCopy[] =
  4390. {
  4391. "$nocull",
  4392. NULL
  4393. };
  4394. void CMaterialSystem::LoadReplacementMaterials()
  4395. {
  4396. const char* cLocation = "materials";
  4397. if ( CommandLine()->FindParm( "-matscan") ) {
  4398. ScanDirForReplacements( cLocation );
  4399. } else {
  4400. InitReplacementsFromFile( cLocation );
  4401. }
  4402. }
  4403. void CMaterialSystem::ScanDirForReplacements( const char *pszPathName )
  4404. {
  4405. char szBaseName[ MAX_PATH ];
  4406. V_sprintf_safe( szBaseName, "%s/replacements.vmt", pszPathName );
  4407. if ( g_pFullFileSystem->FileExists( szBaseName ) )
  4408. {
  4409. KeyValues *pKV = g_pFullFileSystem->LoadKeyValues( IFileSystem::TYPE_VMT, szBaseName );
  4410. if ( pKV )
  4411. {
  4412. V_sprintf_safe( szBaseName, "%s/", pszPathName );
  4413. m_Replacements.Insert( szBaseName, pKV );
  4414. }
  4415. }
  4416. V_sprintf_safe( szBaseName, "%s/*", pszPathName );
  4417. FileFindHandle_t FindHandle;
  4418. const char *pFindFileName = g_pFullFileSystem->FindFirst( szBaseName, &FindHandle );
  4419. while ( pFindFileName && pFindFileName[ 0 ] != '\0' )
  4420. {
  4421. if ( g_pFullFileSystem->FindIsDirectory( FindHandle ) )
  4422. {
  4423. if ( strcmp( pFindFileName, "." ) != 0 && strcmp( pFindFileName, ".." ) != 0 )
  4424. {
  4425. char szNextBaseName[ MAX_PATH ];
  4426. V_sprintf_safe( szNextBaseName, "%s/%s", pszPathName, pFindFileName );
  4427. ScanDirForReplacements( szNextBaseName );
  4428. }
  4429. }
  4430. pFindFileName = g_pFullFileSystem->FindNext( FindHandle );
  4431. }
  4432. g_pFullFileSystem->FindClose( FindHandle );
  4433. }
  4434. void CMaterialSystem::InitReplacementsFromFile( const char *pszPathName )
  4435. {
  4436. CUtlVector<char*> replacementFiles;
  4437. char szBaseName[MAX_PATH];
  4438. V_sprintf_safe( szBaseName, "%s/replacements.txt", pszPathName );
  4439. int replacementCount = ReadListFromFile( &replacementFiles, szBaseName );
  4440. for ( int i = 0; i < replacementCount; ++i )
  4441. {
  4442. V_snprintf( szBaseName, sizeof(szBaseName), "%s/%s/replacements.vmt", pszPathName, replacementFiles[i] );
  4443. if ( g_pFullFileSystem->FileExists(szBaseName) )
  4444. {
  4445. KeyValues *pKV = g_pFullFileSystem->LoadKeyValues( IFileSystem::TYPE_VMT, szBaseName );
  4446. if (pKV)
  4447. {
  4448. V_sprintf_safe( szBaseName, "%s/%s/", pszPathName, replacementFiles[i] );
  4449. m_Replacements.Insert( szBaseName, pKV );
  4450. }
  4451. }
  4452. }
  4453. replacementFiles.PurgeAndDeleteElements();
  4454. }
  4455. void CMaterialSystem::PreloadReplacements( )
  4456. {
  4457. int nIndex = m_Replacements.First();
  4458. while( m_Replacements.IsValidIndex( nIndex ) )
  4459. {
  4460. m_Replacements.Element( nIndex )->deleteThis();
  4461. nIndex = m_Replacements.Next( nIndex );
  4462. }
  4463. m_Replacements.Purge();
  4464. COM_TimestampedLog( "LoadReplacementMaterials(): Begin" );
  4465. LoadReplacementMaterials();
  4466. COM_TimestampedLog( "LoadReplacementMaterials(): End" );
  4467. m_bReplacementFilesValid = true;
  4468. }
  4469. IMaterialProxy *CMaterialSystem::DetermineProxyReplacements( IMaterial *pMaterial, KeyValues *pFallbackKeyValues )
  4470. {
  4471. CReplacementProxy *pReplacementProxy = NULL;
  4472. if ( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_0() )
  4473. {
  4474. return NULL;
  4475. }
  4476. if ( !m_bReplacementFilesValid )
  4477. {
  4478. PreloadReplacements();
  4479. }
  4480. const char *pszMaterialName = pMaterial->GetName();
  4481. char szCheckPath[ MAX_PATH ], szCheckName[ MAX_PATH ], szLastPath[ MAX_PATH ];
  4482. const char *pszShadername = pFallbackKeyValues->GetName();
  4483. V_strcpy_safe( szLastPath, pszMaterialName );
  4484. int nLength = strlen( szLastPath ) - strlen( REPLACEMENT_NAME );
  4485. if ( nLength > 0 && strcmpi( &szLastPath[ nLength ], REPLACEMENT_NAME ) == 0 )
  4486. {
  4487. return NULL;
  4488. }
  4489. while( 1 )
  4490. {
  4491. const char *pszRemoveSlashes;
  4492. V_ExtractFilePath( szLastPath, szCheckPath, sizeof( szCheckPath ) );
  4493. pszRemoveSlashes = szCheckPath;
  4494. while ( ( *pszRemoveSlashes ) != 0 && ( ( *pszRemoveSlashes ) == '/' || ( *pszRemoveSlashes ) == '\\' ) )
  4495. {
  4496. pszRemoveSlashes++;
  4497. }
  4498. V_sprintf_safe( szCheckName, "materials/%s", pszRemoveSlashes );
  4499. int nIndex = m_Replacements.Find( szCheckName );
  4500. if ( m_Replacements.IsValidIndex( nIndex ) )
  4501. {
  4502. KeyValues *pKV = m_Replacements.Element( nIndex );
  4503. KeyValues *pTemplatesKV = pKV->FindKey( "templates" );
  4504. KeyValues *pPatternsKV = pKV->FindKey( "patterns" );
  4505. const char *pszFileName = V_GetFileName( pszMaterialName );
  4506. if ( !pTemplatesKV || !pPatternsKV )
  4507. {
  4508. Warning( "Replacements: Invalid KV file %s\n", szCheckName );
  4509. }
  4510. else
  4511. {
  4512. for ( KeyValues *pSubKey = pPatternsKV->GetFirstSubKey(); pSubKey; pSubKey = pSubKey->GetNextKey() )
  4513. {
  4514. const char *pszReplacementName = pSubKey->GetName();
  4515. // Msg( " Sub: %s\n", pSubKey->GetName() );
  4516. if ( strnicmp( pszFileName, pszReplacementName, strlen( pszReplacementName ) ) == 0 )
  4517. { // We found a replacement!
  4518. const char *pszTemplateName = pSubKey->GetString( "template", NULL );
  4519. KeyValues *pReplacementMaterial = NULL;
  4520. if ( pszTemplateName && pTemplatesKV )
  4521. {
  4522. KeyValues *pTemplateKV = pTemplatesKV->FindKey( pszTemplateName );
  4523. if ( pTemplateKV )
  4524. {
  4525. pTemplateKV = pTemplateKV->FindKey( pszShadername );
  4526. if ( pTemplateKV && pTemplateKV->GetFirstSubKey() )
  4527. {
  4528. pReplacementMaterial = pTemplateKV->GetFirstSubKey()->MakeCopy();
  4529. }
  4530. }
  4531. }
  4532. else
  4533. {
  4534. if ( pSubKey->GetFirstSubKey() )
  4535. {
  4536. pReplacementMaterial = pSubKey->GetFirstSubKey()->MakeCopy();
  4537. }
  4538. }
  4539. if ( !pReplacementMaterial )
  4540. {
  4541. break;
  4542. }
  4543. if ( pReplacementMaterial->GetInt( "$copyall" ) == 1 )
  4544. {
  4545. for( KeyValues *pCopyKV = pFallbackKeyValues->GetFirstSubKey(); pCopyKV; pCopyKV = pCopyKV->GetNextKey() )
  4546. {
  4547. const char *pszCopyValue = pReplacementMaterial->GetString( pCopyKV->GetName(), NULL );
  4548. if ( !pszCopyValue )
  4549. {
  4550. pReplacementMaterial->SetString( pCopyKV->GetName(), pCopyKV->GetString() );
  4551. }
  4552. }
  4553. }
  4554. else
  4555. {
  4556. int nReplaceIndex = 0;
  4557. while( pszReplacementForceCopy[nReplaceIndex] )
  4558. {
  4559. const char *pszCopyValue = pFallbackKeyValues->GetString( pszReplacementForceCopy[nReplaceIndex], NULL );
  4560. if ( pszCopyValue )
  4561. {
  4562. pReplacementMaterial->SetString( pszReplacementForceCopy[nReplaceIndex], pszCopyValue );
  4563. }
  4564. nReplaceIndex++;
  4565. }
  4566. }
  4567. for( KeyValues *pSearchKV = pReplacementMaterial->GetFirstSubKey(); pSearchKV; pSearchKV = pSearchKV->GetNextKey() )
  4568. {
  4569. const char *pszValue = pSearchKV->GetString();
  4570. if ( pszValue[ 0 ] == '$' )
  4571. {
  4572. const char *pszCopyValue = pFallbackKeyValues->GetString( pszValue, NULL );
  4573. if ( pszCopyValue )
  4574. {
  4575. pSearchKV->SetStringValue( pszCopyValue );
  4576. }
  4577. else
  4578. {
  4579. pSearchKV->SetStringValue( "" );
  4580. }
  4581. }
  4582. }
  4583. pReplacementProxy = new CReplacementProxy();
  4584. pReplacementProxy->Init( pMaterial, pReplacementMaterial );
  4585. break;
  4586. }
  4587. }
  4588. }
  4589. if ( pReplacementProxy == NULL )
  4590. {
  4591. // Msg( "Failed to find: %s\n", GetName() );
  4592. }
  4593. break;
  4594. }
  4595. if ( szCheckPath[ 0 ] == 0 )
  4596. {
  4597. break;
  4598. }
  4599. strcpy( szLastPath, szCheckPath );
  4600. }
  4601. return pReplacementProxy;
  4602. }
  4603. //-----------------------------------------------------------------------------
  4604. //
  4605. //-----------------------------------------------------------------------------
  4606. void CMaterialSystem::CompactMemory()
  4607. {
  4608. for ( int i = 0; i < ARRAYSIZE(m_QueuedRenderContexts); i++)
  4609. {
  4610. m_QueuedRenderContexts[i].CompactMemory();
  4611. }
  4612. }
  4613. void CMaterialSystem::OnRenderingAsyncComplete()
  4614. {
  4615. Assert( m_pActiveAsyncJob == NULL );
  4616. // Update the texture manager, which may cause some textures to become available for compositing.
  4617. // Because updating textures may cause textures to swap out their active texture handles, this can only be done
  4618. // while the async job is not running.
  4619. bool bThreadHadOwnership = m_bThreadHasOwnership;
  4620. TextureManager()->UpdatePostAsync();
  4621. if ( bThreadHadOwnership && !m_bThreadHasOwnership )
  4622. ThreadAcquire( true );
  4623. }
  4624. //-----------------------------------------------------------------------------
  4625. // Material + texture related commands
  4626. //-----------------------------------------------------------------------------
  4627. void CMaterialSystem::DebugPrintUsedMaterials( const CCommand &args )
  4628. {
  4629. if( args.ArgC() == 1 )
  4630. {
  4631. DebugPrintUsedMaterials( NULL, false );
  4632. }
  4633. else
  4634. {
  4635. DebugPrintUsedMaterials( args[ 1 ], false );
  4636. }
  4637. }
  4638. void CMaterialSystem::DebugPrintUsedMaterialsVerbose( const CCommand &args )
  4639. {
  4640. if( args.ArgC() == 1 )
  4641. {
  4642. DebugPrintUsedMaterials( NULL, true );
  4643. }
  4644. else
  4645. {
  4646. DebugPrintUsedMaterials( args[ 1 ], true );
  4647. }
  4648. }
  4649. void CMaterialSystem::DebugPrintUsedTextures( const CCommand &args )
  4650. {
  4651. DebugPrintUsedTextures();
  4652. }
  4653. #if defined( _X360 )
  4654. void CMaterialSystem::ListUsedMaterials( const CCommand &args )
  4655. {
  4656. ListUsedMaterials();
  4657. }
  4658. #endif // !_X360
  4659. void CMaterialSystem::ReloadAllMaterials( const CCommand &args )
  4660. {
  4661. ReloadMaterials( NULL );
  4662. }
  4663. void CMaterialSystem::ReloadMaterials( const CCommand &args )
  4664. {
  4665. if( args.ArgC() != 2 )
  4666. {
  4667. ConWarning( "Usage: mat_reloadmaterial material_name_substring\n"
  4668. " or mat_reloadmaterial substring1*substring2*...*substringN\n" );
  4669. return;
  4670. }
  4671. ReloadMaterials( args[ 1 ] );
  4672. }
  4673. void CMaterialSystem::ReloadTextures( const CCommand &args )
  4674. {
  4675. ReloadTextures();
  4676. }
  4677. CON_COMMAND( mat_hdr_enabled, "Report if HDR is enabled for debugging" )
  4678. {
  4679. if( HardwareConfig() && HardwareConfig()->GetHDREnabled() )
  4680. {
  4681. Warning( "HDR Enabled\n" );
  4682. }
  4683. else
  4684. {
  4685. Warning( "HDR Disabled\n" );
  4686. }
  4687. }
  4688. static int ReadListFromFile(CUtlVector<char*>* outReplacementMaterials, const char *pszPathName)
  4689. {
  4690. Assert(outReplacementMaterials != NULL);
  4691. Assert(pszPathName != NULL);
  4692. CUtlBuffer fileContents;
  4693. if ( !g_pFullFileSystem->ReadFile( pszPathName, NULL, fileContents ) )
  4694. return 0;
  4695. const char* seps[] = { "\r", "\r\n", "\n" };
  4696. V_SplitString2( (char*)fileContents.Base(), seps, ARRAYSIZE(seps), *outReplacementMaterials );
  4697. return outReplacementMaterials->Size();
  4698. }