文档章节

Lite2D的渲染线程尝试

梦想游戏人
 梦想游戏人
发布于 2016/10/17 21:04
字数 904
阅读 69
收藏 0

项目地址      https://github.com/dreamyouxi/Lite2D

注意:

1.GL只能和一个线程相关,所以纹理产生,初始化等都要放到渲染线程。

2.双缓冲默认是垂直同步的 可用  glfwSwapInterval; 来设置

GL API 参考自      http://www.glfw.org/docs/latest/group__context.html

 

暂且用以下方案:

1.渲染线程拷贝一个主线程产生的 纹理(暂定)

2.遍历Node的时候吧渲染参数 包装为命令(RenderCmd)  放到渲染队列里面(RenderCmdQueue)

3.因为线程安全问题,GL相关操作都用回调 在渲染线程来处理

逻辑线程执行的时候 会强制同步到渲染线程

 

逻辑帧数60,渲染帧数11999,逻辑延时0.000467 MS,测试平台 i7 4790K GTX 950

 

帧数限制:

通过最大帧数的时间来控制渲染次数,当渲染次数和逻辑次数不匹配会自动丢帧,保证当前渲染的始终是最新帧

static void   ThreadFunc(RenderCmdQueue * reder)
{
	Director::getInstance()->getGLView()->init(); // init gl in render thread 

	LARGE_INTEGER nLast;
	LARGE_INTEGER nNow;

	QueryPerformanceFrequency(&nFreq);
	perFrame.QuadPart = (LONGLONG)(1.0 / DEFAULT_FPS* nFreq.QuadPart);

	QueryPerformanceCounter(&nLast);

	float delta = 0.0f;
	while (true)
	{
		QueryPerformanceCounter(&nNow);
		if (nNow.QuadPart - nLast.QuadPart > perFrame.QuadPart)//default fps is 120
		{
			delta = (float)(nNow.QuadPart - nLast.QuadPart) / (float)nFreq.QuadPart;
			reder->render();
			reder->setRenderFPS(1.0f / delta + 1);

			nLast.QuadPart = nNow.QuadPart;
		}
		else
		{
			//std::this_thread::sleep_for(std::chrono::microseconds(0));
		}
	}

}

demo项目表现良好

 

渲染命令

//.h
class RenderCmd :public Ref
{
public:
	virtual void exec(Texture2D*) = 0;
	float   *_coord2f = 0;
	Vec2 _vertex[4];
	float _opacity = 0.0f;
	Texture2D*tex=nullptr;
};


class RenderCmd_Quad :public RenderCmd
{
public:
	virtual void exec(Texture2D*)override;
};


//.cpp

void  RenderCmd_Quad::exec(Texture2D *tex)
{

	GLuint id = tex->getTextureID();
	tex->getFileName().c_str();


	glLoadIdentity();// vetex can work once

	glBindTexture(GL_TEXTURE_2D, id);

	// able alpha blend for the texture who has alpha
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	//able opacity
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER, 0.0f);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	glColor4f(1.0f, 1.0f, 1.0f, _opacity);


	//start to render

	glBegin(GL_QUADS);

	glTexCoord2f(_coord2f[0], _coord2f[1]); glVertex2f(_vertex[0].x, _vertex[0].y);
	glTexCoord2f(_coord2f[2], _coord2f[3]); glVertex2f(_vertex[1].x, _vertex[1].y);
	glTexCoord2f(_coord2f[4], _coord2f[5]); glVertex2f(_vertex[2].x, _vertex[2].y);
	glTexCoord2f(_coord2f[6], _coord2f[7]); glVertex2f(_vertex[3].x, _vertex[3].y);


	glDisable(GL_BLEND);
	glDisable(GL_ALPHA_TEST);
	glEnd();
}

 

 

渲染队列(渲染线程)

class RenderCmdQueue
{

public:

	void addFuncToRenderThread(const std::function<Texture2D*(void)> &func);
	void addCustomFuncToRenderThread(const std::function<void(void)> &func);
private:

	std::unordered_map<std::string  , Texture2D*> tex_pool;

	std::vector<std::function<Texture2D*(void)>> _func;
	std::vector <std::function<void(void)>> _func1;
	void processOtherThreadFunc();



	std::mutex _mutex;

public:
	static RenderCmdQueue*create();
	void addRenderCmd(RenderCmd*cmd);

	void clear();
	void NextTick();//thread safe 
 
	
	void draw();
	void setVerticalSynchronization(bool enable);

private:
	std::atomic<bool> isNextTick = false;
	std::vector<RenderCmd*> _queue;
 
	void clearAllRenderCmd();

	RenderCmdQueue()
	{
		_queue.reserve(200);
	}
};

 

.cpp

static void   ThreadFunc(RenderCmdQueue * reder)
{
	Director::getInstance()->getGLView()->init(); // init gl in render thread 

	LARGE_INTEGER nLast;
	LARGE_INTEGER nNow;

	QueryPerformanceFrequency(&nFreq);
	perFrame.QuadPart = (LONGLONG)(1.0 / 120 * nFreq.QuadPart);

	QueryPerformanceCounter(&nLast);

	float delta = 0.0f;
	while (true)
	{
		QueryPerformanceCounter(&nNow);
		if (nNow.QuadPart - nLast.QuadPart > perFrame.QuadPart)
		{
			delta = (float)(nNow.QuadPart - nLast.QuadPart) / (float)nFreq.QuadPart;
			reder->render();
			reder->setRenderFPS(1.0f / delta + 1);

			nLast.QuadPart = nNow.QuadPart;
		}
		else
		{
			//std::this_thread::sleep_for(std::chrono::microseconds(0));
		}
	}

}


RenderCmdQueue* RenderCmdQueue::create()
{
	RenderCmdQueue*ret = new RenderCmdQueue;

	//Director::getInstance()->getGLView()->init();

	/*std::thread t([ret]()
	{
	Director::getInstance()->getGLView()->init();

	while (true)
	{
	ret->draw();
	//	Sleep(100);

	}

	}); t.detach();*/

	static std::thread t(&ThreadFunc, ret); t.detach();

	return ret;
}


void RenderCmdQueue::addRenderCmd(RenderCmd*cmd)
{
	_mutex.lock();
	_queue.push_back(cmd);
	_mutex.unlock();
}



void RenderCmdQueue::clear()
{
	isNextTick = false;
	_mutex.lock();
	++_tick_status;
	if (_tick_status > 5)
	{
		_tick_status = 0;
		auto dir = Director::getInstance();

		_cache_fps = dir->getFPS();
		_cache_last_fps = this->getRenderFPS();
		_cache_redertime = dir->getRenderTime();
	}
	this->clearAllRenderCmd();

	_mutex.unlock();
}

void  RenderCmdQueue::setVerticalSynchronization(bool enable)
{
	if (enable)
	{
		glfwSwapInterval(0xff);
	}
	else
	{
		glfwSwapInterval(0x0);
	}
}


void RenderCmdQueue::NextTick()//thread safe 
{
	this->isNextTick = true;
}

void  RenderCmdQueue::clearAllRenderCmd()
{

	for (int i = 0; i < _queue.size(); i++)
	{
		_queue[i]->release();
	}
	_queue.clear();

}




void RenderCmdQueue::render()
{
	do
	{
		if (isNextTick == false)break;

		std::lock_guard<std::mutex> lock(_mutex);

		//	if (_queue.empty())break;

		glClear(GL_COLOR_BUFFER_BIT);
		//	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glEnable(GL_TEXTURE_2D);

		for (int i = 0; i < _queue.size(); i++)
		{

			RenderCmd *cmd = _queue[i];

			auto it = tex_pool.find(cmd->tex->getFileName());
			if (it == tex_pool.end())
			{

				Texture2D* tex = new Texture2D;

				auto image = new Image;
				image->initWithFile(cmd->tex->getFileName());
				tex->initWithImage(image);

				cmd->exec(tex);
				tex_pool[cmd->tex->getFileName()] = tex;
			}
			else
			{
				cmd->exec((*it).second);
			}
		}

		glDisable(GL_TEXTURE_2D);
		Director::getInstance()->getGLView()->swapBuffers();


	} while (false);

	this->processOtherThreadFunc();

}





void  RenderCmdQueue::processOtherThreadFunc()
{
	_mutex.lock();

	for (auto &func : _func)
	{
		Texture2D*  tex = func();
		tex_pool[tex->getFileName()] = tex;
	}
	_func.clear();

	for (auto &func : _func1)
	{
		func();
	}
	_func1.clear();

	_mutex.unlock();
}


void  RenderCmdQueue::addFuncToRenderThread(const std::function<Texture2D*(void)> &func)
{
	this->_mutex.lock();

	_func.push_back(func);
	this->_mutex.unlock();
}


void  RenderCmdQueue::addCustomFuncToRenderThread(const std::function<void(void)> &func)
{
	_mutex.lock();
	_func1.push_back(func);
	_mutex.unlock();
}

实测,当object很多时候 渲染效率反而底下,比如1万个同纹理的 单线程依然50+FPS 多线程版本就只有20+FPS,

© 著作权归作者所有

共有 人打赏支持
梦想游戏人
粉丝 36
博文 432
码字总数 123495
作品 0
成都
私信 提问
加载中

评论(1)

裙下之臣
裙下之臣
留:laughing:
Lite2D的HttpClient

封装了curl 由于网络是独立的一个线程 所以需要线程同步 下面是Director的同步代码 void Director::addFuncToMainThread(const std::function<void()>& func){mutexmainThread.lock();queue......

梦想游戏人
2016/03/23
10
0
渲染Freetype2字体

将字符串的每个字 通过freetype 获得bitmap 然后渲染至GL 下面 Lite2D ::Text 的实现 CharBitMap *Text::getCharBitMapData(unsigned short _char){CharBitMap *bitmap = new CharBitMap; F......

梦想游戏人
2016/03/23
133
0
旋转缓存的设计

关于旋转Lite2D之前选用了矩阵的转换 发现自己写出来的效率还不如普通的计算算法加上缓存 由于sin cos 的计算很费时间,所以设计了一个缓存,程序启动后就 计算0-90度的结果,精度为0.00000...

梦想游戏人
2016/03/23
7
0
序列动作Sequence

序列动作就是一个一个的执行动作 以下是Lite2D的Sequence 实现 #include"Sequence.h" include <stdarg.h> Sequence::Sequence() :current(0){ } Sequence Sequence::create(Action _action1,......

梦想游戏人
2016/03/23
4
0
帧动画缓存

吧帧动画存储在内存里面,供使用 以下是Lite2D的实现 #include"AnimationCache.h" AnimationCacheAnimationCache::getInstance(){static AnimationCacheins = nullptr; if (ins == nullptr)......

梦想游戏人
2016/03/23
22
0

没有更多内容

加载失败,请刷新页面

加载更多

当S8遇上边缘计算:谈阿里云ENS对直播业务场景的支撑

摘要: 类似S8赛事这样的大型活动直播的特点和技术挑战是什么?为什么业务要下沉到边缘?自建边缘节点和与云服务厂商合作到底该如何选择?边缘节点服务(ENS)又是如何进行技术支撑?提供的针...

阿里云官方博客
8分钟前
1
0
supervisor安装配置

supervisor安装配置 安装 wget -c https://files.pythonhosted.org/packages/44/60/698e54b4a4a9b956b2d709b4b7b676119c833d811d53ee2500f1b5e96dc3/supervisor-3.3.4.tar.gztar -zxvf su......

jackmanwu
18分钟前
1
0
laravel定时器

民间高手: https://blog.csdn.net/zhezhebie/article/details/79205414 官方文档: https://laravel-china.org/docs/laravel/5.5/scheduling/1325...

vio小黑
41分钟前
0
0
Apache Zeppelin安装及使用

Apache Zeppelin官网:http://zeppelin.apache.org/ Apache Zeppelin介绍:A web-based notebook that enables interactive data analytics. You can make beautiful data-driven, interacti......

GordonNemo
42分钟前
4
0
关于python开发多个项目环境配置Anaconda

关于Anaconda用来管理Python的包和环境 下载并安装Anaconda 创建项目:windows键+R ==> 进入CMD => 输入conda create -n 项目名称 python=3 conda info -e 查看项目以及项目所在的位置,默认...

上官清偌
44分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部