/trunk/source/Engine/JetEngine/Engine/Drivers/D3DDrv/D3DCACHE.CPP
# · C++ · 1609 lines · 917 code · 370 blank · 322 comment · 195 complexity · 3d0bccbcf4a88747e287b6cdf5219a72 MD5 · raw file
- /****************************************************************************************/
- /* D3DCACHE.CPP */
- /* */
- /* Author: */
- /* Description: */
- /* */
- /* The contents of this file are subject to the Jet3D Public License */
- /* Version 1.02 (the "License"); you may not use this file except in */
- /* compliance with the License. You may obtain a copy of the License at */
- /* http://www.jet3d.com */
- /* */
- /* Software distributed under the License is distributed on an "AS IS" */
- /* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
- /* the License for the specific language governing rights and limitations */
- /* under the License. */
- /* */
- /* The Original Code is Jet3D, released December 12, 1999. */
- /* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */
- /* */
- /****************************************************************************************/
-
- // see @@ and <> for todos
-
- #define DO_LOG
-
- /*******
-
- Notes on D3DCache by Charles Bloom
-
- call _Update() at the end of a scene; it gathers stats and re-balances the cache
- for the current vis set
- _Balance() tries to move memory from one type to another to better reflect the
- textures that are visible
-
- The MipData in the Slot is the THandle it corresponds to.
- The RefCount in the Type is the number of THandles of that type
- We gather the usage stats from the THandles build in SetupTexture() in PCache
-
- NOTE : we currently maintain separate caches for texture and lightmaps !
- This would all work better if we merged the two caches
- ** see USE_ONE_CACHE flag in THandle.cpp ; try it!
-
- The DDMemMgr is just an accountant for adds and subtracts.
- We query the free memory in THandle : D3DDrvInfo.VidMemFree
- Originally set up in Main_GetVideoMemory
- <> NOTE : this is not accurate !! The actual amount of vidmem used may not
- be the same as the width*height*bpp !!!
- this isn't terrible, because in the end, we actually judge free mem by
- trying to allocate.
-
- -----------------------------------------------------
-
- <> Misses due to max-ing the # of slots should not cause a bias adjust!
- done : just using Diff2, no longer Diff1
-
- <> when you have a huge number of textures on screen that are continuously missing,
- then we are far from optimal : eg. you want to draw A,B,C and only have room for two;
- we do :
- up&draw A,B
- kick A ; up&draw C
- kick B ; up&draw A
- kick C ; up&draw B , etc...
- eg. with a pure LRU we are always uploading, when really one of the three could stay up
- all the time. The traditional solution to this in caching is to use several "ways". That's
- a really goofy solution. One solution in rendering is to reverse the render order each
- frame : A,B,C ; C,B,A ; A,B,C ... then the cache looks like :
- up&draw A,B
- kick A ; up&draw C
- draw C,B
- kick C, up&draw A
- draw A,B
- kick A ; up&draw C
- -> I'm now doing this reversing in pcache; unfortunately, partial flushes hurt this
-
- <> There's some contention between balancing and mip biasing. When you're looking back and
- forth the balance keeps changing, so the bias will never do its work.
-
- <> Note that we only crank Mip Bias when the total texture memory overflows the total card
- space. There can be overflows that are not due to full texture overflow. Examples :
- if the memory is fragmented, and we cannot allocate the texture type we need in the
- remaining memory
-
- <> There's a sort of hysterisys that can happen with the mip bias : you overflow the card,
- so you crank up the bias. Now, with the new bias, you suddenly underflow, so you kick
- the mip bias back down. Our makes this happen once per five frames or so, instead of
- every single frame. There's no real way to avoid this, because we can't tell how much
- memory mipping-down really saves (unless we check every rendered poly)
-
- <> note : Mip Bias changes cause loads of "fresh" mip misses
- did : might be good to quantize the mip biases to some buckets at the last minute;
- 1.0 , 1.25 , 1.5 , or something
-
- <> tiny texture misses (eg. lightmaps) need to be handled more intelligently -
- eg. they shouldn't affect the mip bias, and they should not be so greedy for textures;
- ie. letting them miss is not so bad, and creating surfaces for them may be costly
- we need logic like this :
- 1. if the card is near full, just don't bother trying to make new small slots
- 2. make small slots slowly - eg. if the demand is 20 slots, make 2 per frame
- the idea is so that if you suddenly see 100 new textures, you don't make loads of slots,
- just let them miss, unless they stay on screen for a while
- (this may be automatically handled by BALANCES_PER_FRAME and OVERFLOW_MAX)
- on second thought, this may be all automagic; just need to think about it a little
-
- ********/
-
- #include <Windows.h>
- #include <Stdio.h>
- #include <Assert.h>
- #include <DDraw.h>
- #include <D3D.h>
-
- #include "D3DCache.h"
- #include "d3d_main.h" //for GetLog
- #include "d3d_thandle.h"
-
- #include "mempool.h"
-
- extern uint32 Scene_CurrentFrame;
-
- // tweakable config for the cache balancing :
- #define MAX_BALANCES_PER_FRAME (12)
- #define HISTORY_SIZE (8)
- #define BIAS_HISTORY_SIZE (10)
- #define BALANCE_FRAME_DELAY (2)
- #define CACHE_LINGER_FRAMES (8) // newly added slot won't be removed for this long
- #define OVERFLOW_MAX (8)
- #define MIPBIAS_MAX (5.0f)
-
- // Cache types are just the different types of textures
- // Textures may vary from width/height/num miplevels/etc...
- // Cache types is just a way to combine them to similar types...
- #define D3DCACHE_MAX_CACHE_TYPES (64)
- #define D3DCACHE_MAX_CACHE_SLOTS (1024) // per type!
-
- static uint32 Log2(uint32 P2);
- static int32 SnapToPower2(int32 Width);
- static int32 GetLog(int32 Width, int32 Height);
-
- //=====================================================================================
- // Log2
- // Return the log of a size
- //=====================================================================================
- static uint32 Log2(uint32 P2)
- {
- uint32 p = 0;
- int32 i = 0;
-
- for (i = P2; i > 0; i>>=1)
- p++;
-
- return (p-1);
- }
-
- //=====================================================================================
- // SnapToPower2
- // Snaps a number to a power of 2
- //=====================================================================================
- static int32 SnapToPower2(int32 Width)
- {
- if (Width <= 1) return 1;
- else if (Width <= 2) return 2;
- else if (Width <= 4) return 4;
- else if (Width <= 8) return 8;
- else if (Width <= 16) return 16;
- else if (Width <= 32) return 32;
- else if (Width <= 64) return 64;
- else if (Width <= 128) return 128;
- else if (Width <= 256) return 256;
- else if (Width <= 512) return 512;
- else if (Width <= 1024) return 1024;
- else if (Width <= 2048) return 2048;
- else
- return -1;
- }
-
- //=====================================================================================
- // Return the max log of a (power of 2) width and height
- //=====================================================================================
- static int32 GetLog(int32 Width, int32 Height)
- {
- int32 LWidth = SnapToPower2(max(Width, Height));
-
- return Log2(LWidth);
- }
-
- //========================================================================================================
- //========================================================================================================
-
- typedef struct D3DCache_Slot
- {
- jeBoolean IsActive; // indicates whether it is used & set up
-
- struct D3DCache_Slot *SelfCheck;
-
- D3DCache_Type *CacheType;
-
- LPDIRECTDRAWSURFACE7 Surface; // The DD surface for this slot
-
- uint32 LRU; // Current LRU for cache slot
-
- THandle_MipData *MipData; // whose data do I have?
- } D3DCache_Slot;
-
- typedef struct D3DCache_Type
- {
- int32 Log;
- int32 Width; // Width/Height
- int32 Height;
- int32 NumMipLevels;
- int32 Stage;
- int32 RefCount; // How many references to this cache_type
- // {} when refcount is zero, nothing is set up
- // RefCount is the number of thandles of this type
- int32 Size; // in bytes
-
- DDSURFACEDESC2 ddsd; // DD surface description
-
- D3DCache_Slot * SlotPtrs[D3DCACHE_MAX_CACHE_SLOTS]; // Cache slots for this Cache type
- int32 NumSlots; // number of slots allocated
-
- D3DCache_Type *SelfCheck;
- D3DCache *Cache;
-
- int32 Misses,FreshMisses,Uses,AddedCountdown;
- int32 OverflowMax,OverflowHistory[HISTORY_SIZE],OverflowHistoryI;
- //int32 MissesMax,FreshMissesMax,UsesMax;
- int32 SlotNeedRating;
- } D3DCache_Type;
-
- typedef struct D3DCache
- {
- struct D3DCache *SelfCheck;
-
- char Name[D3DCACHE_MAX_NAME];
-
- LPDIRECTDRAW7 lpDD; // DD object for the cache manager
-
- DDMemMgr_Partition *Partition; // just counts off a pre-queried FreeMem variable
-
- jeBoolean UseStages;
-
- D3DCache_Type CacheTypes[D3DCACHE_MAX_CACHE_TYPES]; // CacheTypes
-
- int32 SoughtMem,AvailMem,CardMem;
-
- float StoreMipBias[BIAS_HISTORY_SIZE];
- int StoreMipBiasI;
-
- MemPool *SlotPool;
-
- jeBoolean DoMipBias;
-
- int32 TotNumSlots;
-
- } D3DCache;
-
- #ifdef DO_LOG
- typedef struct D3DCacheLogType
- {
- int frames;
- double updateTime;
- int slotsCreated,slotsDestroyed;
- int maxCacheTypes;
-
- int TexMissesTot;
- int LMapMissesTot;
- int TexMissBytesTot;
- int LMapMissBytesTot;
-
- int CardMemTot,SlotMemTot,UsedMemTot;
- float MipBiasTot,MipBiasMax;
- } D3DCacheLogType;
-
- static D3DCacheLogType D3DCacheLog;
- #endif
-
-
- //========================================================================================================
- //========================================================================================================
-
- void D3DCache_InitStaticsAndGlobals(void)
- {
- }
-
- int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, jeBoolean UseStage, int32 Stage);
- jeBoolean D3DCache_FreeAllSlots(D3DCache *Cache);
- void D3DCache_Balance(D3DCache *Cache);
- jeBoolean D3DCache_TypeAddSlot(D3DCache_Type *pCacheType);
- jeBoolean D3DCache_RemoveOldestSlot(D3DCache *Cache,D3DCache_Type *NotType,jeBoolean Critical);
- void D3DCacheLog_WriteToFile(void);
-
- //========================================================================================================
- // D3DCache_Create
- //========================================================================================================
- D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW7 lpDD, DDMemMgr_Partition *Partition,jeBoolean UseStages)
- {
- D3DCache *Cache;
-
- assert(strlen(Name) < D3DCACHE_MAX_NAME);
-
- Cache = (D3DCache*)malloc(sizeof(D3DCache));
-
- if (!Cache)
- return NULL;
-
- memset(Cache, 0, sizeof(D3DCache));
-
- Cache->SlotPool = MemPool_Create(sizeof(D3DCache_Slot),1024,1024);
-
- if ( ! Cache->SlotPool )
- {
- free(Cache);
- return NULL;
- }
-
- Cache->lpDD = lpDD;
-
- Cache->Partition = Partition;
-
- Cache->UseStages = UseStages;
-
- Cache->SelfCheck = Cache;
-
- Cache->CardMem = DDMemMgr_PartitionGetTotalMem(Cache->Partition);
-
- strcpy(Cache->Name, Name);
-
- for(int i=0;i<BIAS_HISTORY_SIZE;i++)
- {
- Cache->StoreMipBias[i] = 1.0f;
- }
-
- Cache->DoMipBias = JE_TRUE;
-
- return Cache;
- }
-
- //========================================================================================================
- // D3DCache_Destroy
- //========================================================================================================
- void D3DCache_Destroy(D3DCache *Cache)
- {
- assert(Cache);
-
- D3DCache_FreeAllSlots(Cache);
-
- MemPool_Destroy(&(Cache->SlotPool));
-
- free(Cache);
-
- #ifdef DO_LOG
- D3DCacheLog_WriteToFile();
- #endif
-
- }
-
- //========================================================================================================
- // D3DCache_IsValid
- //========================================================================================================
- jeBoolean D3DCache_IsValid(D3DCache *Cache)
- {
- if (!Cache)
- return JE_FALSE;
-
- if (Cache->SelfCheck != Cache)
- return JE_FALSE;
-
- return JE_TRUE;
- }
-
- //========================================================================================================
- // D3DCache_SeriousSelfCheck
- //========================================================================================================
- void D3DCache_SeriousSelfCheck(D3DCache *Cache)
- {
- int i;
- D3DCache_Type *pCacheType;
-
- assert(D3DCache_IsValid(Cache));
-
-
- int PartTotMem = DDMemMgr_PartitionGetTotalMem(Cache->Partition);
- int PartFreeMem = DDMemMgr_PartitionGetFreeMem(Cache->Partition);
- int MemUsed = 0;
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- if ( ! pCacheType->RefCount && ! pCacheType->NumSlots ) // nothing here
- continue;
-
- assert( D3DCache_TypeIsValid(pCacheType) );
-
- //assert( pCacheType->NumSlots >= 1 ); // NumSlots can be zero now
- //assert( pCacheType->NumSlots <= pCacheType->RefCount ); // may have destroyed texes & left slots
- assert( pCacheType->Cache == Cache );
-
- MemUsed += pCacheType->NumSlots * pCacheType->Size;
-
- int k;
- int ActiveSlots = 0;
- // count the number of slots with IsActive
- for (k=0; k< D3DCACHE_MAX_CACHE_SLOTS; k++)
- {
- D3DCache_Slot *pSlot;
-
- pSlot = pCacheType->SlotPtrs[k];
-
- if ( k < pCacheType->NumSlots )
- {
- assert(pSlot);
- assert(pSlot->IsActive);
- assert( D3DCache_SlotIsValid(pSlot) );
- assert( pSlot->CacheType = pCacheType );
- ActiveSlots ++;
- }
- else
- {
- assert(pSlot == NULL);
- }
-
- }
-
- assert( pCacheType->NumSlots == ActiveSlots );
- }
-
- assert( MemUsed == (PartTotMem - PartFreeMem) );
- }
-
- //========================================================================================================
- // D3DCache_Update
- //========================================================================================================
-
- extern float PCache_MipBias;
- extern DRV_CacheInfo PCache_CacheInfo;
-
- void D3DCache_TypeUsed(D3DCache_Type *CacheType)
- {
- CacheType->Uses ++;
- }
-
- #ifdef DO_LOG
- #include "tsc.h"
- #endif
-
- void D3DCache_Update(D3DCache *Cache)
- {
- int32 i;
- D3DCache_Type *pCacheType;
- int32 SlotMemNonEssential,SlotMemEssential,SoughtMemExcess;
-
- #ifdef DO_LOG
- tsc_type tsc1,tsc2;
- #endif
-
- assert(D3DCache_IsValid(Cache));
-
- Cache->SoughtMem = 0;
- SlotMemNonEssential = SlotMemEssential = SoughtMemExcess = 0;
-
- #ifdef _DEBUG
- D3DCache_SeriousSelfCheck(Cache);
- #endif
-
- #ifdef DO_LOG
- readTSC(tsc1);
- #endif
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- pCacheType->Uses = 0;
- }
-
- THandle_GetCacheTypeUses();
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- if ( ! pCacheType->RefCount )
- {
- assert( pCacheType->Uses == 0 );
- SlotMemNonEssential += pCacheType->NumSlots * pCacheType->Size;
- continue;
- }
-
- if ( pCacheType->Uses > 0 )
- {
- Cache->SoughtMem += pCacheType->Uses * pCacheType->Size;
- SoughtMemExcess += (pCacheType->Uses - 1) * pCacheType->Size;
- }
-
- if ( pCacheType->NumSlots > 0 )
- {
- SlotMemNonEssential += (pCacheType->NumSlots - 1) * pCacheType->Size;
- SlotMemEssential += pCacheType->Size;
- }
-
- //pCacheType->UsesMax = (pCacheType->UsesMax + pCacheType->Uses)*0.5f;
- //pCacheType->MissesMax = (pCacheType->MissesMax + pCacheType->Misses)*0.5f;
- //pCacheType->FreshMissesMax = (pCacheType->FreshMissesMax + pCacheType->FreshMisses)*0.5f;
- pCacheType->OverflowMax = 0;
- pCacheType->OverflowHistory[pCacheType->OverflowHistoryI] = pCacheType->Uses - pCacheType->NumSlots;
- pCacheType->OverflowHistoryI = (pCacheType->OverflowHistoryI + 1)%HISTORY_SIZE;
- for(int j=0;j<HISTORY_SIZE;j++)
- {
- pCacheType->OverflowMax = max(pCacheType->OverflowMax,pCacheType->OverflowHistory[j]);
- }
- }
-
- // we've not got Misses,Uses, and UsesMax on all cache types
- D3DCache_Balance(Cache);
-
- PCache_CacheInfo.CacheTypes = 0;
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- if ( ! pCacheType->RefCount )
- continue;
-
- assert( pCacheType->FreshMisses <= pCacheType->Misses );
-
- PCache_CacheInfo.CacheMisses[PCache_CacheInfo.CacheTypes] = pCacheType->Misses;
- PCache_CacheInfo.CacheFreshMisses[PCache_CacheInfo.CacheTypes] = pCacheType->FreshMisses;
- PCache_CacheInfo.CacheUses[PCache_CacheInfo.CacheTypes] = pCacheType->Uses;
- PCache_CacheInfo.CacheSlots[PCache_CacheInfo.CacheTypes] = pCacheType->NumSlots;
- PCache_CacheInfo.CacheTypes++;
-
- // reset the count
- pCacheType->Misses = 0;
- pCacheType->FreshMisses = 0;
-
- if ( pCacheType->AddedCountdown == CACHE_LINGER_FRAMES ) // <> just balanced
- {
- // clear the history!
- for(int j=0;j<HISTORY_SIZE;j++)
- pCacheType->OverflowHistory[j] = 0;
- }
-
- if ( pCacheType->AddedCountdown > 0 )
- pCacheType->AddedCountdown --;
- }
-
- PCache_CacheInfo.CardMem = Cache->CardMem;
- PCache_CacheInfo.SlotMem = Cache->CardMem - DDMemMgr_PartitionGetFreeMem(Cache->Partition);
- PCache_CacheInfo.UsedMem = Cache->SoughtMem;
-
- Cache->AvailMem = SlotMemNonEssential;
-
- if ( Cache->DoMipBias )
- {
- float MipBias;
- MipBias = PCache_MipBias;
- {
- int Diff2;
- // Diff1 = SoughtMemExcess - SlotMemNonEssential - 111111;
- Diff2 = Cache->SoughtMem - Cache->CardMem;
- // Diff2 doesn't account for headers & other complications,
- // but that's probably a good thing
- if ( Diff2 > 0 )
- {
- // we overflowed the card
- MipBias += 0.33f;
- }
- else if ( Diff2 < -555555 )
- {
- // we underloaded
- /*
- if ( MipBias > 1.0f )
- {
- MipBias -= 0.1f;
- MipBias = max(MipBias,1.0f);
- }
- */
- // just snap it back to 1.0f
- MipBias = 1.0f;
- }
- }
-
- Cache->StoreMipBias[Cache->StoreMipBiasI] = MipBias;
- Cache->StoreMipBiasI = (Cache->StoreMipBiasI + 1)%BIAS_HISTORY_SIZE;
-
- #if 1 // average of some biases
- PCache_MipBias = 0.0f;
- for(int i=0;i<BIAS_HISTORY_SIZE;i++)
- {
- PCache_MipBias += Cache->StoreMipBias[i];
- }
- PCache_MipBias *= (1.0f/BIAS_HISTORY_SIZE);
- #else // max
- PCache_MipBias = 1.0f;
- for(int i=0;i<BIAS_HISTORY_SIZE;i++)
- {
- PCache_MipBias = max(PCache_MipBias,Cache->StoreMipBias[i]);
- }
- #endif
-
- #if 1 // <> quantize it to multiples of 0.25
- {
- int32 q;
- q = (int32)(PCache_MipBias * 4 + 0.5f);
- PCache_MipBias = q * 0.25f;
- }
- #endif
-
- if ( PCache_MipBias > MIPBIAS_MAX )
- PCache_MipBias = MIPBIAS_MAX;
- }
- else
- {
- PCache_MipBias = 1.0f;
- }
-
- PCache_CacheInfo.MipBias = PCache_MipBias;
-
- #ifdef DO_LOG
- readTSC(tsc2);
-
- D3DCacheLog.frames ++;
- D3DCacheLog.updateTime += diffTSC(tsc1,tsc2);
-
- D3DCacheLog.CardMemTot += Cache->CardMem;
- D3DCacheLog.SlotMemTot += PCache_CacheInfo.SlotMem;
- D3DCacheLog.UsedMemTot += Cache->SoughtMem;
-
- D3DCacheLog.MipBiasTot += PCache_MipBias;
- D3DCacheLog.MipBiasMax = max(D3DCacheLog.MipBiasMax,PCache_MipBias);
-
- D3DCacheLog.TexMissesTot += PCache_CacheInfo.TexMisses;
- D3DCacheLog.TexMissBytesTot += PCache_CacheInfo.TexMissBytes;
- D3DCacheLog.LMapMissesTot += PCache_CacheInfo.LMapMisses;
- D3DCacheLog.LMapMissBytesTot += PCache_CacheInfo.LMapMissBytes;
- #endif
- }
-
- void D3DCache_Balance(D3DCache *Cache)
- {
- int32 i,ChoseMissSizeMax,FailedSize,Creations;
- D3DCache_Type *pCacheType,*ChoseCacheType;
-
- assert(D3DCache_IsValid(Cache));
-
- /***
-
- doing only 1 per frame means we never take a huge hit,
- but it means we take a really long time to balance when a bunch of new
- low-mip stuff comes into view in the distance
-
- it seems we can do alot without taking a framerate hit ! I put
- MAX_BALANCES_PER_FRAME == 32 and it's fast!!
-
- ***/
-
- PCache_CacheInfo.Balances = PCache_CacheInfo.BalancesFailed = 0;
-
- FailedSize = 999999999;
-
- for(Creations=0;Creations < MAX_BALANCES_PER_FRAME;Creations++)
- {
- // look the highest (Size * OverflowMax)
-
- TryAgain:
-
- /***
-
- We'd like to take account of the misses too, but misses that don't result from overflow are
- very hard to account for properly. There are two types :
-
- 1. when you first walk into a room, you get misses until the new textures get on the card
-
- 2. if there are two places, each with too many textures, you'll get misses every time you
- go between them.
-
- Perhaps adjust for misses if there are no overflows ?
-
- <> use the FreshMisses !
-
- <> the FreshMisses aren't behaving quite as they should
- (aside from not working, they also seem to whack out the normal balances)
-
- ***/
-
- ChoseMissSizeMax = 0;
-
- // choose a type to try to extend
-
- int AvailSlots = D3DInfo.MaxSurfaceCount - Cache->TotNumSlots + 1;
-
- AvailSlots = min(AvailSlots,OVERFLOW_MAX);
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- int32 MissSizeMax;
- int32 overflow;
-
- pCacheType->SlotNeedRating = 0;
-
- if ( ! pCacheType->RefCount )
- continue;
- if ( pCacheType->NumSlots == D3DCACHE_MAX_CACHE_SLOTS )
- continue; // can't add any here
-
- // overflow is a much higher priority than fresh misses
- /*
- if ( pCacheType->OverflowMax > 0.1f )
- MissSizeMax = (int32)(pCacheType->Size * pCacheType->OverflowMax * 256.0f);
- else if ( pCacheType->FreshMissesMax > 0.1f )
- MissSizeMax = (int32)(pCacheType->Size * pCacheType->FreshMissesMax);
- */
-
- overflow = pCacheType->OverflowMax;
- overflow = min(overflow,AvailSlots);
-
- MissSizeMax = (int32)(pCacheType->Size * overflow);
-
- pCacheType->SlotNeedRating = MissSizeMax;
-
- if ( pCacheType->Size >= FailedSize )
- continue; // rate me but don't add to me (already tried)
-
- if ( MissSizeMax > ChoseMissSizeMax )
- {
- ChoseMissSizeMax = MissSizeMax;
- ChoseCacheType = pCacheType;
- }
- }
-
- if ( ! ChoseMissSizeMax )
- return; // found nothing to do
-
- // found something that missed
-
- // try to add a slot to this type
-
- while ( ! D3DCache_TypeAddSlot(ChoseCacheType) )
- {
- if ( ! D3DCache_RemoveOldestSlot(Cache,ChoseCacheType,JE_FALSE) )
- {
- PCache_CacheInfo.BalancesFailed ++;
-
- // we might have been unable to find space for a 256x256 ,
- // but there might be a smaller type that also missed !
- // go back and restart with a smaller max size
- FailedSize = ChoseCacheType->Size;
-
- goto TryAgain;
- }
- }
-
- PCache_CacheInfo.Balances ++;
-
- // we did it!
- // clear the history of failure
- ChoseCacheType->AddedCountdown = CACHE_LINGER_FRAMES; // can't remove from here for this many frames
- ChoseCacheType->OverflowMax = max(ChoseCacheType->OverflowMax - BALANCE_FRAME_DELAY,0);
- // <> if we subtract one here, then we could build slots for all the overflows in one frame
- // if we subtract N, we spread the rebuild over N frames
-
- // loop around and do another
- }
- }
-
- //========================================================================================================
- //========================================================================================================
- jeBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache) // called by THandle_EvictAll, from Main_RestoreAll
- {
- int32 i;
- D3DCache_Type *pCacheType;
-
- assert(D3DCache_IsValid(Cache));
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- D3DCache_Slot *pSlot;
- int32 s;
-
- assert(D3DCache_TypeIsValid(pCacheType));
-
- // just forces a re-upload, doesn't free any memory
-
- for (s=0; s< pCacheType->NumSlots; s++)
- {
- pSlot = pCacheType->SlotPtrs[s];
- pSlot->MipData = NULL;
- }
- }
-
- return JE_TRUE;
- }
-
- //========================================================================================================
- //========================================================================================================
- static D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
- {
- int32 i;
- D3DCache_Type *pCacheType;
-
- assert(D3DCache_IsValid(Cache));
-
- // {} never called externally
-
- pCacheType = Cache->CacheTypes;
-
- for (i=0; i<D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- if (pCacheType->RefCount == 0 && pCacheType->NumSlots == 0) // this slot contains no type
- continue;
-
- assert(D3DCache_TypeIsValid(pCacheType));
-
- if (pCacheType->Width != Width)
- continue;
- if (pCacheType->Height != Height)
- continue;
-
- if (pCacheType->NumMipLevels != NumMipLevels)
- continue;
-
- if (pCacheType->Stage != Stage)
- continue;
-
- if (memcmp(&pCacheType->ddsd, ddsd, sizeof(DDSURFACEDESC2)))
- continue;
-
- return pCacheType; // Found a match
- }
-
- return NULL; // Cache Type not found!!!
- }
-
- //========================================================================================================
- //========================================================================================================
- static D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
- {
- int32 i;
- D3DCache_Type *pCacheType;
-
- assert(D3DCache_IsValid(Cache));
-
- // {} never called externally
-
- pCacheType = Cache->CacheTypes;
-
- for (i=0; i<D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- if ( pCacheType->RefCount == 0 && pCacheType->NumSlots == 0 ) // Nobody is using this slot yet
- break; // found a vacancy
- }
-
- #ifdef DO_LOG
- D3DCacheLog.maxCacheTypes = max(D3DCacheLog.maxCacheTypes,i);
- #endif
-
- if (i == D3DCACHE_MAX_CACHE_TYPES) // No types left
- return NULL;
-
- memset(pCacheType,0,sizeof(*pCacheType)); // {} redundant ?
-
- assert( pCacheType->RefCount == 0 && pCacheType->NumSlots == 0 );
-
- pCacheType->Width = Width;
- pCacheType->Height = Height;
- pCacheType->NumMipLevels = NumMipLevels;
- pCacheType->Stage = Stage;
-
- pCacheType->ddsd = *ddsd;
-
- pCacheType->SelfCheck = pCacheType;
- pCacheType->Cache = Cache;
-
- pCacheType->Log = GetLog(Width, Height);
-
- // {} this Size assumes W & H are pow2's ! (and square?)
- pCacheType->Size = Width*Height*(pCacheType->ddsd.ddpfPixelFormat.dwRGBBitCount>>3);
-
- // <> doesn't account for NumMipLevels !? (Neither did the old stuff)
-
- // Found one
- pCacheType->RefCount++;
-
- return pCacheType;
- }
-
- //========================================================================================================
- //========================================================================================================
- D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
- {
- D3DCache_Type *CacheType;
-
- assert(D3DCache_IsValid(Cache));
-
- // {} called whenever a new THandle is made
-
- CacheType = D3DCache_FindCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd);
-
- if (CacheType)
- {
- // Increase the ref count on this slot, and return it
- CacheType->RefCount++;
- return CacheType;
- }
-
- // Could not find one allready in the list, so add a new one...
- return D3DCache_InsertCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd);
- }
-
- //========================================================================================================
- // D3DCache_FreeSlot
- //========================================================================================================
- void D3DCache_FreeSlot(D3DCache_Slot *pSlot)
- {
- D3DCache * Cache;
-
- assert( pSlot );
-
- Cache = pSlot->CacheType->Cache;
-
- if ( pSlot->IsActive )
- {
- assert(D3DCache_SlotIsValid(pSlot));
- assert(pSlot->Surface);
-
- if (pSlot->Surface)
- pSlot->Surface->Release();
-
- if ( pSlot->MipData && pSlot->MipData->Slot == pSlot )
- {
- pSlot->MipData->KickedFrame = Scene_CurrentFrame;
- pSlot->MipData->Slot = NULL;
- }
-
- assert( pSlot->CacheType->NumSlots >= 1 );
- pSlot->CacheType->NumSlots --;
-
- assert( Cache->TotNumSlots >= 1 );
- Cache->TotNumSlots --;
-
- DDMemMgr_PartitionFreeMem(pSlot->CacheType->Cache->Partition, pSlot->CacheType->Size);
-
- #ifdef DO_LOG
- D3DCacheLog.slotsDestroyed ++;
- #endif
- }
-
- memset(pSlot,0,sizeof(*pSlot));
-
- pSlot->SelfCheck = pSlot;
-
- MemPool_FreeHunk(Cache->SlotPool,pSlot);
- }
-
- //========================================================================================================
- // D3DCache_TypeDestroy
- //========================================================================================================
- void D3DCache_TypeDestroy(D3DCache_Type *CacheType)
- {
- assert(CacheType->RefCount > 0);
- assert(D3DCache_TypeIsValid(CacheType));
-
- CacheType->RefCount--;
-
- if (CacheType->RefCount > 0)
- return;
-
- // <> there should be no textures pointing at this Type anymore
-
- #if 0 // {
-
- // don't free now, just let the balance free them later
- //
- // henever you rebuild the bsp, it destroys all lightmaps then remakes them
- // we'd like to not destroy the type, just let it hang around,
-
- int32 k,ns;
-
- OutputDebugString("D3DCache_TypeDestroy : no textures of this type left, freeing slots\n");
-
- ns = CacheType->NumSlots;
- // Go through each slot, and free all the surfaces on them
- for (k=0; k< ns; k++)
- {
- D3DCache_FreeSlot(CacheType->SlotPtrs[k]);
- CacheType->SlotPtrs[k] = NULL;
- }
-
- CacheType->NumSlots = 0;
-
- #endif //}
- }
-
- //========================================================================================================
- // D3DCache_TypeIsValid
- //========================================================================================================
- jeBoolean D3DCache_TypeIsValid(D3DCache_Type *Type)
- {
- if (!Type)
- return JE_FALSE;
-
- // <> cheat!
- if ( Type->SelfCheck == NULL )
- Type->SelfCheck = Type;
-
- if (Type->SelfCheck != Type)
- return JE_FALSE;
-
- if (!D3DCache_IsValid(Type->Cache))
- return JE_FALSE;
-
- return JE_TRUE;
- }
- //========================================================================================================
- // D3DCache_RemoveOldestSlot
- //========================================================================================================
- jeBoolean D3DCache_RemoveOldestSlot(D3DCache *Cache,D3DCache_Type *NotType,jeBoolean Critical)
- {
- int32 i,OldestIndex;
- D3DCache_Type *pCacheType,*OldestType;
- D3DCache_Slot *OldestSlot;
-
- assert(D3DCache_IsValid(Cache));
-
- OldestSlot = NULL;
-
- // try to find a nice one to remove
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- D3DCache_Slot *pSlot;
- int32 k;
-
- if ( pCacheType == NotType )
- continue;
-
- if ( pCacheType->NumSlots == 0 ) // nothing to do
- continue;
-
- if ( pCacheType->RefCount >= pCacheType->NumSlots )
- {
- if ( pCacheType->NumSlots == 1 ) // can't free the last slot of a type
- continue;
-
- if ( pCacheType->SlotNeedRating >= NotType->SlotNeedRating )
- continue; // I need it more that you do!
-
- if ( pCacheType->Uses >= pCacheType->NumSlots )
- continue; // don't free if all slots are used!!
-
- if ( pCacheType->OverflowMax > 0.1f )
- continue; // don't free it if recently missed
-
- if ( pCacheType->AddedCountdown > 0 )
- continue; // just added one here recently, don't remove it !
- }
- else
- {
- // RefCount < NumSlots ; take me!
- }
-
- // find the oldest slot
- for (k=0; k< pCacheType->NumSlots; k++)
- {
- pSlot = pCacheType->SlotPtrs[k];
-
- assert( pSlot->IsActive );
-
- if ( ! OldestSlot || pSlot->LRU < OldestSlot->LRU )
- {
- OldestSlot = pSlot;
- OldestType = pCacheType;
- OldestIndex = k;
- }
- }
- }
-
- if ( ! OldestSlot )
- {
- // now look for one that's not so readily removed
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- D3DCache_Slot *pSlot;
- int32 k;
-
- if ( pCacheType == NotType )
- continue;
-
- if ( pCacheType->NumSlots <= 1 ) // can't free the last slot of a type
- continue;
-
- if ( pCacheType->SlotNeedRating >= NotType->SlotNeedRating )
- continue; // I need it more that you do!
-
- if ( pCacheType->AddedCountdown > 0 )
- continue; // just added one here recently, don't remove it !
-
- // find the oldest slot
- for (k=0; k< pCacheType->NumSlots; k++)
- {
- pSlot = pCacheType->SlotPtrs[k];
-
- assert( pSlot->IsActive );
-
- if ( ! OldestSlot || pSlot->LRU < OldestSlot->LRU )
- {
- OldestSlot = pSlot;
- OldestType = pCacheType;
- OldestIndex = k;
- }
- }
- }
- }
-
- if ( Critical && ! OldestSlot )
- {
- // now remove one at all cost!
-
- if ( ! OldestSlot )
- {
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- D3DCache_Slot *pSlot;
- int32 k;
-
- if ( pCacheType == NotType )
- continue;
-
- if ( pCacheType->NumSlots == 0 ) // nothing to do
- continue;
-
- // find the oldest slot
- for (k=0; k< pCacheType->NumSlots; k++)
- {
- pSlot = pCacheType->SlotPtrs[k];
-
- assert( pSlot->IsActive );
-
- if ( ! OldestSlot || pSlot->LRU < OldestSlot->LRU )
- {
- OldestSlot = pSlot;
- OldestType = pCacheType;
- OldestIndex = k;
- }
- }
- }
- }
- }
-
- if ( ! OldestSlot )
- return JE_FALSE; // nothing to free!
-
- if ( ! Critical )
- {
- // compare OldestType and NotType
- if ( OldestType->Uses >= OldestType->NumSlots ) // seriously try to avoid destroying this
- {
- // if both types are overflowing, don't destroy a larger one to make a smaller
- if ( OldestType->Size >= NotType->Size )
- return JE_FALSE;
- }
- }
-
- D3DCache_FreeSlot(OldestSlot);
-
- if ( OldestType->NumSlots > 0 )
- {
- D3DCache_Slot *pSlot;
-
- // slide the list to keep it linear
-
- pSlot = OldestType->SlotPtrs[OldestType->NumSlots];
- assert( pSlot );
-
- OldestType->SlotPtrs[OldestIndex] = pSlot;
- OldestType->SlotPtrs[OldestType->NumSlots] = NULL;
- }
-
- // OldestType->RemovedCountdown = 7; // <> don't add here again right away ?
- // <> not good : the _Balance may look like this :
- // trying to add type 1
- // remove type 2, remove type 3
- // add type 1 still fails!
- // so now re-add a type 2 & type 3
- // hence we MUST be able to add right after a remove
-
- return JE_TRUE;
- }
-
-
- //========================================================================================================
- // D3DCache_FreeAllSlots
- //========================================================================================================
- jeBoolean D3DCache_FreeAllSlots(D3DCache *Cache) // never called externally
- {
- int32 i;
- D3DCache_Type *pCacheType;
-
- assert(D3DCache_IsValid(Cache));
-
- #ifdef _DEBUG
- D3DMain_Log("D3DCache_FreeAllSlots starting\n");
- #endif
-
- OutputDebugString("D3DCache_FreeAllSlots\n");
-
- for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
- {
- D3DCache_Slot *pSlot;
- int32 k,ns;
-
- if ( pCacheType->RefCount == 0 && pCacheType->NumSlots == 0 )
- continue; // nothing here!
-
- assert(D3DCache_TypeIsValid(pCacheType));
-
- // Go through each slot, and free all the surfaces on them
- ns = pCacheType->NumSlots;
- for (k=0; k< ns; k++)
- {
- pSlot = pCacheType->SlotPtrs[k];
- assert(pSlot->IsActive);
- D3DCache_FreeSlot(pSlot);
- }
-
- assert( pCacheType->NumSlots == 0 );
- }
-
- DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager
-
- Cache->AvailMem = Cache->CardMem;
- Cache->SoughtMem = 0;
-
- #ifdef _DEBUG
- D3DMain_Log("D3DCache_FreeAllSlots done\n");
- #endif
-
- return JE_TRUE;
- }
-
- //========================================================================================================
- // D3DCache_WriteToFile
- //========================================================================================================
- void D3DCacheLog_WriteToFile(void)
- {
-
- #ifdef DO_LOG
- SYSTEMTIME Time;
- FILE *f;
-
- #pragma message("D3DCache : Logging")
-
- f = fopen("D3DCache.log", "a+t");
-
- if (!f)
- return;
-
- GetSystemTime(&Time);
-
- fprintf(f, "=======================================================\n");
- fprintf(f, "Date: %i/%i/%i, Time: %i:%02i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute);
-
- fprintf(f, "Compiled : %s,%s\n",__DATE__,__TIME__);
-
- fprintf(f, "---------- total:\n");
-
- fprintf(f, "Frames = %d; Cache Types = %d; slots created/destroyed = %d/%d\n",
- D3DCacheLog.frames,D3DCacheLog.maxCacheTypes,D3DCacheLog.slotsCreated,D3DCacheLog.slotsDestroyed);
-
- fprintf(f, "tex misses = %d/%d , lmap misses = %d/%d\n",
- D3DCacheLog.TexMissesTot,D3DCacheLog.TexMissBytesTot,
- D3DCacheLog.LMapMissesTot,D3DCacheLog.LMapMissBytesTot);
-
- fprintf(f, "---------- per frame:\n");
-
- fprintf(f, "update = %f secs, mip bias = %f avg/%f max\n",
- D3DCacheLog.updateTime/(double)D3DCacheLog.frames,
- D3DCacheLog.MipBiasTot/(double)D3DCacheLog.frames,
- D3DCacheLog.MipBiasMax);
-
- fprintf(f, "mem = %f card/%f slots/%f sought\n",
- D3DCacheLog.CardMemTot/(double)D3DCacheLog.frames,
- D3DCacheLog.SlotMemTot/(double)D3DCacheLog.frames,
- D3DCacheLog.UsedMemTot/(double)D3DCacheLog.frames);
-
- fclose(f);
- #endif
-
- }
-
- //========================================================================================================
- // D3DCache_TypeAddSlot
- //========================================================================================================
- jeBoolean D3DCache_TypeAddSlot(D3DCache_Type *pCacheType)
- {
- D3DCache_Slot *pSlot;
- uint32 Result;
-
- // allocates a new slot for this type
- // returns true if actually did an alloc
- assert( D3DCache_TypeIsValid(pCacheType) );
-
- if (pCacheType->RefCount <= 0) // nothing here
- {
- // <> !! why are you calling TypeAddSlot !?
- return JE_FALSE;
- }
-
- // NumAvail > NumTextures
- if (pCacheType->NumSlots >= pCacheType->RefCount)
- return JE_FALSE; // This is all we need for this slot...
-
- if ( pCacheType->NumSlots == D3DCACHE_MAX_CACHE_SLOTS )
- return JE_FALSE;
-
- assert( pCacheType->Cache->TotNumSlots <= D3DInfo.MaxSurfaceCount );
- if ( pCacheType->Cache->TotNumSlots == D3DInfo.MaxSurfaceCount )
- {
- // sorry, no more slots allowed
- return JE_FALSE;
- }
-
- if (!DDMemMgr_PartitionAllocMem(pCacheType->Cache->Partition, pCacheType->Size))
- {
- return JE_FALSE; // No more memory in the partition, stop now...
- // <> CB : there might actually still be memory on the card !
- }
-
- // find a free slot
- pSlot = (D3DCache_Slot *) MemPool_GetHunk(pCacheType->Cache->SlotPool);
-
- pSlot->SelfCheck = pSlot;
- pSlot->CacheType = pCacheType;
- pSlot->MipData = NULL;
- pSlot->LRU = Scene_CurrentFrame - 1; //<>
-
- // Allocate surfaces now
- Result = D3DCache_SetupSlot(pCacheType->Cache, pSlot, pCacheType->Width, pCacheType->Height, &pCacheType->ddsd, pCacheType->Cache->UseStages, pCacheType->Stage);
-
- if ( Result <= 0)
- {
- // Out of ram, cancel operation, and stop allocating
- // DON'T memset it to zero, cuz someone else might have a ref to this slot!
- pSlot->Surface = NULL;
- pSlot->IsActive = JE_FALSE;
-
- assert(Result == 0); // if not == 0, it's worse than out-of-memory !!
-
- DDMemMgr_PartitionFreeMem(pCacheType->Cache->Partition, pCacheType->Size);
-
- MemPool_FreeHunk(pCacheType->Cache->SlotPool, pSlot);
-
- return JE_FALSE;
- }
-
- pSlot->IsActive = JE_TRUE;
-
- assert( D3DCache_SlotIsValid(pSlot) );
-
- assert( pCacheType->SlotPtrs[pCacheType->NumSlots] == NULL );
-
- pCacheType->SlotPtrs[pCacheType->NumSlots] = pSlot;
-
- // The slot was allocated, so increase the number of slots now
- pCacheType->NumSlots++;
- pCacheType->Cache->TotNumSlots ++;
-
- #ifdef DO_LOG
- D3DCacheLog.slotsCreated ++;
- #endif
-
- return JE_TRUE;
- }
-
- //========================================================================================================
- // D3DCache_CheckSlots
- //========================================================================================================
- jeBoolean D3DCache_CheckSlots(D3DCache *Cache)
- {
-
- // do nothing
-
- return JE_TRUE;
- }
-
- //========================================================================================================
- // D3DCache_SlotIsValid
- //========================================================================================================
- jeBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot)
- {
- if (!Slot)
- return JE_FALSE;
-
- if (Slot->SelfCheck != Slot)
- return JE_FALSE;
-
- return JE_TRUE;
- }
-
- //=====================================================================================
- // D3DCache_SetupSlot
- //
- // Returns -1 on failure
- // Returns 0 on out of memory
- // Returns 1 on success
- //=====================================================================================
- int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, jeBoolean UseStage, int32 Stage)
- {
- LPDIRECTDRAWSURFACE7 Surface;
- DDSURFACEDESC2 ddsd;
- HRESULT Hr;
-
- assert(D3DCache_IsValid(Cache));
- assert(D3DCache_SlotIsValid(Slot));
-
- memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2));
-
- ddsd.dwSize = sizeof(DDSURFACEDESC2);
- ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
-
- if (UseStage)
- ddsd.dwFlags |= DDSD_TEXTURESTAGE;
-
- ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
- ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC;
- ddsd.ddsCaps.dwCaps3 = 0;
- ddsd.ddsCaps.dwCaps4 = 0;
- ddsd.dwHeight = Width;
- ddsd.dwWidth = Height;
-
- ddsd.dwTextureStage = Stage;
-
- Hr = Cache->lpDD->CreateSurface(&ddsd, &Surface, NULL);
-
- if(Hr != DD_OK)
- {
- if (Hr == DDERR_OUTOFVIDEOMEMORY)
- {
- return 0;
- }
-
- return -1;
- }
-
- Slot->Surface = Surface;
-
- // Set the color key
- #if 0
- {
- DDCOLORKEY CKey;
-
- // Create the color key for this surface
- CKey.dwColorSpaceLowValue = 1;
- CKey.dwColorSpaceHighValue = 1;
-
- if (Slot->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK)
- {
- Slot->Surface->Release();
- Slot->Surface = NULL;
- return -1;
- }
- }
- #endif
-
- return 1; // All good dude
- }
-
-
- //========================================================================================================
- // D3DCache_TypeFindSlot
- //========================================================================================================
- void D3DCache_TypeMissed(D3DCache_Type *CacheType,int KickFrame)
- {
- // TypeFindSlot is called whenever you get a cache miss
- // sort of a hack
- CacheType->Misses ++;
-
- // <> use the stage to tell whether it's a Tex or LMap
- // kind of a hack;
- // with the layer system there will be no difference between texes & lmaps
- if ( CacheType->Stage == 0 )
- {
- PCache_CacheInfo.TexMisses++;
- PCache_CacheInfo.TexMissBytes += CacheType->Size;
- }
- else
- {
- PCache_CacheInfo.LMapMisses++;
- PCache_CacheInfo.LMapMissBytes += CacheType->Size;
- }
-
- assert((int)Scene_CurrentFrame >= KickFrame);
-
- if ( Scene_CurrentFrame > 30 && (Scene_CurrentFrame - KickFrame) < 10 )
- {
- CacheType->FreshMisses ++;
-
- PCache_CacheInfo.TexMissesFresh ++;
- }
- }
-
- D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType)
- {
- D3DCache_Slot *pBestSlot, *pSlot;
- int32 i;
-
- assert(D3DCache_TypeIsValid(CacheType));
-
- if ( CacheType->NumSlots == 0 )
- {
- // no slots ! must make one
-
- while ( ! D3DCache_TypeAddSlot(CacheType) )
- {
- if ( ! D3DCache_RemoveOldestSlot(CacheType->Cache,CacheType,JE_TRUE) )
- {
- return NULL;
- }
- }
- }
-
- assert( CacheType->NumSlots > 0 );
-
- // find the oldest active slot
-
- pBestSlot = NULL;
-
- for (i=0; i<CacheType->NumSlots; i++)
- {
- pSlot = CacheType->SlotPtrs[i];
-
- assert(pSlot);
- assert(pSlot->IsActive);
- assert(D3DCache_SlotIsValid(pSlot));
-
- if ( ! pBestSlot || pSlot->LRU < pBestSlot->LRU)
- {
- pBestSlot = pSlot;
- }
- }
-
- assert(pBestSlot);
-
- // possibly kick the texture that's in there now
-
- if ( pBestSlot->MipData && pBestSlot->MipData->Slot == pBestSlot )
- {
- pBestSlot->MipData->KickedFrame = Scene_CurrentFrame;
- pBestSlot->MipData->Slot = NULL;
- }
-
- pBestSlot->LRU = Scene_CurrentFrame - 1; // so it doesn't get kicked right away
- pBestSlot->MipData = NULL;
-
- assert(D3DCache_SlotIsValid(pBestSlot));
-
- return pBestSlot;
- }
-
- //========================================================================================================
- // D3DCache_SlotSetMipData
- //========================================================================================================
- void D3DCache_SlotSetMipData(D3DCache_Slot *Slot, THandle_MipData *MipData)
- {
- assert(D3DCache_SlotIsValid(Slot));
-
- if ( MipData )
- MipData->KickedFrame = 0; // <> eg. hasn't been kicked
- Slot->MipData = MipData;
- }
-
- //========================================================================================================
- // D3DCache_SlotGetMipData
- //========================================================================================================
- THandle_MipData *D3DCache_SlotGetMipData(D3DCache_Slot *Slot)
- {
- assert(D3DCache_SlotIsValid(Slot));
-
- if ( ! Slot->IsActive )
- return NULL;
-
- return Slot->MipData;
- }
-
- //========================================================================================================
- // D3DCache_SlotSetLRU
- //========================================================================================================
- void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU)
- {
- assert(D3DCache_SlotIsValid(Slot));
-
- Slot->LRU = LRU;
- }
-
- //========================================================================================================
- // D3DCache_SlotGetLRU
- //========================================================================================================
- uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot)
- {
- assert(D3DCache_SlotIsValid(Slot));
-
- return Slot->LRU;
- }
-
- //========================================================================================================
- // D3DCache_SlotGetSurface
- //========================================================================================================
- LPDIRECTDRAWSURFACE7 D3DCache_SlotGetSurface(D3DCache_Slot *Slot)
- {
- assert(D3DCache_SlotIsValid(Slot));
-
- assert( Slot->IsActive );
-
- return Slot->Surface;
- }