Why is GPU emulation so demanding? [Part 2: API Emulation / Wine]

Disclaimer: I am a former Wine developer, but I never really dealt with any of the lower-level stuff. Much of the Wine-related technical stuff I’m talking about here is just an educated guess which roughly gives a simplified explanation of what’s going on but should be taken with a grain of salt for anything else.

Another topic which was brought up in the thread which inspired this blog series was how Wine compares to Dolphin.

In case you don’t know, Wine (an acronym for Wine Is Not an Emulator) is a program collection which can be used to run many Microsoft Windows applications within Unix environments like Linux. However, Wine doesn’t need to emulate a whole PC to do this; instead it’s using a technique called “API emulation”. Instead of emulating the underlying hardware, the program binary code gets directly processed by the host but whenever a call to a Windows-specific function is going to be made, Wine doesn’t actually call that function but uses an own wrapper function which provides the same functionality like the original function but uses the underlying Unix APIs for the actual implementation. That’s why Wine is often called a compatibility layer. Read on for details.

In order to understand why what Wine is doing works, you’ll need to know some basics about how Windows program binaries usually look like. Basically, the program binary is just a bunch of x86/x64 machine code which per se isn’t operating system specific at all¹. However, what is OS specific are calls to functions stored in external system libraries, i.e. DLLs (Dynamic Link Libraries) or in Unix terminology SOs (Shared Objects). For example, kernel functions obviously are operating specific; but this also applies to libraries which strongly depend on the underlying system libraries (like Direct3D) and many libraries which just aren’t available on Unix platforms.

Now Wine uses some clever tricks to make Windows executables work on Unix anyway: It’s using means of static recompilation in order to produce an ELF executable (which can be run by any Unix-like operating system) from the Windows PE executable.This step is basically just a “format conversion”, just like you’d convert a PNG image to a JPEG image (.. just that it’s a lot harder and more technical). In that step it also takes care of the little quirks I mentioned above like calling convention.The resulting ELF image can basically be just run like any other Unix application.

It’s of course not quite as simple, Wine has to deal with a lot of other things, e.g. providing proper memory management to windows applications. That stuff is usually handled by the Windows kernel, which is not available on Unix platforms obviously. Instead, a separate process called wineserver  is started whenever Wine is run. It basically does all the work that would usually be done by the Windows kernel.

The point is, most Windows applications don’t depend on the underlying hardware they’re running on. Instead, they’re using the “abstraction layer” provided by the system libraries. That’s what allows Wine to run as efficiently and well as it does: It doesn’t need to emulate a complete set of computer hardware but just needs to recompile the Windows executable to an ELF binary and simulate a Windows environment. A nontrivial task for sure, but with very good results 😉

[1] Apart from stuff like calling convention and other quirks which can be taken care of by means of static recompilation without causing any major problems though.

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: