diff --git a/cocos/2d/CCDirector.cpp b/cocos/2d/CCDirector.cpp index 7e90fe92d8..36f72c81c5 100644 --- a/cocos/2d/CCDirector.cpp +++ b/cocos/2d/CCDirector.cpp @@ -1026,9 +1026,6 @@ void DisplayLinkDirector::startAnimation() } _invalid = false; -#ifndef EMSCRIPTEN - Application::getInstance()->setAnimationInterval(_animationInterval); -#endif // EMSCRIPTEN } void DisplayLinkDirector::mainLoop() @@ -1040,6 +1037,9 @@ void DisplayLinkDirector::mainLoop() } else if (! _invalid) { + // invoke call back from other thread + ThreadHelper::doCallback(); + drawScene(); // release the objects diff --git a/cocos/2d/CCTextureCache.cpp b/cocos/2d/CCTextureCache.cpp index 15b30ccb6a..a16f85f28d 100644 --- a/cocos/2d/CCTextureCache.cpp +++ b/cocos/2d/CCTextureCache.cpp @@ -162,10 +162,6 @@ void TextureCache::loadImage() while (true) { - // create autorelease pool for iOS - Thread thread; - thread.createAutoreleasePool(); - std::queue *pQueue = _asyncStructQueue; _asyncStructQueueMutex.lock(); if (pQueue->empty()) diff --git a/cocos/2d/platform/CCThread.cpp b/cocos/2d/platform/CCThread.cpp index d3f5b15999..7d4a23a216 100644 --- a/cocos/2d/platform/CCThread.cpp +++ b/cocos/2d/platform/CCThread.cpp @@ -24,23 +24,62 @@ THE SOFTWARE. #include "CCThread.h" +NS_CC_BEGIN + // iOS and Mac already has a Thread.mm #if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_MAC) -NS_CC_BEGIN +std::list>* ThreadHelper::_callbackList = new std::list>(); +std::mutex* ThreadHelper::_mutex = new std::mutex; +long ThreadHelper::_callbackNumberPerFrame = 5; -Thread::~Thread() + +void* ThreadHelper::createAutoreleasePool() { - // To prevent warning: private field '_autoreasePool' is not - // used [-Wunused-private-field] by CLANG. - _autoReleasePool = nullptr; + return nullptr; } -void Thread::createAutoreleasePool() +void ThreadHelper::releaseAutoreleasePool(void* autoreleasePool) { - + } -NS_CC_END +void ThreadHelper::runOnGLThread(std::function f) +{ + // Insert call back function + _mutex->lock(); + _callbackList->push_back(f); + _mutex->unlock(); +} + +void ThreadHelper::doCallback() +{ + _mutex->lock(); + auto iter = _callbackList->begin(); + long i = 0; + while (iter != _callbackList->end()) + { + auto f = *iter; + f(); + + ++i; + if (i >= _callbackNumberPerFrame) + { + break; + } + else + { + iter = _callbackList->erase(iter); + } + } + _mutex->unlock(); +} + +void ThreadHelper::setCallbackNumberPerFrame(long callbackNumberPerFrame) +{ + _callbackNumberPerFrame = callbackNumberPerFrame; +} #endif + +NS_CC_END diff --git a/cocos/2d/platform/CCThread.h b/cocos/2d/platform/CCThread.h index 46936642eb..b0998eeb59 100644 --- a/cocos/2d/platform/CCThread.h +++ b/cocos/2d/platform/CCThread.h @@ -25,8 +25,12 @@ THE SOFTWARE. #ifndef __CC_PLATFORM_THREAD_H__ #define __CC_PLATFORM_THREAD_H__ +#include +#include +#include #include "platform/CCCommon.h" #include "CCPlatformMacros.h" +#include "CCDirector.h" NS_CC_BEGIN @@ -39,27 +43,45 @@ NS_CC_BEGIN * and release it when the thread end. */ -class CC_DLL Thread +class CC_DLL ThreadHelper { public: - /** + friend DisplayLinkDirector; + + /** Create an autorelease pool for objective-c codes. * @js NA * @lua NA */ - Thread() : _autoReleasePool(nullptr) {} + static void* createAutoreleasePool(); + /** * @js NA * @lua NA - */ - ~Thread(); - /** + */ + static void releaseAutoreleasePool(void *autoreleasePool); + + /** To run a function in gl thread. * @js NA * @lua NA + @since v3.0 */ - void createAutoreleasePool(); + static void runOnGLThread(std::function f); + + /** Set how many callback functions being invoked per frame. Default value is 5. + * @js NA + * @lua NA + @since v3.0 + */ + static void setCallbackNumberPerFrame(long callbackNumberPerFrame); private: - void *_autoReleasePool; + // This function will be call by Director to call some call back function on gl thread + static void doCallback(); + + static std::list> *_callbackList; + static std::mutex *_mutex; + // How many callback functions invoked per frame + static long _callbackNumberPerFrame; }; // end of platform group diff --git a/cocos/2d/platform/apple/CCThread.mm b/cocos/2d/platform/apple/CCThread.mm index 80b319bae4..4e138fb889 100644 --- a/cocos/2d/platform/apple/CCThread.mm +++ b/cocos/2d/platform/apple/CCThread.mm @@ -26,14 +26,55 @@ THE SOFTWARE. NS_CC_BEGIN -Thread::~Thread() +std::list>* ThreadHelper::_callbackList = new std::list>(); +std::mutex* ThreadHelper::_mutex = new std::mutex; +long ThreadHelper::_callbackNumberPerFrame = 5; + +void* ThreadHelper::createAutoreleasePool() { - [(id)_autoReleasePool release]; + id pool = [[NSAutoreleasePool alloc] init]; + return pool; } -void Thread::createAutoreleasePool() +void ThreadHelper::releaseAutoreleasePool(void *autoreleasePool) { - _autoReleasePool = [[NSAutoreleasePool alloc] init]; + [(NSAutoreleasePool*)autoreleasePool release]; +} + +void ThreadHelper::runOnGLThread(std::function f) +{ + // Insert call back function + _mutex->lock(); + _callbackList->push_back(f); + _mutex->unlock(); +} + +void ThreadHelper::doCallback() +{ + _mutex->lock(); + auto iter = _callbackList->begin(); + long i = 0; + while (iter != _callbackList->end()) + { + auto f = *iter; + f(); + + ++i; + if (i >= _callbackNumberPerFrame) + { + break; + } + else + { + iter = _callbackList->erase(iter); + } + } + _mutex->unlock(); +} + +void ThreadHelper::setCallbackNumberPerFrame(long callbackNumberPerFrame) +{ + _callbackNumberPerFrame = callbackNumberPerFrame; } NS_CC_END diff --git a/cocos/editor-support/cocostudio/CCDataReaderHelper.cpp b/cocos/editor-support/cocostudio/CCDataReaderHelper.cpp index 27b0a70bb8..00e1d7f3f4 100644 --- a/cocos/editor-support/cocostudio/CCDataReaderHelper.cpp +++ b/cocos/editor-support/cocostudio/CCDataReaderHelper.cpp @@ -154,10 +154,6 @@ void DataReaderHelper::loadData() while (true) { - // create autorelease pool for iOS - Thread thread; - thread.createAutoreleasePool(); - std::queue *pQueue = _asyncStructQueue; _asyncStructQueueMutex.lock(); // get async struct from queue if (pQueue->empty()) diff --git a/extensions/assets-manager/AssetsManager.cpp b/extensions/assets-manager/AssetsManager.cpp index 0a7b9c8c4b..aefb9fc978 100644 --- a/extensions/assets-manager/AssetsManager.cpp +++ b/extensions/assets-manager/AssetsManager.cpp @@ -86,15 +86,10 @@ AssetsManager::AssetsManager(const char* packageUrl/* =NULL */, const char* vers , _shouldDeleteDelegateWhenExit(false) { checkStoragePath(); - _schedule = new Helper(); } AssetsManager::~AssetsManager() { - if (_schedule) - { - _schedule->release(); - } if (_shouldDeleteDelegateWhenExit) { delete _delegate; @@ -161,7 +156,10 @@ bool AssetsManager::checkUpdate() if (res != 0) { - sendErrorMessage(ErrorCode::NETWORK); + ThreadHelper::runOnGLThread([&, this]{ + if (this->_delegate) + this->_delegate->onError(ErrorCode::NETWORK); + }); CCLOG("can not get version file content, error code is %d", res); curl_easy_cleanup(_curl); return false; @@ -170,7 +168,10 @@ bool AssetsManager::checkUpdate() string recordedVersion = UserDefault::getInstance()->getStringForKey(keyOfVersion().c_str()); if (recordedVersion == _version) { - sendErrorMessage(ErrorCode::NO_NEW_VERSION); + ThreadHelper::runOnGLThread([&, this]{ + if (this->_delegate) + this->_delegate->onError(ErrorCode::NO_NEW_VERSION); + }); CCLOG("there is not new version"); // Set resource search path. setSearchPath(); @@ -190,25 +191,45 @@ void AssetsManager::downloadAndUncompress() { if (! downLoad()) break; - // Record downloaded version. - AssetsManager::Message *msg1 = new AssetsManager::Message(); - msg1->what = ASSETSMANAGER_MESSAGE_RECORD_DOWNLOADED_VERSION; - msg1->obj = this; - _schedule->sendMessage(msg1); + ThreadHelper::runOnGLThread([&, this]{ + UserDefault::getInstance()->setStringForKey(this->keyOfDownloadedVersion().c_str(), + this->_version.c_str()); + UserDefault::getInstance()->flush(); + }); } // Uncompress zip file. if (! uncompress()) { - sendErrorMessage(ErrorCode::UNCOMPRESS); + ThreadHelper::runOnGLThread([&, this]{ + if (this->_delegate) + this->_delegate->onError(ErrorCode::UNCOMPRESS); + }); break; } - // Record updated version and remove downloaded zip file - AssetsManager::Message *msg2 = new AssetsManager::Message(); - msg2->what = ASSETSMANAGER_MESSAGE_UPDATE_SUCCEED; - msg2->obj = this; - _schedule->sendMessage(msg2); + ThreadHelper::runOnGLThread([&, this] { + + // Record new version code. + UserDefault::getInstance()->setStringForKey(this->keyOfVersion().c_str(), this->_version.c_str()); + + // Unrecord downloaded version code. + UserDefault::getInstance()->setStringForKey(this->keyOfDownloadedVersion().c_str(), ""); + UserDefault::getInstance()->flush(); + + // Set resource search path. + this->setSearchPath(); + + // Delete unloaded zip file. + string zipfileName = this->_storagePath + TEMP_PACKAGE_FILE_NAME; + if (remove(zipfileName.c_str()) != 0) + { + CCLOG("can not remove downloaded zip file %s", zipfileName.c_str()); + } + + if (this->_delegate) this->_delegate->onSuccess(); + }); + } while (0); _isDownloading = false; @@ -452,18 +473,20 @@ static size_t downLoadPackage(void *ptr, size_t size, size_t nmemb, void *userda int assetsManagerProgressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded) { - AssetsManager* manager = (AssetsManager*)ptr; - AssetsManager::Message *msg = new AssetsManager::Message(); - msg->what = ASSETSMANAGER_MESSAGE_PROGRESS; + static int percent = 0; + int tmp = (int)(nowDownloaded / totalToDownload * 100); - ProgressMessage *progressData = new ProgressMessage(); - progressData->percent = (int)(nowDownloaded/totalToDownload*100); - progressData->manager = manager; - msg->obj = progressData; - - manager->_schedule->sendMessage(msg); - - CCLOG("downloading... %d%%", (int)(nowDownloaded/totalToDownload*100)); + if (percent != tmp) + { + percent = tmp; + ThreadHelper::runOnGLThread([=]{ + auto manager = static_cast(ptr); + if (manager->_delegate) + manager->_delegate->onProgress(percent); + }); + + CCLOG("downloading... %d%%", percent); + } return 0; } @@ -475,7 +498,10 @@ bool AssetsManager::downLoad() FILE *fp = fopen(outFileName.c_str(), "wb"); if (! fp) { - sendErrorMessage(ErrorCode::CREATE_FILE); + ThreadHelper::runOnGLThread([&, this]{ + if (this->_delegate) + this->_delegate->onError(ErrorCode::CREATE_FILE); + }); CCLOG("can not create file %s", outFileName.c_str()); return false; } @@ -492,7 +518,10 @@ bool AssetsManager::downLoad() curl_easy_cleanup(_curl); if (res != 0) { - sendErrorMessage(ErrorCode::NETWORK); + ThreadHelper::runOnGLThread([&, this]{ + if (this->_delegate) + this->_delegate->onError(ErrorCode::NETWORK); + }); CCLOG("error when download package"); fclose(fp); return false; @@ -560,133 +589,6 @@ unsigned int AssetsManager::getConnectionTimeout() return _connectionTimeout; } -void AssetsManager::sendErrorMessage(AssetsManager::ErrorCode code) -{ - Message *msg = new Message(); - msg->what = ASSETSMANAGER_MESSAGE_ERROR; - - ErrorMessage *errorMessage = new ErrorMessage(); - errorMessage->code = code; - errorMessage->manager = this; - msg->obj = errorMessage; - - _schedule->sendMessage(msg); -} - -// Implementation of AssetsManagerHelper - -AssetsManager::Helper::Helper() -{ - _messageQueue = new list(); - Director::getInstance()->getScheduler()->scheduleUpdateForTarget(this, 0, false); -} - -AssetsManager::Helper::~Helper() -{ - Director::getInstance()->getScheduler()->unscheduleAllForTarget(this); - delete _messageQueue; -} - -void AssetsManager::Helper::sendMessage(Message *msg) -{ - _messageQueueMutex.lock(); - _messageQueue->push_back(msg); - _messageQueueMutex.unlock(); -} - -void AssetsManager::Helper::update(float dt) -{ - Message *msg = NULL; - - // Returns quickly if no message - _messageQueueMutex.lock(); - if (0 == _messageQueue->size()) - { - _messageQueueMutex.unlock(); - return; - } - //remove unnecessary message - std::list::iterator it; - Message *proMsg = nullptr; - for (it = _messageQueue->begin(); it != _messageQueue->end(); ++it) - { - if((*it)->what == ASSETSMANAGER_MESSAGE_PROGRESS) - { - if (proMsg) - { - _messageQueue->remove(proMsg); - delete (ProgressMessage*)proMsg->obj; - delete proMsg; - } - proMsg = *it; - } - } - // Gets message - msg = *(_messageQueue->begin()); - _messageQueue->pop_front(); - _messageQueueMutex.unlock(); - - switch (msg->what) { - case ASSETSMANAGER_MESSAGE_UPDATE_SUCCEED: - handleUpdateSucceed(msg); - - break; - case ASSETSMANAGER_MESSAGE_RECORD_DOWNLOADED_VERSION: - UserDefault::getInstance()->setStringForKey(((AssetsManager*)msg->obj)->keyOfDownloadedVersion().c_str(), - ((AssetsManager*)msg->obj)->_version.c_str()); - UserDefault::getInstance()->flush(); - - break; - case ASSETSMANAGER_MESSAGE_PROGRESS: - if (((ProgressMessage*)msg->obj)->manager->_delegate) - { - ((ProgressMessage*)msg->obj)->manager->_delegate->onProgress(((ProgressMessage*)msg->obj)->percent); - } - - delete (ProgressMessage*)msg->obj; - - break; - case ASSETSMANAGER_MESSAGE_ERROR: - // error call back - if (((ErrorMessage*)msg->obj)->manager->_delegate) - { - ((ErrorMessage*)msg->obj)->manager->_delegate->onError(((ErrorMessage*)msg->obj)->code); - } - - delete ((ErrorMessage*)msg->obj); - - break; - default: - break; - } - - delete msg; -} - -void AssetsManager::Helper::handleUpdateSucceed(Message *msg) -{ - AssetsManager* manager = (AssetsManager*)msg->obj; - - // Record new version code. - UserDefault::getInstance()->setStringForKey(manager->keyOfVersion().c_str(), manager->_version.c_str()); - - // Unrecord downloaded version code. - UserDefault::getInstance()->setStringForKey(manager->keyOfDownloadedVersion().c_str(), ""); - UserDefault::getInstance()->flush(); - - // Set resource search path. - manager->setSearchPath(); - - // Delete unloaded zip file. - string zipfileName = manager->_storagePath + TEMP_PACKAGE_FILE_NAME; - if (remove(zipfileName.c_str()) != 0) - { - CCLOG("can not remove downloaded zip file %s", zipfileName.c_str()); - } - - if (manager->_delegate) manager->_delegate->onSuccess(); -} - AssetsManager* AssetsManager::create(const char* packageUrl, const char* versionFileUrl, const char* storagePath, ErrorCallback errorCallback, ProgressCallback progressCallback, SuccessCallback successCallback ) { class DelegateProtocolImpl : public AssetsManagerDelegateProtocol diff --git a/extensions/assets-manager/AssetsManager.h b/extensions/assets-manager/AssetsManager.h index 2cc253c165..e37ee4b3d9 100644 --- a/extensions/assets-manager/AssetsManager.h +++ b/extensions/assets-manager/AssetsManager.h @@ -166,40 +166,7 @@ protected: bool uncompress(); bool createDirectory(const char *path); void setSearchPath(); - void sendErrorMessage(ErrorCode code); void downloadAndUncompress(); - -private: - typedef struct _Message - { - public: - _Message() : what(0), obj(NULL){} - unsigned int what; // message type - void* obj; - } Message; - - class Helper : public cocos2d::Object - { - public: - /** - * @js ctor - */ - Helper(); - /** - * @js NA - * @lua NA - */ - ~Helper(); - - virtual void update(float dt); - void sendMessage(Message *msg); - - private: - void handleUpdateSucceed(Message *msg); - - std::list *_messageQueue; - std::mutex _messageQueueMutex; - }; private: /** @brief Initializes storage path. @@ -224,7 +191,6 @@ private: void *_curl; - Helper *_schedule; unsigned int _connectionTimeout; AssetsManagerDelegateProtocol *_delegate;