我可以在Windows上的c ++上检索微秒或非常精确的毫秒数吗?

时间:2012-09-26 14:20:17

标签: c++ windows time timer

所以我制作了一个使用SDL_Delay函数限制frames per second的游戏循环,它看起来像这样:

//While the user hasn't qui

while( stateID != STATE_EXIT )
{
    //Start the frame timer
    fps.start();

    //Do state event handling
    currentState->handle_events();

    //Do state logic
    currentState->logic();

    //Change state if needed
    change_state();

    //Do state rendering
    currentState->render();

    //Update the screen
    if( SDL_Flip( screen ) == -1 )
    {
        return 1;    
    }

    //Cap the frame rate
    if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
    {
        SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
    }
}

因此,当我在60 frames per second(我认为是“眼罩”)上运行游戏时,我仍然可以看到滞后的运动类型,这意味着我看到框架独立出现,导致运动不畅。
这是因为显然SDL_Delay函数不太准确,导致+,- 15 milliseconds或帧之间的差异大于我想要的值。
(所有这些只是我的假设)

所以我只是在寻找一个好的,准确的计时器来帮助我解决这个问题。

有什么建议吗?

5 个答案:

答案 0 :(得分:4)

我认为How to make thread sleep less than a millisecond on Windows

中存在类似的问题

但作为一名游戏程序员,我不依赖睡眠功能来管理帧速率(他们所采用的参数只是最小)。我只是尽可能快地在屏幕上画东西。我在游戏循环中有一堆函数调用,然后我会跟踪我调用它们的频率。例如,我经常检查输入(1000x /秒)以使游戏更具响应性,但我不会检查网络收件箱超过100x /秒。

例如:

#define NW_CHECK_INTERVAL    10
#define INPUT_CHECK_INTERVAL  1
uint32_t last_nw_check = 0, last_input_check = 0;

while (game_running) {
    uint32_t now = SDL_GetTicks();

    if (now - last_nw_check > NW_CHECK_INTERVAL) {
        check_network();
        last_nw_check = now;
    }

    if (now - last_input_check > INPUT_CHECK_INTERVAL) {
        check_input();
        last_input_check = now;
    }

    check_video();

    // and so on...
}

答案 1 :(得分:2)

这是我使用QueryPerformanceCounter创建的用于计时midi序列的小等待函数:

void wait(int waitTime) {
    LARGE_INTEGER time1, time2, freq;

    if(waitTime == 0)
        return;

    QueryPerformanceCounter(&time1);
    QueryPerformanceFrequency(&freq);

    do {
        QueryPerformanceCounter(&time2);
    } while((time2.QuadPart - time1.QuadPart) * 1000000ll / freq.QuadPart < waitTime);
}

要将刻度转换为微秒,请计算刻度差,乘以1,000,000(微秒/秒)并除以每秒刻度的频率。

请注意,有些事情可能会使其失效,例如高分辨率计数器的精度可能不会降至一微秒。例如,如果你想等待10微秒并且精度/频率是每6微秒一个滴答,你的10微秒等待实际上将不小于12微秒。同样,该频率取决于系统,并且因系统而异。

此外,Windows不是实时操作系统。可以在任何时候抢占进程,由Windows决定何时重新安排进程。应用程序可能会在此功能的中间被抢占,并且在预期的等待时间过去很久之后才会重新启动。你真的没什么可做的,但如果它发生的话,你可能永远都不会注意到它。

答案 2 :(得分:2)

使用QueryPerformanceCounter / Frequency。

LARGE_INTEGER start, end, tps; //tps = ticks per second
QueryPerformanceFrequency( &tps );
QueryPerformanceCounter( &start );
QueryPerformanceCounter( &end );
int usPassed = (end.QuadPart - start.QuadPart) * 1000000 / tps.QuadPart;

答案 3 :(得分:0)

SDL_Delay:

This function waits a specified number of milliseconds before returning. It waits at least the specified time, but possible longer due to OS scheduling. The delay granularity is at least 10 ms. Some platforms have shorter clock ticks but this is the most common.

此功能观察到的实际延迟取决于操作系统设置。我建议调查一下 Mutimedia Timer API,特别是timeBeginPeriod函数,用于根据您的要求调整中断频率。

Obtaining and Setting Timer Resolution显示了如何将中断周期更改为大约1ms的示例。这样你就不再拥有15ms的hickup了。 BTW:捕捉时间约为40毫秒。

Waitable Timer Objects也可以解决获得固定时间段的问题。但无论如何,使用多媒体计时器都必须获得合适的分辨率。

使用其他工具来改善计时功能,我们讨论了here

答案 4 :(得分:-1)

每秒60个成名只是美国的电力频率(欧洲有50个,非洲和亚洲有些混合),并且出于硬件舒适的原因,它是视频刷新的频率(在更复杂的显示器上它可以是整数倍) 。这是CRT显示的强制性约束,它仍然是LCD的舒适参考(帧频缓冲区上传到显示器的频率)

眼罩不超过20-25 fps - 不要与视网膜持续性相混淆,大约只有一半 - 这就是电视在每次刷新时交错两个方格的原因。

独立于定时精度,无论硬件设备在缓冲区扫描期间无法更新(否则图像在显示时会发生变化,导致半画断帧),因此,如果你的速度超过一半设备刷新你排在它后面并被迫等待它。

游戏循环中的60 fps仅用于帮助CPU制造商销售更快的CPU。慢慢降到25以下,一切都会变得更加流畅。