How Steam ports games in Linux

valve_linux

A few days ago in SIGGRAPH 12 conference, Valve explained how the Linux version of Left 4 Dead 2 outperforms Windows. Given a speech called “From 6 to 300 FPS” by Mr.Rich, Valve made clear that they don’t follow the proper programming design (writing the whole high level API from scratch) but following another (more inexpensive and faster) sensible approach (translating Direct3D into OpenGL on-the-fly).

In order to understand this article, it’s recommended to be familiar with basic programming terms. The definitions bellow are provided by Wildfire.

API (Application Programming Interface): Simply put, an API is an interface between your code, and someone else’s code and/or hardware. For example OpenGL is an API that lets you talk to graphics cards (or rather, their drivers). Thanks to this, you do not need to write specific code for each and every GPU out there. You write code against the OpenGL API, and the driver does the work of translating these calls to the underlying hardware.

An abstraction layer is a piece of code (e.g. an API) that “abstracts away” some of the complexity of another system by providing a simplified interface. You can think of OpenGL as an abstraction layer for graphics hardware, because OpenGL hides the actual hardware from you and provides a simplified, generic interface that can be used for any hardware that provides OpenGL compatible drivers. The downside is that you can only use features supported by OpenGL. That is, you can’t use vendor specific hardware features that aren’t supported by OpenGL.

In the context of this discussion dynamic translation means that calls to the Direct3D API are translated to OpenGL calls while the application is already running. The alternative would be to have some kind of offline-translator, that takes your source code and alters it before it is compiled (which is probably quite complex). Or you could rewrite your code by hand to support both Direct3D and OpenGL. Or you could write your own API which takes care of calling either.

Similar to an abstraction layer, a wrapper is used to either reduce complexity, or to provide a common interface for otherwise incompatible systems/interfaces/APIs. An abstraction layer is basically a collection of wrappers.

Game makers know very well that nowadays there’s more than one platform (Linux, Windows, Apple, PS3, XBox, Nintendo) and more than one API (DirectX, OpenGL, …) to do the same things (basically play games). If you want a game to be as platform independent as possible you’ll typically end up writing your own API (or abstraction layer) which “wraps” these APIs. Instead, Valve preferred another path called dynamic translation.

 

Valve’s design sucks

Any reasonable developer wraps the API in something else. In their case they didn’t wrap it correctly enough  so they could rewrite the implementation without rewriting the higher level API. Programming-wise, if you want to compile once and for all platforms,  using a preprocessor would be an ideal approach avoiding portability issues. Instead of that, Valve programmers are implementing a “translator” between Direct3D to OpenGL, which maybe incurs a performance penalty, more than doing it right in the first place.

In order to understand the concept of abstract classes (OOP) and how they could help the programmer to develop a cross-platform 3D application, take a look to this simple example:

Abstract Class example
void DrawSomething()
{
    #if defined(__Windows__)
        UseDirect3D();
    #elif defined(__Linux__)
        UseOpenGL();
    #elif defined(__APPLE__)
        UseOpenGL_APPLE();
    #endif
}

However Valve does not use abstract classes but something else they ‘d like to call – Direct3D dynamic translator — to do the dirty job copying D3D code and pasting OpenG on the fly while the game is running. Seriously, Linux 3D programmers were expecting a better design from Valve. If you have seen Irrlicht or OGRE renderer for example, you would have known that a renderer should be independent from Opengl or DirectX. Meaning that you need to write abstract classes and implement for OpenGL 2.0 or 3.0 or 4.0 or DirectX9 or DirectX 10 or DirectX11 and so on. If valve would have done so there would be no sense in translating DirectX calls to OpenGL. Sad but true, this kind of design is not what Linux programmers were expecting from Valve. Are they using any kind of OOP design at all? It just shows that sometimes even the “best” programmers mess it up.

All in all, using a thing called Direct3D translator means bad design and leads our thoughts to believe Steam was not meant to be a cross-platform app. No sir, you thought wrong, because back in 2003 there was an incedent with leaked Half-Life 2 code.  Notice that in Half-Life 2 source code Valve used a switch for Direct3D — OpenGL — Software. That been told, there is no way that Steam was meant to be just a single-platform (Windows) application. No mistake here.

So, if they knew from the beginning that Steam is meant to be a cross-platform app, why on earth they did such a bad design for OpenGL? Or, let me rephrase the question asking you why a Direct3D translator is the best choice for Steam portability? They answer is found in two words: “time” and “money” and Valve needs them both! Let analyze this theory a little bit…

Answering: Time and Money

So, they are making a translation layer as universal as it can get for their engine, because it would be universal for all Linux distributions and it will make extremely simple and fast to convert other Source engine titles to Linux.

BTW time n Greek translated into Χρόνος — likely Kronos is the name of the team behind OpenGL)

It’s common sense that “time equals money” and if Valve can port games in 6 months then what they actually care about is reducing the porting costs to very low levels. Thus making it even easier to achieve profits from Linux ports and SteamBox. One aspect that is quite interesting to see if Linux gamers will support Valve by purchasing games via Steam.

end-users perspective: You and Me

No matter if they are using a translation layer nor abstract classes or a preprocessor — they are achieving an impressive performance scoring 300 FPS. In my opinion this is a quite impressive performance for such a bad design, don’t you think? In addition, they said that they can squeeze easily 5 % more of speed from further optimization of that layer.

Following this approach Valve and Linux gamers are both happy, although Linux  3D programmers are being quite dissapointed from Valve’s design. As you can see today we are standing in front of the big picture drawing a Linux gaming revolution. Valve’s approach is just the first attempt.

 

SHARE THIS POST

  • Facebook
  • Twitter
  • Google Buzz
  • Reddit
  • Stumnleupon
  • Delicious
  • Digg
  • Technorati
  • Andrés Schwartz

    Yes, but I’m developer and I know that if you try to “save” time it is worst. You cannot do that programming. Instead, you will get more bugs in your program (and worst, you will get big bugs because you begin bad).

    It is not so hard to decide use only OpenGL and later use Direct3D and you will have already a good wrap API. I prefer to develop a good abstraction api independent of Direct3D, OpenGL, and so. Using for now only OpenGL does not will take a long time and will let you implement Direct3D faster the next time if you want.

    The answes is: Bad decisions from the Valve directors. Money and time, yes, but bad decision too. (I guess they like Direct3D and that is the answer, just a personal taste, not money exclusive).