Impeller
Impeller is a 2D vector graphics renderer used in Flutter. Impeller can also be used standalone (without flutter) with its C API. This crate provides a safe rust wrapper around the C API (and also the raw bindings).
NOTE: It is HIGHLY recommended that you use
cache_libsfeature to improve build times and save bandwidth.
What can it do?
- draw 2D shapes like paths (lines/curvies), rectangles, circles, etc.
- draw AND layout text.
- draw effects like blurs, shadows, color blending etc.
- clipping using any shape.
Where do I want to use it?
- UI libraries are the best use-case.
- 2D games? easy to embed Impeller into any opengl/vk/metal app.
Docs
The docs and examples of this crate are good enough for really basic drawing (eg: drawing a rect). But this is nowhere enough for real world usage. They will tell you how to use a object, but now why or where you would use this.
For example, pretty much NONE of the enums are documented. We will slowly improve the situation, but until then, the below resources should help cover the gaps. Most rust item docs will also contain direct links to their counterparts in dart/skiasharp/react-native-skia.
Dart:Ui Docs
Impeller is actually designed for dart/flutter, so, it is the best place to find documentation. Most of the object and function names are same in rust/dart, so you can easily translate the docs from dart to rust. eg: StrokeCap Enum.
Some names are different though. DisplayListBuilder is the combination of PictureRecorder and Canvas items in dart. DisplayList is Picture in dart.
It also has the best explanation for BlendMode with lots of pictures.
One jpeg screenshot is worth a thousand words of text documentation. - Albert Einstein
React Native Skia Docs
Technically, this is documenting Skia. But both Impeller and Skia have such a large overlap in terminology, design and functionality that a lot of learning transfers over seamlessly.
It also provides a lot of images showing the different options (eg: MaskFilters Blur).
SkiaSharp docs
Again, skia. But lots of guide-level docs for people who are starting out with Vector graphics.
Why Impeller?
- Blazingly? Fast - It is used in Flutter, so, you know it will be maintained and improved continuously. The focus is also on consistency to keep everything running smooth.
- Great text rendering AND layout - The rust ecosystem is severely lacking when it comes to text. Impeller should cover most of your needs.
- Simple Object Model: The object model is very simple and takes like 5 minutes to learn. see Object Model
- Easy to Embed - Any (opengl/vk/mtl)-based app/game can embed Impeller in less than 10 lines.
- Fast compilation - The only bottleneck is network speed to download the prebuilt libs.
And even that can be amortized with the
cache_libsfeature. see Features - Easy Bindings - The C API is really easy and allows us to "auto-generate" bindings. So, if we are trying to generate lua or wasm bindings, this is a huge QoL feature.
Why not Impeller?
- Impeller is written in C++ and we do not support building from source. We use pre-built static/shared libraries instead.
- No support for d3d and no fallback software renderer.
- No powerful features like custom shaders. use Skia-rs instead.
- As the bindings are not widely used yet, we may still have some bugs.
How to use the crate
For libraries who are just "using" the API, all you need to do is just use the crate with no features.
The final binary/executable should enable the prebuilt_libs feature to download the prebuilt libraries from github releases and link them.
NOTE: We use curl to download and tar (or unzip on linux) to extract the archives. linux, mac and windows (10+) will have these by default.
Features
prebuilt_libs- Downloads the prebuilt libraries from github releases and links them to your project.static_link- If enabled, we will link static libraries. may not be available on all platforms (see Custom Linking).cache_libs- If enabled, we will cache the prebuilt-libs in.impeller_cachedirectory inside your project directory (parent dir oftarget). Add/.impeller_cacheto.gitignore, if you enable this feature.- You can customize cache directory path with
IMPELLER_CACHE_DIRenv variable. And also use this to provide your own custom built libs. - caching avoids redownloading after
cargo cleansaving bandwidth and this in turns also makes the builds faster. - You also get to inspect the downloaded archives in the cache to debug any errors.
- You can customize cache directory path with
bindgen_live- This feature lets you build the rust bindings for impeller header at build time using bindgen. This is necessary on non-64bit platforms. If this is disabled, we will use pre-generated bindings for most mainstream platforms like windows/linux/android/mac 64bit.sys: This feature exposes the raw unsafe bindings asimpellers::sysmodule. Useful, if the safe wrappers have any unsoundness or limitations, that need direct workarounds.
Safety
I try to keep the bindings sound, but graphics programming is just really really unsafe. Especially around the handling of context/surface lifetimes.
Objects like textures/contexts are inherently linked to platform resources (like openGL context or vulkan device). So, they must ALL be destroyed before you destroy the underlying window or opengl context. That is the sole reason creating them is unsafe.
Custom Linking
When you want to link in your own custom impeller library:
- Enable
cache_libsfeature to make it use libraries from a cached directory. - set
IMPELLER_CACHE_DIRenvironment variable to manually set the location of the cache directory. - Inside that directory, create
targetos_targetarch(eg:linux_x64) directory. - depending on the features
static_link, build script will search for dynamic libs or static libs (eg:linux_x64/libimpeller.a).