Lite2D的渲染线程尝试

Stella981
• 阅读 426

项目地址      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相关操作都用回调 在渲染线程来处理

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

Lite2D的渲染线程尝试

逻辑帧数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));
        }
    }

}

Lite2D的渲染线程尝试

demo项目表现良好

Lite2D的渲染线程尝试

渲染命令

//.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,

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
4、jstack查看线程栈信息
1、介绍利用jps、top、jstack命令找到进程中耗时最大的线程,以及线程状态等等,同时最后还可以显示出死锁的线程查找:FoundoneJavaleveldeadlock即可1、jps获得进程号!(https://oscimg.oschina.net/oscnet/da00a309fa6
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这