← На главную

Разработчик сделал софтрендер для Playdate с картами Quake BSP

22.07.2026 18:09 · hackernews

Разработчик взялся за создание софтверного 3D-рендерера для Playdate, не имея понятия, насколько это реально. Первым делом он запустил простой рейкастер — тот самый, что обычно использует для оценки процессорной мощи и скорости отрисовки на слабых устройствах. Производительность оказалась ниже ожиданий, но маленький 400×240 1-bit экран Playdate давал надежду на хитрые оптимизации. Автор решил, что по ощущениям игрока можно дотянуть до уровня 3DO или Sega Saturn, хотя технически всё иначе: у Playdate нет GPU и вообще никакого 3D-железа, только CPU. Трансформации вершин, сортировка, клиппинг, текстуры — всё приходится считать на процессоре.

Рендерер загружает карты в формате Quake BSP. Это позволило не писать редактор уровней с нуля, а взять TrenchBroom для маппинга и ericw-tools для компиляции геометрии, видимости и освещения. BSP-дерево и предпросчитанный PVS-индекс дают мощное отсечение невидимых частей сцены ещё до растеризации, что критически экономит время.

От идеи рисовать без z-буфера по принципу «от дальнего к ближнему» отказались: выигрыша почти нет, зато сплошные проблемы. Поставили 16-битный reciprocal depth buffer, который даёт больше точности вблизи камеры и упрощает работу с дверьми, подвижными объектами и текстурами с прозрачностью. Текстурное картирование сделали перспективно-корректным — интерполируются 1/z, u/z, v/z, а координаты восстанавливаются делением. Но деление на CPU Playdate слишком дорогое, поэтому полный reciprocal вычисляется раз в несколько пикселей, а между ними используется быстрое приближение. Визуальная разница незаметна, а скорость подрастает ощутимо.

С освещением пришлось повозиться: дисплей только чёрно-белый, поэтому любые градации яркости имитируются дизерингом. Рендерер читает заранее просчитанные лайтмапы, переводит их в вершинное освещение и пропускает через 8×8 матрицу Байера — пиксель становится белым, если яркость выше порога, и чёрным, если ниже. Первые прогоны с обычными текстурами дали нечитаемую шумную кашу. Вдохновением стали Return of the Obra Dinn и Jet Set Radio, поэтому автор выбрал минималистичный cel-shading look с сильными контурами и простыми текстурами — картинка стала чёткой, стиль обрёл лицо.

Оптимизировали каждый шаг. Компилятор нацелили на точное железо: -mcpu=cortex-m7 -mthumb, жёсткий float ABI через -mfloat-abi=hard, FPU-инструкции под -mfpu=fpv5-sp-d16. Агрессивный -Ofast проверили против -O2, -O3 и -Os — он оказался быстрее. Вычистили лишний код флагами -ffunction-sections -fdata-sections -Wl,--gc-sections -fno-unwind-tables -fno-asynchronous-unwind-tables и запретили случайные double через -Wdouble-promotion -fsingle-precision-constant. Для самых горячих операций написали собственные floor, ceil, sqrtf, fabsf на ассемблере ARM Cortex-M7. Самый мощный буст дал рендер в половинном разрешении 200×120 с последующим масштабом. Критический код разметили макросами PD_HOT для лучшего попадания в кеш и PD_FORCEINLINE для коротких частовызываемых функций, но применяли их только там, где бенчмарки подтверждали реальный прирост.

Рендерер далёк от идеала, но он уже достаточно хорош, чтобы собрать играбельный прототип и обкатывать геймплейные идеи. Совет автор заимствует из старой мудрости Майкла Абраша: любые оптимизации надо измерять самому, потому что лучший оптимизатор — вы сами.

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