The graphics-core20 Snap interface

The problem with snapping userspace graphics drivers

Over the past few years developing graphical snaps to run on Ubuntu Core we’ve encountered various issues. One of these is the need to make userspace graphics drivers available inside snap confinement. There’s a partial solution in snapd that, on desktop systems can make these available from the host system but among the cases where this doesn’t work is on Ubuntu Core.

Until recently, we have been including the mesa drivers inside the snap as these have the least licensing issues, and cover a wide range of hardware. But it is not an ideal solution:

  • Both server (e.g. mir-kiosk) and client (e.g. mir-kiosk-kodi) snaps contain these drivers;
  • Security updates to mesa require all the server and client snaps to be rebuilt and distributed; and
  • There’s no way to introduce other drivers, even if Mir supports them.

This led to some frustration as there are a number of graphics stacks that Mir supports that are not supported by mir-kiosk.

Introducing graphics-core20

Fundamentally, userspace graphics drivers are just files. And snapd has a way to share files between snaps: content interfaces. Care is needed to ensure that the binaries are ABI compatible, but as the binaries come from a stable archive (20.04LTS) that isn’t a problem here.

The Mir team are now maintaining a mesa-core20 content snap with the current mesa drivers from the archive:

  • lib contains the mesa shared libraries (add to LD_LIBRARY_PATH)
  • drv contains the mesa drivers (set LIBGL_DRIVERS_PATH/LIBVA_DRIVERS_PATH to this)
  • glvnd/egl_vendor.d contains the mesa ICD (set __EGL_VENDOR_LIBRARY_DIRS to this)
  • etc/mir-quirks contains any Mir configuration for driver support (none for mesa)

We’ve also built and tested a number of snaps to prove this approach. As well as setting the above environment variables, they need the following plug declaration:

    interface: content
    target: $SNAP/graphics
    default-provider: mesa-core20

In addition, it is desirable to avoid shipping anything from mesa that gets pulled into the snap with a “cleanup” part similar to this:

    after: [kodi, mir-kiosk-snap-launch]
    plugin: nil
    build-snaps: [ mesa-core20 ]
    override-prime: |
      set -eux
      cd /snap/mesa-core20/current/egl/lib
      find . -type f,l -exec rm -f $SNAPCRAFT_PRIME/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/{} \;
      rm -fr "$SNAPCRAFT_PRIME/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/dri"
      for CRUFT in bug lintian man; do
        rm -rf "$SNAPCRAFT_PRIME/usr/share/$CRUFT"

(This example is taken from a mir-kiosk-kodi PR).

The result

With this approach:

  • There’s only one copy of the drivers in one snap;
  • Mesa updates only require one snap to be rebuilt and distributed; and,
  • It is possible to replace mesa with other (compatible) drivers

Now and the future

We have been testing this approach with a new Mir based server [Ubuntu Frame] both with mesa-core20 and (experimentally, for now) other drivers providing KMS, libgbm and an EGL supporting EGL_WL_bind_wayland_display.

Ubuntu Frame has yet to be released to stable, but we are already confident that we can use this approach to enable gbm-kms support for drivers other than mesa and, with additional work, expand it to support some of the other Mir “graphics platforms”.

Longer term, we’re hopeful that the experience gained will feed into improvements in graphics support in snapd that make this unnecessary.