mirror of
https://github.com/ayozetr/bloodborne_linux.git
synced 2026-11-13 20:05:52 -10:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97a60dd497 | ||
|
|
a3a8a3af6e | ||
|
|
f1091cc0b1 | ||
|
|
c496667284 | ||
|
|
a8b7a8eaa1 | ||
|
|
4d934b7529 | ||
|
|
442c2b66bd | ||
|
|
d7a42fde94 | ||
|
|
d0318b1ab5 | ||
|
|
1bc4f37504 | ||
|
|
44a6b7c3ce | ||
|
|
efdf7b176e | ||
|
|
4f7df3de5c | ||
|
|
e3c51c48aa | ||
|
|
33393185b9 | ||
|
|
c294942db4 | ||
|
|
6c6974a742 | ||
|
|
83246710d7 | ||
|
|
b71eb7cfee | ||
|
|
b6c25e1fb4 | ||
|
|
3c57da4198 | ||
|
|
0e2b626358 | ||
|
|
b060b9fa2b | ||
|
|
18a7dd7e39 | ||
|
|
28a9233034 | ||
|
|
9c056c437f | ||
|
|
2683273a17 | ||
|
|
4d297b96bb | ||
|
|
917c4bdd20 | ||
|
|
8e24cfdcf5 | ||
|
|
cfede387ed | ||
|
|
f44390da19 | ||
|
|
c89f4d432c | ||
|
|
4fd1cd6ee6 | ||
|
|
c7e3e55eff | ||
|
|
cfe7af67a5 | ||
|
|
124384eac1 | ||
|
|
10baf9df25 | ||
|
|
f2cd4ca0c4 | ||
|
|
af9e66db2f | ||
|
|
39940f25eb |
No files matched your search
@@ -0,0 +1 @@
|
||||
ko_fi: ayozetr
|
||||
@@ -18,13 +18,15 @@ directly on the PC:
|
||||
[shadPS4](https://github.com/shadps4-emu/shadPS4) and heavily extended for this game, including
|
||||
temporal upscaling with AMD FSR 3.1, FSR 4 and FSR 4.1.1;
|
||||
- memory and the GPU's work are moving to the PC model: the launcher has an experimental
|
||||
*New memory and translation model* mode (AMD GPUs only); without it the game runs on the old
|
||||
*New memory and translation model* mode; without it the game runs on the old
|
||||
memory model, as in 0.3.
|
||||
|
||||
Two steps remain to the full Wine + DXVK model: make the new mode the default, and move the
|
||||
reading of resource descriptors (textures, buffers) from the CPU to the GPU (see below).
|
||||
One step remains to the full Wine + DXVK model: make the new mode the default and remove the old
|
||||
memory model (see below).
|
||||
|
||||
> **No game files are included.** You need your own dump of Bloodborne (CUSA03173, v1.09).
|
||||
> **No game files are included.** You need your own dump of Bloodborne with update 1.09: any retail
|
||||
> release (CUSA00900 in the US, CUSA03173 for the European Game of the Year edition, ...), as they
|
||||
> share the same executable.
|
||||
> This project is not affiliated with Sony Interactive Entertainment, FromSoftware or AMD.
|
||||
|
||||
**Status: experimental, playable.** The game boots, loads saves and plays (the Hunter's Dream
|
||||
@@ -41,17 +43,28 @@ Mesa/RADV) has been tested thoroughly.
|
||||
- **Switch off (the default) — as in 0.3.** The old memory model: VRAM copies of the game's
|
||||
memory, writes tracked through page protection. With every fix made since 0.3 (motion
|
||||
vectors and the upscaler, flicker with DoF on, a damaged shader cache).
|
||||
- **New memory and translation model — experimental, AMD GPUs only.** The game's memory lives
|
||||
- **New memory and translation model — experimental.** The game's memory lives
|
||||
in system RAM and the GPU reads it where it is, as a PC game's buffers; data it reads often
|
||||
is kept in VRAM and given back when unused (textures after 20 s, buffers after 60 s). No
|
||||
write tracking, no copies of the whole GPU-visible memory. The PS4 command processor's work
|
||||
is kept in VRAM and given back when unused (textures after 20 s, buffers after 60 s). The
|
||||
layer's memory module tracks CPU writes to mirrored blocks to keep those copies coherent;
|
||||
it does not copy the whole GPU-visible memory. The PS4 command processor's work
|
||||
is translated into Vulkan commands rather than emulated on the CPU: memory writes
|
||||
(`WRITE_DATA`, DMA) are done by the GPU in command-stream order, and fences are written once
|
||||
the GPU has really finished the work. Where the game is CPU-bound it runs 20–25% faster
|
||||
(measured standing in the Hunter's Dream), with fewer stutters. **It may crash**, and has
|
||||
been tested thoroughly only on the author's PC (RX 7800 XT). On NVIDIA and Intel the switch
|
||||
is unavailable: NVIDIA's driver cannot map the game's memory as needed, Intel is untested.
|
||||
Without the launcher: `BB_PC_MODEL=1`; to try it on another GPU: `BB_PC_MODEL_ANY_GPU=1`.
|
||||
(`WRITE_DATA`, DMA) are done by the GPU in command-stream order, and fences are written by the
|
||||
GPU itself at the end of the pipeline, at the same point of the stream as the PS4's command
|
||||
processor writes them. **It may crash**; hardware testing has been performed on an
|
||||
RX 7800 XT, and performance depends on the scene and settings. On AMD the game's memory is kept
|
||||
in a sparse buffer (the arena). **On NVIDIA, Intel and others** it goes through the layer's
|
||||
memory module: the game's memory is bound in place and VRAM copies are separate buffers, with
|
||||
no sparse rebinding. This avoids the sparse-binding path associated with reported freezes
|
||||
on a GTX 1660 Ti. On NVIDIA the module runs on a tester's GTX 1660 Ti, its speed is still
|
||||
being checked; not tested on Intel. Without the launcher: `BB_PC_MODEL=1`; to choose the memory
|
||||
path: `BB_GUEST_MEMORY=host|dmabuf`; the memory module: `BB_LAYER_MEMORY=1/0`.
|
||||
|
||||
[0.5-pre4 changes](docs/CHANGES_0.5-pre4.md): no stutter of the memory module (NVIDIA) while areas
|
||||
stream in, shader compilation in the background, VRAM on 4–6 GB cards, damaged game extractions
|
||||
reported, the settings menu as in 0.3. [0.5-pre3](docs/CHANGES_0.5-pre3.md): the memory module on
|
||||
NVIDIA — VRAM copies, one VRAM budget with the texture cache, watched blocks. [0.5-pre2](docs/CHANGES_0.5-pre2.md): the memory
|
||||
module, native GPU copy shader, portable GPU completion labels, and shader-cache migration.
|
||||
|
||||
Unused textures are freed in both modes, so VRAM no longer grows with every area visited.
|
||||
- **Unlocked frame rate.** Community patches (`patches/Bloodborne.xml`) make the simulation
|
||||
@@ -78,9 +91,11 @@ Mesa/RADV) has been tested thoroughly.
|
||||
and draws are bound and recorded on another (two-stage pipeline), with a Vulkan recording
|
||||
thread and helper threads for memory copies. Early on the single GPU thread capped the game
|
||||
at ~26 FPS; now it runs at 90–150 FPS depending on resolution and scene.
|
||||
- **In-game menu** (Insert or L3+R3): upscaler, preset, sharpness, output resolution, game
|
||||
effects (chromatic aberration, DoF, motion blur, SSAO, the game's own AA, SSR, model LOD).
|
||||
It opens where it was left, with the mouse cursor shown over it.
|
||||
- **Settings inside the game's own menu:** *System → Display / Game effects / Game patches*
|
||||
(after *Screen/Sound*), built and drawn by the game itself — output resolution, upscaler,
|
||||
preset, sharpness, FPS counter, model detail and the effect patches, in the game's language.
|
||||
- **Overlay menu** (Insert or L3+R3), styled like the game's dialogs: everything above plus the
|
||||
advanced settings, with gamepad, keyboard and mouse.
|
||||
- **GTK4 launcher** and an **AppImage** for the Steam Deck.
|
||||
|
||||
## How it differs from shadPS4
|
||||
@@ -89,7 +104,7 @@ Mesa/RADV) has been tested thoroughly.
|
||||
|---|---|---|
|
||||
| Scope | General PS4 emulator, many games | One game: Bloodborne v1.09 |
|
||||
| Loading | Its own ELF loader and kernel emulation at run time | The eboot is converted offline (`scripts/`) into an image with PS4 libc/Fios2 linked in; a C loader maps it and jumps into the game (loader and runtime: ~5k lines) |
|
||||
| Memory | The GPU's view of PS4 memory is kept in VRAM copies, synchronized through page-protection write tracking | By default the same model (as in 0.3); in the *New memory and translation model* mode (AMD): the game's memory in system RAM, used by the GPU in place, frequently read data in VRAM, freed when unused |
|
||||
| Memory | The GPU's view of PS4 memory is kept in VRAM copies, synchronized through page-protection write tracking | By default the same model (as in 0.3); in the *New memory and translation model* mode: the game's memory in system RAM, used by the GPU in place, frequently read data in VRAM, freed when unused |
|
||||
| Command processor | Emulated: memory writes, DMA and fences are done by the CPU while decoding | By default the same; in the new mode translated into Vulkan commands that the GPU runs in stream order, fences written after the work has really finished |
|
||||
| System libraries | Broad HLE of the PS4 OS | A small runtime (`src/runtime_*.c`) that implements exactly what Bloodborne calls: memory, threads, sync, files, audio (incl. ATRAC9), pad, saves, AppContent |
|
||||
| GPU | shadPS4 video core and shader recompiler | The same core (vendored, GPL) with ~200 marked changes (`bbport:`) plus new modules: two-stage draw pipeline, render-state and texture-set memoization, render-scale proxies, motion vectors, FSR 3.1/4/4.1.1, frame capture and GPU profiler |
|
||||
@@ -108,15 +123,20 @@ the graphics side.
|
||||
implements exactly the PS4 OS functions Bloodborne calls: memory, threads, files, audio, pad,
|
||||
saves.
|
||||
- **Memory.** In the new mode, as in a PC game: the game's data in system RAM, VRAM used the way
|
||||
a PC game uses it. The mode is still experimental and runs on AMD GPUs only.
|
||||
a PC game uses it. The mode is still experimental.
|
||||
- **Graphics.** The PS4 GPU's command stream (PM4) is a recording of the game's graphics API
|
||||
calls: it is written by 99 functions of the statically linked libGnm, so decoding the stream
|
||||
and translating the calls themselves come to the same thing. GCN shaders are translated to
|
||||
SPIR-V. In the new mode the command processor's work (memory writes, DMA, fences) is
|
||||
translated into Vulkan commands as well. One part still works the old way: the translator
|
||||
reads resource descriptors (textures, buffers) from the game's memory on the CPU, and
|
||||
recognises textures by address. The next big step is the GPU reading the descriptors itself
|
||||
(bindless), with textures as objects created at load time.
|
||||
translated into Vulkan commands as well; fences are written by the GPU itself. Resource
|
||||
descriptors (textures, buffers) are read by the translator on the CPU, as DXVK reads resource
|
||||
bindings: a PS4 texture has to be converted from the PS4 tiling into a Vulkan image before the
|
||||
draw runs, so the CPU must know its descriptor beforehand — translation, not emulation. The
|
||||
descriptor tables (the constant engine's dumps) are read only by the translator, so the CPU
|
||||
performs them. The game's occlusion queries (~60 a frame) are
|
||||
Vulkan occlusion queries; predication, `COPY_DATA` and `COND_EXEC` are translated too (check:
|
||||
`BB_PM4_SELFTEST=1`). Details:
|
||||
[docs/EMULATION_REMOVAL_PLAN.ru.md](docs/EMULATION_REMOVAL_PLAN.ru.md), "Шаг 4" (Russian).
|
||||
|
||||
"Port" here means a build for this one game, not a rewrite of its source code, which the project
|
||||
neither has nor includes.
|
||||
@@ -124,18 +144,20 @@ neither has nor includes.
|
||||
## Requirements
|
||||
|
||||
- Linux x86-64, a Vulkan 1.3 GPU. Tested: AMD RX 7800 XT with Mesa 26 (RADV).
|
||||
The *New memory and translation model* mode needs an AMD GPU.
|
||||
The *New memory and translation model* mode is not tested on NVIDIA yet.
|
||||
FSR 4 / 4.1.1 require shader Float16, Int8/Int16, integer dot products, linear compute
|
||||
derivatives and extended storage image formats; FSR 4.1.1 additionally requires
|
||||
`VK_VALVE_shader_mixed_float_dot_product`. Unsupported choices fall back to FSR 3.1
|
||||
before the first frame and are disabled in the in-game menu.
|
||||
- Your decrypted game dump: the `CUSA03173` folder (eboot.bin, sce_module, ...), version 1.09.
|
||||
The EU release (`CUSA00900`) runs too: its 1.09 executable is the same as the US one.
|
||||
The US release (`CUSA00900`) runs too: its 1.09 executable is the same as this European
|
||||
Game of the Year edition's.
|
||||
A dumped update is a separate folder: copy it over the base game, replacing files. The base
|
||||
game alone (1.00) crashes at start (guest offset 0x20348b8); the launcher and `run.sh` check
|
||||
the executable and say what is missing (`BB_SKIP_GAME_CHECK=1` skips the check). Some dumps
|
||||
ship the 1.09 eboot.bin with Lance McDonald's 60 fps patch baked in; that one crashes when the
|
||||
gestures menu opens, and the check asks for a clean eboot.bin (bbport has its own 60 fps).
|
||||
the executable and say what is missing (`BB_SKIP_GAME_CHECK=1` skips the check). The other
|
||||
retail releases (the US `CUSA00900`, the Asian `CUSA03023`, ...) run the same 1.09 executable. Some dumps ship it
|
||||
with Lance McDonald's 60 fps patch baked in, which crashes when the gestures menu opens: the
|
||||
check asks for a clean eboot.bin then (bbport has its own 60 fps).
|
||||
- To build: GCC, CMake, Ninja, Python 3, glslang, SDL3, Vulkan headers and the libraries in
|
||||
`shell.nix`. With [Nix](https://nixos.org) everything comes from `shell.nix` automatically.
|
||||
|
||||
@@ -160,13 +182,16 @@ when several are connected; `BB_GAMEPAD=<GUID or part of the name>`). The keyboa
|
||||
also next to a connected gamepad (the Steam Deck always has one); both are remapped in the
|
||||
launcher (*Controls*). The character name is typed on the keyboard in a box over the game.
|
||||
The touchpad: its left half (Tab, Back/Select) opens the gestures, the right half (Backspace)
|
||||
the key items.
|
||||
the key items. There is no PSN: the *Play online / offline* screen is skipped and the game opens
|
||||
its main menu offline (a game patch; the launcher's *Game effects → Skip the “play online / offline” choice*,
|
||||
`BB_SKIP_NETWORK_CHOICE=0` shows it). With several monitors, *Screen → Monitor* in the launcher
|
||||
(`BB_DISPLAY=<number or part of the name>`) picks the one for the game.
|
||||
|
||||
Add-ons: `BB_DLC_DIR=/path/to/dlc` (the launcher's *DLC folder*) holds the dumped add-ons of
|
||||
the game, one folder each (`SPEXPANSIONDLC03/sce_sys/param.sfo`, ...). Their data ships with
|
||||
the 1.09 update, so a folder with only `sce_sys` is enough: `scripts/content_profile.py` lists
|
||||
the add-ons of this title into `out/content.bin` and `sceAppContentGetAddcontInfoList` reports
|
||||
them to the game. The GOTY edition (CUSA03173) needs none.
|
||||
the game, one folder each named by its entitlement label (`SPEXPANSIONDLC03/sce_sys/...`).
|
||||
Their data ships with the 1.09 update, so a folder with only `sce_sys` is enough. `run.sh` links
|
||||
it as `user/addcont/<title id>`, where the runtime finds add-ons (see **DLC** below); a real
|
||||
folder already there is kept. The GOTY edition (CUSA03173) needs none.
|
||||
|
||||
**Resolution and preset changes:** for outputs other than 1080p (720p on the Steam Deck,
|
||||
1440p, 4K) the whole game renders at the preset's resolution, set by a patch at start — the
|
||||
@@ -192,12 +217,19 @@ with enable switches and load order. A sibling `CUSA03173-mods/` overlay also wo
|
||||
The original game is preserved; later mods override conflicting files.
|
||||
**Third-party patches:** shadPS4-format XML patch files in the data directory's `patches/`,
|
||||
switched on and off in the launcher. See [mods and patches](docs/MODS.md).
|
||||
**DLC:** put your add-on dumps in `user/addcont/<title id>/<entitlement label>/` (shadPS4's
|
||||
layout, e.g. `user/addcont/CUSA03173/SPEXPANSIONDLC03` for The Old Hunters): each folder there is
|
||||
reported to the game as an installed add-on.
|
||||
|
||||
**Launcher language:** Russian, English or Brazilian Portuguese (follows the system language by default).
|
||||
**Launcher language:** Russian, English, Brazilian Portuguese, Spanish, Italian, French, German or Simplified Chinese (follows the system language by default).
|
||||
**Game language:** the PS4 system language, *System language* in the launcher; by default it
|
||||
follows the desktop's locale (Japanese, English, French, Spanish, German, Italian or Russian,
|
||||
English for the rest). `run.sh` takes it as `BB_LANGUAGE` (PS4 code: 0 Japanese, 1 English,
|
||||
2 French, 3 Spanish, 4 German, 5 Italian, 8 Russian; without it, the desktop's locale as above).
|
||||
**Game region:** *Game region* in the launcher, `BB_REGION=eu|na` for `run.sh`: the regional text
|
||||
of a language, such as Spanish from Spain (`eu`) or Latin American Spanish (`na`). It sets the
|
||||
game's `USER_DEFINED_PARAM_1` (13 Europe, 2 the Americas) for the launch; by default the dump's
|
||||
`param.sfo` decides.
|
||||
|
||||
**Free camera and game debug menu** (v1.09): enable the corresponding switches in the
|
||||
launcher or in-game menu and restart. Free camera uses Lance McDonald's
|
||||
@@ -245,6 +277,30 @@ time, ~1.7 GB); the AppImage runs the recording on the system itself, through th
|
||||
enable FSR 4.1 there, build on a PC and copy the `fsr4_411` folder. The same from the command
|
||||
line: the launcher's (and the AppImage's) `--build-fsr411 <DLL>`.
|
||||
|
||||
**DLSS (NVIDIA GeForce RTX).** NVIDIA's DLSS SDK is not included: check out
|
||||
[github.com/NVIDIA/DLSS](https://github.com/NVIDIA/DLSS) (`include/` and `lib/Linux_x86_64` are
|
||||
enough) and build with `DLSS_SDK_ROOT=/path/to/DLSS bash build.sh`. That also builds the bridge
|
||||
`out/libbbport_dlss.so` (`gpu/dlss_bridge`, the only code that uses the SDK) and copies NVIDIA's
|
||||
`libnvidia-ngx-dlss.so.<version>` next to `out/bb-probe`; the driver provides the rest. Then pick
|
||||
*DLSS* in the launcher or the in-game menu: the preset sets the render size, Native AA is DLAA.
|
||||
DLSS gets the inputs FSR 3.1 gets (scene color, depth, motion vectors, jitter). Without the
|
||||
libraries, on other GPUs or with `BB_DLSS=0` it is listed as unavailable, and a DLSS setting falls
|
||||
back to FSR 3.1.
|
||||
|
||||
On Linux, DLSS also needs NVIDIA's CUDA/UVM runtime. If device creation fails with the DLSS
|
||||
extensions, the renderer retries without them and uses FSR 3.1. If `/dev/nvidia-uvm` is missing,
|
||||
load the installed driver module with `sudo modprobe nvidia_uvm` and restart the game. Installing
|
||||
the distribution's `nvidia-modprobe` package lets NVIDIA's libraries load the module when needed.
|
||||
If `modprobe` reports `Key was rejected by service` with Secure Boot enabled, enroll the
|
||||
module's signing key using the distribution's [MOK procedure](https://documentation.ubuntu.com/security/security-features/platform-protections/secure-boot/#mok-generation-and-signing-process).
|
||||
|
||||
The AppImage built with `DLSS_SDK_ROOT` carries the bridge and NVIDIA's library (NVIDIA's RTX SDK
|
||||
license allows that in an application; its text is `NVIDIA-DLSS-LICENSE.txt` in the package). A
|
||||
newer `libnvidia-ngx-dlss.so.<version>` (from the SDK's `lib/Linux_x86_64/rel`) is chosen in the
|
||||
launcher: *Upscaler → DLSS: NVIDIA's library → Choose a file…*, as the FSR 4.1.1 DLL; it is
|
||||
copied to `<user>/dlss/`, which the game prefers. A game's `nvngx_dlss.dll` is the Windows
|
||||
library: NVIDIA's Linux driver does not load it.
|
||||
|
||||
From source the script takes its tools from the system (MinGW GCC, CMake, Ninja, Python 3,
|
||||
SPIRV-Tools, Git) or from Nix; the AppImage has them prebuilt.
|
||||
|
||||
@@ -302,7 +358,7 @@ When running from source, install MangoHud separately. A diagnostic launch with
|
||||
|
||||
Useful variables: `BB_FRAME_STATS=1` (frame statistics, including a `Memory:` line: VRAM, GTT,
|
||||
RSS, images and guest blocks in VRAM), `BB_PC_MODEL=1` (the new memory and translation model,
|
||||
AMD only; 0, the old model as in 0.3, is the default), `BB_ANISO=N` (anisotropic filtering of scene textures; 16 by
|
||||
0, the old model as in 0.3, is the default), `BB_ANISO=N` (anisotropic filtering of scene textures; 16 by
|
||||
default, 0 = the game's own),
|
||||
`BB_GC_IDLE_SECONDS=N` / `BB_VRAM_IDLE_SECONDS=N` (how long unused textures / buffers stay in VRAM;
|
||||
20 / 60), `BB_BREADCRUMBS=0` (no GPU breadcrumbs; with them a GPU hang names the draw or dispatch
|
||||
@@ -312,7 +368,9 @@ pass), `BB_FSR4_PROFILE=1` (GPU time per FSR 4 pass), `BB_UPSCALER=taa|fsr3|fsr4
|
||||
0 = unbounded), `BB_PRESENT_THREAD=0` (present on the vblank thread, as before),
|
||||
`BB_LIVE_RES=1` (live resolution changes instead of the startup patch for outputs other than 1080p),
|
||||
`BB_PAD_RECORD=file` / `BB_PAD_REPLAY=file` (record a route with F9, replay it in scripted tests),
|
||||
`BB_GC_BUDGET_MB=N` (texture cache budget, as on integrated GPUs), `BB_PRESENT_DUMP_TRIGGER=file`
|
||||
`BB_GC_BUDGET_MB=N` (texture cache budget, as on integrated GPUs), `BB_VRAM_LIMIT_MB=N` (the VRAM
|
||||
budget taken as at most N MiB: checks the behaviour of cards with little VRAM), `BB_ASYNC_PIPELINES=0`
|
||||
(new pipelines compile at once and the game waits; by default in the background), `BB_PRESENT_DUMP_TRIGGER=file`
|
||||
with `BB_PRESENT_DUMP_COUNT=N` (dump N consecutive presented frames),
|
||||
`BB_FSR411_VARIANT=int8|fp8|fp8emu` (FSR 4.1.1 variant; by default FP8 where the GPU has FP8
|
||||
matrices), `BB_READBACKS=0|1|2` (reads of GPU-written memory by the game: 1 by default, 2
|
||||
@@ -320,6 +378,14 @@ precise and slow, 0 off).
|
||||
More in [docs/](docs); recent changes: [docs/CHANGES_0.4.md](docs/CHANGES_0.4.md) (in Russian),
|
||||
[docs/CHANGES_2026-10-06.md](docs/CHANGES_2026-10-06.md).
|
||||
|
||||
**Online play (shadNet).** A separate module, `out/gpu/libbbnet.so` (`gpu/bbnet`: shadPS4's network
|
||||
and PSN libraries from shadp2p, a shadPS4 fork, with the shadNet client), built when protobuf,
|
||||
nlohmann_json, OpenSSL, zlib and miniupnpc are there (`shell.nix`) and included in the AppImage.
|
||||
The launcher's *Online* page turns it on (`BB_ONLINE=1`): messages, bloodstains and ghosts come
|
||||
from The Hunter's Dream, bells and summons go through a shadNet server (`srv.shadps4.net:31313` by
|
||||
default) with a shadNet account (Online ID and password). Offline the module is never loaded; a
|
||||
build without it plays offline only.
|
||||
|
||||
## Repository layout
|
||||
|
||||
| Path | Contents |
|
||||
@@ -338,18 +404,16 @@ Tests: `bash build.sh --test`, `python3 -m unittest discover -s tests`, and
|
||||
|
||||
## Roadmap
|
||||
|
||||
- The new memory and translation model on by default once it is stable, NVIDIA included; the
|
||||
old model is removed after that.
|
||||
- The GPU reads resource descriptors itself (bindless), textures are objects created at load
|
||||
time: no shader code or constant engine executed on the CPU, no texture cache keyed by
|
||||
address.
|
||||
- The new memory and translation model on by default once it is stable and tested on NVIDIA;
|
||||
the old model is removed after that.
|
||||
- Textures as objects created at load time (less guessing by address, uploads outside the
|
||||
frame).
|
||||
- Shaders translated ahead of time, at install, not during play.
|
||||
- More CPU parallelism in GPU command processing (split the draw-recording stage further),
|
||||
scaling to all hardware threads — most important for the Steam Deck.
|
||||
- Async compute for the upscaler (the frame is GPU-bound at 4K).
|
||||
- XeSS (super resolution) and XeFG frame generation through a Wine helper sharing Vulkan
|
||||
memory (a memory-bridge prototype is in `tools/bridge_helper`); DLSS for NVIDIA users;
|
||||
inputs exposed so that OptiScaler-style mapping works.
|
||||
memory (a memory-bridge prototype is in `tools/bridge_helper`); inputs exposed so that OptiScaler-style mapping works.
|
||||
- Frame generation (FSR 3.1 FG first), reactive and transparency masks for particles and fog.
|
||||
- Fix the races in AMD's FSR 4.1.1 shaders at output widths that are not multiples of 64
|
||||
(e.g. 1600×900), as already done for the left-edge race in FSR 4 v07 at 1080p.
|
||||
@@ -366,5 +430,7 @@ FSR 4 v07 provider), AMD FidelityFX SDK (MIT), [LibAtrac9](https://github.com/Th
|
||||
(MIT), [Dear ImGui](https://github.com/ocornut/imgui) (MIT), DejaVu fonts,
|
||||
[dxil-spirv](https://github.com/HansKristian-Work/dxil-spirv) (MIT, used to build the
|
||||
FSR 4.1.1 assets). Game patches by Kyo, Lance McDonald, auser1337, illusion, emoose and other
|
||||
community members (`patches/Bloodborne.xml`). AMD's FSR 4 DLLs and model data are not
|
||||
distributed here.
|
||||
community members (`patches/Bloodborne.xml`). The DLSS bridge (`gpu/dlss_bridge`, MIT) and
|
||||
loader come from [Supermedo's Windows port](https://github.com/Supermedo/bloodborne_pc), adapted
|
||||
from [IFreemz/shadPS4-Bloodborne-DLSS-FSR](https://github.com/IFreemz/shadPS4-Bloodborne-DLSS-FSR).
|
||||
AMD's FSR 4 DLLs and model data and NVIDIA's DLSS SDK and libraries are not distributed here.
|
||||
+105
-42
@@ -16,14 +16,16 @@ bbport — это аналог Wine + DXVK, только для одной иг
|
||||
- **как в DXVK**, графика игры переводится в Vulkan — рендером на основе
|
||||
[shadPS4](https://github.com/shadps4-emu/shadPS4), сильно доработанным под Bloodborne, вплоть
|
||||
до временного апскейлинга AMD FSR 3.1, FSR 4 и FSR 4.1.1;
|
||||
- память и работа видеочипа переезжают на модель ПК: в лаунчере есть экспериментальный режим
|
||||
*Новая модель памяти и трансляции* (только видеокарты AMD); без него игра работает со старой
|
||||
моделью памяти, как в 0.3.
|
||||
- память и работа видеочипа на AMD по умолчанию устроены как у игры для ПК (новая модель памяти
|
||||
и трансляции); NVIDIA и другие видеокарты пока работают со старой моделью памяти, как в 0.3.
|
||||
В лаунчере *Модель памяти* переключается в обе стороны.
|
||||
|
||||
До полной модели Wine + DXVK осталось два шага: довести новый режим до режима по умолчанию и
|
||||
перенести чтение дескрипторов ресурсов (текстур, буферов) с процессора на видеочип (см. ниже).
|
||||
До полной модели Wine + DXVK остался один шаг: новая модель и на NVIDIA, затем удаление старой
|
||||
модели памяти (см. ниже).
|
||||
|
||||
> **Файлов игры в репозитории нет.** Нужен свой дамп Bloodborne (CUSA03173, v1.09).
|
||||
> **Файлов игры в репозитории нет.** Нужен свой дамп Bloodborne с обновлением 1.09: любое издание
|
||||
> из магазина (CUSA00900 в США, CUSA03173 — европейское Game of the Year, ...): у них один и тот же
|
||||
> исполняемый файл.
|
||||
> Проект не связан с Sony Interactive Entertainment, FromSoftware и AMD.
|
||||
|
||||
**Состояние: экспериментальный, играбельный.** Игра запускается, загружает сохранения и
|
||||
@@ -36,22 +38,30 @@ bbport — это аналог Wine + DXVK, только для одной иг
|
||||
- **Нативное исполнение.** eboot заранее превращается в плоский образ памяти, в который как
|
||||
нативный код прилинкованы libc и libSceFios2 из PS4. Никакой эмуляции процессора и
|
||||
трансляции инструкций: код игры работает на полной скорости.
|
||||
- **Два режима работы** (лаунчер → *Режим работы*):
|
||||
- **Переключатель выключен (по умолчанию) — как в 0.3.** Старая модель памяти: копии памяти
|
||||
- **Две модели памяти** (лаунчер → *Режим работы → Модель памяти и трансляции*; *Авто*, по
|
||||
умолчанию, выбирает по видеокарте):
|
||||
- **Старая модель памяти, как в 0.3, — по умолчанию на NVIDIA, Intel и других.** Копии памяти
|
||||
игры в VRAM, записи отслеживаются защитой страниц. Со всеми исправлениями после 0.3
|
||||
(векторы движения и апскейлер, мерцание при включённом DoF, повреждённый кэш шейдеров).
|
||||
- **Новая модель памяти и трансляции — экспериментальная, только видеокарты AMD.** Память
|
||||
- **Новая модель памяти и трансляции — по умолчанию на AMD.** Память
|
||||
игры находится в оперативной памяти, и GPU читает её на месте, как буферы игры для ПК; то,
|
||||
что он читает часто, держится в видеопамяти и освобождается, когда перестаёт использоваться
|
||||
(текстуры — через 20 с, буферы — через 60 с). Нет отслеживания записей и копий всей памяти,
|
||||
видимой GPU. Работа командного процессора PS4 переводится в команды Vulkan, а не
|
||||
(текстуры — через 20 с, буферы — через 60 с). Модуль памяти прослойки отслеживает записи CPU
|
||||
в блоки с зеркалами для согласования данных; вся память, видимая GPU, не копируется.
|
||||
Работа командного процессора PS4 переводится в команды Vulkan, а не
|
||||
эмулируется на процессоре: записи в память (`WRITE_DATA`, DMA) выполняет видеочип в порядке
|
||||
потока команд, метки (fences) пишутся, когда видеочип действительно закончил работу.
|
||||
Где игра упирается в процессор, FPS выше на 20–25 % (замер на месте в Сне Охотника), рывков
|
||||
меньше. **Может вылетать**; основательно проверена только на ПК автора (RX 7800 XT). На
|
||||
NVIDIA и Intel переключатель недоступен: драйвер NVIDIA не отображает память игры нужным
|
||||
образом, Intel не проверялся. Без лаунчера — `BB_PC_MODEL=1`; попробовать на другой
|
||||
видеокарте — `BB_PC_MODEL_ANY_GPU=1`.
|
||||
потока команд, метки (fences) пишет сам видеочип в конце конвейера, в той же точке потока,
|
||||
что и командный процессор PS4.
|
||||
На AMD память игры держится в sparse-буфере (арене); на NVIDIA, Intel и других — через модуль
|
||||
памяти прослойки: привязывается на месте, копии в VRAM — отдельные буферы, без
|
||||
sparse-перепривязок (на NVIDIA sparse binding держал видеочип секундами); `BB_LAYER_MEMORY=1/0`
|
||||
— выбрать вручную. Проверено на RX 7800 XT. На NVIDIA её можно выбрать
|
||||
вручную (*Новая*); у тестеров результат зависит от сцены, в части сцен медленнее старой
|
||||
модели, поэтому там она пока не по умолчанию. На Intel не проверялась. Без лаунчера —
|
||||
`BB_PC_MODEL=1/0` (не задано — по видеокарте, как *Авто*).
|
||||
|
||||
[Изменения в 0.5](docs/CHANGES_0.5.md); пререлизы: [pre4](docs/CHANGES_0.5-pre4.md),
|
||||
[pre3](docs/CHANGES_0.5-pre3.md), [pre2](docs/CHANGES_0.5-pre2.md).
|
||||
|
||||
Неиспользуемые текстуры освобождаются в обоих режимах, поэтому видеопамять больше не растёт
|
||||
с каждой локацией.
|
||||
@@ -79,9 +89,11 @@ bbport — это аналог Wine + DXVK, только для одной иг
|
||||
привязка ресурсов и запись draw — в другом (двухстадийный конвейер), плюс отдельный поток
|
||||
записи команд Vulkan и вспомогательные потоки для копий памяти. В начале проекта единственный
|
||||
поток GPU ограничивал игру ~26 FPS; сейчас 90–150 FPS в зависимости от разрешения и сцены.
|
||||
- **Меню в игре** (Insert или L3+R3): апскейлер, пресет, резкость, разрешение вывода, эффекты
|
||||
игры (аберрация, DoF, размытие в движении, SSAO, сглаживание игры, SSR, детализация моделей).
|
||||
Открывается там, где его оставили, курсор мыши над ним виден.
|
||||
- **Настройки в меню самой игры:** *Система → Изображение / Эффекты* (после *Экран/звук*) — их
|
||||
строит и рисует сама игра: разрешение вывода, апскейлер, пресет, резкость, счётчик FPS,
|
||||
детализация моделей и эффекты игры, на языке игры.
|
||||
- **Меню поверх игры** (Insert или L3+R3) в стиле диалогов игры: всё то же и расширенные
|
||||
настройки; геймпад, клавиатура и мышь.
|
||||
- **Лаунчер на GTK4** и **AppImage** для Steam Deck.
|
||||
|
||||
## Чем отличается от shadPS4
|
||||
@@ -90,7 +102,7 @@ bbport — это аналог Wine + DXVK, только для одной иг
|
||||
|---|---|---|
|
||||
| Охват | Универсальный эмулятор PS4, много игр | Одна игра: Bloodborne v1.09 |
|
||||
| Загрузка | Свой ELF-загрузчик и эмуляция ядра во время работы | eboot заранее превращается (`scripts/`) в образ с прилинкованными libc/Fios2 PS4; загрузчик на C отображает его и передаёт управление игре (загрузчик и рантайм — ~5 тыс. строк) |
|
||||
| Память | Вид памяти PS4 со стороны GPU хранится копиями в VRAM, синхронизация через отслеживание записей защитой страниц | По умолчанию та же модель (как в 0.3); в режиме *Новая модель памяти и трансляции* (AMD): память игры в оперативной памяти, GPU использует её на месте, часто читаемое — в VRAM, освобождается, когда не нужно |
|
||||
| Память | Вид памяти PS4 со стороны GPU хранится копиями в VRAM, синхронизация через отслеживание записей защитой страниц | По умолчанию та же модель (как в 0.3); в режиме *Новая модель памяти и трансляции*: память игры в оперативной памяти, GPU использует её на месте, часто читаемое — в VRAM, освобождается, когда не нужно |
|
||||
| Командный процессор | Эмулируется: записи в память, DMA и метки выполняет процессор во время разбора команд | По умолчанию так же; в новом режиме переводится в команды Vulkan, их выполняет видеочип в порядке потока, метки — после реального завершения работы |
|
||||
| Системные библиотеки | Широкий HLE ОС PS4 | Небольшой рантайм (`src/runtime_*.c`) ровно под то, что вызывает Bloodborne: память, потоки, синхронизация, файлы, звук (включая ATRAC9), геймпад, сохранения, AppContent |
|
||||
| GPU | Видеоядро и рекомпилятор шейдеров shadPS4 | То же ядро (вложено, GPL) с ~200 помеченными правками (`bbport:`) и новыми модулями: двухстадийный конвейер draw, мемоизация состояния прохода и наборов текстур, уменьшенные цели сцены, векторы движения, FSR 3.1/4/4.1.1, захват кадра, профайлер GPU |
|
||||
@@ -108,15 +120,18 @@ bbport — это аналог Wine + DXVK, только для одной иг
|
||||
реализует ровно те функции ОС PS4, которые вызывает Bloodborne: память, потоки, файлы, звук,
|
||||
геймпад, сохранения.
|
||||
- **Память.** В новом режиме — как у игры для ПК: данные игры в оперативной памяти, видеопамять
|
||||
используется так, как её использует игра для ПК. Пока режим экспериментальный и работает только
|
||||
на видеокартах AMD.
|
||||
используется так, как её использует игра для ПК. Пока режим экспериментальный.
|
||||
- **Графика.** Поток команд видеочипа PS4 (PM4) — это записанные вызовы графического API игры:
|
||||
его пишут 99 функций статически слинкованной libGnm, так что разбор потока и перевод самих
|
||||
вызовов дают одно и то же. Шейдеры GCN переводятся в SPIR-V. В новом режиме работа командного
|
||||
процессора (записи в память, DMA, метки) тоже переводится в команды Vulkan. По-старому
|
||||
осталось одно: дескрипторы ресурсов (текстур, буферов) транслятор читает из памяти игры на
|
||||
процессоре, а текстуры узнаёт по адресу. Следующий большой шаг — чтение дескрипторов
|
||||
видеочипом (bindless) и текстуры как объекты, которые создаются при загрузке.
|
||||
процессора (записи в память, DMA, метки) тоже переводится в команды Vulkan; метки пишет сам
|
||||
видеочип. Дескрипторы ресурсов (текстур, буферов) транслятор читает на процессоре, как DXVK
|
||||
читает привязки ресурсов: текстуру PS4 нужно перевести из раскладки PS4 в образ Vulkan до
|
||||
отрисовки, поэтому процессор должен знать её дескриптор заранее — это трансляция, а не
|
||||
эмуляция. Таблицы дескрипторов (дампы движка констант) читает только транслятор, поэтому их
|
||||
выполняет процессор. Occlusion-запросы игры (~60 за кадр) — настоящие запросы Vulkan; предикация, `COPY_DATA`,
|
||||
`COND_EXEC` тоже переводятся (проверка — `BB_PM4_SELFTEST=1`).
|
||||
Подробно — [docs/EMULATION_REMOVAL_PLAN.ru.md](docs/EMULATION_REMOVAL_PLAN.ru.md), «Шаг 4».
|
||||
|
||||
«Порт» здесь — сборка под одну игру, а не переписанный исходный код: исходного кода игры у
|
||||
проекта нет, и он его не содержит.
|
||||
@@ -124,7 +139,7 @@ bbport — это аналог Wine + DXVK, только для одной иг
|
||||
## Требования
|
||||
|
||||
- Linux x86-64, видеокарта с Vulkan 1.3. Проверено: AMD RX 7800 XT, Mesa 26 (RADV).
|
||||
Режим *Новая модель памяти и трансляции* — только видеокарты AMD.
|
||||
Режим *Новая модель памяти и трансляции* на NVIDIA пока не проверен.
|
||||
FSR 4 / 4.1.1 требуют shader Float16, Int8/Int16, целочисленных dot-произведений,
|
||||
linear compute derivatives и extended storage image formats; FSR 4.1.1 дополнительно
|
||||
требует `VK_VALVE_shader_mixed_float_dot_product`. Неподдерживаемый вариант заменяется
|
||||
@@ -133,13 +148,16 @@ bbport — это аналог Wine + DXVK, только для одной иг
|
||||
Дамп обновления — отдельная папка: скопируйте её поверх базовой игры с заменой файлов. Одна
|
||||
базовая игра (1.00) падает при запуске (guest offset 0x20348b8); лаунчер и `run.sh` проверяют
|
||||
исполняемый файл и пишут, чего не хватает (`BB_SKIP_GAME_CHECK=1` отключает проверку).
|
||||
Другие издания (американское `CUSA00900`, азиатское `CUSA03023`, ...) запускают тот же
|
||||
исполняемый файл 1.09. В некоторых дампах в него уже вшит патч 60 FPS от Lance McDonald, из-за которого игра
|
||||
падает при открытии меню жестов: проверка тогда просит чистый eboot.bin (у bbport свои 60 FPS).
|
||||
- Для сборки: GCC, CMake, Ninja, Python 3, glslang, SDL3, заголовки Vulkan и библиотеки из
|
||||
`shell.nix`. С [Nix](https://nixos.org) всё берётся из `shell.nix` автоматически.
|
||||
|
||||
## Сборка и запуск
|
||||
|
||||
```bash
|
||||
git clone --recursive <этот репозиторий> bbport && cd bbport
|
||||
git clone --recursive https://github.com/deadinside28/bloodborne_pc.git bbport && cd bbport
|
||||
bash build.sh # собирает out/bb-probe и out/gpu/libbbgpu.so
|
||||
BB_GAME_DIR=/путь/к/CUSA03173 bash run.sh
|
||||
```
|
||||
@@ -156,7 +174,10 @@ SDL3 (если их несколько, нужный выбирается в л
|
||||
`BB_GAMEPAD=<GUID или часть имени>`). Клавиатура тоже работает, и при подключённом геймпаде
|
||||
(на Steam Deck он есть всегда); обе раскладки меняются в лаунчере (*Управление*). Имя персонажа
|
||||
вводится с клавиатуры в окне поверх игры. Тачпад: левая половина (Tab, Back/Select) открывает
|
||||
жесты, правая (Backspace) — личные вещи.
|
||||
жесты, правая (Backspace) — личные вещи. PSN нет: экран «Играть по сети / вне сети» пропускается,
|
||||
игра сразу открывает главное меню вне сети (патч игры; в лаунчере *Эффекты игры → Пропускать
|
||||
выбор «по сети / вне сети»*, `BB_SKIP_NETWORK_CHOICE=0` — показывать). При нескольких мониторах нужный выбирается в
|
||||
лаунчере: *Экран → Монитор* (`BB_DISPLAY=<номер или часть имени>`).
|
||||
|
||||
**Смена разрешения и пресетов:** для вывода не 1080p (720p на Steam Deck, 1440p, 4K) вся игра
|
||||
рисуется в разрешении пресета, которое задаёт патч при запуске, — это самый быстрый путь.
|
||||
@@ -178,8 +199,11 @@ Turing). Вывод 1080p и TAA всегда идут живым путём.
|
||||
папкой-обёрткой или сразу с папками игры вроде `chr/`; регистр имён не важен), с переключателями
|
||||
и порядком загрузки. **Сторонние патчи:** XML-файлы в формате shadPS4 в папке `patches/` каталога
|
||||
данных, включаются в лаунчере. Подробнее — [моды и патчи](docs/MODS.md).
|
||||
**DLC:** дампы дополнений клади в `user/addcont/<title id>/<метка>/` (как в shadPS4, например
|
||||
`user/addcont/CUSA03173/SPEXPANSIONDLC03` для The Old Hunters): каждая такая папка сообщается
|
||||
игре как установленное дополнение.
|
||||
|
||||
**Язык лаунчера:** русский или английский (по умолчанию — как в системе).
|
||||
**Язык лаунчера:** русский, английский, бразильский португальский или упрощённый китайский (по умолчанию — как в системе).
|
||||
|
||||
**Свободная камера и debug menu игры** (v1.09): включи соответствующие галочки в лаунчере
|
||||
или игровом меню и перезапусти игру. Для камеры используется
|
||||
@@ -225,6 +249,31 @@ Experimental от октября 2026; Proton 11.0 из Steam и GE-Proton 9 —
|
||||
там FSR 4.1, собери на ПК и скопируй папку `fsr4_411`. То же из командной строки:
|
||||
`--build-fsr411 <DLL>` у лаунчера (и у AppImage).
|
||||
|
||||
**DLSS (NVIDIA GeForce RTX).** SDK DLSS от NVIDIA не входит в репозиторий: скачай
|
||||
[github.com/NVIDIA/DLSS](https://github.com/NVIDIA/DLSS) (достаточно `include/` и
|
||||
`lib/Linux_x86_64`) и собери с `DLSS_SDK_ROOT=/путь/к/DLSS bash build.sh`. Тогда собирается и мост
|
||||
`out/libbbport_dlss.so` (`gpu/dlss_bridge`, единственный код, использующий SDK), а
|
||||
`libnvidia-ngx-dlss.so.<версия>` от NVIDIA копируется рядом с `out/bb-probe`; остальное даёт
|
||||
драйвер. Затем выбери *DLSS* в лаунчере или во внутриигровом меню: пресет задаёт разрешение
|
||||
рендера, Native AA — это DLAA. DLSS получает те же входы, что и FSR 3.1 (цвет сцены, глубину,
|
||||
векторы движения, jitter). Без библиотек, на других видеокартах или с `BB_DLSS=0` он недоступен,
|
||||
а выбранный DLSS заменяется на FSR 3.1.
|
||||
|
||||
На Linux DLSS также нужен CUDA/UVM из драйвера NVIDIA. Если устройство не создаётся с
|
||||
расширениями DLSS, рендерер повторяет попытку без них и использует FSR 3.1. Если отсутствует
|
||||
`/dev/nvidia-uvm`, загрузи установленный модуль командой `sudo modprobe nvidia_uvm` и перезапусти
|
||||
игру. Пакет `nvidia-modprobe` из репозитория дистрибутива позволяет библиотекам NVIDIA загружать
|
||||
модуль по мере необходимости.
|
||||
Если при включённом Secure Boot команда `modprobe` сообщает `Key was rejected by service`,
|
||||
зарегистрируй ключ подписи модуля по [процедуре MOK своего дистрибутива](https://documentation.ubuntu.com/security/security-features/platform-protections/secure-boot/#mok-generation-and-signing-process).
|
||||
|
||||
AppImage, собранный с `DLSS_SDK_ROOT`, содержит мост и библиотеку NVIDIA (лицензия RTX SDK от NVIDIA
|
||||
это разрешает в составе приложения; её текст — `NVIDIA-DLSS-LICENSE.txt` в пакете). Более новая
|
||||
`libnvidia-ngx-dlss.so.<версия>` (из `lib/Linux_x86_64/rel` в SDK) выбирается в лаунчере:
|
||||
*Апскейлер → DLSS: библиотека NVIDIA → Выбрать файл…*, как DLL для FSR 4.1.1; она копируется в
|
||||
`<user>/dlss/`, и игра берёт её первой. `nvngx_dlss.dll` из игр — библиотека для Windows: драйвер
|
||||
NVIDIA на Linux её не загружает.
|
||||
|
||||
Скрипт из исходников берёт инструменты из системы (MinGW GCC, CMake, Ninja, Python 3,
|
||||
SPIRV-Tools, Git) или из Nix; в AppImage они уже собраны.
|
||||
|
||||
@@ -263,7 +312,9 @@ Vulkan-драйвер и подключает его вместе с компл
|
||||
дистрибутивах они доступны в `/usr/lib*`; на NixOS внутренний `/nix/store` AppImage может скрывать
|
||||
драйвер хоста. В этом случае библиотеки NVIDIA нужно скопировать в доступную папку и указать
|
||||
`BB_NVIDIA_LIB_DIR=/путь/к/библиотекам` (манифест NVIDIA тоже должен быть доступен).
|
||||
Явные `VK_DRIVER_FILES`/`VK_ICD_FILENAMES` сохраняются. Проверка драйвера внутри пакета:
|
||||
С драйвером NVIDIA хоста AppImage передаёт и файлы EGL-вендоров хоста, NVIDIA первым
|
||||
(`__EGL_VENDOR_LIBRARY_FILENAMES`; без них ICD NVIDIA на некоторых системах не отдавал
|
||||
`vkCreateInstance`, #107; `BB_NVIDIA_EGL=0` — выключить). Явные `VK_DRIVER_FILES`/`VK_ICD_FILENAMES` сохраняются. Проверка драйвера внутри пакета:
|
||||
|
||||
```bash
|
||||
./Bloodborne-bbport-x86_64.AppImage --vulkan-info 2>&1 | tee bbport-vulkan.log
|
||||
@@ -279,8 +330,8 @@ MangoHud включён в AppImage; включи его галочку в ла
|
||||
с `VK_LOADER_LAYERS_DISABLE=~implicit~` отключает и MangoHud.
|
||||
|
||||
Полезные переменные: `BB_FRAME_STATS=1` (статистика кадров, в том числе строка `Memory:` —
|
||||
VRAM, GTT, RSS, текстуры и блоки памяти игры в VRAM), `BB_PC_MODEL=1` (новая модель памяти и трансляции,
|
||||
только AMD; по умолчанию 0 — старая модель, как в 0.3), `BB_ANISO=N` (анизотропная фильтрация текстур сцены; по умолчанию
|
||||
VRAM, GTT, RSS, текстуры и блоки памяти игры в VRAM), `BB_PC_MODEL=1` (новая модель памяти и трансляции;
|
||||
по умолчанию 0 — старая модель, как в 0.3), `BB_ANISO=N` (анизотропная фильтрация текстур сцены; по умолчанию
|
||||
16, 0 — как в игре),
|
||||
`BB_GC_IDLE_SECONDS=N` / `BB_VRAM_IDLE_SECONDS=N` (сколько неиспользуемые текстуры / буферы
|
||||
остаются в VRAM; 20 / 60), `BB_BREADCRUMBS=0` (без меток GPU; с ними зависание видеокарты
|
||||
@@ -290,7 +341,9 @@ VRAM, GTT, RSS, текстуры и блоки памяти игры в VRAM), `
|
||||
ограничения), `BB_PRESENT_THREAD=0` (показ в потоке vblank, как раньше), `BB_LIVE_RES=1` (смена
|
||||
разрешения без перезапуска вместо патча при запуске для вывода не 1080p),
|
||||
`BB_PAD_RECORD=файл` / `BB_PAD_REPLAY=файл` (запись маршрута по F9 и его повтор в тестах),
|
||||
`BB_GC_BUDGET_MB=N` (бюджет кэша текстур, как на встроенных GPU), `BB_PRESENT_DUMP_TRIGGER=файл`
|
||||
`BB_GC_BUDGET_MB=N` (бюджет кэша текстур, как на встроенных GPU), `BB_VRAM_LIMIT_MB=N` (бюджет
|
||||
VRAM считается не больше N МиБ: проверка поведения карт с малой VRAM), `BB_ASYNC_PIPELINES=0`
|
||||
(новые конвейеры компилируются сразу, игра ждёт; по умолчанию — в фоне), `BB_PRESENT_DUMP_TRIGGER=файл`
|
||||
с `BB_PRESENT_DUMP_COUNT=N` (снимок N показанных кадров подряд),
|
||||
`BB_FSR411_VARIANT=int8|fp8|fp8emu` (вариант FSR 4.1.1; по умолчанию FP8, где у видеокарты есть
|
||||
матрицы FP8), `BB_READBACKS=0|1|2` (чтение игрой памяти, записанной GPU: по умолчанию 1, 2 —
|
||||
@@ -298,6 +351,13 @@ VRAM, GTT, RSS, текстуры и блоки памяти игры в VRAM), `
|
||||
Подробнее — в [docs/](docs); последние изменения — [docs/CHANGES_0.4.md](docs/CHANGES_0.4.md),
|
||||
[docs/CHANGES_2026-10-06.md](docs/CHANGES_2026-10-06.md).
|
||||
|
||||
**Игра по сети (shadNet).** Отдельный модуль `out/gpu/libbbnet.so` (`gpu/bbnet`: сетевые и PSN-библиотеки
|
||||
shadPS4 из shadp2p, форка shadPS4, с клиентом shadNet); собирается, когда есть protobuf, nlohmann_json,
|
||||
OpenSSL, zlib и miniupnpc (`shell.nix`), входит в AppImage. Включается на странице лаунчера *Онлайн*
|
||||
(`BB_ONLINE=1`): сообщения, пятна крови и призраки — с The Hunter's Dream, колокола и призывы — через
|
||||
сервер shadNet (по умолчанию `srv.shadps4.net:31313`) с учётной записью shadNet (Online ID и пароль).
|
||||
Офлайн модуль не загружается; сборка без него играет только офлайн.
|
||||
|
||||
## Устройство репозитория
|
||||
|
||||
| Путь | Содержимое |
|
||||
@@ -316,17 +376,16 @@ VRAM, GTT, RSS, текстуры и блоки памяти игры в VRAM), `
|
||||
|
||||
## Что будет дальше
|
||||
|
||||
- Новая модель памяти и трансляции по умолчанию — когда она станет стабильной, в том числе на
|
||||
NVIDIA; после этого старая модель удаляется.
|
||||
- Дескрипторы ресурсов читает видеочип (bindless), текстуры — объекты, которые создаются при
|
||||
загрузке: без выполнения кода шейдеров и движка констант на процессоре и без кэша текстур по
|
||||
адресам.
|
||||
- Новая модель памяти и трансляции по умолчанию и на NVIDIA, когда она станет там не медленнее;
|
||||
после этого старая модель удаляется.
|
||||
- Текстуры — объекты, которые создаются при загрузке (меньше угадывания по адресам, загрузка
|
||||
вне кадра).
|
||||
- Шейдеры переводятся заранее, при установке, а не во время игры.
|
||||
- Больше параллельности CPU в обработке GPU-команд (дальнейшее разделение стадии записи draw)
|
||||
с масштабированием на все потоки — важнее всего для Steam Deck.
|
||||
- Async compute для апскейлера (в 4K кадр упирается в GPU).
|
||||
- XeSS (суперразрешение) и генерация кадров XeFG через помощник под Wine с общей памятью Vulkan
|
||||
(прототип моста памяти — `tools/bridge_helper`); DLSS для владельцев NVIDIA; входы апскейлера
|
||||
(прототип моста памяти — `tools/bridge_helper`); входы апскейлера
|
||||
в виде, совместимом с подходом OptiScaler.
|
||||
- Генерация кадров (сначала FSR 3.1 FG), маски реактивности и прозрачности для частиц и тумана.
|
||||
- Исправление гонок в шейдерах FSR 4.1.1 от AMD при ширине вывода, не кратной 64 (например,
|
||||
@@ -344,4 +403,8 @@ bbport распространяется по **GNU GPL v2 или новее** ([
|
||||
(MIT), [Dear ImGui](https://github.com/ocornut/imgui) (MIT), шрифты DejaVu,
|
||||
[dxil-spirv](https://github.com/HansKristian-Work/dxil-spirv) (MIT, для сборки ассетов FSR 4.1.1).
|
||||
Патчи игры — Kyo, Lance McDonald, auser1337, illusion, emoose и другие участники сообщества
|
||||
(`patches/Bloodborne.xml`). DLL и данные модели FSR 4 от AMD здесь не распространяются.
|
||||
(`patches/Bloodborne.xml`). Мост DLSS (`gpu/dlss_bridge`, MIT) и загрузчик взяты из
|
||||
[Windows-порта Supermedo](https://github.com/Supermedo/bloodborne_pc), адаптированного из
|
||||
[IFreemz/shadPS4-Bloodborne-DLSS-FSR](https://github.com/IFreemz/shadPS4-Bloodborne-DLSS-FSR).
|
||||
DLL и данные модели FSR 4 от AMD, а также SDK и библиотеки DLSS от NVIDIA здесь не
|
||||
распространяются.
|
||||
@@ -7,28 +7,39 @@ This fork builds on [bbport](https://github.com/deadinside28/bloodborne_pc), the
|
||||
by deadinside28. It adds the features of [Supermedo's Windows port](https://github.com/Supermedo/bloodborne_pc)
|
||||
(online play, DLSS, cheats) brought to Linux, plus a few of its own.
|
||||
|
||||
> **No game files are included.** You need your own decrypted dump of Bloodborne, US
|
||||
> (`CUSA03173`) or EU (`CUSA00900`), game version **1.09**. This project is not affiliated with
|
||||
> Sony Interactive Entertainment or FromSoftware.
|
||||
> **No game files are included.** You need your own decrypted dump of Bloodborne with update
|
||||
> 1.09, from a retail release: [which ones, and which have been checked](docs/COMPATIBILITY.md).
|
||||
> This project is not affiliated with Sony Interactive Entertainment or FromSoftware.
|
||||
|
||||
## Features
|
||||
|
||||
- **Online play (beta)** through [The Hunter's Dream](https://thehuntersdream.com) and shadNet:
|
||||
messages, bloodstains, ghosts, bells and summons. Linux and Windows players can play together.
|
||||
messages, bloodstains, ghosts, bells and summons. Linux and Windows players can play together,
|
||||
through shadPS4's public server or [one of your own](docs/SERVER.md).
|
||||
- **Upscaling:** AMD FSR 3.1, FSR 4 and FSR 4.1.1, **NVIDIA DLSS** on GeForce RTX, and
|
||||
native-resolution TAA.
|
||||
- **Unlocked frame rate**, capped at your display's refresh rate up to 120 FPS (above that the
|
||||
game's own movement timing breaks), or 30/60/90 FPS. Output from 720p to 4K.
|
||||
- **Launcher** with every setting in one window, in English, Spanish, Italian, French, German,
|
||||
Portuguese and Russian, like the in-game menu (Insert or L3+R3).
|
||||
- **Settings in the game's own System menu** as well (Display and Effects pages), in the game's
|
||||
language.
|
||||
- **Two memory models:** the new one, where the GPU works with the game's memory as in a PC game
|
||||
(the default on AMD), and the one of 0.3 (the default elsewhere); the launcher switches them.
|
||||
- **Xbox, Switch and keyboard button prompts**, picked by the controller in use, and a gestures
|
||||
menu without the motion-control icons.
|
||||
- **Cheats and gameplay tweaks:** never die, stealth, silent steps, enemy control, camera
|
||||
distance, ragdoll physics and more.
|
||||
- **Trophies:** a notice in the game, in the style of the PS4's, and a Trophies page in the
|
||||
launcher with every trophy, from your own dump. Their names and descriptions need the PS4's
|
||||
trophy key (shadPS4's TrophyKey), which you enter in the launcher; without it, only the icons.
|
||||
- **Game effects** on and off, **mods** and community **patches**, loaded without changing the
|
||||
game files.
|
||||
- **Add to Steam** in one click, and **Discord Rich Presence**.
|
||||
- **AppImage:** one file with everything inside, for any distribution and the Steam Deck.
|
||||
game files ([how](docs/MODS.en.md)).
|
||||
- **Add to Steam** in one click (native or Flatpak Steam), and **Discord Rich Presence** with the
|
||||
area you are in and your co-op partners.
|
||||
- **AppImage:** one file with everything inside, for any distribution and the Steam Deck. It
|
||||
updates itself: the launcher's **About** page checks this repository's releases and installs
|
||||
a new AppImage over the old one.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -65,14 +76,26 @@ With [Nix](https://nixos.org), `bash build.sh` gets every dependency from `shell
|
||||
|
||||
### Online play
|
||||
|
||||
1. Register a shadNet account at [shadnet.shadps4.net](https://shadnet.shadps4.net).
|
||||
2. In the launcher, open **Online**, turn on **Play online** and enter your account name (not
|
||||
your email) and password. **Test the connection**: all three servers should be reachable.
|
||||
1. Register a shadNet account at [shadnet.shadps4.net](https://shadnet.shadps4.net), or get one
|
||||
from the owner of your group's own server.
|
||||
2. In the launcher, open **Online**, turn on **Play online**, choose the shadNet server and enter
|
||||
your account name (not your email) and password. **Test the connection**: every line should
|
||||
be green.
|
||||
3. Start the game and choose online at the title screen.
|
||||
|
||||
Everyone in a session needs game version 1.09 and the same servers. Turn cheats off when you
|
||||
play with others.
|
||||
|
||||
**Co-op needs your own server for now:** shadPS4's public server does not answer on its UDP port,
|
||||
so summons do not connect through it (messages, bloodstains and ghosts do).
|
||||
[docs/SERVER.md](docs/SERVER.md) sets one up with Docker and Tailscale; it has been tested with a
|
||||
Linux and a Windows player.
|
||||
|
||||
Co-op connects the players directly over UDP. UPnP opens the port on the router by itself; with
|
||||
ufw or firewalld on, the launcher's **Online** page says so and gives the commands: pin the
|
||||
**Co-op port** (for example 3658), open it (`sudo ufw allow 3658/udp`), and for UPnP let the
|
||||
router's answers in (`sudo ufw allow from <router> proto udp`). [More in docs/ONLINE.md](docs/ONLINE.md).
|
||||
|
||||
### DLSS
|
||||
|
||||
On a PC with a GeForce RTX, run `bash tools/build_dlss.sh` once after `build.sh`. It downloads
|
||||
@@ -82,10 +105,21 @@ upscaler.
|
||||
### DLC
|
||||
|
||||
The Game of the Year edition (`CUSA03173`) already includes The Old Hunters. With the base game
|
||||
(such as the EU `CUSA00900`), dump your add-ons too: each one is a folder (`SPEXPANSIONDLC03`,
|
||||
(such as the US `CUSA00900`), dump your add-ons too: each one is a folder (`SPEXPANSIONDLC03`,
|
||||
`SPDLCMESSENGER00`…) with only `sce_sys` inside, because their data ships with the 1.09 update.
|
||||
Put them in one folder and pick it in the launcher (**Game → DLC folder**), or set
|
||||
`BB_DLC_DIR=/path/to/dlc` for `run.sh`. The launcher shows how many it found.
|
||||
`BB_DLC_DIR=/path/to/dlc` for `run.sh`; the launcher shows how many it found. Each folder must
|
||||
keep the add-on's name (its entitlement label, such as `SPEXPANSIONDLC03`). Copying them to
|
||||
`user/addcont/<title id>/`, shadPS4's layout, works too.
|
||||
|
||||
### Add to Steam
|
||||
|
||||
**Game → Add to Steam** puts Bloodborne in your Steam library; it starts with the launcher's
|
||||
settings. Steam has to be closed while the game is added, and the launcher offers to do that.
|
||||
Flatpak Steam runs games inside its sandbox, which has neither the game nor your drivers, so
|
||||
the shortcut starts the game outside it with `flatpak-spawn --host`. That needs the
|
||||
`org.freedesktop.Flatpak` permission for Steam, which the launcher asks for once: it lets Steam
|
||||
start programs on your system.
|
||||
|
||||
### Button prompts
|
||||
|
||||
@@ -96,6 +130,11 @@ Keyboard**. **Gestures menu without motion-control icons** cleans up the gesture
|
||||
prompts are put into your own game's menu files at each start, and nothing in the game folder
|
||||
changes.
|
||||
|
||||
## Support
|
||||
|
||||
If this fork is useful to you and you would like to support it, you can on
|
||||
[Ko-fi](https://ko-fi.com/ayozetr). The port itself is deadinside28's work (see below).
|
||||
|
||||
## Credits
|
||||
|
||||
- [deadinside28/bloodborne_pc](https://github.com/deadinside28/bloodborne_pc): **bbport**, the
|
||||
|
||||
@@ -34,19 +34,41 @@ mkdir -p pgo
|
||||
if [[ ! -f gpu/third_party/fsr-vulkan/CMakeLists.txt || ! -f gpu/third_party/imgui/imgui.h ]]; then
|
||||
git submodule update --init --recursive
|
||||
fi
|
||||
for patch in gpu/patches/fsr-vulkan/*.patch; do
|
||||
if ! git -C gpu/third_party/fsr-vulkan apply --reverse --check "$PWD/$patch" 2>/dev/null; then
|
||||
git -C gpu/third_party/fsr-vulkan apply "$PWD/$patch"
|
||||
fi
|
||||
done
|
||||
# Issue #124: a checkout updated from an earlier version keeps that version's patch applied, and
|
||||
# the new one applies neither way ("patch does not apply"): the submodule's tree holds nothing but
|
||||
# these patches, so it is reset and they are applied again.
|
||||
fsr_patches_apply() {
|
||||
for patch in gpu/patches/fsr-vulkan/*.patch; do
|
||||
if ! git -C gpu/third_party/fsr-vulkan apply --reverse --check "$PWD/$patch" 2>/dev/null; then
|
||||
git -C gpu/third_party/fsr-vulkan apply "$@" "$PWD/$patch" || return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
if ! fsr_patches_apply --check 2>/dev/null; then
|
||||
echo 'FSR-Vulkan: an earlier version of the port changed it; resetting it and patching again'
|
||||
git -C gpu/third_party/fsr-vulkan checkout -- .
|
||||
fi
|
||||
fsr_patches_apply
|
||||
cmake -S gpu -B out/gpu -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBB_PGO="$pgo" \
|
||||
-DBB_LTO="${BB_LTO:-ON}" -DBB_PGO_DIR="$PWD/pgo" >/dev/null
|
||||
echo "GPU library: PGO $pgo, LTO ${BB_LTO:-ON}"
|
||||
# A failed GPU build must stop here: an older libbbgpu.so would otherwise be used silently.
|
||||
if ! ninja -C out/gpu bbgpu > out/gpu-build.log 2>&1; then
|
||||
if ! ninja -C out/gpu bbgpu $(grep -q "^build bbnet:" out/gpu/build.ninja && echo bbnet) > out/gpu-build.log 2>&1; then
|
||||
grep -v '^\[' out/gpu-build.log | tail -40 >&2
|
||||
echo 'GPU library build failed (full log: out/gpu-build.log)' >&2; exit 1
|
||||
fi
|
||||
# Optional DLSS (NVIDIA RTX): DLSS_SDK_ROOT=<github.com/NVIDIA/DLSS checkout> builds the bridge
|
||||
# (gpu/dlss_bridge, the only code using NVIDIA's SDK) and puts it next to bb-probe with NVIDIA's
|
||||
# libnvidia-ngx-dlss.so. Without them the DLSS upscaler is listed as unavailable.
|
||||
if [[ -n ${DLSS_SDK_ROOT:-} ]]; then
|
||||
cmake -S gpu/dlss_bridge -B out/dlss-bridge -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DDLSS_SDK_ROOT="$DLSS_SDK_ROOT" >/dev/null
|
||||
ninja -C out/dlss-bridge >/dev/null
|
||||
rm -f out/libnvidia-ngx-dlss.so.*
|
||||
cp out/dlss-bridge/libbbport_dlss.so "$DLSS_SDK_ROOT"/lib/Linux_x86_64/rel/libnvidia-ngx-dlss.so.* out/
|
||||
cp "$DLSS_SDK_ROOT/LICENSE.txt" out/NVIDIA-DLSS-LICENSE.txt
|
||||
echo "DLSS bridge: out/libbbport_dlss.so"
|
||||
fi
|
||||
# $ORIGIN/gpu: packaged copies keep the library next to the binary without patching it.
|
||||
gpu=(-Lout/gpu -lbbgpu -Wl,-rpath,'$ORIGIN/gpu' -Wl,-rpath,"$PWD/out/gpu" -rdynamic)
|
||||
runtime=(src/runtime*.c)
|
||||
@@ -74,5 +96,4 @@ if [[ ${1:-} == --test ]]; then
|
||||
out/online-test
|
||||
"$CC" -std=c11 -D_GNU_SOURCE -O2 -g -Wall -Wextra -Werror -I. -Isrc tests/test_content.c src/runtime_content.c -o out/content-test
|
||||
out/content-test
|
||||
out/content-test --addons
|
||||
fi
|
||||
@@ -0,0 +1,107 @@
|
||||
# 0.5-pre2 — pre-release for testing
|
||||
|
||||
Second 0.5 prerelease, built from the `testing` branch. This release focuses on the experimental
|
||||
memory and GPU command translation path. Changes are listed relative to
|
||||
[0.5-pre1](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre1).
|
||||
|
||||
## English
|
||||
|
||||
- **New memory module for NVIDIA and other non-AMD GPUs.** When the experimental mode is enabled,
|
||||
the layer binds chunks of game memory directly and keeps frequently used data in separate VRAM
|
||||
buffers. It does not use `vkQueueBindSparse`. The launcher now exposes the mode on all GPU
|
||||
vendors; the startup capability check is retained. AMD still selects the sparse arena by
|
||||
default within this mode; `BB_LAYER_MEMORY=1` selects the new module manually.
|
||||
- **Memory coherence fixes.** CPU writes to mirrored blocks are tracked selectively. Buffer
|
||||
bindings and command-processor copies use the current GPU data, CPU writes invalidate stale
|
||||
GPU ownership, and mixed ranges can use refreshed VRAM fringes. Promotion respects the VRAM
|
||||
budget, and cached binding decisions reduce repeated checks and locking.
|
||||
- **Original GPU copy shader enabled by default in the new model.** The game's copy shader is
|
||||
translated to SPIR-V and reads its copy list on the GPU. Its writes update both the current
|
||||
GPU view and game memory, keeping VRAM mirrors and CPU consumers consistent.
|
||||
`BB_COPY_SHADER_NATIVE=0` retains the HLE path for comparison.
|
||||
- **Portable GPU completion labels.** Supported EOP/EOS/RELEASE_MEM labels can be written by
|
||||
standard Vulkan commands on GPUs without `VK_AMD_buffer_marker`. Prior GPU results become
|
||||
visible before the completion label; the AMD fast path remains available. The portable path
|
||||
can be forced for testing with `BB_GPU_LABELS_PORTABLE=1`.
|
||||
- **Synchronization and bounds fixes.** Corrected update/inline-data stage dependencies and
|
||||
index-buffer read tracking. Paged buffer accesses reject invalid ranges before accessing the
|
||||
page table. Vulkan initialization also enables the required surface extension for headless
|
||||
validation.
|
||||
- **Shader-cache migration.** The shader binary format is now version 9. Binary, metadata and
|
||||
pipeline versions are checked together before loading the cache, preventing old and new
|
||||
shader variants from being mixed. AppImage startup chooses the GPU cache directory before
|
||||
loading the GPU library, following the selected user-data directory.
|
||||
- **Regression checks.** Added GPU tests for paged copies, mirror/guest writes, range guards and
|
||||
32/64-bit portable labels. The PM4 occlusion check now spans multiple submissions to avoid
|
||||
false failures when a single submission contains no draws.
|
||||
|
||||
**How to test:** enable *New memory and translation model* in the launcher, or set
|
||||
`BB_PC_MODEL=1`. The experimental mode remains **off by default**. For testing the new module
|
||||
on AMD, also set `BB_LAYER_MEMORY=1`.
|
||||
|
||||
**Validation and limits:** runtime tests, packaged Vulkan-driver discovery tests, the new GPU
|
||||
tests and all eight in-game PM4 checks passed. GPU and AppImage checks used an RX 7800 XT/RADV;
|
||||
the portable label path was forced on AMD. Physical NVIDIA/Intel hardware and NVIDIA host-memory
|
||||
import have not been tested. Full-game Vulkan validation still reports graphics-pipeline and
|
||||
image-layout errors. A consistent FPS improvement over the previous copy path has not been
|
||||
established, and long gameplay sessions still need testing.
|
||||
|
||||
The earlier 0.5 changes remain included: settings in the game's System menu, display/monitor
|
||||
selection, effect and patch controls, the updated overlay, launcher log export, Chinese
|
||||
translation, DLC add-on folders and atomic save-file writes. See the
|
||||
[0.5-pre1 notes](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre1) for details.
|
||||
|
||||
The AppImage contains no game files. Proprietary FSR 4 model assets and NVIDIA's DLSS SDK/libraries
|
||||
are not bundled. `SHA256SUMS` accompanies the download.
|
||||
|
||||
## Русский
|
||||
|
||||
- **Новый модуль памяти для NVIDIA и остальных не-AMD GPU.** При включённом экспериментальном
|
||||
режиме прослойка привязывает куски памяти игры напрямую и держит часто используемые данные
|
||||
в отдельных буферах VRAM. `vkQueueBindSparse` не используется. Переключатель в лаунчере
|
||||
доступен для всех производителей GPU, стартовая проверка возможностей драйвера сохранена.
|
||||
На AMD внутри нового режима по умолчанию остаётся sparse-арена; новый модуль можно выбрать
|
||||
через `BB_LAYER_MEMORY=1`.
|
||||
- **Согласование памяти CPU и GPU.** Записи CPU в блоки с зеркалами отслеживаются выборочно.
|
||||
Привязки буферов и копии командного процессора используют актуальные данные GPU; новые записи
|
||||
CPU снимают устаревшие пометки GPU. Смешанные диапазоны могут использовать обновляемые края
|
||||
зеркал VRAM. Переносы соблюдают бюджет видеопамяти, кэш решений уменьшает повторные проверки
|
||||
и блокировки.
|
||||
- **Оригинальный GPU copy shader по умолчанию в новой модели.** Шейдер игры транслируется
|
||||
в SPIR-V и сам читает список копий на видеокарте. Результат записывается и в актуальное
|
||||
GPU-представление, и в память игры: зеркала VRAM и потребители на CPU видят согласованные
|
||||
данные. `BB_COPY_SHADER_NATIVE=0` оставляет HLE для сравнения.
|
||||
- **Переносимые метки завершения GPU.** Поддерживаемые метки EOP/EOS/RELEASE_MEM записываются
|
||||
стандартными командами Vulkan на GPU без `VK_AMD_buffer_marker`. Предшествующие результаты
|
||||
GPU становятся видимыми до метки завершения. Быстрый путь AMD сохранён;
|
||||
`BB_GPU_LABELS_PORTABLE=1` принудительно выбирает переносимый путь для проверки.
|
||||
- **Синхронизация и границы доступа.** Исправлены зависимости update/inline data и учёт чтения
|
||||
index buffer. Недопустимые диапазоны отклоняются до обращения к таблице страниц. Для
|
||||
headless-проверки Vulkan включается необходимое расширение surface.
|
||||
- **Миграция кэша шейдеров.** Формат shader binary поднят до версии 9. Версии binary, metadata
|
||||
и pipeline проверяются вместе до загрузки кэша, чтобы старые и новые варианты шейдеров
|
||||
не смешивались. AppImage выбирает GPU-каталог до загрузки GPU-библиотеки, с учётом выбранного
|
||||
каталога пользовательских данных.
|
||||
- **Проверки регрессий.** Добавлены GPU-тесты копирования через таблицу страниц, записей
|
||||
в зеркало и память игры, границ доступа и переносимых 32/64-битных меток. PM4-проверка
|
||||
occlusion теперь охватывает несколько отправок команд, чтобы отправка без отрисовок
|
||||
не давала ложный FAIL.
|
||||
|
||||
**Как проверить:** включить *Новую модель памяти и трансляции* в лаунчере или задать
|
||||
`BB_PC_MODEL=1`. Экспериментальный режим по умолчанию **выключен**. Для нового модуля на AMD
|
||||
также нужен `BB_LAYER_MEMORY=1`.
|
||||
|
||||
**Проверки и ограничения:** пройдены тесты рантайма, поиска Vulkan-драйвера в пакете, новые
|
||||
GPU-тесты и все восемь PM4-проверок в игре. GPU и AppImage проверялись на RX 7800 XT/RADV;
|
||||
переносимые метки принудительно включались на AMD. Физические NVIDIA/Intel и импорт host memory
|
||||
на NVIDIA пока не проверены. Полная Vulkan-валидация игры ещё сообщает об ошибках графических
|
||||
конвейеров и раскладок изображений. Стабильный прирост FPS относительно предыдущего пути
|
||||
копирования не подтверждён; длительное прохождение также требует проверки.
|
||||
|
||||
Все изменения первого prerelease 0.5 включены: настройки в меню System самой игры, выбор
|
||||
дисплея/монитора, управление эффектами и патчами, обновлённый оверлей, экспорт логов лаунчера,
|
||||
китайский перевод, папки DLC и атомарная запись сохранений. Подробности — в
|
||||
[описании 0.5-pre1](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre1).
|
||||
|
||||
Игровых файлов в AppImage нет. Проприетарные модели FSR 4 и SDK/библиотеки DLSS не включены.
|
||||
К загрузке приложен `SHA256SUMS`.
|
||||
@@ -0,0 +1,103 @@
|
||||
# 0.5-pre3 — pre-release for testing
|
||||
|
||||
Third 0.5 prerelease, built from the `testing` branch. It addresses the first hardware logs of the
|
||||
new memory module on NVIDIA (GTX 1660 Ti laptop, 6 GB, driver 615.71). Changes are listed relative
|
||||
to [0.5-pre2](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre2). Details and
|
||||
measurements: [NVIDIA_MEMORY_MODEL.ru.md](NVIDIA_MEMORY_MODEL.ru.md).
|
||||
|
||||
## English
|
||||
|
||||
- **VRAM copies were disabled on NVIDIA.** The fixed-arena workaround for NVIDIA's sparse binding
|
||||
was also applied to the memory module, which has no sparse arena: it made no VRAM copies of the
|
||||
game's memory at all (10–15 FPS on the GTX 1660 Ti). The workaround no longer applies to the
|
||||
module; `BB_FIXED_ARENA=0` is no longer needed.
|
||||
- **One VRAM budget for textures and copies of the game's memory.** The texture collector counts
|
||||
all of our VRAM. On cards below ~9 GB its critical mark (3.9 GB on the 6 GB card) was below what
|
||||
the copies and the textures need together, so it kept evicting textures in use (155–1255 every
|
||||
5 s, stutters) while the copies kept growing up to 90 % of the driver's budget. Copies now stop
|
||||
384 MiB short of that mark; close to it the module frees room itself, first the unused room of
|
||||
its copies, then copies not used for 3 s (`BB_VRAM_PRESSURE_IDLE_SECONDS`).
|
||||
- **Fewer reallocations of VRAM copies.** A copy that met newly loaded data was replaced by a
|
||||
bigger one each time: loading a level allocated 15–27 GB for 1.3 GB of data, with up to 7.4 GB
|
||||
of VRAM in use at once, and streaming areas did the same while playing. A growing copy now gets
|
||||
room to grow (up to 64 MiB, `BB_LAYER_MIRROR_GROWTH_MB`): 5–10 GB, and the worst loading frame of
|
||||
a test route went from 555 to 87 ms (RX 7800 XT). Replaced copies are freed as soon as the GPU is
|
||||
done with them.
|
||||
- **Command-processor writes (WRITE_DATA)** update the VRAM copy as well, instead of sending the
|
||||
block back to system memory (with watched blocks, below, up to 2 GB a minute went back and forth).
|
||||
- **Watched blocks** (`BB_LAYER_WATCH`, on by default). Memory the CPU writes without announcing
|
||||
it was always read by the GPU from system memory, over the bus on NVIDIA. It now gets a VRAM
|
||||
copy for reading bindings too; a write trap catches the next CPU write and the block is uploaded
|
||||
again before its next use. This also replaces most volatile-block refreshes (RX 7800 XT:
|
||||
1.3 GB/s of copies → 36 MB/s; the NVIDIA log showed 455 MB/s). Blocks the CPU writes nearly every
|
||||
frame still stay in system memory: uploading them before draws ended render passes (GPU frame
|
||||
4.8 → 7.2 ms on the RX 7800 XT); `BB_LAYER_WATCH_HOT=1` turns that on for experiments.
|
||||
- **File reads retry on EFAULT** (a page protected again between the runtime's touch and the
|
||||
kernel's copy).
|
||||
- **Testing aids:** `BB_VRAM_LIMIT_MB=N` takes the driver's VRAM budget as at most N MiB (5600
|
||||
gives the texture-collector marks of a 6 GB card); `BB_RESIDENCY_MIX=1` also says why blocks are
|
||||
not watched; the `Layer memory:` lines report watched blocks and write traps by kind.
|
||||
|
||||
**How to test:** enable *New memory and translation model* in the launcher, or set
|
||||
`BB_PC_MODEL=1`; the mode remains **off by default**. Logs with `BB_FRAME_STATS=1
|
||||
BB_GPU_PROFILE=1` at one place, once as is, once with `BB_LAYER_WATCH=0` and once with the mode off,
|
||||
show where the time goes.
|
||||
|
||||
**Validation and limits:** RX 7800 XT/RADV (PCIe 3.0) with the memory module forced on and
|
||||
`BB_VRAM_LIMIT_MB=5600`: model of 0.3 ~195 FPS, module ~195–213 FPS (GPU 4.6–5.2 ms a frame; runs
|
||||
vary by about ±10 %), VRAM kept under the collector's critical mark, a recorded route without
|
||||
frames over 25 ms, a 3-minute walk without errors, unchanged images; runtime, unit (101) and GPU
|
||||
tests passed. Not tested on physical NVIDIA or Intel hardware: on AMD reads of the game's memory
|
||||
in place cost little, so whether NVIDIA now reaches the speed of the 0.3 model is not established.
|
||||
|
||||
The AppImage contains no game files. Proprietary FSR 4 model assets and NVIDIA's DLSS SDK/libraries
|
||||
are not bundled. `SHA256SUMS` accompanies the download.
|
||||
|
||||
## Русский
|
||||
|
||||
- **На NVIDIA не было копий в VRAM.** Обход sparse binding на NVIDIA («фиксированная арена»)
|
||||
применялся и к модулю памяти, у которого sparse-арены нет: модуль вообще не копировал память
|
||||
игры в VRAM (10–15 FPS на GTX 1660 Ti). Теперь обход на модуль не действует,
|
||||
`BB_FIXED_ARENA=0` больше не нужен.
|
||||
- **Общий бюджет VRAM для текстур и копий памяти игры.** Сборщик кэша текстур считает всю нашу
|
||||
VRAM. На картах меньше ~9 ГБ его критическая отметка (3,9 ГБ на 6 ГБ) оказалась ниже того, что
|
||||
нужно копиям и текстурам вместе: он постоянно выселял используемые текстуры (155–1255 за 5 с,
|
||||
фризы), а копии росли до 90 % бюджета драйвера. Теперь копии встают за 384 МиБ до отметки, а
|
||||
рядом с ней модуль сам освобождает место: сначала неиспользуемый запас своих копий, затем
|
||||
копии, не нужные 3 с (`BB_VRAM_PRESSURE_IDLE_SECONDS`).
|
||||
- **Меньше перевыделений копий.** Копия, к которой примыкали новые данные, каждый раз заменялась
|
||||
большей: загрузка уровня выделяла 15–27 ГБ на 1,3 ГБ данных, до 7,4 ГБ VRAM одновременно; то же
|
||||
при подгрузке районов во время игры. Растущая копия теперь получает запас под рост (до 64 МиБ,
|
||||
`BB_LAYER_MIRROR_GROWTH_MB`): 5–10 ГБ, худший кадр загрузки в тестовом маршруте 555 → 87 мс
|
||||
(RX 7800 XT). Заменённые копии освобождаются сразу, как только видеочип с ними закончил.
|
||||
- **Записи командного процессора (WRITE_DATA)** обновляют и копию в VRAM, а не возвращают блок
|
||||
в системную память (с наблюдаемыми блоками, ниже, туда и обратно ходило до 2 ГБ в минуту).
|
||||
- **Наблюдаемые блоки** (`BB_LAYER_WATCH`, по умолчанию включено). Память, в которую процессор
|
||||
пишет без предупреждения, видеочип всегда читал из системной памяти, на NVIDIA через шину.
|
||||
Теперь для читающих привязок у неё тоже есть копия в VRAM: ловушка записи ловит следующую
|
||||
запись процессора, и блок перезаливается перед следующим использованием. Это же заменило
|
||||
большую часть обновлений летучих блоков (RX 7800 XT: 1,3 ГБ/с копий → 36 МБ/с; в логе с NVIDIA
|
||||
было 455 МБ/с). Блоки, которые процессор пишет почти каждый кадр, остаются в системной памяти:
|
||||
их заливка перед отрисовками завершала render pass (кадр видеочипа 4,8 → 7,2 мс на RX 7800 XT);
|
||||
`BB_LAYER_WATCH_HOT=1` включает это для экспериментов.
|
||||
- **Чтение файлов повторяется при EFAULT** (страница снова защищена между касанием рантайма и
|
||||
копированием ядром).
|
||||
- **Для проверок:** `BB_VRAM_LIMIT_MB=N` — бюджет VRAM драйвера считается не больше N МиБ (5600
|
||||
даёт пороги сборщика текстур карты на 6 ГБ); `BB_RESIDENCY_MIX=1` объясняет, почему блоки не
|
||||
наблюдаются; строки `Layer memory:` показывают наблюдаемые блоки и срабатывания ловушек по видам.
|
||||
|
||||
**Как проверить:** включить *Новую модель памяти и трансляции* в лаунчере или задать
|
||||
`BB_PC_MODEL=1`; режим по-прежнему **выключен по умолчанию**. Логи с `BB_FRAME_STATS=1
|
||||
BB_GPU_PROFILE=1` в одном месте — как есть, с `BB_LAYER_WATCH=0` и с выключенным режимом —
|
||||
покажут, куда уходит время.
|
||||
|
||||
**Проверки и ограничения:** RX 7800 XT/RADV (PCIe 3.0), модуль памяти включён вручную,
|
||||
`BB_VRAM_LIMIT_MB=5600`: модель 0.3 ~195 FPS, модуль ~195–213 FPS (видеочип 4,6–5,2 мс за кадр;
|
||||
разброс между запусками около ±10 %), VRAM держится ниже критической отметки сборщика,
|
||||
записанный маршрут без кадров дольше 25 мс, 3 минуты прогулки без ошибок, картинка не
|
||||
изменилась; тесты рантайма, юнит-тесты (101) и GPU-тесты пройдены. На физических NVIDIA и Intel
|
||||
не проверялось: на AMD чтения памяти игры на месте почти бесплатны, поэтому достигает ли NVIDIA
|
||||
теперь скорости модели 0.3, не установлено.
|
||||
|
||||
Игровых файлов в AppImage нет. Проприетарные модели FSR 4 и SDK/библиотеки DLSS не включены.
|
||||
К загрузке приложен `SHA256SUMS`.
|
||||
@@ -0,0 +1,147 @@
|
||||
# 0.5-pre4 — pre-release for testing
|
||||
|
||||
Fourth 0.5 prerelease, built from the `testing` branch, after the first tests of 0.5-pre3 on
|
||||
NVIDIA (GTX 1060 6 GB, GTX 1660 Ti 6 GB and a 4 GB card). Changes are listed relative to
|
||||
[0.5-pre3](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre3). Details and
|
||||
measurements: [NVIDIA_MEMORY_MODEL.ru.md](https://github.com/deadinside28/bloodborne_pc/blob/testing/docs/NVIDIA_MEMORY_MODEL.ru.md).
|
||||
|
||||
## English
|
||||
|
||||
- **The new memory model on NVIDIA no longer stutters while areas stream in.** On NVIDIA (and
|
||||
any GPU other than AMD) the new model keeps VRAM copies of the game's memory itself. After
|
||||
each run of blocks it copied to VRAM, it rewrote the page table entries of the whole copy (up
|
||||
to 160 000 entries in one frame), looking up every block in the runtime's memory map under a
|
||||
lock the game's threads hold while they map memory: the GPU thread waited 30–70 ms in frames
|
||||
where an area streamed in. Only the entries that changed are written now, with one lookup per
|
||||
mapping. On a recorded route (RX 7800 XT forced into this path, five runs) the 99th percentile
|
||||
frame went from 11–13 ms to 5.1–7.5 ms (9.4 ms in a run where the GPU itself ran slower), the
|
||||
worst frame from 32–57 ms to 9–16 ms, close to AMD's default path (5.2–6.0 ms).
|
||||
- **No more copying the same memory to VRAM and back every frame.** Where the GPU writes
|
||||
memory the CPU also wrote, the write goes to the game's memory; a reading binding then copied
|
||||
the range to VRAM again, the next writing binding sent it back, every frame (seen at one
|
||||
spot with 42 FPS: about 200 MB/s each way). A range sent
|
||||
back for the GPU's writes a second time now stays where it is. Write traps on VRAM copies are
|
||||
set and cleared with one call per run of blocks instead of one per 64 KiB.
|
||||
- **Fewer shader-compilation hitches.** A new graphics pipeline of a pass that draws into a
|
||||
render target used in each of the last 8 frames is compiled on worker threads while its draws
|
||||
go without it for a frame or two. Translating a new shader and compute pipelines still happen at once, and so
|
||||
do passes rendered once and loading screens. `BB_ASYNC_PIPELINES=0` restores the old
|
||||
behaviour, `BB_ASYNC_PIPELINE_THREADS=N` sets the worker count. The drivers' own shader caches
|
||||
are kept between sessions (NVIDIA: no cleanup, 10 GB; Mesa: 4 GB). As before, the first start
|
||||
of a new build compiles its pipeline cache again.
|
||||
- **4 GB cards: the new memory model no longer collapses to ~5 FPS.** 0.5-pre3 stopped copying
|
||||
the game's memory to VRAM short of the texture collector's critical mark; on a 4 GB card the
|
||||
textures alone held the usage there, so no copy was made again and everything was read over
|
||||
the bus after a few minutes. VRAM copies now have their own share (25 % of the driver's
|
||||
budget, `BB_LAYER_MIRROR_FLOOR_PERCENT`) that the texture collector's mark does not take.
|
||||
Cards with 4 GB are still faster with the 0.3 memory model.
|
||||
- **No VRAM left behind after travelling.** Copies of an area left behind stayed in VRAM (large
|
||||
bindings over all memory marked every copy as in use), and the copies of the new area waited,
|
||||
read over the bus (about 10 FPS less after a lamp travel on a GTX 1060). When VRAM is short,
|
||||
copies not bound directly for 3 s now go back first, and copies with memory left without
|
||||
valid data are made again over their valid data only, giving that memory back.
|
||||
- **Damaged game extractions are reported instead of hanging (#81).** Some extraction tools
|
||||
(LibOrbisPkg PkgTool on .NET 6 or newer) leave parts of compressed sectors stale without an
|
||||
error; the game then hung while loading shaders (`shaderBinarySize … is not equal to Program
|
||||
size`). The launcher and the game's preparation now unpack the shader files (under a second)
|
||||
and say that the extraction is damaged. `scripts/game_check.py GAME_DIR` checks every file.
|
||||
- **NVIDIA driver diagnostics (#107).** `--vulkan-info` now lists the NVIDIA libraries linked
|
||||
for the package, the kernel module, the `/dev/nvidia*` nodes, hybrid-graphics variables and
|
||||
the NVIDIA libraries the dynamic linker searched for and did not load: one log shows why the
|
||||
host driver gave no `vkCreateInstance` inside the AppImage.
|
||||
- **A crash window in command recording closed.** Handing recorded commands to the recording
|
||||
threads left the current command chunk empty for a moment; anything recording on that thread
|
||||
then (a fault handler) read a null chunk. The same crash was reported for a Windows build
|
||||
(#100). The replacement chunk is now swapped in before the old one leaves.
|
||||
- **The in-game settings menu (Insert, L3+R3) looks as in 0.3 and 0.4 again:** one movable window
|
||||
with sections, check boxes, sliders and `(?)` hints, keyboard and gamepad navigation. Its
|
||||
content is that of 0.5 (DLSS, debug views, current hints).
|
||||
|
||||
**How to test:** enable *New memory and translation model* in the launcher, or set
|
||||
`BB_PC_MODEL=1`; the mode remains **off by default**. On AMD it uses the sparse arena;
|
||||
`BB_LAYER_MEMORY=1` forces NVIDIA's path there. Logs with `BB_FRAME_STATS=1` show compiles per 5 s,
|
||||
a line `GPU: N pipelines compiled in the background, M draws went without theirs`, and for
|
||||
frames over 40 ms where the new model's VRAM copies spent their time (`layer memory ms`).
|
||||
|
||||
**Validation and limits:** RX 7800 XT/RADV, a recorded 25 s route: AMD's default path p99
|
||||
5.2–6.0 ms; NVIDIA's path forced, before/after as above; no frames over 20 ms in either. A 4-minute
|
||||
session on NVIDIA's path with the VRAM budget limited to 4.5 GB (`BB_VRAM_LIMIT_MB=4608`): 177 FPS
|
||||
on average, p99 9.7 ms, VRAM at most 3.0 GB; 11 of the 12 frames over 40 ms were compiles or the
|
||||
loading screen. Runtime, unit (106) and GPU tests passed. NVIDIA's own path (the game's memory imported as
|
||||
host memory) cannot run on AMD: the gains there are not measured yet, logs from NVIDIA testers
|
||||
are welcome. Physical Intel GPUs are not tested.
|
||||
|
||||
The AppImage contains no game files. Proprietary FSR 4 model assets and NVIDIA's DLSS SDK/libraries
|
||||
are not bundled. `SHA256SUMS` accompanies the download.
|
||||
|
||||
## Русский
|
||||
|
||||
- **Новая модель памяти на NVIDIA больше не дёргается при подгрузке локаций.** На NVIDIA (и
|
||||
любой видеокарте, кроме AMD) новая модель сама держит копии памяти игры в VRAM. После каждого
|
||||
куска, скопированного в VRAM, она переписывала записи таблицы страниц по всей копии (до 160 000
|
||||
записей за кадр) и для каждого блока искала его в карте памяти рантайма под блокировкой,
|
||||
которую держат потоки игры, когда отображают память: поток видеокарты ждал по 30–70 мс в
|
||||
кадрах, где подгружалась локация. Теперь пишутся только изменившиеся записи, с одним поиском
|
||||
на отображение. На записанном маршруте (RX 7800 XT, принудительно на этом пути, пять прогонов)
|
||||
99-й процентиль кадра — 5,1–7,5 мс вместо 11–13 (9,4 мс в прогоне, где медленнее работала сама
|
||||
видеокарта), худший кадр — 9–16 мс вместо 32–57, близко к обычному пути AMD (5,2–6,0 мс).
|
||||
- **Память больше не гоняется в VRAM и обратно каждый кадр.** Где видеокарта пишет в память,
|
||||
в которую писал и процессор, запись идёт в память игры; привязка на чтение снова копировала
|
||||
этот диапазон в VRAM, следующая привязка на запись отправляла обратно — и так каждый кадр
|
||||
(замечено в одном месте при 42 FPS: около 200 МБ/с в каждую сторону). Диапазон, который вернулся из-за записи видеокарты второй раз, теперь
|
||||
остаётся на месте. Ловушки записи на копиях в VRAM ставятся и снимаются одним вызовом на
|
||||
участок, а не на каждые 64 КБ.
|
||||
- **Меньше рывков от компиляции шейдеров.** Новый графический конвейер прохода, который рисует
|
||||
в цель рендера, использованную в каждом из последних 8 кадров, собирается в фоновых потоках, а
|
||||
его отрисовки кадр-другой идут без него. Перевод нового шейдера и compute-конвейеры
|
||||
по-прежнему компилируются сразу, как и разовые проходы и экраны загрузки.
|
||||
`BB_ASYNC_PIPELINES=0` — как раньше, `BB_ASYNC_PIPELINE_THREADS=N` — число потоков. Дисковые
|
||||
кэши шейдеров драйверов сохраняются между сессиями (NVIDIA — без очистки, 10 ГБ; Mesa — 4 ГБ).
|
||||
Как и раньше, при первом запуске новой сборки кэш конвейеров собирается заново.
|
||||
- **Карты на 4 ГБ: новая модель памяти больше не падает до ~5 FPS.** В 0.5-pre3 копии памяти
|
||||
игры в VRAM останавливались, не доходя до критической отметки сборщика текстур; на карте 4 ГБ
|
||||
одни текстуры держали память там, копии больше не создавались, и через несколько минут всё
|
||||
читалось через шину. Теперь у копий есть своя доля VRAM (25 % бюджета драйвера,
|
||||
`BB_LAYER_MIRROR_FLOOR_PERCENT`), которую отметка сборщика текстур не забирает. На картах
|
||||
4 ГБ модель памяти 0.3 по-прежнему быстрее.
|
||||
- **После перемещений VRAM не остаётся занятой.** Копии покинутой локации оставались в VRAM
|
||||
(большие привязки на всю память помечали каждую копию как используемую), а копии новой ждали
|
||||
и читались через шину (около 10 FPS меньше после телепорта к лампе на GTX 1060). Теперь при
|
||||
нехватке VRAM сначала уходят копии, к которым напрямую не привязывались 3 с, а копии, в
|
||||
которых осталась память без действительных данных, пересоздаются только поверх
|
||||
действительных данных и отдают эту память.
|
||||
- **Повреждённая распаковка игры теперь называется прямо, а не приводит к зависанию (#81).**
|
||||
Некоторые распаковщики (LibOrbisPkg PkgTool на .NET 6 и новее) без ошибки оставляют части
|
||||
сжатых секторов устаревшими; игра зависала на загрузке шейдеров (`shaderBinarySize … is not
|
||||
equal to Program size`). Лаунчер и подготовка игры теперь распаковывают файлы шейдеров (меньше
|
||||
секунды) и сообщают, что распаковка повреждена. `scripts/game_check.py ПАПКА_ИГРЫ` проверяет
|
||||
все файлы.
|
||||
- **Диагностика драйвера NVIDIA (#107).** `--vulkan-info` теперь показывает библиотеки NVIDIA,
|
||||
подключённые для пакета, модуль ядра, узлы `/dev/nvidia*`, переменные гибридной графики и
|
||||
библиотеки NVIDIA, которые динамический компоновщик искал и не загрузил: по одному логу видно,
|
||||
почему драйвер хоста не отдал `vkCreateInstance` внутри AppImage.
|
||||
- **Закрыто окно для вылета при записи команд.** При передаче записанных команд потокам записи
|
||||
текущий кусок команд на мгновение оставался пустым; если в этот момент на том же потоке
|
||||
что-то записывало (обработчик ошибки доступа), оно читало пустой указатель. Такой же вылет был
|
||||
у сборки для Windows (#100). Теперь новый кусок подставляется до того, как уходит старый.
|
||||
- **Меню настроек в игре (Insert, L3+R3) снова выглядит как в 0.3 и 0.4:** одно перемещаемое
|
||||
окно с разделами, флажками, ползунками и подсказками `(?)`, управление клавиатурой и
|
||||
геймпадом. Содержимое — как в 0.5 (DLSS, отладочные виды, актуальные подсказки).
|
||||
|
||||
**Как проверить:** включить *Новую модель памяти и трансляции* в лаунчере или задать
|
||||
`BB_PC_MODEL=1`; режим по-прежнему **выключен по умолчанию**. На AMD он работает через
|
||||
sparse-арену; `BB_LAYER_MEMORY=1` включает на AMD путь NVIDIA. В логе с `BB_FRAME_STATS=1` —
|
||||
число компиляций за 5 с, строка `GPU: N pipelines compiled in the background, M draws went
|
||||
without theirs` и для кадров дольше 40 мс — на что ушло время копий новой модели в VRAM
|
||||
(`layer memory ms`).
|
||||
|
||||
**Проверки и ограничения:** RX 7800 XT/RADV, записанный маршрут на 25 с: обычный путь AMD —
|
||||
p99 5,2–6,0 мс; путь NVIDIA, принудительно, — до и после, как выше; ни одного кадра дольше
|
||||
20 мс. Сессия на 4 минуты на пути NVIDIA с бюджетом VRAM 4,5 ГБ (`BB_VRAM_LIMIT_MB=4608`):
|
||||
в среднем 177 FPS, p99 9,7 мс, VRAM не больше 3,0 ГБ; 11 из 12 кадров дольше 40 мс — компиляция
|
||||
или экран загрузки. Тесты рантайма, юнит-тесты (106) и GPU-тесты пройдены. Собственный путь NVIDIA (память
|
||||
игры импортируется как память хоста) на AMD не запустить: выигрыш там ещё не измерен, логи от
|
||||
тестеров с NVIDIA приветствуются. Физические Intel не проверялись.
|
||||
|
||||
Игровых файлов в AppImage нет. Проприетарные модели FSR 4 и SDK/библиотеки DLSS не включены.
|
||||
К загрузке приложен `SHA256SUMS`.
|
||||
@@ -0,0 +1,172 @@
|
||||
**English** · [Русский](#русский)
|
||||
|
||||
bbport is the counterpart of Wine + DXVK for a single game: Bloodborne (CUSA03173, v1.09) on Linux.
|
||||
The game's x86-64 code runs directly on the CPU, a runtime written for this game replaces the PS4
|
||||
system libraries, and the graphics are translated to Vulkan.
|
||||
|
||||
Questions about this project: Discord https://discord.gg/KYZRKk9CB — not the shadPS4 server.
|
||||
|
||||
### What's new since 0.4
|
||||
|
||||
Details and measurements of each step are in the prerelease notes:
|
||||
[pre1](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre1),
|
||||
[pre2](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre2),
|
||||
[pre3](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre3),
|
||||
[pre4](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre4).
|
||||
|
||||
**The new memory and translation model — the default on AMD**
|
||||
- Launcher: *Mode → Memory and translation model*. *Auto* (the default) gives AMD GPUs the new
|
||||
model and NVIDIA, Intel and others the memory model of 0.3 with all its fixes; *New* and *Old*
|
||||
choose by hand. Without the launcher: `BB_PC_MODEL=1/0` (unset: as *Auto*).
|
||||
- The GPU uses the game's memory where it is, as a PC game's buffers; what it reads often is kept
|
||||
in VRAM — on AMD in a sparse buffer (the arena), on other GPUs by the layer's memory module
|
||||
without sparse rebinding (`BB_LAYER_MEMORY=1/0` by hand). The PS4 command processor's work is
|
||||
translated rather than emulated: memory writes and fences are done by the GPU in stream order,
|
||||
`COPY_DATA`, `COND_EXEC`, predication, `MEM_SEMAPHORE` and the GPU clock (100 MHz, as on the
|
||||
PS4) follow the GPU's timeline.
|
||||
- The game's occlusion queries as Vulkan queries are available with `BB_OCCLUSION_QUERIES=1`, off
|
||||
by default: with an upscaler the scene is drawn smaller and jittered, and a lamp's glow then
|
||||
flashed grey over the whole frame now and then. Off, everything counts as visible, as in the
|
||||
0.3 model.
|
||||
- The layer's memory module (NVIDIA and others): some launches no longer run the GPU 1.3–1.7 times
|
||||
slower (copies that broke render passes up to ~100 times a frame).
|
||||
- On NVIDIA the new model can be chosen by hand; testers' results differ by scene (some scenes are
|
||||
slower than with the old model), so it is not the default there yet. Logs are welcome.
|
||||
|
||||
**Settings inside the game's own menu**
|
||||
- *System* has *Display* and *Effects*, real pages of the game's menu, on the title screen and
|
||||
in the pause menu: output resolution, quality preset and sharpness as sliders, FPS counter,
|
||||
model detail and upscaler; chromatic aberration, depth of field, motion blur, SSAO, dynamic
|
||||
shadows and SSR. The game's patches and its own AA are in the overlay menu and the launcher.
|
||||
- The overlay menu (Insert / L3+R3) looks as in 0.3 again.
|
||||
- No "Play online / offline" screen: there is no PSN, the game opens its main menu offline.
|
||||
|
||||
**Smoother play**
|
||||
- New graphics pipelines of passes drawn every frame compile in the background: fewer hitches.
|
||||
Only geometry goes without its pipeline meanwhile (it shows a frame later); full-screen passes
|
||||
(lighting, fog, post-processing) wait for theirs — skipping one left whole frames grey. The
|
||||
drivers' shader caches are kept between sessions. In the game's menu the output resolution and
|
||||
preset sliders apply once they rest for 0.4 s, not at every step.
|
||||
- Cards with little VRAM: FPS no longer falls the longer you play (the texture collector evicted
|
||||
textures used a moment ago and read them again over the bus: 32 915 in ~7 minutes in an NVIDIA
|
||||
log); the game no longer stops when VRAM for its memory copies runs out; VRAM is given back
|
||||
after travelling.
|
||||
|
||||
**New**
|
||||
- DLC: add-on folders under `user/addcont/` are reported as installed; saves with The Old Hunters
|
||||
load (#33, PR #84).
|
||||
- DLSS on Linux for NVIDIA RTX when built with NVIDIA's DLSS SDK (PR #83; not in the AppImage).
|
||||
- Launcher: monitor choice (#69), *Copy* and *Export log…* (PR #78), Simplified Chinese (PR #75).
|
||||
- Damaged game extractions are reported instead of hanging while loading shaders (#81);
|
||||
`scripts/game_check.py GAME_DIR` checks every file.
|
||||
- NVIDIA in the AppImage: the host's EGL vendor files are passed along (without them NVIDIA's
|
||||
driver gave no `vkCreateInstance` on some hosts, #107; `BB_NVIDIA_EGL=0`: off); `--vulkan-info`
|
||||
prints the driver report together with the summary.
|
||||
- AMD Polaris, Vega and their APUs under RADV: `RADV_DEBUG=nohiz` is set automatically (black
|
||||
halos and vanishing geometry, #54, #99; your own `RADV_DEBUG` or `BB_AUTO_NOHIZ=0` keeps it off).
|
||||
- The FSR 4.1.1 build also finds Proton installed system-wide (PR #112). The bundled Dear ImGui
|
||||
is private to the GPU library: Vulkan layers with their own copy no longer crash the game
|
||||
(PR #113).
|
||||
|
||||
**Fixes**
|
||||
- Saves are no longer damaged by a crash during saving (#64).
|
||||
- FSR 4.1.1 build: Proton runs without Steam's container where it cannot start (#61).
|
||||
- The item picture on the loading screen at outputs other than 1080p (#67).
|
||||
- GPU hangs from garbage indirect dispatch sizes (#34); a crash window while recording commands
|
||||
(the same crash was reported for a Windows build, #100).
|
||||
- Small mips of tiled textures are detiled the way the GPU stores them (from shadPS4 #5196).
|
||||
- Chinese/Japanese/Korean Windows locales in the game preparation (#55); an `eboot.bin` dumped as a
|
||||
plain ELF (#49); stick calibration for Switch Pro clones (#70, PR #71); `BB_FSR4_STATS=1`
|
||||
(PR #80).
|
||||
|
||||
**Known limits:** one machine was tested thoroughly (RX 7800 XT, Mesa/RADV). Banding in dark
|
||||
gradients is not confirmed fixed. The Windows build is a separate port.
|
||||
|
||||
The AppImage contains no game files. Proprietary FSR 4 model assets and NVIDIA's DLSS SDK/libraries
|
||||
are not bundled. `SHA256SUMS` accompanies the download.
|
||||
|
||||
## Русский
|
||||
|
||||
bbport — аналог Wine + DXVK для одной игры: Bloodborne (CUSA03173, v1.09) на Linux. Код игры x86-64
|
||||
выполняется прямо на процессоре, системные библиотеки PS4 заменяет рантайм, написанный под эту игру,
|
||||
графика переводится в Vulkan.
|
||||
|
||||
Вопросы по проекту: Discord https://discord.gg/KYZRKk9CB — не сервер shadPS4.
|
||||
|
||||
### Что нового после 0.4
|
||||
|
||||
Подробности и замеры каждого шага — в описаниях пререлизов:
|
||||
[pre1](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre1),
|
||||
[pre2](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre2),
|
||||
[pre3](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre3),
|
||||
[pre4](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5-pre4).
|
||||
|
||||
**Новая модель памяти и трансляции — по умолчанию на AMD**
|
||||
- Лаунчер: *Режим работы → Модель памяти и трансляции*. *Авто* (по умолчанию) даёт видеокартам
|
||||
AMD новую модель, а NVIDIA, Intel и остальным — модель памяти 0.3 со всеми исправлениями;
|
||||
*Новая* и *Старая* — вручную. Без лаунчера — `BB_PC_MODEL=1/0` (не задано — как *Авто*).
|
||||
- Видеокарта работает с памятью игры на месте, как с буферами игры для ПК; то, что она читает
|
||||
часто, держится в VRAM — на AMD в sparse-буфере (арене), на остальных видеокартах модулем
|
||||
памяти прослойки без sparse-перепривязок (`BB_LAYER_MEMORY=1/0` — вручную). Работа командного
|
||||
процессора PS4 переводится, а не эмулируется: записи в память и метки делает видеочип в порядке
|
||||
потока, `COPY_DATA`, `COND_EXEC`, предикация, `MEM_SEMAPHORE` и часы видеочипа (100 МГц, как у
|
||||
PS4) — во времени видеочипа.
|
||||
- Occlusion-запросы игры как запросы Vulkan — по `BB_OCCLUSION_QUERIES=1`, по умолчанию выключены:
|
||||
с апскейлером сцена рисуется меньше и со сдвигом, и свечение лампы время от времени вспыхивало
|
||||
серым на весь кадр. Без них всё считается видимым, как в модели 0.3.
|
||||
- Модуль памяти прослойки (NVIDIA и другие): некоторые запуски больше не гоняют видеокарту в
|
||||
1,3–1,7 раза медленнее (копирования, разрывавшие проходы рендера до ~100 раз за кадр).
|
||||
- На NVIDIA новую модель можно выбрать вручную; у тестеров результат зависит от сцены (в части
|
||||
сцен медленнее старой модели), поэтому там она пока не по умолчанию. Логи приветствуются.
|
||||
|
||||
**Настройки — в меню самой игры**
|
||||
- В *Системе* — *Изображение* и *Эффекты*, настоящие страницы меню игры, и на титульном экране,
|
||||
и в паузе: разрешение вывода, пресет качества и резкость ползунками, счётчик FPS, детализация
|
||||
моделей и апскейлер; хроматическая аберрация, глубина резкости, размытие в движении, SSAO,
|
||||
динамические тени и SSR. Патчи игры и её собственное сглаживание — в меню оверлея и лаунчере.
|
||||
- Меню оверлея (Insert / L3+R3) снова выглядит как в 0.3.
|
||||
- Без экрана «Играть онлайн / офлайн»: PSN нет, игра сразу открывает главное меню офлайн.
|
||||
|
||||
**Ровнее**
|
||||
- Новые графические конвейеры проходов, которые рисуются каждый кадр, собираются в фоне: меньше
|
||||
рывков. Без своего конвейера в это время остаётся только геометрия (она появляется кадром
|
||||
позже); полноэкранные проходы (освещение, туман, постобработка) ждут свой — пропуск такого
|
||||
прохода давал целые серые кадры. Дисковые кэши шейдеров драйверов сохраняются между сессиями. В
|
||||
меню игры ползунки разрешения вывода и пресета применяются, когда простоят 0,4 с, а не на
|
||||
каждом шаге.
|
||||
- Карты с малым объёмом VRAM: FPS больше не падает со временем (сборщик текстур выгружал только что
|
||||
использованные текстуры и читал их снова через шину: 32 915 за ~7 минут в логе с NVIDIA); игра
|
||||
не останавливается, когда кончается VRAM для копий её памяти; после перемещений VRAM
|
||||
освобождается.
|
||||
|
||||
**Новое**
|
||||
- DLC: папки дополнений в `user/addcont/` сообщаются игре как установленные, сохранения с The Old
|
||||
Hunters загружаются (#33, PR #84).
|
||||
- DLSS на Linux для NVIDIA RTX при сборке с SDK DLSS от NVIDIA (PR #83; в AppImage не входит).
|
||||
- Лаунчер: выбор монитора (#69), *Копировать* и *Экспорт лога…* (PR #78), упрощённый китайский
|
||||
(PR #75).
|
||||
- Повреждённая распаковка игры называется прямо, а не приводит к зависанию на загрузке шейдеров
|
||||
(#81); `scripts/game_check.py ПАПКА_ИГРЫ` проверяет все файлы.
|
||||
- NVIDIA в AppImage: передаются файлы EGL-вендоров хоста (без них драйвер NVIDIA на некоторых
|
||||
системах не отдавал `vkCreateInstance`, #107; `BB_NVIDIA_EGL=0` — выключить); `--vulkan-info`
|
||||
печатает отчёт о драйвере вместе со сводкой.
|
||||
- AMD Polaris, Vega и их APU под RADV: `RADV_DEBUG=nohiz` ставится сам (чёрные ореолы и пропадающая
|
||||
геометрия, #54, #99; свой `RADV_DEBUG` или `BB_AUTO_NOHIZ=0` — не ставить).
|
||||
- Сборка FSR 4.1.1 находит и Proton, установленный в систему (PR #112). Встроенный Dear ImGui
|
||||
скрыт внутри библиотеки GPU: слои Vulkan со своей копией больше не роняют игру (PR #113).
|
||||
|
||||
**Исправления**
|
||||
- Сохранения не портятся при вылете во время сохранения (#64).
|
||||
- Сборка FSR 4.1.1: Proton запускается без контейнера Steam там, где тот не стартует (#61).
|
||||
- Картинка предмета на экране загрузки при выводе не в 1080p (#67).
|
||||
- Зависания видеочипа от мусорных размеров непрямых запусков (#34); окно для вылета при записи
|
||||
команд (такой же вылет был у сборки для Windows, #100).
|
||||
- Мелкие мипы тайловых текстур раскладываются так, как их хранит видеокарта (из shadPS4 #5196).
|
||||
- Китайская/японская/корейская локали Windows при подготовке игры (#55); `eboot.bin`, снятый как
|
||||
обычный ELF (#49); калибровка стиков у клонов Switch Pro (#70, PR #71); `BB_FSR4_STATS=1` (PR #80).
|
||||
|
||||
**Ограничения:** подробно проверена одна машина (RX 7800 XT, Mesa/RADV). Полосы в тёмных
|
||||
градиентах — исправление не подтверждено. Сборка для Windows — отдельный порт.
|
||||
|
||||
Игровых файлов в AppImage нет. Проприетарные модели FSR 4 и SDK/библиотеки DLSS не включены.
|
||||
К загрузке приложен `SHA256SUMS`.
|
||||
@@ -0,0 +1,109 @@
|
||||
**English** · [Русский](#русский)
|
||||
|
||||
bbport is the counterpart of Wine + DXVK for a single game: Bloodborne (v1.09) on Linux.
|
||||
Changes since [0.5](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5); details and
|
||||
measurements: [CHANGES_after_0.5.md](https://github.com/deadinside28/bloodborne_pc/blob/master/docs/CHANGES_after_0.5.md) (Russian).
|
||||
|
||||
Questions about this project: Discord https://discord.gg/KYZRKk9CB — not the shadPS4 server.
|
||||
|
||||
### New
|
||||
|
||||
- **Online play (shadNet)**, as a separate module (`libbbnet.so`, loaded only when online play is
|
||||
on): messages, bloodstains and ghosts from The Hunter's Dream, bells and summons through a
|
||||
shadNet server (`srv.shadps4.net:31313` by default) with a shadNet account. Launcher → *Online*:
|
||||
servers, account, UPnP, connection test. The router port is opened by UPnP (#121). The same
|
||||
servers as the Windows port. The network and PSN libraries come from shadp2p (a shadPS4 fork,
|
||||
GPL-2.0) by way of the Linux and Windows forks of bbport.
|
||||
- **Mouse look**: click into the game to take the mouse, F1 releases it; mouse buttons and the
|
||||
wheel can be bound like keys (Mouse Left = R1, Mouse Right = L2, Middle = R3, side buttons
|
||||
R2/L1, wheel = quick items). Launcher → *Controls*: mouse look, sensitivity, invert Y (#51, #52).
|
||||
- **DLSS in the AppImage** (NVIDIA GeForce RTX): the bridge and NVIDIA's DLSS 310.9.1 library are
|
||||
included (NVIDIA's RTX SDK license allows it within an application; its text is in the package).
|
||||
A newer `libnvidia-ngx-dlss.so.*` can be chosen in the launcher (*Upscaler → DLSS: NVIDIA's
|
||||
library*), like the FSR 4.1.1 DLL.
|
||||
- **Every retail release** of Bloodborne with update 1.09 is accepted (US CUSA00900, EU, UK, JP,
|
||||
Asia and The Old Hunters editions; PR #117); an `eboot.bin` with a 60 fps patch baked in is
|
||||
reported.
|
||||
- **Quit the game** from the overlay (Insert / L3+R3; press twice) — #74, #116.
|
||||
|
||||
### Fixes
|
||||
|
||||
- The US release (and other regions) crashed with code 139 on entering the world in the new
|
||||
memory model: they ran without the game's profile (#119).
|
||||
- Motion blur smeared the whole frame while the camera turned in the new memory model (#122).
|
||||
- Cards with 4 GB (NVIDIA): "Failed to allocate 64 MiB for guest memory copies" stopped the game;
|
||||
now it frees textures sooner and uses other memory instead.
|
||||
- The main menu flickered with output resolutions above 1080p (live resolution).
|
||||
- Online, "Could not get information from the Bloodborne server" in the AppImage on NixOS (HTTPS
|
||||
certificates).
|
||||
- NVIDIA on Wayland: the swapchain is recreated through `oldSwapchain` (PR #93).
|
||||
- Building from git after updating from 0.4: "patch failed: src/ffx_vk_fsr4_v07.c" (#124).
|
||||
- `bb-launcher.sh --play` through nix-shell (PR #120); FSR 4.1.1 recording from the AppImage on
|
||||
SteamOS (PR #89).
|
||||
|
||||
### Smaller download
|
||||
|
||||
The AppImage is **399 MB instead of 925 MB**: only Mesa's Vulkan drivers (RADV without LLVM and
|
||||
ANV) instead of all of Mesa, no debug info in the game binary, MangoHud without its 32-bit half,
|
||||
the launcher's GTK without GStreamer.
|
||||
|
||||
**Known limits:** online login and summons were not tested by the author (no shadNet account);
|
||||
the UDP side of the public shadNet server did not answer in #121. Mouse look and DLSS need
|
||||
testing on more systems.
|
||||
|
||||
The AppImage contains no game files. AMD's FSR 4 model assets are not bundled. `SHA256SUMS`
|
||||
accompanies the download.
|
||||
|
||||
## Русский
|
||||
|
||||
bbport — аналог Wine + DXVK для одной игры: Bloodborne (v1.09) на Linux. Изменения после
|
||||
[0.5](https://github.com/deadinside28/bloodborne_pc/releases/tag/0.5); подробности и замеры —
|
||||
[CHANGES_after_0.5.md](https://github.com/deadinside28/bloodborne_pc/blob/master/docs/CHANGES_after_0.5.md).
|
||||
|
||||
Вопросы по проекту: Discord https://discord.gg/KYZRKk9CB — не сервер shadPS4.
|
||||
|
||||
### Новое
|
||||
|
||||
- **Игра по сети (shadNet)** — отдельным модулем (`libbbnet.so`, загружается, только когда онлайн
|
||||
включён): сообщения, пятна крови и призраки — с The Hunter's Dream, колокола и призывы — через
|
||||
сервер shadNet (по умолчанию `srv.shadps4.net:31313`) с учётной записью shadNet. Лаунчер →
|
||||
*Онлайн*: серверы, учётная запись, UPnP, проверка соединения. Порт на роутере открывается по UPnP
|
||||
(#121). Серверы те же, что у Windows-версии. Сетевые и PSN-библиотеки — из shadp2p (форк shadPS4,
|
||||
GPL-2.0), через Linux- и Windows-форки bbport.
|
||||
- **Камера мышью**: щелчок в окне игры захватывает мышь, F1 — отпускает; кнопки мыши и колесо
|
||||
назначаются как клавиши (левая — R1, правая — L2, средняя — R3, боковые — R2/L1, колесо —
|
||||
быстрые предметы). Лаунчер → *Управление*: камера мышью, чувствительность, инверсия (#51, #52).
|
||||
- **DLSS в AppImage** (NVIDIA GeForce RTX): мост и библиотека DLSS 310.9.1 от NVIDIA в пакете
|
||||
(лицензия RTX SDK разрешает это в составе приложения; её текст — в пакете). Более новую
|
||||
`libnvidia-ngx-dlss.so.*` можно выбрать в лаунчере (*Апскейлер → DLSS: библиотека NVIDIA*), как DLL
|
||||
для FSR 4.1.1.
|
||||
- **Любое розничное издание** Bloodborne с обновлением 1.09 (США CUSA00900, Европа, Великобритания,
|
||||
Япония, Азия и издания с The Old Hunters; PR #117); о `eboot.bin` со вшитым патчем 60 FPS
|
||||
сообщается.
|
||||
- **Выход из игры** из оверлея (Insert / L3+R3; нажать дважды) — #74, #116.
|
||||
|
||||
### Исправления
|
||||
|
||||
- Американское и другие издания падали с кодом 139 при входе в мир в новой модели памяти: они шли
|
||||
без профиля игры (#119).
|
||||
- Размытие в движении размазывало весь кадр при повороте камеры в новой модели памяти (#122).
|
||||
- Карты на 4 ГБ (NVIDIA): «Failed to allocate 64 MiB for guest memory copies» останавливало игру;
|
||||
теперь текстуры освобождаются раньше, используется другая память.
|
||||
- Мерцание главного меню при выводе выше 1080p (живая смена разрешения).
|
||||
- Онлайн: «Не удалось получить информацию от сервера Bloodborne» в AppImage на NixOS (сертификаты
|
||||
HTTPS).
|
||||
- NVIDIA на Wayland: swapchain пересоздаётся через `oldSwapchain` (PR #93).
|
||||
- Сборка из git после обновления с 0.4: «patch failed: src/ffx_vk_fsr4_v07.c» (#124).
|
||||
- `bb-launcher.sh --play` через nix-shell (PR #120); запись FSR 4.1.1 из AppImage на SteamOS (PR #89).
|
||||
|
||||
### Меньше скачивать
|
||||
|
||||
AppImage — **399 МБ вместо 925 МБ**: из Mesa только Vulkan-драйверы (RADV без LLVM и ANV), без
|
||||
отладочной информации в бинарнике игры, MangoHud без 32-битной части, GTK лаунчера без GStreamer.
|
||||
|
||||
**Ограничения:** вход в shadNet и призыв автор не проверял (нет учётной записи); UDP-часть
|
||||
публичного сервера shadNet в #121 не отвечала. Камеру мышью и DLSS нужно проверить на большем числе
|
||||
систем.
|
||||
|
||||
Файлов игры в AppImage нет. Ассеты моделей FSR 4 от AMD не входят. К загрузке прилагается
|
||||
`SHA256SUMS`.
|
||||
@@ -0,0 +1,434 @@
|
||||
# Изменения после 0.4 (с 2026-10-08)
|
||||
|
||||
Замеры — RX 7800 XT / RADV, Кошмар охотника у лампы (сохранение пользователя), 1080p без лимита
|
||||
FPS, новая модель (`BB_PC_MODEL=1`); «4 ядра» — `CPUS=0-3,8-11` (4 ядра / 8 потоков).
|
||||
Подробности и что осталось — [EMULATION_REMOVAL_PLAN.ru.md](EMULATION_REMOVAL_PLAN.ru.md),
|
||||
«Шаг 3».
|
||||
|
||||
## Метки EOP/EOS пишет видеочип (новая модель)
|
||||
|
||||
- `EVENT_WRITE_EOP` без прерывания, `EVENT_WRITE_EOS` и `RELEASE_MEM` очередей compute:
|
||||
буферный маркер Vulkan (`VK_AMD_buffer_marker`, конец конвейера) прямо в память игры, в той же
|
||||
точке потока, где их пишет командный процессор PS4. Раньше каждую метку писал поток процессора
|
||||
после завершения всей отправки Vulkan — ~330 меток за кадр, 61 тыс. в секунду.
|
||||
- 64-битная метка — две 32-битные записи, старшая половина первой (кто видит новую младшую,
|
||||
видит и новую старшую).
|
||||
- Метки с прерыванием, а также без `VK_AMD_buffer_marker` (NVIDIA) и с `BB_FREE_CHECK=1` — как
|
||||
раньше. `BB_GPU_LABELS=0` — как раньше везде.
|
||||
- EOS с записью из GDS: копия видеочипом в порядке потока вместо ожидания всего видеочипа
|
||||
(`Finish()`) и записи процессором.
|
||||
- Статистика: строка `EOP fences` показывает, сколько меток за кадр записал видеочип.
|
||||
- FPS тот же (16 потоков: 233; 4 ядра: ~217 против ~215), картинка та же; 8 минут ходьбы — см.
|
||||
ниже.
|
||||
|
||||
## Перехваты кода игры без ловушек
|
||||
|
||||
- Точки, где игра выделяет память GPU (аллокатор диапазонов, три места кучи) и где загрузчики
|
||||
копируют ресурсы (`memcpy`), раньше были `int3`: каждый вызов — сигнал ядра (SIGTRAP), ~1200
|
||||
в секунду только у аллокатора. Теперь переход в заглушку рядом с образом игры: заглушка
|
||||
вызывает обработчик и выполняет перекрытые инструкции; вызов `memcpy` идёт через трамплин.
|
||||
- Байты переписываются поверх уже стоящего `int3` (поток, наткнувшийся на него в этот момент,
|
||||
уходит в заглушку). `BB_GUEST_HOOK_TRAPS=1` — ловушки, как раньше. Диагностические точки
|
||||
(`BB_FRAME_STATS`, `BB_HEAP_SITES`) остались ловушками.
|
||||
|
||||
## Новая модель памяти на NVIDIA
|
||||
|
||||
- Новый способ отдать память игры видеочипу — импорт памяти хоста
|
||||
(`VK_EXT_external_memory_host`): кусок прямой памяти остаётся в memfd рантайма, видеочип
|
||||
импортирует его второе отображение. Процессор работает с обычной кэшируемой памятью, видеочип —
|
||||
через шину, как с upload heap игры для ПК. Освобождённая память в таких кусках обнуляется, а не
|
||||
выбрасывается из memfd (видеочип держит эти страницы).
|
||||
- При запуске самопроверка в точности как в работе: импорт куска memfd, привязка к sparse-буферу,
|
||||
запись видеочипом — чтение процессором через другое отображение, запись процессором — копия
|
||||
видеочипом; sparse-буфер для такой памяти должен принимать и VRAM. Не прошла — dma-buf (на
|
||||
NVIDIA — «кусок на выделение»), для которого теперь меряется скорость чтения процессором через
|
||||
отображение драйвера (меньше 1 ГБ/с — не используется: код игры работает на этой памяти). Не
|
||||
прошло и это — старая модель. В журнале: `Guest memory: host memory imported by the GPU`,
|
||||
`host memory import does not work here: …`, `CPU reads through the driver's dma-buf: N MB/s`.
|
||||
- Порядок: на AMD — dma-buf (как раньше; RADV не импортирует memfd —
|
||||
`ErrorInvalidExternalHandle`, проверено), на остальных — сначала импорт. `BB_GUEST_MEMORY=host`
|
||||
или `dmabuf` выбирает сам.
|
||||
- Арена (sparse-буфер памяти игры) создаётся с тем типом внешней памяти, который выбран; если
|
||||
драйвер с ним не пускает в арену VRAM — старая модель с сообщением в журнале.
|
||||
- Лаунчер: переключатель *Новая модель памяти и трансляции* доступен на AMD и NVIDIA (тексты на
|
||||
трёх языках). Без лаунчера — `BB_PC_MODEL=1`.
|
||||
- **На NVIDIA не проверено** (у автора только AMD): нужен журнал с NVIDIA.
|
||||
|
||||
## Диагностика
|
||||
|
||||
- `BB_DCB_STATS=1`: кроме структуры буферов команд — пакеты PM4 в секунду по типам, события
|
||||
`EVENT_WRITE` по типам, EOP по источнику данных и прерыванию, EOS по команде, `WAIT_REG_MEM` по
|
||||
месту и движку, и чем закончились ожидания (метка VO, метка в порядке потока, выполнено сразу,
|
||||
ждали — и сколько мс в секунду).
|
||||
|
||||
## Шейдер копирования игры: записи остаются в памяти игры; трансляция вместо подмены — по выбору
|
||||
|
||||
- Вычислительный шейдер копирования игры (`cs fefebf9f`, 2–50 запусков за кадр) выполнялся
|
||||
подменой: процессор при записи команд читал список копий из памяти игры и делал копии своим
|
||||
шейдером. Теперь его можно транслировать как есть (`BB_COPY_SHADER_NATIVE=1`, только новая
|
||||
модель): список читает видеочип во время выполнения, как на PS4.
|
||||
- Найдено: рядом с тем, куда он копирует, лежат код шейдеров и таблицы описателей, которые наш
|
||||
транслятор читает процессором. Пока эти блоки в памяти игры, всё верно; копия в VRAM (правило
|
||||
«видеочип пишет это 3 кадра из 60») давала транслятору устаревший код — чёрная сцена. Подмена
|
||||
держала их в памяти игры случайно (её диапазоны каждый раз разные). Теперь записи этого шейдера
|
||||
в обоих режимах остаются в памяти игры (`force_writes_in_place`).
|
||||
- По умолчанию — подмена: родной шейдер на 4 ядрах стоит потоку записи отрисовок ~0,3 мкс на
|
||||
пакет (+10 %), видеочипу +2 %. Бит 2 второго числа `BB_TOGGLE_FILE` переключает на ходу.
|
||||
|
||||
## Константы на месте (по выбору) и привязка буферов
|
||||
|
||||
- `BB_CONSTANTS_IN_PLACE=1` (новая модель): маленькие буферы только для чтения (константы)
|
||||
видеочип читает прямо из памяти игры, а не из копии, сделанной при разборе (кольцо констант) или
|
||||
при записи (стрим-буфер). Копии защищали отрисовку от записей командного процессора, которые
|
||||
процессор выполнял «наперёд»; в новой модели эти записи выполняет видеочип в порядке потока,
|
||||
так что копия больше не нужна для правильности. Замер (4 ядра, у лампы): разбор −0,8 мкс на
|
||||
отрисовку, видеочип +3 % (константы идут по PCIe), FPS тот же — поэтому выключено по умолчанию.
|
||||
Бит 1 второго числа `BB_TOGGLE_FILE` переключает на ходу.
|
||||
- Привязка буфера только для чтения, уже лежащего в памяти игры, запоминается до изменения
|
||||
резидентности (без обхода блоков на каждую привязку); проверки «на месте ли буфер» для
|
||||
диагностики `BB_TRACE_SHADER` больше не выполняются, когда она выключена (были две на привязку).
|
||||
|
||||
## Исправление
|
||||
|
||||
- Реестр обработчиков ошибок доступа к памяти терял обработчик с тем же приоритетом, что у уже
|
||||
зарегистрированного (множество упорядочивалось только по приоритету). Порядок теперь явный:
|
||||
диагностическая ловушка VRAM, менеджер страниц, SRT walker.
|
||||
|
||||
## Диагностика (новая)
|
||||
|
||||
- `BB_RES_STATS=1`: откуда шейдеры берут описатели ресурсов — из регистров или из таблиц в памяти
|
||||
(SRT walker), по видам, на привязку.
|
||||
- `BB_VRAM_ACCESS_TRAP=1` (+ `BB_VRAM_TRAP_RANGE=адрес,размер`): блоки памяти игры, перенесённые
|
||||
в VRAM, закрываются от процессора; печатаются места кода, которые к ним обращаются (кто читает
|
||||
устаревшую копию).
|
||||
- `BB_WATCH=адрес,размер`: что транслятор читает из диапазона (указатели в пользовательских
|
||||
данных, буферы, код шейдеров). `BB_TRACE_ADDR=адрес,размер` (с `BB_TRACE_SIZE`): привязки над
|
||||
диапазоном с самого начала. `BB_TILE_BACK_LOG=1`: образы, записанные обратно в память, потому
|
||||
что их читают как текстурный буфер. `BB_COPY_SHADER_TRACE=1`: буферы шейдера копирования.
|
||||
|
||||
## Occlusion-запросы игры — настоящие запросы Vulkan (новая модель)
|
||||
|
||||
- Bloodborne делает около 60 occlusion-запросов за кадр (`ZPASS_DONE`); раньше они получали
|
||||
фиктивную последовательность «всё видно». Теперь сэмплы считают запросы Vulkan, а результаты
|
||||
записывает видеочип в память игры в формате PS4 (счётчики блоков глубины с битом готовности).
|
||||
Проходы рендера не разрываются: запрос режется на границах проходов и буферов команд, запись
|
||||
результатов откладывается до ближайшей точки вне прохода и делается одним запуском шейдера. На
|
||||
4 ядрах разница с фиктивным счётчиком — в пределах шума. `BB_OCCLUSION_QUERIES=0` — как раньше.
|
||||
- `COPY_DATA` (константы, регистры, часы, память, GDS) — записи и копии видеочипа в порядке потока;
|
||||
`COND_EXEC` — условие по метке в порядке потока или после работы видеочипа до пакета;
|
||||
`SET_PREDICATION` (ZPass, Bool64/32) — отрисовки и запуски с битом предиката пропускаются, если
|
||||
предикат не выполнен. Bloodborne последние три не использует; это для переноса других игр.
|
||||
- `BB_PM4_SELFTEST=1`: самопроверка всего этого в работающей игре (8 проверок, печатает PASS/FAIL).
|
||||
- Исправлена взаимоблокировка при чтении процессором данных видеочипа из потока разбора.
|
||||
|
||||
## Шейдер копирования игры — по умолчанию как есть
|
||||
|
||||
- Шейдер копирования игры (`cs fefebf9f`, ~36 запусков за кадр) теперь по умолчанию переводится и
|
||||
выполняется сам: список копий читает видеочип. `BB_COPY_SHADER_NATIVE=0` — прежняя подмена (список
|
||||
читает процессор). Цена на 4 ядрах — +6 % к потоку записи отрисовок, видеочип и FPS те же.
|
||||
- Чтобы цена была такой: запись видеочипа в память ищет затронутую текстуру только по первому байту
|
||||
(нужна лишь текстура, начинающаяся с этого адреса; раньше обходился весь диапазон под мьютексом), а
|
||||
запись поверх страниц, которые процессор не менял и которые уже помечены как данные видеочипа,
|
||||
проходит без блокировки трекера.
|
||||
- Подмены «копирование текстуры через буферы» и «очистка текстуры через буфер» оставлены: путь через
|
||||
память (выгрузить отрисованный кадр в память, выполнить шейдер игры, перезалить текстуру) сейчас
|
||||
даёт застывшую картинку — содержимое целей рендера не доходит до памяти игры, а при рендере сцены в
|
||||
пониженном разрешении его там и нет. `BB_HLE_OFF=1|2|4` — опыт с отключением подмен,
|
||||
`BB_HLE_STATS=1` — сколько раз они срабатывают (~4, ~15 и ~10 за кадр).
|
||||
- Опыт `BB_GUEST_VRAM=1`: вся память игры в VRAM через Resizable BAR — 16 FPS уже в меню (процессор
|
||||
читает её через PCIe), не годится.
|
||||
|
||||
## Сохранения не портятся при вылете (#64)
|
||||
|
||||
- Bloodborne сохраняется примерно раз в секунду: удаляет `backupN`, переименовывает `userdataN` в
|
||||
`backupN` и пишет новый `userdataN` (1,3 МБ). Вылет или снятие процесса посреди записи оставляли
|
||||
обрезанный `userdataN`.
|
||||
- Теперь файл сохранения (`/savedataN/...`), открытый на запись, пишется во временную копию
|
||||
(`<имя>.<n>.bbtmp` рядом), а при закрытии она сбрасывается на диск (`fsync`) и одной операцией
|
||||
`rename` встаёт на место файла. Вылет посреди записи оставляет прежний файл (или его отсутствие,
|
||||
если игра уже переименовала его в `backupN`: тогда игра сама читает `backupN` — проверено).
|
||||
- Пока файл открыт, операции по пути (`stat`, `access`, `truncate`, повторное открытие) видят копию:
|
||||
игра проверяет размер записываемого файла по пути.
|
||||
- Копия не попадает в списки каталога; оставшиеся после вылета копии удаляются при монтировании.
|
||||
- `param.bin` и `icon0.png` записываются так же (временный файл, `fsync`, `rename`).
|
||||
- `BB_SAVE_TRACE=1` — все операции игры с файлами сохранений в журнал.
|
||||
|
||||
## Подготовка файлов игры и геймпад
|
||||
|
||||
- `prepare.py` и остальные скрипты, лаунчер: текстовые файлы читаются и пишутся в UTF-8 явно, вывод в
|
||||
консоль не падает на символах вне её кодировки (#55: китайская, японская, корейская локаль Windows,
|
||||
`™` в названии игры).
|
||||
- `eboot.bin` (и модули `sce_module`) принимаются и обычным ELF, без обёртки SELF: так их пишут
|
||||
некоторые программы дампа (#49). Проверено: ELF, извлечённый из нашего eboot, даёт тот же `boot.bin`
|
||||
байт в байт.
|
||||
- Стики (PR #71; #70): клон Switch Pro, у которого все четыре оси в покое смещены на
|
||||
~±16380 и ход вдвое меньше, калибруется — нейтраль берётся из спокойного окна после подключения,
|
||||
ход каждой оси — по её собственному диапазону. Мёртвая зона как в shadPS4: `BB_PAD_DEADZONE`
|
||||
(по умолчанию 5 из 127) и `BB_PAD_DEADZONE_OUTER` (127). `BB_PAD_CENTER=lx,ly,rx,ry` — нейтраль
|
||||
вручную, `BB_PAD_CENTER_CAL=0` — без замера.
|
||||
Отличие от PR: нейтраль принимается, только если смещены все четыре оси (иначе обычный геймпад,
|
||||
подключённый с зажатым стиком, запомнил бы этот наклон как нейтраль до переподключения); пока
|
||||
нейтраль не известна, стики читаются как раньше, а не стоят на месте.
|
||||
- README.ru.md: адрес репозитория в команде `git clone` (PR #43; в английском README он уже был).
|
||||
|
||||
## Зависания видеочипа: непрямые запуски, VRAM, сведения о видеокарте
|
||||
|
||||
- Непрямые запуски (#34, комментарий к #32; новая модель памяти): дважды игра теряла устройство на
|
||||
симуляции частиц, получившей вместо числа групп мусор (1,2 и 3,8 млрд групп; у нас в логах от
|
||||
2026-10-06 такое тоже было — 1,4 млрд и 6,4 млн, обошлось). Настоящие числа у Bloodborne — не больше
|
||||
нескольких сотен. Теперь перед каждым непрямым запуском шейдер из одного потока
|
||||
(`indirect_guard.comp`) копирует числа групп в наш буфер, обнуляя неправдоподобные (больше
|
||||
пределов устройства или `BB_INDIRECT_GUARD_MAX` групп всего, по умолчанию 4M), и запуск идёт из
|
||||
этой копии. Худшее, что теперь бывает, — пропущенный шаг частиц вместо вылета; пропуски
|
||||
печатаются строкой `Indirect dispatches: N skipped ...`. `BB_INDIRECT_GUARD=0` — как раньше.
|
||||
Причина мусора в памяти игры не найдена (только новая модель, редко). Цена: в пределах шума
|
||||
(183–184 FPS, видеочип 5,42–5,47 мс в одной сцене). Проверено с порогом 10 (пропуски
|
||||
срабатывают, игра идёт) и под слоем валидации (новых ошибок нет).
|
||||
- Перенос блоков памяти игры в VRAM теперь учитывает бюджет видеопамяти драйвера: если занято больше
|
||||
`BB_VRAM_PROMOTE_PERCENT` (по умолчанию 90 %), новые копии не создаются — блоки читаются на месте
|
||||
(медленнее, но без переполнения VRAM на картах с 8 ГБ), а перенос возобновляется, когда память
|
||||
освободится. Строка в логе при переключении. Число «MiB of loaded blocks moved ... to VRAM» —
|
||||
накопительное (сколько перенесено за сессию), а не занятое место; занятое — в строке `Memory:`.
|
||||
- В начале лога теперь строка с видеокартой, объёмом VRAM, драйвером и версией Vulkan (в отчётах
|
||||
о зависаниях, как #56, её не было).
|
||||
- #56 (старая модель, зависание при загрузке карты): два лога — два разных места остановки (обычная
|
||||
отрисовка из 5 индексов и копирования между проходами), шейдер из первого у нас работает 4–12 раз
|
||||
за кадр без проблем, те же патчи (Disable DoF, Motion Blur) у нас включены. Воспроизвести не
|
||||
удалось; без модели видеокарты и версии Mesa дальше не продвинуться (теперь они будут в логе).
|
||||
|
||||
## Баги из issues (2026-10-08, день)
|
||||
|
||||
- **Сборка FSR 4.1.1 там, где контейнер Steam не запускается (#61).** Bazzite + 9070 XT: ни один
|
||||
Proton «не запустил FSR 4.1», причина в списке была пустой, а в конце лога — `bwrap: No permissions
|
||||
to create a new namespace`: контейнер Steam (pressure-vessel, и под umu-run тоже) не может создать
|
||||
пространство имён — так бывает, когда сам лаунчер запущен в песочнице (Flatpak, ярлык Steam с
|
||||
рантаймом) или ядро это запрещает. Теперь при такой ошибке Proton запускается напрямую, без
|
||||
контейнера (сообщение `Steam's container could not start here (...): running Proton without it`,
|
||||
дальше до конца сборки так же); `BB_FSR4CAP_RUNNER=direct` — сразу так.
|
||||
Причина отказа каждого Proton — последняя непустая строка журнала записи, иначе ошибка контейнера
|
||||
или Wine (раньше — последняя строка, часто пустая). Один и тот же Proton больше не пробуется дважды
|
||||
по путям `/home/...` и `/var/home/...` (Fedora Atomic): одинаковые папки узнаются по устройству и
|
||||
inode, а не по `realpath`.
|
||||
Проверено: запись внутри `bwrap --disable-userns` (та же ошибка контейнера) — запасной путь
|
||||
записал кадры FSR 4.1.1 под GE-Proton 11-6, результат совпадает с обычной записью побайтно (кроме
|
||||
адресов указателей в `trace.txt`).
|
||||
- **MangoHud снова работает с системным MangoHud (#66).** С 0.3 `run.sh` при системном MangoHud
|
||||
отключал встроенный в AppImage слой по имени (`VK_LOADER_LAYERS_DISABLE`), но у системного слоя
|
||||
обычно то же имя (`VK_LAYER_MANGOHUD_overlay_64_x86_64`) — загрузчик Vulkan отключал оба. Теперь
|
||||
встроенный MangoHud убирается из путей поиска слоёв (`XDG_DATA_DIRS`), а системный остаётся.
|
||||
Проверено загрузчиком Vulkan (`VK_LOADER_DEBUG=layer`): раньше «forced disabled», теперь слой
|
||||
вставляется.
|
||||
- **Картинка предмета на экране загрузки не пропадает (#67, патч bmy).** Маски Scaleform рисуются
|
||||
без записи цвета; при выводе не 1080p они попадали в глубину игры, а следующая отрисовка UI
|
||||
переключалась на глубину UI размера вывода с очищенным трафаретом — картинка не проходила тест.
|
||||
Теперь отрисовки UI без цели цвета тоже идут в глубину UI. В игре не проверено (на macOS у автора —
|
||||
да).
|
||||
- **Выбор монитора (#69).** Окно и полноэкранный режим шли на монитор, который SDL считает основным.
|
||||
*Экран → Монитор* в лаунчере (`BB_DISPLAY`: номер или часть имени; список —
|
||||
`bb-gpu-capabilities --displays`), в логе при запуске — строки `Display N: ...` с отметкой
|
||||
выбранного. Проверено на Hyprland с двумя мониторами: полноэкранное окно открывается на выбранном
|
||||
(обычное окно на Wayland размещает композитор).
|
||||
- **Дебаг-меню: шрифты из мода находятся.** Патч дебаг-меню читает шрифты из
|
||||
`dvdroot_ps4/adhoc/font/DbgFont14h.ccm` и `.tpf` (и шейдеры `adhoc/FontShader/debugFont_*`),
|
||||
причём игра запрашивает имена в нижнем регистре (`dbgfont14h.ccm`, найдено с новым
|
||||
`BB_FILE_TRACE=1`). Проверка в `patches.py` искала их в `dvdroot_ps4/font` с точным регистром, а
|
||||
рантайм на Linux различал регистр — шрифты не находились ни модом, ни в дампе, и запуск падал с
|
||||
трассировкой Python. Теперь: рантайм, не найдя файл игры, ищет его без учёта регистра (как PS4 и
|
||||
shadPS4; только при промахе, без затрат для найденных файлов); проверка смотрит в `adhoc/`
|
||||
без учёта регистра; без шрифтов патч дебаг-меню не применяется (строка `Patches: debug menu off:
|
||||
...`, подсказка, если шрифты лежат в старом `dvdroot_ps4/font`), игра запускается; папка `adhoc`
|
||||
в моде узнаётся как папка игры. Проверено: мод `Adhoc/Font/DbgFont14h.*` открывается игрой
|
||||
(`Mods: open /app0/dvdroot_ps4/adhoc/font/dbgfont14h.ccm -> .../Adhoc/Font/DbgFont14h.ccm`).
|
||||
С настоящими шрифтами меню не проверено (их нет).
|
||||
- `BB_FILE_TRACE=1`: каждый путь, который игра открывает, проверяет или читает (`File trace: ...`).
|
||||
- **Экрана «Играть по сети / вне сети» больше нет.** У порта нет PSN; теперь игра сразу открывает
|
||||
главное меню в режиме вне сети — при запуске и после «Выйти из игры», с сохранением и без. Патч игры
|
||||
«Skip Online/Offline Choice» (`patches/Bloodborne.xml`): функция, которая строит этот диалог
|
||||
(`0x1b39030`, найдена по ID строк 401010/401011 из `menu.msgbnd`), возвращает то же, что вернул бы
|
||||
её пункт «ИГРАТЬ ВНЕ СЕТИ» (вызов его обработчика `0x1b49cd0`, vtable `0x533be30`): следующий
|
||||
диалог цепочки, так что выбор не показывается. Включается `patches.py` по умолчанию (лаунчер:
|
||||
*Эффекты игры → Пропускать выбор*, `BB_SKIP_NETWORK_CHOICE=0` — показывать). Прежний вариант
|
||||
(порт нажимал «крест», экран мелькал) удалён. `tools/restart.sh` по-прежнему показывает выбор
|
||||
(его сценарий сам нажимает на титуле). Проверено скриншотами: запуск без ввода — сразу главное
|
||||
меню; «Продолжить» → «Выйти из игры» — сразу главное меню.
|
||||
- Память при повторной загрузке локации (6 циклов «Продолжить → выйти», новая модель): RSS
|
||||
707 → 733 МиБ, VRAM выходит на ~3,7 ГБ; старая модель (4 цикла): RSS 3735 → 3795 МиБ, VRAM ~3 ГБ.
|
||||
Утечки на гигабайты (сообщение из Discord про телепорты) так не видно; телепорт между разными
|
||||
локациями не проверен.
|
||||
- **Нехватка видеопамяти у копий памяти игры не роняет игру.** Старая модель держит копии памяти
|
||||
игры в блоках VRAM по 64 МиБ; на картах с 4 ГБ (RTX 3050 mobile, сообщение из Discord) выделение
|
||||
блока могло вернуть `ErrorOutOfDeviceMemory`, и игра останавливалась (`vk_platform.h:73`, код 23).
|
||||
Теперь такой блок берётся из системной памяти, которую GPU читает по шине (строка `Guest memory:
|
||||
VRAM is full ...`): медленнее, но без вылета. `BB_RESIDENCY_VRAM_LIMIT_MB=N` — проверка (VRAM
|
||||
«кончается» после N МиБ блоков). Проверено с 32 МиБ: игра идёт, картинка верна, 28 FPS (всё в
|
||||
системной памяти; в жизни туда уходит только излишек). То ли это место, где упал отчёт из
|
||||
Discord, не доказано — строки перед остановкой в нём нет.
|
||||
- **«Чтение данных GPU: Precise» больше не замораживает первую катсцену.** Новая игра → катсцена
|
||||
стояла на первом кадре (звук шёл): видеоплеер писал кадр ролика в память, которую GPU писал
|
||||
раньше; обработчик попросил поток GPU о чтении, а тот, снимая копию байтов игры для «двойников»
|
||||
(`BB_GPU_WRITE_TWINS`) под их мьютексом, сам попал на защищённую от чтения страницу и в
|
||||
обработчике ждал тот же мьютекс. Найдено по стекам потоков (SIGUSR2). Теперь байты игры для
|
||||
«двойников» читаются через вид без защиты (`ReadBacking`), а с `BB_READBACKS=2` «двойники»
|
||||
выключены: страница с байтами GPU, в которую игре можно писать, была бы «только для записи»
|
||||
(следующей остановкой был `page_manager.cpp: ... write-only`). Проверено: новая игра с
|
||||
`BB_READBACKS=2` и без — катсцена идёт до создания персонажа.
|
||||
- **Меню настроек — как в ПК-играх, в стиле Bloodborne.** Вместо окна ImGui поверх игры
|
||||
(Insert / L3+R3): игра затемнена, по центру панель с орнаментными линиями, как у диалогов самой
|
||||
игры (шрифт с засечками DejaVu Serif, встроен рядом с DejaVu Sans), заголовок и вкладки
|
||||
«Изображение / Апскейлер / Эффекты игры / Дополнительно» (L1/R1, Q/E, PageUp/PageDown, мышь).
|
||||
Каждая настройка — строка «название ◀ значение ▶»: вверх/вниз (крестовина, стик, стрелки) —
|
||||
выбор строки, влево/вправо — значение, Крест/Enter — следующее значение, мышь — клик по
|
||||
стрелкам или строке, ползунки тянутся мышью. Описание выбранной настройки — внизу (вместо «(?)»),
|
||||
там же предупреждение о перезапуске; строка «Применить и перезапустить игру» — когда нужно.
|
||||
Подсказки кнопок — в подвале; Esc / Круг / Insert / L3+R3 — закрыть. Недоступные значения
|
||||
(FSR 4 без поддержки) пропускаются, зависимые строки гаснут (пресет при TAA, сила резкости без
|
||||
резкости, маска реактивности). Фокус — свой (навигация ImGui до строк не доходила).
|
||||
`BB_MENU_KEYS_FILE=<файл>` — сценарное управление меню для проверок (`toggle up down left right
|
||||
enter back l1 r1 kup kdown`).
|
||||
- **Настройки порта — родные страницы в меню игры «Система».** После «Экран/звук» появились пункты
|
||||
«Изображение», «Эффекты игры» и «Патчи игры»: их строит и рисует сама игра (её строки, списки,
|
||||
ползунок, подсказка внизу, «По умолчанию» с подтверждением), и на титульном экране, и в паузе.
|
||||
«Изображение»: разрешение вывода, апскейлер (в списке только то, что эта видеокарта и сборка
|
||||
умеют: без NVIDIA нет DLSS), пресет, резкость (ползунок 0–10, 0 — выкл, 10 = 2.0), счётчик FPS —
|
||||
меняются сразу и пишутся в `bbport.ini`. «Эффекты игры» / «Патчи игры»: детализация моделей и
|
||||
патчи-эффекты (после перезапуска). «По умолчанию» ставит значения порта по умолчанию. Тексты на
|
||||
языке самой игры (русский — если её тексты на кириллице, иначе английский). Как устроено
|
||||
(`gpu/shim/bbport_game_menu.cpp`): перехват поиска текстов игры (свои id 0x7F0000+) и добавления
|
||||
пункта в меню (0x1b4e2a0, после «Экран/звук»); страница — макет «ControllSetting» со своими
|
||||
строками и заголовком; последний аргумент строк игры — указатель на значение по умолчанию.
|
||||
Каждая перехваченная функция сверяется побайтно, `BB_GAME_MENU=0` — выключить. Проверено: 16
|
||||
открытий страниц — рост памяти как у родных страниц игры; оверлей (Insert / L3+R3) остался.
|
||||
- Ровность 60 FPS со временем (сообщение из Discord: «через некоторое время кадры неровные»):
|
||||
6 минут стоя, `BB_FPS=60` — каждую минуту 16,67 мс, разброс 0,00–0,01 мс, ни одного кадра
|
||||
дольше 20 мс (кроме загрузки в первой минуте). На RX 7800 XT не воспроизводится.
|
||||
|
||||
## Влитые PR (2026-10-08, вечер)
|
||||
|
||||
- **PR #84: DLC.** Папки `<user>/addcont/<title>/<метка>` (как у shadPS4) сообщаются игре
|
||||
как установленные дополнения: сохранения с The Old Hunters загружаются, области DLC доступны
|
||||
(#33). Данные дополнений не монтируются — The Old Hunters нужна только метка, данные в патче
|
||||
1.09. При вливании: `_GNU_SOURCE` под `#ifndef` (тест собирает с `-D_GNU_SOURCE` и `-Werror`), в
|
||||
тест AppContent — заглушка папки пользователя и проверка: папка `addcont/CUSA00900/SPEXPANSIONDLC03`
|
||||
даёт одну запись «установлено».
|
||||
- **PR #80:** `BB_FSR4_STATS=1` больше не ломает пайплайны FSR 4 v07 без
|
||||
`VK_EXT_pipeline_executable_statistics`. Патч к подмодулю FSR-Vulkan изменился: рабочую копию
|
||||
подмодуля нужно вернуть (`git -C gpu/third_party/fsr-vulkan checkout -- src/ffx_vk_fsr4_v07.c`), и
|
||||
`build.sh` наложит новую версию.
|
||||
- **PR #78:** лаунчер — кнопки «Копировать» и «Экспорт лога…» на вкладке «Журнал».
|
||||
- **PR #75:** лаунчер на упрощённом китайском (строки, добавленные сегодня, — на
|
||||
английском до перевода).
|
||||
- **PR #83: DLSS на Linux.** Мост `gpu/dlss_bridge` (MIT, единственный код с SDK NVIDIA)
|
||||
собирается с `DLSS_SDK_ROOT=<github.com/NVIDIA/DLSS> bash build.sh` в `out/libbbport_dlss.so`,
|
||||
рядом копируется библиотека NVIDIA; игра загружает мост при запуске. Новый апскейлер `dlss`
|
||||
(лаунчер, меню, `bbport.ini`): те же входы, что у FSR 3.1, Native AA = DLAA, при ошибке — FSR 3.1.
|
||||
Без моста и библиотеки, на не-NVIDIA или с `BB_DLSS=0` ничего не меняется (DLSS в меню недоступен).
|
||||
При вливании: пункт DLSS и его описание перенесены в новое меню, строка в списке апскейлеров
|
||||
лаунчера — после строки языков PR #75. Проверено здесь: сборка без SDK, игра на AMD (FSR 4.1.1,
|
||||
FSR 4 v07 со статистикой). С DLSS не проверено (нет NVIDIA); автор — RTX 4090. В AppImage мост и
|
||||
библиотека NVIDIA не входят.
|
||||
|
||||
## После 0.5-pre1 (2026-10-09)
|
||||
|
||||
- **Новая модель памяти снова только для AMD.** Лог с GTX 1660 Ti (драйвер 615.71, Hyprland):
|
||||
импорт памяти хоста прошёл проверку при запуске, но после первого переноса блоков в VRAM
|
||||
(`84 MiB of loaded blocks moved`) — `GPU watchdog: submission 4114 not finished after 10 s`:
|
||||
видеочип закончил шейдер копирования и не начинал следующий запуск. Отправка ждёт семафор
|
||||
перепривязки памяти (`vkQueueBindSparse` арены), и на NVIDIA каждая такая перепривязка держала
|
||||
видеочип 10 секунд и дольше; рабочий стол вставал вместе с ним, со стороны — «зависает вся
|
||||
система». Проверка при запуске этого не ловит (там одна маленькая привязка). Теперь на NVIDIA
|
||||
переключатель недоступен, у кого он был включён — старая модель (лаунчер передаёт
|
||||
`BB_PC_MODEL=0`, библиотека GPU тоже не включает её на NVIDIA); `BB_PC_MODEL_ANY_GPU=1` — всё же
|
||||
попробовать. README и тексты лаунчера исправлены.
|
||||
- `BB_RESIDENCY_REPORT=<файл>` (диагностика новой модели): когда файл появляется, в журнал —
|
||||
блоки памяти игры, которые видеочип недавно читал на месте, а не из VRAM, и почему они не
|
||||
перенесены (процессор пишет часто; байты, о записи которых мы не знаем; ждут переноса).
|
||||
У лампы в Кошмаре охотника: ~1,2 ГБ таких блоков памяти Garlic целиком «неизвестны».
|
||||
- Сообщение «первая загрузка медленнее, после телепорта 90 FPS» (RX 7900 XTX, новая модель): здесь
|
||||
не воспроизвелось — первая и повторная загрузка (выход в титул, «Продолжить») 131,7 и 131,9 FPS
|
||||
на RX 7800 XT; переносы в VRAM после загрузки заканчиваются за секунды. Нужен лог тестера.
|
||||
|
||||
## Новая модель на NVIDIA: разбор (2026-10-09, продолжение)
|
||||
|
||||
- **Причина зависания найдена.** Это известная регрессия проприетарного драйвера NVIDIA на Linux
|
||||
(с 555 и до сих пор, у тестера 615): время `vkQueueBindSparse` растёт с числом страниц, **уже**
|
||||
привязанных во всех sparse-ресурсах, и вызов держит глобальную блокировку (форум разработчиков
|
||||
NVIDIA, «Sparse texture binding is painfully slow»: 9200 страниц — 3,6 с; исправления нет).
|
||||
В арене новой модели — гигабайты страниц по 64 КиБ (у тестера 863 МиБ привязано на месте ещё
|
||||
до первых переносов), так что каждый перенос блоков в VRAM стоил секунды. Игра сама заметила
|
||||
остановку видеочипа ещё до первого переноса («Stall during rendering at flush 1»).
|
||||
- **Почему не обойти «одной правкой».** Замер `BB_RESIDENCY_MIX=1` (новая диагностика): ~17 тыс.
|
||||
привязок в секунду (~85 за кадр) — диапазоны в сотни МБ, где одновременно блоки в VRAM и на
|
||||
месте (шейдеры, привязанные ко всей памяти; треть — поверх данных, записанных видеочипом).
|
||||
Одна sparse-арена смешивает их бесплатно; схема «VRAM-арена + отдельные буферы памяти игры»
|
||||
их не обслужит. Без перепривязок вообще (`BB_FIXED_ARENA=1`, всё читается на месте через шину):
|
||||
**48,6 FPS против ~205** на RX 7800 XT — хуже старой модели.
|
||||
- Итог: новая модель остаётся только для AMD. Для NVIDIA нужна либо починка драйвера (или
|
||||
Mesa NVK, где sparse работает нормально), либо программная подкачка страниц в транслированных
|
||||
шейдерах вместо sparse — многодневная переделка.
|
||||
- Добавлено: `BB_FIXED_ARENA=1/0` (арена держит первые привязки: без переносов в VRAM, блоки вне
|
||||
кусков памяти игры — в системной памяти; по умолчанию — при импорте памяти хоста, т. е. на NVIDIA
|
||||
с `BB_PC_MODEL_ANY_GPU=1`); строка в журнале `vkQueueBindSparse of N ranges took X ms` (дольше
|
||||
50 мс, в обеих моделях); в отчёте сторожа видеочипа — `Arena binds: ...` (ждут ли отправки
|
||||
незавершённую привязку); `BB_RESIDENCY_MIX=1` — привязки «на месте / VRAM / смешанные» за 2 с.
|
||||
|
||||
## Новая модель на всех видеокартах: модуль памяти прослойки (2026-10-09)
|
||||
|
||||
- **Новая модель включается на любой видеокарте.** На AMD — как раньше, sparse-арена. На NVIDIA,
|
||||
Intel и остальных — модуль памяти прослойки (`gpu/layer`, docs/MEMORY_MODULE_PLAN.ru.md): память
|
||||
игры привязывается на месте через буферы её кусков, копии в VRAM — отдельные буферы («зеркала»),
|
||||
перенос — копия плюс учёт в модуле. `vkQueueBindSparse`, из-за которого на NVIDIA зависали игра
|
||||
и рабочий стол, в этом режиме не вызывается ни разу. Вручную: `BB_LAYER_MEMORY=1/0`. Лаунчер
|
||||
больше не прячет переключатель на не-AMD; README и подсказка (три языка) исправлены. **На
|
||||
NVIDIA не проверено** — нужен лог тестера.
|
||||
- Замеры на RX 7800 XT, стоя: было 48–60 FPS в режиме модуля, стало ~205 (sparse ~205–238, старая
|
||||
модель ~220). В другом месте: модуль 167,5, sparse 164,5, старая модель 146. 5 минут ходьбы с
|
||||
подгрузкой областей — без ошибок, 166–240 FPS.
|
||||
- Что мешало (найдено по профилю видеочипа):
|
||||
- **HLE копий и очисток образов не срабатывало.** Детекторы `IsComputeImageCopy` /
|
||||
`IsComputeImageClear` требуют у шейдера ровно два буфера, а в режиме модуля каждому шейдеру
|
||||
с буферами игры добавлялся третий — таблица страниц. Копия памяти целей рендеринга
|
||||
(`cs 3d5ebf4e`) и очистка (`cs 8b355b5a`, 31 запуск за кадр) шли настоящими шейдерами через
|
||||
память, а образы перезагружались из неё каждый кадр (~16 образов 1080p вместо ~2,6).
|
||||
Теперь таблица страниц не считается (`ShaderBufferCount`): 60 → 136 FPS.
|
||||
- **Смешанные диапазоны.** Диапазон, у которого все блоки в VRAM, кроме одного с «неизвестными»
|
||||
байтами (край, промежуток между образами), целиком читался через PCIe (8 МБ на привязку).
|
||||
Теперь такой блок «летучий» в зеркале: обновляется из памяти игры перед каждой привязкой, то,
|
||||
что запуск записал, копируется обратно после запуска. 139 → 207 FPS. `BB_LAYER_VOLATILE=0` —
|
||||
выключить.
|
||||
- Перенос в VRAM при первой привязке диапазона известных данных (как делала арена); он
|
||||
соблюдает `BB_GARLIC_VRAM=0` и бюджет VRAM (`BB_VRAM_PROMOTE_PERCENT`, важно для карт с 6 ГБ).
|
||||
- Стартовая проверка импорта памяти хоста в режиме модуля проверяет запись видеочипа и процессора
|
||||
через сам импортированный буфер, без sparse-буфера.
|
||||
- Диагностика: `BB_RESIDENCY_MIX=2` — ещё и самые тяжёлые привязки на месте / смешанные с
|
||||
разбором блоков (VRAM, подходят, «динамические», неизвестные байты); в строке `Layer memory:` —
|
||||
число вызовов `vkQueueBindSparse` и байты, скопированные обратно.
|
||||
|
||||
## Модуль памяти: взрывы вершин и скорость (2026-10-09, день)
|
||||
|
||||
Итог работы над новой моделью для NVIDIA — в `docs/NVIDIA_MEMORY_MODEL.ru.md`: ловушки записи на
|
||||
блоках с копией в VRAM, чтения через модуль везде, где есть копия, данные процессора больше не
|
||||
затираются данными видеочипа, запись видеочипа в VRAM только в блоки, которые процессор не трогал
|
||||
(`BB_LAYER_GPU_WRITES`), шейдер копирования в режиме модуля через HLE, кэши ответов модуля.
|
||||
|
||||
## 0.5-pre2: оригинальное GPU-копирование и переносимые метки
|
||||
|
||||
В итоговой сборке шейдер копирования в новой модели теперь нативный по умолчанию: его записи
|
||||
согласованы между памятью игры и зеркалами VRAM. Добавлены стандартные Vulkan-метки завершения
|
||||
для GPU без `VK_AMD_buffer_marker`, исправлены зависимости записи/чтения буферов и миграция
|
||||
всего кэша при изменении формата. Подробное описание релиза и проверок:
|
||||
[CHANGES_0.5-pre2.md](CHANGES_0.5-pre2.md).
|
||||
|
||||
## 0.5-pre3: модуль памяти на NVIDIA
|
||||
|
||||
По первым логам с GTX 1660 Ti: копии в VRAM снова включены для модуля (их выключал обход
|
||||
sparse-арены), общий бюджет VRAM с кэшем текстур, запас роста копий вместо их перевыделения,
|
||||
записи WRITE_DATA в копию, наблюдаемые блоки (`BB_LAYER_WATCH`), повтор чтения файлов при EFAULT.
|
||||
Подробности: [CHANGES_0.5-pre3.md](CHANGES_0.5-pre3.md) и
|
||||
[NVIDIA_MEMORY_MODEL.ru.md](NVIDIA_MEMORY_MODEL.ru.md).
|
||||
|
||||
## 0.5-pre4: компиляция шейдеров в фоне, VRAM на картах 4–6 ГБ, меню как в 0.3
|
||||
|
||||
Новые конвейеры проходов, рисуемых каждый кадр, компилируются в фоновых потоках
|
||||
(`BB_ASYNC_PIPELINES`); у копий памяти игры в VRAM своя доля бюджета (регрессия pre3 на картах
|
||||
4 ГБ); после перемещений VRAM освобождается от копий покинутой локации; меню настроек в игре —
|
||||
снова одно окно, как в 0.3 и 0.4. Подробности: [CHANGES_0.5-pre4.md](CHANGES_0.5-pre4.md).
|
||||
@@ -0,0 +1,159 @@
|
||||
# Изменения после 0.5 (с 2026-10-10)
|
||||
|
||||
Замеры — RX 7800 XT / RADV, сохранение пользователя (Соборный округ), 1080p.
|
||||
|
||||
## Все розничные издания получают профиль игры (#119)
|
||||
|
||||
- Профиль Bloodborne (`gpu/games/bloodborne.cpp`) выбирался только для CUSA03173. Американское
|
||||
издание (CUSA00900) и остальные регионы запускают тот же исполняемый файл 1.09, но шли без
|
||||
профиля, и новая модель падала при входе в мир: `Guest fault ... at guest offset 0x2085xxx,
|
||||
address (nil)` в аллокаторе игры (#119, RX 7600, US-издание).
|
||||
- Воспроизведено у себя на CUSA03173 с `BB_GAME_PROFILE=none`: то же падение (`0x208596a`) при
|
||||
входе в мир. С профилем, но без перехватов (`BB_GUEST_HOOKS=0`) — не падает: спасает
|
||||
`DynamicWriters` — код аллокатора, чьи служебные данные лежат в памяти GPU; без этой отметки
|
||||
их блоки уходят в VRAM-копию.
|
||||
- Профиль, проверка игры (`scripts/game_check.py`), патчи (`scripts/patches.py`), «звуковой
|
||||
фикс» сохранений и папки модов теперь знают все издания: CUSA00900, CUSA00207, CUSA00208,
|
||||
CUSA00299, CUSA01363 и издания с The Old Hunters CUSA03179, CUSA03173, CUSA03014, CUSA03023.
|
||||
- Проверка игры: другие регионы базовой игры без обновления просят 1.09 вместо «поддерживается
|
||||
только CUSA03173»; eboot.bin со вшитым патчем 60 FPS (падает в меню жестов) — отдельное
|
||||
сообщение (PR #117).
|
||||
- Осталось: общий путь без профиля должен не падать сам (служебные данные аллокатора в
|
||||
VRAM-копии). Сейчас он нужен только для чужих игр.
|
||||
|
||||
## Размытие в движении на весь кадр в новой модели (#122)
|
||||
|
||||
- С включённым размытием в движении (по умолчанию) кадр при повороте камеры размазывался целиком,
|
||||
в старой модели — нет (#122, RX 9060 XT). Воспроизведено: резкость кадра во время поворота
|
||||
(стандартное отклонение лапласиана) 6,9 против 8,5–12 в старой модели.
|
||||
- Поиск: `BB_GARLIC_VRAM_RANGE=начало,конец` (новый диагностический ключ: VRAM-копии только в
|
||||
этом диапазоне) и деление диапазона пополам — блок 64 КиБ `0x104ff00000`. Его читает только
|
||||
видеочип (буфер 11,4 МиБ каждый кадр), записей буферами и процессором нет: это память
|
||||
рендер-таргета, который игра потом читает как буфер.
|
||||
- Причина: выгрузка изображения в память игры шла через staging и отложенную запись процессора,
|
||||
когда у этой памяти была VRAM-копия; копия обновлялась лишь после той записи (инвалидацией) —
|
||||
буфер читал данные прошлых кадров. Теперь видеочип копирует изображение и в арену (VRAM-копию)
|
||||
в порядке потока; в память игры — как раньше. И `IsRegionGpuModified` считает изменённым то,
|
||||
что видеочип записал в VRAM-копию (`gpu_written_bytes`, не на месте): без этого обновление после
|
||||
записи процессора поверх затирало копию старыми байтами (`BB_GPU_DATA_CHECK=0` — как раньше).
|
||||
Нужны обе правки. После: 11,9–13,0, как в старой модели; FPS тот же (127–131 в обоих
|
||||
вариантах, по три запуска).
|
||||
|
||||
## Нехватка VRAM на 4 ГБ больше не останавливает игру
|
||||
|
||||
- RTX 3050 4 ГБ, старая модель (Авто на NVIDIA), 0.5: три падения за вечер —
|
||||
`Failed to allocate 64 MiB for guest memory copies: ErrorOutOfDeviceMemory`. Запасного типа
|
||||
памяти (системной) для арены нет: разреженные буферы NVIDIA берут только VRAM. В pre5
|
||||
сборщик текстур стал держать текстуры по 5 с (FPS не падал со временем), и на 4 ГБ VRAM
|
||||
заканчивалась.
|
||||
- Теперь: блок поменьше (ровно запрошенный), затем любой другой тип памяти, к которому можно
|
||||
привязать арену; и 30 с сборщик под давлением снова выселяет по отправкам, как до 0.5. Он же
|
||||
делает так сам, когда занято больше 92 % бюджета драйвера (`VK_EXT_memory_budget`, раз в
|
||||
секунду). Проверить можно только на такой карте.
|
||||
|
||||
## Выход из игры с геймпада (#74, #116)
|
||||
|
||||
- Оверлей (Insert или L3+R3): кнопка «Выйти из игры», второе нажатие подтверждает; игра
|
||||
закрывается как по кнопке окна.
|
||||
|
||||
## Мышь
|
||||
|
||||
- Камера мышью: щелчок в окне игры захватывает мышь (относительный режим SDL), F1 или уход из
|
||||
окна — отпускает; меню настроек и ввод имени тоже отпускают. Движение мыши — правый стик:
|
||||
отклонение по скорости мыши (~1000 пикселей/с — полный поворот при чувствительности 1), за
|
||||
60 мс спадает; движущаяся мышь сразу проходит мёртвую зону игры (`BB_MOUSE_DEADZONE`, 16 из
|
||||
127), так что медленное прицеливание тоже поворачивает камеру. Одинаково при любом FPS.
|
||||
- Кнопки мыши и колесо — те же «клавиши» в привязках: `Mouse Left` R1, `Mouse Right` L2 (огнестрел),
|
||||
`Mouse Middle` R3 (захват цели), `Mouse X1` R2, `Mouse X2` L1, колесо — крестовина вверх/вниз
|
||||
(быстрые предметы); каждое деление колеса — короткое нажатие. Кнопки работают только при
|
||||
захваченной мыши: щелчок, который её захватывает, не атакует.
|
||||
- bbport.ini: `mouse_look=0/1`, `mouse_sensitivity` (0.05–20), `mouse_invert_y`; лаунчер —
|
||||
*Управление*: «Камера мышью», чувствительность, инверсия; «Клавиатура и мышь» — назначение
|
||||
кнопок, «Назначить» принимает и кнопку мыши/колесо. Основа — PR #108 (виртуальный стик от
|
||||
движения мыши); раскладка клавиатуры не менялась.
|
||||
|
||||
## Прочее
|
||||
|
||||
- Swapchain пересоздаётся через `oldSwapchain` (PR #93): на NVIDIA под Wayland пересоздание
|
||||
падало с «Surface already has a tearing controller».
|
||||
- `launcher/bb-launcher.sh` передаёт аргументы (`--play`) и через nix-shell (PR #120).
|
||||
- Запись FSR 4.1.1 из AppImage на SteamOS и других дистрибутивах (PR #89): запись на хосте
|
||||
через systemd, повтор с GPU, представленным как RX 7800 XT, если DLL не предлагает FSR 4.1.
|
||||
- Лаунчер: у DLSS — подсказка, есть ли он в этой сборке (в AppImage его нет: DLSS SDK от NVIDIA
|
||||
не распространяется, игра включает FSR 3.1).
|
||||
|
||||
## DLSS в AppImage и своя библиотека NVIDIA
|
||||
|
||||
- Сборка с `DLSS_SDK_ROOT` (DLSS SDK 310.9.1 с github.com/NVIDIA/DLSS) кладёт в пакет мост
|
||||
`libbbport_dlss.so`, `libnvidia-ngx-dlss.so.310.9.1` и `NVIDIA-DLSS-LICENSE.txt` (лицензия RTX
|
||||
SDK разрешает распространение в составе приложения, не отдельно). Тестовый AppImage:
|
||||
`dist/…-test-1010-dlss.AppImage`.
|
||||
- Лаунчер, *Апскейлер → DLSS: библиотека NVIDIA → Выбрать файл…* — как DLL для FSR 4.1.1:
|
||||
`libnvidia-ngx-dlss.so.<версия>` копируется в `<user>/dlss/`, игра берёт её раньше встроенной
|
||||
(лог: `DLSS: NVIDIA's library from …`). Выбранная `nvngx_dlss.dll` — подсказка, что нужна
|
||||
библиотека для Linux. Мост ищется рядом с `bb-probe`, затем в `<user>/dlss/`.
|
||||
- Мост собирается и с защитными флагами Nix (`-Werror=format-security`).
|
||||
- Проверено на RX 7800 XT только до «not an NVIDIA GPU»: путь к библиотеке (встроенной и
|
||||
своей) выбирается верно. Сам DLSS — на карте NVIDIA RTX.
|
||||
|
||||
## Сборка из git после обновления с 0.4 (#124)
|
||||
|
||||
- `build.sh` останавливался: «patch failed: src/ffx_vk_fsr4_v07.c:35» — в подмодуле FSR-Vulkan
|
||||
оставался применённым патч прошлой версии, а новый не применялся ни вперёд, ни назад. Теперь
|
||||
подмодуль в этом случае сбрасывается и патчи применяются заново (проверено на копии в таком
|
||||
состоянии).
|
||||
|
||||
## Онлайн (shadNet) — отдельным модулем
|
||||
|
||||
- `gpu/bbnet` → `out/gpu/libbbnet.so`: сетевые и PSN-библиотеки shadPS4 из shadp2p (форк shadPS4,
|
||||
GPL-2.0) с клиентом shadNet, перенесены из Linux-форка bbport с онлайном (а тот — из Windows-порта).
|
||||
Модуль собирается отдельной целью, его C++ скрыт (`-fvisibility=hidden`, `-Bsymbolic`), наружу —
|
||||
только `bbnet_init` и `bbnet_resolve` (`gpu/bbnet/bbnet.h`). Свои заголовки модуля
|
||||
(`gpu/bbnet/include`) только дополняют общие: в `gpu/shim` и `gpu/shadps4` ничего не менялось.
|
||||
- Рантайм (`src/runtime_net.c`): с `BB_ONLINE=1` на первом сетевом/PSN-импорте загружает модуль
|
||||
(`dlopen`, `RTLD_LOCAL`; `BB_NET_MODULE` — другой путь), отдаёт ему данные игры и гостевые потоки
|
||||
для обратных вызовов NP; трофеи, голос и диалоги магазина остаются в рантайме. Без `BB_ONLINE`
|
||||
модуль не загружается; без модуля или если он не стартовал — офлайн, как раньше.
|
||||
- Сборка: protobuf, nlohmann_json, OpenSSL, zlib, miniupnpc (`shell.nix`); без них модуль не
|
||||
собирается (`BB_NET=OFF` — вручную), порт собирается как раньше. AppImage содержит модуль.
|
||||
- `run.sh`: перенаправления адресов (`scripts/online.py`: сервер игры → The Hunter's Dream,
|
||||
знаки призыва → WebAPI shadNet), сервер shadNet по умолчанию `srv.shadps4.net:31313`.
|
||||
- Лаунчер: страница *Онлайн* (сервер игры, сервер кооператива и WebAPI, учётная запись shadNet,
|
||||
UPnP, проверка соединения); `settings.json` — только для владельца (0600, там пароль).
|
||||
- UPnP: порт P2P теперь открывается на роутере, когда транспорт готов, и закрывается при выходе
|
||||
(#121: `AddMapping` не вызывался нигде).
|
||||
- Проверено: `tests/test_online.c` (импорты сети и NP → модуль, трофеи → рантайм); игра с
|
||||
`BB_ONLINE=1` без учётной записи доходит до уровня (модуль: 1399 функций; «no users connected
|
||||
to shadNet»). Вход в shadNet и призыв не проверены: нет учётной записи, а UDP-часть публичного
|
||||
сервера, по #121, не отвечает.
|
||||
- HTTPS в AppImage: «Не удалось получить информацию от сервера Bloodborne» — проверка сертификата
|
||||
The Hunter's Dream проваливалась (`SSL server verification failed`): OpenSSL из Nix берёт корневые
|
||||
сертификаты из `/etc/ssl/certs/ca-certificates.crt`, а на NixOS это ссылка в `/nix/store` хоста,
|
||||
которого внутри AppImage не видно. Обёртки пакета теперь задают `SSL_CERT_FILE` на свой пакет
|
||||
сертификатов (`nss-cacert`), если указанный не читается; `run.sh` из исходников берёт системный.
|
||||
Лаунчер: текст ошибки в проверке соединения не терялся из-за разметки (`<urlopen error …>`), значки
|
||||
— из темы Adwaita.
|
||||
|
||||
## Мерцание главного меню при выводе выше 1080p
|
||||
|
||||
- С живой сменой разрешения (вывод 3840×2160 на мониторе 2560×1080) главное меню мерцало: часть
|
||||
кадров показывалась в родных 1920×1080 игры, остальные — с интерфейсом в разрешении вывода
|
||||
(4 из 50 снимков). `BB_UI_TRACE=1` (новая диагностика: отрисовки кадров без интерфейса в
|
||||
разрешении вывода) показал: пока меню анимирует подсветку, игра рисует его другими шейдерами
|
||||
Scaleform (`bb4d5f8c`, `e94b5b06`, `9951d199`, `44072322`, `a334a845`), а не `09957251`; их не было в
|
||||
списке шейдеров интерфейса (`ui_composition.h`), и такие кадры не собирались в разрешении
|
||||
вывода. После: 0 из 80; в уровне картинка та же.
|
||||
|
||||
## AppImage меньше
|
||||
|
||||
- В пакете были весь Mesa с LLVM (~800 МБ: нужны только Vulkan-драйверы RADV и ANV), полный GCC
|
||||
и заголовки Vulkan (их пути в отладочной информации `bb-probe`), 32-битная половина MangoHud
|
||||
(вторые glibc, gtk3, icu, perl) и GStreamer у GTK4 лаунчера. Теперь: свои RADV (без LLVM, ACO)
|
||||
и ANV без остального Mesa, `bb-probe` без отладочной информации, MangoHud 64-битный, GTK4 без
|
||||
GStreamer, печати и tracker.
|
||||
- Ещё: SDL3 без зашитого zenity (тот тянул вторую GTK4 с GStreamer; теперь zenity хоста, если
|
||||
есть), libdecor без плагина GTK 3 (у SDL3 и у glfw MangoHud; рамки рисует его cairo-плагин),
|
||||
MangoHud без xdg-utils (Perl; `xdg-open` хоста). Сборка своей Mesa включает Dozen только потому,
|
||||
что рецепт nixpkgs ждёт его выход `spirv2dxil`; в пакет он не попадает.
|
||||
- Итог: AppImage 925 → 399 МБ, пакет без сжатия 2,85 → 1,06 ГБ. Проверено: лаунчер открывается,
|
||||
игра из пакета стартует на встроенном RADV до титульного экрана.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Game compatibility
|
||||
|
||||
bbport runs Bloodborne for PS4 with **update 1.09**. Its hooks and patches use the addresses of
|
||||
one executable: the launcher hashes the loaded `eboot.bin` image and runs only that one 1.09
|
||||
executable (`scripts/game_check.py`). A dump that passes the check runs; one that does not is
|
||||
told why (no 1.09 update, another executable, or an `eboot.bin` with Lance McDonald's 60 fps
|
||||
patch baked in).
|
||||
|
||||
## Releases the launcher accepts
|
||||
|
||||
Every retail release of Bloodborne. Title and content IDs as listed in
|
||||
[deadinside28/bloodborne_pc#117](https://github.com/deadinside28/bloodborne_pc/pull/117).
|
||||
|
||||
| Edition | Region | Title ID | Content ID | 1.09 executable checked |
|
||||
|---|---|---|---|---|
|
||||
| Bloodborne | US | `CUSA00900` | `UP9000-CUSA00900_00-BLOODBORNE000000` | Yes |
|
||||
| Bloodborne | Europe | `CUSA00207` | `EP9000-CUSA00207_00-BLOODBORNE0000EU` | Not yet |
|
||||
| Bloodborne | UK | `CUSA00208` | `EP9000-CUSA00208_00-BLOODBORNE0000UK` | Not yet |
|
||||
| Bloodborne | Japan | `CUSA00299` | `JP9000-CUSA00299_00-BLOODBORNE0000JP` | Not yet |
|
||||
| Bloodborne | Asia | `CUSA01363` | `HP9000-CUSA01363_00-BLOODBORNE0000AS` | Not yet |
|
||||
| The Old Hunters Edition | US | `CUSA03179` | `UP9000-CUSA03179_00-BLOODBORNE000000` | Not yet |
|
||||
| Game of the Year Edition | Europe | `CUSA03173` | `EP9000-CUSA03173_00-BLOODBORNE0000EU` | Yes |
|
||||
| The Old Hunters Edition | Japan | `CUSA03014` | `JP9000-CUSA03014_00-BLOODBORNE0000JP` | Not yet |
|
||||
| The Old Hunters Edition | Asia | `CUSA03023` | `HP9000-CUSA03023_00-BLOODBORNE0000AS` | Not yet |
|
||||
|
||||
*Checked* means a dump of that release with update 1.09 had exactly the executable bbport runs.
|
||||
The others are accepted on the expectation that every release shares the same 1.09 executable;
|
||||
if one does not, the launcher says so instead of starting a game that would crash. A report of
|
||||
how yours goes is welcome either way.
|
||||
|
||||
The alpha tests (`CUSA01318`, `CUSA01322`, `CUSA01333`, `CUSA01335`) are not supported.
|
||||
|
||||
The Game of the Year and The Old Hunters editions include the DLC. With a base game, dump the
|
||||
add-ons too and choose their folder in the launcher (see the README's *DLC* section).
|
||||
|
||||
## Tested with this fork
|
||||
|
||||
On Linux (CachyOS, NVIDIA GeForce RTX 3060), with the US release (`CUSA00900`):
|
||||
|
||||
- The base game with update 1.09 and the add-ons dumped separately (The Old Hunters and the two
|
||||
messenger add-ons), from the launcher's DLC folder.
|
||||
- A dump whose `eboot.bin` had Lance McDonald's 60 fps patch baked in: the launcher reports it,
|
||||
and the clean 1.09 `eboot.bin` runs.
|
||||
- Both regional texts through *Game region*: Spanish from Spain (Europe) and Latin American
|
||||
Spanish (the Americas).
|
||||
|
||||
The European Game of the Year edition (`CUSA03173`) is the release the original bbport is
|
||||
developed and tested with.
|
||||
@@ -1,5 +1,10 @@
|
||||
# Уход от эмуляции: что сделано и что дальше (2026-10-06)
|
||||
|
||||
Исторический план и замеры по этапам разработки. В `0.5-pre2` новая модель остаётся
|
||||
экспериментальной и выключена по умолчанию; для NVIDIA и других не-AMD GPU добавлен модуль
|
||||
памяти без sparse-перепривязок. Актуальное состояние и проверки:
|
||||
[CHANGES_0.5-pre2.md](CHANGES_0.5-pre2.md).
|
||||
|
||||
## Где проходит граница API
|
||||
|
||||
Bloodborne собран со статической libGnm. Пакеты PM4 пишет не драйвер, а сама игра, функциями
|
||||
@@ -90,3 +95,261 @@ GPU в порядке потока (`vkCmdUpdateBuffer`, у DMA для памя
|
||||
Что осталось на стадии B (мкс на пакет, 3,5 всего): привязка ресурсов 1,0 (буферы 0,4, текстуры
|
||||
0,45), `ObtainBuffer` 0,6, начало прохода 0,26, вершины 0,34, задачи 0,2. Дальше —
|
||||
разделение стадии B или привязка ресурсов на стадии A (см. п. 2 выше).
|
||||
|
||||
## Шаг 3 (2026-10-08): метки пишет видеочип, перехваты без сигналов, NVIDIA
|
||||
|
||||
Что игра реально отправляет (новый счётчик `BB_DCB_STATS=1`: пакеты PM4 по типам, события,
|
||||
метки, исходы `WAIT_REG_MEM`; Кошмар охотника, у лампы, ~185 FPS): `EVENT_WRITE_EOP` 61 тыс./с
|
||||
(~330 за кадр, все без прерывания, 32- и 64-битные метки), `WAIT_REG_MEM` 31 тыс./с (все по
|
||||
памяти и все выполнены по меткам, ожидающим в порядке потока — процессор не ждёт ни разу),
|
||||
`EVENT_WRITE_EOS` 371/с, `WRITE_DATA` 3,5 тыс./с, `DUMP_CONST_RAM` 6,6 тыс./с, сбросы кэшей
|
||||
(`EVENT_WRITE`, `ACQUIRE_MEM`) — около 70 тыс./с. Не встречаются: occlusion-запросы
|
||||
(`ZPASS_DONE`), `SET_PREDICATION`, `COND_EXEC`, `MEM_SEMAPHORE`, `REWIND`, `COPY_DATA`, метки
|
||||
со временем GPU, отправки в очереди compute.
|
||||
|
||||
Сделано:
|
||||
- **Метки EOP/EOS пишет видеочип** (`Rasterizer::WriteLabelOnGpu`, `BB_GPU_LABELS=0` — как
|
||||
раньше): буферный маркер Vulkan (`VK_AMD_buffer_marker`, конец конвейера) прямо в память игры
|
||||
(кусок гостевой памяти), в той же точке потока, где метку пишет командный процессор PS4.
|
||||
64-битная метка — две 32-битные записи, старшая половина первой. Раньше метку писал поток
|
||||
процессора после завершения всей отправки Vulkan (61 тыс. записей в секунду). Метки с
|
||||
прерыванием по-прежнему сигналятся с процессора (прерывание — оттуда). То же для меток
|
||||
`RELEASE_MEM` очередей compute. EOS с записью из GDS — копия видеочипом в порядке потока вместо
|
||||
`Finish()` и чтения процессором.
|
||||
- **Перехваты кода игры без ловушек** (`gpu/shim/bbport_guest_hooks.cpp`, `BB_GUEST_HOOK_TRAPS=1`
|
||||
— ловушки `int3`): точки загрузчиков, аллокатора диапазонов и кучи GPU переходят в заглушки
|
||||
рядом с образом, которые вызывают обработчик и выполняют перекрытые инструкции; вызовы `memcpy`
|
||||
загрузчиков идут через трамплин. Раньше каждый вызов был сигналом ядра (SIGTRAP), ~1200 в
|
||||
секунду только у аллокатора.
|
||||
- **Новая модель на NVIDIA** (`gpu/shim/bbport_guest_memory.cpp`): кроме кусков dma-buf (AMD) —
|
||||
режим «память хоста, импортированная видеочипом» (`VK_EXT_external_memory_host`): кусок
|
||||
остаётся в memfd рантайма, видеочип импортирует его второе отображение. При запуске
|
||||
самопроверка в точности как в работе: импорт memfd, привязка к sparse-буферу, запись
|
||||
видеочипом и чтение процессором через другое отображение, и обратно. Не прошла — dma-buf
|
||||
(у NVIDIA «кусок на выделение»), для которого теперь меряется скорость чтения процессором
|
||||
(некэшируемое отображение замедлило бы код игры; меньше 1 ГБ/с — не используется). Не прошло
|
||||
и это — старая модель. Выбор: `BB_GUEST_MEMORY=host|dmabuf`. Переключатель в лаунчере доступен
|
||||
на AMD и NVIDIA. На AMD (RADV) импорт memfd драйвер не принимает — там dma-buf, как раньше.
|
||||
На NVIDIA не проверено: в журнале видно, какой путь выбран и почему.
|
||||
|
||||
Замеры (у лампы): 16 потоков — 233 FPS и с метками видеочипа, и без; 4 ядра / 8 потоков —
|
||||
~217 против ~215 FPS (в пределах шума; выигрыш — свободный поток сигналов).
|
||||
|
||||
### Что ещё осталось и почему
|
||||
|
||||
Всё, что осталось от эмуляции, держится на одном: **транслятор читает описатели ресурсов
|
||||
(V#/T#/S#) и таблицы с ними из памяти игры во время разбора**. Из-за этого:
|
||||
- `DUMP_CONST_RAM` выполняет процессор (дампы читает только транслятор — это его таблицы
|
||||
описателей, видеочип их не читает ни разу);
|
||||
- DMA и `WRITE_DATA` в память не «на месте» выполняет процессор (туда приходят код шейдеров и
|
||||
описатели, которые транслятор читает сразу);
|
||||
- SRT walker (код шейдера, переведённый в x86) обходит таблицы на процессоре;
|
||||
- шейдер специализируется по полям описателей (шаг, формат, перестановка каналов, тип
|
||||
изображения), конвейер выбирается по регистрам;
|
||||
- текстуры узнаются по адресу и формату из T#.
|
||||
|
||||
Перенос на видеочип — новый режим рекомпилятора: шейдер сам читает V# (адрес через BDA-арену,
|
||||
формат и шаг — во время выполнения), изображения через bindless-массив с таблицей T# → индекс,
|
||||
барьеры из сбросов кэшей самой игры (`ACQUIRE_MEM`/`EVENT_WRITE`), резидентность всей памяти
|
||||
сразу при отображении. Это несколько дней работы с риском для картинки: не начато.
|
||||
|
||||
Остальное — не эмуляция в смысле «вместо видеочипа»: перевод GCN → SPIR-V во время игры (как у
|
||||
DXVK), синтетический vblank (HLE VideoOut), заглушки для неиспользуемых игрой пакетов
|
||||
(occlusion — фиктивный счётчик, `SET_PREDICATION`, `COND_EXEC`, `MEM_SEMAPHORE`).
|
||||
|
||||
## Шаг 4 (2026-10-08): где проходит граница между эмуляцией и трансляцией
|
||||
|
||||
Замер (`BB_RES_STATS=1`, Кошмар охотника у лампы): ~97 тыс. привязок ресурсов в секунду; почти у
|
||||
каждой (0,96 стадии на привязку) описатели лежат в таблицах в памяти, а не в регистрах: на одну
|
||||
привязку буферы — 1,3 из регистров и 2,8 из памяти, текстуры — 0,6 и 3,3, сэмплеры — 1,0 и 0,9.
|
||||
|
||||
**Описатели на видеочипе для текстур сделать правильно нельзя.** Текстура PS4 лежит в памяти в
|
||||
раскладке PS4 (tiling), которой нет в Vulkan: её нужно перевести в образ Vulkan, а для этого
|
||||
процессор должен знать T# (адрес, формат, размеры) до того, как отрисовка выполнится. Если шейдер
|
||||
будет сам читать T# из памяти и искать образ в таблице на видеочипе, то при первом использовании
|
||||
текстуры образа ещё нет — правильного запасного пути у видеочипа нет (только кадр с неверной
|
||||
текстурой). Поэтому чтение описателей процессором (SRT walker, таблицы, которые заполняет движок
|
||||
констант) — не эмуляция, а трансляция привязки ресурсов, как у DXVK и vkd3d, которые тоже читают
|
||||
привязки на процессоре и создают по ним объекты Vulkan. Для буферов описатели на видеочипе
|
||||
возможны (BDA), но выигрыш — только запись дескрипторов (~0,1 мкс на пакет), если не переделать
|
||||
резидентность и барьеры целиком; не начато.
|
||||
|
||||
Что из эмуляции на самом деле осталось, и используется ли это Bloodborne:
|
||||
|
||||
| Что | Bloodborne |
|
||||
|---|---|
|
||||
| Ожидание флипа (метка VideoOut) блокирует поток разбора | да — это синхронизация с дисплеем, как ожидание в Present у DXVK |
|
||||
| Счётчик occlusion-запросов — фиктивный | **да**, ~60 событий `ZPASS_DONE` за кадр (в счётчике пакетов их не было видно: они во вложенных буферах); переведено — «Шаг 5» |
|
||||
| `SET_PREDICATION`, `COND_EXEC`, `COPY_DATA` не транслируются | нет; переведено — «Шаг 5» |
|
||||
| `MEM_SEMAPHORE`, `REWIND` — ожидание на процессоре | нет |
|
||||
| Очереди compute (ASC) — корутины в одном потоке | нет (0 отправок за кадр) |
|
||||
| Запись процессором в память, видимую видеочипу, «объявляется» (обёртки `memcpy`, перехваты загрузчиков, кучи, аллокатора, чтение файлов) | да — для копий в VRAM и текстур; `BB_WRITE_VERIFY` на маршруте не нашёл необъявленных записей, кроме ожидаемых |
|
||||
| Шейдер копирования игры — подмена (список читается процессором) | да; теперь можно транслировать (`BB_COPY_SHADER_NATIVE=1`) |
|
||||
|
||||
Строки «нет» нужны только при переносе на другие игры (Driveclub, inFAMOUS: там асинхронный
|
||||
compute и occlusion есть) — проверить их на Bloodborne нельзя.
|
||||
|
||||
Шейдер копирования (`cs fefebf9f`): подмену можно заменить трансляцией самого шейдера. Она нашла
|
||||
настоящую опасность новой модели: рядом с тем, куда он копирует, лежат код шейдеров и таблицы
|
||||
описателей, которые транслятор читает процессором; если эти блоки уходят в VRAM («видеочип пишет
|
||||
это 3 кадра из 60»), транслятор читает устаревший код (чёрная сцена). Подмена обходила это
|
||||
случайно. Теперь записи этого шейдера всегда остаются в памяти игры. Общее правило «то, что
|
||||
видеочип пишет, но сам не читает, остаётся в памяти игры» (как readback heap) пробовалось: ломает
|
||||
производительность (видеочип 4,2 → 6,1 мс за кадр — так попадают в оперативную память и области
|
||||
размером с цели рендера), убрано.
|
||||
|
||||
Константы: копирование в кольцо при разборе было нужно, пока записи командного процессора
|
||||
выполнялись процессором «наперёд». В новой модели оно больше не нужно для правильности —
|
||||
`BB_CONSTANTS_IN_PLACE=1` читает их на месте; по умолчанию выключено (видеочип +3 % из-за PCIe,
|
||||
FPS не выше). То есть кольцо констант теперь — оптимизация (копия в VRAM), а не эмуляция.
|
||||
|
||||
Дальше по трансляции для Bloodborne делать почти нечего; дальнейшая работа — производительность
|
||||
(стадия B на слабых процессорах) и перенос: настоящие запросы occlusion (`vkCmdBeginQuery` +
|
||||
копия результата видеочипом в память игры), предикация (`VK_EXT_conditional_rendering`),
|
||||
очереди compute как очередь Vulkan с семафорами — когда появится игра, которая их использует.
|
||||
|
||||
## Шаг 5 (2026-10-08): occlusion-запросы, COPY_DATA, COND_EXEC, предикация
|
||||
|
||||
Поправка к шагам 3 и 4: Bloodborne **использует** occlusion-запросы — около 60 событий
|
||||
`ZPASS_DONE` за кадр (~14 тыс. в секунду у лампы в Кошмаре охотника). Счётчик пакетов их не
|
||||
показал: он смотрел только буферы команд верхнего уровня. До сих пор игра получала фиктивную
|
||||
последовательность «всё видно».
|
||||
|
||||
Сделано (только новая модель; `BB_OCCLUSION_QUERIES=0` — как раньше, бит 4 второго числа
|
||||
`BB_TOGGLE_FILE` — переключение на ходу):
|
||||
|
||||
- **Occlusion-запросы → запросы Vulkan** (`vk_occlusion.{h,cpp}`, `occlusion_resolve.comp`). На
|
||||
PS4 каждый блок глубины ведёт счётчик сэмплов, прошедших тест глубины; событие `ZPASS_DONE`
|
||||
записывает счётчики (16 байт между блоками, бит готовности 63), игра берёт разность «после −
|
||||
до». Здесь с первого события всегда активен запрос Vulkan; он режется на отрезки на каждом
|
||||
событии и на каждой границе, через которую запрос нельзя протянуть (начало и конец прохода
|
||||
рендера, буфер команд — `Scheduler::CarriedScope`, Suspend/Resume). Событие запоминает, сколько
|
||||
отрезков закончилось до него. В ближайшей точке вне прохода результаты отрезков копируются, и
|
||||
один запуск шейдера складывает их по порядку и пишет каждому ожидающему событию его накопленное
|
||||
значение в память игры через адрес видеочипа (BDA). Проходы рендера не разрываются; цена на
|
||||
4 ядрах — в пределах шума (220 против 219 FPS с фиктивным счётчиком, видеочип 4,54 против
|
||||
4,56 мс). Результаты появляются чуть позже, чем на PS4, до этого бит готовности снят — игра
|
||||
проверяет его, как на PS4. Счётчики всегда остаются в памяти игры (их читает процессор).
|
||||
- **COPY_DATA**: значения, известные при разборе (константа, регистр, часы), записывает видеочип
|
||||
в порядке потока, как `WRITE_DATA`; копии из памяти и GDS — копии видеочипа в порядке потока,
|
||||
как `DMA_DATA`. Запись в регистр — пока предупреждение.
|
||||
- **COND_EXEC**: условие берётся из ожидающей метки в порядке потока, иначе — после того, как
|
||||
видеочип выполнил работу до пакета (раньше читалось при разборе, впереди видеочипа).
|
||||
- **SET_PREDICATION** (ZPass, Bool64, Bool32; CONTINUE — ИЛИ с предыдущим): пропускаются
|
||||
отрисовки и запуски, у которых в заголовке стоит бит предиката. Предикат вычисляется при
|
||||
первом таком пакете, после того как видеочип выполнил работу до него (правильно, но с
|
||||
ожиданием видеочипа; Bloodborne предикацию не использует). `VK_EXT_conditional_rendering` не
|
||||
подошёл: он пропускал бы и наши внутренние запуски (детайлинг текстур, копии), и не переходит
|
||||
через границы буферов команд.
|
||||
|
||||
Проверка: `BB_PM4_SELFTEST=1` — через ~40 с игры в отправки игры подмешиваются тестовые пакеты
|
||||
(в память, выделенную самой проверкой), через несколько секунд результаты сверяются: occlusion
|
||||
по отправке с отрисовками (> 0 сэмплов) и пустой интервал (0), `COPY_DATA` (32 и 64 бита,
|
||||
память → память в порядке, часы), `COND_EXEC` (ложь пропускает запись, истина выполняет),
|
||||
предикация (ZPass и Bool32: 2 из 4 пустых предикатных отрисовок пропущены). Все 8 — PASS. Слой
|
||||
валидации Vulkan на 67 тыс. событий не нашёл нарушений правил запросов.
|
||||
|
||||
Попутно найдена и исправлена взаимоблокировка: чтение памяти для процессора из потока разбора
|
||||
(`ReadMemory`) отправляло задачу этому же потоку и ждало её.
|
||||
|
||||
Что осталось без перевода: очереди compute (ASC) по-прежнему выполняются в том же потоке, что и
|
||||
графика, и отправляются в ту же очередь Vulkan (это допустимая сериализация); `MEM_SEMAPHORE`
|
||||
меняет счётчик процессором при разборе; время видеочипа в метках и `COPY_DATA` — часы процессора.
|
||||
Bloodborne ничего из этого не использует.
|
||||
|
||||
## Дополнение 2026-10-09: copy shader в модуле памяти и GPU-метки без AMD-расширения
|
||||
|
||||
В `BB_PC_MODEL=1 BB_LAYER_MEMORY=1` оригинальный `fefebf9f` теперь исполняется по умолчанию: paged stores обновляют память игры и актуальные зеркала. HLE доступен через `BB_COPY_SHADER_NATIVE=0`.
|
||||
|
||||
Без `VK_AMD_buffer_marker` метки EOP/EOS и применимый RELEASE_MEM пишет GPU стандартными Vulkan updates с барьерами. AMD сохраняет быстрые markers; `BB_GPU_LABELS_PORTABLE=1` позволяет проверить переносимый вариант. Подробности и аппаратные ограничения: [TRANSLATION_GPU_COPY_LABELS.ru.md](TRANSLATION_GPU_COPY_LABELS.ru.md).
|
||||
|
||||
## План от 2026-10-10: что осталось и как перевести на трансляцию
|
||||
|
||||
Требование: одинаково для AMD и NVIDIA и без опоры на код именно Bloodborne (адреса функций игры,
|
||||
хеши её шейдеров) там, где модель трансляции отвечает за правильность.
|
||||
|
||||
| Что осталось | Где | Почему это эмуляция или привязка |
|
||||
|---|---|---|
|
||||
| Модель памяти 0.3 (копии в VRAM с защитой страниц, обратное чтение, `fault_manager`, BB_UFFD, предзагрузка) | **по умолчанию** | делает вместо видеочипа то, чего у ПК нет: одна память |
|
||||
| Два пути новой модели: sparse-арена (AMD) и модуль памяти (остальные) | новая модель | sparse-перепривязки — путь одного производителя (на NVIDIA держат видеочип секундами) |
|
||||
| Записи загрузчиков в текстуры и буферы видны видеочипу через перехваты кода Bloodborne (`memcpy` игры в 0x216d420/0x2171d60, аллокатор 0x26aa070, куча TLSF) | новая модель | в другой игре этих адресов нет: записи остались бы незамеченными |
|
||||
| `MEM_SEMAPHORE` меняется при разборе (впереди видеочипа), время видеочипа в метках и `COPY_DATA` — часы процессора, очереди compute — в одном потоке с графикой | командный процессор | Bloodborne не использует; нужно для других игр |
|
||||
| CE и SRT walker читают описатели на процессоре, кэш текстур по адресу, синтетический vblank | — | трансляция привязок и платформенный слой, как у DXVK/vkd3d (шаг 4): остаётся |
|
||||
|
||||
Этапы:
|
||||
|
||||
1. **Один путь памяти для всех GPU.** Модуль памяти — по умолчанию и на AMD (на маршруте 2026-10-09
|
||||
вровень со sparse-ареной: p99 5,1–7,5 мс против 5,2–6,0). Sparse-арена — запасной вариант
|
||||
`BB_LAYER_MEMORY=0`. Заодно на AMD по умолчанию исполняется сам шейдер копирования игры вместо
|
||||
подмены по его хешу.
|
||||
2. **Согласование памяти без перехватов игры.** Записи процессора в память, которую видеочип
|
||||
держит как образ или копию, ловятся общим механизмом (ловушки записи по 64 КиБ, как у модуля),
|
||||
перехваты Bloodborne остаются ускорением (меньше срабатываний ловушек). Проверка: прогон с
|
||||
`BB_GUEST_HOOKS=0` и `BB_WRITE_VERIFY=1` (необъявленные записи), картинка и время кадра.
|
||||
3. **Остатки командного процессора — на видеочип.** `MEM_SEMAPHORE`: сигнал — запись видеочипа в
|
||||
порядке потока; время видеочипа — метки времени Vulkan, переведённые в часы PS4 (100 МГц) и
|
||||
записанные видеочипом. Проверка — `BB_PM4_SELFTEST` (Bloodborne их не использует). Очереди
|
||||
compute как отдельная очередь Vulkan — после, когда будет игра для проверки.
|
||||
4. **Новая модель по умолчанию** (после логов с NVIDIA на 0.5-pre4), затем удаление модели 0.3 и
|
||||
sparse-арены.
|
||||
|
||||
### Ход работ (2026-10-10)
|
||||
|
||||
- **Этап 1 сделан:** модуль памяти по умолчанию на всех GPU (на AMD тоже; sparse-арена —
|
||||
`BB_LAYER_MEMORY=0`), 0 вызовов `vkQueueBindSparse`.
|
||||
- **Модульность:** профили игр `gpu/games/` (`game_profile.h`, `bloodborne.cpp`): перехваты кода
|
||||
игры, её код, пишущий данные каждый кадр, хеш шейдера копирования — только там. Профиль
|
||||
выбирается по TITLE_ID; `BB_GAME_PROFILE=none` — игра как незнакомая, `BB_GUEST_HOOKS=0` — без
|
||||
перехватов.
|
||||
- **Этап 2, запись:** общий учёт ловушек записи в рантайме (`runtime_memory_trap`, причины по
|
||||
страницам; `gpu/layer/bblayer_write_traps.h`): копии модуля в VRAM и текстуры ловят записи на
|
||||
одних страницах, не мешая друг другу; `mprotect` игры ловушки сохраняет, новое отображение
|
||||
начинается без них (тест в `tests/test_runtime.c`). Страницы под текстурами под ловушками по
|
||||
умолчанию (`BB_IMAGE_TRAPS=0` — как раньше), записи libc и перехваченных загрузчиков
|
||||
объявляются до записи (без срабатываний). На маршруте с профилем — как без ловушек (4,18 мс
|
||||
видеочипа), 4–29 срабатываний за 5 с.
|
||||
- **Найдено попутно — разброс «некоторые запуски в 1,3–1,7 раза медленнее»:** «летучие» блоки
|
||||
модуля (блоки, в которые пишет процессор, в общей копии диапазона в VRAM) обновлялись копией
|
||||
перед каждой привязкой на чтение; копия разрывает проход рендера, и объёмы света (по отрисовке на
|
||||
каждый) рвали свой проход до ~100 раз за кадр (`BB_PASS_BREAK_TRACE=1`: 92–109 тыс. разрывов за
|
||||
5 с из `Runtime::CopyBuffer` против ~700). Летучие блоки выключены по умолчанию
|
||||
(`BB_LAYER_VOLATILE=1` — включить; тогда чтения внутри открытого прохода идут на месте): 10 из 10
|
||||
прогонов быстрые. Порядок «результаты occlusion до последующих меток»
|
||||
(`OcclusionQueries::WriteBeforeLabel`) оставлен как поведение PS4, но причиной не был: игра читает
|
||||
результаты через 2–10 мс и находит их записанными (`BB_OCCLUSION_READ_TRACE=1`, ловушки на
|
||||
чтение в рантайме — причины от 16 делают страницу без доступа).
|
||||
- **Незнакомая игра (этап 2, чтение):** прежний вывод «без профиля — снова медленный режим» был
|
||||
тем же разбросом из-за летучих блоков (один прогон). Без профиля маршрут идёт так же быстро
|
||||
(3 из 3, 4,29–4,30 мс) и выглядит так же. Ловушки на чтение для данных, которые есть только в
|
||||
VRAM (копия обратно при чтении процессором), остаются нужны для правильности в других играх;
|
||||
механизм причин «без доступа» в рантайме уже есть и проверен тестом.
|
||||
- **Этап 3 сделан (кроме отдельной очереди compute):**
|
||||
- `MEM_SEMAPHORE`: сигнал — в порядке потока, после завершения работы видеочипа перед ним
|
||||
(`RunMemSemaphoreSignal`, как метки EOP); ожидание сбрасывает конвейер записи и отправляет
|
||||
записанное, как `WAIT_REG_MEM`. `BB_MEM_SEMAPHORE_ORDER=0` — сигнал при разборе (как раньше).
|
||||
- Часы видеочипа: у PS4 100 МГц; теперь одна шкала для процессора и видеочипа — монотонные часы
|
||||
хоста в тиках по 10 нс (`GetGpuClock64`, раньше — настенные наносекунды). Метки EOP/RELEASE_MEM
|
||||
с часами и `COPY_DATA` из часов пишет сам видеочип: метка времени Vulkan → копия из запроса →
|
||||
короткий шейдер (`gpu_timestamp.comp`) переводит в шкалу PS4 и пишет в память игры
|
||||
(`vk_timestamps.cpp`). Привязка тиков к часам хоста — один раз, на простаивающем видеочипе
|
||||
(на RX 7800 XT точность 152 мкс). `BB_GPU_TIMESTAMPS=0` — пишет процессор.
|
||||
- Проверка — `BB_PM4_SELFTEST=1`: 11 из 11; новые проверки «сигнал не раньше предшествующей
|
||||
метки» (со старым порядком — FAIL), «ожидание и списание», «часы 100 МГц в шкале процессора»
|
||||
(2 с между метками: 1,961–1,999 с). Bloodborne ни то, ни другое не использует.
|
||||
- **Этап 2, чтение — готово, включается `BB_LAYER_READ_TRAPS=1`:** то, что видеочип записал только в
|
||||
копию в VRAM (запись привязки в зеркало), под ловушкой «без доступа» (причина `VramData` в
|
||||
рантайме); первое касание процессора (игра, транслятор, libc рантайма) копирует данные блока
|
||||
назад через очередь обратного чтения (`FastReadback`, как в модели 0.3: ждёт только тик этой
|
||||
записи) и снимает ловушку. Запись в файл из такой страницы сначала её читает (`touch_for_read`),
|
||||
чтение файла в неё — уже касалось (`touch_for_write`). На маршруте: 60 МиБ под ловушками, 0–1
|
||||
касание за 10 с, время видеочипа то же (4,28–4,30 мс). Bloodborne такие данные процессором не
|
||||
читает, поэтому само копирование назад здесь не проверено — по умолчанию выключено до игры,
|
||||
которой это нужно.
|
||||
- **Пересмотрено перед 0.5 (вечер 2026-10-10):** на AMD по умолчанию снова sparse-арена
|
||||
(`BB_LAYER_MEMORY=1` — модуль). Модуль шёл вровень с ареной на маршруте в Ярнаме, но в Сне
|
||||
охотника держал вне VRAM ~1 ГБ данных области (диапазоны с несколькими «неизвестными» блоками
|
||||
без летучих блоков остаются на месте): 100 FPS против 154 с ареной; с летучими блоками — 120, но
|
||||
с ~225 тыс. срабатываний ловушек в секунду. Нужен доступ по блокам для смешанных диапазонов.
|
||||
Occlusion-запросы как запросы Vulkan — по выбору (`BB_OCCLUSION_QUERIES=1`): с апскейлером
|
||||
(сцена меньше и со сдвигом) свечение лампы вспыхивало серым на весь кадр; счёт нужно сделать
|
||||
устойчивым к этому. Фоновая компиляция больше не пропускает полноэкранные проходы (серые кадры).
|
||||
@@ -0,0 +1,68 @@
|
||||
# Модуль памяти прослойки: адреса видеочипа PS4 без sparse (план, 2026-10-09)
|
||||
|
||||
## Зачем
|
||||
|
||||
Новая модель памяти держит память игры в одной sparse-арене и переносит блоки между памятью
|
||||
игры и VRAM перепривязкой (`vkQueueBindSparse`). На NVIDIA (Linux, драйверы ≥ 555) время
|
||||
привязки растёт с числом уже привязанных страниц, вызов держит глобальную блокировку: каждый
|
||||
перенос в VRAM стоил секунды, игра и рабочий стол вставали (GTX 1660 Ti, 615.71). Без переносов
|
||||
(`BB_FIXED_ARENA=1`) — 48,6 FPS против ~205 на RX 7800 XT. Нужна модель, работающая одинаково на
|
||||
AMD, NVIDIA и Intel, и не привязанная к буферному кэшу shadPS4: часть будущей прослойки запуска
|
||||
игр PS4.
|
||||
|
||||
## Идея
|
||||
|
||||
У видеочипа PS4 своя виртуальная память (GPUVM) над общей памятью; любой V#, T#, указатель в
|
||||
user data — виртуальный адрес. На ПК то же самое делаем средствами Vulkan 1.2 (BDA):
|
||||
|
||||
- **Источники памяти** — обычные (не sparse) буферы Vulkan:
|
||||
- куски памяти игры: dma-buf (AMD) или импорт памяти хоста (NVIDIA, Intel), по куску на
|
||||
выделение прямой памяти игры (выделения отображаются целиком — диапазон внутри одного
|
||||
отображения всегда непрерывен в одном куске);
|
||||
- зеркала в VRAM: сегменты, выровненные по адресам игры (страница игры X лежит в сегменте по
|
||||
тому же смещению), выделяются, когда в сегменте появляется первая страница в VRAM.
|
||||
- **Таблица страниц** (буфер на видеочипе): страница адреса PS4 → адрес устройства (BDA) её
|
||||
текущего источника. Меняется копией в потоке команд — в порядке с отрисовками, без семафоров.
|
||||
- **Прямой путь**: диапазон V# целиком в одном источнике (почти все привязки) → обычный
|
||||
дескриптор (буфер источника, смещение, размер). Транслятор шейдеров не меняется.
|
||||
- **Страничный путь**: диапазон смешанный (≈85 огромных привязок за кадр: шейдеры, привязанные
|
||||
ко всей памяти) → дескриптор указывает на запись {адрес PS4, размер}, шейдер переводит каждый
|
||||
адрес через таблицу. Вариант пайплайна только для таких привязок (ключ специализации).
|
||||
- **Вершины, индексы, аргументы indirect, копии, загрузка текстур**: прямой путь, иначе сборка
|
||||
в непрерывный временный буфер (только чтение) или копии по страницам (процессор знает таблицу).
|
||||
- **Перенос в VRAM и обратно** — политика нынешней новой модели (данные, о записи которых мы
|
||||
знаем: загрузчики, видеочип; неизвестные писатели — на месте), но исполнение — копия + запись в
|
||||
таблицу + выбор источника при привязке. Привязки, записанные до переноса, читают старый
|
||||
источник — он ещё верен; освобождение VRAM — когда видеочип прошёл эти команды.
|
||||
|
||||
## Порядок работ
|
||||
|
||||
1. **Ядро модуля** (`gpu/layer/`, без зависимостей от shadPS4): источники, страницы, таблица,
|
||||
`Resolve(адрес, размер)` → прямой источник или «смешанный», обход по источникам для копий.
|
||||
Интерфейс записи команд — абстрактный (копия, запись таблицы), чтобы не тянуть планировщик.
|
||||
2. **Подключение без VRAM**: новая модель отдаёт диапазоны на месте через буферы кусков, а не
|
||||
через арену; sparse-арена в новой модели не создаётся. Ожидание: ~48 FPS на AMD (как
|
||||
`BB_FIXED_ARENA`), никаких `vkQueueBindSparse`. Проверка картинки, затем сборка для NVIDIA.
|
||||
3. **Зеркала в VRAM + перенос**: политика из `BufferCache`, таблица страниц, страничный путь в
|
||||
шейдерах для смешанных привязок. Цель — паритет с sparse-ареной на AMD (~205 FPS).
|
||||
4. **NVIDIA/Intel**: тестовая сборка, лог тестера; затем убрать sparse из новой модели совсем.
|
||||
|
||||
Замеры — RX 7800 XT, стоя (`tools/bench.sh`), `BB_PC_MODEL=1`; диагностика `BB_RESIDENCY_MIX=1`.
|
||||
|
||||
## Состояние (2026-10-09, утро)
|
||||
|
||||
- Шаги 1–3 сделаны. На RX 7800 XT стоя: модуль ~205 FPS, sparse-арена ~205–238, старая модель
|
||||
~220 (у лампы в Кошмаре охотника); в другом месте (1170 вызовов отрисовки) — 167,5 / 164,5 / 146.
|
||||
`vkQueueBindSparse` в режиме модуля не вызывается ни разу (счётчик в строке `Layer memory:`).
|
||||
- Смешанные привязки решены без страничного пути: «летучие» блоки (`layer_volatile`) — блок с
|
||||
неизвестными байтами (край диапазона, промежуток между образами) кладётся в зеркало вместе с
|
||||
остальным диапазоном, обновляется из памяти игры перед каждой привязкой, а то, что запуск в него
|
||||
записал, копируется обратно после запуска (`LayerAfterBindings`). Страничный путь остаётся для
|
||||
привязок от 64 МиБ. `BB_LAYER_VOLATILE=0` — выключить (для сравнения).
|
||||
- По умолчанию: AMD — sparse-арена, остальные видеокарты — модуль (`BB_LAYER_MEMORY=1/0` —
|
||||
вручную). Шаг 4 (NVIDIA): нужен лог тестера; путь импорта памяти хоста на AMD не проверить
|
||||
(RADV не импортирует memfd).
|
||||
|
||||
## Дополнение: оригинальное копирование и переносимые метки (2026-10-09)
|
||||
|
||||
В новом модуле исправлен paged-путь оригинального copy shader: записи обновляют память игры и актуальное зеркало; нативный шейдер теперь выбран по умолчанию. Для GPU-меток добавлен стандартный Vulkan-путь без AMD buffer marker. Реализация, переключатели и границы проверки описаны в [TRANSLATION_GPU_COPY_LABELS.ru.md](TRANSLATION_GPU_COPY_LABELS.ru.md). Это закрывает зависимость записи меток от AMD-расширения, но не заменяет аппаратную проверку NVIDIA.
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
# Mods and third-party patches
|
||||
|
||||
Both are on the launcher's **Settings** page and apply at the next start. The game folder itself
|
||||
is never changed.
|
||||
|
||||
## File mods
|
||||
|
||||
The **Mods** group has the folder, a **Load mods** switch, and the list of mods: each one can be
|
||||
turned on or off and moved up or down. The lowest mod that is on wins: when two mods replace the
|
||||
same file, the log says which one replaced the other.
|
||||
|
||||
The mods folder is `~/.local/share/bbport/mods/` with the AppImage (`mods/` in the data
|
||||
directory when running from the repository). Extract each mod into a folder of its own:
|
||||
|
||||
```text
|
||||
mods/
|
||||
Mod name/
|
||||
dvdroot_ps4/
|
||||
chr/...
|
||||
param/...
|
||||
menu/...
|
||||
```
|
||||
|
||||
These layouts work as well:
|
||||
|
||||
- `Mod name/app0/dvdroot_ps4/...`, and `Mod name/<title ID>/dvdroot_ps4/...` with whichever
|
||||
release the mod was made for (`CUSA03173`, `CUSA00900`, ...).
|
||||
- One extra wrapper folder, as extracting an archive into a folder of its name leaves it:
|
||||
`Mod name/Mod name v1.2/dvdroot_ps4/...` (readme files and pictures may sit next to it).
|
||||
- The game's folders without `dvdroot_ps4`: `Mod name/chr/...`, `Mod name/parts/...` (`chr`,
|
||||
`parts`, `map`, `menu`, `msg`, `param`, `sfx`, `sound`, `font` and the other folders of
|
||||
`dvdroot_ps4`).
|
||||
|
||||
Upper or lower case does not matter: a mod made on Windows with
|
||||
`DVDROOT_PS4/Chr/C0000.chrbnd.dcx` replaces the game's `dvdroot_ps4/chr/c0000.chrbnd.dcx`.
|
||||
The log shows how many game files the mods replaced and added, e.g.
|
||||
`Mods: 12 game files replaced, 0 added`. A mod meant to replace files that says
|
||||
`0 game files replaced` has its files in the wrong place.
|
||||
|
||||
What works: ready-made replacements of `dvdroot_ps4` files (textures, models, params,
|
||||
interface, sound, fonts). What does not:
|
||||
|
||||
- ZIP or 7z archives: extract them first.
|
||||
- Two mods changing different parts of the same `.dcx` or `.bnd` file: the last one replaces
|
||||
it whole, the files are not merged.
|
||||
- Mods that replace `eboot.bin`, `sce_module` or `sce_sys`, DLL injectors and script plugins.
|
||||
Changes to the game's code are patches (below).
|
||||
- Symbolic links inside a mod.
|
||||
|
||||
Whether a mod works with Bloodborne 1.09 is up to its author.
|
||||
|
||||
A shadPS4-style folder next to the game folder, `<game folder>-mods/dvdroot_ps4/...` (for
|
||||
example `CUSA03173-mods` next to `CUSA03173`), is loaded too, before the mods in the list. You
|
||||
can also choose a folder that holds `dvdroot_ps4` directly as the mods folder: it is then loaded
|
||||
as one mod. **Load mods** turns all of them off. The launcher's button prompts and gestures
|
||||
menu work the same way, as files laid under the mods; they are settings of their own and stay
|
||||
on when mods are off.
|
||||
|
||||
### How it works
|
||||
|
||||
For each start, the data directory gets a merged tree of links, `out/mod-game-*`: the game sees
|
||||
the mods' files where they replace its own and the original files everywhere else. `/app0` is
|
||||
read-only, and saves go to the usual folder. The tree is removed when the game exits normally
|
||||
or the launcher stops it; one left behind by a crash is not reused.
|
||||
|
||||
The order and the mods turned off are kept in `mods.json` in the data directory:
|
||||
|
||||
```json
|
||||
{"order": ["First", "Second"], "disabled": ["First"]}
|
||||
```
|
||||
|
||||
New folders are turned on and added at the end, in alphabetical order.
|
||||
|
||||
From a terminal:
|
||||
|
||||
```sh
|
||||
BB_GAME_DIR=/path/to/game BB_MODS_DIR=/path/to/mods bash run.sh
|
||||
BB_GAME_DIR=/path/to/game BB_MODS_ENABLED=0 bash run.sh
|
||||
```
|
||||
|
||||
`BB_MODS_CONFIG` sets another `mods.json`. `BB_MOD_TRACE=1` (with `BB_MODS_DIR`) logs the
|
||||
first reads of files that come from mods, to see whether a mod is being used.
|
||||
|
||||
## Third-party patches
|
||||
|
||||
The **Third-party patches** group loads patches in the shadPS4/GoldHEN XML format from the
|
||||
patches folder: `~/.local/share/bbport/patches/` with the AppImage, or another folder chosen in
|
||||
the launcher.
|
||||
|
||||
- Only patches for version `01.09` of `eboot.bin` are listed. Files for other games are
|
||||
skipped: a file applies when it lists any retail release of Bloodborne, or none.
|
||||
- Each patch starts on or off as the file says (`isEnabled`); the choice in the launcher is
|
||||
kept in `patches.json` in the data directory:
|
||||
|
||||
```json
|
||||
{"enabled": ["file.xml/Patch name"], "disabled": ["file.xml/Other patch"]}
|
||||
```
|
||||
|
||||
- Lines of type `bytes`, `bytes16`, `bytes32`, `bytes64`, `float32`, `float64`, `utf8` and
|
||||
`utf16` work. A patch with a `mask` line (a pattern search) or an address outside the
|
||||
executable is skipped whole, and the log says so.
|
||||
- They apply after bbport's own patches (`patches/Bloodborne.xml`), so where both change the
|
||||
same bytes, the third-party patch wins.
|
||||
- Patches that replace pointers in tables, such as *60 FPS++*, are moved to where the game is
|
||||
loaded.
|
||||
|
||||
From a terminal: `BB_PATCHES_DIR=/path BB_PATCHES_CONFIG=/path/patches.json bash run.sh`.
|
||||
|
||||
This guide is based on bbport's [MODS.md](MODS.md) (Russian), by deadinside28.
|
||||
@@ -0,0 +1,232 @@
|
||||
# Новая модель памяти на NVIDIA: итог работы (2026-10-09)
|
||||
|
||||
Замеры ниже относятся к этапу разработки модуля. Актуальные изменения `0.5-pre2` и результаты
|
||||
проверки оригинального copy shader: [CHANGES_0.5-pre2.md](CHANGES_0.5-pre2.md) и
|
||||
[TRANSLATION_GPU_COPY_LABELS.ru.md](TRANSLATION_GPU_COPY_LABELS.ru.md).
|
||||
|
||||
## Задача
|
||||
|
||||
Новая модель памяти и трансляции (`BB_PC_MODEL=1`) держала память игры в одном sparse-буфере
|
||||
(«арене») и переносила горячие блоки в VRAM перепривязкой страниц (`vkQueueBindSparse`). На
|
||||
проприетарном драйвере NVIDIA для Linux это не работает: начиная с версии 555 время
|
||||
`vkQueueBindSparse` растёт с числом уже привязанных страниц, а сам вызов держит глобальную
|
||||
блокировку. У тестера (GTX 1660 Ti, драйвер 615.71) каждый перенос держал видеочип 10 секунд и
|
||||
дольше, и вместе с игрой вставал рабочий стол. Поэтому новая модель была доступна только на AMD.
|
||||
|
||||
Цель: новая модель памяти на всех видеокартах.
|
||||
|
||||
## Решение: модуль памяти прослойки
|
||||
|
||||
Вместо sparse-арены работает собственный модуль памяти (`gpu/layer/bblayer_gpu_memory.*`,
|
||||
`gpu/shadps4/video_core/buffer_cache/buffer_cache_layer.cpp`, план — `MEMORY_MODULE_PLAN.ru.md`):
|
||||
|
||||
- память игры привязывается **на месте**, через буферы её кусков (dma-buf на AMD, импорт памяти
|
||||
хоста `VK_EXT_external_memory_host` на NVIDIA);
|
||||
- часто читаемое копируется в VRAM в отдельные буферы-«зеркала». Перенос сводится к копии и
|
||||
учёту в модуле, без перепривязки страниц;
|
||||
- привязка берёт зеркало, если диапазон целиком в VRAM, иначе память игры на месте. Диапазоны от
|
||||
64 МиБ идут через таблицу страниц в транслированных шейдерах.
|
||||
|
||||
**`vkQueueBindSparse` в этом режиме не вызывается ни разу**: счётчик выводится в строке журнала
|
||||
`Layer memory: ... vkQueueBindSparse: 0 calls`.
|
||||
|
||||
### Когда включается
|
||||
|
||||
| Видеокарта | По умолчанию |
|
||||
|---|---|
|
||||
| AMD | sparse-арена, как раньше |
|
||||
| NVIDIA, Intel и остальные | модуль памяти, автоматически |
|
||||
|
||||
`BB_LAYER_MEMORY=1` / `=0` выбирает вручную. Лаунчер больше не прячет переключатель «Новая модель
|
||||
памяти и трансляции» на видеокартах не от AMD. Стартовая проверка импорта памяти хоста в режиме
|
||||
модуля проверяет запись видеочипа и процессора через сам импортированный буфер, без sparse-буфера.
|
||||
|
||||
## Что пришлось исправить, чтобы модуль заработал правильно и быстро
|
||||
|
||||
### Скорость: с 48–60 FPS до ~205 FPS на AMD (стоя у лампы)
|
||||
|
||||
1. **Подмена копий и очисток образов не срабатывала.** Детекторы `IsComputeImageCopy` и
|
||||
`IsComputeImageClear` ждали у шейдера ровно два буфера, а модуль добавлял каждому шейдеру
|
||||
третий — таблицу страниц. Копия целей рендеринга (`cs 3d5ebf4e`) и очистка (`cs 8b355b5a`,
|
||||
31 раз за кадр) выполнялись настоящими шейдерами через память, а образы 1080p
|
||||
перезагружались каждый кадр. Теперь таблица страниц не считается (`ShaderBufferCount`):
|
||||
60 → 136 FPS.
|
||||
2. **Смешанные диапазоны.** Если у диапазона все блоки в VRAM, кроме одного-двух крайних с
|
||||
«неизвестными» байтами (промежуток между образами, чужие данные), весь диапазон читался через
|
||||
шину. Такие блоки теперь «летучие»: лежат в зеркале и обновляются из памяти игры перед каждой
|
||||
привязкой на чтение. 139 → 207 FPS. Для привязок на запись летучие блоки не используются.
|
||||
3. **Перенос в VRAM при первой привязке** диапазона известных данных (как делала арена). Он
|
||||
соблюдает `BB_GARLIC_VRAM=0` и бюджет VRAM (`BB_VRAM_PROMOTE_PERCENT`, важно для карт на 6 ГБ).
|
||||
4. **Нагрузка на процессор.** Ответы модуля кэшируются по поколению размещения; повторные
|
||||
проверки «можно ли перенести» — не чаще раза за кадр на диапазон; проверка «есть ли у
|
||||
диапазона копия в VRAM» — без блокировок, по счётчику версий модуля. Это сняло около 20%
|
||||
времени привязок и почти все блокировки в потоке командного процессора.
|
||||
|
||||
### Правильность: взрывы вершин и мусорные текстуры
|
||||
|
||||
Причина была одна: **копия в VRAM расходилась с памятью игры**. Найдено и закрыто несколько
|
||||
путей:
|
||||
|
||||
1. **Код игры пишет в память без нашего ведома**: заголовки её кучи (`0x2085a60` / `0x20858a0`),
|
||||
часть загрузчика ресурсов (`0x216d420`). Блоки с копией в VRAM теперь защищены от записи
|
||||
собственными ловушками модуля. Запись проходит сразу, а блок возвращается на место перед
|
||||
следующей привязкой. Часто записываемые блоки остаются на месте навсегда (`NoteCpuWrite`).
|
||||
2. **Чтения мимо модуля.** Мелкие привязки, кольцо констант и копирования командного процессора
|
||||
брали данные из памяти игры, хотя новые данные видеочипа лежали в VRAM: в новой модели
|
||||
`IsRegionGpuModified` знает только о незавершённых записях. Теперь всё, что задевает блок с
|
||||
копией в VRAM, идёт через модуль (`LayerMirrored`).
|
||||
3. **Данные видеочипа затирали новые данные процессора.** При возврате блока на место и при
|
||||
повторной выдаче памяти игре модуль копировал «изменённое видеочипом» обратно, в том числе
|
||||
поверх того, что процессор успел записать позже: пометки ставились слишком широко. Теперь
|
||||
заявленные записи процессора снимают пометки со своих байтов (`LayerForgetGpuData`), выдача
|
||||
памяти заново снимает пометки со своего диапазона, а после незаявленной записи данные видеочипа
|
||||
в блоке считаются мёртвыми и назад не копируются.
|
||||
4. **Куда видеочипу можно писать в VRAM** (`BB_LAYER_GPU_WRITES`): по умолчанию (`1`) — только в
|
||||
блоки, которые процессор не трогал с момента выделения: цели рендеринга и другие данные одного
|
||||
видеочипа. `0` — никогда (правильно, но 60–70 FPS: записи идут через шину), `2` — везде (давало
|
||||
взрывы).
|
||||
5. **Шейдер копирования игры** в `0.5-pre2` по умолчанию транслируется в SPIR-V и выполняется
|
||||
на GPU. Таблица страниц содержит актуальное GPU-представление и адреса памяти игры;
|
||||
copy shader записывает результат в оба представления. Это устраняет расхождение зеркала
|
||||
VRAM и памяти игры без подмены оригинального списка копий на CPU.
|
||||
`BB_COPY_SHADER_NATIVE=0` оставляет HLE для сравнения.
|
||||
|
||||
На предыдущем этапе проверено в игре на AMD (модуль включён вручную, шейдер копирования через HLE): с
|
||||
`BB_LAYER_GPU_WRITES=0` и с правилом «видеочип пишет в VRAM только внутри образов» — Сон
|
||||
Охотника, собаки и трупы в Ярнаме чистые. На последней сборке (правило «блоки, которые процессор
|
||||
не трогал») артефактов при игре не замечено, но отдельной проверки всех мест ещё не было.
|
||||
|
||||
## Замеры (RX 7800 XT, AMD, модуль включён вручную)
|
||||
|
||||
| Место | Модуль | Sparse-арена | Старая модель |
|
||||
|---|---|---|---|
|
||||
| У лампы, утром (до исправлений правильности) | ~205 FPS | ~205–238 | ~220 |
|
||||
| Сон Охотника, сейчас | 130–144 FPS | — | — |
|
||||
|
||||
В Сне Охотника упираемся то в поток команд видеочипа на процессоре (~3,9 мкс на вызов при
|
||||
~1500 вызовах за кадр), то в сам видеочип: проходы G-буфера 960×540, FSR ~1,07 мс.
|
||||
|
||||
**Открытый вопрос:** в части запусков на том же месте видеочип работает заметно медленнее
|
||||
(70–95 FPS, FSR до 3,2 мс вместо 1,07). Причина не найдена; версии с компиляцией шейдеров,
|
||||
поучастковым профилем `BB_SECTIONS` и обновлением летучих блоков не подтвердились. Сравнение
|
||||
запусков осложняет то, что игра рисует разные проходы в зависимости от ракурса и сцены.
|
||||
|
||||
## Что не проверено
|
||||
|
||||
- **Сама NVIDIA.** На AMD путь NVIDIA (импорт памяти хоста + модуль) не воспроизвести: RADV не
|
||||
импортирует memfd. Нужен лог тестера.
|
||||
- Карты с малым объёмом VRAM (6 ГБ): поведение при заполненной VRAM проверено только
|
||||
искусственно (`BB_VRAM_PROMOTE_PERCENT=1`: копий нет, ~38 FPS, стабильно).
|
||||
- Intel.
|
||||
|
||||
## Что попросить у тестера на NVIDIA
|
||||
|
||||
Сборку с включённой в лаунчере «Новой моделью памяти и трансляции». В журнале должны быть строки:
|
||||
|
||||
- `Guest memory: host memory imported by the GPU (VK_EXT_external_memory_host ...)`;
|
||||
- `Guest memory: the new memory model through the layer's memory module on this GPU (vendor 0x10de)`;
|
||||
- `Layer memory: ... vkQueueBindSparse: 0 calls, 0 ranges; write traps hit N`;
|
||||
- `Frame stats: ... FPS`.
|
||||
|
||||
Если видна строка `vkQueueBindSparse of N ranges took X ms`, значит, sparse где-то всё же
|
||||
используется — это ошибка.
|
||||
|
||||
## Первые логи с NVIDIA и исправления (вечер 2026-10-09, `0.5-pre3`)
|
||||
|
||||
Тестер: GTX 1660 Ti (ноутбук, 6 ГБ, PCIe 3.0), драйвер 615.71, сборка 0.5-pre2. Импорт памяти
|
||||
хоста и модуль включились, `vkQueueBindSparse: 0`.
|
||||
|
||||
1. **Зеркал не было вовсе** (10–15 FPS, мерцание фона на титульном экране): `FixedArena()` по
|
||||
умолчанию включалась при импорте памяти хоста и через `GarlicInVramForLayer()` запрещала модулю
|
||||
переносы. Теперь в режиме модуля она всегда выключена. До новой сборки обход — `BB_FIXED_ARENA=0`:
|
||||
с ним у тестера 30–35 FPS (видео), против 60–70 в старой модели.
|
||||
2. **Кэш текстур и зеркала делили VRAM без общего бюджета.** Сборщик кэша текстур сравнивает с
|
||||
порогами всю VRAM процесса, зеркала тоже, а пороги на картах меньше ~9 ГБ — 40 и 80 %
|
||||
стартового бюджета (у тестера давление 1963 МиБ, критическая отметка 3927 МиБ). Переносы же
|
||||
вставали только на 90 % бюджета драйвера. Итог — 3,9–4,0 ГБ, сборщик постоянно за критической
|
||||
отметкой: 155–1255 выселенных образов за 5 с против 0–29 на AMD. Теперь:
|
||||
- переносы в VRAM встают за 384 МиБ до критической отметки (`VramPromotionsPaused`, строка
|
||||
`copies of loaded blocks wait`);
|
||||
- за 128 МиБ до неё модуль сам освобождает место (`LayerYieldToImages`): сначала обрезает запас
|
||||
роста зеркал, затем возвращает на место целые зеркала, не использовавшиеся 3 с
|
||||
(`BB_VRAM_PRESSURE_IDLE_SECONDS`).
|
||||
3. **Перестройка зеркал.** Участок, примыкающий к зеркалу, создавал новое зеркало целиком с
|
||||
копией старого. При загрузке уровня это 15–27 ГБ выделений на 1,3 ГБ данных и всплеск VRAM до
|
||||
7,4 ГБ (у тестера в логе 5,6 ГБ при физических 6). Во время игры, при подгрузке районов,
|
||||
то же самое. Теперь растущее вверх зеркало получает запас под рост, равный своему размеру, но
|
||||
не больше 64 МиБ (`BB_LAYER_MIRROR_GROWTH_MB`): 5–10 ГБ выделений, худший кадр загрузки 555 →
|
||||
87 мс. Заменённые зеркала освобождаются на каждой отправке, а не раз в секунду.
|
||||
4. **Записи `WRITE_DATA` в зеркало.** Командный процессор пишет на видеочипе в память игры; блок
|
||||
с зеркалом раньше уходил на место. Если диапазон целиком в одном зеркале, запись идёт в оба
|
||||
представления (`CommandWriteMirror`).
|
||||
5. **Наблюдаемые блоки** (`BB_LAYER_WATCH`, по умолчанию включено). Блоки, в которых процессор
|
||||
когда-то писал без предупреждения, раньше всегда читались на месте, а значит на NVIDIA через
|
||||
шину. Теперь для читающих привязок они тоже получают зеркало под ловушкой записи. Запись
|
||||
процессора не возвращает блок на место: он перезаливается перед следующей привязкой, а
|
||||
ловушка взводится снова. Видеочип в такие блоки пишет на месте; блок, куда он записал,
|
||||
больше не наблюдается. Наблюдение почти полностью заменило летучие блоки (RX 7800 XT:
|
||||
1,3 ГБ/с перезаливок → 36 МБ/с; у тестера летучих было 455 МБ/с). Блоки, которые процессор
|
||||
пишет часто (3 кадра из 60), по-прежнему уходят на место: перезаливка их перед привязками
|
||||
завершала render pass (видеочип 4,8 → 7,2 мс за кадр). `BB_LAYER_WATCH_HOT=1` — эксперимент
|
||||
с ними.
|
||||
6. Чтения файлов рантайма (`read`/`pread`) повторяются, если ядро вернуло `EFAULT`: ловушку могли
|
||||
взвести снова между касанием страниц и чтением.
|
||||
|
||||
Проверка на RX 7800 XT с `BB_VRAM_LIMIT_MB=5600` (пороги сборщика как у тестера: 1960/3920):
|
||||
старая модель ~195 FPS; модуль ~200–213 FPS, видеочип 4,6–5,2 мс; VRAM держится ниже
|
||||
критической отметки; маршрут `docs/route2.txt` без кадров дольше 25 мс; 3 минуты прогулки без
|
||||
ошибок; картинка в Сне Охотника и в конце маршрута как без наблюдения. Сама NVIDIA этими
|
||||
замерами не проверена: на AMD чтения на месте почти бесплатны.
|
||||
|
||||
## Отзывы на 0.5-pre3 и исправления (`0.5-pre4`)
|
||||
|
||||
- **GTX 1060 6 ГБ:** новая модель вровень со старой (41–48 FPS при ~1500 вызовах за кадр в обеих,
|
||||
видеочип 21–24 мс). Ранние просадки — компиляция шейдеров в первой сессии (160–241 компиляция
|
||||
за 5 с, рывки 1–3,7 с): теперь новые конвейеры проходов, рисуемых каждый кадр, собираются в
|
||||
фоне (`BB_ASYNC_PIPELINES`), а их отрисовки кадр-другой пропускаются.
|
||||
- **Карта на 4 ГБ:** через ~4,5 минуты 5 FPS — регрессия pre3. Переносы в VRAM вставали за
|
||||
384 МиБ до критической отметки сборщика текстур (у карты 4 ГБ — нижние значения порогов,
|
||||
1536/3072 МиБ), а текстуры и служебные выделения уже держали 2808 МиБ: копий стало 124 МиБ на
|
||||
1,9 ГБ данных, видеочип ~200 мс на кадр. Теперь у зеркал своя доля (25 % бюджета драйвера,
|
||||
`BB_LAYER_MIRROR_FLOOR_PERCENT`): ниже неё пауза из-за сборщика не действует.
|
||||
- **После телепорта ~10 FPS меньше:** большие привязки на всю память (через таблицу страниц)
|
||||
помечали каждые 2 МиБ как используемые, поэтому в игре ничего не простаивало, и зеркала
|
||||
покинутой локации держали VRAM. Теперь учитываются только прямые привязки
|
||||
(`layer_group_use`): при нехватке VRAM сначала уходят данные, к которым напрямую не
|
||||
привязывались 3 с, а зеркала с памятью без действительных блоков пересоздаются только поверх
|
||||
действительных (`LayerCompactMirrors`) — иначе частично вернувшееся на место зеркало держало
|
||||
всю свою память. На RX 7800 XT с `BB_VRAM_LIMIT_MB=4200–4600` это освобождало 160–490 МиБ за
|
||||
раз, картинка не менялась. На NVIDIA не проверено.
|
||||
|
||||
## Переключатели и диагностика
|
||||
|
||||
| Переменная | Что делает |
|
||||
|---|---|
|
||||
| `BB_LAYER_MEMORY=1/0` | модуль памяти вкл/выкл (по умолчанию: на не-AMD вкл) |
|
||||
| `BB_LAYER_GPU_WRITES=0/1/2` | где видеочипу можно писать в VRAM (см. выше), по умолчанию 1 |
|
||||
| `BB_LAYER_WRITE_TRAPS=0` | без ловушек записи (только для сравнения: вернутся взрывы) |
|
||||
| `BB_LAYER_VOLATILE=1` | с летучими блоками (с 2026-10-10 выключены по умолчанию: их копии разрывали проходы рендера) |
|
||||
| `BB_LAYER_PAGED=0` | без таблицы страниц для привязок от 64 МиБ |
|
||||
| `BB_COPY_SHADER_NATIVE=0/1` | HLE / нативный шейдер копирования игры; в новой модели по умолчанию нативный |
|
||||
| `BB_RESIDENCY_MIX=1/2` | привязки на месте / в VRAM / смешанные; `2` — ещё и самые тяжёлые с разбором блоков |
|
||||
| `BB_LAYER_WRITE_LOG=1` | крупные записи видеочипа, оставленные на месте, и образы рядом |
|
||||
| `BB_TOGGLE_FILE`, бит эксперимента 8 | чтение на месте вместо копий в VRAM (проверка устаревших копий) |
|
||||
| `BB_TOGGLE_FILE`, бит эксперимента 16 | без обновлений летучих блоков |
|
||||
| `BB_LAYER_WATCH=0` | без наблюдаемых блоков (блоки, где писал процессор, читаются на месте) |
|
||||
| `BB_LAYER_WATCH_HOT=1` | наблюдать и часто записываемые процессором блоки (эксперимент) |
|
||||
| `BB_LAYER_MIRROR_GROWTH_MB=N` | запас роста зеркала, по умолчанию 64; `0` — без запаса |
|
||||
| `BB_VRAM_PRESSURE_IDLE_SECONDS=N` | при нехватке VRAM на место уходят данные, к которым напрямую не привязывались N с (3; `0` — нет) |
|
||||
| `BB_LAYER_MIRROR_FLOOR_PERCENT=N` | доля бюджета VRAM, которую сборщик текстур не забирает у зеркал (25) |
|
||||
| `BB_ASYNC_PIPELINES=0` | новые конвейеры компилируются сразу, игра ждёт (по умолчанию — в фоне для проходов, рисуемых каждый кадр) |
|
||||
| `BB_ASYNC_PIPELINE_THREADS=N` | число потоков фоновой компиляции (по умолчанию четверть потоков процессора, 1–4) |
|
||||
| `BB_VRAM_LIMIT_MB=N` | тест: бюджет VRAM драйвера считается не больше N МиБ (имитация карты на 6 ГБ: 5600) |
|
||||
| `BB_RESIDENCY_MIX=1` | строка `Layer in place` теперь также говорит, почему блоки не наблюдаются |
|
||||
|
||||
## Что дальше
|
||||
|
||||
1. Лог с NVIDIA.
|
||||
2. Найти причину медленных запусков (или доказать, что это разная сцена).
|
||||
3. Летучие блоки обновляются на 0,9–1,6 ГБ/с — дешевле было бы обновлять их только после
|
||||
записи процессора (ловушки уже есть).
|
||||
4. Если модуль на NVIDIA подтвердится, перевести на него и AMD и убрать sparse-арену из новой
|
||||
модели.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Online play and co-op
|
||||
|
||||
Online play is a beta. Messages, bloodstains and ghosts come from the community game server,
|
||||
[The Hunter's Dream](https://thehuntersdream.com). Bells and summons go through a shadNet server,
|
||||
and then the players' games connect to each other directly. Linux and Windows players can play
|
||||
together: everyone needs the game at version 1.09 and the same servers.
|
||||
|
||||
> **Co-op does not connect through shadPS4's public server.** It does not answer the UDP ping
|
||||
> that tells it each player's address, so a summon times out
|
||||
> ([deadinside28/bloodborne_pc#121](https://github.com/deadinside28/bloodborne_pc/issues/121));
|
||||
> the shadPS4 team does not support forks. Messages, bloodstains and ghosts work. For co-op, a
|
||||
> group runs its own server: [SERVER.md](SERVER.md). *Test the connection* tells which case
|
||||
> yours is: the shadNet server's UDP line is red on the public server.
|
||||
|
||||
## Account
|
||||
|
||||
1. On shadPS4's public server, register at [shadnet.shadps4.net](https://shadnet.shadps4.net).
|
||||
On your own server, its owner creates the account ([SERVER.md](SERVER.md)).
|
||||
2. In the launcher's **Online** page, turn on **Play online**, choose the **shadNet server**
|
||||
(shadPS4's public one or your own, with its address), and enter the **account name** (not the
|
||||
email) and the password. The password is kept on this computer with the launcher's settings.
|
||||
3. **Test the connection**: the game server, the shadNet server, its UDP port and its WebAPI
|
||||
should all answer.
|
||||
|
||||
If the game says you are not signed in to PlayStation Network, the shadNet login failed. The
|
||||
usual cause is the password: the log then has a shadNet login error (code 8 is a wrong
|
||||
password). *Test the connection* only checks that the servers answer, not the account.
|
||||
|
||||
## Summoning in the game
|
||||
|
||||
- The host rings the **Beckoning Bell** (one Insight each time); the helper rings the **Small
|
||||
Resonant Bell**.
|
||||
- Use the same **password** in the game's network settings, so you find each other whatever
|
||||
your levels.
|
||||
- Be in the same area, close to each other, with the area's boss still alive in the host's
|
||||
world.
|
||||
|
||||
## Ports
|
||||
|
||||
Co-op traffic is UDP, straight between the players' computers. With your own server on
|
||||
Tailscale ([SERVER.md](SERVER.md)) it goes through Tailscale: turn **UPnP** off and skip this
|
||||
section. Otherwise each player has to be reachable from the Internet:
|
||||
|
||||
1. **The router.** With **UPnP** on (the default), the game opens its port on the router itself:
|
||||
the log says `UPNP: mapped UDP port <port>`. A router without UPnP needs a port forward by
|
||||
hand (UDP, the pinned port below, to your computer's LAN address).
|
||||
2. **Pin the port** when you open it by hand or in a firewall: **Co-op port (UDP)** in the
|
||||
Online page, for example 3658 (0, the default, is a random port each time). The log then says
|
||||
`P2P transport ready: UDP physical_port=3658`.
|
||||
3. **Open it in the firewall.** UPnP opens the port on the router only, not in this computer's
|
||||
firewall. With ufw or firewalld on, the launcher's **Online** page says
|
||||
so and gives the commands. For ufw:
|
||||
```sh
|
||||
sudo ufw allow 3658/udp
|
||||
sudo ufw allow from <router IP> proto udp # the router's UPnP answers
|
||||
```
|
||||
On Windows, in a terminal as administrator:
|
||||
```
|
||||
netsh advfirewall firewall add rule name="Bloodborne co-op" dir=in action=allow protocol=UDP localport=3658
|
||||
```
|
||||
|
||||
A router whose public address is shared by many customers (CG-NAT) cannot forward ports: the
|
||||
log's `UPNP: IGD found - external IP=...` should be your real public address. Tailscale works
|
||||
behind CG-NAT too.
|
||||
|
||||
## Reading the log
|
||||
|
||||
Run with `BB_GPU_LOG=info` in the extra variables for the online details. In a summon:
|
||||
|
||||
| Line | Meaning |
|
||||
|---|---|
|
||||
| `Logged in npid='...'` | The shadNet login worked. |
|
||||
| `summon_messenger/create` | Your sign is placed (helper). |
|
||||
| `summon_messenger/get`, `sceNpMatching2CreateJoinRoom`, `summon_messenger/request` | The host found the sign, made the room and sent the summon. |
|
||||
| `peer '...' endpoint unresolved` | shadNet has no address for the other player: its UDP port did not answer (the public server, above). |
|
||||
| `event=0(DEAD)` | The connection gave up. |
|
||||
@@ -0,0 +1,40 @@
|
||||
# Documentation
|
||||
|
||||
## For players
|
||||
|
||||
- [COMPATIBILITY.md](COMPATIBILITY.md): which releases of Bloodborne run, and which have been
|
||||
checked.
|
||||
- [MODS.en.md](MODS.en.md): file mods and third-party patches.
|
||||
- [ONLINE.md](ONLINE.md): online play and co-op: the account, the bells, the ports.
|
||||
- [SERVER.md](SERVER.md): hosting your own co-op server (shadnet-p2p) for a group of friends.
|
||||
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md): common problems and what to do.
|
||||
|
||||
## For this fork
|
||||
|
||||
- [RELEASE_TEMPLATE.md](RELEASE_TEMPLATE.md): the format of every release's notes.
|
||||
|
||||
## bbport's development notes
|
||||
|
||||
Everything else here comes from [bbport](https://github.com/deadinside28/bloodborne_pc) by
|
||||
deadinside28, kept as it is so that its updates merge cleanly. Many are in Russian (`.ru.md`, or
|
||||
a Russian title).
|
||||
|
||||
- **What changed in each version:** [CHANGES_0.5.md](CHANGES_0.5.md),
|
||||
[CHANGES_0.5-pre4.md](CHANGES_0.5-pre4.md), [CHANGES_0.5-pre3.md](CHANGES_0.5-pre3.md),
|
||||
[CHANGES_0.5-pre2.md](CHANGES_0.5-pre2.md), [CHANGES_after_0.4.md](CHANGES_after_0.4.md),
|
||||
[CHANGES_0.4.md](CHANGES_0.4.md), [CHANGES_2026-10-06.md](CHANGES_2026-10-06.md) (0.3),
|
||||
[CHANGES_2026-10-03.md](CHANGES_2026-10-03.md), [CHANGES_2026-10-02.md](CHANGES_2026-10-02.md).
|
||||
- **Where the port is going:** [ROADMAP.md](ROADMAP.md),
|
||||
[EMULATION_REMOVAL_PLAN.ru.md](EMULATION_REMOVAL_PLAN.ru.md),
|
||||
[TRANSLATOR_ARCHITECTURE.ru.md](TRANSLATOR_ARCHITECTURE.ru.md).
|
||||
- **Memory and GPU commands:** [MEMORY_MODULE_PLAN.ru.md](MEMORY_MODULE_PLAN.ru.md),
|
||||
[NVIDIA_MEMORY_MODEL.ru.md](NVIDIA_MEMORY_MODEL.ru.md),
|
||||
[TRANSLATION_GPU_COPY_LABELS.ru.md](TRANSLATION_GPU_COPY_LABELS.ru.md),
|
||||
[parallel_gpu.md](parallel_gpu.md).
|
||||
- **Upscaling, TAA and motion vectors:** [upscaler.md](upscaler.md),
|
||||
[DEPTH_ADAPTIVE_TAA.md](DEPTH_ADAPTIVE_TAA.md),
|
||||
[TEMPORAL_REVIEW_2026-10-01.md](TEMPORAL_REVIEW_2026-10-01.md),
|
||||
[motion_vectors.md](motion_vectors.md).
|
||||
- **Mods, patches and TAA sharpness** (the original of MODS.en.md): [MODS.md](MODS.md).
|
||||
- **The first experiments:** [DEVELOPMENT_LOG.ru.md](DEVELOPMENT_LOG.ru.md), and the session
|
||||
notes in [history/](history/).
|
||||
@@ -11,8 +11,9 @@ changes since the previous release. Third-party work is credited in the line tha
|
||||
```markdown
|
||||
<One or two sentences: what this release is and which upstream bbport it is based on.>
|
||||
|
||||
**Requirements:** your own decrypted dump of Bloodborne 1.09, US (`CUSA03173`) or EU
|
||||
(`CUSA00900`). No game files are included. Linux x86-64 and a Vulkan 1.3 GPU.
|
||||
**Requirements:** your own decrypted dump of Bloodborne with update 1.09, any retail release (US,
|
||||
Europe, UK, Japan, Asia, and the editions with The Old Hunters). No game files are included.
|
||||
Linux x86-64 and a Vulkan 1.3 GPU.
|
||||
|
||||
## Download
|
||||
|
||||
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
# Hosting your own co-op server
|
||||
|
||||
Bells and summons go through a shadNet server. Players who connect through shadPS4's public one
|
||||
(`srv.shadps4.net`) get no co-op at the moment: it does not answer on its UDP port, so a summon
|
||||
never connects ([deadinside28/bloodborne_pc#121](https://github.com/deadinside28/bloodborne_pc/issues/121)).
|
||||
A group of friends can run their own server instead:
|
||||
[shadnet-p2p](https://github.com/Wozzardman/shadnet-p2p) by Wozzardman, the shadNet server with
|
||||
that UDP port working and a summon service of its own.
|
||||
|
||||
Messages, bloodstains and ghosts still come from The Hunter's Dream, whichever shadNet server you
|
||||
use. Windows players of [Supermedo's port](https://github.com/Supermedo/bloodborne_pc) can join
|
||||
the same server.
|
||||
|
||||
Tested with two players, one on this Linux port and one on Supermedo's Windows port, over
|
||||
Tailscale, with the server below on a home server (Ubuntu 26.04): summons, a boss fight together
|
||||
and summoning again after the helper died.
|
||||
|
||||
## How it fits together
|
||||
|
||||
- **One always-on computer runs the server:** a VPS, a home server, or one of the players' PCs
|
||||
(then it has to be on while you play).
|
||||
- **Everyone joins one [Tailscale](https://tailscale.com) network** (a *tailnet*): the server and
|
||||
every player. Tailscale gives each computer an address starting with `100.` and encrypts the
|
||||
traffic between them. This matters: shadNet's login on TCP 31313 is not encrypted, so it should
|
||||
not be open to the Internet. And the games then reach each other over Tailscale too, so nobody
|
||||
has to open ports on their router.
|
||||
|
||||
| Protocol | Port | Used for |
|
||||
|---|---|---|
|
||||
| TCP | 31313 | Login and matchmaking |
|
||||
| UDP | 31314 | Each player's address, for the other player of a summon |
|
||||
| TCP | 31315 | WebAPI and the summon service |
|
||||
|
||||
## 1. Tailscale
|
||||
|
||||
On the server and on every player's computer, install Tailscale
|
||||
([download](https://tailscale.com/download); on Linux `curl -fsSL https://tailscale.com/install.sh | sh`)
|
||||
and sign in:
|
||||
|
||||
```sh
|
||||
sudo tailscale up
|
||||
```
|
||||
|
||||
The server's owner invites the players from the
|
||||
[admin console](https://login.tailscale.com/admin/users) (**Users → Invite external users**),
|
||||
and each player accepts the invitation and signs in on the computer they play on. Then, on the
|
||||
server:
|
||||
|
||||
```sh
|
||||
tailscale ip -4 # the server's address, 100.x.y.z: the players need it
|
||||
tailscale status # every player's computer should be listed
|
||||
```
|
||||
|
||||
## 2. The server
|
||||
|
||||
### With Docker (any Linux)
|
||||
|
||||
This repository has a Docker image for it: [tools/shadnet-server](../tools/shadnet-server). It
|
||||
builds shadnet-p2p on Debian 13, because shadnet-p2p needs Qt 6.8 or newer and some
|
||||
distributions are older (Ubuntu 24.04 has Qt 6.4). It runs on any Linux with Docker, Ubuntu 24.04
|
||||
included.
|
||||
|
||||
```sh
|
||||
mkdir shadnet-server && cd shadnet-server
|
||||
for f in Dockerfile entrypoint.sh; do
|
||||
curl -fsSLO "https://raw.githubusercontent.com/ayozetr/bloodborne_linux/main/tools/shadnet-server/$f"
|
||||
done
|
||||
docker build -t bbport-shadnet .
|
||||
```
|
||||
|
||||
Then start it, with the server's Tailscale address and a signup code of your own (letters,
|
||||
digits, `-` and `_`; the players never need it, only you, to create their accounts):
|
||||
|
||||
```sh
|
||||
docker run -d --name shadnet --restart unless-stopped --network host \
|
||||
-v shadnet-data:/data \
|
||||
-e SHADNET_HOST=100.x.y.z \
|
||||
-e SHADNET_REGISTRATION_KEY=a-long-code-of-your-own \
|
||||
bbport-shadnet
|
||||
docker logs shadnet
|
||||
```
|
||||
|
||||
The log should end with the three listeners on the Tailscale address:
|
||||
|
||||
```text
|
||||
Unsecured TCP listener on: 100.x.y.z:31313. No encryption, use it only on trusted networks
|
||||
STUN UDP listener on: 100.x.y.z:31314
|
||||
WebApiServer listening on: 100.x.y.z:31315
|
||||
```
|
||||
|
||||
`SHADNET_HOST` keeps the server off the computer's other networks. After a reboot, it waits until
|
||||
Tailscale is up. The configuration (`shadnet.cfg`) and the accounts (`db/shadnet.db`) live in the
|
||||
`shadnet-data` volume. To stop or update the server:
|
||||
|
||||
```sh
|
||||
docker stop shadnet && docker rm shadnet # the volume, with the accounts, stays
|
||||
docker build -t bbport-shadnet . # after downloading a newer Dockerfile
|
||||
```
|
||||
|
||||
Then run the same `docker run` again.
|
||||
|
||||
### Without Docker
|
||||
|
||||
Follow [shadnet-p2p's README](https://github.com/Wozzardman/shadnet-p2p#readme). It needs Qt 6.8
|
||||
or newer: Arch Linux and its derivatives, Debian 13, Ubuntu 26.04, Fedora 41 or newer. On Debian
|
||||
and Ubuntu, install `qt6-websockets-dev` along with the packages it lists, or CMake does not find
|
||||
Qt's HTTP server module (checked on Debian 13 and Ubuntu 26.04). In `build/shadnet.cfg`, set `Host` to the server's Tailscale address (or
|
||||
`0.0.0.0`), `Matching2Enabled=true` and `RegistrationSecretKey` to your signup code.
|
||||
|
||||
### A firewall on the server
|
||||
|
||||
With ufw, let the tailnet in:
|
||||
|
||||
```sh
|
||||
sudo ufw allow in on tailscale0
|
||||
```
|
||||
|
||||
## 3. Accounts
|
||||
|
||||
One account per player, created on the server with the signup code. The name is 3 to 16
|
||||
letters, digits, `-` or `_`:
|
||||
|
||||
```sh
|
||||
docker exec shadnet shadnet-sample 127.0.0.1 31313 register <name> <password> <email> <signup code>
|
||||
```
|
||||
|
||||
`127.0.0.1` works only when the server listens on every address (`SHADNET_HOST` unset or
|
||||
`0.0.0.0`). With `SHADNET_HOST` set, use that address instead. The tool answers
|
||||
`Account created successfully.`, or `FAILED: Unauthorized` when the code is wrong. Give each player
|
||||
their own name and password.
|
||||
|
||||
To back up the accounts, stop the server and copy the volume's `db/shadnet.db`.
|
||||
|
||||
## 4. Each player's launcher
|
||||
|
||||
In the **Online** page:
|
||||
|
||||
| Setting | Value |
|
||||
|---|---|
|
||||
| Play online | On |
|
||||
| shadNet server | **Your own server** |
|
||||
| Server address | `100.x.y.z` (the port, 31313, is added) |
|
||||
| WebAPI address | Empty (the server's port 31315) |
|
||||
| Online ID / Password | The player's own account |
|
||||
| UPnP | Off (Tailscale needs no router ports) |
|
||||
|
||||
Then **Test the connection**. Every line should be green, the shadNet server's UDP among them: it
|
||||
shows the address the server sees for you, a `100.` one through Tailscale. A red UDP line means
|
||||
summons cannot connect: check that the server is running and that its log lists the UDP listener.
|
||||
|
||||
Summons go through the server's own summon service: the log of a game says
|
||||
`Co-op: summon signs through http://100.x.y.z:31315`.
|
||||
|
||||
Windows players set the same server, WebAPI and account in the Windows port's launcher.
|
||||
|
||||
## Seamless co-op (experimental)
|
||||
|
||||
shadnet-p2p can also summon between different areas: the guest is moved to the host's area. To
|
||||
use it, the server and every player must have it on:
|
||||
|
||||
- The server: add `-e SHADNET_BLOODBORNE_SEAMLESS_COOP=1` to `docker run`, or set
|
||||
`BloodborneSeamlessCoop=true` in `shadnet.cfg`. Its log then says `seamless co-op enabled`.
|
||||
- Each player: **Seamless co-op (experimental)** in the launcher's Online page.
|
||||
|
||||
Ring the host's Beckoning Bell first, then the guest's Small Resonant Bell. Travelling together
|
||||
by lantern once the session has started does not work yet.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **The log shows `127.0.0.1` or another address in the listeners:** check `SHADNET_HOST`, or
|
||||
`Host` in the `shadnet.cfg` beside the server's executable.
|
||||
- **`Waiting for 100.x.y.z` in the log:** Tailscale is not up on the server, or the address is
|
||||
wrong (`tailscale ip -4`).
|
||||
- **The game says it is not signed in to PlayStation Network:** a wrong name or password (code 8 in
|
||||
the log), or two players using one account.
|
||||
- **The test is green but summons fail:** every player's computer must be in the tailnet, not only
|
||||
the server; `tailscale ping <player>` from each side. Everyone needs the game at version 1.09
|
||||
and the same co-op mode.
|
||||
|
||||
See also [ONLINE.md](ONLINE.md) for the bells, passwords and log lines of a summon.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Оригинальное GPU-копирование и переносимые метки
|
||||
|
||||
Срез 09.10.2026. Область проверки: `BB_PC_MODEL=1 BB_LAYER_MEMORY=1`; новая модель, без оценки старой модели памяти.
|
||||
|
||||
## Оригинальный copy shader
|
||||
|
||||
В режиме памяти игры на месте шейдер `fefebf9f` теперь по умолчанию транслируется в SPIR-V и исполняется на GPU. Его список копий читает сам шейдер при исполнении; CPU не заменяет его списком Vulkan-копий. `BB_COPY_SHADER_NATIVE=0` сохраняет HLE для сравнения. Эксперимент 2 по-прежнему инвертирует выбор.
|
||||
|
||||
Для больших привязок таблица BDA содержит два представления: в первой половине — актуальные адреса (зеркало или память игры), во второй — адреса памяти игры. Существующая адресация первой половины сохранена для DMA/ReadConst. Описание привязки содержит флаг записи насквозь и смещение второй таблицы.
|
||||
|
||||
Оригинальный copy shader записывает результат в актуальный GPU-адрес и в память игры. Поэтому CPU-потребители видят результат после синхронизации, а GPU-потребители не читают устаревшее зеркало. Когда обе записи адресуют память игры, они дают тот же результат. Остальные вычислительные шейдеры сохраняют свой учёт GPU-владения зеркалами. Записи насквозь не помечают всё зеркало огромной привязки как требующее обратного копирования; ранее накопленные GPU-записи при этом сохраняются в учёте.
|
||||
|
||||
Проверка диапазона не допускает переполнения `offset + size`; отвергнутый доступ не индексирует произвольную страницу таблицы. Версия shader binary cache поднята до 9. Профиль кэша теперь содержит версии binary/meta/pipeline: при их смене весь кэш перестраивается до загрузки модулей. Старые метаданные и SPIR-V с совпадающими именами индексов вариаций не смешиваются с новыми.
|
||||
|
||||
`run.sh` задаёт `BB_GPU_USER_DIR` до запуска процесса, из `BB_USER_DIR` или `$BB_DATA_DIR/user`. GPU-каталоги создаются при загрузке библиотеки, поэтому установка этого значения внутри `bbgpu_init` была слишком поздней. Это обеспечивает правильный выбор кэша для AppImage и отдельных профилей сохранений; явный `BB_GPU_USER_DIR` сохраняется.
|
||||
|
||||
## EOP/EOS и RELEASE_MEM
|
||||
|
||||
Если `VK_AMD_buffer_marker` доступно, сохраняется быстрый путь AMD. Без расширения метку пишет GPU через стандартный `vkCmdUpdateBuffer`. `BB_GPU_LABELS_PORTABLE=1` принудительно выбирает этот путь и позволяет проверить его на AMD. `BB_GPU_LABELS=0` оставляет прежний callback CPU после завершения GPU.
|
||||
|
||||
Переносимый путь завершает текущий render pass, публикует предшествующие GPU-записи для CPU, записывает старшую половину 64-битной метки, ставит зависимость и записывает младшую половину. Следующая зависимость обеспечивает видимость метки для GPU и CPU. Уведомление планировщику и обработка WAIT_REG_MEM сохраняются. Неподходящие адреса и метки с прерыванием сохраняют соответствующие запасные пути.
|
||||
|
||||
Стандартная команда разрешена вне render pass: [vkCmdUpdateBuffer](https://docs.vulkan.org/refpages/latest/refpages/source/vkCmdUpdateBuffer.html). Маски стадий и доступа соответствуют [правилам Vulkan synchronization](https://docs.vulkan.org/spec/latest/chapters/synchronization.html). Завершение проходов и барьеры имеют стоимость; принудительный переносимый путь на AMD не выбран по умолчанию.
|
||||
|
||||
При проверке также исправлены две зависимости соседних путей: update/inline data учитываются на стадии CLEAR, а диапазон index buffer учитывается после draw, чтобы последующая загрузка в зеркало ожидала чтения индексов.
|
||||
|
||||
## Проверки
|
||||
|
||||
`translation-memory-test` исполняет SPIR-V производственного backend и производственную функцию переносимых меток на Vulkan GPU. Проверяются чтение актуального источника, запись в зеркало и память игры, граница страниц, unmapped/out-of-range store, отключённая запись насквозь, 32/64-битные метки, порядок половин, видимость предшествующего GPU-результата при опросе CPU, последующий GPU-потребитель и нулевое значение. Диагностические AMD breadcrumbs отключены, чтобы тест не записывал AMD-маркеры.
|
||||
|
||||
```sh
|
||||
nix-shell shell.nix --run 'ninja -C out/gpu translation-memory-test'
|
||||
# VK_LAYER_PATH при необходимости указывает каталог установленного Khronos validation layer.
|
||||
BB_VK_VALIDATION_SYNC=1 out/gpu/translation-memory-test out/translation-shaders
|
||||
spirv-val --target-env vulkan1.3 out/translation-shaders/paged-copy.spv
|
||||
```
|
||||
|
||||
PM4 self-test измеряет положительный occlusion-интервал через несколько отправок. Большая отдельная отправка могла содержать только compute/state и давать ложный FAIL. Требования positive samples, valid bits, нулевой интервал и predication сохранены.
|
||||
|
||||
Аппаратная проверка выполнена на RX 7800 XT / RADV. Переносимый путь проверен принудительно на AMD; выполнение на настоящей NVIDIA, импорт её host memory и длительное прохождение игры требуют отдельного аппаратного прогона.
|
||||
|
||||
Локальные журналы, копии исходников перед изменениями, замеры и снимки: `out/dev/translation-fixes-20261009/`. Игровые проверки используют копии сохранений и настроек. Исходные сохранения и настройки не заменяются. Журналы и игровые данные в релиз не включены.
|
||||
@@ -0,0 +1,92 @@
|
||||
# Свой транслятор вместо shadPS4: устройство и порядок работ (2026-10-10)
|
||||
|
||||
Цель: уйти от эмуляции и от кода shadPS4 — собственный транслятор команд PS4 и собственный
|
||||
графический рендер, которые масштабируются на другие игры (всё, что про одну игру, — в её
|
||||
профиле, `gpu/games/`), одинаковые для AMD и NVIDIA. Потом — shadnet (сетевая игра).
|
||||
|
||||
## Что сейчас
|
||||
|
||||
Заимствовано из shadPS4 (`gpu/VENDOR.txt`, коммит b4e7ae7 от 2026-09-24) около 116 тыс. строк:
|
||||
|
||||
| Часть | Строк | Что делает | Наше в ней |
|
||||
|---|---|---|---|
|
||||
| `video_core/amdgpu` | 8,3 тыс. | разбор PM4 (командный процессор `liverpool.cpp`), регистры, тайлинг | метки видеочипом, occlusion, предикация, самотест PM4 |
|
||||
| `video_core/renderer_vulkan` | 28,6 тыс. | рендер Vulkan: конвейеры, растеризатор, планировщик, презентер | конвейер отрисовок (стадии A/B), потоки записи, апскейлеры, фоновая компиляция |
|
||||
| `video_core/buffer_cache` | 7,4 тыс. | память игры для видеочипа | почти всё переписано (модуль памяти, копии в VRAM, ловушки) |
|
||||
| `video_core/texture_cache` | 4,8 тыс. | текстуры по адресу, детайлинг | сборщик по времени, загрузки |
|
||||
| `shader_recompiler` | 38,6 тыс. | GCN → IR → SPIR-V | постраничные буферы (BDA), исправления |
|
||||
| `core`, `common` | 21,8 тыс. | VideoOut, GnmDriver, очереди событий, утилиты | vblank, метки |
|
||||
|
||||
Своё, вне кода shadPS4: `gpu/layer/` (модуль памяти `BbLayer::GpuMemory`), `gpu/games/` (профили
|
||||
игр), `gpu/shim/` (оверлей, настройки, перехваты), рантайм `src/` (ядро, libc, файлы, сохранения).
|
||||
|
||||
## Устройство, к которому идём
|
||||
|
||||
Модули с узкими интерфейсами; ни один не знает адресов кода игры (это профиль) и не делает
|
||||
работу видеочипа на процессоре (это эмуляция):
|
||||
|
||||
1. **memory** — память игры на месте, копии в VRAM как кэш, общий учёт защиты страниц (ловушки
|
||||
записи для копий и текстур). Есть: `layer/` + модуль в `buffer_cache_layer.cpp`.
|
||||
2. **cp** — командный процессор: разбор PM4 в поток команд транслятора (состояние, отрисовки,
|
||||
запуски, синхронизация) в порядке исполнения видеочипом. Заменяет `liverpool.cpp`.
|
||||
3. **state** — регистры контекста → ключи конвейеров и динамическое состояние Vulkan. Заменяет
|
||||
`liverpool_to_vk`, сборку ключей в `vk_pipeline_cache`.
|
||||
4. **resources** — описатели V#/T#/S# → буферы, образы, сэмплеры (кэши, детайлинг). Заменяет
|
||||
`buffer_cache`, `texture_cache` (буферная часть уже почти наша).
|
||||
5. **render** — Vulkan: запись команд по потокам, барьеры, отправка, вывод. Заменяет
|
||||
`renderer_vulkan` (планировщик и стадии A/B уже наши).
|
||||
6. **shaders** — GCN → SPIR-V. Самая большая часть; заменяется последней, по стадиям (декодер,
|
||||
IR, проходы, генерация).
|
||||
7. **platform** — VideoOut, GnmDriver, события ядра (`core/libraries`), рядом с рантаймом.
|
||||
8. **games** — профили игр (есть).
|
||||
|
||||
## Порядок
|
||||
|
||||
Замена по одному модулю: сначала интерфейс в нашем коде и за ним — код shadPS4 как есть, потом
|
||||
наша реализация за тем же интерфейсом. После каждого шага: маршрут (`route_bench.sh`, кадры и
|
||||
снимки), самотест PM4 (`BB_PM4_SELFTEST=1`), юнит-тесты, игра на AMD и (по логам тестеров) NVIDIA.
|
||||
|
||||
| Шаг | Что | Почему в этом порядке |
|
||||
|---|---|---|
|
||||
| 1 | memory: общий учёт защиты страниц; ловушки под текстурами по умолчанию; модель 0.3 и sparse-арена удаляются | убирает остаток эмуляции памяти и привязку к перехватам игры |
|
||||
| 2 | cp: поток команд транслятора; `MEM_SEMAPHORE`, время видеочипа, очереди compute — видеочипом | в командном процессоре осталась последняя эмуляция |
|
||||
| 3 | state + resources | опираются на 1 и 2; буферная часть уже наша |
|
||||
| 4 | render | планировщик и стадии уже наши; остаются растеризатор и конвейеры |
|
||||
| 5 | shaders | самый большой и рискованный; к этому времени остальное уже наше |
|
||||
| 6 | shadnet | сеть, когда графика своя |
|
||||
|
||||
Шаги 1 и 2 — это план ухода от эмуляции (`EMULATION_REMOVAL_PLAN.ru.md`, раздел от 2026-10-10).
|
||||
|
||||
## Ход работ
|
||||
|
||||
### 2026-10-10: свой декодер PM4 (шаг 2, начало)
|
||||
|
||||
- `gpu/cp/` — свой код, без shadPS4: формат пакетов и опкоды (`cp_pm4.h`), файл регистров и
|
||||
декодер (`cp_decoder.{h,cpp}`). Декодер идёт по буферу в порядке потока, применяет пакеты
|
||||
регистров (`SET_*_REG`, `CLEAR_STATE`, регистры, которые пишут пакеты отрисовки), спускается во
|
||||
вложенные буферы и отдаёт каждый пакет «приёмнику» (`BbCp::Sink`) с уже применённым состоянием:
|
||||
отрисовки и запуски — типизированно, остальное — пакетами. `COND_EXEC` решает приёмник. Про
|
||||
Vulkan, игру и место исполнения декодер не знает.
|
||||
- Юнит-тест `tests/test_cp_decoder.cpp` (цель `cp-decoder-test`): регистры, частичные записи,
|
||||
отрисовки, запуски, вложенные буферы, `COND_EXEC`, `CLEAR_STATE`, битые буферы.
|
||||
- Адреса регистров сверены с раскладкой shadPS4 на этапе сборки (`static_assert`): так нашлась
|
||||
ошибка — на CIK `CP_STRMOUT_CNTL` в uconfig (`0xC03F`), не в config.
|
||||
- Теневая проверка в игре (`BB_CP_SHADOW=1`): новый декодер разбирает каждый буфер верхнего уровня
|
||||
с того же состояния, в конце буфера файлы регистров сравниваются. На маршруте — все буферы
|
||||
совпали (~800 тыс. буферов, ~200 млн пакетов, 0 расхождений, 0 ошибок разбора). Вложенных
|
||||
буферов Bloodborne не использует (проверены юнит-тестом).
|
||||
- Дальше: декодер как курсор (пакет за пакетом, чтобы цикл командного процессора мог уступать
|
||||
другим очередям на ожиданиях), файл регистров — общее хранилище состояния (раскладка совпадает
|
||||
с `Regs` shadPS4 по словам), затем перенос обработки пакетов из `liverpool.cpp` в приёмник
|
||||
транслятора по одному виду пакетов, каждый раз с теневой проверкой и маршрутом.
|
||||
|
||||
### 2026-10-10: новый декодер — настоящий путь разбора
|
||||
|
||||
- Декодер стал курсором (`BbCp::Cursor`: пакет за пакетом, вложенные буферы — по желанию
|
||||
вызывающего), файл регистров может жить в хранилище владельца (у командного процессора — его
|
||||
`regs`, раскладка по словам та же), наблюдатель записей (`RegisterObserver`, один вызов на
|
||||
пакет) даёт то, что нужно подготовке отрисовок: записанные блоки и контрольную сумму пакетов.
|
||||
- `ProcessGraphics` берёт пакеты и запись регистров у курсора (`BB_CP_DECODER=0` — старый обход);
|
||||
что делает каждый пакет — пока прежний код. PM4-самопроверка — 11 из 11; доля подготовленных
|
||||
отрисовок та же (747 тыс. использовано, 19 тыс. нет, против 755/24 тыс.) — контрольные суммы
|
||||
сходятся; картинка та же.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Troubleshooting
|
||||
|
||||
When asking for help, attach the log: in the launcher's **Log** page, **Export log…** saves it to
|
||||
a file and **Copy** puts it on the clipboard.
|
||||
|
||||
## The launcher rejects the game
|
||||
|
||||
The launcher checks the game folder before starting. What it says, and what to do:
|
||||
|
||||
| Message | What to do |
|
||||
|---|---|
|
||||
| bbport needs the 1.09 update merged into the game folder | Copy everything from the dumped 1.09 update into the game folder, replacing files (`eboot.bin` and `sce_sys` too). |
|
||||
| param.sfo is from 1.09 but eboot.bin is not | Copy `eboot.bin` from the dumped 1.09 update over the old one. |
|
||||
| This eboot.bin has the 60 fps patch by Lance McDonald applied | Use a clean `eboot.bin` from the 1.09 update. bbport has its own 60 FPS. |
|
||||
| This is not a retail release of Bloodborne | Alpha tests and other games do not run. See [COMPATIBILITY.md](COMPATIBILITY.md). |
|
||||
| eboot.bin could not be read as a decrypted PS4 executable | Dump the game and the update again. |
|
||||
| The game files are damaged | The extraction tool broke compressed files (LibOrbisPkg PkgTool on .NET 6 or newer); the game would hang while loading. Extract the game and the update again with a fixed tool. |
|
||||
|
||||
## The game shows *New Game* instead of my save
|
||||
|
||||
Saves live in the data directory, and each way of running the port has its own:
|
||||
|
||||
- The AppImage: `~/.local/share/bbport/user/savedata/1/<title ID>/`.
|
||||
- From the repository (`run.sh`): `user/savedata/1/<title ID>/` in the repository.
|
||||
|
||||
To move a save, close the game, back up both folders, and copy the `savedata` folder over.
|
||||
|
||||
## DLSS is "not supported by this GPU"
|
||||
|
||||
The log says why, on a line starting with `DLSS:`.
|
||||
|
||||
- DLSS needs a GeForce RTX (20 series or newer) and NVIDIA's own driver; it does not work with
|
||||
NVK.
|
||||
- The 0.4-linux.1 AppImage ships a modified copy of NVIDIA's DLSS library, which the driver
|
||||
refuses (`Feature requirement query failed: 0xbad00012`): update to 0.5-linux.1 or newer.
|
||||
- From the repository, DLSS needs `bash tools/build_dlss.sh` once after `build.sh`.
|
||||
- If the log says `Device creation with DLSS extensions failed`, NVIDIA's CUDA/UVM
|
||||
module is missing: the game then uses FSR 3.1. Load it with `sudo modprobe nvidia_uvm` (the
|
||||
`nvidia-modprobe` package loads it when needed); with Secure Boot, a module signing key that
|
||||
is not enrolled stops it (`Key was rejected by service`).
|
||||
|
||||
## Spanish shows the Latin American text (or the other way round)
|
||||
|
||||
The game picks a language's regional text by the dump's region. Choose it in **Settings → Game
|
||||
region**: *Europe* for Spanish from Spain, *The Americas* for Latin American Spanish.
|
||||
|
||||
## The game crashes after playing a while, on a card with little VRAM
|
||||
|
||||
On a 6 GB card the texture cache can run out of video memory: the log then repeats
|
||||
`Texture cache: memory pressure, ... (critical ...)`. Lower what uses VRAM: a 60 FPS limit,
|
||||
a lower output resolution, lower **Model detail** in the game's *Display* settings, and close
|
||||
other programs that use the GPU (browsers, video players, other games).
|
||||
|
||||
## Summons never connect
|
||||
|
||||
Run **Test the connection** in the **Online** page. A red line for the shadNet server's UDP means
|
||||
the server never learns your address, and no summon can connect: shadPS4's public server does
|
||||
this. Use your own server: [SERVER.md](SERVER.md).
|
||||
|
||||
## Other online problems
|
||||
|
||||
See [ONLINE.md](ONLINE.md): the account, the bells, the ports and the log lines of a summon.
|
||||
+50
-39
@@ -97,6 +97,9 @@ add_host_shader(fsr4_color.comp fsr4_decode_comp)
|
||||
add_host_shader(fsr4_color.comp fsr4_encode_comp ENCODE=1)
|
||||
add_host_shader(fsr4_reactive.comp fsr4_reactive_comp)
|
||||
add_host_shader(buffer_multi_copy.comp buffer_multi_copy_comp)
|
||||
add_host_shader(occlusion_resolve.comp occlusion_resolve_comp)
|
||||
add_host_shader(gpu_timestamp.comp gpu_timestamp_comp)
|
||||
add_host_shader(indirect_guard.comp indirect_guard_comp)
|
||||
add_host_shader(depth_resample.frag depth_resample_frag)
|
||||
add_host_shader(depth_resample.frag depth_stencil_resample_frag HAS_STENCIL=1)
|
||||
add_host_shader(depth_resample.frag depth_stencil_bits_frag STENCIL_BITS=1)
|
||||
@@ -119,59 +122,37 @@ set(COMMON
|
||||
file(GLOB AVPLAYER CONFIGURE_DEPENDS shadps4/core/libraries/avplayer/*.cpp)
|
||||
pkg_check_modules(FFMPEG REQUIRED IMPORTED_TARGET libavformat libavcodec libavutil libswscale libswresample)
|
||||
file(GLOB SHIM_SOURCES CONFIGURE_DEPENDS shim/*.cpp shim/*/*.cpp)
|
||||
add_library(bbgpu SHARED ${VIDEO_CORE} ${RECOMPILER} ${COMMON} ${SHIM_SOURCES}
|
||||
# The layer's own modules (independent of the shadPS4 code): layer/.
|
||||
file(GLOB LAYER_SOURCES CONFIGURE_DEPENDS layer/*.cpp)
|
||||
# Game profiles (what the translator knows about one game, out of its core): games/.
|
||||
file(GLOB GAME_SOURCES CONFIGURE_DEPENDS games/*.cpp)
|
||||
# The translator's own command processor (docs/TRANSLATOR_ARCHITECTURE.ru.md, step 2): cp/.
|
||||
file(GLOB CP_SOURCES CONFIGURE_DEPENDS cp/*.cpp)
|
||||
add_library(bbgpu SHARED ${VIDEO_CORE} ${RECOMPILER} ${COMMON} ${SHIM_SOURCES} ${LAYER_SOURCES} ${GAME_SOURCES} ${CP_SOURCES}
|
||||
shadps4/core/libraries/gnmdriver/gnmdriver.cpp
|
||||
shadps4/core/libraries/videoout/driver.cpp shadps4/core/libraries/videoout/video_out.cpp
|
||||
shadps4/core/libraries/kernel/equeue.cpp ${AVPLAYER}
|
||||
shadps4/core/libraries/videodec/video_utils.cpp)
|
||||
add_dependencies(bbgpu host_shaders)
|
||||
# bbport co-op: PS4 network and PSN libraries with the shadNet client, from shadp2p
|
||||
# (github.com/Wozzardman/shadp2p, GPL-2.0), for private Bloodborne co-op servers.
|
||||
find_package(Protobuf CONFIG REQUIRED)
|
||||
set(SHADNET_PROTO_OUT "${CMAKE_CURRENT_BINARY_DIR}/shadnet_proto_gen")
|
||||
file(MAKE_DIRECTORY "${SHADNET_PROTO_OUT}")
|
||||
add_custom_command(
|
||||
OUTPUT "${SHADNET_PROTO_OUT}/shadnet.pb.cc" "${SHADNET_PROTO_OUT}/shadnet.pb.h"
|
||||
COMMAND protobuf::protoc "--proto_path=${CMAKE_CURRENT_SOURCE_DIR}/shadps4/shadnet"
|
||||
"--cpp_out=${SHADNET_PROTO_OUT}" "${CMAKE_CURRENT_SOURCE_DIR}/shadps4/shadnet/shadnet.proto"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/shadps4/shadnet/shadnet.proto")
|
||||
file(GLOB_RECURSE BBNET_SOURCES CONFIGURE_DEPENDS shadps4/core/libraries/network/*.cpp
|
||||
shadps4/core/libraries/np/*.cpp shadps4/shadnet/*.cpp)
|
||||
# Trophies and the system dialogs stay in the C runtime; their shadPS4 versions need the
|
||||
# emulator's UI layers.
|
||||
list(FILTER BBNET_SOURCES EXCLUDE REGEX
|
||||
"np_trophy|trophy_ui|np_sns_facebook_dialog|np_profile_dialog/|np_commerce/")
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
add_library(bbnet STATIC ${BBNET_SOURCES} "${SHADNET_PROTO_OUT}/shadnet.pb.cc" bbnet/bbnet_glue.cpp)
|
||||
target_include_directories(bbnet PRIVATE shim shadps4 shadps4/shadnet "${SHADNET_PROTO_OUT}"
|
||||
third_party/imgui third_party/httplib)
|
||||
target_link_libraries(bbnet PRIVATE nlohmann_json::nlohmann_json)
|
||||
# HTTPS (the community game server only speaks TLS) and gzip replies in cpp-httplib.
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_compile_definitions(bbnet PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT CPPHTTPLIB_ZLIB_SUPPORT)
|
||||
target_link_libraries(bbnet PRIVATE OpenSSL::SSL OpenSSL::Crypto ZLIB::ZLIB)
|
||||
# UPnP: opens the co-op port on the router (net_upnp.cpp).
|
||||
find_path(MINIUPNPC_INCLUDE miniupnpc.h PATH_SUFFIXES miniupnpc REQUIRED)
|
||||
find_library(MINIUPNPC_LIBRARY NAMES miniupnpc REQUIRED)
|
||||
target_include_directories(bbnet PRIVATE "${MINIUPNPC_INCLUDE}")
|
||||
target_link_libraries(bbnet PRIVATE "${MINIUPNPC_LIBRARY}")
|
||||
target_compile_definitions(bbnet PRIVATE BOOST_ASIO_STANDALONE NDEBUG)
|
||||
target_compile_options(bbnet PRIVATE -Wno-deprecated-declarations -Wno-missing-field-initializers)
|
||||
target_link_libraries(bbnet PUBLIC Vulkan::Headers fmt::fmt Boost::headers magic_enum::magic_enum
|
||||
protobuf::libprotobuf)
|
||||
target_link_libraries(bbgpu PUBLIC bbnet)
|
||||
# In-game settings menu: Dear ImGui (third_party/imgui, MIT) with its Vulkan backend, and an
|
||||
# embedded Cyrillic font (third_party/fonts).
|
||||
target_sources(bbgpu PRIVATE third_party/imgui/imgui.cpp third_party/imgui/imgui_draw.cpp
|
||||
third_party/imgui/imgui_tables.cpp third_party/imgui/imgui_widgets.cpp
|
||||
third_party/imgui/backends/imgui_impl_vulkan.cpp)
|
||||
target_include_directories(bbgpu PRIVATE third_party/imgui third_party/imgui/backends)
|
||||
# Dear ImGui stays private to libbbgpu.so. The library is linked into bb-probe, so its exports are
|
||||
# in the global symbol scope; a Vulkan layer carrying its own Dear ImGui without -Bsymbolic
|
||||
# (vkShade 0.1) had its ImGui_ImplVulkan_Init bound to this copy, which called the Vulkan loader
|
||||
# with the layer's down-chain physical device handle ("Invalid physicalDevice", abort).
|
||||
set_source_files_properties(third_party/imgui/imgui.cpp third_party/imgui/imgui_draw.cpp
|
||||
third_party/imgui/imgui_tables.cpp third_party/imgui/imgui_widgets.cpp
|
||||
third_party/imgui/backends/imgui_impl_vulkan.cpp PROPERTIES
|
||||
COMPILE_OPTIONS "-fvisibility=hidden;-fvisibility-inlines-hidden")
|
||||
target_compile_definitions(bbgpu PRIVATE IMGUI_IMPL_VULKAN_NO_PROTOTYPES
|
||||
BB_FONT_PATH="${CMAKE_CURRENT_SOURCE_DIR}/third_party/fonts/DejaVuSans.ttf")
|
||||
set_source_files_properties(shim/bbport_overlay.cpp PROPERTIES
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/fonts/DejaVuSans.ttf)
|
||||
target_include_directories(bbgpu PRIVATE shim shadps4 ${SHADER_INCLUDE} third_party/gcn/include third_party/half/include)
|
||||
OBJECT_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/fonts/DejaVuSans.ttf")
|
||||
target_include_directories(bbgpu PRIVATE shim layer games cp shadps4 ${SHADER_INCLUDE} third_party/gcn/include third_party/half/include)
|
||||
target_compile_definitions(bbgpu PRIVATE BOOST_ASIO_STANDALONE NDEBUG)
|
||||
target_compile_options(bbgpu PRIVATE -Wno-deprecated-declarations -Wno-missing-field-initializers)
|
||||
# Loaded with bb-probe at startup (DT_NEEDED, never dlopen): thread_local access without a
|
||||
@@ -193,6 +174,9 @@ target_link_libraries(motion-shader-test PRIVATE bbgpu)
|
||||
add_executable(ui-composition-test EXCLUDE_FROM_ALL ../tests/test_ui_composition.cpp)
|
||||
target_compile_options(ui-composition-test PRIVATE -UNDEBUG -Wall -Wextra -Werror)
|
||||
target_include_directories(ui-composition-test PRIVATE ..)
|
||||
add_executable(cp-decoder-test EXCLUDE_FROM_ALL ../tests/test_cp_decoder.cpp cp/cp_decoder.cpp)
|
||||
target_compile_options(cp-decoder-test PRIVATE -UNDEBUG -Wall -Wextra -Werror)
|
||||
target_include_directories(cp-decoder-test PRIVATE cp)
|
||||
add_executable(settings-test EXCLUDE_FROM_ALL ../tests/test_settings.cpp shim/bbport_settings.cpp)
|
||||
target_compile_options(settings-test PRIVATE -UNDEBUG -Wall -Wextra -Werror)
|
||||
target_include_directories(settings-test PRIVATE .. shim)
|
||||
@@ -219,6 +203,14 @@ target_compile_options(camera-motion-test PRIVATE -UNDEBUG -fPIC)
|
||||
target_link_libraries(camera-motion-test PRIVATE bbgpu)
|
||||
add_dependencies(camera-motion-test host_shaders)
|
||||
|
||||
add_executable(translation-memory-test EXCLUDE_FROM_ALL ../tests/test_translation_memory.cpp
|
||||
../tests/test_gpu_runtime_stubs.cpp)
|
||||
target_include_directories(translation-memory-test PRIVATE shim shadps4 third_party/gcn/include)
|
||||
target_compile_options(translation-memory-test PRIVATE -UNDEBUG -fPIC)
|
||||
set_source_files_properties(../tests/test_translation_memory.cpp PROPERTIES
|
||||
COMPILE_OPTIONS "-fvisibility=hidden;-fvisibility-inlines-hidden")
|
||||
target_link_libraries(translation-memory-test PRIVATE bbgpu)
|
||||
|
||||
# bbport: FSR 4 benchmark outside the game (tools/fsr4_bench.cpp): ninja -C out/gpu fsr4-bench.
|
||||
add_executable(upscaler-support-test EXCLUDE_FROM_ALL ../tests/test_upscaler_support.cpp
|
||||
shim/bbport_settings.cpp)
|
||||
@@ -229,3 +221,22 @@ add_executable(fsr4-bench EXCLUDE_FROM_ALL tools/fsr4_bench.cpp
|
||||
shadps4/video_core/renderer_vulkan/fsr411/fsr411.cpp)
|
||||
target_include_directories(fsr4-bench PRIVATE shadps4/video_core/renderer_vulkan/fsr411)
|
||||
target_link_libraries(fsr4-bench PRIVATE ffx-vulkan::fsr4-v07-vulkan ffx-vulkan::fsr4-v07-assets Vulkan::Vulkan)
|
||||
|
||||
# bbport online module (gpu/bbnet, libbbnet.so): built when its libraries are there (shell.nix);
|
||||
# BB_NET=OFF leaves it out. Without it the port plays offline.
|
||||
option(BB_NET "Build the online module (shadNet)" ON)
|
||||
if (BB_NET)
|
||||
find_package(Protobuf CONFIG QUIET)
|
||||
find_package(nlohmann_json CONFIG QUIET)
|
||||
find_package(OpenSSL QUIET)
|
||||
find_package(ZLIB QUIET)
|
||||
find_path(MINIUPNPC_INCLUDE miniupnpc.h PATH_SUFFIXES miniupnpc)
|
||||
find_library(MINIUPNPC_LIBRARY NAMES miniupnpc)
|
||||
if (Protobuf_FOUND AND nlohmann_json_FOUND AND OpenSSL_FOUND AND ZLIB_FOUND AND
|
||||
MINIUPNPC_INCLUDE AND MINIUPNPC_LIBRARY)
|
||||
add_subdirectory(bbnet)
|
||||
message(STATUS "Online module: on (libbbnet.so)")
|
||||
else()
|
||||
message(STATUS "Online module: off (protobuf, nlohmann_json, OpenSSL, zlib or miniupnpc missing)")
|
||||
endif()
|
||||
endif()
|
||||
+10
-2
@@ -16,8 +16,6 @@ typedef struct {
|
||||
} BbGpuConfig;
|
||||
/* Registers kernel event queues (needed with or without graphics). */
|
||||
void bbgpu_register_kernel(void);
|
||||
/* Co-op: the game folder and param.sfo identity for the network and PSN libraries. */
|
||||
void bbnet_configure(const char *app0, const char *serial, const char *title, const char *app_ver);
|
||||
/* Creates window, Vulkan device, presenter and GPU command processor. */
|
||||
int bbgpu_init(const BbGpuConfig *config);
|
||||
/* Function for an imported NID ("NID#lib#mod"), or 0 when the GPU library does not provide it. */
|
||||
@@ -32,6 +30,16 @@ int bbgpu_text_input_begin(const char *initial_utf8, const char *prompt_utf8);
|
||||
int bbgpu_text_input_poll(char *out_utf8, uint64_t size);
|
||||
/* 1 while the in-game settings menu is open: the game's pad input is held neutral. */
|
||||
int bbgpu_overlay_captures_input(void);
|
||||
/* A trophy the game unlocked (runtime_services.c): the overlay's notice. grade: P, G, S, B or '-';
|
||||
* icon: a TROPxxx.rgba file of scripts/trophies.py (u32 width, u32 height, RGBA), or NULL. */
|
||||
void bbgpu_trophy_notice(int id, char grade, const char *name_utf8, const char *icon_path);
|
||||
/* Mouse look (runtime_pad.c): the window takes the mouse when it is clicked (relative mode) and
|
||||
* lets it go on F1, losing focus or the menu opening. take: motion (pixels) and wheel notches
|
||||
* since the last call, reset; captured: 1 while the window holds it; enable: mouse_look=0 in
|
||||
* bbport.ini keeps the window from taking it. */
|
||||
void bbgpu_mouse_take(double *dx, double *dy, int *wheel_up, int *wheel_down);
|
||||
int bbgpu_mouse_captured(void);
|
||||
void bbgpu_mouse_look_enable(int enabled);
|
||||
/* Patches the loaded image before the game runs (image still writable): libGnm entry hooks. */
|
||||
void bbgpu_patch_image(unsigned char *image, uint64_t size);
|
||||
/* Number of symbols registered by the vendored libraries (diagnostics). */
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# bbport online module: libbbnet.so, the PS4 network and PSN libraries with the shadNet client
|
||||
# (shadp2p, a shadPS4 fork, GPL-2.0), loaded by the runtime only for online play
|
||||
# (src/runtime_net.c). Its headers (include/) extend the port's shim for these libraries alone;
|
||||
# everything in it is hidden and bound to itself (-Bsymbolic) except bbnet.h's two calls, so its
|
||||
# copies of shadPS4's kernel shims and symbol table never meet libbbgpu's.
|
||||
# Needs protobuf, nlohmann_json, OpenSSL, zlib and miniupnpc (shell.nix); without them the port
|
||||
# builds without it and plays offline (gpu/CMakeLists.txt: BB_NET).
|
||||
|
||||
set(SHADNET_PROTO_OUT "${CMAKE_CURRENT_BINARY_DIR}/shadnet_proto_gen")
|
||||
file(MAKE_DIRECTORY "${SHADNET_PROTO_OUT}")
|
||||
add_custom_command(
|
||||
OUTPUT "${SHADNET_PROTO_OUT}/shadnet.pb.cc" "${SHADNET_PROTO_OUT}/shadnet.pb.h"
|
||||
COMMAND protobuf::protoc "--proto_path=${CMAKE_CURRENT_SOURCE_DIR}/shadps4/shadnet"
|
||||
"--cpp_out=${SHADNET_PROTO_OUT}" "${CMAKE_CURRENT_SOURCE_DIR}/shadps4/shadnet/shadnet.proto"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/shadps4/shadnet/shadnet.proto")
|
||||
file(GLOB_RECURSE BBNET_SOURCES CONFIGURE_DEPENDS shadps4/core/libraries/network/*.cpp
|
||||
shadps4/core/libraries/np/*.cpp shadps4/shadnet/*.cpp)
|
||||
# Trophies and the system dialogs stay in the C runtime; their shadPS4 versions need the
|
||||
# emulator's UI layers.
|
||||
list(FILTER BBNET_SOURCES EXCLUDE REGEX
|
||||
"np_trophy|trophy_ui|np_sns_facebook_dialog|np_profile_dialog/|np_commerce/")
|
||||
|
||||
add_library(bbnet SHARED ${BBNET_SOURCES} "${SHADNET_PROTO_OUT}/shadnet.pb.cc" bbnet_glue.cpp)
|
||||
# The module's own headers first, then the port's shim and shadPS4 (common/, logging).
|
||||
target_include_directories(bbnet PRIVATE include shadps4 shadps4/shadnet "${SHADNET_PROTO_OUT}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR} ../shim ../shadps4 ../third_party/imgui ../third_party/httplib)
|
||||
target_compile_definitions(bbnet PRIVATE BOOST_ASIO_STANDALONE NDEBUG
|
||||
CPPHTTPLIB_OPENSSL_SUPPORT CPPHTTPLIB_ZLIB_SUPPORT)
|
||||
target_compile_options(bbnet PRIVATE -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
-Wno-deprecated-declarations -Wno-missing-field-initializers)
|
||||
target_link_options(bbnet PRIVATE -Wl,-Bsymbolic -Wl,--exclude-libs,ALL)
|
||||
# libbbgpu (already in the process) provides shadPS4's common code: logging, threads' names.
|
||||
set_target_properties(bbnet PROPERTIES BUILD_RPATH "\$ORIGIN" INSTALL_RPATH "\$ORIGIN"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") # beside libbbgpu.so, where the runtime looks
|
||||
target_link_libraries(bbnet PRIVATE bbgpu nlohmann_json::nlohmann_json protobuf::libprotobuf
|
||||
OpenSSL::SSL OpenSSL::Crypto ZLIB::ZLIB "${MINIUPNPC_LIBRARY}" Vulkan::Headers fmt::fmt
|
||||
Boost::headers magic_enum::magic_enum)
|
||||
target_include_directories(bbnet PRIVATE "${MINIUPNPC_INCLUDE}")
|
||||
@@ -0,0 +1,40 @@
|
||||
/* bbport online module (libbbnet.so, gpu/bbnet): the PS4 network and PSN libraries with the
|
||||
* shadNet client. A separate library the runtime loads only for online play (BB_ONLINE=1,
|
||||
* src/runtime_net.c); offline the port never touches it, and a build without it runs offline.
|
||||
* Its C++ inside is private (hidden symbols, -Bsymbolic): these two calls are all it exports. */
|
||||
#ifndef BBNET_H
|
||||
#define BBNET_H
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BBNET_ABI_VERSION 1
|
||||
|
||||
/* What the runtime gives the module: the game's identity (param.sfo, its folder for
|
||||
* sce_sys/npbind.dat) and guest threads for the NP libraries' callbacks into the game. */
|
||||
typedef struct BbNetHost {
|
||||
uint32_t abi; /* BBNET_ABI_VERSION */
|
||||
const char *app0; /* the game's folder */
|
||||
const char *serial; /* TITLE_ID */
|
||||
const char *title; /* TITLE */
|
||||
const char *app_ver; /* APP_VER */
|
||||
/* 0 or a positive errno value; entry has the System V ABI (the game's code calls it). */
|
||||
int32_t (*thread_spawn)(void **thread, void *(__attribute__((sysv_abi)) *entry)(void *),
|
||||
void *argument, uint64_t stack_size, const char *name);
|
||||
int32_t (*thread_join)(void *thread, void **result);
|
||||
} BbNetHost;
|
||||
|
||||
/* Registers the libraries; 0 on success, else the module cannot run (the game stays offline). */
|
||||
typedef int (*BbNetInitFn)(const BbNetHost *host);
|
||||
int bbnet_init(const BbNetHost *host);
|
||||
|
||||
/* The module's function for an imported NID ("NID#lib#mod"), or 0. */
|
||||
typedef uintptr_t (*BbNetResolveFn)(const char *scoped_nid);
|
||||
uintptr_t bbnet_resolve(const char *scoped_nid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+52
-13
@@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// bbport co-op: what the network and NP libraries from shadp2p need from the rest of
|
||||
// shadPS4, implemented on top of the bbport runtime, and their registration.
|
||||
// bbport online module (libbbnet.so): what the network and NP libraries from shadp2p need
|
||||
// from the rest of shadPS4, on top of the bbport runtime (BbNetHost), their registration and the
|
||||
// module's C interface (bbnet.h). From the Linux co-op fork of bbport, which took it from the
|
||||
// Windows port; the libraries are shadp2p's (a shadPS4 fork, GPL-2.0).
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
@@ -59,11 +61,12 @@
|
||||
#include "core/libraries/np/np_web_api/np_web_api.h"
|
||||
#include "core/libraries/np/np_web_api2/np_web_api2.h"
|
||||
|
||||
extern "C" {
|
||||
int32_t runtime_thread_spawn(void** out, void* PS4_SYSV_ABI (*entry)(void*), void* argument,
|
||||
uint64_t stack, const char* name);
|
||||
int32_t runtime_thread_join_spawned(void* thread, void** result);
|
||||
}
|
||||
#include "bbnet.h"
|
||||
|
||||
namespace {
|
||||
/// The runtime's side (bbnet_init).
|
||||
BbNetHost g_host{};
|
||||
} // namespace
|
||||
|
||||
// ---- Kernel ---------------------------------------------------------------------------------
|
||||
|
||||
@@ -278,10 +281,10 @@ int posix_pthread_create_name_np(PthreadT* thread, const PthreadAttrT* attr,
|
||||
PthreadEntryFunc start, void* arg, const char* name) {
|
||||
if (!thread || !start) return 22;
|
||||
const u64 stack = attr && *attr ? (*attr)->stack : 0;
|
||||
return runtime_thread_spawn(thread, start, arg, stack, name ? name : "np");
|
||||
return g_host.thread_spawn(thread, start, arg, stack, name ? name : "np");
|
||||
}
|
||||
int posix_pthread_join(PthreadT thread, void** ret) {
|
||||
return runtime_thread_join_spawned(thread, ret);
|
||||
return g_host.thread_join(thread, ret);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
@@ -442,18 +445,52 @@ private:
|
||||
};
|
||||
} // namespace Core
|
||||
|
||||
extern "C" void bbnet_configure(const char* app0, const char* serial, const char* title,
|
||||
const char* app_ver) {
|
||||
namespace {
|
||||
void Configure(const char* app0, const char* serial, const char* title, const char* app_ver) {
|
||||
Core::Emulator::SetGame(app0, serial, title, app_ver);
|
||||
const auto& ids = Common::ElfInfo::Instance().GetNpCommIds();
|
||||
std::printf("Co-op: %s, NP communication id %s%s\n", serial ? serial : "?",
|
||||
ids.empty() ? "missing" : ids.front().c_str(),
|
||||
EmulatorSettings.IsShadNetEnabled() ? "; online play on" : "");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// ---- Registration ------------------------------------------------------------------------------
|
||||
// ---- Registration and the C interface ------------------------------------------------------------
|
||||
|
||||
extern "C" void bbnet_register(void) {
|
||||
// The module's own table (the port's libbbgpu keeps another one: this library's symbols are its
|
||||
// own, -Bsymbolic).
|
||||
namespace {
|
||||
struct Symbol {
|
||||
std::string nid;
|
||||
u64 address;
|
||||
};
|
||||
std::vector<Symbol> g_symbols;
|
||||
} // namespace
|
||||
|
||||
namespace Core::Loader {
|
||||
void SymbolsResolver::AddSymbol(const char* nid, const char*, const char*, SymbolType, u64 address) {
|
||||
g_symbols.push_back({nid, address});
|
||||
}
|
||||
} // namespace Core::Loader
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) uintptr_t bbnet_resolve(const char* scoped_nid) {
|
||||
const char* hash = std::strchr(scoped_nid, '#');
|
||||
const size_t length = hash ? size_t(hash - scoped_nid) : std::strlen(scoped_nid);
|
||||
for (const auto& symbol : g_symbols) {
|
||||
if (symbol.nid.size() == length && !std::memcmp(symbol.nid.data(), scoped_nid, length)) {
|
||||
return uintptr_t(symbol.address);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) int bbnet_init(const BbNetHost* host) {
|
||||
if (!host || host->abi != BBNET_ABI_VERSION || !host->thread_spawn || !host->thread_join) {
|
||||
std::printf("Online: the runtime and the online module are from different versions\n");
|
||||
return -1;
|
||||
}
|
||||
g_host = *host;
|
||||
Configure(host->app0, host->serial, host->title, host->app_ver);
|
||||
Core::Loader::SymbolsResolver resolver;
|
||||
Core::Loader::SymbolsResolver* sym = &resolver;
|
||||
Libraries::Net::RegisterLib(sym);
|
||||
@@ -473,4 +510,6 @@ extern "C" void bbnet_register(void) {
|
||||
Libraries::Np::NpTus::RegisterLib(sym);
|
||||
Libraries::Np::NpWebApi::RegisterLib(sym);
|
||||
Libraries::Np::NpWebApi2::RegisterLib(sym);
|
||||
std::printf("Online: %zu network and PSN functions\n", g_symbols.size());
|
||||
return 0;
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,93 @@
|
||||
// bbport: shadPS4 settings used by the video core, read once from BB_* environment
|
||||
// variables (defaults match shadPS4 except the pipeline cache, which is on).
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include "common/types.h"
|
||||
|
||||
enum GpuReadbacksMode : int { Disabled, Relaxed, Precise };
|
||||
|
||||
class EmulatorSettingsImpl {
|
||||
public:
|
||||
static EmulatorSettingsImpl* GetInstance() { static EmulatorSettingsImpl s; return &s; }
|
||||
static bool Flag(const char* name, bool fallback) {
|
||||
const char* v = std::getenv(name);
|
||||
return v ? (v[0] == '1' || v[0] == 'y' || v[0] == 't') : fallback;
|
||||
}
|
||||
static long Number(const char* name, long fallback) {
|
||||
const char* v = std::getenv(name);
|
||||
return v ? std::strtol(v, nullptr, 10) : fallback;
|
||||
}
|
||||
s32 GetGpuId() { static const auto value = s32(Number("BB_GPU_ID", -1)); return value; }
|
||||
u32 GetInternalScreenWidth() { static const auto value = u32(Number("BB_INTERNAL_WIDTH", 1920)); return value; }
|
||||
u32 GetInternalScreenHeight() { static const auto value = u32(Number("BB_INTERNAL_HEIGHT", 1080)); return value; }
|
||||
std::string GetPresentMode() { const char* v = std::getenv("BB_PRESENT_MODE"); return v ? v : "Mailbox"; }
|
||||
int GetRcasAttenuation() { static const auto value = int(Number("BB_RCAS_ATTENUATION", 250)); return value; }
|
||||
// bbport: Relaxed by default: without readbacks FaceGen reads stale GPU-written vertices
|
||||
// (vertex explosions); in Hunter's Nightmare it costs no measurable frame rate.
|
||||
u32 GetReadbacksMode() { static const auto value = u32(Number("BB_READBACKS", GpuReadbacksMode::Relaxed)); return value; }
|
||||
// bbport: uncapped presets (run.sh: BB_VBLANK_HZ=480; 0 means the same): vblank runs at
|
||||
// 480 Hz, and a finished frame is presented as soon as it arrives (IsUncappedVblank), not on
|
||||
// the next vblank tick (at the display rate frames alternated 10/20 ms at 100 Hz: judder; at
|
||||
// 480 Hz they snap to ~2.1 ms steps). The frame rate is not limited unless BB_FPS_LIMIT
|
||||
// (launcher: "FPS limit") asks for it. Other values are used as given (60/90: the
|
||||
// fixed-timestep presets, flips on vblank ticks).
|
||||
u32 GetVblankFrequency() {
|
||||
static const u32 value = [] {
|
||||
const long hz = Number("BB_VBLANK_HZ", 60);
|
||||
return hz > 0 ? u32(hz) : 480u;
|
||||
}();
|
||||
return value;
|
||||
}
|
||||
/// Vblank faster than any fixed-timestep preset (above 120 Hz, or 0): flips at once.
|
||||
bool IsUncappedVblank() {
|
||||
static const bool value = [] {
|
||||
const long hz = Number("BB_VBLANK_HZ", 60);
|
||||
return hz <= 0 || hz > 120;
|
||||
}();
|
||||
return value;
|
||||
}
|
||||
/// Frames per second the present thread lets through; 0 = no limit (BB_FPS_LIMIT).
|
||||
u32 GetFrameLimit() {
|
||||
static const u32 value = u32(std::max(0L, Number("BB_FPS_LIMIT", 0)));
|
||||
return value;
|
||||
}
|
||||
bool IsCopyGpuBuffers() { static const auto value = Flag("BB_COPY_GPU_BUFFERS", false); return value; }
|
||||
bool IsDirectMemoryAccessEnabled() { static const auto value = Flag("BB_DIRECT_MEMORY_ACCESS", false); return value; }
|
||||
bool IsDumpShaders() { static const auto value = Flag("BB_DUMP_SHADERS", false); return value; }
|
||||
bool IsFsrEnabled() { static const auto value = Flag("BB_FSR1", false); return value; }
|
||||
bool IsHdrAllowed() { static const auto value = Flag("BB_HDR", false); return value; }
|
||||
bool IsNullGPU() { static const auto value = Flag("BB_NULL_GPU", false); return value; }
|
||||
bool IsPatchShaders() { return false; }
|
||||
bool IsPipelineCacheArchived() { return false; }
|
||||
bool IsPipelineCacheEnabled() { static const auto value = Flag("BB_PIPELINE_CACHE", true); return value; }
|
||||
bool IsRcasEnabled() { static const auto value = Flag("BB_RCAS", true); return value; }
|
||||
bool IsReadbackLinearImagesEnabled() { static const auto value = Flag("BB_READBACK_LINEAR", false); return value; }
|
||||
bool IsRenderdocEnabled() { return false; }
|
||||
bool IsShaderCollect() { return false; }
|
||||
bool IsUserfaultfdTracking() { return false; }
|
||||
bool IsVkCrashDiagnosticEnabled() { return false; }
|
||||
bool IsVkGuestMarkersEnabled() { static const auto value = Flag("BB_VK_MARKERS", false); return value; }
|
||||
bool IsVkHostMarkersEnabled() { static const auto value = Flag("BB_VK_MARKERS", false); return value; }
|
||||
bool IsVkValidationCoreEnabled() { return true; }
|
||||
bool IsVkValidationEnabled() { static const auto value = Flag("BB_VK_VALIDATION", false); return value; }
|
||||
bool IsVkValidationGpuEnabled() { return false; }
|
||||
bool IsVkValidationSyncEnabled() { static const auto value = Flag("BB_VK_VALIDATION_SYNC", false); return value; }
|
||||
// bbport co-op: online play through a shadNet server (BB_ONLINE=1, set by the launcher).
|
||||
static std::string Text(const char* name, const char* fallback) {
|
||||
const char* v = std::getenv(name);
|
||||
return v && v[0] ? v : fallback;
|
||||
}
|
||||
bool IsConnectedToNetwork() { static const auto value = Flag("BB_ONLINE", false); return value; }
|
||||
bool IsShadNetEnabled() { return IsConnectedToNetwork() && !shadnet_session_disabled.load(); }
|
||||
void SetShadNetSessionDisabled(bool v) { shadnet_session_disabled.store(v); }
|
||||
std::string GetShadNetServer() { return Text("BB_SHADNET_SERVER", "127.0.0.1:31313"); }
|
||||
std::string GetShadNetWebApiServer() { return Text("BB_SHADNET_WEBAPI", "http://127.0.0.1:31315"); }
|
||||
bool IsUPnPEnabled() { static const auto value = Flag("BB_UPNP", true); return value; }
|
||||
|
||||
private:
|
||||
std::atomic<bool> shadnet_session_disabled{false};
|
||||
};
|
||||
#define EmulatorSettings (*EmulatorSettingsImpl::GetInstance())
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,15 @@
|
||||
// bbport: the parts of shadPS4's kernel.h used by vendored libraries.
|
||||
#pragma once
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
namespace Libraries::Kernel {
|
||||
int* PS4_SYSV_ABI __Error();
|
||||
s32 ErrnoToSceKernelError(s32 e);
|
||||
|
||||
struct SwVersionStruct {
|
||||
u64 struct_size;
|
||||
char text_representation[0x1c];
|
||||
u32 hex_representation;
|
||||
};
|
||||
s32 PS4_SYSV_ABI sceKernelGetSystemSwVersion(SwVersionStruct* ret);
|
||||
} // namespace Libraries::Kernel
|
||||
File renamed without changes.
@@ -0,0 +1,40 @@
|
||||
// bbport: host threads that may call guest code (AvPlayer allocator callbacks).
|
||||
// Each thread gets a guest TCB (GS base, TLS) from the C runtime before running.
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <stop_token>
|
||||
#include <thread>
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/threads/pthread.h"
|
||||
|
||||
extern "C" void runtime_thread_attach_host(const char* name);
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
class Thread {
|
||||
public:
|
||||
Thread() = default;
|
||||
~Thread() { Stop(); }
|
||||
void Run(std::function<void(std::stop_token)>&& func) {
|
||||
thread = std::jthread([func = std::move(func)](std::stop_token stop) {
|
||||
runtime_thread_attach_host("bb:hle");
|
||||
func(stop);
|
||||
});
|
||||
}
|
||||
// A thread may stop its own Thread object (AvPlayer does); it detaches instead of joining.
|
||||
void Join() {
|
||||
if (!thread.joinable()) return;
|
||||
if (thread.get_id() == std::this_thread::get_id()) thread.detach();
|
||||
else thread.join();
|
||||
}
|
||||
bool Joinable() const { return thread.joinable(); }
|
||||
void Stop() {
|
||||
if (thread.joinable()) {
|
||||
thread.request_stop();
|
||||
Join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::jthread thread;
|
||||
};
|
||||
} // namespace Libraries::Kernel
|
||||
File renamed without changes.
@@ -0,0 +1,22 @@
|
||||
// bbport: shadPS4 registers HLE functions with LIB_FUNCTION(nid, library,
|
||||
// version, module, fn). Here the registrations fill a table that the C
|
||||
// loader queries by NID (see bbgpu.cpp: bbgpu_resolve).
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
#include "core/emulator_settings.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
enum class SymbolType { Function, Object };
|
||||
class SymbolsResolver {
|
||||
public:
|
||||
void AddSymbol(const char* nid, const char* library, const char* module, SymbolType type, u64 address);
|
||||
};
|
||||
} // namespace Core::Loader
|
||||
|
||||
#define LIB_FUNCTION(nid, lib, libversion, mod, function) \
|
||||
sym->AddSymbol(nid, lib, mod, Core::Loader::SymbolType::Function, \
|
||||
reinterpret_cast<u64>(function))
|
||||
#define LIB_OBJ(nid, lib, libversion, mod, obj) \
|
||||
sym->AddSymbol(nid, lib, mod, Core::Loader::SymbolType::Object, reinterpret_cast<u64>(obj))
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+18
@@ -23,6 +23,8 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/network/net_upnp.h"
|
||||
#include "core/emulator_settings.h"
|
||||
#include "core/libraries/network/net_util.h"
|
||||
#include "net.h"
|
||||
#include "net_error.h"
|
||||
@@ -217,6 +219,19 @@ public:
|
||||
LOG_INFO(Lib_Net,
|
||||
"P2P transport ready: UDP physical_port={} (set SHADPS4_P2P_PORT to pin it)",
|
||||
physical_port);
|
||||
// bbport: open the port on the router (UPnP, BB_UPNP). Discovery runs in the background,
|
||||
// so the mapping waits for it (issue #121: the port was never mapped, and summons from
|
||||
// behind a NAT without a manual forward could not reach this player).
|
||||
if (EmulatorSettings.IsUPnPEnabled()) {
|
||||
const u16 port = physical_port;
|
||||
std::thread([port] {
|
||||
auto& upnp = UPnPClient::Instance();
|
||||
upnp.Start();
|
||||
if (upnp.WaitReady(10000)) {
|
||||
upnp.AddMapping(port);
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
@@ -233,6 +248,9 @@ public:
|
||||
}
|
||||
|
||||
CloseSocket(host_socket);
|
||||
if (EmulatorSettings.IsUPnPEnabled() && physical_port != 0) {
|
||||
UPnPClient::Instance().RemoveMapping(physical_port);
|
||||
}
|
||||
physical_port = 0;
|
||||
#endif
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 319 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user