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

Все статьи

Работа с 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, и выводит точку красного цвета:

; 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, я с радостью на них отвечу. Приятного клавишевания.

2002-2013 (c) wasm.ru