Я собрал очень простой игровой цикл на C++, используя SDL2, и заметил, что каждые несколько секунд SDL_PollEvent кажется необычно медленным, даже когда ничего не происходит.
Я отправил свой deltaTime на консоль в каждом цикле, и разница в циклах, по которым SDL_PollEvent отстает, составляет около 100 мс. Я уже подтвердил, что это что-то с этой функцией, перемещая свои таймеры, но я не уверен, где диагностировать проблему дальше.
Моя петля:
while (!quit) {
uint32_t startTime = SDL_GetTicks();
while (SDL_PollEvent(&e) != 0) {
std::cout << "Event: "<< e.type << std::endl; // Added later, read update
if (e.type == SDL_QUIT) {
quit = true;
}
}
if (engine.AllowUpdate()) { // Restricts updates to every 20ms
GameState::Update();
}
engine.rMan.BeginRender();
//^v Literally just SDL_RenderClear and SDL_RenderPresent
engine.rMan.FinishRender();
engine.deltaTime = SDL_GetTicks() - startTime;
std::cout << std::setw(10) << engine.deltaTime;
}
Консольный вывод без Vsync, обратите внимание на 106. Это мое отставание: 
С помощью Vsync. Обратите внимание, что дельта, следующая за запаздыванием, немного короче. Не знаю почему: 
Я также заметил, что эта проблема возникает, даже если я не занимаюсь отладкой, и ее нет хотя бы на одном другом компьютере. Любые предложения о том, как действовать дальше, будут очень приветствоваться.
РЕДАКТИРОВАТЬ 1: Пытался распечатать для консоли все события, проходящие через очередь, чтобы узнать, не вызвало ли одно из них проблему. В приведенный выше код добавлена строка печати. Казалось, что никакие события не запускаются в то время, когда была задержка, а в остальном я бездействовал.
Обновлено еще раз: По запросу, некоторый исполняемый код, созданный с помощью C++ 14 на VS2017 с SDL2-2.0.9:
#include <iostream>
#include <SDL.h>
void InitSDL();
void BuildWindow();
void BuildRenderer();
SDL_Window* window;
SDL_Renderer* renderer;
int main(int argc, char* args[]) {
InitSDL();
BuildWindow();
BuildRenderer();
bool quit = false;
uint32_t deltaTime = 0;
while (!quit) {
uint32_t startTime = SDL_GetTicks();
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
}
}
deltaTime = SDL_GetTicks() - startTime;
std::cout << deltaTime << std::endl;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
return 0;
}
void InitSDL() {
Uint32 flags = SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS;
SDL_Init(flags);
}
void BuildWindow() {
window = SDL_CreateWindow
("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800, 600, NULL);
}
void BuildRenderer() {
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
}
Собирая это вместе, я заметил несколько вещей:
1. Заикание не происходило без SDL_RenderPresent После двойной проверки, похоже, это не так, однако на SDL_RenderPresent влияет заикание.
Увеличение deltaTime, которое совпадает с заиканием, похоже, происходит где-то во время SDL_PollEvent, о чем свидетельствует то, где назначается deltaTime
Первый deltaTime ВСЕГДА длиннее, хотя я подозреваю, что это как-то связано с некоторыми событиями по умолчанию, запускаемыми при запуске.
РЕДАКТИРОВАТЬ 3: Еще немного покопался. Пытался переместить мое назначение дельты только на SDL_RenderPresent.
Пример фрагмента:
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
std::cout << "Event: "<< e.type << std::endl;
if (e.type == SDL_QUIT) {
quit = true;
}
}
uint32_t startTime = SDL_GetTicks();
//SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
//SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
deltaTime = SDL_GetTicks() - startTime;
std::cout << deltaTime << std::endl;
При включенной vsync на консоли был получен следующий вывод: 
РЕДАКТИРОВАТЬ 4: БОЛЬШЕ ДАННЫХ. Похоже, что заикание происходит каждые 3000 мс почти точно. У меня на консоли были только дельты, которые были> 50 мс. Формат изображения: # циклов игрового цикла | deltaTime | SDL_GetTicks ()

Я также считал, что это аппаратная проблема, так как у меня нет этой проблемы на другой машине, и я также загрузил несколько других игр SDL с открытым исходным кодом и испытываю то же заикание, с разницей в 3000 мс. Я также наблюдаю ту же проблему на одном и том же оборудовании как в Windows 10, так и в Windows 7. Я не собираюсь публиковать свои спецификации, если кто-то не считает это необходимым, но я уже исключил возможность ошибки моего выделенного графического процессора, увидев то же самое. точная проблема при запуске игры через RDP с удаленным графическим процессором.
РЕДАКТИРОВАТЬ 5: Похоже, задержка как-то связана с USB-устройствами. Выполняет ли SDL поиск всех устройств каждые 3000 мс или что-то в этом роде?
После установки графического процессора обратно в машину я заметил, что задержка значительно снизилась, и я заметил, что единственное отличие от того, что было до и после, заключалось в том, что моя USB-гарнитура больше не была подключена.
Думая, я снова запустил цикл, на этот раз наблюдая за любым deltaTime более 3 мс. Я наблюдал за изменениями консоли по мере удаления устройств:

Эврика! Вроде, как бы, что-то вроде. При отсутствии подключенных USB-устройств deltaTime постоянно оставался ниже 3 мс. Вторичная машина, на которой я тестировал, была ноутбуком, и поэтому к ней не было подключено никаких USB-устройств. Я вернулся и протестировал ее с той же USB-мышью, и, как и ожидалось, я заметил заметное заикание каждые 3000 мс.
Итак, текущий вопрос: как USB-устройства могут вызывать такое заикание? Что делает SDL каждые 3000 мс, что связано с (а) USB-устройствами и (б) SDL_RenderPresent ()?
Я переместил свой таймер deltaTime так, чтобы он окружал только цикл SDL_PollEvent, и получил аналогичные результаты с консолью. Когда я переместил свои таймеры, чтобы исключить цикл SDL_PollEvent, консоль показывала стабильную дельту, но у меня все еще появлялось заикание. Попробую скинуть то, что есть, и обновить.
@keltar Вопрос был обновлен запрошенным кодом.
Что-нибудь изменится, если вы перейдете в полноэкранный режим (например, полноценный полноэкранный режим SDL_WINDOW_FULLSCREEN с изменением режима, а не окно без полей размером с рабочий стол) вместо окна?
Никаких изменений для разных типов окон, но я собираюсь немного обновить сообщение. Похоже, это как-то связано с USB-устройствами.





Я до сих пор не уверен, что именно вызывает проблему, но это определенно связано с USB-устройствами. Чем больше подключено устройств, тем дольше всплеск задержки, и он происходит точно каждые 3000 мс.
Я откатился с SDL2-2.0.9 на SDL2-2.0.8, и проблема исчезла.
Обновлено: набор изменений, найденный в https://hg.libsdl.org/SDL/rev/9091b20040cf, похоже, решает эту проблему в SDL2-2.0.9.
Я предлагаю отправить отчет об ошибке регрессии.
@genpfault Похоже, это исправление решает проблему. Добавлю к ответу.
Это связано с количеством подключенных USB-устройств ?! Какого черта? Это сводило меня с ума довольно долгое время. Переключили язык и библиотеку игры, и это продолжало происходить. Большое спасибо за то, что сузили этот вопрос!
Я думал, что схожу с ума, часами отлаживая странные заикания сегодня вечером. Вернулся с v2.0.9 на v2.0.7, и проблема исчезла и для меня. Им действительно нужно выпустить v2.0.10 с вашим исправлением опроса джойстика в нем.
омфг. кто в здравом уме одобрил 2.0.9. количество нелепых ошибок, которые вы должны выследить, чтобы найти еще более нелепый ответ / решение, просто ошеломляет. спасибо OP за подсказку, это не давало мне уснуть всю ночь!
Почему вы думаете, что заикание вызывает PollEvent, а не, например, RenderPresent? Можете ли вы сделать минимальный полный пример, который другие могут проверить на своих машинах (и отредактировать его в вопросе)? Вы уверены, что замедление происходит не из-за printf / cout?