Erwan - cache fixes - Code review highly appreciated, please criticize my code!

- fix issue 65 (quads when no image  load slowly in shop/deck editor)
- Possibly fix issue 92, please let me know if it reproduces
- Fix issue 97 (Deck editor: weird behavior of deck display)
- Fix issue 39 - please verify
- Issue 56 can probably be closed as well
- Fix issue 86
This commit is contained in:
wagic.the.homebrew@gmail.com
2009-10-13 14:16:30 +00:00
parent 90a29437d2
commit 6f159fb39c
25 changed files with 231 additions and 432 deletions

View File

@@ -9,6 +9,7 @@
#include <JFileSystem.h>
#include "../include/WResourceManager.h"
WResourceManager resources;
unsigned int vTime = 0;
int WResourceManager::RetrieveError(){
@@ -36,12 +37,8 @@ void WResourceManager::DebugRender(){
font->SetScale(DEFAULT_MAIN_FONT_SCALE);
renderer->FillRect(0,0,SCREEN_WIDTH,20,ARGB(128,155,0,0));
#ifdef DEBUG_CACHE
if(debugMessage.size())
renderer->FillRect(0,SCREEN_HEIGHT-30,SCREEN_WIDTH,40,ARGB(128,155,0,0));
else
#endif
renderer->FillRect(0,SCREEN_HEIGHT-20,SCREEN_WIDTH,40,ARGB(128,155,0,0));
renderer->FillRect(0,SCREEN_HEIGHT-20,SCREEN_WIDTH,40,ARGB(128,155,0,0));
char buf[512];
@@ -167,9 +164,9 @@ WResourceManager::WResourceManager(){
mFontList.reserve(4);
mFontMap.clear();
psiWCache.Resize(SMALL_CACHE_LIMIT,6); //Plenty of room for mana symbols, or whatever.
sampleWCache.Resize(SMALL_CACHE_LIMIT,MAX_CACHED_SAMPLES);
textureWCache.Resize(LARGE_CACHE_LIMIT,MAX_CACHE_OBJECTS);
psiWCache.Resize(PSI_CACHE_SIZE,20);
sampleWCache.Resize(SAMPLES_CACHE_SIZE,MAX_CACHED_SAMPLES);
textureWCache.Resize(TEXTURES_CACHE_MINSIZE,MAX_CACHE_OBJECTS);
lastTime = 0;
lastError = CACHE_ERROR_NONE;
}
@@ -192,32 +189,33 @@ WResourceManager::~WResourceManager(){
LOG("==Successfully Destroyed WResourceManager==");
}
JQuad * WResourceManager::RetrieveCard(MTGCard * card, int style, int submode){
//Cards are never, ever resource managed, so just check cache.
if(!card || options[Options::DISABLECARDS].number)
return NULL;
JQuad * WResourceManager::RetrieveCard(MTGCard * card, int style, int submode){
//Cards are never, ever resource managed, so just check cache.
if(!card || options[Options::DISABLECARDS].number)
return NULL;
submode = submode | TEXTURE_SUB_CARD;
string filename = card->getSetName();
filename += "/";
filename += card->getImageName();
JQuad * jq = RetrieveQuad(filename,0,0,0,0,"",style,submode|TEXTURE_SUB_5551);
lastError = textureWCache.mError;
if(jq){
jq->SetHotSpot(jq->mTex->mWidth / 2, jq->mTex->mHeight / 2);
return jq;
}
return NULL;
}
submode = submode | TEXTURE_SUB_CARD;
string filename = card->getSetName();
filename += "/";
filename += card->getImageName();
JQuad * jq = RetrieveQuad(filename,0,0,0,0,"",style,submode|TEXTURE_SUB_5551);
lastError = textureWCache.mError;
if(jq){
jq->SetHotSpot(jq->mTex->mWidth / 2, jq->mTex->mHeight / 2);
return jq;
}
return NULL;
}
int WResourceManager::CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height){
if(!quadName.size() || !textureName.size())
return INVALID_ID;
string resname = quadName;
std::transform(resname.begin(),resname.end(),resname.begin(),::tolower);
vector<WManagedQuad*>::iterator it;
int pos = 0;
@@ -253,7 +251,6 @@ int WResourceManager::CreateQuad(const string &quadName, const string &textureNa
JQuad * WResourceManager::GetQuad(const string &quadName){
string lookup = quadName;
std::transform(lookup.begin(),lookup.end(),lookup.begin(),::tolower);
for(vector<WManagedQuad*>::iterator it=managedQuads.begin();it!=managedQuads.end();it++){
if((*it)->resname == lookup)
@@ -289,11 +286,7 @@ JQuad * WResourceManager::RetrieveQuad(string filename, float offX, float offY,
}
//Aliases.
if(style == RETRIEVE_VRAM){
submode = submode | TEXTURE_SUB_VRAM;
style = RETRIEVE_LOCK;
}
else if(style == RETRIEVE_THUMB){
if(style == RETRIEVE_THUMB){
submode = submode | TEXTURE_SUB_THUMB;
style = RETRIEVE_NORMAL;
}
@@ -319,8 +312,7 @@ JQuad * WResourceManager::RetrieveQuad(string filename, float offX, float offY,
if(jtex){
WTrackedQuad * tq = jtex->GetTrackedQuad(offX,offY,width,height,resname);
if(tq == NULL)
return NULL;
if(!tq) return NULL;
if(style == RETRIEVE_MANAGE && resname != ""){
WManagedQuad * mq = NEW WManagedQuad();
@@ -398,11 +390,7 @@ JTexture * WResourceManager::RetrieveTexture(string filename, int style, int sub
WCachedTexture * res = NULL;
//Aliases.
if(style == RETRIEVE_VRAM){
submode = submode | TEXTURE_SUB_VRAM;
style = RETRIEVE_LOCK;
}
else if(style == RETRIEVE_THUMB){
if(style == RETRIEVE_THUMB){
submode = submode | TEXTURE_SUB_THUMB;
style = RETRIEVE_NORMAL;
}
@@ -521,9 +509,8 @@ string WResourceManager::graphicsFile(const string filename, const string specif
//Check the theme folder.
string theme = options[Options::ACTIVE_THEME].str;
std::transform(theme.begin(), theme.end(), theme.begin(), ::tolower);
if(theme != "" && theme != "default"){
if(theme != "" && theme != "Default"){
sprintf(buf,"themes/%s/%s",theme.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -531,9 +518,8 @@ string WResourceManager::graphicsFile(const string filename, const string specif
//Failure. Check mode graphics
string mode = options[Options::ACTIVE_MODE].str;
std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
if(mode != "" && mode != "defualt"){
if(mode != "" && mode != "Default"){
sprintf(buf,"modes/%s/graphics/%s",mode.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -567,8 +553,8 @@ string WResourceManager::avatarFile(const string filename, const string specific
//Check the profile folder.
string profile = options[Options::ACTIVE_PROFILE].str;
std::transform(profile.begin(), profile.end(), profile.begin(), ::tolower);
if(profile != "" && profile != "default"){
if(profile != "" && profile != "Default"){
sprintf(buf,"profiles/%s/%s",profile.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -580,9 +566,8 @@ string WResourceManager::avatarFile(const string filename, const string specific
//Check the theme folder.
string theme = options[Options::ACTIVE_THEME].str;
std::transform(theme.begin(), theme.end(), theme.begin(), ::tolower);
if(theme != "" && theme != "default"){
if(theme != "" && theme != "Default"){
sprintf(buf,"themes/%s/%s",theme.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -590,9 +575,8 @@ string WResourceManager::avatarFile(const string filename, const string specific
//Failure. Check mode graphics
string mode = options[Options::ACTIVE_MODE].str;
std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
if(mode != "" && mode != "defualt"){
if(mode != "" && mode != "Default"){
sprintf(buf,"modes/%s/graphics/%s",mode.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -615,9 +599,12 @@ string WResourceManager::avatarFile(const string filename, const string specific
string WResourceManager::cardFile(const string filename, const string specific){
JFileSystem* fs = JFileSystem::GetInstance();
//PUT Back the following when we have an actual usage for it (theme, or whatever)
//Right now I'm removing this for performance
/*
char buf[512];
//Check the specific location, if any.
if(specific != ""){
sprintf(buf,"%s/sets/%s",specific.c_str(),filename.c_str());
@@ -627,9 +614,8 @@ string WResourceManager::cardFile(const string filename, const string specific){
//Check the theme folder.
string theme = options[Options::ACTIVE_THEME].str;
std::transform(theme.begin(), theme.end(), theme.begin(), ::tolower);
if(theme != "" && theme != "default"){
if(theme != "" && theme != "Default"){
sprintf(buf,"themes/%s/sets/%s",theme.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -637,14 +623,14 @@ string WResourceManager::cardFile(const string filename, const string specific){
//Failure. Check mode
string mode = options[Options::ACTIVE_MODE].str;
std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
if(mode != "" && mode != "defualt"){
if(mode != "" && mode != "Default"){
sprintf(buf,"modes/%s/sets/%s",mode.c_str(),filename.c_str());
if(fileOK(buf,true))
if(fileOK(buf,true))
return buf;
}
*/
//Failure. Check sets
char defdir[512];
sprintf(defdir,"sets/%s",filename.c_str());
@@ -687,9 +673,8 @@ string WResourceManager::musicFile(const string filename, const string specific)
//Check the theme folder.
string theme = options[Options::ACTIVE_THEME].str;
std::transform(theme.begin(), theme.end(), theme.begin(), ::tolower);
if(theme != "" && theme != "default"){
if(theme != "" && theme != "Default"){
sprintf(buf,"themes/%s/sound/%s",theme.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -697,9 +682,8 @@ string WResourceManager::musicFile(const string filename, const string specific)
//Failure. Check mode
string mode = options[Options::ACTIVE_MODE].str;
std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
if(mode != "" && mode != "defualt"){
if(mode != "" && mode != "Default"){
sprintf(buf,"modes/%s/sound/%s",mode.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -727,9 +711,8 @@ string WResourceManager::sfxFile(const string filename, const string specific){
//Check the theme folder.
string theme = options[Options::ACTIVE_THEME].str;
std::transform(theme.begin(), theme.end(), theme.begin(), ::tolower);
if(theme != "" && theme != "default"){
if(theme != "" && theme != "Default"){
sprintf(buf,"themes/%s/sound/sfx/%s",theme.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -737,8 +720,7 @@ string WResourceManager::sfxFile(const string filename, const string specific){
//Failure. Check mode
string mode = options[Options::ACTIVE_MODE].str;
std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
if(mode != "" && mode != "defualt"){
if(mode != "" && mode != "Default"){
sprintf(buf,"modes/%s/sound/sfx/%s",mode.c_str(),filename.c_str());
if(fileOK(buf,true))
return buf;
@@ -793,40 +775,20 @@ int WResourceManager::LoadJLBFont(const string &fontName, int height){
else
return itr->second;
}
void WResourceManager::CacheForState(int state){
#if (defined WIN32 || defined LINUX) && !defined DEBUG_CACHE
textureWCache.Resize(HUGE_CACHE_LIMIT,HUGE_CACHE_ITEMS);
return;
#else
switch(state){
//Default is not to change cache sizes.
case GAME_STATE_MENU:
case GAME_STATE_OPTIONS:
break;
//Duels use a smaller cache, so there's more room for game stuff.
case GAME_STATE_DUEL:
if (options[Options::CACHESIZE].number)
textureWCache.Resize(LARGE_CACHE_LIMIT,LARGE_CACHE_ITEMS);
else
textureWCache.Resize(SMALL_CACHE_LIMIT,SMALL_CACHE_ITEMS);
sampleWCache.Resize(SMALL_CACHE_LIMIT,MAX_CACHED_SAMPLES);
break;
//Deck editor and shop are entirely cache safe, so give it near infinite resources.
case GAME_STATE_SHOP:
case GAME_STATE_DECK_VIEWER:
textureWCache.Resize(HUGE_CACHE_LIMIT,HUGE_CACHE_ITEMS);
break;
//Anything unknown, use large cache.
default:
textureWCache.Resize(LARGE_CACHE_LIMIT,LARGE_CACHE_ITEMS);
break;
}
//Switching game states clears the cache on PSP.
ClearUnlocked();
void WResourceManager::autoResize(){
#if defined WIN32 || defined LINUX
textureWCache.Resize(HUGE_CACHE_LIMIT,MAX_CACHE_OBJECTS);
#else
unsigned int ram = ramAvailable();
unsigned int myNewSize = ram - OPERATIONAL_SIZE + textureWCache.totalSize;
if (myNewSize < TEXTURES_CACHE_MINSIZE){
fprintf(stderr, "Error, Not enough RAM for Cache: %i - total Ram: %i\n", myNewSize, ram);
}
textureWCache.Resize(myNewSize,MAX_CACHE_OBJECTS);
#endif
return;
}
JMusic * WResourceManager::ssLoadMusic(const char *fileName){
@@ -993,17 +955,6 @@ void WCache<cacheItem, cacheActual>::Resize(unsigned long size, int items){
maxCached = items;
}
template <class cacheItem, class cacheActual>
cacheItem* WCache<cacheItem, cacheActual>::Recycle(){
typename vector<cacheItem*>::iterator it = garbage.begin();
if(it == garbage.end())
return NULL;
cacheItem * item = (*it);
garbage.erase(it);
return item;
}
template <class cacheItem, class cacheActual>
cacheItem* WCache<cacheItem, cacheActual>::AttemptNew(string filename, int submode){
@@ -1012,70 +963,49 @@ cacheItem* WCache<cacheItem, cacheActual>::AttemptNew(string filename, int submo
return NULL;
}
cacheItem* item = NULL;
item = Recycle();
//There was nothing to recycle. Make absolutely certain we have an item.
if(item == NULL){
item = NEW cacheItem;
if(item)
mError = CACHE_ERROR_NONE;
else{
//Try a few times to get an item.
for(int attempt=0;attempt<MAX_CACHE_ATTEMPTS;attempt++){
if(!RemoveOldest() || item)
break;
item = NEW cacheItem;
}
//We /really/ shouldn't get this far.
cacheItem* item = NEW cacheItem;
if(!item) {
//Try a few times to get an item.
for(int attempt=0;attempt<MAX_CACHE_ATTEMPTS;attempt++){
if(!RemoveOldest() || item)
break;
item = NEW cacheItem;
}
//We /really/ shouldn't get this far.
if(!item){
resources.ClearUnlocked();
item = NEW cacheItem;
if(!item){
resources.ClearUnlocked();
item = NEW cacheItem;
if(!item){
//Nothing let us make an item. Failure.
mError = CACHE_ERROR_BAD_ALLOC;
return NULL;
}
//Nothing let us make an item. Failure.
mError = CACHE_ERROR_BAD_ALLOC;
return NULL;
}
}
}
//Attempt to populate item.
mError = CACHE_ERROR_NONE;
for(int attempts = 0; attempts < MAX_CACHE_ATTEMPTS;attempts++)
{
//We use try/catch so any memory alloc'd in Attempt isn't lost.
try{
//If we don't get a good item, remove oldest cache and continue trying.
if(!item->Attempt(filename,submode,mError) || !item->isGood())
if(!item->Attempt(filename,submode,mError) || !item->isGood()) {
//No such file. Fail on first try.
if(mError == CACHE_ERROR_404){
SAFE_DELETE(item);
return NULL;
}
throw std::bad_alloc();
}
}
catch(std::bad_alloc){
RemoveOldest();
}
//No such file. Fail on first try.
if(item && mError == CACHE_ERROR_404){
if(garbage.size() < MAX_CACHE_GARBAGE){
item->Trash();
garbage.push_back(item);
}
else
SAFE_DELETE(item);
return NULL;
}
//Succeeded, so enforce limits and return.
if(item->isGood()){
mError = CACHE_ERROR_NONE;
item->lock();
Cleanup();
item->unlock();
return item;
}
//Succeeded
if(item->isGood())
break;
}
//Still no result, so clear local cache, then try again.
@@ -1089,23 +1019,18 @@ cacheItem* WCache<cacheItem, cacheActual>::AttemptNew(string filename, int submo
//Failed, so clear every cache we've got in prep for the next try.
resources.ClearUnlocked();
}
try{
if(!item->Attempt(filename,submode,mError) || !item->isGood())
throw std::bad_alloc();
}
catch(std::bad_alloc){
//Complete failure. Trash this object and return NULL.
if(item && !item->isGood()){
if(garbage.size() < MAX_CACHE_GARBAGE){
item->Trash();
garbage.push_back(item);
}
else
if(!item->isGood()){
try{
if(!item->Attempt(filename,submode,mError) || !item->isGood())
throw std::bad_alloc();
}
catch(std::bad_alloc){
//Complete failure. Trash this object and return NULL.
if(!item->isGood()){
SAFE_DELETE(item);
mError = CACHE_ERROR_BAD;
return NULL;
mError = CACHE_ERROR_BAD;
return NULL;
}
}
}
}
@@ -1136,15 +1061,19 @@ cacheItem * WCache<cacheItem, cacheActual>::Retrieve(string filename, int style,
//Perform lock or unlock on entry.
if(tc){
if(style == RETRIEVE_LOCK) tc->lock();
else if(style == RETRIEVE_UNLOCK) tc->unlock();
else if(style == RETRIEVE_MANAGE && !tc->isPermanent()) {
//Unlink the managed resource from the cache.
UnlinkCache(tc);
//Post it in managed resources.
managed[makeID(filename,submode)] = tc;
tc->deadbolt();
switch(style){
case RETRIEVE_LOCK: tc->lock(); break;
case RETRIEVE_UNLOCK: tc->unlock(); break;
case RETRIEVE_MANAGE:
if (!tc->isPermanent()) {
//Unlink the managed resource from the cache.
UnlinkCache(tc);
//Post it in managed resources.
managed[makeID(filename,submode)] = tc;
tc->deadbolt();
}
break;
}
}
@@ -1154,10 +1083,8 @@ cacheItem * WCache<cacheItem, cacheActual>::Retrieve(string filename, int style,
tc->hit();
return tc; //Everything fine.
}
else{
//Something went wrong.
RemoveItem(tc);
}
//Something went wrong.
RemoveItem(tc);
}
//Record managed failure. Cache failure is recorded in Get().
@@ -1196,113 +1123,62 @@ cacheItem * WCache<cacheItem, cacheActual>::Get(string id, int style, int submod
//Something is managed.
if(it != managed.end()) {
if(!it->second && style == RETRIEVE_RESOURCE)
return NULL; //A miss.
else
return it->second; //A hit.
return it->second; //A hit.
}
//Failed to find managed resource and won't create one. Record a miss.
else if(style == RETRIEVE_RESOURCE){
if(style == RETRIEVE_RESOURCE){
managed[lookup] = NULL;
return NULL;
}
//Not managed, so look in cache.
if(it == managed.end() && style != RETRIEVE_MANAGE && style != RETRIEVE_RESOURCE ){
if(style != RETRIEVE_MANAGE){
it = cache.find(lookup);
//Well, we've found something...
if(it != cache.end()) {
if(!it->second && (submode & CACHE_EXISTING)){
mError = CACHE_ERROR_404;
return NULL; //A miss.
}
else
return it->second; //A hit.
return it->second; //A hit.
}
}
cacheItem * item = NULL;
if(style != RETRIEVE_MANAGE)
item = cache[lookup]; //We don't know about this one yet.
//Found something.
if(item){
//Item went bad?
if(!item->isGood()){
//If we're allowed, attempt to revive it.
if(!(submode & CACHE_EXISTING))
item->Attempt(id,submode,mError);
//Still bad, so remove it and return NULL
if(submode & CACHE_EXISTING || !item->isGood()){
if(!item->isLocked()){
RemoveItem(item); //Delete it.
mError = CACHE_ERROR_BAD;
}
//Worst case scenerio. Hopefully never happens.... hasn't so far.
else{
item->Nullify(); //We're giving up on anything allocated here.
mError = CACHE_ERROR_LOST; //This is a potential memory leak, but might prevent a crash.
}
return NULL;
}
}
//Alright, everythings fine!
mError = CACHE_ERROR_NONE;
return item;
}
//Didn't exist in cache.
if(submode & CACHE_EXISTING ){
RemoveMiss(lookup);
mError = CACHE_ERROR_NOT_CACHED;
return NULL;
}
else{
//Space in cache, make new texture
item = AttemptNew(id,submode);
//Couldn't make GOOD new item.
if(item && !item->isGood())
{
if(garbage.size() < MAX_CACHE_GARBAGE){
item->Trash();
garbage.push_back(item);
}
else
SAFE_DELETE(item);
}
}
//Space in cache, make new texture
cacheItem * item = AttemptNew(id,submode);
if(style == RETRIEVE_MANAGE){
managed[lookup] = item; //Record hit or miss
if(item)
if(item){
managed[lookup] = item; //Record a hit.
item->deadbolt(); //Make permanent.
}
else{
//Record it, hit or miss.
cache[lookup] = item;
}
//Succeeded in making a new item.
if(item){
unsigned long isize = item->size();
totalSize += isize;
mError = CACHE_ERROR_NONE;
if(style != RETRIEVE_MANAGE){
cacheItems++;
cacheSize += isize;
}
return item;
else if(mError == CACHE_ERROR_404)
managed[lookup] = NULL; //File not found. Record a miss
}
else {
if(item || mError == CACHE_ERROR_404)
cache[lookup] = item;
}
//Failure.
return NULL;
if (!item) return NULL; //Failure
//Succeeded in making a new item.
unsigned long isize = item->size();
totalSize += isize;
mError = CACHE_ERROR_NONE;
if(style != RETRIEVE_MANAGE){
cacheItems++;
cacheSize += isize;
}
return item;
}
template <class cacheItem, class cacheActual>
@@ -1327,7 +1203,7 @@ WCache<cacheItem, cacheActual>::WCache(){
cacheSize = 0;
totalSize = 0;
maxCacheSize = SMALL_CACHE_LIMIT;
maxCacheSize = TEXTURES_CACHE_MINSIZE;
maxCached = MAX_CACHE_OBJECTS;
cacheItems = 0;
@@ -1340,24 +1216,13 @@ WCache<cacheItem, cacheActual>::~WCache(){
//Delete from cache & managed
for(it=cache.begin();it!=cache.end();it++){
if(!it->second)
continue;
SAFE_DELETE(it->second);
}
for(it=managed.begin();it!=managed.end();it++){
if(!it->second)
continue;
SAFE_DELETE(it->second);
}
//Clean up all the garbage
typename vector<cacheItem*>::iterator g;
for(g=garbage.begin();g!=garbage.end();g++){
SAFE_DELETE(*g);
}
}
@@ -1462,24 +1327,17 @@ bool WCache<cacheItem, cacheActual>::Delete(cacheItem * item){
if(maxCached == 0)
item->Nullify();
unsigned long isize = item->size();
totalSize -= isize;
cacheSize -= isize;
unsigned long isize = item->size();
totalSize -= isize;
cacheSize -= isize;
#ifdef DEBUG_CACHE
if(cacheItems == 0)
OutputDebugString("cacheItems out of sync.\n");
if(cacheItems == 0)
OutputDebugString("cacheItems out of sync.\n");
#endif
cacheItems--;
cacheItems--;
if(garbage.size() > MAX_CACHE_GARBAGE)
SAFE_DELETE(item);
else{
item->Trash();
item->lastTime = 0;
item->loadedMode = 0;
garbage.push_back(item);
}
SAFE_DELETE(item);
return true;
}