В программе, созданной в среде TMT Pascal, в любом экранном режиме текст может быть выведен средствами стандартного модуля graph. Однако при этом могут возникнуть проблемы с использованием кириллических символов. Рассмотрим два других способа отображения текста: как стандартными средствами Паскаля, так и с помощью команд MMX. Сначала же внесем изменения в модуль text256, написанный на Borland Pascal (см. «Мир ПК», № 12/01). Однако непосредственно применять этот модуль из-за несовместимости адресации в реальном и защищенном режимах нельзя. Внесем коррективы в ту часть программы, где происходит запрос адреса шрифта знакогенератора. Поскольку в дальнейшем удобнее будет хранить таблицы шрифта в области данных программы, перепишем их (таблицы) в массив, созданный для этих целей. Кроме того, следует заменить прямую запись в память на обращение к стандартной процедуре PutPixel, чтобы обеспечить возможность работы в любом из доступных экранных разрешений.
Текст модуля приведен в листинге 1. Если пользоваться отключенными при переходе в DOS32 операторами вывода текста (см. «Мир ПК», № 9—11/02), то надпись будет выведена сбоку экрана. Чтобы обеспечить отображение текста посередине экрана при любом разрешении, целесообразно применить следующую конструкцию:
PutText(ScrSizeX div 2 - 4*Length(MyString), ScrSizeY div 2 - 4,MyString);
Четверка в формуле — половина ширины или высоты символа (размер шрифта — 8x8).
Кроме того, нас интересует скорость, с которой программа будет рисовать буквы на экране, поэтому вместо одной строки станем выводить по 50. Для этого в главном цикле программы сразу после BackBufferToScreen поместим фрагмент:
if (MouseStatus and 1) = 1 then for i := 0 to 49 do PutText(20,16+i*8, ?Левая кнопка мыши нажата?); if (MouseStatus and 2) = 2 then for i := 0 to 49 do PutText(ScrSizeX -208-20,16+i*8, ?Правая кнопка мыши нажата?); if (MouseStatus and 4) = 4 then for i := 0 to 49 do PutText(ScrSizeX div 2 - 100,16+i*8, ?Средняя кнопка мыши нажата?);
Теперь восстановим вывод частоты кадров сразу после ее вычисления:
FPS := GetFPS; str(FPS:0:1,s); PutText(ScrSizeX div 2 - 40,ScrSizeY - 32,? ?+s+? fps ?);
Помимо того, необходимо ввести имя нового модуля в директиву uses, а также отключить синхронизацию с обратным ходом развертки, иначе измерение скорости будет некорректным.
Запустите программу, понажимайте кнопки мыши, и вы увидите, что вывод даже нескольких десятков строк существенно снижает скорость работы, те самые fps, за которые постоянно бьются как программисты, так и разработчики аппаратного обеспечения. Что же делать? Напишем новый модуль (назовем его text256a), способный заполнять текстом весь экран без заметного снижения производительности.
В начале статьи встречается термин ММХ. Это расширение набора команд, впервые примененное компанией Intel в процессоре Pentium MMX и ставшее затем индустриальным стандартом*. Одна команда MMX обрабатывает 8 байт данных. Так как ширина символа составляет 8 точек, а в используемых нами режимах на точку приходится по 1 байту, именно это нам и требуется. Сделаем формат таблицы шрифтов совпадающим с форматом экрана: 1 байт на 1 точку, точку фона обозначим значением 0, а точку символа — $ff. Кроме того, нам понадобятся два массива, соответствующих по длине регистру MMX (т. е. 8 байт), причем в каждом их байте будет содержаться либо цвет символа, либо цвет фона. Все это поможет избавиться от медленных команд — условных переходов, а также обойтись лишь логическими операциями при формировании маски символа.
Текст нового модуля text256a приведен в листинге 2 с небольшими сокращениями (пропущенные части точно повторяют соответствующие фрагменты модуля text256).
Теперь, когда есть два модуля, можно сравнить скорость вывода текста каждым из них, изменяя всего одну букву в основной программе (в директиве uses). Особенно заметно их различие при небольшом количестве спрайтов. Запустите программу с новым модулем и сравните скорость отображения текста. В таблице приведены результаты измерений, проведенных с использованием процессора Pentium III-667 при пяти спрайтах на экране.
Из анализа таблицы видно, что время отображения строки различается более чем в 100 раз. Чтобы добиться большего повышения производительности, как правило, приходится чем-либо жертвовать, например объемом оперативной памяти, универсальностью или совместимостью.
- Совместимость. В процессорах 386, 486 и Pentium наша программа работать не сможет из-за отсутствия команд ММХ.
- Объем оперативной памяти. В результате перехода с 1 бита на точку на 1 байт на точку объем таблиц шрифта увеличится в 8 раз и составит 32 Кбайт.
- Универсальность. Многообразие способов работы с видеопамятью не позволяет совместить эффективность с универсальностью, поэтому наш новый модуль будет предназначен только для работы с экранным буфером, т. е. в терминологии создателей TMT Pascal - VirtualMode. Кроме того, он подходит лишь для режимов с 256 цветами. Для работы в True- или Hi-Color его следует несколько видоизменить.
Стоит ли овчинка выделки? В общем случае самым простым и универсальным будет вывод текста стандартными средствами модуля graph. Но при этом возникнут проблемы с русификацией программ, так как таблицы шрифтов берутся из файлов, входящих в комплект поставки компилятора (small.obj, medium.obj и large.obj), а они не русифицированы. При желании, правда, можно самому их русифицировать и даже обеспечить совместимость либо с кодовой страницей 866 (DOS), либо с Windows. По скорости данный метод почти такой же, какой обеспечивает модуль text256.
Также универсальным можно считать использование модуля text256. Он берет таблицы шрифтов не из файлов, а из тела установленного драйвера, поэтому если система русифицирована, то кириллические символы всегда будут в вашем распоряжении. Модуль сохраняет работоспособность при различной глубине цвета — от 8 до 32 бит на точку.
Если нужно быстро вывести большой объем текста с высокой частотой обновления, то целесообразнее применить специализированный модуль text256a, работающий на два порядка быстрее.
* Бердышев Е. Технология ММХ. М.: Диалог-МИФИ, 1998.