Ticket #9284: toon-resourcecache.diff

File toon-resourcecache.diff, 10.1 KB (added by eriktorbjorn, 13 years ago)

Patch against current Git trunk

  • engines/toon/resource.cpp

    diff --git a/engines/toon/resource.cpp b/engines/toon/resource.cpp
    index 61e3ffb..0e21ebf 100644
    a b  
    3232
    3333namespace Toon {
    3434
    35 Resources::Resources(ToonEngine *vm) : _vm(vm) {
     35Resources::Resources(ToonEngine *vm) : _vm(vm), _cacheSize(0) {
     36        _resourceCache.clear();
    3637}
    3738
    3839Resources::~Resources() {
     40        while (!_resourceCache.empty()) {
     41                CacheEntry *temp = _resourceCache.back();
     42                _resourceCache.pop_back();
     43                delete temp;
     44        }
     45
    3946        while(!_pakFiles.empty()) {
    4047                PakFile *temp = _pakFiles.back();
    4148                _pakFiles.pop_back();
    Resources::~Resources() {  
    4552        purgeFileData();
    4653}
    4754
    48 void Resources::openPackage(Common::String fileName, bool preloadEntirePackage) {
    49         debugC(1, kDebugResource, "openPackage(%s, %d)", fileName.c_str(), (preloadEntirePackage) ? 1 : 0);
     55void Resources::removePackageFromCache(Common::String packName) {
     56        // I'm not sure what's a good strategy here. It seems unnecessary to
     57        // actually remove the cached resources, because the player may be
     58        // wandering back and forth between rooms. So for now, do nothing.
     59}
     60
     61bool Resources::getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData) {
     62        for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
     63                if ((*entry)->_fileName.compareToIgnoreCase(fileName) == 0) {
     64                        debugC(5, kDebugResource, "getFromCache(%s) - Got %d bytes from %s", fileName.c_str(), (*entry)->_size, (*entry)->_packName.c_str());
     65                        (*entry)->_age = 0;
     66                        *fileSize = (*entry)->_size;
     67                        *fileData = (*entry)->_data;
     68                        return true;
     69                }
     70        }
     71        return false;
     72}
     73
     74void Resources::addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData) {
     75        debugC(5, kDebugResource, "addToCache(%s, %s, %d) - Total Size: %d", packName.c_str(), fileName.c_str(), fileSize, _cacheSize + fileSize);
     76
     77        for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
     78                if ((*entry)->_data) {
     79                        (*entry)->_age++;
     80                }
     81        }
     82
     83        _cacheSize += fileSize;
     84
     85        while (_cacheSize > MAX_CACHE_SIZE) {
     86                CacheEntry *bestEntry = 0;
     87                for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
     88                        if ((*entry)->_data) {
     89                                if (!bestEntry || ((*entry)->_age >= bestEntry->_age && (*entry)->_size >= bestEntry->_size)) {
     90                                        bestEntry = *entry;
     91                                }
     92                        }
     93                }
     94                if (!bestEntry)
     95                        break;
     96                free(bestEntry->_data);
     97                bestEntry->_data = 0;
     98                _cacheSize -= bestEntry->_size;
     99                debugC(5, kDebugResource, "Freed %s (%s) to reclaim %d bytes", bestEntry->_fileName.c_str(), bestEntry->_packName.c_str(), bestEntry->_size);
     100        }
     101
     102        for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
     103                if (!(*entry)->_data) {
     104                        (*entry)->_packName = packName;
     105                        (*entry)->_fileName = fileName;
     106                        (*entry)->_age = 0;
     107                        (*entry)->_size = fileSize;
     108                        (*entry)->_data = fileData;
     109                        return;
     110                }
     111        }
     112
     113        CacheEntry *entry = new CacheEntry();
     114        entry->_packName = packName;
     115        entry->_fileName = fileName;
     116        entry->_size = fileSize;
     117        entry->_data = fileData;
     118        _resourceCache.push_back(entry);
     119}
     120
     121void Resources::openPackage(Common::String fileName) {
     122        debugC(1, kDebugResource, "openPackage(%s)", fileName.c_str());
    50123
    51124        Common::File file;
    52125        bool opened = file.open(fileName);
    void Resources::openPackage(Common::String fileName, bool preloadEntirePackage)  
    55128                return;
    56129
    57130        PakFile *pakFile = new PakFile();
    58         pakFile->open(&file, fileName, preloadEntirePackage);
    59 
    60         if (preloadEntirePackage)
    61                 file.close();
     131        pakFile->open(&file, fileName);
    62132
     133        file.close();
    63134        _pakFiles.push_back(pakFile);
    64135}
    65136
    66137void Resources::closePackage(Common::String fileName) {
     138        removePackageFromCache(fileName);
    67139        for (uint32 i = 0; i < _pakFiles.size(); i++) {
    68140                if (_pakFiles[i]->getPackName() == fileName) {
    69141                        delete _pakFiles[i];
    uint8 *Resources::getFileData(Common::String fileName, uint32 *fileSize) {  
    91163                _allocatedFileData.push_back(memory);
    92164                return memory;
    93165        } else {
    94                 for (uint32 i = 0; i < _pakFiles.size(); i++) {
    95                         uint32 locFileSize = 0;
    96                         uint8 *locFileData = 0;
     166                uint32 locFileSize = 0;
     167                uint8 *locFileData = 0;
    97168
     169                if (getFromCache(fileName, &locFileSize, &locFileData)) {
     170                        *fileSize = locFileSize;
     171                        return locFileData;
     172                }
     173
     174                for (uint32 i = 0; i < _pakFiles.size(); i++) {
    98175                        locFileData = _pakFiles[i]->getFileData(fileName, &locFileSize);
    99176                        if (locFileData) {
    100177                                *fileSize = locFileSize;
     178                                addToCache(_pakFiles[i]->getPackName(), fileName, locFileSize, locFileData);
    101179                                return locFileData;
    102180                        }
    103181                }
    void Resources::purgeFileData() {  
    136214        }
    137215        _allocatedFileData.clear();
    138216}
     217
    139218Common::SeekableReadStream *PakFile::createReadStream(Common::String fileName) {
    140219        debugC(1, kDebugResource, "createReadStream(%s)", fileName.c_str());
    141220
    142         int32 offset = 0;
    143         int32 size = 0;
    144         for (uint32 i = 0; i < _numFiles; i++) {
    145                 if (fileName.compareToIgnoreCase(_files[i]._name) == 0) {
    146                         size = _files[i]._size;
    147                         offset = _files[i]._offset;
    148                         break;
    149                 }
    150         }
    151         if (!size)
    152                 return 0;
     221        uint32 fileSize = 0;
     222        uint8 *buffer = getFileData(fileName, &fileSize);
    153223
    154         if (_fileHandle)
    155                 return new Common::SeekableSubReadStream(_fileHandle, offset, offset + size);
     224        if (buffer)
     225                return new Common::MemoryReadStream(buffer, fileSize, DisposeAfterUse::YES);
    156226        else
    157                 return new Common::MemoryReadStream(_buffer + offset, size);
     227                return 0;
    158228}
    159229
    160230uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) {
    uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) {  
    162232
    163233        for (uint32 i = 0; i < _numFiles; i++) {
    164234                if (fileName.compareToIgnoreCase(_files[i]._name) == 0) {
    165                         *fileSize = _files[i]._size;
    166                         return _buffer + _files[i]._offset;
     235                        Common::File file;
     236
     237                        if (file.open(_packName)) {
     238                                *fileSize = _files[i]._size;
     239                                file.seek(_files[i]._offset);
     240
     241                                // Use malloc() because that's what MemoryReadStream
     242                                // uses to dispose of the memory when it's done.
     243                                uint8 *buffer = (uint8 *)malloc(*fileSize);
     244                                file.read(buffer, *fileSize);
     245                                file.close();
     246                                return buffer;
     247                        }
    167248                }
    168249        }
    169250
    170251        return 0;
    171252}
    172253
    173 void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage) {
    174         debugC(1, kDebugResource, "open(rs, %d)", (preloadEntirePackage) ? 1 : 0);
     254void PakFile::open(Common::SeekableReadStream *rs, Common::String packName) {
     255        debugC(1, kDebugResource, "open(rs)");
    175256
    176257        char buffer[64];
    177258        int32 currentPos = 0;
    void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool  
    199280                _numFiles++;
    200281                _files.push_back(newFile);
    201282        }
    202 
    203         if (preloadEntirePackage) {
    204                 _bufferSize = rs->size();
    205                 delete[] _buffer;
    206                 _buffer = new uint8[_bufferSize];
    207                 rs->seek(0);
    208                 rs->read(_buffer, _bufferSize);
    209         }
    210283}
    211284
    212285void PakFile::close() {
    213         delete[] _buffer;
    214 
    215         if (_fileHandle) {
    216                 _fileHandle->close();
    217                 delete _fileHandle;
    218         }
    219286}
    220287
    221288PakFile::PakFile() {
    222         _bufferSize = 0;
    223         _buffer = NULL;
    224 
    225         _fileHandle = NULL;
    226289}
    227290
    228291PakFile::~PakFile() {
  • engines/toon/resource.h

    diff --git a/engines/toon/resource.h b/engines/toon/resource.h
    index e117c8e..590dfcd 100644
    a b  
    3131#include "common/file.h"
    3232#include "common/stream.h"
    3333
     34#define MAX_CACHE_SIZE  (2 * 1024 * 1024)
     35
    3436namespace Toon {
    3537
    3638class PakFile {
    public:  
    3840        PakFile();
    3941        ~PakFile();
    4042
    41         void open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage);
     43        void open(Common::SeekableReadStream *rs, Common::String packName);
    4244        uint8 *getFileData(Common::String fileName, uint32 *fileSize);
    4345        Common::String getPackName() { return _packName; }
    4446        Common::SeekableReadStream *createReadStream(Common::String fileName);
    protected:  
    5254        };
    5355        Common::String _packName;
    5456
    55         uint8 *_buffer;
    56         int32 _bufferSize;
    57 
    5857        uint32 _numFiles;
    5958        Common::Array<File> _files;
    6059        Common::File *_fileHandle;
    protected:  
    6261
    6362class ToonEngine;
    6463
     64class CacheEntry {
     65public:
     66        CacheEntry() : _age(0), _size(0), _data(0) {}
     67        ~CacheEntry() {
     68                free(_data);
     69        }
     70
     71        Common::String _packName;
     72        Common::String _fileName;
     73        uint32 _age;
     74        uint32 _size;
     75        uint8 *_data;
     76};
     77
    6578class Resources {
    6679public:
    6780        Resources(ToonEngine *vm);
    6881        ~Resources();
    69         void openPackage(Common::String file, bool preloadEntirePackage);
     82        void openPackage(Common::String file);
    7083        void closePackage(Common::String fileName);
    7184        Common::SeekableReadStream *openFile(Common::String file);
    7285        uint8 *getFileData(Common::String fileName, uint32 *fileSize); // this memory must be copied to your own structures!
    protected:  
    7689        ToonEngine *_vm;
    7790        Common::Array<uint8 *> _allocatedFileData;
    7891        Common::Array<PakFile *> _pakFiles;
     92        uint32 _cacheSize;
     93        Common::Array<CacheEntry *> _resourceCache;
     94
     95        void removePackageFromCache(Common::String packName);
     96        bool getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData);
     97        void addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData);
    7998};
    8099
    81100} // End of namespace Toon
  • engines/toon/toon.cpp

    diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
    index d65230d..a6cb8a7 100644
    a b void ToonEngine::init() {  
    106106
    107107        _pathFinding = new PathFinding(this);
    108108
    109         resources()->openPackage("LOCAL.PAK", true);
    110         resources()->openPackage("ONETIME.PAK", true);
    111         resources()->openPackage("DREW.PAK", true);
     109        resources()->openPackage("LOCAL.PAK");
     110        resources()->openPackage("ONETIME.PAK");
     111        resources()->openPackage("DREW.PAK");
    112112
    113113        for (int32 i = 0; i < 32; i++)
    114114                _characters[i] = NULL;
    void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {  
    10801080
    10811081        // load package
    10821082        strcpy(temp, createRoomFilename(Common::String::format("%s.PAK", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
    1083         resources()->openPackage(temp, true);
     1083        resources()->openPackage(temp);
    10841084
    10851085        strcpy(temp, state()->_locations[SceneId]._name);
    10861086        strcat(temp, ".NPP");