I like playing games. My 1600-word review of Portal 2 should have been at least some indication of that. I enjoy console and PC video games, tabletop roleplaying games, and board games. But today, I'm talking about playing PC video games in Linux.

wine is not an emulator

Let's start with the basics (then probably skip the middle ground and jump straight to the advanced stuff). Programs written for Windows or Mac OS can't be run natively in Linux. By 'natively', I mean you can't just click on a Windows application, or type its name on your terminal, and expect it to work. You'll get an error like this:
bash: ./windowsprogram.exe: cannot execute binary file

There are a number of reasons this doesn't work. The first and most fundamental is that Windows and Linux use different binary file formats; that is, the actual program code is structured in an entirely different way.

So why not just create a tool that can take one binary format and convert it to another? Well, to begin with, that would be pretty complicated, and probably fraught with problems; these binary formats are actually pretty complex, and include things like how to dynamically access libraries. Libraries are big chunks of code that are written separately from the program, then used by the program so that software developers don't have to repeatedly write the same code to accomplish common tasks.

And that leads us to the real problem - Linux and Windows have fundamentally different sets of libraries available. Each OS has a large collection of system libraries that developers can use to interact with the Operating System in different ways. And there is very, very little overlap between these libraries. A prominent example of a library that exists only in Windows is Direct3D, which is used by a lot of game developers; it contains code that makes it easier to do a lot of complicated things with the graphics card, thus making it easier to make pretty, visually involved games.

So, if you want to run a Windows program in Linux, you would have to create a tool that could take a Windows program, make it "think" it is running in a Windows environment, and then take its library calls and somehow convert them into a set of library calls that Linux can understand. Direct3D calls, for instance, might be converted into equivalent OpenGL calls in Linux. This is exactly what the wine project does.

Wine has been around for a long time, and it has aged well (these are the jokes, folks). The latest wine codebase does a great job handling a ton of Windows applications, including a great many games. This article is an overview of my experience using wine to play games on Fedora.

blizzards and steam valves

My journey begins with wine-1.3.18, the version packaged with fedora 13. Wanting to play Starcraft 2, I ran the installer, which executed without a problem. The game itself also ran great, without having to make any tweaks at all to wine's configuration. So, Starcraft 2 was an easy win. Blizzard's games, in general, work great under wine. I'm not sure if Blizzard just avoids strange API calls, or if wine has a lot of developers interested in making certain Blizzard's games work. Either way, this one was phenomenally easy.

The next thing I tried was Valve's Steam client. If you're somehow reading this from the past, or Steam no longer exists in the future (or you have recently emerged from a coma), Steam is a game distribution platform. You can buy electronic copies of games, install them in steam, and play them. Many games also support achievements and server-side syncing of your game data. This makes gaming on multiple computers really nice (as long as you're the only one using Steam, that is). It also has community features; you can see what your friends are playing, join them in multiplayer games, etc.

So, I have quite a few games on Steam, and before I can try to run the games under wine, I have to get Steam to run. This was a little bit trickier than running Starcraft 2. First, the Steam installer is a .msi file, which requires the msiexec tool to run. Luckily, recent versions of wine come equipped with an open-source clone of the msiexec tool. So, all I had to do was:
msiexec SteamInstall.msi

Once this was done, Steam launched, but I ran into a new problem: every time I move my mouse over the Steam windows, they would flicker, making it hard to see what I was doing. This was solved by using winecfg to set the 'Windows Version' to Windows 7. Problem solved.

The next problem I encountered with Steam was that, when I drag a Steam window, it continues to move around after I release the mouse button, as if I'm still holding it. I have to click on another Steam window to make it stop. This problem remains unsolved in the latest version of wine (1.3.21 as of this writing).

Having Steam running, though, I was able to try a few games. The first thing I discovered was that every game I tried had major problems until I unchecked 'Enable Steam community in-game'. Once I had done this, Plants vs Zombies and Darkstar One both worked great 'out of the box', with no tweaking required.

Portal, on the other hand, was not as great. Every few seconds of game play (not exactly precise, and it happens more when portals are open) the game will stutter for a moment. I spent a lot of time tweaking wine to try to fix this, but the problem remains in the latest version of wine. In addition, in wine 1.3.20, an even worse problem appeared - instead of stuttering, the game would act as if the mouse had been moved a random distance in a random direction periodically.

The last game I tried out was Team Fortress 2. It refused to start until I added an override for hl2.exe (in winecfg) disabling gameoverlayrenderer.dll and changing the Windows version to NT 4.0 (who knew Windows NT was a good gaming platform?). After this, the game worked with a stuttering problem similar to Portal's, but more dependent on how much action was happening on screen. This was probably my most disappointing experience with wine, and 1 problematic game out of 5 isn't bad.

So far, I have a (let's say) 80% success rate with running Windows games under Linux using wine, with comparatively little effort required on my part. This is a fantastic result compared to even 2 years ago, and I look forward to watching the wine project enable ever more games under Linux.

tips, tricks, caveats

If you're using Fedora, you may run into problems with pulseaudio. I recommend disabling it completely, via the following:
yum remove alsa-plugins-pulseaudio
echo > ~/.pulse/client.conf << EOF
autospawn = no
daemon-binary = /bin/true

Then, reboot your machine (or make sure you kill all running pulseaudio processes). Wine works a lot better this way. You'll probably also want to run:
setsebool wine_mmap_zero_ignore 1

To make SELinux play well with games in wine.

Something I wanted to do but was unable to achieve was run native Linux games directly from Steam, and have Steam keep track of them. After asking on the wine-users mailing list, I learned that the way wine emulates Windows process handling makes this impossible. So, instead, I created steamstub, a Windows program written specifically for Steam under wine. To use it, add it as a non-steam game to Steam, then edit the game's properties and change the name to a native Linux game of your choice. Now, before you go play your Linux game, click 'Play' on this game in Steam. Steamstub will deliver a small popup, and to your Steam friends, it will look like you are playing a non-steam game until you click 'OK'. This lets you advertise what game you are playing, even when Steam can't launch it.

One more thing you may find interesting is a tool I developed called wino. It lets you keep track of multiple wine prefixes (virtual Windows environments), so you can keep your programs separated. This makes it easier to recover if something in your drive_c directory gets broken; you only have to worry about reinstalling at most one program. If you make heavy use of steam's 'non-Steam game' functionality, like I do, then this is not as useful for you. However, wino also does a lot of other useful things, like allow you to have a default command assigned to a wineprefix (so you could just run 'wino steam' to launch Steam.exe). It can also run winecfg (and a lot of other tools) on a prefix via 'wino prefixname --config'.