Обзор
Игровые движки эволюционировали в сложные системы, включающие компоненты физики, звука, графики, ввода, искусственного интеллекта и сетевого взаимодействия. Графические движки выходят за рамки игровых приложений и используются в анимации, фреймворках ИИ/VR и научной визуализации.
Эта статья предоставляет базовые знания о возможностях рендеринга DirectX 12 для новичков и разработчиков, переходящих с других графических API. Автор ссылается на демонстрацию и исходный код, доступные на GitHub.
Графические API
OpenGL, Vulkan, Metal, Direct3D и собственные интерфейсы консолей представляют графические API — динамические библиотеки, позволяющие приложениям выводить содержимое на экран.
Популярные API для видеокарт Nvidia (Windows)
DirectX:
- DirectX 9:
nvumdshim.dll - DirectX 10/11:
nvd3dum.dll(32-бит) иnvd3dumx.dll(64-бит) - DirectX 12:
nvldumdx.dll
Vulkan:
- 32-бит:
nvoglv32.dll - 64-бит:
nvoglv64.dll
OpenGL:
- 32-бит:
nvoglv32.dll - 64-бит:
nvoglv64.dll
Vulkan и OpenGL имеют похожие соглашения об именовании драйверов, так как Nvidia часто использует одинаковые драйверы для обоих.

Компромиссы в сложности
Direct3D 12 и Vulkan требуют ручного управления синхронизацией, предкомпилированных корневых сигнатур, состояний конвейера и тонкозернистого управления ресурсами. OpenGL и DirectX 11 абстрагируют сложность, но ограничивают выполнение GPU однопоточностью.
Интерфейс операционной системы
Для кроссплатформенной разработки движков существует два основных подхода:
- Абстракция библиотеки (например, GLFW): позволяет переносить код между платформами
- Нативные вызовы API: обеспечивает больший контроль, но жертвует переносимостью
В этой статье используется второй подход с использованием нативных API Windows и DirectX 12.

Работа с окном
Все графические API имеют одинаковый процесс создания окна. После задания параметров приложения получают дескриптор (например, hwnd в DirectX), идентифицирующий экземпляр окна. Этот дескриптор облегчает получение событий — нажатия клавиш, движения мыши, управление окном — первоначально обрабатываемых операционной системой и передаваемых ожидающим приложениям.
Исходный код демонстрирует создание окна с указанием обработчика событий.
Ввод
Хотя обычно это отдельный компонент с выделенными менеджерами и классами, обработка ввода остается существенной в графических движках, поддерживающих взаимодействие с пользователем.
Интерфейс видеокарты
Графические API взаимодействуют с оборудованием для выделения ресурсов, отладки, выполнения конвейера и асинхронных вычислений на нескольких видеокартах и мониторах.
Ключевые компоненты DirectX 12
DXGI Factory: интерфейс абстракции, перечисляющий адаптеры (видеокарты и мониторы), управляющий переходами в полноэкранный режим и привязывающий окна к цепочкам замены.

Адаптер: представляет физические видеокарты, предоставляя информацию о памяти, ID устройства, поддержку функций и характеристики производительности. Используется в основном для создания Device.
Device: логический интерфейс, обеспечивающий прямые операции видеокарты — выделение ресурсов, управление дескрипторами, создание состояния конвейера и спецификация корневой сигнатуры.
См. класс ODevice в исходном коде для практической реализации.
Очереди команд
Выполнение команд на графическом оборудовании происходит через отдельные объекты: Command Queue и Command List, отвечающие за запись и выполнение инструкций GPU последовательно.
Очереди команд выполняют списки команд после их закрытия и передачи в очередь.
GPU поддерживают параллельное выполнение на разных очередях, позволяя одновременно работать графическому и вычислительному конвейерам.

Синхронизация через барьеры (Fence)
Прямое выполнение команд устройства создает проблемы синхронизации между GPU и CPU. Очереди команд в памяти GPU позволяют указывать точки синхронизации, называемые Fences, позволяющие CPU возобновить работу после завершения инструкций GPU.
Барьеры облегчают синхронизацию CPU-GPU и синхронизацию между очередями GPU. Например, завершение рендеринга требует ожидания CPU перед обработкой последующих кадров.
Обратитесь к реализации синхронизации в репозитории.
Заключение
DirectX 12 устанавливает стандартизованное взаимодействие с видеокартой, сохраняя универсальные принципы API. Разработчики, знакомые с CUDA, могут заметить сходство с операциями вычислительных шейдеров.
Овладение настройкой окна, обработкой ввода, интерфейсами видеокарты и очередями команд позволяет разработчикам эффективно использовать возможности GPU для реалистичного рендеринга.