24-разрядный код точки
Стандартом VESA не оговорено обязательное наличие резервного байта в
коде точки. Поэтому видеокарты, у которых он отсутствует, а код точки
занимает всего 24 разряда, формально соответствуют требованиям стандарта
VBE 1.2.
Такой размер кода точки был обнаружен автором при исследовании единственной
видеокарты МАСН64 фирмы ATI Technologies, выпущенной 20 октября 1997 г.
Как уже говорилось в главе 1, по данным на сентябрь 1998 года фирма ATI
вошла в первую пятерку производителей графических чипов, на ее долю приходится
27% этой продукции. Поэтому весьма вероятно, что видеокарты, поддерживающие
24-разрядный код в режимах True color, будет выпускать не только фирма
ATI.
Расположение базовых цветов в коде точки и их размеры соответствуют
табл. 7.2, за исключением отсутствующего пустого байта. Поэтому не будем
повторять все сказанное о кодировании цвета, а перейдем к существу проблемы.
Недостатки трехбайтового кода
У рассмотренных ранее видеорежимов размер кода точки совпадал с одной
из единиц измерения памяти — байт, слово, двойное слово. Нас не интересовало
хорошо это или плохо, поскольку не было оснований для постановки такого
вопроса, но, прочитав данный раздел, вы поймете, что это было хорошо.
Трехбайтовый код точки порождает две основные проблемы.
- 1. У всех без исключения команд микропроцессоров Intel
размер операнда кратен степени двойки, поэтому обработать три байта
одной командой нельзя. В таком случае при обмене данными с видеопамятью
приходится обрабатывать сначала слово, а затем байт или наоборот, что
замедляет процесс обмена. Однако это не самое неприятное.
- 2. Размер сегмента оперативной или видеопамяти так же
кратен степени двойки.
Поэтому в нем не помещается целое количество трехбайтовых точек. У одной
из них (первой или последней) в текущем сегменте окажется только часть
кода, соответствующая одному или двум базовым цветам. Вот это настоящий
подарок! Он вынуждает пересмотреть логику манипуляций с точками, которая
использовалась до сих пор, и в некоторых случаях применять специальные
подпрограммы для записи кодов точек в видеопамять и их чтения из нее.
Подпрограммы для записи и чтения трехбайтового кода точки приведены
ниже. При их составлении учтено следующее:
- код точки находится в трех младших байтах регистра
еах, причем базовые цвета расположены так, как показано в табл.
7.2, а старший резервный байт не используется;
- адрес видеопамяти находится в регистре di, а текущее
окно задает переменная! cur_win, при выполнении подпрограмм исходные
значения адреса и окна не изменяются;
- код видеосегмента находится в регистре es;
- доступ к видеопамяти происходит через два окна, окно
А используется при записи, а окно в — при чтении;
- если код точки помещается в текущем окне, то подпрограммы
должны выполнять минимум вспомогательных действий.
Подпрограмма записи кода точки
Текст подпрограммы, выполняющей запись кода точки из регистра еах в видеопамять,
приведен в примере 7.1.
Пример 7.1. Подпрограмма записи 24-разрядного кода точки
wrtpnt : push eax сохранение содержимого еах
mov es: [di] , al запись первого байта кода точки
shr eax, 08 сдвиг содержимого еах
cmp di, -2 сколько байтов до конца окна ?
jae wrtpnl -> 1 или 2 байта
mov es : [di+1] , ax запись остатка кода точки
pop eax восстановление содержимого еах
ret выход из подпрограммы
wrtpnl : push Cur win сохранение значения Cur win
je wrtpn2 -> до конца окна 2 байта
call NxtWinA установка следующего окна
mov es: [di+1] , ax запись остатка кода точки
jmp SHORT wrtpn3 переход на метку wrtpnS
wrtpn2 : mov es : [di+1] , al запись второго байта кода точки
call NxtWinA установка следующего окна
mov es: [di+2] , ah запись третьего байта кода точки
wrtpnS : pop Cur win восстановление значения Cur win
call SetWinA восстановление исходного окна
pop eax восстановление еах
ret выход из подпрограммы
Выполнение примера 7.1 начинается с сохранения в стеке кода точки, записи
в видеопамять его младшего байта и сдвига содержимого регистра
еах на 8 разрядов влево. После сдвига оставшиеся два байта кода
точки находятся в регистре ах. Теперь надо проверить,
сколько байтов осталось до конца окна, и выбрать способ записи остатка
кода точки. Если оставалось больше двух байтов, то команда
jae не выполняет переход на метку wrtpni.
Последние два байта кода точки записываются в видеопамять, восстанавливается
исходный код в регистре еах и происходит возврат из подпрограммы.
Если до конца окна оставалось 1 или 2 байта, то команда
jae выполняет переход на метку wrtpni.
На этой ветке подпрограммы сначала в стеке сохраняется значение переменной
cur_win и вновь проверяется оставшееся количество
байтов (команда push не изменяет состояние флагов).
Если до конца окна оставался 1 байт, то команда je
не производит переход на метку wrtpn2 и выполняется
следующая команда, устанавливающая новое окно видеопамяти. Затем в это
окно записываются два оставшихся байта кода точки, и происходит безусловный
переход на метку wrtpn3 для завершающих действий.
Если до конца окна оставалось ровно 2 байта, то команда je
выполнит переход на метку wrtpn2. В этом случае
в видеопамять надо записать еще один байт кода точки, находящийся в регистре
ai, вызвать подпрограмму для установки следующего окна и записать
в это окно старший байт кода точки из регистра ah.
Фрагмент подпрограммы, начинающийся с метки wrtpns,
является общим для случаев, когда до конца буфера оставался один или два
байта. В нем восстанавливается исходное значение переменной cur__win,
исходное окно видеопамяти и содержимое регистра еах. После этих действий
происходит возврат на вызывающий модуль.
Подпрограмма чтения кода точки
Текст подпрограммы приведен в примере 7.2. При ее использовании в разделе
данных задачи надо зарезервировать один байт, присвоив ему имя DotBuff.
Пример 7.2. Подпрограмма чтения 24-разрядного кода точки
rdpnt : xor еах, еах очистка регистра еах
mov al, es: [di] чтение младшего байта кода точки
mov DotBuff, al и его сохранение в DotBuff
cmp di, -2 сколько байтов до конца окна ?
jae rdpnt 2 -> 1 или 2 байта
mov ax, es: [di+1] чтение старших байтов кода точки
rdpntl: shl eax, 08 сдвиг содержимого еах влево
mov al, DotBuff добавление кода младшего байта
ret выход из подпрограммы
rdpnt2 : push Cur win сохранение значения Cur win
je rdpnt3 -> до конца окна 2 байта
call NxtWinB установка следующего окна
mov ax, es: [di+1] чтение старших байтов кода точки
jmp SHORT rdpnt4 переход на метку rdpnt4
rdpnt3: mov al, es: [di+1] чтение 2-го байта кода точки
call NxtWinB установка следующего окна
mov ah, es: [di+2] чтение старшего байта кода точки
rdpnt4 : pop Cur win восстановление значения Cur win
call SetWinB восстановление исходного окна
jmp SHORT rdpntl переход на метку rdpnt2
Выполнение примера 7.2 начинается с очистки регистра еах.
Это нужно для очистки старшего байта формируемого кода. Затем младший
байт кода точки считывается в регистр al и помещается
в DotBuff. Теперь надо проверить, сколько байтов осталось до конца окна,
и выбрать способ чтения старших байтов кода точки.
Если до конца окна осталось больше двух байтов, то переход на метку
rdpnt2 не происходит и выполняется команда, следующая за
jae rdpnt2. Она помещает в регистр ах два старших байта кода точки.
Содержимое регистра еах сдвигается на 8 разрядов влево, в освободившийся
младший байт копируется содержимое DotBuff и происходит возврат'из подпрограммы
на вызывающий модуль.
Если до конца окна осталось меньше чем 3 байта, то команда jae
выполняет переход на метку rdpnt2. При этом
в стеке сохраняется значение переменной cur_win,
и если в буфере остался 1 байт, то команда je не
выполняет переход на метку rdpnts. В этом случае
устанавливается следующее окно видеопамяти, в регистр ах
считываются два старших байта кода точки, и происходит безусловный переход
на метку rdpnt4 для завершающих действий.
Если до конца окна осталось 2 байта, то команда je
rdpnts выполняет переход на метку rdpna.
В таком случае в регистр al сначала записывается
средний код точки, после этого устанавливается следующее окно видеопамяти
и в регистр ah считывается старший байт кода
точки.
Далее выполняется фрагмент подпрограммы, имеющий метку
rdpnt4. В нем восстанавливаются значение переменной cur__win
и исходное окно видеопамяти, после чего происходит безусловный переход
на метку rdpntl для окончательного формирования кода и выхода из подпрограммы.
Работа с двумя окнами
В приведенных примерах использованы имена подпрограмм Nxtwin и Setwin
с добавленными к ним буквами див. Они встречаются первый раз, потому уточним,
о чем идет речь.
Способы работы с двумя окнами видеопамяти описаны в разделе.
Там говорилось о двух вариантах переключения окон, одно из которых доступно
только для чтения, а другое только для записи. Первый вариант основан
на одновременном переключении окон. Текст соответствующей подпрограммы
Setwin приведен в примере 2.9. Второй вариант основан на независимом переключении
окон для записи и чтения. В разделе
описано, как составить две группы подпрограмм для независимой работы с
окнами. При этом рекомендовалось добавить к основным именам подпрограмм
буквы А и В. Выбор одного из этих вариантов зависит от конкретных особенностей
алгоритма преобразования графического объекта. До сих пор нас вполне устраивало
одновременное изменение номеров обоих окон.
Таким образом, если при использовании подпрограмм примеров 7.1 и 7.2
необходимо работать с двумя разными окнами, то надо использовать два комплекта
подпрограмм с именами, указанными в примерах 7.1 и 7.2. Если же допустимо
одновременное переключение окон, то в именах подпрограмм надо просто убрать
буквы А и В.
Когда используются подпрограммы
Расположение кода точки в двух смежных окнах событие достаточно редкое.
Если вести отсчет от начала видеопамяти, то в трех подряд расположенных
окнах оно происходит дважды. Например, при установке режима H2h на экране
помещается 307 200 точек, их коды занимают 15 неполных окон видеопамяти.
Из них только коды 10 точек расположены в двух смежных окнах (10 случаев
из 307 200)!
Если код точки расположен в одном окне, то в описанных подпрограммах
выполняется 9 команд при записи и 10 при чтении (с учетом команды вызова
подпрограммы). Поэтому при разработке конкретной задачи имеет смысл взвесить
все доводы за и против применения описанных подпрограмм. Одним из возможных
компромиссов между размером задачи и временем ее выполнения является обращение
к подпрограммам только в тех случаях, когда код точки находится в двух
смежных окнах.
Замечание
При работе видеокарты ATI MACH64 в режимах True color используемый объем
видеопамяти сокращается на 25%. В обмен на это мы получаем не только усложнение
программ и замедление процесса выполнения задач. Впервые видеокарта, формально
соответствующая стандарту VESA, оказывается несовместимой с другими видеокартами.
Эта несовместимость проявляется только при работе в среде DOS в режимах
True Color, но факт остается фактом! |