- PVSM.RU - https://www.pvsm.ru -
${habrauser}, Привет!
При разработке игрового фреймворка Oriol Engine (которая, к слову, до сих пор ведётся) мы столкнулись с проблемой написания шейдеров для Cross-API рендеринга. В RHI-слой данного фреймворка было запланировано добавить поддержку таких графических API, как DX11/DX12, OpenGL и Vulkan.
И вот тут возникает вопрос: как же писать шейдеры на одном языке и обеспечить их поддержку на других графических API?
Для начала стоит определиться: на каком языке изначально мы планируем писать шейдеры? Из‑за приоритетов разработки игр в дальнейшем под продукцию Microsoft, в нашем случае логичнее переводить HLSL (версии 4 и 5) в GLSL, а не наоборот, ибо нет полного контроля над HLSL‑исходником.
Итак, уже начинает вырисовываться какая-то общая концепция: сначала конвертируем HLSL-исходник в GLSL, компилируем эти два исходника и помещаем в один бинарный файл под тегами [HLSL] и [GLSL] для дальнейшего удачного прочтения бинарника.
Да, в конечном итоге оно так и работает.
Почему же мы даже не стали смотреть в сторону SPIR-V? Потому что нам нужно было что-то компактное и самостоятельное, что можно добавить одним компонентом в фреймворк и дальше не париться.
Составление самого бинарного файла .shader особого интереса из себя не представляет, потому что это файл с довольно простой структурой: под тегами [HLSL] и [GLSL] хранится соответствующий байт-код того или иного исходника.
Но вот сама конвертация HLSL To GLSL (HTG) требует должного внимания. Сперва разберём этот компилятор на этапы: Frontend, Middle-end, Backend, и подробно рассмотрим каждый.
Фронтовая часть HTG обрабатывает исходный HLSL-код в такой последовательности (мало чем отличается от frontend любого другого компилятора).
Препроцессинг
По официальному справочнику от Microsoft, препроцессор HLSL должен распознавать 12 директив: #define, #elif, #else, #endif и другие.
Не буду подробно про них здесь рассказывать. HTG в данном плане работает в точности по справочнику, поэтому welcome to the Microsoft Learn [1].
Парсинг
Здесь тоже всё достаточно стандартно. Сначала проводим лексический и синтаксический анализы. На этих этапах:
выявляются лексические и синтаксические ошибки;
проверяется соответствие HLSL‑спецификации;
извлекаются семантики (например, POSITION, TEXCOORD).
Данный этап является переходным в конвертации HLSL в GLSL. Здесь происходит трансляция в промежуточное низкоуровневое IR-представление на основе AST-дерева, близкое к GLSL. Сперва HLSL-семантики переводятся в GLSL-директивы (например, layout(location = 0)). Затем текстуры и сэмплеры разделяются, структуры и типы данных адаптируются под GLSL-синтаксис.
В конечном этапе IR транслируется в GLSL-код: формируются объявления переменных и функций, вставляются необходимые препроцессорные директивы, обрабатываются особенности целевой платформы (например, версии GLSL). К выходному коду применяются форматирование (отступы, переносы) и манглинг имён там, где это требуется.
Про последнее давайте поподробнее:
Для разных категорий идентификаторов применяются разные схемы генерации префикса или суффикса:
Глобальные переменные: g_ + хеш или уникальный индекс (например, g_var123).
Локальные переменные: l_ + номер блока + индекс (например, l_blk2_var4).
Параметры функций: p_ + имя функции + индекс (например, p_main_arg0).
Поля структур: s_ + имя структуры + имя поля (например, s_VertexInput_pos).
HLSL‑семантики преобразуются в GLSL‑атрибуты, а имя переменной может быть манглено для отражения семантики:
// HLSL
float4 pos : POSITION;
// GLSL
layout(location = 0) in vec4 s_VertexInput_pos;
Если два идентификатора после манглинга совпадают, к ним добавляется уникальный суффикс (например, _1, _2).
Да, на этом, в общем-то, всё. На данный проект мы потратили почти половину года своей жизни. Это была довольно кропотливая работа, и я не исключаю того факта, что что-то мог упустить в данной статье, поэтому смело критикуйте в комментариях.
Если у вас возник интерес самостоятельно покопаться в коде, то оставлю ссылку на сам компонент вот тут [2].
Спасибо за прочтение :-)
Автор: alex_02
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/shejdery/435678
Ссылки в тексте:
[1] welcome to the Microsoft Learn: https://learn.microsoft.com/ru-ru/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-preprocessor
[2] оставлю ссылку на сам компонент вот тут: https://github.com/Anagar-Games/Oriol_Engine/blob/main/Oriol/API/Gfx/ShaderPack/HowToUse.md
[3] Источник: https://habr.com/ru/articles/963306/?utm_source=habrahabr&utm_medium=rss&utm_campaign=963306
Нажмите здесь для печати.