El tema de cursor ya cargaba (sin "Failed to load cursor theme") pero el cursor seguía apareciendo/desapareciendo: kwin usaba el plano de cursor por HARDWARE del DRM, que en virtio-gpu con render software no se presenta bien. KWIN_FORCE_SW_CURSOR=1 ⇒ kwin compone el cursor dentro del framebuffer principal (software) ⇒ visible y estable. Verificado por screendump: la flecha breeze aparece compuesta en el scanout. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
216 lines
11 KiB
Bash
216 lines
11 KiB
Bash
#!/bin/sh
|
|
# plasma-start-qemu.sh — arranca Plasma en una VM QEMU con render por SOFTWARE (kms_swrast/llvmpipe)
|
|
# sobre el DRM de virtio-gpu (/dev/dri/card0). Derivado de plasma-start-metal.sh pero SIN hardware iris:
|
|
# en QEMU no hay GPU real, así que kwin presenta por el DRM de virtio con EGL/GBM de software.
|
|
#
|
|
# Se instala como /usr/bin/plasma-start en la imagen QEMU y lo AUTO-LANZA /etc/profile (console-getty
|
|
# autologin). Trae los arreglos de la campaña KDE 2026-07: QT_QUICK_BACKEND=software (plasmashell no crea
|
|
# contexto GL sin él), QT_QPA_FONTDIR (mata los tofu; qtbase se construyó sin fontconfig), kdeglobals +
|
|
# QT_QPA_PLATFORMTHEME=kde (iconos + estilo Breeze), kactivitymanagerd (plasmashell aborta sin él).
|
|
#
|
|
# Logs: /tmp/{kwin,kamd,plasmashell}.log + tee a /dev/console. Salir: matar kwin.
|
|
set -u
|
|
# getty ejecuta este script DIRECTO (no vía login shell) ⇒ PATH viene vacío: mkdir/tr/cat/dbus-daemon
|
|
# no se hallan y kwin nunca levanta. Seteamos PATH explícito (busybox + userland KDE) ANTES de todo.
|
|
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
|
# tee a la consola gráfica (tty0) Y al serial (ttyS0) — el host captura ttyS0 con -serial file:
|
|
say() { echo "== plasma-qemu :: $*" | tee -a /dev/console /dev/ttyS0 2>/dev/null; }
|
|
dump() { echo "---- $1 ----" > /dev/ttyS0 2>/dev/null; cat "$1" > /dev/ttyS0 2>/dev/null; }
|
|
|
|
export LD_LIBRARY_PATH=/usr/lib64:/usr/lib/qt6:/usr/lib:/lib
|
|
export QT_PLUGIN_PATH=/usr/lib64/qt6/plugins:/usr/lib/qt6/plugins
|
|
export QML2_IMPORT_PATH=/usr/lib64/qt6/qml:/usr/lib/qt6/qml
|
|
export QML_IMPORT_PATH=$QML2_IMPORT_PATH
|
|
export XDG_DATA_DIRS=/usr/share
|
|
export XDG_RUNTIME_DIR=/run/user/0
|
|
export XDG_CONFIG_HOME=/root/.config
|
|
export XDG_CACHE_HOME=/root/.cache
|
|
export HOME=/root
|
|
|
|
# --- render por software sobre virtio-gpu ---
|
|
export LIBGL_ALWAYS_SOFTWARE=1
|
|
export GALLIUM_DRIVER=llvmpipe
|
|
# GBM_ALWAYS_SOFTWARE=1 — EL FIX del segfault (MURO 2, verificado en fuente mesa 24.0.9). virtio-gpu-pci
|
|
# SIN 3D expone un nodo KMS-only (no render-capable). Con MESA_LOADER_DRIVER_OVERRIDE solo, gbm carga
|
|
# kms_swrast pero deja gbm_dri->software=FALSE (dri_screen_create tiene éxito ⇒ nunca cae al fallback
|
|
# dri_screen_create_sw, el único que setea software=true). Entonces dri2_initialize_drm entra al bloque
|
|
# `if(!software)` y llama gbm_dri->mesa->queryCompatibleRenderOnlyDeviceFd() — NULL en el driver software
|
|
# ⇒ SIGSEGV. GBM_ALWAYS_SOFTWARE=1 fuerza dri_screen_create_sw ⇒ software=true ⇒ se salta ese bloque.
|
|
export GBM_ALWAYS_SOFTWARE=1
|
|
# kms_swrast (NO swrast): kwin abre card0 como dispositivo KMS y crea un gbm device sobre él ⇒ necesita
|
|
# el driver de software para KMS (dumb buffers). Con 'swrast' a secas gbm_create_device falla ("Failed
|
|
# to create gbm device"). kms_swrast_dri.so está en /usr/lib/dri.
|
|
export MESA_LOADER_DRIVER_OVERRIDE=kms_swrast
|
|
export LIBGL_DRIVERS_PATH=/usr/lib/dri
|
|
export QT_QUICK_BACKEND=software
|
|
# LP_NUM_THREADS=1: llvmpipe SINCRÓNICO (sin pool de threads del rasterizador) — el JIT multi-thread de
|
|
# llvmpipe segfaultea al componer la 1ra superficie en esta VM. KWIN_DRM_NO_AMS=1: desactiva atomic
|
|
# modesetting (algunos virtio-gpu lo rompen). Ambos son fixes conocidos de kwin/llvmpipe en VMs.
|
|
export LP_NUM_THREADS=1
|
|
# KWIN_DRM_NO_AMS (legacy modeset) fue una corazonada del segfault (que resultó ser GBM_ALWAYS_SOFTWARE).
|
|
# Dejamos atomic (virtio soporta atomic nativo; legacy es el frágil).
|
|
# export KWIN_DRM_NO_AMS=1
|
|
#
|
|
# EL FIX DEL NEGRO: virtio-gpu ADVIERTE soportar drmModeAddFB2WithModifiers pero RECHAZA el modifier
|
|
# explícito (aún LINEAR=0) con EINVAL ⇒ "Failed to create a framebuffer" ⇒ sin output layer ⇒ NEGRO.
|
|
# El modeset inicial usa un buffer dumb (sin modifiers) y SÍ pinta (por eso se ve el wallpaper un instante),
|
|
# pero los buffers del compositor van por AddFB2WithModifiers y fallan ⇒ vuelve a negro. KWIN_DRM_USE_MODIFIERS=0
|
|
# fuerza a kwin a usar drmModeAddFB2 plano (modifier implícito) que virtio-gpu sí acepta.
|
|
export KWIN_DRM_USE_MODIFIERS=0
|
|
# KWIN_COMPOSE=Q — compositor QPainter (raster de Qt directo al buffer, SIN escena llvmpipe). El
|
|
# compositor GL por defecto usa el rasterizador de llvmpipe, cuyo hilo SEGFAULTEA en lp_rast_clear_color
|
|
# → util_fill_rect al limpiar el color buffer (backtrace del core.llvmpipe-0): kwin pinta unos frames y
|
|
# muere → "vuelve a negro". QPainter no arma escenas llvmpipe ⇒ esquiva ese crash. (El segfault viejo con
|
|
# =Q era el de gbm-init, ya resuelto por GBM_ALWAYS_SOFTWARE.) llvmpipe sigue disponible para gbm/EGL.
|
|
export KWIN_COMPOSE=Q
|
|
export QT_QPA_PLATFORM=wayland
|
|
export QT_QPA_PLATFORMTHEME=kde
|
|
export QT_QPA_FONTDIR=/usr/share/fonts/dejavu
|
|
# cursor: kwin busca el tema "default" y no lo halla ("Failed to load cursor theme") ⇒ cursor invisible.
|
|
# Apuntamos al breeze_cursors del rootfs (115 cursores) por env + kcminputrc (kwin lee [Mouse] cursorTheme).
|
|
export XCURSOR_THEME=breeze_cursors
|
|
export XCURSOR_PATH=/usr/share/icons:/usr/share/pixmaps
|
|
export XCURSOR_SIZE=24
|
|
# El tema ya carga (sin "Failed to load cursor theme") pero el cursor SIGUE invisible: kwin usa el plano
|
|
# de cursor por HARDWARE del DRM, y en virtio-gpu con render software ese plano no se presenta (aparece y
|
|
# desaparece). KWIN_FORCE_SW_CURSOR=1 ⇒ kwin dibuja el cursor DENTRO del framebuffer principal (software)
|
|
# ⇒ visible y estable en VMs sin GPU real.
|
|
export KWIN_FORCE_SW_CURSOR=1
|
|
|
|
# --- DIAGNÓSTICO del segfault-al-1er-composite (MURO 2) ---
|
|
# Sin gdb en la imagen: subimos el logging categorizado de kwin (kwin_core/drm/scene/opengl) + mesa/egl
|
|
# para ver EN QUÉ FASE muere (bind EGL, alloc GBM, JIT llvmpipe, o el paint real). DIAG=0 para apagarlo.
|
|
if [ "${DIAG:-1}" = 1 ]; then
|
|
export QT_LOGGING_RULES="kwin_*=true;qt.qpa.*=true"
|
|
export EGL_LOG_LEVEL=debug
|
|
export LIBGL_DEBUG=verbose
|
|
export MESA_DEBUG=1
|
|
export GALLIUM_HUD= # no HUD, sólo para dejar constancia
|
|
export KWIN_DRM_DEBUG=1
|
|
fi
|
|
|
|
mkdir -p "$XDG_RUNTIME_DIR" "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" /run/dbus /root
|
|
chmod 700 "$XDG_RUNTIME_DIR"
|
|
[ -s /etc/machine-id ] || cat /proc/sys/kernel/random/uuid 2>/dev/null | tr -d - > /etc/machine-id
|
|
|
|
# kdeglobals: iconos + estilo Breeze (sin esto Qt cae a hicolor vacío = escritorio pelado)
|
|
cat > "$XDG_CONFIG_HOME/kdeglobals" <<EOF
|
|
[Icons]
|
|
Theme=breeze
|
|
|
|
[General]
|
|
ColorScheme=BreezeLight
|
|
widgetStyle=Breeze
|
|
|
|
[KDE]
|
|
widgetStyle=Breeze
|
|
EOF
|
|
|
|
# kcminputrc: el tema de cursor que kwin lee al arrancar (además del env XCURSOR_THEME)
|
|
cat > "$XDG_CONFIG_HOME/kcminputrc" <<EOF
|
|
[Mouse]
|
|
cursorTheme=breeze_cursors
|
|
cursorSize=24
|
|
EOF
|
|
|
|
say "GPU DRM: $(ls /dev/dri/ 2>/dev/null | tr '\n' ' ')"
|
|
[ -e /dev/dri/card0 ] || say "!! no hay /dev/dri/card0 — ¿virtio-gpu no cargó? (dmesg | grep -i drm)"
|
|
|
|
# D-Bus de SISTEMA: sin él, kf.solid/udisks2 spamea "Not connected to D-Bus server" y powerdevil + los
|
|
# applets de dispositivos/energía no inician. Escucha en el path estándar /run/dbus/system_bus_socket
|
|
# (los clientes lo hallan por DBUS_SYSTEM_BUS_ADDRESS por defecto ⇒ no exportamos nada). Corre como root
|
|
# y hace setuid a messagebus (uid 81, sembrado en el passwd de la imagen). No hay udisksd/upowerd reales
|
|
# en el rootfs ⇒ no habrá discos/batería, pero el bus existe y solid deja de errorear en cada poll.
|
|
mkdir -p /run/dbus /var/lib/dbus
|
|
cp -f /etc/machine-id /var/lib/dbus/machine-id 2>/dev/null || true
|
|
if [ ! -S /run/dbus/system_bus_socket ]; then
|
|
if dbus-daemon --system --fork 2>/tmp/dbus-system.log; then
|
|
say "system bus ON (/run/dbus/system_bus_socket)"
|
|
else
|
|
say "!! system bus NO arrancó:"; dump /tmp/dbus-system.log
|
|
fi
|
|
fi
|
|
|
|
# D-Bus de sesión
|
|
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
|
|
DBUS_SESSION_BUS_ADDRESS=$(dbus-daemon --session --fork --print-address 2>/dev/null)
|
|
export DBUS_SESSION_BUS_ADDRESS
|
|
fi
|
|
say "dbus: ${DBUS_SESSION_BUS_ADDRESS:-NO ARRANCO}"
|
|
|
|
# --- CORE DUMP del segfault (MURO 2): sin gdb en la imagen, sacamos un core y lo leemos con el gdb del
|
|
# host apuntando al rootfs fundido. Localiza el frame culpable (libLLVM/llvmpipe vs kwin vs mesa). ---
|
|
if [ "${DIAG:-1}" = 1 ]; then
|
|
ulimit -c unlimited 2>/dev/null || true
|
|
# /core en la RAÍZ ext4 (NO /tmp: es tmpfs=RAM y se pierde al matar QEMU). Tras el crash hacemos sync
|
|
# explícito ⇒ el core persiste en la imagen aunque después mate QEMU con SIGKILL.
|
|
echo '/core.%e.%p' > /proc/sys/kernel/core_pattern 2>/dev/null || true
|
|
say "core dumps ON (pattern=$(cat /proc/sys/kernel/core_pattern 2>/dev/null), ulimit -c=$(ulimit -c))"
|
|
fi
|
|
|
|
# SÓLO el card de virtio-gpu: el efifb/simpledrm sobrevive como 2º DRM ("Unknown-1", read-only) y kwin
|
|
# intenta manejar ambos outputs ⇒ conflicto de presentación ⇒ pinta y vuelve a NEGRO. Detectamos el card
|
|
# cuyo driver es virtio_gpu (robusto al numerado card0/card1 que cambia entre boots) y se lo pasamos a kwin.
|
|
VIRTIO_CARD=
|
|
for c in /dev/dri/card*; do
|
|
n=$(basename "$c")
|
|
drv=$(readlink -f "/sys/class/drm/$n/device/driver" 2>/dev/null)
|
|
case "$drv" in *virtio*) VIRTIO_CARD="$c"; break;; esac
|
|
done
|
|
if [ -n "$VIRTIO_CARD" ]; then
|
|
export KWIN_DRM_DEVICES="$VIRTIO_CARD"
|
|
say "KWIN_DRM_DEVICES=$VIRTIO_CARD (ignorando efifb/simpledrm)"
|
|
else
|
|
say "!! no hallé card virtio_gpu; kwin verá todos los DRM (posible doble output)"
|
|
fi
|
|
|
|
# Compositor sobre el DRM de virtio (software EGL/GBM vía kms_swrast). SIN --virtual: presenta al display.
|
|
say "lanzando kwin_wayland (DRM virtio, software GL)..."
|
|
/usr/bin/kwin_wayland --drm >/tmp/kwin.log 2>&1 &
|
|
KWIN=$!
|
|
# stream EN VIVO del kwin.log al serial (busybox sed NO soporta -u ⇒ nada de sed/pipes: tail -f directo).
|
|
( echo "==== kwin.log (stream vivo) ===="; tail -f /tmp/kwin.log ) > /dev/ttyS0 2>/dev/null &
|
|
TAILPID=$!
|
|
i=0
|
|
while [ $i -lt 60 ]; do
|
|
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] && break
|
|
kill -0 $KWIN 2>/dev/null || { say "!! kwin murio:"; dump /tmp/kwin.log; exec /bin/sh; }
|
|
i=$((i+1)); sleep 0.5
|
|
done
|
|
if [ -S "$XDG_RUNTIME_DIR/wayland-0" ]; then
|
|
say "compositor OK (wayland-0)"
|
|
else
|
|
say "!! kwin no expuso wayland-0:"; dump /tmp/kwin.log; exec /bin/sh
|
|
fi
|
|
export WAYLAND_DISPLAY=wayland-0
|
|
|
|
# kactivitymanagerd: plasmashell ABORTA sin el
|
|
KAMD=$(ls /usr/lib*/libexec/kactivitymanagerd 2>/dev/null | head -1)
|
|
[ -n "$KAMD" ] && { "$KAMD" >/tmp/kamd.log 2>&1 & sleep 2; say "kactivitymanagerd lanzado"; }
|
|
|
|
say "lanzando plasmashell..."
|
|
/usr/bin/plasmashell >/tmp/plasmashell.log 2>&1 &
|
|
sleep 8
|
|
say "procesos: $(ps axo comm 2>/dev/null | grep -E 'kwin|plasma' | sort -u | tr '\n' ' ')"
|
|
say "escritorio arriba (o mira /tmp/plasmashell.log). Ctrl-C mata la sesion."
|
|
dump /tmp/plasmashell.log
|
|
# monitor de estado: cada 15s dice si kwin/plasmashell siguen vivos ⇒ si vuelve a negro, sabremos si
|
|
# fue plasmashell que murió (containment) o kwin/output. (busybox pgrep -c cuenta procesos.)
|
|
( n=0; while sleep 15; do
|
|
n=$((n+1))
|
|
say "STATUS +$((n*15))s: kwin=$(pgrep kwin_wayland 2>/dev/null | wc -l) plasmashell=$(pgrep plasmashell 2>/dev/null | wc -l)"
|
|
done ) &
|
|
wait $KWIN
|
|
RC=$?
|
|
# kwin salió ⇒ volcá su log para saber por qué (backend QPainter, DRM, modeset…)
|
|
say "kwin salió (código $RC) — volcando kwin.log:"
|
|
dump /tmp/kwin.log
|
|
# copiar los logs a la ext4 raíz y SYNC ⇒ core + logs persisten en la imagen para leer desde el host
|
|
# con debugfs/gdb (el SIGKILL de QEMU no sincroniza; sin este sync se pierde todo lo de esta sesión).
|
|
cp /tmp/kwin.log /kwin.log 2>/dev/null || true
|
|
cp /tmp/plasmashell.log /plasmashell.log 2>/dev/null || true
|
|
say "cores en /: $(ls -la /core.* 2>/dev/null | tr '\n' ' ' || echo NINGUNO)"
|
|
sync; sync
|
|
say "== disco SYNCED (core+logs en la raíz). serial CONGELADO. matá QEMU desde el host. =="
|
|
sleep 3600
|