Jeck - Cache fix, booster duplicate fix.
* Restored OptionItem saving fix. * Booster duplicate replacement was picking random cards from the wrong set. My fault, but I've fixed it :) * The problem with cache had nothing to do with memory fragmentation, but I've switched to an array rather than map<> just in case. The actual issue was that in GameStateDeckViewer, I'd given the cache unlimited space, thinking that AttemptNew would recover from any bad_allocs. Unfortunately, the image loading routines and similar stuff called by various implementations of WResource::Attempt() could fail halfway through, leaking memory. The temporary solution is to set a proper limit (8000000 px, more or less) and (in case we still run out of memory) test to make certain CACHE_SPACE_RESERVED can be malloc'd/free'd. The proper solution would be to keep byte-perfect records of memory used (right now we're kinda fuzzy-- we track pixels per image and bytes per sound, but not the space for jquads or other incidentals) instead of testing a malloc, and potentially cleaning up all calls inside of Attempt() so they fail without leaks. That's what I'm working on now. Still, it's nice to have identified the problem. This version of the cache should be fully functional, it's just a bit inelegant.
This commit is contained in:
Binary file not shown.
@@ -21,6 +21,7 @@ public:
|
||||
virtual unsigned long size()=0; //Size of cached item in bytes.
|
||||
virtual bool isGood()=0; //Return true if this has data.
|
||||
virtual bool isLocked(); //Is the resource locked?
|
||||
virtual bool isTrash(); //Is the resource locked?
|
||||
virtual void lock(); //Lock it.
|
||||
virtual void unlock(bool force = false); //Unlock it. Forcing a lock will also remove "permanent" status.
|
||||
|
||||
@@ -29,6 +30,7 @@ public:
|
||||
void hit(); //Update resource's last used time.
|
||||
|
||||
protected:
|
||||
string id; //Our lookup value.
|
||||
int loadedMode; //What submode settings were we loaded with? (For refresh)
|
||||
unsigned int lastTime; //When was the last time we were hit?
|
||||
unsigned char locks; //Remember to unlock when we're done using locked stuff, or else this'll be useless.
|
||||
|
||||
@@ -6,17 +6,21 @@
|
||||
#include "MTGDeck.h"
|
||||
#include "MTGCard.h"
|
||||
#include "WCachedResource.h"
|
||||
#include <list>
|
||||
|
||||
//Soft limits.
|
||||
#define HUGE_CACHE_LIMIT 10000000
|
||||
#define HUGE_CACHE_ITEMS 400
|
||||
//For values higher than ~8000000, we run the danger of hitting our reserved space in deck editor.
|
||||
#define HUGE_CACHE_LIMIT 8000000
|
||||
#define LARGE_CACHE_LIMIT 6000000
|
||||
#define SMALL_CACHE_LIMIT 3000000
|
||||
|
||||
#define LARGE_CACHE_LIMIT 5000000
|
||||
#define LARGE_CACHE_ITEMS 300
|
||||
|
||||
#define SMALL_CACHE_LIMIT 1000000
|
||||
#define SMALL_CACHE_ITEMS 200
|
||||
#define HUGE_CACHE_ITEMS 200
|
||||
#define LARGE_CACHE_ITEMS 150
|
||||
#define SMALL_CACHE_ITEMS 100
|
||||
|
||||
//We keep a certain amount of space reserved for non-cache use.
|
||||
//This value was chosen to guarantee space for image loading.
|
||||
#define CACHE_SPACE_RESERVED (512*512*sizeof(PIXEL_TYPE))
|
||||
|
||||
//Hard Limits.
|
||||
#define MAX_CACHE_OBJECTS HUGE_CACHE_ITEMS
|
||||
@@ -30,6 +34,7 @@ enum ENUM_WRES_INFO{
|
||||
WRES_MAX_LOCK = 250, //Maximum number of locks for a resource.
|
||||
WRES_PERMANENT = 251, //Resource is permanent (ie, managed)
|
||||
WRES_UNDERLOCKED = 252, //Resource was released too many times.
|
||||
WRES_TRASH = 253, //Resource is trash, and can be recycled.
|
||||
};
|
||||
|
||||
enum ENUM_RETRIEVE_STYLE{
|
||||
@@ -60,12 +65,13 @@ enum ENUM_CACHE_SUBTYPE{
|
||||
|
||||
enum ENUM_CACHE_ERROR{
|
||||
CACHE_ERROR_NONE = 0,
|
||||
CACHE_ERROR_NOT_CACHED = CACHE_ERROR_NONE,
|
||||
CACHE_ERROR_404,
|
||||
CACHE_ERROR_BAD, //Something went wrong with item->attempt()
|
||||
CACHE_ERROR_BAD_ALLOC, //Couldn't allocate item
|
||||
CACHE_ERROR_LOST,
|
||||
CACHE_ERROR_NOT_CACHED,
|
||||
CACHE_ERROR_NOT_MANAGED,
|
||||
CACHE_ERROR_404,
|
||||
CACHE_ERROR_BAD, //Something went wrong with item->attempt()
|
||||
CACHE_ERROR_BAD_ALLOC, //Couldn't allocate item
|
||||
CACHE_ERROR_FULL, //Cache is at maxCached.
|
||||
CACHE_ERROR_LOST,
|
||||
};
|
||||
|
||||
template <class cacheItem, class cacheActual>
|
||||
@@ -89,19 +95,21 @@ public:
|
||||
void Resize(unsigned long size, int items); //Sets new limits, then enforces them. Lock safe, so not a "hard limit".
|
||||
|
||||
protected:
|
||||
bool RemoveItem(cacheItem * item, bool force = true); //Removes an item, deleting it. if(force), ignores locks / permanent
|
||||
bool UnlinkCache(cacheItem * item); //Removes an item from our cache, does not delete it. Use with care.
|
||||
bool Delete(cacheItem * item); //SAFE_DELETE and garbage collect. If maxCached == 0, nullify first. (This means you have to free that cacheActual later!)
|
||||
cacheItem* Get(string id, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); //Subordinate to Retrieve.
|
||||
cacheItem* AttemptNew(string filename, int submode); //Attempts a new cache item, progressively clearing cache if it fails.
|
||||
cacheItem* Recycle(); //Returns a cache item from the trash.
|
||||
bool RemoveItem(cacheItem* item, bool force = true); //Removes an item, deleting it. if(force), ignores locks / permanent
|
||||
bool Delete(cacheItem* item); //Garbage collect. If maxCached == 0, nullify first. (This means you have to free that cacheActual later!)
|
||||
|
||||
bool AttemptNew(cacheItem* item, int submode); //Attempts to load item, progressively clearing mCache if it fails.
|
||||
cacheItem* Get(string id, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); //Subordinate to Retrieve. Guarenteed isGood().
|
||||
cacheItem* Recycle(); //Returns a cache item from the trash, or (worst possible case) pops a new one onto mCache.
|
||||
|
||||
void RecordMiss(string miss);
|
||||
|
||||
string makeID(string filename, int submode); //Makes an ID appropriate to the submode.
|
||||
string makeFilename(string id, int submode); //Makes a filename from an ID.
|
||||
|
||||
map<string,cacheItem*> cache;
|
||||
map<string,cacheItem*> managed; //Cache can be arbitrarily large, so managed items are seperate.
|
||||
vector<cacheItem*> garbage; //Garbage collection.
|
||||
cacheItem mCached[MAX_CACHE_OBJECTS];
|
||||
list<cacheItem> mManaged; //Cache and managed items are seperate to improve performance.
|
||||
list<string> mMisses;
|
||||
unsigned long totalSize;
|
||||
unsigned long cacheSize;
|
||||
|
||||
@@ -138,6 +146,8 @@ public:
|
||||
JQuad * RetrieveTempQuad(string filename);
|
||||
hgeParticleSystemInfo * RetrievePSI(string filename, JQuad * texture, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL);
|
||||
|
||||
int RetrieveError(); //Returns the error from the last call to ANY retrieve function.
|
||||
|
||||
void Release(JTexture * tex);
|
||||
void Release(JQuad * quad);
|
||||
void Release(JSample * sample);
|
||||
@@ -202,6 +212,7 @@ private:
|
||||
|
||||
//Statistics of record.
|
||||
unsigned int lastTime;
|
||||
int lastError;
|
||||
};
|
||||
|
||||
extern WResourceManager resources;
|
||||
|
||||
@@ -548,8 +548,12 @@ void GameStateDeckViewer::renderCard(int id, float rotation){
|
||||
JQuad * quad = NULL;
|
||||
|
||||
int showName = 0;
|
||||
#ifdef DEBUG_CACHE
|
||||
quad = resources.RetrieveCard(card,RETRIEVE_NORMAL);
|
||||
#else
|
||||
quad = resources.RetrieveCard(card,RETRIEVE_EXISTING);
|
||||
if (!quad){
|
||||
#endif
|
||||
if (!quad && resources.RetrieveError() != CACHE_ERROR_404){
|
||||
if(last_user_activity > (abs(2-id) + 1)* NO_USER_ACTIVITY_SHOWCARD_DELAY)
|
||||
quad = resources.RetrieveCard(card);
|
||||
else{
|
||||
|
||||
@@ -526,7 +526,6 @@ void OptionsList::save(){
|
||||
for (int i = 0; i < nbitems; i++){
|
||||
listItems[i]->setData();
|
||||
}
|
||||
::options.save();
|
||||
}
|
||||
|
||||
void OptionsList::Update(float dt){
|
||||
@@ -652,6 +651,8 @@ void OptionsMenu::save(){
|
||||
for(int x=0;x<MAX_OPTION_TABS;x++)
|
||||
if(tabs[x] != NULL)
|
||||
tabs[x]->save();
|
||||
|
||||
::options.save();
|
||||
}
|
||||
|
||||
bool OptionsMenu::isTab(string name){
|
||||
|
||||
@@ -384,7 +384,7 @@ void ShopItems::ButtonPressed(int controllerId, int controlId){
|
||||
tempDeck->remove(it->first);
|
||||
|
||||
int rarity = (int) tempDeck->database->getCardById(it->first)->getRarity();
|
||||
tempDeck->addRandomCards(dupes,&rarity);
|
||||
tempDeck->addRandomCards(dupes,sets,1,rarity);
|
||||
it = tempDeck->cards.begin();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,13 +16,16 @@ WResource::~WResource(){
|
||||
return;
|
||||
}
|
||||
WResource::WResource(){
|
||||
locks = WRES_UNLOCKED;
|
||||
locks = WRES_TRASH;
|
||||
lastTime = resources.nowTime();
|
||||
loadedMode = 0;
|
||||
}
|
||||
|
||||
bool WResource::isLocked(){
|
||||
return (locks != WRES_UNLOCKED);
|
||||
return (locks != WRES_UNLOCKED && locks != WRES_TRASH);
|
||||
}
|
||||
bool WResource::isTrash(){
|
||||
return (locks == WRES_TRASH);
|
||||
}
|
||||
|
||||
bool WResource::isPermanent(){
|
||||
@@ -171,8 +174,10 @@ WTrackedQuad * WCachedTexture::GetTrackedQuad(float offX, float offY, float widt
|
||||
tq = *gtq;
|
||||
garbageTQs.erase(gtq);
|
||||
}
|
||||
else
|
||||
else{
|
||||
tq = NEW WTrackedQuad(resname);
|
||||
tq->unlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(tq == NULL)
|
||||
@@ -244,6 +249,9 @@ unsigned long WCachedTexture::size(){
|
||||
}
|
||||
|
||||
bool WCachedTexture::isGood(){
|
||||
if(locks == WRES_TRASH)
|
||||
return false;
|
||||
|
||||
if(!texture)
|
||||
return false;
|
||||
|
||||
@@ -321,6 +329,9 @@ bool WCachedTexture::Attempt(string filename, int submode, int & error){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(locks == WRES_TRASH)
|
||||
locks = WRES_UNLOCKED;
|
||||
|
||||
error = CACHE_ERROR_NONE;
|
||||
return true;
|
||||
}
|
||||
@@ -330,6 +341,11 @@ void WCachedTexture::Nullify(){
|
||||
texture = NULL;
|
||||
}
|
||||
void WCachedTexture::Trash(){
|
||||
id = "";
|
||||
locks = WRES_TRASH;
|
||||
#ifdef DEBUG_CACHE
|
||||
OutputDebugString("WCachedTexture::Trash()\n");
|
||||
#endif
|
||||
SAFE_DELETE(texture);
|
||||
|
||||
vector<WTrackedQuad*>::iterator it;
|
||||
@@ -355,6 +371,11 @@ void WCachedSample::Nullify(){
|
||||
}
|
||||
|
||||
void WCachedSample::Trash(){
|
||||
id = "";
|
||||
locks = WRES_TRASH;
|
||||
#ifdef DEBUG_CACHE
|
||||
OutputDebugString("WCachedSample::Trash()\n");
|
||||
#endif
|
||||
SAFE_DELETE(sample);
|
||||
}
|
||||
|
||||
@@ -388,6 +409,9 @@ unsigned long WCachedSample::size(){
|
||||
}
|
||||
|
||||
bool WCachedSample::isGood(){
|
||||
if(locks == WRES_TRASH)
|
||||
return false;
|
||||
|
||||
if(!sample || !sample->mSample)
|
||||
return false;
|
||||
|
||||
@@ -412,12 +436,18 @@ bool WCachedSample::Attempt(string filename, int submode, int & error){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(locks == WRES_TRASH)
|
||||
locks = WRES_UNLOCKED;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//WCachedParticles
|
||||
|
||||
bool WCachedParticles::isGood(){
|
||||
if(locks == WRES_TRASH)
|
||||
return false;
|
||||
|
||||
if(!particles)
|
||||
return false;
|
||||
return true;
|
||||
@@ -463,6 +493,10 @@ bool WCachedParticles::Attempt(string filename, int submode, int & error){
|
||||
|
||||
particles->sprite=NULL;
|
||||
error = CACHE_ERROR_NONE;
|
||||
|
||||
if(locks == WRES_TRASH)
|
||||
locks = WRES_UNLOCKED;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -489,6 +523,11 @@ void WCachedParticles::Nullify(){
|
||||
}
|
||||
|
||||
void WCachedParticles::Trash(){
|
||||
id = "";
|
||||
locks = WRES_TRASH;
|
||||
#ifdef DEBUG_CACHE
|
||||
OutputDebugString("WCachedParticles::Trash()\n");
|
||||
#endif
|
||||
SAFE_DELETE(particles);
|
||||
}
|
||||
|
||||
@@ -498,6 +537,11 @@ void WTrackedQuad::Nullify() {
|
||||
}
|
||||
|
||||
void WTrackedQuad::Trash(){
|
||||
id = "";
|
||||
locks = WRES_TRASH;
|
||||
#ifdef DEBUG_CACHE
|
||||
OutputDebugString("WTrackedQuad::Trash()\n");
|
||||
#endif
|
||||
resname.clear();
|
||||
SAFE_DELETE(quad);
|
||||
}
|
||||
@@ -510,6 +554,9 @@ unsigned long WTrackedQuad::size() {
|
||||
return sizeof(JQuad);
|
||||
}
|
||||
bool WTrackedQuad::isGood(){
|
||||
if(locks == WRES_TRASH)
|
||||
return false;
|
||||
|
||||
return (quad != NULL);
|
||||
}
|
||||
WTrackedQuad::WTrackedQuad(string _resname) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user