# Изменения в 0.4 (после 0.3, с 2026-10-06) Замеры — RX 7800 XT / RADV, Yahar'gul стоя, 1080p без лимита FPS; «4 ядра» — `CPUS=0-3,8-11` (4 ядра / 8 потоков, как у Steam Deck). ## Модель памяти ПК — снова по умолчанию, и для NVIDIA - `BB_GUEST_IN_PLACE=1` по умолчанию (`run.sh`). В лаунчере вместо «Новой модели памяти» — переключатель *Старая модель памяти* (ключ `legacy_memory_model`): модель 0.2 как запасной вариант. - NVIDIA отображает dma-buf только со смещения 0. Раньше порт тогда возвращался к старой модели; теперь у таких драйверов каждое выделение прямой памяти игры — отдельный кусок памяти Vulkan (игра делает 14 выделений и каждое отображает один раз целиком, со смещения 0). Проверка при запуске пишет «the driver's dma-buf maps at offset 0 only: one chunk per direct memory allocation». `BB_GUEST_WHOLE_CHUNKS=1` включает этот режим и на других драйверах (проверка без NVIDIA): на RX 7800 XT 188–190 FPS, картинка в порядке. **На NVIDIA не проверено.** ## Уровень API: libGnm игры Игра собрана со статической libGnm: пакеты PM4 пишет не драйвер, а сама игра, через функции `sce::Gnm::DrawCommandBuffer` / `DispatchCommandBuffer` / `ConstantCommandBuffer` в `0x1068000–0x10a0000` и `0x11fd000–0x11fe000`. Это и есть графический API игры — уровень, на котором работают слои вроде DXVK. - `tools/re/`: поиск пакетов PM4 в коде (`pm4_scan.py`), граф вызовов по границам функций из `.eh_frame` (`callgraph.py`), сигнатуры функций по регистрам (`gnm_sigs.py`), таблица перехватов (`gen_gnm_table.py` → `gpu/shim/bbport_gnm_table.inc`), имена функций (`gnm_names.txt`). - `gpu/shim/bbport_gnm_hooks.cpp`: перехват 513 функций libGnm в начале (jmp на заглушку рядом с образом, перенесённый пролог), до запуска кода игры; каждая точка сверяется с eboot 1.09. - `BB_GNM_CENSUS=1` — счёт вызовов (`BB_GNM_CENSUS_FILE` — полный список в файл). - `BB_GNM_OBSERVE=1` — каждый метод командного буфера отмечает пакеты, которые записал; при отправке проверяется, откуда пришёл каждый пакет. Итог: **100,0 % пакетов (99,9 % слов) пишут известные вызовы API** — командный поток игры целиком описывается вызовами Gnm. - `BB_GNM_TRACE=адрес[:число]` — аргументы, вызывающий код и записанные пакеты. - Найдено: игра вызывает 99 методов командных буферов; обратный вызов резервирования `0x26af230` начинает новый кусок буфера (список кусков уходит в отправку отдельными DCB); `writeDataInline` (`0x1073b80`) из GX обнуляет 192 байта по разу на проход; метки EOP (`writeAtEndOfPipe`, значение 1) ставит распределитель памяти GPU, `waitOnAddress` ждёт их же — это барьер в порядке очереди, а не ожидание CPU. ## Быстрее на слабых процессорах - `WRITE_DATA` и DMA ждали все отложенные копии хоста (22 мкс на каждый `WRITE_DATA`, ~35 за кадр, 12 % времени потока записи отрисовок на 4 ядрах). Теперь ждут только копии, которые читают записываемый диапазон (`Scheduler::WaitHostCopiesFor`, таблица источников по 64 КиБ); командный процессор PS4 тоже не ждёт предыдущих отрисовок перед такой записью. Ожидания: 37 → 2 за кадр. `BB_HOST_COPY_WAITS=all` — прежнее поведение. - Проверка одновременной записи в планировщик (`ProducerScope`) включается только с `BB_PRODUCER_CHECK=1` (лаунчер: *Диагностика вылетов*). - 4 ядра: 158 → 167 FPS. - `BB_SECTIONS=1` показывает и задачи стадии B по функциям. ## Исправления - Свёрнутое окно (Win+D, «Показать рабочий стол») больше не завершает игру (issue #31): поверхность 0×0 не попадает ни в размер кадра, ни в swapchain; кадры, пока окно свёрнуто, не выводятся. Проверено только, что обычный вывод не изменился: в Hyprland окно не сворачивается до 0×0. ## Сравнение с 0.3 Лаунчер, раздел «Для разработчика»: *Синхронизация как в 0.3* (`BB_AS_0_3=1` в `run.sh`) возвращает то, что изменилось после релиза: старая модель памяти, `WRITE_DATA`/DMA ждут все копии хоста (`BB_HOST_COPY_WAITS=all`), проверка одновременной записи (`BB_PRODUCER_CHECK=1`). Yahar'gul стоя, 1080p: 123 FPS против ~186 с новой моделью памяти и трансляции. Из командной строки: `bash tools/play_ab.sh v03 BB_AS_0_3=1`. ## Глубина резкости (DoF) снова работает (issue #44) С DoF и любым апскейлером (FSR 3/4/4.1.1, TAA) в дальнем размытии — небо, туман — появлялись тёмные прямоугольники с резкими краями, полосы и перевёрнутая копия сцены; в 0.2 этого не было. Причина — прицельные ожидания дампов констант из 0.3 (`DumpConstRam` ждёт поток записи отрисовок, только если пересекается с их чтениями): в список чтений попадали лишь константные буферы, а вершины и индексы поток записи тоже читает из памяти игры. Игра пишет мелкие данные отрисовок (в том числе полноэкранные квады DoF) через движок констант, и дамп для следующих отрисовок перезаписывал их раньше, чем их успевали прочитать. Окно открывалось, когда поток записи задерживался прямо перед проходами DoF — на проходах апскейлера. Теперь диапазоны вершин и индексов тоже в списке (неподготовленные отрисовки ждут целиком). Ожиданий стало ~850/с вместо ~150/с, FPS в проверенных местах не изменился. `BB_CONSTRAM_PIPE=0` — полное ожидание на каждом дампе (A/B). Возможно, это же чинит мерцающие значки и глифы интерфейса (issue #11) — не проверено. ## Кэш шейдеров больше не ломает запуск (issues #28, #38, #39) - Файлы кэша пишутся под временным именем и переименовываются: вылет или отключение питания оставляют старый файл или никакого, а не обрезанный. - Обрезанная запись при чтении больше не останавливает игру (`Invalid or corrupted deserialization container`, код 23): повреждённые записи считаются, кэш пересобирается. То же для SPIR-V с неверным заголовком и для пайплайнов, которые драйвер отверг при предзагрузке. Код SRT walker из кэша регистрируется только после проверки длины. ## Прочее - Процессор без AVX, BMI1, MOVBE, LZCNT, POPCNT или SSE4.2 (Intel до Haswell) — понятное сообщение при запуске вместо `Guest fault (signal 4)`, код 132 (issue #26). `BB_SKIP_CPU_CHECK=1` — запустить всё равно. - `tools/fsr4cap/build_assets.sh` молча завершался, если в одной из папок Steam не было GE-Proton (issue #40). - Копии памяти игры, поставленные в прямом режиме записи (отрисовка после проходов апскейлера, `BB_VK_RECORD_THREAD=0`), выполняются сразу, а не со следующей отправкой. - Внутриигровое меню на английском или русском — переключатель «Language» в меню (PR #36); по умолчанию язык лаунчера. Лаунчер на бразильском португальском (PR #10); строки без перевода — на английском. README: адрес репозитория в команде клонирования (PR #43). - Переключатель `BB_TOGGLE_FILE`: бит 31 отключает сборщик текстур; второе число в файле — временные биты экспериментов (`BbToggle::Experiment`). ## Векторы движения (ночь на 2026-10-07, проверяется) - Знак оси Y векторов камеры берётся из вьюпорта G-buffer каждый кадр (`BB_CAMERA_Y=up/down` — принудительно), а не задан константой: 0.2 и 0.3 ошибались каждая в своих местах (issues #41, #42, #47, #18). - Если в кадре несколько проходов G-buffer, камера берётся у того, чья глубина идёт в векторы. - FSR 4 на пресетах с апскейлом получает кадр в линейном свете (`BB_FSR4_LINEAR=0` — как раньше). - Маска реактивности работает и с FSR 4: его результат смешивается с текущим кадром на эффектах (туман, свет, частицы). ## Поток записи отрисовок не ждёт потоки записи команд (2026-10-07) - Презентер (барьер кадра, FSR 1, постобработка) записывается так же, как отрисовки, на потоках записи команд. Раньше он брал командный буфер напрямую: поток отрисовок ждал, пока потоки записи закончат всё переданное (~90 мкс каждый кадр), и сам отправлял кадр (~45 мкс). - Где команды всё же пишутся напрямую (проходы апскейлера: векторы движения, TAA, FSR 3/4, резкость), они идут в отдельный сегмент со своим пулом команд, после переданных сегментов, без ожидания (`BB_DIRECT_SEGMENT=0` — ожидание, как раньше). Сигналы и упорядоченные задачи в таком сегменте остаются в очереди, чтобы не обогнать более ранние метки. - Поток показа ждёт, пока отправка кадра (с потока записи) ушла в очередь, прежде чем ставить своё ожидание на неё: иначе одна очередь ждала бы более позднюю отправку (зависание GPU при запуске, найдено на этой работе). - DMA в память, которую GPU использует на месте (модель ПК) или которую писал GPU, — это копия на GPU в порядке потока; поток отрисовок больше не ждёт перед ней копии и отложенные сигналы (~16 мкс на каждую, ~900 в секунду: 4-байтовые счётчики GDS). - Исправлены два давних редких случая записи в уже отправленный командный буфер: смена размера при резкости больше 1 (`Finish()` посреди прохода апскейлера) и смена пресета FSR 4 в меню. - `BB_FINAL_DUMP_TRIGGER` (`KIND=final tools/frame.sh`): снимок кадра после FSR и постобработки. Замеры (Hunter's Dream, стоя, 4 ядра / 8 потоков, модель ПК): 143–144 → 146 FPS; поток отрисовок больше не блокируется на записи команд (было 1,8–3,3 % времени). 16 потоков: модель ПК ~186, старая модель 144–151 (разброс между запусками ±3 %, без разницы с прежней сборкой). ## Режим работы в лаунчере (2026-10-07) - Группа *Режим работы*, переключатель *Новая модель памяти и трансляции* (`BB_PC_MODEL=1`), по умолчанию выключен. Выключен — старая модель памяти, как в 0.3, со всеми исправлениями после неё. Включён — память игры используется видеочипом на месте, работа командного процессора переводится в команды Vulkan (экспериментально). - Только видеокарты AMD: лаунчер находит их по `/sys/class/drm/card*/device/vendor` (0x1002) и без AMD делает переключатель недоступным; библиотека GPU сама держит режим выключенным, если выбранное устройство Vulkan не AMD (гибридные ноутбуки). `BB_PC_MODEL_ANY_GPU=1` — включить всё равно, для проверки. - Прежний переключатель *Как в версии 0.3* переехал в раздел «Для разработчика» под именем *Синхронизация как в 0.3*: это откат для поиска регрессий, а не один из двух режимов. - README (оба) описывают оба режима, таблицу отличий от shadPS4 и планы. ## FSR 4.1.1 из своей DLL — кнопкой в лаунчере (2026-10-07) - *Апскейлер → FSR 4.1.1 из своей DLL AMD → Выбрать DLL…*: выбираешь `amd_fidelityfx_upscaler_dx12.dll` 4.1.x, лаунчер собирает ассеты (`tools/fsr4cap/build_assets.sh`) в фоне, ход — в подписи строки и во вкладке «Журнал», в конце FSR 4.1.1 выбирается. Отмена той же кнопкой. Без окна: `--build-fsr411 [загрузчик]`. - DLL проверяется до записи (`tools/fsr4cap/dll_info.py`: версия из свойств файла, модели FSR 4 по именам шейдеров). Сборки сообщества OptiScaler (4.0.2b/c: модель `v07_i8`, 16 проходов вместо 29, другие веса) пока не подходят — об этом сразу сообщение, без записи. Загрузчик ищется рядом с DLL и папкой выше под обоими именами (`amd_fidelityfx_loader_dx12.dll`, у OptiScaler — `amd_fidelityfx_dx12.dll`), иначе лаунчер его спрашивает. - Proton запускается через umu-run, если он установлен, иначе в контейнере Steam, который требует этот Proton (`toolmanifest.vdf`: Steam Linux Runtime 4 для GE-Proton 11) — umu больше не нужен. - AppImage содержит собранные заранее dxil-spirv и fsr4cap.exe (Nix), SPIRV-Tools: компиляторы и сеть не нужны, только GE-Proton. Рабочая папка (префикс Proton ~300 МБ) удаляется после сборки. - Заголовки FidelityFX API (MIT) лежат в `tools/fsr4cap/ffx`: SDK больше не клонируется. - Новый набор заменяет старый только целиком; коды выхода скрипта (2–7) лаунчер показывает понятным текстом. Собранная ранее dxil-spirv, которая не запускается (дерево переехало), собирается заново. Проверено: из исходников (Nix, umu) и пакет (Steam Linux Runtime 4 в FHS-окружении) — результат побайтно совпадает с прежним `fsr4_411`; кнопка в лаунчере (headless-сессия): ход «N из 20», отказ для 4.0.2c. Не проверено: AppImage на обычном дистрибутиве / Steam Deck (на NixOS AppImage скрывает системный `/nix` и FHS-ссылки). - После первой проверки (DLL из Pragmata): это официальная FSR 4.0.3 с той же моделью `v07_fp8_no_scale`, но её провайдер AMD показывает только на RDNA4 — на RX 7800 XT под любым Proton DLL предлагает лишь FSR 3.1.5 и 2.3.4. Теперь 4.0.x отклоняется сразу с объяснением. Отклоняется и «загрузчик», который на самом деле DLL апскейлера (так получилось в видео: загрузчика рядом не было, и в окне выбора оказалась та же DLL). - Proton выбирается перебором: первый, под которым DLL включает FSR 4.1 (GE-Proton 10+, Proton-CachyOS, Proton Experimental, затем Proton 11.0/10.0 из Steam), у каждого свой префикс. Проверено на RX 7800 XT: GE-Proton 11-6, Proton-CachyOS 11 (июль), Experimental (октябрь) — да; Proton 11.0-2c и GE-Proton 9 — нет. На Steam Deck был только GE-Proton 9. - На NixOS AppImage сразу говорит, что рантайм Steam там не запустить (код 8), вместо непонятного «не запустился под Proton». ## FSR 4.1.1: одна DLL и вариант FP8 для RDNA4 (2026-10-07, день) - **Загрузчик больше не нужен.** DLL апскейлера AMD сама экспортирует FidelityFX API (`ffxCreateContext` …), и `fsr4cap.exe` загружает её напрямую; `dll_info.py` проверяет экспорт по таблице PE. Загрузчик спрашивается только у DLL без этих функций (таких пока не встречалось). Запись с DLL напрямую совпадает с записью через загрузчик (кроме двух байт неинициализированной константы в кадре 0), набор — побайтно. - Повторная сборка из AppImage падала: `cp: cannot create regular file …/fsr4cap.exe: Permission denied` — копия файла из AppImage только для чтения, и вторая копия поверх неё не создаётся. Теперь старый файл удаляется перед копированием (и DLL, если она только для чтения). - **FP8 на RDNA4.** На RDNA4 vkd3d-proton даёт DLL матрицы FP8, и она запускает другой вариант проходов (issue #12): те же 29 проходов, константы и буферы, но шейдеры на WMMA FP8, свои веса и своя сетка групп (у каждого прохода свой тайл: 16×8, 32×1, 16×4 …; `_post` — ширина тензора выровнена до 32, а не до 4). Сборка после INT8 пробует FP8 на первом размере и, если DLL отдаёт другие шейдеры (RDNA4), записывает все 20 размеров во второй раз (`fp8/capture_*`). `extract.py` проверяет правила обоих вариантов и пишет `fsr4_411/fp8/` (матрицы FP8, `VK_EXT_shader_float8`) и `fsr4_411/fp8emu/` (FP8 через FP16-матрицы, как vkd3d-proton на RDNA3 — только для проверки). Игра выбирает FP8 сама, если у видеокарты есть матрицы FP8 и набор собран; `BB_FSR411_VARIANT=int8|fp8|fp8emu` — принудительно. В строке `Upscaler: FSR 4.1.1 replay, …` теперь указан вариант. - Проходы с матрицами запускаются с подгруппой 32 и полными подгруппами, как у vkd3d-proton (эвристика размера волны у них совпадает с использованием матриц — `extract.py` это проверяет). Устройство игры включает `VK_KHR_cooperative_matrix`, `VK_EXT_shader_float8`, `vulkanMemoryModel`, `computeFullSubgroups`, если они есть. - Проверено на RX 7800 XT: FP8 с эмуляцией (GE-Proton 11-6, `BB_FSR4CAP_FP8=1`) — DLL и повтор **побайтно одинаковы** на 7 размерах, обе модели, 4 кадра (`VARIANT=fp8emu verify.sh`; с dxil-spirv той же версии, что в vkd3d-proton GE-Proton 11-6 — наша закреплённая новее и иначе округляет преобразования FP8 в эмуляции). INT8 — как прежде (1600×900 расходится у правого края из-за гонки в самой DLL). На RDNA4 вживую **не проверено**: проходы модели FP8 от обеих версий dxil-spirv одинаковы, различаются только `_post`. - На RDNA3 FP8 по умолчанию не записывается: эмуляция почти вдвое медленнее INT8 (1440p Balanced, RX 7800 XT: 3,35 мс против 1,82 мс). `BB_FSR4CAP_FP8=1` — записать и там, `BB_FSR4CAP_FP8=0` — не записывать нигде. ## Управление и игровое меню (2026-10-07) - **Меню жестов с тачпада.** Касания тачпада приходили с id 0 и без времени удержания, и игра их не принимала: ни тачпад, ни Back, ни Tab не открывали жесты. Теперь каждое новое касание получает свой id (1–127), как у DualShock 4, и время удержания. Проверено в игре: левая половина тачпада — «Жесты», правая — «Личные вещи» (с включённым debug menu левая половина открывает его). В лаунчере это подписано у привязок тачпада. - **Клавиатура работает и при подключённом геймпаде.** Раньше она управляла игрой, только когда геймпада нет (а на Steam Deck он есть всегда); работали лишь Tab и Backspace. Теперь кнопки клавиатуры добавляются к кнопкам геймпада, а зажатая клавиша движения/камеры отклоняет стик до конца. Вживую с клавиатурой не проверено (только сборка и тесты). - **Меню настроек (Insert / L3+R3) помнит своё место** — и между открытиями, и между запусками (`menu_pos` в bbport.ini, доля экрана: переживает смену разрешения). Раньше оно каждый раз открывалось у левого края. - **Курсор мыши над меню.** Пока меню открыто, показывается системный курсор (в полноэкранном режиме и после 3 с без движения он скрыт), а меню сразу знает, где мышь, а не после первого движения. - **Настройки из меню больше не стирают назначения кнопок.** Меню записывало bbport.ini целиком, только со своими ключами: назначения клавиатуры и геймпада из лаунчера (`key.*`, `pad.*`) и другие его ключи пропадали после любого изменения в игре. Теперь меню меняет только свои строки, остальное оставляет, файл заменяется целиком (обрыв записи оставляет старый). Тест: `ninja -C out/gpu settings-test`. ## BB_READBACKS=2 больше не зависает при запуске Точный режим обратного чтения защищает страницы, записанные GPU, и от чтения. Их читали и потоки копирования порта (выгрузка в VRAM: `bb:Copy*`, `bb:VkRecorder`): чтение падало в обработчик сбоев, тот ставил обратное чтение в очередь потоку GPU и ждал, а поток GPU в это время ждал поток записи отрисовок, который ждал эти копии. Теперь копии порта в точном режиме читают память игры через второе отображение тех же страниц, которое защита не трогает. Проверено: с `BB_READBACKS=2` игра доходит до титульного экрана и работает (раньше вставала на загрузке). В самой игре в этом режиме не проверено. `BB_PROBE=<обёртка>` в run.sh — запуск под gdb и т. п. и из исходников. ## FSR 4.1.1 из AppImage на NixOS (2026-10-07, вечер) AppImage работает в своём пространстве монтирования с chroot, где её `/nix/store` заменяет системный: изнутри не видны ни `umu-run`, ни `nix-shell`, ни FHS-окружение Steam, и кнопка сборки на NixOS заканчивалась ошибкой 8. Теперь `capture_all.sh` на NixOS без `umu-run`: - если есть `nix-shell` (из исходников, на самой системе) — перезапускается в `nix-shell -p umu-launcher`; - в AppImage — копирует себя и `proton.sh` в рабочую папку (`~/.local/share/bbport/fsr4cap`, её видят обе стороны) и запускает запись на системе через `systemd-run --user --wait --pipe` в login-shell (PATH и NIX_PATH пользователя); ход и код выхода приходят обратно, отмена останавливает службу. Перевод в SPIR-V — уже внутри AppImage. `systemd-run` из systemd-minimal (он и так был в пакете) добавлен в PATH лаунчера. Проверено на этом ПК (NixOS): кнопка без окна (`--build-fsr411`) из AppImage собирает FSR 4.1.1 до конца, набор побайтно как эталонный, рабочая папка удалена; отмена посреди записи останавливает службу на системе.