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