2

私はゲームループと物理学をいじっています。先日、デバッグ ステートメントを追加して、ゲーム ループの各フレームにかかる時間を確認しました。予想通り、結果は 16 ミリ秒台でした。ただし、vsync を無効にしてみましたが、これらの結果は変わりませんでした。明らかに vsync がまだ発生していました。SFML の表示呼び出しをコメント アウトしたところ、フレームが高速化されました。

では、なぜ vsync が動かなくなったのでしょうか? 最初は、DSFML (D 言語の SFML バインディング) のバグに違いないと思いました。SFML を直接使用する C++ で簡単なテスト ケースを作成しましたが、パフォーマンス特性はまったく同じです。

私のシステムは次のとおりです。

$ inxi -SMG
システム: ホスト: c7カーネル: 3.16.4-1-ARCH x86_64 (64 ビット)デスクトップ: i3 4.8 ディストリビューション: Arch Linux マシン: システム: Google 製品: オウム v: 1.0
モボ: 該当なし モデル: N /A Bios: coreboot v: 4.0-4744-gac16405-dirty 日付: 10/23/2013
グラフィック: カード: Intel 第 2 世代コア プロセッサ ファミリ Integrated Graphics Controller
ディスプレイ サーバー: X.Org 1.16.1 ドライバー: intel解像度: 1366x768@ 60.02hz
GLX レンダラー: Mesa DRI Intel Sandybridge Mobile GLX バージョン: 3.0 Mesa 10.3.1

SFML vsync テスト ケースを以下に示します。vsync はオンになっています。

#include <chrono>
#include <iostream>
#include "SFML/Graphics.hpp"

int main()
{
    auto* window = new sf::RenderWindow(sf::VideoMode(640, 480), "test",
        sf::Style::Titlebar | sf::Style::Close);
    window->setVerticalSyncEnabled(true);
    auto firstTime = std::chrono::high_resolution_clock::now();
    while(window->isOpen())
    {
        //print frame timing
        {
            auto secondTime = std::chrono::high_resolution_clock::now();
            using dMsecs = std::chrono::duration<double, std::chrono::milliseconds::period>;
            auto elapsed = dMsecs(secondTime - firstTime);
            firstTime = secondTime;
            std::cout << elapsed.count() << '\n';
        }
        //event handler
        {
            sf::Event e;
            while(window->pollEvent(e))
            {
                if(e.type == sf::Event::EventType::Closed)
                    window->close();
            }
        }
        //render
        {
            window->clear();
            window->display();
        }
    }
}

この問題をグーグルで検索すると、グラフィックス ドライバーが vsync を強制的にオンにしていることを示唆する結果が表示されます。しかし、なぜ vsync がシステム上の他のプログラムで機能するのか疑問に思いました。

今回はSDL2を使用して、別のテストケースを作成しました。

#include <chrono>
#include <iostream>
#include "SDL2/SDL.h"

int main()
{
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = SDL_CreateWindow("test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
    auto firstTime = std::chrono::high_resolution_clock::now();
    auto quit = false;
    while(!quit)
    {
        //print frame timing
        {
            auto secondTime = std::chrono::high_resolution_clock::now();
            using dMsecs = std::chrono::duration<double, std::chrono::milliseconds::period>;
            auto elapsed = dMsecs(secondTime - firstTime);
            firstTime = secondTime;
            std::cout << elapsed.count() << '\n';
        }
        //event handler
        {
            SDL_Event e;
            while(SDL_PollEvent(&e))
            {
                if(e.type == SDL_QUIT) quit = true;
            }
        }
        //render
        {
            SDL_RenderClear(renderer);
            SDL_RenderPresent(renderer);
        }
    }
}

このテスト ケースで vsync を無効にすると、予想どおり、0 ミリ秒の範囲のフレーム時間が表示されます。そのため、SFML が vsync を実装する方法は私のシステムではバグがありますが、SDL は適切に処理しているようです。

この異なる動作を引き起こしている 2 つのライブラリの実装の違いは何ですか? また、それを解決できますか? SFML で正しい動作を得るにはどうすればよいですか?

4

1 に答える 1

0

バギードライバーです。glXSwapIntervalMESA は動作します。glXSwapIntervalSGI に対して返されるポインタは有効であるため、SFML は SDL と同様のアプローチを取らなければこの問題を検出できません。

于 2014-10-21T22:33:33.117 に答える