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
androdio
, have features that optionally depend on C code, namelybz2
andminimp3
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 thegilrs
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 aboutggez
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 translatesdl2
’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 usesmint
, 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 takingggez
functions takingnalgebra::Point2<f32>
or whatever as arguments, all functions that need aPoint2
of some kind now takeInto<mint::Point2<f32>>
. This means you can feedggez
nalgebra
types,cgmath
types, or whatever math library you feel like using, as long as the types for it implementInto<mint::Whatever>
. You will probably have to activate themint
feature fornalgebra
orcgmath
, 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!