mirror of https://github.com/axmolengine/axmol.git
Merge pull request #4401 from minggo/thread-helper
[ci skip]add helper funcion to invoke a function in gl thread
This commit is contained in:
commit
3268da3a4d
|
@ -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
|
||||
|
|
|
@ -162,10 +162,6 @@ void TextureCache::loadImage()
|
|||
|
||||
while (true)
|
||||
{
|
||||
// create autorelease pool for iOS
|
||||
Thread thread;
|
||||
thread.createAutoreleasePool();
|
||||
|
||||
std::queue<AsyncStruct*> *pQueue = _asyncStructQueue;
|
||||
_asyncStructQueueMutex.lock();
|
||||
if (pQueue->empty())
|
||||
|
|
|
@ -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<std::function<void(void)>>* ThreadHelper::_callbackList = new std::list<std::function<void(void)>>();
|
||||
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<void(void)> 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
|
||||
|
|
|
@ -25,8 +25,12 @@ THE SOFTWARE.
|
|||
#ifndef __CC_PLATFORM_THREAD_H__
|
||||
#define __CC_PLATFORM_THREAD_H__
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#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<void(void)> 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<std::function<void(void)>> *_callbackList;
|
||||
static std::mutex *_mutex;
|
||||
// How many callback functions invoked per frame
|
||||
static long _callbackNumberPerFrame;
|
||||
};
|
||||
|
||||
// end of platform group
|
||||
|
|
|
@ -26,14 +26,55 @@ THE SOFTWARE.
|
|||
|
||||
NS_CC_BEGIN
|
||||
|
||||
Thread::~Thread()
|
||||
std::list<std::function<void(void)>>* ThreadHelper::_callbackList = new std::list<std::function<void(void)>>();
|
||||
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<void(void)> 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
|
||||
|
|
|
@ -154,10 +154,6 @@ void DataReaderHelper::loadData()
|
|||
|
||||
while (true)
|
||||
{
|
||||
// create autorelease pool for iOS
|
||||
Thread thread;
|
||||
thread.createAutoreleasePool();
|
||||
|
||||
std::queue<AsyncStruct *> *pQueue = _asyncStructQueue;
|
||||
_asyncStructQueueMutex.lock(); // get async struct from queue
|
||||
if (pQueue->empty())
|
||||
|
|
|
@ -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<AssetsManager*>(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<Message*>();
|
||||
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<Message*>::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
|
||||
|
|
|
@ -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<Message*> *_messageQueue;
|
||||
std::mutex _messageQueueMutex;
|
||||
};
|
||||
|
||||
private:
|
||||
/** @brief Initializes storage path.
|
||||
|
@ -224,7 +191,6 @@ private:
|
|||
|
||||
void *_curl;
|
||||
|
||||
Helper *_schedule;
|
||||
unsigned int _connectionTimeout;
|
||||
|
||||
AssetsManagerDelegateProtocol *_delegate;
|
||||
|
|
Loading…
Reference in New Issue