3

これはプログラマーの間では大きな秘密のように思えます。誰もこのコードを共有したくありません。なんで?

v-sync を使用せずに FPS を少なくとも 60 に制限できる有効な FPS リミッターが見つかりません。

もちろん、私はそれを正しい方法で行いたいと思っています。だから私はまだ自分のものを作っていません.彼らは皆、fpsリミッターのすべてのトリックを学ぶのに1年かかったと言っています...

編集:これは完璧ではない私の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 :提案されたように待機可能なタイマーを使用して、2回目の試行を行います:

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つのチェックが失敗する可能性があるのではないかと心配しています...これまでのところ、失敗していません。これは、そのサポートを確認する正しいアプローチですか?

4

3 に答える 3

2

システム タイマーを 16.6666 ミリ秒ごとにオフに設定し、そのイベントでレンダリングを行います。さらに良いことに、タイマーでレンダリングとページめくりを行い、次のフレームのレンダリングを開始します。これは大きな秘密ではありません。Windows で高解像度タイマーを使用して実行できます。

これが機能するようになると、ティアリングが発生し、任意のタイマーの代わりに v-sync を待つことにします。

于 2010-11-02T12:44:11.060 に答える
1

DirectXでは、Present()に引数を渡すだけで、現在のスレッドが戻るまでアイドル状態になり、リフレッシュレートの倍数でFPSが制限されます。私はそれを使用しましたが、私のシステムはこのシステムを使用することで約1%のCPU使用率を達成したと言えます。基本的に、現在のコードは間違っています。これは、Sleepがこれまでで最も信頼性の低い関数であり、事実上、ゼロ以外の引数で使用するべきではないためです。

Sleep()と一緒にQueryPerformanceCounterを使用してみることができます。

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);
}

最善の方法は、待機可能なタイマーを使用することです-http ://msdn.microsoft.com/en-us/library/ms682492(v= VS.85 ).aspx 。これにより、タイマーが警告するまでスレッドがスリープ状態になります。

于 2010-11-05T22:04:23.927 に答える
1

私が間違っている魔法がある場合はご容赦ください。しかし、私が理解している限り、VSync とティアリングは密接に関連しています。フレーム制限が何であれ、フレーム バッファーがフレームの途中で反転すると、ティアリングが発生します。これが VSync の目的です。

フレーム制限コードに関しては、プロデューサー/コンシューマー タイム ステップを実行するためのいくつかの手法を次に示します。

http://gafferongames.com/game-physics/fix-your-timestep/

彼の理由は物理学に焦点を当てているようですが、フレーム制限にも完全に当てはまります。

于 2010-11-05T22:09:35.923 に答える