Работа с LFB в DOS

Дата публикации 5 окт 2006

Работа с LFB в DOS — Архив WASM.RU

Осознав своё место в мире, постигнув
единство всего сущего, относительность
добра и зла, человек обретает душевное
равновесие и покой, поколебать который
не в силах никакие бури…

Традиции воинских искусств «КЭМПО»

Наверняка всем кто только начинал программировать на Ассемблере, неизбежно приходилось сталкиваться с проблемой вывода на экран в режимах SVGA. Многие использовали банки видеопамяти или перемещение окна, но есть несколько минусов использования такого подхода:

  • Нужно написать довольно большую процедуру для вывода точек на экран
  • Переключение банков занимает значительное время. (Особенно заметно на 386-ом с VGA картой :smile3: )

Но есть и плюс: переключение банков видеопамяти можно использовать даже на 286-ом, в то время как для работы LFB нужна видеокарта как минимум поддерживающая спецификацию VESA VBE 2.0 и т.д. и т.п.

Не будем забегать вперёд и разберём всё по порядку…

И так, LFB (Linear Frame Buffer) – линейный кадровый буфер, использующийся для отображения видеопамяти на непрерывный кусок адресного пространства. Для работы с видеорежимами и видеокартой используется соответствующее прерывание BIOS – INT 10. Программировать линейный кадровый буфер мы будем в BIG REAL MODE, так как в реальном режиме LFB не используется, за исключением совсем экзотических случаев. Я предполагаю, что вы немного разбираетесь в защищённом режиме (далее PM), селекторах, дескрипторах и прочей бесовщине, а если нет, тоже не беда… Ведь чтобы использовать электрочайник не обязательно в совершенстве знать его устройство, формулы теплового баланса и т.п. :smile3: Если вы готовы, то начнём-с!

Прерывание INT 10

Прежде всего, нам понадобятся несколько функций для переключения режимов и определения номера версии VBE:

INT 10h АН = 4Fh, AL = 00 — Получить общую SVGA-информацию

Ввод:

AX = 4F00h
ES:DI = адрес буфера (512 байт)

Вывод:

AL = 4Fh, если функция поддерживается
АН = 01, если произошла ошибка
АН = 00, если данные получены и записаны в буфер

Буфер для общей SVGA-информации:

+00h:

4 байта — будет содержать «VESA» после вызова прерывания, чтобы получить поля, начиная с 14h, здесь надо предварительно записать строку «VBE2»

+04h:

слово — номер версии VBE в двоично-десятичном формате (0102h — для 1.2, 0200h — для 2.0)

+06h:

4 байта — адрес строки-идентификатора производителя

+0Ah:

4 байта — флаги:

бит 0 — АЦП поддерживает 8-битные цветовые компоненты (см. подфункцию 08h)
бит 1 — видеоадаптер несовместим с VGA
бит 2 — АЦП можно программировать только при обратном ходе луча
бит 3 — поддерживается спецификация аппаратного ускорения графики VBE/AF 1.0
бит 4 — требуется вызов EnableDirectAccess перед использованием LFB
бит 5 — поддерживается аппаратный указатель мыши
бит 6 — поддерживается аппаратное отсечение
бит 7 — поддерживается аппаратное копирование блоков
биты 8 – 31 зарезервированы

+0Eh:

4 байта — адрес списка номеров поддерживаемых видеорежимов (массив слов, последнее слово = FFFFh, после которого обычно следует список нестандартных режимов, также заканчивающийся словом FFFFh)

+12h:

слово — объем видеопамяти в 64-килобайтных блоках

+14h:

слово — внутренняя версия данной реализации VBE

+16h:

4 байта — адрес строки с названием производителя

+1Ah:

4 байта — адрес строки с названием видеоадаптера

+1Eh:

4 байта — адрес строки с версией видеоадаптера

+22h:

слово — версия VBE/AF (BCD, то есть 0100h для 1.0)

+24h:

4 байта — адрес списка номеров режимов, поддерживающих аппаратное ускорение (если бит поддержки VBE/AF установлен в 1)

+28h:

216 байт — зарезервировано VESA

+100h:

256 байт — зарезервировано для внутренних данных VBE. Так, например, в эту область копируются строки с названиями производителя, видеоадаптера, версии и т.д.

INT 10h АН = 4FH, AL = 02 — Установить режим

Ввод:

AX=4F02h
ВХ = номер режима:

биты 0 – 6 — собственно номер режима
бит 7 — видеопамять не очищается при установке режима, если все следующие биты — нули
бит 8 — стандартный VBE SVGA-режим
бит 9 — нестандартный SVGA-режим
биты 10 – 12 — зарезервированы
бит 13 — режим использует аппаратное ускорение
бит 14 — режим использует LFB
бит 15 — видеопамять не очищается при установке режима

Кроме того, специальный номер режима 81FFh соответствует доступу ко всей видеопамяти и может использоваться для сохранения ее содержимого.

Вывод:

AL = 4Fh, если функция поддерживается
АН = 00, если режим установлен
АН = 01 или 02, если произошла ошибка

Вот номера всех стандартных режимов (в скобках указан размер требуемой памяти):

4-битные режимы (16 цветов):

VGA

  • 012h: 640x480 (64 Кб)

VESA VBE 1.0

  • 102h: 800x600 (256 Кб)
  • 104h: 1024x768 (192 Кб)
  • 106h: 1280x1024 (768 Кб)

Каждый пиксель описывается одним битом, для вывода цветного изображения требуется программирование видеоадаптера на уровне портов ввода-вывода.

8-битные режимы (256 цветов):

VGA

  • 013h: 320x200 (64 Кб)

VBE 1.0

  • 100h: 640x400 (256 Кб)
  • 101h: 640x480 (320 Кб)
  • 103h: 800x600 (512 Кб)
  • 105h: 1024x768 (768 Кб)
  • 107h: 1280x1024 (1,3 Мб)

VBE 2.0

  • 120h: 1600x1200 (1,9 Мб)

Каждый пиксель описывается ровно одним байтом. Значение байта — номер цвета из палитры, значения цветов которой можно изменять, например, вызывая подфункцию 09 видеофункции 4Fh.

15-битные режимы (32 К цветов):

VBE 1.2

  • 10Dh: 320x200 (128 Кб)
  • 110h: 640x480 (768 Кб)
  • 113h: 800x600 (1 Мб)
  • 116h: 1024x768 (1,5 Мб)
  • 119h: 1280x1024 (2,5 Мб)

VBE 2.0

  • 121h: 1600x1200 (3,8 Мб)

Каждый пиксель описывается ровно одним словом (16 бит), в котором биты 0 – 4 содержат значение синей компоненты цвета, биты 5 – 9 — зеленой, а биты 10 – 14 — красной. Бит 15 не используется.

16-битные режимы (64 К цветов):

VBE 1.2

  • 10Eh: 320x200 (128 Кб)
  • 111h: 640x480 (768 Кб)
  • 114h: 800x600 (1 Мб)
  • 117h: 1024x768 (1,5 Мб)
  • 11Ah: 1280x1024 (2,5 Мб)

VBE 2.0

  • 121h: 1600x1200 (3,8 Мб)

Так же как и в 15-битных режимах, каждый пиксель описывается ровно одним словом. Обычно биты 0 – 4 (5 бит) содержат значение синей компоненты, биты 5 – 10 (6 бит) — зеленой, а биты 11 – 15 (5 бит) — красной. В нестандартных режимах число бит, отводимое для каждого цвета, может отличаться, так что при их использовании следует вызвать подфункцию 01 видеофункции 4Fh и получить информацию о видеорежиме, включающую битовые маски и битовые смещения для цветов.

24-битные и 32-битные режимы (16 М цветов):

VBE 1.2

  • 10Fh: 320x200 (192 Кб)
  • 112h: 640x480 (1 Мб)
  • 115h: 800x600 (1,4 Мб)
  • 118h: 1024x768 (2,3 Мб)
  • 11Bh: 1280x1024 (3,7 Мб)

VBE 2.0

  • 122h: 1600x1200 (7,7 Мб)

В режимах с 24-битным и 32-битным цветом каждому пикселю на экране соответствуют три байта и одно двойное слово (4 байта). Если видеорежим использует модель памяти 6 (Direct Color), то младший байт (байт 0) содержит значение синего цвета, байт 1 содержит значение зеленого, байт 2 — значение красного, а байт 3 — в 32-битных режимах резервный и используется либо для выравнивания, либо содержит значение для альфа-канала. Некоторые видеорежимы могут использовать не Direct Color, a YUV (модель памяти 7) — здесь младший байт соответствует насыщенности красного, байт 1 — насыщенности синего, а байт 2 — яркости.

INT 10h АН = 4Fh, AL = 01 — Получить информацию о режиме

Ввод:

AX = 4F01h
СХ = номер SVGA-режима (бит 14 соответствует использованию LFB, бит 13 — аппаратному ускорению)
ES:DI = адрес буфера для информации о режиме (256 байт)

Вывод:

AL = 4Fh, если функция поддерживается
АН = 01, если произошла ошибка
АН = 00, если данные получены и записаны в буфер

Буфер для информации о SVGA-режиме:

+00h:

слово — атрибуты режима:

бит 0 — режим присутствует
бит 1 — дополнительная информация (смещения 12h – 1Eh) присутствует (для VBE 2.0 эта информация обязательна и бит всегда установлен)
бит 2 — поддерживается вывод текста на экран средствами BIOS
бит 3 — режим цветной
бит 4 — режим графический
бит 5 — режим несовместим с VGA
бит 6 — переключение банков не поддерживается
бит 7 — LFB не поддерживается
бит 8 — не определен
бит 9 — (для VBE/AF) приложения должны вызвать EnableDirectAccess, прежде чем переключать банки

+02h:

байт — атрибуты окна А:

бит 1 — окно существует
бит 2 — чтение из окна разрешено
бит 3 — запись в окно разрешена

+03h:

байт — атрибуты окна В

+04h:

слово — гранулярность окна — число килобайтов, которому всегда кратен адрес начала окна в видеопамяти (обычно 64)

+06h:

слово — размер окна в килобайтах (обычно 64)

+08h:

слово — сегментный адрес окна А (обычно A000h)

+0Ah:

слово — сегментный адрес окна В

+0Ch:

4 байта — адрес процедуры перемещения окна (аналог подфункции 05h, но выполняется быстрее)

+10h:

слово — число целых байт в логической строке

+12h:

слово — ширина в пикселях (для графики) или символах (для текста)

+14h:

слово — высота в пикселях (для графики) или символах (для текста)

+16h:

байт — высота символов в пикселях

+17h:

байт — ширина символов в пикселях

+18h:

байт — число плоскостей памяти (4 — для 16-цветных режимов, 1 — для обычных, число переключений банков, требуемое для доступа ко всем битам (4 или 8), — для модели памяти 5)

+19h:

байт — число бит на пиксель

+1Ah:

байт — число банков для режимов, в которых строки группируются в банки (2 — для CGA, 4 — для HGC)

+1Bh:

байт — модель памяти:
00h — текст
01h — CGA-графика
02h — HGC-графика
03h — EGA-графика (16 цветов)
04h — VGA-графика (256 цветов в одной плоскости)
05h — Режим X (256 цветов в разных плоскостях)
06h — RGB (15-битные и выше)
07h — YUV
08h – 0Fh — зарезервированы VESA
10h – FFh — нестандартные модели

+1Ch:

байт — размер банка в килобайтах (8 — для CGA и HGC, 0 — для остальных)

+1Dh:

байт — число видеостраниц

+1Eh:

байт — зарезервирован

+1Fh:

байт — битовая маска красной компоненты

+20h:

байт — первый бит красной компоненты

+21h:

байт — битовая маска зеленой компоненты

+22h:

байт — первый бит зеленой компоненты

+23h:

байт — битовая маска синей компоненты

+24h:

байт — первый бит синей компоненты

+25h:

байт — битовая маска зарезервированной компоненты

+26h:

байт — первый бит зарезервированной компоненты

+27h:

байт — дополнительные флаги:

бит 0: —поддерживается перепрограммирование цветов (подфункция 09h)
бит 1 — приложение может использовать биты в зарезервированной компоненте

+28h:

4 байта — физический адрес начала LFB

+2Ch:

4 байта — смещение от начала LFB, указывающее на первый байт после конца участка памяти, отображающейся на экране

+30h:

слово — размер памяти в LFB, не отображающейся на экране, в килобайтах

+32h:

206 байт — зарезервировано

Реализация.

            И так, мы изучили достаточно, чтобы приступить непосредственно к программированию. Собирать всё будем в TASM 5.0. Как уже было сказано выше, для каждого режима свой алгоритм вывода точки,  будем использовать в нашем примере 640X480X32 бита или 112h, но т.к  мы используем LFB, то необходимо бит 14, номера режима, установить в 1. Так же неплохо было бы, сделать проверку на наличие VBE 2.0 и выше. И конечно же не нужно забывать о двух дескрипторах: нулевом и 16-бином, лимитом в 4 Гб. Вроде всё. Вот наконец код, который переводит экран в режим 112h, и выводит точку красного цвета:

Код (Text):
  1.  
  2. ; LFB.asm
  3. ; Простенькая программа, демонстрирующая работу с LFB
  4. ; Компиляция:
  5. ;   tasm.exe /m  LFB.asm
  6. ; Линк:
  7. ;   tlink.exe /x /3 LFB.obj
  8.  
  9.     .386p                   ; 32-битные регистры появились на 386
  10. LFB_seg segment para public "code" use16        ; Наш сегмент
  11.     assume  CS:LFB_seg,DS:LFB_seg,SS:LFB_seg    ; Код, данные, стек
  12.                                 ; находятся в одном сегменте
  13. start:
  14.  
  15. ; Этот блок кода отвечает за переход в BIG REAL MODE
  16. ; мы не будем на нём подробно останавливаться…
  17.  
  18.     push    cs
  19.     pop ds
  20.     mov eax,cr0
  21.     test    al,1
  22.     jz  no_V86
  23.     mov dx,offset v86_msg
  24. err_exit:
  25.     mov ah,9
  26.     int 21h
  27.     mov ah,4Ch
  28.     int 21h
  29. v86_msg db  "Error!Bad mode in v86!$"
  30. win_msg db  "Error!Windows is runing!$"
  31. no_V86:
  32.     mov ax,1600h
  33.     int 2Fh
  34.     test    al,al
  35.     jz  no_windows
  36.     mov dx,offset win_msg
  37.     jmp err_exit
  38. no_windows:
  39.     xor eax,eax
  40.     mov ax,cs
  41.     shl eax,4
  42.     add ax,offset GDT
  43.     mov gdt_base,eax
  44.     lgdt    fword ptr gdtr
  45.     cli
  46.     mov eax,cr0
  47.     or  al,1
  48.     mov cr0,eax
  49.     jmp start_PM
  50.    
  51. start_PM:
  52.     mov ax,8
  53.     mov ds,ax
  54.     mov es,ax
  55.     mov fs,ax
  56.     mov gs,ax
  57.    
  58.     mov eax,cr0
  59.     and al,0FEh
  60.     mov cr0,eax
  61.     jmp exit_PM
  62.  
  63. exit_PM:
  64.     xor ax,ax
  65.     mov ds,ax
  66.     mov es,ax
  67.     mov fs,ax
  68.     mov gs,ax
  69.     sti
  70.     mov ax,cs
  71.     mov ds,ax
  72. ; Всё, теперь мы в BIG REAL MODE
  73. ; Нам нужны некоторые сегментные регистры
  74.     push    ds
  75.     pop es
  76. ; Получаем общую SVGA информацию
  77.     mov ax,4F00h
  78. ; Сохраняем её в буфере
  79.     mov di,offset Video_Buffer
  80.     int 10h
  81. ; Считываем номер версии VBE в BX
  82.     mov bx,word ptr [Video_Buffer+04h]
  83. ; Если он ниже чем 2.0
  84.     cmp bx,0200h
  85. ; Выдать сообщение об ошибке
  86.     jl  Not_support_LFB
  87. ; Иначе переходим далее
  88.     jmp Next_step
  89. Not_support_LFB:
  90.     mov ah,9
  91.     mov dx,offset Error
  92.     int 21h
  93.     ret
  94. Next_step:
  95.  
  96. ; Получаем информацию о режиме
  97.     mov ax,4F01h
  98.     mov cx,4112h
  99.     mov es:edi,offset Info_Buffer
  100.     int 10h
  101. ; Записываем физический адрес начала LFB в ESI
  102.     mov esi,dword ptr [Info_Buffer+028h]
  103.     push    esi
  104. ; Устанавливаем режим
  105.     mov ax,4F02h
  106.     mov bx,4112h
  107.     int 10h
  108.     pop esi
  109. ; Теперь выводим точку
  110.  
  111.     mov X_scr,640
  112.     mov Pos_X,100
  113.     mov Pos_Y,100
  114.     mov Cr_Red,255
  115.     mov Cr_Blue,0
  116.     mov Cr_Green,0
  117.     mov Cr_Alpha,0
  118.     call    pset32bit
  119. ; Ожидание нажатия клавиши
  120.     mov ah,1
  121.     int 21h
  122. ; Выход
  123.     mov ah,4Ch
  124.     int 21h
  125.  
  126. ; Процедура вывода точки на экран
  127.  
  128. pset32bit   proc
  129.     pusha
  130. ; В общем случае формула выглядит так:
  131. ;  X_scr * Pos_Y * Количество компонент цвета + Pos_X * Количество компонент цвета
  132.  
  133.     mov eax,Pos_Y
  134.     mov ebx,X_scr
  135.     imul    eax,ebx
  136.     imul    eax,4
  137.     mov ebx,Pos_X
  138.     imul    ebx,4
  139.     add eax,ebx
  140.     xor ecx,ecx
  141.     xor ebx,ebx
  142.     mov cl,Cr_Blue
  143.     mov ch,Cr_Green
  144.     mov bl,Cr_Red
  145.     mov bh,Cr_Alpha
  146.     mov byte ptr fs:[esi+eax],cl
  147.     inc eax
  148.     mov byte ptr fs:[esi+eax],ch
  149.     inc eax
  150.     mov byte ptr fs:[esi+eax],bl
  151.     inc eax
  152.     mov byte ptr fs:[esi+eax],bh
  153.     popa
  154.     ret
  155. pset32bit   endp
  156. ; Начало области данных
  157.  
  158. GDT label   byte
  159. ; Нулевой дескриптор
  160.     db  8 dup(0)
  161. ; 16-битный 4 Гб сегмент:
  162.     db  0FFh,0FFh,0,0,0,10010010b,11001111b,0
  163. ; Размер GDT
  164. gdtr    dw  16
  165. ; Линейный адрес GDT
  166. gdt_base    dd  ?
  167. Pos_X           dd  0   ; Координата X точки
  168. Pos_Y           dd  0   ; Координата Y точки
  169. X_scr           dd  0   ; Разрешение по X
  170. Cr_Red      db  0   ; Красная компонента
  171. Cr_Green        db  0   ; Зелёная компонента
  172. Cr_Blue     db  0   ; Синяя компонента
  173. Cr_Alpha        db  0   ; Альфа
  174. Info_Buffer     db  256 dup(0)  ; Буфер для информации о режиме
  175. Video_Buffer        db  512 dup (0) ; Буфер для общей SVGA информации
  176. Error           db  "Not support VESA VBE 2.0 or higher!$"
  177. LFB_seg ends
  178.     end start

Вот собственно и всё. Если возникнут вопросы по теме, мыльте на Exs42@yandex.ru, я с радостью на них отвечу. Приятного клавишевания.

© Exs42

0 1.851
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532