Custom Yocto Linux image for the Project Speedrun board (NXP i.MX 8M Mini EVK) built on the Walnascar (6.12) BSP release. This build replaces the stock NXP imx-image-full demo image with a GNOME 48 desktop featuring hardware-accelerated Chromium, media playback, and game engines targeting the Vivante GC NanoUltra GPU.
Machine: imx8mmevk | Distro: fsl-imx-xwayland | Image: imx-image-multimedia | Layer: meta-quilter (priority 99)
Thanks especially to Brandin Claar of remodulate. for helping us put this recipe together.
The stock NXP image ships Weston as its compositor with Qt5/6 demos. This build replaces the entire desktop stack and adds significant customization:
| Area | Stock NXP | Project Speedrun |
|---|---|---|
| Desktop | Weston compositor + Qt demos | GNOME 48 (Mutter 48 + GDM) |
| Init system | systemd (NXP default) | systemd with GNOME targets, GDM as display manager |
| Browser | None | Chromium 129 with V4L2 HW encode/decode, Firefox 147 (pre-built) |
| Media player | GStreamer demos | mpv with V4L2 M2M HW decode, ffmpeg with V4L2 codecs |
| Boot splash | psplash (Yocto default) | Plymouth (spinner theme) with Quilter logo watermark |
| U-Boot branding | NXP/DENX logos | Quilter splash logo, "Project Speedrun" device tree model string |
| Audio | Basic ALSA | PulseAudio with WM8524 codec config, Bluetooth A2DP |
| Package format | RPM | Debian (.deb) with apt package management on-device |
| Games | None | GZDoom (Freedoom 1 & 2), Quake GLES1 port |
| GPU renderer | N/A (Weston direct) | GSK Cairo + COGL GLES2 (Vivante workarounds) |
Chromium 129.0.6668.100 runs on Wayland/Ozone with the Vivante GLES 2.0 GPU. NXP provides V4L2 video decode patches in meta-imx-sdk/dynamic-layers/chromium-browser-layer/ (22 patches for Amphion/Hantro decoders, HEVC, G2D, NV12 zero-copy). Three additional custom patches in meta-quilter enable encode and fix a GPU crash:
| Patch | Purpose |
|---|---|
chromium-v4l2-hw-encode-129.patch |
V4L2 MMAP hardware video encoding for the Hantro H1 encoder (WebRTC/Google Meet). Forces MMAP memory type, adds stride-aware buffer copy, removes VP9 SW encoder to force HW codec selection, prioritizes HW formats in WebRTC negotiation, disables low-resolution software fallback. Touches 8 source files. |
chromium-v4l2-hw-encode-codec-filter-129.patch |
Debug CLI flags (--webrtc-disable-vp8, --webrtc-disable-h264, HW-only variants) for isolating codec issues during development. |
chromium-gles2-glgetstringi-null-check-129.patch |
Fixes chrome://gpu SIGSEGV on GLES 2.0 drivers. The Vivante GC NanoUltra lacks glGetStringi (a GLES 3.0+ function); Chromium's extension enumeration calls a NULL function pointer. Patch installs a safe stub at init time in DriverGL::InitializeStaticBindings() — required because thin LTO inlines across compilation units, making call-site guards insufficient. |
use_v4l2_codec=true use_linux_v4l2_only=true
proprietary_codecs=true ffmpeg_branding="Chrome"
--use-gl=egl --ozone-platform=wayland --enable-features=VaapiVideoEncoder
--video-capture-use-gpu-memory-buffer --ignore-gpu-blocklist
GNOME 48 with Mutter 48.0 running on Wayland via the fsl-imx-xwayland distro. The upgrade from Scarthgap (Mutter 46.x) was driven by persistent screen flickering caused by Mutter's multi-GPU detection treating the i.MX 8M Mini's split DRM architecture (card0 = LCDIF display controller, card1 = Vivante GPU) incorrectly. Mutter 48 includes native triple buffering merged upstream, eliminating the issue.
The Vivante GC NanoUltra only supports GLES 2.0. Several workarounds are required:
| Package | What It Does |
|---|---|
gsk-cairo-config |
Sets GSK_RENDERER=cairo globally — GTK4's GL renderer calls GLES 3.0 functions unsupported by Vivante |
gles-env |
Sets COGL_DRIVER=gles2, CLUTTER_DRIVER=gles2, GDK_GL=gles via /etc/profile.d/ |
mutter_%.bbappend |
Injects stub EGL/eglmesaext.h into sysroot — Mutter 48 unconditionally includes this Mesa-specific header which Vivante EGL doesn't provide |
gnome-session_%.bbappend |
Relaxes -Werror=incompatible-pointer-types — Vivante EGL native types differ from Mesa's |
mpv_%.bbappend |
Disables egl-drm/gbm (Vivante EGL types are Wayland-only, incompatible with GBM surfaces); forces gpu-api=opengl in /etc/mpv/mpv.conf |
packagegroup-gnome-desktop, gnome-terminal, nautilus, gedit, evince, eog, gnome-tweaks, cantarell-fonts, networkmanager
GDM replaces NXP's default Weston service. The imx-image-multimedia.bbappend masks Weston systemd units and enables gdm.service under graphical.target. A Weston session .desktop file is also installed for GDM's session chooser.
The u-boot-imx_%.bbappend makes two changes at compile time:
- Splash logo: Replaces the DENX logo bitmap (
tools/logos/denx.bmpanddrivers/video/u_boot_logo.bmp) with a Quilter logo BMP - Device tree model string:
sedreplaces themodel =property inimx8mm-evk.dtsandimx8mm-evk-u-boot.dtsiwith"Project Speedrun"
No other U-Boot configuration (boot commands, environment variables, memory layout) is modified. However, U-Boot 2025.04 in Walnascar dropped legacy environment variables (mmcargs, mmcroot) that previously passed root= to the kernel. The kernel CONFIG_CMDLINE fragment compensates for this (see Boot Sequence below).
Two kernel config fragments applied via DELTA_KERNEL_DEFCONFIG in linux-imx_%.bbappend:
CONFIG_RFKILL=y— enables Bluetooth/WiFi RF kill switch management
CONFIG_CMDLINE_EXTEND=ywithCONFIG_CMDLINE_FROM_BOOTLOADERexplicitly unset (Kconfigchoiceconflict resolution)CONFIG_CMDLINE="root=/dev/mmcblk1p2 rootwait rw loglevel=0 quiet splash plymouth.ignore-serial-consoles plymouth.persist-splash vt.global_cursor_default=0"— provides root device (U-Boot 2025.04 no longer sets bootargs), enables Plymouth, suppresses serial console fallbackCONFIG_CONSOLE_LOGLEVEL_DEFAULT=1/CONFIG_CONSOLE_LOGLEVEL_QUIET=1— suppresses kernel messages for clean boot splashCONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y— prevents fbcon from clearing the screen before Plymouth attaches to DRM
- U-Boot: Quilter splash logo displayed, device tree reports "Project Speedrun"
- Kernel: Boots with built-in
CONFIG_CMDLINE(root on mmcblk1p2), fbcon deferred, console quiet - Plymouth: Spinner theme with Quilter watermark logo on DRM/KMS (card0/LCDIF). systemd drop-ins delay
plymouth-quituntildisplay-manager.serviceis ready - GDM: Login screen. Default user
speedrun, hostnamespeedrun - GNOME 48: Mutter/Wayland desktop with GLES2 rendering
- Hostname:
speedrun - User account:
speedrun(groups: video, audio, input, render) - Timezone: America/Los_Angeles
- Locale: en_US.UTF-8
- Packaging: Debian
.debformat withapton-device package management - First-boot resize:
resize-rootfsservice expands rootfs partition to fill SD card, then disables itself
- CPU governor:
performancemode set at boot viacpu-performance-modesystemd service - Suspend disabled: systemd sleep/suspend/hibernate targets masked, GNOME power settings overridden via GSettings schema override (
90_disable-suspend.gschema.override)
- PulseAudio: Configured as default sound server (NXP's BSP removes it; re-enabled via
DISTRO_FEATURES_BACKFILL_CONSIDERED:remove) - WM8524 codec: Default audio sink configured for the EVK headphone jack
- Bluetooth A2DP:
packagegroup-tools-bluetoothfor wireless audio
- mpv: Video player with V4L2 M2M hardware decode, forced OpenGL API (Vivante Vulkan ICD is broken)
- ffmpeg: Built with
v4l2andgplPACKAGECONFIG,--enable-v4l2-m2mfor Hantro VPU encode/decode - Firefox 147: Pre-built ARM64 binary installed to
/opt/firefoxwith GNOME desktop integration
- GZDoom: With Freedoom WADs (Episode 1 and 2)
- Quake GLES1: SDL-based port, patched for GCC 14 (
-Wno-error=implicit-function-declaration)
glmark2,kmscube,mesa-demos,es2-info(GLES2 capability query)weston,weston-examples(alternate compositor for debugging)htop,git,curl,lsof
These bbappends fix issues in the Walnascar NXP BSP when building with GNOME:
| Recipe | Fix |
|---|---|
systemd_%.bbappend |
Removes 0001-binfmt-Don-t-install-dependency-links-at-install-tim.patch — incompatible with systemd 257.6 |
unicode-ucd_%.bbappend |
Updated license checksum (upstream unicode.org changed the file) |
libcanberra_%.bbappend |
Removes GTK2 module (no X11 support on Vivante) |
xserver-xorg_%.bbappend |
Removes obsolete GL_BGRA_EXT patch (merged upstream in xserver 21.1.18); adds libxshmfence dep for DRI3 |
gtk+3_%.bbappend |
Re-enables X11 backend (NXP incorrectly removes it, breaking GNOME XWayland components) |
libdisplay-info_git.bbappend |
Bumps 0.1.1 → 0.2.0 (Mutter 48 requires >= 0.2) |
webkitgtk_%.bbappend |
Limits parallel compile to -j 4 (OOM prevention on 16GB build hosts) |
imx-image-multimedia.bbappend |
Removes broken NXP audio packages (packagegroup-fsl-tools-audio), disables Weston, enables GDM |
packagegroup-fsl-gstreamer1.0.bbappend |
Removes gstreamer1.0-rtsp-server (freedesktop.org fetch failures) |
gnome-tweaks_%.bbappend |
Skips buildpaths QA (Python .pyc embeds TMPDIR) |
gzdoom_%.bbappend |
Skips buildpaths QA (generated C source debug info) |
Two NXP BSP source files must be patched directly because they use :remove which cannot be overridden from a layer:
# Re-enable pulseaudio (GNOME requires it)
sed -i 's/^DISTRO_FEATURES:remove = "pulseaudio"/# &/' \
sources/meta-imx/meta-imx-sdk/conf/distro/include/fsl-imx-base.inc
# Re-enable X11 in GTK3 (GNOME needs gtk+-x11-3.0 for XWayland)
sed -i 's/^PACKAGECONFIG:remove:imxgpu = "x11"/# &/' \
sources/meta-imx/meta-imx-bsp/recipes-gnome/gtk+3/gtk+3_%.bbappendpoky/meta, poky/meta-poky
meta-openembedded (meta-oe, meta-gnome, meta-multimedia, meta-python, meta-networking, meta-filesystems, meta-perl)
meta-freescale, meta-freescale-3rdparty, meta-freescale-distro
meta-imx (meta-imx-bsp, meta-imx-sdk)
meta-arm, meta-arm-toolchain
meta-clang
meta-qt6
meta-browser/meta-chromium
meta-virtualization
meta-security (meta-parsec, meta-tpm)
meta-nxp-connectivity (meta-nxp-matter-baseline, meta-nxp-openthread)
meta-doom
meta-quilter ← Project Speedrun customizations (priority 99)
See yocto-imx/walnascar/sources/meta-quilter/BUILD_GUIDE.md for the full step-by-step build guide.
Quick reference:
# Source environment
cd yocto-imx/walnascar
MACHINE=imx8mmevk DISTRO=fsl-imx-xwayland source imx-setup-release.sh -b build-gnome
# Copy meta-quilter configs
cp sources/meta-quilter/conf/build-gnome/local.conf build-gnome/conf/local.conf
cp sources/meta-quilter/conf/build-gnome/bblayers.conf build-gnome/conf/bblayers.conf
# Build
bitbake imx-image-multimedia
# Flash to SD card
zstdcat tmp/deploy/images/imx8mmevk/imx-image-multimedia-imx8mmevk.wic.zst | dd of=/dev/sdX bs=1M conv=fsyncyocto-imx/walnascar/sources/meta-quilter/README.md— meta-quilter layer overviewyocto-imx/walnascar/sources/meta-quilter/BUILD_GUIDE.md— Full build reproduction guideyocto-imx/walnascar/build-gnome/GNOME_BUILD_NOTES.md— Chronological development log with every issue encountered and resolved