返回> 网站首页 

[转载]改良Cocos2d-x win32 版本的CPU占用问题

yoours2014-06-21 12:05:04 阅读 1542

简介一边听听音乐,一边写写文章。

Cocos2d-x win32 版本,CPU占用率很高是由于在主循环里使用了 Sleep(0),它位于cocos2dx\platform\win32\CCApplication.cpp,如下:

    while (1)
    {
        if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // Get current time tick.
            QueryPerformanceCounter(&nNow);

            // If it's the time to draw next frame, draw it, else sleep a while.
            if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
            {
                nLast.QuadPart = nNow.QuadPart;
                CCDirector::sharedDirector()->mainLoop();
            }
            else
            {
                Sleep(0);
            }
            continue;
        }
也就是说,该循环除了执行 mainLoop 以外,花了大量时间在检查消息和 Sleep(0) 上面。
并且
// set FPS. the default value is 1.0/60 if you don't call this
pDirector->setAnimationInterval(1.0 / 60);
上面的 60 ,如果改大,不起任何作用,帧速始终是 60 不会变。但如果改到小于60,是可以起作用的。于是,解决 CPU 占用的思路,始于 “是否可以降低循环精度” 的念头。
已知正常情况下,执行 Sleep(1) ,会睡大概 1/50 秒,这个时间并不精确也不准确,看上去无法满足 60 fps 这个流畅度需求。不过,如果游戏运行帧速不需要这么高,比如 30 fps,则该方案大为可行。
经实际测试,将 Sleep(0) 改成 Sleep(1), 再将上面代码中的 60 改成 25, 效果非常显著。但另一个问题来了:如果每游戏循环做的事有点多,时间有点长,那么游戏将被拖慢。

原engine中,同步时间的代码如下:
QueryPerformanceCounter(&nNow);
if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart) {
nLast.QuadPart = nNow.QuadPart;

因为每次在 nLast 中记录 nNow 时间,并用时间差与设定间隔作比较,时间差往往会比设定间隔要大,如果是在不精确的 Sleep(1) 以及每循环负担比较大的情况下,将导致每帧实际所花的时间,会超出设定间隔不少,从而拖慢游戏速度(如果游戏按帧步进计时的话)。
为解决这个问题,改了一下更新nLast 的表达式:
nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % m_nAnimationInterval.QuadPart);
这样每帧的总消耗时间就相当的恒定了。至于在保持 60 fps的情况下,也能让 cpu占用率在0%,可以修改 Sleep(1) 的精度。
通过查找资料,发现 Winmm.lib 库中有timeBeginPeriod(1); timeEndPeriod(1); 函数可以用于该目的,令 Sleep(1) 的精度提升到1毫秒级别,遂动手改之:
1. 添加 Winmm.lib 库的引用,在 CCApplication.cpp 头部添加  #pragma   comment(lib, "Winmm.lib")  语句。
2. 在 while(1) 代码段的前后,分别放上 timeBeginPeriod(1); timeEndPeriod(1);  这样基本就搞定了。

    while (1)
    {
        if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // Get current time tick.
            QueryPerformanceCounter(&nNow);

            // If it's the time to draw next frame, draw it, else sleep a while.
            if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
            {
                //nLast.QuadPart = nNow.QuadPart;
// 2014.6.21
nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % m_nAnimationInterval.QuadPart);
                CCDirector::sharedDirector()->mainLoop();
            }
            else
            {
timeBeginPeriod(1);
Sleep(1);
timeEndPeriod(1);
                //Sleep(0);
            }
            continue;
        }
微信小程序扫码登陆

文章评论

1542人参与,0条评论