Я пытался создать простую графическую программу для 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
покроет это ...
Есть ли другой способ надежно дождаться завершения кадра (кроме простого цикла)?
Заранее спасибо, ребята ...