游戏开发论坛

 找回密码
 立即注册
搜索
查看: 3701|回复: 9

原创:一个可以精确控制FPS的程序框架

[复制链接]

11

主题

190

帖子

255

积分

中级会员

Rank: 3Rank: 3

积分
255
发表于 2009-5-21 18:12:00 | 显示全部楼层 |阅读模式
经常看到有人讨论如何在主循环中控制帧速的问题,很多人使用Sleep之类的函数,其实Sleep本身虽然能释放CPU,但无法做到精确控制FPS的值,这里介绍一种比较巧妙的框架,对FPS可以做到比较精确的控制,而且也不会占用CPU。

这个框架用到了两个比较关键的函数:
    timeSetEvent,调用这个函数后,操作系统创建了一个后台线程,这个线程由winmm.dll控制,按照指定的频率执行指定某函数或者将某个信号设置为“有信号”。
    MsgWaitForMultipleObjects,这个函数和WaitForMultipleObjects相比,除了等待多个信号外,同时还可以同时等待指定的窗口消息。
这个框架的原理就是首先创建一个Event作为渲染信号,并且用timeSetEvent函数按照帧速频率控制它变为“有信号”


// Create render signal event
HANDLE g_hTickEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
ResetEvent(g_hTickEvent);

// Create time event
MMRESULT g_hEventTimer = ::timeSetEvent(
    (INT)(1000.0f/MAX_FPS),
    1,
    (LPTIMECALLBACK)g_hTickEvent,
    0,
    TIME_PERIODIC|TIME_CALLBACK_EVENT_SET);

在主循环中,使用MsgWaitForMultipleObjects释放CPU,如果等待的结果是渲染信号,则进入渲染函数,如果是窗口消息,则进入消息处理函数


MSG msg;
ZeroMemory( &msg, sizeof(msg) );

while(msg.message!=WM_QUIT)
{
    if(WAIT_OBJECT_0 == MsgWaitForMultipleObjects(1, &g_hTickEvent, FALSE, 1000, QS_ALLINPUT))
    {
        Render();
    }
    else
    {
        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if(msg.message==WM_QUIT) break;
        
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        };
    }
}


源代码下载: http://www.thecodeway.com/blog/w ... 009/05/fpsframe.rar (5.6k)


-----------------
欢迎光临我的博客 http://www.thecodeway.com


59

主题

404

帖子

404

积分

中级会员

Rank: 3Rank: 3

积分
404
发表于 2009-5-21 18:32:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

thanks!

59

主题

404

帖子

404

积分

中级会员

Rank: 3Rank: 3

积分
404
发表于 2009-5-21 18:36:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

试了下, 发现你的程序运行时会占用 2% 的cpu.

若用Sleep(1)则cpu占用率为 0%

30

主题

146

帖子

152

积分

注册会员

Rank: 2

积分
152
发表于 2009-5-21 19:14:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

我也说说我的想法吧。
假设想要稳定的帧数是frame,那一帧花费的时间是t = 1000(ms) / frame
通常的帧数稳定是基于控制1帧的时间为t,但是程序运行时的外部环境可能不是稳定的,因此通常1帧使用的时间不会是t,而是一个接近值。
我的想法是,不控制1帧的时间为t,而是控制n帧的总时间为nt。这样的好处是n帧所累积的误差可以在帧与帧之间被不断修正。最后让n帧的总误差平均到各帧后变得很小。
比如frame = 60, t = 16.666666(ms)
假设第i帧的运行加休眠用了16ms,那么有0.666666的误差,这个误差可以让第i + 1帧少休眠0.666666来补偿。
n帧的总误差在0的左右摆动,努力将误差补偿为0。

休眠,我也是用sleep,比如需要休眠t,那么先sleep(t/2),唤醒进程计算剩余休眠时间t1,sleep(t1/2)。当ti大于0时,继续。
此法和上面的n帧修正配合使用,可以让程序在cpu比较忙的时候也能稳定在需要的帧数,且cpu使用率为0。

59

主题

404

帖子

404

积分

中级会员

Rank: 3Rank: 3

积分
404
发表于 2009-5-21 19:49:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

没必要这么精确吧

2

主题

79

帖子

85

积分

注册会员

Rank: 2

积分
85
QQ
发表于 2009-5-22 11:06:00 | 显示全部楼层

Re: 原创:一个可以精确控制FPS的程序框架


  timeSetEvent用的是系统时钟,记住是软计时器,本身耗的系统资源比起一次Sleep的挂起,唤醒花费更多.

   Event在系统处理时,也占用资源,MsgWaitForMultipleObjects也一样,而且event是系统级的信号.

  Sleep是简单的把当前的线程挂起和唤醒,实际上Sleep比你的方法更省系统资源.

  timeSetEvent不是你想象中哪么精确.

  Sleep容易实现,更方便实时改变sleep的时间.

 

227

主题

1793

帖子

1866

积分

金牌会员

Rank: 6Rank: 6

积分
1866
发表于 2009-5-22 16:02:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

Sleep误差是在太大
大到无法让人接受
我的方法和4楼基本一致
超过1毫秒的部分用sleep
少于1毫秒的部分用系统时钟
我认为这样已经够了
一般来说单核心cpu占用率极少超过50%

59

主题

404

帖子

404

积分

中级会员

Rank: 3Rank: 3

积分
404
发表于 2009-5-22 16:36:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

如果动画是靠时间来插值的话, 帧率完全不是问题.

因为不管帧率是大是小, 动画播放所需的时间是相等的

1367

主题

1993

帖子

2118

积分

金牌会员

Rank: 6Rank: 6

积分
2118
发表于 2009-5-24 12:13:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

这么精确??????????????

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
发表于 2009-5-25 01:25:00 | 显示全部楼层

Re:原创:一个可以精确控制FPS的程序框架

Sleep(1); 即可

PS. timeGetTime() 比 GetTickCount() 精确。
(需要引用 winmm.lib)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-20 04:33

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表