Bgfx
| А категории за тебя Этой статье не хватает категорий. К сожалению, нет никаких идей, какие категории следовало бы здесь проставить. Быть может, у вас имеется парочка?
|
bgfx (от англ. Branimir's Graphics Framework или, как ласково величают его раздосадованные красноглазики в моменты компиляционного тупика, Butts, Guts, Fluids & eXcrements) — эпичная, монументальная и обросшая легендами кроссплатформенная библиотека рендеринга за авторством сербского программиста Бранимира Караджича (bkaradzic). Позиционируется как единственный спасительный круг для тех разработчиков велосипедов (сиречь наколеночных игровых движков), которым окончательно надоело переписывать один и тот же графический конвейер под 100500 разных операционных систем и графических API.
Главная идея девайса формулируется как Bring Your Own Engine (принеси свой собственный движок). В отличие от жирных и неповоротливых монстров вроде Unreal Engine или Unity, bgfx не пытается учить тебя жить, навязывать физику, импорт ассетов, трехмерные сцены, звуки или искусственный интеллект для виртуальных тараканов. Она просто даёт тебе низкоуровневый, но абстрагированный от конкретного железа API, позволяющий рисовать полигоны на экране Windows, Linux, macOS, iOS, Android, PlayStation 4, Nintendo Switch, Raspberry Pi и даже в браузере через WebGL/WebGPU.
Основная целевая аудитория — суровые программисты, инди-разработчики, авторы эмуляторов и просто любители пострадать в обнимку с C++ в 3 часа ночи, пытаясь заставить вращающийся куб не жрать 100% ресурсов центрального процессора.
История вопроса[править]
Чтобы в полной мере осознать, зачем вообще в 2010 году Бранимир решил сесть за написание этого чуда, нужно совершить краткий экскурс в историю и вспомнить, какой ад царил в мире графического программирования в конце нулевых и начале десятых годов.
Эпоха раздробленности[править]
Когда-то давно мир графики казался простым и понятным. Существовал теплый ламповый OpenGL, который теоретически работал везде, и проприетарный DirectX (в основном DirectX 9), намертво привязавший игроков к операционной системе Windows.
Но затем наступила эра смартфонов, портативных консолей и систем нового поколения, и начался сущий кошмар:
- На десктопной винде безраздельно властвовал DirectX 11.
- На мобилках (Android и iOS) правил урезанный OpenGL ES 2, а затем и OpenGL ES 3.
- Корпорация зла Apple внезапно решила, что OpenGL — это устаревший хлам, и выкатила свой собственный Metal API, начав активно закручивать гайки разработчикам.
- Khronos Group в ответ разродилась Vulkan API — монструозным низкоуровневым чудовищем, в котором для того, чтобы просто очистить экран синим цветом, нужно написать около 1000 строк шаблонного кода, настроить 10 очередей команд, проинициализировать 5 физических устройств и трижды принести в жертву девственную видеокарту.
- В вебе зародился WebGL (фактически тот же OpenGL ES 2/3), заставивший веб-разработчиков страдать от нехватки памяти и медленного JavaScript-биндинга.
Рождение велосипеда[править]
В этих условиях обычный программист, решивший написать свою инди-игру средней паршивости (или, упаси боже, эмулятор старых игровых автоматов), оказывался перед выбором из трех стульев:
- Написать 5 отдельных рендереров под каждый API вручную. Результат: сойти с ума, пропустить все дедлайны и уйти работать в веб-студию верстать лендинги.
- Использовать тяжелый готовый движок. Результат: игра весит 500 мегабайт, запускается 2 минуты и жрёт 1 гигабайт оперативной памяти ради вывода на экран двухмерного пиксель-арта.
- Найти готовую библиотеку-абстракцию.
Именно тогда Бранимир Караджич посмотрел на этот бардак и решил: Я сделаю свой собственный RHI (Rendering Hardware Interface), но без лишнего пафоса. Так на свет появился bgfx.
Суть[править]
Архитектурно bgfx представляет собой тонкую прослойку над нативными графическими API. Она скрывает от разработчика всю мерзкую специфику инициализации конкретного железа, предоставляя взамен единый набор функций. Под капотом библиотека сама решает, как перевести твой абстрактный вызов в вызовы DirectX 11, DirectX 12, Vulkan, Metal или старый добрый OpenGL.
Главные концепции[править]
Вся логика работы с bgfx крутится вокруг нескольких базовых сущностей:
- Вьюпорты (Views). В bgfx рендеринг организован в виде цепочки шагов, называемых Views (всего их может быть от 0 до 255). Каждому шагу присваивается числовой ID. Например, во View 0 мы рендерим трехмерную сцену, во View 1 рисуем тени, во View 2 накладываем пост-эффекты (свечение, размытие), а во View 255 поверх всего этого рисуем интерфейс. Библиотека сама сортирует вызовы по этим ID, избавляя тебя от необходимости вручную жонглировать состояниями конвейера.
- Буферы вершин и индексов (Vertex/Index Buffers). Здесь всё стандартно для компьютерной графики. Ты создаешь разметку вершин (Vertex Layout), пихаешь туда координаты, цвета, текстурные координаты, загружаешь это в память видеокарты и вуаля. Есть динамические буферы (которые можно обновлять каждый кадр, например, для систем частиц или текста) и статические (для неизменяемых трехмерных моделей).
- Шейдеры и программа (Shaders & Program). Шейдеры в bgfx — это отдельный круг ада, о котором мы поговорим ниже. По сути, ты загружаешь скомпилированные бинарники вершинного и фрагментного шейдеров, объединяешь их в единую программу (Program) и скармливаешь видеокарте.
- Текстуры и юниформы (Textures & Uniforms). Юниформы — это параметры, которые ты передаешь из своего кода на C++ прямо в шейдер (матрицы трансформации, цвета, таймеры, текстурные сэмплеры).
Цикл рендеринга на bgfx[править]
Выглядит этот процесс примерно следующим образом:
- Инициализируем окно с помощью какой-нибудь сторонней библиотеки (обычно SDL3 или GLFW, потому что сама bgfx создавать окна не умеет — она принципиально Bring Your Own Window).
- Передаем указатель на нативное окно (HWND для Windows, NSWindow для macOS, WL_SURFACE для Wayland на Linux) в структуру инициализации `bgfx::Init`.
- В главном цикле вызываем `bgfx::setViewRect` и `setViewClear` для настройки цвета очистки экрана.
- Каждый кадр очищаем состояние с помощью `bgfx::touch(0)` (это локальный мем библиотеки — если ты не отправишь хотя бы один пустой вызов отрисовки во View 0, bgfx просто решит, что тебе ничего не нужно выводить на экран, и оставит его девственно черным, заставив тебя 2 часа искать баг в инициализации).
- Заполняем буферы, биндим текстуры через `bgfx::setTexture`.
- Отправляем геометрию на отрисовку с помощью `bgfx::submit`.
- В самом конце кадра дергаем `bgfx::frame()`. Эта функция — сердце библиотеки. Именно в этот момент все твои ленивые вызовы отрисовки, которые ты накидал за кадр, отправляются в отдельный поток рендеринга, где они переводятся на язык конкретного Vulkan или DirectX и реально выполняются видеокартой.
Бранимир Караджич и его суровый сербский характер[править]
Любой крупный опенсорсный проект несет на себе неизгладимый отпечаток личности своего создателя. В случае с bgfx этот отпечаток глубок, суров и периодически бьет по рукам невнимательных контрибьюторов.
Бранимир Караджич (bkaradzic) — легендарная личность в узких кругах графических программистов. Он придерживается прагматичного, близкого к железу стиля программирования (часто называемого C with Classes). Никаких жирных абстракций, никакого безудержного использования шаблонов из STL (никаких `std::vector` или `std::string` в критических путях выполнения, упаси боже!), только чистые структуры, указатели, хэндлы и явное выделение памяти через кастомные аллокаторы.
Порядок в репозитории[править]
Бранимир известен своим бескомпромиссным отношением к качеству кода и оформлению пулл-реквестов. Если ты решишь внести свой вклад в развитие bgfx, тебе придется столкнуться со следующими правилами:
- Кодстайл должен соблюдаться идеально, вплоть до каждого пробела и переноса строки. Никаких табов, только пробелы.
- Если твой PR содержит хоть каплю лишнего оверхеда или пытается втащить в проект ненужную Бранимиру абстракцию, он будет закрыт без лишних сантиментов.
- На GitHub Discussions и в Discord-каналах Бранимир общается предельно конкретно. Если ты задашь вопрос, ответ на который есть на первой странице документации или в одном из 48 примеров, тебя, скорее всего, отправят читать мануалы со всей сербской прямотой. Зато если вопрос действительно сложный и технически грамотный, ты получишь исчерпывающий ответ от мастера в течение нескольких минут.
Такой подход позволил сохранить кодовую базу bgfx удивительно чистой, быстрой и лишенной архитектурной гнили, которая обычно поражает проекты, разрабатываемые комитетами из 50 человек.
Главные фичи[править]
Конечно, если бы всё было так просто и идеально, bgfx не заслужила бы отдельной статьи. Как и любой масштабный проект, разрабатываемый волевым решением одного человека, библиотека полна компромиссов, странных решений и скрытых граблей, на которые регулярно наступают неофиты.
Шейдерный ад[править]
Пожалуй, самый главный источник слез, боли и анального зуда при работе с bgfx — это кроссплатформенные шейдеры.
Как известно, у каждого графического API свой любимый язык шейдеров:
- У DirectX это HLSL.
- У OpenGL — GLSL.
- У Vulkan — SPIR-V (бинарный формат, получаемый обычно из GLSL или HLSL).
- У Metal — MSL (Metal Shading Language).
Если ты хочешь, чтобы твоя игра запускалась везде, тебе нужно либо писать 5 версий каждого шейдера вручную, либо использовать какую-то утилиту для трансляции. Бранимир решил пойти своим путем и написал собственный компилятор шейдеров под названием `shaderc` (Shader Compiler).
Работает это так: ты пишешь шейдер на некоем гибридном псевдо-GLSL языке с кучей кастомных макросов (`BGFX_SHADER_START`, `mul`, `vec4` вместо стандартных типов в определенных контекстах). К этому шейдеру ты обязан приложить специальный файл описания переменных — `varying.def.sc`. Без этого текстового файла, где ты вручную расписываешь, какие данные передаются из вершинного шейдера в пиксельный, компилятор просто откажется работать, сыпля непонятными трехстрочными ошибками.
Пример типичного `varying.def.sc`:
vec3 a_position : POSITION;
vec4 a_color0 : COLOR0;
vec2 a_texcoord0 : TEXCOORD0;
vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0);
vec2 v_texcoord0 : TEXCOORD0;
А теперь самое веселое: компилятор `shaderc` — это консольная утилита. Ты не можешь просто так взять и скормить bgfx исходный код шейдера в виде строки в рантайме (как это делается в OpenGL через `glShaderSource`). Тебе нужно:
- Встроить вызов `shaderc` в свой билд-скрипт (CMake, Makefile, SCons или что там у тебя).
- Скомпилировать шейдер под каждую целевую платформу отдельно. Для Windows компилируем в HLSL (профили `vs_5_0` и `ps_5_0`), для Android — в ESSL, для Linux — в SPIR-V, для Mac — в Metal Shading Language.
- На выходе получить кучу бинарных файлов (`.bin`).
- В самой игре загрузить нужный бинарник в зависимости от того, какой бэкенд рендеринга выбрал пользователь.
Если ты забыл прописать переменную в `varying.def.sc` или опечатался на одну букву, `shaderc` выдаст ошибку сборки, которая заставит тебя усомниться в своем выборе профессии.
Вот пример простого вершинного шейдера `vertex.sc` на специфическом диалекте bgfx:
$input a_position, a_color0, a_texcoord0
$output v_color0, v_texcoord0
#include <bgfx_shader.sh>
void main()
{
gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
v_color0 = a_color0;
v_texcoord0 = a_texcoord0;
}
Обрати внимание на безумные макросы вроде `$input` и `$output`. Это не стандартный GLSL, это проприетарная магия Бранимира, которую парсит `shaderc` перед тем, как сгенерировать реальный код под целевые API.
Битва титанов[править]
Второй эпичный холивар вокруг bgfx связан с системой сборки проекта.
Весь цивилизованный мир C++ (пусть и со слезами на глазах) использует CMake как стандарт де-факто для сборки кроссплатформенных проектов. Но Бранимир Караджич — человек суровых правил и твердых убеждений. Он испытывает к CMake глубокую личную неприязнь, считая его медленным, неудобным и переусложненным куском кода.
Поэтому для сборки bgfx используется GENie — собственный форк системы Premake, написанный на языке Lua. Чтобы собрать bgfx из исходников под Windows, тебе нужно запустить командный файл, который вызовет GENie, сгенерирует проект для Visual Studio 2022 (или другой версии), и только потом ты сможешь открыть его и нажать кнопку Собрать.
Разумеется, когда обычные программисты пытаются интегрировать bgfx в свои CMake-проекты (а таких примерно 99%), начинается сущий ад. Попытки подружить GENie с CMake привели к созданию огромного количества неофициальных костылей и форков на GitHub. В итоге сообщество настолько задолбало Бранимира этой темой, что на официальном аккаунте bgfx появился репозиторий `bgfx.cmake` — обертка, поддерживаемая сообществом, которая позволяет подключать библиотеку через стандартный CMake FetchContent. Но даже там периодически что-то ломается при обновлении основной кодовой базы.
Если ты попробуешь скомпилировать проект без учета этой специфики, тебя ждет увлекательное путешествие в мир конфликтов рантайм-библиотек:
error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug'
Эта ошибка означает, что bgfx по умолчанию собралась со статической линковкой рантайма C++ (`/MT` или `/MTd`), а твой любимый проект на CMake упорно хочет динамическую (`/MD` или `/MDd`). Чтобы решить эту проблему, тебе придется долго и упорно курить мануалы и передавать в скрипты сборки хитрые флаги вроде `--with-dynamic-runtime`.
Отсутствие глобального состояния (почти)[править]
В кругах профессиональных разработчиков графических движков (например, на отечественном ресурсе GameDev.ru или в сабреддите `r/gameenginedevs`) bgfx регулярно подвергается жесткой критике за свою архитектуру.
Дело в том, что современный рендеринг уходит в сторону максимальной явности (explicit APIs) — Vulkan и DirectX 12 требуют от программиста четкого управления барьерами памяти, выделением буферов, дескрипторными сетами и конвейерами состояний (Pipeline State Objects, PSO).
bgfx же пытается усидеть на двух стульях: она предоставляет упрощенный API, который внутри себя эмулирует старую добрую модель состояний (state machine), похожую на OpenGL. Из-за этого возникают следующие проблемы:
- Ограниченный контроль. Ты не можешь напрямую управлять низкоуровневыми вещами вроде проходов рендеринга (render passes) в стиле Vulkan, суб-пассами для мобильных тайловых видеокарт (TBDR) или сложными схемами барьеров памяти.
- Проблемы с производительностью на Vulkan/DX12. Поскольку bgfx вынуждена транслировать свои высокоуровневые команды в низкоуровневые API, под капотом происходит постоянное пересоздание объектов состояния, кэширование и сверка параметров. Из-за этого на некоторых сценах Vulkan-бэкенд bgfx может работать медленнее, чем простой и понятный DirectX 11 рендерер. На Reddit регулярно появляются треды в духе: Я портировал свой 2D-движок с WebGPU на bgfx, и на Vulkan у меня упал фреймрейт в 2 раза, почему?.
- Управление юниформами. Передача констант в шейдеры сделана через глобальный пул юниформ-хэндлов. Из-за этого ты не можешь легко использовать современные подходы вроде bindless ресурсов (когда видеокарта просто получает указатели на текстуры прямо в шейдере без промежуточных вызовов биндинга) или кастомных Uniform Buffer Objects (UBO) в полной мере.
Известный отечественный геймдев-гуру Александр Санников (более известный как Suslik на форумах GameDev.ru) в свое время так охарактеризовал философию библиотеки:
|
bgfx — библиотека, построенная на внутренних состояниях. типа glMatrixMode(), glLoadMatrixf() и прочем шлаке, который трудно отлаживать, трудно менеджить, трудно расширять. мне нравится философия, которой придерживается bgfx в плане легковесности, но глобальные состояния — это путь в никуда. |
||
| — Suslik, GameDev.ru | ||
Где это крутится[править]
Несмотря на всю критику, костыли с компиляцией шейдеров и ненависть к CMake, bgfx — это невероятно успешный проект. Он доказал свою жизнеспособность в суровых коммерческих условиях. Список проектов, использующих эту библиотеку под капотом, внушает уважение.
MAME (Multiple Arcade Machine Emulator)[править]
Эмулятор всего и вся MAME использует bgfx в качестве одного из основных видеорежимов. Именно благодаря bgfx в MAME можно применять сложнейшие шейдеры постобработки, имитирующие эксцентричные особенности старых мониторов с лучевой трубкой (CRT).
Легендарные шейдеры `CRT-Geom` и `CRT-Royale`, которые заставляют плоскую картинку на твоем современном 4K-мониторе выглядеть так, будто ты сидишь перед пыльным пузатым телевизором в зале игровых автоматов 1993 года, написаны именно на кастомном шейдерном языке bgfx. Они на лету перекомпилируются под DirectX на Windows или OpenGL на Linux, выдавая аутентичное размытие пикселей, свечение люминофора и закругление краев экрана.
Guild Wars 2[править]
Да-да, культовая MMORPG Guild Wars 2 от ArenaNet в свое время успешно переехала со старого, дряхлого и тормозящего DirectX 9 на современный DirectX 11 именно с помощью интеграции bgfx. Разработчики смогли обновить графический движок десятилетней давности без полного переписывания игры с нуля, что значительно подняло производительность на современных многоядерных процессорах и избавило игроков от диких лагов в массовых замесах.
Minecraft (Bedrock Edition)[править]
Мобильно-консольно-виндовая версия Minecraft (знаменитый движок RenderDragon) в определенных версиях и платформах использовала bgfx для обеспечения кроссплатформенного рендеринга. Возможность компилировать шейдеры один раз и запускать их и на Nintendo Switch, и на дешевом Android-смартфоне, и на Xbox One — это как раз то, ради чего Mojang и Microsoft обратили внимание на творение Бранимира.
Однако в сообществе это вызвало немало бурлений: старые шейдерные паки, которые игроки легко писали под простой OpenGL/GLSL, внезапно превратились в тыкву. Пришлось разбираться в тонкостях компиляции под RenderDragon, что значительно усложнило жизнь мододелам.
Другие заметные проекты[править]
- Football Manager (начиная с версии 2018) — симулятор таблиц и экселя от SEGA использует bgfx для отрисовки своего трехмерного матча.
- Crypt of the NecroDancer — зубодробительный ритм-рогалик крутится на bgfx на Windows, macOS, Linux, Nintendo Switch и PlayStation 4.
- World of Goo 2 — продолжение культовой физической головоломки про липкие шарики использует bgfx для рисования своей стильной двухмерной жижи на всех платформах.
- Griftlands — карточный рогалик от Klei Entertainment (создателей Don't Starve) полагается на bgfx для вывода своей шикарной рисованной 2D-графики.
- Braid, Anniversary Edition — обновленная версия легендарного платформера Джонатана Блоу использует bgfx в своей Android-версии.
Альтернативы[править]
Если ты обычный программист, решивший войти в мир компьютерной графики в 2026 году, перед тобой встает вопрос: Стоит ли тащить bgfx в свой проект или есть варианты получше?
1. Чистый OpenGL (через GLAD/GLEW)[править]
- Плюсы: Огромное количество туториалов (один сайт `learnopengl.com` чего стоит). Всё пишется в один поток рендеринга, никакой магии, шейдеры загружаются прямо из текстовых файлов в рантайме.
- Минусы: OpenGL официально мертв на устройствах Apple (работает через медленную эмуляцию поверх Metal). На Windows драйверы AMD и Intel для OpenGL часто работают через пень-колоду. Нет нормальной поддержки многопоточности.
- Вердикт: Отлично подходит для обучения основам графики. Но если ты планируешь выпускать коммерческую игру на консолях или iOS — OpenGL быстро покажет тебе свою нежизнеспособность.
2. Нативный Vulkan / DirectX 12 / Metal[править]
- Плюсы: Абсолютный контроль над железом. Выжмешь максимум кадров в секунду, сможешь использовать самые передовые технологии (транссировка лучей, меш-шейдеры, биндлесс-текстуры). Разовьешь навыки, востребованные в AAA-индустрии.
- Минусы: Порог входа высотой с Эверест. Чтобы просто вывести на экран один текстурированный треугольник, придется написать около 1500 строк кода. Любая ошибка в барьерах памяти приводит к мгновенному падению видеодрайвера без объяснения причин.
- Вердикт: Если твоя цель — стать высокооплачиваемым графическим программистом в Ubisoft или CD Projekt RED, страдай и учи Vulkan/DX12. Если ты просто хочешь сделать игру — беги отсюда.
3. WebGPU (через Dawn или wgpu-native)[править]
- Плюсы: Современный, чистый API, спроектированный с учетом ошибок Vulkan и Metal. Отличная переносимость между вебом и нативными приложениями. Поддерживается крупными корпорациями (Google, Mozilla).
- Минусы: Экосистема еще не до конца устоялась. Полноценных туториалов на C++ маловато (многие библиотеки написаны на Rust, что накладывает специфический отпечаток на биндинги).
- Вердикт: Перспективный претендент на трон. Если тебя не пугает необходимость ковыряться в свежих репозиториях без вменяемой документации — отличный выбор на будущее.
4. Diligent Engine[править]
- Плюсы: Намного более современная архитектура по сравнению с bgfx. Спроектирован изначально под DirectX 12 и Vulkan. Поддерживает полноценные шейдерные эффекты, управление ресурсами и имеет отличную производительность. Использует стандартный CMake из коробки.
- Минусы: Чуть более сложен в освоении для новичков. Сама библиотека тяжелее и монументальнее.
- Вердикт: Главный конкурент bgfx для серьезных 3D-движков. Если тебе нужен современный рендерер с поддержкой тяжелых графических пайплайнов — Diligent смотрится предпочтительнее.
5. SDL3 GPU[править]
- Плюсы: Новейший графический API, встроенный прямо в состав популярной библиотеки SDL3. Создан как раз для того, чтобы дать разработчикам простой кроссплатформенный доступ к Vulkan, DX12 и Metal без необходимости писать тонны бойлерплейта. Никаких сторонних зависимостей, всё поставляется в одном флаконе.
- Минусы: Появился относительно недавно. Документации мало, многие сложные вещи вроде кверирования GPU или хитрых барьеров памяти еще дорабатываются. Нет встроенной поддержки веб-платформ (пока что).
- Вердикт: Идеальный вариант для простых 2D/3D игр средней сложности, если ты уже используешь SDL3 для управления окнами и ввода.
Ссылки[править]
- Официальный репозиторий bgfx на GitHub — исходный код, примеры, баг-трекер и бесконечные обсуждения систем сборки.
- Документация bgfx — сухая, лаконичная, но очень полезная дока, которую Бранимир обновляет лично.
- Неофициальный CMake-порт для bgfx — спасительный круг для тех, кто боится Lua-скриптов GENie как огня.