SDL_PollEvent () заикается во время простоя? - PullRequest
0 голосов
/ 06 декабря 2018

Я собрал очень простой игровой цикл в C ++ с использованием SDL2, и заметил, что каждые несколько секунд SDL_PollEvent кажется необычайно медленным, даже когда ничего не происходит.

Я отправлял свойdeltaTime для поддержки каждого цикла, и его разность составляет около 100 мс в циклах, которые запаздывает в SDL_PollEvent.Я уже подтвердил, что это что-то с этой функцией, перемещая мои таймеры, но я не уверен, где диагностировать проблему дальше.

Мой цикл:

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. Это мое отставание: No Vsync console output

С Vsync.Обратите внимание, что дельта после лага немного короче.Не знаю, почему: Vsync console output

Я также заметил, что эта проблема возникает, даже если я не отлаживаю, и отсутствует по крайней мере на одном другом компьютере.Любые предложения о том, как поступить, будут очень приветствоваться.

РЕДАКТИРОВАТЬ 1: Попытка распечатать на консоли все события, проходящие через очередь, чтобы увидеть, если одно из них вызывает проблему.Добавил строку печати к коду выше.Похоже, что в те моменты, когда была задержка, события не запускались, и в остальном я бездействовал.

РЕДАКТИРОВАТЬ 2: В соответствии с запросом, некоторый исполняемый код, созданный с 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 получен следующий вывод консоли: Console output vsync delta on render

РЕДАКТИРОВАТЬ 4: БОЛЬШЕ ДАННЫХ.Похоже, заикание происходит каждые 3000 мс почти точно.У меня был вывод на консоль только дельты, которые были> 50 мс.Формат изображения: количество игровых циклов |deltaTime |SDL_GetTicks () just bad deltas

Я также считал, что это аппаратная проблема, поскольку у меня нет этой проблемы на другой машине, и я также скачал несколькодругие игры с открытым исходным кодом SDL, и я испытываю то же самое заикание, на расстоянии 3000 мс.Я также вижу ту же проблему на одном и том же оборудовании как в Windows 10, так и в Windows 7. Я не собираюсь публиковать свои спецификации, если кто-то не считает это необходимым, но я уже исключил возможность ошибки моего выделенного графического процессора, увидев то же самоеТочная проблема при запуске игры через RDP с удаленным графическим процессором.

РЕДАКТИРОВАТЬ 5: Похоже, что задержка связана с USB-устройствами.Выполняет ли SDL поиск всех устройств каждые 3000 мс или что-то в этом роде?

После установки моего графического процессора обратно в компьютер я заметил, что отставание значительно уменьшилось, и я заметил, что единственное отличие до и после было в том, что мой USBгарнитура больше не была подключена.

По догадкам я снова запустил свой цикл, на этот раз, наблюдая за deltaTime более 3 мс.Я наблюдал за консолью на предмет изменений, когда убирал устройства: USB device impact

Эврика!Вроде, как бы, что-то вроде.При отсутствии подключенных USB-устройств deltaTime постоянно оставалась ниже 3 мс.Вторичная машина, на которой я тестировал, была ноутбуком, и поэтому не имела подключенных USB-устройств. Я вернулся и протестировал ее с той же USB-мышью, и, как и ожидалось, каждые 3000 мс я видел заметное заикание.

Итак, текущий вопрос: как устройства USB могут вызывать такое заикание?Что делает SDL каждые 3000 мс, что связано с (а) USB-устройствами и (б) SDL_RenderPresent ()?

1 Ответ

0 голосов
/ 06 декабря 2018

Я до сих пор не уверен, что именно является причиной проблемы, но это, безусловно, связано с USB-устройствами.Чем больше устройств подключено, тем дольше происходит задержка, и это происходит почти каждые 3000 мсек точно.

Я откатился с SDL2-2.0.9 до SDL2-2.0.8, и проблема прекратилась.

РЕДАКТИРОВАТЬ: ревизия найдена в https://hg.libsdl.org/SDL/rev/9091b20040cf, кажется, чтобы решить эту проблему в SDL2-2.0.9.

...