Ещё раз про быстрый JPEG на CUDA
В 2012 году на Хабре уже была моя статья про быстрое сжатие в JPEG на видеокарте. С тех пор прошло уже довольно много времени и мне хотелось бы в общих чертах рассказать про результаты, которые были получены по этой теме. Надеюсь, многим будет интересно узнать, какой уровень производительности можно получить на современных видеокартах NVIDIA при решении практических задач на CUDA.
При обсуждении времени работы алгоритма сжатия, я буду приводить результаты для измерений времени работы на видеокарте без учёта загрузки и выгрузки данных. Этот подход имеет смысл при организации сложных вычислительных систем, когда все расчёты делаются на видеокарте и для большинства стадий общей схемы обработки начальные и конечные данные располагаются в памяти видеокарты. Также существуют методы копирования данных в видеокарту и обратно одновременно с вычислениями, поэтому обсуждение производительности в терминах времени работы алгоритма именно на видеокарте вполне оправдано. Все измерения сделаны с помощью NVIDIA Visual Profiler. Алгоритм JPEG реализован в базовом варианте (Baseline JPEG), т. е. 8 бит на канал, со стандартными таблицами квантования и Хаффмана, без арифметического кодирования и без прогрессивного режима.
Скорость кодирования в JPEG на CUDA со времени прошлой публикации выросла значительно и теперь за 0,78 мс на видеокарте NVIDIA GeForce GTX 1080 можно сжать в 10 раз (качество 90%) 24-битную картинку формата 4К (3840×2160) с дискретизацией 4:2:0, что соответствует производительности кодирования порядка 30 Гбайт/с. Для изображений формата 8К и более, скорость сжатия при аналогичных параметрах может быть ещё почти в полтора раза выше.
С одной стороны, это заслуга NVIDIA, которая выпускает все более быстрые видеокарты. С другой, это наш результат распараллеливания и оптимизации алгоритма JPEG на CUDA. Время пересылки несжатого изображения формата 4К из оперативной памяти через PCI-Express x16 (Gen3) в эту видеокарту равно 2,17 мс. Получаем интересный результат: сжатие в JPEG теперь можно сделать в два с половиной раза быстрее по сравнению со скоростью копирования несжатых данных через PCI-Express x16. Скорость декодирования у нас пока сильно отстаёт от скорости кодирования, а аналогичную 4К картинку мы можем декодировать за 2,6 мс. В ближайшее время надеемся устранить этот разрыв между кодером и декодером.
Такая высокая производительность нужна в тех случаях, когда требуется обрабатывать большие массивы или потоки данных. Для сохранения в JPEG одиночных изображений в графическом редакторе такая скорость не нужна, хотя режим пачки вполне востребован. Быстрым кодированием и декодированием в основном интересуются разработчики приложений для визуализации 3D и VR, потому что удобно хранить исходные данные в виде джипегов, копировать их в видеокарту, а уже там делать быстрое декодирование и вывод на монитор или на очки через OpenGL. Таким образом, можно добиться высокой частоты кадров при большом разрешении, например, 100–120 к/с для 12-мегапиксельных изображений. Важным условием быстрого декодирования является наличие внутри джипегов необходимого количества рестарт-маркеров, которые позволяют достигать высокой степени распараллеливания при декодировании. Без этих рестарт-маркеров скорость декодирования JPEG падает на порядок или даже больше. Наш кодер ставит эти маркеры по умолчанию, но их также можно добавлять в оффлайне с помощью утилит типа jpegtran, после чего станет возможным быстрое декодирование джипегов на видеокарте.
Для работы с современными видеокамерами мы реализовали на CUDA и 12-битный кодер JPEG, который тоже имеет очень высокую производительность. Он сжимает 12-битную картинку 4К с качеством 90% и дискретизацией 4:2:0 на видеокарте GeForce GTX 1080 за 1,2 мс. Для большинства видеокамер (мы работаем в основном с промышленными и скоростными камерами) диапазон в 12 бит покрывает основные потребности, а высокая производительность сжатия позволяет решать массу задач в реальном времени даже при очень высокой частоте кадров.
Кроме кодека JPEG мы также реализовали на CUDA алгоритмы демозаики, ресайза, подавления шума и др. Фактически, это набор быстрых параллельных алгоритмов для обработки RAW данных на видеокарте. Эти решения обеспечивают практически полный цикл предварительной обработки изображений от видеокамер и они работают на всех видеокартах NVIDIA, в том числе и на мобильных Tegra K1 и Tegra X1. В ближайшее время на базе этого функционала мы выпустим приложение на CUDA для обработки в реальном времени серий изображений формата DNG от кинокамер BlackMagic Design.