diff options
author | sylvaintv | 2011-03-05 23:01:25 +0100 |
---|---|---|
committer | sylvaintv | 2011-03-05 23:01:25 +0100 |
commit | 6873e9673213516539acca37c08b1d6c0bfaa350 (patch) | |
tree | a394cae9a24abfa538b209387020b8491c4beef8 | |
parent | d2dd614996452f653d8a2710b55b9b3799350688 (diff) | |
download | scummvm-rg350-6873e9673213516539acca37c08b1d6c0bfaa350.tar.gz scummvm-rg350-6873e9673213516539acca37c08b1d6c0bfaa350.tar.bz2 scummvm-rg350-6873e9673213516539acca37c08b1d6c0bfaa350.zip |
TOON: Integrated resource cache patch by eriktorbjorn
Reduced global memory usage of the game
Global PAK files are not loaded entirely anymore
-rw-r--r-- | engines/toon/resource.cpp | 154 | ||||
-rw-r--r-- | engines/toon/resource.h | 29 |
2 files changed, 134 insertions, 49 deletions
diff --git a/engines/toon/resource.cpp b/engines/toon/resource.cpp index 61e3ffb111..d635c5ab79 100644 --- a/engines/toon/resource.cpp +++ b/engines/toon/resource.cpp @@ -32,10 +32,18 @@ namespace Toon { -Resources::Resources(ToonEngine *vm) : _vm(vm) { +Resources::Resources(ToonEngine *vm) : _vm(vm), _cacheSize(0) { + _resourceCache.clear(); } Resources::~Resources() { + + while (!_resourceCache.empty()) { + CacheEntry *temp = _resourceCache.back(); + _resourceCache.pop_back(); + delete temp; + } + while(!_pakFiles.empty()) { PakFile *temp = _pakFiles.back(); _pakFiles.pop_back(); @@ -45,8 +53,73 @@ Resources::~Resources() { purgeFileData(); } -void Resources::openPackage(Common::String fileName, bool preloadEntirePackage) { - debugC(1, kDebugResource, "openPackage(%s, %d)", fileName.c_str(), (preloadEntirePackage) ? 1 : 0); +void Resources::removePackageFromCache(Common::String packName) { + // I'm not sure what's a good strategy here. It seems unnecessary to + // actually remove the cached resources, because the player may be + // wandering back and forth between rooms. So for now, do nothing. +} + +bool Resources::getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData) { + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if ((*entry)->_data && (*entry)->_fileName.compareToIgnoreCase(fileName) == 0) { + debugC(5, kDebugResource, "getFromCache(%s) - Got %d bytes from %s", fileName.c_str(), (*entry)->_size, (*entry)->_packName.c_str()); + (*entry)->_age = 0; + *fileSize = (*entry)->_size; + *fileData = (*entry)->_data; + return true; + } + } + return false; +} + +void Resources::addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData) { + debugC(5, kDebugResource, "addToCache(%s, %s, %d) - Total Size: %d", packName.c_str(), fileName.c_str(), fileSize, _cacheSize + fileSize); + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if ((*entry)->_data) { + (*entry)->_age++; + } + } + _cacheSize += fileSize; + + while (_cacheSize > MAX_CACHE_SIZE) { + CacheEntry *bestEntry = 0; + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if ((*entry)->_data) { + if (!bestEntry || ((*entry)->_age >= bestEntry->_age && (*entry)->_size >= bestEntry->_size)) { + bestEntry = *entry; + } + } + } + if (!bestEntry) + break; + + free(bestEntry->_data); + bestEntry->_data = 0; + _cacheSize -= bestEntry->_size; + debugC(5, kDebugResource, "Freed %s (%s) to reclaim %d bytes", bestEntry->_fileName.c_str(), bestEntry->_packName.c_str(), bestEntry->_size); + } + + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if (!(*entry)->_data) { + (*entry)->_packName = packName; + (*entry)->_fileName = fileName; + (*entry)->_age = 0; + (*entry)->_size = fileSize; + (*entry)->_data = fileData; + return; + } + } + + CacheEntry *entry = new CacheEntry(); + entry->_packName = packName; + entry->_fileName = fileName; + entry->_size = fileSize; + entry->_data = fileData; + _resourceCache.push_back(entry); +} + +void Resources::openPackage(Common::String fileName) { + debugC(1, kDebugResource, "openPackage(%s)", fileName.c_str()); Common::File file; bool opened = file.open(fileName); @@ -55,15 +128,16 @@ void Resources::openPackage(Common::String fileName, bool preloadEntirePackage) return; PakFile *pakFile = new PakFile(); - pakFile->open(&file, fileName, preloadEntirePackage); + pakFile->open(&file, fileName); - if (preloadEntirePackage) - file.close(); + file.close(); _pakFiles.push_back(pakFile); } void Resources::closePackage(Common::String fileName) { + + removePackageFromCache(fileName); for (uint32 i = 0; i < _pakFiles.size(); i++) { if (_pakFiles[i]->getPackName() == fileName) { delete _pakFiles[i]; @@ -91,13 +165,21 @@ uint8 *Resources::getFileData(Common::String fileName, uint32 *fileSize) { _allocatedFileData.push_back(memory); return memory; } else { - for (uint32 i = 0; i < _pakFiles.size(); i++) { - uint32 locFileSize = 0; - uint8 *locFileData = 0; + uint32 locFileSize = 0; + uint8 *locFileData = 0; + + if (getFromCache(fileName, &locFileSize, &locFileData)) { + *fileSize = locFileSize; + return locFileData; + } + + for (uint32 i = 0; i < _pakFiles.size(); i++) { + locFileData = _pakFiles[i]->getFileData(fileName, &locFileSize); if (locFileData) { *fileSize = locFileSize; + addToCache(_pakFiles[i]->getPackName(), fileName, locFileSize, locFileData); return locFileData; } } @@ -139,22 +221,12 @@ void Resources::purgeFileData() { Common::SeekableReadStream *PakFile::createReadStream(Common::String fileName) { debugC(1, kDebugResource, "createReadStream(%s)", fileName.c_str()); - int32 offset = 0; - int32 size = 0; - for (uint32 i = 0; i < _numFiles; i++) { - if (fileName.compareToIgnoreCase(_files[i]._name) == 0) { - size = _files[i]._size; - offset = _files[i]._offset; - break; - } - } - if (!size) - return 0; - - if (_fileHandle) - return new Common::SeekableSubReadStream(_fileHandle, offset, offset + size); + uint32 fileSize = 0; + uint8 *buffer = getFileData(fileName, &fileSize); + if (buffer) + return new Common::MemoryReadStream(buffer, fileSize, DisposeAfterUse::YES); else - return new Common::MemoryReadStream(_buffer + offset, size); + return 0; } uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) { @@ -162,16 +234,26 @@ uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) { for (uint32 i = 0; i < _numFiles; i++) { if (fileName.compareToIgnoreCase(_files[i]._name) == 0) { - *fileSize = _files[i]._size; - return _buffer + _files[i]._offset; + Common::File file; + if (file.open(_packName)) { + *fileSize = _files[i]._size; + file.seek(_files[i]._offset); + + // Use malloc() because that's what MemoryReadStream + // uses to dispose of the memory when it's done. + uint8 *buffer = (uint8 *)malloc(*fileSize); + file.read(buffer, *fileSize); + file.close(); + return buffer; + } } } return 0; } -void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage) { - debugC(1, kDebugResource, "open(rs, %d)", (preloadEntirePackage) ? 1 : 0); +void PakFile::open(Common::SeekableReadStream *rs, Common::String packName) { + debugC(1, kDebugResource, "open(rs)"); char buffer[64]; int32 currentPos = 0; @@ -199,30 +281,14 @@ void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool _numFiles++; _files.push_back(newFile); } - - if (preloadEntirePackage) { - _bufferSize = rs->size(); - delete[] _buffer; - _buffer = new uint8[_bufferSize]; - rs->seek(0); - rs->read(_buffer, _bufferSize); - } } void PakFile::close() { - delete[] _buffer; - if (_fileHandle) { - _fileHandle->close(); - delete _fileHandle; - } } PakFile::PakFile() { - _bufferSize = 0; - _buffer = NULL; - _fileHandle = NULL; } PakFile::~PakFile() { diff --git a/engines/toon/resource.h b/engines/toon/resource.h index e117c8e259..d6ed29b81b 100644 --- a/engines/toon/resource.h +++ b/engines/toon/resource.h @@ -31,6 +31,8 @@ #include "common/file.h" #include "common/stream.h" +#define MAX_CACHE_SIZE (4 * 1024 * 1024) + namespace Toon { class PakFile { @@ -38,7 +40,7 @@ public: PakFile(); ~PakFile(); - void open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage); + void open(Common::SeekableReadStream *rs, Common::String packName); uint8 *getFileData(Common::String fileName, uint32 *fileSize); Common::String getPackName() { return _packName; } Common::SeekableReadStream *createReadStream(Common::String fileName); @@ -52,9 +54,6 @@ protected: }; Common::String _packName; - uint8 *_buffer; - int32 _bufferSize; - uint32 _numFiles; Common::Array<File> _files; Common::File *_fileHandle; @@ -62,11 +61,25 @@ protected: class ToonEngine; +class CacheEntry { +public: + CacheEntry() : _age(0), _size(0), _data(0) {} + ~CacheEntry() { + free(_data); + } + + Common::String _packName; + Common::String _fileName; + uint32 _age; + uint32 _size; + uint8 *_data; +}; + class Resources { public: Resources(ToonEngine *vm); ~Resources(); - void openPackage(Common::String file, bool preloadEntirePackage); + void openPackage(Common::String file); void closePackage(Common::String fileName); Common::SeekableReadStream *openFile(Common::String file); uint8 *getFileData(Common::String fileName, uint32 *fileSize); // this memory must be copied to your own structures! @@ -76,6 +89,12 @@ protected: ToonEngine *_vm; Common::Array<uint8 *> _allocatedFileData; Common::Array<PakFile *> _pakFiles; + uint32 _cacheSize; + Common::Array<CacheEntry *> _resourceCache; + + void removePackageFromCache(Common::String packName); + bool getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData); + void addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData); }; } // End of namespace Toon |