Compare commits

...
Author SHA1 Message Date
ayozetr 97a60dd497 0.51-linux.2, and co-op on your own server tested with two players
The launcher's version for the About page's updates. docs/SERVER.md and the README say that a
private server has been tested with a Linux and a Windows player: summons, a boss fight together
and summoning again after the helper died.
2026-10-11 16:51:45 +01:00
0xCydral a3a8a3af6e fix(vulkan): include vulkan.hpp with NDEBUG so the dispatcher layout matches
vulkan.hpp adds two fields to DispatchLoaderBase when NDEBUG is undefined, which moves every
function pointer in vk::detail::DispatchLoaderDynamic by 16 bytes. libbbgpu is built with NDEBUG
while the renderer tests build with -UNDEBUG so their asserts run, so the two sides disagreed on
the layout. The linker keeps one inline copy of DispatchLoaderDynamic::init(Instance): the test
translation unit's copy read vkGetInstanceProcAddr at offset 88 while CreateInstance had stored it
at offset 72, and Instance construction called a null pointer (exit 139 on Windows).

vk_common.h now defines NDEBUG around the vulkan.hpp include and restores assert() afterwards,
so every translation unit sees the same layout while test asserts stay active.

(cherry picked from commit 03b383b34ccb74085d74baa1e3b87ca0b50013aa)
2026-10-11 16:50:59 +01:00
0xCydral f1091cc0b1 fix(gpu): keep the camera vector where an object vector strays far from it
Object motion history that was not the object's gave still geometry huge
vectors. At one moment of the Hunter's Dream test route, bushes behind the
workshop moved 100-650 px a frame while the camera vectors around them were
right, and FSR and frame generation smeared them. The motion merge now keeps
the camera vector when the object vector differs from it by more than 5% of
the render width (at least 32 px; 85 px at 1706x960).

Measured on 24 frames at the same moment: object vectors over 100 px went
from 2.8% of the picture on the worst frames of two runs to none. The camera
motion test gains two cases, a far object vector that is rejected and a 30 px
one that is kept; that test does not run on Windows yet.

(cherry picked from commit a12911460872b37aba2bff4895903ad20aabf1e2)
2026-10-11 16:50:59 +01:00
0xCydral c496667284 feat(log): a performance line every 30 seconds in normal play
Players' last_run.log carried no frame rate, so a report of low FPS or stutter came with nothing
to measure. Without BB_FRAME_STATS the game now prints one line per 30 seconds: game frames per
second, the 1% low, the worst frame and the shader/pipeline compiles of the window, for example
"Perf: 68.0 FPS over 30 s, 1% low 62.8 FPS, worst frame 22.1 ms, 0 shader/pipeline compiles".

(cherry picked from commit 6c73bf375ea55972fd19bb5dcc254a92ab57ee54)
2026-10-11 16:50:59 +01:00
0xCydral a8b7a8eaa1 fix(gpu): keep the default indirect guard limit when BB_INDIRECT_GUARD_MAX is not a positive number
An unparsable value gave strtoul 0, so the shader skipped every indirect dispatch without a word. A value that is not a number from 1 to 4294967295 now keeps the default and prints one warning line.

(cherry picked from commit 62177377cf6c4a390d95d61b804505b077e7648c)
2026-10-11 16:50:59 +01:00
0xCydral 4d934b7529 fix(run.sh): give an explicit render size above 1080p the larger direct memory
run.sh raised BB_DMEM_MB to 9152 MiB only on the scaled path. An explicit BB_RENDER_RES skips that path, but patches.py still grows the graphics heap above 1080p, so the game asked for more memory than it had and stopped at start (exit 139). run.sh now does what run.py does since e5276cf: a WxH size above 1920x1080 by pixel count gets 9152 MiB unless BB_DMEM_MB is already set.

(cherry picked from commit 674b72e650f990dce906bc43446d024ab7109520)
2026-10-11 16:50:59 +01:00
0xCydral 442c2b66bd fix(gpu): resync the graphics command decoder at an invalid PM4 header
A cut-short SET_SH_REG leaves the next packets inside its body, and the
decoder then hit UNREACHABLE (Unimplemented PM4 type 0) at area loads. On
that path only, decoding now resumes at the next dword that can start a
type 3 packet, so the rest of the buffer and its fences still run. Each
resync logs the header dword and its offset; the buffer report stays
limited to the first 8.

From GoncaloLobo0/bloodborne_pc_win a334d26 and 9dc909d (adapted: crash path
only, no look-ahead on valid register packets)

(cherry picked from commit e0b464db61362d5c8b966ec645c592cf0a680667)
2026-10-11 16:50:59 +01:00
0xCydral d7a42fde94 fix(motion): object vectors for 16-64 KiB bone palettes; unknown SnormNz format is not fatal
Palettes of whole bones between 16 and 64 KiB (24576, 49152 bytes: the
large beasts in Central Yharnam) are now LargeSkeleton: gated like small
skeletons (history only while the palette changes). BB_MOTION_LARGE=0
restores the old rule (camera vectors only).

MapNumberConversion returns NumberConversion::None for a data format with
no SnormNz mapping instead of hitting UNREACHABLE (seen with data format 45,
a stale or unused descriptor).

From bmy/bbport-mac 80898cf and 5cf5684 (gpu part only)

(cherry picked from commit 4ff6b6292df844129332d75c6a1eb56eda14232b)
2026-10-11 16:50:59 +01:00
0xCydral d0318b1ab5 fix(upscaler): UI mask draws write the UI's output-size stencil
Scaleform masks are drawn with color writes off, so they reached the UI
composition without a color target and stayed in the game-size depth. The
next UI draw switched to the output-size UI depth, whose stencil
PrepareUiDepth clears, and the mask was gone: images cut out through a mask
(the loading screen's item picture) vanished at output sizes other than
1080p.

The frame generation HUD-less capture is unaffected: it runs in the
!Scaled() path before ui_phase, and the new branch only applies in ui_phase.

From bmy/bbport-mac e4f7d33

(cherry picked from commit 55b4a0d7247ec05dafc0d40643a2a146869c9531)
2026-10-11 16:50:59 +01:00
0xCydral 1bc4f37504 fix(texture-cache): hash the same guest range at marking and refresh
MarkAsMaybeDirty hashed the whole image but RefreshImage only its first 8x8
pixels, so the two never matched and stale guest memory replaced
GPU-written small images (black character preview, missing loading-screen
item picture). Both now use MaybeDirtyHash, and every upload records its
mip hash so an unchanged guest copy is not re-uploaded over GPU contents.

From yumlevi/bloodborne_pc 43fcf95

(cherry picked from commit 0d2dfd2f4ba3a13d5bee415769f5f0ff4f58fb2e)
2026-10-11 16:50:59 +01:00
0xCydral 44a6b7c3ce fix(shader): ReadUdReg on a null user-data table returns an empty sharp
An unbound descriptor table dereferenced a near-null pointer (access
violation at 0x8 on map load). Return a zeroed value so the existing
empty-sharp handling runs.

From Mrsuss60/bloodborne_pc_windows_port 8d8ac28 (info.h hunk only)

(cherry picked from commit 5e4513bad8b952bea95f6df76d94c97d5e827de8)
2026-10-11 16:50:59 +01:00
0xCydral efdf7b176e fix(runtime): split flexible mappings keep their own pool offset
split_at moved the offset only for direct memory, so the right piece of a
split flexible mapping kept the left piece's. Unmapping it then freed and
zeroed the left piece's pages (still mapped) and leaked its own; read/write
backing used the wrong pages too.

From bmy/bbport-mac 9ffc78d

(cherry picked from commit 389a1e5c3573460f73f96f255f5fbf7da43c981c)
2026-10-11 16:50:59 +01:00
ayozetr 4f7df3de5c Trophies: a notice in the game and a Trophies page
The game's trophies come from the player's own dump: scripts/trophies.py reads
sce_sys/trophy/trophy00.trp, keeps its icons, and decrypts the trophy lists with the PS4's
trophy key (shadPS4's TrophyKey, entered in the launcher), in the game's language. Without the
key, only the icons. AES is in Python, as the AppImage has no crypto package.

When the game unlocks a trophy, the runtime records it in earned.tsv, the first time only, and
the overlay shows a card in the top-left corner in the style of the PS4's: the trophy's icon,
"You have earned a trophy." and its name. The platinum follows once every other trophy is
earned. The launcher's Trophies page lists them all, earned first, with the date; hidden ones
stay hidden until earned. BB_TROPHY_PREVIEW=<id> shows a trophy's notice at the game's first
trophy call, to see how it looks.
2026-10-11 15:35:42 +01:00
ayozetr e3c51c48aa Discord Rich Presence: the area and the co-op partners
Discord shows the area the player is in, and under it "Co-op with <partners>", "Online" or
"Offline". The game writes both into BB_PRESENCE_DIR, which run.sh makes new for each start:

- The runtime takes the area from the MapStudio files the game opens, one per map it loads.
  The player's own map comes first, then the maps around it (Central Yharnam brings the
  Forbidden Woods), so a map opened 5 s or more after the previous one starts a new load and
  names the area. It changes at loading screens only.
- The online module writes the online IDs of the players it has an established connection
  with, when a connection is established or removed.

The area names are those of Smithbox's Bloodborne map aliases (MIT); the Chalice Dungeons are
one name.
2026-10-11 15:11:09 +01:00
ayozetr 33393185b9 Support on Ko-fi: the About page, the README and GitHub's Sponsor button
A "Support this project" row in the launcher's About page opens ko-fi.com/ayozetr, the
README has a Support section, and .github/FUNDING.yml shows the link in GitHub's Sponsor
button.
2026-10-11 14:51:58 +01:00
ayozetr c294942db4 Launcher: the game folder names the release that is in it
The row said "Game folder (CUSA03173)" and the check's tooltip "Bloodborne CUSA03173,
version 1.09" whatever the folder held, from when only the European Game of the Year edition
ran. Both now name the title ID in the folder's param.sfo (CUSA00900, ...), or none without a
game.
2026-10-11 14:33:28 +01:00
obrikash 6c6974a742 Fix Vulkan startup when optional DLSS device extensions fail 2026-10-11 13:34:39 +01:00
ayozetr 83246710d7 0.51-linux.1, and what each tool is for
The launcher's version for the About page's updates. tools/README.md tells the tools the port,
the launcher and the AppImage use from bbport's development tools, kept as they are so that
its updates merge cleanly.
2026-10-11 02:53:20 +01:00
ayozetr b71eb7cfee Online: your own co-op server
shadPS4's public server never answers on its UDP port, so summons through it cannot connect
(deadinside28/bloodborne_pc#121). The Online page now chooses between that server and your
own, a shadnet-p2p server for a group of friends: its address and WebAPI, and seamless co-op,
which the server has to have on as well. The co-op port is a setting of its own instead of
SHADPS4_P2P_PORT in the extra variables, and the firewall warning uses it and says that UPnP
opens the port on the router only.

Test the connection pings the shadNet server's UDP port the way the game does and shows the
public address the server sees, or that it does not answer. It uses a made-up online ID: the
server keeps one address per account, and the player's own would replace the address of a
game running at the same time.

tools/shadnet-server builds shadnet-p2p in Docker on Debian 13, for the Qt 6.8 it needs
(Ubuntu 24.04 has 6.4), and keeps the configuration and accounts in a volume. With the
server's Tailscale address, it waits for the address before starting: shadnet-p2p keeps
running without its listeners when the address is missing.

Checked against shadnet-p2p 5a849a1: login, the UDP ping, matchmaking and a summon sign
reaching its summon service. docs/SERVER.md is the guide; ONLINE.md and TROUBLESHOOTING.md
cover online play and the common problems.
2026-10-11 01:41:53 +01:00
ayozetr b6c25e1fb4 Merge upstream 0.51 (master)
The online module from upstream replaces this fork's copy: the same shadp2p libraries, now
in gpu/bbnet as libbbnet.so, loaded only for online play, and UPnP opens the co-op port on
the router. Kept from this fork: game region, firewall warning, About page and updates,
cheats, Discord, title-ID mod folders and the sharun AppImage, which now bundles
libbbnet.so (BB_NET_MODULE). DLSS: the launcher's choice of NVIDIA's library looks in
BB_DLSS_DIR, the AppImage's copy. The launcher's new texts are translated.
2026-10-11 00:28:06 +01:00
deadinsideandClaude Opus 5.5 3c57da4198 0.51: online play (shadNet module), mouse look, DLSS in the AppImage, fixes, 399 MB AppImage
- Online play through shadNet as a separate module (gpu/bbnet -> libbbnet.so), loaded by the
  runtime only with BB_ONLINE=1; launcher Online page; UPnP maps the P2P port (#121).
- Mouse look and mouse/wheel bindings (#51, #52); quit from the overlay (#74, #116).
- DLSS bridge and NVIDIA's runtime library in the package; a newer one chosen in the launcher.
- Every retail release with update 1.09 gets the game profile and passes the game check
  (#119, PR #117).
- New memory model: motion blur smear (#122); 4 GB VRAM out-of-memory stop; title menu
  flicker above 1080p.
- HTTPS certificates in the AppImage; NVIDIA Wayland swapchain (PR #93); git build after 0.4
  (#124); nix-shell launcher arguments (PR #120); FSR 4.1.1 recording on SteamOS (PR #89).
- AppImage 925 -> 399 MB: Vulkan-only Mesa (RADV without LLVM, ANV), stripped game binary,
  slimmer MangoHud, SDL3 and launcher GTK.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 01:57:36 +03:00
ayozetr 0e2b626358 Mods and patches: every retail release, and a guide in English
A mod wrapped in a title ID folder was found only as CUSA03173/dvdroot_ps4; one made with the
US release (CUSA00900/dvdroot_ps4) was not. Any title ID folder is accepted now. Third-party
patch files listed six of the nine retail releases: a file for the Japanese release or the US
and Japanese The Old Hunters editions was skipped. The list is now the game check's.

docs/MODS.en.md is the guide to mods and third-party patches in English, based on bbport's
docs/MODS.md and checked against the code; the README and docs/README.md link to it, and the
Russian original moves to the development notes.
2026-10-10 22:33:31 +01:00
ayozetr b060b9fa2b Document which game releases run, and which have been checked
docs/COMPATIBILITY.md lists the nine retail releases the launcher accepts, with their title and
content IDs (from deadinside28/bloodborne_pc#117), and which ones have had their 1.09
executable checked: the US release (CUSA00900) and the European Game of the Year edition
(CUSA03173). The others are accepted on the expectation that they share that executable, and
the image hash still decides. It also lists what was tested with this fork. The README's note
on game files links to it.

game_check.py said the Asian The Old Hunters Edition (CUSA03023) shares the executable; nobody
has checked it, so it now says what is known.

docs/README.md is an index of docs/: what is for players, what is this fork's, and bbport's
development notes by topic, which stay as they are so that upstream updates merge cleanly.
2026-10-10 22:26:45 +01:00
ayozetr 18a7dd7e39 AppImage: only what the port needs, and DLSS's files intact
quick-sharun's OpenGL and Vulkan deployment copies every libEGL*/libGLX* library and every ICD
manifest of the build host. Built on a PC with NVIDIA's driver, the AppImage carried that
driver's user-space libraries (one exact version, 615.71.09 in 0.4-linux.1) and manifests,
which load next to the player's own driver and cannot match another kernel module. They are
now removed before the AppImage is made; NVIDIA's driver always comes from the host, where
launcher/bbport_vulkan.py points Vulkan.

quick-sharun also strips and patches every library in the AppDir, DLSS's among them. NVIDIA's
DLSS library is signed: changed, NGX refused it (0xbad00012) and DLSS was unavailable in the
AppImage on an RTX 3060 that runs it from the repository. The DLSS files are now copied after
quick-sharun, as built.

DEPLOY_PYTHON copied the build host's whole site-packages (scipy, Qt bindings, matplotlib, ...:
431 MB). Only PyGObject, pycairo and Pillow stay, which is all the launcher imports. The
AppImage goes from 342 MB to 225 MB.
2026-10-10 21:38:02 +01:00
ayozetr 28a9233034 Launcher: About page, and updates from this fork's releases
A new About page shows the version and links this project, the original bbport by
deadinside28 and Supermedo's Windows port, and names the license (GNU GPL v2 or later, no
game files included).

It also checks GitHub for the latest release: at start, unless turned off, and with a Check
now button; a newer release at start is announced with a toast. From the AppImage, Update
downloads the release's AppImage next to the running one and renames it over it (a failed
download leaves the old one as it was); the running copy keeps its mount, and Restart starts
the new one once this launcher has exited (with the same application ID still held, the new
one would only raise the old window). From a git checkout, or an AppImage in a folder that is
not writable, the button opens the release page instead.

The version lives in launcher/bbport_update.py (0.5-linux.1); tags follow
<upstream version>-linux.<n>, and a release carries the AppImage as an asset.
2026-10-10 21:38:02 +01:00
ayozetr 9c056c437f Launcher: warn when a firewall blocks co-op
Co-op peers connect straight to each other over UDP, and UPnP's discovery replies come from the
router on random source ports. With ufw enabled or firewalld running, both are dropped, and
nothing in the launcher said why co-op could not connect.

The Online page now names the firewall and gives the commands: pin the P2P port with
SHADPS4_P2P_PORT=3658, open it, and with ufw let the router's answers in (the default gateway
read from /proc/net/route). Both are detected without root.
2026-10-10 21:38:02 +01:00
ayozetr 2683273a17 Launcher: game region
Bloodborne picks a language's regional text from USER_DEFINED_PARAM_1 in param.sfo: 13 Europe
(Spanish from Spain), 2 the Americas (Latin American Spanish). A US dump played in Spanish showed
the Latin American text, and the only way to change it was editing the dump's param.sfo.

The launcher's Game region (As in the game dump, Europe, the Americas) sets BB_REGION, and
content_profile.py writes the matching parameter for the launch; the dump stays as it is.
2026-10-10 21:38:02 +01:00
ayozetr 4d297b96bb Translate 0.5's new texts, and the game's System menu pages
The launcher's new texts (memory model, log export, monitors, the offline patch, damaged game
files) in Spanish, Italian, French, German and Brazilian Portuguese; Portuguese also gets the
52 texts it never had (controls, game check, frame limit, memory options, diagnostics).

The Display and Effects pages in the game's System menu were English or Russian only. They now
follow the game's language (BB_LANGUAGE, else the desktop's locale, as the runtime tells the
game), with the texts in bbport_menu_i18n.h. The README lists 0.5's new features.

tests/test_i18n.py now checks that every text the launcher translates exists in English,
Spanish, Italian, French, German and Portuguese, and that translations keep the placeholders:
the 18 texts 0.5 added had slipped through unnoticed.
2026-10-10 21:38:02 +01:00
ayozetr 917c4bdd20 Record large copy lists in slices
Loading an area on NVIDIA with 0.5, a download of the buffer cache carried 178563 buffer copies
(4.3 MB) into one deferred command. A command's data shares a 128 KiB recording chunk with it,
so ReserveRecordData's assertion stopped the game. Buffer copies, guest chunk copies and
buffer-to-image uploads are now recorded as one command per 64 KiB of regions.
2026-10-10 21:38:02 +01:00
ayozetr 8e24cfdcf5 Merge main: the region fix and every retail release
main corrected the regions (CUSA00900 is the US release, CUSA03173 the EU GOTY) and accepts
every retail release; the 0.5 merge still had upstream's older texts. Conflicts take main's
side; the Chinese launcher text of the old message is replaced by the new one.
2026-10-10 21:38:02 +01:00
ayozetr cfede387ed Merge upstream 0.5 (master)
0.5 on top of 0.5-pre4: the memory model chosen by GPU (the new one on AMD, the 0.3 one
elsewhere, or either by hand in the launcher), the command decoder, game profiles, GPU
timestamps, less VRAM churn, the finished Display and Effects pages of the game's System menu,
NVIDIA EGL discovery and RADV nohiz for older AMD GPUs.

Conflicts: README.md keeps this fork's own; tools/gpu_capabilities.c's header now lists both
the gamepad type (button prompts) and upstream's new --device.
2026-10-10 17:37:45 +01:00
ayozetr f44390da19 Game check: every retail release of Bloodborne
The list of content IDs posted by h0kd33 in deadinside28/bloodborne_pc
PR #117 covers every Bloodborne release: the US, EU, UK, Japanese and
Asian ones and the four editions with The Old Hunters. A base game of
any of them without the update is now asked for 1.09 instead of being
called another edition; whether the executable runs is still decided by
its image hash. The message is reworded in every launcher language.
2026-10-10 16:02:32 +01:00
ayozetr c89f4d432c Fix the regions: CUSA00900 is the US release, CUSA03173 the EU GOTY
CUSA00900 was called the EU release and CUSA03173 the US one, the other
way round: their content IDs are UP9000-CUSA00900 (America) and
EP9000-CUSA03173_00-BLOODBORNE0000EU (Europe, Game of the Year edition).
Only names change: the README, BBPORT.md, the release template, the
game check's texts and the launcher's message in every language.
2026-10-10 15:21:24 +01:00
ayozetr 4fd1cd6ee6 Restore what the 0.5 merge dropped: menu languages, cheats, co-op setup
Resolving the merge, three files of the in-game menu were taken whole
from upstream to settle conflicts that were only about DLSS, and
probe.c to drop the old add-on profile. That also dropped this fork's
own changes in them: the menu's Language selector and its Spanish,
Italian, French, German and Portuguese texts, the cheats and gameplay
tweaks, and the bbnet_configure call that gives the co-op code the
game's identity. With online play on, the game stopped at start
(ElfInfo GameSerial assertion). Now merged line by line, with upstream's
version only in the DLSS hunks.
2026-10-10 15:12:23 +01:00
deadinside c7e3e55eff 0.5: native game settings, AMD memory model by default, GPU translation and driver fixes
Default to the new memory and translation model on AMD using its sparse arena,
and retain the 0.3 memory model on other GPUs unless selected manually.
Add the command decoder, game profiles, shared memory traps and GPU timestamps;
reduce VRAM churn and background pipeline compilation artifacts.

Finish the game's Display and Effects settings pages, add the launcher's memory
model selector, host NVIDIA EGL discovery and RADV nohiz for affected older AMD
GPUs. Include the Proton and ImGui integration fixes and updated release notes.
Keep MangoHud startup behavior exactly as in 0.4.

Validation: 108 Python tests, runtime tests and command decoder tests passed.
The rebuilt public AppImage's MangoHud startup block matches 0.4 byte for byte.
2026-10-10 16:22:21 +03:00
ayozetr cfe7af67a5 Add to Steam: Flatpak Steam
Flathub's Steam keeps its data in ~/.var/app/com.valvesoftware.Steam
and starts non-Steam games inside its sandbox, which has neither the
game folder nor the host's drivers and cannot mount an AppImage. The
launcher now finds it, closes and starts it through flatpak run, and
writes a shortcut that runs the game on the host with
flatpak-spawn --host. That needs Steam to talk to org.freedesktop.Flatpak:
the launcher explains what the permission allows and grants it
(flatpak override --user) only when the player agrees.

A flatpak-spawn shortcut is only replaced when it is this port's (same
name, runs --play), so other launchers' games in Steam are left alone.
2026-10-10 14:10:32 +01:00
ayozetr 124384eac1 Merge upstream 0.5-pre4 (testing)
bbport 0.5-pre1 to pre4: the memory module (now on NVIDIA too), native
GPU copies, background pipelines, settings in the game's System menu,
DLSS, DLC folders and the damaged-extraction check.

Where both sides did the same thing, upstream's version is kept:
- DLSS: upstream's bridge and loader (libraries next to bb-probe, built
  by build.sh with DLSS_SDK_ROOT). BB_DLSS_DIR still overrides the
  folder, for the AppImage; tools/build_dlss.sh now installs into out/.
- DLC: upstream's <user>/addcont/<title>/<label> reporting. The
  launcher's DLC folder (BB_DLC_DIR) is linked there by run.sh, a real
  folder in its place left alone; our content.bin add-on list is gone.
- The memory-model switch is no longer AMD-only, as upstream has it.

Kept from this fork: launcher and in-game menu languages (Simplified
Chinese joins them), the game check for the EU and Asian releases and
the 60 fps-patched eboot (as sent upstream in PR #117), button prompts
and the controller type in bb-gpu-capabilities --gamepads, which also
lists displays now. Upstream's README changes went into BBPORT.md.
2026-10-10 14:07:39 +01:00
deadinsideandClaude Opus 5.5 10baf9df25 0.5-pre4: memory module without stutter, background pipelines, damaged-extraction check
Rewrite only the page table entries that changed after a promotion, with one runtime lookup per mapping instead of one per block (whole-mirror rewrites under the runtime's memory lock stalled the GPU thread 30-70 ms while areas streamed in). Keep ranges in place after a second write bounce, set write traps per run of blocks, give VRAM copies a floor of the budget on 4 GB cards, let stale copies yield and compact mirrors after travelling. Compile new pipelines of per-frame passes on worker threads. Report damaged game extractions (#81), add NVIDIA driver diagnostics to --vulkan-info (#107), never leave the current command chunk null (#100), restore the 0.4 settings menu look, and add layer timing to stall diagnostics. Bilingual release notes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 22:22:43 +03:00
deadinsideandClaude Opus 5.5 f2cd4ca0c4 0.5-pre3: memory module on NVIDIA: VRAM copies, one VRAM budget, watched blocks
Re-enable VRAM copies for the memory module on host-import GPUs (the fixed-arena workaround no longer applies to it). Keep copies short of the texture collector's critical mark and let idle copies and their growth room yield near it, give growing copies room instead of reallocating them on every load, write WRITE_DATA into VRAM copies too, and watch CPU-written blocks with write traps so they get VRAM copies re-uploaded after CPU writes. Retry file reads on EFAULT, add BB_VRAM_LIMIT_MB for small-VRAM tests, and include bilingual release notes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:36:44 +03:00
deadinside af9e66db2f 0.5-pre2: memory layer, native GPU copies and portable labels
Add the memory layer for non-AMD GPUs and preserve coherent guest/VRAM views. Translate the original copy shader by default in the new model, add standard Vulkan completion labels, and migrate versioned shader caches before loading. Include GPU regressions, launcher support and bilingual release notes.
2026-10-09 14:27:09 +03:00
deadinsideandClaude Opus 5.5 39940f25eb 0.5-pre1: settings in the game's System menu, no online/offline screen, DLC, DLSS, save safety
Game menu
- The port's settings as native pages of the game's System menu (Display, Game effects,
  Game patches after Screen/Sound), built and drawn by the game's menu code: hooks on its
  message lookup and item adder, rows bound to the port's values, the game's "Default" sets
  the port's defaults, texts in the game's language (gpu/shim/bbport_game_menu.cpp,
  BB_GAME_MENU=0 off).
- The online/offline choice is skipped by a game patch ("Skip Online/Offline Choice"): the
  game opens its main menu offline (BB_SKIP_NETWORK_CHOICE=0 shows it).
- Overlay menu restyled like the game's dialogs (tabs, rows with values, own focus, serif font).

New
- DLC folders user/addcont/<title>/<label> reported as installed add-ons (#33, PR #84).
- DLSS on Linux through gpu/dlss_bridge when built with NVIDIA's SDK (PR #83).
- Monitor choice (#69, BB_DISPLAY); launcher log copy/export (PR #78), Simplified Chinese
  (PR #75).

Fixes
- Save files written to a temporary copy, fsync and rename: no damaged saves on a crash (#64).
- fsr4cap runs Proton without Steam's container when it cannot start (#61).
- System MangoHud no longer disabled with the bundled one (#66).
- UI draws without a color target go into the UI depth: loading screen item picture (#67).
- Debug menu fonts from adhoc/font, case-insensitive file fallback; no crash without fonts.
- VRAM exhaustion for guest memory blocks falls back to system memory; readbacks=Precise
  no longer deadlocks the first cutscene; indirect dispatch guard (#34); VRAM budget for
  promotion; UTF-8 everywhere in scripts (#55); plain ELF eboot (#49); Switch Pro clone stick
  calibration (#70, PR #71); BB_FSR4_STATS without pipeline statistics (PR #80); GPU info in
  the log (#56).

New memory and translation model (experimental, off by default)
- Offered on NVIDIA too (host memory import, untested there); GPU-written EOP/EOS labels;
  occlusion queries as Vulkan queries; COPY_DATA, COND_EXEC, predication translated; the
  game's copy shader runs as itself; native detours instead of int3 traps in the game's code.

Details: docs/CHANGES_after_0.4.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 00:34:14 +03:00
319 changed files with 21119 additions and 2602 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
ko_fi: ayozetr
+110 -44
View File
@@ -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
View File
@@ -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 здесь не
распространяются.
+51 -12
View File
@@ -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
+28 -7
View File
@@ -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
+107
View File
@@ -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`.
+103
View File
@@ -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`.
+147
View File
@@ -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`.
+172
View File
@@ -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`.
+109
View File
@@ -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`.
+434
View File
@@ -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).
+159
View File
@@ -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 до титульного экрана.
+48
View File
@@ -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.
+263
View File
@@ -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`): с апскейлером
(сцена меньше и со сдвигом) свечение лампы вспыхивало серым на весь кадр; счёт нужно сделать
устойчивым к этому. Фоновая компиляция больше не пропускает полноэкранные проходы (серые кадры).
+68
View File
@@ -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
View File
@@ -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.
+232
View File
@@ -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-арену из новой
модели.
+76
View File
@@ -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. |
+40
View File
@@ -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/).
+3 -2
View File
@@ -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
View File
@@ -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.
+42
View File
@@ -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/`. Игровые проверки используют копии сохранений и настроек. Исходные сохранения и настройки не заменяются. Журналы и игровые данные в релиз не включены.
+92
View File
@@ -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 тыс.) — контрольные суммы
сходятся; картинка та же.
+62
View File
@@ -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
View File
@@ -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
View File
@@ -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). */
+38
View File
@@ -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}")
+40
View File
@@ -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
View File
@@ -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.
@@ -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
@@ -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
+22
View File
@@ -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.
@@ -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
}
Loaded 100 of 319 files, more files were not shown because too many files have changed in this diff. Show more