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.

3102 lines
91 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <stdlib.h>
  7. #include <malloc.h>
  8. #include "materialsystem_global.h"
  9. #include "string.h"
  10. #include "shaderapi/ishaderapi.h"
  11. #include "materialsystem/materialsystem_config.h"
  12. #include "IHardwareConfigInternal.h"
  13. #include "texturemanager.h"
  14. #include "materialsystem/imaterialvar.h"
  15. #include "materialsystem/IColorCorrection.h"
  16. #include "tier1/strtools.h"
  17. #include "utlvector.h"
  18. #include "utldict.h"
  19. #include "itextureinternal.h"
  20. #include "vtf/vtf.h"
  21. #include "pixelwriter.h"
  22. #include "basetypes.h"
  23. #include "utlbuffer.h"
  24. #include "filesystem.h"
  25. #include "materialsystem/imesh.h"
  26. #include "materialsystem/ishaderapi.h"
  27. #include "vstdlib/random.h"
  28. #include "imorphinternal.h"
  29. #include "tier1/utlrbtree.h"
  30. #include "tier1/utlpair.h"
  31. #include "ctype.h"
  32. #include "utlqueue.h"
  33. #include "tier0/icommandline.h"
  34. #include "ctexturecompositor.h"
  35. #include "vprof_telemetry.h"
  36. // Need lightmaps access here
  37. #define MATSYS_INTERNAL
  38. #include "cmatlightmaps.h"
  39. #include "cmaterialsystem.h"
  40. #undef MATSYS_INTERNAL
  41. #include "tier0/memdbgon.h"
  42. #define ERROR_TEXTURE_SIZE 32
  43. #define WHITE_TEXTURE_SIZE 1
  44. #define BLACK_TEXTURE_SIZE 1
  45. #define GREY_TEXTURE_SIZE 1
  46. #define NORMALIZATION_CUBEMAP_SIZE 32
  47. struct AsyncLoadJob_t;
  48. struct AsyncReadJob_t;
  49. class AsyncLoader;
  50. class AsyncReader;
  51. #define MAX_READS_OUTSTANDING 2
  52. static ImageFormat GetImageFormatRawReadback( ImageFormat fmt );
  53. #ifdef STAGING_ONLY
  54. static ConVar mat_texture_list_dump( "mat_texture_list_dump", "0" );
  55. #endif
  56. const char* cTextureCachePathDir = "__texture_cache";
  57. // TODO: Relocate this somewhere else. It works like python's "strip" function,
  58. // removing leading and trailing whitespace, including newlines. Whitespace between
  59. // non-whitespace characters is preserved.
  60. void V_StripWhitespace( char* pBuffer )
  61. {
  62. Assert( pBuffer );
  63. char* pSrc = pBuffer;
  64. char* pDst = pBuffer;
  65. char* pDstFirstTrailingWhitespace = NULL;
  66. // Remove leading whitespace
  67. bool leading = true;
  68. while ( *pSrc )
  69. {
  70. if ( leading )
  71. {
  72. if ( V_isspace( *pSrc ) )
  73. {
  74. ++pSrc;
  75. continue;
  76. }
  77. else
  78. {
  79. leading = false;
  80. // Drop through
  81. }
  82. }
  83. if ( pDst != pSrc )
  84. *pDst = *pSrc;
  85. if ( !leading && V_isspace( *pDst ) && pDstFirstTrailingWhitespace == NULL )
  86. pDstFirstTrailingWhitespace = pDst;
  87. else if ( !leading && !V_isspace( *pDst ) && pDstFirstTrailingWhitespace != NULL )
  88. pDstFirstTrailingWhitespace = NULL;
  89. ++pSrc;
  90. ++pDst;
  91. }
  92. (*pDst) = 0;
  93. if ( pDstFirstTrailingWhitespace )
  94. ( *pDstFirstTrailingWhitespace ) = 0;
  95. }
  96. //-----------------------------------------------------------------------------
  97. //
  98. // Various procedural texture regeneration classes
  99. //
  100. //-----------------------------------------------------------------------------
  101. //-----------------------------------------------------------------------------
  102. // Creates a checkerboard texture
  103. //-----------------------------------------------------------------------------
  104. class CCheckerboardTexture : public ITextureRegenerator
  105. {
  106. public:
  107. CCheckerboardTexture( int nCheckerSize, color32 color1, color32 color2 ) :
  108. m_nCheckerSize( nCheckerSize ), m_Color1(color1), m_Color2(color2)
  109. {
  110. }
  111. virtual ~CCheckerboardTexture() { }
  112. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  113. {
  114. for (int iFrame = 0; iFrame < pVTFTexture->FrameCount(); ++iFrame )
  115. {
  116. for (int iFace = 0; iFace < pVTFTexture->FaceCount(); ++iFace )
  117. {
  118. int nWidth = pVTFTexture->Width();
  119. int nHeight = pVTFTexture->Height();
  120. int nDepth = pVTFTexture->Depth();
  121. for (int z = 0; z < nDepth; ++z)
  122. {
  123. // Fill mip 0 with a checkerboard
  124. CPixelWriter pixelWriter;
  125. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  126. pVTFTexture->ImageData( iFrame, iFace, 0, 0, 0, z ), pVTFTexture->RowSizeInBytes( 0 ) );
  127. for (int y = 0; y < nHeight; ++y)
  128. {
  129. pixelWriter.Seek( 0, y );
  130. for (int x = 0; x < nWidth; ++x)
  131. {
  132. if ( ((x & m_nCheckerSize) ^ (y & m_nCheckerSize)) ^ (z & m_nCheckerSize) )
  133. {
  134. pixelWriter.WritePixel( m_Color1.r, m_Color1.g, m_Color1.b, m_Color1.a );
  135. }
  136. else
  137. {
  138. pixelWriter.WritePixel( m_Color2.r, m_Color2.g, m_Color2.b, m_Color2.a );
  139. }
  140. }
  141. }
  142. }
  143. }
  144. }
  145. }
  146. virtual void Release()
  147. {
  148. delete this;
  149. }
  150. private:
  151. int m_nCheckerSize;
  152. color32 m_Color1;
  153. color32 m_Color2;
  154. };
  155. static void CreateCheckerboardTexture( ITextureInternal *pTexture, int nCheckerSize, color32 color1, color32 color2 )
  156. {
  157. ITextureRegenerator *pRegen = new CCheckerboardTexture( nCheckerSize, color1, color2 );
  158. pTexture->SetTextureRegenerator( pRegen );
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Creates a solid texture
  162. //-----------------------------------------------------------------------------
  163. class CSolidTexture : public ITextureRegenerator
  164. {
  165. public:
  166. CSolidTexture( color32 color ) : m_Color(color)
  167. {
  168. }
  169. virtual ~CSolidTexture() { }
  170. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  171. {
  172. int nMipCount = pTexture->IsMipmapped() ? pVTFTexture->MipCount() : 1;
  173. for (int iFrame = 0; iFrame < pVTFTexture->FrameCount(); ++iFrame )
  174. {
  175. for (int iFace = 0; iFace < pVTFTexture->FaceCount(); ++iFace )
  176. {
  177. for (int iMip = 0; iMip < nMipCount; ++iMip )
  178. {
  179. int nWidth, nHeight, nDepth;
  180. pVTFTexture->ComputeMipLevelDimensions( iMip, &nWidth, &nHeight, &nDepth );
  181. for (int z = 0; z < nDepth; ++z)
  182. {
  183. CPixelWriter pixelWriter;
  184. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  185. pVTFTexture->ImageData( iFrame, iFace, iMip, 0, 0, z ), pVTFTexture->RowSizeInBytes( iMip ) );
  186. for (int y = 0; y < nHeight; ++y)
  187. {
  188. pixelWriter.Seek( 0, y );
  189. for (int x = 0; x < nWidth; ++x)
  190. {
  191. pixelWriter.WritePixel( m_Color.r, m_Color.g, m_Color.b, m_Color.a );
  192. }
  193. }
  194. }
  195. }
  196. }
  197. }
  198. }
  199. virtual void Release()
  200. {
  201. delete this;
  202. }
  203. private:
  204. color32 m_Color;
  205. };
  206. static void CreateSolidTexture( ITextureInternal *pTexture, color32 color )
  207. {
  208. ITextureRegenerator *pRegen = new CSolidTexture( color );
  209. pTexture->SetTextureRegenerator( pRegen );
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Creates a normalization cubemap texture
  213. //-----------------------------------------------------------------------------
  214. class CNormalizationCubemap : public ITextureRegenerator
  215. {
  216. public:
  217. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  218. {
  219. // Normalization cubemap doesn't make sense on low-end hardware
  220. // So we won't construct a spheremap out of this
  221. CPixelWriter pixelWriter;
  222. Vector direction;
  223. for (int iFace = 0; iFace < 6; ++iFace)
  224. {
  225. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  226. pVTFTexture->ImageData( 0, iFace, 0 ), pVTFTexture->RowSizeInBytes( 0 ) );
  227. int nWidth = pVTFTexture->Width();
  228. int nHeight = pVTFTexture->Height();
  229. float flInvWidth = 2.0f / (float)(nWidth-1);
  230. float flInvHeight = 2.0f / (float)(nHeight-1);
  231. for (int y = 0; y < nHeight; ++y)
  232. {
  233. float v = y * flInvHeight - 1.0f;
  234. pixelWriter.Seek( 0, y );
  235. for (int x = 0; x < nWidth; ++x)
  236. {
  237. float u = x * flInvWidth - 1.0f;
  238. float oow = 1.0f / sqrt( 1.0f + u*u + v*v );
  239. int ix = (int)(255.0f * 0.5f * (u*oow + 1.0f) + 0.5f);
  240. ix = clamp( ix, 0, 255 );
  241. int iy = (int)(255.0f * 0.5f * (v*oow + 1.0f) + 0.5f);
  242. iy = clamp( iy, 0, 255 );
  243. int iz = (int)(255.0f * 0.5f * (oow + 1.0f) + 0.5f);
  244. iz = clamp( iz, 0, 255 );
  245. switch (iFace)
  246. {
  247. case CUBEMAP_FACE_RIGHT:
  248. pixelWriter.WritePixel( iz, 255 - iy, 255 - ix, 255 );
  249. break;
  250. case CUBEMAP_FACE_LEFT:
  251. pixelWriter.WritePixel( 255 - iz, 255 - iy, ix, 255 );
  252. break;
  253. case CUBEMAP_FACE_BACK:
  254. pixelWriter.WritePixel( ix, iz, iy, 255 );
  255. break;
  256. case CUBEMAP_FACE_FRONT:
  257. pixelWriter.WritePixel( ix, 255 - iz, 255 - iy, 255 );
  258. break;
  259. case CUBEMAP_FACE_UP:
  260. pixelWriter.WritePixel( ix, 255 - iy, iz, 255 );
  261. break;
  262. case CUBEMAP_FACE_DOWN:
  263. pixelWriter.WritePixel( 255 - ix, 255 - iy, 255 - iz, 255 );
  264. break;
  265. default:
  266. break;
  267. }
  268. }
  269. }
  270. }
  271. }
  272. // NOTE: The normalization cubemap regenerator is stateless
  273. // so there's no need to allocate + deallocate them
  274. virtual void Release() {}
  275. };
  276. //-----------------------------------------------------------------------------
  277. // Creates a normalization cubemap texture
  278. //-----------------------------------------------------------------------------
  279. class CSignedNormalizationCubemap : public ITextureRegenerator
  280. {
  281. public:
  282. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  283. {
  284. // Normalization cubemap doesn't make sense on low-end hardware
  285. // So we won't construct a spheremap out of this
  286. CPixelWriter pixelWriter;
  287. Vector direction;
  288. for (int iFace = 0; iFace < 6; ++iFace)
  289. {
  290. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  291. pVTFTexture->ImageData( 0, iFace, 0 ), pVTFTexture->RowSizeInBytes( 0 ) );
  292. int nWidth = pVTFTexture->Width();
  293. int nHeight = pVTFTexture->Height();
  294. float flInvWidth = 2.0f / (float)(nWidth-1);
  295. float flInvHeight = 2.0f / (float)(nHeight-1);
  296. for (int y = 0; y < nHeight; ++y)
  297. {
  298. float v = y * flInvHeight - 1.0f;
  299. pixelWriter.Seek( 0, y );
  300. for (int x = 0; x < nWidth; ++x)
  301. {
  302. float u = x * flInvWidth - 1.0f;
  303. float oow = 1.0f / sqrt( 1.0f + u*u + v*v );
  304. #ifdef DX_TO_GL_ABSTRACTION
  305. float flX = (255.0f * 0.5 * (u*oow + 1.0f) + 0.5f);
  306. float flY = (255.0f * 0.5 * (v*oow + 1.0f) + 0.5f);
  307. float flZ = (255.0f * 0.5 * (oow + 1.0f) + 0.5f);
  308. switch (iFace)
  309. {
  310. case CUBEMAP_FACE_RIGHT:
  311. flX = 255.0f - flX;
  312. flY = 255.0f - flY;
  313. break;
  314. case CUBEMAP_FACE_LEFT:
  315. flY = 255.0f - flY;
  316. flZ = 255.0f - flZ;
  317. break;
  318. case CUBEMAP_FACE_BACK:
  319. break;
  320. case CUBEMAP_FACE_FRONT:
  321. flY = 255.0f - flY;
  322. flZ = 255.0f - flZ;
  323. break;
  324. case CUBEMAP_FACE_UP:
  325. flY = 255.0f - flY;
  326. break;
  327. case CUBEMAP_FACE_DOWN:
  328. flX = 255.0f - flX;
  329. flY = 255.0f - flY;
  330. flZ = 255.0f - flZ;
  331. break;
  332. default:
  333. break;
  334. }
  335. flX -= 128.0f;
  336. flY -= 128.0f;
  337. flZ -= 128.0f;
  338. flX /= 128.0f;
  339. flY /= 128.0f;
  340. flZ /= 128.0f;
  341. switch ( iFace )
  342. {
  343. case CUBEMAP_FACE_RIGHT:
  344. pixelWriter.WritePixelF( flZ, flY, flX, 0.0f );
  345. break;
  346. case CUBEMAP_FACE_LEFT:
  347. pixelWriter.WritePixelF( flZ, flY, flX, 0.0f );
  348. break;
  349. case CUBEMAP_FACE_BACK:
  350. pixelWriter.WritePixelF( flX, flZ, flY, 0.0f );
  351. break;
  352. case CUBEMAP_FACE_FRONT:
  353. pixelWriter.WritePixelF( flX, flZ, flY, 0.0f );
  354. break;
  355. case CUBEMAP_FACE_UP:
  356. pixelWriter.WritePixelF( flX, flY, flZ, 0.0f );
  357. break;
  358. case CUBEMAP_FACE_DOWN:
  359. pixelWriter.WritePixelF( flX, flY, flZ, 0.0f );
  360. break;
  361. default:
  362. break;
  363. }
  364. #else
  365. int ix = (int)(255 * 0.5 * (u*oow + 1.0f) + 0.5f);
  366. ix = clamp( ix, 0, 255 );
  367. int iy = (int)(255 * 0.5 * (v*oow + 1.0f) + 0.5f);
  368. iy = clamp( iy, 0, 255 );
  369. int iz = (int)(255 * 0.5 * (oow + 1.0f) + 0.5f);
  370. iz = clamp( iz, 0, 255 );
  371. switch (iFace)
  372. {
  373. case CUBEMAP_FACE_RIGHT:
  374. ix = 255 - ix;
  375. iy = 255 - iy;
  376. break;
  377. case CUBEMAP_FACE_LEFT:
  378. iy = 255 - iy;
  379. iz = 255 - iz;
  380. break;
  381. case CUBEMAP_FACE_BACK:
  382. break;
  383. case CUBEMAP_FACE_FRONT:
  384. iy = 255 - iy;
  385. iz = 255 - iz;
  386. break;
  387. case CUBEMAP_FACE_UP:
  388. iy = 255 - iy;
  389. break;
  390. case CUBEMAP_FACE_DOWN:
  391. ix = 255 - ix;
  392. iy = 255 - iy;
  393. iz = 255 - iz;
  394. break;
  395. default:
  396. break;
  397. }
  398. ix -= 128;
  399. iy -= 128;
  400. iz -= 128;
  401. Assert( ix >= -128 && ix <= 127 );
  402. Assert( iy >= -128 && iy <= 127 );
  403. Assert( iz >= -128 && iz <= 127 );
  404. switch (iFace)
  405. {
  406. case CUBEMAP_FACE_RIGHT:
  407. // correct
  408. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  409. pixelWriter.WritePixelSigned( iz, iy, ix, 0 );
  410. break;
  411. case CUBEMAP_FACE_LEFT:
  412. // correct
  413. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  414. pixelWriter.WritePixelSigned( iz, iy, ix, 0 );
  415. break;
  416. case CUBEMAP_FACE_BACK:
  417. // wrong
  418. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  419. pixelWriter.WritePixelSigned( ix, iz, iy, 0 );
  420. // pixelWriter.WritePixelSigned( -127, -127, 127, 0 );
  421. break;
  422. case CUBEMAP_FACE_FRONT:
  423. // wrong
  424. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  425. pixelWriter.WritePixelSigned( ix, iz, iy, 0 );
  426. break;
  427. case CUBEMAP_FACE_UP:
  428. // correct
  429. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  430. pixelWriter.WritePixelSigned( ix, iy, iz, 0 );
  431. break;
  432. case CUBEMAP_FACE_DOWN:
  433. // correct
  434. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  435. pixelWriter.WritePixelSigned( ix, iy, iz, 0 );
  436. break;
  437. default:
  438. break;
  439. }
  440. #endif
  441. } // x
  442. } // y
  443. } // iFace
  444. }
  445. // NOTE: The normalization cubemap regenerator is stateless
  446. // so there's no need to allocate + deallocate them
  447. virtual void Release() {}
  448. };
  449. static void CreateNormalizationCubemap( ITextureInternal *pTexture )
  450. {
  451. // NOTE: The normalization cubemap regenerator is stateless
  452. // so there's no need to allocate + deallocate them
  453. static CNormalizationCubemap s_NormalizationCubemap;
  454. pTexture->SetTextureRegenerator( &s_NormalizationCubemap );
  455. }
  456. static void CreateSignedNormalizationCubemap( ITextureInternal *pTexture )
  457. {
  458. // NOTE: The normalization cubemap regenerator is stateless
  459. // so there's no need to allocate + deallocate them
  460. static CSignedNormalizationCubemap s_SignedNormalizationCubemap;
  461. pTexture->SetTextureRegenerator( &s_SignedNormalizationCubemap );
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Creates a color correction texture
  465. //-----------------------------------------------------------------------------
  466. class CColorCorrectionTexture : public ITextureRegenerator
  467. {
  468. public:
  469. CColorCorrectionTexture( ColorCorrectionHandle_t handle ) : m_ColorCorrectionHandle(handle)
  470. {
  471. }
  472. virtual ~CColorCorrectionTexture() { }
  473. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  474. {
  475. int nWidth = pVTFTexture->Width();
  476. int nHeight = pVTFTexture->Height();
  477. int nDepth = pVTFTexture->Depth();
  478. Assert( nWidth == COLOR_CORRECTION_TEXTURE_SIZE && nHeight == COLOR_CORRECTION_TEXTURE_SIZE && nDepth == COLOR_CORRECTION_TEXTURE_SIZE );
  479. for ( int z = 0; z < nDepth; ++z )
  480. {
  481. CPixelWriter pixelWriter;
  482. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  483. pVTFTexture->ImageData( 0, 0, 0, 0, 0, z ), pVTFTexture->RowSizeInBytes( 0 ) );
  484. for ( int y = 0; y < nHeight; ++y )
  485. {
  486. pixelWriter.Seek( 0, y );
  487. for (int x = 0; x < nWidth; ++x)
  488. {
  489. RGBX5551_t inColor;
  490. inColor.r = x;
  491. inColor.g = y;
  492. inColor.b = z;
  493. color24 col = ColorCorrectionSystem()->GetLookup( m_ColorCorrectionHandle, inColor );
  494. pixelWriter.WritePixel( col.r, col.g, col.b, 255 );
  495. }
  496. }
  497. }
  498. }
  499. virtual void Release()
  500. {
  501. delete this;
  502. }
  503. private:
  504. ColorCorrectionHandle_t m_ColorCorrectionHandle;
  505. };
  506. void CreateColorCorrectionTexture( ITextureInternal *pTexture, ColorCorrectionHandle_t handle )
  507. {
  508. ITextureRegenerator *pRegen = new CColorCorrectionTexture( handle );
  509. pTexture->SetTextureRegenerator( pRegen );
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Implementation of the texture manager
  513. //-----------------------------------------------------------------------------
  514. class CTextureManager : public ITextureManager
  515. {
  516. public:
  517. CTextureManager( void );
  518. // Initialization + shutdown
  519. virtual void Init( int nFlags ) OVERRIDE;
  520. virtual void Shutdown();
  521. virtual void AllocateStandardRenderTargets( );
  522. virtual void FreeStandardRenderTargets();
  523. virtual void CacheExternalStandardRenderTargets();
  524. virtual ITextureInternal *CreateProceduralTexture( const char *pTextureName, const char *pTextureGroupName, int w, int h, int d, ImageFormat fmt, int nFlags, ITextureRegenerator* generator = NULL );
  525. virtual ITextureInternal *FindOrLoadTexture( const char *textureName, const char *pTextureGroupName, int nAdditionalCreationFlags = 0 );
  526. virtual bool IsTextureLoaded( const char *pTextureName );
  527. virtual void AddTextureAlias( const char *pAlias, const char *pRealName );
  528. virtual void RemoveTextureAlias( const char *pAlias );
  529. virtual void SetExcludedTextures( const char *pScriptName );
  530. virtual void UpdateExcludedTextures();
  531. virtual void ResetTextureFilteringState();
  532. void ReloadTextures( void );
  533. // These are used when we lose our video memory due to a mode switch etc
  534. void ReleaseTextures( void );
  535. void RestoreNonRenderTargetTextures( void );
  536. void RestoreRenderTargets( void );
  537. // Suspend or resume texture streaming requests
  538. void SuspendTextureStreaming( void );
  539. void ResumeTextureStreaming( void );
  540. // delete any texture that has a refcount <= 0
  541. void RemoveUnusedTextures( void );
  542. void DebugPrintUsedTextures( void );
  543. // Request a texture ID
  544. virtual int RequestNextTextureID();
  545. // Get at a couple standard textures
  546. virtual ITextureInternal *ErrorTexture();
  547. virtual ITextureInternal *NormalizationCubemap();
  548. virtual ITextureInternal *SignedNormalizationCubemap();
  549. virtual ITextureInternal *ShadowNoise2D();
  550. virtual ITextureInternal *IdentityLightWarp();
  551. virtual ITextureInternal *ColorCorrectionTexture( int i );
  552. virtual ITextureInternal *FullFrameDepthTexture();
  553. virtual ITextureInternal *DebugLuxels2D();
  554. // Generates an error texture pattern
  555. virtual void GenerateErrorTexture( ITexture *pTexture, IVTFTexture *pVTFTexture );
  556. // Updates the color correction state
  557. virtual void SetColorCorrectionTexture( int i, ITextureInternal *pTexture );
  558. virtual void ForceAllTexturesIntoHardware( void );
  559. virtual ITextureInternal *CreateRenderTargetTexture(
  560. const char *pRTName, // NULL for auto-generated name
  561. int w,
  562. int h,
  563. RenderTargetSizeMode_t sizeMode,
  564. ImageFormat fmt,
  565. RenderTargetType_t type,
  566. unsigned int textureFlags,
  567. unsigned int renderTargetFlags );
  568. virtual bool HasPendingTextureDestroys() const;
  569. virtual void MarkUnreferencedTextureForCleanup( ITextureInternal *pTexture );
  570. virtual void RemoveTexture( ITextureInternal *pTexture );
  571. virtual void ReloadFilesInList( IFileList *pFilesToReload );
  572. // start with -1, list terminates with -1
  573. virtual int FindNext( int iIndex, ITextureInternal **ppTexture );
  574. virtual void ReleaseTempRenderTargetBits( void );
  575. // Called once per frame by material system "somewhere."
  576. virtual void Update();
  577. // Load a texture asynchronously and then call the provided callback.
  578. virtual void AsyncFindOrLoadTexture( const char *pTextureName, const char *pTextureGroupName, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs, bool bComplain, int nAdditionalCreationFlags );
  579. void CompleteAsyncLoad( AsyncLoadJob_t* pJob );
  580. virtual void AsyncCreateTextureFromRenderTarget( ITexture* pSrcRt, const char* pDstName, ImageFormat dstFmt, bool bGenMips, int nAdditionalCreationFlags, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs );
  581. void CompleteAsyncRead( AsyncReadJob_t* pJob );
  582. ITextureInternal* AcquireReadbackTexture( int w, int h, ImageFormat fmt );
  583. void ReleaseReadbackTexture( ITextureInternal* pTex );
  584. void WarmTextureCache();
  585. void CoolTextureCache();
  586. virtual void RequestAllMipmaps( ITextureInternal* pTex );
  587. virtual void EvictAllTextures();
  588. virtual void UpdatePostAsync();
  589. virtual void ReleaseAsyncScratchVTF( IVTFTexture* pScratchVTF );
  590. virtual bool ThreadInAsyncLoadThread() const;
  591. virtual bool ThreadInAsyncReadThread() const;
  592. virtual bool AddTextureCompositorTemplate( const char* pName, KeyValues* pTmplDesc ) OVERRIDE;
  593. virtual bool VerifyTextureCompositorTemplates() OVERRIDE;
  594. virtual CTextureCompositorTemplate* FindTextureCompositorTemplate( const char* pName ) OVERRIDE;
  595. protected:
  596. ITextureInternal *FindTexture( const char *textureName );
  597. ITextureInternal *LoadTexture( const char *textureName, const char *pTextureGroupName, int nAdditionalCreationFlags = 0, bool bDownload = true );
  598. void AsyncLoad( const AsyncLoadJob_t& job );
  599. void AsyncReadTexture( AsyncReadJob_t* job );
  600. // Restores a single texture
  601. void RestoreTexture( ITextureInternal* pTex );
  602. void CleanupPossiblyUnreferencedTextures();
  603. #ifdef STAGING_ONLY
  604. void DumpTextureList( );
  605. #endif
  606. void FindFilesToLoad( CUtlDict< int >* pOutFilesToLoad, const char* pFilename );
  607. void ReadFilesToLoad( CUtlDict< int >* pOutFilesToLoad, const char* pFilename );
  608. CUtlDict< ITextureInternal *, unsigned short > m_TextureList;
  609. CUtlDict< const char *, unsigned short > m_TextureAliases;
  610. CUtlDict< int, unsigned short > m_TextureExcludes;
  611. CUtlDict< CCopyableUtlVector<AsyncLoadJob_t> > m_PendingAsyncLoads;
  612. CUtlVector< ITextureInternal* > m_ReadbackTextures;
  613. CUtlVector< ITextureInternal* > m_preloadedTextures;
  614. CUtlMap< ITextureInternal*, int > m_textureStreamingRequests;
  615. CTSQueue< ITextureInternal* > m_asyncStreamingRequests;
  616. CTSQueue< ITextureInternal * > m_PossiblyUnreferencedTextures;
  617. CUtlDict< CTextureCompositorTemplate *, unsigned short > m_TexCompTemplates;
  618. int m_iNextTexID;
  619. int m_nFlags;
  620. ITextureInternal *m_pErrorTexture;
  621. ITextureInternal *m_pBlackTexture;
  622. ITextureInternal *m_pWhiteTexture;
  623. ITextureInternal *m_pGreyTexture;
  624. ITextureInternal *m_pGreyAlphaZeroTexture;
  625. ITextureInternal *m_pNormalizationCubemap;
  626. ITextureInternal *m_pFullScreenTexture;
  627. ITextureInternal *m_pSignedNormalizationCubemap;
  628. ITextureInternal *m_pShadowNoise2D;
  629. ITextureInternal *m_pIdentityLightWarp;
  630. ITextureInternal *m_pColorCorrectionTextures[ COLOR_CORRECTION_MAX_TEXTURES ];
  631. ITextureInternal *m_pFullScreenDepthTexture;
  632. ITextureInternal *m_pDebugLuxels2D;
  633. // Used to generate various error texture patterns when necessary
  634. CCheckerboardTexture *m_pErrorRegen;
  635. friend class AsyncLoader;
  636. AsyncLoader* m_pAsyncLoader;
  637. friend class AsyncReader;
  638. AsyncReader* m_pAsyncReader;
  639. uint m_nAsyncLoadThread;
  640. uint m_nAsyncReadThread;
  641. int m_iSuspendTextureStreaming;
  642. };
  643. //-----------------------------------------------------------------------------
  644. // Singleton instance
  645. //-----------------------------------------------------------------------------
  646. static CTextureManager s_TextureManager;
  647. ITextureManager *g_pTextureManager = &s_TextureManager;
  648. struct AsyncLoadJob_t
  649. {
  650. CUtlString m_TextureName;
  651. CUtlString m_TextureGroupName;
  652. IAsyncTextureOperationReceiver* m_pRecipient;
  653. void* m_pExtraArgs;
  654. bool m_bComplain;
  655. int m_nAdditionalCreationFlags;
  656. ITextureInternal* m_pResultData;
  657. AsyncLoadJob_t()
  658. : m_pRecipient( NULL )
  659. , m_pExtraArgs( NULL )
  660. , m_bComplain( false )
  661. , m_nAdditionalCreationFlags( 0 )
  662. , m_pResultData( NULL )
  663. { }
  664. AsyncLoadJob_t( const char *pTextureName, const char *pTextureGroupName, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs, bool bComplain, int nAdditionalCreationFlags )
  665. : m_TextureName( pTextureName )
  666. , m_TextureGroupName( pTextureGroupName )
  667. , m_pRecipient( pRecipient )
  668. , m_pExtraArgs( pExtraArgs )
  669. , m_bComplain( bComplain )
  670. , m_nAdditionalCreationFlags( nAdditionalCreationFlags )
  671. , m_pResultData( NULL )
  672. {
  673. }
  674. };
  675. class CAsyncCopyRequest : public IAsyncTextureOperationReceiver
  676. {
  677. public:
  678. CAsyncCopyRequest()
  679. : m_nReferenceCount( 0 )
  680. , m_bSignalled( false )
  681. { }
  682. virtual ~CAsyncCopyRequest() { }
  683. virtual int AddRef() OVERRIDE{ return ++m_nReferenceCount; }
  684. virtual int Release() OVERRIDE
  685. {
  686. int retVal = --m_nReferenceCount;
  687. if ( retVal == 0 )
  688. delete this;
  689. return retVal;
  690. }
  691. virtual int GetRefCount() const OVERRIDE{ return m_nReferenceCount; }
  692. virtual void OnAsyncCreateComplete( ITexture* pTex, void* pExtraArgs ) OVERRIDE { }
  693. virtual void OnAsyncFindComplete( ITexture* pTex, void* pExtraArgs ) OVERRIDE { }
  694. virtual void OnAsyncMapComplete( ITexture* pTex, void* pExtraArgs, void* pMemory, int nPitch ) OVERRIDE { }
  695. virtual void OnAsyncReadbackBegin( ITexture* pDst, ITexture* pSrc, void* pExtraArgs ) OVERRIDE
  696. {
  697. m_bSignalled = true;
  698. }
  699. bool IsSignalled() const { return m_bSignalled; }
  700. private:
  701. CInterlockedInt m_nReferenceCount;
  702. volatile bool m_bSignalled;
  703. };
  704. class CAsyncMapResult : public IAsyncTextureOperationReceiver
  705. {
  706. public:
  707. CAsyncMapResult( ITextureInternal* pTex )
  708. : m_pTexToMap( pTex )
  709. , m_nReferenceCount( 0 )
  710. , m_pMemory( NULL )
  711. , m_nPitch( 0 )
  712. , m_bSignalled( false )
  713. { }
  714. virtual ~CAsyncMapResult() { }
  715. virtual int AddRef() OVERRIDE { return ++m_nReferenceCount; }
  716. virtual int Release() OVERRIDE
  717. {
  718. int retVal = --m_nReferenceCount;
  719. if ( retVal == 0 )
  720. delete this;
  721. return retVal;
  722. }
  723. virtual int GetRefCount() const OVERRIDE{ return m_nReferenceCount; }
  724. virtual void OnAsyncCreateComplete( ITexture* pTex, void* pExtraArgs ) OVERRIDE { }
  725. virtual void OnAsyncFindComplete( ITexture* pTex, void* pExtraArgs ) OVERRIDE { }
  726. virtual void OnAsyncMapComplete( ITexture* pTex, void* pExtraArgs, void* pMemory, int nPitch ) OVERRIDE
  727. {
  728. Assert( pTex == m_pTexToMap );
  729. m_pMemory = pMemory;
  730. m_nPitch = nPitch;
  731. m_bSignalled = true;
  732. }
  733. virtual void OnAsyncReadbackBegin( ITexture* pDst, ITexture* pSrc, void* pExtraArgs ) OVERRIDE { }
  734. bool IsSignalled() const { return m_bSignalled; }
  735. ITextureInternal* const m_pTexToMap;
  736. CInterlockedInt m_nReferenceCount;
  737. volatile void* m_pMemory;
  738. volatile int m_nPitch;
  739. private:
  740. volatile bool m_bSignalled;
  741. };
  742. struct AsyncReadJob_t
  743. {
  744. ITexture* m_pSrcRt;
  745. ITextureInternal* m_pSysmemTex;
  746. CAsyncCopyRequest* m_pAsyncRead;
  747. CAsyncMapResult* m_pAsyncMap;
  748. const char* m_pDstName;
  749. ImageFormat m_dstFmt;
  750. bool m_bGenMips;
  751. int m_nAdditionalCreationFlags;
  752. IAsyncTextureOperationReceiver* m_pRecipient;
  753. void* m_pExtraArgs;
  754. CUtlMemory<unsigned char> m_finalTexelData;
  755. AsyncReadJob_t()
  756. : m_pSrcRt( NULL )
  757. , m_pSysmemTex( NULL )
  758. , m_pAsyncRead( NULL )
  759. , m_pAsyncMap( NULL )
  760. , m_pDstName( NULL )
  761. , m_dstFmt( IMAGE_FORMAT_UNKNOWN )
  762. , m_bGenMips( false )
  763. , m_nAdditionalCreationFlags( 0 )
  764. , m_pRecipient( NULL )
  765. , m_pExtraArgs( NULL )
  766. { }
  767. AsyncReadJob_t( ITexture* pSrcRt, const char* pDstName, ImageFormat dstFmt, bool bGenMips, int nAdditionalCreationFlags, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
  768. : m_pSrcRt( pSrcRt )
  769. , m_pSysmemTex( NULL )
  770. , m_pAsyncRead( NULL )
  771. , m_pAsyncMap( NULL )
  772. , m_pDstName( pDstName ) // We take ownership of this string.
  773. , m_dstFmt( dstFmt )
  774. , m_bGenMips( bGenMips )
  775. , m_nAdditionalCreationFlags( nAdditionalCreationFlags )
  776. , m_pRecipient( pRecipient )
  777. , m_pExtraArgs( pExtraArgs )
  778. {
  779. }
  780. ~AsyncReadJob_t()
  781. {
  782. Assert( ThreadInMainThread() );
  783. delete [] m_pDstName;
  784. SafeRelease( &m_pRecipient );
  785. if ( m_pSysmemTex )
  786. {
  787. if ( m_pAsyncMap )
  788. {
  789. extern CMaterialSystem g_MaterialSystem;
  790. g_MaterialSystem.GetRenderContextInternal()->AsyncUnmap( m_pSysmemTex );
  791. }
  792. assert_cast< CTextureManager* >( g_pTextureManager )->ReleaseReadbackTexture( m_pSysmemTex );
  793. m_pSysmemTex = NULL;
  794. }
  795. SafeRelease( &m_pAsyncMap );
  796. }
  797. };
  798. bool IsJobCancelled( AsyncReadJob_t* pJob )
  799. {
  800. Assert( pJob != NULL );
  801. // The texture manager holds a reference to the object, so if we're the only one who is holding a ref
  802. // then the job has been abandoned. This gives us the opportunity to cleanup and skip some work.
  803. if ( pJob->m_pRecipient->GetRefCount() == 1 )
  804. {
  805. return true;
  806. }
  807. return false;
  808. }
  809. bool IsJobCancelled( AsyncLoadJob_t* pJob )
  810. {
  811. Assert( pJob != NULL );
  812. // The texture manager holds a reference to the object, so if we're the only one who is holding a ref
  813. // then the job has been abandoned. This gives us the opportunity to cleanup and skip some work.
  814. if ( pJob->m_pRecipient->GetRefCount() == 1 )
  815. {
  816. return true;
  817. }
  818. return false;
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Functions can be called from any thread, unless they are prefixed with a thread name.
  822. class AsyncLoader
  823. {
  824. public:
  825. AsyncLoader()
  826. : m_bQuit( false )
  827. {
  828. for ( int i = 0; i < MAX_READS_OUTSTANDING; ++i )
  829. {
  830. m_asyncScratchVTFs.PushItem( CreateVTFTexture() );
  831. }
  832. // Do this after everything else.
  833. m_LoaderThread = CreateSimpleThread( AsyncLoader::LoaderMain, this );
  834. }
  835. ~AsyncLoader()
  836. {
  837. Assert( m_asyncScratchVTFs.Count() == MAX_READS_OUTSTANDING );
  838. while ( m_asyncScratchVTFs.Count() > 0 )
  839. {
  840. IVTFTexture* pScratchVTF = NULL;
  841. m_asyncScratchVTFs.PopItem( &pScratchVTF );
  842. delete pScratchVTF;
  843. }
  844. }
  845. void AsyncLoad( const AsyncLoadJob_t& job )
  846. {
  847. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  848. // TODO: This could be made faster by keeping a pool of these things.
  849. m_pendingJobs.PushItem( new AsyncLoadJob_t( job ) );
  850. }
  851. void Shutdown()
  852. {
  853. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  854. m_bQuit = true;
  855. ThreadJoin( m_LoaderThread );
  856. }
  857. void ThreadMain_Update()
  858. {
  859. Assert( ThreadInMainThread() );
  860. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  861. AsyncLoadJob_t *pJob = NULL;
  862. if ( m_completedJobs.PopItem( &pJob ) )
  863. {
  864. Assert( pJob != NULL );
  865. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - CompleteAsyncLoad", __FUNCTION__ );
  866. // Complete the load, then make the callback.
  867. assert_cast< CTextureManager* >( g_pTextureManager )->CompleteAsyncLoad( pJob );
  868. delete pJob;
  869. pJob = NULL;
  870. }
  871. }
  872. void ReleaseAsyncReadBuffer( IVTFTexture *pScratchVTF )
  873. {
  874. Assert( pScratchVTF != NULL );
  875. m_asyncScratchVTFs.PushItem( pScratchVTF );
  876. }
  877. private:
  878. inline bool ThreadInLoaderThread()
  879. {
  880. return s_TextureManager.ThreadInAsyncLoadThread();
  881. }
  882. void ThreadLoader_Main( )
  883. {
  884. Assert( ThreadInLoaderThread() );
  885. while ( !m_bQuit )
  886. {
  887. AsyncLoadJob_t *pJob = NULL;
  888. IVTFTexture *pScratchVTF = NULL;
  889. while ( !m_pendingJobs.PopItem( &pJob ) )
  890. {
  891. // "awhile"
  892. ThreadSleep( 8 );
  893. if ( m_bQuit )
  894. return;
  895. }
  896. Assert( pJob != NULL );
  897. while ( !m_asyncScratchVTFs.PopItem( &pScratchVTF ) )
  898. {
  899. // Also awhile, but not as long..
  900. ThreadSleep( 4 );
  901. if ( m_bQuit )
  902. return;
  903. }
  904. Assert( pScratchVTF != NULL );
  905. ThreadLoader_ProcessLoad( pJob, pScratchVTF );
  906. }
  907. }
  908. void ThreadLoader_ProcessLoad( AsyncLoadJob_t *pJob, IVTFTexture* pScratchVTF )
  909. {
  910. Assert( ThreadInLoaderThread() );
  911. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  912. Assert( pJob->m_pResultData );
  913. if ( !pJob->m_pResultData->AsyncReadTextureFromFile( pScratchVTF, pJob->m_nAdditionalCreationFlags ) )
  914. m_asyncScratchVTFs.PushItem( pScratchVTF );
  915. m_completedJobs.PushItem( pJob );
  916. }
  917. static unsigned LoaderMain( void* _this )
  918. {
  919. ThreadSetDebugName( "Loader" );
  920. s_TextureManager.m_nAsyncLoadThread = ThreadGetCurrentId();
  921. ( ( AsyncLoader* )_this )->ThreadLoader_Main();
  922. s_TextureManager.m_nAsyncLoadThread = 0xFFFFFFFF;
  923. return 0;
  924. }
  925. ThreadHandle_t m_LoaderThread;
  926. volatile bool m_bQuit;
  927. CTSQueue< AsyncLoadJob_t *> m_pendingJobs;
  928. CTSQueue< AsyncLoadJob_t *> m_completedJobs;
  929. CTSQueue< IVTFTexture *> m_asyncScratchVTFs;
  930. };
  931. //-----------------------------------------------------------------------------
  932. // Functions can be called from any thread, unless they are prefixed with a thread name.
  933. class AsyncReader
  934. {
  935. public:
  936. AsyncReader()
  937. : m_bQuit( false )
  938. {
  939. // Do this after everything else.
  940. m_HelperThread = CreateSimpleThread( AsyncReader::ReaderMain, this );
  941. }
  942. void AsyncReadback( AsyncReadJob_t* job )
  943. {
  944. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  945. m_requestedCopies.PushItem( job );
  946. }
  947. void Shutdown()
  948. {
  949. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  950. m_bQuit = true;
  951. ThreadJoin( m_HelperThread );
  952. }
  953. void ThreadMain_Update()
  954. {
  955. Assert( ThreadInMainThread() );
  956. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  957. while ( !m_queuedMaps.IsEmpty() )
  958. {
  959. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CompleteMap" );
  960. AsyncReadJob_t* pMapped = m_queuedMaps.Head();
  961. Assert( pMapped != NULL );
  962. {
  963. if ( IsJobCancelled( pMapped ) )
  964. {
  965. // Remove the head, which is pMapped
  966. m_queuedMaps.RemoveAtHead();
  967. delete pMapped;
  968. continue;
  969. }
  970. if ( pMapped->m_pAsyncMap->IsSignalled() )
  971. {
  972. if ( pMapped->m_pAsyncMap->m_pMemory != 0 && pMapped->m_pAsyncMap->m_nPitch != 0 )
  973. {
  974. // Stick it in the queue for the other thread to work on it.
  975. m_pendingJobs.PushItem( pMapped );
  976. }
  977. else
  978. {
  979. Assert( !"Failed to perform a map that shouldn't fail, need to deal with this if it ever happens." );
  980. DevWarning( "Failed to perform a map that shouldn't fail, need to deal with this if it ever happens." );
  981. }
  982. // Remove the head, which is pMapped
  983. m_queuedMaps.RemoveAtHead();
  984. }
  985. // Stop as soon as we complete one, regardless of success.
  986. break;
  987. }
  988. }
  989. // This is ugly, but basically we need to do map and unmap on the main thread. Other
  990. // stuff can (mostly) happen on the async thread
  991. while ( !m_queuedReads.IsEmpty() )
  992. {
  993. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CompleteQueuedRead" );
  994. AsyncReadJob_t* pRead = NULL;
  995. if ( m_queuedReads.RemoveAtHead( pRead ) )
  996. {
  997. if ( IsJobCancelled( pRead ) )
  998. {
  999. delete pRead;
  1000. continue;
  1001. }
  1002. SafeAssign( &pRead->m_pAsyncMap, new CAsyncMapResult( pRead->m_pSysmemTex ) );
  1003. // Trigger the map.
  1004. extern CMaterialSystem g_MaterialSystem;
  1005. g_MaterialSystem.GetRenderContextInternal()->AsyncMap( pRead->m_pSysmemTex, pRead->m_pAsyncMap, NULL );
  1006. m_queuedMaps.Insert( pRead );
  1007. // Stop as soon as we complete one successfully.
  1008. break;
  1009. }
  1010. }
  1011. if ( !m_scheduledReads.IsEmpty() )
  1012. {
  1013. if ( m_scheduledReads.Head()->m_pAsyncRead->IsSignalled() )
  1014. {
  1015. AsyncReadJob_t* pScheduledRead = m_scheduledReads.RemoveAtHead();
  1016. SafeRelease( &pScheduledRead->m_pAsyncRead );
  1017. m_queuedReads.Insert( pScheduledRead );
  1018. }
  1019. }
  1020. AsyncReadJob_t* pRequestCopy = NULL;
  1021. if ( m_requestedCopies.PopItem( &pRequestCopy ) )
  1022. {
  1023. SafeAssign( &pRequestCopy->m_pAsyncRead, new CAsyncCopyRequest );
  1024. extern CMaterialSystem g_MaterialSystem;
  1025. g_MaterialSystem.GetRenderContextInternal()->AsyncCopyRenderTargetToStagingTexture( pRequestCopy->m_pSysmemTex, pRequestCopy->m_pSrcRt, pRequestCopy->m_pAsyncRead, NULL );
  1026. m_scheduledReads.Insert( pRequestCopy );
  1027. }
  1028. while ( m_completedJobs.Count() > 0 )
  1029. {
  1030. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CreateTextureFromBits" );
  1031. AsyncReadJob_t* pCreate = NULL;
  1032. if ( m_completedJobs.PopItem( &pCreate ) )
  1033. {
  1034. // Check after we do the unmap, we need to do that here.
  1035. if ( IsJobCancelled( pCreate ) )
  1036. {
  1037. delete pCreate;
  1038. continue;
  1039. }
  1040. extern CMaterialSystem g_MaterialSystem;
  1041. g_MaterialSystem.GetRenderContextInternal()->AsyncUnmap( pCreate->m_pSysmemTex );
  1042. SafeRelease( &pCreate->m_pAsyncMap );
  1043. assert_cast< CTextureManager* >( g_pTextureManager )->CompleteAsyncRead( pCreate );
  1044. delete pCreate;
  1045. pCreate = NULL;
  1046. // Stop as soon as we complete one successfully.
  1047. break;
  1048. }
  1049. }
  1050. }
  1051. private:
  1052. inline bool ThreadInReaderThread()
  1053. {
  1054. return s_TextureManager.ThreadInAsyncReadThread();
  1055. }
  1056. void ThreadReader_Main()
  1057. {
  1058. Assert( ThreadInReaderThread() );
  1059. while ( !m_bQuit )
  1060. {
  1061. AsyncReadJob_t *pJob = NULL;
  1062. if ( m_pendingJobs.PopItem( &pJob ) )
  1063. {
  1064. Assert( pJob != NULL );
  1065. ThreadReader_ProcessRead( pJob );
  1066. }
  1067. else
  1068. {
  1069. // "awhile"
  1070. ThreadSleep( 8 );
  1071. }
  1072. }
  1073. }
  1074. void ThreadReader_ProcessRead( AsyncReadJob_t *pJob )
  1075. {
  1076. Assert( ThreadInReaderThread() );
  1077. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1078. // This code does a few things:
  1079. // 1. Reads from a previously mapped scratch buffer texture and performs byte swapping (if necessary).
  1080. // 2. Uses byteswapped data to generate mipmaps
  1081. // 3. Encodes mipmapped data into the destination format.
  1082. const int h = pJob->m_pSysmemTex->GetActualHeight();
  1083. const int w = pJob->m_pSysmemTex->GetActualWidth();
  1084. const ImageFormat srcFmt = pJob->m_pSysmemTex->GetImageFormat();
  1085. // Convert the data
  1086. CUtlMemory< unsigned char > srcBufferFinestMip;
  1087. CUtlMemory< unsigned char > srcBufferAllMips;
  1088. const int srcFinestMemRequired = ImageLoader::GetMemRequired( w, h, 1, srcFmt, false );
  1089. const int srcAllMemRequired = ImageLoader::GetMemRequired( w, h, 1, srcFmt, pJob->m_bGenMips );
  1090. const int srcPitch = ImageLoader::GetMemRequired( w, 1, 1, srcFmt, false );
  1091. const ImageFormat dstFmt = pJob->m_dstFmt;
  1092. CUtlMemory< unsigned char > dstBufferAllMips;
  1093. const int dstMemRequried = ImageLoader::GetMemRequired( w, h, 1, dstFmt, pJob->m_bGenMips );
  1094. {
  1095. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s-Allocations", __FUNCTION__ );
  1096. srcBufferFinestMip.EnsureCapacity( srcFinestMemRequired );
  1097. if ( srcFinestMemRequired != srcAllMemRequired )
  1098. {
  1099. srcBufferAllMips.EnsureCapacity( srcAllMemRequired );
  1100. }
  1101. else
  1102. {
  1103. Assert( !pJob->m_bGenMips );
  1104. }
  1105. if ( srcFmt != dstFmt )
  1106. {
  1107. dstBufferAllMips.EnsureCapacity( dstMemRequried );
  1108. }
  1109. }
  1110. // If this fires, you will get data corruption below. We can fix this case, it just doesn't seem
  1111. // to be needed right now.
  1112. Assert( pJob->m_pAsyncMap->m_nPitch == srcPitch );
  1113. srcPitch; // Hush compiler.
  1114. {
  1115. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s-ByteSwapInPlace", __FUNCTION__ );
  1116. ImageLoader::ConvertImageFormat( (unsigned char*) pJob->m_pAsyncMap->m_pMemory, GetImageFormatRawReadback( srcFmt ), srcBufferFinestMip.Base(), srcFmt, w, h );
  1117. }
  1118. if ( pJob->m_bGenMips )
  1119. {
  1120. GenerateMipmaps( &srcBufferAllMips, srcBufferFinestMip.Base(), w, h, srcFmt );
  1121. }
  1122. else
  1123. {
  1124. // If we're not generating mips, then allmips == finest mip, but the code below expects everything to
  1125. // be in all mips.
  1126. srcBufferAllMips.Swap( srcBufferFinestMip );
  1127. }
  1128. // Code below expects that the data is here one way or another.
  1129. Assert( srcBufferAllMips.Count() == srcAllMemRequired );
  1130. if ( srcFmt != dstFmt )
  1131. {
  1132. ConvertTexelData( &dstBufferAllMips, dstFmt, srcBufferAllMips, w, h, srcFmt, pJob->m_bGenMips );
  1133. pJob->m_finalTexelData.Swap( dstBufferAllMips );
  1134. }
  1135. else
  1136. {
  1137. // Just swap out the buffers.
  1138. pJob->m_finalTexelData.Swap( srcBufferAllMips );
  1139. }
  1140. // At this point, the data should be ready to go. Quick sanity check.
  1141. Assert( pJob->m_finalTexelData.Count() == dstMemRequried );
  1142. m_completedJobs.PushItem( pJob );
  1143. }
  1144. void GenerateMipmaps( CUtlMemory< unsigned char >* outBuffer, unsigned char* pSrc, int w, int h, ImageFormat fmt ) const
  1145. {
  1146. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1147. ImageLoader::GenerateMipmapLevelsLQ( pSrc, outBuffer->Base(), w, h, fmt, 0 );
  1148. }
  1149. void ConvertTexelData( CUtlMemory< unsigned char > *outBuffer, ImageFormat dstFmt, /* const */ CUtlMemory< unsigned char > &inBuffer, int w, int h, ImageFormat srcFmt, bool bGenMips )
  1150. {
  1151. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1152. const int mipmapCount = bGenMips ? ImageLoader::GetNumMipMapLevels( w, h ) : 1;
  1153. unsigned char* pSrc = inBuffer.Base();
  1154. unsigned char* pDst = (*outBuffer).Base();
  1155. int mip_w = w;
  1156. int mip_h = h;
  1157. for ( int i = 0; i < mipmapCount; ++i )
  1158. {
  1159. ImageLoader::ConvertImageFormat( pSrc, srcFmt, pDst, dstFmt, mip_w, mip_h );
  1160. pSrc += ImageLoader::GetMemRequired( mip_w, mip_h, 1, srcFmt, false );
  1161. pDst += ImageLoader::GetMemRequired( mip_w, mip_h, 1, dstFmt, false );
  1162. mip_w = Max( 1, mip_w >> 1 );
  1163. mip_h = Max( 1, mip_h >> 1 );
  1164. }
  1165. }
  1166. static unsigned ReaderMain( void* _this )
  1167. {
  1168. ThreadSetDebugName( "Helper" );
  1169. s_TextureManager.m_nAsyncReadThread = ThreadGetCurrentId();
  1170. ( ( AsyncReader* ) _this )->ThreadReader_Main();
  1171. s_TextureManager.m_nAsyncReadThread = 0xFFFFFFFF;
  1172. return 0;
  1173. }
  1174. ThreadHandle_t m_HelperThread;
  1175. volatile bool m_bQuit;
  1176. CTSQueue< AsyncReadJob_t*> m_requestedCopies;
  1177. CUtlQueue< AsyncReadJob_t* > m_queuedReads;
  1178. CUtlQueue< AsyncReadJob_t* > m_scheduledReads;
  1179. CUtlQueue< AsyncReadJob_t* > m_queuedMaps;
  1180. CTSQueue< AsyncReadJob_t* > m_pendingJobs;
  1181. CTSQueue< AsyncReadJob_t* > m_completedJobs;
  1182. };
  1183. //-----------------------------------------------------------------------------
  1184. // Texture manager
  1185. //-----------------------------------------------------------------------------
  1186. CTextureManager::CTextureManager( void )
  1187. : m_TextureList( true )
  1188. , m_TextureAliases( true )
  1189. , m_TextureExcludes( true )
  1190. , m_PendingAsyncLoads( true )
  1191. , m_textureStreamingRequests( DefLessFunc( ITextureInternal* ) )
  1192. , m_nAsyncLoadThread( 0xFFFFFFFF )
  1193. , m_nAsyncReadThread( 0xFFFFFFFF )
  1194. {
  1195. m_pErrorTexture = NULL;
  1196. m_pBlackTexture = NULL;
  1197. m_pWhiteTexture = NULL;
  1198. m_pGreyTexture = NULL;
  1199. m_pGreyAlphaZeroTexture = NULL;
  1200. m_pNormalizationCubemap = NULL;
  1201. m_pErrorRegen = NULL;
  1202. m_pFullScreenTexture = NULL;
  1203. m_pSignedNormalizationCubemap = NULL;
  1204. m_pShadowNoise2D = NULL;
  1205. m_pIdentityLightWarp = NULL;
  1206. m_pFullScreenDepthTexture = NULL;
  1207. m_pDebugLuxels2D = NULL;
  1208. m_pAsyncLoader = new AsyncLoader;
  1209. m_pAsyncReader = new AsyncReader;
  1210. m_iSuspendTextureStreaming = 0;
  1211. }
  1212. //-----------------------------------------------------------------------------
  1213. // Initialization + shutdown
  1214. //-----------------------------------------------------------------------------
  1215. void CTextureManager::Init( int nFlags )
  1216. {
  1217. m_nFlags = nFlags;
  1218. color32 color, color2;
  1219. m_iNextTexID = 4096;
  1220. // setup the checkerboard generator for failed texture loading
  1221. color.r = color.g = color.b = 0; color.a = 128;
  1222. color2.r = color2.b = color2.a = 255; color2.g = 0;
  1223. m_pErrorRegen = new CCheckerboardTexture( 4, color, color2 );
  1224. // Create an error texture
  1225. m_pErrorTexture = CreateProceduralTexture( "error", TEXTURE_GROUP_OTHER,
  1226. ERROR_TEXTURE_SIZE, ERROR_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY );
  1227. CreateCheckerboardTexture( m_pErrorTexture, 4, color, color2 );
  1228. m_pErrorTexture->SetErrorTexture( true );
  1229. // Create a white texture
  1230. m_pWhiteTexture = CreateProceduralTexture( "white", TEXTURE_GROUP_OTHER,
  1231. WHITE_TEXTURE_SIZE, WHITE_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRX8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY );
  1232. color.r = color.g = color.b = color.a = 255;
  1233. CreateSolidTexture( m_pWhiteTexture, color );
  1234. // Create a black texture
  1235. m_pBlackTexture = CreateProceduralTexture( "black", TEXTURE_GROUP_OTHER,
  1236. BLACK_TEXTURE_SIZE, BLACK_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRX8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY );
  1237. color.r = color.g = color.b = 0;
  1238. CreateSolidTexture( m_pBlackTexture, color );
  1239. // Create a grey texture
  1240. m_pGreyTexture = CreateProceduralTexture( "grey", TEXTURE_GROUP_OTHER,
  1241. GREY_TEXTURE_SIZE, GREY_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY );
  1242. color.r = color.g = color.b = 128;
  1243. color.a = 255;
  1244. CreateSolidTexture( m_pGreyTexture, color );
  1245. // Create a grey texture
  1246. m_pGreyAlphaZeroTexture = CreateProceduralTexture( "greyalphazero", TEXTURE_GROUP_OTHER,
  1247. GREY_TEXTURE_SIZE, GREY_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY );
  1248. color.r = color.g = color.b = 128;
  1249. color.a = 0;
  1250. CreateSolidTexture( m_pGreyAlphaZeroTexture, color );
  1251. if ( HardwareConfig()->GetMaxDXSupportLevel() >= 80 )
  1252. {
  1253. // Create a normalization cubemap
  1254. m_pNormalizationCubemap = CreateProceduralTexture( "normalize", TEXTURE_GROUP_CUBE_MAP,
  1255. NORMALIZATION_CUBEMAP_SIZE, NORMALIZATION_CUBEMAP_SIZE, 1, IMAGE_FORMAT_BGRX8888,
  1256. TEXTUREFLAGS_ENVMAP | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY |
  1257. TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_CLAMPU );
  1258. CreateNormalizationCubemap( m_pNormalizationCubemap );
  1259. }
  1260. if ( HardwareConfig()->GetMaxDXSupportLevel() >= 90 )
  1261. {
  1262. // In GL, we have poor format support, so we ask for signed float
  1263. ImageFormat fmt = IsOpenGL() ? IMAGE_FORMAT_RGBA16161616F : IMAGE_FORMAT_UVWQ8888;
  1264. int nTextureFlags = TEXTUREFLAGS_ENVMAP | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_CLAMPU;
  1265. #ifdef OSX
  1266. // JasonM - ridiculous hack around R500 lameness...we never use this texture on OSX anyways (right?)
  1267. // Now assuming this was an OSX specific workaround.
  1268. nTextureFlags |= TEXTUREFLAGS_POINTSAMPLE;
  1269. #endif
  1270. // Create a normalization cubemap
  1271. m_pSignedNormalizationCubemap = CreateProceduralTexture( "normalizesigned", TEXTURE_GROUP_CUBE_MAP,
  1272. NORMALIZATION_CUBEMAP_SIZE, NORMALIZATION_CUBEMAP_SIZE, 1, fmt, nTextureFlags );
  1273. CreateSignedNormalizationCubemap( m_pSignedNormalizationCubemap );
  1274. m_pIdentityLightWarp = FindOrLoadTexture( "dev/IdentityLightWarp", TEXTURE_GROUP_OTHER );
  1275. m_pIdentityLightWarp->IncrementReferenceCount();
  1276. }
  1277. // High end hardware needs this texture for shadow mapping
  1278. if ( HardwareConfig()->ActuallySupportsPixelShaders_2_b() )
  1279. {
  1280. m_pShadowNoise2D = FindOrLoadTexture( "engine/NormalizedRandomDirections2D", TEXTURE_GROUP_OTHER );
  1281. m_pShadowNoise2D->IncrementReferenceCount();
  1282. }
  1283. m_pDebugLuxels2D = FindOrLoadTexture( "debug/debugluxelsnoalpha", TEXTURE_GROUP_OTHER );
  1284. m_pDebugLuxels2D->IncrementReferenceCount();
  1285. }
  1286. void CTextureManager::Shutdown()
  1287. {
  1288. // Clean up any textures we have hanging around that are waiting to go.
  1289. CleanupPossiblyUnreferencedTextures();
  1290. // Cool the texture cache first to drop all the refs back to 0 for the streamable things.
  1291. CoolTextureCache();
  1292. if ( m_pAsyncLoader )
  1293. {
  1294. m_pAsyncLoader->Shutdown();
  1295. delete m_pAsyncLoader;
  1296. m_pAsyncLoader = NULL;
  1297. }
  1298. if ( m_pAsyncReader )
  1299. {
  1300. m_pAsyncReader->Shutdown();
  1301. delete m_pAsyncReader;
  1302. m_pAsyncReader = NULL;
  1303. }
  1304. FreeStandardRenderTargets();
  1305. FOR_EACH_VEC( m_ReadbackTextures, i )
  1306. {
  1307. m_ReadbackTextures[ i ]->Release();
  1308. }
  1309. if ( m_pDebugLuxels2D )
  1310. {
  1311. m_pDebugLuxels2D->DecrementReferenceCount();
  1312. m_pDebugLuxels2D = NULL;
  1313. }
  1314. // These checks added because it's possible for shutdown to be called before the material system is
  1315. // fully initialized.
  1316. if ( m_pWhiteTexture )
  1317. {
  1318. m_pWhiteTexture->DecrementReferenceCount();
  1319. m_pWhiteTexture = NULL;
  1320. }
  1321. if ( m_pBlackTexture )
  1322. {
  1323. m_pBlackTexture->DecrementReferenceCount();
  1324. m_pBlackTexture = NULL;
  1325. }
  1326. if ( m_pGreyTexture )
  1327. {
  1328. m_pGreyTexture->DecrementReferenceCount();
  1329. m_pGreyTexture = NULL;
  1330. }
  1331. if ( m_pGreyAlphaZeroTexture )
  1332. {
  1333. m_pGreyAlphaZeroTexture->DecrementReferenceCount();
  1334. m_pGreyAlphaZeroTexture = NULL;
  1335. }
  1336. if ( m_pNormalizationCubemap )
  1337. {
  1338. m_pNormalizationCubemap->DecrementReferenceCount();
  1339. m_pNormalizationCubemap = NULL;
  1340. }
  1341. if ( m_pSignedNormalizationCubemap )
  1342. {
  1343. m_pSignedNormalizationCubemap->DecrementReferenceCount();
  1344. m_pSignedNormalizationCubemap = NULL;
  1345. }
  1346. if ( m_pShadowNoise2D )
  1347. {
  1348. m_pShadowNoise2D->DecrementReferenceCount();
  1349. m_pShadowNoise2D = NULL;
  1350. }
  1351. if ( m_pIdentityLightWarp )
  1352. {
  1353. m_pIdentityLightWarp->DecrementReferenceCount();
  1354. m_pIdentityLightWarp = NULL;
  1355. }
  1356. if ( m_pErrorTexture )
  1357. {
  1358. m_pErrorTexture->DecrementReferenceCount();
  1359. m_pErrorTexture = NULL;
  1360. }
  1361. ReleaseTextures();
  1362. if ( m_pErrorRegen )
  1363. {
  1364. m_pErrorRegen->Release();
  1365. m_pErrorRegen = NULL;
  1366. }
  1367. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1368. {
  1369. ITextureInternal::Destroy( m_TextureList[i], true );
  1370. }
  1371. m_TextureList.RemoveAll();
  1372. for( int i = m_TextureAliases.First(); i != m_TextureAliases.InvalidIndex(); i = m_TextureAliases.Next( i ) )
  1373. {
  1374. delete []m_TextureAliases[i];
  1375. }
  1376. m_TextureAliases.RemoveAll();
  1377. m_TextureExcludes.RemoveAll();
  1378. }
  1379. //-----------------------------------------------------------------------------
  1380. // Allocate, free standard render target textures
  1381. //-----------------------------------------------------------------------------
  1382. void CTextureManager::AllocateStandardRenderTargets( )
  1383. {
  1384. bool bAllocateFullscreenTexture = ( m_nFlags & MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE ) != 0;
  1385. bool bAllocateMorphAccumTexture = g_pMorphMgr->ShouldAllocateScratchTextures();
  1386. if ( IsPC() && ( bAllocateFullscreenTexture || bAllocateMorphAccumTexture ) )
  1387. {
  1388. MaterialSystem()->BeginRenderTargetAllocation();
  1389. // A offscreen render target which is the size + format of the back buffer (*not* HDR format!)
  1390. if ( bAllocateFullscreenTexture )
  1391. {
  1392. m_pFullScreenTexture = CreateRenderTargetTexture( "_rt_FullScreen", 1, 1, RT_SIZE_FULL_FRAME_BUFFER_ROUNDED_UP,
  1393. MaterialSystem()->GetBackBufferFormat(), RENDER_TARGET, TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, 0 );
  1394. m_pFullScreenTexture->IncrementReferenceCount();
  1395. }
  1396. // This texture is the one we accumulate morph deltas into
  1397. if ( bAllocateMorphAccumTexture )
  1398. {
  1399. g_pMorphMgr->AllocateScratchTextures();
  1400. g_pMorphMgr->AllocateMaterials();
  1401. }
  1402. MaterialSystem()->EndRenderTargetAllocation();
  1403. }
  1404. }
  1405. void CTextureManager::FreeStandardRenderTargets()
  1406. {
  1407. if ( m_pFullScreenTexture )
  1408. {
  1409. m_pFullScreenTexture->DecrementReferenceCount();
  1410. m_pFullScreenTexture = NULL;
  1411. }
  1412. g_pMorphMgr->FreeMaterials();
  1413. g_pMorphMgr->FreeScratchTextures();
  1414. }
  1415. void CTextureManager::CacheExternalStandardRenderTargets()
  1416. {
  1417. m_pFullScreenDepthTexture = FindTexture( "_rt_FullFrameDepth" ); //created/destroyed in engine/matsys_interface.cpp to properly track hdr changes
  1418. }
  1419. //-----------------------------------------------------------------------------
  1420. // Generates an error texture pattern
  1421. //-----------------------------------------------------------------------------
  1422. void CTextureManager::GenerateErrorTexture( ITexture *pTexture, IVTFTexture *pVTFTexture )
  1423. {
  1424. m_pErrorRegen->RegenerateTextureBits( pTexture, pVTFTexture, NULL );
  1425. }
  1426. //-----------------------------------------------------------------------------
  1427. // Updates the color correction state
  1428. //-----------------------------------------------------------------------------
  1429. ITextureInternal *CTextureManager::ColorCorrectionTexture( int i )
  1430. {
  1431. Assert( i<COLOR_CORRECTION_MAX_TEXTURES );
  1432. return m_pColorCorrectionTextures[ i ];
  1433. }
  1434. void CTextureManager::SetColorCorrectionTexture( int i, ITextureInternal *pTexture )
  1435. {
  1436. Assert( i<COLOR_CORRECTION_MAX_TEXTURES );
  1437. if( m_pColorCorrectionTextures[i] )
  1438. {
  1439. m_pColorCorrectionTextures[i]->DecrementReferenceCount();
  1440. }
  1441. m_pColorCorrectionTextures[i] = pTexture;
  1442. if( pTexture )
  1443. pTexture->IncrementReferenceCount();
  1444. }
  1445. //-----------------------------------------------------------------------------
  1446. // Releases all textures (cause we've lost video memory)
  1447. //-----------------------------------------------------------------------------
  1448. void CTextureManager::ReleaseTextures( void )
  1449. {
  1450. g_pShaderAPI->SetFullScreenTextureHandle( INVALID_SHADERAPI_TEXTURE_HANDLE );
  1451. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1452. {
  1453. // Release the texture...
  1454. m_TextureList[i]->ReleaseMemory();
  1455. }
  1456. }
  1457. //-----------------------------------------------------------------------------
  1458. // Request a texture ID
  1459. //-----------------------------------------------------------------------------
  1460. int CTextureManager::RequestNextTextureID()
  1461. {
  1462. // FIXME: Deal better with texture ids
  1463. // The range between 19000 and 21000 are used for standard textures + lightmaps
  1464. if (m_iNextTexID == 19000)
  1465. {
  1466. m_iNextTexID = 21000;
  1467. }
  1468. return m_iNextTexID++;
  1469. }
  1470. //-----------------------------------------------------------------------------
  1471. // Restores a single texture
  1472. //-----------------------------------------------------------------------------
  1473. void CTextureManager::RestoreTexture( ITextureInternal* pTexture )
  1474. {
  1475. // Put the texture back onto the board
  1476. pTexture->OnRestore(); // Give render targets a chance to reinitialize themselves if necessary (due to AA changes).
  1477. pTexture->Download();
  1478. }
  1479. //-----------------------------------------------------------------------------
  1480. // Purges our complete list of textures that might currently be unreferenced
  1481. //-----------------------------------------------------------------------------
  1482. void CTextureManager::CleanupPossiblyUnreferencedTextures()
  1483. {
  1484. if ( !ThreadInMainThread() || MaterialSystem()->GetRenderThreadId() != 0xFFFFFFFF )
  1485. {
  1486. Assert( !"CTextureManager::CleanupPossiblyUnreferencedTextures should never be called here" );
  1487. // This is catastrophically bad, don't do this. Someone needs to fix this. See JohnS or McJohn
  1488. DebuggerBreakIfDebugging_StagingOnly();
  1489. return;
  1490. }
  1491. // It is perfectly valid for a texture to become referenced again (it lives on in our texture list, and can be
  1492. // re-loaded) and then free'd again, so ensure we don't have any duplicates in queue.
  1493. CUtlVector< ITextureInternal * > texturesToDelete( /* growSize */ 0, /* initialSize */ m_PossiblyUnreferencedTextures.Count() );
  1494. ITextureInternal *pMaybeUnreferenced = NULL;
  1495. while ( m_PossiblyUnreferencedTextures.PopItem( &pMaybeUnreferenced ) )
  1496. {
  1497. Assert( pMaybeUnreferenced->GetReferenceCount() >= 0 );
  1498. if ( pMaybeUnreferenced->GetReferenceCount() == 0 && texturesToDelete.Find( pMaybeUnreferenced ) == texturesToDelete.InvalidIndex() )
  1499. {
  1500. texturesToDelete.AddToTail( pMaybeUnreferenced );
  1501. }
  1502. }
  1503. // Free them
  1504. FOR_EACH_VEC( texturesToDelete, i )
  1505. {
  1506. RemoveTexture( texturesToDelete[ i ] );
  1507. }
  1508. }
  1509. //-----------------------------------------------------------------------------
  1510. // Restore all textures (cause we've got video memory again)
  1511. //-----------------------------------------------------------------------------
  1512. void CTextureManager::RestoreNonRenderTargetTextures( )
  1513. {
  1514. // 360 should not have gotten here
  1515. Assert( !IsX360() );
  1516. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1517. {
  1518. if ( !m_TextureList[i]->IsRenderTarget() )
  1519. {
  1520. RestoreTexture( m_TextureList[i] );
  1521. }
  1522. }
  1523. }
  1524. //-----------------------------------------------------------------------------
  1525. // Restore just the render targets (cause we've got video memory again)
  1526. //-----------------------------------------------------------------------------
  1527. void CTextureManager::RestoreRenderTargets()
  1528. {
  1529. // 360 should not have gotten here
  1530. Assert( !IsX360() );
  1531. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1532. {
  1533. if ( m_TextureList[i]->IsRenderTarget() )
  1534. {
  1535. RestoreTexture( m_TextureList[i] );
  1536. }
  1537. }
  1538. if ( m_pFullScreenTexture )
  1539. {
  1540. g_pShaderAPI->SetFullScreenTextureHandle( m_pFullScreenTexture->GetTextureHandle( 0 ) );
  1541. }
  1542. CacheExternalStandardRenderTargets();
  1543. }
  1544. //-----------------------------------------------------------------------------
  1545. // Reloads all textures
  1546. //-----------------------------------------------------------------------------
  1547. void CTextureManager::ReloadTextures()
  1548. {
  1549. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1550. {
  1551. // Put the texture back onto the board
  1552. m_TextureList[i]->Download();
  1553. }
  1554. }
  1555. static void ForceTextureIntoHardware( ITexture *pTexture, IMaterial *pMaterial, IMaterialVar *pBaseTextureVar )
  1556. {
  1557. if ( IsX360() )
  1558. return;
  1559. pBaseTextureVar->SetTextureValue( pTexture );
  1560. CMatRenderContextPtr pRenderContext( MaterialSystem()->GetRenderContext() );
  1561. pRenderContext->Bind( pMaterial );
  1562. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1563. CMeshBuilder meshBuilder;
  1564. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 1 );
  1565. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  1566. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  1567. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  1568. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  1569. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1570. meshBuilder.AdvanceVertex();
  1571. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  1572. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  1573. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  1574. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  1575. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1576. meshBuilder.AdvanceVertex();
  1577. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  1578. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  1579. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  1580. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  1581. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1582. meshBuilder.AdvanceVertex();
  1583. meshBuilder.End();
  1584. pMesh->Draw();
  1585. }
  1586. //-----------------------------------------------------------------------------
  1587. // Reloads all textures
  1588. //-----------------------------------------------------------------------------
  1589. void CTextureManager::ForceAllTexturesIntoHardware( void )
  1590. {
  1591. if ( IsX360() )
  1592. return;
  1593. IMaterial *pMaterial = MaterialSystem()->FindMaterial( "engine/preloadtexture", "texture preload" );
  1594. pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion(); //always work with the realtime material internally
  1595. pMaterial->IncrementReferenceCount();
  1596. bool bFound;
  1597. IMaterialVar *pBaseTextureVar = pMaterial->FindVar( "$basetexture", &bFound );
  1598. if( !bFound )
  1599. {
  1600. return;
  1601. }
  1602. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1603. {
  1604. // Put the texture back onto the board
  1605. ForceTextureIntoHardware( m_TextureList[i], pMaterial, pBaseTextureVar );
  1606. }
  1607. pMaterial->DecrementReferenceCount();
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. // Get at a couple standard textures
  1611. //-----------------------------------------------------------------------------
  1612. ITextureInternal *CTextureManager::ErrorTexture()
  1613. {
  1614. return m_pErrorTexture;
  1615. }
  1616. ITextureInternal *CTextureManager::NormalizationCubemap()
  1617. {
  1618. return m_pNormalizationCubemap;
  1619. }
  1620. ITextureInternal *CTextureManager::SignedNormalizationCubemap()
  1621. {
  1622. return m_pSignedNormalizationCubemap;
  1623. }
  1624. ITextureInternal *CTextureManager::ShadowNoise2D()
  1625. {
  1626. return m_pShadowNoise2D;
  1627. }
  1628. ITextureInternal *CTextureManager::IdentityLightWarp()
  1629. {
  1630. return m_pIdentityLightWarp;
  1631. }
  1632. ITextureInternal *CTextureManager::FullFrameDepthTexture()
  1633. {
  1634. return m_pFullScreenDepthTexture;
  1635. }
  1636. ITextureInternal *CTextureManager::DebugLuxels2D()
  1637. {
  1638. return m_pDebugLuxels2D;
  1639. }
  1640. //-----------------------------------------------------------------------------
  1641. // Creates a procedural texture
  1642. //-----------------------------------------------------------------------------
  1643. ITextureInternal *CTextureManager::CreateProceduralTexture(
  1644. const char *pTextureName,
  1645. const char *pTextureGroupName,
  1646. int w,
  1647. int h,
  1648. int d,
  1649. ImageFormat fmt,
  1650. int nFlags,
  1651. ITextureRegenerator *generator )
  1652. {
  1653. ITextureInternal *pNewTexture = ITextureInternal::CreateProceduralTexture( pTextureName, pTextureGroupName, w, h, d, fmt, nFlags, generator );
  1654. if ( !pNewTexture )
  1655. return NULL;
  1656. // Add it to the list of textures so it can be restored, etc.
  1657. m_TextureList.Insert( pNewTexture->GetName(), pNewTexture );
  1658. // NOTE: This will download the texture only if the shader api is ready
  1659. pNewTexture->Download();
  1660. return pNewTexture;
  1661. }
  1662. //-----------------------------------------------------------------------------
  1663. // FIXME: Need some better understanding of when textures should be added to
  1664. // the texture dictionary here. Is it only for files, for example?
  1665. // Texture dictionary...
  1666. //-----------------------------------------------------------------------------
  1667. ITextureInternal *CTextureManager::LoadTexture( const char *pTextureName, const char *pTextureGroupName, int nAdditionalCreationFlags /* = 0 */, bool bDownload /* = true */ )
  1668. {
  1669. ITextureInternal *pNewTexture = ITextureInternal::CreateFileTexture( pTextureName, pTextureGroupName );
  1670. if ( pNewTexture )
  1671. {
  1672. int iIndex = m_TextureExcludes.Find( pNewTexture->GetName() );
  1673. if ( m_TextureExcludes.IsValidIndex( iIndex ) )
  1674. {
  1675. // mark the new texture as excluded
  1676. int nDimensionsLimit = m_TextureExcludes[iIndex];
  1677. pNewTexture->MarkAsExcluded( ( nDimensionsLimit == 0 ), nDimensionsLimit );
  1678. }
  1679. // Stick the texture onto the board
  1680. if ( bDownload )
  1681. pNewTexture->Download( NULL, nAdditionalCreationFlags );
  1682. // FIXME: If there's been an error loading, we don't also want this error...
  1683. }
  1684. return pNewTexture;
  1685. }
  1686. ITextureInternal *CTextureManager::FindTexture( const char *pTextureName )
  1687. {
  1688. if ( !pTextureName || pTextureName[0] == 0 )
  1689. return NULL;
  1690. char szCleanName[MAX_PATH];
  1691. NormalizeTextureName( pTextureName, szCleanName, sizeof( szCleanName ) );
  1692. int i = m_TextureList.Find( szCleanName );
  1693. if ( i != m_TextureList.InvalidIndex() )
  1694. {
  1695. return m_TextureList[i];
  1696. }
  1697. i = m_TextureAliases.Find( szCleanName );
  1698. if ( i != m_TextureAliases.InvalidIndex() )
  1699. {
  1700. return FindTexture( m_TextureAliases[i] );
  1701. }
  1702. // Special handling: lightmaps
  1703. if ( char const *szLightMapNum = StringAfterPrefix( szCleanName, "[lightmap" ) )
  1704. {
  1705. int iLightMapNum = atoi( szLightMapNum );
  1706. extern CMaterialSystem g_MaterialSystem;
  1707. CMatLightmaps *plm = g_MaterialSystem.GetLightmaps();
  1708. if ( iLightMapNum >= 0 &&
  1709. iLightMapNum < plm->GetNumLightmapPages() )
  1710. {
  1711. ShaderAPITextureHandle_t hTex = plm->GetLightmapPageTextureHandle( iLightMapNum );
  1712. if ( hTex != INVALID_SHADERAPI_TEXTURE_HANDLE )
  1713. {
  1714. // Establish the lookup linking in the dictionary
  1715. ITextureInternal *pTxInt = ITextureInternal::CreateReferenceTextureFromHandle( pTextureName, TEXTURE_GROUP_LIGHTMAP, hTex );
  1716. m_TextureList.Insert( pTextureName, pTxInt );
  1717. return pTxInt;
  1718. }
  1719. }
  1720. }
  1721. return NULL;
  1722. }
  1723. void CTextureManager::AddTextureAlias( const char *pAlias, const char *pRealName )
  1724. {
  1725. if ( (pAlias == NULL) || (pRealName == NULL) )
  1726. return; //invalid alias
  1727. char szCleanName[MAX_PATH];
  1728. int index = m_TextureAliases.Find( NormalizeTextureName( pAlias, szCleanName, sizeof( szCleanName ) ) );
  1729. if ( index != m_TextureAliases.InvalidIndex() )
  1730. {
  1731. AssertMsg( Q_stricmp( pRealName, m_TextureAliases[index] ) == 0, "Trying to use one name to alias two different textures." );
  1732. RemoveTextureAlias( pAlias ); //remove the old alias to make room for the new one.
  1733. }
  1734. size_t iRealNameLength = strlen( pRealName ) + 1;
  1735. char *pRealNameCopy = new char [iRealNameLength];
  1736. memcpy( pRealNameCopy, pRealName, iRealNameLength );
  1737. m_TextureAliases.Insert( szCleanName, pRealNameCopy );
  1738. }
  1739. void CTextureManager::RemoveTextureAlias( const char *pAlias )
  1740. {
  1741. if ( pAlias == NULL )
  1742. return;
  1743. char szCleanName[MAX_PATH];
  1744. int index = m_TextureAliases.Find( NormalizeTextureName( pAlias, szCleanName, sizeof( szCleanName ) ) );
  1745. if ( index == m_TextureAliases.InvalidIndex() )
  1746. return; //not found
  1747. delete []m_TextureAliases[index];
  1748. m_TextureAliases.RemoveAt( index );
  1749. }
  1750. void CTextureManager::SetExcludedTextures( const char *pScriptName )
  1751. {
  1752. // clear all exisiting texture's exclusion
  1753. for ( int i = m_TextureExcludes.First(); i != m_TextureExcludes.InvalidIndex(); i = m_TextureExcludes.Next( i ) )
  1754. {
  1755. ITextureInternal *pTexture = FindTexture( m_TextureExcludes.GetElementName( i ) );
  1756. if ( pTexture )
  1757. {
  1758. pTexture->MarkAsExcluded( false, 0 );
  1759. }
  1760. }
  1761. m_TextureExcludes.RemoveAll();
  1762. MEM_ALLOC_CREDIT();
  1763. // get optional script
  1764. CUtlBuffer excludeBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1765. if ( g_pFullFileSystem->ReadFile( pScriptName, NULL, excludeBuffer ) )
  1766. {
  1767. char szToken[MAX_PATH];
  1768. while ( 1 )
  1769. {
  1770. // must support spaces in names without quotes
  1771. // have to brute force parse up to a valid line
  1772. while ( 1 )
  1773. {
  1774. excludeBuffer.EatWhiteSpace();
  1775. if ( !excludeBuffer.EatCPPComment() )
  1776. {
  1777. // not a comment
  1778. break;
  1779. }
  1780. }
  1781. excludeBuffer.GetLine( szToken, sizeof( szToken ) );
  1782. int tokenLength = strlen( szToken );
  1783. if ( !tokenLength )
  1784. {
  1785. // end of list
  1786. break;
  1787. }
  1788. // remove all trailing whitespace
  1789. while ( tokenLength > 0 )
  1790. {
  1791. tokenLength--;
  1792. if ( isgraph( szToken[tokenLength] ) )
  1793. {
  1794. break;
  1795. }
  1796. szToken[tokenLength] = '\0';
  1797. }
  1798. // first optional token may be a dimension limit hint
  1799. int nDimensionsLimit = 0;
  1800. char *pTextureName = szToken;
  1801. if ( pTextureName[0] != 0 && isdigit( pTextureName[0] ) )
  1802. {
  1803. nDimensionsLimit = atoi( pTextureName );
  1804. // skip forward to name
  1805. for ( ;; )
  1806. {
  1807. char ch = *pTextureName;
  1808. if ( !ch || ( !isdigit( ch ) && !isspace( ch ) ) )
  1809. {
  1810. break;
  1811. }
  1812. pTextureName++;
  1813. }
  1814. }
  1815. char szCleanName[MAX_PATH];
  1816. NormalizeTextureName( pTextureName, szCleanName, sizeof( szCleanName ) );
  1817. if ( m_TextureExcludes.Find( szCleanName ) != m_TextureExcludes.InvalidIndex() )
  1818. {
  1819. // avoid duplicates
  1820. continue;
  1821. }
  1822. m_TextureExcludes.Insert( szCleanName, nDimensionsLimit );
  1823. // set any existing texture's exclusion
  1824. // textures that don't exist yet will get caught during their creation path
  1825. ITextureInternal *pTexture = FindTexture( szCleanName );
  1826. if ( pTexture )
  1827. {
  1828. pTexture->MarkAsExcluded( ( nDimensionsLimit == 0 ), nDimensionsLimit );
  1829. }
  1830. }
  1831. }
  1832. }
  1833. void CTextureManager::UpdateExcludedTextures( void )
  1834. {
  1835. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1836. {
  1837. m_TextureList[i]->UpdateExcludedState();
  1838. }
  1839. }
  1840. ITextureInternal *CTextureManager::FindOrLoadTexture( const char *pTextureName, const char *pTextureGroupName, int nAdditionalCreationFlags /* = 0 */ )
  1841. {
  1842. ITextureInternal *pTexture = FindTexture( pTextureName );
  1843. if ( !pTexture )
  1844. {
  1845. pTexture = LoadTexture( pTextureName, pTextureGroupName, nAdditionalCreationFlags );
  1846. if ( pTexture )
  1847. {
  1848. // insert into the dictionary using the processed texture name
  1849. m_TextureList.Insert( pTexture->GetName(), pTexture );
  1850. }
  1851. }
  1852. return pTexture;
  1853. }
  1854. bool CTextureManager::IsTextureLoaded( const char *pTextureName )
  1855. {
  1856. ITextureInternal *pTexture = FindTexture( pTextureName );
  1857. return ( pTexture != NULL );
  1858. }
  1859. //-----------------------------------------------------------------------------
  1860. // Creates a texture that's a render target
  1861. //-----------------------------------------------------------------------------
  1862. ITextureInternal *CTextureManager::CreateRenderTargetTexture(
  1863. const char *pRTName, // NULL for auto-generated name
  1864. int w,
  1865. int h,
  1866. RenderTargetSizeMode_t sizeMode,
  1867. ImageFormat fmt,
  1868. RenderTargetType_t type,
  1869. unsigned int textureFlags,
  1870. unsigned int renderTargetFlags )
  1871. {
  1872. MEM_ALLOC_CREDIT_( __FILE__ ": Render target" );
  1873. ITextureInternal *pTexture;
  1874. if ( pRTName )
  1875. {
  1876. // caller is re-initing or changing
  1877. pTexture = FindTexture( pRTName );
  1878. if ( pTexture )
  1879. {
  1880. // Changing the underlying render target, but leaving the pointer and refcount
  1881. // alone fixes callers that have exisiting references to this object.
  1882. ITextureInternal::ChangeRenderTarget( pTexture, w, h, sizeMode, fmt, type,
  1883. textureFlags, renderTargetFlags );
  1884. // download if ready
  1885. pTexture->Download();
  1886. return pTexture;
  1887. }
  1888. }
  1889. pTexture = ITextureInternal::CreateRenderTarget( pRTName, w, h, sizeMode, fmt, type,
  1890. textureFlags, renderTargetFlags );
  1891. if ( !pTexture )
  1892. return NULL;
  1893. // Add the render target to the list of textures
  1894. // that way it'll get cleaned up correctly in case of a task switch
  1895. m_TextureList.Insert( pTexture->GetName(), pTexture );
  1896. // NOTE: This will download the texture only if the shader api is ready
  1897. pTexture->Download();
  1898. return pTexture;
  1899. }
  1900. void CTextureManager::ResetTextureFilteringState( )
  1901. {
  1902. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1903. {
  1904. m_TextureList[i]->SetFilteringAndClampingMode();
  1905. }
  1906. }
  1907. void CTextureManager::SuspendTextureStreaming( void )
  1908. {
  1909. m_iSuspendTextureStreaming++;
  1910. }
  1911. void CTextureManager::ResumeTextureStreaming( void )
  1912. {
  1913. AssertMsg( m_iSuspendTextureStreaming, "Mismatched Suspend/Resume texture streaming calls" );
  1914. if ( m_iSuspendTextureStreaming )
  1915. {
  1916. m_iSuspendTextureStreaming--;
  1917. }
  1918. }
  1919. void CTextureManager::RemoveUnusedTextures( void )
  1920. {
  1921. // First, need to flush all of our textures that are pending cleanup.
  1922. CleanupPossiblyUnreferencedTextures();
  1923. int iNext;
  1924. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = iNext )
  1925. {
  1926. iNext = m_TextureList.Next( i );
  1927. #ifdef _DEBUG
  1928. if ( m_TextureList[i]->GetReferenceCount() < 0 )
  1929. {
  1930. Warning( "RemoveUnusedTextures: pTexture->m_referenceCount < 0 for %s\n", m_TextureList[i]->GetName() );
  1931. }
  1932. #endif
  1933. if ( m_TextureList[i]->GetReferenceCount() <= 0 )
  1934. {
  1935. ITextureInternal::Destroy( m_TextureList[i] );
  1936. m_TextureList.RemoveAt( i );
  1937. }
  1938. }
  1939. }
  1940. void CTextureManager::MarkUnreferencedTextureForCleanup( ITextureInternal *pTexture )
  1941. {
  1942. Assert( pTexture->GetReferenceCount() == 0 );
  1943. m_PossiblyUnreferencedTextures.PushItem( pTexture );
  1944. }
  1945. void CTextureManager::RemoveTexture( ITextureInternal *pTexture )
  1946. {
  1947. TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
  1948. Assert( pTexture->GetReferenceCount() <= 0 );
  1949. if ( !ThreadInMainThread() || MaterialSystem()->GetRenderThreadId() != 0xFFFFFFFF )
  1950. {
  1951. Assert( !"CTextureManager::RemoveTexture should never be called here");
  1952. // This is catastrophically bad, don't do this. Someone needs to fix this.
  1953. DebuggerBreakIfDebugging_StagingOnly();
  1954. return;
  1955. }
  1956. bool bTextureFound = false;
  1957. // If the queue'd rendering thread is running, RemoveTexture() is going to explode. If it isn't, calling
  1958. // RemoveTexture while still dealing with immediate removal textures seems fishy, but could be legit, in which case
  1959. // this assert could be softened.
  1960. int nUnreferencedQueue = m_PossiblyUnreferencedTextures.Count();
  1961. if ( nUnreferencedQueue )
  1962. {
  1963. Assert( !"RemoveTexture() being called while textures sitting in possibly unreferenced queue" );
  1964. // Assuming that this is all a wholesome main-thread misunderstanding, we can try to continue after filtering
  1965. // this texture from the queue.
  1966. ITextureInternal *pPossiblyUnreferenced = NULL;
  1967. for ( int i = 0; i < nUnreferencedQueue && m_PossiblyUnreferencedTextures.PopItem( &pPossiblyUnreferenced ); i++ )
  1968. {
  1969. m_PossiblyUnreferencedTextures.PushItem( pPossiblyUnreferenced );
  1970. if ( pPossiblyUnreferenced == pTexture )
  1971. {
  1972. bTextureFound = true;
  1973. break;
  1974. }
  1975. }
  1976. }
  1977. if ( bTextureFound )
  1978. {
  1979. Assert( !"CTextureManager::RemoveTexture has been called for a texture that has already requested cleanup. That's a paddlin'." );
  1980. // This is catastrophically bad, don't do this. Someone needs to fix this.
  1981. DebuggerBreakIfDebugging_StagingOnly();
  1982. return;
  1983. }
  1984. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1985. {
  1986. // search by object
  1987. if ( m_TextureList[i] == pTexture )
  1988. {
  1989. // This code is always sure that the texture we're tryign to clean up is no longer in the the possibly unreferenced list,
  1990. // So let Destroy work without checking.
  1991. ITextureInternal::Destroy( m_TextureList[i], true );
  1992. m_TextureList.RemoveAt( i );
  1993. break;
  1994. }
  1995. }
  1996. }
  1997. void CTextureManager::ReloadFilesInList( IFileList *pFilesToReload )
  1998. {
  1999. if ( !IsPC() )
  2000. return;
  2001. for ( int i=m_TextureList.First(); i != m_TextureList.InvalidIndex(); i=m_TextureList.Next( i ) )
  2002. {
  2003. ITextureInternal *pTex = m_TextureList[i];
  2004. pTex->ReloadFilesInList( pFilesToReload );
  2005. }
  2006. }
  2007. void CTextureManager::ReleaseTempRenderTargetBits( void )
  2008. {
  2009. if( IsX360() ) //only sane on 360
  2010. {
  2011. int iNext;
  2012. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = iNext )
  2013. {
  2014. iNext = m_TextureList.Next( i );
  2015. if ( m_TextureList[i]->IsTempRenderTarget() )
  2016. {
  2017. m_TextureList[i]->ReleaseMemory();
  2018. }
  2019. }
  2020. }
  2021. }
  2022. void CTextureManager::DebugPrintUsedTextures( void )
  2023. {
  2024. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  2025. {
  2026. ITextureInternal *pTexture = m_TextureList[i];
  2027. Msg( "Texture: '%s' RefCount: %d\n", pTexture->GetName(), pTexture->GetReferenceCount() );
  2028. }
  2029. if ( m_TextureExcludes.Count() )
  2030. {
  2031. Msg( "\nExcluded Textures: (%d)\n", m_TextureExcludes.Count() );
  2032. for ( int i = m_TextureExcludes.First(); i != m_TextureExcludes.InvalidIndex(); i = m_TextureExcludes.Next( i ) )
  2033. {
  2034. char buff[256];
  2035. const char *pName = m_TextureExcludes.GetElementName( i );
  2036. V_snprintf( buff, sizeof( buff ), "Excluded: %d '%s' \n", m_TextureExcludes[i], pName );
  2037. // an excluded texture is valid, but forced tiny
  2038. if ( IsTextureLoaded( pName ) )
  2039. {
  2040. Msg( "%s", buff );
  2041. }
  2042. else
  2043. {
  2044. // warn as unknown, could be a spelling error
  2045. Warning( "%s", buff );
  2046. }
  2047. }
  2048. }
  2049. }
  2050. int CTextureManager::FindNext( int iIndex, ITextureInternal **pTexInternal )
  2051. {
  2052. if ( iIndex == -1 && m_TextureList.Count() )
  2053. {
  2054. iIndex = m_TextureList.First();
  2055. }
  2056. else if ( !m_TextureList.Count() || !m_TextureList.IsValidIndex( iIndex ) )
  2057. {
  2058. *pTexInternal = NULL;
  2059. return -1;
  2060. }
  2061. *pTexInternal = m_TextureList[iIndex];
  2062. iIndex = m_TextureList.Next( iIndex );
  2063. if ( iIndex == m_TextureList.InvalidIndex() )
  2064. {
  2065. // end of list
  2066. iIndex = -1;
  2067. }
  2068. return iIndex;
  2069. }
  2070. void CTextureManager::Update()
  2071. {
  2072. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2073. #ifdef STAGING_ONLY
  2074. if ( mat_texture_list_dump.GetBool() )
  2075. {
  2076. DumpTextureList();
  2077. mat_texture_list_dump.SetValue( 0 );
  2078. }
  2079. #endif
  2080. if ( m_pAsyncReader )
  2081. m_pAsyncReader->ThreadMain_Update();
  2082. }
  2083. // Load a texture asynchronously and then call the provided callback.
  2084. void CTextureManager::AsyncFindOrLoadTexture( const char *pTextureName, const char *pTextureGroupName, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs, bool bComplain, int nAdditionalCreationFlags )
  2085. {
  2086. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2087. bool bStreamingRequest = ( nAdditionalCreationFlags & TEXTUREFLAGS_STREAMABLE ) != 0;
  2088. ITextureInternal* pLoadedTex = FindTexture( pTextureName );
  2089. // It'd be weird to indicate that we're streaming and not actually have a texture that already exists.
  2090. Assert( !bStreamingRequest || pLoadedTex != NULL );
  2091. if ( pLoadedTex )
  2092. {
  2093. if ( !bStreamingRequest )
  2094. {
  2095. if ( pLoadedTex->IsError() && bComplain )
  2096. DevWarning( "Texture '%s' not found.\n", pTextureName );
  2097. pRecipient->OnAsyncFindComplete( pLoadedTex, pExtraArgs );
  2098. SafeRelease( pRecipient );
  2099. return;
  2100. }
  2101. }
  2102. AsyncLoadJob_t asyncLoad( pTextureName, pTextureGroupName, pRecipient, pExtraArgs, bComplain, nAdditionalCreationFlags );
  2103. // If this is the first person asking to load this, then remember so we don't load the same thing over and over again.
  2104. int pendingIndex = m_PendingAsyncLoads.Find( pTextureName );
  2105. if ( pendingIndex == m_PendingAsyncLoads.InvalidIndex() )
  2106. {
  2107. // Create the texture here, we'll load the data in the async thread. Load is a misnomer, because it doesn't actually
  2108. // load the data--Download does.
  2109. if ( bStreamingRequest )
  2110. asyncLoad.m_pResultData = pLoadedTex;
  2111. else
  2112. asyncLoad.m_pResultData = LoadTexture( pTextureName, pTextureGroupName, nAdditionalCreationFlags, false );
  2113. AsyncLoad( asyncLoad );
  2114. pendingIndex = m_PendingAsyncLoads.Insert( pTextureName );
  2115. }
  2116. else
  2117. {
  2118. // If this is a thing we've seen before, just note that we also need it.
  2119. m_PendingAsyncLoads[ pendingIndex ].AddToTail( asyncLoad );
  2120. }
  2121. }
  2122. void CTextureManager::CompleteAsyncLoad( AsyncLoadJob_t* pJob )
  2123. {
  2124. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2125. Assert( pJob );
  2126. bool bDownloaded = false;
  2127. if ( !IsJobCancelled( pJob ) )
  2128. {
  2129. // Perform the download. We did the read already.
  2130. pJob->m_pResultData->Download( NULL, pJob->m_nAdditionalCreationFlags );
  2131. bDownloaded = true;
  2132. }
  2133. // Then notify the caller that they're finished.
  2134. pJob->m_pRecipient->OnAsyncFindComplete( pJob->m_pResultData, pJob->m_pExtraArgs );
  2135. // Finally, deal with any other stragglers that asked for the same surface we did.
  2136. int pendingIndex = m_PendingAsyncLoads.Find( pJob->m_TextureName.Get() );
  2137. Assert( pendingIndex != m_PendingAsyncLoads.InvalidIndex() );
  2138. FOR_EACH_VEC( m_PendingAsyncLoads[ pendingIndex ], i )
  2139. {
  2140. AsyncLoadJob_t& straggler = m_PendingAsyncLoads[ pendingIndex ][ i ];
  2141. straggler.m_pResultData = pJob->m_pResultData;
  2142. if ( !bDownloaded && !IsJobCancelled( &straggler ) )
  2143. {
  2144. bDownloaded = true;
  2145. straggler.m_pResultData->Download( NULL, straggler.m_nAdditionalCreationFlags );
  2146. }
  2147. straggler.m_pRecipient->OnAsyncFindComplete( straggler.m_pResultData, straggler.m_pExtraArgs );
  2148. SafeRelease( &straggler.m_pRecipient );
  2149. }
  2150. // Add ourselves to the list of loaded things.
  2151. if ( bDownloaded )
  2152. {
  2153. // The texture list has to be protected by the materials lock.
  2154. MaterialLock_t hMaterialLock = materials->Lock();
  2155. // It's possible that the texture wasn't actually unloaded, so we may have reloaded something unnecessarily.
  2156. // If so, just don't re-add it.
  2157. if ( m_TextureList.Find( pJob->m_pResultData->GetName() ) == m_TextureList.InvalidIndex() )
  2158. m_TextureList.Insert( pJob->m_pResultData->GetName(), pJob->m_pResultData );
  2159. materials->Unlock( hMaterialLock );
  2160. }
  2161. else
  2162. {
  2163. // If we didn't download, need to clean up the leftover file data that we loaded on the other thread
  2164. pJob->m_pResultData->AsyncCancelReadTexture();
  2165. }
  2166. // Can't release the Recipient until after we tell the stragglers, because the recipient may be the only
  2167. // ref to the texture, and cleaning it up may clean up the texture but leave us with a seemingly valid pointer.
  2168. SafeRelease( &pJob->m_pRecipient );
  2169. // Dump out the whole lot.
  2170. m_PendingAsyncLoads.RemoveAt( pendingIndex );
  2171. }
  2172. void CTextureManager::AsyncLoad( const AsyncLoadJob_t& job )
  2173. {
  2174. Assert( m_pAsyncLoader );
  2175. m_pAsyncLoader->AsyncLoad( job );
  2176. }
  2177. void CTextureManager::AsyncCreateTextureFromRenderTarget( ITexture* pSrcRt, const char* pDstName, ImageFormat dstFmt, bool bGenMips, int nAdditionalCreationFlags, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
  2178. {
  2179. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2180. Assert( pSrcRt );
  2181. AsyncReadJob_t* pAsyncRead = new AsyncReadJob_t( pSrcRt, pDstName, dstFmt, bGenMips, nAdditionalCreationFlags, pRecipient, pExtraArgs );
  2182. AsyncReadTexture( pAsyncRead );
  2183. }
  2184. void CTextureManager::CompleteAsyncRead( AsyncReadJob_t* pJob )
  2185. {
  2186. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2187. // Release the texture back into the pool.
  2188. ReleaseReadbackTexture( pJob->m_pSysmemTex );
  2189. pJob->m_pSysmemTex = NULL;
  2190. int w = pJob->m_pSrcRt->GetActualWidth();
  2191. int h = pJob->m_pSrcRt->GetActualHeight();
  2192. int mips = pJob->m_bGenMips ? ImageLoader::GetNumMipMapLevels( w, h ) : 1;
  2193. int nFlags = pJob->m_nAdditionalCreationFlags
  2194. | TEXTUREFLAGS_SINGLECOPY
  2195. | TEXTUREFLAGS_IGNORE_PICMIP
  2196. | ( mips > 1
  2197. ? TEXTUREFLAGS_ALL_MIPS
  2198. : TEXTUREFLAGS_NOMIP
  2199. )
  2200. ;
  2201. // Create the texture
  2202. ITexture* pFinalTex = materials->CreateNamedTextureFromBitsEx( pJob->m_pDstName, TEXTURE_GROUP_RUNTIME_COMPOSITE, w, h, mips, pJob->m_dstFmt, pJob->m_finalTexelData.Count(), pJob->m_finalTexelData.Base(), nFlags );
  2203. Assert( pFinalTex );
  2204. // Make the callback!
  2205. pJob->m_pRecipient->OnAsyncCreateComplete( pFinalTex, pJob->m_pExtraArgs );
  2206. SafeRelease( &pJob->m_pSrcRt );
  2207. SafeRelease( &pJob->m_pRecipient );
  2208. SafeRelease( &pFinalTex );
  2209. }
  2210. void CTextureManager::AsyncReadTexture( AsyncReadJob_t* pJob )
  2211. {
  2212. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2213. Assert( m_pAsyncReader );
  2214. Assert( pJob );
  2215. pJob->m_pSysmemTex = AcquireReadbackTexture( pJob->m_pSrcRt->GetActualWidth(), pJob->m_pSrcRt->GetActualHeight(), pJob->m_pSrcRt->GetImageFormat() );
  2216. Assert( pJob->m_pSysmemTex );
  2217. if ( !pJob->m_pSysmemTex )
  2218. {
  2219. Assert( !"Need to deal with this error case" ); // TODOERROR
  2220. return;
  2221. }
  2222. m_pAsyncReader->AsyncReadback( pJob );
  2223. }
  2224. ITextureInternal* CTextureManager::AcquireReadbackTexture( int w, int h, ImageFormat fmt )
  2225. {
  2226. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2227. {
  2228. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s-TryExisting", __FUNCTION__ );
  2229. MaterialLock_t hMaterialLock = materials->Lock();
  2230. FOR_EACH_VEC( m_ReadbackTextures, i )
  2231. {
  2232. ITextureInternal* pTex = m_ReadbackTextures[ i ];
  2233. Assert( pTex );
  2234. if ( pTex->GetActualWidth() == w
  2235. && pTex->GetActualHeight() == h
  2236. && pTex->GetImageFormat() == fmt )
  2237. {
  2238. // Found one in the cache already
  2239. pTex->AddRef();
  2240. m_ReadbackTextures.Remove( i );
  2241. materials->Unlock( hMaterialLock );
  2242. return pTex;
  2243. }
  2244. }
  2245. materials->Unlock( hMaterialLock );
  2246. }
  2247. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s-CreateNew", __FUNCTION__ );
  2248. ITextureInternal* stagingTex = CreateProceduralTexture( "readbacktex", TEXTURE_GROUP_OTHER, w, h, 1, fmt, TEXTUREFLAGS_STAGING_MEMORY | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_IMMEDIATE_CLEANUP );
  2249. // AddRef here for caller.
  2250. stagingTex->AddRef();
  2251. return stagingTex;
  2252. }
  2253. void CTextureManager::ReleaseReadbackTexture( ITextureInternal* pTex )
  2254. {
  2255. Assert( pTex );
  2256. MaterialLock_t hMaterialLock = materials->Lock();
  2257. // Release matching AddRef in AcquireReadbackTexture
  2258. pTex->Release();
  2259. m_ReadbackTextures.AddToTail( pTex );
  2260. materials->Unlock( hMaterialLock );
  2261. }
  2262. #ifdef STAGING_ONLY
  2263. static int SortTexturesForDump( const CUtlPair< CUtlString, void* >* sz1, const CUtlPair< CUtlString, void* >* sz2 )
  2264. {
  2265. int sortVal = CUtlString::SortCaseSensitive( &sz1->first, &sz2->first );
  2266. if ( sortVal != 0 )
  2267. return sortVal;
  2268. return int( ( int ) sz1->second - ( int ) sz2->second );
  2269. }
  2270. void CTextureManager::DumpTextureList()
  2271. {
  2272. CUtlVector< CUtlPair< CUtlString, void* > > textures;
  2273. MaterialLock_t hMaterialLock = materials->Lock();
  2274. FOR_EACH_DICT( m_TextureList, i )
  2275. {
  2276. textures.AddToTail( MakeUtlPair( CUtlString( m_TextureList[i]->GetName() ), (void*) m_TextureList[i] ) );
  2277. }
  2278. materials->Unlock( hMaterialLock );
  2279. // Now dump them out, sorted first by the texture name, then by address.
  2280. textures.Sort( SortTexturesForDump );
  2281. FOR_EACH_VEC( textures, i )
  2282. {
  2283. CUtlPair< CUtlString, void* >& pair = textures[i];
  2284. Warning( "[%p]: %s\n", pair.second, pair.first.Get() ) ;
  2285. }
  2286. }
  2287. #endif
  2288. //-----------------------------------------------------------------------------
  2289. // Warms the texture cache from a vpk. This will cause coarse mipmaps to be
  2290. // available all the time, starting with mipmap level 3. This allows us to have
  2291. // all the textures available all the time, but we only pay for fine levels when
  2292. // we actually need them.
  2293. //-----------------------------------------------------------------------------
  2294. void CTextureManager::WarmTextureCache()
  2295. {
  2296. // Disable cache for osx/linux for now.
  2297. if ( CommandLine()->CheckParm( "-no_texture_stream" ) )
  2298. return;
  2299. MemoryInformation memInfo;
  2300. if ( GetMemoryInformation( &memInfo ) )
  2301. {
  2302. if ( memInfo.m_nPhysicalRamMbTotal <= 3584 )
  2303. return;
  2304. }
  2305. COM_TimestampedLog( "WarmTextureCache() - Begin" );
  2306. // If this fires, we need to relocate this elsewhere--there's no point in doing the loading
  2307. // if we're not going to be able to download them right now.
  2308. Assert( g_pShaderAPI->CanDownloadTextures() );
  2309. g_pFullFileSystem->AddSearchPath( "tf2_texture_cache.vpk", cTextureCachePathDir, PATH_ADD_TO_TAIL );
  2310. CUtlDict< int > filesToLoad( k_eDictCompareTypeCaseSensitive );
  2311. // TODO: Maybe work directly with VPK (still need to add to the filesystem for LoadTexture)?
  2312. // CPackFile
  2313. // Add the pak and then walk through the contents.
  2314. FindFilesToLoad( &filesToLoad, "*.*" );
  2315. // Then add the list of files from the cache, which will deal with running without a VPK and also
  2316. // allow us to add late stragglers.
  2317. ReadFilesToLoad( &filesToLoad, "texture_preload_list.txt" );
  2318. if ( filesToLoad.Count() == 0 )
  2319. {
  2320. COM_TimestampedLog( "WarmTextureCache() - End (No files loaded)" );
  2321. return;
  2322. }
  2323. Assert( filesToLoad.Count() > 0 );
  2324. // Now read all of the files.
  2325. // TODO: This needs to read in specific order to ensure peak performance.
  2326. FOR_EACH_DICT( filesToLoad, i )
  2327. {
  2328. const char* pFilename = filesToLoad.GetElementName( i );
  2329. // Load the texture. This will only load the lower mipmap levels because that's the file we'll find now.
  2330. ITextureInternal* pTex = LoadTexture( pFilename, TEXTURE_GROUP_PRECACHED, TEXTUREFLAGS_STREAMABLE_COARSE );
  2331. COM_TimestampedLog( "WarmTextureCache(): LoadTexture( %s ): Complete", pFilename );
  2332. if ( ( pTex->GetFlags() & TEXTUREFLAGS_STREAMABLE ) == 0 )
  2333. {
  2334. STAGING_ONLY_EXEC( Warning( "%s is listed in texture_preload_list.txt or is otherwise marked for streaming. It cannot be streamed and should be removed from the streaming system.\n", pFilename ) );
  2335. ITextureInternal::Destroy( pTex );
  2336. continue;
  2337. }
  2338. if ( !pTex->IsError() )
  2339. {
  2340. m_TextureList.Insert( pTex->GetName(), pTex );
  2341. pTex->AddRef();
  2342. m_preloadedTextures.AddToTail( pTex );
  2343. }
  2344. else
  2345. {
  2346. // Don't preload broken textures
  2347. ITextureInternal::Destroy( pTex );
  2348. }
  2349. }
  2350. g_pFullFileSystem->RemoveSearchPath( "tf2_texture_cache.vpk", cTextureCachePathDir );
  2351. COM_TimestampedLog( "WarmTextureCache() - End" );
  2352. }
  2353. //-----------------------------------------------------------------------------
  2354. // Reads the list of files contained in the vpk loaded above, and adds them to the
  2355. // list of files we need to load (passing in as pOutFilesToLoad). The map contains
  2356. // the
  2357. //-----------------------------------------------------------------------------
  2358. void CTextureManager::FindFilesToLoad( CUtlDict< int >* pOutFilesToLoad, const char* pFilename )
  2359. {
  2360. Assert( pOutFilesToLoad != NULL );
  2361. FileFindHandle_t fh;
  2362. pFilename = g_pFullFileSystem->FindFirstEx( pFilename, cTextureCachePathDir, &fh );
  2363. while ( pFilename != NULL )
  2364. {
  2365. if ( g_pFullFileSystem->FindIsDirectory( fh ) )
  2366. {
  2367. if ( pFilename[0] != '.' )
  2368. {
  2369. char childFilename[_MAX_PATH];
  2370. V_sprintf_safe( childFilename, "%s/*.*", pFilename );
  2371. FindFilesToLoad( pOutFilesToLoad, childFilename );
  2372. }
  2373. }
  2374. else
  2375. {
  2376. char filenameNoExtension[_MAX_PATH];
  2377. V_StripExtension( pFilename, filenameNoExtension, _MAX_PATH );
  2378. // Add the file to the list, which we will later traverse in order to ensure we're hitting these in the expected order for the VPK.
  2379. ( *pOutFilesToLoad ).Insert( CUtlString( filenameNoExtension ), 0 );
  2380. }
  2381. pFilename = g_pFullFileSystem->FindNext( fh );
  2382. }
  2383. }
  2384. //-----------------------------------------------------------------------------
  2385. // Read the contents of pFilename, which should just be a list of texture names
  2386. // that we should load.
  2387. //-----------------------------------------------------------------------------
  2388. void CTextureManager::ReadFilesToLoad( CUtlDict< int >* pOutFilesToLoad, const char* pFilename )
  2389. {
  2390. Assert( pOutFilesToLoad != NULL );
  2391. FileHandle_t fh = g_pFullFileSystem->Open( pFilename, "r" );
  2392. if ( !fh )
  2393. return;
  2394. CUtlBuffer fileContents( 0, 0, CUtlBuffer::TEXT_BUFFER );
  2395. if ( !g_pFullFileSystem->ReadToBuffer( fh, fileContents ) )
  2396. goto cleanup;
  2397. char buffer[_MAX_PATH + 1];
  2398. while ( 1 )
  2399. {
  2400. fileContents.GetLine( buffer, _MAX_PATH );
  2401. if ( buffer[ 0 ] == 0 )
  2402. break;
  2403. V_StripWhitespace( buffer );
  2404. if ( buffer[ 0 ] == 0 )
  2405. continue;
  2406. // If it's not in the map already, add it.
  2407. if ( pOutFilesToLoad->Find( buffer ) == pOutFilesToLoad->InvalidIndex() )
  2408. ( *pOutFilesToLoad ).Insert( buffer, 0 );
  2409. }
  2410. cleanup:
  2411. g_pFullFileSystem->Close( fh );
  2412. }
  2413. void CTextureManager::UpdatePostAsync()
  2414. {
  2415. TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
  2416. // Update the async loader, which affects streaming in (streaming out is handled below).
  2417. // Both stream in and stream out have to happen while the async job is not running because
  2418. // they muck with shaderapi texture handles which could be in use if the async job is currently
  2419. // being run
  2420. if ( m_pAsyncLoader )
  2421. m_pAsyncLoader->ThreadMain_Update();
  2422. // First, move everything from the async request queue to active list
  2423. ITextureInternal* pRequest = NULL;
  2424. while ( m_asyncStreamingRequests.PopItem( &pRequest ) )
  2425. {
  2426. Assert( pRequest != NULL );
  2427. // Update the LOD bias to smoothly stream the texture in. We only need to do this on frames that
  2428. // we actually have been requested to draw--other frames it doesn't matter (see, because we're not drawing?)
  2429. pRequest->UpdateLodBias();
  2430. m_textureStreamingRequests.InsertOrReplace( pRequest, g_FrameNum );
  2431. }
  2432. // Then update streaming
  2433. const int cThirtySecondsOrSoInFrames = 2000;
  2434. // First, remove old stuff.
  2435. FOR_EACH_MAP_FAST( m_textureStreamingRequests, i )
  2436. {
  2437. if ( m_textureStreamingRequests[ i ] + cThirtySecondsOrSoInFrames < g_FrameNum )
  2438. {
  2439. ITextureInternal* pTex = m_textureStreamingRequests.Key( i );
  2440. // It's been awhile since we were asked to full res this texture, so let's evict
  2441. // if it's still full res.
  2442. if ( pTex->GetTargetResidence() == RESIDENT_FULL )
  2443. pTex->MakeResident( RESIDENT_PARTIAL );
  2444. m_textureStreamingRequests.RemoveAt( i );
  2445. }
  2446. }
  2447. // Then, start allowing new stuff to ask for data.
  2448. FOR_EACH_MAP_FAST( m_textureStreamingRequests, i )
  2449. {
  2450. int requestFrame = m_textureStreamingRequests[ i ];
  2451. if ( g_FrameNum == requestFrame )
  2452. {
  2453. ITextureInternal* pTex = m_textureStreamingRequests.Key( i );
  2454. if ( pTex->GetTargetResidence() == RESIDENT_FULL )
  2455. continue;
  2456. // TODO: What to do if this fails? Auto-reask next frame?
  2457. pTex->MakeResident( RESIDENT_FULL );
  2458. }
  2459. }
  2460. // Finally, flush any immediate release textures marked for cleanup that are still unreferenced.
  2461. CleanupPossiblyUnreferencedTextures();
  2462. }
  2463. void CTextureManager::ReleaseAsyncScratchVTF( IVTFTexture *pScratchVTF )
  2464. {
  2465. Assert( m_pAsyncLoader != NULL && pScratchVTF != NULL );
  2466. m_pAsyncLoader->ReleaseAsyncReadBuffer( pScratchVTF );
  2467. }
  2468. bool CTextureManager::ThreadInAsyncLoadThread() const
  2469. {
  2470. return ThreadGetCurrentId() == m_nAsyncLoadThread;
  2471. }
  2472. bool CTextureManager::ThreadInAsyncReadThread() const
  2473. {
  2474. return ThreadGetCurrentId() == m_nAsyncReadThread;
  2475. }
  2476. bool CTextureManager::AddTextureCompositorTemplate( const char* pName, KeyValues* pTmplDesc )
  2477. {
  2478. Assert( pName && pTmplDesc );
  2479. int ndx = m_TexCompTemplates.Find( pName );
  2480. if ( ndx != m_TexCompTemplates.InvalidIndex() )
  2481. {
  2482. // Later definitions stomp earlier ones. This lets the GC win.
  2483. delete m_TexCompTemplates[ ndx ];
  2484. m_TexCompTemplates.RemoveAt( ndx );
  2485. }
  2486. CTextureCompositorTemplate* pNewTmpl = CTextureCompositorTemplate::Create( pName, pTmplDesc );
  2487. // If this is the case, the logging has already been done.
  2488. if ( pNewTmpl == NULL )
  2489. return false;
  2490. m_TexCompTemplates.Insert( pName, pNewTmpl );
  2491. return true;
  2492. }
  2493. bool CTextureManager::VerifyTextureCompositorTemplates()
  2494. {
  2495. TM_ZONE_DEFAULT( TELEMETRY_LEVEL1 );
  2496. bool allSuccess = true;
  2497. FOR_EACH_DICT_FAST( m_TexCompTemplates, i )
  2498. {
  2499. if ( m_TexCompTemplates[ i ]->ResolveDependencies() )
  2500. {
  2501. if ( m_TexCompTemplates[ i ]->HasDependencyCycles() )
  2502. {
  2503. allSuccess = false;
  2504. }
  2505. }
  2506. else
  2507. {
  2508. allSuccess = false;
  2509. }
  2510. }
  2511. return allSuccess;
  2512. }
  2513. CTextureCompositorTemplate* CTextureManager::FindTextureCompositorTemplate( const char* pName )
  2514. {
  2515. unsigned short i = m_TexCompTemplates.Find( pName );
  2516. if ( m_TexCompTemplates.IsValidIndex( i ) )
  2517. return m_TexCompTemplates[ i ];
  2518. return NULL;
  2519. }
  2520. bool CTextureManager::HasPendingTextureDestroys() const
  2521. {
  2522. return m_PossiblyUnreferencedTextures.Count() != 0;
  2523. }
  2524. void CTextureManager::CoolTextureCache()
  2525. {
  2526. FOR_EACH_VEC( m_preloadedTextures, i )
  2527. {
  2528. m_preloadedTextures[ i ]->Release();
  2529. }
  2530. m_preloadedTextures.RemoveAll();
  2531. }
  2532. void CTextureManager::RequestAllMipmaps( ITextureInternal* pTex )
  2533. {
  2534. Assert( pTex );
  2535. // Don't mark these for load if suspended
  2536. if ( m_iSuspendTextureStreaming )
  2537. return;
  2538. unsigned int nTexFlags = pTex->GetFlags();
  2539. // If this isn't a streamable texture or if there are no mipmaps, there's nothing to do.
  2540. if ( !( nTexFlags & TEXTUREFLAGS_STREAMABLE ) || ( nTexFlags & TEXTUREFLAGS_NOMIP ) )
  2541. return;
  2542. m_asyncStreamingRequests.PushItem( pTex );
  2543. }
  2544. void CTextureManager::EvictAllTextures()
  2545. {
  2546. FOR_EACH_DICT_FAST( m_TextureList, i )
  2547. {
  2548. ITextureInternal* pTex = m_TextureList[ i ];
  2549. if ( !pTex )
  2550. continue;
  2551. // If the fine mipmaps are present
  2552. if ( ( ( pTex->GetFlags() & TEXTUREFLAGS_STREAMABLE ) != 0 ) && pTex->GetTargetResidence() == RESIDENT_FULL )
  2553. pTex->MakeResident( RESIDENT_PARTIAL );
  2554. }
  2555. }
  2556. CON_COMMAND( mat_evict_all, "Evict all fine mipmaps from the gpu" )
  2557. {
  2558. TextureManager()->EvictAllTextures();
  2559. }
  2560. // ------------------------------------------------------------------------------------------------
  2561. // ------------------------------------------------------------------------------------------------
  2562. // ------------------------------------------------------------------------------------------------
  2563. static ImageFormat GetImageFormatRawReadback( ImageFormat fmt )
  2564. {
  2565. switch ( fmt )
  2566. {
  2567. case IMAGE_FORMAT_RGBA8888:
  2568. return IMAGE_FORMAT_BGRA8888;
  2569. case IMAGE_FORMAT_BGRA8888:
  2570. return IMAGE_FORMAT_BGRA8888;
  2571. default:
  2572. Assert( !"Unsupported format in GetImageFormatRawReadback, this will likely result in color-swapped textures" );
  2573. };
  2574. return fmt;
  2575. }