Я играл с игровыми циклами и физикой.
На днях я добавил несколько отладочных операторов, чтобы увидеть, сколько времени занимает каждый кадр моего игрового цикла.
Как и ожидалось, результаты были в диапазоне 16 мс.
Однако я попытался отключить vsync, и эти результаты не изменились.
Очевидно, что vsync все еще происходил. Я закомментировал вызов дисплея SFML и, конечно же, ускорил кадры.
Хорошо, тогда почему vsync зависает? Сначала я подумал, что это ошибка в DSFML (привязки SFML для языка D). Я создал простой тестовый пример на C ++, который напрямую использует SFML, и характеристики производительности точно такие же!
Моя система выглядит следующим образом:
$ inxi -SMG
Система: Хост: c7 Ядро: 3.16.4-1-ARCH x86_64 (64 бита) Рабочий стол: i3 4.8 Distro: Arch Linux
Машина: Система: Google продукт: Parrot v: 1.0
Mobo: N / A модель: N / A Bios: coreboot v: 4.0-4744-gac16405-dirty дата: 23.10.2013
Видеокарта: Интегрированный графический контроллер семейства процессоров Intel второго поколения
Дисплей сервер: X.Org 1.16.1 драйвер: Intel Разрешение: 1366×[email protected]
GLX Renderer: 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();
}
}
}
Поиск этой проблемы в Google дает результаты, свидетельствующие о том, что графический драйвер включает 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, кажется, справляется с этим должным образом.
Какая разница в реализации между двумя библиотеками, вызывающая это разное поведение, и можно ли ее устранить? Как мне получить правильное поведение с SFML?
Это глючный драйвер. glXSwapIntervalMESA работает. Указатель, возвращаемый для glXSwapIntervalSGI, является допустимым, поэтому SFML не может обнаружить эту проблему, не применяя подход, аналогичный SDL.