207 lines
43 KiB
Markdown
207 lines
43 KiB
Markdown
# Faset Engine — архитектура
|
||
|
||
Редакция 1.4 · 24 сентября 2026 · **MVP принят; реализация P1–P3 описана отдельно от исходных решений**.
|
||
|
||
Этот файл фиксирует решения пользователя. **Принято** означает выбранное направление реализации, а не автоматически завершённую возможность движка. Работающий код, выполненные проверки и текущие ограничения перечислены в [журнале реализации](IMPLEMENTATION.md). Этапы до MVP и после него, зависимости работ и критерии готовности находятся в [PLAN.md](../PLAN.md).
|
||
|
||
Исследовательская база: [Unreal Engine, Godot, Unity и Blender](studies/README.md). Исторические сравнения не отменяют принятые здесь решения. Подробности: [ECS](studies/11-ecs-and-ergonomics.md), [MCP и Blender](studies/12-mcp-and-blender-integration.md), [стек и экспорт](studies/13-build-pipeline-and-stack.md), [renderer](studies/15-renderer-implementation-notes.md), [метаданные](studies/16-native-gameplay-and-metadata.md), [импорт](studies/17-asset-pipeline-and-blender-roundtrip.md), [build/cook](studies/18-build-cook-and-delivery.md).
|
||
|
||
## 1. Назначение и границы — принято
|
||
|
||
**Faset Engine** предназначен для десктопных **2D- и 3D-игр под Linux и Windows**. Важны удобное ручное редактирование, полноценная работа с проектом через MCP, передовая графика, интеграция с обычным Blender и экспорт самостоятельной игры. Независимость означает собственные форматы и API на границах движка, контролируемые зависимости и отсутствие обязательных облачных сервисов; это не обещание реализации всех библиотек с нуля или отсутствия платформенных SDK.
|
||
|
||
**Основной язык движка — английский:** интерфейс редактора, встроенные команды, диагностические сообщения, идентификаторы публичного API и описания CLI/MCP tools. Пользовательский текст и содержимое проектов поддерживают Unicode; язык создаваемых игр не ограничивается английским. Локализация редактора относится к развитию после MVP. Текущие исследования и проектная документация могут оставаться на русском; публичный корневой README ведётся на английском.
|
||
|
||
**MCP существует только в Editor и его headless-сервисах.** Он работает с авторскими документами, импортом, сборкой, запуском/остановкой Play и журналами редактора. MCP не читает и не изменяет runtime world, entities, компоненты или physics state. В Player, экспортной игре и SchemaExporter нет MCP-сервера, адаптера, зависимостей или транзитивного обхода этой границы через Editor.
|
||
|
||
## 2. Принятый стек
|
||
|
||
- **C++** — ядро и первый способ написания игровой логики; **Lua** обязательно добавляется следующим языковым этапом отдельным модулем. Использование Lua конкретной игрой необязательно.
|
||
- **EnTT** — runtime ECS за API Faset. Свои: сцены, метаданные, lifecycle, команды, планирование систем и связь с инструментами.
|
||
- **Box2D / Box3D** — отдельные физические миры 2D/3D; Box3D — [erincatto/box3d](https://github.com/erincatto/box3d).
|
||
- **Собственный retained C++ UI** — основной редактор: сохраняемое дерево виджетов, декларативные layout/styles, сначала тёмная тема. **Dear ImGui** — диагностические инструменты, не основная оболочка редактора.
|
||
- **Vulkan 1.3**, собственные renderer и RenderGraph; **Slang** для шейдеров и совместимого с ним подмножества HLSL.
|
||
- **SDL3 за Faset Platform API** — окна, события и платформенные службы; типы SDL не становятся обязательными типами gameplay API.
|
||
- **CMake + Ninja**, **Clang на Linux**, **clang-cl на Windows** с согласованными Windows SDK и runtime-библиотеками.
|
||
- **JSON authoring**, версионированные **бинарные cooked-форматы**, стабильные идентификаторы данных.
|
||
|
||
Выбор библиотеки не фиксирует её версию. Точные releases/commits, минимальные версии ОС/драйверов, Linux runtime baseline и разрешённые GPU formats/limits закрепляются в dependency lock и профилях перед интеграцией. Vulkan 1.3 сам по себе не гарантирует RT, mesh shaders или любые дополнительные features.
|
||
|
||
## 3. Процессы, модули и версии — принято
|
||
|
||
**Editor** владеет AuthoringService, UI, asset/build services, editor plugins и MCP adapter. Его headless-режим предоставляет те же авторские операции без окон. **Player** — отдельный процесс с runtime, renderer, физикой и игровым кодом; сбой gameplay не должен завершать редакторскую сессию. Это не изолирует native-плагин, загруженный непосредственно в Editor.
|
||
|
||
Gameplay оформляется **отдельной статической библиотекой, связанной с Player, в development и release**. Исправление `.cpp` пересобирает затронутые файлы и перелинковывает Player; изменения общих заголовков учитываются по графу зависимостей. Цикл разработки: **stop → build → restart Play**. Горячая замена C++, перенос действующих vtables/layout и сохранение произвольного runtime-состояния в этот контракт не входят.
|
||
|
||
Editor plugins — **DLL/SO под конкретный Editor SDK/build**, загружаемые при запуске. Обновление требует перезапуска Editor. Manifest содержит module ID/version, зависимости, назначение `runtime/editor`, API version и build fingerprint: ОС, архитектуру, toolchain, стандартную библиотеку/CRT и существенные настройки. Зависимости проверяются на циклы; editor и MCP targets не попадают в Player. Статическая gameplay-библиотека не означает статической линковки всех системных зависимостей.
|
||
|
||
Entry function плагина согласует версию интерфейса; память освобождает создавшая её сторона, ошибки имеют явный контракт. Нативные плагины не получают обещания стабильного ABI между любыми компиляторами. EnTT registry и детали storage не экспортируются как универсальный plugin ABI. Панели custom Inspector принадлежат отдельному Editor module и изменяют документы через общий command API.
|
||
|
||
## 4. Метаданные и схема без запуска gameplay в Editor — принято
|
||
|
||
Используется **собственная явная регистрация C++** выбранных компонентов, полей, методов и событий. Типизированные helpers проверяют поддерживаемые accessors и сигнатуры. Универсальный parser/binding generator произвольного C++ не нужен для первой версии.
|
||
|
||
После сборки отдельный служебный **SchemaExporter** выполняет registration entrypoints и пишет декларативный schema manifest. Он связывается с теми же регистрациями gameplay, но не запускает мир, renderer, `OnStart` или игровой цикл. Editor получает `TypeId`, `FieldId`, version, переносимые value types, defaults, units, constraints и UI hints **без загрузки игрового native-кода в процесс редактора**. MCP в SchemaExporter отсутствует. Manifest связывается с build fingerprint; сбой/ошибка экспорта не заменяет последнюю корректную схему.
|
||
|
||
В exporter всё же исполняется C++ регистрация: отдельный процесс изолирует её сбой, но не является sandbox для недоверенного кода. Defaults объявляются явно, а не извлекаются созданием произвольного игрового мира. Декларативные ограничения валидируются AuthoringService; дополнительные исполняемые authoring-валидаторы требуют явного editor/helper-контракта, а не неявного вызова gameplay из Inspector.
|
||
|
||
`TypeId/FieldId` описывают смысл сохраняемых данных и не зависят от имени C++, offset, порядка членов или `typeid`. Layout fingerprint нужен для совместимости конкретной сборки. Переименование сохраняет ID; изменение смысла/единиц требует миграции. Отсутствующий плагин не уничтожает неизвестные записи. Lua позже использует явно экспортированный runtime API и проверяемые handles; наличие metadata не делает каждый native-метод доступным MCP или Lua.
|
||
|
||
MVP доставляет декларативные шаги миграции через тот же schema manifest: `default`, `scale` и `require_manual`. Вся схема и правила проверяются до публикации Player/schema generation. Старые версии открываются как opaque data; миграция выполняется явно командой `component.migrate` с revision, одним Undo и записью recovery. Inherited component изменяется в исходной сцене; sparse overrides других экземпляров требуют явного обзора при изменении смысла или единиц. Произвольный C++ migration callback в Editor не загружается. Контракт и проверяемый пример — в [Manual](manual/scripting/api.md#editor-data-migrations).
|
||
|
||
## 5. Авторские данные, сцены и редактор — принято
|
||
|
||
Пользователь работает со сценами, объектами, компонентами и ресурсами. Сцены допускают **вложенные экземпляры шаблонов**. JSON хранит ссылку на исходный шаблон и **sparse overrides** — только локальные отличия, с устойчивыми адресами полей/объектов. Подписи и пути не являются идентичностью. Для добавления, удаления и изменения вложенного содержимого нужны явные операции; потерянная цель override становится диагностируемым конфликтом, а не молчаливым удалением данных.
|
||
|
||
AuthoringService владеет документами, схемами, validation, revisions, транзакциями и Undo. **GUI, CLI, MCP и editor extensions вызывают одни authoring-команды.** Команда получает явные document/entity/asset IDs. Ручной drag создаёт preview и один commit; MCP batch проверяется целиком и создаёт один шаг Undo. В первом контракте атомарность ограничена одним документом; конфликт revision не применяет половину изменений. Idempotency действует для одинакового key/payload в пределах объявленного scope и срока хранения журнала.
|
||
|
||
Scene compiler переводит авторские данные в runtime и сохраняет соответствие `SceneEntityId → RuntimeEntity[]`. Persistent SceneEntityId/AssetId отличаются от runtime handle с world/session/generation. Runtime storage не становится источником истины для JSON и не обязан повторять layout документа. Изменение игрового компонента не создаёт редакторский Undo и не сохраняется в authoring автоматически.
|
||
|
||
Retained UI получает состояние и уведомления от AuthoringService; состояние виджетов не заменяет состояние документа. Стили/layout отделены от команд; ключевые действия доступны из интерфейса и через editor API. Импорт, компиляция и cook не блокируют event loop. Необходимые текстовый ввод, focus, clipboard, DPI и платформенные поведения проверяются на обеих ОС как часть UI, а не считаются автоматически решёнными SDL3.
|
||
|
||
**UI-референс не является источником истины.** Сгенерированные изображения задают визуальное направление: тёмные поверхности, плотность, типографику и иерархию. Состав функций, состояние документов и поведение определяют эти контракты, PLAN и проверенные пользовательские сценарии. Референс можно менять под рабочий функционал.
|
||
|
||
## 6. Runtime ECS, поведение и игровой цикл — принято
|
||
|
||
EnTT используется для компонентов и запросов за типизированным API Faset. Простое поведение и массовая система обращаются к одному состоянию. Собственная ECS не разрабатывается на первом этапе; выбор EnTT не обещает большей скорости или дешёвой замены backend. Системы объявляют фазу, чтение/запись компонентов и внешних ресурсов, зависимости и диагностическое имя.
|
||
|
||
Публичный lifecycle: **`OnStart`, `FixedUpdate`, `Update`, `LateUpdate`, `OnDestroy`**. `OnStart` вызывается один раз после создания и привязки компонентов, перед первым обновлением; `OnDestroy` — один раз при применении удаления, пока допустимые данные ещё доступны. После него подписки снимаются, handles инвалидируются. Начальная загрузка проходит тот же явный барьер инициализации.
|
||
|
||
Главный цикл собирает ввод, выполняет нужное число фиксированных ticks, вызывает `Update`, вычисляет интерполированные presentation transforms, затем вызывает `LateUpdate` для камеры и зависимых визуальных объектов, финализирует render snapshot и рисует кадр. Одноразовые события ввода потребляются один раз соответствующим tick, удерживаемое состояние доступно последующим ticks. `Update/LateUpdate` не переписывают рассчитанный physics transform динамического тела; движения физических тел задаются командами следующего шага.
|
||
|
||
**Fixed tick — 60 Гц по умолчанию, настраиваемый для проекта.** Порядок tick: применить ожидающие structural commands → выполнить `FixedUpdate` и системы до физики → применить команды физическим телам → завершить Box2D/Box3D step → перенести transforms и события → выполнить системы реакции после физики. События доставляются через явную очередь; произвольный gameplay/Lua не вызывается из потоков physics callbacks.
|
||
|
||
Spawn/despawn и add/remove компонентов записываются в **runtime structural command buffer** и вступают в силу **в начале следующего фиксированного tick**, после завершения прежних задач. У применения один владелец; очередь имеет заданный порядок. Ссылки на память компонентов не переживают этот барьер. `create/add/delete`, повторное удаление и порядок lifecycle обрабатываются по единому контракту, который проверяется отдельными сценариями.
|
||
|
||
Catch-up ограничен числом ticks за проход главного цикла; начальный профиль — максимум четыре, с возможностью настройки. При перегрузке локальный Player отбрасывает избыточные целые интервалы накопленного времени, сохраняет дробный остаток и показывает `dropped_time`; не увеличивает physics `dt` произвольно. После паузы накопитель сбрасывается. Это политика локальной игры, не обещание deterministic lockstep/rollback.
|
||
|
||
Подготовка presentation transforms перед `LateUpdate` интерполирует предыдущий и текущий завершённые ticks с `alpha = accumulator / fixed_dt`; результат не записывается обратно в физику. Такой путь добавляет до одного tick визуальной задержки. Spawn, teleport и новая сессия сбрасывают историю. Motion vectors используют предыдущий **отрисованный** transform, а не просто предыдущий physics tick.
|
||
|
||
Первый scheduler — **последовательные именованные фазы** с измерением времени. Затем распараллеливаются отдельные независимые проходы: storage создаётся заранее, read/write conflicts и shared resources явно учитываются, structural changes остаются за барьером. EnTT не делает registry и пользовательские данные автоматически thread-safe. Полный task graph и подключение physics task callbacks к согласованному пулу workers вводятся после корректного последовательного варианта и профилирования.
|
||
|
||
## 7. Физика и renderer — принято
|
||
|
||
2D и 3D имеют отдельные миры и spatial-типы. Для динамического тела итоговым transform владеет физика; teleport и кинематическое управление — отдельные операции. Физическое тело связано с entity через проверяемый handle. Миры 2D и 3D не сталкиваются автоматически. Внутренние substeps solver настраиваются отдельно от частоты gameplay ticks; начальная настройка — четыре substeps с проверкой на сценах проекта.
|
||
|
||
Собственный Vulkan 1.3 renderer получает подготовленный snapshot, не обходит изменяемый EnTT registry с render thread. RenderGraph описывает reads/writes ресурсов, порядок проходов, barriers и lifetimes. MVP создал проверяемый raster-путь 2D/3D без обязательных RT/mesh shaders. P2 добавил выбираемые GPU frustum и GPU occlusion режимы для opaque static meshes; Direct остаётся начальным режимом и эталоном. Scene extraction задаёт устойчивые keys для постоянных объектов; renderer отслеживает generation и консервативные bounds. GPU instance record несёт стабильные slot и generation, а компактный индекс в candidate/visible буферах служит адресом записи только текущего кадра. `DrawItem` может содержать заранее подготовленные LOD meshes. CPU формирует фиксированные совместимые bins, GPU заполняет visible IDs и `instanceCount` для indirect draws. В occlusion-режиме previous HZB даёт предварительное решение, а current HZB и PostCull возвращают объекты, которые открылись в этом кадре. Camera cut, несовместимые view/projection/extent и смена instance generation инвалидируют историю. Тени, прозрачные meshes, спрайты и UI не теряют независимый порядок из-за camera culling. Точная реализованная область и проверка приведены в [P2 acceptance](studies/19-p2-gpu-visibility-acceptance.md).
|
||
|
||
**Vulkan API вызывается напрямую внутри собственного backend Faset.** Он владеет Vulkan handles, созданием GPU-ресурсов и pipelines, записью команд, синхронизацией и отправкой в очереди. Renderer и RenderGraph используют небольшой внутренний интерфейс ресурсов и команд Faset; Vulkan-типы и вызовы `vk*` не входят в gameplay API или команды редактора. SDL3 обеспечивает окно и создание Vulkan surface, но не заменяет графический backend; Slang отвечает за компиляцию шейдеров. Универсальная абстракция нескольких графических API не является задачей MVP.
|
||
|
||
Slang компилирует шейдеры в SPIR-V и выдаёт сведения для согласования CPU/GPU данных. Совместимый HLSL проходит выбранный pipeline; поддержка любого существующего HLSL-кода не обещается. Cook учитывает compiler/version, includes, defines и GPU profile. Nanite/Lumen-подобные системы остаются исследовательскими направлениями, не готовыми возможностями MVP.
|
||
|
||
Граница зависимости проходит через **готовый пакет SPIR-V + нормализованную reflection-метаинформацию Faset**. В текущей реализации CMake требует `slangc` для сборки этого пакета, а `compile_shader.py` преобразует Slang reflection в формат `faset.shader-reflection` с hash и layout fingerprint. Сам Vulkan backend создаёт pipelines из SPIR-V и проверяет этот контракт; он не вызывает Slang во время игры и не линкует его runtime. Однако структура descriptor sets, push constants, входов вершин и соглашение о матрицах сейчас явно согласованы с существующими Slang-шейдерами. Поэтому новый компилятор возможен без переписывания команд Vulkan, если он выдаёт эквивалентный SPIR-V и тот же проверяемый контракт. При появлении второго компилятора отдельным шагом вводится интерфейс shader package producer и тесты эквивалентности ABI; преждевременная абстракция компиляторов в MVP/P2 не нужна.
|
||
|
||
P2 не требует синхронного чтения GPU-счётчиков для решения видимости: readback включается редакторской диагностикой. Current HZB preview также читается только по запросу. Существующий путь полного framebuffer capture всё ещё ждёт GPU, поэтому измерения полной длительности кадра включают эту стоимость; `gpu_ms` и времена отдельных проходов не заменяют полную CPU/GPU-профилировку. [Первое измерение](studies/20-p2-gpu-visibility-benchmark-2026-09-23.md) обнаружило дорогой MainCull на Linux reference GPU в Debug/validation. [Повтор после оптимизации](studies/21-p2-gpu-visibility-optimization-2026-09-23.md) отдельно измерил эффект device-local выходных буферов и замены CAS-цикла на atomic add: MainCull p50 уменьшился до 0,030–0,042 мс в тех же синтетических сценах. Direct остаётся performance default до проверки Release-сборки и игровых нагрузок. Mesh LOD выбирается среди заранее подготовленных вариантов с hysteresis; генерация LOD, streaming и cluster geometry пока не реализованы. GPU-режимы дополнительно проверяют необходимые limits/formats устройства и не считаются доступными на любом Vulkan 1.3 GPU без такой проверки.
|
||
|
||
Диагностика различает запрошенный и фактически выполненный visibility mode в каждом кадре. Если GPU culling недоступен, фактический режим Direct; если доступен frustum, но нет подходящего HZB, запрос GPU occlusion явно понижается до GPU frustum. Player записывает оба режима в профиль и сообщает о fallback в stderr, редактор показывает Effective path и факт расхождения с выбранным режимом.
|
||
|
||
## 8. Blender и ассеты — принято
|
||
|
||
Используется **обычный Blender**, без обязательного форка или установленного MCP-плагина. Базовый обмен — **GLB и manifest со стабильными asset/subasset IDs**. Обычный экспорт принимается движком; удобный add-on для публикации, UUID и повторного экспорта остаётся необязательным помощником. Если источник не предоставляет устойчивые subasset IDs, importer не обещает надёжно угадать соответствие после произвольного rename/reparent: сохраняет mapping и показывает конфликты.
|
||
|
||
`.blend` и исходные изображения отделены от cooked/cache-данных. Геометрия и skeleton принадлежат источнику, placement/gameplay — сцене Faset, локальные замены материалов — overrides. Reimport сохраняет ссылки и локальные отличия; удалённые или конфликтующие outputs видны пользователю. Export recipe фиксирует units/axes, материалы и поддержанный animation profile. Blender nodes не превращаются автоматически в Slang shaders. Live link и расширенный roundtrip следуют после надёжного файлового импорта по плану.
|
||
|
||
## 9. Build, доставка и проверка — принято
|
||
|
||
Один сервис сборки для Editor/CLI/editor MCP разделяет компиляцию C++, schema export, компиляцию шейдеров, cook и упаковку. CMake/Ninja отвечают за native build graph. Inputs фиксируются snapshot, зависимости явные, worker пишет в свой build tree; cache учитывает content, recipe, toolchain и версии форматов. Candidate публикуется лишь после проверки, предыдущая успешная сборка остаётся доступной.
|
||
|
||
Development и release Player содержат runtime, выбранные игровые модули и бинарные cooked assets. **Editor UI, editor plugins, import/build services, SchemaExporter и MCP не входят в экспортную игру.** Lua включается только при зависимости проекта. JSON authoring, стабильные IDs, schema versions и миграции не заменяются дампом памяти C++.
|
||
|
||
Первый путь доставки — самостоятельный каталог/архив игры и отдельно symbols. Windows и Linux собираются и проверяются собственными native workers. Clang/clang-cl не устраняют необходимость платформенных SDK/runtime; кросс-экспорт из Linux в Windows не считается готовой возможностью. Полностью побайтово воспроизводимый executable и стабильный ABI любых компиляторов не обещаются наличием build manifest.
|
||
|
||
Критерии [плана](../PLAN.md) включают цикл сцена → Inspector → MCP authoring edit → Undo → save → build → отдельный Player, повторный импорт GLB с сохранением overrides, lifecycle/handle tests и запуск на обеих ОС без Editor/Blender/MCP/SDK. Выполненные проверки и незакрытые условия перечислены в [журнале реализации](IMPLEMENTATION.md); наличие теста само по себе не означает прохождения на обеих ОС.
|
||
|
||
## 10. P1 — проверяемая итерация gameplay
|
||
|
||
Для native-сборки источником истины остаются CMake/Ninja и их dependency graph.
|
||
BuildService сохраняет проверяемую копию `Scripts` по хешу содержимого,
|
||
отделяет Debug от Release и
|
||
запоминает версионированный fingerprint рецепта, исходников, Lua-деклараций,
|
||
toolchain, шейдерных и runtime-входов. Повторное использование schema/package
|
||
разрешено лишь после проверки полного manifest и схемы; испорченная или устаревшая
|
||
генерация не выдаётся за cache hit. Переключение указателя на успешную генерацию
|
||
атомарно; сбой сборки оставляет предыдущую доступной, но Inspector помечает
|
||
метаданные устаревшими. Исходный каталог и копия повторно хешируются после native
|
||
build и перед повторным использованием кэша или публикацией. Это обнаруживает сохранившееся изменение;
|
||
запись и восстановление прежних байтов другим процессом того же пользователя во
|
||
время чтения компилятором не исключены. Build и Export возвращают хеш снимка,
|
||
который захватил worker, а не хеш на момент постановки команды в очередь;
|
||
Session использует его для статуса Inspector. Экспорт отдельно проверяет asset
|
||
generations.
|
||
|
||
Структурированные сообщения компилятора/Lua дополняют сырой лог. Для исходников
|
||
проекта Editor и MCP вызывают один `faset_source_open` с относительным путём и
|
||
позициями; внешний редактор запускается аргументами без shell. Четыре стартовых
|
||
проекта комбинируют C++/Lua и 2D/3D. C++ остаётся rebuild-and-restart, а Lua
|
||
development reload проверяет candidate и перезапускает script/world state, не
|
||
сохраняя произвольное runtime-состояние.
|
||
|
||
Autosave относится только к именованным dirty сценам Editor после двух секунд
|
||
покоя. Он использует ревизию документа и прежний disk-hash conflict check, не
|
||
перезаписывает внешний файл и не создаёт Undo-операцию. Неназванная сцена требует
|
||
Save As; recovery journal работает независимо от autosave. Статусы видны в UI и
|
||
через Editor MCP. Player и экспортная игра по-прежнему не имеют MCP.
|
||
|
||
Измерения P1 разделяют Debug-время итераций, offscreen первый кадр и старый
|
||
Release reference baseline точных демо. Исходный отчёт, raw-профили и отдельное
|
||
дополнение о версиях/хешах исполняемых инструментов находятся в
|
||
[датированном dossier](validation/p1-iteration-2026-09-24/README.md). Большая
|
||
синтетическая сцена выявляет стоимость CPU simulation/snapshot; её время нельзя
|
||
переносить на 2D/3D демо или выдавать за обещание кадровой частоты.
|
||
|
||
## 11. P3 — освещение, тени и temporal reconstruction
|
||
|
||
Один типизированный Light schema подаёт directional, point и spot sources в
|
||
Direct и GPU visibility пути через общий shader ABI. При наличии любого
|
||
авторского Light compatibility sun не создаётся. В кадре не более 128 local
|
||
lights: selection ранжируется по priority, экранному влиянию и стабильному ID,
|
||
а omitted lights явно видны в диагностике. Материал остаётся descriptor set 0,
|
||
освещение — set 1, GPU scene graphics — set 2. Тени рассчитываются из frustum
|
||
камеры и light views независимо от camera culling и prepared LOD: до четырёх
|
||
стабилизированных sun cascades, отдельный атлас 16 spot/point faces и общий
|
||
лимит 4096 caster draws. Шесть граней point-light резервируются атомарно; при
|
||
переполнении свет сохраняется, но его тень отключается. Sun/local атласы пока
|
||
создаются заранее и требуют памяти даже для сцены без shadow raster.
|
||
|
||
Режим `Auto` использует прямой перебор submitted lights во фрагментном шейдере.
|
||
Отдельный depth-free `Tiled` строит списки для 16×16 tiles, максимум 64 индекса
|
||
на tile; переполнение возвращается к полному списку. Это безопасный явный выбор
|
||
для измеренной сцены с локализованным светом. На плотном reference workload
|
||
tile construction и raster вместе медленнее, поэтому автоматический выбор не
|
||
основан на непроверенной occupancy-эвристике. [Совмещённый benchmark](studies/24-p3-integrated-forward-plus-2026-09-24.md)
|
||
публикует оба результата и исходные кадры.
|
||
|
||
`Off` остаётся default и эталонным выходом renderer. `TAA` рендерит 3D scene
|
||
в выходном разрешении с jitter; `Upscale` использует внутреннее разрешение
|
||
`ceil(output × scale)` при scale `[0.5, 1)`, но хранит color/depth history в
|
||
выходном разрешении. Оба режима обрабатывают непрозрачную scene до отдельного
|
||
UI pass, так что Editor/game UI не проходит temporal resolve. Предыдущие
|
||
transforms и motion vectors имеют stable instance identity. Истории HZB и
|
||
temporal color независимы; cut, смена view/projection/viewport/scale, resize,
|
||
несовместимый shader reload и teleport сбрасывают temporal history. Pixels с
|
||
невалидным motion, depth mismatch или reactive geometry используют текущий
|
||
цвет. Упаковка Player содержит готовые Slang SPIR-V и reflection; runtime не
|
||
требует Slang compiler. Фактический режим и причина fallback видны в профиле.
|
||
При неудачной пересборке temporal pipelines во время переключения Direct → GPU
|
||
активные pipelines, layout fingerprints и TAA history сохраняются; после
|
||
исправления shader package переключение можно повторить.
|
||
|
||
TAA/Upscale пока **опциональны**: малые фиксированные сцены показывают
|
||
уменьшение temporal variation, но тонкая геометрия теряет часть пиковой
|
||
контрастности, а sparse 720p сцена не выигрывает по GPU времени. Оба режима
|
||
добавляют output-resolution histories и повышают явные GPU allocations.
|
||
[Датированная temporal-проверка](validation/p3-temporal-2026-09-24/README.md)
|
||
показывает кадры, метрики и ограничения; это не эквивалент TSR/FSR/DLSS.
|
||
|
||
## История решений
|
||
|
||
- **17.09.2026:** выбраны имя Faset Engine, Linux/Windows desktop 2D/3D, ручная работа и MCP, интеграция с Blender, Box2D и Box3D; подготовлены исследования.
|
||
- **18.09.2026:** принят порядок C++ → Lua, затем EnTT, собственный retained UI, SDL3, Vulkan 1.3/RenderGraph/Slang и CMake/Ninja/Clang.
|
||
- **18.09.2026:** утверждены процессы и linkage, явная metadata registration/schema export, JSON/binary formats, вложенные шаблоны/sparse overrides, lifecycle, фиксированный tick и последовательный scheduler; граница MCP ограничена Editor/headless authoring services.
|
||
- **18.09.2026:** английский принят основным языком интерфейса, диагностик и публичного API; уточнена граница прямых Vulkan-вызовов внутри собственного backend.
|
||
- **23.09.2026:** после принятого MVP выполнен P2 GPU visibility/LOD на Linux reference GPU; direct renderer сохранён как начальный режим и эталон, ограничения и измерения вынесены в отдельный [протокол](studies/19-p2-gpu-visibility-acceptance.md).
|
||
- **24.09.2026:** P1 итерация фиксирует проверяемое повторное использование schema/package, структурированную диагностику, стартовые C++/Lua проекты, безопасный autosave и измерительный протокол без C++ hot reload.
|
||
- **24.09.2026:** P3 реализует typed lights, bounded shadow views, measured Forward+/forward selection и opt-in TAA/upscale с отдельными histories и sharp UI; результаты привязаны к контрольным сценам и GPU.
|
||
|
||
Реализация идёт по [PLAN.md](../PLAN.md). Последующие изменения принятых контрактов фиксируются здесь с причиной и способом проверки.
|