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