216 lines
5.5 KiB
C++
216 lines
5.5 KiB
C++
#ifndef _CACHE_ENGINE_H_
|
|
#define _CACHE_ENGINE_H_
|
|
|
|
#include "PrecompiledHeader.h"
|
|
|
|
#include "Threading.h"
|
|
#include <queue>
|
|
#include <set>
|
|
|
|
|
|
struct CacheRequest
|
|
{
|
|
CacheRequest()
|
|
{
|
|
}
|
|
|
|
CacheRequest(std::string inFilename, int inSubmode, int inCacheID)
|
|
: filename(inFilename), submode(inSubmode), cacheID(inCacheID)
|
|
{
|
|
}
|
|
|
|
std::string filename;
|
|
int submode;
|
|
int cacheID;
|
|
};
|
|
|
|
const boost::posix_time::milliseconds kIdleTime(100);
|
|
|
|
|
|
class CardRetrieverBase
|
|
{
|
|
public:
|
|
|
|
CardRetrieverBase(WCache<WCachedTexture,JTexture>& inCache)
|
|
: mTextureCache(inCache)
|
|
{
|
|
}
|
|
|
|
virtual ~CardRetrieverBase()
|
|
{
|
|
}
|
|
|
|
virtual void QueueRequest(const std::string& inFilePath, int inSubmode, int inCacheID) = 0;
|
|
|
|
protected:
|
|
|
|
WCache<WCachedTexture,JTexture>& mTextureCache;
|
|
};
|
|
|
|
/*
|
|
**
|
|
*/
|
|
class UnthreadedCardRetriever : public CardRetrieverBase
|
|
{
|
|
public:
|
|
|
|
UnthreadedCardRetriever(WCache<WCachedTexture,JTexture>& inCache)
|
|
: CardRetrieverBase(inCache)
|
|
{
|
|
DebugTrace("Unthreaded version");
|
|
}
|
|
|
|
virtual ~UnthreadedCardRetriever()
|
|
{
|
|
}
|
|
|
|
/*
|
|
** In a non-threaded model, simply pass on the request to the texture cache directly
|
|
*/
|
|
void QueueRequest(const std::string& inFilePath, int inSubmode, int inCacheID)
|
|
{
|
|
mTextureCache.LoadIntoCache(inCacheID, inFilePath, inSubmode);
|
|
}
|
|
};
|
|
|
|
/**
|
|
** Threaded implementation.
|
|
*/
|
|
class ThreadedCardRetriever : public CardRetrieverBase
|
|
{
|
|
public:
|
|
|
|
ThreadedCardRetriever(WCache<WCachedTexture,JTexture>& inCache)
|
|
: CardRetrieverBase(inCache), mProcessing(true)
|
|
{
|
|
DebugTrace("Threaded Version");
|
|
mWorkerThread = boost::thread(ThreadProc, this);
|
|
}
|
|
|
|
virtual ~ThreadedCardRetriever()
|
|
{
|
|
LOG("Tearing down ThreadedCardRetriever");
|
|
mProcessing = false;
|
|
mWorkerThread.join();
|
|
}
|
|
|
|
void QueueRequest(const std::string& inFilePath, int inSubmode, int inCacheID)
|
|
{
|
|
boost::mutex::scoped_lock lock(mMutex);
|
|
// mRequestLookup is used to prevent duplicate requests for the same id
|
|
if (mRequestLookup.find(inCacheID) == mRequestLookup.end() && mTextureCache.cache.find(inCacheID) == mTextureCache.cache.end())
|
|
{
|
|
#ifdef DOLOG
|
|
std::ostringstream stream;
|
|
stream << "Queueing request: " << inFilePath;
|
|
LOG(stream.str().c_str());
|
|
#endif
|
|
mRequestLookup.insert(inCacheID);
|
|
mRequestQueue.push(CacheRequest(inFilePath, inSubmode, inCacheID));
|
|
|
|
// capping the number of queued decodes to 7, as this is
|
|
// the maximum # of cards we display concurrently in the deck editor.
|
|
if (mRequestQueue.size() > 7)
|
|
{
|
|
int cacheIDToRemove;
|
|
while (mRequestQueue.size() > 7)
|
|
{
|
|
// pop the older requests out of the queue
|
|
cacheIDToRemove = mRequestQueue.front().cacheID;
|
|
mRequestQueue.pop();
|
|
mRequestLookup.erase(cacheIDToRemove);
|
|
|
|
assert(mRequestLookup.size() - mRequestQueue.size() < 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected:
|
|
ThreadedCardRetriever();
|
|
|
|
static void ThreadProc(void* inParam)
|
|
{
|
|
LOG("Entering ThreadedCardRetriever::ThreadProc");
|
|
ThreadedCardRetriever* instance = reinterpret_cast<ThreadedCardRetriever*>(inParam);
|
|
if (instance)
|
|
{
|
|
while (instance->mProcessing)
|
|
{
|
|
while (!instance->mRequestQueue.empty())
|
|
{
|
|
CacheRequest request;
|
|
{
|
|
boost::mutex::scoped_lock lock(instance->mMutex);
|
|
request = instance->mRequestQueue.front();
|
|
instance->mRequestQueue.pop();
|
|
}
|
|
|
|
instance->mTextureCache.LoadIntoCache(request.cacheID, request.filename, request.submode);
|
|
|
|
{
|
|
boost::mutex::scoped_lock lock(instance->mMutex);
|
|
instance->mRequestLookup.erase(request.cacheID);
|
|
}
|
|
|
|
// not sure this is necessary, adding it to potentially prevent SIGHUP on the psp
|
|
// rumour has it that if a worker thread doesn't allow the main thread a chance to run, it can hang the unit
|
|
#ifdef PSP
|
|
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
|
|
#endif
|
|
}
|
|
|
|
boost::this_thread::sleep(kIdleTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
boost::thread mWorkerThread;
|
|
|
|
std::queue<CacheRequest> mRequestQueue;
|
|
std::set<int> mRequestLookup;
|
|
boost::mutex mMutex;
|
|
volatile bool mProcessing;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CacheEngine
|
|
{
|
|
public:
|
|
template <class T>
|
|
static void Create(WCache<WCachedTexture,JTexture>& inCache)
|
|
{
|
|
LOG("Creating Card Retriever instance");
|
|
sInstance = NEW T(inCache);
|
|
ThreadedCardRetriever* test = dynamic_cast<ThreadedCardRetriever*>(sInstance);
|
|
sIsThreaded = (test != NULL);
|
|
}
|
|
|
|
static CardRetrieverBase* Instance()
|
|
{
|
|
return sInstance;
|
|
}
|
|
|
|
static void Terminate()
|
|
{
|
|
SAFE_DELETE(sInstance);
|
|
}
|
|
|
|
static bool IsThreaded()
|
|
{
|
|
return sIsThreaded;
|
|
}
|
|
|
|
|
|
static CardRetrieverBase* sInstance;
|
|
static bool sIsThreaded;
|
|
};
|
|
|
|
CardRetrieverBase* CacheEngine::sInstance = NULL;
|
|
bool CacheEngine::sIsThreaded = false;
|
|
|
|
#endif //_CACHE_ENGINE_H_
|