Видеокарта для рендеринга

Зачем оно нужно?

Современные видеокарты – это настоящие вычислительные монстры, вся мощь которых обычно тратится на игры. Неглупые люди смекнули, что если организовать программистам прямой доступ к вычислительным блокам видеочипов, то можно всю эту колоссальную мощь задействовать под любые другие задачи, а не только обработку 3D-графики.
Первой в реализации этой идеи преуспела компания NVIDIA со своей архитектурой параллельных вычислений CUDA (Compute Unified Device Architecture). При помощи расширенного синтаксиса языка C и особого компилятора разработчики получили возможность задействовать для вычислительных задач графический чип. AMD, в свою очередь, представила Stream SDK – свое фирменное видение CUDA.
Результат был феноменальный – процессы, связанные с обработкой медиаданных, что подразумевает высокий уровень распараллеливания, завершались в разы быстрее, чем в случае вычислений силами центрального процессора. Особенно явно преимущество GPU проявлялось при рендеринге в программах 3D-моделирования и видеообработке.

Год спустя после выхода CUDA консорциум Khronos Group выпустил фреймворк OpenCL. Фактически он должен был унифицировать код для доступа к вычислительным мощностям процессоров на разных архитектурах, включая видеоядра. С этого момента в профессиональный софт начала активно внедряться поддержка нового фреймворка.
На сегодняшний день OpenCL поддерживают программы Adobe, медиаконвертеры, ряд популярных 3D-рендеров, CAD и софт для математического моделирования.

Лучше CUDA или OpenCL?

Очень частый и очень интересный вопрос вынесен в подзаголовок. Эти две технологии, как непохожие братья. Как и многострадальный PhysX, CUDA – технология закрытая, поддерживаемая только чипами NVIDIA и далеко не всем специализированным ПО. OpenCL – экстраверт, код открыт любому энтузиасту, любое ПО с поддержкой вычислений на GPU по определению работает с OpenCL.
Программисты NVIDIA не лаптем щи хлебают – если взять две сферические видеокарты в вакууме с одинаковой производительностью, то CUDA на чипе NVIDIA показывает в среднем на 20% большую производительность, чем OpenCL на чипе AMD. Но есть, как говорится, нюанс – если CUDA от NVIDIA работает быстро и хорошо, то OpenCL на картах этой компании немного уступает скорости обработки OpenCL от AMD. Несколько лет назад ситуация была совсем плачевная, но со временем с помощью драйверов разрыв удалось наверстать. Тем не менее, удельная производительность NVIDIA GeForce в OpenCL до сих пор немного ниже таковой у AMD Radeon. Поэтому в самом дурном положении окажутся те, кто приобрёл карту NVIDIA для работы с приложением, поддерживающим исключительно OpenCL — сам адаптер выйдет дороже, а его эффективность может быть ниже, чем у Radeon. Такая игра свеч не стоит.

Железо

Прекрасный мир OpenCL я открыл для себя лишь этим летом, купив сразу две видеокарты AMD Radeon серии 300: SAPPHIRE NITRO R9 380 и SAPPHIRE Tri-X R9 390X. Одну из них планировалось сдать обратно в магазин в зависимости от результатов домашних тестов. Карты покупались для надомного видеомонтажа, выбор в сторону Radeon был вполне осознанным: с одной стороны, CUDA работает быстрее, чем OpenCL. С другой, как выяснилось, OpenCL поддерживается значительно большим количеством профессионального софта, чем CUDA, а производительность карт NVIDIA в OpenCL оставляет желать лучшего.

Из предложенного ассортимента карты SAPPHIRE мне понравились более остальных. В отличие от любителей референсного дизайна, SAPPHIRE использует в системе охлаждения классические вентиляторы, которые работают значительно тише референсных центробежных ветродуев – к таким у меня выработалась стойкая неприязнь после беглого знакомства с видеокартой-пылесосом Radeon 4870×2.
Дома при распаковке двух огромных коробок я почувствовал себя замшелым мастодонтом – видеокарты немаленькие. SAPPHIRE R9 390X так и вовсе огромная, с тремя вентиляторами и радиатором, превышающим размеры печатной платы. Сперва я даже поволновался, влезут ли эти монстры в мой корпус. К счастью, влезли, но из корзины для жестких дисков пришлось демонтировать один хард. Киловаттный блок питания также был не лишним – R9 390X требует два четырехконтактных разъема питания, а такой ток вытянет не каждый БП.

Итак, мой домашний конфиг, на котором и проводились сравнительные тесты OpenCL:

  • Процессор: Intel Core i5-2500K, разогнанный до 3.7 ГГц
  • Оперативная память: 12 Гбайт DDR-1333
  • Материнская плата: ASUS P8Z77-V PRO
  • Накопители: системный SSD A-DATA 120 Гб, для контента HDD WD Black WD20EARS 2 Тб
  • Блок питания: Corsair 1000 Вт

Тесты

В качестве тестового проекта я выбрал двухминутный ролик, состоящий из множества отрезков с видео Full HD с битрейтом 72 Мбит/с и фреймрейтом 24 кадра в секунду. Поверх всего этого безобразия был наложен ускоряемый эффект Lumetri Color, которым я провел цветокорррекцию. На выходе должен был получиться ролик в формате h.264, в разрешении 1920х1080 (то есть без изменений), битрейтом 6-7 Мбит/с, применялась двухпроходное кодирование.

Для подтверждения работы видеокарты я снимал параметры GPU-Z – глядя на частоту графического ядра, легко понять, когда рендеринг видео идет силами центрального процессора, а когда GPU.


В первом тестовом прогоне я отключил эффект Lumetri Color, так что весь рендеринг заключался в изменении битрейта видео.
Прогон 1:
проект 2 минуты, h.264, 6-7 mbps, без эффектов

CPU 3:09
SAPPHIRE Tri-X R9 390X 2:33
SAPPHIRE NITRO R9 380 2:38

Без применения эффектов разница в скорости рендеринга между процессором и мощной современной видеокартой очень невелика. При обработке видео общей длительностью около часа выигрыш от использования OpenCL будет более заметным, но все равно очень незначительным. Тем не менее, практически всегда в процессе монтажа к видео применяют эффекты цветокоррекции, поэтому данный тест стоит считать «синтетическим».
Прогон 2:
проект 2 минуты, h.264, 6-7 mbps, эффект Lumetri Color

CPU 11:33
SAPPHIRE Tri-X R9 390X 2:42
SAPPHIRE NITRO R9 380 2:48

Результаты говорят сами за себя – если обе видеокарты играючи рендерили видео чуть медленнее риалтайма, то процессор на рендеринг каждой минуты тратил почти шесть минут. И это только с одним включенным эффектом! Если перед тестом я рассчитывал в том числе обработать часовой ролик с цветокоррекцией на всей продолжительности, то после полученных результатов от этой идеи решил отказаться. В своей работе я применяю цветокоррекцию для небольших отрезков видео, и час-два рендера меня не сильно напрягают. Терять же четыре-пять часов в тестовых целях мне было некогда.
Экстраполируя результаты, можно считать, что с цветокоррекцией длительностью 60 минут процессор справился бы за 4.5 часа, тогда как видеокартам потребовалось бы менее одного часа!

Выводы

По результатам тестов я оставил себе SAPPHIRE NITRO R9 380 – карта стоит заметно дешевле наикрутейшей R9 390X, но в Premiere Pro производительность двух адаптеров практически идентична. Учитывая, что адаптер покупался для выполнения работы, а значит зарабатывания денег, потраченных 17 тысяч рублей совсем не жалко. Тем более, что и в GTA V карта показала себя молодцом, но это тема совсем для другой заметки.
Что касается опыта применения OpenCL, то нельзя не признать – в мир видеомонтажа пришел спаситель: рендеринг превратился в удовольствие. По сравнению даже с разогнанным Intel Core i5, видеочипы играючи обрабатывают видео с наложенными эффектами в Premiere Pro. При таких результатах тестирования не стоит вопроса, использовать ли рендеринг силами GPU. Вопрос лишь в том, какую видеокарту под это приспособить. Что-нибудь из верхнего игрового сегмента будет в самый раз, например, AMD Radeon R9 3xx. Мои нужды полностью удовлетворил SAPPHIRE NITRO R9 380. Но адаптеры среднего и даже начального уровня также поддерживают OpenCL, а значит заметно ускорят вашу работу в профессиональном софте.

Вы можете помочь и перевести немного средств на развитие сайта

Качественный скалинг

Не секрет, что штатный скалер в программе Adobe Premiere Pro один из самых плохих среди прошумер программ нелинейного редактирования. Поэтому на различных форумах по Adobe Premiere Pro есть большие ветки по методикам вывода видео из программы для качественного скалирования третьими программами. Некоторые пользователи Adobe Premiere Pro, даже не заметили появление функции Maximum Render Quality (Максимальное качество рендеринга) для качественного скалирования видео. А те кто заметил и пользуются, не могли не отметить главный недостаток использования Maximum Render Quality (Максимальное качество рендеринга) – очень долгий просчет. Так вот появился третий способ, который лишен недостатков первых двух, использование движка: Mercury Playback Engine GPU Acceleration (Аппаратное GPU-ускорение ядра Mercury Playback). При использовании CUDA видеокарты, мы получаем качество лучше чем при установленной галке Use Maximum Render Quality (Наилучшее качество визуализации). И к тому же просчет будет быстрее чем без установленной галки Use Maximum Render Quality (Наилучшее качество визуализации), и намного быстрее, чем с установленной (иногда в десятки раз). Подробнее о методах скалирования и используемых алгоритмах читаем . Небольшой нюанс: если мы выводим с таймлайна 1920х1080 видео в SD Widescreen…

То получаем черные полосы побокам:

Поэтому создаем новую последовательность: File > New > Sequence (Файл > Создать > Эпизод) или нажимаем комбинацию горячих клавиш: Ctrl+N. И выбираем целевой SD пресет:

Копируем и вставляем туда HD видео или последовательность (Ctrl+C, Ctrl+V). И уменьшаем Scale (Масштаб) до 55%.

Shift+3, Ctrl+M и выбираем пресет: PAL DV Widescreen (PAL DV, широкоэкранный).

Второй вариант, тот же пресет, но ставим галку перед пунктом: Use Maximum Render Quality (Наилучшее качество визуализации).

Третий вариант экспорта. Выполняем: Project > Project Settings > General (Файл > Настройки проекта > Общие…). Выбираем Renderer: Mercury Playback Engine GPU Acceleration (Средство рендеринга: Аппаратное GPU-ускорение ядра Mercury Playback).

Нажимаем ОК. Потом нажимаем: Delete Previews.

В окне Program (Программа) выбираем для Playback (Разрешение при воспроизведении) и Paused Resolution (Разрешение при приостановке) режим Full (Полное). Обратите внимание на качество паузы при включенном движке Mercury Playback Engine GPU Acceleration (Аппаратное GPU-ускорение ядра Mercury Playback).

Смотрим на качество просчитанного материала с включенным движком Mercury Playback Engine GPU Acceleration (Аппаратное GPU-ускорение ядра Mercury Playback). Просчет с помощью центрального процессора.

Просчет с помощью центрального процессора с включенной галкой Use Maximum Render Quality (Наилучшее качество визуализации).

Просчет с помощью движка: Mercury Playback Engine GPU Acceleration (Аппаратное GPU-ускорение ядра Mercury Playback).

Просчет с помощью центрального процессора.

Просчет с помощью центрального процессора с включенной галкой Use Maximum Render Quality (Наилучшее качество визуализации).

Просчет с помощью движка: Mercury Playback Engine GPU Acceleration (Аппаратное GPU-ускорение ядра Mercury Playback).

*Если у нас в настройках стоит галка Use Maximum Render Quality (Наилучшее качество визуализации), то при выводе видео с одним разрешением, например: FullHD видео в FullHD видео, данный установленный флажок может привести к низкой нагрузке ядер процессора. Т.е. установка данной галки, мало того что не дает никакого результата (ибо скалинга нет, либо используется GPU), но приводит к обратным результатам — увеличению времени рендеринга, за счет низкой загрузке ядер и потоков центрального процессора (это справедливо для ряда форматов).
Про нюансы вывода видео не напрямую из Adobe Premiere Pro CS5.5, а через Adobe Media Encoder CS5.5 читаем пункт 25.

А мы продолжаем рассматривать различные пункты меню, которые встречаются в смартфонах на базе Android. В этой статье мы говорим о таком пункте, как «GPU-ускорение», который можно найти в разделе «Для разработчиков». Что это такое?

Включение данного пункта меню позволяет всегда использовать GPU для двухмерного рисования (еще этот пункт может называться «Рендеринг принудительно»), то есть принудительно переносит обработку графики с процессора на GPU. Если говорить в целом, включение данного пункта позволяет улучшить скорость работы некоторых приложений, в том числе игр. Увы, касается это не всех случаев, поэтому может получиться и наоборот — скорость работы приложения замедлится.

Найти этот пункт можно в разделе «Для разработчиков». Откройте настройки.

Выберите раздел «Для разработчиков» или «Режим разработчика». Если у вас его нет, включите с помощью этой инструкции.

Здесь вы можете увидеть строку «GPU-ускорение» в подразделе «Аппаратное ускорение визуализации».

Включите при необходимости. Или отключите.

Используем векторные изображения SVG в приложениях Android, или как убить фрагментацию экранов и не потерять в качестве (плюсы, минусы, особенности)

Достаточно долгое время мы занимаемся разработкой детских приложений под Android, постепенно постигая множество нюансов этой платформы. Есть одни грабли, которые подстерегают нас в каждом приложении, – это фрагментация экранов. Если делать одно изображение только под телефон маленького размера, то на планшете оно выглядит мягко говоря “не очень”. А если делать изображение высокого разрешения для планшетов и пытаться использовать его на телефонах, то с очень большой вероятность приложение вывалится с OutOfMemory.
Приходится готовить несколько экземляров одного и того же изображения под разные экраны. Еще сильнее облака сгущает новый монстр Galaxy Nexus 10 с безумным разрешением 2560х1600.

В общем, неплохо бы что-то изменить, решили мы. А что если использовать в приложениях не растровые изображения, а векторные? Такие изображения легко масштабируются под разные разрешения экранов, при этом не теряя в качестве. Можно использовать всего одно изображение под разные разрешения и размеры.
Сказано — сделано. Итак, под катом история внедрения векторных изображений в одно из наших приложений. В статье мы поделимся опытом и особенностями использования векторных изображений в формате SVG в приложениях Android.
Немного погуглив, выяснили, что векторные изображения для web и приложений обычно используются в формате SVG. С данным форматом работают векторные редакторы Adobe Illustrator и Inkscape. Вооружившись Inkscape, нарезали пробных картинок и принялись искать способы их загрузки и отображения в приложении Android.
Разбираться с устройством формата SVG и писать свой парсер не хотелось — наверняка же люди сталкивались с этим и до нас! Что ж, гуглим «android svg».
В итоге есть:

  • 2 проекта на гуглокоде:
    code.google.com/p/svg-android
    code.google.com/p/svg-android-2
  • подробная статья с использование NDK:
    horribileru.blogspot.ru/2011/10/android-imageview-svg.html
  • и несколько ссылок на мертвые проекты на разных форумах.

Берем самый популярный — SVG-Android (он, кстати, переехал на Github, но новых коммитов там нет). Подключаем библиотеку, векторное изображение помещаем в res/raw, загружаем её и устанавливаем ее во вьюшку:
SVG svg = SVGParser.getSVGFromResource(getResources(), R.raw.filename); Drawable drawable = svg.createPictureDrawable(); imageView.setImageDrawable(drawable);
Загружаем тестовый проект с изображениями — всё отлично! Подключаем наши изображения — пусто. Как оказалось, данная библиотека поддерживает только формат SVG basic 1.1, который не поддерживается Inkspace, а рождается только в Adobe Illustrator.

Пробуем вторую библиотеку SVG-Android-2, которая является форком первого проекта и ушла чуть-чуть дальше.
Она уже понимает Inkscape, а также поддерживает другие фишки этого формата, о чем можно почитать . Здесь всё пошло проще, картинки загрузились и выглядели шикарно и на телефоне, и на планшете. На нем мы и остановились.
Пример SVG-изображения и неадаптированного по размеру под планшет PNG-изображения на планшете.
(просмотреть изображение в оригинальном размере 1280х800)

Первое — SVG (10 Кб), второе — PNG (22 Кб). Второе изображение имеет размытый контур и ступенчатый градиент

Масштабирование изображений

Изображения масштабируются только с сохранением пропорций. Поэтому использовать их в качестве фона, который может немного менять пропорции на разных разрешениях, не получится. В этом случае мы обычно делаем какое-то абстрактное изображение в PNG, которое довольно легко меняет свои пропорции для разных экранов.
Не забываем для SVG устанавливать свойство аdjustViewBounds в значение true, иначе изображение может рассчитывать свои границы не так, как вы задумали.

Размер изображений с тенями и подсветками

Некоторые элементы в нашем приложении изначально были отрисованы с небольшими тенями и подстветками — например, этот смайлик имеет серую подсветку сзади. Но это приводит к колоссальному увеличению размера файла SVG. 118 Кб против 1 Кб без этой подсветки. Чем больше размер файла — тем больше времени надо на его загрузку в программе, поэтому мы решили отказаться от этого эффекта.

Изорбражения с тенью и без: 118 Кб vs 1 Кб
Подсветку можно отключить или в графическом редакторе, или же прямым редактированием SVG-файла — удаляем тэг <image /> с огромным содержимым.

Отображение градиентов

На некоторых изображениях вдруг обнаружились черные пятна вместо фона. Оказалось, что градиент не поддерживается!
Проблема с градиентами решилась удалением лишних тэгов из svg (описано далее в статье). Но в принципе, и с этим можно было бы жить и в наших простых изображениях заменить градиент однородной заливкой, если бы не другой нюанс — значительное время загрузки изображений.
Вот как это выглядело на экране: слева — черное небо в виде градиента, справа — корректная картинка.

Время загрузки изображений

В приложении нужно было по 6 изображений на одной странице ViewPager, а поскольку они подгружаются в процессе прокрутки (если не кэшировать), интерфейс заметно дергался при скроллинге. Этого очень не хотелось, и было решено загружать все изображения при старте приложения. Получили время инициализации порядка 8 секунд, что было слишком долго.
В проблеме решили разобраться. Выкачали исходники проекта SVG-Android-2 и стали искать, что именно так тормозит. Оказалось, что в классе SVGParser XML-файл изображения парсится дважды: первый раз он собирает информацию о дополнительных атрибутах, которые используются при втором проходе. И, что самое интересное, — анализируется лишь атрибут xlink:href, который является некоторым подобием гиперссылок внутри самого документа. В наших проблемных изображениях как раз были такие ссылки, и вели они никуда. После того, как мы избавились от данных ссылок, отредактировав код SVG в некоторых изображениях, градиент стал корректно отображаться. Более того, убрав этот предварительный проход и немного оптимизирорав процесс загрузки, мы смогли уменьшить скорость загрузки с 8 секунд до 1,8-2. Следует заметить, что это соизмеримо с PNG среднего размера — загрузка этих же изображений в память заняла 1,7 секунд.

Ниже приведено сравнение загрузки 35 файлов в формате SVG и PNG.

SVG PNG(~500×500)
Размер, КБ 327 943
Время загрузки, с 1,9 1,7

Прозрачность и цветовые фильтры

Часто в играх мы используем полупрозрачные картинки для неактивных элементов. В этом проекте помимо прозрачности нужны были цветовые фильтры для генерации элементов в играх, то есть чтобы один элемент можно было использовать один раз, но, раскрашивая его по-разному, мы получали бы разные элементы.
Оказалось, что ни alpha, ни colorFilter мы применить не сможем, т.к. библиотека загружает не типичные bitmapDrawable, а pictureDrawable, и в исходниках Android мы видим пустые методы для этого класса:
@Override public void setColorFilter(ColorFilter colorFilter) {} @Override public void setAlpha(int alpha) {}
До этого с классом pictureDrawable никогда не сталкивались, и это было большой неожиданностью.
Опять покопавшись в исходниках библиотеки, мы нашли в классе SVGHandler поле fillPaint типа Paint, которым рисуются все компоненты. Если до загрузки элемента ему установить colorFilter, то он будет работать как положено. Нас это вполне устраивало, поэтому мы чуть-чуть изменили метод загрузки SVG, добавив возможность передавать туда цвет фильтра, который при необходимости устанавливается перед загрузкой изображения. Теперь изображения загружались так:
SVG svg = SVGParser.getSVGFromResource(getResources(), rawSvgId, filterColor);
А в самом SVGHandler появился такой метод:
public void setFilterColor(int filterColor) { fillPaint.setColorFilter(new PorterDuffColorFilter(filterColor, Mode.MULTIPLY)); }
В итоге мы смогли получать из одной картинки сколько угодно изображений разных оттенков.

Также можно установить и Alpha для fillPaint, но в играх это свойство требуется в динамической форме (нажали на элемент — сделался полупрозрачным), и подгружать каждый раз новое изображение неудобно. Поэтому этот эффект заменили масштабированием (нажали — элемент уменьшился).

Нюанс с принудительной обработкой GPU

После запуска приложения к нам стали такие поступать ошибки:
java.lang.UnsupportedOperationException at android.view.GLES20Canvas.drawPicture(GLES20Canvas.java:895) at android.graphics.drawable.PictureDrawable.draw(PictureDrawable.java:73)
Оказалось, что если на устройстве включена настройка “Принудительная обработка GPU” (Developer options — Force GPU Rendering), то наше приложение валится, т.к. метод drawPicture() у Canvas не поддерживает аппаратное ускорение. Об этом можно почитать на android developer.
Причем простое указание в манифесте android:hardwareAccelerated=»false» проблему не решает — пользовательская галочка в настройках имеет более высокий приоритет.
Было найдено довольно простое решение: для всех view, которые работают с нашими pictureDrawable, полученными из SVG, отключить аппаратное ускорение.
Так как функция аппаратного ускорения появилась в Аndroid 3.0 (api 11), то для работы с этим функционалом пришлось изменить target sdk нашего проекта с 8 на 11. И, конечно же, надо помнить про обратную совместимость — на более ранних платформах этих методов нет.
public static void setSoftwareLayerType(View view) { try { view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } catch (NoSuchMethodError e) { //Do nothing — this happens on API < 11 } }

Давайте подведем краткий итог работы с векторными изображениями в формате SVG в Android.
Плюсы:

  • Один огромный плюс, из которого следуют все остальные, — это одна векторная картинка.
  • Так как картинка векторная, она отлично отображается на всех размерах экранов.
  • Размер SVG-картинок мал.
  • Одна картинка используется несколько раз для разных разрешений.
  • Сокращается процесс подготовки изображений для приложения.

Минусы:

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

В результате экспериментов с SVG родилось приложение для детей “Учим формы и фигуры”. Ознакомится с приложением можно в Google Play:
play.google.com/store/apps/details?id=com.whisperarts.kids.forms
Количество получившихся изображений:

  • PNG — 3 (сплэшскрин и 2 фона для меню);
  • SVG-элементов — 97;
  • Размер приложения 3,5 Мб.

В сравнении с почти похожим по функционалу нашим приложением “Учим цвета” (размер которого 8 Мб) выигрыш более 50% налицо.
Для себя мы приняли решение использовать SVG-изображения в наших приложениях, так как это существенно ускоряет процесс разработки и адаптации картинок под разные разрешения экранов, а также существенно уменьшает вес приложения.
Надеемся, опыт, которым мы поделились в статье, поможет вам также пересмотреть процесс подготовки изображений для приложений и задуматься над использованием формата SVG.