mirror of https://github.com/axmolengine/axmol.git
add async task callback dipatcher, call it in the main thread
This commit is contained in:
parent
f17df4b0bc
commit
bc57e47ddb
|
@ -92,25 +92,24 @@ void Sprite3D::createAsync(const std::string &modelPath, const std::string &text
|
|||
}
|
||||
|
||||
sprite->_asyncLoadParam.afterLoadCallback = callback;
|
||||
sprite->_asyncLoadParam.asyncFuture = AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_IO, [](Sprite3D* sp, const std::string& path)
|
||||
sprite->_asyncLoadParam.texPath = texturePath;
|
||||
sprite->_asyncLoadParam.path = modelPath;
|
||||
sprite->_asyncLoadParam.materialdatas = new (std::nothrow) MaterialDatas();
|
||||
sprite->_asyncLoadParam.meshdatas = new (std::nothrow) MeshDatas();
|
||||
sprite->_asyncLoadParam.nodeDatas = new (std::nothrow) NodeDatas();
|
||||
AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_IO, CC_CALLBACK_1(Sprite3D::afterAsyncLoad, sprite), (void*)(&sprite->_asyncLoadParam), [](Sprite3D* sp)
|
||||
{
|
||||
sp->_asyncLoadParam.materialdatas = new (std::nothrow) MaterialDatas();
|
||||
sp->_asyncLoadParam.meshdatas = new (std::nothrow) MeshDatas();
|
||||
sp->_asyncLoadParam.nodeDatas = new (std::nothrow) NodeDatas();
|
||||
sp->_asyncLoadParam.path = path;
|
||||
sp->_asyncLoadParam.result = sp->loadFromFile(path, sp->_asyncLoadParam.nodeDatas, sp->_asyncLoadParam.meshdatas, sp->_asyncLoadParam.materialdatas);
|
||||
}, sprite, modelPath);
|
||||
|
||||
sprite->schedule(SEL_SCHEDULE(&Sprite3D::asyncLoadChecker), 0);
|
||||
sp->_asyncLoadParam.result = sp->loadFromFile(sp->_asyncLoadParam.path, sp->_asyncLoadParam.nodeDatas, sp->_asyncLoadParam.meshdatas, sp->_asyncLoadParam.materialdatas);
|
||||
}, sprite);
|
||||
|
||||
}
|
||||
|
||||
void Sprite3D::asyncLoadChecker(float delta)
|
||||
void Sprite3D::afterAsyncLoad(void* param)
|
||||
{
|
||||
static std::chrono::milliseconds span(0);
|
||||
if (_asyncLoadParam.asyncFuture.valid() && _asyncLoadParam.asyncFuture.wait_for(span) == std::future_status::ready)
|
||||
Sprite3D::AsyncLoadParam* asyncParam = (Sprite3D::AsyncLoadParam*)param;
|
||||
if (asyncParam)
|
||||
{
|
||||
if (_asyncLoadParam.result)
|
||||
if (asyncParam->result)
|
||||
{
|
||||
_meshes.clear();
|
||||
_meshVertexDatas.clear();
|
||||
|
@ -118,9 +117,9 @@ void Sprite3D::asyncLoadChecker(float delta)
|
|||
removeAllAttachNode();
|
||||
|
||||
//create in the main thread
|
||||
auto& meshdatas = _asyncLoadParam.meshdatas;
|
||||
auto& materialdatas = _asyncLoadParam.materialdatas;
|
||||
auto& nodeDatas = _asyncLoadParam.nodeDatas;
|
||||
auto& meshdatas = asyncParam->meshdatas;
|
||||
auto& materialdatas = asyncParam->materialdatas;
|
||||
auto& nodeDatas = asyncParam->nodeDatas;
|
||||
if (initFrom(*nodeDatas, *meshdatas, *materialdatas))
|
||||
{
|
||||
//add to cache
|
||||
|
@ -132,7 +131,7 @@ void Sprite3D::asyncLoadChecker(float delta)
|
|||
data->glProgramStates.pushBack(mesh->getGLProgramState());
|
||||
}
|
||||
|
||||
Sprite3DCache::getInstance()->addSprite3DData(_asyncLoadParam.path, data);
|
||||
Sprite3DCache::getInstance()->addSprite3DData(asyncParam->path, data);
|
||||
meshdatas = nullptr;
|
||||
materialdatas = nullptr;
|
||||
nodeDatas = nullptr;
|
||||
|
@ -140,9 +139,13 @@ void Sprite3D::asyncLoadChecker(float delta)
|
|||
delete meshdatas;
|
||||
delete materialdatas;
|
||||
delete nodeDatas;
|
||||
|
||||
if (asyncParam->texPath != "")
|
||||
{
|
||||
setTexture(asyncParam->texPath);
|
||||
}
|
||||
}
|
||||
_asyncLoadParam.afterLoadCallback(this);
|
||||
unschedule(SEL_SCHEDULE(&Sprite3D::asyncLoadChecker));
|
||||
asyncParam->afterLoadCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#define __CCSPRITE3D_H__
|
||||
|
||||
#include <unordered_map>
|
||||
#include <future>
|
||||
|
||||
#include "base/CCVector.h"
|
||||
#include "base/ccTypes.h"
|
||||
|
@ -163,7 +162,7 @@ CC_CONSTRUCTOR_ACCESS:
|
|||
|
||||
void onAABBDirty() { _aabbDirty = true; }
|
||||
|
||||
void asyncLoadChecker(float delta);
|
||||
void afterAsyncLoad(void* param);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -185,10 +184,10 @@ protected:
|
|||
|
||||
struct AsyncLoadParam
|
||||
{
|
||||
std::future<void> asyncFuture; // future for load 3d sprite async
|
||||
std::function<void(Sprite3D*)> afterLoadCallback; // callback after load
|
||||
bool result; // sprite load result
|
||||
std::string path;
|
||||
std::string texPath; //
|
||||
MeshDatas* meshdatas;
|
||||
MaterialDatas* materialdatas;
|
||||
NodeDatas* nodeDatas;
|
||||
|
|
|
@ -29,6 +29,8 @@ NS_CC_BEGIN
|
|||
|
||||
AsyncTaskPool* AsyncTaskPool::s_asyncTaskPool = nullptr;
|
||||
|
||||
int AsyncTaskPool::s_maxCallBackPerProcess = -1;
|
||||
|
||||
AsyncTaskPool* AsyncTaskPool::getInstance()
|
||||
{
|
||||
if (s_asyncTaskPool == nullptr)
|
||||
|
@ -44,6 +46,17 @@ void AsyncTaskPool::destoryInstance()
|
|||
s_asyncTaskPool = nullptr;
|
||||
}
|
||||
|
||||
int AsyncTaskPool::getMaxTaskCallBackPerProcess()
|
||||
{
|
||||
return s_maxCallBackPerProcess;
|
||||
}
|
||||
|
||||
void AsyncTaskPool::setMaxTaskCallBackPerProcess(int numTaskCallBack)
|
||||
{
|
||||
if (numTaskCallBack > 0 || numTaskCallBack == -1)
|
||||
s_maxCallBackPerProcess = numTaskCallBack;
|
||||
}
|
||||
|
||||
AsyncTaskPool::AsyncTaskPool()
|
||||
{
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ THE SOFTWARE.
|
|||
#define __CCSYNC_TASK_POOL_H_
|
||||
|
||||
#include "platform/CCPlatformMacros.h"
|
||||
#include "base/CCRef.h"
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
|
@ -43,6 +44,8 @@ NS_CC_BEGIN
|
|||
class AsyncTaskPool
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(void*)> TaskCallBack;
|
||||
|
||||
enum class TaskType
|
||||
{
|
||||
TASK_IO,
|
||||
|
@ -50,12 +53,35 @@ public:
|
|||
TASK_OTHER,
|
||||
TASK_MAX_TYPE,
|
||||
};
|
||||
/**
|
||||
* get instance
|
||||
*/
|
||||
static AsyncTaskPool* getInstance();
|
||||
|
||||
/**
|
||||
* destroy instance
|
||||
*/
|
||||
static void destoryInstance();
|
||||
|
||||
/**
|
||||
* get max number of call back per process, -1 means unlimited (-1 is the default value)
|
||||
*/
|
||||
static int getMaxTaskCallBackPerProcess();
|
||||
|
||||
/**
|
||||
* set max number of call back per process, -1 means unlimited
|
||||
*/
|
||||
static void setMaxTaskCallBackPerProcess(int numTaskCallBack);
|
||||
|
||||
/**
|
||||
* process the call back after task, this should be called in the main thread
|
||||
*/
|
||||
void processTaskCallBack()
|
||||
{
|
||||
_taskcallbackDispatcher.update();
|
||||
}
|
||||
|
||||
template<class F, class... Args>
|
||||
auto enqueue(TaskType type, F&& f, Args&&... args)
|
||||
auto enqueue(TaskType type, const TaskCallBack& callback, void* callbackParam, F&& f, Args&&... args)
|
||||
-> std::future<typename std::result_of<F(Args...)>::type>;
|
||||
|
||||
CC_CONSTRUCTOR_ACCESS:
|
||||
|
@ -63,6 +89,12 @@ CC_CONSTRUCTOR_ACCESS:
|
|||
~AsyncTaskPool();
|
||||
|
||||
protected:
|
||||
struct AsyncTaskCallBack
|
||||
{
|
||||
TaskCallBack callback;
|
||||
void* callbackParam;
|
||||
};
|
||||
|
||||
// thread tasks internally used
|
||||
class ThreadTasks {
|
||||
friend class AsyncTaskPool;
|
||||
|
@ -76,7 +108,7 @@ protected:
|
|||
for(;;)
|
||||
{
|
||||
std::function<void()> task;
|
||||
|
||||
AsyncTaskCallBack callback;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->_queue_mutex);
|
||||
this->_condition.wait(lock,
|
||||
|
@ -84,10 +116,14 @@ protected:
|
|||
if(this->_stop && this->_tasks.empty())
|
||||
return;
|
||||
task = std::move(this->_tasks.front());
|
||||
callback = std::move(this->_taskCallBacks.front());
|
||||
this->_tasks.pop();
|
||||
this->_taskCallBacks.pop();
|
||||
}
|
||||
|
||||
task();
|
||||
AsyncTaskPool::getInstance()->_taskcallbackDispatcher.enqueue(callback);
|
||||
//task();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -100,10 +136,13 @@ protected:
|
|||
_thread.join();
|
||||
}
|
||||
private:
|
||||
|
||||
// need to keep track of thread so we can join them
|
||||
std::thread _thread;
|
||||
// the task queue
|
||||
std::queue< std::function<void()> > _tasks;
|
||||
std::queue<AsyncTaskCallBack> _taskCallBacks;
|
||||
// std::queue< AsyncTask > _tasks;
|
||||
|
||||
// synchronization
|
||||
std::mutex _queue_mutex;
|
||||
|
@ -111,13 +150,55 @@ protected:
|
|||
bool _stop;
|
||||
};
|
||||
|
||||
class AfterAsyncTaskDispatcher
|
||||
{
|
||||
public:
|
||||
void update()
|
||||
{
|
||||
if (_callBacks.empty())
|
||||
return;
|
||||
|
||||
std::unique_lock<std::mutex> lock(_queue_mutex);
|
||||
int numCallBack = 0;
|
||||
|
||||
for (auto& it : _callBacks) {
|
||||
if (s_maxCallBackPerProcess != -1 && ++numCallBack > s_maxCallBackPerProcess)
|
||||
break;
|
||||
|
||||
if (it.callback)
|
||||
{
|
||||
it.callback(it.callbackParam);
|
||||
}
|
||||
}
|
||||
|
||||
_callBacks.erase(_callBacks.begin(), _callBacks.begin() + numCallBack);
|
||||
}
|
||||
|
||||
AfterAsyncTaskDispatcher() {}
|
||||
~AfterAsyncTaskDispatcher() {}
|
||||
|
||||
void enqueue(const AsyncTaskCallBack& callback)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_queue_mutex);
|
||||
_callBacks.push_back(callback);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<AsyncTaskCallBack> _callBacks;
|
||||
std::mutex _queue_mutex;
|
||||
};
|
||||
|
||||
//tasks
|
||||
ThreadTasks _threadTasks[int(TaskType::TASK_MAX_TYPE)];
|
||||
//deal task call back
|
||||
AfterAsyncTaskDispatcher _taskcallbackDispatcher;
|
||||
static AsyncTaskPool* s_asyncTaskPool;
|
||||
static int s_maxCallBackPerProcess;
|
||||
};
|
||||
|
||||
template<class F, class... Args>
|
||||
auto AsyncTaskPool::enqueue(AsyncTaskPool::TaskType type, F&& f, Args&&... args)
|
||||
auto AsyncTaskPool::enqueue(AsyncTaskPool::TaskType type, const TaskCallBack& callback, void* callbackParam, F&& f, Args&&... args)
|
||||
-> std::future<typename std::result_of<F(Args...)>::type>
|
||||
{
|
||||
auto& threadTask = _threadTasks[(int)type];
|
||||
|
@ -132,6 +213,7 @@ auto AsyncTaskPool::enqueue(AsyncTaskPool::TaskType type, F&& f, Args&&... args)
|
|||
auto& stop = threadTask._stop;
|
||||
auto& tasks = threadTask._tasks;
|
||||
auto& condition = threadTask._condition;
|
||||
auto& taskcallbacks = threadTask._taskCallBacks;
|
||||
std::future<return_type> res = task->get_future();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
|
@ -143,7 +225,11 @@ auto AsyncTaskPool::enqueue(AsyncTaskPool::TaskType type, F&& f, Args&&... args)
|
|||
return res;
|
||||
}
|
||||
|
||||
AsyncTaskCallBack taskCallBack;
|
||||
taskCallBack.callback = callback;
|
||||
taskCallBack.callbackParam = callbackParam;
|
||||
tasks.emplace([task](){ (*task)(); });
|
||||
taskcallbacks.emplace(taskCallBack);
|
||||
}
|
||||
condition.notify_one();
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ THE SOFTWARE.
|
|||
#include "base/CCConsole.h"
|
||||
#include "base/CCAutoreleasePool.h"
|
||||
#include "base/CCConfiguration.h"
|
||||
#include "base/CCAsyncTaskPool.h"
|
||||
#include "platform/CCApplication.h"
|
||||
//#include "platform/CCGLViewImpl.h"
|
||||
|
||||
|
@ -266,6 +267,7 @@ void Director::drawScene()
|
|||
{
|
||||
_scheduler->update(_deltaTime);
|
||||
_eventDispatcher->dispatchEvent(_eventAfterUpdate);
|
||||
AsyncTaskPool::getInstance()->processTaskCallBack();
|
||||
}
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
|
Loading…
Reference in New Issue