Speaker Rabbit

abbra


CIFS: curious information funneled sometimes


Previous Entry Share Next Entry
Видео (1)
Speaker Rabbit
abbra
Построение экранного изображения, в принципе, довольно примитивное занятие. Если отбросить все безумные подробности, X11 и OpenGL, то дело сводится к наличию некоторого количества фрагментов памяти (буферов), имеющих разную структуру (глубина цвета, цветовое пространство, упаковка пикселов) и к механизму смешивания этих буферов. В конце концов, в контроллер дисплея попадает один или несколько буферов, представляющих растр, которые по довольно простым правилам смешиваются между собой. Скажем, в N900, таких аппаратных буферов три. Называются они планами -- графический и два видео-плана -- и по сути дела ничего, кроме этих планов в N900 и не важно. То, что имеется еще "трехмерный ускоритель", ситуацию особенно не меняет -- в конце концов, трехмерный ускоритель выдает "на гора" растровый буфер, который используется для заполнения графического плана.

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

Если содержимое окон меняется очень быстро, например, при отображении видео, у приложений остается не так-то и много вариантов. Если пропускная способность контроллера памяти и графического контроллера, а также производительности процессора достаточно для перемещения кадра за время, меньшее определенного интервала, то можно все сделать по-черному: просто представляем видео-кадр картинкой и выводим ее на экран. Проблемы с этим вариантом возникают сразу. Во-первых, модель рисования приложения через X11 предполагает, что рисует всегда сервер -- XPutImage/XShmPutImage передают изображение на сервер, а он уже доводит эту картинку до графического плана. Фактически, в идеальном случае это означает минимум одну-две копии картинки до момента, как она попадет на экран. Если вывод одного кадра занимает, скажем, 2мс, а его копирование -- 3мс, то при двух-трех копированиях мы можем добиться теоретически картинки с частотой 100Гц. Это все большое ЕСЛИ. X-протокол не гарантирует, что выполняемые действия будут произведены с абсолютной временной точностью. X-протокол работает только с изображениями в RGB-совместимых форматах, а видео-поток из себя представляет чаще всего разновидность YUV, что требует как минимум одно дополнительное копирование для преобразования цветового пространства.

Для решения этой проблемы было придумано расширение XVideo. Смысл его состоит в том, что графический ускоритель предоставляет альтернативный путь смешивания на экране видео-потока, а XVideo реализует его в рамках X-протокола. Альтернативный путь я уже упоминал выше -- те самые видео-планы. Фактически, нам говорят: "у нас тут есть еще несколько буферов размером с экран в заначке и можно рисовать на них специальным образом". В N900 таких дополнительны буферов два, а в nVidia Quadro NVS 140M, который стоит в T61, на котором я сейчас пишу этот текст, поддерживает 32 таких буфера. При выводе в эти буфера можно не конвертировать данные из YUV, вот что говорит по поводу поддерживаемых форматов NVS 140M:

    maximum XvImage size: 2046 x 2046
    Number of image formats: 4
      id: 0x32595559 (YUY2)
        guid: 59555932-0000-0010-8000-00aa00389b71
        bits per pixel: 16
        number of planes: 1
        type: YUV (packed)
      id: 0x32315659 (YV12)
        guid: 59563132-0000-0010-8000-00aa00389b71
        bits per pixel: 12
        number of planes: 3
        type: YUV (planar)
      id: 0x59565955 (UYVY)
        guid: 55595659-0000-0010-8000-00aa00389b71
        bits per pixel: 16
        number of planes: 1
        type: YUV (packed)
      id: 0x30323449 (I420)
        guid: 49343230-0000-0010-8000-00aa00389b71
        bits per pixel: 12
        number of planes: 3
        type: YUV (planar)


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

Однако в случае использования XVideo получается некоторая нестыковка. Конечная картинка, которую мы видим, представляет собой смешивание данных со всех планов. Для того, чтобы смешать графический и видео-планы, дисплейной подсистеме необходимо знать, как пропускать пикселы с одного плана и брать их из другого. В XVideo для этого введено понятие color key. Приложение зарисовывает средствами X11 те пикселы в drawable, которые должны быть заменены на пикселы из видео-планов. То есть, помимо передачи каждого кадра для отрисовки командами XvPutImage/XvShmPutImage необходимо также на каждое событие, приводящее к перерисовке drawable, его перерисовывать с использованием color key. Асинхронность операций в X-протоколе может привести к тому, что рисование color key и кадра будут рассинхронизированы и пользователь увидит color key -- обычно это magenta, как единственный цвет, который отсутствует в естественном световом потоке.

Если у нас есть OpenGL и мы все равно рисуем весь интерфейс средставим OpenGL, может появиться желание вместо XVideo рисовать видеокадры как текстуры. На декстопе (и даже иногда на лаптопах и нетбуках) такое может сработать, потому что пропускная способность контроллера памяти, да и частота на которой работает графический ускоритель, вполне себе позволяет добиться 24Гц-60Гц. Но OpenGL API не рассчитано на такое использование. Во-первых, текстуры в конечном итоге должны быть в RGB-совместимом формате. Во вторых, ускорители OpenGL рассчитаны на динамически изменяемую сцены с относительно статическим набором ресурсов, среди которых и текстуры. Для эффективной работы текстуры при заливке внутрь ускорителя преобразуются во внутренний формат (twiddling). В случае видео "текстуры" у нас одноразовые, они не нужны после формирования кадра, а сцена, наоборот, статическая. Получается, что для изображения видео в рамках традиционного OpenGL мы тратим ресурсы как основного процессора, так и ускорителя на то, что потребуется лишь однажды. Если учесть, что графический ускоритель требует чаще всего DMA для перекачки данных, а при использовании системной памяти как видео-памяти (типичная ситуация для встроенных ускорителей Intel или в случае N900) придется еще озаботиться сбросами кэша памяти. Результат -- использование "в лоб" текстурирования для показа видео приводит к производительности вроде 6-15 кадров в секунду на N900.

Для решения этой проблемы производители графических трехмерных ускорителей придумали свои нестандартные расширения. Как бы они не назывались, суть их одна -- они позволяют обойти стандартный путь представления данных для текстур и прикрепления текстуры к контексту рисования для таких одноразовых кадров. Традиционное название этого процесса -- texture streaming. При этом, фактически, речь идет о том, что графический ускоритель выделяет несколько буферов для приложения и говорит: "складывай свои данные в эти буфера, а я их помогу тебе представить в виде текстур". Если мы сразу кладем наш видеокадр в такой буфер, то можем его использовать после этого в виде текстуры. Такой путь позволяет достичь хорошей производительности за счет энергопотребления. Скажем, на N900 я наблюдал отображение предварительно раскодированного потока 720p с масштабированием на полный экран (получалось 800х480 из оригинальных 1280х720) с потреблением 7-9% CPU. Энергопотребление возрастало по сравнению с XVideo на несколько процентов. Понятно, что декодирование видеопотока в этом случае займет в несколько раз больше. Вывод этого же потока через XVideo потреблял 20% CPU, то есть все же CPU мы разгружаем прилично.



Получилось довольно большое введение. Зачем оно надо -- в следующей заметке.
Tags:

  • 1
"обычно это либо magenta, как единственный цвет, который отсутствует в естественном световом потоке."
либо что?

Либо все, что удалось подобрать автору приложения. Многие используют оттенок синего, что не очень правильно.

Я убрал "либо".

Какие GL расширения отвечают за него?

Отвечают за что? За texture streaming?

Да. Или вопрос лишен смысла?

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

В случае PowerVR, который стоит в N900 (SGX530) и во многих других мобильных устройствах, соответствующие функции доступны в расширении GL_IMG_texture_stream. В качестве работающего примера на OMAP3 смотри код Роба Кларка из TI -- http://gitorious.org/gst-plugin-bc/gst-plugin-bc/blobs/master/bc-app/bc-app.c
Этот код требует сборки модуля к ядру. :)

А почему не используется ARB ВЕЗДЕ? Ведь стандарт-то всегда лучше? Или он кривой-косой?

Потому что я еще не дописал вторую часть (зачем это надо). :) Потому что реализации GL_ARM_pixel_buffer_object не позволяют подсунуть буфер, который выделен другой подсистемой, а только работают с буферами, которые выделены драйверами графического ускорителя. Обратное (подсунуть буфер, полученный от драйвера ускорителя в другую подсистему в ядре) не всегда работает, в частности, это не работает с V4L2 -- почему-то V4L2 не признает такой буфер за "свой" и отказывается в него выкладывать данные с сенсора.

ммм. а разве Х-сервер не умеет асинхронно буферизовать? (т.е. частота запихивания кадров в конвейер всегда ограничена временем полной прокрутки конвейера?)

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

XFlush() лишь заставит все запросы с нашей стороны реальной уйти на сервер, но не гарантирует, что хоть какая-то обработка этих запросов реально произошла. Можно было бы использовать в этом случае XSync(), это как раз его случай -- для синхронизации доступа к одной и той же картинке, разделяемой через MIT-SHM, но в общем случае XSync() скорее вреден, чем полезен.

Да, пардон, XSync(). И в данном конкретном случае XSync() - это именно то, что прописал доктор. Вне зависимости от суровых предупреждений X11 Programming Guide.

Ага. О чудесах взаимодействия X11 и современных client-side rendering toolkits -- в следующей серии.

спасибо, очень интересно, узнал много нового! :)
а можно поподробнее, или где можно почитать на тему того что magenta отсутствует в естественном?

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

Также важно понимать, что фуксин, который использовали для создания этого цвета до изобретения печатной magenta в 1890-х и электронной magenta в 1980-х, отличается от электронной magenta (#FF00FF в RGB). Поэтому то, что мы наблюдаем при печати и в природе, это чуть другой цвет. Точнее, наш мозг воспринимает их по-разному, потому что цвета -- это реакция нашего мозга на свет.

Почитайте http://www.biotele.com/magenta.html для начала.

Какой ужас ))
Ну ноты, надеюсь, все реально существующие? Нельзя ж так представления о мире резко разрушать ))))

:) Страшно жить стало? Не доверяешь своему сознанию?

А буква "ш" существует, или её мозг тоже дорисовывает для полноты видения мира? ))))

Подозреваю, что все мозг дорисовывает. Финны, например, говорят: "Какой у вас, русских, сложный язык -- целых шесть букв "С", как так можно?".

Хуже, когда он с кем-то координируется и ты не понимаешь, кто он там такой...

Вообще, конечно же, всегда можно open("/dev/fb0",O_RDWR);mmap(...

Хочется обеспечить что-нибудь цивилизованное. :) К тому же, не все драйвера фреймбуферов выставляют дополнительные порты как /dev/fb*, например, это не так с Nvidia.

Получается исключительно непереносимый код. В следующей заметке я напишу о том, что можно сделать, чтобы его избежать.

Ну тут же явный случай просящийся в fb0: имеет место полноэкранное приложение которое все делает само, а от системы хочет всего лишь место чтобы положить картинку. То есть оно (приложение) практически прямым текстом просит у системы frame buffer :)

Насчет непереносимости, я бы поспорил: в отличие от всех этих X, Xext, Xv, и прочих заклинаний, кусок памяти с картинкой нынче имеется практически везде.

Да, если оно полноэкранное. Мне интересен случай неполноэкранного (вроде application grid в N900 и видео во фрагменте окна). Полноэкранное никто не даст, там же композитный менеджер в общем случае всю малину портит. Да и в камере есть конкретный пример с toolbar, а значит, и остальным хозяйством извне.

Ага. Это меняет дело. Но наводит на мысль о том, что если каждый image plane сделать /dev/fb* и имплементировать слегка расширенные FBIOSET_VSCREENINFO / FBIOSET_FSCREENINFO, то и это покатит.

  • 1
?

Log in

No account? Create an account