← На главную

Портировал через Emscripten: баги Windows не помешали порту на itchio

12.06.2026 17:30 · hackernews

Разработчик портировал свою игру на C с кастомным движком (bgfx, SDL2, miniaudio, cimgui) на Web через Emscripten и выложил на itchio. Вот с какими проблемами он столкнулся.

Первое — пришлось вернуться к Visual Studio. Его основной отладчик RemedyBG не поддерживает 32-битные процессы, а WASM — 32-битный. Для локального воспроизведения багов пришлось собирать 32-битную нативную версию. Решение — просто запускать devenv build\main.exe и добавить vcvars32 в сборку. Без sln-файла, но работает.

Главная причина большинства багов — WASM 32-битный, а указатели занимают 4 байта, а не 8. Структуры с сырыми указателями вроде AssetSprite сериализовались на 64-битной Windows, а на WASM выравнивание ломалось. Размер sizeof(Assets) отличался на 772 байта. Починили, разделив данные времени выполнения и «запекания»: указатели убрали из сериализуемых структур, теперь всё хранится в плоском массиве AssetDataBytes с индексом.

Лучше отлаживать в 32-битной нативной среде, а не в браузере. Размеры структур совпадают с WASM, а отладчик реальный. Использовали /fsanitize=address и точки останова по данным — ASan ловит плохой доступ, точка останова говорит, кто пишет в адрес.

Нашелся классический баг, который случайно работал на 64-бит: sizeof(ThingHandle*) на 64-бит равен 8 — столько же, сколько sizeof(ThingHandle). Ошибочное выделение памяти под массив указателей вместо массива структур проходило незамеченным. На 32-бит WASM указатель занимает 4 байта, выделялась половина нужной памяти.

OpenGL ES (WebGL) строже Direct3D. На D3D проходили: BGFX_RENDERER_TYPE_NOOP для vertex layout (на OpenGL не назначаются атрибуты), несовпадение числа компонентов COLOR1 (2 в layout, vec4 в шейдере — OpenGL ES падает каждый кадр), перевёрнутый Y (у OpenGL ноль внизу, у D3D — вверху). Пришлось переключать UV в финальном блите.

Шейдеры надо перекомпилировать под GLSL ES. lerp() — только HLSL, в GLSL используется mix()bgfx_shader.sh есть кросс-платформенный макрос). GLSL ES не прощает передачу 0 вместо 0.0 в float-параметр — ошибка компиляции.

Проблема с Web Audio: miniaudio сам вешает обработчики кликов для пробуждения AudioContext, но это не работало. Оказалось, последние версии Emscripten по умолчанию убирают из экспорта HEAPF32, который нужен miniaudio. Пришлось явно добавить -s EXPORTED_RUNTIME_METHODS="['ccall','cwrap','HEAPF32']".

В итоге порт занял выходные. Кастомный C-движок, быстрая загрузка без тяжеловесных Unity или Godot. Emscripten — солидный инструмент, большая часть проблем — то, что случайно работало на Windows. Игра уже на itchio и в списке желаемого Steam.

Читать оригинал →