На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Все статьи должны быть оформлены согласно Правил оформления статей.
2. Любые обсуждения должны происходить в специальной теме, обсуждение в любых других темах раздела запрещены.
3. Запрещается писать статьи о создании и распространении вирусов, троянов и других вредоносных программ!
4. За грамотно написанные и правильно оформленные статьи авторы награждаются DigiMoney.

Дополнительные ссылки:
Желаю творческих успехов! ;)
Модераторы: Jin X
  
    > Низкоуровневое программирование видеоадаптеров ATI (часть первая), x86, DOS, Hardware
      Низкоуровневое программирование видеоадаптеров ATI (часть первая)

      С некоторой периодичностью на различных форумах по программированию возникают новые темы примерно такого содержания: "Как программировать видеоадаптер (графический акселератор) на уровне регистров устройства (под DOS)?". А ответом на подобный вопрос служит либо предложение "забыть" об этой идее или ограничится использованием VESA. Собственно оно и очевидно: современные видеоадаптеры на уровне регистров, пожалуй самые нестандартизированные устройства (конечно для совместимости они эмулируют блок стандартных VGA регистров, но возможности которые можно через них реализовать вряд-ли кого-то удовлетворят). Практически на все современные видеоадаптеры отсутствуют необходимые даташиты и к этому стоит добавить, что низкоуровневое программирование видеоадаптера и встроенного ускорителя, на мой взгляд, представляется наиболее сложным по сравнению с оборудованием другого типа. В этой статье я собираюсь приоткрыть завесу этой "тайны" на примере видеоадаптеров семейства radeon (у кого nvidia, intel или нечто другое можете почитать лишь для общего ознакомления, совместимости между ними, увы, нет никакой). Далее я предполагаю, что в качестве ОС будет использоваться DOS по причине простоты работы с устройствами из под нее и отсутствия конфликтов с системными драйверами.
      Итак, прежде чем приступить к непосредственной работе с регистрами контроллера я рекомендую изучить (для тех, кто не знаком):
      1. архитектуру х86, желательно еще и ассемблер;
      2. защищенный режим процессора и "нереальный режим" (если не устраивает защищенный);
      3. шину PCI и сервисы PCI BIOS (в защищенном режиме можно работать и через регистры, но знать не лишнее);
      4. основные принципы низкоуровневой работы с устройствами;
      5. VESA BIOS (я предполагаю, что мы будем работать в видеорежиме уже установленном через VESA BIOS, установить его через регистры конечно можно, но лично меня возможности VESA в этом плане полностью удовлетворяют).

      Некоторые предварительные сведения

      Для начала устройство необходимо найти на шине PCI по коду класса видеоадаптеров 0x030000. Все radeon'ы имеют идентификатор изготовителя 0x1002 (AMD). Сам контроллер должен сконфигурировать BIOS и VGA BIOS, поэтому из всего конфигурационного пространства нас интересует только идентификатор устройства (слово по смещению 0x02) и физический адрес блока MMIO регистров (двойное слово по смещению 0x18), физический адрес видеопамяти лучше узнать через VESA BIOS. Вообще говоря GP видеоадаптеров управляется отдельно от блока регистров контролера управления видеорежимом и как ни странно блок регистров 2D ускорения radeon'ов не претерпел существенных изменений начиная с первых моделей (upd: начиная с r600 выпилен начисто). А вот с блоком регистров контроллера ситуация сложнее: начиная с серии RV515 введен новый блок регистров AVIVO описанный в открытом даташите "RV630 Register Reference Guide". А вот с регистрами GP и регистрами контроллера чипов старее RV515 ситуация хуже: открытого даташита с их полным описанием (описаны лишь некоторые отдельные регистры) в открытом доступе нет. Единственным источником являются исходники линуксового драйвера "xf86-video-ati", наибольший интерес там представляют определения регистров в файле radeon_reg.h, некоторые функции 2Д ускорения в radeon_accelfuncs.c и поддержка мыши в radeon_cursor.c. Из регистров контроллера, на мой взгляд, представляет интерес только регистры управления аппаратным курсором, также некоторую пользу для лучевых мониторов можно получить увеличив частоту обновления экрана, но в следствии устаревания лучевых мониторов я не рассматриваю эту возможность подробнее, при необходимости вы без труда сможете это сделать проанализировав как это делает линуксовый драйвер. Сам доступ к регистрам GP и контроллера осуществляется посредством записи или чтения из физической области памяти блока MMIO регистров. В примере к статье запись осуществляется так: mov GS:[EBX + REG], EAX, где GS - сегментрый регистр с базой = 0, пределом = 4Гб, EBX содержит адрес блока регистров MMIO, EAX - значение которое требуется записать, чтение mov EAX, GS:[EBX + REG]. Естественно, что возможно бесконечное множество других вариантов, в защищенном режиме доступ может осуществляться еще проще, кстати с MMIO регистрами очень удобно работать на многих ЯВУ (в отличии от записи в порты ввода-вывода). Перед непосредственной работой с GP нужно установить графический режим (лучше полноцветный, хотя GP поддерживает и 256 цветной с палитрой). В примере к статье используется видеорежим группы TrueColor32 , т.к. рабоать намного удобнее. Взаимодействии с GP может осуществляться через AGP GART (или DMA для PCI-E карт), но работа с AGP GART (с PCI-E ситуация не намного лучше) затрагивает низкоуровневое конфигурирование Северного Моста и специальную инициализацию командного процессора GP. Желающие могут этим заняться, но можно работать с GP и в режиме PIO, хотя это и накладывает ряд ограничений, в частности передача изображения через регистры не будет быстрее прямой записи в видеопамять. Но если изображение все же загрузить в видеопамять (не обязательно отображаемую), то операцию копирования в "своей" памяти GP осуществляет очень быстро. Все регистры которые я рассматриваю в этой статье 32х разрядные.

      Определение режима работы контроллера

      Определить работает ли контроллер с регистрами AVIVO можно по крайней мере двумя способами:
      1. Найти в линуксовом драйвере таблицу соответствия идентификатора устройства и кодового номера GP, все RV >= 515 модели работают через AVIVO.
      2. Считать из AVIVO регистра информацию, которая уже заведомо известна и проверить - если совпадает, значит наш RV AVIVO поддерживает, иначе нет. Вообще говоря если он AVIVO не поддерживает, то должен считаться "0". В качестве такого регистра я использую регистр с номером 0x6000.

      Работа с аппаратным курсором

      Аппаратный курсор - очень полезная вещь, позволяющая значительно повысить скорость вывода графики т.к. не требуется контролировать пересечение его границ, в добавок контроллер берет на себя его отрисовку, достаточно лишь указать его координаты. Курсор невозможно затереть через отображаемую видеопямять, если само изображение курсора разместить где-нибудь за ее пределами (но в видеопамяти). Он рисуется как бы дополнительным слоем поверх отображаемой части видеопамяти. Стандартный размер аппаратного курсора 64х64 пиксела, в изображении можно использовать альфа-канал. Взаимодействие через AVIVO регистры и через стандартные немного отличается, но все же схоже.
      Если не AVIVO:
      - регистр 0x0260 содержит смещение изображения курсора в видеопамяти
      - регистр 0x0264 содержит в старшей части координату X курсора и Y в младшей
      - регистр 0x0268 содержит смещение начала отображения курсора относительно начала его изображения в видеопамяти, в старшей части содержится смещение по Х, в младшей - по Y. К примеру Если в этот регистр записан 0, то контроллер будет отображать весь курсор целиком в виде квадрата 64х64 (при использовании альфа-канала курсор можно сделать любой формы), если 0x00100010, то контроллер будет отображать только правый нижний квадрат размером 48х48.
      Чтобы разблокировать курсор (т.е. чтобы контроллер его начал отображать) нужно установить определенные биты в регистре управления CRTC (0x0050) (помимо управления курсором я там ничего трогать не советую), его нужно считать и установить биты 20...22 на нужную цветовую модель курсора и бит 16 в 1. Для того, чтобы отключить курсор достаточно сбросить бит 16 в этом регистре. Возможные цветовые модели можно посмотреть в Линуксовом драйвере, я всегда используй модель с номером 2 - ARGB32, то есть курсор будет представлять обычное RGB32 изображение, где старший байт - альфа-канал.
      Для AVIVO:
      - регистр 0x6408 содержит смещение изображения курсора в видеопамяти
      - регистр 0x6414 содержит в старшей части координату X курсора и Y в младшей
      - регистр 0x6410 содержит в старшей части координату ширину курсора и высоту в младшей
      - регистр 0x6400 содержит в битах 8...9 цветовую модель, с помощью бита 0 можно разрещить(1) или запретить(0) отрисовку курсора.
      Инициализация аппаратного курсора весьма тривиальна и представляет собой последовательную установку всех регистров в определенные значения, а также загрузку изображения курсора в видеопамять.

      Непосредственная работа с графическим процессором

      После инициализации видеоадаптера VGA BIOS, GP должен работать в режиме PIO, поэтому для того чтобы было возможно использовать функции 2D ускорения необходимо привести некоторые регистры в определенные значения. Доступ к любому регистру GP интерпретируется как команда, GP имеет буфер FIFO переполнение которого нужно контролировать с помощью специального регистра состояния 0x0E40, в нем в битах 0..7 содержится количество свободных слотов команд. Перед любой записью в регистры нужно убедиться, что необходимое количество слотов свободно, иначе ждать их освобождения, допустим мы собираемся записать значения в 5 регистров GP, тогда мы должны дождаться того момента когда как минимум 5 слотов будет свободно. Хотя на практике GP имеет очень высокое быстродействие и получить переполнение буфера команд сложно (запись в регистры, хоть они и MMIO, но все же занимает определенное время), но проверки никогда не бывают лишними. Я не собираюсь описывать тут все регистры блока 2D ускорения (3D тем более), к тому же я постарался максимально подробно все описать в примере к статье, но все же остановлюсь на некоторых моментах. В примере к статье процедура radeon_init_2d_engine производит инициализацию блока 2D регистров. Прежде всего устанавливается глобальное "окно" вывода на максимальные оазмеры, т.е. фактически отключается глобальное обрезание вывода графики. Это произвобится путем записи в регистр 0x16E8 значения 0x1FFF1FFF, в принципе можно его и использовать, но лучше не стоит, т.к. это может ограничить в использовании некоторых фитч. Намного лучше использовать локальные регистры обрезания вывода графики с номерарами 0x16EC и 0x16F0. В старшей части первого регистра указывается координата Y, в младшей части X начала региона отображения графики (все, что в него входить не будет, то будет обрезаться), соответственно в регистре 0x16F0 в таком же порядке указываются координаты конца региона. Кстати именно благодаря использованию такой возможности осуществляется вывод графики в видимую часть окна любого уровня в моей ОС. Присмотревшись к названиям регистров можно выделить несколько групп, я раскажу про 4 самые важные начинающиеся на: SC_ от слова scissors - ножницы (управление регионом обрезания), DST_ - destination (получатель), SRC_ - source (источник) и DP_ - это регистры управления и конфигурации. Регистры помеченные как "получатель" содержат характеристики объекта куда GP передает данные, а как "источник" соответственно откуда берет. При инициализации имеет смысл задать определенные значения регистров выбора цвета. Регистр с загадочным названием DP_WRITE_MASK представляет собой некий интерфейс управления альфа-смешивания старший байт отвечает за общий коэффициент, а все остальные за соответствующую цветовую компоненту. При инициализации имеет смысл записать в него значение 0FFFFFFFFh, т.е. фактически отключить альфа-смешивание, при настройке выводимого объекта можно им воспользоваться. Также при инициализации необходимо установить логической ширины строки источника и приемника в байтах, это значение нужно поделить на 64 и сдвинуть на 22 разряда влево, и записать в регистры 0x142C, 0x1428 соответственно. Для некоторых операций связанных с копированием блоков видеопамяти иногда имеет смысл использовать длину логической строки источника отличную, от той, которая используется в текущем видеорежиме. После того как блок 2D ускорения установлен в нужное состояние можно приступать непосредственно к выводу графики посредством GP. Регистр DP_GUI_MASTER_CNTL с номером 0x146C задает фактически операцию, которую будет делать GP. Формат его подробно описан в спецификации "Radeon R5xx Acceleration" на странице 30, поэтому я дублировать не буду. Далее в зависимости от операции устанавливается цвет, координаты, загружаются паттерны и пр. Единственное чего я замечу, это то, что GP начнет выполнять операцию сразу после записи в регистр DST_WIDTH_HEIGHT (ширина и высота оъекта) для объектов прямоугольной формы и DST_LINE_END (координаты конца линии) для линий. Тут также отмечу, что подавляющего большинства операций применимы только к объектам прямоугольной формы.

      В примере к статье приведен исходной код простой демонстрационной программы для видеоадаптеров radeon (я планирую сделать поддержку и ATI128). Программа периодически рисует случайные линии и прямоугольники, также по экрану перемещается аппаратный курсор в виде полупрозрачного оранжевого квадрата. Желающие могут придумать нечто по оригинальнее. В ближайшем будущем я собираюсь добавить демонстрацию вывода текста с использованием GP, и функции BitBlt. У кого есть какие идеи по поводу статьи или примера - пишите, постараюсь добавить.
      Прикреплённый файлПрикреплённый файлatidemo.7z (8 Кбайт, скачиваний: 170)

      upd: поправил пример. В руки мне попали более современные карточки. Как выяснилось начиная с r600 блок регистров 2D-ускорения выпилен начисто. Владельцы rv6xx-rv7xx и м.б. некоторых более новых карточек смогут увидеть только аппаратный курсор в виде оранжевого двигающегося квадратика. Теперь чтобы банально нарисовать прямоугольник аппаратно нужно инить 3D-рендеринг, а для этого потребуется: инициализация GART, загрузка микрокода, низкоуровневая инициализация GP, инициализация кольцевого буфера команд... Выйдет такой пример на несколько тысяч строк в лучшем случае. Пока я не готов за это браться.

      вторая часть (установка видеорежима)
      Сообщение отредактировано: shm -
      Цитата TheMachine @
      т.е. в общем случае вы правы конечно, а мне надо спать больше а пить меньше
        Красава.
        Не вкурсе, как видеорежимы через порты менять.
        Есть чтонибудь для защищенного режима?
          Видеорежими через порты менять можно, схема примерно такая: вырубаешь монитор, загружаешь оптом в регистры управления значения из таблички для нужного видеорежима, включаешь монитор. А вот конкретно сказать не могу так как набор регистров и значения, которые в них нужно загружать в разных моделях различны. В настоящее время я занят, может к февралю поосвобожусь, надо статью поправить под новые версии Radeon'ов (мой пример работать на них не будет), ну может и тебе помогу. Хотя я не вижу объективных причин зачем переключать видеорежим через порты: VESA нормально это делает, если есть нужно переключать видеорежимы прямо из PM32, то можно использовать V86.
          Цитата TheMachine @
          т.е. в общем случае вы правы конечно, а мне надо спать больше а пить меньше
            Да я ставлю весу перед переходом в защищенку, но мой родной режим 1366 на 768. А что курсор не поставиш уже скажем на радеон нд4570?
              Различных видеоадаптеров ATI огромное количество, у некоторых есть особенности, естественно я не имею возможности протестировать на всех. Попробуй сам под него допилить мой пример, у него доступ управление курсором вроде через группу регистров AVIVO осуществляется - они описаны в соответствующем даташите. Если получится, то выложи код, я поправлю.
              Цитата TheMachine @
              т.е. в общем случае вы правы конечно, а мне надо спать больше а пить меньше
                Хорошо попробую
                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                0 пользователей:


                Рейтинг@Mail.ru
                [ Script Execution time: 0,1104 ]   [ 18 queries used ]   [ Generated: 23.10.18, 13:57 GMT ]