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
00026 #include "GCache.h"
00027 #include "GMemMGr.h"
00028 #include "DCommon.h"
00029 #include "Glide.h"
00030
00031 #define GCACHE_WRITELOG
00032
00033
00034
00035 #define GCACHE_MAX_CACHE_TYPES 128
00036
00037
00038
00039 typedef struct GCache_Type
00040 {
00041 GrTexInfo Info;
00042 int32 Log;
00043 int32 Width;
00044 int32 Height;
00045 uint8 NumMipLevels;
00046 uint32 Size;
00047
00048 geFloat OneOverWidth_255;
00049 geFloat OneOverHeight_255;
00050
00051 GCache_Slot *Slots;
00052 int32 RefCount;
00053 int32 UsedSlots;
00054
00055 #ifdef DYNAMIC_CACHE
00056 struct GCache_Type *PrevNext[2];
00057 #endif
00058
00059 } GCache_Type;
00060
00061 typedef struct GCache
00062 {
00063 char Name[GCACHE_MAX_NAME];
00064
00065 GMemMgr *MemMgr;
00066
00067 GCache_Type CacheTypes[GCACHE_MAX_CACHE_TYPES];
00068
00069 uint32 LastMemAddr;
00070
00071 struct GCache *SelfCheck;
00072 } GCache;
00073
00074 typedef struct GCache_Slot
00075 {
00076
00077 GCache_Type *Type;
00078
00079 uint32 MemAddr;
00080 uint32 LRU;
00081
00082 void *UserData;
00083
00084 struct GCache_Slot *SelfCheck;
00085
00086 } GCache_Slot;
00087
00088
00089
00090
00091
00092
00093
00094 GCache *GCache_Create(const char *Name, GMemMgr *MemMgr)
00095 {
00096 GCache *Cache;
00097
00098 assert(Name);
00099 assert(strlen(Name) < GCACHE_MAX_NAME);
00100 assert(MemMgr);
00101
00102 Cache = malloc(sizeof(GCache));
00103
00104 if (!Cache)
00105 return NULL;
00106
00107 memset(Cache, 0, sizeof(GCache));
00108
00109 strcpy(Cache->Name, Name);
00110
00111 Cache->MemMgr = MemMgr;
00112
00113 Cache->LastMemAddr = 0xffffffff;
00114
00115 Cache->SelfCheck = Cache;
00116
00117 if (!GCache_Reset(Cache))
00118 goto ExitWithError;
00119
00120 return Cache;
00121
00122 ExitWithError:
00123 {
00124 if (Cache)
00125 free(Cache);
00126
00127 return NULL;
00128 }
00129 }
00130
00131
00132
00133
00134 void GCache_Destroy(GCache *Cache)
00135 {
00136 assert(Cache);
00137
00138 free(Cache);
00139 }
00140
00141
00142
00143 geBoolean GCache_Reset(GCache *Cache)
00144 {
00145 int32 i;
00146 GCache_Type *pCacheType;
00147
00148 GCache_FreeAllSlots(Cache);
00149
00150 for (pCacheType = Cache->CacheTypes, i=0; i<GCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00151 {
00152 memset(pCacheType, 0, sizeof(GCache_Type));
00153
00154 #ifdef DYNAMIC_CACHE
00155
00156 if (i > 0)
00157 pCacheType->PrevNext[0] = (pCacheType-1);
00158 if (i < GCACHE_MAX_CACHE_TYPES-1)
00159 pCacheType->PrevNext[1] = (pCacheType+1);
00160 #endif
00161 }
00162
00163 return GE_TRUE;
00164 }
00165
00166
00167
00168 GCache_Type *GCache_FindCacheTypeByInfo(GCache *Cache, const GrTexInfo *Info)
00169 {
00170 int32 i;
00171 GCache_Type *pCacheType;
00172
00173 pCacheType = Cache->CacheTypes;
00174
00175 for (i=0; i<GCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00176 {
00177
00178
00179 if (pCacheType->RefCount == 0)
00180 continue;
00181
00182 if (Info->smallLod != pCacheType->Info.smallLod)
00183 continue;
00184 if (Info->largeLod != pCacheType->Info.largeLod)
00185 continue;
00186 if (Info->aspectRatio != pCacheType->Info.aspectRatio)
00187 continue;
00188
00189 if (Info->format != pCacheType->Info.format)
00190 continue;
00191
00192 #if 0
00193
00194 Size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, (GrTexInfo*)Info);
00195
00196
00197 continue;
00198 #endif
00199
00200 return pCacheType;
00201 }
00202
00203 return NULL;
00204 }
00205
00206
00207
00208 GCache_Type *GCache_InsertCacheTypeByInfo(GCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, const GrTexInfo *Info)
00209 {
00210 int32 i;
00211 GCache_Type *pCacheType;
00212
00213 assert(NumMipLevels <= 255);
00214 assert(NumMipLevels >= 0);
00215
00216 pCacheType = Cache->CacheTypes;
00217
00218 for (i=0; i<GCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00219 {
00220 if (pCacheType->RefCount == 0)
00221 {
00222 assert(pCacheType->Slots == NULL);
00223 assert(pCacheType->UsedSlots == 0);
00224 break;
00225 }
00226 }
00227
00228 if (i == GCACHE_MAX_CACHE_TYPES)
00229 return NULL;
00230
00231 pCacheType->Info = *Info;
00232 pCacheType->Info.data = NULL;
00233 pCacheType->Width = Width;
00234 pCacheType->Height = Height;
00235 pCacheType->NumMipLevels = (uint8)NumMipLevels;
00236 pCacheType->Size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, (GrTexInfo*)Info);
00237
00238
00239 pCacheType->RefCount++;
00240
00241 return pCacheType;
00242 }
00243
00244
00245
00246
00247 geBoolean GCache_UpdateSlot(GCache *Cache, GCache_Slot *Slot, GrTexInfo *Info)
00248 {
00249 assert(GCache_SlotIsValid(Slot));
00250
00251 grTexDownloadMipMap(GMemMgr_GetTmu(Cache->MemMgr), Slot->MemAddr, GR_MIPMAPLEVELMASK_BOTH, Info);
00252
00253 return GE_TRUE;
00254 }
00255
00256
00257
00258
00259 geBoolean GCache_SetTexture(GCache *Cache, GCache_Slot *Slot)
00260 {
00261 assert(GCache_SlotIsValid(Slot));
00262
00263 if (Cache->LastMemAddr == Slot->MemAddr)
00264 return GE_TRUE;
00265
00266 grTexSource(GMemMgr_GetTmu(Cache->MemMgr), Slot->MemAddr, GR_MIPMAPLEVELMASK_BOTH, &Slot->Type->Info);
00267
00268 Cache->LastMemAddr = Slot->MemAddr;
00269
00270 Slot->LRU++;
00271
00272 return GE_TRUE;
00273 }
00274
00275
00276
00277 GCache_Type *GCache_TypeCreate(GCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, const GrTexInfo *Info)
00278 {
00279 GCache_Type *CacheType;
00280
00281 CacheType = GCache_FindCacheTypeByInfo(Cache, Info);
00282
00283 if (CacheType)
00284 {
00285 CacheType->RefCount++;
00286 return CacheType;
00287 }
00288
00289
00290 return GCache_InsertCacheTypeByInfo(Cache, Width, Height, NumMipLevels, Info);
00291 }
00292
00293
00294
00295
00296 void GCache_TypeDestroy(GCache_Type *CacheType)
00297 {
00298 assert(CacheType->RefCount > 0);
00299
00300 CacheType->RefCount--;
00301
00302 if (CacheType->RefCount == 0)
00303 {
00304 if (CacheType->Slots)
00305 {
00306 assert(CacheType->UsedSlots > 0);
00307 free(CacheType->Slots);
00308 }
00309 else
00310 {
00311 assert(CacheType->UsedSlots == 0);
00312 }
00313
00314 CacheType->UsedSlots = 0;
00315 CacheType->Slots = NULL;
00316 }
00317 }
00318
00319
00320
00321
00322 geBoolean GCache_FreeAllSlots(GCache *Cache)
00323 {
00324 int32 i;
00325 GCache_Type *pCacheType;
00326
00327 pCacheType = Cache->CacheTypes;
00328
00329 for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00330 {
00331 assert(pCacheType->RefCount >= 0);
00332
00333 if (pCacheType->RefCount == 0)
00334 {
00335 assert(pCacheType->Slots == NULL);
00336 assert(pCacheType->UsedSlots == 0);
00337 continue;
00338 }
00339
00340 if (pCacheType->Slots)
00341 {
00342 assert(pCacheType->UsedSlots > 0);
00343 free(pCacheType->Slots);
00344 }
00345 else
00346 assert(pCacheType->UsedSlots == 0);
00347
00348 pCacheType->Slots = NULL;
00349 pCacheType->UsedSlots = 0;
00350 }
00351
00352 return GE_TRUE;
00353 }
00354
00355
00356
00357
00358 geBoolean GCache_WriteToFile(GCache *Cache, const char *FileName, geBoolean Append)
00359 {
00360 int32 i;
00361 GCache_Type *pCacheType;
00362 int32 TotalRef, TotalUsed;
00363 SYSTEMTIME Time;
00364 FILE *f;
00365
00366 if (Append)
00367 f = fopen(FileName, "a+t");
00368 else
00369 f = fopen(FileName, "w");
00370
00371 if (!f)
00372 return GE_FALSE;
00373
00374 pCacheType = Cache->CacheTypes;
00375
00376 TotalRef = TotalUsed = 0;
00377
00378 GetSystemTime(&Time);
00379
00380 fprintf(f, "=======================================================\n");
00381 fprintf(f, "Date: %i/%i/%i, Time: %i:%i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute);
00382 fprintf(f, "Cache Name: %s\n", Cache->Name);
00383 fprintf(f, "Total Memory for Cache: %6i\n", GMemMgr_GetTotalMemory(Cache->MemMgr));
00384 fprintf(f, "Free Memory for Cache: %6i\n", GMemMgr_GetFreeMemory(Cache->MemMgr));
00385 fprintf(f, "--- Slots ---\n");
00386
00387 for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00388 {
00389 if (!pCacheType->RefCount)
00390 continue;
00391
00392 fprintf(f, "Width: %3i, Height %3i, Mips: %2i, Ref: %4i, Used: %4i\n",
00393 pCacheType->Width, pCacheType->Height, pCacheType->NumMipLevels, pCacheType->RefCount, pCacheType->UsedSlots);
00394
00395 TotalRef += pCacheType->RefCount;
00396 TotalUsed += pCacheType->UsedSlots;
00397 }
00398
00399 fprintf(f, "Total Ref: %4i, Total Used: %4i\n", TotalRef, TotalUsed);
00400
00401 fclose(f);
00402
00403 return GE_TRUE;
00404 }
00405
00406 static geBoolean AppendHack = GE_FALSE;
00407
00408
00409
00410
00411 geBoolean GCache_AdjustSlots(GCache *Cache)
00412 {
00413 GCache_Type *pCacheType;
00414 int32 i;
00415
00416 GCache_FreeAllSlots(Cache);
00417
00418 GMemMgr_Reset(Cache->MemMgr);
00419
00420 while(1)
00421 {
00422 GCache_Slot *LastSlot;
00423
00424 LastSlot = NULL;
00425
00426 pCacheType = Cache->CacheTypes;
00427
00428 for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00429 {
00430 GCache_Slot *pSlot;
00431 uint32 Size;
00432
00433 if (pCacheType->RefCount <= 0)
00434 {
00435 assert(pCacheType->Slots == NULL);
00436 assert(pCacheType->UsedSlots == 0);
00437 continue;
00438 }
00439
00440 if (pCacheType->UsedSlots >= pCacheType->RefCount)
00441 continue;
00442
00443 if (!pCacheType->Slots)
00444 {
00445 assert(pCacheType->UsedSlots == 0);
00446
00447 pCacheType->Slots = malloc(sizeof(GCache_Type)*pCacheType->RefCount);
00448
00449 if (!pCacheType->Slots)
00450 return GE_FALSE;
00451
00452 memset(pCacheType->Slots, 0, sizeof(GCache_Type)*pCacheType->RefCount);
00453 }
00454
00455 Size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &pCacheType->Info);
00456
00457 if (GMemMgr_GetFreeMemory(Cache->MemMgr) < Size)
00458 break;
00459
00460 pSlot = &pCacheType->Slots[pCacheType->UsedSlots++];
00461 pSlot->SelfCheck = pSlot;
00462
00463 pSlot->Type = pCacheType;
00464
00465 if (!GMemMgr_AllocMem(Cache->MemMgr, Size, &pSlot->MemAddr))
00466 {
00467 pCacheType->UsedSlots--;
00468 break;
00469 }
00470
00471 LastSlot = pSlot;
00472 }
00473
00474 if (!LastSlot)
00475 break;
00476 }
00477
00478 pCacheType = Cache->CacheTypes;
00479
00480
00481 for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++)
00482 {
00483 if (pCacheType->RefCount <= 0)
00484 {
00485 assert(pCacheType->Slots == NULL);
00486 assert(pCacheType->UsedSlots == 0);
00487 continue;
00488 }
00489
00490 if (pCacheType->UsedSlots <= 0)
00491 return GE_FALSE;
00492
00493 assert(pCacheType->Slots != NULL);
00494 }
00495
00496 #ifdef GCACHE_WRITELOG
00497 GCache_WriteToFile(Cache, "GCache.Log", AppendHack);
00498
00499 AppendHack = GE_TRUE;
00500 #endif
00501
00502 return GE_TRUE;
00503 }
00504
00505
00506
00507
00508 uint32 GCache_SlotGetMemAddress(GCache_Slot *Slot)
00509 {
00510 assert(GCache_SlotIsValid(Slot));
00511
00512 return Slot->MemAddr;
00513 }
00514
00515
00516
00517
00518 geBoolean GCache_SlotIsValid(GCache_Slot *Slot)
00519 {
00520 if (!Slot)
00521 return GE_FALSE;
00522
00523 if (Slot->SelfCheck != Slot)
00524 return GE_FALSE;
00525
00526 return GE_TRUE;
00527 }
00528
00529 #ifdef DYNAMIC_CACHE
00530
00531 #define GROW_DIR_LEFT 0
00532 #define GROW_DIR_RIGHT 1
00533
00534 #define MAX_STACK 64
00535
00536 typedef struct
00537 {
00538 GCache_Type *Type;
00539 int32 UsedSlots;
00540 } GCache_TypeStack;
00541
00542
00543
00544
00545 GCache_Slot *GCache_TypeGrowDir(GCache_Type *CacheType, GCache_Type *Current, int32 Dir)
00546 {
00547 uint32 Size;
00548 int32 UsedSlots;
00549 GCache_Type *Original;
00550 GCache_TypeStack Stack[MAX_STACK], *pStack;
00551
00552 assert(CacheType);
00553 assert(Current);
00554
00555 Original = Current;
00556
00557 Size = Current->Size;
00558 UsedSlots = Current->UsedSlots;
00559
00560 pStack = Stack;
00561
00562
00563 while (CacheType->Size > Size)
00564 {
00565
00566
00567 if (pStack >= &Stack[MAX_STACK])
00568 return NULL;
00569
00570 if (UsedSlots <= 1)
00571 {
00572 pStack->Type = Current;
00573 pStack->UsedSlots = UsedSlots;
00574 pStack++;
00575
00576 Current = Current->PrevNext[Dir];
00577
00578 if (!Current)
00579 return NULL;
00580
00581 UsedSlots = Current->UsedSlots;
00582 continue;
00583 }
00584
00585 UsedSlots--;
00586 Size += Current->Size;
00587
00588 pStack->Type = Current;
00589 pStack->UsedSlots = UsedSlots;
00590 pStack++;
00591 }
00592
00593
00594 while (pStack-- > Stack)
00595 {
00596 pStack->Type->UsedSlots = pStack->UsedSlots;
00597 }
00598
00599 return &Original->Slots[Original->UsedSlots++];
00600 }
00601
00602
00603
00604
00605
00606 GCache_Slot *GCache_TypeGrow(GCache_Type *CacheType)
00607 {
00608 GCache_Type **PrevNext;
00609 GCache_Slot *Slot;
00610 int32 Dir;
00611
00612 PrevNext = CacheType->PrevNext;
00613
00614 assert(PrevNext[0] || PrevNext[1]);
00615
00616 if (!PrevNext[0])
00617 return GCache_TypeGrowDir(CacheType, PrevNext[1], GROW_DIR_RIGHT);
00618 if (!PrevNext[1])
00619 return GCache_TypeGrowDir(CacheType, PrevNext[0], GROW_DIR_LEFT);
00620
00621
00622 if (PrevNext[GROW_DIR_LEFT]->Size > PrevNext[GROW_DIR_RIGHT]->Size)
00623 Dir = GROW_DIR_LEFT;
00624 else
00625 Dir = GROW_DIR_RIGHT;
00626
00627 Slot = GCache_TypeGrowDir(CacheType, PrevNext[Dir], Dir);
00628
00629 if (!Slot)
00630 Slot = GCache_TypeGrowDir(CacheType, PrevNext[!Dir], !Dir);
00631
00632 return Slot;
00633 }
00634
00635 #endif
00636
00637
00638
00639
00640 GCache_Slot *GCache_TypeFindSlot(GCache_Type *CacheType)
00641 {
00642 GCache_Slot *pBestSlot, *pSlot;
00643 uint32 BestLRU;
00644 int32 i;
00645
00646 assert(CacheType->Slots);
00647
00648 #ifdef DYNAMIC_CACHE
00649
00650
00651 if (pBestSlot = GCache_TypeGrow(CacheType))
00652 goto GotIt;
00653 #endif
00654
00655 pSlot = CacheType->Slots;
00656 pBestSlot = pSlot;
00657 BestLRU = pBestSlot->LRU;
00658
00659 for (i=0; i< CacheType->UsedSlots; i++, pSlot++)
00660 {
00661 if (pSlot->LRU < BestLRU)
00662 {
00663 pBestSlot = pSlot;
00664 BestLRU = pSlot->LRU;
00665 }
00666 }
00667
00668 #ifdef DYNAMIC_CACHE
00669 GotIt:
00670 #endif
00671
00672 pBestSlot->LRU = 0;
00673 pBestSlot->UserData = NULL;
00674
00675 return pBestSlot;
00676 }
00677
00678
00679
00680
00681 void GCache_SlotSetUserData(GCache_Slot *Slot, void *UserData)
00682 {
00683 assert(GCache_SlotIsValid(Slot));
00684
00685 Slot->UserData = UserData;
00686 }
00687
00688
00689
00690
00691 void *GCache_SlotGetUserData(GCache_Slot *Slot)
00692 {
00693 assert(GCache_SlotIsValid(Slot));
00694
00695 return Slot->UserData;
00696 }
00697
00698
00699
00700
00701 GrTexInfo *GCache_SlotGetInfo(GCache_Slot *Slot)
00702 {
00703 assert(GCache_SlotIsValid(Slot));
00704
00705 return &Slot->Type->Info;
00706 }
00707
00708
00709
00710
00711 void GCache_SlotSetLRU(GCache_Slot *Slot, uint32 LRU)
00712 {
00713 assert(GCache_SlotIsValid(Slot));
00714
00715 Slot->LRU = LRU;
00716 }