TDF is a small project aiming to make it easy to install, package and safely run Windows games on GNU/Linux. You can think of it as a portable (as in requiring no installation) version of Proton, based on most of the same technology, with better sandboxing.
TDF is based on the following awesome projects:
- Wine, for Windows emulation, more specifically it includes two custom builds made with wine-tkg, one best suited for modern games, and one more suited for applications and older games
- DXVK, for DirectX 8/9/10/11 emulation, and dxvk-nvapi for nvapi support on nVidia GPUs
- VKD3D-Proton, for DirectX 12 emulation, built from source
- D7VK, for DirectX 3-7 emulation, as an alternative to WineD3D
- xdotool, a useful tool to handle games with problematic window/fullscreen behaviors
- Zenity, a tool to display simple graphical interfaces such as loading bars, error messages, etc.
- libstrangle, used to limit FPS in games that don't support it and don't use DXVK/VKD3D
- Reaper, used to detect "stray" processes
- bubblewrap, used to create a secure sandbox using Linux namespaces
- ...and a handful of other useful things
TDF's main goals are:
- Being able to easily install and run games that you can't or don't want to play through Steam: things like GOG installers, ISOs, repacks, etc.
- Strong sandboxing: give games only what they absolutely need to work and nothing more. By default, TDF doesn't let games access files on your computer and blocks all network traffic
- Being as lightweight and portable as possible: virtually any modern GNU/Linux distro with a GUI can run a game packaged with TDF out of the box
- Being able to easily update TDF instances as well as testing different versions of the main components, making it possible to help their respective developers
- Being able to easily package and transfer a TDF instance to another computer or redistribute it (legally)
- Focus on modern games, but a lot of older titles will work as well with some tinkering
- Targeted at advanced users who want something safer than Lutris or Bottles
This section explains how to use TDF to install, play and optionally package a game.
- A relatively recent PC that's fast enough to run modern games. An x86_64 CPU is required, as well as a GPU with support for Vulkan 1.3 or newer
- An AMD graphics card with the latest Mesa driver or newer is recommended, but it will also work on nVidia and Intel cards
- Linux kernel 6.14 or newer is strongly recommended, but it will work on older versions. For best compatibility, use the latest kernel.
- A modern-ish distro with basic stuff like the GNU coreutils, glibc, systemd, Wayland or X11, etc. installed. Arch-based distros will work best
- An SSD is strongly recommended, with a file system like ext4 or btrfs. Do not use NTFS, FAT or exFAT
- You must be able to use a Linux system, do file and folder management, know how to install games manually, know some basic shell scripting, etc.
- Download the latest build of TDF (or build it yourself)
- Extract the archive somewhere, optionally renaming the folder from
template-YYYYMMDDto something more descriptive. We'll call this folder a TDF instance, you can have as many instances as you want- Inside this folder, you'll see 4 things:
run.sh: the script that starts all the TDF magicvars.conf: the main configuration file for this instance, you use this to tell TDF where to find the game and to change emulation settingssystem: a folder containing all the TDF files and scripts, leave it alone for nowconfs: a folder for additional configuration files, so you can install multiple games in the same instance (we'll talk about it later)
- Inside this folder, you'll see 4 things:
- Launch
run.sh, it will automatically initialize everything for you and open a Windows command prompt- Once everything is ready, the TDF instance folder will contain a new folder called
data, inside it you'll find a folder calledwineprefix, this is your "fake Windows". Insidewineprefix, you'll find among other things a folder calleddrive_c, this is the fake C drive, you can enter it to copy game files, mods, etc. at any time - Depending on the system and the configuration, other folders may also be created inside
data, likehome - If you're not familiar with the Windows command prompt, just type
explorerand press enter to have a more familiar file manager interface. For convenience during installation, TDF will show you a read-only H drive that contains the files on your computer (this can be turned off later)
- Once everything is ready, the TDF instance folder will contain a new folder called
- Use the command prompt or explorer to install the game like you would on Windows but don't launch it yet
- During the installation, you won't need to install things like DirectX, the Visual C++ Redistributables, etc. because TDF has already done it during the initialization
- If you need to copy or modify some files inside the fake C drive, do it through the Linux file manager, it's easier
- Once you're done, close the command prompt
- Edit
vars.confand place the location of the game's exe file in thegame_exevariable. The path must be Windows-style, likeC:\Doom\doom.exe. It is also recommended to set theSteamGameIdvariable, as it will automatically enable fixes for some known problematic games (you can find the IDs here: https://steamdb.info/) - Launch
run.shagain and hopefully the game will start- From now on, you can just launch
run.sh(or create links to it) to launch this game. - About 90% of games will work out of the box, some will require some tinkering, usually in the form of changing some variables in
vars.conf, which we'll discuss later - Online games that require anticheat software will usually not work (and that's probably for the best)
- From now on, you can just launch
The following lists contain all the variables that can be added in vars.conf to configure emulation settings, work around issues, improve performance, etc.
game_exe
Specifies the Windows-style path to the game's exe file. If empty, the command prompt will be launched instead.
Example: game_exe='C:\GTAV\PlayGTAV.exe'
game_workingDir
The working directory of the game. By default this is set to the same folder where the game_exe resides. All paths must be Windows-style.
Example:
game_exe='bin\indy.exe'
game_workingDir='C:\Indy'
game_args
Arguments to be passed to the game.
Accepts a string or a bash array.
Examples: ('-iwad' 'doom2.wad') or '-iwad doom2.wad'
SteamGameId
Optional numeric Steam App ID for the game. Identifies a specific game on Steam, enabling game-specific workarounds in the wine-games build (e.g., known configuration tweaks, known fixes). This does NOT require Steam to be installed; it's purely a lookup key for internal game-specific optimizations.
Look up IDs here: https://steamdb.info/
Example: export SteamGameId="1174180"
TDF uses bubblewrap to create a secure sandbox using Linux namespaces. This provides very strong isolation giving games only the bare minimum that they need to work: access to the display, sound, input devices, and the GPU; a potential malware running inside the sandbox won't be able to touch your files, interact with other processes on your computer (or even see them), use the network, use dbus, etc. unless you explicitly allow it.
TDF_ALLOW_HOST_FILESYSTEM
Controls which host filesystem paths are exposed inside the sandbox.
Possible values:
0: Do not expose the real filesystem at all (most secure)1: Expose the real filesystem as a read-onlyH:drive2: Expose the real filesystem as a read-onlyH:drive only when running command prompt (game_exeis empty). This makes it easy to install games, but gives games no access to the files on your computer when you actually run them3: Expose the real filesystem as a read-writeH:drive
TDF_CUSTOM_MOUNTS
Additional custom mounts in the format "letter:access:hostPath" or "letter".
letter: single letter A-Z (except forC, which is reserved)access:"ro"for read-only,"rw"for read-writehostPath: absolute path on the host filesystem (~is not allowed)- If
accessandhostPathare omitted, a directory nameddata/<letter>is created inside the TDF data folder and mounted read-write. This is useful for things like arcade games that save on a USB drive.
Example: TDF_CUSTOM_MOUNTS=("D:ro:$HOME/Desktop" "E:rw:/media/games" "F")
TDF_BLOCK_NETWORK
Network access blocking method.
Possible values:
0: Don't block network1(default): Block with bwrap--unshare-net2: Block withunshare -nc(old method)
Note that unblocking networking will also allow the sandboxed app to communicate with some services on your computer that use sockets (like CUPS).
TDF_BLOCK_BROWSER
Block Wine from launching the system's native web browser.
Possible values:
1(default): applications running in Wine won't be able to launch a browser0: Allow Wine to launch browsers (RUNS OUTSIDE THE SANDBOX!)
TDF_BLOCK_SHM
Block access to /dev/shm (shared memory).
Possible values:
1(default): Block/dev/shmaccess (recommended, stronger sandboxing)0: Don't block (weaker sandboxing, but some apps may need it)
Note: Setting TDF_WINE_SYNC="fsync" requires TDF_BLOCK_SHM=0. Keep in mind that fsync is an obsolete Wine feature and not blocking shared memory is a security concern.
TDF_BLOCK_NATIVE_INPUT
Block direct access to native input devices (/dev/input) for better security.
Possible values:
0(default): Allow access (default)1: Block direct access to keyboard, mouse, gamepad, etc. (can break gamepad support)
Note: regardless of this setting, unless udev is misconfigured on your system, this won't allow games to log keypresses to other applications.
TDF_WINE_PREFERRED_VERSION
TDF comes with 2 different versions of Wine and can also use the one on your system (if installed). This variable lets you choose which one you prefer.
Possible values:
games(default): use the game-optimized build. This version is based on Valve's version of Wine (bleeding-edge branch), with additional patches appliedmainline: use a mostly regular version of Wine, useful for applications and old games that don't work with the game-optimized buildsystem: use the version of Wine that's installed in the system, if it's not installedmainlinewill be used insteadcustom: use the version of Wine that you can put in a folder calledwine-customoutside the system folder (next torun.sh). This is useful to keep TDF updates easy for the occasional game that requires a custom build of Wine- any other value: tries to use
./wine-<value>folder (where<value>is the value you set), falls back to system Wine if not found
TDF_WINE_ARCH
The architecture of the Wine installation. Can only be set before the initialization is performed, and can't be changed afterwards without deleting the wineprefix.
Possible values:
win64(default): create a 64-bit Windows installationwow64(orwin32): create a 32-on-64 prefix (useful for some old games)
TDF_WINEMONO
Whether to install Wine Mono in the prefix or not. Mostly useful for launchers and applications based on .NET, games don't usually need this.
Possible values:
0(default): don't install Wine Mono1: install Wine Mono
TDF_WINEGECKO
Whether to install Wine Gecko in the prefix or not. This provides the equivalent of a Webview, mostly useful for launchers and applications based on IE, games don't usually need this.
Possible values:
0(default): don't install Wine Gecko1: install Wine Gecko
TDF_VCREDIST
Whether to install the official Microsoft Visual C++ Redistributables (2015+) or not. This is useful for modern games but unnecessary for older ones.
Possible values:
1(default): install the official MSVC redistributables0: use Wine's built-in implementations
export WINEDLLOVERRIDES
Some game fixes and mods come in the form of DLLs that override one of Windows' DLL, usually winmm, dinput8, version, d3d9, etc.
Unlike Windows, which happily loads random DLLs from the game's folder, by default Wine prefers to use its own DLLs and overrides need to be specified manually.
This is not a TDF variable, but it's part of Wine. More about this here.
Example:
#load winmm.dll and dinput8 from the game's folder (if available)
export WINEDLLOVERRIDES="winmm,dinput8=n,b"
This can also be used to fix games that complain about outdated drivers on AMD cards or that don't detect the correct amount of VRAM, since they often obtain this information through a DLL called amd_ags_x64.dll:
Example:
#use wine's own fake amd_ags_x64 instead of the game's version
export WINEDLLOVERRIDES="amd_ags_x64=b"
Multiple overrides can be separated by a semicolon ;.
export WINE_PREFER_NATIVE_DLL
Sets the default DLL load order for DLLs that are not being overridden with WINEDLLOVERRIDES or registry entries.
By default, Wine uses the b,n load order for DLLs unless overridden, which may cause issues with some games and mods that override DLLs like winmm, dinput8, version, etc.; if this setting is enabled, it will change the default to n,b, meaning that Wine will try to load DLLs provided by the game first and only use its own as a fallback.
This improves compatibility with mods and cracks, but can cause issues such as outdated driver warnings or straight up crashes, so it is disabled by default.
Possible values:
0(default): useb,nload order for DLLs that are not overridden (Wine default)1: usen,bload order for DLLs that are not overridden
Notes:
WINEDLLOVERRIDESwill still be applied, this setting only applies if a DLL is NOT overridden- This setting is only supported by the game-optimized build
export WINEDEBUG
Enables/disables some Wine debug channels.
By default, TDF sets this to -all to improve performance, but you might want to enable one or more of these for troubleshooting.
Don't add +relay to this variable, as it's controlled by the TDF_WINE_DEBUG_RELAY variable.
Example:
#log loaded DLLs to the terminal and show the pid of the process that generated each message
export WINEDEBUG=+loaddll,+pid
export DRI_PRIME
Sometimes on systems with multiple GPUs, a game might start using the wrong GPU, such as the integrated graphics on your laptop instead of the dedicated card.
By setting a value for DRI_PRIME you can tell the game which graphics card to use.
Example:
#use the second GPU
export DRI_PRIME=1
This is not a TDF variable and you can find more about it here.
TDF_WINE_HIDE_CRASHES
When a Wine application crashes, it normally shows a dialog similar to the "Stopped working" thing on Windows, but depending on the game and configuration, it may be impossible to interact with that window, leaving you stuck. By default, TDF disables this crash window, but it can be enabled for debugging and troubleshooting purposes.
Possible values:
1(default): hide the crash window0: show the crash window
TDF_WINE_AUDIO_DRIVER
Sets the preferred audio driver for Wine. This can be useful if you have crackling audio or if one of the drivers has a lower latency than the others. Default is usually fine.
Possible values:
pulse: use PulseAudio (you may also want to addexport PULSE_LATENCY_MSEC=20for lower latency in rhythm games orexport PULSE_LATENCY_MSEC=120if you have crackling/dropouts)alsa: use ALSAjack: use Jackdefault(default): let Wine decide
Note: Choosing a driver that doesn't exist in Wine or is not installed in your system will result in no sound being played.
Note: Wine doesn't natively support PipeWire yet, it uses PulseAudio by default for compatibility if you're using PipeWire.
TDF_WINE_GRAPHICS_DRIVER
Sets the preferred graphics driver for Wine (as in how it outputs, not how it renders 3D graphics). This can be useful if you're messing around with Wayland and X11 and Wine doesn't work properly.
Possible values:
default(default): let Wine decidex11: use X11, does not support HDRwayland: use Wayland, supports HDR. Beware, it sucks.auto: let TDF decide based on what you're using. IfWAYLAND_DISPLAYis set,waylandwill be used, otherwise ifDISPLAYis setx11will be used, otherwise default (let Wine decide)
Note: Choosing a driver that doesn't exist in Wine or in your system will result in no graphics being displayed.
Note: This setting is automatically forced to wayland when TDF_HDR is set to 1.
TDF_COREFONTS
Whether to install the Microsoft Corefonts or not. These are fonts like Arial, Comic Sans, etc. that are required by some games such as PC Building Simulator. This is generally harmless, but if some application has font rendering issues, try disabling it.
Possible values:
1(default): install the Corefonts0: don't install the Corefonts
TDF_WINE_WINVER
Sets the Windows version to emulate.
Possible values:
""(empty string) (default): let Wine decide on prefix creation (at the moment it'swin10). Can be changed throughwinecfg- Sensible values:
win10,win11,win7,win8,win81,vista,winxp,winxp64 - Other values:
win2003,win2008,win2008r2,winme,win2k,win98,win95,nt40,nt351,win31,win30,win20
Note: If using an older Windows version, TDF_WINE_ARCH should also be set accordingly. It usually doesn't break anything, but applications may not expect to see 64-bit versions of legacy systems.
TDF_WINE_THEME
Sets the Wine theme.
Possible values:
""(empty string) (default): let Wine decide on prefix creation (at the moment it'slight). Can be changed throughwinecfgclassic: use the classic 9x style theme (can fix some old apps that have drawing issues with modern themes)light: use the modern 11-ish style theme
Note: It's possible to install msstyles themes, in this case, leave this empty and install them through winecfg.
TDF_WINE_LANGUAGE
By default, TDF will pass the system language to Wine, which may be undesirable for some games and applications that just use the system language instead of showing a language selector. Here's a complete list of locales, obviously not all games will support them.
Example: TDF_WINE_LANGUAGE='it_IT.utf-8'
As CPUs get more and more cores and threads, problems such as crashes, inconsistent performance and general instability can occur in older games. For this reason, TDF implements several ways to limit which cores can be used.
Note: these settings apply to the game-optimized build only
Before we get into the settings, some terminology:
- Logical CPU: A "core" as you see in task manager, also known as physical thread. For CPUs with HyperThreading/SMT, 2+ logical CPUs are present for each physical core. Some games work well with SMT, others hate it
- Core: A physical core inside your CPU
- Sockets (multi-CPU systems): refers to the number of CPU chips physically inside your system. For gaming PCs, this is usually 1, but if you're gaming on a harvested multi-CPU server, this is going to be 2+, and not all games react well to that
If a game doesn't support a high number of cores, TDF can limit the number of logical CPUs assigned to it and choose the best ones to maximize performance.
Note: These limits affect the performance of everything running inside Wine, including DXVK and VKD3D. Use them only if absolutely necessary.
Note: if WINE_CPU_TOPOLOGY is set, these settings will have no effect.
TDF_WINE_MAXLOGICALCPUS
The maximum number of logical CPUs that can be assigned to this game.
Possible values:
0(default): unlimited- any other positive number: limit the number of logical CPUs to this value
If the number of logical CPUs exceeds this value, they are assigned intelligently in this way:
- For CPUs with P-cores and E-cores, the first logical CPU of each P-core are assigned first, then E-cores, then the second logical CPU of each core, etc. until we either run out of logical CPUs to assign or the limit is reached
- For CPUs with HyperThreading/SMT: the first logical CPU of each core is assigned first, then the second logical CPU of each core, etc. until we either run out of logical CPUs to assign or the limit is reached
- For multi-CPU systems, see
TDF_WINE_PREFER_SAMESOCKETbelow
Generally speaking, this is the only limit you should set. Let TDF do the rest for you.
Example 1: We're on an Intel Core i7 12900K (8 P-cores with 2 threads each, 8 E-cores with 1 thread each, 24 threads in total), the CPU topology is the following (obtained with lscpu --all --extended):
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE MAXMHZ MINMHZ
0 0 0 0 0:0:0:0 yes 6700.0000 800.0000
1 0 0 0 0:0:0:0 yes 6700.0000 800.0000
2 0 0 1 1:1:1:0 yes 6700.0000 800.0000
3 0 0 1 1:1:1:0 yes 6700.0000 800.0000
4 0 0 2 2:2:2:0 yes 6500.0000 800.0000
5 0 0 2 2:2:2:0 yes 6500.0000 800.0000
6 0 0 3 3:3:3:0 yes 6500.0000 800.0000
7 0 0 3 3:3:3:0 yes 6500.0000 800.0000
8 0 0 4 4:4:4:0 yes 6500.0000 800.0000
9 0 0 4 4:4:4:0 yes 6500.0000 800.0000
10 0 0 5 5:5:5:0 yes 6500.0000 800.0000
11 0 0 5 5:5:5:0 yes 6500.0000 800.0000
12 0 0 6 6:6:6:0 yes 6500.0000 800.0000
13 0 0 6 6:6:6:0 yes 6500.0000 800.0000
14 0 0 7 7:7:7:0 yes 6500.0000 800.0000
15 0 0 7 7:7:7:0 yes 6500.0000 800.0000
16 0 0 8 8:8:8:0 yes 3900.0000 800.0000
17 0 0 9 9:9:8:0 yes 3900.0000 800.0000
18 0 0 10 10:10:8:0 yes 3900.0000 800.0000
19 0 0 11 11:11:8:0 yes 3900.0000 800.0000
20 0 0 12 12:12:9:0 yes 3900.0000 800.0000
21 0 0 13 13:13:9:0 yes 3900.0000 800.0000
22 0 0 14 14:14:9:0 yes 3900.0000 800.0000
23 0 0 15 15:15:9:0 yes 3900.0000 800.0000
If you want to play Colin McRae Dirt (2007), a game that supports 4 cores at most, you'll have to set TDF_WINE_MAXLOGICALCPUS=4, and with this CPU TDF will select logical CPUs 0,2,4,6, because they are the fastest cores available, one thread per core.
If you want to play Lara Croft and the Guardian of Light (2010), a game that supports 12 cores at most, you'll have to set TDF_WINE_MAXLOGICALCPUS=12, and with this CPU TDF will select logical CPUs 0,2,4,6,8,10,12,14,16,17,18,19. The first 8 are the P-cores, one thread per core, the last 4 are E-cores, one thread per core.
If you want to play The Witcher 2 (2010), a game that supports 31 cores at most, you'll have to set TDF_WINE_MAXLOGICALCPUS=31, and with this CPU TDF will not apply any special restriction because it only has 24 logical CPUs.
Example 2: We're on an AMD Ryzen 7 5800X (8 cores with 2 threads each, 16 threads in total), the CPU topology is the following:
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE MAXMHZ MINMHZ
0 0 0 0 0:0:0:0 yes 4850.1948 2200.0000
1 0 0 1 1:1:1:0 yes 4850.1948 2200.0000
2 0 0 2 2:2:2:0 yes 4850.1948 2200.0000
3 0 0 3 3:3:3:0 yes 4850.1948 2200.0000
4 0 0 4 4:4:4:0 yes 4850.1948 2200.0000
5 0 0 5 5:5:5:0 yes 4850.1948 2200.0000
6 0 0 6 6:6:6:0 yes 4850.1948 2200.0000
7 0 0 7 7:7:7:0 yes 4850.1948 2200.0000
8 0 0 0 0:0:0:0 yes 4850.1948 2200.0000
9 0 0 1 1:1:1:0 yes 4850.1948 2200.0000
10 0 0 2 2:2:2:0 yes 4850.1948 2200.0000
11 0 0 3 3:3:3:0 yes 4850.1948 2200.0000
12 0 0 4 4:4:4:0 yes 4850.1948 2200.0000
13 0 0 5 5:5:5:0 yes 4850.1948 2200.0000
14 0 0 6 6:6:6:0 yes 4850.1948 2200.0000
15 0 0 7 7:7:7:0 yes 4850.1948 2200.0000
(Notice the different interleaving in the CORE column compared to the previous example).
If you want to play Colin McRae Dirt (2007), a game that supports 4 cores at most, you'll have to set TDF_WINE_MAXLOGICALCPUS=4, and with this CPU TDF will select logical CPUs 0,1,2,3, which are simply the first 4 logical CPUs, one per core.
If you want to play Lara Croft and the Guardian of Light (2010), a game that supports 12 cores at most, you'll have to set TDF_WINE_MAXLOGICALCPUS=12, and with this CPU TDF will select logical CPUs 0,1,2,3,4,5,6,7,8,9,10,11. The first 8 are the first logical CPU of each core, one thread per core, the last 4 are the second logical CPU of the first 4 cores.
If you want to play The Witcher 2 (2010), a game that supports 31 cores at most, you'll have to set TDF_WINE_MAXLOGICALCPUS=31, and with this CPU TDF will not apply any special restriction because it only has 16 logical CPUs.
TDF_WINE_NOSMT
Whether to hide the additional logical CPUs on CPUs that support HyperThreading/SMT.
Possible values:
0(default): use SMT1: do not use SMT. If this is set, only the first logical CPU of each core will be used, the others will be ignored. This can improve the performance of some older games.
TDF_WINE_NOECORES
Whether to hide E-cores on CPUs like Intel Alder Lake.
Possible values:
0(default): use E-cores1: do not use E-cores
Note: for compatibility reasons, these CPUs have no easy way to tell which cores are P-cores and which ones are E-cores, so TDF "guesses" that the E-cores are the ones with a maximum clock that's <75% of that of any other core. This may be improved in the future.
TDF_WINE_PREFER_SAMESOCKET
How to use multiple CPUs.
Possible values:
0(default): let Wine decide1: assign logical CPUs based on speed, but prioritize cores on the same physical CPU (first assign all the logical CPUs in the first socket, then the second, etc.). This is generally the best for games.2: only show the first CPU/NUMA socket to the application. Useful for multi-CPU servers.
export WINE_CPU_TOPOLOGY
This is not a TDF variable, but it allows you to set Wine to use specific CPU cores, similar to the /AFFINITY option of the start command in Windows, but more fine grained. This should be used as a last resort or if you want to do dumb things like restrict a game to only use E-cores.
Example:
#limits wine to one CPU core
export WINE_CPU_TOPOLOGY="1:0"
Example:
#limits wine to use the first 4 CPU cores
export WINE_CPU_TOPOLOGY="4:0,1,2,3"
Note: if WINE_CPU_TOPOLOGY is set, the settings above will have no effect.
TDF_WINE_DPI
DPI value for display scaling of Wine applications.
Possible values:
0(default): let Wine handle scaling-1: use DPI from the main display (auto-detected via xrdb)- number: use this DPI value (96=100% scaling, 120=125% scaling, 144=150% scaling, etc.). 96 DPI will fix some older games
TDF_WINE_SYNC
The synchronization method to be used by Wine (game-optimized build only).
Possible values:
""(empty string) (default): let Wine decide (ntsync if available, falls back to fsync/esync)fsync: force futex-based fsync (not recommended)esync: force Wine esync (not recommended)
Note: Using fsync requires TDF_BLOCK_SHM=0, which reduces sandbox security.
TDF_WINE_LAA
Enable Large Address Aware (LAA) support for 32-bit applications. Allows 32-bit games to address more than 2GB of memory.
Possible values:
1(default): Enable LAA0: Disable
TDF_WINE_HEAP_DELAY_FREE
Enable heap delay-free optimization. Delays freeing heap memory for better compatibility with games with use-after-free bugs and reduces overhead from system calls.
Possible values:
1(default): Enable0: Disable
TDF_WINE_SMOKETEST
Whether or not to perform a "smoke test" to make sure that Wine actually works before trying to run the game, that way you can tell if a crash is a Wine problem or a game problem. TDF does this by default but you can disable it if it takes too long at the "Starting Wine" screen.
Possible values:
1(default): do the "smoke test"0: skip the "smoke test" for faster startup
TDF_WINE_DEBUG_RELAY
Enables the Wine relay feature, which traces all interaction between the application and the rest of the system to a file. Extremely slow but can be useful to debug weird issues and crashes.
Possible values:
0(default): disabled1: when the game is launched, TDF will ask where you want to save the trace, then launch the game with relay enabled
TDF_WINE_DEBUG_GSTREAMER
Enables gstreamer debug output (to the terminal). This can be used to debug issues like games not playing videos or crashing when a video is supposed to play.
Possible values:
0(default): disabled1: enable gstreamer debug output
TDF_DXVK
Whether to install DXVK or not, which provides Direct3D 8/9/10/11 to Vulkan translation and DXGI implementation. If this is disabled, WineD3D will be used instead, which may be better for some older games. If VKD3D or D7VK is enabled, DXVK is auto-enabled as a dependency.
Settings for DXVK can be changed by downloading the default configuration file, placing it into the game's folder and editing it.
Possible values:
1(default): use DXVK0: use WineD3D
TDF_DXVK_NVAPI
Enable dxvk-nvapi (Nvidia API layer for DXVK). Provides NVAPI support and some performance optimizations on NVIDIA cards. Requires DXVK.
Possible values:
0(default): don't use dxvk-nvapi1: use dxvk-nvapi
TDF_VKD3D
Whether to install VKD3D-Proton, which provides Direct3D 12 to Vulkan translation. If this is disabled, Wine's version of VKD3D is used instead, which has very poor game compatibility compared to this version. Requires DXVK.
Possible values:
1(default): use VKD3D-Proton0: use Wine's VKD3D implementation
VKD3D's config can be changed by using its environment variables.
TDF_D7VK
Whether to install D7VK or not, which provides DirectX 3-7 to Vulkan translation. If this is disabled, WineD3D will be used instead. Requires DXVK.
Settings for D7VK can be changed by downloading the default configuration file, placing it into the game's folder and editing it.
Possible values:
0(default): use WineD3D1: use D7VK
TDF_HDR
Whether to expose HDR support to the application or not. HDR must be enabled in the system settings for this to work and an HDR compatible display is required. This setting has no effect if HDR is disabled or unsupported.
Possible values:
0(default): don't expose HDR (this is the default because HDR kinda sucks in most games)1: expose HDR if available
Note: HDR only works on Wayland, enabling this setting will force Wine to use Wayland, which may break some games.
TDF_GL_MAXFPS
Enables an FPS limiter for OpenGL applications, based on libstrangle.
Possible values:
0(default): disabled, and don't load libstrangle- number: limit FPS to this number
export FSR4_UPGRADE
Enable AMD FSR4 on supported GPUs and games. This installs a proprietary AMD DLL into the sandbox.
Possible values:
0(default): don't enable FSR41: enable FSR4
TDF_DND
Enable Do Not Disturb mode while the game is running. Works on supported desktop environments (GNOME, KDE, etc.).
Possible values:
1(default): Enable DND0: Don't enable DND
TDF_NOSLEEP
Inhibit system sleep while the game is running. Works on supported desktop environments (GNOME, KDE, etc.).
Possible values:
1(default): Inhibit sleep0: Don't inhibit sleep
TDF_MANGOHUD
Whether to launch the game with the MangoHud performance overlay or not. If MangoHud is not installed in the system, it has no effect. Note that some games will crash when launched with MangoHud.
Possible values:
0(default): don't use MangoHud1: use MangoHud
Note: If MangoHud is enabled alongside Gamescope, MangoHud is automatically disabled and Gamescope's built-in mangoapp is used instead.
TDF_GAMESCOPE
Whether to enable Gamescope when running the game or not. This is generally not recommended when using the game-optimized version of Wine, since it integrates the fshack patches which make it mostly useless, but it can be useful when using the mainline version for games that change the screen resolution often, require low resolutions, integers scaling, etc. such as KOTOR or WinQuake. If Gamescope is not installed in the system, it has no effect.
Possible values:
0(default): don't use Gamescope1: use Gamescope when running games if available
TDF_GAMESCOPE_PARAMETERS
The command line arguments used to start Gamescope. You can see a complete list here. Can be a string or a bash array.
By default, TDF sets this variable to -f -r 60 -w $XRES -h $YRES, where XRES and YRES are two read-only variables provided by TDF for convenience that contain the horizontal and vertical resolution of the main display. This default value emulates a virtual screen with the same resolution as the real display, with a refresh rate of 60hz and sets Gamescope to run in fullscreen without any special scaling.
TDF_TITLE
The title to show on the title bar of the TDF windows. By default it's set to "Launcher".
TDF_UI_LANGUAGE
The language to use for the TDF user interface. Does not affect Wine or games (see TDF_WINE_LANGUAGE for that).
By default, TDF tries to obtain the language from the OS. If a translation is not available, it will fall back to English.
Currently implemented languages:
en: Englishit: Italian
TDF_HIDE_GAME_RUNNING_DIALOG
Whether to hide the TDF window that says "Game running". By default, TDF shows it so you can stop the game at any time.
Possible values:
0(default): show the window1: hide it
TDF_IGNORE_EXIST_CHECKS
By default, TDF checks whether the executable specified in game_exe actually exists before trying to launch it, but this is not always desirable and can be disabled, which can be useful to run certain commands.
Possible values:
0(default): check that the executable actually exists and show an error if it doesn't1: don't check and don't show an error if it doesn't exist
TDF_SHOW_PLAY_TIME
Show playtime after the game closes.
Possible values:
0(default): don't show playtime1: show playtime for the current session2: show playtime for the current session and total played hours
You can optionally define the following functions inside vars.conf and they will be called at specific moments during operation. This can be useful to fix games that have issues with window positioning, focusing, etc. or that have some special requirements. The language is just bash.
NEVER CALL WINE FROM THESE SCRIPTS
If you need to define some variables, do it inside the callback functions, as the configuration is loaded more than once during the initialization process.
Note: callbacks run inside a subshell outside the sandbox; therefore they cannot:
- Run wine commands (they would launch system wine outside the sandbox)
- Change any of the settings in this file
- They have full access to the host system, including file system and network (the sandbox is in
$PWD/data)
customChecks
This function will be called immediately after the configuration is loaded. It's useful to run some custom checks specific to the game or to change some settings depending on hardware/software configuration. The function returns 0 if the checks succeed, 1 to indicate that they failed and stop TDF. If the function has no return, it will be treated as a success.
Example:
customChecks(){
if [ "$XDG_SESSION_TYPE" == "x11" ]; then
return 0
else
zenity --error --text="Sorry, this game requires X11"
return 1
fi
}
Note that this function is blocking and TDF won't continue the initialization until it has finished running.
onGameStart
This function will be called right before the game is launched.
Example:
onGameStart(){
echo "Pre-launch: copying mods..."
cp -r mods/* "data/wineprefix/drive_c/Game/"
}
Note that this function is blocking and the game won't be launched until it has finished running.
onGameEnd
This function will be called when the game's main process finishes running.
Example:
onGameEnd(){
echo "Post-game: cleaning up temp files..."
rm -rf "data/home/wine/.cache"
}
Note that this function is blocking and TDF won't close until it has finished running.
whileGameRunning
This function will be called while the game is actively running. It runs in a background subshell and is automatically killed when the game exits. It can run indefinitely or perform periodic tasks.
Example:
whileGameRunning(){
while true; do
echo "Game is running..."
sleep 30
done
}
Note that the game process may not have been created yet when this function is called, make sure to check the game's process using isProcessRunning
onArchiveStart
This function will be called right before the packaging process begins when using ./run.sh archive (mentioned later). It can be used to remove or move some unnecessary files like DXVK/VKD3D caches, saved games, etc. The function receives the same arguments passed to run.sh and can return 1 to prevent the packaging process from starting if something's wrong.
Example:
onArchiveStart(){
TEMPDIR="/tmp/requiem$RANDOM"
mkdir "$TEMPDIR"
mv "data/wineprefix/drive_c/APTRequiem/vkd3d-proton.cache" "$TEMPDIR"
mv "data/wineprefix/drive_c/users/wine/AppData/Local/GOG.com" "$TEMPDIR"
}
Note that this function is blocking and the packaging process won't start until it has finished running.
onArchiveEnd
This function will be called at the end of the packaging process when using ./run.sh archive (mentioned later). It can be used to restore files modified or deleted by onArchiveStart. This function receives 0 in input if the packaging process has succeeded, 1 otherwise.
Example:
onArchiveEnd(){
mv "$TEMPDIR/vkd3d-proton.cache" "data/wineprefix/drive_c/APTRequiem/"
mv "$TEMPDIR/GOG.com" "data/wineprefix/drive_c/users/wine/AppData/Local/"
rm -rf "$TEMPDIR"
}
Note that this function is blocking and TDF won't close until it has finished running.
For convenience, TDF comes with some functions that can be used inside the callback functions mentioned before, in addition to everything provided by bash such as sleep, grep, etc..
waitForWindow exe title [timeout]
Scans windows to find one that matches the specified exe and contains title in the name. If no matching window is found, it will keep trying for timeout seconds (30 if not specified). If exe is an empty string, it will match any process with the specified title, if title is an empty string, it will match any window from the specified process.
The window IDs will be copied to a WINDOWS array, with the first matching window easily accessible with a WINDOW variable.
The function returns 0 if a match was found, 1 if the timeout was reached.
Examples:
waitForWindow "APlagueTaleRequiem_x64.exe" "A Plague Tale: Requiem" 10: waits up to 10 seconds for the process "APlagueTaleRequiem_x64.exe" to spawn a window that contains "A Plague Tale: Requiem" in the titlewaitForWindow "APlagueTaleRequiem_x64.exe": waits up to 30 seconds for the process "APlagueTaleRequiem_x64.exe" to spawn a windowwaitForWindow "" "A Plague Tale: Requiem": waits up to 30 seconds for any process to spawn a window that contains "A Plague Tale: Requiem" in the titlewaitForWindow "APlagueTaleRequiem_x64.exe" "" 10: waits up to 10 seconds for the process "APlagueTaleRequiem_x64.exe" to spawn a window
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
focusWindow id
Makes the specified window active and focused, useful to fix games where the taskbar is visible and you have to alt-tab to get rid of it.
The id of the window can be obtained with the waitForWindow function.
Returns 0 if the operation succeeded, 1 if there's no window with the specified id.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
maximizeWindow id
Makes the specified window maximized.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
restoreWindow id
Makes the specified window not maximized.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
minimizeWindow id
Makes the specified window minimized.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
activateWindow id
Makes a minimized window active again.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
moveWindow id x y
Moves the specified window to the requested position.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
resizeWindow id width height
Resizes the specified window to the requested width and height.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
makeFullscreen id
Adds the fullscreen attribute to the specified window, essentially making it borderless and maximized. Don't use this unless the game has no other way to go to fullscreen.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
removeFullscreen id
Removes the fullscreen attribute to the specified window. Games react differently to this, don't use this if the game has a better way to go to windowed mode.
The id of the window can be obtained with the waitForWindow function.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
keepWindowFocused exe title [timeout]
Keeps a game focused automatically, useful for games that have issues when alt-tabbing or when the taskbar is still visible when the game is in fullscreen.
The arguments are the same as the waitForWindow function, since it works in much the same way.
This function is blocking until the window no longer exists.
Example:
whileGameRunning(){
keepWindowFocused "MassEffect.exe"
}
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
keepWindowFocusedById id
Keeps a game focused automatically, useful for games that have issues when alt-tabbing or when the taskbar is still visible when the game is in fullscreen.
This is essentially the same as the keepWindowFocused except it takes a window id as input, which you can obtain with the waitForWindow function.
This function is blocking until the window no longer exists. Returns 1 if the specified window was not found in the first place, 0 if the window was found.
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
pressKey keys [repeats]
Simulates the pressing of the specified key or key combination, which is sent to the currently active and focused window. Useful for games where you have to press alt+enter to enter fullscreen or where you need to press some keys to get rid of a problem.
If a number is added for the repeats parameter, the specified key or key combination will be repeated repeats times, with a delay of 0.5s between each press.
Example:
#workaround for the lag spike when you first press a key in GTA V
whileGameRunning(){
waitForWindow "GTA5.exe" "Grand Theft Auto V"
sleep 3
focusWindow $WINDOW
sleep 1
pressKey w
}
Note: this function uses xdotool internally and may not work properly on Wayland, depending on how good the X11 emulation in your display manager is (works on major ones).
setGamma gamma
Sets the gamma for the main screen. gamma can either be a single decimal number (1.0 is the default gamma), or it can be expressed as 3 separate values r:g:b. Useful for games that look too dark on modern displays or when using gamescope since it doesn't support hardware gamma yet.
Returns 0 if the operation succeeded, 1 if an error occurred.
The gamma level is not restored automatically when the game ends, so restoreGamma must be called later.
Note: this function only works on X11.
saveGamma
Stores the current gamma level so it can be restored later with restoreGamma.
Returns 0 if the operation succeeded, 1 if an error occurred.
Note: this function only works on X11.
restoreGamma
Restores the gamma level previously saved with saveGamma. If a gamma level was never saved, it restores the gamma level from when TDF was started.
Returns 0 if the operation succeeded, 1 if an error occurred.
Example:
onGameStart(){
saveGamma
setGamma 1.2
}
onGameEnd(){
restoreGamma
}
Note: this function only works on X11.
defaultGamma
Sets the default 1.0 gamma.
Returns 0 if the operation succeeded, 1 if an error occurred.
Note: this function only works on X11.
resetResolution
Resets the main display to its default screen resolution and gamma. This is useful for when you're not using the game-optimized wine build and an old game crashes without restoring the screen resolution.
Returns 0 if the operation succeeded, 1 if an error occurred.
Note: this function only works on X11.
Example:
TDF_WINE_PREFERRED_VERSION='mainline'
onGameEnd(){
resetResolution
}
isProcessRunning exe
Determines whether there's a process with a name that contains the value in exe (case sensitive). Not limited to Wine executables.
Returns 1 if a process was found, 0 otherwise.
Example:
while ! isProcessRunning "APlagueTaleRequiem_x64.exe"; do
sleep 0.5
done
Ideally, you want to have one TDF instance for each game, which keeps them nicely isolated, but some game series like Mass Effect need to import the previous game's data or the game itself has expansions/mods that need to be started with different commands, and therefore need to be installed in the same TDF instance. This is where the confs folder comes in.
Inside the confs folder, you can make as many .conf files as you need, one for each game/mod installed in the TDF instance. These files follow the same syntax as the vars.conf file and each one contains the configuration necessary to launch one game.
TDF will automatically detect the presence of files in the confs folder and show a menu with the list of games in alphabetical order.
When using this mode, the vars.conf file will always be loaded first and its settings will apply to all games, then once the user has chosen one of the games, the specific .conf file will be loaded. If a variable or a callback function is defined both in vars.conf and in one of the .conf file, the latter wins because it's more specific.
Example for Mass Effect Legendary Edition:
vars.conf:#all 3 games use the same arguments so we can put them here game_args='-NoHomeDir -SeekFreeLoadingPCConsole -Subtitles 20 -OVERRIDELANGUAGE=INT'confs/Mass Effect 1.conf:game_exe='C:\MELE\Game\ME1\Binaries\Win64\MassEffect1.exe' whileGameRunning(){ keepWindowFocused "MassEffect1.exe" }confs/Mass Effect 2.confgame_exe='C:\MELE\Game\ME2\Binaries\Win64\MassEffect2.exe' whileGameRunning(){ keepWindowFocused "MassEffect2.exe" }confs/Mass Effect 3.confgame_exe='C:\MELE\Game\ME3\Binaries\Win64\MassEffect3.exe' whileGameRunning(){ keepWindowFocused "MassEffect3.exe" }
Note: the TDF_UI_LANGUAGE variable can only be set in vars.conf, since it's applied before TDF is started, all other variables can be changed at any moment.
By default, when the list of games is displayed, they are shown in alphabetical order. If you want them to appear in a specific order, create a file called _list.txt in the confs folder, with the list of the configuration files in the order in which you want them to appear (filenames only, no extension).
Example:
Mass Effect 1
Mass Effect 2
Mass Effect 3
Mass Effect 1 - Configuration Utility
Mass Effect 2 - Configuration Utility
Mass Effect 3 - Configuration Utility
Command Prompt (for modding)
Windows Explorer (for modding)
You installed your game(s) in a TDF instance and made sure it works perfectly? Did you test it on different hardware? Different distros? All good? Great! You're ready to package it.
To start the packaging process, open a terminal inside the TDF instance and type ./run.sh archive. This will create an archive containing the whole TDF instance that you can easily redistribute. Users will be able to simply extract these archives and launch run.sh to start the game.
By default, TDF creates a highly compressed .tar.zst archive, which takes a long time to create but can be extracted very quickly.
During the compression process, TDF will show you a progress indicator. At the end of the process, it will tell you the compressed size and the compression ratio.
If you want to customize the way these archives are created, the following short commands can be added after ./run.sh archive:
nocompress: creates a simple uncompressed.tararchive. Very fast but not ideal for redistributionfastcompress: creates a compressed.tar.xzarchive, compressed with multithread XZ. Compression is relatively fast, decompression is also quite fast, but the compression ratio is not the bestmaxcompress: creates a compressed.tar.zstarchive, compressed with single thread ZStandard with the highest settings. This is pretty slow but decompression is very fast and also has good compression ratio. This is what Fitgirl would call a "monkey repack"
Generally speaking, the short commands above are the only ones you should need but if you want to customize it further, you can specify the following options after ./run.sh archive instead of the short commands above:
-o path: path to output file (relative or absolute). If the path contains an extension such as .tar.zst, TDF will automatically select the appropriate compression method; otherwise an appropriate extension will be added automatically. If not specified, it creates a file with the same name as the folder containing the TDF instance.-m method: compression method to use. Supported values arezstd(default),xz,gzipandtar(uncompressed). Not required if a file extension has already been specified with-o-p preset: compression preset to use. TDF provides 3 presets for each method:max(slow but smallest size),normal(balances speed and compression),fast(favors speed over compression). By default,zstdusesmax, which is very slow,xzusesfastandgzipusesnormal,tardoes not compress so this parameter will be ignored-f: overwrite the output file if it already exists, otherwise it will just show an error-s size: split the output file in a multipart archive of the specified size. Supported values are any positive integer followed byMorG, such as100Mor1G.autocan also be used to automatically decide the split size based on input size, similar to scene releases (<1G: 100M parts, 1G-10G: 1G parts, 10G-100G: 5G parts, 100G-250G: 10G parts, 250G-500G: 25G parts, >500G: 100G parts). A script to extract the multipart archive will also be created, in case your archive manager doesn't support it.
Examples:
#compress using zstd maximum to a file called example.tar.zst in the upper directory
./run.sh archive -o ../example.tar.zst#compress using xz normal to a file called example.tar.xz in the home directory
./run.sh archive -m xz -p normal -o ~/example.tar.xz#compress using xz fast to a file with the same name as the current folder and put it in the upper directory
./run.sh archive -m xz -p fast#compress using zstd maximum to a file called example.tar.zst in the upper directory, split in 5G parts
./run.sh archive -o ../example.tar.zst -s 5GNote: this feature assumes that tar, xz, gzip and zstd are installed on your system (they probably are).
If you want to transfer a TDF instance from one PC to another using an external drive, it is strongly recommended to use the archive function so that it's just one big file. Never copy a TDF instance to an NTFS, exFAT or a FAT32 partition, it will become unusable.
TDF is designed to be easy to update. To update a TDF instance from an older version:
- Download (or build) a new version of TDF
- Delete the
systemfolder andrun.shfrom the old TDF instance - Copy
systemandrun.shfrom the newer version to the TDF instance, where the old ones used to be - Launch
run.shand it will update everything automatically
It is also possible to downgrade to an older version of TDF in the same way, in case the newer version doesn't work properly.
Note: Loading a wineprefix created with TDF 1.x is not supported. The easiest way to upgrade it is to rename the zzprefix folder from the old instance to wineprefix, make a new instance and launch it at least once, then replace data/wineprefix in the new instance with the renamed folder. Keep in mind that several TDF settings have changed with TDF 2.0, and you will have to redo the vars.conf file as well as any additional config file in the confs directory from scratch.
TDF will automatically detect and apply changes to the files in the following folders inside the system folder of a TDF instance:
d7vkdxvkdxvk-nvapifsr4localizationmsireaperstrangletdfutilsvcredistvkd3dwine-gameswine-mainlinexutilszenitybwrap
So for instance, if you need to test a custom version of DXVK, simply replace the DLLs in system/dxvk with your build (making sure to keep the same folder structure); when you launch run.sh, TDF will detect that these DLLs don't match the ones in the wineprefix and reinstall DXVK. The same goes for Wine and the other components in the list above.
The following folders are not monitored for changes as they are very rarely needed:
corefonts
Should you need to test changes to them, simply disable that component, launch run.sh, then reenable it and launch it again.
TDF is built to be partially modular, meaning that if your game doesn't need certain components, such as Wine Mono, they can be removed to reduce overhead.
Do not do this unless you know what you're doing.
The following folders can be deleted from the system folder of a TDF instance if they are not needed and disabled in the configuration:
d7vkdxvkdxvk-nvapimsi/winemono.msimsi/winegecko32.msiandmsi/winegecko64.msistranglethemes(Note: if this is removed, leaveTDF_WINE_THEMEempty)vcredistvkd3dwine-games(Note: if this is removed, it is recommended to set eitherTDF_WINE_PREFERRED_VERSION="mainline"orTDF_WINE_PREFERRED_VERSION="system", otherwise TDF will try to use the version of Wine provided by the system orwine-mainlineas a last resort. If neither are available, TDF will fail to start)wine-mainline(Note: if this is removed, it is recommended to set eitherTDF_WINE_PREFERRED_VERSION="games"orTDF_WINE_PREFERRED_VERSION="system", otherwise TDF will try to use the version of Wine provided by the system orwine-gamesas a last resort. If neither are available, TDF will fail to start)zenity(Note: if this is removed and Zenity is not installed in the system, TDF will not work)fsr4bwrap(Note: if this is removed, TDF will try to use the system's bubblewrap binary instead. If bubblewrap is not installed, TDF will refuse to start for security reasons)
Folders and files not mentioned in this list should not be removed to avoid breaking TDF.
If a component has been removed, TDF will not try to use it, install it or remove it, even if explicitly requested in the config, therefore it is better to remove and disable unnecessary components before the first time initialization of the wineprefix.
Never remove a component that is currently installed in the wineprefix, as this will leave it in an inconsistent state, especially during Wine updates. If that happens, simply restore the removed components and TDF should take care of the problem.
This section covers troubleshooting games on Wine in general, with a focus on how to do it with TDF. In general, some good knowledge of Windows and Linux will be very useful here.
If a game doesn't work out of the box, before you even start troubleshooting, check ProtonDB for known issues/fixes for this game. Solutions that work on Proton can easily be adapted to work in TDF.
Wine depends on a lot of libraries, and some may be missing. TDF is built exclusively using 64-bit libraries, so multilib is not required. The easiest way to obtain the required libraries is to install Wine on your system and then remove it.
* For Arch-based distros:
sudo pacman -S wine sudo pacman -R wine
* For Debian-based distros:
sudo apt-get install wine sudo apt-get remove wine
- If it still doesn't work, your distro may have a version of glibc that's older than the one that was used to build the prebuilt version of TDF that you have downloaded. You can verify this by opening the terminal and typing
./run.sh, and looking at the errors that appear while TDF tries to load. If this is your case, at the moment the only solution is either building TDF yourself or using a more modern distro - If you moved/copied the TDF instance from another drive, it may have made a mess with permissions. Open a terminal and try
sudo chmod -R 777 . && sudo chown -R $(id -u):$(id -g) .to fix permissions and ownership
Game won't install, the installer doesn't start, doesn't work, it freezes or gives an error during the installation
- Try using
TDF_WINE_PREFERRED_VERSION='mainline'during the installation, using a normal version of Wine instead of the game-optimized one can get it to work - Some crappy installers (especially repacks) don't work in Wine; if that happens you can try to find a version of the game with a different installer (ideally a Steam rip), or you can just install it in a Windows VM and copy the files over to
data/wineprefix/drive_c, most modern games are ok with that
- These are not a problem in Wine, ignore them
- Use a cracked version of the game
- If this is a cracked game, the crack may not have been loaded correctly due to a missing DLL override (see
WINEDLLOVERRIDES) or it could be missing some DLL (see next section) - Try a different crack, some don't work in Wine
- If this is an older game, it may not support high core count CPUs, try setting
TDF_WINE_MAXLOGICALCPUS=4to simulate a quad-core - If you're using mods, they may require
TDF_WINEMONO=1or specific overrides (seeWINEDLLOVERRIDES) to load DLLs like winmm, dinput8, and similar - This issue can be caused by missing DLLs
- If there's a folder called
_CommonRedistor_Redistsin the game's folder, that will most likely contain some installers for libraries required by the game. They're usually not necessary with Wine but some older redists like PhysX will need to be installed.- Remove
game_exeand launchrun.shto open a command prompt - Navigate to that folder and install the redists
- Put back
game_exeand try launching the game again
- Remove
- If it still doesn't work, investigate missing DLLs
- Add
export WINEDEBUG=-all,+loaddlltovars.conf - Open a terminal and run
./run.sh - While the game is starting you'll see each DLL that it tries to load, if you see errors about missing DLLs, they need to be installed
- Missing files like
xinput1_3.dllord3dcompiler_43.dllindicates that you need to install the old DirectX redistributable - Missing files like
mscoree.dllindicates that you're trying to load a .net application, try addingTDF_WINEMONO=1to the configuration - Missing files like
msvcrt###.dllorvcruntime###.dllindicates that you need a specific version of the Microsoft Visual C++ Redistributable - Missing files like
mshtml.dllindicates that you're trying to load an application that depends on Internet Explorer, try addingTDF_WINEGECKO=1to the configuration - Missing any file that's not part of Windows or some Microsoft redistributable indicates that there's a problem with the game installation (incomplete/corrupt setup)
- Missing files like
- Once you've downloaded what you need
- If it's a single DLL just copy it to the game's folder
- If it's an installer, remove
game_exefrom the configuration and launchrun.shto open a command prompt, install what you downloaded, then put backgame_exeand try launching the game again
- Add
- If there's a folder called
- If you don't see complaints about missing DLLs, it could be that the game is crashing immediately
- Add
unset WINEDEBUGandTDF_WINE_HIDE_CRASHES=0to enable Wine's default debugging messages and "stopped working" screen - Open a terminal and run
./run.sh - While the game is trying to start, you'll see a lot of messages in the terminal, most of them are innocuous, but some of them may provide some info about the problem that you can search online. Typical causes are missing files/registry keys, issues with video playback, incompatibility with DXVK/VKD3D-Proton (rare), DRM issues, mods failing to load. It's hard to tell and you'll have to figure it out
- A useful tool to investigate is Wine's relay feature, which logs all interaction between the application and the system to a file. To enable relay, add
TDF_WINE_DEBUG_RELAY=1and launch the game, it will ask you where you want to save the trace and then try to launch the game. Keep in mind that Wine runs extremely slow while this is enabled and the generated trace could be several GB in size - After the game has crashed, open the trace with a text editor and start looking for clues (especially around the end of the file)
- A useful tool to investigate is Wine's relay feature, which logs all interaction between the application and the system to a file. To enable relay, add
- Add
- If your game is a UWP app (like an extracted appx package), this is not supported by Wine at the moment, you'll need a regular Win32 version of the game. This is easily identifiable by the presence of an .appx version of VCRuntime
- Find some way online to bypass the launcher, usually it involves setting
game_exeto another file or adding some arguments withgame_args - Find an alternative launcher online
- Some games have .net applications as launchers or they need Internet Explorer, try adding
TDF_WINEMONO=1andTDF_WINEGECKO=1
- Add
export DRI_PRIME=1to the config, where 1 is the number of the GPU that you want to use (starting from 0)
- Wine doesn't automatically load overrides for system DLLs like
dinput8.dll,version.dll,winmm.dll,dsound.dll, etc., this is a common technique used by mods to inject code, addexport WINEDLLOVERRIDES="filename1,filename2,...=n,b". Note that the filenames must not have an extension, only the name. Example:export WINEDLLOVERRIDES="winmm=n,b".
- See the
TDF_WINE_LANGUAGEvariable - If the game is using a Steam/EGS/whatever emulator, there's usually a file nearby like
steam_api.inithat will contain some configuration, including the language - Some games require a command line option to change the language (
game_argsvariable) - Some older games store the language in the registry, remove
game_exefrom the configuration to get into "install mode", run regedit and find the key
- Modern games usually obtain this information through a proprietary API like AMD AGS. If you see files like
amd_ags_x64.dllornvapi.dll, you can force Wine to use its own fake version to fix this problem by addingexport WINEDLLOVERRIDES="amd_ags_x64=b". If you need to add multiple overrides, separate them with a semicolon. Example:export WINEDLLOVERRIDES="winmm=n,b;amd_ags_x64=b"
- Make sure TDF is updated to the latest version
- Make sure you're running the latest Linux kernel and the latest version of Mesa (AMD/Intel) or the NVIDIA driver. Ideally, if you're on an Arch-based distro and using AMD/Intel, use the mesa-git package from the AUR
- If you experience severe stuttering or performance drops, these are some likely causes:
- You may be running out of VRAM. Linux doesn't handle this very well, games will stutter heavily or have a sudden drop in performance when that happens. Try installing MangoHud and add
TDF_MANGOHUD=1, this provides a nice overlay for various things, including VRAM usage. When it's above 90%, you'll start running into problems - If this is a modern game, your CPU may not be fast enough to handle the game and the emulation overhead
- If this is an older game, it may not support high core count CPUs, try setting
TDF_WINE_MAXLOGICALCPUS=4to simulate a quad-core - The game may have issues with ntsync, try adding
TDF_WINE_SYNC="esync"
- You may be running out of VRAM. Linux doesn't handle this very well, games will stutter heavily or have a sudden drop in performance when that happens. Try installing MangoHud and add
- If this is an older game, it may also be a good idea to run it using regular Wine, add
TDF_WINE_PREFERRED_VERSION=mainline - If this is an older game that used DX8-11, try running it with WineD3D instead of DXVK by adding
TDF_DXVK=0 - If this is an older game that used DX3-7, try running it with D7VK instead of WineD3D by adding
TDF_D7VK=1 - Look for known issues and fixes for this game in the DXVK issues page (DX8-11), the VKD3D-Proton issues page (DX12), and if you're on an AMD/Intel GPU check the Mesa issues page as well
- If this is a DX8-11 game, create a file called
dxvk.confin the game's folder and tinker with DXVK's settings - If this is a DX12 game, try tinkering with VKD3D-Proton's settings
- If you're on AMD/Intel, try tinkering with Mesa's settings. These are some typical settings to try first for issues on AMD (try them one by one!):
export RADV_DEBUG=nodccexport RADV_DEBUG=llvmexport ACO_DEBUG=nooptexport RADV_PERFTEST=nosamexport AMD_DEBUG=nongg
- Some games have memory management issues that can be workarounded by adding
export WINE_HEAP_DELAY_FREE=1 - Look for game-specific fixes on PCGamingWiki, even if it's focused on Windows, the same fixes often apply to Wine as well
- If this is an old DX9 game, add
unset WINEDEBUGto the configuration, open a terminal and run./run.sh, if you see errors about shader compilation, you probably need to install the old DirectX redistributable - It is extremely rare but some very old games don't work with Wine's msvcrt/msvcp, for those you'll have to find an old version of the Visual C++ Redistributable (version 6 and older) or take it from Windows, put the DLLs in the game's folder and add
export WINEDLLOVERRIDES="msvcrt,msvcp=n,b" - Add
unset WINEDEBUGandTDF_WINE_HIDE_CRASHES=0to the config, open a terminal and run./run.sh, most of the messages you'll see are innocuous, but some may provide clues about what's going on
If you find a solution to a problem, always make sure to report it somewhere. If you can't find a solution, report the problem to one of the projects involved, at worst they'll tell you it's not their fault and where to report it. People are generally very friendly in the Linux gaming community.
Some games only enable ray tracing if they detect and NVIDIA GPU. You can fake it by adding this to the config to pretend that you have a 4090: export DXVK_CONFIG='dxgi.customVendorId = 10de; dxgi.hideAmdGpu = True; dxgi.customDeviceId = 2684; dxgi.customDeviceDesc = "NVIDIA GeForce RTX 4090"'
- Try using the alsa sound backend by adding
TDF_WINE_AUDIO_DRIVER="alsa" - Increase sound buffer size by adding
export PULSE_LATENCY_MSEC=120 - If this is an older game, try using an EAX emulator like DSOAL, you can find prebuilt DLLs online if you don't want to mess with Visual Studio, all you have to do is put them in the game's folder and add
export WINEDLLOVERRIDES="dsound=n,b" - The game may not support surround sound or your sample rate, set your system to 44.1KHz stereo
- If the sound issues are happening mostly when there's heavy CPU load (shader compilation, entering new areas, etc.) and you're using pipewire, your system may be affected by this issue
- Try adding
TDF_WINE_DEBUG_GSTREAMER=1, it may provide details about what's happening
- If this is an older game, it may not support display scaling, try adding
TDF_WINE_DPI=96 - See the section on Builtin functions for how to lock on to a window and manipulate it
- Make sure you have
TDF_BLOCK_NATIVE_INPUT=0in your config - You may have to add some udev rules to allow your user permissions to use controllers. If you're on an Arch-based distro, the
game-devices-udevpackage on the AUR will take care of most models, otherwise, this article will help users of all distros. Reboot after applying the udev rules
TDF no longer starts after being copied/moved to an external drive or syncing through cloud to another computer
- To transfer a TDF instance, you should use the archive feature instead, it's faster and more reliable
- If you're using syncthing to keep a TDF instance synced between PCs, you need to set that folder to sync and send extended attributes on all your machines. This is a bad idea though, a much better thing to do would be to only sync the saved games folder inside that TDF instance
- If you moved a TDF instance to an NTFS, exFAT or god forbid a FAT32 drive, or any other file system that doesn't support UNIX permissions and symlinks, you're out of luck and I told you so in the beginning of this document. Recover your saved games from
data/wineprefixand start over with a new TDF instance - If you see the error "This sandbox was created by another user", the
datafolder's ownership has changed. Use this command to fix it:sudo chown -R $(id -u):$(id -g) data
The TDF build scripts are designed to download the latest version of each component in TDF, build what needs to be compiled from source, and create a template-YYYYMMDD.tar.zst ready to extract and use.
TDF depends on a lot of dependencies when building and , or who want a reproducible build environment, you can use Distrobox with Podman:
- Make sure you have distrobox and podman installed and working properly
- Download and extract the preconfigured image based on Debian 13
- Load the
tdfbuildimage:podman load -i tdfbuild.tar - Create the
tdfbuildcontainer:distrobox create --image tdfbuild --name tdfbuild - Launch the container:
distrobox enter tdfbuild - Clone the TDF repo and enter it:
git clone https://github.com/adolfintel/tdf && cd tdf - Build it:
TDF_BUILD_AUTOUPDATE=1 ./makeTemplate.sh - Stop the container:
distrobox stop tdfbuild
The finished template-YYYYMMDD.tar.zst will be inside the folder where you cloned the TDF repo.
For future builds, just distrobox enter tdfbuild, go to your cloned TDF repo, and run the build script again.
If you don't trust my image (understandable) or you just want to experience the pain of building it yourself, TDF can be built on both Arch and Debian, and will help you download dependencies along the way
To build TDF natively:
- Download the latest version of this repo:
git clone https://github.com/adolfintel/tdf - Enter the downloaded folder:
cd tdf - Launch the automatic build script:
./makeTemplate.sh
Every time it encounters a missing dependency, it will stop and you'll have to download it.
The following prebuilt components will be downloaded automatically:
- Wine Mono: latest version from the Wine website
- Wine Gecko: latest 32 and 64-bit versions from the Wine website
- Microsoft Corefonts: from Sourceforge
- Microsoft Visual C++ Redistributable: latest 32 and 64-bit versions from Microsoft
- AMD FSR4: from the AMD website
The following components will be built from source:
- Wine: latest master using the wine-tkg build system with some custom config
- DXVK: latest master from Github
- DXVK-nvapi: latest master from Github
- D7VK: latest master from Github
- VKD3D-Proton: latest master from Github
- bubblewrap: latest master from Github
- xdotool: latest master from Github
- zenity: version 4.2 from Gnome's GitLab
- Reaper: latest master from Github
- libstrangle: latest master from Gitlab
- Some C programs included with the TDF source code (used for smoke tests, DND, sleep inhibition, etc.)
The first build will take a good 15-60 minutes to download and compile everything, but subsequent builds will be quicker as the download phase will only download updates for the components and the TDF repo itself.
If the build fails (and let's be honest, the first few times it probably will), fix the problem and run ./makeTemplate.sh again, the script will automatically resume from where it left off.
If you don't want to use this caching and resuming system, you can run a clean build using ./makeTemplate.sh clean, this will delete all saved data and redownload everything, then build TDF.
If you're going to build TDF regularly, you can enable automatic updates for the TDF repo using TDF_BUILD_AUTOUPDATE=1 ./makeTemplate.sh (git only).
At the end of the build process, the package will be compressed using a slow but efficient zstd compression and the finished archive will be created as a .tar.zst file.
Wine is an HLE (High Level Emulator) which means that it doesn't emulate an entire system like dosbox does because that would be too slow, instead it provides a way to load Windows exe files, intercept Windows system calls and "convert" them to equivalent Linux system calls. It also provides a ton of libraries and other functionality but that's not relevant here. Without TDF, this means that any random Windows exe that you run in Wine is to all intents and purposes, a regular UNIX process that's running under your user, and therefore it has access to everything you have access to, and malware can easily escape the restrictions put in place by Wine by using Linux system calls directly, it only requires some modest knowledge of how Wine works.
TDF was designed to sandbox Wine itself rather than games running inside it. It provides very strong security compared to a regular installation of Wine, Proton, Lutris, Bottles, and other similar tools, and does it by running Wine inside a sandbox created using bubblewrap, the same technology used to sandbox apps distributed through Flatpak, but configured differently. In other words, TDF assumes that your games are malware and treats them as such, by design.
Out of the box, a game running inside TDF has:
- No network access (games are launched in a separate network namespace where they can only see a loopback interface that is limited to the sandbox). You can enable it if the game has online functionality with
TDF_BLOCK_NETWORK=0 - No access to processes outside of the sandbox: no way to see them or communicate with them
- No access to dbus
- No shared memory between processes (except between parent and children, which is required for some mods to work, and only inside the sandbox)
- No way to launch applications installed outside the sandbox (except for the browser, which is disabled by default)
- No capabilities
- A completely fake file system:
- Inside of Wine:
- The C drive points to
data/wineprefix/drive_c, read-write - The H drive lets you access files on your computer, read-only, and only while running the command prompt to install the game
- The C drive points to
- Outside of Wine:
- The root file system is completely fake, it resides in RAM and is destroyed immediately when TDF is closed
- Some files and folders on your system are mounted read-only to allow access to basic commands, drivers, etc., specifically the following (and only if they exist):
"/usr" "/bin" "/lib" "/lib32" "/lib64" "/sys" "/etc/hosts" "/etc/localtime" "/etc/hostname" "/etc/resolv.conf" "/etc/fonts" "/etc/machine-id" /homeis mounted read-write todata/home, this way the shader cache can persist- The TDF instance folder is mounted to
/tdf, read-only except for/tdf/data, which is where the sandbox data is stored and is read-write. This way, a malware will not be able to modify TDF itself or your configuration files - Custom mounts defined with
TDF_CUSTOM_MOUNTSand the host file system (if enabled withTDF_ALLOW_HOST_FILESYSTEM) are mounted to/customMounts/<letter>
- Inside of Wine:
- Minimal access to devices: games will be able to use the CPU, GPU, the audio (through Pulse, PipeWire or ALSA), the display (through X11 or Wayland), and input devices. Nothing else is exposed.
- No information about the real users on your computer (there's only a fake
"wine"user inside the sandbox) at all and no way to use su, sudo, and similar commands
With that being said, I don't encourage you to run malware in it. In order for games to work, TDF needs to allow some access to your system, and this is potential attack surface:
- Malware can use the graphics and sound systems to try and record your screen. If you're on a modern distro with Wayland and PipeWire this would be immediately noticeable, but it could go unnoticed on other distros
- Malware can try to run exploits and 0-days againts the kernel, the drivers or bubblewrap. That would be very difficult to pull off, but potentially very bad if successful
- Incorrect configuration, such as exposing your home directory with read-write permissions, will allow malware to create a persistance mechanism and escape the sandbox (like modifying .bashrc), or allowing network access while having the H drive enabled. That would be very stupid and it would be entirely your fault
If you need to test malware, use a proper hardened VM, this is for games.
- Implement something similar to the Steam Runtime but based on Arch to mitigate Wine's dependency hell
- Automatically recognize some known problematic games and apply tweaks to the configuration
No. TDF predates the generative AI boom, so the code was written by me. Some AI tools were used (specifically a local instance of Qwen 3.6 and pi) to do things like exploring the Wine source code to look for specific settings or behaviors, updating the documentation, sandbox testing, etc. and it was actually quite helpful.
This project started off in 2021 as a "template" that I could use to easily create these self-contained ready-made environments to easily and safely run Windows games, something that things like Lutris couldn't do really well despite having a nice GUI.
Eventually, my friends started calling it "Template Di Frederico", meaning Frederico's Template in Italian (Frederico being a common misspelling of my name, Federico); the temporary name eventually stuck, it got abbreviated to TDF or just "the template", and I couldn't come up with a better name so TDF became the official name in 2023 when I finally decided to write some documentation and release it.
All TDF code is distributed under the GNU GPL v3 license, but a built version of TDF will contain components with multiple licenses, including proprietary ones.
Copyright (C) 2021-2026 Federico Dossena
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.