Welcome to the second installment of our three-part Linux post-mortem. Part 1 lay the foundations for the article and where we’re coming from. Today’s post directly addresses the question “What worked and what didn’t?” with a set of ‘pros and cons’ that cropped up during the port. The final post will offer a more nuanced set of reflections on these experiences, their implications for game development, and my advice for moving Linux forward as a gaming platform.
Porting Osmos to Linux: What I Loved
Let’s start with an account of the stuff that stands out as having worked really well — things that were well designed, pleasant to use, and easy to learn.
Love: Live discs and bootable USBs
Being able to boot into an OS from USB without having to first install to the HD is fab, and the various Linux distros have for the most part done a good job of supporting this behaviour. During development, live discs were helpful in two main ways. Firstly, when I was starting out, they made it easy for me to poke around and find a distro to use as my ‘core’ Linux install (i.e. the install on which to do the bulk of my Linux development; I settled for Ubuntu 9.04). Secondly, live discs made it easier to do quick first-blush tests of cross-distro/DE/WM compatibility for my executables and packages without having to first fully install and configure every OS.
One wish for the live discs would be for the OS versions they contain to have more robust HW drivers, particularly for video. I realize drivers are a tricky issue in Linux and hard to support generically out-of-the-box, especially on a live OS (where, for example, rebooting to install a better driver isn’t in the cards), but for game development it would be great to have decent video performance when booting from a live disc.
I was looking for a simple, light-weight, easy-to-use C++ IDE that was easy to find in binary form for several distributions (I didn’t want to have to compile an IDE myself) and that had some kind of interface sitting on top of gdb. Code::Blocks was the answer. It wasn’t bug free, mind you, and crashed on me once or twice per day (at times to great frustration because of state loss… but nothing reliably reproducable, I’m afraid, hence no bug reports filed). But, critically, it provided a simple project system, a simple-yet-powerful set of compiler/linker options, the essential find/error/debug/bookmark interactions, and a basic gdb front-end. Essentially everything I needed was there, it was simple to use, and it was available and (relatively) stable cross-distro.
Love: The Linux Package Manager
Linux’s package system may not have been easy-breezy to support (more on this below), but it sure was easy-breezy to use. It was straightforward to find the developer libs/headers I needed and get them automatically installed into the right places. It was fantastic that dependencies are automatically tracked and installed, and that headers/libs install to central and standard places for trivial inclusion/linkage into the project.
Two footnotes: firstly, this smoothness of experience was conditioned in part by the legwork that went into ensuring Osmos relied only on the most core of libs (libs/packages that ought to play nice and be easily found on any distro; GL/GLX, X11, FreeType, OpenAL, libogg/libvorbis, etc). Secondly, a couple of the enterprise-oriented distros seemed to require a prohibitive amount of leg-work to configure for engineering purposes; this makes sense if the distro is targeted towards the consumer/office end of the market spectrum rather than the engineer, but for someone new to development on Linux, it’s painful if you don’t do your homework ahead of time.
Love: Support from the Linux Community and our Beta-Testers
It’s great to see how keen Linux users are to help support software on Linux. The average Linux user is on-the-ball and really encouraging in terms of their enthusiasm for Linux and their appreciation of our efforts to get Osmos on Linux. Post-launch, we’ve been getting great feedback and PR support from a few key folks in particular.
When the Linux port went into beta I issued a public call for testers and recruited about 50 people. Each one was top-notch in terms of being observant while playing the game. They were all helpful with their detective work, and the average level of technical savy-ness was very high when it came to sniffing out audio and WM/X issues for repro. Folks were keen to try the game on as many machine specs as they could, and were keen to volunteer information and “run with” the testing on their own. All this resulted in a very short beta period (less than two weeks) in which a lot of solid testing occurred very quickly, and with only a single patch being required to hammer out all known issues.
Love: Cross-Platform Compatibility is Good for your Code
While not a Linux-specific observation, there’s no doubt that developing multiplatform software is always beneficial for the code. Each platform has different analysis tools, compilers that issue different warnings and generate different code, and video drivers with different behaviour; all of these serve to highlight any underlying issues in your project, and so the work invested on one platform has benefits for the other platforms too. For the sake quality and stability, cross-platform compatibility has been a good thing for Osmos.
What I Didn’t Love
Let’s move on to the stuff that was less easy to love; things that stood out as being frustrating, difficult to use, and in some cases broken.
Didn’t Love: Supporting multiple Distros/DEs/WMs/drivers/etc.
The #1 obstacle to getting more games on Linux is that it’s very difficult to get your game working correctly and acceptably on all machines. It’s really hard to guarantee a smooth experience for all players when there’s a combinatorial explosion of possible distributions, desktop environments, window managers, driver/hardware versions — each with their own unique foibles, bugs, and undocumented behaviours. It’s the classic PC gaming problem, but magnified. Linux loves freedom and choice, which I applaud — but some amount of standardization, collaboration and “Let’s work together”-ness is required for the platform to be friendly to application developers.
Didn’t Love: Audio
Brace yourselves, folks, because I’m going to put it bluntly: audio in Linux is a mess. The audio situation is another major obstacle to game development on Linux. It’s 2010; audio is a solved problem. And yet on Linux, it’s shocking that you cannot count on something as simple as non-streaming playback, never mind any kind of processing (which most games are wont to do!) There are a variety of standards (ALSA, OSS, PulseAudio, Phonon, …) — which one to choose? Each standard has different problems on different machines. For a given standard, some drivers are buggy and poorly configured by default, while others do horrible thinks like block on open when another process opened the device. This is all another way of saying that there are no audio standards. What is a developer to do?
“But doesn’t OpenAL hide all the mess behind a single stable API? Ideally you’d write the audio code once in OpenAL and then walk away.” This isn’t how it happens in practice, because the fact of the matter is that the mess is still there. Simply wrapping another software layer around the underlying problem doesn’t make it go away. Using OpenAL for audio doesn’t all-of-a-sudden mean I can count on anything runtime-behavior-wise. I write my code in OpenAL (rather than having to write directly in ALSA, PulseAudio, etc), but at runtime I still need to make choices — for example, by saying which underlying audio layer I want to use — and different people’s machine/lib/driver combos will do different things. Simply using the local machine’s default audio device doesn’t guarantee anything about what’s going to work and what doesn’t, and a game needs guarantees in order to work correctly. The audio situation is quite horrible I’m afraid.
Didn’t Love: Lack of Documentation and Consensus
In the Linux world there is so much choice and non-standardization, and it’s really hard to find out about things. Documentation is sorely lacking, and it’s hard to find solutions because when a question is asked, people don’t agree on the answer. Forum threads aren’t a good substitute for proper documentation, because forum threads can quickly become historical and fall out of date, meaning folks looking for answers spend a lot of time chasing down false-leads and asking themselves “Is this forum thread relevant to me? Is it really what I’m looking for?” In the Linux world, it seems to take a great deal of detective work and reverse engineering to get things done; the plethora of choice means that the newcomer is never certain about their choices — and there will always be someone who disagrees with you (often vocally).
Didn’t Love: Drivers and Hardware Support
My main development machines are two off-the-shelf laptops with mainstream components, and neither of them had WiFi or video that worked out-of-the-box on any distribution I installed. It took many hours to get decent hardware performance. Proprietary drivers, open source drivers… which do I chose? Do I really have to compile a driver for myself? What’s more, when a new Linux user inquires about driver problems on a forum, the standard line of defense is to blame the problems on hardware manufacturers. Whether or not the manufacturers deserve blame, the Linux platform folks need to step up, acknowledge the reality of the situation, and try to work to improve the platform. The chipsets that didn’t work for me (without great effort) were nowhere close to bleeding edge (ATI and Intel graphics, Broadcom Wifi; some models dating back to 2007) and all are widely available on a large segment of the consumer-level market. Linux needs better support for its HW; if I can’t walk into BestBuy, pick up a run-of-the-mill laptop and have my video and networking hardware work, then the platform is troubled.
Didn’t Love: Packaging the Game
It took days of effort to create the binary packages for Osmos (I’m happy to say that it’s looking like we don’t have to patch!) How should an app be packaged in Linux? Should I build my own libs and package them with my game, or rely on package dependency info and hope the distros have the right versions in their package repositories? Which package formats do I choose (.deb, .rpm, .tar.gz, others)? Do any of the package formats have naming conventions I need to follow? What do you need to do to support both 32bit and 64bit? What are the standard practices for where/how my game is layed out on the filesystem? What goes where and where do you commonly put softlinks? How do I represent softlinks in the various package systems? Do architecture-specific files belong in special places? Are there any standards for what’s in the environment path? How do I integrate my app into the desktop environment? What DEs are worth supporting? Do I need to do separate things to support separate DEs?
There are no standards or clear answers to any of these questions. There’s no documentation for this stuff! Asking on the forums will typically net you a spectrum of answers with no consensus answer and lots of little side arguments. I basically reverse engineered what I saw other apps doing (which sadly was of little comfort because everyone does it differently). I settled on supporting .deb/.rpm/.tar.gz with explicit 32bit and 64bit executables for both the demo and retail versions of Osmos, with no redistributed libs and instead relying on package dependency info. So far, this has worked out for nearly all distros except CentOS which has an archaic version of libvorbis and nothing new in the standard repositories.
Side-note for those interested: I didn’t venture anywhere near cross-compilation and instead simply built the 32bit and 64bit executables on separate 32bit and 64bit Ubuntu installs (which, interestingly enough, both displayed unique and undocumented WM/Xserver interactions, despite being the same version of Ubuntu!)
Didn’t Love: No OS-level GUI layer for simple dialogs
This is something of a minor point compared to the above, but I want to mention it because it comes up often enough in cross-platform development. Because Linux has no OS-level GUI layer, games that need any kind of UI must link against heavy-weight UI libraries (GTK, QT, etc) which typically impose some kind of application framework. Common examples of the usage of UI in the gaming world would be a dialog that prompts the user for input the first time a game is run (e.g. “Launch in fullscreen?”) or that displays a message when an app terminates unexpectedly. For Osmos, I had to cut such user-friendly elements because I didn’t want the game to have any but the most basic of dependencies.
Whew! Alright: in part 3, I’m going present a more general discussion of the implications of some of these issues for game developers, and reflect on ways to improve matters. Stay tuned…