Пятничные факты #281 – Немного больше кадров

Spread the love

опубликовал posila

Немного больше кадров

Ранее в FFF (#264): “Неудивительно, что сцены, в которых много дыма или деревьев, могут воровать FPS, особенно в 4K. Может быть, мы должны что-то с этим сделать .”

Иногда это просто ошибка

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

Например, я сделал визуализацию  только для скриншота для FFF-264, и пока писал FFF, я не анализировал их. Сразу после того, как сообщение в блоге было выпущено, я посмотрел на него и задумался – почему дым создает такой огромный шарик перерисовки, когда он едва заметен в игре? Что ж, оказалось, что это во многом связано с ошибкой. Некоторое время назад мы оптимизировали частицы дыма, чтобы они обновлялись только один раз каждые 120 тиков (2 секунды), а их анимация (движение, масштаб и непрозрачность) интерполировалась во время рисования.

Дело в том, что частицы уничтожаются только во время их обновления, если время жизни частицы закончится где-то в середине окна 120 тиков, частица будет по-прежнему нарисована до разрушения. Поскольку дым исчезает и нарастает в течение своей жизни, он будет полностью прозрачным на большой площади. Если частица дыма не рисовалась после своего срока службы, то количество частиц, нарисованных на 15%, уменьшается и еще больше уменьшается число растриуемых пикселей. Кроме того, частицы с непрозрачностью ниже 2% на самом деле ничего не добавляют к окончательному изображению, поэтому мы можем смело не рисовать их, чтобы получить небольшое дополнительное улучшение.

Оптимизация визуализации диапазона стрельбы турели

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

Диапазоны турели в виде карты отображаются в виде непрозрачной геометрии (без спрайтов) в буфере за пределами экрана, который впоследствии отображается полупрозрачно для вида игры. Это позволяет диапазонам турелей сливаться в единую сплошную форму одного цвета. Каждый пиксель записывается для каждой башни в диапазоне, но если он записан один раз, последующие записи не нужны.

У нас было две идеи, как это оптимизировать. Сначала включить проверку трафарета, чтобы пиксели могли быть записаны только один раз. Во-вторых, передать список турелей в графический процессор и проверить, находится ли каждый пиксель в диапазоне любой турели, используя пиксельный шейдер. Идея тестирования трафарета дала примерно 3-кратное ускорение в наших экстремальных тестовых случаях (20×20 турелей), что было недостаточно хорошо – если бы у вашего GPU была проблема с сеткой 3×3, у нее снова были бы проблемы с сеткой 9×3, что не так уж нелепая схема, чтобы иметь. Идея пиксельного шейдера оказалась смешанной – если бы весь экран находился в диапазоне, шейдер был бы молниеносным, но как только пиксели выходили за пределы диапазона, это означало, что шейдеру пришлось бы перебирать весь список турелей к рисунку из-за того, что это не покрывает, производительность начала быстро падать. В худшем случае было бы хуже, чем без оптимизации.

Jiri выступил с идеей сделать предварительный переход, в котором мы будем рендерить геометрию в гораздо меньший буфер (скажем, в 16 раз меньше по ширине и высоте), а затем в шейдере диапазона турели мы будем проверять, находится ли пиксель в определенном диапазоне (пиксель). в буфере предварительного прохождения полностью непрозрачный), определенно вне диапазона (пиксель в буфере предварительного прохождения полностью прозрачен) или мы не знаем (пиксель в буфере предварительного прохождения полупрозрачен из-за линейной фильтрации), и нам нужно, чтобы пиксель находился напротив списка турелей. Он сделал это, и производительность немного улучшилась, но не так, как мы надеялись. После дальнейших исследований мы выяснили, что GPU действительно не нравится ранний выход в пиксельный шейдер. Jiri удалось удалить его, сначала отобразив все определенные случаи, пометив неопределенные пиксели в буфере трафарета, и на другом проходе он запустил шейдер диапазона турели только с трафаретными пикселями. Это решение оказалось в 20 раз быстрее в случаях, которые были слишком медленными с неоптимизированным решением, но по мере увеличения масштаба и увеличения количества турелей, покрывающих меньше пикселей на экране, оригинальное решение станет лучше. Поэтому мы включаем оптимизацию только тогда, когда вы увеличите масштаб.

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

Производительность GPU

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

Когда вы не выполняете никаких математических операций по добавлению динамических деталей, а все детали появляются при рисовании большего количества слоев спрайтов, ядра графического процессора быстро достигают своего предела максимального количества задач, и каждое из них останавливается из-за доступа к памяти. Это не значит, что мы не достигли ограничения пропускной способности памяти на некоторых устройствах. Для случаев, когда мы достигаем пределов пропускной способности памяти, мы добавили опцию рендеринга с глубиной цвета 16 бит (в отличие от обычной 32-битной). Эта опция предназначена для старых и встроенных графических процессоров.

Очевидный способ улучшить это –  рисовать меньше пикселей. Это то, что я упоминал ранее в FFF-227, разделяя тени деревьев от стволов деревьев, чтобы удалить большие области полностью прозрачных пикселей. Это может быть улучшено путем рисования спрайтов не в виде прямоугольников, а в виде общих полигонов, которые обертывают спрайты так, что большая часть полностью прозрачных областей не будет растрирована. Это то, что мы, вероятно, сделаем для самых проблемных спрайтов (деревьев и декоративных элементов).

Еще один способ уменьшить количество затененных пикселей – просто рендерить в более низком разрешении. На самом деле мы уже давно это делаем для источников света, но это может быть использовано для других эффектов, которые не имеют важных высокочастотных деталей, например, для дыма. В конечном счете, некоторые графические процессоры не предназначены для рендеринга игры в разрешении FullHD, несмотря ни на что (например, на ум приходят Intel HD Graphics 2500 или мультимедийные карты, такие как GeForce GT 710 и Radeon HD 6450), поэтому им будет полезен вариант рендеринга. игры в более низком разрешении с наложением графического интерфейса в собственном разрешении.

В FFF-227 я также упомянул mipmaps – уменьшенные копии текстур, которые используются при уменьшении текстуры. Это помогает лучше использовать кэши на графическом процессоре и, следовательно, уменьшает необходимость доступа к основной памяти. Мы уже использовали mipmaps для деревьев и декоративных элементов в 0.16, но, как это ни парадоксально, у некоторых людей были проблемы с производительностью, когда у них были включены mipmaps. Проблема в том, что в 0.16 мы всегда используем трилинейную фильтрацию для текстур с mipmapped. Это означает, что если вы хотите рисовать в виде спрайта в масштабе 75%, графический процессор будет получать пиксель из mipmap со 100% -ным масштабом и mipmap со шкалой 50% и усреднять их, чтобы получить пиксель для версии с масштабом 75%. Доступ к двум разным уровням mipmap замедлит работу. В новом коде рендеринга мы можем контролировать это, поэтому для спрайтов, которые могут вызвать проблемы с производительностью (например, дым), мы можем просто извлечь пиксели из ближайшего более мелкого подробного mipmap.

Сжатие текстур

Графические процессоры изначально поддерживают блочные сжатые форматы – текстура делится на 4×4 пикселя (или, возможно, разных размеров в форматах, которые обычно не поддерживаются GPU ПК), и каждый блок сжимается в фиксированное количество байтов. Обычно поддерживаемые форматы на настольных GPU – BC1-7. Наиболее интересными для нас являются:

  • BC1 (раньше был DXT1) – предназначен для RGB без альфы (или 1-битного альфа) с использованием 4 бит на пиксель (в отличие от 32-битного необработанного RGBA).
  • BC3 (раньше был DXT5) – использует 8 бит на пиксель – тот же формат для цвета, что и BC1, но использует 4 дополнительных бита для альфа-канала.
  • BC4 – хранит только один цветной канал в том же формате, что и альфа-канал в BC3. Таким образом, сохраняется 4 бита на пиксель.

Эти форматы довольно хорошо работают с обычными текстурами, но не очень хорошо с 2D-графикой, которая содержит много мелких деталей. С нашей графикой  все не так плохо, пока спрайты статичны, но как только мы применяем сжатие к анимациям, даже крошечные изменения в отдельных пикселях приводят к большим изменениям в блоках, которые их содержат, и получающаяся анимация выглядит очень шумный.

Несжатая и сжатая ВС3

Разработчики Awesomenouts рассказали об этом в своем блоге о том, как работают сжатые форматы, поддерживаемые графическими процессорами, какие артефакты они создают в своем искусстве и что они делают для улучшения качества. Они хранят свои спрайты с чуть более высоким разрешением (например, на 41% большей шириной и высотой), чтобы разделить детали с более высокой частотой. Это делает сжатие менее эффективным, но оно того стоит. Проблема в том, что мы не можем этого сделать, потому что наши спрайты выглядят довольно плохо и размыто.

Во время наших первоначальных экспериментов со сжатием мы считали, что качество сжатия слишком низкое. Кроме того, это несколько замедлило запуск игры, так как мы сначала создавали атласы спрайтов в несжатом формате и сжимали их в конце процесса загрузки спрайтов. Я оставил параметр «Сжатие текстур» для людей, которым действительно нужно его использовать, и он будет сжимать только спрайты, которые обычно смешиваются с какой-либо другой графикой (например, цветными масками, тенями и дымом).

Наиболее часто используемые форматы сжатия изображений или видео (например, JPEG или H.264) используют тот факт, что человеческое зрение на самом деле довольно плохо распознает цвета и намного более чувствительно к изменениям яркости. Вместо цветового пространства RGB они используют цветовое пространство на основе яркости (яркости) и цветности (цвета) и применяют более качественное сжатие к компоненту яркости и более низкое качество к цветным компонентам, что приводит к очень высокому качеству изображения для человеческого глаза. Некоторые умные люди думали, что эту технику можно использовать для улучшения качества форматов сжатия блоков графических процессоров.

Одной из идей является сжатие YCoCg-DXT, которое использует BC3 в качестве базового формата и сохраняет яркость в альфа-канале для более высокого качества сжатия и цветности в каналах RGB. Пиксельные шейдеры, использующие эти текстуры, должны немного по математике преобразовать цвета из цветового пространства YCoCg в RGB. Мы попытались интегрировать это (используя отдельную сжатую текстуру BC4 для альфа-канала) и были приятно удивлены результатом. Вы, вероятно, не заметите артефакты, если не будете увеличивать масштаб и искать их. Фактически, две недели назад я включил сжатие текстур по умолчанию (и никому не сказал), и всякий раз, когда я спрашиваю кого-то в команде, отключили ли они его, они говорят, что не знали, что оно включено. Так что я очень рад этому. Небольшим недостатком является необходимость использования двух текстур (BC3 + BC4), что дает 12 бит на пиксель, но лучше всего, несмотря на то, что пиксельному шейдеру приходится выбирать из 2 текстур вместо одной, графический процессор способен рендерить в два раза быстрее из-за того, что кэши могут вмещать больше пикселей в сжатых форматах, чем в необработанных форматах.

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

В 0.17 настройка графики сжатия текстур изменяется на выпадающий список, содержащий «Нет», «Высокое качество» и «Низкое качество»:

  • Высокое качество будет использовать пользовательское сжатие YCoCg-DXT и будет использоваться по умолчанию на большинстве компьютеров.
  • Низкое качество будет использовать BC3 и предназначено для использования только на действительно слабых графических процессорах.

У вас не должно быть никаких причин отключать сжатие, возможность сделать это в основном на случай, если возникнут какие-то технические проблемы. Сжатие применяется ко всем спрайтам, кроме GUI, который должен быть максимально четким. Кроме того, независимо от параметра сжатия текстуры, теневые спрайты всегда будут сжиматься в формате BC4.

Несжатое  и сжатие высокого качества и сжатие низкого качества

После того, как мы добавили червей с высоким разрешением, кусак и плевак, использование VRAM возросло до 3,5 ГБ (с включенным высоким разрешением, очевидно), когда не было применено сжатие (даже теневое). Сжатие только теней уменьшило использование VRAM до уровня 0,16 ~ 2,5 ГБ. При включенном сжатии высокого качества использование спрайтов в VRAM в настоящее время составляет ~ 1 ГБ (без mipmap). Это означает, что ваниль должна отлично воспроизводиться в графических процессорах с высоким разрешением с 2 ГБ видеопамяти, а в сочетании с потоковой передачей текстур эти графические процессоры должны поддерживать высокое разрешение даже в тех случаях, когда моды добавляют много новых спрайтов. Спрайты с высоким разрешением изначально предназначались для игроков с самыми мощными компьютерами, но в 0.17 они по сути станут новым стандартом. Цель состоит в том, чтобы в конечном итоге удалить параметры «низкого» и «очень низкого» разрешения спрайтов, поскольку сжатие текстур «низкого качества» на обычных спрайтах + потоковая передача текстур должны быть в состоянии работать даже на графических процессорах с очень маленькими размерами VRAM.

Примечание: я упоминал, что существует 7 форматов BC. BC7 предназначен для текстур RGB или RGBA и потенциально обладает гораздо лучшим качеством, чем BC3, с той же степенью сжатия. Проблема в том, что формат был представлен в DirectX 11, поэтому он не поддерживается оборудованием класса DirectX 10 и недоступен в OpenGL на macOS. Вторая проблема заключается в том, что сжатие чего-либо в этот формат занимает очень очень много времени, поскольку компрессор должен испытать большое количество конфигураций для каждого блока, чтобы найти тот, который дает наилучшее качество. Так как Factorio отличается от других тем, что его искусство распространяется в виде множества файлов PNG вместо того, чтобы все аккуратно упаковывать, чтобы графические ресурсы можно было загружать непосредственно в графический процессор без какого-либо перекодирования в другой формат или динамического создания атласов спрайтов, нам требуется решение для сжатия в реальном времени. Мы не стремимся изменить то, как игра распределяется слишком сильно, поскольку наличие всего в отдельных файлах делает обновления достаточно небольшими, когда мы меняем некоторые из них, а наличие полностью открытых ванильных данных облегчает людям модификацию игры.

Теперь посмотрим на эти графики

Мы взяли несколько эталонов экстремальных сцен. Первый из них – от проекта Clusterio в прошлом году. Твинсен прислал мне сохранение, потому что он получал снижение частоті кадров в середине большого массива паровых турбин. Второй – из сообщения об ошибке. Я выбрал сохранение, потому что у него есть рельсы, идущие через лес, и потому что я мог действительно получить низкий FPS даже на 0,16, я использовал редактор карт, чтобы покрыть землю декоративными травами.

Мы протестировали на графических процессорах с 2 ГБ или 1 ГБ видеопамяти, которые есть в офисе. Тесты для настольных графических процессоров выполнялись на одном ПК (мы только что поменяли местами графические процессоры) – Intel Core i7-4790K, 16 ГБ ОЗУ, Windows 10. Мы измерили время обработки кадра на графическом процессоре для 1000 кадров и усреднили результаты , Мы сравнили его со сборкой 0,17 до того, как были реализованы оптимизации на стороне GPU, к сожалению, у нас нет способа зафиксировать время GPU в 0,16. Тесты проводились в разрешении FullHD (1920×1080) с включенными спрайтами высокого разрешения, с графической конфигурацией, которая, на мой взгляд, является лучшей для производительности рендеринга. Для старой сборки: Mipmaps, специализация Atlas, отдельный атлас нижних объектов опции сжатия текстур включены, использование видеопамяти установлено на All. И эквивалентная конфигурация для новой сборки, за исключением использования новой опции сжатия высокого качества.

Мы также включили результат от одного высокопроизводительного графического процессора (GeForce GTX 980 4 ГБ), но он работал в разрешении 4K (3840×2160) в отличие от FullHD. Тест Intel HD Graphics 5500 выполнялся на ноутбуке с процессором Intel Core i7-5600U и 16 ГБ оперативной памяти, а вместо этого использовалось сжатие текстур низкого качества. Мы также включили результаты с включенной 16-битной глубиной цвета.

Время измерялось в миллисекундах. Чем меньше время, тем лучше, и для 60 кадров в секунду кадр должен занимать 16,66 мс.

Если вам интересно, как графические процессоры работают более подробно, Фабиан Гизен написал хорошую серию статей на эту тему.

Как всегда, дайте нам знать, что вы думаете на нашем форуме.


Комментарии: