2013-09-15 3 views
0

У меня есть симуляция, которую я пытаюсь преобразовать в «реальное время». Я говорю «в реальном времени», потому что это нормально для производительности, чтобы окунуться в случае необходимости (время замедления для наблюдателей и клиентов). Однако, если есть небольшое количество объектов, я хочу ограничить производительность, чтобы она работала с постоянной частотой кадров (в этом случае ~ 100 FPS).Эффективное ограничение рамки

Я попытался sleep() и Sleep() для Linux и Windows, соответственно, но это, кажется, не достаточно точны, как FPS действительно провалов на долю того, что я стремился. Я предполагаю, что этот сценарий распространен для игр, особенно онлайн-игр, но я не смог найти полезный материал по этому вопросу. Каков предпочтительный способ ограничения кадров? Есть ли метод сна, который может гарантировать, что он не откажется от времени больше, чем указано?

Примечание: Я запускаю это на двух разных кластерах (linux и windows), и все узлы имеют только встроенное видео. Поэтому я должен реализовать ограничение на обеих платформах, и он не должен основываться на видеокарте (если есть такая вещь). Мне также нужно реализовать ограничение только на одном потоке/узле, потому что уже существует синхронизация между узлами, а остальные будут автоматически ограничены, если один поток будет правильно ограничен.

Edit: некоторые псевдо-код, который показывает, как я реализовал ограничитель тока:

while (ProcessControlMessages()) 
{ 
    uint64 tStart; 
    SimulateFrame(); 
    uint64 newT =_context.GetTimeMs64(); 
    if (newT - tStart < DESIRED_FRAME_RATE_DURATION) 
     this_thread::sleep_for(chrono::milliseconds(DESIRED_FRAME_RATE_DURATION - (newT - tStart))); 
} 

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

+0

Какова ваша мера приемлемого джиттера? –

+0

+ -20% должно быть хорошо. Это не должно быть очень точным, я просто не хочу, чтобы FPS проходила над крышей, когда объектов меньше. Это нормально было бы хорошо, но теперь я предоставляю ввод для другого моделирования, и результаты становятся непредсказуемыми, когда я имитирую тысячи кадров в секунду. Они не должны быть тесно синхронизированы, но должны оставаться в разумных пределах. – Mel

ответ

2

Для игр ограничитель кадра обычно неадекватен. Вместо этого методы, которые обновляют состояние игры (в вашем случае SimulateFrame()), сохраняют независимость от частоты кадров. Например. если вы хотите переместить объект, то фактическое смещение - это скорость объекта, умноженная на длительность последнего кадра. Точно так же вы можете сделать это для всех расчетов.

Этот подход имеет то преимущество, что пользователь получает максимальную частоту кадров при сохранении реального времени. Однако вы должны следить за тем, чтобы длительность кадров не становилась слишком малой (< 1 мс). Это может привести к неточным расчетам. В этом случае может помочь небольшой sleep с фиксированной продолжительностью.

Как обычно игры справляются с этой проблемой. Вы должны проверить, подходит ли ваша симуляция для этой техники.

+0

спасибо. это, безусловно, стоит расследовать – Mel

1

Вместо того, чтобы каждый кадр старался спать достаточно долго, чтобы быть полным кадром, попросите их спать, чтобы попытаться уснуть. Храните глобальный/потоковый счет времени. для каждого кадра есть «желаемое раннее время окончания», вычисленное от предыдущего желаемого времени не ранее конца, а не от текущего времени

tGoalEndTime = _context.GetTimeMS64() + DESIRED_FRAME_RATE_DURATION; 
while (ProcessControlMessages()) 
{ 
    SimulateFrame(); 
    uint64 end =_context.GetTimeMs64(); 
    if (end < tGoalEndTime) { 
     this_thread::sleep_for(chrono::milliseconds(tGoalEndTime - end))); 
     tGoalEndTime += DESIRED_FRAME_RATE_DURATION; 
    } else { 
     tGoalEndTime = end; // we ran over, pretend we didn't and keep going 
} 

Примечания: это использует ваш пример-х sleep_for, потому что я хотел показать минимальное количество изменения для его принятия. sleep_until работает лучше здесь.

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

Примечание: Вы не можете получить какое-либо время в течение 2 мс (20% джиттера на 100 кадров в секунду) на современных потребительских ОС. Квант для потоков на большинстве потребительских ОС составляет около 100 мс, поэтому в тот момент, когда вы спите, вы можете спать за несколько квантов, прежде чем настанет ваш черед. sleep_untilможет использовать специальную технику ОС, чтобы иметь меньше дрожания, но вы не можете положиться на нее.

+0

спасибо, что это очень информативно. Я думаю, что это приемлемо, потому что, если кадр заканчивается очень быстро (<8 мс для 120FPS), то, если я приостановил один поток за <200 мс, я могу по-прежнему компенсировать 100 FPS или если его спит дольше просто компенсирует то, что я могу (еще лучше, чем то, что Я делал это раньше!) Спасибо! – Mel

Смежные вопросы