- Android: Формат сжатых текстур
- Сжатие мобильной графики в формат ETC1 и открытая утилита
- Использование сжатых текстур в формате ETC1
- Особенности подготовки атласов перед сжатием в формат ETC1
- Чем можно качественно сжать в формат ETC1?
- Идеи качественного сжатия в формат ETC1
- Идеи ускорения качественного сжатия в формат ETC1
- Достигнутые результаты
Android: Формат сжатых текстур
Привет. Хотел узнать у вас по поводу «железных» текстур.
Сделал поддежку 3х форматов
Все наборы текстур будут идти в комплекте с игрой, и в зависимости от типа поддерживаемого расширения будут загружаться нужные
Выбор по расширирениям
И еще вопрос, как быть с Mali ?
Из расширений которые они поддерживают
Все какие то не ведомые
GL_OES_texture_compression_astc
GL_KHR_texture_compression_astc_hdr
GL_KHR_texture_compression_astc_ldr
GL_OES_compressed_ETC1_RGB8_texture — не пойдет, по причине отсуцтвия альфа канала. Вариант с двумя текстурами, тоже вариант, но пока не до него!
Раздел Android Texture Formats: https://docs.unrealengine.com/latest/INT/Platforms/Android/Refere… extureformats
Я делал билды с ETC2, и нормально работало на малишных девайсах.
wmask
> Раздел Android Texture Formats:
> https://docs.unrealengine.com/latest/INT/Platforms/Android/Refere…
> extureformats
> Я делал билды с ETC2, и нормально работало на малишных девайсах.
Супер, спасибо.
А как узнать поддерживает ли устройсво ETC2 ?
Чет сколько смотрю, у всех GL_OES_compressed_ETC1_RGB8_texture, а чтобы ETC2 ни у кого не ведать
К примеру вот последний Mali
Или поддежка Open GL ES 3.0 автоматически гарантирует 100% что будет работать ETC2 ?
Просто к примеру проц который используется в iPhone 5s хоть и поддерживает ES 3.0 но ETC2 точно нет!
FDsagizi
> А как узнать поддерживает ли устройсво ETC2 ?
Не знаю. Я просто в википедии смотрел: если у девайса гпу мали, то делал билд под ETC2.
FDsagizi
> GL_OES_texture_compression_astc
> GL_KHR_texture_compression_astc_hdr
> GL_KHR_texture_compression_astc_ldr
Это вообще самый крутой формат. Поддерживает всё, можно регулировать степень сжатия. Можно даже сжать так, что плотность данных будет меньше бита на пиксель. Вроде этот формат планируют вводить в следующие версии OpenGL и OpenGL ES.
FDsagizi
> Или поддежка Open GL ES 3.0 автоматически гарантирует 100% что будет работать ETC2 ?
Не факт, что аппаратной поддержки достаточно. Надо, чтобы ещё версия Android была от 4.3.
FDsagizi
> Просто к примеру проц который используется в iPhone 5s хоть и поддерживает ES
> 3.0 но ETC2 точно нет!
А вообще айфоны поддерживают OpenGL ES 3.0? Если проц поддерживает, то не факт, что драйвер есть. Они вроде как свой API Metal продвигать хотели, а на OpenGL ES выше 2.0 забить. Но я не очень за ним слежу, могу и ошибаться.
В общем, если устройство заявляет поддержку OpenGL ES 3.0, но не поддерживает ETC2, то оно врёт и OpenGL ES 3.0 не поддерживает, потому что ETC2 часть стандарта.
FDsagizi
> Все наборы текстур будут идти в комплекте с игрой, и в зависимости от типа
> поддерживаемого расширения будут загружаться нужные
Почему бы не собирать разные APKшки с разными форматами текстур под разные GPU, чтобы пользователи качали только нужные им текстуры? Если ты уже используешь Gradle (а не устаревший ADT), это делается элементарно.
FDsagizi
> И еще вопрос, как быть с Mali ?
Грузить tga.
> Все ли верно?
Да. Я так-же делаю. Но ты врядли встретишь расширение GL_ATI_texture_compression_atitc. GL_AMD_compressed_ATC_texture достаточно
wmask
> Я делал билды с ETC2, и нормально работало на малишных девайсах.
>если у девайса гпу мали, то делал билд под ETC2.
ETC2 не держат Mali ниже T6x т.е. те что не держат OpenGL ES 3.x. Например очень распространенные Mali 400/Mali 450. На каких девайсах это могло работать? может для старых все таки были tga/png ?
Andrey
> ETC2 не держат Mali ниже T6x т.е. те что не держат OpenGL ES 3.x. Например
> очень распространенные Mali 400/Mali 450.
Странно все это. Вот тут Mali 400 упоминается, а по ссылке в моем первом посте написано, что для мали нужно ставить ETC2. В общем, это уже сами разбирайтесь, я глубоко не копался, даю ссылки на вики UE4. Можно, кстати, посмотреть там исходный код, как они определяют, что использовать.
Сам я, естественно, не тестил на старых девайсах, но эпики пишут: Expected — Device has passed Functional testing
Так — по скольку у нас OpenGL ES 3.0 обязателен, и Areno 330 мин видео карта.
Получается что ATI TC не нужен, т.к. Adreno 330 прекрасно работает с ETC2
Adreno 330 и Mali — ETC2
Nvidia — DXT1
Pover WR — PVR
кстати а как дела с графикой от Intel ? Которая на андроиде идет? На компе то — она спокойно работаетc S3TC(DXT1)
Кстати посмотреть поддежку текстур, лучше смотреть через — OpenGL Extension Viewer
FDsagizi
>и Areno 330 мин видео карта.
точнее 305 минимум
>Nvidia — DXT1
>Pover WR — PVR
А разве они в случае OpenGL ES 3.0 не держат ETC2 ? если так то для OpenGL ES 3.0 вообще выбрать ETC2, а лучше GL_OES_texture_compression_astc
Andrey
> > vidia — DXT1
> > over WR — PVR
> А разве они в случае OpenGL ES 3.0 не держат ETC2 ? если так то для OpenGL ES 3.0 вообще выбрать ETC2
Нету таких устройств, надо смотреть — у нас в городе(Астана) либо блотные, либо дешевые, а на тегре — для геймеров уже несыщешь. На каком форме можно задать вопрос, чтобы узнать такую инфу ?
Andrey
> а лучше GL_OES_texture_compression_astc
Хорошо посмотрю! А не подкинете ссылку, где можно глянуть сравнение и как сжать — либу. А то гугл меня немного в ступор вводит))
FDsagizi
> Нету таких устройств, надо смотреть — у нас в городе(Астана) либо блотные, либо
> дешевые, а на тегре — для геймеров уже несыщешь. На каком форме можно задать
> вопрос, чтобы узнать такую инфу ?
То есть ты не веришь, что ETC2 есть везде, где есть OpenGL ES 3.0 и хочешь это проверить?
FDsagizi
> Хорошо посмотрю! А не подкинете ссылку, где можно глянуть сравнение и как
> сжать — либу. А то гугл меня немного в ступор вводит))
Если не ошибаюсь, есть тулза от Mali, которая сжимает в ASTC и ETC1\2. Только для её скачивания надо вроде бы зарегистрироваться на их сайте.
Зачем удалил моё сообщение? Каким таким правилам оно не соответствует?
Источник
Сжатие мобильной графики в формат ETC1 и открытая утилита
При развитии free-to-play мобильной игры вместе с новыми фичами регулярно добавляется и новая графика. Часть ее включается в дистрибутив, часть скачивается в ходе игры. Для возможности запуска приложения на устройствах с небольшим размером оперативной памяти разработчики применяют аппаратно сжатые текстуры.
Формат ETC1 обязателен к поддержке на всех Android-устройствах с OpenGL ES 2.0 и является хорошей отправной точкой оптимизации потребляемой оперативной памяти. По сравнению с форматами PNG, JPEG, WebP загрузка текстур ETC1 осуществляется без интенсивных расчетов обычным копированием памяти. Также улучшается производительность игры по причине меньших размеров данных текстур пересылаемых из медленной памяти в быструю.
На любом устройстве с OpenGL ES 3.0 возможно использование текстур в формате ETC1, являющимся подмножеством улучшенного формата ETC2.
Использование сжатых текстур в формате ETC1
Формат ETC1 содержит только компоненты цвета RGB, поэтому он подходит для непрозрачных фонов, которые рекомендуется рисовать с отключенным Alpha-blending.
Что делать с прозрачной графикой? Для нее задействуем две текстуры ETC1 (далее — 2xETC1):
— в первой текстуре храним исходный RGB;
— во второй текстуре храним исходную альфу (далее — A), скопировав ее в компоненты RGB.
Тогда в пиксельном шейдере 2xETC1 восстановим цвета таким образом:
Особенности подготовки атласов перед сжатием в формат ETC1
Формат ETC1 использует независимые блоки 4×4 пикселя, поэтому положение помещаемых в атлас элементов желательно выравнивать на 4 пикселя, чтобы исключить попадание разных элементов в общий блок.
Все элементы при помещении в атлас слегка увеличиваются по площади, потому что нуждаются в дополнительной защитной рамочке толщиной 1-2 пикселя. Это связано с дробными координатами отрисовки (при плавном движении спрайтов) и с билинейной фильтрацией текстур. Математическое обоснование причин происходящего заслуживает отдельной статьи.
В случае полигональных атласов элементы разводятся на приемлемое расстояние. Все блоки ETC1 при размере 4×4 состоят из пары полосок 2×4 или 4×2, поэтому даже расстояние в 2 пикселя может иметь хороший изолирующий эффект.
Чем можно качественно сжать в формат ETC1?
Имеется выбор среди бесплатных утилит:
Для качественного сжатия графики приходится задавать perceptual метрику, учитывающую особенности восприятия, а также выбирать медленные режимы best и slow. Один раз попробовав качественно сжать текстуру 2048×2048 понимаешь, что это долгий процесс… Возможно поэтому многие разработчики ограничиваются быстрыми альтернативами medium и fast. Можно ли сделать лучше?
История создания с нуля собственной утилиты EtcCompress одним из программистов Playrix берет начало в январе 2014 года, когда финальное сжатие графики в формат ETC1 превысило по длительности трехчасовой поход в гости.
Идеи качественного сжатия в формат ETC1
Формат ETC1 является форматом с независимыми блоками. Поэтому мы используем классический подход сжатия отдельных блоков, который хорошо распараллеливается. Конечно, можно пытаться улучшить стыковку блоков, рассматривая наборы блоков, но в таком случае потребуется информация о принадлежности элементам атласа и резко возрастает вычислительная сложность задачи.
Для сравнения результатов сжатия подходит утилита dssim.
Для каждого блока придется перебрать все 4 возможные режима кодирования, чтобы найти наилучший, в коде функция CompressBlockColor:
— две полоски 2×4, каждая имеющая свой базовый 4-битный цвет, в коде вызовы CompressBlockColor44(…, 0);
— две полоски 4×2, каждая имеющая свой базовый 4-битный цвет, в коде вызовы CompressBlockColor44(…, 1);
— две полоски 2×4, первая имеющая базовый 5-битный цвет, вторая отличающаяся базовым цветом от первой в диапазоне 3-бит, в коде вызовы CompressBlockColor53 (…, 2);
— две полоски 4×2, первая имеющая базовый 5-битный цвет, вторая отличающаяся базовым цветом от первой в диапазоне 3-бит, в коде вызовы CompressBlockColor53 (…, 3).
2×4, 444+444 | 4×2, 444+444 | 2×4, 555+333 | 4×2, 555+333 |
Кстати об ошибке, во многих утилитах используется классический PSNR. Мы тоже используем эту метрику. Выберем весовые коэффициенты из таблицы.
Перейдем к целочисленным значениям, умножив коэффициенты на 1000 и округлив. Тогда начальная ошибка блока 4×4 составит kUnknownError = (255^2) * 1000 * 16 + 1 , где 255 — максимальная ошибка цветовой компоненты, 1000 – фиксированная сумма весов, 16 — количество пикселей. Такая ошибка укладывается в int32_t . Можно заметить, что целочисленное квадрирование близко по смыслу учету гаммы 2.2.
У PSNR есть слабые места. Например, кодирование заливки цветом c0 выбором из палитры c1 = c0 — d и c2 = c0 + d вносит одинаковую ошибку d^2 . Это означает случайный выбор между c1 и c2 влекущий всевозможные шашки.
Для улучшения результата финальный расчет в блоке выполним по SSIM. В коде это делается в функции ComputeTableColor с использованием макросов SSIM_INIT, SSIM_UPDATE, SSIM_CLOSE, SSIM_OTHER, SSIM_FINAL. Идея в том, что для всех решений с наилучшим PSNR (в найденном режиме кодирования) выбирается решение с наибольшим SSIM.
Для каждого режима кодирования блока придется перебрать все возможные комбинации базовых цветов. В случае независимых базовых цветов функция CompressBlockColor44 выполняет независимое сжатие полосок двумя вызовами функции GuessColor4.
Функция GuessColor4 выполняет перебор отклонений и компонент базового цвета:
В случае зависимых базовых цветов возрастает алгоритмическая сложность из-за двойной вложенности циклов полосок. Функция CompressBlockColor53 выполняет перебор отклонений.
Функция AdjustColors53 выполняет перебор компонент двух базовых цветов:
Представленный полный перебор ничем не быстрее наилучших режимов сжатия аналогичных утилит, зато это наш полный перебор, который будет сильно ускорен далее.
В случае графики 2xETC1 полностью прозрачные пиксели в общем случае могут иметь произвольный цвет RGB, который будет умножен на нулевую альфу.
Незначащие пиксели мы можем не учитывать, поэтому отфильтруем их в самом начале, в коде это вызовы FilterPixelsColor. С другой стороны, не всякий прозрачный пиксель является незначащим, вспомним хотя бы защитную рамочку в 1-2 пикселя и эффект отбеливания границ.
Поэтому сделаем трафарет, в котором ноль будет означать незначащий пиксель, а положительная величина покажет значимый пиксель. Трафарет создается на основе канала A применением обводки, чаще размера 1 или 2 пикселя, в коде это функция OutlineAlpha.
Как показала практика, при использовании трафарета улучшаются сжатые границы объектов, а невидимые блоки быстро принимают хорошо пакуемый zip черный цвет. Именно идея трафарета дает заметный выигрыш по качеству в сравнении с раздельным сжатием RGB и A, в том числе перечисленными утилитами.
Таким образом, сжатие 2xETC1 можно представить следующими шагами, реализованными в функции EtcMainWithArgs:
1) сжимаем канал A в формат ETC1;
2) распаковываем сжатый канал A обратно;
3) делаем обводку видимого, где A > 0, получая трафарет;
4) сжимаем каналы RGB в формат ETC1 с учетом трафарета.
Идеи ускорения качественного сжатия в формат ETC1
Чтобы утилита нашла свое применение, помимо качества результата важно и время работы. Рассматриваемый переборный алгоритм сжатия блока достоин быстрой начальной эвристической оценки и полезных отсечений в ходе работы, в том числе на основе жадных алгоритмов.
Для формата с независимыми блоками легко реализуется инкрементальное сжатие. Например, когда сохранились результаты предыдущего сжатия.
В данном случае упаковщик пытается прочитать выходной файл, распаковать его и рассчитать имеющуюся ошибку, это будет начальным решением. Если же файла нет, то берется начальное решение из нулей. В коде это LoadEtc1, CompressBlockColor, MeasureHalfColor.
Последующие шаги должны пытаться улучшить имеющееся решение алгоритмами по возрастанию сложности. Поэтому сначала вызываются быстрые CompressBlockColor44, лишь затем медленные CompressBlockColor53. Такая цепочечная конструкция в перспективе позволит интегрировать сжатие в формат ETC2.
Перед началом перебора вложенными циклами есть смысл найти решение в разрезе цветовых компонент. Дело в том, что наилучшее решение не может иметь ошибку меньше, чем суммарная ошибка наилучших решений для каждой из компонент G, R, B. Часто результирующая ошибка будет существенно больше, что характеризует нелинейность и сложность алгоритма ETC1.
Решения в разрезе цветовых компонент представлены структурами GuessStateColor и AdjustStateColor. Для каждого значения из таблицы отклонений g_table рассчитываются ошибки полосок Half и сохраняются в поля node0, node1, node2. Причем в GuessStateColor в индексах [0x00..0x0F] хранятся рассчитанные ошибки для всех возможных базовых цветов g_colors4, а в индексе [0x10] наилучшее решение. Для AdjustStateColor наилучшее решение хранится в индексе [0x20], все возможные базовые цвета берутся из g_colors5.
Расчет ошибки по компонентам цвета осуществляется функциями ComputeLevel, GuessLevels, AdjustLevels на основе таблиц g_errors4, g_errors5, предварительно рассчитанных функцией InitLevelErrors.
Перебор цветовых компонент есть смысл сделать в порядке возрастания вносимой ими ошибки, для этого осуществляется сортировка полей node0, node1, node2 функциями SortNodes10 и SortNodes20.
Для ускорения самой сортировки применяются сортирующие сети, рассчитанные на тематическом сайте.
Перед выполнением сортировки есть смысл отбросить большие ошибки, превышающие найденное решение. При этом заметно уменьшается количество элементов в полях node0, node1, node2, что существенно ускоряет сортировку и дальнейший перебор.
Третий вложенный цикл по цветовым компонентам G, R, B можно попытаться отсечь, найдя наилучшее решение для текущих G, R функцией ComputeErrorGR, которая в 2 раза быстрее функции ComputeErrorGRB. Это, кстати, горячие места в профилировщике.
В режиме зависимых базовых цветов хорошее ускорение дает поиск наилучшего решения по каждой половинке, потому что найденная ошибка часто превышает оптимистичный прогноз по цветовым компонентам и одновременно является критерием отсечения.
Этим занимаются функции Walk и Bottom.
64 вызова функции AdjustColors53 могут привести к повторным вызовам функций ComputeErrorGR и ComputeErrorGRB с одинаковыми параметрами базового цвета, поэтому будем кэшировать результаты вызовов. В свою очередь, для быстрой инициализации кэша можно использовать ленивые вычисления по третьему цветовому компоненту.
В структуре AdjustStateColor поля ErrorsG, ErrorsGR и поле ErrorsGRB очищаемое LazyGR дают существенный прирост производительности.
После различных алгоритмических улучшений пришло время использовать SIMD, в данном случае опубликовано решение на целочисленном SSE4.1. Данные одного пикселя храним как int32x4_t.
Команды _mm_adds_epu8 и _mm_subs_epu8 удобны для расчета четырехцветной палитры из базового цвета и отклонений.
В функциях ComputeErrorGRB и ComputeErrorGR сначала применяются частично развернутые циклы, оптимизированные командой _mm_madd_epi16, так как в большинстве случаев достаточно ее разрядности. В случае же больших погрешностей работает второй цикл на «медленных» командах _mm_mullo_epi32.
Функция ComputeLevel рассчитывает ошибку сразу для четырех значений базового цвета.
Для сжатия одного канала A можно упростить полученный код сжатия RGB. Будет заметно меньше вложенных циклов и повысится производительность.
Достигнутые результаты
Изложенные подходы позволяют уменьшить требования к оперативной памяти в Android-версиях игр за счет использования сжатых текстур в аппаратном формате ETC1.
В скриптах формирования атласов и самой утилите сжатия уделяется внимание вопросам предотвращения артефактов и повышения качества сжатой графики.
На удивление, вместе с повышением качества сжатой графики удалось ускорить само сжатие! В нашем проекте Gardenscapes сжатие атласов в формат ETC1 на процессоре Intel Core i7 6700 занимает 24 секунды. Это быстрее генерации самих атласов и в несколько раз быстрее предыдущей утилиты сжатия в режиме fast. Предложенное инкрементальное сжатие происходит за 19 секунд.
В заключение приведу пример сжатия текстуры 8192×8192 RGB представленной утилитой EtcCompress под Win64 на процессоре Intel Core i7 6700:
Надеемся, что утилита поможет качественно и быстро сжимать мобильную графику.
Источник