00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <Windows.h>
00023 #include <Stdio.h>
00024 #include <DDraw.h>
00025 #include <D3D.h>
00026
00027 #include "D3DCache.h"
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #define D3DCACHE_MAX_CACHE_TYPES 128
00040
00041
00042
00043 typedef struct D3DCache_Type
00044 {
00045 int32 Log;
00046 int32 Width;
00047 int32 Height;
00048 int32 NumMipLevels;
00049 int32 Stage;
00050 int32 RefCount;
00051
00052 DDSURFACEDESC2 ddsd;
00053
00054 D3DCache_Slot *Slots;
00055 int32 NumUsedSlots;
00056
00057 D3DCache_Type *SelfCheck;
00058 D3DCache *Cache;
00059 } D3DCache_Type;
00060
00061 typedef struct D3DCache
00062 {
00063 struct D3DCache *SelfCheck;
00064
00065 char Name[D3DCACHE_MAX_NAME];
00066
00067 LPDIRECTDRAW4 lpDD;
00068
00069 DDMemMgr_Partition *Partition;
00070
00071 geBoolean UseStages;
00072
00073 D3DCache_Type CacheTypes[D3DCACHE_MAX_CACHE_TYPES];
00074 } D3DCache;
00075
00076 typedef struct D3DCache_Slot
00077 {
00078 struct D3DCache_Slot *SelfCheck;
00079
00080 D3DCache_Type *CacheType;
00081
00082 LPDIRECTDRAWSURFACE4 Surface;
00083 LPDIRECT3DTEXTURE2 Texture;
00084
00085 uint32 LRU;
00086
00087 void *UserData;
00088
00089 } D3DCache_Slot;
00090
00091
00092
00093
00094
00095
00096
00097 D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages)
00098 {
00099 D3DCache *Cache;
00100
00101 Cache = (D3DCache*)malloc(sizeof(D3DCache));
00102
00103 if (!Cache)
00104 return NULL;
00105
00106 memset(Cache, 0, sizeof(D3DCache));
00107
00108 Cache->lpDD = lpDD;
00109
00110 Cache->Partition = Partition;
00111
00112 Cache->UseStages = UseStages;
00113
00114 Cache->SelfCheck = Cache;
00115
00116 strcpy(Cache->Name, Name);
00117
00118 return Cache;
00119 }
00120
00121
00122
00123
00124 void D3DCache_Destroy(D3DCache *Cache)
00125 {
00126 D3DCache_FreeAllSlots(Cache);
00127
00128 free(Cache);
00129 }
00130
00131
00132
00133
00134 geBoolean D3DCache_IsValid(D3DCache *Cache)
00135 {
00136 if (!Cache)
00137 return GE_FALSE;
00138
00139 if (Cache->SelfCheck != Cache)
00140 return GE_FALSE;
00141
00142 return GE_TRUE;
00143 }
00144
00145
00146
00147 geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache)
00148 {
00149 int32 i;
00150 D3DCache_Type *pCacheType;
00151
00152
00153 for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00154 {
00155 D3DCache_Slot *pSlot;
00156 int32 s;
00157
00158 if (!pCacheType->RefCount)
00159 continue;
00160
00161 for (pSlot = pCacheType->Slots, s=0; s<pCacheType->NumUsedSlots; s++, pSlot++)
00162 {
00163 D3DCache_SlotSetUserData(pSlot, NULL);
00164 }
00165 }
00166
00167 return GE_TRUE;
00168 }
00169
00170
00171
00172 D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
00173 {
00174 int32 i;
00175 D3DCache_Type *pCacheType;
00176
00177
00178 pCacheType = Cache->CacheTypes;
00179
00180 for (i=0; i<D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00181 {
00182 if (pCacheType->RefCount == 0)
00183 continue;
00184
00185 if (pCacheType->Width != Width)
00186 continue;
00187 if (pCacheType->Height != Height)
00188 continue;
00189
00190 if (pCacheType->NumMipLevels != NumMipLevels)
00191 continue;
00192
00193 if (pCacheType->Stage != Stage)
00194 continue;
00195
00196 if (memcmp(&pCacheType->ddsd, ddsd, sizeof(DDSURFACEDESC2)))
00197 continue;
00198
00199 return pCacheType;
00200 }
00201
00202 return NULL;
00203 }
00204
00205
00206
00207 D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
00208 {
00209 int32 i;
00210 D3DCache_Type *pCacheType;
00211
00212
00213 pCacheType = Cache->CacheTypes;
00214
00215 for (i=0; i<D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00216 {
00217 if (pCacheType->RefCount == 0)
00218 break;
00219 }
00220
00221 if (i == D3DCACHE_MAX_CACHE_TYPES)
00222 return NULL;
00223
00224 pCacheType->Width = Width;
00225 pCacheType->Height = Height;
00226 pCacheType->NumMipLevels = NumMipLevels;
00227 pCacheType->Stage = Stage;
00228 pCacheType->ddsd = *ddsd;
00229
00230 pCacheType->SelfCheck = pCacheType;
00231 pCacheType->Cache = Cache;
00232
00233 pCacheType->Log = GetLog(Width, Height);
00234
00235
00236 pCacheType->RefCount++;
00237
00238 return pCacheType;
00239 }
00240
00241
00242
00243 D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd)
00244 {
00245 D3DCache_Type *CacheType;
00246
00247
00248 CacheType = D3DCache_FindCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd);
00249
00250 if (CacheType)
00251 {
00252 CacheType->RefCount++;
00253 return CacheType;
00254 }
00255
00256
00257 return D3DCache_InsertCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd);
00258 }
00259
00260
00261
00262
00263 void D3DCache_TypeDestroy(D3DCache_Type *CacheType)
00264 {
00265 CacheType->RefCount--;
00266
00267 if (CacheType->RefCount == 0)
00268 {
00269 if (CacheType->Slots)
00270 {
00271 D3DCache_Slot *pSlot;
00272 int32 k;
00273
00274
00275 for (pSlot = CacheType->Slots, k=0; k< CacheType->NumUsedSlots; k++, pSlot++)
00276 {
00277 if (pSlot->Texture)
00278 pSlot->Texture->Release();
00279 if (pSlot->Surface)
00280 pSlot->Surface->Release();
00281 }
00282
00283 free(CacheType->Slots);
00284 CacheType->Slots = NULL;
00285 CacheType->NumUsedSlots = 0;
00286 }
00287 }
00288 }
00289
00290
00291
00292
00293 geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type)
00294 {
00295 if (!Type)
00296 return GE_FALSE;
00297
00298 if (Type->SelfCheck != Type)
00299 return GE_FALSE;
00300
00301 if (!D3DCache_IsValid(Type->Cache))
00302 return GE_FALSE;
00303
00304 return GE_TRUE;
00305 }
00306
00307
00308
00309
00310 geBoolean D3DCache_FreeAllSlots(D3DCache *Cache)
00311 {
00312 int32 i;
00313 D3DCache_Type *pCacheType;
00314
00315
00316 pCacheType = Cache->CacheTypes;
00317
00318 for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00319 {
00320 D3DCache_Slot *pSlot;
00321 int32 k;
00322
00323 if (pCacheType->RefCount == 0)
00324 continue;
00325
00326
00327 for (pSlot = pCacheType->Slots, k=0; k< pCacheType->NumUsedSlots; k++, pSlot++)
00328 {
00329 if (pSlot->Texture)
00330 pSlot->Texture->Release();
00331 if (pSlot->Surface)
00332 pSlot->Surface->Release();
00333 }
00334
00335 if (pCacheType->Slots)
00336 free(pCacheType->Slots);
00337
00338 pCacheType->Slots = NULL;
00339 pCacheType->NumUsedSlots = 0;
00340 }
00341
00342 DDMemMgr_PartitionReset(Cache->Partition);
00343
00344 return GE_TRUE;
00345 }
00346
00347
00348
00349
00350 geBoolean D3DCache_WriteToFile(D3DCache *Cache, const char *FileName, geBoolean Append)
00351 {
00352 int32 i;
00353 D3DCache_Type *pCacheType;
00354 int32 TotalRef, TotalUsed;
00355 SYSTEMTIME Time;
00356 FILE *f;
00357
00358 if (Append)
00359 f = fopen(FileName, "a+t");
00360 else
00361 f = fopen(FileName, "w");
00362
00363 if (!f)
00364 return GE_FALSE;
00365
00366 GetSystemTime(&Time);
00367
00368 fprintf(f, "=======================================================\n");
00369 fprintf(f, "Date: %i/%i/%i, Time: %i:%i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute);
00370 fprintf(f, "Cache Name: %s\n", Cache->Name);
00371 fprintf(f, "Total Mem: %5i\n", DDMemMgr_PartitionGetTotalMem(Cache->Partition));
00372 fprintf(f, "Free Mem: %5i\n", DDMemMgr_PartitionGetFreeMem(Cache->Partition));
00373 fprintf(f, " --- Slots ---\n");
00374
00375 TotalRef = TotalUsed = 0;
00376
00377 pCacheType = Cache->CacheTypes;
00378
00379 for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00380 {
00381 if (!pCacheType->RefCount)
00382 continue;
00383
00384 fprintf(f, "Width: %3i, Height %3i, Mips: %2i, Stage: %2i, Ref: %4i, Used: %4i\n",
00385 pCacheType->Width, pCacheType->Height, pCacheType->NumMipLevels, pCacheType->Stage, pCacheType->RefCount, pCacheType->NumUsedSlots);
00386
00387 TotalRef += pCacheType->RefCount;
00388 TotalUsed += pCacheType->NumUsedSlots;
00389 }
00390
00391 fprintf(f, "Total Ref: %4i, Total Used: %4i\n", TotalRef, TotalUsed);
00392
00393 fclose(f);
00394
00395 return GE_TRUE;
00396 }
00397
00398 static geBoolean AppendHack = GE_FALSE;
00399
00400
00401 void D3DMain_Log(LPSTR Str, ... );
00402
00403
00404
00405 geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition)
00406 {
00407 D3DCache_Type *pCacheType;
00408 int32 i, Total, NumPasses;
00409 D3DCache_FreeAllSlots(Cache);
00410 DDMemMgr_PartitionReset(Cache->Partition);
00411 Total = 0;
00412 NumPasses = 0;
00413
00414 while(1)
00415 {
00416 D3DCache_Slot *LastSlot;
00417
00418 LastSlot = NULL;
00419
00420 pCacheType = Cache->CacheTypes;
00421
00422 for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00423 {
00424 D3DCache_Slot *pSlot;
00425 uint32 Size, Width, Height, Result;
00426
00427 if (pCacheType->RefCount <= 0)
00428 continue;
00429
00430 if (pCacheType->NumUsedSlots >= pCacheType->RefCount)
00431 continue;
00432
00433 if (pCacheType->NumUsedSlots >= MaxTable[pCacheType->Log])
00434 continue;
00435
00436 if (!pCacheType->Slots)
00437 {
00438 pCacheType->Slots = (D3DCache_Slot*)malloc(sizeof(D3DCache_Type)*pCacheType->RefCount);
00439 memset(pCacheType->Slots, 0, sizeof(D3DCache_Type)*pCacheType->RefCount);
00440 }
00441
00442 Width = pCacheType->Width;
00443 Height = pCacheType->Height;
00444
00445 Size = Width*Height*(pCacheType->ddsd.ddpfPixelFormat.dwRGBBitCount>>3);
00446
00447 if (UsePartition)
00448 {
00449 if (!DDMemMgr_PartitionAllocMem(Cache->Partition, Size))
00450 {
00451 LastSlot = NULL;
00452 break;
00453 }
00454 }
00455
00456 pSlot = &pCacheType->Slots[pCacheType->NumUsedSlots];
00457 pSlot->SelfCheck = pSlot;
00458
00459 pSlot->CacheType = pCacheType;
00460
00461
00462 Result = D3DCache_SetupSlot(Cache, pSlot, Width, Height, &pCacheType->ddsd, Cache->UseStages, pCacheType->Stage);
00463
00464 if (!Result)
00465 {
00466 memset(pSlot, 0, sizeof(D3DCache_Slot));
00467 break;
00468 }
00469 else if (Result == -1)
00470 {
00471 D3DMain_Log("D3DCache_AdjustSlots: D3DCache_SetupSlot failed.\n");
00472 return GE_FALSE;
00473 }
00474
00475 pCacheType->NumUsedSlots++;
00476 Total++;
00477
00478 LastSlot = pSlot;
00479 }
00480
00481 NumPasses++;
00482
00483 if (!LastSlot)
00484 break;
00485 }
00486
00487 pCacheType = Cache->CacheTypes;
00488
00489
00490 for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00491 {
00492 if (pCacheType->RefCount <= 0)
00493 continue;
00494
00495 if (pCacheType->NumUsedSlots <= 0)
00496 {
00497 D3DMain_Log("D3DCache_AdjustSlots: Out of ram creating surfaces for cache.\n");
00498 D3DMain_Log("D3DCache_AdjustSlots: Pick a display mode with a smaller resolution.\n");
00499 return GE_FALSE;
00500 }
00501 }
00502
00503 D3DCache_WriteToFile(Cache, "D3DCache.Log", AppendHack);
00504 AppendHack = GE_TRUE;
00505
00506 return GE_TRUE;
00507 }
00508
00509
00510
00511
00512 geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot)
00513 {
00514 if (!Slot)
00515 return GE_FALSE;
00516
00517 if (Slot->SelfCheck != Slot)
00518 return GE_FALSE;
00519
00520 return GE_TRUE;
00521 }
00522
00523
00524
00525
00526
00527
00528
00529
00530 int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage)
00531 {
00532 LPDIRECTDRAWSURFACE4 Surface;
00533 DDSURFACEDESC2 ddsd;
00534 HRESULT Hr;
00535
00536 memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2));
00537
00538 ddsd.dwSize = sizeof(DDSURFACEDESC2);
00539 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
00540
00541 if (UseStage)
00542 ddsd.dwFlags |= DDSD_TEXTURESTAGE;
00543
00544 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
00545 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC;
00546 ddsd.ddsCaps.dwCaps3 = 0;
00547 ddsd.ddsCaps.dwCaps4 = 0;
00548 ddsd.dwHeight = Width;
00549 ddsd.dwWidth = Height;
00550 ddsd.dwTextureStage = Stage;
00551
00552 Hr = Cache->lpDD->CreateSurface(&ddsd, &Surface, NULL);
00553
00554 if(Hr != DD_OK)
00555 {
00556 if (Hr == DDERR_OUTOFVIDEOMEMORY)
00557 {
00558 return 0;
00559 }
00560
00561 return -1;
00562 }
00563
00564 Slot->Surface = Surface;
00565
00566
00567 Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Slot->Texture);
00568
00569 if(Hr != DD_OK)
00570 {
00571 Surface->Release();
00572 return -1;
00573 }
00574
00575 return 1;
00576 }
00577
00578
00579
00580
00581
00582 D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType)
00583 {
00584 D3DCache_Slot *pBestSlot, *pSlot;
00585 uint32 BestLRU;
00586 int32 i;
00587
00588 pSlot = CacheType->Slots;
00589 pBestSlot = pSlot;
00590 BestLRU = pBestSlot->LRU;
00591
00592 for (i=0; i< CacheType->NumUsedSlots; i++, pSlot++)
00593 {
00594 if (pSlot->LRU < BestLRU)
00595 {
00596 pBestSlot = pSlot;
00597 BestLRU = pSlot->LRU;
00598 }
00599 }
00600
00601 pBestSlot->LRU = 0;
00602 pBestSlot->UserData = NULL;
00603
00604 return pBestSlot;
00605 }
00606
00607
00608
00609
00610 void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData)
00611 {
00612 Slot->UserData = UserData;
00613 }
00614
00615
00616
00617
00618 void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot)
00619 {
00620 return Slot->UserData;
00621 }
00622
00623
00624
00625
00626 void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU)
00627 {
00628 Slot->LRU = LRU;
00629 }
00630
00631
00632
00633
00634 uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot)
00635 {
00636 return Slot->LRU;
00637 }
00638
00639 LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot)
00640 {
00641 return Slot->Texture;
00642 }
00643
00644 LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot)
00645 {
00646 return Slot->Surface;
00647 }
00648
00649
00650
00651
00652
00653 uint32 Log2(uint32 P2)
00654 {
00655 uint32 p = 0;
00656 int32 i = 0;
00657
00658 for (i = P2; i > 0; i>>=1)
00659 p++;
00660
00661 return (p-1);
00662 }
00663
00664
00665
00666
00667
00668 int32 SnapToPower2(int32 Width)
00669 {
00670 if (Width > 0 && Width <= 1) Width = 1;
00671 else if (Width > 1 && Width <= 2) Width = 2;
00672 else if (Width > 2 && Width <= 4) Width = 4;
00673 else if (Width > 4 && Width <= 8) Width = 8;
00674 else if (Width > 8 && Width <= 16) Width =16;
00675 else if (Width > 16 && Width <= 32) Width = 32;
00676 else if (Width > 32 && Width <= 64) Width = 64;
00677 else if (Width > 64 && Width <= 128) Width = 128;
00678 else if (Width > 128 && Width <= 256) Width = 256;
00679 else
00680 return -1;
00681
00682 return Width;
00683 }
00684
00685
00686
00687
00688 int32 GetLog(int32 Width, int32 Height)
00689 {
00690 int32 LWidth = SnapToPower2(max(Width, Height));
00691
00692 return Log2(LWidth);
00693 }
00694