#skia #vulkan #ash #2d #graphics

skulpin

This crate provides an easy option for drawing hardware-accelerated 2D by combining Vulkan and Skia

28 releases (10 breaking)

0.11.1 Nov 3, 2020
0.10.0 Sep 12, 2020
0.9.5 May 30, 2020
0.9.0 Mar 24, 2020
0.2.2 Nov 24, 2019

#18 in GUI

Download history 88/week @ 2020-08-11 36/week @ 2020-08-18 32/week @ 2020-08-25 77/week @ 2020-09-01 221/week @ 2020-09-08 64/week @ 2020-09-15 38/week @ 2020-09-22 25/week @ 2020-09-29 33/week @ 2020-10-06 17/week @ 2020-10-13 38/week @ 2020-10-20 23/week @ 2020-10-27 106/week @ 2020-11-03 34/week @ 2020-11-10 51/week @ 2020-11-17 268/week @ 2020-11-24

239 downloads per month
Used in 2 crates

MIT/Apache

170KB
3K SLoC

skulpin

Skia + Vulkan = Skulpin

This crate provides an easy option for drawing hardware-accelerated 2D by combining vulkan and skia.

Build Status Crates.io

Example Screenshot

This crate mainly depends on:

NOTE: See skia-bindings for more info on how a skia binary acquired. In many cases, this crate will download a binary created by their project's CI.

Running the Examples

First, ensure that the below requirements are met depending on OS. Afterwards, the examples can be run normally.

The interactive example is good to look at for an easy way to get keyboard/mouse input.

cargo run --example interactive_winit_app

The physics demo is fun too.

cargo run --example physics

Here's a video of the physics and interactive examples.

IMAGE ALT TEXT

Status

This crate is in "maintenance" mode - I'm not adding features or planning any API reworks, but I do plan to make fixes as necessary to address issues that might come up and maintain compatibility with the broader rust ecosystem.

Originally this was just a proof-of-concept, but it is now being used by neovide. I've received anecdotal reports that this library is working will on windows, macOS and linux (including wayland.) There are some bugs with winit, so I added sdl2 support as a more stable option. I think this could realistically be used for shipping software when used with the sdl2 backend.

Flutter, Google's new UI framework, uses a Skia + Vulkan stack to achieve 60+ FPS on mobile devices. Because Google is deeply invested in this stack, I anticipate relatively long term support of this type of usage in Skia.

Windowing Backends

This library currently supports two windowing backends:

  • winit - Cross-platform window handling implemented in Rust.
  • sdl2 - SDL2 isn't written in rust, and it does far more than windowing. However, it's a mature project that's been around for a long time.

If you're just poking around, winit is fine. For a "shipping" project, I'd consider using sdl2 since at time of this writing, it's more stable.

You can also use the skulpin-renderer crate directly and implement Window trait for yourself.

By default, support (and dependencies) for both winit and sdl2 are pulled in when building against the skulpin crate. This can be avoided either by directly linking against crates like skulpin-renderer or by using feature flags. See the Feature Flags section for more info.

Usage

Currently there are two ways to use this library with winit.

  • app - Implement the AppHandler trait and launch the app. It's simple but not as flexible. This is currently only supported when using winit.
  • renderer_only - You manage the window and event loop yourself. Then add the renderer to draw to it. The window should be wrapped in an implementation of skulpin::Window. Implementations for sdl2 and winit are provided.

If you prefer sdl2 you'll need to use the renderer directly. See sdl2 renderer only

Don't forget to install the prerequisites below appropriate to your platform! (See "Requirements")

Feature Flags

Skia-related features:

  • skia_complete - Includes all the below skia features. ** This is on by default **
  • skia_shaper - Enables text shaping with Harfbuzz and ICU
  • skia_svg - This feature enables the SVG rendering backend
  • skia_textlayout - Makes the Skia module skparagraph available, which contains types that are used to lay out paragraphs
  • More information on these flags is available in the skia-safe readme

The skia-bindings prebuilt binaries are only available for certain combinations of features. As of this writing, it is available for none, each feature individually, or all features enabled. The vulkan feature is required and implicitly used, so enabling any features individually will substantially increase build times. It's recommended to use all features (default behavior), or disable all features. (use default-features = false)

Skulpin features:

  • skulpin_sdl2 - Re-export sdl2-related types from the skulpin crate
  • skulpin_winit - Re-export winit-related types from the skulpin crate

Winit versions:

By default, skulpin uses winit 0.22. If you want to override this, use the appropriate winit feature flag. You will need to disable default features (i.e. --no-default-features/default-features = false) so that the default winit-22 feature does not get included.

  • winit-21
  • winit-22
  • winit-23
  • winit-latest

(These feature names match the imgui-rs crate.)

Examples of Feature Flag Usage

# Pull in all skia features and support for all backends (sdl2 and winit)
skulpin = "0"

# Pull in all skia features and support for winit only
skulpin = { version = "0", default-features = false, features = ["skia_complete", "skulpin_winit"] }

# Pull in no optional skia features and support for sdl2 only
skulpin = { version = "0", default-features = false, features = ["skulpin_sdl2"] }

Upstream Versioning of ash and skia-safe

Skulpin can be built and used with many versions of ash and skia-safe. In order to be accomodating to users of the library, the required version has been left open-ended. This allows new projects to use more recent versions of these libraries while not forcing old projects to update.

Documentation

Documentation fails to build on docs.rs because the skia_safe crate requires an internet connection to build. (It will either grab skia source code, or grab a prebuilt binary.) So the best way to view docs is to build them yourself:

cargo doc -p skulpin --open

Requirements

Minimum required rust version: 1.43.0

Windows

  • If you're using the GNU toolchain (MSVC is the default) you might run into an issue building curl. (Curl is a dependency of skia-safe bindings, which is used to download prebuilt skia binaries.) There are some workarounds listed here. Again, this should only affect you if you are running the non-default GNU toolchain.
  • If you're using SDL2, see the requirements for the SDL2 bindings. The easiest method is to use the "bundled" and "static" features. To do this, add sdl2 = { version = ">=0.33", features = ["bundled", "static-link"] } to you Cargo.toml. These are enabled by default for the examples.
  • Enabling vulkan validation requires the LunarG Validation layers and a Vulkan library that is visible in your PATH. An easy way to get started is to use the LunarG Vulkan SDK

MacOS

  • If you're using SDL2, see the requirements for the SDL2 bindings. The easiest method is to use the "bundled" and "static" features. To do this, add sdl2 = { version = ">=0.33", features = ["bundled", "static-link"] } to you Cargo.toml. These are enabled by default for the examples.
  • Enabling vulkan validation requires the LunarG Validation layers and a Vulkan library that is visible in your PATH. An easy way to get started is to use the LunarG Vulkan SDK

Linux

  • If you're using SDL2, see the requirements for the SDL2 bindings. The easiest method is to use the "bundled" and "static" features. To do this, add sdl2 = { version = ">=0.33", features = ["bundled", "static-link"] } to you Cargo.toml. These are enabled by default for the examples.
  • On linux you'll also need to link against bz2, GL, fontconfig, and freetype.
    • On ubuntu, you could use libbz2-dev, libfreetype6-dev, libfontconfig1-dev, and libgl-dev. (And libvulkan-dev to pick up the Vulkan SDK)
  • Enabling vulkan validation requires the LunarG Validation layers and a Vulkan library that is visible in your PATH. An easy way to get started is to use the LunarG Vulkan SDK

Other Platforms

It may be possible to build this for mobile platforms, but I've not investigated this yet.

A note on High-DPI Display Support

For the common case, you can draw to the skia canvas using "logical" coordinates and not worry about dpi/scaling issues.

Internally, the skia surface will match the swapchain size, but this size is not necessarily LogicalSize or PhysicalSize of the window. In order to produce consistently-sized results, the renderer will apply a scaling factor to the skia canvas before handing it off to your draw implementation.

Important configuration choices

There are a few primary choices you should consider when configuring how your app runs

  • Coordinate System - This library can be configured to use a few different coordinate systems.
    • Logical - Use logical coordinates, which are pixels with a factor applied to count for high resolution displays
    • Physical - Use raw pixels for coordinates
    • VisibleRange - Try to fit the given range to the window
    • FixedWidth - Use the given X extents and aspect ratio to calculate Y extents
    • None - Do not modify the canvas matrix
  • Presentation Mode - You'll likely either want Fifo (default) or Mailbox
    • Fifo (VK_PRESENT_MODE_FIFO_KHR) is the default behavior and is always present on devices that fully comply to spec. This will be VSync,shouldn't ever screen tear, and will generally run at display refresh rate.
    • Mailbox (VK_PRESENT_MODE_MAILBOX_KHR) will render as quickly as possible. The frames are queued and the latest complete frame will be drawn. Other frames will be dropped. This rendering method will produce the lowest latency, but is not always available, and could be an unnecessary drain on battery life for laptops and mobile devices.
    • See prefer_fifo_present_mode/prefer_mailbox_present_mode for a simple way to choose between the two recommended options or present_mode_priority for full control.
    • For full details see documentation for PresentMode and the Vulkan spec.
  • Device Type - The most common device types will be Dedicated or Integrated. By default, a Dedicated device is chosen when available.
    • Discrete (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - When available, this is likely to be the device with best performance
    • Integrated (VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) - This will generally be more power efficient that a Discrete GPU.
    • I suspect the most likely case of having both would be a laptop with a discrete GPU. I would expect that favoring the integrated GPU would be better for battery life, at the cost of some performance. However I don't have a suitable device to test this.
    • See prefer_integrated_gpu/prefer_discrete_gpu for a simple way to choose between the two recommended options or physical_device_type_priority for full control
    • For full details see documentation for PhysicalDeviceType and the Vulkan spec.
  • Vulkan Debug Layer - Debug logging is not enabled by default
    • use_vulkan_debug_layer turns all logging on/off
    • validation_layer_debug_report_flags allows choosing specific log levels
    • If the Vulkan SDK is not installed, the app will fail to start if any vulkan debugging is enabled

License

Licensed under either of

at your option.

The fonts directory contains several fonts under their own licenses:

sdl2 uses the zlib license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

See LICENSE-APACHE and LICENSE-MIT.

Dependencies

~4.5–7MB
~172K SLoC