Sunday, August 29, 2010

Setting up an OpenGL ES 2.0 dev environment for Android (The horror!)

It is a well known phenomenon that if you give a software developer (a REAL developer) any device which contains a CPU (and even a great many that don't) you will also install in them a great and uncontrollable urge to put their own programs on the damn thing. This urge cannot be satisfied by any old "Hello World" app either, oh no. It has to be something significant. Something that uses the device in a non-trivial way. Something that makes your peers say "Woah!" (The "Woah" factor is incredibly important, ask anyone.)

As such, being a developer and recently coming to posses a shiny new smartphone I've been dying to do some code for it for a while now. Finishing up some of my WebGL stuff and keeping up with my normal work (you know, the one that actually pays me) has prevented me from acting on it so far, and I still may not get a chance to code for it for a little while, but I finally had enough time lately to sit down and actually set up the SDK and play with some of the examples.

Now, I have a history of managing to choose the absolute worst case scenario as my first attempt at any platform I develop for. One of my very first large-scale .NET apps had me writing dynamic MSIL injection to create arbitrary event signatures, which is a really harsh way to introduce yourself to the language, let me assure you! In this case, hearing that Android can run OpenGL ES 2.0 was quite exciting to me, especially since that's essentially what WebGL is anyway so in theory it shouldn't be a huge change in direction. Thus being the graphics geek that I am that was my first target. (After shouting my salutations to the world, of course. Tradition!) This turned out to be a Bad Idea of epic proportions.

I was able to get the OpenGL sample app (a couple of spinning cubes) up and running on the emulator immediately, so it all seemed to be going well. Looking at the code, however, I realized that the sample was using ES 1.0, which was less-than-desirable. Why would I want to trudge through fixed function madness when I have a fully programmable GPU at my disposal? So I set out to find an ES 2.0 example.

I found it. Yes, that's a link to the NDK (Native Development Kit). Turns out that ES 2.0 is only accessible via JNI and C code. That's a bit of an annoyance, but in many ways it makes sense. Java isn't really designed for things like high performance graphics, and I actually prefer writing native code anyway so a little bit of Java/C interfacing wasn't a huge turn off. So I downloaded the NDK, got it set up, and tried to build the program... and found out that the native bits need to be compiled separately. In cygwin. *sigh*

Note for aspiring developers: Make sure you click the checkbox for the "make" package when installing cygwin. It'll save you time and grief. Trust me!

Okay, so now cygwin is installed, the native bit is built, I can link it to the Java project, and launch it on the emulator... all's well, right? Not exactly. You see, I use the word "launch" loosely because while the app does start up it crashes within moments without ever showing anything on screen besides a nasty error message. Poo. Only after much toy around with settings trying to get this to work do I discover that the emulator that you use for debugging doesn't support OpenGL ES 2.0. Absolutely fantastic. This means that in order to develop against that API I need to constantly be deploying unstable code to my phone. Color me thrilled. That fixed function madness is starting to look really attractive about now...

In any case, that means I have to be able to actually push developed apps to my phone, which I hadn't done yet. The method for doing this is via a simple little command line app called ADB. You call adb install app/path to push your freshly built app out to your phone via USB, easy-peasy. Well, except when it starts yelling that there's no phone attached. (Of course there is silly computer! See! The cable is right here!) So a couple of things need to happen in order for ADB to "see" the phone:
  1. The phone needs to be set to allow debugging (settings->Applications->Development->USB Debugging)
  2. The phone needs to be set to "Charge Only" mode when connected, which I found slightly counter intuitive. (This may be Droid X specific. I've heard conflicting stories online)
  3. You need the appropriate ADB driver installed.
Item three seems obvious, and in fact the first time you plug your phone in there's a whole slew of drivers installed. With my X, however, it was complaining that it couldn't find the right ADB driver. Fortunately the driver you need is included with the SDK if your phone doesn't install it automagically. (/usb_driver) Unfortunately when I attempted to point my device manager to this driver manually it just shrugged and told me it couldn't find anything. So... back to the forums I go in search of help.

As it turns out there's an issue with Motorola's phones and the SDK drivers under Windows 7 64 bit (take a wild guess what I'm running!) that requires you to dive into the .inf and replace some device ID's manually. For me, I ended up needing to change the Motorola device ID's from this:

;Moto Sholes
%SingleAdbInterface%        = USB_Install, USB\VID_22B8&PID_41DB
%CompositeAdbInterface%     = USB_Install, USB\VID_22B8&PID_41DB&MI_01

to this:

;Moto Sholes
%SingleAdbInterface%        = USB_Install, USB\VID_22B8&PID_428C&REV_0216&MI_01
%CompositeAdbInterface%     = USB_Install, USB\VID_22B8&PID_428C&MI_01

Your mileage my vary.

So now, after much pain and suffering (this whole process spanned several days of random poking) I was finally able to send my ES 2.0 sample app to my phone and see it running for the first time! YAY! The reward for my perseverance? An ugly green triangle against a pulsing grayscale background. Hm... ever-so-slightly-less-than-impressive. But it's a start, and now that I've got all this garbage sorted out I should be able to make some actual headway developing something cool. Something with a good "Woah" factor. :)

I have come away from this experience with a couple of thoughts: Primarily that if Google EVER wants to compete with Apple in the mobile gaming market this process
absolutely must to get better! Granted, many of the driver issues and whatnot were just bad configuration for my phone (and I seriously doubt Motorola cares about developers working with their phones in the slightest) but the very idea that I have to deploy my code to my phone with every change just to run the thing is appalling. Yes, you will probably get some very motivated people that do a few cool tech demos with it but many serious development studios are going to balk.

Second: This entire process feels so incredibly... Linux-ish. I know, I know, that's what the thing is built on so of course some of it is going to shine through, but the entire snobbish "if you can't figure out how to set up a make file by hand then you're obviously not worthy to develop for our OS" attitude is something that we don't want to inherit! Even the hardcore amongst us appreciate a good drag and drop UI builder sooner or later. After playing around with the Android SDK/NDK it's increasingly difficult to ignore the siren's song of Apple's nicely packaged development environment. (I mean, come on? Xcode vs Eclipse and cygwin? Is that even a contest?)

Still, I don't have an iOS device, and even if I did I don't have a Mac to develop with (not for lack of wanting...) In the end I'm going to develop against what I've got, no matter how painful the process might be. But I'm a hobby developer with a limited budget, those excuses don't apply to big publishers and that's where platforms like this are really built or buried. There's a lot of potential here, I'd hate to see it passed by because of some crummy development tools.

Oh, and since this is a post about my phone: MotoBlur still bites. And no, I'm not going to let that one go.