文档章节

Lite2D的渲染线程尝试

梦想游戏人
 梦想游戏人
发布于 2016/10/17 21:04
字数 904
阅读 274
收藏 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,

梦想游戏人
粉丝 43
博文 505
码字总数 200978
作品 0
成都
私信 提问
加载中
此博客有 1 条评论,请先登录后再查看。
Swift百万线程攻破单例(Singleton)模式

一、不安全的单例实现 在上一篇文章我们给出了单例的设计模式,直接给出了线程安全的实现方法。单例的实现有多种方法,如下面: class SwiftSingleton { } 这段代码的实现,在shared中进行条...

一叶博客
2014/06/20
3.3K
16
跨平台 3D 游戏引擎--Castle Game Engine

Castle Game Engine 是一个用 Object Pascal 开发的跨平台 3D 游戏引擎。包含一个灵活的 3D 对象系统与开箱即用的水平,项目,智能生物等等。使用 X3D、VRML、Collada 和其他格式实现渲染和处理...

匿名
2013/02/05
2K
0
开源渲染器--LuxRender

LuxRender 是一款物理真实的、无偏差的开源渲染器。 LuxRender渲染是根据渲染方程来模拟光的传输,生成物理真实的图像。但LuxRender 只是一款渲染程序而不是3D建模程序,它需要其它3D程序来创...

匿名
2013/03/03
10K
0
游戏引擎--DarkGDK

Dark游戏开发工具包是一个完整的游戏引擎技术利用最新DirectX 9.0。 微软公司制作的编游戏的链接库工具,专门配合Visual C++ 2008 Express 和 DirextX 9.0 SDK,可以编辑制作3D,2D游戏,制作...

匿名
2013/04/01
2.2K
0
Markdown Reader

Markdown Reader 是 Chrome 的扩展,用来阅读 Markdown 格式文档。 软件功能: 渲染样式美化,看起文档更舒服 代码块增加代码高亮和行号功能 监测文件修改,并自动重新加载并渲染markdown,使...

YanisWang
2012/11/22
7.1K
2

没有更多内容

加载失败,请刷新页面

加载更多

PHP实现RabbitMQ消息队列

先安装PHP对应的RabbitMQ,这里用的是 php_amqp 不同的扩展实现方式会有细微的差异. php扩展地址: http://pecl.php.net/package/amqp 具体以官网为准 http://www.rabbitmq.com/getstarted.htm...

PHP圈子
5分钟前
0
0
pdd笔试题

拼多多提前批的笔试没有报名,但昨天听伙伴们说很难,所以一共4道题,挑了2道会的,自己编了一下。 #include<iostream>#include<vector>#include<algorithm>using namespace std;int ma...

osc_tylqml9v
5分钟前
0
0
拓扑排序算法

/** * 拓扑排序算法,拓扑都是有向无环图 * 使用场景:编译的时候,比如,springboot启动的时候要读取docker系统环境变量,还要读取各配置文件按照顺序 * 还有比如,a的包依赖...

osc_94gn551r
7分钟前
0
0
巨微代理MS1581蓝牙无线收发器

上海巨微MS1581包含8位单片机和低功耗、低成本的BLE收发器,内部集成了发射机、接收机、GFSK调制解调器和BLE基带处理。遵循BLE广播通道通信,具有成本低、体积小、控制方便等优点。巨微代理英...

英尚微电子
7分钟前
0
0
链接测试(内部)

1、长链 https://chelun.eclicks.cn/web/information?info_tid=156984 - 文章test http://cjjl-h5-test.chelun.com/2020/big/index.html - 以小博大test 2、scheme : 钱包 supercoach://myw......

osc_hwc3munb
8分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部