Today I’m happy to officially announce a project that has been the culmination of about five months of work. This makes it probably the most involved programming project I’ve ever done, and I’m proud of the final result.
The GUI ecosystem in Rust is still in a nascent stage. There are well-defined ecosystem crates for doing certain things, like window management. On the other hand, other essential GUI components are still wanting for a good solution. In my own travels, I’ve found that there’s no good out-of-the-box solution to vector graphics yet, which is an essential part of any GUI. The closest thing is
piet-common, but it’s hard to integrate into non-
druid systems like
theo is my attempt at resolving this issue. It’s an implementation of
piet, a common vector graphics API, that can be used with any windowing system that implements the
raw-window-handle traits. The goal is to provide a system that can be effortlessly plugged into whatever system you already have in place, and provide a simple, easy-to-use API for drawing vector graphics.
It has a number of benefits over
piet-common and other contemporary solutions. First of all, as mentioned, it works with the
raw-window-handle interoperability traits, meaning that it should, in theory, work anywhere. Another primary benefit is its use of GPU acceleration. Where possible, it uses either
wgpu or OpenGL as the underlying drawing backend, which should provide benefits for systems with lower CPU power, like Risc-V boxes. However, it is able to fall back to a software rasterization backend based on
softbuffer, which should work on any system that can run
If you’re building a GUI system, consider giving it a try! See the examples in the repository for an example of how to use it.
The Vellophant in the Room
At the time of writing, the Linebender team is working on a similar vector graphics system named
vello. It uses GPU acceleration via
wgpu and is designed to work with systems like
winit as well. So why did I go to all the effort? Why not just wait for
vello to be ready?
First of all,
vello use different strategies.
vello is a compute-based renderer, while
theo uses a rasterize renderer. The difference comes down to strategy:
vello tries to use the GPU to the fullest extent by uploading vector data to the GPU and then rendering it there. On the other hand,
theo uses a more traditional strategy: converting shapes on the CPU to textured triangles and then pushing those to the GPU. It is this author’s opinion that the rasterization-based strategy is more ergonomic and easier to cache, so I created
theo around this strategy. Your mileage may vary.
Was it hard to make?
theo, I had to write a handful of other crates to make the current Rust rendering ecosystem easier to work with. Here’s a quick rundown of them:
line-straddler, which generates underlines and strikethroughs for glyphs.
piet-cosmic-text, which provides a uniform text rendering interface for
piet-tiny-skia, which implements a
piet-hardware, which converts
pietrendering calls to buffering textured triangles.
piet-glow, which implements a
pietbackend using OpenGL.
piet-wgpu, which implements a