Fashionably Late: On Bringing Vessel to Mac

Critically-acclaimed puzzle-platformer Vessel is coming to Mac. The Mac version was originally planned to be launched in time for the Humble Indie Bundle 6 back in September, but problems porting the game caused this to slip, even prompting Humble Bundle themselves to issue an apology over the delay. We spoke to developer Ethan Lee, tasked with porting the game (along with several others) to Mac and Linux, about the technicalities, trials and tribulations of bringing games to the Mac, and pitfalls for developers to avoid.

Why was the decision made to port Vessel to Mac?

Well, I got this port via Humble Bundle, so I suppose the primary reason the port came about was because of that. However, they likely had the intention of making a port before this came up, as the engine was very clearly built as a cross-platform engine, even though they were only building for consoles and Windows originally.

Was any sort of market research carried out beforehand, to assess the viability of making the Mac version?

I’m actually not sure. For most of my clients it was never really about the numbers as much as “can we just get the port in some way?” Game developers, particularly independent developers, are happy to have people playing their games, regardless of platform and said platform’s market share. Whether Mac/Linux support is genuinely worthwhile according to the numbers or not hasn’t come up in my work quite yet… though I’ve not been in this line of work long enough to know if it’s still prominent amongst independent developers.

Vessel

Just how long has the Mac port taken?

I started full-time port work in early August and ended up shipping them in December/January. It took WAY longer than it was supposed to… we figured it was a slam-dunk port that would take a couple of months at the very most to get 100% solid and done, so it was put in HIB6 in September. Quite a ways off from December!

How difficult was it to convert DirectX code to openGL?

This is where it got really ugly really fast… right around the time that I started porting the graphics backend, I got suddenly put into Ultra Crunch Mode (TM), so when doing the D3D->GL port I attempted to do an LLE-ish port of what Direct3D was doing… with pretty disastrous results.

To help speed up the port, Ryan Gordon came in and wrote the GL renderer with a much, MUCH better system than I had. It works pretty much exactly like the Direct3D device, and then we take care of all the behavioral differences in separate code. This is really the way you should be porting platform-specific graphics code, I think.

Translating the code isn’t really that hard, though. What is difficult is getting the two rendering backends to genuinely behave in the same way. Some of it can be really obvious, like “hey, Direct3D is dumb and flips the Y-axis in a few places, I need to flip these for GL,” but when you get to the end you start debugging completely insane things. The last rendering bug that I fixed in Vessel involved most of the lighting flickering. The fix was to force-update the mag filter for all the sampler states when flushing the OpenGL state, rather than checking to see if it’s changed since the last update. I still have no clue why this is needed, but it works.

Two things that made it really easy were a couple libraries Ryan developed, MojoDDS and MojoShader. MojoDDS is a C file that lets us easily load DDS texture files into OpenGL, and MojoShader takes compiled D3D shaders and recompiles them into OpenGL shaders (with various shader profiles to accommodate as many cards/drivers as possible). Not only does this simplify a lot of the port work, but it means we can retain content compatibility with the Windows version. My ideal port is one that shares 100% of the content with the original game.

Early Mac build of Vessel

What was the most time-consuming/challenging part of the port?

Debugging, I guess. Porting code isn’t really that hard, but identifying the errors (particularly those caused by subtle behavioral differences in libraries on different platforms) can get difficult fast. Sure, sometimes you’ll get those really obvious segmentation faults that Windows somehow lets by in its memory management, but then you come across something that is genuinely unfixable, and that can leave you really depressed when you know you’re going to have to ship with that bug.

One that I feel is worth mentioning was a bug we had in FMOD: whenever you tried to adjust category gains, the FMOD library would just segfault. It was totally fine on Windows, but it just flat-out would not work on Linux or Mac. I actually found a solution for Linux, which was to use a totally different version, regardless of content compatibility! It was totally “incorrect”, but it worked and I actually shipped with it in v1.0. I couldn’t figure out a similar fix for Mac though, so eventually I contacted Firelight Technologies and they actually went to the trouble of getting me a custom build of that FMOD version to use for Vessel. That was pretty rad of them, I must say, but stuff like that can make you panic, especially if you don’t quite have the ability to get a massive company’s attention like I did.

Do you make use of any Cocoa libraries to help in any way?

I suppose SDL does, but I’ve never written any OSX-specific code. I’m very insistent on 100% portable code, so that would kind of get in the way.

To tell you the truth, I actually develop mostly on Linux, with the expectation that my code will just work on OSX. Generally this is the case; occasionally I’ll come across some odd OSX-specific issues like Apple not supporting ARB_draw_instanced in Snow Leopard, but most of the time I can trust that my code will work everywhere.

That’s not to say that I’m not a fan of Mac OS in general, though! I recently got a new Macbook, that retina display is something else, man.

Vessel

Would taking the Mac version and making an iOS version from it be feasible, or would you mostly have to start over?

If I used SDL2 I guess this could be the case, but I’d be more concerned with having your game’s design work on iOS first. Not just “oh, this game would suck on a phone,” but you really would have to change a number of things to get it to work appropriately on the iPhone/iPad (input is the obvious example, GLES2 support is a slightly less-thought-about example). You could probably work with the Mac version to make an iOS version, but the two platforms are just totally different types of… er, computers. It’s a design problem, rather than a technical problem.

Is having to sandbox the game a big deal?

I’ll do this to be sure that it boots on a vanilla installation, but generally I’ll test on whatever I’ve got handy. Doing actual testing in a sandbox isn’t testing, in my opinion. It’s like learning to vacuum in one of those clean rooms where hard drives are manufactured/repaired in. Find the most bizarre, Frankenstein-y computers you possibly can and throw the game in there.

Does the variety of graphics hardware available on different Macs lead to compatibility issues?

Apple hardware support is generally consistent, though I will say, Apple’s OpenGL support isn’t exactly stellar compared to Windows and Linux. Not just in terms of “oh, Lion/Mountain Lion only supports GL 3.2,” but Apple’s OpenGL drivers really do need quite a bit more attention compared to the others. GLSL support in particular requires bracing yourself for silly errors. It’s not bad, but stuff you can compile on other drivers gets totally rejected by the Apple GLSL compiler (small example: initializing uniform values in the shader source).

Is getting good performance a challenge?

Generally no, but Vessel was actually one instance where the performance took a massive hit. Vessel, since it used Direct3D, was actually able to run the renderer from two threads (one during loading and one during the actual game), and lots of D3D calls were coming from several other threads, which fails horrendously in OpenGL. Technically both APIs should fail when used in multiple threads, but you can actually get away with it in D3D. This sounds good when you need to ship a game ASAP, but it will come back to haunt you later.

Vessel shipped as a single-threaded game for Mac/Linux, so it currently runs a bit slow for a lot of people. Strange Loop are handling this internally, since they know their engine a lot better than I do.

Does Apple provide enough support to developers wanting to bring their game to the Mac?

They have great documentation, but when it comes to one-on-one support, I don’t know how I could really criticize them. I tend to think of it as “an ant shouting angrily at Godzilla.” I mean, what do you expect? I actually did get an Apple developer’s attention after a Reddit post, but again, what about the guys who don’t have that kind of community support?

What could they be doing better?

I think a well-maintained development community with Apple guys on the front lines could go a long way. They do have some mailing lists, but for a lot of amateur developers this can be sort of intimidating (especially younger people, who may not even know what a mailing list is). For some reason forums are just less frightening to people, as far as my non-research has seen.

Vessel

The Mac version will be available on Steam, but not on the Mac App Store. Do the additional restrictions that Apple places on App Store submissions simply not justify doing an App Store-compatible version?

You know, I’ve never really thought about the Mac App Store. I tend to lean towards stores that are cross-platform as well. I can’t really give an educated opinion about the App Store; I don’t even use it myself unless it just provides an updated build of a cross-platform app (XChat, for example).

You might expect this to be because I lean towards Linux anyway, but I don’t even like the Ubuntu Software Center that much, either. I usually just work with Steam and the Humble Store. A part of me wants to work with Desura, but the only thing keeping me looking is work on the Desurium client (Mac users: if you’re looking for Desura’s Mac support, I suggest helping the Desurium team out).

Of course, all of this is just my opinion. If Strange Loop wanted to put it up on the App Store, I don’t think I would object to it.

Are you able to determine how many people actually play the Mac versions of games rather than Windows ones?

I think you can grab stats from Steam, but I’ve never looked at the numbers closely. I’ve occasionally gotten sales numbers back, but I don’t think about it very much. There are Mac users, they play games, sometimes they’re games I worked on. Neato!

Was there a degree of overlap between doing the Mac and Linux versions, or were they treated as individual ports?

All of my ports are designed as cross-platform applications. The goal is always, always 100% overlap. This doesn’t always happen, of course, but as a cross-platform porter, I’d just feel wrong to take any other approach to my job.

Most of the time I will port to one platform, then get it verified and working on the other in a weekend. That gap gets bigger as the other platform’s list of needs gets longer, but yeah.

Is there anything you would do differently next time?

Trying to enforce a strict policy of not even considering my work for promotions of any kind until they are gold. It was very pleasant to see that customers (as well as my client) were patient for Vessel’s release, but 3 months after the bundle launched? That’s just unacceptable and plain embarrassing for me personally, regardless of the port’s stability at 1.0. I’m sure it was a nightmare for Humble Bundle Inc. as well.

I also think that finding a way to open up my development to customers is needed. I’ve always done this with with all of my projects (but obviously this can’t be done with [projects under NDA]). On the other hand, customer support was WAY better once I was able to talk about Vessel as I was porting it. Quite the conundrum.

And finally, would you recommend that other developers consider making their games Mac-compatible?

As far as I’m concerned, you should be ready to build that sucker for Haiku. Seriously.

Use cross-platform apps and libraries for everything. Compile it everywhere, with various compilers. Use CMake for your project files. Use static analysis, Valgrind, and every code quality tool you can possibly find. I assume your readers are developing on a Mac, right? You, reader! Go grab the Clang Static Analyzer! Be horrified at what it finds!

Thanks for your time.

You can read more on the Vessel port on Ethan’s site, and in this Reddit thread. Vessel will be available for Mac soon.

Your thoughts on this?