/trunk/source/Engine/JetEngine/Engine/Drivers/D3DDrv/D3DCACHE.CPP

# · C++ · 1609 lines · 917 code · 370 blank · 322 comment · 195 complexity · 3d0bccbcf4a88747e287b6cdf5219a72 MD5 · raw file

  1. /****************************************************************************************/
  2. /* D3DCACHE.CPP */
  3. /* */
  4. /* Author: */
  5. /* Description: */
  6. /* */
  7. /* The contents of this file are subject to the Jet3D Public License */
  8. /* Version 1.02 (the "License"); you may not use this file except in */
  9. /* compliance with the License. You may obtain a copy of the License at */
  10. /* http://www.jet3d.com */
  11. /* */
  12. /* Software distributed under the License is distributed on an "AS IS" */
  13. /* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
  14. /* the License for the specific language governing rights and limitations */
  15. /* under the License. */
  16. /* */
  17. /* The Original Code is Jet3D, released December 12, 1999. */
  18. /* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */
  19. /* */
  20. /****************************************************************************************/
  21. // see @@ and <> for todos
  22. #define DO_LOG
  23. /*******
  24. Notes on D3DCache by Charles Bloom
  25. call _Update() at the end of a scene; it gathers stats and re-balances the cache
  26. for the current vis set
  27. _Balance() tries to move memory from one type to another to better reflect the
  28. textures that are visible
  29. The MipData in the Slot is the THandle it corresponds to.
  30. The RefCount in the Type is the number of THandles of that type
  31. We gather the usage stats from the THandles build in SetupTexture() in PCache
  32. NOTE : we currently maintain separate caches for texture and lightmaps !
  33. This would all work better if we merged the two caches
  34. ** see USE_ONE_CACHE flag in THandle.cpp ; try it!
  35. The DDMemMgr is just an accountant for adds and subtracts.
  36. We query the free memory in THandle : D3DDrvInfo.VidMemFree
  37. Originally set up in Main_GetVideoMemory
  38. <> NOTE : this is not accurate !! The actual amount of vidmem used may not
  39. be the same as the width*height*bpp !!!
  40. this isn't terrible, because in the end, we actually judge free mem by
  41. trying to allocate.
  42. -----------------------------------------------------
  43. <> Misses due to max-ing the # of slots should not cause a bias adjust!
  44. done : just using Diff2, no longer Diff1
  45. <> when you have a huge number of textures on screen that are continuously missing,
  46. then we are far from optimal : eg. you want to draw A,B,C and only have room for two;
  47. we do :
  48. up&draw A,B
  49. kick A ; up&draw C
  50. kick B ; up&draw A
  51. kick C ; up&draw B , etc...
  52. eg. with a pure LRU we are always uploading, when really one of the three could stay up
  53. all the time. The traditional solution to this in caching is to use several "ways". That's
  54. a really goofy solution. One solution in rendering is to reverse the render order each
  55. frame : A,B,C ; C,B,A ; A,B,C ... then the cache looks like :
  56. up&draw A,B
  57. kick A ; up&draw C
  58. draw C,B
  59. kick C, up&draw A
  60. draw A,B
  61. kick A ; up&draw C
  62. -> I'm now doing this reversing in pcache; unfortunately, partial flushes hurt this
  63. <> There's some contention between balancing and mip biasing. When you're looking back and
  64. forth the balance keeps changing, so the bias will never do its work.
  65. <> Note that we only crank Mip Bias when the total texture memory overflows the total card
  66. space. There can be overflows that are not due to full texture overflow. Examples :
  67. if the memory is fragmented, and we cannot allocate the texture type we need in the
  68. remaining memory
  69. <> There's a sort of hysterisys that can happen with the mip bias : you overflow the card,
  70. so you crank up the bias. Now, with the new bias, you suddenly underflow, so you kick
  71. the mip bias back down. Our makes this happen once per five frames or so, instead of
  72. every single frame. There's no real way to avoid this, because we can't tell how much
  73. memory mipping-down really saves (unless we check every rendered poly)
  74. <> note : Mip Bias changes cause loads of "fresh" mip misses
  75. did : might be good to quantize the mip biases to some buckets at the last minute;
  76. 1.0 , 1.25 , 1.5 , or something
  77. <> tiny texture misses (eg. lightmaps) need to be handled more intelligently -
  78. eg. they shouldn't affect the mip bias, and they should not be so greedy for textures;
  79. ie. letting them miss is not so bad, and creating surfaces for them may be costly
  80. we need logic like this :
  81. 1. if the card is near full, just don't bother trying to make new small slots
  82. 2. make small slots slowly - eg. if the demand is 20 slots, make 2 per frame
  83. the idea is so that if you suddenly see 100 new textures, you don't make loads of slots,
  84. just let them miss, unless they stay on screen for a while
  85. (this may be automatically handled by BALANCES_PER_FRAME and OVERFLOW_MAX)
  86. on second thought, this may be all automagic; just need to think about it a little
  87. ********/
  88. #include <Windows.h>
  89. #include <Stdio.h>
  90. #include <Assert.h>
  91. #include <DDraw.h>
  92. #include <D3D.h>
  93. #include "D3DCache.h"
  94. #include "d3d_main.h" //for GetLog
  95. #include "d3d_thandle.h"
  96. #include "mempool.h"
  97. extern uint32 Scene_CurrentFrame;
  98. // tweakable config for the cache balancing :
  99. #define MAX_BALANCES_PER_FRAME (12)
  100. #define HISTORY_SIZE (8)
  101. #define BIAS_HISTORY_SIZE (10)
  102. #define BALANCE_FRAME_DELAY (2)
  103. #define CACHE_LINGER_FRAMES (8) // newly added slot won't be removed for this long
  104. #define OVERFLOW_MAX (8)
  105. #define MIPBIAS_MAX (5.0f)
  106. // Cache types are just the different types of textures
  107. // Textures may vary from width/height/num miplevels/etc...
  108. // Cache types is just a way to combine them to similar types...
  109. #define D3DCACHE_MAX_CACHE_TYPES (64)
  110. #define D3DCACHE_MAX_CACHE_SLOTS (1024) // per type!
  111. static uint32 Log2(uint32 P2);
  112. static int32 SnapToPower2(int32 Width);
  113. static int32 GetLog(int32 Width, int32 Height);
  114. //=====================================================================================
  115. // Log2
  116. // Return the log of a size
  117. //=====================================================================================
  118. static uint32 Log2(uint32 P2)
  119. {
  120. uint32 p = 0;
  121. int32 i = 0;
  122. for (i = P2; i > 0; i>>=1)
  123. p++;
  124. return (p-1);
  125. }
  126. //=====================================================================================
  127. // SnapToPower2
  128. // Snaps a number to a power of 2
  129. //=====================================================================================
  130. static int32 SnapToPower2(int32 Width)
  131. {
  132. if (Width <= 1) return 1;
  133. else if (Width <= 2) return 2;
  134. else if (Width <= 4) return 4;
  135. else if (Width <= 8) return 8;
  136. else if (Width <= 16) return 16;
  137. else if (Width <= 32) return 32;
  138. else if (Width <= 64) return 64;
  139. else if (Width <= 128) return 128;
  140. else if (Width <= 256) return 256;
  141. else if (Width <= 512) return 512;
  142. else if (Width <= 1024) return 1024;
  143. else if (Width <= 2048) return 2048;
  144. else
  145. return -1;
  146. }
  147. //=====================================================================================
  148. // Return the max log of a (power of 2) width and height
  149. //=====================================================================================
  150. static int32 GetLog(int32 Width, int32 Height)
  151. {
  152. int32 LWidth = SnapToPower2(max(Width, Height));
  153. return Log2(LWidth);
  154. }
  155. //========================================================================================================
  156. //========================================================================================================
  157. typedef struct D3DCache_Slot
  158. {
  159. jeBoolean IsActive; // indicates whether it is used & set up
  160. struct D3DCache_Slot *SelfCheck;
  161. D3DCache_Type *CacheType;
  162. LPDIRECTDRAWSURFACE7 Surface; // The DD surface for this slot
  163. uint32 LRU; // Current LRU for cache slot
  164. THandle_MipData *MipData; // whose data do I have?
  165. } D3DCache_Slot;
  166. typedef struct D3DCache_Type
  167. {
  168. int32 Log;
  169. int32 Width; // Width/Height
  170. int32 Height;
  171. int32 NumMipLevels;
  172. int32 Stage;
  173. int32 RefCount; // How many references to this cache_type
  174. // {} when refcount is zero, nothing is set up
  175. // RefCount is the number of thandles of this type
  176. int32 Size; // in bytes
  177. DDSURFACEDESC2 ddsd; // DD surface description
  178. D3DCache_Slot * SlotPtrs[D3DCACHE_MAX_CACHE_SLOTS]; // Cache slots for this Cache type
  179. int32 NumSlots; // number of slots allocated
  180. D3DCache_Type *SelfCheck;
  181. D3DCache *Cache;
  182. int32 Misses,FreshMisses,Uses,AddedCountdown;
  183. int32 OverflowMax,OverflowHistory[HISTORY_SIZE],OverflowHistoryI;
  184. //int32 MissesMax,FreshMissesMax,UsesMax;
  185. int32 SlotNeedRating;
  186. } D3DCache_Type;
  187. typedef struct D3DCache
  188. {
  189. struct D3DCache *SelfCheck;
  190. char Name[D3DCACHE_MAX_NAME];
  191. LPDIRECTDRAW7 lpDD; // DD object for the cache manager
  192. DDMemMgr_Partition *Partition; // just counts off a pre-queried FreeMem variable
  193. jeBoolean UseStages;
  194. D3DCache_Type CacheTypes[D3DCACHE_MAX_CACHE_TYPES]; // CacheTypes
  195. int32 SoughtMem,AvailMem,CardMem;
  196. float StoreMipBias[BIAS_HISTORY_SIZE];
  197. int StoreMipBiasI;
  198. MemPool *SlotPool;
  199. jeBoolean DoMipBias;
  200. int32 TotNumSlots;
  201. } D3DCache;
  202. #ifdef DO_LOG
  203. typedef struct D3DCacheLogType
  204. {
  205. int frames;
  206. double updateTime;
  207. int slotsCreated,slotsDestroyed;
  208. int maxCacheTypes;
  209. int TexMissesTot;
  210. int LMapMissesTot;
  211. int TexMissBytesTot;
  212. int LMapMissBytesTot;
  213. int CardMemTot,SlotMemTot,UsedMemTot;
  214. float MipBiasTot,MipBiasMax;
  215. } D3DCacheLogType;
  216. static D3DCacheLogType D3DCacheLog;
  217. #endif
  218. //========================================================================================================
  219. //========================================================================================================
  220. void D3DCache_InitStaticsAndGlobals(void)
  221. {
  222. }
  223. int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, jeBoolean UseStage, int32 Stage);
  224. jeBoolean D3DCache_FreeAllSlots(D3DCache *Cache);
  225. void D3DCache_Balance(D3DCache *Cache);
  226. jeBoolean D3DCache_TypeAddSlot(D3DCache_Type *pCacheType);
  227. jeBoolean D3DCache_RemoveOldestSlot(D3DCache *Cache,D3DCache_Type *NotType,jeBoolean Critical);
  228. void D3DCacheLog_WriteToFile(void);
  229. //========================================================================================================
  230. // D3DCache_Create
  231. //========================================================================================================
  232. D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW7 lpDD, DDMemMgr_Partition *Partition,jeBoolean UseStages)
  233. {
  234. D3DCache *Cache;
  235. assert(strlen(Name) < D3DCACHE_MAX_NAME);
  236. Cache = (D3DCache*)malloc(sizeof(D3DCache));
  237. if (!Cache)
  238. return NULL;
  239. memset(Cache, 0, sizeof(D3DCache));
  240. Cache->SlotPool = MemPool_Create(sizeof(D3DCache_Slot),1024,1024);
  241. if ( ! Cache->SlotPool )
  242. {
  243. free(Cache);
  244. return NULL;
  245. }
  246. Cache->lpDD = lpDD;
  247. Cache->Partition = Partition;
  248. Cache->UseStages = UseStages;
  249. Cache->SelfCheck = Cache;
  250. Cache->CardMem = DDMemMgr_PartitionGetTotalMem(Cache->Partition);
  251. strcpy(Cache->Name, Name);
  252. for(int i=0;i<BIAS_HISTORY_SIZE;i++)
  253. {
  254. Cache->StoreMipBias[i] = 1.0f;
  255. }
  256. Cache->DoMipBias = JE_TRUE;
  257. return Cache;
  258. }
  259. //========================================================================================================
  260. // D3DCache_Destroy
  261. //========================================================================================================
  262. void D3DCache_Destroy(D3DCache *Cache)
  263. {
  264. assert(Cache);
  265. D3DCache_FreeAllSlots(Cache);
  266. MemPool_Destroy(&(Cache->SlotPool));
  267. free(Cache);
  268. #ifdef DO_LOG
  269. D3DCacheLog_WriteToFile();
  270. #endif
  271. }
  272. //========================================================================================================
  273. // D3DCache_IsValid
  274. //========================================================================================================
  275. jeBoolean D3DCache_IsValid(D3DCache *Cache)
  276. {
  277. if (!Cache)
  278. return JE_FALSE;
  279. if (Cache->SelfCheck != Cache)
  280. return JE_FALSE;
  281. return JE_TRUE;
  282. }
  283. //========================================================================================================
  284. // D3DCache_SeriousSelfCheck
  285. //========================================================================================================
  286. void D3DCache_SeriousSelfCheck(D3DCache *Cache)
  287. {
  288. int i;
  289. D3DCache_Type *pCacheType;
  290. assert(D3DCache_IsValid(Cache));
  291. int PartTotMem = DDMemMgr_PartitionGetTotalMem(Cache->Partition);
  292. int PartFreeMem = DDMemMgr_PartitionGetFreeMem(Cache->Partition);
  293. int MemUsed = 0;
  294. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  295. {
  296. if ( ! pCacheType->RefCount && ! pCacheType->NumSlots ) // nothing here
  297. continue;
  298. assert( D3DCache_TypeIsValid(pCacheType) );
  299. //assert( pCacheType->NumSlots >= 1 ); // NumSlots can be zero now
  300. //assert( pCacheType->NumSlots <= pCacheType->RefCount ); // may have destroyed texes & left slots
  301. assert( pCacheType->Cache == Cache );
  302. MemUsed += pCacheType->NumSlots * pCacheType->Size;
  303. int k;
  304. int ActiveSlots = 0;
  305. // count the number of slots with IsActive
  306. for (k=0; k< D3DCACHE_MAX_CACHE_SLOTS; k++)
  307. {
  308. D3DCache_Slot *pSlot;
  309. pSlot = pCacheType->SlotPtrs[k];
  310. if ( k < pCacheType->NumSlots )
  311. {
  312. assert(pSlot);
  313. assert(pSlot->IsActive);
  314. assert( D3DCache_SlotIsValid(pSlot) );
  315. assert( pSlot->CacheType = pCacheType );
  316. ActiveSlots ++;
  317. }
  318. else
  319. {
  320. assert(pSlot == NULL);
  321. }
  322. }
  323. assert( pCacheType->NumSlots == ActiveSlots );
  324. }
  325. assert( MemUsed == (PartTotMem - PartFreeMem) );
  326. }
  327. //========================================================================================================
  328. // D3DCache_Update
  329. //========================================================================================================
  330. extern float PCache_MipBias;
  331. extern DRV_CacheInfo PCache_CacheInfo;
  332. void D3DCache_TypeUsed(D3DCache_Type *CacheType)
  333. {
  334. CacheType->Uses ++;
  335. }
  336. #ifdef DO_LOG
  337. #include "tsc.h"
  338. #endif
  339. void D3DCache_Update(D3DCache *Cache)
  340. {
  341. int32 i;
  342. D3DCache_Type *pCacheType;
  343. int32 SlotMemNonEssential,SlotMemEssential,SoughtMemExcess;
  344. #ifdef DO_LOG
  345. tsc_type tsc1,tsc2;
  346. #endif
  347. assert(D3DCache_IsValid(Cache));
  348. Cache->SoughtMem = 0;
  349. SlotMemNonEssential = SlotMemEssential = SoughtMemExcess = 0;
  350. #ifdef _DEBUG
  351. D3DCache_SeriousSelfCheck(Cache);
  352. #endif
  353. #ifdef DO_LOG
  354. readTSC(tsc1);
  355. #endif
  356. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  357. {
  358. pCacheType->Uses = 0;
  359. }
  360. THandle_GetCacheTypeUses();
  361. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  362. {
  363. if ( ! pCacheType->RefCount )
  364. {
  365. assert( pCacheType->Uses == 0 );
  366. SlotMemNonEssential += pCacheType->NumSlots * pCacheType->Size;
  367. continue;
  368. }
  369. if ( pCacheType->Uses > 0 )
  370. {
  371. Cache->SoughtMem += pCacheType->Uses * pCacheType->Size;
  372. SoughtMemExcess += (pCacheType->Uses - 1) * pCacheType->Size;
  373. }
  374. if ( pCacheType->NumSlots > 0 )
  375. {
  376. SlotMemNonEssential += (pCacheType->NumSlots - 1) * pCacheType->Size;
  377. SlotMemEssential += pCacheType->Size;
  378. }
  379. //pCacheType->UsesMax = (pCacheType->UsesMax + pCacheType->Uses)*0.5f;
  380. //pCacheType->MissesMax = (pCacheType->MissesMax + pCacheType->Misses)*0.5f;
  381. //pCacheType->FreshMissesMax = (pCacheType->FreshMissesMax + pCacheType->FreshMisses)*0.5f;
  382. pCacheType->OverflowMax = 0;
  383. pCacheType->OverflowHistory[pCacheType->OverflowHistoryI] = pCacheType->Uses - pCacheType->NumSlots;
  384. pCacheType->OverflowHistoryI = (pCacheType->OverflowHistoryI + 1)%HISTORY_SIZE;
  385. for(int j=0;j<HISTORY_SIZE;j++)
  386. {
  387. pCacheType->OverflowMax = max(pCacheType->OverflowMax,pCacheType->OverflowHistory[j]);
  388. }
  389. }
  390. // we've not got Misses,Uses, and UsesMax on all cache types
  391. D3DCache_Balance(Cache);
  392. PCache_CacheInfo.CacheTypes = 0;
  393. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  394. {
  395. if ( ! pCacheType->RefCount )
  396. continue;
  397. assert( pCacheType->FreshMisses <= pCacheType->Misses );
  398. PCache_CacheInfo.CacheMisses[PCache_CacheInfo.CacheTypes] = pCacheType->Misses;
  399. PCache_CacheInfo.CacheFreshMisses[PCache_CacheInfo.CacheTypes] = pCacheType->FreshMisses;
  400. PCache_CacheInfo.CacheUses[PCache_CacheInfo.CacheTypes] = pCacheType->Uses;
  401. PCache_CacheInfo.CacheSlots[PCache_CacheInfo.CacheTypes] = pCacheType->NumSlots;
  402. PCache_CacheInfo.CacheTypes++;
  403. // reset the count
  404. pCacheType->Misses = 0;
  405. pCacheType->FreshMisses = 0;
  406. if ( pCacheType->AddedCountdown == CACHE_LINGER_FRAMES ) // <> just balanced
  407. {
  408. // clear the history!
  409. for(int j=0;j<HISTORY_SIZE;j++)
  410. pCacheType->OverflowHistory[j] = 0;
  411. }
  412. if ( pCacheType->AddedCountdown > 0 )
  413. pCacheType->AddedCountdown --;
  414. }
  415. PCache_CacheInfo.CardMem = Cache->CardMem;
  416. PCache_CacheInfo.SlotMem = Cache->CardMem - DDMemMgr_PartitionGetFreeMem(Cache->Partition);
  417. PCache_CacheInfo.UsedMem = Cache->SoughtMem;
  418. Cache->AvailMem = SlotMemNonEssential;
  419. if ( Cache->DoMipBias )
  420. {
  421. float MipBias;
  422. MipBias = PCache_MipBias;
  423. {
  424. int Diff2;
  425. // Diff1 = SoughtMemExcess - SlotMemNonEssential - 111111;
  426. Diff2 = Cache->SoughtMem - Cache->CardMem;
  427. // Diff2 doesn't account for headers & other complications,
  428. // but that's probably a good thing
  429. if ( Diff2 > 0 )
  430. {
  431. // we overflowed the card
  432. MipBias += 0.33f;
  433. }
  434. else if ( Diff2 < -555555 )
  435. {
  436. // we underloaded
  437. /*
  438. if ( MipBias > 1.0f )
  439. {
  440. MipBias -= 0.1f;
  441. MipBias = max(MipBias,1.0f);
  442. }
  443. */
  444. // just snap it back to 1.0f
  445. MipBias = 1.0f;
  446. }
  447. }
  448. Cache->StoreMipBias[Cache->StoreMipBiasI] = MipBias;
  449. Cache->StoreMipBiasI = (Cache->StoreMipBiasI + 1)%BIAS_HISTORY_SIZE;
  450. #if 1 // average of some biases
  451. PCache_MipBias = 0.0f;
  452. for(int i=0;i<BIAS_HISTORY_SIZE;i++)
  453. {
  454. PCache_MipBias += Cache->StoreMipBias[i];
  455. }
  456. PCache_MipBias *= (1.0f/BIAS_HISTORY_SIZE);
  457. #else // max
  458. PCache_MipBias = 1.0f;
  459. for(int i=0;i<BIAS_HISTORY_SIZE;i++)
  460. {
  461. PCache_MipBias = max(PCache_MipBias,Cache->StoreMipBias[i]);
  462. }
  463. #endif
  464. #if 1 // <> quantize it to multiples of 0.25
  465. {
  466. int32 q;
  467. q = (int32)(PCache_MipBias * 4 + 0.5f);
  468. PCache_MipBias = q * 0.25f;
  469. }
  470. #endif
  471. if ( PCache_MipBias > MIPBIAS_MAX )
  472. PCache_MipBias = MIPBIAS_MAX;
  473. }
  474. else
  475. {
  476. PCache_MipBias = 1.0f;
  477. }
  478. PCache_CacheInfo.MipBias = PCache_MipBias;
  479. #ifdef DO_LOG
  480. readTSC(tsc2);
  481. D3DCacheLog.frames ++;
  482. D3DCacheLog.updateTime += diffTSC(tsc1,tsc2);
  483. D3DCacheLog.CardMemTot += Cache->CardMem;
  484. D3DCacheLog.SlotMemTot += PCache_CacheInfo.SlotMem;
  485. D3DCacheLog.UsedMemTot += Cache->SoughtMem;
  486. D3DCacheLog.MipBiasTot += PCache_MipBias;
  487. D3DCacheLog.MipBiasMax = max(D3DCacheLog.MipBiasMax,PCache_MipBias);
  488. D3DCacheLog.TexMissesTot += PCache_CacheInfo.TexMisses;
  489. D3DCacheLog.TexMissBytesTot += PCache_CacheInfo.TexMissBytes;
  490. D3DCacheLog.LMapMissesTot += PCache_CacheInfo.LMapMisses;
  491. D3DCacheLog.LMapMissBytesTot += PCache_CacheInfo.LMapMissBytes;
  492. #endif
  493. }
  494. void D3DCache_Balance(D3DCache *Cache)
  495. {
  496. int32 i,ChoseMissSizeMax,FailedSize,Creations;
  497. D3DCache_Type *pCacheType,*ChoseCacheType;
  498. assert(D3DCache_IsValid(Cache));
  499. /***
  500. doing only 1 per frame means we never take a huge hit,
  501. but it means we take a really long time to balance when a bunch of new
  502. low-mip stuff comes into view in the distance
  503. it seems we can do alot without taking a framerate hit ! I put
  504. MAX_BALANCES_PER_FRAME == 32 and it's fast!!
  505. ***/
  506. PCache_CacheInfo.Balances = PCache_CacheInfo.BalancesFailed = 0;
  507. FailedSize = 999999999;
  508. for(Creations=0;Creations < MAX_BALANCES_PER_FRAME;Creations++)
  509. {
  510. // look the highest (Size * OverflowMax)
  511. TryAgain:
  512. /***
  513. We'd like to take account of the misses too, but misses that don't result from overflow are
  514. very hard to account for properly. There are two types :
  515. 1. when you first walk into a room, you get misses until the new textures get on the card
  516. 2. if there are two places, each with too many textures, you'll get misses every time you
  517. go between them.
  518. Perhaps adjust for misses if there are no overflows ?
  519. <> use the FreshMisses !
  520. <> the FreshMisses aren't behaving quite as they should
  521. (aside from not working, they also seem to whack out the normal balances)
  522. ***/
  523. ChoseMissSizeMax = 0;
  524. // choose a type to try to extend
  525. int AvailSlots = D3DInfo.MaxSurfaceCount - Cache->TotNumSlots + 1;
  526. AvailSlots = min(AvailSlots,OVERFLOW_MAX);
  527. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  528. {
  529. int32 MissSizeMax;
  530. int32 overflow;
  531. pCacheType->SlotNeedRating = 0;
  532. if ( ! pCacheType->RefCount )
  533. continue;
  534. if ( pCacheType->NumSlots == D3DCACHE_MAX_CACHE_SLOTS )
  535. continue; // can't add any here
  536. // overflow is a much higher priority than fresh misses
  537. /*
  538. if ( pCacheType->OverflowMax > 0.1f )
  539. MissSizeMax = (int32)(pCacheType->Size * pCacheType->OverflowMax * 256.0f);
  540. else if ( pCacheType->FreshMissesMax > 0.1f )
  541. MissSizeMax = (int32)(pCacheType->Size * pCacheType->FreshMissesMax);
  542. */
  543. overflow = pCacheType->OverflowMax;
  544. overflow = min(overflow,AvailSlots);
  545. MissSizeMax = (int32)(pCacheType->Size * overflow);
  546. pCacheType->SlotNeedRating = MissSizeMax;
  547. if ( pCacheType->Size >= FailedSize )
  548. continue; // rate me but don't add to me (already tried)
  549. if ( MissSizeMax > ChoseMissSizeMax )
  550. {
  551. ChoseMissSizeMax = MissSizeMax;
  552. ChoseCacheType = pCacheType;
  553. }
  554. }
  555. if ( ! ChoseMissSizeMax )
  556. return; // found nothing to do
  557. // found something that missed
  558. // try to add a slot to this type
  559. while ( ! D3DCache_TypeAddSlot(ChoseCacheType) )
  560. {
  561. if ( ! D3DCache_RemoveOldestSlot(Cache,ChoseCacheType,JE_FALSE) )
  562. {
  563. PCache_CacheInfo.BalancesFailed ++;
  564. // we might have been unable to find space for a 256x256 ,
  565. // but there might be a smaller type that also missed !
  566. // go back and restart with a smaller max size
  567. FailedSize = ChoseCacheType->Size;
  568. goto TryAgain;
  569. }
  570. }
  571. PCache_CacheInfo.Balances ++;
  572. // we did it!
  573. // clear the history of failure
  574. ChoseCacheType->AddedCountdown = CACHE_LINGER_FRAMES; // can't remove from here for this many frames
  575. ChoseCacheType->OverflowMax = max(ChoseCacheType->OverflowMax - BALANCE_FRAME_DELAY,0);
  576. // <> if we subtract one here, then we could build slots for all the overflows in one frame
  577. // if we subtract N, we spread the rebuild over N frames
  578. // loop around and do another
  579. }
  580. }
  581. //========================================================================================================
  582. //========================================================================================================
  583. jeBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache) // called by THandle_EvictAll, from Main_RestoreAll
  584. {
  585. int32 i;
  586. D3DCache_Type *pCacheType;
  587. assert(D3DCache_IsValid(Cache));
  588. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  589. {
  590. D3DCache_Slot *pSlot;
  591. int32 s;
  592. assert(D3DCache_TypeIsValid(pCacheType));
  593. // just forces a re-upload, doesn't free any memory
  594. for (s=0; s< pCacheType->NumSlots; s++)
  595. {
  596. pSlot = pCacheType->SlotPtrs[s];
  597. pSlot->MipData = NULL;
  598. }
  599. }
  600. return JE_TRUE;
  601. }
  602. //========================================================================================================
  603. //========================================================================================================
  604. static D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
  605. {
  606. int32 i;
  607. D3DCache_Type *pCacheType;
  608. assert(D3DCache_IsValid(Cache));
  609. // {} never called externally
  610. pCacheType = Cache->CacheTypes;
  611. for (i=0; i<D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  612. {
  613. if (pCacheType->RefCount == 0 && pCacheType->NumSlots == 0) // this slot contains no type
  614. continue;
  615. assert(D3DCache_TypeIsValid(pCacheType));
  616. if (pCacheType->Width != Width)
  617. continue;
  618. if (pCacheType->Height != Height)
  619. continue;
  620. if (pCacheType->NumMipLevels != NumMipLevels)
  621. continue;
  622. if (pCacheType->Stage != Stage)
  623. continue;
  624. if (memcmp(&pCacheType->ddsd, ddsd, sizeof(DDSURFACEDESC2)))
  625. continue;
  626. return pCacheType; // Found a match
  627. }
  628. return NULL; // Cache Type not found!!!
  629. }
  630. //========================================================================================================
  631. //========================================================================================================
  632. static D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
  633. {
  634. int32 i;
  635. D3DCache_Type *pCacheType;
  636. assert(D3DCache_IsValid(Cache));
  637. // {} never called externally
  638. pCacheType = Cache->CacheTypes;
  639. for (i=0; i<D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  640. {
  641. if ( pCacheType->RefCount == 0 && pCacheType->NumSlots == 0 ) // Nobody is using this slot yet
  642. break; // found a vacancy
  643. }
  644. #ifdef DO_LOG
  645. D3DCacheLog.maxCacheTypes = max(D3DCacheLog.maxCacheTypes,i);
  646. #endif
  647. if (i == D3DCACHE_MAX_CACHE_TYPES) // No types left
  648. return NULL;
  649. memset(pCacheType,0,sizeof(*pCacheType)); // {} redundant ?
  650. assert( pCacheType->RefCount == 0 && pCacheType->NumSlots == 0 );
  651. pCacheType->Width = Width;
  652. pCacheType->Height = Height;
  653. pCacheType->NumMipLevels = NumMipLevels;
  654. pCacheType->Stage = Stage;
  655. pCacheType->ddsd = *ddsd;
  656. pCacheType->SelfCheck = pCacheType;
  657. pCacheType->Cache = Cache;
  658. pCacheType->Log = GetLog(Width, Height);
  659. // {} this Size assumes W & H are pow2's ! (and square?)
  660. pCacheType->Size = Width*Height*(pCacheType->ddsd.ddpfPixelFormat.dwRGBBitCount>>3);
  661. // <> doesn't account for NumMipLevels !? (Neither did the old stuff)
  662. // Found one
  663. pCacheType->RefCount++;
  664. return pCacheType;
  665. }
  666. //========================================================================================================
  667. //========================================================================================================
  668. D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
  669. {
  670. D3DCache_Type *CacheType;
  671. assert(D3DCache_IsValid(Cache));
  672. // {} called whenever a new THandle is made
  673. CacheType = D3DCache_FindCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd);
  674. if (CacheType)
  675. {
  676. // Increase the ref count on this slot, and return it
  677. CacheType->RefCount++;
  678. return CacheType;
  679. }
  680. // Could not find one allready in the list, so add a new one...
  681. return D3DCache_InsertCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd);
  682. }
  683. //========================================================================================================
  684. // D3DCache_FreeSlot
  685. //========================================================================================================
  686. void D3DCache_FreeSlot(D3DCache_Slot *pSlot)
  687. {
  688. D3DCache * Cache;
  689. assert( pSlot );
  690. Cache = pSlot->CacheType->Cache;
  691. if ( pSlot->IsActive )
  692. {
  693. assert(D3DCache_SlotIsValid(pSlot));
  694. assert(pSlot->Surface);
  695. if (pSlot->Surface)
  696. pSlot->Surface->Release();
  697. if ( pSlot->MipData && pSlot->MipData->Slot == pSlot )
  698. {
  699. pSlot->MipData->KickedFrame = Scene_CurrentFrame;
  700. pSlot->MipData->Slot = NULL;
  701. }
  702. assert( pSlot->CacheType->NumSlots >= 1 );
  703. pSlot->CacheType->NumSlots --;
  704. assert( Cache->TotNumSlots >= 1 );
  705. Cache->TotNumSlots --;
  706. DDMemMgr_PartitionFreeMem(pSlot->CacheType->Cache->Partition, pSlot->CacheType->Size);
  707. #ifdef DO_LOG
  708. D3DCacheLog.slotsDestroyed ++;
  709. #endif
  710. }
  711. memset(pSlot,0,sizeof(*pSlot));
  712. pSlot->SelfCheck = pSlot;
  713. MemPool_FreeHunk(Cache->SlotPool,pSlot);
  714. }
  715. //========================================================================================================
  716. // D3DCache_TypeDestroy
  717. //========================================================================================================
  718. void D3DCache_TypeDestroy(D3DCache_Type *CacheType)
  719. {
  720. assert(CacheType->RefCount > 0);
  721. assert(D3DCache_TypeIsValid(CacheType));
  722. CacheType->RefCount--;
  723. if (CacheType->RefCount > 0)
  724. return;
  725. // <> there should be no textures pointing at this Type anymore
  726. #if 0 // {
  727. // don't free now, just let the balance free them later
  728. //
  729. // henever you rebuild the bsp, it destroys all lightmaps then remakes them
  730. // we'd like to not destroy the type, just let it hang around,
  731. int32 k,ns;
  732. OutputDebugString("D3DCache_TypeDestroy : no textures of this type left, freeing slots\n");
  733. ns = CacheType->NumSlots;
  734. // Go through each slot, and free all the surfaces on them
  735. for (k=0; k< ns; k++)
  736. {
  737. D3DCache_FreeSlot(CacheType->SlotPtrs[k]);
  738. CacheType->SlotPtrs[k] = NULL;
  739. }
  740. CacheType->NumSlots = 0;
  741. #endif //}
  742. }
  743. //========================================================================================================
  744. // D3DCache_TypeIsValid
  745. //========================================================================================================
  746. jeBoolean D3DCache_TypeIsValid(D3DCache_Type *Type)
  747. {
  748. if (!Type)
  749. return JE_FALSE;
  750. // <> cheat!
  751. if ( Type->SelfCheck == NULL )
  752. Type->SelfCheck = Type;
  753. if (Type->SelfCheck != Type)
  754. return JE_FALSE;
  755. if (!D3DCache_IsValid(Type->Cache))
  756. return JE_FALSE;
  757. return JE_TRUE;
  758. }
  759. //========================================================================================================
  760. // D3DCache_RemoveOldestSlot
  761. //========================================================================================================
  762. jeBoolean D3DCache_RemoveOldestSlot(D3DCache *Cache,D3DCache_Type *NotType,jeBoolean Critical)
  763. {
  764. int32 i,OldestIndex;
  765. D3DCache_Type *pCacheType,*OldestType;
  766. D3DCache_Slot *OldestSlot;
  767. assert(D3DCache_IsValid(Cache));
  768. OldestSlot = NULL;
  769. // try to find a nice one to remove
  770. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  771. {
  772. D3DCache_Slot *pSlot;
  773. int32 k;
  774. if ( pCacheType == NotType )
  775. continue;
  776. if ( pCacheType->NumSlots == 0 ) // nothing to do
  777. continue;
  778. if ( pCacheType->RefCount >= pCacheType->NumSlots )
  779. {
  780. if ( pCacheType->NumSlots == 1 ) // can't free the last slot of a type
  781. continue;
  782. if ( pCacheType->SlotNeedRating >= NotType->SlotNeedRating )
  783. continue; // I need it more that you do!
  784. if ( pCacheType->Uses >= pCacheType->NumSlots )
  785. continue; // don't free if all slots are used!!
  786. if ( pCacheType->OverflowMax > 0.1f )
  787. continue; // don't free it if recently missed
  788. if ( pCacheType->AddedCountdown > 0 )
  789. continue; // just added one here recently, don't remove it !
  790. }
  791. else
  792. {
  793. // RefCount < NumSlots ; take me!
  794. }
  795. // find the oldest slot
  796. for (k=0; k< pCacheType->NumSlots; k++)
  797. {
  798. pSlot = pCacheType->SlotPtrs[k];
  799. assert( pSlot->IsActive );
  800. if ( ! OldestSlot || pSlot->LRU < OldestSlot->LRU )
  801. {
  802. OldestSlot = pSlot;
  803. OldestType = pCacheType;
  804. OldestIndex = k;
  805. }
  806. }
  807. }
  808. if ( ! OldestSlot )
  809. {
  810. // now look for one that's not so readily removed
  811. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  812. {
  813. D3DCache_Slot *pSlot;
  814. int32 k;
  815. if ( pCacheType == NotType )
  816. continue;
  817. if ( pCacheType->NumSlots <= 1 ) // can't free the last slot of a type
  818. continue;
  819. if ( pCacheType->SlotNeedRating >= NotType->SlotNeedRating )
  820. continue; // I need it more that you do!
  821. if ( pCacheType->AddedCountdown > 0 )
  822. continue; // just added one here recently, don't remove it !
  823. // find the oldest slot
  824. for (k=0; k< pCacheType->NumSlots; k++)
  825. {
  826. pSlot = pCacheType->SlotPtrs[k];
  827. assert( pSlot->IsActive );
  828. if ( ! OldestSlot || pSlot->LRU < OldestSlot->LRU )
  829. {
  830. OldestSlot = pSlot;
  831. OldestType = pCacheType;
  832. OldestIndex = k;
  833. }
  834. }
  835. }
  836. }
  837. if ( Critical && ! OldestSlot )
  838. {
  839. // now remove one at all cost!
  840. if ( ! OldestSlot )
  841. {
  842. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  843. {
  844. D3DCache_Slot *pSlot;
  845. int32 k;
  846. if ( pCacheType == NotType )
  847. continue;
  848. if ( pCacheType->NumSlots == 0 ) // nothing to do
  849. continue;
  850. // find the oldest slot
  851. for (k=0; k< pCacheType->NumSlots; k++)
  852. {
  853. pSlot = pCacheType->SlotPtrs[k];
  854. assert( pSlot->IsActive );
  855. if ( ! OldestSlot || pSlot->LRU < OldestSlot->LRU )
  856. {
  857. OldestSlot = pSlot;
  858. OldestType = pCacheType;
  859. OldestIndex = k;
  860. }
  861. }
  862. }
  863. }
  864. }
  865. if ( ! OldestSlot )
  866. return JE_FALSE; // nothing to free!
  867. if ( ! Critical )
  868. {
  869. // compare OldestType and NotType
  870. if ( OldestType->Uses >= OldestType->NumSlots ) // seriously try to avoid destroying this
  871. {
  872. // if both types are overflowing, don't destroy a larger one to make a smaller
  873. if ( OldestType->Size >= NotType->Size )
  874. return JE_FALSE;
  875. }
  876. }
  877. D3DCache_FreeSlot(OldestSlot);
  878. if ( OldestType->NumSlots > 0 )
  879. {
  880. D3DCache_Slot *pSlot;
  881. // slide the list to keep it linear
  882. pSlot = OldestType->SlotPtrs[OldestType->NumSlots];
  883. assert( pSlot );
  884. OldestType->SlotPtrs[OldestIndex] = pSlot;
  885. OldestType->SlotPtrs[OldestType->NumSlots] = NULL;
  886. }
  887. // OldestType->RemovedCountdown = 7; // <> don't add here again right away ?
  888. // <> not good : the _Balance may look like this :
  889. // trying to add type 1
  890. // remove type 2, remove type 3
  891. // add type 1 still fails!
  892. // so now re-add a type 2 & type 3
  893. // hence we MUST be able to add right after a remove
  894. return JE_TRUE;
  895. }
  896. //========================================================================================================
  897. // D3DCache_FreeAllSlots
  898. //========================================================================================================
  899. jeBoolean D3DCache_FreeAllSlots(D3DCache *Cache) // never called externally
  900. {
  901. int32 i;
  902. D3DCache_Type *pCacheType;
  903. assert(D3DCache_IsValid(Cache));
  904. #ifdef _DEBUG
  905. D3DMain_Log("D3DCache_FreeAllSlots starting\n");
  906. #endif
  907. OutputDebugString("D3DCache_FreeAllSlots\n");
  908. for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
  909. {
  910. D3DCache_Slot *pSlot;
  911. int32 k,ns;
  912. if ( pCacheType->RefCount == 0 && pCacheType->NumSlots == 0 )
  913. continue; // nothing here!
  914. assert(D3DCache_TypeIsValid(pCacheType));
  915. // Go through each slot, and free all the surfaces on them
  916. ns = pCacheType->NumSlots;
  917. for (k=0; k< ns; k++)
  918. {
  919. pSlot = pCacheType->SlotPtrs[k];
  920. assert(pSlot->IsActive);
  921. D3DCache_FreeSlot(pSlot);
  922. }
  923. assert( pCacheType->NumSlots == 0 );
  924. }
  925. DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager
  926. Cache->AvailMem = Cache->CardMem;
  927. Cache->SoughtMem = 0;
  928. #ifdef _DEBUG
  929. D3DMain_Log("D3DCache_FreeAllSlots done\n");
  930. #endif
  931. return JE_TRUE;
  932. }
  933. //========================================================================================================
  934. // D3DCache_WriteToFile
  935. //========================================================================================================
  936. void D3DCacheLog_WriteToFile(void)
  937. {
  938. #ifdef DO_LOG
  939. SYSTEMTIME Time;
  940. FILE *f;
  941. #pragma message("D3DCache : Logging")
  942. f = fopen("D3DCache.log", "a+t");
  943. if (!f)
  944. return;
  945. GetSystemTime(&Time);
  946. fprintf(f, "=======================================================\n");
  947. fprintf(f, "Date: %i/%i/%i, Time: %i:%02i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute);
  948. fprintf(f, "Compiled : %s,%s\n",__DATE__,__TIME__);
  949. fprintf(f, "---------- total:\n");
  950. fprintf(f, "Frames = %d; Cache Types = %d; slots created/destroyed = %d/%d\n",
  951. D3DCacheLog.frames,D3DCacheLog.maxCacheTypes,D3DCacheLog.slotsCreated,D3DCacheLog.slotsDestroyed);
  952. fprintf(f, "tex misses = %d/%d , lmap misses = %d/%d\n",
  953. D3DCacheLog.TexMissesTot,D3DCacheLog.TexMissBytesTot,
  954. D3DCacheLog.LMapMissesTot,D3DCacheLog.LMapMissBytesTot);
  955. fprintf(f, "---------- per frame:\n");
  956. fprintf(f, "update = %f secs, mip bias = %f avg/%f max\n",
  957. D3DCacheLog.updateTime/(double)D3DCacheLog.frames,
  958. D3DCacheLog.MipBiasTot/(double)D3DCacheLog.frames,
  959. D3DCacheLog.MipBiasMax);
  960. fprintf(f, "mem = %f card/%f slots/%f sought\n",
  961. D3DCacheLog.CardMemTot/(double)D3DCacheLog.frames,
  962. D3DCacheLog.SlotMemTot/(double)D3DCacheLog.frames,
  963. D3DCacheLog.UsedMemTot/(double)D3DCacheLog.frames);
  964. fclose(f);
  965. #endif
  966. }
  967. //========================================================================================================
  968. // D3DCache_TypeAddSlot
  969. //========================================================================================================
  970. jeBoolean D3DCache_TypeAddSlot(D3DCache_Type *pCacheType)
  971. {
  972. D3DCache_Slot *pSlot;
  973. uint32 Result;
  974. // allocates a new slot for this type
  975. // returns true if actually did an alloc
  976. assert( D3DCache_TypeIsValid(pCacheType) );
  977. if (pCacheType->RefCount <= 0) // nothing here
  978. {
  979. // <> !! why are you calling TypeAddSlot !?
  980. return JE_FALSE;
  981. }
  982. // NumAvail > NumTextures
  983. if (pCacheType->NumSlots >= pCacheType->RefCount)
  984. return JE_FALSE; // This is all we need for this slot...
  985. if ( pCacheType->NumSlots == D3DCACHE_MAX_CACHE_SLOTS )
  986. return JE_FALSE;
  987. assert( pCacheType->Cache->TotNumSlots <= D3DInfo.MaxSurfaceCount );
  988. if ( pCacheType->Cache->TotNumSlots == D3DInfo.MaxSurfaceCount )
  989. {
  990. // sorry, no more slots allowed
  991. return JE_FALSE;
  992. }
  993. if (!DDMemMgr_PartitionAllocMem(pCacheType->Cache->Partition, pCacheType->Size))
  994. {
  995. return JE_FALSE; // No more memory in the partition, stop now...
  996. // <> CB : there might actually still be memory on the card !
  997. }
  998. // find a free slot
  999. pSlot = (D3DCache_Slot *) MemPool_GetHunk(pCacheType->Cache->SlotPool);
  1000. pSlot->SelfCheck = pSlot;
  1001. pSlot->CacheType = pCacheType;
  1002. pSlot->MipData = NULL;
  1003. pSlot->LRU = Scene_CurrentFrame - 1; //<>
  1004. // Allocate surfaces now
  1005. Result = D3DCache_SetupSlot(pCacheType->Cache, pSlot, pCacheType->Width, pCacheType->Height, &pCacheType->ddsd, pCacheType->Cache->UseStages, pCacheType->Stage);
  1006. if ( Result <= 0)
  1007. {
  1008. // Out of ram, cancel operation, and stop allocating
  1009. // DON'T memset it to zero, cuz someone else might have a ref to this slot!
  1010. pSlot->Surface = NULL;
  1011. pSlot->IsActive = JE_FALSE;
  1012. assert(Result == 0); // if not == 0, it's worse than out-of-memory !!
  1013. DDMemMgr_PartitionFreeMem(pCacheType->Cache->Partition, pCacheType->Size);
  1014. MemPool_FreeHunk(pCacheType->Cache->SlotPool, pSlot);
  1015. return JE_FALSE;
  1016. }
  1017. pSlot->IsActive = JE_TRUE;
  1018. assert( D3DCache_SlotIsValid(pSlot) );
  1019. assert( pCacheType->SlotPtrs[pCacheType->NumSlots] == NULL );
  1020. pCacheType->SlotPtrs[pCacheType->NumSlots] = pSlot;
  1021. // The slot was allocated, so increase the number of slots now
  1022. pCacheType->NumSlots++;
  1023. pCacheType->Cache->TotNumSlots ++;
  1024. #ifdef DO_LOG
  1025. D3DCacheLog.slotsCreated ++;
  1026. #endif
  1027. return JE_TRUE;
  1028. }
  1029. //========================================================================================================
  1030. // D3DCache_CheckSlots
  1031. //========================================================================================================
  1032. jeBoolean D3DCache_CheckSlots(D3DCache *Cache)
  1033. {
  1034. // do nothing
  1035. return JE_TRUE;
  1036. }
  1037. //========================================================================================================
  1038. // D3DCache_SlotIsValid
  1039. //========================================================================================================
  1040. jeBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot)
  1041. {
  1042. if (!Slot)
  1043. return JE_FALSE;
  1044. if (Slot->SelfCheck != Slot)
  1045. return JE_FALSE;
  1046. return JE_TRUE;
  1047. }
  1048. //=====================================================================================
  1049. // D3DCache_SetupSlot
  1050. //
  1051. // Returns -1 on failure
  1052. // Returns 0 on out of memory
  1053. // Returns 1 on success
  1054. //=====================================================================================
  1055. int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, jeBoolean UseStage, int32 Stage)
  1056. {
  1057. LPDIRECTDRAWSURFACE7 Surface;
  1058. DDSURFACEDESC2 ddsd;
  1059. HRESULT Hr;
  1060. assert(D3DCache_IsValid(Cache));
  1061. assert(D3DCache_SlotIsValid(Slot));
  1062. memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2));
  1063. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1064. ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  1065. if (UseStage)
  1066. ddsd.dwFlags |= DDSD_TEXTURESTAGE;
  1067. ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
  1068. ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC;
  1069. ddsd.ddsCaps.dwCaps3 = 0;
  1070. ddsd.ddsCaps.dwCaps4 = 0;
  1071. ddsd.dwHeight = Width;
  1072. ddsd.dwWidth = Height;
  1073. ddsd.dwTextureStage = Stage;
  1074. Hr = Cache->lpDD->CreateSurface(&ddsd, &Surface, NULL);
  1075. if(Hr != DD_OK)
  1076. {
  1077. if (Hr == DDERR_OUTOFVIDEOMEMORY)
  1078. {
  1079. return 0;
  1080. }
  1081. return -1;
  1082. }
  1083. Slot->Surface = Surface;
  1084. // Set the color key
  1085. #if 0
  1086. {
  1087. DDCOLORKEY CKey;
  1088. // Create the color key for this surface
  1089. CKey.dwColorSpaceLowValue = 1;
  1090. CKey.dwColorSpaceHighValue = 1;
  1091. if (Slot->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK)
  1092. {
  1093. Slot->Surface->Release();
  1094. Slot->Surface = NULL;
  1095. return -1;
  1096. }
  1097. }
  1098. #endif
  1099. return 1; // All good dude
  1100. }
  1101. //========================================================================================================
  1102. // D3DCache_TypeFindSlot
  1103. //========================================================================================================
  1104. void D3DCache_TypeMissed(D3DCache_Type *CacheType,int KickFrame)
  1105. {
  1106. // TypeFindSlot is called whenever you get a cache miss
  1107. // sort of a hack
  1108. CacheType->Misses ++;
  1109. // <> use the stage to tell whether it's a Tex or LMap
  1110. // kind of a hack;
  1111. // with the layer system there will be no difference between texes & lmaps
  1112. if ( CacheType->Stage == 0 )
  1113. {
  1114. PCache_CacheInfo.TexMisses++;
  1115. PCache_CacheInfo.TexMissBytes += CacheType->Size;
  1116. }
  1117. else
  1118. {
  1119. PCache_CacheInfo.LMapMisses++;
  1120. PCache_CacheInfo.LMapMissBytes += CacheType->Size;
  1121. }
  1122. assert((int)Scene_CurrentFrame >= KickFrame);
  1123. if ( Scene_CurrentFrame > 30 && (Scene_CurrentFrame - KickFrame) < 10 )
  1124. {
  1125. CacheType->FreshMisses ++;
  1126. PCache_CacheInfo.TexMissesFresh ++;
  1127. }
  1128. }
  1129. D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType)
  1130. {
  1131. D3DCache_Slot *pBestSlot, *pSlot;
  1132. int32 i;
  1133. assert(D3DCache_TypeIsValid(CacheType));
  1134. if ( CacheType->NumSlots == 0 )
  1135. {
  1136. // no slots ! must make one
  1137. while ( ! D3DCache_TypeAddSlot(CacheType) )
  1138. {
  1139. if ( ! D3DCache_RemoveOldestSlot(CacheType->Cache,CacheType,JE_TRUE) )
  1140. {
  1141. return NULL;
  1142. }
  1143. }
  1144. }
  1145. assert( CacheType->NumSlots > 0 );
  1146. // find the oldest active slot
  1147. pBestSlot = NULL;
  1148. for (i=0; i<CacheType->NumSlots; i++)
  1149. {
  1150. pSlot = CacheType->SlotPtrs[i];
  1151. assert(pSlot);
  1152. assert(pSlot->IsActive);
  1153. assert(D3DCache_SlotIsValid(pSlot));
  1154. if ( ! pBestSlot || pSlot->LRU < pBestSlot->LRU)
  1155. {
  1156. pBestSlot = pSlot;
  1157. }
  1158. }
  1159. assert(pBestSlot);
  1160. // possibly kick the texture that's in there now
  1161. if ( pBestSlot->MipData && pBestSlot->MipData->Slot == pBestSlot )
  1162. {
  1163. pBestSlot->MipData->KickedFrame = Scene_CurrentFrame;
  1164. pBestSlot->MipData->Slot = NULL;
  1165. }
  1166. pBestSlot->LRU = Scene_CurrentFrame - 1; // so it doesn't get kicked right away
  1167. pBestSlot->MipData = NULL;
  1168. assert(D3DCache_SlotIsValid(pBestSlot));
  1169. return pBestSlot;
  1170. }
  1171. //========================================================================================================
  1172. // D3DCache_SlotSetMipData
  1173. //========================================================================================================
  1174. void D3DCache_SlotSetMipData(D3DCache_Slot *Slot, THandle_MipData *MipData)
  1175. {
  1176. assert(D3DCache_SlotIsValid(Slot));
  1177. if ( MipData )
  1178. MipData->KickedFrame = 0; // <> eg. hasn't been kicked
  1179. Slot->MipData = MipData;
  1180. }
  1181. //========================================================================================================
  1182. // D3DCache_SlotGetMipData
  1183. //========================================================================================================
  1184. THandle_MipData *D3DCache_SlotGetMipData(D3DCache_Slot *Slot)
  1185. {
  1186. assert(D3DCache_SlotIsValid(Slot));
  1187. if ( ! Slot->IsActive )
  1188. return NULL;
  1189. return Slot->MipData;
  1190. }
  1191. //========================================================================================================
  1192. // D3DCache_SlotSetLRU
  1193. //========================================================================================================
  1194. void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU)
  1195. {
  1196. assert(D3DCache_SlotIsValid(Slot));
  1197. Slot->LRU = LRU;
  1198. }
  1199. //========================================================================================================
  1200. // D3DCache_SlotGetLRU
  1201. //========================================================================================================
  1202. uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot)
  1203. {
  1204. assert(D3DCache_SlotIsValid(Slot));
  1205. return Slot->LRU;
  1206. }
  1207. //========================================================================================================
  1208. // D3DCache_SlotGetSurface
  1209. //========================================================================================================
  1210. LPDIRECTDRAWSURFACE7 D3DCache_SlotGetSurface(D3DCache_Slot *Slot)
  1211. {
  1212. assert(D3DCache_SlotIsValid(Slot));
  1213. assert( Slot->IsActive );
  1214. return Slot->Surface;
  1215. }