Multiseat
Déport d'affichage
01/2009 : j'ai testé le déport d'affichage à partir d'une 2e machine se connectant à Olive. J'ai utilisé Wimpy pour tester la solution en lançant X via un :
X :1 -query olive
X démarre, les applications graphiquement légères fonctionnent bien mais OpenOffice est lent et saccadé et les vidéos ne se jouent pas . C'est “normal”, ce n'est qu'un déport d'affichage, le rendu est calculé sur le serveur puis transmis via le réseau au client pour un bête affichage à la différence d'un X avec une carte graphique locale qui déleste le processeur d'un certains nombre de tâches.
Debian/Lenny
Intégration difficile
02/2009 : ce 2e essai nécessite une carte graphique dédiée à chaque place physique.
Par contre, ma carte mère, ne supporte l'utilisation de sa carte graphique intégrée en plus d'une carte additionnelle (limitation du BIOS )
J'ai ajouté une GeForce 7600 GT en PCI-Express et une GeForce FX 5200 (elle chauffait trop) Ati Radeon 7000 sur bus PCI.
La version 7.2 de Xorg inclus des options permettant de lancer plusieurs X sur un même VT à l'aide de des options -sharevts
et -novtswitch
. Cela autorise plusieurs instance de X à s'exécuter réellement simultanément à la différence du lancement traditionnel de plusieurs X sur des displays différents mais sur un même VT et nécessitant de basculer de l'un à l'autre avec les touches CTRL + ALT + F7 ou CTRL + ALT + F8.
Par contre, l'intégration du multiseat dans Debian Lenny est inexistante. Après avoir passé plusieurs très longues soirées à tenter de faire marcher l'ensemble, voici l'état des lieux :
- il faut configurer le bios pour démarrer sur la carte graphique du bus PCI, sinon celle ci n'est reconnue qu'avec 0 Kbits de ram…
- à cause de ce paramétrage, il faut lancer un X qui “ping” les cartes graphiques avec l'option
-probeonly
afin d'initialiser les cartes graphiques; - Pour démarrer 2 serveurs avec un même fichier de configuration, il faut spécifier dedans des sections
ServerLayout
pour chaque place en définissant écran, clavier, souris; - GDM n'est pas en mesure de lancer 2 X avec 2 utilisateurs différents, il faut alors s'en passer et tout faire à sa place : lancement du X avec le
DISPLAY
, le user, leServerLayout
correspondant, lancement du gestionnaire de bureau…
Le problème de cette configuration est qu'elle était très fragile : une mise à jour sur 2 des paquets Xorg
ou des drivers NVidia la cassait. A chaque problème, le WAF prends une claque .
Au final, j'ai verrouillé les mises à jour pour empêcher les problèmes. Mais bien sûr avec le temps, ma distribution vieillissait, je ne pouvais plus installer de nouveaux paquets sans devoir tout mettre à jour…
Configuration manuelle
Voici mes fichiers de configurations et scripts :
le script de démarrage /etc/init.d/multiseat
lance les différentes instances de X de la manière suivante :
- lecture du fichier de configuration
/etc/multiseat.conf
; - pour chaque seat lue, invoque
startx-autologin
avec le user donné et en lui passant le display et layout; startx-autologin
est en charge de lancer le X et de la relancer lorsqu'il plante avec un maximum de 3 tentatives;/etc/X11/xorg.conf.multiseat
est la conf de X et contient l'agencement des places Place > Ecran > Carte graphique > Clavier > Souris. Il y a également le chemin du device précis dans/dev
pour la souris ou le clavier.
- /etc/multiseat.conf
[place1] layout=Layout1 user=user1 display=:0 [place2] layout=Layout2 user=user2 display=:1
- /etc/init.d/multiseat
#! /bin/bash ### BEGIN INIT INFO # Provides: multiseat # Should-Start: console-screen kbd acpid dbus hal network-manager # Required-Start: $local_fs $remote_fs x11-common # Required-Stop: $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: xorg autologin multiseat ### END INIT INFO # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin CONF="/etc/multiseat.conf" DESC="Multiseat" NAME=multiseat DAEMON=/usr/local/bin/startx-autologin # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 #exit 0 # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. . /lib/lsb/init-functions declare -Ax layout declare -Ax user declare -Ax display # # Function that starts the daemon/service # do_start() { ARG_SEAT=$1 # returns # 0 if daemon has been started echo -n " ${ARG_SEAT}" rm -f /var/run/xorg-autologin-${layout[$ARG_SEAT]}.exit /bin/su -l ${user[$ARG_SEAT]} -c "${DAEMON} ${display[$ARG_SEAT]} ${layout[$ARG_SEAT]}" >/home/${user[$ARG_SEAT]}/.xsession-errors 2>&1 & return 0 } # # Function that stops the daemon/service # do_stop() { ARG_SEAT=$1 # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred echo -n " ${ARG_SEAT}" touch /var/run/xorg-autologin-${layout[$ARG_SEAT]}.exit pkill -u ${user[$ARG_SEAT]} startx-autologin pkill -u ${user[$ARG_SEAT]} xinit return 0 } print_usage() { cat >&2 << EOC Usage: $SCRIPTNAME start [seat] stop [seat] restart [seat]} EOC exit 3 } read_conf() { while IFS='= ' read var val do if [[ $var == \[*] ]] then section=$var elif [[ $val ]] then eval "$var$section=$val" fi done < $CONF } check_user() { if [ "${user[$1]}" == "" ]; then echo -n " seat '$1' unknown" log_end_msg 1 exit 1 fi } read_conf case "$1" in start) log_daemon_msg "Starting $DESC" set +e if [ "$#" -eq 2 ]; then check_user $2 do_start $2 elif [ "$#" -eq 1 ]; then for K in "${!layout[@]}"; do do_start $K; done else echo print_usage fi set -e case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; stop) log_daemon_msg "Stopping $DESC" if [ "$#" -eq 2 ]; then check_user $2 do_stop $2 elif [ "$#" -eq 1 ]; then for K in "${!layout[@]}"; do do_stop $K; done else echo print_usage fi set -e case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; restart) shift $0 stop $* sleep 1 $0 start $* ;; *) print_usage ;; esac :
- /usr/local/bin/startx-autologin
#!/bin/sh NB_RETRY=3 EXIT_FILE=/var/run/xorg-autologin-$2.exit start() { NB=0 while [ $NB_RETRY -eq 0 ] || [ $NB -lt $NB_RETRY ] do echo "Exec nb $NB $*" $* #if [ $? -eq 0 -o -f $EXIT_FILE ]; # le process est tjs relance if [ -f $EXIT_FILE ]; then exit fi ps=$(ps auxww | grep -v grep) # reboot echo $ps | grep -q "/etc/rc.d/rc 6" ret=$? if [ $ret -eq 0 ] then exit fi # shutdown echo $ps | grep -q "/etc/rc.d/rc 0" ret=$? if [ $ret -eq 0 ] then exit fi NB=$(($NB + 1)) sleep 2 done } CMD="/usr/bin/xinit -- $1 -layout $2 -sharevts -novtswitch" start $CMD
- /etc/X11/xorg.conf.multiseat
Section "ServerLayout" Identifier "Layout2" Screen 0 "LCD2" 0 0 InputDevice "Mouse2" "CorePointer" InputDevice "Keyboard2" "CoreKeyboard" EndSection Section "ServerLayout" Identifier "Layout1" Screen 0 "LCD1" 0 0 InputDevice "Mouse1" "CorePointer" InputDevice "Keyboard1" "CoreKeyboard" EndSection Section "Files" FontPath "/usr/X11R6/lib/X11/fonts/local/" FontPath "/usr/X11R6/lib/X11/fonts/misc/" FontPath "/usr/X11R6/lib/X11/fonts/75dpi/:unscaled" FontPath "/usr/X11R6/lib/X11/fonts/100dpi/:unscaled" FontPath "/usr/X11R6/lib/X11/fonts/Type1/" FontPath "/usr/X11R6/lib/X11/fonts/Speedo/" FontPath "/usr/X11R6/lib/X11/fonts/75dpi/" FontPath "/usr/X11R6/lib/X11/fonts/100dpi/" EndSection Section "InputDevice" Identifier "Mouse1" Driver "evdev" Option "Protocol" "auto" Option "Device" "/dev/input/by-id/usb-Microsoft_Corporation_Microsoft_®_Laser_Mouse_6000-event-mouse" Option "Emulate3Buttons" "no" Option "ZAxisMapping" "4 5" Option "GrabDevice" "on" EndSection Section "InputDevice" Identifier "Keyboard1" Driver "evdev" Option "Device" "/dev/input/by-path/platform-i8042-serio-0-event-kbd" Option "XkbModel" "microsoft" Option "XkbRules" "xorg" Option "XkbLayout" "fr" Option "XkbOptions" "altwin:super_win" Option "GrabDevice" "on" EndSection Section "InputDevice" Identifier "Mouse2" Driver "evdev" Option "Protocol" "auto" Option "Device" "/dev/input/by-id/usb-Logitech_USB_Optical_Mouse-event-mouse" Option "Emulate3Buttons" "no" Option "ZAxisMapping" "4 5" Option "GrabDevice" "on" EndSection Section "InputDevice" Identifier "Keyboard2" Driver "evdev" Option "Device" "/dev/input/by-id/usb-_USB_Keyboard-event-kbd" Option "XkbModel" "pc105" Option "XkbLayout" "fr" Option "GrabDevice" "on" EndSection Section "Monitor" Identifier "Monitor_iiyama" ModeLine "1680x1050_60.00" 147.14 1680 1784 1968 2256 1050 1051 1054 1087 -hsync +vsync ModelName "Idek Iiyama PLE2003WSV" HorizSync 31.0 - 83.0 VertRefresh 55.0 - 76.0 EndSection Section "Monitor" Identifier "Monitor_iiyama2" VendorName "Unknown" ModelName "Idek Iiyama PL2480H" HorizSync 30.0 - 83.0 VertRefresh 55.0 - 76.0 EndSection Section "Device" Identifier "nvidia 7600 GT" Driver "nvidia" Option "NoLogo" "true" Option "NvAGP" "1" Option "TripleBuffer" "true" BusID "PCI:1:0:0" EndSection Section "Device" Identifier "radeon 7000" Driver "ati" Screen 0 BusID "PCI:7:0:0" EndSection Section "Screen" Identifier "LCD1" Device "nvidia 7600 GT" Monitor "Monitor_iiyama2" DefaultDepth 24 Option "metamodes" "1920x1080_60_0 +0+0; 1680x1050_60_0 +0+0" SubSection "Display" Depth 24 EndSubSection EndSection Section "Screen" Identifier "LCD2" Device "radeon 9200" Monitor "Monitor_iiyama" SubSection "Display" Viewport 0 0 Modes "1680x1050_60.00" "1440x900" EndSubSection EndSection Section "ServerFlags" Option "HandleSpecialKeys" "Always" Option "AutoAddDevices" "off" Option "AutoEnableDevices" "off" Option "AllowEmptyInput" "off" EndSection
Ubuntu
14.04 : Works out of the box
J'ai refait ma configuration multiseat sous Ubuntu en m'aidant de cette doc.
La configuration s'est grandement simplifiée depuis Xorg 7.2 et est maintenant très bien intégrée dans la distribution, il suffit de :
- tagguer les périphériques souris, clavier, carte graphique à l'aide de règles UDEV
- ajouter un fichier de configuration Xorg par seat
- configurer LightDM
Plus besoin d'écrire de script de lancement de X ni de se battre avec un “ping” des cartes graphiques pendant le boot…
Matériel
Le choix de la carte graphique a été compliqué car je veux du matériel silencieux et pas trop vieux. Mais, qui dit silence, dit moins de performance… De plus, je veux refaire ma configuration multi-seat et ajouter une place supplémentaire ⇒ il faut donc 3 cartes graphiques :
- carte n°1 : Comme toute les CM de cette génération, elle est équipée d'une carte graphique intégrée. Contrairement à ma CM précédente, sur celle ci, il est possible d'avoir la carte intégrée active en même temps que des cartes additionnelles sur bus PCI-e, ce qui me permet de n'avoir à ajouter que 2 autres cartes.
- carte n°2 : L'ATI Radéon commence à être juste même en bureautique : elle n'a pas assez de RAM pour afficher un bureau en 1680×1050 avec une profondeur de couleur de 32 bits. De plus, du tearing apparait lors de la lecture des vidéos car la carte n'offre aucune accélération matérielle et la lecture s'effectue avec un driver
X11
au lieu de passer parxv
. J'ai choisi une Geforce GT 610 fanless en PCI-e pour servir de carte graphique. Elle ne chauffe pas trop grâce à son radiateur imposant.
- carte n°3 : La GeForce GTX 750 Ti en PCI-e m'a semblé être un bon compromis entre prix, silence et performance. Au final, dans Battlefield, toutes les options sont pratiquement au maximum et le jeu tourne à 60 fps. Il arrive qu'en haut de la tour de transmission sur la map “Paracel Storm” les fps chutent un peu puis reviennent ⇒ le paris a été payant
Configuration
Voici un extrait de mes règles UDEV, l'objectif est d'identifier le périphérique voulu et de le tagguer avec seat0, seat1 ou seat2. Pour les cartes graphiques, il faut ajouter en plus le tag master-of-seat.
- /etc/udev/rules.d/99-multiseat.rules
# périphériques HID # Souris Logitech noir ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c05b", ENV{ID_SEAT}="seat1", TAG+="seat1" # Souris Microsoft Laser 6000 ATTRS{idVendor}=="045e", ATTRS{idProduct}=="00f0", ENV{ID_SEAT}="seat0", TAG+="seat0" # Souris verte ATTRS{idVendor}=="15d9", ATTRS{idProduct}=="0a4f", ENV{ID_SEAT}="seat2", TAG+="seat2" # il est également possible d'affecter une clés USB à une place ATTRS{idVendor}=="13fe", ATTRS{idProduct}=="3e00", ENV{ID_SEAT}="seat1", TAG+="seat1" # ou même un port USB particulier d'un HUB DEVPATH=="/devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4.1/3-4.1.4/*", ENV{ID_SEAT}="seat1", TAG+="seat1" # cartes graphiques # carte nvidia SUBSYSTEM=="drm", KERNEL=="card[0-9]*", ATTRS{vendor}=="0x10de", TAG+="master-of-seat" DEVPATH=="/devices/pci0000:00/0000:00:01.0/0000:01:00.0/*", ENV{ID_SEAT}="seat0", TAG+="seat0" DEVPATH=="/devices/pci0000:00/0000:00:1c.4/0000:06:00.0/*", ENV{ID_SEAT}="seat1", TAG+="seat1" # carte intel integrée SUBSYSTEM=="drm", KERNEL=="card[0-9]*", ATTRS{vendor}=="0x8086", TAG+="master-of-seat" DEVPATH=="/devices/pci0000:00/0000:00:02.0/*", ENV{ID_SEAT}="seat2", TAG+="seat2"
Pour identifier un périphérique plusieurs méthodes peuvent être utilisées :
udevadm info --export-db
Ne choisir que les devices avec TAGS=:seat:
et récupérer les valeurs ATTRS{idVendor}
et ATTRS{idProduct}
.
ou lancer
udevadm monitor
puis brancher le device et tenter de l'identifier. Pour avoir tout les détails :
udevadm info -a -p /devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.2
Optionnellement, un fichier de conf Xorg par seat permet de surcharger la configuration par défaut.
- /etc/X11/xorg.conf.d/90-seat0.conf
Section "Device" Identifier "card0" Driver "nvidia" Option "NoLogo" "True" MatchSeat "seat0" Option "ProbeAllGpus" "false" BusID "PCI:1:0:0" EndSection
- /etc/X11/xorg.conf.d/90-seat2.conf
Section "Device" Identifier "card0" Driver "intel" BusID "PCI:0:2:0" EndSection
LightDM supporte désormais le lancement de plusieurs sessions en parallèle avec le user correspondant et les bonnes options pour X :
- /etc/lightdm/lightdm.conf
[LightDM] logind-load-seats=true logind-check-graphical=true [Seat:seat0] xserver-config=/etc/X11/xorg.conf.d/90-seat0.conf autologin-user=user1 [Seat:seat1] xserver-config=/etc/X11/xorg.conf.d/90-seat1.conf autologin-user=user2 [Seat:seat2] autologin-user=user3
Reboot et magie ! Les 3 écrans s'allument !
16.04 : évolutions
Ma crainte lors de l'upgrade en 16.04 était de casser cette configuration, mais tout s'est passé sans trop de problèmes mais 2 choses ont changées : l'affectation d'un display et le son
DISPLAY
Les display ne sont plus fixes entre chaque reboot, ainsi l'assise seat1
se verra affecté le display :0
ou :1
ou :2
en fonction de l'âge du capitaine et il n'est pas possible de fixer cela
Pour valoriser correctement la variable d'environnement DISPLAY
, un petit shell dans le ~/.zshrc
ou ~/.bashrc
est à ajouter :
export DISPLAY=$(w -oush | grep $USER | cut -d: -f 2 | awk '{print ":"$1}')
Son
Dans ma configuration précédente, j'avais supprimé les paquets relatifs à pulseaudio
et les programmes fonctionnait avec alsa
directement mais pulseaudio
est désormais légion en 16.04.
Le soucis est qu'un démon pulseaudio
par utilisateur est lancé avec chaque session et qu'il semble y avoir un accès exclusif à la carte son. Seule une session pouvait jouer du son et les autres se retrouvait avec un driver Dummy Ouput
.
Les utilisateurs de ma configuration sont proches physiquement et partagent les mêmes enceintes branchées à une la carte son de la carte mère. Je n'ai pas besoin d'avoir une carte audio par utilisateur. La méthode la plus simple pour résoudre ce problème est de lancer pulseaudio
en mode system-wide
pour partager le même matériel audio. Il faut juste [https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/WhatIsWrongWithSystemWide/|être conscient des risques].
Pour lancer pulseaudio
au boot, créer un service systemd
en éditant le fichier /etc/systemd/system/pulseaudio-system.service
:
- /etc/systemd/system/pulseaudio-system.service
[Unit] Description=PulseAudio Daemon System Wide [Install] WantedBy=multi-user.target [Service] PrivateTmp=true ExecStart=/usr/bin/pulseaudio --system --realtime --disallow-exit --no-cpu-limit --daemonize=no ExecReload=/bin/kill -HUP $MAINPID
Recharger la configuration de systemd
sudo systemctl daemon-reload
Ajouter les utilisateurs au groupe pulse-access
sudo useradd -G pulse-access <user>
Editer le fichier de configuration /etc/pulse/daemon.conf
pour mettre les valeurs suivantes :
- /etc/pulse/daemon.conf
daemonize = yes system-instance = yes
Un reboot et normalement tout est bon !
Systemd
Pour connaitre les différentes places affectées, la commande loginctl
du paquet systemd
permet de lister les utilisateurs connectés :
loginctl SESSION UID USER SEAT c1 1002 user3 seat2 c3 1001 user2 seat1 c2 1000 user1 seat0
Il est également de les énumérer de la manière suivante :
w -oush user3 :2 ? mate-session user1 tty7 :0 4:53m cinnamon-session --session cinnamon user2 :1 ? cinnamon-session --session cinnamon
Windows 8
Aster
Pour jouer à Battlefield, il faut impérativement un Windows, donc j'ai mis un dual boot. Mais pendant que je joue, le WAF est au plus bas . J'ai recherché des logiciels faisant la même chose sous Windows et j'ai acheté Aster. Via une interface graphique assez simple, il est possible de configurer plusieurs utilisateurs tout en gardant la possibilité de jouer sur la place principale.
Configuration
L'interface permet d'affecter un clavier / souris / carte vidéo à une seat et de sélectionner les utilisateurs correspondant. L'ensemble démarre automatiquement au boot de Windows.
VM Ubuntu
Le WAF n'est pas encore suffisant : l'accès sous Windows aux fichiers stockés sur la partition Linux n'est pas simple. De plus, je ne voulais pas imposer un changement d'interface graphique Windows ou Gnome lorsque je joue. J'ai testé et mis en place une VM Ubuntu possédant un disque virtuel mappé sur la partition Linux du disque physique.
Ainsi, je démarre un VM Ubuntu qui monte le /home
du disque physique en lecture / écriture comme un disque normal. En installant les mêmes paquets entre l'Ubuntu natif et l'Ubuntu VM, l'interface graphique est identique entre les 2. De plus, la VM s'affiche en plein écran et la perte de réactivité est à peine perceptible.
La procédure pour créer un disque virtuel sur un disque physique est censée être simple :
C:\Program Files\Oracle\VirtualBox>VBoxManage.exe internalcommands createrawvmdk -filename "C:\LinuxRAW.vmdk" -rawdisk "\\.\PhysicalDrive0" -partitions 3
Cela créer un disque vmdk de quelques ko qui est ensuite utilisable dans n'importe quelle VM. Il faut faire très attention à ne pas mettre un disque virtuel qui accède aux mêmes données que l'OS hôte : les systèmes de fichiers ne sont pas conçus pour être lus et écrit par 2 noyaux (Windows ou Linux) en même temps.
Malheureusement, la commande plante :
VBoxManage.exe: error: Cannot open the raw disk '\\.\PhysicalDrive0': VERR_SHARING_VIOLATION VBoxManage.exe: error: The raw disk vmdk file was not created
J'ai ce bug qui n'était toujours pas résolu . Pas de possibilité de créer le disque sous Windows ⇒ reboot sous Linux et création du disque virtuel sur la partition qui héberge mon linux en priant très fort pour qu'il n'accède pas aux données car le disque est déjà monté et … ça marche sans casse !
La configuration de la VM Ubuntu sous Windows est traditionnelle avec 3 Go de RAM, ce qui est suffisant pour un Firefox + OpenOffice. Les disques sont finalement les suivants :
- 1 disque virtuel à allocation dynamique contenant le / de la distribution;
- 1 disque virtuel raw mappé sur le LVM de mon linux contenant notamment le /home.
En sus, pour m'assurer une bonne fluidité dans les jeux, je n'ai alloué que 90% maximum de la CPU à cette VM .