The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

9.5.1 Интерфейс кадрового буфера Linux

9.5.1 Интерфейс кадрового буфера Linux

Предыдущая  Содержание  Следующая V*D*V

Кадровый буфер на Linux реализован как интерфейс символьного устройства. Это означает, что приложения делают стандартные системные вызовы, такие как open(), read(), write() и ioctl() на указанном имени устройства. Устройство с кадровым буфером доступно в пространстве пользователя как /dev/fb[0-31]. В Таблице 9.2 перечислены интерфейсы и их операции. Первые две операции в списке являются общими для любого другого устройства. Третья, mmap, это то, что делает интерфейс кадрового буфера уникальным. Сейчас немного отойдём от основой темы и обсудим возможности системного вызова mmap().

 

Таблица 9.2 Интерфейс кадрового буфера

 

Интерфейс

Операция

Обычный ввод/вывод

open, read, write с /dev/fb

ioctl

Команды для настройки видеорежима, запроса информации о чипсете, и так далее

mmap

Отображение области памяти видеобуфера в память программ

 

Мощь mmap

 

Драйверы являются частью ядра и, следовательно, работают в памяти ядра, в то время как приложения находятся на стороне пользователя и работают в пользовательской памяти. Единственным интерфейсом, доступным для взаимодействия между драйверами и приложениями являются файловые операции (fops), такие как open, read, write и ioctl. Рассмотрим простую операцию записи. Вызов write происходит от пользовательского процесса, с данными, размещёнными в пользовательском буфере (выделенном в памяти пользовательского пространства), и переданными драйверу. Драйвер выделяет буфер в пространстве ядра и копирует пользовательский буфер в буфер ядра с помощью функции ядра copy_from_user и выполняет с буфером необходимые действия. В случае драйверов с кадровым буфером необходимо скопировать/DMA его для вывода в память кадрового буфера. Если приложение вынуждено писать с определённым смещением, становится необходимо делать вызов seek(), а за ним write() Рисунок 9.7 подробно показывает разные этапы в ходе операции записи.

 

Рисунок 9.7 Поиск/запись с повтором.

Рисунок 9.7 Поиск/запись с повтором.

 

Теперь рассмотрим графическое приложение. Оно должно писать данные по всей области экрана. Возможно, придётся обновить какой-то один прямоугольник или даже весь экран, или иногда просто помигать курсором. Каждое выполнение seek(), а затем write() стоит дорого и отнимает много времени. Для использования в таких приложениях интерфейс fops предлагает API mmap(). Если  драйвер в своей структуре fops реализует mmap(), пользовательское приложение может напрямую получить в пользовательском пространстве отображённый на память эквивалент аппаратного адреса кадрового буфера. Для драйверов класса кадрового буфера реализация mmap() является обязательной (* Обратите внимание, что это не требуется в операционных системах без MMU, таких как VxWorks или uClinux, потому что всё адресное пространство памяти - это единая область. В модели flataddresing любой процесс может обратиться к любой области памяти, независимо ядро это, или пользователя.). Рисунок 9.8 показывает различные шаги при использовании mmap.

 

Рисунок 9.8 Запись через mmap.

Рисунок 9.8 Запись через mmap.

 

Все приложения, работающие с кадровым буфером, просто вызывают open() для /dev/fb, делая необходимой ioctl(), чтобы установить разрешение экрана, размерность пикселя, частоту обновления и так далее, и, наконец, вызывают mmap(). Реализация mmap в драйвере просто отображает полный буфер кадра видеооборудования. В результате приложение получает указатель на память кадрового буфера. Любые изменения, сделанные в этой области памяти, прямо отражаются на экране.

 

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

 

Установка драйвера кадрового буфера

 

Ядро Linux должно быть загружено с опцией кадрового буфера, чтобы использовать кадровый буфер консоли и проинициализировать драйвер кадрового буфера. Передайте при запуске ядра параметр командной строки vga=0x761 (* Для достижения того же результата можно отредактировать конфигурационные файлы загрузчика /etc/lilo.conf или grub.conf). Число представляет собой режим разрешения  экрана карты; для получения полной информации о том, что означает это число, обратитесь к Documentation/fb.txt в каталоге исходных текстов ядра Linux. Если ядро грузится с активированным режимом кадрового буфера, вы сразу же заметите при загрузке в верхней левой части экрана известный образ пингвина. Кроме того, распечатки ядра будут отображаться шрифтами с высоким разрешением. Для дальнейшего подтверждения просто сделайте для любого файла cat, направив вывод в /dev/fb0. Вы увидите на экране мусор. Если это не сработало, вам, возможно, придётся скомпилировать поддержку кадрового буфера в ядре, а затем повторить попытку. Для получения дополнительной помощи по настройке устройства с кадровым буфером смотрите раздел frame buffer HOWTO, доступный на http://www.tldp.org/.

 

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

 

Режим 1: 640 × 480, цвет 24 бита, RGB 888

Режим 2: 320 × 480, цвет 16 бит, RGB 565

Режим 3: 640 × 480, монохромный, индексный

 

Драйвер устройства сообщает об установленных параметрах в определённом режиме с помощью структуры fb_fix_screeninfo. Иными словами, структура fb_fix_screeninfo определяет зафиксированные или неизменные свойства видеокарты, когда началась работа в том или ином разрешении экрана/режиме.

 

struct fb_fix_screeninfo {

    char id[16];              /*Идентификационная строка, например "ATI Radeon 360"*/

    unsigned long smem_start; /*Начало памяти кадрового буфера*/

    __u32 smem_len;           /*Размер памяти кадрового буфера*/

    __u32 type;               /*один из многих FB_TYPE_XXX*/

    __u32 visual;             /*один из FB_VISUAL_XXX*/

    …

    …

    __u32 line_length;        /*длина строки в байтах*/

    …

    …

};

 

smem_start - это физический начальный адрес памяти кадрового буфера размером smem_len. Поля type и visual указывают формат пикселя и режим цвета. Для чтения структуры fb_fix_screeninfo используется ioctl FBIOGET_FSCREENINFO.

 

fb_fix_screeninfo fix;

ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &fix)

 

Структура fb_var_screeninfo содержит изменяемые параметры графического режима. Можно использовать эту структуру и  установить необходимый графический режим. Важными членами структуры являются:

 

struct fb_var_screeninfo {

    __u32 xres;         /*видимое разрешение по X, Y*/

    __u32 yres;

    __u32 xres_virtual; /*виртуальное разрешение*/

    __u32 yres_virtual;

    __u32 xoffset;      /*смещение от виртуального к видимому разрешению*/

    __u32 yoffset;

    __u32 bits_per_pixel; /*Число битов в пикселе*/

    __u32 grayscale;    /*!= 0 Уровни серого вместо цветов*/

    …

    …

    struct fb_bitfield red;    /*битовое поле в памяти к/б в режиме true color*/

    struct fb_bitfield green;

    struct fb_bitfield blue;

    struct fb_bitfield transp; /*уровень прозрачности*/

    __u32 nonstd;              /*!= 0 Нестандартный формат пикселя*/

    …

    …

};

 

Вышеупомянутая структура fb_bitfield детализирует размер и смещение битов для каждого цвета пикселя.

 

struct fb_bitfield {

    __u32 offset;    /*начало битового поля*/

    __u32 length;    /*размер битового поля*/

    __u32 msb_right; /*!= 0 : Старший бит справа*/

};

 

Напомним, что разные цветовые режимы, которые были обсуждены, это RGB565, RGB888, и так далее, и элементы fb_bitfield представляют собой то же самое. Например, один пиксель RGB 565 имеет размер 2 байта и имеет формат, показанный на Рисунке 9.9.

 

Рисунок 9.9 Формат пикселя RGB565.

Рисунок 9.9 Формат пикселя RGB565.

 

red.length = 5, red.offset = 16 → 32 оттенка чистого красного

green.length = 6 и green.offset = 11 → 64 оттенка чистого зелёного

blue.length = 5 и blue.offset = 5 → 32 оттенка чистого синего

размер пикселя 16 бит или 2 байта → 65536 всего оттенков.

 

Поля xres и yres представляют собой разрешение видимого экрана по X и Y. Поля xres_virtual и yres_virtual указывают виртуальное разрешение видеокарты, которые могут быть больше, чем видимые координаты. Например, рассмотрим случай, когда видимое разрешение по Y равно 480, а виртуальное разрешение по Y равно 960. Поскольку видны только 480 линий, необходимо указать, какие 480 линий из 960 будут видимы на экране. Для этих целей используются поля xoffset и yoffset. В нашем примере, если yoffset равно 0, то первые 480 строк будут видны или, если yoffset равно 480, видны последние 480 линий. Изменяя только значение смещения программисты могут осуществлять двойную буферизацию и переключение страниц в их графических приложениях (* Двойная буферизация и переключение страниц - это техники графики, в которых изображение отрисовывается в закадровый (невидимый) буфер. Отрисовка изображения на экране выполняется простым переключением указателя).

 

ioctl с FBIOGET_VSCREENINFO возвращает структуру fb_var_screenifno, а ioctl с FBIOSET_VSCREENINFO передаёт настроенную структуру fb_var_screeninfo.

 

fb_var_screeninfo var;

/* Читаем изменяемую информацию */

ioctl(FrameBufferFD, FBIOGET_VCREENINFO, &var);

 

/* Устанавливаем разрешение экрана 1024x768 */

var.xres = 1024; var.yres = 768;

ioctl(FrameBufferFD, FBIOSET_VCREENINFO, &var);

 

Следующей важной структурой в программировании кадрового буфера является структура fb_cmap.

 

struct fb_cmap {

    __u32 start;   /* Первая запись */

    __u32 len;     /* Число записей */

    __u16 *red;    /* Значения цветов */

    __u16 *green;

    __u16 *blue;

    __u16 *transp; /* прозрачность, может быть NULL */

};

 

Каждое поле цвета red, green и blue является массивом из значений цвета длиной len. Таким образом, эта структура представляет собой таблицу карты цветов или CLUT, где значение цвета для любого индекса n получается поиском в таблице по red[n], green[n], blue[n], где start <= n < len. Поле transp используется для указания уровня прозрачности, если это необходимо и не является обязательным (* Поле прозрачности также называют альфа-каналом. Мы добавляем к списку известных режимов новый режим, 32-х битный режим RGBA8888, где A означает альфа-канал (8 бит)).

 

ioctl FBIOGETCMAP используется для чтения из существующей таблицы карты цветов, а ioctl FBIOPUTCMAP программирует/загружает новую таблицу карты цветов/CLUT. (* Загрузка новой CLUT или таблицы цветов упоминается как программирование палитры.)

 

/* Читаем текущую таблицу цветов */

fb_cmap cmap;

/* Инициализируем структура данных cmap */

allocate_cmap(&cmap, 256);

ioctl(FrameBufferFD, FBIOGETCMAP, &cmap);

 

/* Изменяем записи cmap и загружаем 8-ми битовую индексную таблицу цветов */

#define RGB(r, g, b) ((r<<red_offset)|

                    (g << green_offset)|

                    (b << blue_offset))

 

/* Устанавливаем смещение для режима RGB332 */

red_offset = 5; green_offset = 2; blue_offset = 0;

for(r=0;r<3;r++) {

    for(g=0;j<3;g++) {

        for(b=0;b<2;b++) {

            q=RGB(r, g, b);

            cmap.red[q]=r;

            cmap.green[q]=g;

            cmap.blue[q]=b;

        }

    }

}

 

/* Наконец, загружаем нашу CLUT */

ioctl(FrameBufferFD, FBIOPUTCMAP, &cmap);

 

Теперь мы готовы написать нашу программу Hello world для работы с кадровым буфером. Распечатка 9.1 ставит в центре экрана один белый пиксель.

 

Первый шаг достаточно очевиден: открыть устройство с кадровым буфером /dev/fb0 с O_RDWR (чтение/запись). Вторым шагом является чтение структур с информацией об устройстве. Устройство с кадровым буфером имеет две важные структуры: постоянную и переменную. Постоянная информация предназначена только для чтения: читается с помощью ioctl FBIOGET_FSCREENINFO.  Структура fb_fix_screeninfo содержит идентификационную информацию об устройстве с кадровым буфером, информацию о пиксельном формате, поддерживаемом этим устройством и адреса для отображения памяти кадрового буфера. Переменная информация экрана читается с использованием ioctl FBIOGET_VSCREENINFO и записывается с помощью ioctl FBIOSET_VSCREENINFO. Структура fb_var_screeninfo описывает геометрию и временные параметры текущего видеорежима. Следующий шаг - отобразить аппаратный буфер в пространство процесса нашего приложения используя системный вызов mmap().

 

Теперь мы готовы установить наш пиксель. Позаботимся о различных битовых полях и схемах упаковки пикселей. Число бит и смещения для отдельных цветовых каналов предоставляет структура fb_var_screeninfo. Наконец, используя свойство линейного  кадрового буфера (пиксель (х, у) = (line_width * у) + х), мы ставим единственный пиксель. Так много, чтобы установить всего 1 пиксель!

 

Предыдущая  Содержание  Следующая