Frame time что это
Вступление
На просторах интернета можно найти бессчетное множество статей про видеокарты, но большинство их созданы по одному и тому же принципу: все авторы меряют минимальный и средний FPS, а кто-то еще и максимальный. Насколько ценны эти замеры, насколько объективно они отражают уровень комфорта во время игры? Я пришел к выводу, что не очень, а всё потому, что такая методика совершенно не учитывает микрозадержки, они же микролаги или фризы.
Проблема микролагов известна давно, особенно остро она стояла лет пять назад у владельцев карт ATI. Суть в том, что на долю секунды FPS падает до неприлично низкого уровня, причем делает это с раздражающей регулярностью. В такой ситуации средний FPS будет в полном порядке, поскольку на пару «медленных» кадров приходится тысяча нормальных, а минимальный FPS покажет только худший лаг, он может быть не очень сильным, но проблема в том, что лаги частые!
реклама
В наши дни микролаги преследуют владельцев multi-GPU систем или компьютеров с недостаточным объемом оперативной/видео памяти, а также с банально неудачными версиями драйверов. Кроме того, они проявляются при быстрых перемещениях в плохо оптимизированных для такого поведения движках. Типичные примеры это демо сцены полёта над открытой местностью в шутерах. Огромные локации с высокой детализацией, а тем более «бесшовный» мир обязывают подгружать данные с жесткого диска на лету. Если диск не успевает, фризы не заставят себя долго ждать.
Стоит упомянуть и лаги, возникающие при резком усложнении сцены, а именно при красочных взрывах и разрушениях с реалистичной физикой. С ними такая же проблема: минимальный FPS выявит последствия только самого большого взрыва, а средний FPS практически не будет зависеть от числа этих взрывов.
В такой ситуации не остается ничего другого, кроме как записывать время отрисовки каждого кадра. Тут может помочь популярнейшая программа FRAPS, а точнее ее способность записывать лог frametimes, хотя это еще полдела. Результаты нужно переработать так, чтобы их было удобно воспринимать, и чтобы получить возможность объективно сравнивать разные системы между собой. В данной статье описан мой способ это сделать.
Тестовый стенд и настройки.
Демонстрационные примеры снимались на следующем тестовом стенде:
Что означают 1 % и 0,1 % при тестировании видеокарт и процессоров в играх
Содержание
Содержание
Все чаще при измерении производительности ПК в играх можно заметить показатели «0.1 % Low» и «1 % Low». Большинство неопытных пользователей не придают этому значения и по старинке смотрят только на средний FPS. На самом деле эти показатели очень важны и на них стоит обращать внимание. И вот почему.
Что такое средний FPS и Frame Time
Время, требуемое для отрисовки одного кадра называется Frame time или же «время кадра». Измеряется оно в миллисекундах, но обычно используют частоту кадров (Frame rate), которая обозначает количество кадров, отрисованных за единицу времени. Частота кадров же измеряется в количестве кадров в секунду — Frames per second или же FPS.
Главная единица, используемая при измерении производительности — средний FPS (AVG FPS) за весь промежуток времени. Средний FPS находится по формуле FPS = n/t, где n — количество кадров, отрисованное за все время, а t — время проведения теста. У среднего FPS есть недостаток, который не позволяют ему быть единственной единицей измерения в бенчмарках.
0.1 % минимальный и 1 % низкий FPS
При измерении FPS его среднее значение не является точной величиной, поэтому внимание стоит уделить другим — 1 % низкий и 0.1 % минимальный FPS. В нашем случае важно понимать, что время отрисовки кадра зависит от его сложности. Во время игры могут встречаться карты с большим количеством предметов и NPC в поле видимости игрока, на отрисовку которых будет уходить больше времени. Такие кадры могут задерживаться на экране, в результате чего картинка может фризить и испортить впечатление от игры. Проблема среднего FPS заключается в том, что при замерах время «длинных» кадров усредняется с «быстрыми», поэтому информация о первых теряется.
К примеру, за секунду было отрисовано 30 кадров с таким временем отрисовки в мс:
33, 57, 23, 13, 34, 68, 34, 40, 44, 16, 90, 27, 66, 87, 23, 37, 17, 23, 31, 21, 23, 20, 37, 12, 32, 36, 22, 14, 20, 10
В данном случае средний FPS равен 30 кадрам в секунду, а среднее время отрисовки кадра — 33,3 мс. Общая картина достаточно неплоха, но если взглянуть пристальнее, то можно заметить четыре кадра, время отрисовки которых в два, а то и в три раза больше среднего. Как и было сказано ранее, при высчитывании среднего времени отрисовки кадра и среднего FPS «долгие» кадры теряются на фоне «быстрых», в результате чего значения получаются неточными.
Было принято решение как-нибудь дополнить значения среднего FPS, чтобы лучше описать все кадры.
Существует такое понятие как процентиль, с английского — percentile (в русском языке чаще встречаются персентиль или перцентиль). В нашем случае это можно трактовать как значение, ниже которого находится определенный процент данных из общего набора. У нас 99-процентиль — это значение, ниже которого находятся 99 % данных из общего числа. И, если он равен 90 мс, то 99 % значений времени кадра из примера меньше 90 мс, а 1 % больше или равен этому числу.
В бенчмарках по договоренности используются 99.9- и 99-процентили. Поскольку обычно в качестве единицы измерения применяются FPS, то в данном случае используются обратные 0.1- и 1-процентили FPS. В народе их принято называть 0.1 % минимальный и 1 % низкий FPS. Обычно эти значения оказываются ниже среднего FPS, так как это часть данных, которая описывает редкие игровые события с многочисленным количеством объектов. Это говорит о том, что сложность кадров в сцене непостоянна. Плохо это только тогда, когда 0.1 % минимальный и 1 % низкий FPS «просаживаются» до неиграбельного уровня в результате чего картинка начинает подлагивать. Правда, оценить этот неиграбельный уровень статистически невозможно — для каждого он свой в связи с особенностями человеческого глаза и привычками геймера.
Математические объяснения недостатков среднего FPS (для любознательных)
Между временем кадра и частотой кадров есть математическая связь: значение FPS после отрисовки кадра — мгновенный FPS — обратно времени отрисовки этого кадра:
Поскольку время кадра обычно измеряется в миллисекундах, а частота кадров в единицах в секунду, вышеуказанная формула будет выглядеть вот так:
Например, кадр был отрисован за 25 мс, тогда получается, что мгновенный FPS по окончании его отрисовки был равен 1000/25 = 40 FPS.
Как уже было сказано ранее, средний FPS находится по формуле FPS = n/t. Кроме нее средний FPS можно найти так:
Где t — среднее время кадра, равное t = (t1 + t2 + t3 + … + t-нное)/n
n — общее количество кадров, t1, t2, t3 и т. д. — время отрисовки каждого кадра
То есть, средний FPS — величина, обратная среднему времени кадра. Подтверждается это тем, что время бенчмарка равняется сумме времени отрисовки всех кадров:
t1 + t2 + t3 + … + t-нное = t
Но почему же средний FPS — недостаточно точный показатель измерений? Так происходит, потому что средний FPS не является средним арифметическим значений мгновенного FPS:
FPS ≠ (FPS1 + FPS2 + FPS3 + … + FPS-нное)/n
FPS ≠ (1000/t1 + 1000/t2 + 1000/t3 + … + 1000/t-нное)/n
Для подтверждения этому приведем одну из вышеперечисленных формул:
FPS = 1000n/(t1 + t2 + t3 + … + t-нное)
Значения среднего FPS и среднего значения мгновенного FPS будут равны только в том случае, когда все кадры были отрисованы за одинаковые промежутки времени – t1 = t2 = t3 = t-нное = t, что на практике практически невозможно. В этом и заключается главный недостаток среднего FPS.
Средний FPS далеко не идеален, и при измерении производительности системы в играх ориентироваться только на него не стоит. 0.1% минимальный и 1% низкий FPS наоборот являются очень важными единицами измерения. Если говорить простым языком, то они показывают самые большие просадки FPS за время теста, портящие общее впечатление от игры.
За последние годы можно наблюдать всё растущее понимание, что одного только среднего FPS по какой-либо выбранной для целей тестирования игровой сцене недостаточно для описания производительности компьютерной системы, а минимальный и максимальный FPS в этом деле совсем не помощники. Давайте разберёмся, в чём недостаток среднего FPS, чем так плох минимальный FPS, а также познакомимся с набравшими популярность более удачными мерилами игровой производительности — показателями 1% и 0.1% низкие FPS.
Время кадра, мгновенный и средний FPS
реклама
Отрисовка каждого кадра в игре занимает некоторое время, которое называется, временем отрисовки кадра, или, коротко, временем кадра (frame time). Исчисляется время кадра обычно в миллисекундах (мс), т.е. тысячных долях секунды. Однако в игровых бенчмарках вместо этой характеристики много чаще используется частота смены кадров или, коротко, частота кадров (frame rate), равная количеству кадров, отрисованных за единицу времени. Измеряется частота кадров в количестве кадров в секунду (frames per second, fps), и для краткости частоту кадров также очень часто также именуют аббревиатурой от названия её единицы измерения, т.е. FPS.
Между временем кадра и частотой кадров есть очевидная математическая связь: значение FPS, подсчитанное непосредственно после отрисовки очередного кадра, именуемое обычно мгновенным FPS, есть величина обратная времени этого кадра:
Необходимо только учесть, что время кадра обычно исчисляется в миллисекундах, а частота кадров в единицах в секунду, поэтому итоговая формула для мгновенного FPS будет такова:
реклама
Так, например, если очередной кадр был отрисован, скажем, за 16 мс, то сразу по окончании его отрисовки мгновенный FPS был равен 1000/16 = 62.5 кадра в секунду.
Но главное мерило производительности, это, конечно же, средний FPS по всей игровой сцене, который с одной стороны представляет собой не что иное, как количество кадров n, отрисованных за всё время бенчмарка t
реклама
С другой же стороны, средний FPS можно вычислить как величину, обратную среднему времени кадра
В справедливости утверждения, что средний FPS, вычисленный таким образом, совпадает с данным выше определением убедиться нетрудно, ведь время отрисовки всех кадров равно времени бенчмарка
реклама
Впрочем, всё это, в каком-то смысле, очевидно. А вот что совсем не так очевидно, так это то, что средний FPS не является средним арифметическим значений мгновенного FPS
Математически убедиться в этом, впрочем, опять же несложно: нетрудно заметить, что выражение в левой части неравенства выше
хотя и имеет что-то общее с выражением в правой
но ему в общем случае не равно. При ближайшем рассмотрении видно, что равенство будет иметь место лишь в частном случае, когда все ti равны между собой (t1=t2=. =tn), то есть когда значения времени всех кадров идентичны, что, конечно же, практически невозможно.
Вообще, те читатели, кто неплохо знаком с физикой и математикой, тут уже кое-что должны были увидеть. Если вкратце, то, в математике для некого набора чисел
помимо всем хорошо знакомого среднего арифметического существует ещё несколько средних величин, из которых нам интересна здесь лишь одна, а именно, среднее гармоническое Если словами, то среднее гармоническое по некоторому набору чисел есть обратная величина к среднему от обратных к числам величинам. Звучит, конечно, несколько кошмарно, и не очень понятно, зачем вообще нужно, но сейчас разберёмся. Давайте сразу скажем, что в общем и целом две обсуждаемые средние величины не равны друг другу, за исключением частного случая равенства всех чисел в наборе, x1=x2=…=xn, того самого случая, который для среднего FPS мы отмечали выше.
Так же как и среднее арифметическое, среднее гармоническое находит своё применение в ряде практических задач. Так, например, если некоторый объект несколько раз подряд преодолевает одно и тоже расстояние с разной скоростью, то его средняя скорость на всём пути есть среднее гармоническое скоростей на всех участках. То есть если n раз проехать расстояние d со скоростями v1, v2, …, vn, то время прохождения каждого отрезка составит ti = d/vi, а средняя скорость, равная по определению отношению длины пути, пройденного телом, ко времени, за которое этот путь был пройден, будет равна
т.е. среднему гармоническому скоростей, а не их среднему арифметическому. Например, если Вы по пути на дачу на первом километре попали в “пробку” и двигались со скоростью 30 км/ч, а на втором километре “затор” рассосался и Вы “втопили” уже «под 90», то средняя скорость за 2 километра составила, 2 / (1/30 + 1/90) = 45 км/ч, а не (30 + 90) / 2 = 60 км/ч, в чём легко убедиться. Смотрите, Вы проехали 2 км, и если бы Ваша средняя скорость была равна 60 км/ч, то на дорогу у Вас ушло бы всего навсего 2 км / 60 км/ч = 1/30 ч, т.е. 2 минуты. В реальности же только на первый километр Вы уже потратили 1 км / 30 км/ч = 1/30 ч, эти самые 2 минуты, а затем ещё 1 км / 90 км/ч = 1/90 ч (чуть меньше минуты) ушло на второй километр.
Вообще, среднему арифметическому от скоростей средняя скорость равна лишь тогда, когда тело двигалось с этими скоростями одинаковые промежутки времени, а не одинаковые участки пути, но это уже, как должно быть понятно, не наш случай. Почему? Здесь всё просто — мгновенный FPS суть есть скорость смены кадров на участке длиной в 1 кадр, а не продолжительностью в 1 секунду, а значит и среднюю скорость (средний FPS) следует считать как среднее гармоническое значений мгновенного FPS, а не их среднее арифметическое.
Минимальный, 1% и 0.1% низкие FPS
Что ж, со средним FPS разобрались, едем дальше. Собственно, очень давно известно, что использование каких-либо средних величин в качестве единственных характеристик некоего набора данных — всегда плохая идея. Так, например, в нашем конкретном случае необходимо понимать, что время каждого кадра напрямую зависит от его сложности, и периодически в игре могут встречаться кадры со сложностью, существенно превышающей среднюю, на отрисовку которых, как следствие, уходит заметно больше времени. В результате такие “длинные” кадры задерживаются на экране существенно дольше и могут приводить к визуально заметным “подтормаживаниям” и “фризам”, способным испортить всё удовольствие от игры. И тут надо понимать, что такие “длинные” кадры часто бывают редкими, и проблема использования среднего FPS и состоит как раз в том, что в процессе усреднения значений времени кадра информация о “длинных” редких кадрах теряется.
Поясню на небольшом примере. Пускай, за 1 секунду игрового времени было отрисовано 30 кадров со следующими значениями времени отрисовки в мс:
48, 35, 33, 31, 14, 38, 29, 24, 17, 16, 90, 21, 43, 36, 19, 22, 10, 11, 37, 26, 28, 18, 27, 98, 50, 47, 25, 42, 44, 21
Среднее время кадра равняется 33 мс, а средний FPS — 30 кадрам в секунду. Казалось бы, всё неплохо, но обратите внимание на присутствие парочки очень “длинных” кадров (выделенных жирным шрифтом) со временем отрисовки втрое большим среднего, а именно, 90 и 98 мс. При усреднении значений времени кадров информация о наличии столь “длинных” пускай и редких кадров была потеряна, и в результате полученные средние величины вроде бы сигнализируют о достижении минимального порога играбельности, но на деле визуально заметные “просадки” и “фризы” при подобного рода наборах значений времени кадра неизбежны.
Чем же дополнить средний FPS, чтобы лучше описать весь набор значений времени кадров? Возможно, минимальным значением? Нет, не стоит. Дело в том, что минимальный мгновенный FPS, как любой единичный элемент набора данных, может оказаться грубым выбросом. Например, минимальное значение мгновенного FPS может оказаться таковым не по причине сложности соответствующего кадра, а из-за внешних факторов, например, запланированного старта какой-нибудь службы Windows ровно в момент отрисовки этого кадра. При этом, устранить все внешние факторы, которые могут повлиять на единичное значение мгновенного FPS, практически невозможно, и, что важнее, этого и не требуется, при грамотном подходе к описанию имеющегося набора данных. Но каков же этот грамотный подход?
В математической статистике существует понятие процентиля, которое для наших целей можно определить как значение, ниже которого находится определённый процент данных из набора. Например, 99-процентиль — значение, ниже которого находятся 99% данных из набора. В нашем примере с 30 кадрами, отрисованными за 1 с, 99-процентиль равен 96 мс, и означает это, что 99% значений времени кадра из нашего набора меньше 96 мс, и лишь 1% больше или равен этому значению. Обратите особое внимание, что в нашем конкретном случае из-за малого числа данных в наборе существенной разницы между минимальным значением и 99-процентилем нет, и, как следствие, 99-процентиль здесь ничем не лучше минимального значения в отношении грубых промахов. По сути из всего нашего набора данных лишь единственное значение (минимальное) и не попало “под” 99-процентиль. Однако, если набор данных будет существенно больше, скажем, будет содержать время отрисовки нескольких тысяч кадров, то “длинных” кадров, не попадающих “под” 99-процентиль будет уже порядка нескольких десятков и вместо единственного минимального значения, которое, возможно, является грубым выбросом, у нас будет иметься уже какая-никакая статистика по всем редким “длинным” кадрам. Это обеспечит не только более адекватное описание набора данных, но и значительно лучшую воспроизводимость результатов.
Надеюсь, теперь понятно, чем так хороши процентили, и здесь осталось прояснить лишь какие конкретно процентили использовать. И тут всё, по большому счёту, определяется негласными соглашениями в какой-либо области, и в игровых бенчмарках де-факто стандартом стали 99- и 99.9-процентили времени кадра. Точнее, как уже отмечалось выше, в игровых бенчмарках обычно приводят значения FPS, поэтому и вместо 99- и 99.9-процентилей времени кадра в результатах обычно фигурируют обратные им 1- и 0.1-процентили FPS, именуемые 1% низкий FPS и 0.1% низкий FPS, соответственно. При этом следует понимать, что 1% и 0.1% от всего набора данных — это лишь небольшая часть данных, описывающая редкие и крайне редкие игровые события. Поэтому в самом факте, что 1% низкий FPS и 0.1% низкий FPS оказываются зачастую значительно ниже среднего FPS нет ничего страшного — такая картина лишь говорит о том, что сложность кадров в игровой сцене непостоянна, что совершенно нормально. Плохо лишь, если обсуждаемые показатели «просаживаются» на конкретной игровой системе слишком сильно, выходя за границы играбельности, так как в этом случае нас ожидают визуальные неприятности.
Последнее, о чём, пожалуй, стоит ещё обмолвиться, перед тем, как перейти к выводам, так это так называемый средний за секунду (или по секунде) FPS, а также характеристики на нём основанные, например, минимальный средний за секунду FPS. Этот «зверь», впрочем, простой: средний за секунду FPS — это просто средний FPS на отрезке в 1 с. Равен он количеству кадров, отображённых за одну прошедшую конкретную секунду, но, так же как и средний FPS за всё время бенчмарка, может быть посчитан и как среднее гармоническое значений мгновенного FPS за эту конкретную секунду. Обычно, именно средний за секунду FPS и отображают на экране различные счётчики частоты кадров наподобие FRAPS, так как значение мгновенного FPS пришлось бы обновлять настолько часто, что в этом месиве всё равно бы никто ничего не разобрал. Использовать же значения среднего за секунду FPS вместо значений FPS мгновенного для более детального анализа бессмысленно, так как наиболее важная информация о времени отрисовки «длинных» кадров в них уже потеряна (см. пример выше). А касательно минимального среднего за секунду FPS упомянем лишь, что он, в отличие от минимального мгновенного FPS, может быть больше, скажем, 0.1% низкого FPS, что периодически порождает путаницу и неразбериху.
Неуловимая проблема тайминга кадров
Технический директор Croteam Ален Ладавач, участвовавший в разработке Serious Sam и Talos Principle, рассказывает, как ему удалось найти причину торможения графики даже на самых мощных машинах.
Наконец-то появилось объяснение того, почему некоторые игры тормозят на вашем PC (и луч надежды на то, что в ближайшем будущем они тормозить перестанут).
Т-т-тормоза
Вы с нетерпением ждали следующей части вашей любимой серии видеоигр для PC и она наконец вышла. На этот раз вы хотите насладиться ею во всей полноте, поэтому потратили деньги и время на тщательную подготовку. Вы заменили процессор, поставили сверхсовременную видеокарту, добавили ещё ОЗУ — чёрт возьми, даже купили RAID на SSD. Игра должна быть плавной с самой заставки.
Предзаказ наконец разблокирован и вы только что завершили установку. В нервном предвкушении вы впервые запускаете игру. Пока всё хорошо — она работает с частотой 60 кадров в секунду. Или, по крайней мере, так сообщает счётчик кадров тюнера GPU. Но что-то не так. Вы делаете мышью резкие, хаотичные движения. Стрейфитесь влево-вправо, и тут игра… начинает тормозить! Блин, да как такое возможно? Как она может тормозить при 60 кадрах в секунду?
Если такое с вами никогда не случалось, то это может показаться смешным. Но если вы их испытали, то, скорее всего, ненавидите тормоза всей душой. Тормоза в играх. Это не старый добрый «лаг». Не низкая частота кадров. Это просто «тормоза», происходящие при высоких частотах кадров на идеальных, супербыстрых машинах. Что это, откуда они взялись и как от них избавиться? Позвольте мне рассказать вам историю…
Тормоза, плавность, скорость… это ведь одно и то же?
Видеоигры работали с частотой 60 fps ещё со времён первых аркадных автоматов в 70-х годах. Обычно ожидается, что игра работает с той же частотой, которая используется дисплеем. Так было до популяризации 3D-игр, в которых впервые стала допустимой пониженная частота кадров. В 90-х, когда «3D-карты» (так мы называли их до того, как они стали «GPU«) начали заменять программный рендеринг, люди играли в игры при 20 fps, а 35 fps считались приличным значением для серьёзных сетевых боёв. Я не шучу.
Сегодня у нас есть супербыстрые машины и «разумеется, они могут работать при 60 fps«. Однако количество разочарованных скоростью игр пользователей как никогда велико. Как такое возможно? Проблема оказывается не в том, что игры не могут работать достаточно быстро, а в том, что они тормозят, даже когда могут работать быстро!
Если почитаете разные игровые форумы, то наверняка найдёте подобные сообщения:
Можно подумать, что это единичные проблемы, но посмотрите на статистику поисковых запросов Google:
За последние пять лет тормоза (stutter) стали (относительно) более серьёзной проблемой, чем скорость!
(Учтите, что это относительные значения. Они не значат, что в целом люди спрашивают о торможениях больше, чем о частоте кадров. Они значат, что запросы о частоте кадров (frame rate) остаются на том же уровне, а количество запросов о тормозах растёт, особенно в последнее время.)
Десяток лет в поисках причины необъяснимых тормозов
Пациент скорее жив, чем мёртв, просто тормозит чуть больше, чем нужно.
Впервые я столкнулся с этой проблемой ещё примерно в 2003 году. Мы работали над Serious Sam 2, и пользователи начали отправлять нам отчёты о том, что они тестировали что-то на пустом уровне, и при перемещениях мыши движения не были плавными. Это сопровождалось очень характерным паттерном на графике частоты кадров, который мы прозвали «кардиограммой».
Мы думали, что где-то в коде есть баг, но не могли его найти. Казалось, что проблема появляется и исчезает случайным образом — после перезапуска приложения, перезагрузки машины… а потом игрок менял какую-нибудь опцию скорости и она исчезала. Потом игрок снова включал эту опцию, но проблема не возвращалась. Она была похожа на призрака.
Очевидно, что эта проблема возникала не только у нас. Наблюдая за теми же проблемами в других играх, мы начали думать, что виноваты драйверы. Но это происходило на видеокартах разных производителей. Даже на разных API (OpenGL, DirectX 9, DirectX 11…) — единственным общим у них было то, что они появлялись на разных машинах, в некоторых сценах… иногда.
Несси, бигфут… почти столь же неуловимые, как и проблема с «кардиограммой».
Мы выпустили ещё несколько игр, но это странное поведение по-прежнему появлялось и исчезало. Некоторых пользователей оно раздражало, и мы рекомендовали им изменить опции скорости — иногда это помогало, иногда нет. Такова жизнь, не правда ли?
Но однажды, в отличный зимний день в начале 2013 года мой коллега Дин позвал меня, чтобы я увидел ещё один пример этой проблемы, который он на тот момент мог относительно стабильно воспроизводить. На этот раз проблема возникала на уровне из Serious Sam 3. Мы экспериментировали с опциями в этой сцене, пока до меня внезапно не дошло. Я понял, в чём была причина! И она была очень проста — неудивительно, что она ускользала от всех в течение десятка лет.
Изменив всего одну очень простую опцию игрового движка, мы смогли заставить эту проблему появляться и исчезать в этой конкретной сцене. Но нам стало сразу же очевидно, что на её качественное решение потребуется гораздо больше усилий. Усилий не только с нашей стороны, но и всей игровой экосистемы PC — программистов драйверов GPU, разработчиков API, поставщиков ОС — каждого.
В чём же была причина всё это время
Хотел бы я показать вам её на примере сцены из Serious Sam 3, которую мы с Дином исследовали пять лет назад. Или даже ещё лучше — на примере тестовой сцены из Serious Sam 2, в которой мы впервые её увидели. Но, к сожалению, после замены «железа» этот ускользающий зверь может переместиться в другую сцену. У меня есть сцена из The Talos Principle, в которой мне недавно удалось воспроизвести эту проблему, и я заснял несколько видео, позволившие проанализировать её более подробно.
Но прежде чем мы начнём, убедитесь, что вы на самом деле смотрите видео в 60 fps. Для просмотра представленных ниже примеров переключитесь в 1080p60, как показано на картинке:
Чтобы смотреть видео в 60 fps, переключитесь в YouTube на 1080p60.
Если вы всё сделаете правильно, а ваш компьютер и веб-браузер способны показывать видео с частотой 60 fps, то представленное ниже видео должно воспроизводиться плавно и без всяких тормозов. Если это не так, то именно поэтому мы и говорим об этом — многие другие приложения тоже демонстрируют такое поведение, не только игры. Пока я могу только рекомендовать вам попробовать посмотреть видео на какой-нибудь другой машине, или просто читать текст.
Проверка, проверка, раз, два, три… Вы должны видеть это видео в плавных 60 fps.
А теперь перейдём к делу. Если вы сталкиваетесь с тормозами, то вероятнее всего это выглядит примерно так:
Вот как выглядят «тормоза при 60 fps». Мы называем этот симптом «кардиограммой».
Да, именно так выглядят «тормоза», даже когда игра работает с 60 fps. Вы могли сталкиваться с чем-то подобным в любой современной игре, и вероятно думали, что «игра не оптимизирована». Так вот, вам стоит пересмотреть свою теорию (о том, что такие тормоза возникают из-за «медленного» рендеринга игры). Если игра «слишком медленная», то это значит, что в какие-то моменты она не сможет достаточно быстро отрендерить один кадр, а монитору придётся заново показывать предыдущий кадр. Поэтому когда мы записываем видео такой игры в 60 fps, то видим «пропущенные кадры». (Это такие кадры, при которых следующий кадр не был отрендерен вовремя, поэтому текущий кадр показывается дважды.)
Ну как, нашли? Нет? Странно, не правда ли.
Видео выглядит не плавным, когда смотришь всю анимацию в целом, но когда рассматриваешь покадрово, разрывов нет!
Как такое может быть?
Позвольте мне объяснить более подробно. Вот сравнение идеально плавного видео и видео с тормозами в виде «кардиограммы», воспроизводимые на 1/20 от исходной скорости, чтобы мы могли видеть отдельные кадры:
Сверху правильное видео с 60 fps, снизу «кардиограмма». Воспроизведение замедлено в 20 раз.
Можно заметить две вещи: во-первых, они действительно воспроизводятся с одинаковой частотой — когда сверху есть новый кадр, снизу тоже есть новый кадр. Во-вторых, они по какой-то причине движутся немного по-разному — есть заметный «разрыв» в середине изображения, который становится то более, то менее заметным.
Внимательный зритель может заметить и ещё одну любопытную деталь: нижнее — тормозящее — изображение — которое считается «медленным»… на самом деле «опережает» правильное. Странно, правда?
Если мы посмотрим на два соседних кадра и их тайминги (заметьте, что во всех показанных мной видео были точные таймеры (с точностью 1/10 000 секунды), то можем заметить нечто очень интересное: первые два кадра идеально синхронизированы, но третий…
Шесть идущих друг за другом кадров из видео с точными таймингами. Верхние — правильные, нижние — с «кардиограммой».
…на третьем кадре мы видим, что дерево в «тормозящем» видео значительно опережает свою копию из правильного видео (обведено красным). Также можно заметить, что на этот кадр, похоже, ушло больше времени (обведено жёлтым).
Постойте… если видео «медленнее», и на кадр «ушло больше времени», то как он может опережать правильный?
Чтобы разобраться в этом, вам нужно понять, как в наше время игры и другие трёхмерные интерактивные приложения реализуют анимации и рендеринг. (Опытные разработчики должны простить меня за то, что я надоедаю им с очевидными вещами, но мне нужно быть уверенным, что текст смогут понять все читающие этот текст игроки.)
Краткая история таймингов кадра
Давным-давно, в далёкой-далёкой галактике… Когда разработчики создавали первые видеоигры, они обычно подстраивались под точную частоту кадров, с которой работает дисплей. В регионах NTSC, где телевизоры работали при 60 Гц, это означало 60 fps, в регионах PAL/SECAM, где телевизоры работали при 50 Гц, это означало 50 fps. Они даже и думать не могли о какой-то возможности «пропуска кадра».
Большинство игр было очень вылизанными и упрощёнными концептами, работавшими на конкретном оборудовании — обычно на аркадном компьютере, или на «домашнем микрокомпьютере», наподобие ZX Spectrum, C64, Atari ST, Amstrad CPC 464, Amiga и т.д. По сути, разработчик создавал дизайн, реализовывал и тестировал игру под конкретную машину и конкретную частоту кадров, и был на 100% уверен, что она никогда не пропустит ни кадра.
Скорости объектов тоже хранились в единицах «кадров». Поэтому говорили, не на сколько пикселей в секунду должен двигаться персонаж, а на сколько пикселей за кадр. Известно, что в Sonic The Hedgehog для Sega Genesis скорость вращения, например, была равна 16 пикселям за кадр. У многих игр даже были отдельные версии для регионов PAL и NTSC, в которых анимации вручную рисовались специально под 50 fps и 60 fps. По сути, запуск при любой другой частоте кадров даже не рассматривался.
Поэтому было очень сложно предсказать, сколько займёт симуляция и рендеринг одного кадра. (Стоит заметить, что на современных консолях «железо» по-прежнему неизменно, но сами игры всё равно часто непредсказуемы и сложны.)
Если мы не можем быть уверенными, при какой частоте кадров будет работать игра, нам приходится измерять текущую частоту кадров и постоянно адаптировать физику и скорость анимаций игры. Если один кадр занимает 1/60 секунды (16,67 мс), а персонаж бежит со скоростью 10 м/с, то в каждом кадре он перемещается на 1/6 метра. Но если кадр перестаёт занимать 1/60 секунды, а вместо этого внезапно начал занимать 1/30 секунды (33,33 мс), то надо начать перемещать персонажа на 1/3 метра (в два раза «быстрее») за кадр, чтобы на экране он продолжал двигаться с кажущейся постоянной скоростью.
Как же игра это делает? По сути она измеряет время в начале одного кадра, а затем в начале следующего и вычисляет разность. Это довольно простой способ, но он очень хорошо работает. То есть простите, он работал хорошо. В 90-х (вспомните фразу «35 fps считались приличным значением для серьёзных сетевых боёв» из начала статьи), людей более чем устраивал этот способ. Но в то время графическая карта (не забывайте, их даже ещё не называли GPU) была очень «тонким» элементом «железа», и попаданием объектов на экран непосредственно управлял основной ЦП. Если в компьютере не было 3D-ускорителя, процессор даже сам отрисовывал эти объекты. Поэтому он точно знал, когда они появятся на экране.
Что происходит сегодня
Со временем у нас появились более сложные GPU, и они становились всё более и более «асинхронными». Это значит, что когда ЦП отдаёт GPU команду отрисовать что-то на экране, то GPU просто сохраняет эту команду в буфер, чтобы ЦП занимался своими делами, пока GPU выполняет рендеринг. В результате это привело к тому, что когда ЦП сообщает GPU, что «это конец кадра», GPU просто сохраняет сообщение как ещё один фрагмент данных. Но он не относится к нему как чему-то особо срочному. Да и как он может — ведь ему по-прежнему нужно обрабатывать часть из ранее переданных команд. Он покажет кадр на экране, когда закончит всю работу, которую ему дали раньше.
Поэтому когда игра пытается вычислить тайминги, вычитая метки времени начала двух кадров, то актуальность этого, грубо говоря… весьма сомнительна. Давайте вернёмся к нашему примеру из коротких видео. У нас есть эти кадры, где камера перемещается вдоль деревьев:
Шесть идущих друг за другом кадров из видео с точными таймингами. Верхние — правильные, нижние — с «кардиограммой».
Теперь вспомните то, что я говорил о таймингах и перемещениях. В первых двух кадрах тайминг кадра равен 16,67 мс (то есть 1/60 секунды), и камера движется на одну и ту же величину и сверху, и снизу, поэтому деревья синхронизированы. На третьем кадре (внизу) игра увидела, что время кадра равно 24,8 мс (что больше 1/60 секунды), поэтому она думает, что частота кадров снизилась и торопится переместить камеру чуть дальше… только для того, чтобы обнаружить, что тайминг четвёртого кадра составляет всего 10,7 мс, поэтому камера движется здесь чуть медленнее, и деревья снова более-менее синхронизируются. (Синхронизация восстановится полностью только спустя два кадра.)
Здесь происходит следующее: игра измеряет то, что она считает началом каждого кадра, а эти тайминги кадров иногда по разным причинам колеблются, особенно на такой высоконагруженной многозадачной системе, как PC. Поэтому в некоторые моменты игра думает, что не успевает обеспечить 60 fps, и в какие-то моменты генерирует кадры анимации, рассчитанные на меньшую частоту кадров. Но из-за асинхронной природы работы GPU он на самом деле успевает обеспечить 60 fps для каждого отдельного кадра этой последовательности.
Именно это мы воспринимаем как тормоза — анимация, сгенерированная под изменяющуюся частоту кадров («кардиограмму») на самом деле отображается с правильной постоянной частотой кадров.
То есть, по сути, здесь нет никакой проблемы — всё действительно работает плавно, просто игра об этом не знает.
При этом мы возвращаемся к началу статьи. Наконец обнаружив причину проблемы (на самом деле, это иллюзия проблемы — ведь её на самом деле нет, так?), вот что мы сделали для проверки:
Сначала мы наблюдаем «кардиограмму», а затем используем небольшой трюк, чтобы избавиться от неё.
В первой части видео вы с самого начала можете увидеть проблему с «кардиограммой». Затем мы изменяем «магическую» опцию, после чего всё становится идеально плавным!
И на этом всё? Достаточно сделать так и всё станет замечательно?
Неужели решение настолько простое?
К сожалению — нет. Это всего лишь тест разработчиков. Если мы перестанем замерять частоту кадров в реальных ситуациях и просто будем предполагать, что она всегда равна 60, то когда она упадёт ниже 60 — а на PC она рано или поздно обязательно упадёт по тем или иным причинам: ОС запустит какой-нибудь фоновый процесс, включится экономия энергии или защита от перегрева GPU/ЦП… кто знает — то всё замедлится.
Итак, если мы изменяем частоту кадров, то возникают торможения, если нет — то всё в какие-то моменты может замедляться. Что же нам делать?
Реальное решение заключается в том, чтобы измерять не начало/завершение рендеринга кадра, а время отображения картинки на экране.
Как же нам сообщить игре, что изображение кадра уже показывается на экране? Вы можете удивиться, узнав это — но на сегодняшний день такого способа нет!
Это шокирует, я понимаю. Можно было ожидать, что это базовая функция каждого графического API. Но оказывается, в процессе постепенных улучшений тут и там все, в сущности, упустили сам смысл проблемы. Мы все забыли о тонких деталях своей работы, продолжая повторять одно и то же, а графические API эволюционировали во всех других аспектах, кроме этого: приложение никаким образом не может точно узнать, что кадр на самом деле отображается на экране. Мы можем узнать, когда закончится его рендеринг, но не когда он будет показан.
Что дальше?
Уже ведётся работа по созданию аналогичных и более качественных систем для всех основных графических API. Когда она закончится? Сложно сказать, потому что проблема лежит довольно глубоко внутри различных подсистем ОС.
Однако я заверяю вас, что Croteam безустанно работает над тем, чтобы эта проблема была решена как можно скорее, и все участники экосистемы интерактивной графики понимают и поддерживают наши усилия.
Мы стремимся сделать это решение доступным для более широкой аудитории, и когда это случится, мы подготовим апдейт The Talos Principle с реализацией этой функции.
Различные помехи и другие подробности
Последнюю фразу можно считать концом основного текста. Ниже представлены «бонусные разделы», практически не связанные друг с другом и основным текстом. Вероятно, я буду обновлять их, когда ситуация станет меняться, или в случае возникновения более сложных вопросов, требующих решения в ближайшем будущем.
«Композитор»
Эффект матового стекла? Да, для него нам определённо нужен композитор. Он просто-таки необходим, правда?
За кулисами со всем этим связан концепт под названием «композитный менеджер окон», или композитор. Это система, существующая теперь во всех ОС, которая позволяет окнам быть прозрачными, иметь размытый фон, тени, всплывающие поверх окна Skype и т.д. Композиторы даже могут отображать окна в 3D. Для этого композитор перехватывает управление над последним этапом создания картинки кадра и решает, что ему сделать с ней, прежде чем она попадёт на экран монитора. Это ещё больше всё усложняет.
В некоторых ОС композитор можно отключить в полноэкранном режиме. Но это не всегда возможно, а даже если и возможно — то разве можно запретить запускать игру в оконном режиме?
Управление питанием и тепловыделением против сложности рендеринга
Мы также должны учитывать, что современные ЦП и GPU не работают с фиксированной частотой, а имеют системы, изменяющие их скорости в соответствии с нагрузкой и температурой. Поэтому игра не может просто предполагать, что GPU и ЦП будут иметь одинаковую скорость в каждом кадре. С другой стороны, ОС и драйверы не могут ожидать, что у игры в каждом кадре будет одинаковый объём работы. Чтобы учесть это, необходимо разработать сложные системы для общения этих двух сторон.