C++ C++;:在哪里可以获得不使用';你不使用v-sync吗?

C++ C++;:在哪里可以获得不使用';你不使用v-sync吗?,c++,windows,opengl,frame-rate,C++,Windows,Opengl,Frame Rate,这在程序员中似乎是一个巨大的秘密,没有人愿意为此分享他们的代码。为什么? 我找不到一个可以在不使用v-sync的情况下将FPS限制在至少60的工作FPS限制器 当然,我想用正确的方法来做。所以我还没有做出自己的决定,因为他们都说花了一年时间才学会fps限制器的所有技巧 编辑:这是我的fps限制器代码,它并不完美,但我尽了最大努力,它仍然会撕裂: timeBeginPeriod(1); frame_start_time = TimerGetTime(); while(!done){ i

这在程序员中似乎是一个巨大的秘密,没有人愿意为此分享他们的代码。为什么?

我找不到一个可以在不使用v-sync的情况下将FPS限制在至少60的工作FPS限制器

当然,我想用正确的方法来做。所以我还没有做出自己的决定,因为他们都说花了一年时间才学会fps限制器的所有技巧

编辑:这是我的fps限制器代码,它并不完美,但我尽了最大努力,它仍然会撕裂:

timeBeginPeriod(1);

frame_start_time = TimerGetTime();

while(!done){
    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
        if(msg.message == WM_QUIT){
            done = 1;
        }else{
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }else if(active){ 
        draw_everything();
        SwapBuffers(hDC);

        // fps limiter:
        one_frame_limit = 1000.0f/(float)framerate_limit; // 16.666 ms
        while((time_left = one_frame_limit-(TimerGetTime()-frame_start_time)) > 0){
            if(time_left >= 6.0f){
                Sleep((int)(time_left/6.0f));
            }else{
                Sleep(0); // sleep less than 1ms
            }
        }
        frame_start_time = TimerGetTime();
    }
}
EDIT2:这是我的第二次尝试,按照建议使用可等待计时器:

float one_frame_limit = 1000.0f/(float)framerate_limit;
float time_left = one_frame_limit-(TimerGetTime()-frame_start_time); // 4.7432ms
liDueTime.QuadPart = -(LONGLONG)(time_left*10000.0f);
if(SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0)){
    WaitForSingleObject(hTimer, INFINITE);
}
while((time_left = one_frame_limit-(TimerGetTime()-frame_start_time)) > 0.003f){
    Sleep(0);
}
frame_start_time = TimerGetTime();
我觉得效果更好。但是仍然在流泪。。。注意,我在那里添加了while循环,因为它比没有它时更容易撕裂

--

另一个问题:此初始化安全吗

HANDLE hTimer = NULL;
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -100000LL; // testing timer: wait for 10ms

hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
if(hTimer == NULL){
    waitable_timer_supported = 0;
}else if(!SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0)){
    waitable_timer_supported = 0;
}else if(WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0){
    waitable_timer_supported = 0;
}

我担心即使支持等待计时器,最后2次检查也可能失败。。。到目前为止,它还没有失败。这是检查其支持的正确方法吗?

将系统计时器设置为每16.6666ms关闭一次,并在该事件上进行渲染。更好的是,在计时器上进行渲染和页面翻转,然后开始渲染下一帧。这不是什么大秘密,你可以在windows中使用高分辨率定时器来完成


一旦工作正常,您将看到正在撕裂并决定等待v-sync而不是某个任意计时器。

在DirectX中,您只需将一个参数传递给Present(),该参数将使当前线程空闲,直到它返回,从而将FPS限制在刷新速率的某个倍数。我使用过它,可以说我的系统通过使用这个系统实现了大约1%的CPU使用率。您当前的代码基本上是错误的,因为Sleep是最不可靠的函数,简言之,您实际上不应该将它与非零参数一起使用

您可以尝试将QueryPerformanceCounter与Sleep()一起使用

大整数频率,开始,结束;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&begin);
QueryPerformanceCounter(&end);
const unsigned uu int64 waiticks=static_cast(static_cast(1000)/60));
while(end.QuadPart-begin.QuadPart

最好还是使用一个可等待的计时器-。这将使你的线程休眠,直到计时器发出警报。

如果有什么魔法使我出错,请原谅,但据我所知,VSync和撕裂是密切相关的。不管你的帧限制是什么,如果帧缓冲区在帧中间翻转,你仍然会被撕开。这就是VSync的用途

对于帧限制码,以下是一些用于执行生产者/消费者时间步进的技术:



他的理由似乎集中在物理上,但它也完全适用于帧限制。

我不明白。要限制帧速率,您可以继续执行其他工作,直到有足够的时间渲染另一帧,也可以只睡觉不做任何操作。问题是什么?VSync是一种非常好的方法,尽管你可以肯定它会自动选择一个合理的速率,即使在“奇数”硬件上也是如此。在70Hz显示器上以60Hz的频率渲染可能会看到很多撕裂。那么您已经实现了限制器了吗?它有什么问题?垂直同步正是解决撕裂的方法。如果不使用vsync,就无法消除撕裂。撕裂是在屏幕仍在绘制图片时切换帧缓冲区引起的,这导致屏幕的一半显示上一帧(接缝是撕裂)。Vsync是屏幕准备再次从顶部开始绘制的时刻-使您能够在不撕裂的情况下切换帧缓冲区。那么是否可以避免v-sync使用我100%的cpu?我的FPS限制器现在只使用3-7%的cpu,我希望这样。atm我的gfx卡v-sync有缺陷,它也会撕裂。使用非v-sync fps限制器的最重要原因是为了减少cpu使用量,这样当我切换窗口一秒钟时,我的整个计算机不会延迟。你在v-sync上立即翻页,对吗?然后渲染后的下一帧,除非是完整帧,否则不要翻转。只是检查一下…你说的完整框架是什么意思?我要等到帧达到16.66ms?我的意思是你已经完成了渲染。然后,您必须等待下一次v-sync翻页。您可以在等待时开始将下一帧渲染到另一个缓冲区。你必须在v-sync上翻转到一个完整的帧,否则会发生撕裂。@phkahler:你能提供示例代码来说明这个过程如何与我当前的代码示例不同吗?不幸的是,我的gfx卡v-sync也会撕裂,但至少它总是在同一个位置撕裂(从顶部开始约100像素)@Newbie:听起来不对。如果你有一个nVidia视频卡,你可以强制所有3D应用程序使用VSync(也许还有其他的,虽然我从来没有一个非nVidia的卡,我麻烦了w/3D设置)。你试过这个吗?另外,您获得的帧速率是多少?您是否使用双缓冲?我有ATI卡,我的nvidia卡在默认情况下在所有应用程序上都支持v-sync。它真的很好,没有撕裂,也没有高CPU使用率。我想ATI真是糟透了。但英伟达卡也快了10倍。我的屏幕刷新率是60,每秒60帧,我使用双缓冲。@Newbie:愚蠢的建议,但你应该确保安装最新的ATI驱动程序。我在谷歌的某个地方看到,更新驱动程序为一个人解决了类似的问题。也许你会很幸运…我怀疑这也能修复我的笔记本电脑,因为v-sync完全不能使用它。对不起,我在使用opengl,忘了添加标签。我以前尝试过Sleep(0),但它的cpu使用率为100%或接近100%。@新手:尝试使用可等待计时器。我尝试了你的代码,但它似乎没有任何作用,我的fps似乎根本没有受到限制。不适用于男性
LARGE_INTEGER freq, begin, end;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&begin);
QueryPerformanceCounter(&end);
const unsigned __int64 waitinticks = static_cast<unsigned __int64>(static_cast<double>(1000)/60));
while(end.QuadPart - begin.QuadPart < waitinticks) {
    Sleep(0); // If someone else wants to run, let them.
    QueryPerformanceCounter(&end);
}