2
0

run-iso-qemu.sh 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #!/usr/bin/env bash
  2. # Boots mjdev-desktop-<version>.iso in QEMU so the wayland desktop can be tried
  3. # without touching the host session. Uses KVM and virtio-gpu GL acceleration
  4. # when available (the desktop needs GL), falls back to plain emulation.
  5. #
  6. # ./run-iso-qemu.sh # boots releases/<app>-<version>.iso (local gtk window)
  7. # ./run-iso-qemu.sh path/to.iso # boots a specific image
  8. # ./run-iso-qemu.sh --vnc # headless: expose the screen over VNC for remote
  9. # # grab + control (127.0.0.1:5900). egl-headless keeps
  10. # # GL working without a host display. Connect with any
  11. # # VNC client / vncsnapshot / gvncviewer.
  12. # MJDEV_QEMU_VNC=1 ./run-iso-qemu.sh # same via env
  13. # MJDEV_QEMU_VNC_DISPLAY=2 ./run-iso-qemu.sh --vnc # 127.0.0.1:5902
  14. # MJDEV_QEMU_VNC_HOST=0.0.0.0 ./run-iso-qemu.sh --vnc # listen on all interfaces
  15. set -euo pipefail
  16. HERE="$(cd "$(dirname "$0")" && pwd)"
  17. CATALOG="$HERE/gradle/libs.versions.toml"
  18. read_catalog() { sed -n "s/^$1 *= *\"\(.*\)\"/\1/p" "$CATALOG"; }
  19. APP_NAME="$(read_catalog app-name)"
  20. VERSION="$(read_catalog app-pkg-version)"
  21. VNC="${MJDEV_QEMU_VNC:-0}"
  22. ISO=""
  23. for a in "$@"; do
  24. case "$a" in
  25. --vnc) VNC=1;;
  26. *) ISO="$a";;
  27. esac
  28. done
  29. ISO="${ISO:-$HERE/releases/$APP_NAME-$VERSION.iso}"
  30. RAM="${MJDEV_QEMU_RAM:-4096}"
  31. CPUS="${MJDEV_QEMU_CPUS:-4}"
  32. VNC_HOST="${MJDEV_QEMU_VNC_HOST:-127.0.0.1}"
  33. VNC_DISPLAY="${MJDEV_QEMU_VNC_DISPLAY:-0}"
  34. QEMU_WIDTH="${MJDEV_QEMU_WIDTH:-1024}"
  35. QEMU_HEIGHT="${MJDEV_QEMU_HEIGHT:-768}"
  36. command -v qemu-system-x86_64 >/dev/null 2>&1 || { echo "qemu-system-x86_64 not found (apt install qemu-system-x86)"; exit 1; }
  37. [ -f "$ISO" ] || { echo "iso not found: $ISO"; echo "build it first: ./gradlew makeIso"; exit 1; }
  38. ARGS=(
  39. -m "$RAM"
  40. -smp "$CPUS"
  41. -cdrom "$ISO"
  42. -boot d
  43. # absolute-position pointer: without it qemu emulates a relative PS/2 mouse, which needs an
  44. # explicit grab-click and maps host motion to guest deltas — clicks (e.g. the bar's menu
  45. # icon) land in the wrong place or don't register at all until grabbed.
  46. -usb
  47. -device usb-tablet
  48. )
  49. # hardware acceleration when the host exposes it
  50. if [ -w /dev/kvm ]; then
  51. ARGS+=(-enable-kvm -cpu host)
  52. echo ">> KVM enabled"
  53. else
  54. echo ">> /dev/kvm not available - software emulation (slow)"
  55. fi
  56. if [ "$VNC" = "1" ]; then
  57. # headless screen grab + control over VNC. egl-headless renders the guest GPU
  58. # output (so the wayland compositor still gets real GL) and hands the framebuffer
  59. # to qemu's built-in VNC server; VNC injects keyboard/pointer back into the guest.
  60. # Independent of the guest compositor — no in-image vnc server / wlroots screencopy
  61. # needed. Listens on $VNC_HOST:(5900+$VNC_DISPLAY).
  62. if qemu-system-x86_64 -display help 2>/dev/null | grep -q egl-headless; then
  63. ARGS+=(-device "virtio-vga-gl,xres=$QEMU_WIDTH,yres=$QEMU_HEIGHT" -display "egl-headless,gl=on")
  64. else
  65. echo ">> egl-headless unavailable - VNC without GL (compositor falls back to llvmpipe)"
  66. ARGS+=(-device "virtio-vga,xres=$QEMU_WIDTH,yres=$QEMU_HEIGHT")
  67. fi
  68. ARGS+=(-vnc "$VNC_HOST:$VNC_DISPLAY")
  69. echo ">> VNC: connect to $VNC_HOST:$((5900 + VNC_DISPLAY)) (e.g. vncviewer $VNC_HOST:$VNC_DISPLAY)"
  70. # virtio-gpu with GL gives the wayland compositor a real GPU path; gtk display
  71. # with gl=on renders it on the host. Fall back to a plain virtio-gpu if the
  72. # host qemu has no GL display backend. xres/yres pin the guest's initial mode so
  73. # the window opens at a predictable size instead of whatever default the guest picks.
  74. elif qemu-system-x86_64 -display help 2>/dev/null | grep -q gtk; then
  75. # zoom-to-fit=off: without it gtk scales the guest framebuffer to whatever window
  76. # size it started with instead of sizing the window to xres/yres.
  77. ARGS+=(-device "virtio-vga-gl,xres=$QEMU_WIDTH,yres=$QEMU_HEIGHT" -display gtk,gl=on,zoom-to-fit=off)
  78. else
  79. ARGS+=(-device "virtio-vga,xres=$QEMU_WIDTH,yres=$QEMU_HEIGHT" -display sdl)
  80. fi
  81. echo ">> booting $ISO"
  82. exec qemu-system-x86_64 "${ARGS[@]}"