▙▗▌▗ ▗ ▜
▌▘▌▄ ▛▀▖▄ ▛▚▀▖▝▀▖▐
▌ ▌▐ ▌ ▌▐ ▌▐ ▌▞▀▌▐
▘ ▘▀▘▘ ▘▀▘▘▝ ▘▝▀▘ ▘
▛▀▖ ▐ ▗ ▗▀▖▗ ▐ ▗
▙▄▘▙▀▖▞▀▖▜▀ ▞▀▖▛▀▖▄ ▐ ▄ ▞▀▖▝▀▖▜▀ ▄ ▞▀▖▛▀▖
▌ ▌ ▌ ▌▐ ▖▌ ▌▌ ▌▐ ▜▀ ▐ ▌ ▖▞▀▌▐ ▖▐ ▌ ▌▌ ▌
▘ ▘ ▝▀ ▀ ▝▀ ▘ ▘▀▘▐ ▀▘▝▀ ▝▀▘ ▀ ▀▘▝▀ ▘ ▘
what makes Proton a Proton
by ivyl
# What Is Proton?
Proton is a downstream Wine distribution that includes a lot of extras:
- **dxvk** - alternative D3D8-D3D11 implementation to wined3d
- **vkd3d-proton** - alternative D3D12 implementation to vkd3d
- **dxvk-nvapi** - Nvidia's nvapi implementation
- **fonts** patched for metric compatibility
- **piper** - speech synthesis
- **kaldi** - speech recognition
- ...
And some custom bits:
- **steamapi bridge**
- **steam.exe shim**
- **proton** launch script
- tones of **patches** for game compatibility
Proton is intended to run inside of the **Steam Runtime**.
# What Would A Minimal "Proton" Be?
- runs at least some games
- access to Steam API
- launchable via Steam
- as close to upstream Wine
- no Proton build system involved
- no runtimes involved
Let start stripping things down!
# Start Fresh
We are dropping all the external libraries and just start with a clean
`wine-10.15` tree.
We are going to bring back only the bare mnimum.
# Steam.exe Shim?
- lives in `steam_helper/steam.c`
- built using modified `makedep`
- some games expect to be descendants of a `steam.exe`
- sets registry values relatied to currently running steam instance
- calls lsteamclient's `steamclient_init_registry()`
- setups vrclient
- waits to be ptraced when is set `PROTON_WAIT_ATTACH=1`
Most games don't need it, but significant number does.
You definitely don't need it when running software without Steam integration.
I was on the fence but **we are dropping it for our miniminal example.**
# lsteamclient.dll
- `lsteamclient/`
- built using modified `makedep`
- exposes win32 version of Steamworks API (`steamclient*.dll`)
- we have a Wine patch to set up trampolines from the original DLL
- calls into the `steamclient.so`
- code mostly autogenerated using Steamworks SDK headers + libclang
- does some extra work like converting paths unix <-> dos, etc.
You don't need it when running software without Steam integration.
Some games are also fail gracefully and are fine without it.
**We'll include this!** We can import it into `dlls/` and add the new directory
to the `configure.ac` file.
# Wine Patches
Wine has hundreds of patches that make games run or run better - adding hacks,
dll overrides, dlls that are part of driver installation on Windows, etc.
**Only 4 patches are needed** to have a working 'Wine tree'-based Proton build!
I've tried to group the patches in a way that makes for easy cherry-picking on
top of any Wine tree to get a rebase running quickly. They are directly on top
of the upstream `wine-10.0` tag.
I'll keep on iterating on the patch organization each rebase to make the changes
more self contained and make what's essential clearer.
# The Cherry Picks!
Necessary for building lsteamclient.dll:
1d400e3aea5c ("makedep: Allow building modules with C++ sources.")
Redirecting `steamapi*.dll`s to lsteamclient:
38e8f39bda73 ("HACK: steam: ntdll: Setup steamclient trampolines to
lsteamclient.")
Misc Steam ingegration:
912e1b4b9fe9 ("HACK: steam: kernelbase: Substitute the current pid for the
Steam client pid.")
447ecf2a3333 ("HACK: steam: wine.inf: Add required Steam registry entries.")
# The `proton` Script
A complicated Python script that:
- `WINEPREFIX=$STEAM_COMPAT_DATA_PATH/pfx`
- reflinks/links/copies `default_pfx` to speed up the first start
- ... and help with per-game prefix space usage
- copies some dlls provided by Steam to correct directories
- contains special handling for prefix upgrades / downgrades
- copies some files provided by Steam that the games may expect
- applies workarounds based on `SteamAppId`
- starts the actual target via `steam.exe`
- redirects logging, etc.
**We'll be replacing it.**
# The Replacement
`proton waitforexitandrun regedit.exe`
```sh
#!/bin/sh
export WINEPREFIX="$STEAM_COMPAT_DATA_PATH/pfx"
mkdir -p "$STEAM_COMPAT_DATA_PATH/pfx/drive_c/Program Files (x86)/Steam/"
for file in steamclient.dll steamclient64.dll; do
cp "$STEAM_COMPAT_CLIENT_INSTALL_PATH/$file" \
"$STEAM_COMPAT_DATA_PATH/pfx/drive_c/Program Files (x86)/Steam/"
done
if [ "$1" != "waitforexitandrun" ]; then
echo "Unknown verb $1."
exit 1
fi
shift
dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
"$dir/wine/wine" "$@"
```
# Steam Runtime
Proton is built to run inside of the Steam Runtime.
Steam uses `pressure-vessel` (modified bubblewrap + extra tooling) to create a
namespace for the runtime and run things inside of it - think Flatpak-lite.
Pressure-vessel also **imports hosts graphics stack** with dependencies and
checks all the imported host libraries to meet the **ABI guarantees**.
There's a community project to allow running Proton inside of the runtime using
other launchers:
Proton is built inside Proton SDK OCI image based on the Steam Runtime SDK:
# Why A Runtime?
It's designed to benefit Steam, native games and anything else pre-compiled
people may want to redistribute on the platform.
Design docs, host distribution assumptions, debugging instructions, etc.:
**For Proton** the biggest benefit was running in a more predictable
environment.
Once we switched away from the old `LD_LIBRARY_PATH`-style a whole class of bugs
reports was gone - **ABI incompatibility** due to distribution patching
libraries, compiling with unexpected flags causing missing exports or files
being located in unexpected places.
Linux user-space is not really great at ABI compatibility and requires extra
steps added somewhere.
# Compatibility Tool Metadata And Layering
We'll need `toolmanifest.vdf` to tell Steam we are a Proton.
The default file looks like this:
```
"manifest"
{
"version" "2"
"commandline" "/proton %verb%"
"require_tool_appid" "1628350"
"use_sessions" "1"
"compatmanager_layer_name" "proton"
}
```
Note the `require_tool_app_id`.
# Is Steam Runtime Mandatory?
For good experience and getting help? **Yes.**
For tinkering and trying things out? No.
Just remove `require_tool_app_id` and restart Steam.
Providing all the dependencies on the host is on you. Good luck!
# What About Escaping The Runtime Steam Itself Uses?
We really don't need to escape it, everything should run fine at this point.
You still can do this though:
`STEAM_RUNTIME=0 STEAM_RUNTIME_HEAVY=0 steam`
This requires much more 32 bit libs on host and may be broken in unexpected
ways. Extremely not supported. May disappear at any time.
# The Last Step
We also need to add a `compatibilitytool.vdf` next to our `proton` replacement.
```
"compatibilitytools"
{
"compat_tools"
{
"miniproton"
{
"install_path" "."
"display_name" "miniproton"
"from_oslist" "windows"
"to_oslist" "linux"
}
}
}
```
An put everything in `~/.steam/root/compatibilitytools.d/`
# By Those Powers Combined
wine-10.15 + a dozen or so patches + lstemclient dll included in the tree.
Check `miniproton/README` for instructions on how to run it.
**DEMO IF TIME ALLOWS**