Skip to content

Commit

Permalink
extensions: add 'graphics' extension
Browse files Browse the repository at this point in the history
This extension provides a shortcut for snaps that make use of the 'mesa-core22' snap
of graphics libraries & resources.  It configures the conventional 'graphics-core22'
content plug and provides the 'graphics-core22-wrapper' helper script for setting-up
the environment.  It also provides the 'wayland-launch' helper script for Wayland programs.
  • Loading branch information
Mark Boudreau committed Jul 21, 2023
1 parent dbe76f2 commit 690cda4
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 0 deletions.
30 changes: 30 additions & 0 deletions extensions/graphics/wayland/bin/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh
set -e

snap_connect_harder() {
# Note the available slot providers
if ! snap connections %SNAP% | grep --quiet "^content.*%SNAP%:$1.*$"; then
available_providers="$(snap interface "$1" | sed -e '1,/slots:/d')"
else
available_providers="$(snap interface content | sed -e '1,/slots:/d' | grep "$1")"
fi

# For wayland try some well known providers
if [ "wayland" = "$1" ]; then
for PROVIDER in ubuntu-frame mir-kiosk; do
if echo "$available_providers" | grep --quiet "\- ${PROVIDER}"; then
sudo snap connect "%SNAP%:$1" "${PROVIDER}:$1"
return 0
fi
done
fi

echo "Warning: Failed to connect '$1'. Please connect manually, available providers are:\n$available_providers"
}

for PLUG in %PLUGS%; do
if ! snap connections %SNAP% | grep --quiet "^.*%SNAP%:${PLUG}.*${PLUG}.*$"; then
sudo snap connect "%SNAP%:${PLUG}" 2> /dev/null || snap_connect_harder ${PLUG}
fi
done

49 changes: 49 additions & 0 deletions extensions/graphics/wayland/bin/wayland-launch
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/sh
set -e

for PLUG in %PLUGS%; do
if ! snapctl is-connected ${PLUG}
then
echo "WARNING: ${PLUG} interface not connected! Please run: /snap/%SNAP%/current/bin/setup.sh"
fi
done

if ! command -v inotifywait > /dev/null
then
echo "ERROR: inotifywait could not be found, mir-kiosk-snap-launch expects:"
echo " . . : stage-packages:"
echo " . . : - inotify-tools"
exit 1
fi

wait_for()
{
until
until
inotifywait --event create "$(dirname "$1")"&
inotify_pid=$!
[ -e "$1" ] || sleep 2 && [ -e "$1" ]
do
wait "${inotify_pid}"
done
kill "${inotify_pid}"
[ -O "$1" ]
do
sleep 1
done
}

real_xdg_runtime_dir=$(dirname "${XDG_RUNTIME_DIR}")
real_wayland=${real_xdg_runtime_dir}/${WAYLAND_DISPLAY:-wayland-0}

# On core systems may need to wait for real XDG_RUNTIME_DIR
wait_for "${real_xdg_runtime_dir}"
wait_for "${real_wayland}"

mkdir -p "$XDG_RUNTIME_DIR" -m 700
ln -sf "${real_wayland}" "$XDG_RUNTIME_DIR"
ln -sf "${real_wayland}.lock" "$XDG_RUNTIME_DIR"
unset DISPLAY

exec "$@"

150 changes: 150 additions & 0 deletions snapcraft/extensions/graphics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2023 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Extension that automates the use of mesa-core22 (and eventually later) and related helper utilities."""
from typing import Any, Dict, Optional, Tuple

from overrides import overrides

from .extension import Extension, get_extensions_data_dir

_MESA_SNAP = {"core22": "mesa-core22"}
_GRAPHICS_NAME = {"core22": "graphics-core22"}
_BASE_TO_VER = {"core22": "22"}
_EXT_NAME = "graphics"


class Graphics(Extension):
"""An extension that provides graphics libraries for snaps that don't need to integrate with a full desktop environment.
This extension is intended to be used with Wayland-ready application snaps that will execute on an
Ubuntu Core 22 (and eventually later) systems with ubuntu-frame,
however it is not exclusively fixated on Ubuntu Core systems - Desktop should work fine
(though you may want to consider one of the gnome/kde extensions instead).
This extension defines a single plug "graphics-core{base version number}" which is a content
interface to the "mesa-core{base version number}" snap that provides the graphics libraries and
other important resources. It also configures apps to use the "opengl" and "wayland" plugs,
which are essential for graphical output.
To assist in the execution of Wayland applications, this extension provides a helper
"wayland-launch" script that can be added to the app's command-chain.
"""

@staticmethod
@overrides
def get_supported_bases() -> Tuple[str, ...]:
return ("core22",)

@staticmethod
@overrides
def get_supported_confinement() -> Tuple[str, ...]:
return "strict", "devmode"

@staticmethod
@overrides
def is_experimental(base: Optional[str]) -> bool:
return False

@overrides
def get_root_snippet(self) -> Dict[str, Any]:
base = self.yaml_data["base"]
return {
"plugs": {
_GRAPHICS_NAME[base]: {
"interface": "content",
"target": "$SNAP/graphics",
"default-provider": _MESA_SNAP[base],
},
},
"layout": {
"/usr/share/drirc.d": {
"bind": "$SNAP/graphics/drirc.d",
},
"/usr/share/libdrm": {
"bind": "$SNAP/graphics/libdrm",
},
"/usr/share/X11": {
"bind": "$SNAP/graphics/X11",
},
},
}

@overrides
def get_app_snippet(self) -> Dict[str, Any]:
base = self.yaml_data["base"]
return {
"command-chain": [
f"bin/graphics-core{_BASE_TO_VER[base]}-wrapper",
],
"plugs": ["opengl", "wayland"],
}

@overrides
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
return {
"build-packages": [
"libdrm-dev",
"libegl-dev",
"libgbm-dev",
"libgl-dev",
"libgles-dev",
"libglx-dev",
"libnvidia-egl-wayland-dev",
"libva-dev",
"libvdpau-dev",
"libvulkan-dev",
"libwayland-dev",
"libwayland-egl-backend-dev",
"libx11-xcb-dev",
"libxau-dev",
"libxcb-dri2-0-dev",
"libxcb-dri3-dev",
"libxcb-present-dev",
"libxcb-sync-dev",
"libxcb-xfixes0-dev",
"libxcb1-dev",
"libxdamage-dev",
"libxdmcp-dev",
"libxshmfence-dev",
],
}

@overrides
def get_parts_snippet(self) -> Dict[str, Any]:
base = self.yaml_data["base"]
return {
f"{_EXT_NAME}/{_GRAPHICS_NAME[base]}": {
"source": f"https://github.com/MirServer/{_GRAPHICS_NAME[base]}.git",
"plugin": "dump",
"override-prime": "craftctl default\n${CRAFT_PART_SRC}"
f"/bin/{_GRAPHICS_NAME[base]}-cleanup {_MESA_SNAP[base]}",
"prime": [f"bin/{_GRAPHICS_NAME[base]}-wrapper"],
# This should be the last part to prime, so the clean-up can execute properly
"after": list(self.yaml_data["parts"].keys()),
},
f"{_EXT_NAME}/wayland-launch": {
"source": str(get_extensions_data_dir() / _EXT_NAME / "wayland"),
"plugin": "dump",
"stage-packages": ["inotify-tools"],
"override-build": f'PLUGS="opengl wayland {_GRAPHICS_NAME[base]}"\n'
'sed --in-place "s/%PLUGS%/$PLUGS/g" $CRAFT_PART_BUILD/bin/wayland-launch\n'
'sed --in-place "s/%PLUGS%/$PLUGS/g" $CRAFT_PART_BUILD/bin/setup.sh\n'
'sed --in-place "s/%SNAP%/$CRAFT_PROJECT_NAME/g" $CRAFT_PART_BUILD/bin/wayland-launch\n'
'sed --in-place "s/%SNAP%/$CRAFT_PROJECT_NAME/g" $CRAFT_PART_BUILD/bin/setup.sh\n'
'craftctl default',
},
}
2 changes: 2 additions & 0 deletions snapcraft/extensions/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from snapcraft import errors

from .gnome import GNOME
from .graphics import Graphics
from .kde_neon import KDENeon
from .ros2_humble import ROS2HumbleExtension

Expand All @@ -30,6 +31,7 @@
ExtensionType = Type[Extension]

_EXTENSIONS: Dict[str, "ExtensionType"] = {
"graphics": Graphics,
"gnome": GNOME,
"ros2-humble": ROS2HumbleExtension,
"kde-neon": KDENeon,
Expand Down

0 comments on commit 690cda4

Please sign in to comment.