Curious about Native Client? Google's new technology allows native C/C++ code to be run in a web browser -- which is great -- but what are the practical issues around getting a game to run with it? What are the practical pitfalls and drawbacks? Developer Jeff Ward, who's shipped an NaCl game, explains.
The NaCl environment also provides access to tech already available in the browser, including access to the HTML 5 file system, WebGL using an OpenGL ES 2.0 interface, as well as other browser specific APIs.
What NaCl means for you is that you can finally take your C / C++ game engine, libraries and middleware and ship it directly to users on the web, without the user having to install a plugin. NaCl runs on anything Chrome runs on (note: mobile Chrome is excluded for the moment).
Fire Hose's title, Go Home Dinosaurs, is in beta on Chrome Web Store right now, and is using multiple open source libraries that already have NaCl support, including OGRE and Mono. We were even able to bring over our own custom sound engine from our previous game without too many code changes.
Native Client is now automatically available as part of Chrome, and enabled for any games that ship on Chrome Web Store. Most importantly, for the first time your web delivered game can utilize the full power of the CPU and GPU, as if it were running as a native application, on Mac, Windows and Linux.
This doesn't mean porting to Native Client is a completely painless process. I've got a few massive "gotchas" and some tips to get you started.
Getting started with Native Client is fairly easy, and starts at Google's home for everything NaCl, www.gonacl.com. Here you can download the SDK updater, and from there, the SDK of your choice.
SDKs for NaCl roughly line up with versions of Chrome. If you type naclsdk list, you'll see a list of the SDK versions available and roughly where they are in development. SDKs that are listed as beta or development usually line up with beta and development channels of Chrome, while versions listed as stable are part of stable, released versions of Chrome.
Unless you plan on releasing very soon, I almost always recommend going with the most recent version of the SDK.
From there, you'll want to compile and run the samples, following Google's getting started tutorial. The samples use MAKE almost across the board, but for the most part so long as you can replace the compiler with the SDK's provided compilers, you can use the tool of your choice (FH uses a python based build system called waf, for example, and a Visual Studio 2010 plugin will ship with the Pepper 22 SDK.)
Assuming you're still with me, you've probably gotten things up and running, and I don't want to bore you with what Google has already provided. Instead, I'll give you some tips for working with NaCl that we've put into practice and have worked fairly well.
NaCl and Pepper
First, a quick note about terminology:
Native Client (NaCl) is a piece of technology that runs native code securely in the browser, though it possible (with the help of some tools provided in the SDK) to run NaCl binaries outside the browser, using utilities provided in the SDK. However, these stand-alone loaders don't provide methods for doing things like rendering to the screen.
This is where Pepper comes in. Pepper is a plugin API for Chrome, and it gives NaCl applications access to the lower level resource provided by the browser, such as file I/O and rendering. Specifically, NaCl applications must target the Pepper API (PPAPI) in order to interact with the underlying system.
You can learn about Native Client runs and how it interacts with the browser by looking at Google's official documentation.
Three Major "Gotchas"
There are three major things you need to be aware of when working with Native Client.
First, NaCl currently has a restriction that any system calls must occur on the "main" or "Pepper" thread. This is a temporary restriction, and should be resolved in a future SDK release, but for now it's something you have to keep in mind. System calls include all OpenGL calls, all file operation calls, all calls to perform browser operations and all calls to fetch URLs. In addition, these system calls cannot block the Pepper thread. The Pepper API does a fairly good job of not letting these calls block, but it does mean you have to write some functions to receive callbacks when things like File I/O are complete.
To prevent blocking the main thread, it's common for applications to spawn a new thread for performing logic, making that the "main" thread and pushing all system calls to the main thread in such a way that they appear to be blocking calls. There's a listing for how to do this later in the article.
Secondly, file I/O is a bit different than you might expect. All file I/O goes through Pepper's URL api, but depending on whether you're considering doing a hosted application versus a packaged application, this can affect how and when you want to load content. In hosted applications all of your file I/O is going to go through web requests, and will be dependent on Chrome's default caching systems unless you tell it otherwise. This means you have to spend a good amount of time making sure your assets are (at least) well optimized and hopefully packaged for easy deployment both to your host and to your user.
We ended up splitting our assets into several zip files which were downloaded in priority order, so the initial levels would load quickly, without waiting for many more assets.
Lastly, Native Client uses OpenGL ES2 for rendering. This isn't a big deal for those people that already have a GLES2 renderer for their mobile games, but if your engine is heavily based on DirectX, you might have a problem. One good resource is the OpenGL ES 2.0 Programming Guide, also known as the GLES2 Blue Book.