Merge current main into PR #1174

This commit is contained in:
Kurt Himebauch committed 2026-10-22 13:11:08 -04:00
commit 1da489aebb
10 files changed
+180 -12

No files matched your search

+13 -3
View File
@@ -18,9 +18,11 @@ is a new tag and a `release.env` update.
At run time the desktop is started by `tools/linuxfs/desktop/droiddeck-desktop` (the app stages it
at every session): Plasma's own `startplasma-wayland`, with KWin nested in the app's compositor
through `kwin_wayland_wrapper`. KWin composites in software (QPainter) - the Adreno node is not a
DRM device - so games and emulators from the menu go through `droiddeck-gpu`, and Steam goes back
to the app as a Steam session.
through `kwin_wayland_wrapper`. The package's `kwin-compositor` marker selects OpenGL through
Zink for KWin 6.8, which removed QPainter. Older packages retain their software compositor.
On Android the launcher explicitly selects the KGSL render node; the nested backend can use it
when the host's dmabuf feedback cannot name a DRM device. Games and emulators from the menu go
through `droiddeck-gpu`, and Steam goes back to the app as a Steam session.
`kwin.env` pins the KWin version shared by the build and packaging jobs. `build-kwin.sh` builds that version's
Wayland executable and library on a native ARM64 runner, using a disposable
@@ -30,6 +32,14 @@ by SHA-256 from KDE's official source inventory; `patches/0001-respect-nested-de
lets Display Settings control the inner desktop scale independently of the outer window size.
It keeps layer sizes, pointer/touch coordinates and the cursor in the same physical pixels.
The behavior is enabled only with `DROIDDECK_NESTED_SCALE`, which the desktop script supplies.
`0002-select-explicit-nested-render-node.patch` lets that nested backend use one explicitly
selected `KWIN_RENDER_NODES` device when host feedback cannot identify it. It does not guess
between GPUs or change normal KWin device selection.
`pins/mesa/desc` keeps Mesa 26.2.4 and its actual package dependencies ahead of the rolling
repository metadata. Mesa 26.2.5 crashes in Zink shader compilation on Thor with the selected
Turnip driver. `mesa.env` points at immutable copies of the original 26.2.4 package and signature;
both build jobs verify the Arch Linux ARM signature and pinned SHA-256 as for every other package.
The desktop workflow replaces the same-version `kwin_wayland` executable and `libkwin.so`; the rest
comes from the signature-checked Arch packages. `desktop-kde.kwin.txt` records the source, patch,
+15 -5
View File
@@ -4,6 +4,7 @@ out=$(realpath -m "${1:?out dir}")
here=$(cd "$(dirname "$0")" && pwd)
[ "$(uname -m)" = aarch64 ] || { echo 'KWin needs a native aarch64 runner' >&2; exit 1; }
source "$here/kwin.env"
source "$here/mesa.env"
version=$DESKTOP_KWIN_VERSION
source_sha=4bfaf31e29a8f9fdf231dc3bbb9b09b0ce07cae9fee7a01cfc86425ece796258
mirror=https://fl.us.mirror.archlinuxarm.org/aarch64
@@ -24,11 +25,12 @@ case $kwin_package in
"extra/kwin-$version"-[0-9]*-aarch64.pkg.tar.*) ;;
*) echo "KWin package $kwin_package does not match source KWin $version" >&2; exit 1 ;;
esac
export work mirror builder here
export work mirror builder here DESKTOP_MESA_PACKAGE DESKTOP_MESA_URL
download() {
local entry=$1 sum=$2 file=${1#*/}
fetch "$work/pkgs/$file" "$mirror/$entry"
fetch "$work/pkgs/$file.sig" "$mirror/$entry.sig"
local entry=$1 sum=$2 file=${1#*/} url=$mirror/$1
[ "$file" != "$DESKTOP_MESA_PACKAGE" ] || url=$DESKTOP_MESA_URL
fetch "$work/pkgs/$file" "$url"
fetch "$work/pkgs/$file.sig" "$url.sig"
gpgv --status-fd 1 --keyring "$here/archlinuxarm-builder.gpg" "$work/pkgs/$file.sig" "$work/pkgs/$file" 2>/dev/null \
| grep -Eq "^\[GNUPG:\] VALIDSIG .* $builder\$"
echo "$sum $work/pkgs/$file" | sha256sum -c - >/dev/null
@@ -49,19 +51,27 @@ sudo mknod -m 666 "$work/root/dev/urandom" c 1 9
sudo mount -t proc proc "$work/root/proc"
sudo tar -xf "$work/kwin.tar.xz" -C "$work/root/build"
sudo patch -d "$work/root/build/kwin-$version" -p1 < "$here/patches/0001-respect-nested-desktop-scale.patch"
sudo patch -d "$work/root/build/kwin-$version" -p1 < "$here/patches/0002-select-explicit-nested-render-node.patch"
sudo chroot "$work/root" /usr/bin/env PATH=/usr/bin:/bin HOME=/root LC_ALL=C.UTF-8 \
/usr/bin/cmake -S "/build/kwin-$version" -B /build/out -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBEXECDIR=lib -DBUILD_TESTING=OFF
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBEXECDIR=lib \
-DCMAKE_SKIP_RPATH=ON -DBUILD_TESTING=OFF
sudo chroot "$work/root" /usr/bin/env PATH=/usr/bin:/bin HOME=/root LC_ALL=C.UTF-8 \
/usr/bin/cmake --build /build/out --target kwin_wayland --parallel 4
sudo cp "$work/root/build/out/bin/kwin_wayland" "$out/kwin_wayland"
sudo cp "$work/root/build/out/bin/libkwin.so.$version" "$out/libkwin.so.$version"
sudo chown "$(id -u):$(id -g)" "$out/kwin_wayland" "$out/libkwin.so.$version"
strip --strip-unneeded "$out/kwin_wayland" "$out/libkwin.so.$version"
readelf -d "$out/kwin_wayland" "$out/libkwin.so.$version" > "$work/dynamic-tags.txt"
if grep -Eq '\((RPATH|RUNPATH)\)' "$work/dynamic-tags.txt"; then
echo 'KWin artifacts must not contain build-directory runtime search paths' >&2
exit 1
fi
grep -aq DROIDDECK_NESTED_SCALE "$out/libkwin.so.$version"
{
echo "KWin $version source sha256 $source_sha"
echo "Patch sha256 $(sha256sum "$here/patches/0001-respect-nested-desktop-scale.patch" | cut -d' ' -f1)"
echo "Render node patch sha256 $(sha256sum "$here/patches/0002-select-explicit-nested-render-node.patch" | cut -d' ' -f1)"
echo "Executable sha256 $(sha256sum "$out/kwin_wayland" | cut -d' ' -f1)"
echo "Library sha256 $(sha256sum "$out/libkwin.so.$version" | cut -d' ' -f1)"
echo 'Build packages (Arch Linux ARM signatures verified):'
+5 -2
View File
@@ -3,6 +3,7 @@ set -euo pipefail
out=${1:?out dir}
here=$(cd "$(dirname "$0")" && pwd)
source "$here/kwin.env"
source "$here/mesa.env"
mirror=${ALARM_MIRROR:-https://fl.us.mirror.archlinuxarm.org/aarch64}
case $mirror in https://*) ;; *) echo "ALARM_MIRROR must be https" >&2; exit 1 ;; esac
builder=68B3537F39A313B3E574D06777193F152BDBE6A6
@@ -21,8 +22,10 @@ echo "kde: $(wc -l < "$work/pkglist.txt") packages beyond the runtime's own"
while read -r entry sum; do
file=${entry#*/}
[ -s "$pkgs/$file" ] || fetch "$pkgs/$file" "$mirror/$entry"
fetch "$work/pkg.sig" "$mirror/$entry.sig"
url=$mirror/$entry
[ "$file" != "$DESKTOP_MESA_PACKAGE" ] || url=$DESKTOP_MESA_URL
[ -s "$pkgs/$file" ] || fetch "$pkgs/$file" "$url"
fetch "$work/pkg.sig" "$url.sig"
if ! gpgv --status-fd 1 --keyring "$here/archlinuxarm-builder.gpg" "$work/pkg.sig" "$pkgs/$file" 2>/dev/null \
| grep -Eq "^\[GNUPG:\] VALIDSIG .* $builder\$"; then
echo "$file: no valid Arch Linux ARM Build System signature" >&2; rm -f "$pkgs/$file"; exit 1
+8 -2
View File
@@ -72,8 +72,12 @@ def main():
seeds = [l.strip() for l in open(seeds_file) if l.strip() and not l.lstrip().startswith("#")]
pkgs, providers = {}, collections.defaultdict(list)
for repo in REPOS:
root = os.path.join(dbdir, "x_" + repo)
pins = os.path.join(os.path.dirname(__file__), "pins")
sources = [("extra", pins)]
sources.extend((repo, os.path.join(dbdir, "x_" + repo)) for repo in REPOS)
for repo, root in sources:
if not os.path.isdir(root):
continue
for entry in sorted(os.listdir(root)):
fields, key = {}, None
for fname in ("desc", "depends"):
@@ -92,6 +96,8 @@ def main():
name = fields.get("NAME", [None])[0]
if not name or name in pkgs:
continue
if root == pins:
runtime.pop(name, None)
provides = [parse_dep(p) for p in fields.get("PROVIDES", [])]
pkgs[name] = {"repo": repo, "file": fields["FILENAME"][0], "version": fields["VERSION"][0],
"sha256": fields.get("SHA256SUM", [""])[0],
+2
View File
@@ -0,0 +1,2 @@
DESKTOP_MESA_PACKAGE='mesa-1:26.2.4-1-aarch64.pkg.tar.xz'
DESKTOP_MESA_URL='https://github.com/Droid-Deck/DroidDeck-Components/releases/download/build-dependency-mesa-26.2.4-r1/mesa-26.2.4-1-aarch64.pkg.tar.xz'
@@ -0,0 +1 @@
opengl
@@ -0,0 +1,23 @@
--- a/src/backends/wayland/wayland_backend.cpp
+++ b/src/backends/wayland/wayland_backend.cpp
@@ -455,6 +455,20 @@
if (WaylandClient::LinuxDmabufV1 *dmabuf = m_display->linuxDmabuf()) {
m_renderDevice = GpuManager::self()->compatibleRenderDevice(dmabuf->mainDevice());
+ if (!m_renderDevice && qEnvironmentVariableIsSet("DROIDDECK_NESTED_SCALE")) {
+ const auto nodes = GpuManager::splitPathList(qEnvironmentVariable("KWIN_RENDER_NODES"));
+ const auto &devices = GpuManager::self()->renderDevices();
+ // Android's KGSL host cannot name a DRM device in its dmabuf feedback.
+ if (nodes.size() == 1) {
+ for (const auto &device : devices) {
+ if (device->path() == nodes.constFirst()) {
+ m_renderDevice = device.get();
+ qCWarning(KWIN_WAYLAND_BACKEND) << "Using explicitly selected nested render node" << m_renderDevice->path();
+ break;
+ }
+ }
+ }
+ }
}
createOutputs();
+38
View File
@@ -0,0 +1,38 @@
%NAME%
mesa
%VERSION%
1:26.2.4-1
%FILENAME%
mesa-1:26.2.4-1-aarch64.pkg.tar.xz
%SHA256SUM%
b03b498ba04ef5217299a81a1ef4c1c3582a250fab74848a443b85ba4a352fbd
%DEPENDS%
expat
glibc
libdrm
libelf
libgcc
libglvnd
libstdc++
libx11
libxcb
libxext
libxshmfence
libxxf86vm
llvm-libs
lm_sensors
spirv-tools
wayland
zlib
zstd
%PROVIDES%
libva-mesa-driver=1:26.2.4-1
mesa-libgl=1:26.2.4-1
libva-driver
opengl-driver
+7
View File
@@ -73,6 +73,13 @@ if [ -f "$HOME/.droiddeck-remote-run" ]; then
done
) &
fi
if [ "$(cat /usr/share/droiddeck/kwin-compositor 2>/dev/null)" = opengl ]; then
unset LIBGL_ALWAYS_SOFTWARE QT_QUICK_BACKEND
export KWIN_COMPOSE=O2 MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink LIBGL_KOPPER_DRI2=true
if [ -z "${KWIN_RENDER_NODES:-}" ] && [ -c /dev/dri/renderD0 ]; then
export KWIN_RENDER_NODES=/dev/dri/renderD0
fi
fi
echo "== droiddeck-desktop: Plasma on $WAYLAND_DISPLAY"
dbus-run-session -- startplasma-wayland
rc=$?
+68
View File
@@ -0,0 +1,68 @@
import pathlib
import subprocess
import sys
import tempfile
import unittest
ROOT = pathlib.Path(__file__).resolve().parents[2]
BUILDER = ROOT / "tools/desktop-kde"
class MesaPinTest(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = pathlib.Path(self.temp.name)
for repo in ("core", "extra", "alarm"):
(self.root / ("x_" + repo)).mkdir()
rolling = self.root / "x_extra/mesa-26.2.5"
rolling.mkdir()
(rolling / "desc").write_text(
"%NAME%\nmesa\n\n%VERSION%\n1:26.2.5-1\n\n"
"%FILENAME%\nrolling-mesa.pkg.tar.xz\n\n%SHA256SUM%\nrolling\n\n"
"%DEPENDS%\nrolling-only-dependency\n\n%PROVIDES%\nopengl-driver\n"
)
fields = {}
for block in (BUILDER / "pins/mesa/desc").read_text().strip().split("\n\n"):
key, *values = block.splitlines()
fields[key.strip("%")] = values
self.pin = fields
self.runtime = self.root / "runtime.txt"
self.runtime.write_text("".join(name + " 999\n" for name in fields["DEPENDS"]))
self.seeds = self.root / "seeds.txt"
def resolve(self, seed):
self.seeds.write_text(seed + "\n")
return subprocess.run(
[sys.executable, str(BUILDER / "closure.py"), str(self.root),
str(self.runtime), str(self.seeds)],
text=True, capture_output=True,
)
def assertPinned(self, seed):
result = self.resolve(seed)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(
result.stdout.strip(),
"extra/" + self.pin["FILENAME"][0] + " " + self.pin["SHA256SUM"][0],
)
def test_pinned_metadata_overrides_rolling_dependencies(self):
self.assertPinned("mesa")
def test_virtual_provider_uses_pinned_package(self):
self.assertPinned("opengl-driver")
def test_newer_runtime_cannot_bypass_tested_mesa(self):
with self.runtime.open("a") as stream:
stream.write("mesa 1:26.2.5-1\n")
self.assertPinned("mesa")
def test_requirement_above_pin_fails_instead_of_using_rolling_mesa(self):
result = self.resolve("mesa>=1:26.2.5")
self.assertNotEqual(result.returncode, 0)
if __name__ == "__main__":
unittest.main()