私はゲームループと物理学をいじっています。先日、デバッグ ステートメントを追加して、ゲーム ループの各フレームにかかる時間を確認しました。予想通り、結果は 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 で正しい動作を得るにはどうすればよいですか?