Работа с LFB в DOS — Архив WASM.RU
Осознав своё место в мире, постигнув
единство всего сущего, относительность
добра и зла, человек обретает душевное
равновесие и покой, поколебать который
не в силах никакие бури…Традиции воинских искусств «КЭМПО»
Наверняка всем кто только начинал программировать на Ассемблере, неизбежно приходилось сталкиваться с проблемой вывода на экран в режимах SVGA. Многие использовали банки видеопамяти или перемещение окна, но есть несколько минусов использования такого подхода:
- Нужно написать довольно большую процедуру для вывода точек на экран
- Переключение банков занимает значительное время. (Особенно заметно на 386-ом с VGA картой )
Но есть и плюс: переключение банков видеопамяти можно использовать даже на 286-ом, в то время как для работы LFB нужна видеокарта как минимум поддерживающая спецификацию VESA VBE 2.0 и т.д. и т.п.
Не будем забегать вперёд и разберём всё по порядку…
И так, LFB (Linear Frame Buffer) – линейный кадровый буфер, использующийся для отображения видеопамяти на непрерывный кусок адресного пространства. Для работы с видеорежимами и видеокартой используется соответствующее прерывание BIOS – INT 10. Программировать линейный кадровый буфер мы будем в BIG REAL MODE, так как в реальном режиме LFB не используется, за исключением совсем экзотических случаев. Я предполагаю, что вы немного разбираетесь в защищённом режиме (далее PM), селекторах, дескрипторах и прочей бесовщине, а если нет, тоже не беда… Ведь чтобы использовать электрочайник не обязательно в совершенстве знать его устройство, формулы теплового баланса и т.п. Если вы готовы, то начнём-с!
Прерывание 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):
; LFB.asm ; Простенькая программа, демонстрирующая работу с LFB ; Компиляция: ; tasm.exe /m LFB.asm ; Линк: ; tlink.exe /x /3 LFB.obj .386p ; 32-битные регистры появились на 386 LFB_seg segment para public "code" use16 ; Наш сегмент assume CS:LFB_seg,DS:LFB_seg,SS:LFB_seg ; Код, данные, стек ; находятся в одном сегменте start: ; Этот блок кода отвечает за переход в BIG REAL MODE ; мы не будем на нём подробно останавливаться… push cs pop ds mov eax,cr0 test al,1 jz no_V86 mov dx,offset v86_msg err_exit: mov ah,9 int 21h mov ah,4Ch int 21h v86_msg db "Error!Bad mode in v86!$" win_msg db "Error!Windows is runing!$" no_V86: mov ax,1600h int 2Fh test al,al jz no_windows mov dx,offset win_msg jmp err_exit no_windows: xor eax,eax mov ax,cs shl eax,4 add ax,offset GDT mov gdt_base,eax lgdt fword ptr gdtr cli mov eax,cr0 or al,1 mov cr0,eax jmp start_PM start_PM: mov ax,8 mov ds,ax mov es,ax mov fs,ax mov gs,ax mov eax,cr0 and al,0FEh mov cr0,eax jmp exit_PM exit_PM: xor ax,ax mov ds,ax mov es,ax mov fs,ax mov gs,ax sti mov ax,cs mov ds,ax ; Всё, теперь мы в BIG REAL MODE ; Нам нужны некоторые сегментные регистры push ds pop es ; Получаем общую SVGA информацию mov ax,4F00h ; Сохраняем её в буфере mov di,offset Video_Buffer int 10h ; Считываем номер версии VBE в BX mov bx,word ptr [Video_Buffer+04h] ; Если он ниже чем 2.0 cmp bx,0200h ; Выдать сообщение об ошибке jl Not_support_LFB ; Иначе переходим далее jmp Next_step Not_support_LFB: mov ah,9 mov dx,offset Error int 21h ret Next_step: ; Получаем информацию о режиме mov ax,4F01h mov cx,4112h mov es:edi,offset Info_Buffer int 10h ; Записываем физический адрес начала LFB в ESI mov esi,dword ptr [Info_Buffer+028h] push esi ; Устанавливаем режим mov ax,4F02h mov bx,4112h int 10h pop esi ; Теперь выводим точку mov X_scr,640 mov Pos_X,100 mov Pos_Y,100 mov Cr_Red,255 mov Cr_Blue,0 mov Cr_Green,0 mov Cr_Alpha,0 call pset32bit ; Ожидание нажатия клавиши mov ah,1 int 21h ; Выход mov ah,4Ch int 21h ; Процедура вывода точки на экран pset32bit proc pusha ; В общем случае формула выглядит так: ; X_scr * Pos_Y * Количество компонент цвета + Pos_X * Количество компонент цвета mov eax,Pos_Y mov ebx,X_scr imul eax,ebx imul eax,4 mov ebx,Pos_X imul ebx,4 add eax,ebx xor ecx,ecx xor ebx,ebx mov cl,Cr_Blue mov ch,Cr_Green mov bl,Cr_Red mov bh,Cr_Alpha mov byte ptr fs:[esi+eax],cl inc eax mov byte ptr fs:[esi+eax],ch inc eax mov byte ptr fs:[esi+eax],bl inc eax mov byte ptr fs:[esi+eax],bh popa ret pset32bit endp ; Начало области данных GDT label byte ; Нулевой дескриптор db 8 dup(0) ; 16-битный 4 Гб сегмент: db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 ; Размер GDT gdtr dw 16 ; Линейный адрес GDT gdt_base dd ? Pos_X dd 0 ; Координата X точки Pos_Y dd 0 ; Координата Y точки X_scr dd 0 ; Разрешение по X Cr_Red db 0 ; Красная компонента Cr_Green db 0 ; Зелёная компонента Cr_Blue db 0 ; Синяя компонента Cr_Alpha db 0 ; Альфа Info_Buffer db 256 dup(0) ; Буфер для информации о режиме Video_Buffer db 512 dup (0) ; Буфер для общей SVGA информации Error db "Not support VESA VBE 2.0 or higher!$" LFB_seg ends end startВот собственно и всё. Если возникнут вопросы по теме, мыльте на Exs42@yandex.ru, я с радостью на них отвечу. Приятного клавишевания.
© Exs42
Работа с LFB в DOS
Дата публикации 5 окт 2006