TheStateOfGGEZ2019

ggez is a lightweight portable game framework in Rust, inspired by LÖVE. I do most of the actual maintenance and planning behind it, and I’ve been sort of in and out of contact this year, so I thought I’d write up a little thing about the present and future of the project. I remembered that at the beginning of last year I wrote GgezOnWasm, but only remembered a little of what went into it, so I went back and read it. And then got hives from the stress of all the promises I’ve made. So, I feel justified in being a bit slow with working on ggez lately.

Life

First off, I’ve made less progress on ggez than I’d like. A lot of that is life related: I quit my job as an engineer at a university lab, because the treadmill of higher academia is terrible even when I’m just trying to run parallel to it. Depression doesn’t help either, even when treated fairly effectively. So here I am. After a brief, painful stint contracting in the web dev world I’ve settled in to work for an awesome robotics start up… And have just been notified that they don’t have money to keep me full time and probably won’t get investment until summer. I love working with them and will keep doing so in the future, but it there’s going to be a bit of a gap, so, if you know of anyone hiring, take a look at my resume. :-p Or at least donate to my Patreon.

Anyway, all of this has naturally slowed down my motivation for working on ggez, and I apologize to anyone who has been eagerly waiting. The purpose of this post is to bring everyone up to speed on what the current state is.

Webassembly

Welp, ggez still doesn’t build on webassembly, quite, but the list of dependencies that need handling is actually pretty short. The only real blocker is winit support, which is in progress, but also a bit of a tar pit. Basically, the problem is that you can’t actually do a polling event loop in a browser without freezing the browser, because Javascript is single-threaded and runs in the browser’s main rendering thread. This is dumb, and we haven’t been able to improve this in the last twenty-three years. Gods the Web is such a shit-show. Anyway, making winit work nicely in such an environment as well as a normal desktop-ish environment where you actually have control over your program will take some serious API hoop-jumping, from the looks of it, and the more it drags out the less I am convinced it is worth it.

It’s okay winit, I forgive you. Just force us to use a separate, slightly different API as a special case for webassembly, guys. It’s a bit of a pain, but I’d far rather do that than have nothing at all, or have a shoehorned-together API that is super complicated and/or sub-par at everything.

Of course, just because a dependency builds on a particular platform doesn’t mean it will actually work, but that’s another problem… Making WebGL function reliably is probably going to be a huge headache as well, ’cause I’m sure there are many minor, subtle differences between it and normal OpenGL, but I’m going to defer that problem off to the gfx-rs people for a while longer. I expect rodio and gilrs to have similar issues, though they’re more easily disabled or otherwise worked around, and in general less complicated than graphics. Once everything builds, making it actually work properly can be handled incrementally.

Still, that’s a lot better than I expected, actually.

Mobile

To my surprise, several people have asked recently whether ggez works on mobile with the new release. I don’t really do any mobile dev so it’s not much on my radar, and I didn’t actually know the answer! So after much hullabaloo trying to get the right Android NDK installed and trying to build ggez, I can say: I cannot currently get it to work. We are probably quite close though! There are some dependencies such as zip and rodio that vendor C libraries along with them, but those can all be feature’d out without much trouble. The real problem is getting a working toolchain in the first place, since all the docs I can find for it are years out of date, the published version of cargo-apk is old and does not correctly build some of ggez’s dependencies that use newer Cargo features, and the version of cargo-apk currently in git gives me mysterious errors. Thus, the main result of my Android build attempts is generally it frustrates the heck out of me trying to even make a Rust Hello World run on Android. So if any brave soul actually knows how to build Rust programs for Android, and can troubleshoot the process, get in touch with me and we can nail this mess down! It’s probably easiest if conversation happens on the ggez issue tracker. Fixing this bug in cargo-apk might also make life a lot easier.

On the topic of The Other Phone, I want to offer a shout-out to Sev for going through heroic efforts last fall trying to make ggez work on iOS. It was a mighty task and while the attempt was a failure, it was a valiant one. As I recall, Sev introduced himself to me by saying “well I don’t really know anything about low-level graphics or stuff, but…”, and two weeks later he was starting things conversations with “ok I’ve built a modified fork of ggez and gfx-rs…”. Many problems were discovered, explored, and at least somewhat fixed. Like Android, ggez is close to working on iOS, but some of the system interface libraries don’t work properly. Like Android, working that out should hopefully not be too difficult for someone with knowledge of the arcane arts of Rust+iOS development.

One thing that DOES work is there is now a built-in option to make ggez use OpenGL ES 3.0 for graphics, which should greatly simplify things. There are now no fundamental blockers that I am aware of for operating on iOS or Android, no technical decisions that rule out making ggez run on mobile. It’s just a matter of elbow grease to put all the pieces together. Judging from the demand I’ve heard for it, it’s something we should take more seriously.

(Side note: OpenGL ES 2.0 support probably won’t happen, since ggez uses instanced drawing everywhere and afaik ES 2 doesn’t support this. One might be able to hack around this with some cleverness, and despite not knowing much about ES 2 I will happily help the efforts of any brave souls who attempts it. It’s unfortunate to leave this out since there’s so much ES 2 hardware out there that will probably never support ES 3. For instance, Raspberry Pi only supports ES 2. Eventually ES 2 will just become so obsolete no new devices will be built that don’t use ES 3, but that it will probably take a long time.)

Summary: If you want to help get ggez working on mobile, try building it, figure out how to fix the problems, and write down a how-to for making it work nicely. Details for the specific state of both Android and iOS are on in ggez issue tracker.

ggez 0.5

Anyway! ggez 0.5 is Mostly Done. It’s basically down to updating docs, improving some examples, fixing some bugs, and mopping up a bunch of inconvenient little corner cases. Oh, and updating the website. Which isn’t to say that this process will be fast or easy, just that most of the critical stuff is there and works.

So what does this mean, exactly? The changelog is big and a bit messy and probably somewhat incomplete by now, so here’s the low and skinny:

  • Huzzah, ggez is now Pure Rust! …mostly. There’s a couple caveats: Some libraries, such as zip and rodio, have features that optionally depend on C code, namely bz2 and minimp3 respectively. Those are easy to disable though. And if anyone wants to write (well, clean up) a pure Rust MP3 decoder, there’s a good place for you to start available. However, giving up SDL2 also has some down sides…
  • Controller support now uses the gilrs crate, and the gilrs crate doesn’t work on all platforms yet. The main omission is OSX, you can see the full list here. In the short term I’m fine with this because adding more platforms to the list shouldn’t change anything about ggez itself, but in the long term this is kind of a big problem! I do not have a Mac, so I can’t add this! Someone needs to step up and make it work, I would hope it shouldn’t be too hard to just translate sdl2’s code to Rust.
  • The API has had a good clean-up. It is now a bit more Rust-y, some old awkward parts have been removed, and some parts are a bit refactored and reorganized. All text drawing is now cached and batched. Meshes can now be textured, and building them from raw vertices is nicer. Stuff like that.
  • As part of the API cleanup, ggez no longer uses nalgebra in the exposed API. Instead it uses mint, a library specifically for making a common set of vector math types, and this sort of task is exactly what it’s designed for. Instead of taking ggez functions taking nalgebra::Point2<f32> or whatever as arguments, all functions that need a Point2 of some kind now take Into<mint::Point2<f32>>. This means you can feed ggez nalgebra types, cgmath types, or whatever math library you feel like using, as long as the types for it implement Into<mint::Whatever>. You will probably have to activate the mint feature for nalgebra or cgmath, and there’s technically some minor speed overhead to this, but in practice I’ve found it really nice to use.

This doesn’t look like it’s actually a lot of changes, does it? It’s been heckin’ huge.

However, all worth it! I am, in general, really happy with ggez’s API and capabilities. Heck, I was pretty happy with it last version, and now a lot of the slightly rougher bits have been nicely smoothed out. If the 0.6 release works out well then I think we’ll be pretty darn close to calling it 1.0. Speaking of which…

Next step: gfx-hal

So, gfx-hal has been released! To get why this is exciting, we need a bit of nerd-history…

Basically, gfx-rs started as an attempt to make a Rust library that could present a nice, low-level, low-cost drawing API for any graphics backend. You could write graphics code and it would talk to the GPU via OpenGL on Linux, DirectX on Windows, Metal on OSX, whatever. It started in 2013, pre-Rust-1.0 by a long shot, and has morphed and mutated quite a lot since then. ggez started using gfx-rs version 0.15, mainly because SDL2’s drawing code was slow as heck on Windows, things like shaders ranged from painfully limited to impossible, and The Pure Rust Dream was real even then. It now uses gfx 0.17 and the API has not really changed much. It’s a little clunky in places and clearly not finished, but is generally pretty nice. The documentation is poor, the people are awesome, and hacking on the internals is fairly easy if you are willing to do some digging.

The thing is, Vulkan had always been a prime target for the gfx-rs team. (IIRC at least one of them is a member of the Vulkan committee, which I’m sure is a complete coincidence.) And after Vulkan 1.0 was released and they started working on a Vulkan backend in earnest, it became more and more clear that their generally-pretty-nice API was not nice enough. Vulkan is lower-level than what gfx-rs was really handling, and they had to make a lot of choices between “unsafe” and “low-cost” instead of being able to have the best of both worlds. To work nicely with Vulkan and get the performance they wanted, gfx-rs needed a lower-level API beneath what they already had, the “hardware abstraction layer”, and this got called gfx-hal.

(As an aside, I think of Vulkan as basically being GPU assembly language, at least in terms of level of abstraction. Which is to say, there is very little abstraction: it gives you the parts that you have to work with, it has nothing stopping you from doing whatever you feel like with those parts, now go write stuff with it. No there’s no memory allocator; I just told you to go write stuff, didn’t I? Write it. Comparatively, OpenGL is like GPU Javascript: It starts out convenient, but it’s old, wacky, clunky, weird, has a million evolutionary versions and odd edge cases, and it’s not really a convenient model for computation these days. Sure you can make it fast if you try, but you have to jump through lots of hoops to do so.)

Anyway, the gfx-rs team decided that if they had to choose between safety and performance, they would choose performance, because safety could always be layered on top. Eventually the gfx-hal project ended up being essentially a portable Vulkan implementation in Rust, and the old gfx-rs API was basically put in maintenance mode. gfx-hal still has the goal of making a single graphics API that runs on whatever backend a particular OS can offer, but while it’s not quiiiiite 100% Vulkan, it is very very close. It’s low-level, it’s unsafe, and it’s totally rad. In fact, gfx-portability is actually a real implementation of (a slight subset of) Vulkan exposing a C API, similar to MoltenVK. You should be able to run, for example an application written in vulkano on top of gfx-portability, and if you’re using the Vulkan backend for gfx-hal it all basically compiles down to nothing and you get raw Vulkan function calls anyway. This is utter madness, and it actually totally works, though I assume not yet perfectly. And now it’s released!

(I like nerd-history more than I probably should, especially when I know the people involved.)

So, I want the goal for ggez 0.6 to be rewriting the graphics rendering in gfx-hal. Since it’s Mostly Just Vulkan, I feel pretty comfy with the idea of using a 0.1 API, as I doubt there will be huge breaking changes in the future. Maintaining and improving the old gfx-rs backend code, for example making it work well on WebGL, doesn’t seem very useful anymore, and being able to do things like use SPIR-V for shaders and such would actually be nice for ggez’s portability goals. …and I want to play with Vulkan anyway.

This seems like a good opportunity to do something that I’ve talked about a time or two before, which is to pull ggez’s graphics system out into its own crate. A nice, cross-platform, reasonably-fast 2D rendering library is something that will be useful to lots of people, and there are some interesting design decisions that need to be made for gamedev, so we might as well make our own. Vulkan is, as I said, pretty low-level, and so making a higher-level renderer is going to be something I would need to do for ggez anyway. So, someday I will make this happen. The project has been created even if there’s nothing there yet, and a few other people have already expressed interest in both using it and contributing to it.

I am honestly somewhat concerned because creating the gfx-hal OpenGL backend seems like a difficult problem to solve, and making it work on WebGL will probably be even weirder. gfx-hal certainly isn’t interested in compromising its design to better conform to OpenGL’s expectations, after all, and I don’t think they should. On the other hand, OpenGL IS a prime target for them, and I certainly don’t object to digging into the gfx-hal backend code myself and getting my hands dirty to make it work on all platforms. So I’m not yet 100% sold on how well gfx-hal will actually work on OpenGL, but I’m willing to take the risk. The nice thing about ggez is that its a 2D graphics framework for drawing sprites and stuff, so its graphics requirements aren’t honestly super high. The gfx-rs OpenGL backend that ggez already uses is already pretty slow, and it generally doesn’t seem to bother anyone. So crack open a gfx-hal tutorial, get ready to cross-reference it with the official-ish Vulkan tutorial, and join in the fun!

(Oh, and while I’m at it I might as well make the filesystem functions of ggez their own crate, since I’ve been vaguely meaning to since forever.)

Once ggez runs on ggraphics and ggraphics runs on mobile and webassembly, I’d be pretty willing to call ggez Basically Done and make a 1.0 release. BUT…

I’m out… ish

Finally, sadly, I’m a little bit done with ggez, even though that doesn’t mean ggez is done. I’m not going to vanish, and I’m willing to keep maintaining ggez on some level or another more or less forever. But this has been a pretty rough couple years in my life, and while ggez (and Rust in general) is one of the things that’s kept me sane during it, at some point it stopped being fun. I’m sick of chasing after weird graphics transform bugs, I’m sick of dealing with balky OS input API’s, I’m sick of hecked-up graphics drivers doing whatever they feel like, I’m sick of having a million little edge-cases nibbling around my consciousness saying “really you should fix this sometime, you know”. I want to work on other projects, and I don’t really have the time or energy to juggle lots of things at once. I am no longer mentally prepared to look at a major subproject like, say, adding webassembly support to winit, and just shrug, roll up my sleeves and say “let’s do it”. The fun hass run out. I really want to try to actually use ggez in a non-trivial fashion someday, which I haven’t done since 0.3.

So, I am NOT stepping down as maintainer of ggez, and the project is CERTAINLY not dead, but let’s say, I’m taking applications for other people to pick up some more of the slack. It’s not going to be my main side-project in life anymore, I want to do other things for a while that are frankly more important. svenstaro and termhn also have access to the github repo and crates.io account; they have their own lives to run, but at least ggez wouldn’t become orphaned even if I did get hit by a bus. But after 0.5.0 is fully released, I’m going to be making other projects my main priority, and you probably won’t be able to expect to submit a bug report on Monday and get an update and new patch release on Wednesday. The idea of attacking a 0.6 version is frankly only at all appealing because making ggraphics sounds like something new and fun. Stuff like iOS support? Probably won’t happen unless someone else makes it happen. Don’t worry, I expect to return once I need to scratch the itch again.

Conclusion

The Rust gamedev world needs your help! We have really good fundamental interface libraries for graphics, windowing, sound, and so on, with lots of great people on them. But lots of them have some very nasty holes compared to, well, just using SDL2. rodio does not build properly on iOS, gilrs does not work on OSX, winit has some bugs relating to Wayland on Linux, stuff like that. These are usually NOT hard things to fix! All they require is a few weekends and a bit of moxie. All of these projects have really good maintainers around them who will tell you exactly what you need to do. You do not need to be an expert wizard in any of these fields, all you have to do is learn, experiment, and write code.

As always, glory to all zealous challengers!