diff --git a/cocos2dx/shaders/CCShaderCache.cpp b/cocos2dx/shaders/CCShaderCache.cpp index 82c20362d0..0c37ee339b 100644 --- a/cocos2dx/shaders/CCShaderCache.cpp +++ b/cocos2dx/shaders/CCShaderCache.cpp @@ -76,22 +76,22 @@ void ShaderCache::purgeSharedShaderCache() } ShaderCache::ShaderCache() -: _programs(0) +: _programs() { } ShaderCache::~ShaderCache() { + for( auto it = _programs.begin(); it != _programs.end(); ++it ) { + (it->second)->release(); + } + CCLOGINFO("deallocing ShaderCache: %p", this); - _programs->release(); } bool ShaderCache::init() -{ - _programs = Dictionary::create(); - _programs->retain(); - +{ loadDefaultShaders(); return true; } @@ -101,70 +101,54 @@ void ShaderCache::loadDefaultShaders() // Position Texture Color shader GLProgram *p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionTextureColor); - - _programs->setObject(p, GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR); - p->release(); + _programs.insert( std::make_pair( GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR, p ) ); // Position Texture Color alpha test p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionTextureColorAlphaTest); - - _programs->setObject(p, GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST); - p->release(); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST, p) ); // // Position, Color shader // p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionColor); - - _programs->setObject(p, GLProgram::SHADER_NAME_POSITION_COLOR); - p->release(); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_POSITION_COLOR, p) ); // // Position Texture shader // p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionTexture); - - _programs->setObject(p, GLProgram::SHADER_NAME_POSITION_TEXTURE); - p->release(); + _programs.insert( std::make_pair( GLProgram::SHADER_NAME_POSITION_TEXTURE, p) ); // // Position, Texture attribs, 1 Color as uniform shader // p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionTexture_uColor); - - _programs->setObject(p ,GLProgram::SHADER_NAME_POSITION_TEXTURE_U_COLOR); - p->release(); + _programs.insert( std::make_pair( GLProgram::SHADER_NAME_POSITION_TEXTURE_U_COLOR, p) ); // // Position Texture A8 Color shader // p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionTextureA8Color); - - _programs->setObject(p, GLProgram::SHADER_NAME_POSITION_TEXTURE_A8_COLOR); - p->release(); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_POSITION_TEXTURE_A8_COLOR, p) ); // // Position and 1 color passed as a uniform (to simulate glColor4ub ) // p = new GLProgram(); loadDefaultShader(p, kShaderType_Position_uColor); - - _programs->setObject(p, GLProgram::SHADER_NAME_POSITION_U_COLOR); - p->release(); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_POSITION_U_COLOR, p) ); // // Position, Legth(TexCoords, Color (used by Draw Node basically ) // p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionLengthTexureColor); - - _programs->setObject(p, GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR); - p->release(); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR, p) ); } void ShaderCache::reloadDefaultShaders() @@ -297,14 +281,18 @@ void ShaderCache::loadDefaultShader(GLProgram *p, int type) CHECK_GL_ERROR_DEBUG(); } -GLProgram* ShaderCache::programForKey(const char* key) +GLProgram* ShaderCache::programForKey(const std::string &key) { - return static_cast(_programs->objectForKey(key)); + auto it = _programs.find(key); + if( it != _programs.end() ) + return it->second; + return nullptr; } -void ShaderCache::addProgram(GLProgram* program, const char* key) +void ShaderCache::addProgram(GLProgram* program, const std::string &key) { - _programs->setObject(program, key); + program->retain(); + _programs.insert( std::make_pair( key, program) ); } NS_CC_END diff --git a/cocos2dx/shaders/CCShaderCache.h b/cocos2dx/shaders/CCShaderCache.h index deccfb065a..47581290c0 100644 --- a/cocos2dx/shaders/CCShaderCache.h +++ b/cocos2dx/shaders/CCShaderCache.h @@ -27,6 +27,9 @@ THE SOFTWARE. #ifndef __CCSHADERCACHE_H__ #define __CCSHADERCACHE_H__ +#include +#include + #include "cocoa/CCDictionary.h" NS_CC_BEGIN @@ -68,17 +71,17 @@ public: void reloadDefaultShaders(); /** returns a GL program for a given key */ - GLProgram * programForKey(const char* key); + GLProgram * programForKey(const std::string &key); /** adds a GLProgram to the cache for a given name */ - void addProgram(GLProgram* program, const char* key); + void addProgram(GLProgram* program, const std::string &key); private: bool init(); void loadDefaultShader(GLProgram *program, int type); - Dictionary* _programs; - +// Dictionary* _programs; + std::unordered_map _programs; }; // end of shaders group diff --git a/cocos2dx/textures/CCTextureCache.cpp b/cocos2dx/textures/CCTextureCache.cpp index 2e608952c4..958316e2be 100644 --- a/cocos2dx/textures/CCTextureCache.cpp +++ b/cocos2dx/textures/CCTextureCache.cpp @@ -74,17 +74,14 @@ TextureCache::TextureCache() , _asyncRefCount(0) { CCASSERT(_sharedTextureCache == nullptr, "Attempted to allocate a second instance of a singleton."); - - _textures = new Dictionary(); - _textures->init(); - } TextureCache::~TextureCache() { CCLOGINFO("deallocing TextureCache: %p", this); - CC_SAFE_RELEASE(_textures); + for( auto it=_textures.begin(); it!=_textures.end(); ++it) + (it->second)->release(); CC_SAFE_DELETE(_loadingThread); _sharedTextureCache = nullptr; @@ -102,42 +99,34 @@ void TextureCache::destroyInstance() const char* TextureCache::description() const { - return String::createWithFormat("", _textures->count())->getCString(); + return String::createWithFormat("", _textures.size() )->getCString(); } -Dictionary* TextureCache::snapshotTextures() -{ - Dictionary* pRet = new Dictionary(); - DictElement* pElement = NULL; - CCDICT_FOREACH(_textures, pElement) - { - pRet->setObject(pElement->getObject(), pElement->getStrKey()); - } - pRet->autorelease(); - return pRet; -} +//Dictionary* TextureCache::snapshotTextures() +//{ +// Dictionary* pRet = new Dictionary(); +// DictElement* pElement = NULL; +// CCDICT_FOREACH(_textures, pElement) +// { +// pRet->setObject(pElement->getObject(), pElement->getStrKey()); +// } +// pRet->autorelease(); +// return pRet; +//} -void TextureCache::addImageAsync(const char *path, Object *target, SEL_CallFuncO selector) +void TextureCache::addImageAsync(const std::string &path, Object *target, SEL_CallFuncO selector) { - CCASSERT(path != NULL, "TextureCache: fileimage MUST not be NULL"); - Texture2D *texture = NULL; - // optimization + std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path.c_str()); - std::string pathKey = path; + auto it = _textures.find(fullpath); + if( it != _textures.end() ) + texture = it->second; - pathKey = FileUtils::getInstance()->fullPathForFilename(pathKey.c_str()); - texture = static_cast(_textures->objectForKey(pathKey.c_str())); - - std::string fullpath = pathKey; - if (texture != NULL) + if (texture != NULL && target && selector) { - if (target && selector) - { - (target->*selector)(texture); - } - + (target->*selector)(texture); return; } @@ -270,8 +259,10 @@ void TextureCache::addImageAsyncCallBack(float dt) // cache the texture file name VolatileTexture::addImageTexture(texture, filename); #endif - // cache the texture - _textures->setObject(texture, filename); + // cache the texture. retain it, since it is added in the map + _textures.insert( std::make_pair(filename, texture) ); + texture->retain(); + texture->autorelease(); if (target && selector) @@ -292,27 +283,25 @@ void TextureCache::addImageAsyncCallBack(float dt) } } -Texture2D * TextureCache::addImage(const char * path) +Texture2D * TextureCache::addImage(const std::string &path) { - CCASSERT(path != NULL, "TextureCache: fileimage MUST not be NULL"); - Texture2D * texture = NULL; Image* image = NULL; // Split up directory and filename // MUTEX: // Needed since addImageAsync calls this method from a different thread - std::string pathKey = FileUtils::getInstance()->fullPathForFilename(path); - if (pathKey.size() == 0) + std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path.c_str()); + if (fullpath.size() == 0) { return NULL; } - texture = static_cast(_textures->objectForKey(pathKey)); + auto it = _textures.find(fullpath); + if( it != _textures.end() ) + texture = it->second; if (! texture) { - std::string fullpath(pathKey); - // all images are handled by UIImage except PVR extension that is handled by our own handler do { @@ -330,12 +319,12 @@ Texture2D * TextureCache::addImage(const char * path) // cache the texture file name VolatileTexture::addImageTexture(texture, fullpath.c_str()); #endif - _textures->setObject(texture, pathKey); - texture->release(); + // texture already retained, no need to re-retain it + _textures.insert( std::make_pair(fullpath, texture) ); } else { - CCLOG("cocos2d: Couldn't create texture for file:%s in TextureCache", path); + CCLOG("cocos2d: Couldn't create texture for file:%s in TextureCache", path.c_str()); } } while (0); } @@ -345,7 +334,7 @@ Texture2D * TextureCache::addImage(const char * path) return texture; } -Texture2D* TextureCache::addImage(Image *image, const char *key) +Texture2D* TextureCache::addImage(Image *image, const std::string &key) { CCASSERT(image != NULL, "TextureCache: image MUST not be nil"); @@ -353,9 +342,9 @@ Texture2D* TextureCache::addImage(Image *image, const char *key) do { - // If key is nil, then create a new texture each time - if(key && (texture = static_cast(_textures->objectForKey(key))) ) - { + auto it = _textures.find(key); + if( it != _textures.end() ) { + texture = it->second; break; } @@ -363,9 +352,11 @@ Texture2D* TextureCache::addImage(Image *image, const char *key) texture = new Texture2D(); texture->initWithImage(image); - if(key && texture) + if(texture) { - _textures->setObject(texture, key); + _textures.insert( std::make_pair(key, texture) ); + texture->retain(); + texture->autorelease(); } else @@ -386,48 +377,25 @@ Texture2D* TextureCache::addImage(Image *image, const char *key) void TextureCache::removeAllTextures() { - _textures->removeAllObjects(); + for( auto it=_textures.begin(); it!=_textures.end(); ++it ) { + (it->second)->release(); + } + _textures.clear(); } void TextureCache::removeUnusedTextures() { - /* - DictElement* pElement = NULL; - CCDICT_FOREACH(_textures, pElement) - { - CCLOG("cocos2d: TextureCache: texture: %s", pElement->getStrKey()); - Texture2D *value = static_cast(pElement->getObject()); - if (value->retainCount() == 1) - { - CCLOG("cocos2d: TextureCache: removing unused texture: %s", pElement->getStrKey()); - _textures->removeObjectForElememt(pElement); - } - } - */ - - /** Inter engineer zhuoshi sun finds that this way will get better performance - */ - if (_textures->count()) - { - // find elements to be removed - DictElement* pElement = NULL; - list elementToRemove; - CCDICT_FOREACH(_textures, pElement) - { - CCLOG("cocos2d: TextureCache: texture: %s", pElement->getStrKey()); - Texture2D *value = static_cast(pElement->getObject()); - if (value->retainCount() == 1) - { - elementToRemove.push_back(pElement); - } - } - - // remove elements - for (auto iter = elementToRemove.begin(); iter != elementToRemove.end(); ++iter) - { - CCLOG("cocos2d: TextureCache: removing unused texture: %s", (*iter)->getStrKey()); - _textures->removeObjectForElememt(*iter); + for( auto it=_textures.cbegin(); it!=_textures.cend(); /* nothing */) { + Texture2D *tex = it->second; + if( tex->retainCount() == 1 ) { + CCLOG("cocos2d: TextureCache: removing unused texture: %s", it->first.c_str()); + + tex->release(); + _textures.erase(it++); + } else { + ++it; } + } } @@ -438,24 +406,31 @@ void TextureCache::removeTexture(Texture2D* texture) return; } - Array* keys = _textures->allKeysForObject(texture); - _textures->removeObjectsForKeys(keys); -} - -void TextureCache::removeTextureForKey(const char *textureKeyName) -{ - if (textureKeyName == NULL) - { - return; + for( auto it=_textures.cbegin(); it!=_textures.cend(); /* nothing */ ) { + if( it->second == texture ) { + texture->release(); + _textures.erase(it++); + break; + } else + ++it; } - - string fullPath = FileUtils::getInstance()->fullPathForFilename(textureKeyName); - _textures->removeObjectForKey(fullPath); } -Texture2D* TextureCache::textureForKey(const char* key) +void TextureCache::removeTextureForKey(const std::string &textureKeyName) { - return static_cast(_textures->objectForKey(FileUtils::getInstance()->fullPathForFilename(key))); + auto it = _textures.find(textureKeyName); + if( it != _textures.end() ) { + (it->second)->release(); + _textures.erase(it); + } +} + +Texture2D* TextureCache::getTextureForKey(const std::string &key) const +{ + auto it = _textures.find(key); + if( it != _textures.end() ) + return it->second; + return NULL; } void TextureCache::reloadAllTextures() @@ -465,22 +440,21 @@ void TextureCache::reloadAllTextures() #endif } -void TextureCache::dumpCachedTextureInfo() +void TextureCache::dumpCachedTextureInfo() const { unsigned int count = 0; unsigned int totalBytes = 0; - DictElement* pElement = NULL; - CCDICT_FOREACH(_textures, pElement) - { - Texture2D* tex = static_cast(pElement->getObject()); + for( auto it = _textures.begin(); it != _textures.end(); ++it ) { + + Texture2D* tex = it->second; unsigned int bpp = tex->getBitsPerPixelForFormat(); // Each texture takes up width * height * bytesPerPixel bytes. unsigned int bytes = tex->getPixelsWide() * tex->getPixelsHigh() * bpp / 8; totalBytes += bytes; count++; - CCLOG("cocos2d: \"%s\" rc=%lu id=%lu %lu x %lu @ %ld bpp => %lu KB", - pElement->getStrKey(), + log("cocos2d: \"%s\" rc=%lu id=%lu %lu x %lu @ %ld bpp => %lu KB", + it->first.c_str(), (long)tex->retainCount(), (long)tex->getName(), (long)tex->getPixelsWide(), @@ -489,7 +463,7 @@ void TextureCache::dumpCachedTextureInfo() (long)bytes / 1024); } - CCLOG("cocos2d: TextureCache dumpDebugInfo: %ld textures, for %lu KB (%.2f MB)", (long)count, (long)totalBytes / 1024, totalBytes / (1024.0f*1024.0f)); + log("cocos2d: TextureCache dumpDebugInfo: %ld textures, for %lu KB (%.2f MB)", (long)count, (long)totalBytes / 1024, totalBytes / (1024.0f*1024.0f)); } #if CC_ENABLE_CACHE_TEXTURE_DATA diff --git a/cocos2dx/textures/CCTextureCache.h b/cocos2dx/textures/CCTextureCache.h index d725dddf64..0a922a0807 100644 --- a/cocos2dx/textures/CCTextureCache.h +++ b/cocos2dx/textures/CCTextureCache.h @@ -33,9 +33,9 @@ THE SOFTWARE. #include #include #include +#include #include "cocoa/CCObject.h" -#include "cocoa/CCDictionary.h" #include "textures/CCTexture2D.h" #include "platform/CCImage.h" @@ -83,7 +83,7 @@ public: const char* description(void) const; - Dictionary* snapshotTextures(); +// Dictionary* snapshotTextures(); /** Returns a Texture2D object given an filename. * If the filename was not previously loaded, it will create a new Texture2D @@ -91,7 +91,7 @@ public: * Otherwise it will return a reference of a previously loaded image. * Supported image extensions: .png, .bmp, .tiff, .jpeg, .pvr, .gif */ - Texture2D* addImage(const char* fileimage); + Texture2D* addImage(const std::string &filepath); /* Returns a Texture2D object given a file image * If the file image was not previously loaded, it will create a new Texture2D object and it will return it. @@ -100,7 +100,7 @@ public: * Supported image extensions: .png, .jpg * @since v0.8 */ - virtual void addImageAsync(const char *path, Object *target, SEL_CallFuncO selector); + virtual void addImageAsync(const std::string &filepath, Object *target, SEL_CallFuncO selector); /** Returns a Texture2D object given an Image. * If the image was not previously loaded, it will create a new Texture2D object and it will return it. @@ -108,13 +108,14 @@ public: * The "key" parameter will be used as the "key" for the cache. * If "key" is nil, then a new texture will be created each time. */ - Texture2D* addImage(Image *image, const char *key); + Texture2D* addImage(Image *image, const std::string &key); CC_DEPRECATED_ATTRIBUTE Texture2D* addUIImage(Image *image, const char *key) { return addImage(image,key); } /** Returns an already created texture. Returns nil if the texture doesn't exist. @since v0.99.5 */ - Texture2D* textureForKey(const char* key); + Texture2D* getTextureForKey(const std::string& key) const; + CC_DEPRECATED_ATTRIBUTE Texture2D* textureForKey(const char* key) const { return getTextureForKey(key); } /** Purges the dictionary of loaded textures. * Call this method if you receive the "Memory Warning" @@ -138,14 +139,14 @@ public: /** Deletes a texture from the cache given a its key name @since v0.99.4 */ - void removeTextureForKey(const char *textureKeyName); + void removeTextureForKey(const std::string &key); /** Output to CCLOG the current contents of this TextureCache * This will attempt to calculate the size of each texture, and the total texture memory in use * * @since v1.0 */ - void dumpCachedTextureInfo(); + void dumpCachedTextureInfo() const; private: void addImageAsyncCallBack(float dt); @@ -157,9 +158,9 @@ public: public: AsyncStruct(const std::string& fn, Object *t, SEL_CallFuncO s) : filename(fn), target(t), selector(s) {} - std::string filename; - Object *target; - SEL_CallFuncO selector; + std::string filename; + Object *target; + SEL_CallFuncO selector; }; protected: @@ -184,7 +185,7 @@ protected: int _asyncRefCount; - Dictionary* _textures; + std::unordered_map _textures; static TextureCache *_sharedTextureCache; };