Как оптимизировать алгоритм ограничения fps в программе, использующей glfw для рендеринга окна?
Всем привет.
Я создаю программу с графическим интерфейсом, в рендере главного окна которой будет помогать glfw. Сейчас мне нужно разработать участок кода, который будет задерживать выполнение потока в соответствии с fps. Я уже создал три реализации, но ни одна из них меня не устраивает:
//объявлены в области видимости старше:
//bool vsync = false;
//unsigned int fps = 60;
//float max_frame_duration = 1.0f / (float)fps;
//float delta_time = 0.0f;
//float last_frame = 0.0f;
float current_frame = (float)glfwGetTime();
delta_time = current_frame - last_frame;
//#1 Задержка реализована многократным выполнением цикла. Грузит ЦП. Погрешность < 1 миллисекунды
if (!vsync)
{
while (delta_time < max_frame_duration)
{
current_frame = (float)glfwGetTime();
delta_time = current_frame - last_frame;
}
}
//#2 Задержка реализована функцией из windows.h. Погрешность 3-11 миллисекунд. Критично для большого fps
if (!vsync)
{
if (delta_time < max_frame_duration)
{
Sleep((max_frame_duration - delta_time) * 1000);
current_frame = (float)glfwGetTime();
delta_time = current_frame - last_frame;
}
}
//#3 Задержка реализована функцией из thread. Погрешность 3-12 миллисекунд. Критично для большого fps
if (!vsync)
{
if (delta_time < max_frame_duration)
{
std::this_thread::sleep_for(std::chrono::milliseconds(long long((max_frame_duration - delta_time) * 1000)));
current_frame = (float)glfwGetTime();
delta_time = current_frame - last_frame;
}
}
last_frame = current_frame;
Как мне сделать эту часть программы наиболее эффективной (С погрешностью не более миллисекунды и не загружающей ЦП)?
Код немного изменён, для краткости. Но, если есть необходимость, вот ссылка на полный вариант файла с ним: https://drive.google.com/drive/folders/1yXazuY0fCI3buxBt5VxxpYZ1jE4fwv2W?usp=sharing
P.S. Впервые задаю вопрос в каком-то сообществе. Если что, поправьте.
Ответы (1 шт):
Считаю считать код дельта без учёта времени выполнения отрисовки совершенно неточночным способом, поэтому все твои тесты и провалились.
В любом случае нету такой прям магической функции которая бы считала идеально.
Единственное что могу посоветывать это.
- Запомнить perf counter... NtQueryPerformanceCounter
- Выполнить код фрейма (отрисовка и.т.д.)
- Выполнить повторно NtQueryPerformanceCounter
- Расчитать оставшееся время задержки след фрейма
- Создать задержку через NtDelayExecution
Это всё функии ядра ОС и они будут давать максимально близкий, но не идеальный результат.
Ps: Полезная информация
Pss: Использование функций ядра и идеальной точности не всегда помогают играм. Люди любят старые игры и если думать в первую очередь не о супрер-точности, а об общей работоспособности возможно твоя игра будет работать на Windows XX спустя 10-15 лет. Для примера Lines98 она как работала на 98 так-же работает и на 10 и на 11, чему я очень рад.