Когда я изучил историю двоичных файлов Quake, их логика стала мне понятна. quake.exe был первоначальным релизом, который мог работать в DOS и Windows 95. Затем появился vquake.exe для поддержки чипа Vérité 1000 с аппаратным ускорением. Позже выпустили glquake.exe, позволивший использовать аппаратное ускорение любого чипа с драйверами OpenGL. А чтобы совершить революцию в Интернет-deathmatch, id Software выпустила сервер и клиент QuakeWorld (qwsv.exe и qwcl.exe).

Однако я не мог понять смысл winquake.exe... до недавнего времени. В статье я расскажу, что понял, изучив его работу.

Производительность quake.exe

quake.exe работает и в DOS, и в Windows 95, но какова его скорость? Небольшой бенчмарк на моём PC с Pentium MMX на 233 МГц, Matrox Mystique (320x200 с размером экрана 101) и включенным звуком показал следующие результаты.

Конфигурация

Частота кадров

quake.exe, запущенный из DOS

48 fps

quake.exe, запущенный из Windows 95

38 fps

То есть частота кадров — это одна из причин существования WinQuake. quake.exe, работающий из Windows 95, приблизительно на 25% медленнее, чем тот же двоичный файл, запущенный из DOS. И этого стоило ожидать. Windows 95 выполняет приложения DOS в виртуальной машине («DOS BOX»), в которой доступ к памяти, прерывания и сигналы виртуализированы, что создаёт оверхед.

Ещё одна причина заключается в Quake Chunnelquake.exe может получать доступ к стеку TCP/IP Windows 95, но только через запутанную технологию Mpath, связывающую «DOS BOX» с dll-библиотеками win32. Благодаря созданию приложения только для win32 id Software обеспечила прямой доступ к winsock.dll.

Кроме того, id Software очень хотела, чтобы Quake работал в Windows NT. Несмотря на все усилия, разработчики DJGPP не смогли реализовать совместимость своего клиента DPMI в quake.exe с NT Virtual DOS Machine (NTVDM).

В NT не работают ближние указатели — это сильно разочаровало iD, которая провела несколько телефонных конференций с Microsoft.

Чарльз Сэндманн[1]

Как работает winquake.exe

Начать анализ можно с прочтения WQREADME.TXT и изучения всех режимов, доступных в winquake.exe. Они конфигурируются скриптом wq.bat.

Опции запуска WinQuake:
 wq max:      включены все функции, но работает не на всех системах
 wq fast:     максимальная скорость, но работает не на всех системах
 wq fastvid:  максимальная скорость видео, но более безопасный и, возможно, медленный звук
 wq fastsnd:  максимальная скорость звука, но более безопасное и, возможно, медленное видео
 wq safe:     запустится с большой вероятностью, но может быть медленнее
 wq verysafe: почти точно запустится, но может быть медленнее и без звука

Вот показатели, которые я получил для каждого из режимов на той же машине с Pentium MMX 233 МГц и с одинаковой конфигурацией.

Конфигурация

Частота кадров

wq max

42.4 fps 

wq fast

41.8 fps 

wq fastvid

45.0 fps 

wq fastsnd

41.8 fps 

wq safe

45.0 fps 

wq verysafe

40.0 fps*

Впечатляет. winquake.exe удалось достичь частоты кадров, всего на 6% отличающейся от частоты quake.exe , работающего в DOS. Миссия выполнена. Но как ему это удалось?

Бэкенды winquake.exe

Каждый «режим» конфигурируется флагами командной строки. Из этой части становится понятно, что существует три типа бэкенда для ввода, аудио и видео.

max      winquake                                                              -dinput
fast     winquake 
fastvid  winquake -wavonly
fastsnd  winquake          -nodirectdraw -nowindirect
safe     winquake -wavonly -nodirectdraw -nowindirect 
verysafe winquake                                     -dibonly -nosound -nojoy

Потр��сающе, что режим fastvid, обеспечивающий наибольшую частоту кадров, оставляет все параметры по умолчанию, но отключает бэкенд аудио!

Любопытный факт: fastvid — это ещё и название инструмента, исправляющего чудовищно низкие скорости записи видео Pentium Pro на чипсете, поставлявшемся с забагованным «Write Posting». Опция qw.bat никак с ним не связана.

Бэкенды аудио

WinQuake может отправлять свои звуковые эффекты (музыка считывается с дорожек CD) при помощи двух бэкендов аудио (а -nosound полностью отключает звуковые эффекты).

Эти два бэкенда — DirectSound (dsound.h из DirectX) и то, что id называет wave sound, то есть, на самом деле, winmm.h, звуковое API Windows MultiMedia, появившееся ещё в Windows 3.1.

Если доступен DirectSound, WinQuake использует его для обеспечения наименьших задержек. Однако этот бэкенд сильнее нагружает CPU и снижает частоту кадров на 10%. При помощи флага -wavonly пользователи могут принудительно включать использование WinMM , что приводит к увеличению задержек, но и к увеличению частоты кадров.

Бэкенды ввода

Для считывания пользовательского ввода WinQuake использует или DirectInput (dinput.h из DirectX), или устаревший Windows API winuser.h.

По умолчанию WinQuake использует winuser.h, но можно запросить применение DirectInput при помощи ключа -dinput, что немного повышает плавность движений и реакцию при быстрых поворотах. Подозреваю, он не был включен по умолчанию на случай, если DirectX не установлен, а может, из-за опасений проблем с драйверами.

Ввод с джойстиков обрабатывается через joystickapi.h. Похоже, драйверы тоже не были стабильными, потому что id обеспечила возможность его отключения флагом -nojoy.

Бэкенды видео

Сильнее всего меня интересовали бэкенды видео. WinQuake может работать в пяти режимах с использованием GDI, VGA, VESA, Accelerated VESA или DirectDraw.

Бэкенд видео DIB

Graphics Device Interface (GDI) (wingdi.h) — это фундамент рендеринга всей графики на рабочем столе Windows 95. Приложения обычно не использовали его напрямую, и вместо этого вызывали winuser.h (который, в свою очередь, использовал низкоуровневый wingdi.h).

WinQuake может выполнять рендеринг в Device-Independent Bitmap (DIB) — поверхность, накладываемую на окно через GDI. Поверхность может быть любого размера, поэтому «режим дисплея» (display mode) здесь распознавать не нужно; WinQuake жёстко з��даёт свои режимы DIB в разрешениях 320x240, 640x480 и 800x600 с квадратными пикселями.

Так как режим DIB использует Windows в соответствии со всеми стандартами, это самый безопасный режим, который должен работать всегда. А ещё это самый медленный способ рендеринга экрана, потому что WinQuake сначала выполняет рендеринг в DIB, которая затем отправляется GDI, после чего передаётся в видеокарту.

Хоть он и медленнее, в нём возможно аппаратное ускорение. Производители многих графических карт, желавших, чтобы те имели высокую производительность в Windows 95, имели реализацию важных функций наподобие bitBlt с аппаратным ускорением.

Наконец, режим DIB — единственный, способный рендериться в оконном режиме. Все остальные режимы выполняют рендеринг в полноэкранном режиме. Стоит отметить, что DIB также может рендериться в псевдополноэкранном режиме: если WinQuake запустить с флагом dibonly, он имитируется окном без рамок, занимающим весь экран.

Многоплатформенная графическая библиотека SciTech (MGL)

Для всего, что не связано с DIB, WinQuake использует MegaGraph Graphics Library компании SciTech. Это довольно дорогая библиотека ($499 в 1997 году, $1000 в 2025 году)[2], но она оправдывает свою цену, потому что благодаря ней был привнесён порядок в тот хаос, который представлял собой мир видеосистем в 1997 году, если игра работала не с GDI.

WinQuake приходилось иметь дело со следующими типами видеосистем:

1. VBEAF        : VESA Accelerator Function
2. VBE2         : Линейный кадровый буфер VESA для прямого записи/чтения VRAM.
3. DirectDraw   : Доступна только при установленном DirectX.
4. StandardVGA  : Старый добрый видеорежим VGA.

При запуске WinQuake регистрирует драйверы, которые должна загрузить MGL (см. registerAllDispDrivers). MGL затем перечисляет все поддерживаемые разрешения и выбирает для доступа к ним наиболее производительные драйверы.

void registerAllDispDrivers(void) {
  /* Несмотря на то, что эти драйверы требуют WinDirect, мы регистрируем
   * их, чтобы они всё равно были доступны, даже если DirectDraw
   * присутствует, а пользователь отключил высокопроизводительные
   * режимы WinDirect.
   */
  MGL_registerDriver(MGL_VGA8NAME,VGA8_driver);

  if (useWinDirect){
    MGL_registerDriver(MGL_LINEAR8NAME,LINEAR8_driver);
    if (!COM_CheckParm ("-novbeaf"))
      MGL_registerDriver(MGL_ACCEL8NAME,ACCEL8_driver);
  }

  if (useDirectDraw) {
    MGL_registerDriver(MGL_DDRAW8NAME,DDRAW8_driver);
  }
}

Список режимов и выбираемые MGL драйверы можно получить при помощи команды vid_describemodes в консоли Quake. На показанном ниже скриншоте мы видим почти полный набор из драйверов VGA8.DRVDDRAW.DRVLINEAR8.DRV и оконных режимов DIB.

Режим fast
Режим fast
Режим dibonly
Режим dibonly
Режим nowindirect
Режим nowindirect
Режим nodirectdraw
Режим nodirectdraw

До изучения исходного кода MGL я ни разу не слышал о VBE/AF. Насколько я понимаю, особой популярности он так и не получил, и драйверы под него писали лишь немногие производители.

MGL использовалась во многих играх: WinQuake, Hexen II, Grand Theft Auto, Maui Mallard in Cold Shadow, Total Mayhem, Balls of Steel.

Видеосистема DirectDraw

Microsoft вполне чётко осознавала, что GDI подходил для приложений, но для видеоигр его было недостаточно. Уже в Windows 3.1 компания выпустила SDK для разработчиков игр под названием WinG, чтобы предоставить более прямой доступ к полному экрану. Вторую версию WinG переименовали в DirectX; она содержала API полноэкранного 2D-режима, который назвали DirectDraw.

Несмотря на большую безопасность и надёжность, Microsoft Windows накладывала на приложения множество ограничений. Одним из последствий этого стало то, что игры и другие графические приложения, требовавшие высокой производительности, больше не могли получать прямой доступ к аппаратным ресурсам для максимизации скорости и расширения функциональности. Ещё многие годы программисты продолжали трудиться в DOS, а пользователям Windows для запуска игр, симуляций и других графических программ приходилось переключаться в режим DOS. В итоге возникло серьёзное противоречие: графическая операционная система, в которой графические приложения работали с низкой производительностью.

Первым шагом для решения этой проблемы стал продукт под названием WinG (Windows for Games). Первую версию WinG выпустили в 1994 году, она требовала Win32 в Windows 3.1. Её основной фичей стало то, что WinG позволяла программисту игры быстро передавать битовые карты из памяти системы в видеопамять. Благодаря этому стало возможно создавать игры для Windows с гораздо более высокой производительностью.

Microsoft переименовала новую версию Game SDK, назвав её DirectX 2. Последующие версии были выпущены под названиями DirectX 3, DirectX 5, DirectX 6 и текущим DirectX 7.

Фенг Юань, «Windows Graphics Programming Win32 GDI and DirectDraw»

С точки зрения производительности DirectDraw стал шагом вперёд по сравнению с GDI, но в то же время из-за багов драйверов или отсутствия в системе DirectX он не гарантировал работы. Его можно было отключить флагом nodirectdraw.

Видеосистема WinDirect

Внимательные читатели могли заметить очевидную странность. Приложениям Win32 доступ к оборудованию запрещён. Как же MGL могла обходить GDI/DirectDraw и напрямую общаться с VBEAF, VBE и VGA?

Это стало возможно благодаря секретной технологии SciTech под названием WinDirect. Объяснение её работы представлено в SciTech MGL Reference Guide v4.pdf.

Что такое WinDirect?

WinDirect — ключевой компонент SciTech MGL: это пакет среды исполнения для DOS и Windows 95, предоставляющий прямой доступ к дисплейному оборудованию 16- и 32-битным приложениям. Традиционно приложения для Windows должны были выполнять весь графический вывод через стандартный Graphics Device Interface (GDI). Несмотря на мощь и многофункциональность GDI, он не особо быстр в графике, требуемой приложениям реального времени, например видеоиграм.

WinDirect преодолевает этот барьер, позволяя высокопроизводительным приложениям отключать обычный интерфейс GDI и перехватывать всё оборудование для отображения графики, как это делалось в DOS. После отключения GDI интерактивные графические приложения могут перепрограммировать контроллер дисплея и выполнять запись непосредственно в видеопамять. WinDirect-приложение может запрограммировать любой графический режим VGA, например 320x200x256, перепрограммировать контроллер и реализовывать графику в стиле стандартного VGA ModeX или вызывать стандартные сервисы VESA BIOS для реализации графики SuperVGA высокого разрешения.

MGL v4 Programmer Guide[3]

Руководство программиста MGL v4 — бесценный источник информации. Если вы, как и я, задавались вопросом, что это за библиотеки WDIR32.DLL и WDIR16.DLL, поставлявшиеся вместе с WinQuake, то вот вам ответ: в документации они упоминаются, как WinDIRect. Аналогично, там же описываются PMPRO16.DLL и PMPRO32.DLL, как независимый от расширителя DOS API для сервисов защищённого режима. Там же упоминается Zen Timer Майкла Абраша!

В исходный код WinQuake не включена MGL, в нём есть только заголовки и уже скомпилированная 32-битная MGLLT.LIB (MGL Lite), позволяющие выполнить компиляцию. SciTech опубликовала исходники в 2000 году[4], но они уже недоступны. На GitHub[5] загружена v5, которая к тому времени существенно изменилась (например, была убрана WinDirect).

К счастью, какой-то добрый человек сохранил зеркало MGL v4. Если захотите исследовать её самостоятельно, установите mglb405.exe и mgls405.exe. Или просто скачайте мою установку src.rar.

Подведём итог

Если говорить в целом, winquake.exe часто мог находить самый быстрый путь рендеринга или через DirectDraw, или через WinDirect. Откат к режиму DIB был неидеальным решением, но всё равно обеспечивал преимущества перед quake.exe. Также стоит учесть возможность выбора звукового бэкенда для повышения частоты кадров или снижения задержек аудио. В итоге пользователи получали отличный игровой процесс, полностью оправдывающий усилия разработчиков.

Прошло уже больше тридцати лет, но мы всё равно можем запускать winquake.exe в Windows 11. Полноэкранный режим не поддерживает широкие экраны, но оконный режим по-прежнему работает без изъянов. Несмотря на все сомнительные решения Microsoft, её стремление к обеспечению обратной совместимости впечатляет.

Ссылки

[1] Why did ID choose DJGPP for Quake?

[2] Цена SciTech MGL

[3] MGL v4 Programmer Guide

[4] SciTech Releases MGL 4.0 OpenGL Source Code

[5] SciTech Mult-platform Graphics Library

Комментарии (1)


  1. pda0
    16.12.2025 10:31

    Приложениям Win32 доступ к оборудованию запрещён. Как же MGL могла обходить GDI/DirectDraw и напрямую общаться с VBEAF, VBE и VGA?

    Это стало возможно благодаря секретной технологии SciTech под названием WinDirect.

    Да нет там особо никакого секрета. Win 9x была предназначена для самых слабых компьютеров, начиная с 4 Mb памяти и старых 386 процессоров. Реализовать её удалось собрав из костылей и хаков чуть более, чем полностью. Изоляция приложений там представляла собой ажурный штакетник, сделанный из самодельного папье-маше, сделанный в свою очередь из жёванного картона. Местами ещё и отсутствующего. Если защита памяти делала вид, что работает (хотя сбой приложения обычно успевал испортить память ядра), то защиты доступа к портам, например, не было от слова совсем.