Counter Strike : Global Offensive Source Code
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.

2222 lines
59 KiB

  1. //========== Copyright � 2005, Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose: Texture heap.
  4. //
  5. //=============================================================================
  6. #include "tier1/mempool.h"
  7. #include "tier1/convar.h"
  8. #include "tier1/utlmap.h"
  9. #include "shaderapidx8.h"
  10. #include "texturedx8.h"
  11. #include "textureheap.h"
  12. #include "shaderapidx8_global.h"
  13. #include "filesystem.h"
  14. #include "vstdlib/jobthread.h"
  15. #include "tier0/icommandline.h"
  16. #include "tier0/memdbgon.h"
  17. struct THFreeBlock_t
  18. {
  19. THInfo_t heapInfo;
  20. THFreeBlock_t *pPrevFree, *pNextFree;
  21. };
  22. #define BASE_COLOR_BEFORE 0xBB // funky color to show texture while i/o in progress
  23. #define BASE_COLOR_AFTER 0xCC // funky color to show mip0 texture
  24. enum TextureHeapDebug_t
  25. {
  26. THD_OFF = 0,
  27. THD_COLORIZE_BEFOREIO, // mip0 is colorized until i/o replaces with real bits
  28. THD_COLORIZE_AFTERIO, // mip0 is colorized instead of i/o real bits
  29. THD_SPEW
  30. };
  31. ConVar texture_heap_debug( "texture_heap_debug", "0", 0, "0:Off, 1:Color Before I/O 2:Color After I/O 3:Spew" );
  32. bool g_bUseStandardAllocator = true; // mixed texture heap is not yet viable
  33. bool g_bUseBasePools = true; // do texture streaming
  34. void GetCommandLineArgs()
  35. {
  36. #if defined( SUPPORTS_TEXTURE_STREAMING )
  37. static bool bReadCommandLine;
  38. if ( !bReadCommandLine )
  39. {
  40. bReadCommandLine = true;
  41. if ( g_pFullFileSystem->IsDVDHosted() )
  42. {
  43. g_bUseBasePools = false;
  44. }
  45. if ( CommandLine()->FindParm( "-notextureheap" ) )
  46. {
  47. g_bUseStandardAllocator = true;
  48. }
  49. if ( CommandLine()->FindParm( "-notexturestreaming" ) )
  50. {
  51. g_bUseBasePools = false;
  52. }
  53. }
  54. #else
  55. g_bUseStandardAllocator = true;
  56. g_bUseBasePools = false;
  57. #endif
  58. }
  59. bool UseStandardAllocator()
  60. {
  61. GetCommandLineArgs();
  62. return g_bUseStandardAllocator;
  63. }
  64. bool UseBasePoolsForStreaming()
  65. {
  66. GetCommandLineArgs();
  67. return g_bUseBasePools;
  68. }
  69. #if !defined( _RELEASE ) && !defined( _CERT )
  70. #define StrongAssert( expr ) if ( (expr) ) ; else { DebuggerBreak(); }
  71. #else
  72. #define StrongAssert( expr ) ((void)0)
  73. #endif
  74. //-----------------------------------------------------------------------------
  75. // Set Texture HW bases
  76. //-----------------------------------------------------------------------------
  77. inline void SetD3DTextureBasePtr( IDirect3DBaseTexture* pTex, void *pBaseBuffer )
  78. {
  79. pTex->Format.BaseAddress = ((unsigned int)pBaseBuffer) >> 12;
  80. }
  81. inline void SetD3DTextureMipPtr( IDirect3DBaseTexture* pTex, void *pMipBuffer )
  82. {
  83. pTex->Format.MipAddress = ((unsigned int)pMipBuffer) >> 12;
  84. }
  85. MEMALLOC_DEFINE_EXTERNAL_TRACKING(CD3DPoolAllocator);
  86. // only used for the pool allocators
  87. class CD3DPoolAllocator
  88. {
  89. public:
  90. static void *Alloc( int bytes )
  91. {
  92. DWORD attributes = MAKE_XALLOC_ATTRIBUTES(
  93. 0,
  94. false,
  95. TRUE,
  96. FALSE,
  97. eXALLOCAllocatorId_D3D,
  98. XALLOC_PHYSICAL_ALIGNMENT_4K,
  99. XALLOC_MEMPROTECT_WRITECOMBINE,
  100. FALSE,
  101. XALLOC_MEMTYPE_PHYSICAL );
  102. void *retval = XMemAlloc( bytes, attributes );
  103. MemAlloc_RegisterExternalAllocation( CD3DPoolAllocator, retval, XPhysicalSize( retval ) );
  104. return retval;
  105. }
  106. static void Free( void *p )
  107. {
  108. DWORD attributes = MAKE_XALLOC_ATTRIBUTES(
  109. 0,
  110. false,
  111. TRUE,
  112. FALSE,
  113. eXALLOCAllocatorId_D3D,
  114. XALLOC_PHYSICAL_ALIGNMENT_4K,
  115. XALLOC_MEMPROTECT_WRITECOMBINE,
  116. FALSE,
  117. XALLOC_MEMTYPE_PHYSICAL );
  118. MemAlloc_RegisterExternalDeallocation( CD3DPoolAllocator, p, XPhysicalSize( p ) );
  119. XMemFree( p, attributes );
  120. }
  121. };
  122. MEMALLOC_DEFINE_EXTERNAL_TRACKING(CD3DStandardAllocator);
  123. class CD3DStandardAllocator
  124. {
  125. public:
  126. static void *Alloc( int bytes )
  127. {
  128. DWORD attributes = MAKE_XALLOC_ATTRIBUTES(
  129. 0,
  130. false,
  131. TRUE,
  132. FALSE,
  133. eXALLOCAllocatorId_D3D,
  134. XALLOC_PHYSICAL_ALIGNMENT_4K,
  135. XALLOC_MEMPROTECT_WRITECOMBINE,
  136. FALSE,
  137. XALLOC_MEMTYPE_PHYSICAL );
  138. m_nTotalAllocations++;
  139. m_nTotalSize += AlignValue( bytes, 4096 );
  140. void *retval = XMemAlloc( bytes, attributes );
  141. MemAlloc_RegisterExternalAllocation( CD3DStandardAllocator, retval, XPhysicalSize( retval ) );
  142. return retval;
  143. }
  144. static void Free( void *p )
  145. {
  146. DWORD attributes = MAKE_XALLOC_ATTRIBUTES(
  147. 0,
  148. false,
  149. TRUE,
  150. FALSE,
  151. eXALLOCAllocatorId_D3D,
  152. XALLOC_PHYSICAL_ALIGNMENT_4K,
  153. XALLOC_MEMPROTECT_WRITECOMBINE,
  154. FALSE,
  155. XALLOC_MEMTYPE_PHYSICAL );
  156. m_nTotalAllocations--;
  157. m_nTotalSize -= XMemSize( p, attributes );
  158. MemAlloc_RegisterExternalDeallocation( CD3DStandardAllocator, p, XPhysicalSize( p ) );
  159. XMemFree( p, attributes );
  160. }
  161. static int GetAllocations()
  162. {
  163. return m_nTotalAllocations;
  164. }
  165. static int GetSize()
  166. {
  167. return m_nTotalSize;
  168. }
  169. static int m_nTotalSize;
  170. static int m_nTotalAllocations;
  171. };
  172. int CD3DStandardAllocator::m_nTotalSize;
  173. int CD3DStandardAllocator::m_nTotalAllocations;
  174. void SetD3DTextureImmobile( IDirect3DBaseTexture *pTexture, bool bImmobile )
  175. {
  176. if ( pTexture->GetType() == D3DRTYPE_TEXTURE )
  177. {
  178. (( CXboxTexture *)pTexture)->bImmobile = bImmobile;
  179. }
  180. }
  181. CXboxTexture *GetTexture( THInfo_t *pInfo )
  182. {
  183. if ( !pInfo->bFree && !pInfo->bNonTexture )
  184. {
  185. return (CXboxTexture *)((byte *)pInfo - offsetof( CXboxTexture, m_fAllocator ));
  186. }
  187. return NULL;
  188. }
  189. inline THFreeBlock_t *GetFreeBlock( THInfo_t *pInfo )
  190. {
  191. if ( pInfo->bFree )
  192. {
  193. return (THFreeBlock_t *)((byte *)pInfo - offsetof( THFreeBlock_t, heapInfo ));
  194. }
  195. return NULL;
  196. }
  197. MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMixedTextureHeap);
  198. class CMixedTextureHeap
  199. {
  200. enum
  201. {
  202. SIZE_ALIGNMENT = XBOX_HDD_SECTORSIZE,
  203. MIN_BLOCK_SIZE = 1024,
  204. };
  205. public:
  206. CMixedTextureHeap() :
  207. m_nLogicalBytes( 0 ),
  208. m_nActualBytes( 0 ),
  209. m_nAllocs( 0 ),
  210. m_nOldBytes( 0 ),
  211. m_nNonTextureAllocs( 0 ),
  212. m_nBytesTotal( 0 ),
  213. m_pBase( NULL ),
  214. m_pFirstFree( NULL )
  215. {
  216. }
  217. void Init()
  218. {
  219. extern ConVar mat_texturecachesize;
  220. MEM_ALLOC_CREDIT_( "CMixedTextureHeap" );
  221. m_nBytesTotal = ( mat_texturecachesize.GetInt() * 1024 * 1024 );
  222. #if 0
  223. m_nBytesTotal = AlignValue( m_nBytesTotal, SIZE_ALIGNMENT );
  224. m_pBase = CD3DStandardAllocator::Alloc( m_nBytesTotal );
  225. #else
  226. m_nBytesTotal = AlignValue( m_nBytesTotal, 16*1024*1024 );
  227. m_pBase = XPhysicalAlloc( m_nBytesTotal, MAXULONG_PTR, 4096, PAGE_READWRITE | PAGE_WRITECOMBINE | MEM_16MB_PAGES );
  228. MemAlloc_RegisterExternalAllocation( CMixedTextureHeap, m_pBase, XPhysicalSize( m_pBase ) );
  229. #endif
  230. m_pFirstFree = (THFreeBlock_t *)m_pBase;
  231. m_pFirstFree->heapInfo.bFree = true;
  232. m_pFirstFree->heapInfo.bNonTexture = false;
  233. m_pFirstFree->heapInfo.nBytes = m_nBytesTotal;
  234. m_pFirstFree->heapInfo.pNext = NULL;
  235. m_pFirstFree->heapInfo.pPrev = NULL;
  236. m_pFirstFree->pNextFree = NULL;
  237. m_pFirstFree->pPrevFree = NULL;
  238. m_pLastFree = m_pFirstFree;
  239. }
  240. void *Alloc( int bytes, THInfo_t *pInfo, bool bNonTexture = false )
  241. {
  242. pInfo->nBytes = AlignValue( bytes, SIZE_ALIGNMENT );
  243. if ( !m_pBase )
  244. {
  245. Init();
  246. }
  247. if ( bNonTexture && m_nNonTextureAllocs == 0 )
  248. {
  249. Compact();
  250. }
  251. void *p = FindBlock( pInfo );
  252. if ( !p )
  253. {
  254. p = ExpandToFindBlock( pInfo );
  255. }
  256. if ( p )
  257. {
  258. pInfo->nLogicalBytes = bytes;
  259. pInfo->bNonTexture = bNonTexture;
  260. m_nLogicalBytes += bytes;
  261. m_nOldBytes += AlignValue( bytes, 4096 );
  262. m_nActualBytes += pInfo->nBytes;
  263. m_nAllocs++;
  264. if ( bNonTexture )
  265. {
  266. m_nNonTextureAllocs++;
  267. }
  268. }
  269. return p;
  270. }
  271. void Free( void *p, THInfo_t *pInfo )
  272. {
  273. if ( !p )
  274. {
  275. return;
  276. }
  277. m_nOldBytes -= AlignValue( pInfo->nLogicalBytes, 4096 );
  278. if ( pInfo->bNonTexture )
  279. {
  280. m_nNonTextureAllocs--;
  281. }
  282. m_nLogicalBytes -= pInfo->nLogicalBytes;
  283. m_nAllocs--;
  284. m_nActualBytes -= pInfo->nBytes;
  285. THFreeBlock_t *pFree = (THFreeBlock_t *)p;
  286. pFree->heapInfo = *pInfo;
  287. pFree->heapInfo.bFree = true;
  288. AddToBlocksList( &pFree->heapInfo, pFree->heapInfo.pPrev, pFree->heapInfo.pNext );
  289. pFree = MergeLeft( pFree );
  290. pFree = MergeRight( pFree );
  291. AddToFreeList( pFree );
  292. if ( pInfo->bNonTexture && m_nNonTextureAllocs == 0 )
  293. {
  294. Compact();
  295. }
  296. }
  297. int Size( void *p, THInfo_t *pInfo )
  298. {
  299. return AlignValue( pInfo->nBytes, SIZE_ALIGNMENT );
  300. }
  301. bool IsOwner( void *p )
  302. {
  303. return ( m_pBase && p >= m_pBase && p < (byte *)m_pBase + m_nBytesTotal );
  304. }
  305. //-----------------------------------------------------
  306. void *FindBlock( THInfo_t *pInfo )
  307. {
  308. THFreeBlock_t *pCurrent = m_pFirstFree;
  309. int nBytesDesired = pInfo->nBytes;
  310. // Find the first block big enough to hold, then split it if appropriate
  311. while ( pCurrent && pCurrent->heapInfo.nBytes < nBytesDesired )
  312. {
  313. pCurrent = pCurrent->pNextFree;
  314. }
  315. if ( pCurrent )
  316. {
  317. return ClaimBlock( pCurrent, pInfo );
  318. }
  319. return NULL;
  320. }
  321. void AddToFreeList( THFreeBlock_t *pFreeBlock )
  322. {
  323. pFreeBlock->heapInfo.nLogicalBytes = 0;
  324. if ( m_pFirstFree )
  325. {
  326. THFreeBlock_t *pPrev = NULL;
  327. THFreeBlock_t *pNext = m_pFirstFree;
  328. int nBytes = pFreeBlock->heapInfo.nBytes;
  329. while ( pNext && pNext->heapInfo.nBytes < nBytes )
  330. {
  331. pPrev = pNext;
  332. pNext = pNext->pNextFree;
  333. }
  334. pFreeBlock->pPrevFree = pPrev;
  335. pFreeBlock->pNextFree = pNext;
  336. if ( pPrev )
  337. {
  338. pPrev->pNextFree = pFreeBlock;
  339. }
  340. else
  341. {
  342. m_pFirstFree = pFreeBlock;
  343. }
  344. if ( pNext )
  345. {
  346. pNext->pPrevFree = pFreeBlock;
  347. }
  348. else
  349. {
  350. m_pLastFree = pFreeBlock;
  351. }
  352. }
  353. else
  354. {
  355. pFreeBlock->pPrevFree = pFreeBlock->pNextFree = NULL;
  356. m_pLastFree = m_pFirstFree = pFreeBlock;
  357. }
  358. }
  359. void RemoveFromFreeList( THFreeBlock_t *pFreeBlock )
  360. {
  361. if ( m_pFirstFree == pFreeBlock )
  362. {
  363. m_pFirstFree = m_pFirstFree->pNextFree;
  364. }
  365. else if ( pFreeBlock->pPrevFree )
  366. {
  367. pFreeBlock->pPrevFree->pNextFree = pFreeBlock->pNextFree;
  368. }
  369. if ( m_pLastFree == pFreeBlock )
  370. {
  371. m_pLastFree = pFreeBlock->pPrevFree;
  372. }
  373. else if ( pFreeBlock->pNextFree )
  374. {
  375. pFreeBlock->pNextFree->pPrevFree = pFreeBlock->pPrevFree;
  376. }
  377. pFreeBlock->pPrevFree = pFreeBlock->pNextFree = NULL;
  378. }
  379. THFreeBlock_t *GetLastFree()
  380. {
  381. return m_pLastFree;
  382. }
  383. void AddToBlocksList( THInfo_t *pBlock, THInfo_t *pPrev, THInfo_t *pNext )
  384. {
  385. if ( pPrev )
  386. {
  387. pPrev->pNext = pBlock;
  388. }
  389. if ( pNext)
  390. {
  391. pNext->pPrev = pBlock;
  392. }
  393. pBlock->pPrev = pPrev;
  394. pBlock->pNext = pNext;
  395. }
  396. void RemoveFromBlocksList( THInfo_t *pBlock )
  397. {
  398. if ( pBlock->pPrev )
  399. {
  400. pBlock->pPrev->pNext = pBlock->pNext;
  401. }
  402. if ( pBlock->pNext )
  403. {
  404. pBlock->pNext->pPrev = pBlock->pPrev;
  405. }
  406. }
  407. //-----------------------------------------------------
  408. void *ClaimBlock( THFreeBlock_t *pFreeBlock, THInfo_t *pInfo )
  409. {
  410. RemoveFromFreeList( pFreeBlock );
  411. int nBytesDesired = pInfo->nBytes;
  412. int nBytesRemainder = pFreeBlock->heapInfo.nBytes - nBytesDesired;
  413. *pInfo = pFreeBlock->heapInfo;
  414. pInfo->bFree = false;
  415. pInfo->bNonTexture = false;
  416. if ( nBytesRemainder >= MIN_BLOCK_SIZE )
  417. {
  418. pInfo->nBytes = nBytesDesired;
  419. THFreeBlock_t *pRemainder = (THFreeBlock_t *)(((byte *)(pFreeBlock)) + nBytesDesired);
  420. pRemainder->heapInfo.bFree = true;
  421. pRemainder->heapInfo.nBytes = nBytesRemainder;
  422. AddToBlocksList( &pRemainder->heapInfo, pInfo, pInfo->pNext );
  423. AddToFreeList( pRemainder );
  424. }
  425. AddToBlocksList( pInfo, pInfo->pPrev, pInfo->pNext );
  426. return pFreeBlock;
  427. }
  428. THFreeBlock_t *MergeLeft( THFreeBlock_t *pFree )
  429. {
  430. THInfo_t *pPrev = pFree->heapInfo.pPrev;
  431. if ( pPrev && pPrev->bFree )
  432. {
  433. pPrev->nBytes += pFree->heapInfo.nBytes;
  434. RemoveFromBlocksList( &pFree->heapInfo );
  435. pFree = GetFreeBlock( pPrev );
  436. RemoveFromFreeList( pFree );
  437. }
  438. return pFree;
  439. }
  440. THFreeBlock_t *MergeRight( THFreeBlock_t *pFree )
  441. {
  442. THInfo_t *pNext = pFree->heapInfo.pNext;
  443. if ( pNext && pNext->bFree )
  444. {
  445. pFree->heapInfo.nBytes += pNext->nBytes;
  446. RemoveFromBlocksList( pNext );
  447. RemoveFromFreeList( GetFreeBlock( pNext ) );
  448. }
  449. return pFree;
  450. }
  451. //-----------------------------------------------------
  452. bool GetExpansionList( THFreeBlock_t *pFreeBlock, THInfo_t **ppStart, THInfo_t **ppEnd, int depth = 1 )
  453. {
  454. THInfo_t *pStart;
  455. THInfo_t *pEnd;
  456. int i;
  457. pStart = &pFreeBlock->heapInfo;
  458. pEnd = &pFreeBlock->heapInfo;
  459. if ( m_nNonTextureAllocs > 0 )
  460. {
  461. return false;
  462. }
  463. // Walk backwards to start of expansion
  464. i = depth;
  465. while ( i > 0 && pStart->pPrev)
  466. {
  467. THInfo_t *pScan = pStart->pPrev;
  468. while ( i > 0 && pScan && !pScan->bFree && GetTexture( pScan )->CanRelocate() )
  469. {
  470. pScan = pScan->pPrev;
  471. i--;
  472. }
  473. if ( !pScan || !pScan->bFree )
  474. {
  475. break;
  476. }
  477. pStart = pScan;
  478. }
  479. // Walk forwards to start of expansion
  480. i = depth;
  481. while ( i > 0 && pEnd->pNext)
  482. {
  483. THInfo_t *pScan = pStart->pNext;
  484. while ( i > 0 && pScan && !pScan->bFree && GetTexture( pScan )->CanRelocate() )
  485. {
  486. pScan = pScan->pNext;
  487. i--;
  488. }
  489. if ( !pScan || !pScan->bFree )
  490. {
  491. break;
  492. }
  493. pEnd = pScan;
  494. }
  495. *ppStart = pStart;
  496. *ppEnd = pEnd;
  497. return ( pStart != pEnd );
  498. }
  499. THFreeBlock_t *CompactExpansionList( THInfo_t *pStart, THInfo_t *pEnd )
  500. {
  501. // X360TBD:
  502. Assert( 0 );
  503. return NULL;
  504. #if 0
  505. #ifdef TH_PARANOID
  506. Validate();
  507. #endif
  508. StrongAssert( pStart->bFree );
  509. StrongAssert( pEnd->bFree );
  510. byte *pNextBlock = (byte *)pStart;
  511. THInfo_t *pTextureBlock = pStart;
  512. THInfo_t *pLastBlock = pStart->pPrev;
  513. while ( pTextureBlock != pEnd )
  514. {
  515. CXboxTexture *pTexture = GetTexture( pTextureBlock );
  516. // If it's a texture, move it and thread it on. Otherwise, discard it
  517. if ( pTexture )
  518. {
  519. void *pTextureBits = GetD3DTextureBasePtr( pTexture );
  520. int nBytes = pTextureBlock->nBytes;
  521. if ( pNextBlock + nBytes <= pTextureBits)
  522. {
  523. memcpy( pNextBlock, pTextureBits, nBytes );
  524. }
  525. else
  526. {
  527. memmove( pNextBlock, pTextureBits, nBytes );
  528. }
  529. pTexture->Data = 0;
  530. pTexture->Register( pNextBlock );
  531. pNextBlock += nBytes;
  532. if ( pLastBlock)
  533. {
  534. pLastBlock->pNext = pTextureBlock;
  535. }
  536. pTextureBlock->pPrev = pLastBlock;
  537. pLastBlock = pTextureBlock;
  538. }
  539. else
  540. {
  541. StrongAssert( pTextureBlock->bFree );
  542. RemoveFromFreeList( GetFreeBlock( pTextureBlock ) );
  543. }
  544. pTextureBlock = pTextureBlock->pNext;
  545. }
  546. RemoveFromFreeList( GetFreeBlock( pEnd ) );
  547. // Make a new block and fix up the block lists
  548. THFreeBlock_t *pFreeBlock = (THFreeBlock_t *)pNextBlock;
  549. pFreeBlock->heapInfo.pPrev = pLastBlock;
  550. pLastBlock->pNext = &pFreeBlock->heapInfo;
  551. pFreeBlock->heapInfo.pNext = pEnd->pNext;
  552. if ( pEnd->pNext )
  553. {
  554. pEnd->pNext->pPrev = &pFreeBlock->heapInfo;
  555. }
  556. pFreeBlock->heapInfo.bFree = true;
  557. pFreeBlock->heapInfo.nBytes = ( (byte *)pEnd - pNextBlock ) + pEnd->nBytes;
  558. AddToFreeList( pFreeBlock );
  559. #ifdef TH_PARANOID
  560. Validate();
  561. #endif
  562. return pFreeBlock;
  563. #endif
  564. }
  565. THFreeBlock_t *ExpandBlock( THFreeBlock_t *pFreeBlock, int depth = 1 )
  566. {
  567. THInfo_t *pStart;
  568. THInfo_t *pEnd;
  569. if ( GetExpansionList( pFreeBlock, &pStart, &pEnd, depth ) )
  570. {
  571. return CompactExpansionList( pStart, pEnd );
  572. }
  573. return pFreeBlock;
  574. }
  575. THFreeBlock_t *ExpandBlockToFit( THFreeBlock_t *pFreeBlock, unsigned bytes )
  576. {
  577. if ( pFreeBlock )
  578. {
  579. THInfo_t *pStart;
  580. THInfo_t *pEnd;
  581. if ( GetExpansionList( pFreeBlock, &pStart, &pEnd, 2 ) )
  582. {
  583. unsigned sum = 0;
  584. THInfo_t *pCurrent = pStart;
  585. while( pCurrent != pEnd->pNext )
  586. {
  587. if ( pCurrent->bFree )
  588. {
  589. sum += pCurrent->nBytes;
  590. }
  591. pCurrent = pCurrent->pNext;
  592. }
  593. if ( sum >= bytes )
  594. {
  595. pFreeBlock = CompactExpansionList( pStart, pEnd );
  596. }
  597. }
  598. }
  599. return pFreeBlock;
  600. }
  601. void *ExpandToFindBlock( THInfo_t *pInfo )
  602. {
  603. THFreeBlock_t *pFreeBlock = ExpandBlockToFit( GetLastFree(), pInfo->nBytes );
  604. if ( pFreeBlock && pFreeBlock->heapInfo.nBytes >= pInfo->nBytes )
  605. {
  606. return ClaimBlock( pFreeBlock, pInfo );
  607. }
  608. return NULL;
  609. }
  610. void Compact()
  611. {
  612. if ( m_nNonTextureAllocs > 0 )
  613. {
  614. return;
  615. }
  616. for (;;)
  617. {
  618. THFreeBlock_t *pCurrent = m_pFirstFree;
  619. THFreeBlock_t *pNew;
  620. while ( pCurrent )
  621. {
  622. int nBytesOld = pCurrent->heapInfo.nBytes;
  623. pNew = ExpandBlock( pCurrent, 999999 );
  624. if ( pNew != pCurrent || pNew->heapInfo.nBytes != nBytesOld )
  625. {
  626. #ifdef TH_PARANOID
  627. Validate();
  628. #endif
  629. break;
  630. }
  631. #ifdef TH_PARANOID
  632. pNew = ExpandBlock( pCurrent, 999999 );
  633. StrongAssert( pNew == pCurrent && pNew->heapInfo.nBytes == nBytesOld );
  634. #endif
  635. pCurrent = pCurrent->pNextFree;
  636. }
  637. if ( !pCurrent )
  638. {
  639. break;
  640. }
  641. }
  642. }
  643. void Validate()
  644. {
  645. if ( !m_pFirstFree )
  646. {
  647. return;
  648. }
  649. if ( m_nNonTextureAllocs > 0 )
  650. {
  651. return;
  652. }
  653. THInfo_t *pLast = NULL;
  654. THInfo_t *pInfo = &m_pFirstFree->heapInfo;
  655. while ( pInfo->pPrev )
  656. {
  657. pInfo = pInfo->pPrev;
  658. }
  659. void *pNextExpectedAddress = m_pBase;
  660. while ( pInfo )
  661. {
  662. byte *pCurrentAddress = (byte *)(( pInfo->bFree ) ? GetFreeBlock( pInfo ) : GetD3DTextureBasePtr( GetTexture( pInfo ) ) );
  663. StrongAssert( pCurrentAddress == pNextExpectedAddress );
  664. StrongAssert( pInfo->pPrev == pLast );
  665. pNextExpectedAddress = pCurrentAddress + pInfo->nBytes;
  666. pLast = pInfo;
  667. pInfo = pInfo->pNext;
  668. }
  669. THFreeBlock_t *pFree = m_pFirstFree;
  670. THFreeBlock_t *pLastFree = NULL;
  671. int nBytesHeap;
  672. nBytesHeap = XPhysicalSize( m_pBase );
  673. while ( pFree )
  674. {
  675. StrongAssert( pFree->pPrevFree == pLastFree );
  676. StrongAssert( (void *)pFree >= m_pBase && (void *)pFree < (byte *)m_pBase + nBytesHeap );
  677. StrongAssert( !pFree->pPrevFree || ( (void *)pFree->pPrevFree >= m_pBase && (void *)pFree->pPrevFree < (byte *)m_pBase + nBytesHeap ) );
  678. StrongAssert( !pFree->pNextFree || ( (void *)pFree->pNextFree >= m_pBase && (void *)pFree->pNextFree < (byte *)m_pBase + nBytesHeap ) );
  679. StrongAssert( !pFree->pPrevFree || pFree->pPrevFree->heapInfo.nBytes <= pFree->heapInfo.nBytes );
  680. pLastFree = pFree;
  681. pFree = pFree->pNextFree;
  682. }
  683. }
  684. //-----------------------------------------------------
  685. THFreeBlock_t *m_pFirstFree;
  686. THFreeBlock_t *m_pLastFree;
  687. void *m_pBase;
  688. int m_nLogicalBytes;
  689. int m_nActualBytes;
  690. int m_nAllocs;
  691. int m_nOldBytes;
  692. int m_nNonTextureAllocs;
  693. int m_nBytesTotal;
  694. };
  695. CMixedTextureHeap g_MixedTextureHeap;
  696. CAlignedMemPool< 1024*1024, D3DTEXTURE_ALIGNMENT, BASEPOOL1024_SIZE, CD3DPoolAllocator > g_TextureBasePool_1024;
  697. CAlignedMemPool< 512*1024, D3DTEXTURE_ALIGNMENT, BASEPOOL512_SIZE, CD3DPoolAllocator > g_TextureBasePool_512;
  698. CAlignedMemPool< 256*1024, D3DTEXTURE_ALIGNMENT, BASEPOOL256_SIZE, CD3DPoolAllocator > g_TextureBasePool_256;
  699. CAlignedMemPool< 128*1024, D3DTEXTURE_ALIGNMENT, BASEPOOL128_SIZE, CD3DPoolAllocator > g_TextureBasePool_128;
  700. CAlignedMemPool< 64*1024, D3DTEXTURE_ALIGNMENT, BASEPOOL64_SIZE, CD3DPoolAllocator > g_TextureBasePool_64;
  701. CAlignedMemPool< 32*1024, D3DTEXTURE_ALIGNMENT, BASEPOOL32_SIZE, CD3DPoolAllocator > g_TextureBasePool_32;
  702. CTextureHeap g_TextureHeap;
  703. //-----------------------------------------------------------------------------
  704. // Resolve texture parameters into sizes and allocator
  705. //-----------------------------------------------------------------------------
  706. TextureAllocator_t TextureParamsToAllocator( int width, int height, int levels, DWORD usage, D3DFORMAT d3dFormat, unsigned int *pBaseSize, unsigned int *pMipSize )
  707. {
  708. // determine texture component sizes
  709. XGSetTextureHeaderEx(
  710. width,
  711. height,
  712. levels,
  713. usage,
  714. d3dFormat,
  715. 0,
  716. 0,
  717. 0,
  718. 0,
  719. 0,
  720. NULL,
  721. pBaseSize,
  722. pMipSize );
  723. // based on "Xbox 360 Texture Storage"
  724. // can truncate the terminal level due to using tiled and packed tails
  725. // the terminal level must be at 32x32 or 16x16 packed
  726. if ( width == height && levels != 0 )
  727. {
  728. unsigned int nReduction = 0;
  729. int terminalWidth = width >> (levels - 1);
  730. if ( d3dFormat == D3DFMT_DXT1 )
  731. {
  732. if ( terminalWidth <= 32 )
  733. {
  734. nReduction = 4*1024;
  735. }
  736. }
  737. else if ( d3dFormat == D3DFMT_DXT5 )
  738. {
  739. if ( terminalWidth == 32 )
  740. {
  741. nReduction = 8*1024;
  742. }
  743. else if ( terminalWidth <= 16 )
  744. {
  745. nReduction = 12*1024;
  746. }
  747. }
  748. if ( levels == 1 )
  749. {
  750. *pBaseSize -= nReduction;
  751. }
  752. else
  753. {
  754. *pMipSize -= nReduction;
  755. }
  756. }
  757. if ( UseBasePoolsForStreaming() )
  758. {
  759. if ( *pMipSize && *pBaseSize >= 32*1024 )
  760. {
  761. if ( *pBaseSize <= 32*1024 )
  762. {
  763. return TA_BASEPOOL_32;
  764. }
  765. if ( *pBaseSize <= 64*1024 )
  766. {
  767. return TA_BASEPOOL_64;
  768. }
  769. if ( *pBaseSize <= 128*1024 )
  770. {
  771. return TA_BASEPOOL_128;
  772. }
  773. if ( *pBaseSize <= 256*1024 )
  774. {
  775. return TA_BASEPOOL_256;
  776. }
  777. if ( *pBaseSize <= 512*1024 && g_TextureBasePool_512.BytesTotal() )
  778. {
  779. // only allow the pool if the pool has been warmed (proper conditions cause init)
  780. return TA_BASEPOOL_512;
  781. }
  782. if ( *pBaseSize <= 1024*1024 && g_TextureBasePool_1024.BytesTotal() )
  783. {
  784. // only allow the pool if the pool has been warmed (proper conditions cause init)
  785. return TA_BASEPOOL_1024;
  786. }
  787. }
  788. }
  789. return TA_STANDARD;
  790. }
  791. CON_COMMAND( texture_heap_stats, "" )
  792. {
  793. Msg( "Texture heap stats:\n" );
  794. int nActualTotal = 0;
  795. for ( int i = 0; i < TA_MAX; i++ )
  796. {
  797. const char *pName = "???";
  798. int nAllocated = 0;
  799. int nSize = 0;
  800. int nTotal = 0;
  801. switch ( i )
  802. {
  803. case TA_BASEPOOL_1024:
  804. pName = "Mip0 - 1024K";
  805. nAllocated = g_TextureBasePool_1024.NumAllocated();
  806. nSize = g_TextureBasePool_1024.BytesAllocated();
  807. nTotal = g_TextureBasePool_1024.BytesTotal();
  808. break;
  809. case TA_BASEPOOL_512:
  810. pName = "Mip0 - 512K";
  811. nAllocated = g_TextureBasePool_512.NumAllocated();
  812. nSize = g_TextureBasePool_512.BytesAllocated();
  813. nTotal = g_TextureBasePool_512.BytesTotal();
  814. break;
  815. case TA_BASEPOOL_256:
  816. pName = "Mip0 - 256K";
  817. nAllocated = g_TextureBasePool_256.NumAllocated();
  818. nSize = g_TextureBasePool_256.BytesAllocated();
  819. nTotal = g_TextureBasePool_256.BytesTotal();
  820. break;
  821. case TA_BASEPOOL_128:
  822. pName = "Mip0 - 128K";
  823. nAllocated = g_TextureBasePool_128.NumAllocated();
  824. nSize = g_TextureBasePool_128.BytesAllocated();
  825. nTotal = g_TextureBasePool_128.BytesTotal();
  826. break;
  827. case TA_BASEPOOL_64:
  828. pName = "Mip0 - 64K";
  829. nAllocated = g_TextureBasePool_64.NumAllocated();
  830. nSize = g_TextureBasePool_64.BytesAllocated();
  831. nTotal = g_TextureBasePool_64.BytesTotal();
  832. break;
  833. case TA_BASEPOOL_32:
  834. pName = "Mip0 - 32K";
  835. nAllocated = g_TextureBasePool_32.NumAllocated();
  836. nSize = g_TextureBasePool_32.BytesAllocated();
  837. nTotal = g_TextureBasePool_32.BytesTotal();
  838. break;
  839. case TA_MIXED:
  840. continue;
  841. case TA_STANDARD:
  842. pName = "Standard";
  843. nAllocated = CD3DStandardAllocator::GetAllocations();
  844. nSize = CD3DStandardAllocator::GetSize();
  845. nTotal = nSize;
  846. break;
  847. }
  848. Msg( "Pool:%-12s Allocations:%4d Used:%6.2f MB Total:%6.2fMB\n", pName, nAllocated, nSize/( 1024.0f * 1024.0f ), nTotal/( 1024.0f * 1024.0f ) );
  849. nActualTotal += nTotal;
  850. }
  851. Msg( "Total: %.2f MB\n", nActualTotal/( 1024.0f * 1024.0f ) );
  852. if ( !UseStandardAllocator() )
  853. {
  854. Msg( "Mixed textures: %dk/%dk allocated in %d textures\n", g_MixedTextureHeap.m_nLogicalBytes/1024, g_MixedTextureHeap.m_nActualBytes/1024, g_MixedTextureHeap.m_nAllocs );
  855. float oldFootprint, newFootprint;
  856. oldFootprint = g_MixedTextureHeap.m_nOldBytes;
  857. newFootprint = g_MixedTextureHeap.m_nActualBytes;
  858. Msg( "\n Old: %.3fmb, New: %.3fmb\n", oldFootprint / (1024.0*1024.0), newFootprint / (1024.0*1024.0) );
  859. }
  860. }
  861. CON_COMMAND( texture_heap_compact, "" )
  862. {
  863. if ( UseStandardAllocator() )
  864. {
  865. return;
  866. }
  867. Msg( "Validating mixed texture heap...\n" );
  868. g_MixedTextureHeap.Validate();
  869. Msg( "Compacting mixed texture heap...\n" );
  870. unsigned int oldLargest, newLargest;
  871. oldLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
  872. g_MixedTextureHeap.Compact();
  873. newLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
  874. Msg( "\n Old largest block: %.3fk, New largest block: %.3fk\n\n", oldLargest / 1024.0, newLargest / 1024.0 );
  875. Msg( "Validating mixed texture heap...\n" );
  876. g_MixedTextureHeap.Validate();
  877. Msg( "Done.\n" );
  878. }
  879. CON_COMMAND( texture_heap_flushlru, "" )
  880. {
  881. g_TextureHeap.FlushTextureCache();
  882. }
  883. CON_COMMAND( texture_heap_spewlru, "" )
  884. {
  885. g_TextureHeap.SpewTextureCache();
  886. }
  887. void CompactTextureHeap()
  888. {
  889. unsigned oldLargest, newLargest;
  890. oldLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
  891. g_MixedTextureHeap.Compact();
  892. newLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
  893. DevMsg( "Compacted texture heap. Old largest block: %.3fk, New largest block: %.3fk\n", oldLargest / 1024.0, newLargest / 1024.0 );
  894. }
  895. //-----------------------------------------------------------------------------
  896. //
  897. //-----------------------------------------------------------------------------
  898. CTextureHeap::CTextureHeap()
  899. {
  900. }
  901. //-----------------------------------------------------------------------------
  902. // Return the allocator used to create the texture
  903. //-----------------------------------------------------------------------------
  904. inline TextureAllocator_t GetTextureAllocator( IDirect3DBaseTexture9 *pTexture )
  905. {
  906. return ( pTexture->GetType() == D3DRTYPE_CUBETEXTURE ) ? (( CXboxCubeTexture *)pTexture)->m_fAllocator : (( CXboxTexture *)pTexture)->m_fAllocator;
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Build and alloc a texture resource
  910. //-----------------------------------------------------------------------------
  911. IDirect3DTexture *CTextureHeap::AllocTexture( int width, int height, int levels, DWORD usage, D3DFORMAT d3dFormat, bool bNoD3DMemory, bool bCacheable )
  912. {
  913. #if defined( SUPPORTS_TEXTURE_STREAMING )
  914. static bool bInitializedPools;
  915. if ( !bInitializedPools )
  916. {
  917. // Warm the pools, now once
  918. // Pools that should not exist due to state, will inhibit any further potential latent use
  919. bInitializedPools = true;
  920. if ( !g_pFullFileSystem->IsDVDHosted() )
  921. {
  922. MEM_ALLOC_CREDIT_( __FILE__ ": Base, Pooled D3D" );
  923. bool bNo1024 = CommandLine()->FindParm( "-no1024" ) && !CommandLine()->FindParm( "-allow1024" );
  924. if ( !bNo1024 )
  925. {
  926. g_TextureBasePool_1024.Free( g_TextureBasePool_1024.Alloc() );
  927. g_TextureBasePool_512.Free( g_TextureBasePool_512.Alloc() );
  928. }
  929. g_TextureBasePool_256.Free( g_TextureBasePool_256.Alloc() );
  930. g_TextureBasePool_128.Free( g_TextureBasePool_128.Alloc() );
  931. g_TextureBasePool_64.Free( g_TextureBasePool_64.Alloc() );
  932. g_TextureBasePool_32.Free( g_TextureBasePool_32.Alloc() );
  933. }
  934. }
  935. #endif
  936. // determine allocator and texture component sizes
  937. unsigned int nBaseSize;
  938. unsigned int nMipSize;
  939. TextureAllocator_t nAllocator = TextureParamsToAllocator( width, height, levels, usage, d3dFormat, &nBaseSize, &nMipSize );
  940. if ( bCacheable && nAllocator == TA_STANDARD )
  941. {
  942. // texture doesn't meet the cacheing guidelines
  943. bCacheable = false;
  944. }
  945. int mipOffset;
  946. if ( !bCacheable )
  947. {
  948. // a non-cacheable texture is setup with a contiguous base
  949. nAllocator = TA_STANDARD;
  950. mipOffset = XGHEADER_CONTIGUOUS_MIP_OFFSET;
  951. nBaseSize += nMipSize;
  952. nMipSize = 0;
  953. }
  954. else
  955. {
  956. // a cacheable texture has a non-contiguous base and mips
  957. mipOffset = 0;
  958. Assert( nBaseSize && nMipSize );
  959. }
  960. void *pBaseBuffer = NULL;
  961. void *pMipBuffer = NULL;
  962. if ( !bNoD3DMemory )
  963. {
  964. if ( !bCacheable )
  965. {
  966. MEM_ALLOC_CREDIT_( __FILE__ ": Standard D3D" );
  967. // the base and mips are contiguous
  968. // the base is mandatory
  969. pBaseBuffer = CD3DStandardAllocator::Alloc( nBaseSize );
  970. if ( !pBaseBuffer )
  971. {
  972. // shouldn't happen, out of memory
  973. return NULL;
  974. }
  975. }
  976. else
  977. {
  978. {
  979. MEM_ALLOC_CREDIT_( __FILE__ ": Base, Pooled D3D" );
  980. // base goes into its own seperate pool seperate from mips
  981. // pools may be full, a failed pool allocation is permissible
  982. switch ( nAllocator )
  983. {
  984. case TA_BASEPOOL_1024:
  985. pBaseBuffer = g_TextureBasePool_1024.Alloc();
  986. break;
  987. case TA_BASEPOOL_512:
  988. pBaseBuffer = g_TextureBasePool_512.Alloc();
  989. break;
  990. case TA_BASEPOOL_256:
  991. pBaseBuffer = g_TextureBasePool_256.Alloc();
  992. break;
  993. case TA_BASEPOOL_128:
  994. pBaseBuffer = g_TextureBasePool_128.Alloc();
  995. break;
  996. case TA_BASEPOOL_64:
  997. pBaseBuffer = g_TextureBasePool_64.Alloc();
  998. break;
  999. case TA_BASEPOOL_32:
  1000. pBaseBuffer = g_TextureBasePool_32.Alloc();
  1001. break;
  1002. }
  1003. }
  1004. {
  1005. MEM_ALLOC_CREDIT_( __FILE__ ": Mips, Standard D3D" );
  1006. // the mips go elsewhere
  1007. // the mips are mandatory
  1008. pMipBuffer = CD3DStandardAllocator::Alloc( nMipSize );
  1009. if ( !pMipBuffer )
  1010. {
  1011. // shouldn't happen, out of memory
  1012. return NULL;
  1013. }
  1014. }
  1015. }
  1016. }
  1017. MEM_ALLOC_CREDIT_( __FILE__ ": Texture Headers" );
  1018. CXboxTexture* pXboxTexture = new CXboxTexture;
  1019. XGSetTextureHeaderEx(
  1020. width,
  1021. height,
  1022. levels,
  1023. usage,
  1024. d3dFormat,
  1025. 0,
  1026. 0,
  1027. 0,
  1028. mipOffset,
  1029. 0,
  1030. (IDirect3DTexture*)pXboxTexture,
  1031. NULL,
  1032. NULL );
  1033. pXboxTexture->m_fAllocator = nAllocator;
  1034. pXboxTexture->m_nBaseSize = nBaseSize;
  1035. pXboxTexture->m_nMipSize = nMipSize;
  1036. pXboxTexture->m_bBaseAllocated = ( pBaseBuffer != NULL );
  1037. pXboxTexture->m_bMipAllocated = ( pMipBuffer != NULL );
  1038. // assuming that a texture that allocates now is using the synchronous loader
  1039. // and is about to blit textures
  1040. pXboxTexture->m_BaseValid = pXboxTexture->m_bBaseAllocated;
  1041. if ( bCacheable )
  1042. {
  1043. pXboxTexture->m_tcHandle = m_TextureCache.AddToTail( (IDirect3DTexture*)pXboxTexture );
  1044. }
  1045. if ( !bNoD3DMemory )
  1046. {
  1047. if ( !bCacheable )
  1048. {
  1049. // non cacheable texture, base and mip are contiguous
  1050. SetD3DTextureBasePtr( (IDirect3DTexture*)pXboxTexture, pBaseBuffer );
  1051. // retrieve offset and fixup
  1052. void *pMipOffset = GetD3DTextureMipPtr( (IDirect3DTexture*)pXboxTexture );
  1053. if ( pMipOffset )
  1054. {
  1055. SetD3DTextureMipPtr( (IDirect3DTexture*)pXboxTexture, (unsigned char *)pBaseBuffer + (unsigned int)pMipOffset );
  1056. }
  1057. }
  1058. else
  1059. {
  1060. // cacheable texture, base may or may not be allocated now
  1061. if ( !pBaseBuffer )
  1062. {
  1063. // d3d error checking requires we stuff a valid, but bogus base pointer
  1064. // the base pointer gets properly set when this cacheable texture is touched
  1065. SetD3DTextureBasePtr( (IDirect3DTexture*)pXboxTexture, pMipBuffer );
  1066. SetD3DTextureMipPtr( (IDirect3DTexture*)pXboxTexture, pMipBuffer );
  1067. }
  1068. else
  1069. {
  1070. SetD3DTextureBasePtr( (IDirect3DTexture*)pXboxTexture, pBaseBuffer );
  1071. SetD3DTextureMipPtr( (IDirect3DTexture*)pXboxTexture, pMipBuffer );
  1072. }
  1073. }
  1074. }
  1075. return (IDirect3DTexture*)pXboxTexture;
  1076. }
  1077. //-----------------------------------------------------------------------------
  1078. // Build and alloc a cube texture resource
  1079. //-----------------------------------------------------------------------------
  1080. IDirect3DCubeTexture *CTextureHeap::AllocCubeTexture( int width, int levels, DWORD usage, D3DFORMAT d3dFormat, bool bNoD3DMemory )
  1081. {
  1082. MEM_ALLOC_CREDIT_( __FILE__ ": Texture Headers" );
  1083. CXboxCubeTexture* pXboxCubeTexture = new CXboxCubeTexture;
  1084. // create a cube texture with contiguous mips and packed tails
  1085. DWORD dwTextureSize = XGSetCubeTextureHeaderEx(
  1086. width,
  1087. levels,
  1088. usage,
  1089. d3dFormat,
  1090. 0,
  1091. 0,
  1092. 0,
  1093. XGHEADER_CONTIGUOUS_MIP_OFFSET,
  1094. (IDirect3DCubeTexture*)pXboxCubeTexture,
  1095. NULL,
  1096. NULL );
  1097. pXboxCubeTexture->m_fAllocator = TA_STANDARD;
  1098. pXboxCubeTexture->m_nBaseSize = dwTextureSize;
  1099. pXboxCubeTexture->m_bBaseAllocated = ( bNoD3DMemory == false );
  1100. if ( bNoD3DMemory )
  1101. {
  1102. return (IDirect3DCubeTexture*)pXboxCubeTexture;
  1103. }
  1104. void *pBits;
  1105. {
  1106. MEM_ALLOC_CREDIT_( __FILE__ ": Cubemap, Standard D3D" );
  1107. pBits = CD3DStandardAllocator::Alloc( dwTextureSize );
  1108. if ( !pBits )
  1109. {
  1110. delete pXboxCubeTexture;
  1111. return NULL;
  1112. }
  1113. }
  1114. // base and mips are contiguous
  1115. SetD3DTextureBasePtr( (IDirect3DTexture*)pXboxCubeTexture, pBits );
  1116. // retrieve offset and fixup
  1117. void *pMipOffset = GetD3DTextureMipPtr( (IDirect3DTexture*)pXboxCubeTexture );
  1118. if ( pMipOffset )
  1119. {
  1120. SetD3DTextureMipPtr( (IDirect3DTexture*)pXboxCubeTexture, (unsigned char *)pBits + (unsigned int)pMipOffset );
  1121. }
  1122. return (IDirect3DCubeTexture*)pXboxCubeTexture;
  1123. }
  1124. //-----------------------------------------------------------------------------
  1125. // Allocate an Volume Texture
  1126. //-----------------------------------------------------------------------------
  1127. IDirect3DVolumeTexture *CTextureHeap::AllocVolumeTexture( int width, int height, int depth, int levels, DWORD usage, D3DFORMAT d3dFormat )
  1128. {
  1129. MEM_ALLOC_CREDIT_( __FILE__ ": Texture Headers" );
  1130. CXboxVolumeTexture *pXboxVolumeTexture = new CXboxVolumeTexture;
  1131. // create a cube texture with contiguous mips and packed tails
  1132. DWORD dwTextureSize = XGSetVolumeTextureHeaderEx(
  1133. width,
  1134. height,
  1135. depth,
  1136. levels,
  1137. usage,
  1138. d3dFormat,
  1139. 0,
  1140. 0,
  1141. 0,
  1142. XGHEADER_CONTIGUOUS_MIP_OFFSET,
  1143. (IDirect3DVolumeTexture *)pXboxVolumeTexture,
  1144. NULL,
  1145. NULL );
  1146. void *pBits;
  1147. {
  1148. MEM_ALLOC_CREDIT_( __FILE__ ": Volume, Standard D3D" );
  1149. pBits = CD3DStandardAllocator::Alloc( dwTextureSize );
  1150. if ( !pBits )
  1151. {
  1152. delete pXboxVolumeTexture;
  1153. return NULL;
  1154. }
  1155. }
  1156. pXboxVolumeTexture->m_fAllocator = TA_STANDARD;
  1157. pXboxVolumeTexture->m_nBaseSize = dwTextureSize;
  1158. pXboxVolumeTexture->m_bBaseAllocated = true;
  1159. // base and mips are contiguous
  1160. SetD3DTextureBasePtr( (IDirect3DTexture*)pXboxVolumeTexture, pBits );
  1161. // retrieve offset and fixup
  1162. void *pMipOffset = GetD3DTextureMipPtr( (IDirect3DTexture*)pXboxVolumeTexture );
  1163. if ( pMipOffset )
  1164. {
  1165. SetD3DTextureMipPtr( (IDirect3DTexture*)pXboxVolumeTexture, (unsigned char *)pBits + (unsigned int)pMipOffset );
  1166. }
  1167. return pXboxVolumeTexture;
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. // Get current backbuffer multisample type (used in AllocRenderTargetSurface() )
  1171. //-----------------------------------------------------------------------------
  1172. D3DMULTISAMPLE_TYPE CTextureHeap::GetBackBufferMultiSampleType()
  1173. {
  1174. int backWidth, backHeight;
  1175. ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
  1176. // 2xMSAA at 640x480 and 848x480 are the only supported multisample mode on 360 (2xMSAA for 720p would
  1177. // use predicated tiling, which would require a rewrite of *all* our render target code)
  1178. // FIXME: shuffle the EDRAM surfaces to allow 4xMSAA for standard def
  1179. // (they would overlap & trash each other with the current allocation scheme)
  1180. D3DMULTISAMPLE_TYPE backBufferMultiSampleType = g_pShaderDevice->IsAAEnabled() ? D3DMULTISAMPLE_2_SAMPLES : D3DMULTISAMPLE_NONE;
  1181. Assert( ( g_pShaderDevice->IsAAEnabled() == false ) || (backHeight == 480) );
  1182. return backBufferMultiSampleType;
  1183. }
  1184. //-----------------------------------------------------------------------------
  1185. // Allocate an EDRAM surface
  1186. //-----------------------------------------------------------------------------
  1187. IDirect3DSurface *CTextureHeap::AllocRenderTargetSurface( int width, int height, D3DFORMAT d3dFormat, RTMultiSampleCount360_t multiSampleCount, int base )
  1188. {
  1189. // render target surfaces don't need to exist simultaneously
  1190. // force their allocations to overlap at the end of back buffer and zbuffer
  1191. // this should leave 3MB (of 10) free assuming 1280x720 (and 5MB with 640x480@2xMSAA)
  1192. D3DMULTISAMPLE_TYPE backBufferMultiSampleType = GetBackBufferMultiSampleType();
  1193. D3DMULTISAMPLE_TYPE multiSampleType = D3DMULTISAMPLE_NONE;
  1194. switch ( multiSampleCount )
  1195. {
  1196. case RT_MULTISAMPLE_MATCH_BACKBUFFER:
  1197. multiSampleType = backBufferMultiSampleType;
  1198. break;
  1199. case RT_MULTISAMPLE_NONE:
  1200. multiSampleType = D3DMULTISAMPLE_NONE;
  1201. break;
  1202. case RT_MULTISAMPLE_2_SAMPLES:
  1203. multiSampleType = D3DMULTISAMPLE_2_SAMPLES;
  1204. break;
  1205. case RT_MULTISAMPLE_4_SAMPLES:
  1206. multiSampleType = D3DMULTISAMPLE_4_SAMPLES;
  1207. break;
  1208. default:
  1209. Assert( !"Invalid multisample count" );
  1210. multiSampleType = D3DMULTISAMPLE_NONE;
  1211. }
  1212. if ( base < 0 )
  1213. {
  1214. int backWidth, backHeight;
  1215. ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
  1216. D3DFORMAT backBufferFormat = ImageLoader::ImageFormatToD3DFormat( g_pShaderDevice->GetBackBufferFormat() );
  1217. // this is the size of back+depthbuffer in EDRAM
  1218. base = 2*XGSurfaceSize( backWidth, backHeight, backBufferFormat, backBufferMultiSampleType );
  1219. }
  1220. D3DSURFACE_PARAMETERS surfParameters;
  1221. V_memset( &surfParameters, 0, sizeof( surfParameters ) );
  1222. surfParameters.Base = base;
  1223. surfParameters.ColorExpBias = 0;
  1224. surfParameters.HiZFunc = D3DHIZFUNC_DEFAULT;
  1225. if ( ( d3dFormat == D3DFMT_D24FS8 ) || ( d3dFormat == D3DFMT_D24S8 ) || ( d3dFormat == D3DFMT_D16 ) )
  1226. {
  1227. surfParameters.HierarchicalZBase = 0;
  1228. if ( ( surfParameters.HierarchicalZBase + XGHierarchicalZSize( width, height, multiSampleType ) ) > GPU_HIERARCHICAL_Z_TILES )
  1229. {
  1230. // overflow, can't hold the tiles so disable
  1231. surfParameters.HierarchicalZBase = 0xFFFFFFFF;
  1232. }
  1233. }
  1234. else
  1235. {
  1236. // not using
  1237. surfParameters.HierarchicalZBase = 0xFFFFFFFF;
  1238. }
  1239. HRESULT hr;
  1240. IDirect3DSurface9 *pSurface = NULL;
  1241. hr = Dx9Device()->CreateRenderTarget( width, height, d3dFormat, multiSampleType, 0, FALSE, &pSurface, &surfParameters );
  1242. Assert( !FAILED( hr ) );
  1243. return pSurface;
  1244. }
  1245. //-----------------------------------------------------------------------------
  1246. // Perform the real d3d allocation, returns true if succesful, false otherwise.
  1247. // Only valid for a texture created with no d3d bits, otherwise no-op.
  1248. //-----------------------------------------------------------------------------
  1249. bool CTextureHeap::FixupAllocD3DMemory( IDirect3DBaseTexture *pD3DTexture )
  1250. {
  1251. if ( !pD3DTexture )
  1252. {
  1253. return false;
  1254. }
  1255. if ( pD3DTexture->GetType() == D3DRTYPE_SURFACE )
  1256. {
  1257. // there are no d3d bits for a surface
  1258. return false;
  1259. }
  1260. if ( GetD3DTextureBasePtr( pD3DTexture ) )
  1261. {
  1262. // already allocated
  1263. return true;
  1264. }
  1265. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  1266. {
  1267. if ( ((CXboxTexture *)pD3DTexture)->m_bMipAllocated )
  1268. {
  1269. // cacheable texture has already been setup
  1270. return true;
  1271. }
  1272. int nAllocator = ((CXboxTexture *)pD3DTexture)->m_fAllocator;
  1273. unsigned int nBaseSize = ((CXboxTexture *)pD3DTexture)->m_nBaseSize;
  1274. unsigned int nMipSize = ((CXboxTexture *)pD3DTexture)->m_nMipSize;
  1275. bool bCacheable = ( nAllocator != TA_STANDARD );
  1276. void *pBaseBuffer = NULL;
  1277. void *pMipBuffer = NULL;
  1278. if ( !bCacheable )
  1279. {
  1280. MEM_ALLOC_CREDIT_( __FILE__ ": Standard D3D" );
  1281. // base and mips are contiguous
  1282. Assert( nBaseSize && nMipSize == 0 );
  1283. pBaseBuffer = CD3DStandardAllocator::Alloc( nBaseSize );
  1284. if ( !pBaseBuffer )
  1285. {
  1286. // base is required, out of memory
  1287. return false;
  1288. }
  1289. }
  1290. else
  1291. {
  1292. {
  1293. MEM_ALLOC_CREDIT_( __FILE__ ": Mips, Standard D3D" );
  1294. // base and mips are non-contiguous
  1295. Assert( nBaseSize && nMipSize );
  1296. pMipBuffer = CD3DStandardAllocator::Alloc( nMipSize );
  1297. if ( !pMipBuffer )
  1298. {
  1299. // mips are required, out of memory
  1300. return false;
  1301. }
  1302. }
  1303. {
  1304. MEM_ALLOC_CREDIT_( __FILE__ ": Base, Pooled D3D" );
  1305. // base goes into its own seperate pool seperate from mips
  1306. // pools my be filled, failure is allowed
  1307. switch ( nAllocator )
  1308. {
  1309. case TA_BASEPOOL_1024:
  1310. pBaseBuffer = g_TextureBasePool_1024.Alloc();
  1311. break;
  1312. case TA_BASEPOOL_512:
  1313. pBaseBuffer = g_TextureBasePool_512.Alloc();
  1314. break;
  1315. case TA_BASEPOOL_256:
  1316. pBaseBuffer = g_TextureBasePool_256.Alloc();
  1317. break;
  1318. case TA_BASEPOOL_128:
  1319. pBaseBuffer = g_TextureBasePool_128.Alloc();
  1320. break;
  1321. case TA_BASEPOOL_64:
  1322. pBaseBuffer = g_TextureBasePool_64.Alloc();
  1323. break;
  1324. case TA_BASEPOOL_32:
  1325. pBaseBuffer = g_TextureBasePool_32.Alloc();
  1326. break;
  1327. }
  1328. }
  1329. }
  1330. ((CXboxTexture *)pD3DTexture)->m_bBaseAllocated = ( pBaseBuffer != NULL );
  1331. ((CXboxTexture *)pD3DTexture)->m_bMipAllocated = ( pMipBuffer != NULL );
  1332. if ( !bCacheable )
  1333. {
  1334. // non cacheable texture, base and mip are contiguous
  1335. SetD3DTextureBasePtr( pD3DTexture, pBaseBuffer );
  1336. // retrieve offset and fixup
  1337. void *pMipOffset = GetD3DTextureMipPtr( pD3DTexture );
  1338. if ( pMipOffset )
  1339. {
  1340. SetD3DTextureMipPtr( pD3DTexture, (unsigned char *)pBaseBuffer + (unsigned int)pMipOffset );
  1341. }
  1342. // the async queued loader is about to blit textures, so mark valid for render
  1343. ((CXboxTexture *)pD3DTexture)->m_BaseValid = 1;
  1344. }
  1345. else
  1346. {
  1347. // cacheable texture, base may or may not be allocated now
  1348. if ( !pBaseBuffer )
  1349. {
  1350. // d3d error checking requires we stuff a valid, but bogus base pointer
  1351. // the base pointer gets properly set when this cacheable texture is touched
  1352. SetD3DTextureBasePtr( pD3DTexture, pMipBuffer );
  1353. SetD3DTextureMipPtr( pD3DTexture, pMipBuffer );
  1354. }
  1355. else
  1356. {
  1357. SetD3DTextureBasePtr( pD3DTexture, pBaseBuffer );
  1358. SetD3DTextureMipPtr( pD3DTexture, pMipBuffer );
  1359. // the async queued loader is about to blit textures, so mark valid for render
  1360. ((CXboxTexture *)pD3DTexture)->m_BaseValid = 1;
  1361. }
  1362. }
  1363. return true;
  1364. }
  1365. else if ( pD3DTexture->GetType() == D3DRTYPE_CUBETEXTURE )
  1366. {
  1367. MEM_ALLOC_CREDIT_( __FILE__ ": Cubemap, Standard D3D" );
  1368. void *pBaseBuffer = CD3DStandardAllocator::Alloc( ((CXboxCubeTexture *)pD3DTexture)->m_nBaseSize );
  1369. if ( !pBaseBuffer )
  1370. {
  1371. // base is required, out of memory
  1372. return false;
  1373. }
  1374. SetD3DTextureBasePtr( pD3DTexture, pBaseBuffer );
  1375. // retrieve offset and fixup
  1376. void *pMipOffset = GetD3DTextureMipPtr( pD3DTexture );
  1377. if ( pMipOffset )
  1378. {
  1379. SetD3DTextureMipPtr( pD3DTexture, (unsigned char *)pBaseBuffer + (unsigned int)pMipOffset );
  1380. }
  1381. ((CXboxCubeTexture *)pD3DTexture)->m_bBaseAllocated = true;
  1382. return true;
  1383. }
  1384. return false;
  1385. }
  1386. //-----------------------------------------------------------------------------
  1387. // Release the allocated store
  1388. //-----------------------------------------------------------------------------
  1389. void CTextureHeap::FreeTexture( IDirect3DBaseTexture *pD3DTexture )
  1390. {
  1391. if ( !pD3DTexture )
  1392. {
  1393. return;
  1394. }
  1395. if ( pD3DTexture->GetType() == D3DRTYPE_SURFACE )
  1396. {
  1397. // texture heap doesn't own render target surfaces
  1398. // allow callers to call through for less higher level detection
  1399. int ref = ((IDirect3DSurface*)pD3DTexture)->Release();
  1400. Assert( ref == 0 );
  1401. ref = ref;
  1402. return;
  1403. }
  1404. if ( IsBaseAllocated( pD3DTexture ) )
  1405. {
  1406. byte *pBaseBits = (byte *)GetD3DTextureBasePtr( pD3DTexture );
  1407. if ( pBaseBits )
  1408. {
  1409. switch ( GetTextureAllocator( pD3DTexture ) )
  1410. {
  1411. case TA_BASEPOOL_1024:
  1412. g_TextureBasePool_1024.Free( pBaseBits );
  1413. break;
  1414. case TA_BASEPOOL_512:
  1415. g_TextureBasePool_512.Free( pBaseBits );
  1416. break;
  1417. case TA_BASEPOOL_256:
  1418. g_TextureBasePool_256.Free( pBaseBits );
  1419. break;
  1420. case TA_BASEPOOL_128:
  1421. g_TextureBasePool_128.Free( pBaseBits );
  1422. break;
  1423. case TA_BASEPOOL_64:
  1424. g_TextureBasePool_64.Free( pBaseBits );
  1425. break;
  1426. case TA_BASEPOOL_32:
  1427. g_TextureBasePool_32.Free( pBaseBits );
  1428. break;
  1429. case TA_STANDARD:
  1430. CD3DStandardAllocator::Free( pBaseBits );
  1431. break;
  1432. case TA_MIXED:
  1433. g_MixedTextureHeap.Free( pBaseBits, ((CXboxTexture *)pD3DTexture) );
  1434. break;
  1435. }
  1436. }
  1437. }
  1438. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  1439. {
  1440. if ( ((CXboxTexture *)pD3DTexture)->m_tcHandle != INVALID_TEXTURECACHE_HANDLE )
  1441. {
  1442. m_TextureCache.Remove( ((CXboxTexture *)pD3DTexture)->m_tcHandle );
  1443. }
  1444. if ( ((CXboxTexture *)pD3DTexture)->m_bMipAllocated )
  1445. {
  1446. // not an offset, but a true pointer
  1447. void *pMipBits = GetD3DTextureMipPtr( pD3DTexture );
  1448. if ( pMipBits )
  1449. {
  1450. CD3DStandardAllocator::Free( pMipBits );
  1451. }
  1452. }
  1453. delete (CXboxTexture *)pD3DTexture;
  1454. }
  1455. else if ( pD3DTexture->GetType() == D3DRTYPE_VOLUMETEXTURE )
  1456. {
  1457. delete (CXboxVolumeTexture *)pD3DTexture;
  1458. }
  1459. else if ( pD3DTexture->GetType() == D3DRTYPE_CUBETEXTURE )
  1460. {
  1461. delete (CXboxCubeTexture *)pD3DTexture;
  1462. }
  1463. }
  1464. //-----------------------------------------------------------------------------
  1465. // Returns the allocated footprint.
  1466. //-----------------------------------------------------------------------------
  1467. int CTextureHeap::GetSize( IDirect3DBaseTexture *pD3DTexture )
  1468. {
  1469. if ( !pD3DTexture )
  1470. {
  1471. return 0;
  1472. }
  1473. if ( pD3DTexture->GetType() == D3DRTYPE_SURFACE )
  1474. {
  1475. D3DSURFACE_DESC surfaceDesc;
  1476. HRESULT hr = ((IDirect3DSurface*)pD3DTexture)->GetDesc( &surfaceDesc );
  1477. Assert( !FAILED( hr ) );
  1478. hr = hr;
  1479. int size = ImageLoader::GetMemRequired(
  1480. surfaceDesc.Width,
  1481. surfaceDesc.Height,
  1482. 0,
  1483. ImageLoader::D3DFormatToImageFormat( surfaceDesc.Format ),
  1484. false );
  1485. return size;
  1486. }
  1487. else if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  1488. {
  1489. return ((CXboxTexture *)pD3DTexture)->m_nBaseSize + ((CXboxTexture *)pD3DTexture)->m_nMipSize;
  1490. }
  1491. else if ( pD3DTexture->GetType() == D3DRTYPE_CUBETEXTURE )
  1492. {
  1493. return ((CXboxCubeTexture *)pD3DTexture)->m_nBaseSize;
  1494. }
  1495. else if ( pD3DTexture->GetType() == D3DRTYPE_VOLUMETEXTURE )
  1496. {
  1497. return ((CXboxVolumeTexture *)pD3DTexture)->m_nBaseSize;
  1498. }
  1499. return 0;
  1500. }
  1501. //-----------------------------------------------------------------------------
  1502. // Returns the amount of memory needed just for the cacheable component.
  1503. //-----------------------------------------------------------------------------
  1504. int CTextureHeap::GetCacheableSize( IDirect3DBaseTexture *pD3DTexture )
  1505. {
  1506. if ( !pD3DTexture )
  1507. {
  1508. return 0;
  1509. }
  1510. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE && ((CXboxTexture *)pD3DTexture)->m_fAllocator != TA_STANDARD )
  1511. {
  1512. // the base is the cacheable component
  1513. return ((CXboxTexture *)pD3DTexture)->m_nBaseSize;
  1514. }
  1515. return 0;
  1516. }
  1517. //-----------------------------------------------------------------------------
  1518. // Crunch the pools
  1519. //-----------------------------------------------------------------------------
  1520. void CTextureHeap::Compact()
  1521. {
  1522. g_MixedTextureHeap.Compact();
  1523. }
  1524. //-----------------------------------------------------------------------------
  1525. // Query to determine if texture was setup for cacheing.
  1526. //-----------------------------------------------------------------------------
  1527. bool CTextureHeap::IsTextureCacheManaged( IDirect3DBaseTexture *pD3DTexture )
  1528. {
  1529. if ( !pD3DTexture )
  1530. {
  1531. return false;
  1532. }
  1533. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  1534. {
  1535. return ((CXboxTexture *)pD3DTexture)->m_tcHandle != INVALID_TEXTURECACHE_HANDLE;
  1536. }
  1537. return false;
  1538. }
  1539. //-----------------------------------------------------------------------------
  1540. // Query to determine if texture has an allocated base.
  1541. //-----------------------------------------------------------------------------
  1542. bool CTextureHeap::IsBaseAllocated( IDirect3DBaseTexture *pD3DTexture )
  1543. {
  1544. if ( !pD3DTexture )
  1545. {
  1546. return false;
  1547. }
  1548. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  1549. {
  1550. return ((CXboxTexture *)pD3DTexture)->m_bBaseAllocated;
  1551. }
  1552. else if ( pD3DTexture->GetType() == D3DRTYPE_CUBETEXTURE )
  1553. {
  1554. return ((CXboxCubeTexture *)pD3DTexture)->m_bBaseAllocated;
  1555. }
  1556. else if ( pD3DTexture->GetType() == D3DRTYPE_VOLUMETEXTURE )
  1557. {
  1558. return ((CXboxVolumeTexture *)pD3DTexture)->m_bBaseAllocated;
  1559. }
  1560. return true;
  1561. }
  1562. //-----------------------------------------------------------------------------
  1563. // Query to determine if texture is valid for hi-res rendering.
  1564. //-----------------------------------------------------------------------------
  1565. bool CTextureHeap::IsTextureResident( IDirect3DBaseTexture *pD3DTexture )
  1566. {
  1567. if ( !pD3DTexture )
  1568. {
  1569. return false;
  1570. }
  1571. // only the simple texture type streams and can be evicted
  1572. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  1573. {
  1574. return ( ((CXboxTexture *)pD3DTexture)->m_BaseValid != 0 );
  1575. }
  1576. // all other types, cube, volume, are defined as resident
  1577. return true;
  1578. }
  1579. //-----------------------------------------------------------------------------
  1580. // Used for debugging purposes only!!! Forceful eviction. Can cause system lockups
  1581. // under repeated use due to desired forced behavior and ignoring GPU.
  1582. //-----------------------------------------------------------------------------
  1583. void CTextureHeap::FlushTextureCache()
  1584. {
  1585. TextureCacheHandle_t tcHandle;
  1586. for ( tcHandle = m_TextureCache.Head(); tcHandle != m_TextureCache.InvalidIndex(); tcHandle = m_TextureCache.Next( tcHandle ) )
  1587. {
  1588. CXboxTexture *pPurgeCandidate = (CXboxTexture *)m_TextureCache[tcHandle];
  1589. if ( !pPurgeCandidate->m_BaseValid )
  1590. {
  1591. continue;
  1592. }
  1593. byte *pBaseBits = (byte *)GetD3DTextureBasePtr( pPurgeCandidate );
  1594. Assert( pBaseBits );
  1595. if ( pBaseBits )
  1596. {
  1597. switch ( pPurgeCandidate->m_fAllocator )
  1598. {
  1599. case TA_BASEPOOL_1024:
  1600. g_TextureBasePool_1024.Free( pBaseBits );
  1601. break;
  1602. case TA_BASEPOOL_512:
  1603. g_TextureBasePool_512.Free( pBaseBits );
  1604. break;
  1605. case TA_BASEPOOL_256:
  1606. g_TextureBasePool_256.Free( pBaseBits );
  1607. break;
  1608. case TA_BASEPOOL_128:
  1609. g_TextureBasePool_128.Free( pBaseBits );
  1610. break;
  1611. case TA_BASEPOOL_64:
  1612. g_TextureBasePool_64.Free( pBaseBits );
  1613. break;
  1614. case TA_BASEPOOL_32:
  1615. g_TextureBasePool_32.Free( pBaseBits );
  1616. break;
  1617. }
  1618. }
  1619. pPurgeCandidate->m_bBaseAllocated = false;
  1620. pPurgeCandidate->m_BaseValid = 0;
  1621. }
  1622. }
  1623. //-----------------------------------------------------------------------------
  1624. // Computation job to do work after IO, runs callback
  1625. //-----------------------------------------------------------------------------
  1626. static void IOComputationJob( IDirect3DBaseTexture *pD3DTexture, void *pData, int nDataSize, TextureLoadError_t loaderError )
  1627. {
  1628. CXboxTexture *pXboxTexture = (CXboxTexture *)pD3DTexture;
  1629. if ( texture_heap_debug.GetInt() == THD_SPEW )
  1630. {
  1631. char szFilename[MAX_PATH];
  1632. g_pFullFileSystem->String( pXboxTexture->m_hFilename, szFilename, sizeof( szFilename ) );
  1633. Msg( "Arrived: size:%d thread:0x%8.8x %s\n", nDataSize, ThreadGetCurrentId(), szFilename );
  1634. }
  1635. if ( texture_heap_debug.GetInt() == THD_COLORIZE_AFTERIO )
  1636. {
  1637. // colorize the base to use during the i/o latency
  1638. V_memset( GetD3DTextureBasePtr( pD3DTexture ), BASE_COLOR_AFTER, pXboxTexture->m_nBaseSize );
  1639. }
  1640. else if ( pData && nDataSize )
  1641. {
  1642. // get a unique vtf and mount texture
  1643. // vtf can expect non-volatile buffer data to be stable through vtf lifetime
  1644. // this prevents redundant copious amounts of image memory transfers
  1645. IVTFTexture *pVTFTexture = CreateVTFTexture();
  1646. CUtlBuffer vtfBuffer;
  1647. vtfBuffer.SetExternalBuffer( (void *)pData, nDataSize, nDataSize );
  1648. if ( pVTFTexture->UnserializeFromBuffer( vtfBuffer, false, false, false, 0 ) )
  1649. {
  1650. // provided vtf buffer is all mips, determine top mip due to possible picmip
  1651. int mipWidth, mipHeight, mipDepth;
  1652. pVTFTexture->ComputeMipLevelDimensions( pXboxTexture->m_nMipSkipCount, &mipWidth, &mipHeight, &mipDepth );
  1653. // blit the hi-res texture bits into d3d memory
  1654. unsigned char *pSourceBits = pVTFTexture->ImageData( 0, 0, pXboxTexture->m_nMipSkipCount, 0, 0, 0 );
  1655. TextureLoadInfo_t info;
  1656. info.m_TextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  1657. info.m_pTexture = pD3DTexture;
  1658. info.m_nLevel = 0;
  1659. info.m_nCopy = 0;
  1660. info.m_CubeFaceID = (D3DCUBEMAP_FACES)0;
  1661. info.m_nWidth = mipWidth;
  1662. info.m_nHeight = mipHeight;
  1663. info.m_nZOffset = 0;
  1664. info.m_SrcFormat = pVTFTexture->Format();
  1665. info.m_pSrcData = pSourceBits;
  1666. info.m_bSrcIsTiled = pVTFTexture->IsPreTiled();
  1667. info.m_bCanConvertFormat = false;
  1668. LoadTexture( info );
  1669. }
  1670. if ( pVTFTexture )
  1671. {
  1672. DestroyVTFTexture( pVTFTexture );
  1673. }
  1674. }
  1675. if ( pData )
  1676. {
  1677. g_pFullFileSystem->FreeOptimalReadBuffer( pData );
  1678. }
  1679. g_pFullFileSystem->AsyncRelease( pXboxTexture->m_hAsyncControl );
  1680. pXboxTexture->m_hAsyncControl = NULL;
  1681. // ready for render
  1682. pXboxTexture->m_BaseValid = 1;
  1683. }
  1684. //-----------------------------------------------------------------------------
  1685. // Callback from I/O job thread. Purposely lightweight as possible to keep i/o from stalling.
  1686. //-----------------------------------------------------------------------------
  1687. static void IOAsyncCallback( const FileAsyncRequest_t &asyncRequest, int numReadBytes, FSAsyncStatus_t asyncStatus )
  1688. {
  1689. IDirect3DBaseTexture *pD3DTexture = (IDirect3DBaseTexture *)asyncRequest.pContext;
  1690. // interpret the async error
  1691. TextureLoadError_t loaderError;
  1692. switch ( asyncStatus )
  1693. {
  1694. case FSASYNC_OK:
  1695. loaderError = TEXLOADERROR_NONE;
  1696. break;
  1697. case FSASYNC_ERR_FILEOPEN:
  1698. loaderError = TEXLOADERROR_FILEOPEN;
  1699. break;
  1700. default:
  1701. loaderError = TEXLOADERROR_READING;
  1702. }
  1703. // have data or error, do callback as a computation job
  1704. CJob *pComputationJob = new CFunctorJob( CreateFunctor( IOComputationJob, pD3DTexture, asyncRequest.pData, numReadBytes, loaderError ) );
  1705. pComputationJob->SetServiceThread( 1 );
  1706. pComputationJob->SetFlags( pComputationJob->GetFlags() | JF_QUEUE );
  1707. g_pThreadPool->AddJob( pComputationJob );
  1708. pComputationJob->Release();
  1709. }
  1710. //-----------------------------------------------------------------------------
  1711. // Attempts to restore a cacheable texture. An async i/o operation may be kicked
  1712. // off.
  1713. //-----------------------------------------------------------------------------
  1714. bool CTextureHeap::RestoreCacheableTexture( IDirect3DBaseTexture *pD3DTexture )
  1715. {
  1716. static unsigned int s_failedAllocator[TA_MAX];
  1717. unsigned int nFrameCount = g_pShaderAPIDX8->GetCurrentFrameCounter();
  1718. CXboxTexture *pXboxTexture = (CXboxTexture *)pD3DTexture;
  1719. if ( s_failedAllocator[pXboxTexture->m_fAllocator] == nFrameCount )
  1720. {
  1721. // allocator has already failed an eviction this frame
  1722. // avoid costly pointless search, retry next frame
  1723. return false;
  1724. }
  1725. void *pBaseBuffer = NULL;
  1726. TextureCacheHandle_t tcHandle = m_TextureCache.Head();
  1727. int numAttempts = 0;
  1728. while ( numAttempts < 2 )
  1729. {
  1730. {
  1731. MEM_ALLOC_CREDIT_( __FILE__ ": Base, Pooled D3D" );
  1732. switch ( pXboxTexture->m_fAllocator )
  1733. {
  1734. case TA_BASEPOOL_1024:
  1735. pBaseBuffer = g_TextureBasePool_1024.Alloc();
  1736. break;
  1737. case TA_BASEPOOL_512:
  1738. pBaseBuffer = g_TextureBasePool_512.Alloc();
  1739. break;
  1740. case TA_BASEPOOL_256:
  1741. pBaseBuffer = g_TextureBasePool_256.Alloc();
  1742. break;
  1743. case TA_BASEPOOL_128:
  1744. pBaseBuffer = g_TextureBasePool_128.Alloc();
  1745. break;
  1746. case TA_BASEPOOL_64:
  1747. pBaseBuffer = g_TextureBasePool_64.Alloc();
  1748. break;
  1749. case TA_BASEPOOL_32:
  1750. pBaseBuffer = g_TextureBasePool_32.Alloc();
  1751. break;
  1752. }
  1753. }
  1754. if ( pBaseBuffer )
  1755. {
  1756. // found memory!
  1757. break;
  1758. }
  1759. // squeeze lru for memory
  1760. for ( ; tcHandle != m_TextureCache.InvalidIndex(); tcHandle = m_TextureCache.Next( tcHandle ) )
  1761. {
  1762. if ( tcHandle == pXboxTexture->m_tcHandle )
  1763. {
  1764. // skip self
  1765. continue;
  1766. }
  1767. CXboxTexture *pPurgeCandidate = (CXboxTexture *)m_TextureCache[tcHandle];
  1768. if ( !pPurgeCandidate->m_BaseValid ||
  1769. pPurgeCandidate->m_fAllocator != pXboxTexture->m_fAllocator ||
  1770. pPurgeCandidate->m_nFrameCount >= nFrameCount-1 )
  1771. {
  1772. // only allowing eviction from the expected pool
  1773. // using frame counter as the cheapest method to cull GPU busy resources
  1774. continue;
  1775. }
  1776. byte *pBaseBits = (byte *)GetD3DTextureBasePtr( pPurgeCandidate );
  1777. Assert( pBaseBits );
  1778. if ( pBaseBits )
  1779. {
  1780. switch ( pPurgeCandidate->m_fAllocator )
  1781. {
  1782. case TA_BASEPOOL_1024:
  1783. g_TextureBasePool_1024.Free( pBaseBits );
  1784. break;
  1785. case TA_BASEPOOL_512:
  1786. g_TextureBasePool_512.Free( pBaseBits );
  1787. break;
  1788. case TA_BASEPOOL_256:
  1789. g_TextureBasePool_256.Free( pBaseBits );
  1790. break;
  1791. case TA_BASEPOOL_128:
  1792. g_TextureBasePool_128.Free( pBaseBits );
  1793. break;
  1794. case TA_BASEPOOL_64:
  1795. g_TextureBasePool_64.Free( pBaseBits );
  1796. break;
  1797. case TA_BASEPOOL_32:
  1798. g_TextureBasePool_32.Free( pBaseBits );
  1799. break;
  1800. }
  1801. }
  1802. pPurgeCandidate->m_bBaseAllocated = false;
  1803. pPurgeCandidate->m_BaseValid = 0;
  1804. if ( texture_heap_debug.GetInt() == THD_SPEW )
  1805. {
  1806. char szFilename[MAX_PATH];
  1807. g_pFullFileSystem->String( pXboxTexture->m_hFilename, szFilename, sizeof( szFilename ) );
  1808. Msg( "Evicted: %s\n", szFilename );
  1809. }
  1810. // retry allocation
  1811. break;
  1812. }
  1813. numAttempts++;
  1814. }
  1815. if ( !pBaseBuffer )
  1816. {
  1817. // no eviction occured
  1818. // mark which allocator failed
  1819. s_failedAllocator[pXboxTexture->m_fAllocator] = nFrameCount;
  1820. return false;
  1821. }
  1822. pXboxTexture->m_bBaseAllocated = true;
  1823. SetD3DTextureBasePtr( pD3DTexture, pBaseBuffer );
  1824. // setup i/o
  1825. char szFilename[MAX_PATH];
  1826. g_pFullFileSystem->String( pXboxTexture->m_hFilename, szFilename, sizeof( szFilename ) );
  1827. if ( texture_heap_debug.GetInt() == THD_COLORIZE_BEFOREIO || texture_heap_debug.GetInt() == THD_COLORIZE_AFTERIO )
  1828. {
  1829. // colorize the base to use during the i/o latency
  1830. V_memset( pBaseBuffer, BASE_COLOR_BEFORE, pXboxTexture->m_nBaseSize );
  1831. }
  1832. if ( texture_heap_debug.GetInt() == THD_SPEW )
  1833. {
  1834. Msg( "Queued: %s\n", szFilename );
  1835. }
  1836. FileAsyncRequest_t asyncRequest;
  1837. asyncRequest.pszFilename = szFilename;
  1838. asyncRequest.priority = -1;
  1839. asyncRequest.flags = FSASYNC_FLAGS_ALLOCNOFREE;
  1840. asyncRequest.pContext = (void *)pD3DTexture;
  1841. asyncRequest.pfnCallback = IOAsyncCallback;
  1842. g_pFullFileSystem->AsyncRead( asyncRequest, &pXboxTexture->m_hAsyncControl );
  1843. return true;
  1844. }
  1845. //-----------------------------------------------------------------------------
  1846. // Moves to head of LRU. Allocates and queues for loading if evicted. Returns
  1847. // true if texture is resident, false otherwise.
  1848. //-----------------------------------------------------------------------------
  1849. bool CTextureHeap::TouchTexture( CXboxTexture *pXboxTexture )
  1850. {
  1851. bool bValid = true;
  1852. if ( pXboxTexture->m_tcHandle != INVALID_TEXTURECACHE_HANDLE )
  1853. {
  1854. // touch
  1855. m_TextureCache.LinkToTail( pXboxTexture->m_tcHandle );
  1856. bValid = ( pXboxTexture->m_BaseValid != 0 );
  1857. if ( !bValid && !pXboxTexture->m_bBaseAllocated )
  1858. {
  1859. RestoreCacheableTexture( (IDirect3DBaseTexture *)pXboxTexture );
  1860. }
  1861. if ( texture_heap_debug.GetInt() == THD_COLORIZE_BEFOREIO || texture_heap_debug.GetInt() == THD_COLORIZE_AFTERIO )
  1862. {
  1863. // debug mode allows the render to proceed before the i/o completes
  1864. bValid = pXboxTexture->m_bBaseAllocated;
  1865. }
  1866. }
  1867. return bValid;
  1868. }
  1869. //-----------------------------------------------------------------------------
  1870. // Save file info for d3d texture restore process.
  1871. //-----------------------------------------------------------------------------
  1872. void CTextureHeap::SetCacheableTextureParams( IDirect3DBaseTexture *pD3DTexture, const char *pFilename, int mipSkipCount )
  1873. {
  1874. if ( !IsTextureCacheManaged( pD3DTexture ) )
  1875. {
  1876. // wasn't setup for cacheing
  1877. return;
  1878. }
  1879. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  1880. {
  1881. // store compact absolute filename
  1882. ((CXboxTexture *)pD3DTexture)->m_hFilename = g_pFullFileSystem->FindOrAddFileName( pFilename );
  1883. ((CXboxTexture *)pD3DTexture)->m_nMipSkipCount = mipSkipCount;
  1884. }
  1885. }
  1886. void CTextureHeap::SpewTextureCache()
  1887. {
  1888. Msg( "LRU:\n" );
  1889. TextureCacheHandle_t tcHandle;
  1890. for ( tcHandle = m_TextureCache.Head(); tcHandle != m_TextureCache.InvalidIndex(); tcHandle = m_TextureCache.Next( tcHandle ) )
  1891. {
  1892. CXboxTexture *pXboxTexture = (CXboxTexture *)m_TextureCache[tcHandle];
  1893. char szFilename[MAX_PATH];
  1894. g_pFullFileSystem->String( pXboxTexture->m_hFilename, szFilename, sizeof( szFilename ) );
  1895. const char *pState = "???";
  1896. if ( pXboxTexture->m_BaseValid )
  1897. {
  1898. pState = "Valid";
  1899. }
  1900. else
  1901. {
  1902. if ( !pXboxTexture->m_bBaseAllocated )
  1903. {
  1904. pState = "Evicted";
  1905. }
  1906. else if ( pXboxTexture->m_hAsyncControl )
  1907. {
  1908. pState = "Loading";
  1909. }
  1910. }
  1911. Msg( "0x%8.8x (%8s) %s\n", pXboxTexture->m_nFrameCount, pState, szFilename );
  1912. }
  1913. }
  1914. //-----------------------------------------------------------------------------
  1915. // Return the total amount of memory allocated for the base pools.
  1916. //-----------------------------------------------------------------------------
  1917. int CTextureHeap::GetCacheableHeapSize()
  1918. {
  1919. int nTotal = 0;
  1920. for ( int i = 0; i < TA_MAX; i++ )
  1921. {
  1922. switch ( i )
  1923. {
  1924. case TA_BASEPOOL_1024:
  1925. nTotal += g_TextureBasePool_1024.BytesTotal();
  1926. break;
  1927. case TA_BASEPOOL_512:
  1928. nTotal += g_TextureBasePool_512.BytesTotal();
  1929. break;
  1930. case TA_BASEPOOL_256:
  1931. nTotal += g_TextureBasePool_256.BytesTotal();
  1932. break;
  1933. case TA_BASEPOOL_128:
  1934. nTotal += g_TextureBasePool_128.BytesTotal();
  1935. break;
  1936. case TA_BASEPOOL_64:
  1937. nTotal += g_TextureBasePool_64.BytesTotal();
  1938. break;
  1939. case TA_BASEPOOL_32:
  1940. nTotal += g_TextureBasePool_32.BytesTotal();
  1941. break;
  1942. default:
  1943. continue;
  1944. }
  1945. }
  1946. return nTotal;
  1947. }