Могу ли я ожидать чего-нибудь от функции сна Windows -API? - PullRequest
0 голосов
/ 07 мая 2020

Я пытался создать простую графическую программу для Windows (моя машина имеет windows 10) в CPP, и я изо всех сил пытаюсь зафиксировать частоту кадров.

Вот простая иллюстрация моей проблемы:

inline LARGE_INTEGER
get_wall_clock()
{
    LARGE_INTEGER result;
    QueryPerformanceCounter(&result);
    return result;
}

static LARGE_INTEGER frequency;

inline float
get_seconds_elapsed(LARGE_INTEGER begin, LARGE_INTEGER end)
{
    return (float)(end.QuadPart - begin.QuadPart) / (float)frequency.QuadPart;
}

int main()
{
    bool can_sleep = (timeBeginPeriod(1) == TIMERR_NOERROR);
    QueryPerformanceFrequency(&frequency);
    int target_HZ = 60;
    float target_seconds_per_frame = 1.0f / (float)target_HZ;
    LARGE_INTEGER last_counter = get_wall_clock();
    while(true)
    {
        do_something();

        LARGE_INTEGER end_frame = get_wall_clock();
        float seconds_of_work = get_seconds_elapsed(last_counter, end_frame);
        float seconds_of_frame = seconds_of_work;
        if(seconds_of_work < target_seconds_per_frame)
        {
            if(can_sleep)
            {
                int ms_to_sleep = (int)(1000.0f * (target_seconds_per_frame - seconds_of_work));
                if(ms_to_sleep)
                {
                    Sleep(ms_to_sleep);
                }
            }
            float frame_duration = get_seconds_elapsed(last_counter, get_wall_clock());
            Assert(frame_duration < target_seconds_per_frame);
            while(seconds_of_frame < target_seconds_per_frame)
                seconds_of_frame = get_seconds_elapsed(last_counter, get_wall_clock());
        }
        last_counter = get_wall_clock();
    }
    timeEndPeriod(1);
}

Моя проблема в том, что утверждение на:

Assert(frame_duration < target_seconds_per_frame);

почти всегда срабатывает.

Я попытался внести некоторые корректировки в сумму миллисекунд сна, даже сделал так, что он будет спать только 90% нужных миллисекунд - но, похоже, это не помогло.

Но вот что действительно странно ... Когда я попытался измерить время, в течение которого функция сна фактически спала, следующим методом:

LARGE_INTEGER sleep_start = get_wall_clock();
Sleep(ms_to_sleep);
float seconds_slept = get_seconds_elapsed(sleep_start, get_wall_clock());

я обнаружил, что иногда он спит на waaayyy больше, чем миллисекунды просил. нередко можно увидеть разницу в 10-20 миллисекунд (у меня было время, когда ms_to_sleep было 12, и он фактически спал более 30 миллисекунд).

Есть ли что-нибудь очевидное, что я? м пропал здесь? Я знаю, что в соответствии с документацией, Sleep не гарантируется, что он будет спать в течение запрошенного времени, но я думал, что timeBeginPeriod + настил ms_to_sleep покроет это ...

Есть ли другой способ надежно дождаться завершения кадра (кроме простого цикла)?

Заранее спасибо, ребята ...

1 Ответ

0 голосов
/ 07 мая 2020

Есть ли что-то очевидное, чего мне здесь не хватает?

Честно говоря, да. Вы не читали руководство. Из docs :

По истечении интервала ожидания поток готов к запуску. Если вы укажете 0 миллисекунд, поток освободит sh оставшуюся часть своего временного интервала, но останется готовым. Обратите внимание, что готовый поток не может быть запущен немедленно. Следовательно, поток может не работать до тех пор, пока не истечет интервал ожидания. Дополнительные сведения см. В разделе «Приоритеты планирования».

Sleep не переводится в спящий режим точно на то время, которое вы просили.

...