Dolphin pour RomM
RomM — Emulator Streaming avec Dolphin sur Unraid (GPU NVIDIA)
Ce tutoriel explique comment ajouter un conteneur Dolphin (GameCube/Wii) à une instance RomM 5.1.0+ existante pour utiliser la fonctionnalité Emulator Streaming : lancer un jeu depuis l'interface RomM et y jouer dans le navigateur, avec rendu et encodage sur le GPU NVIDIA.
Architecture : RomM ne pilote pas Dolphin directement. Un Docker Mod (maintenu par LoneAngelFayt) injecte dans le conteneur Dolphin un broker HTTP (port 8000) que RomM contacte pour lancer/piloter les jeux. L'image et le son sont diffusés par Selkies (le bureau web intégré aux images LinuxServer), en H.264 NVENC.
⚠️ Testé avec : Unraid 7, RTX 3060, driver NVIDIA 610.x,
lscr.io/linuxserver/dolphin:latest(base Selkies/Wayland), RomM 5.1.0.
1. Prérequis Unraid
1.1 Plugin Nvidia Driver
- Installer le plugin Nvidia Driver (Community Applications).
- Driver propriétaire 580 ou supérieur requis. LinuxServer recommande la branche Production pour Unraid.
- Le GPU ne doit pas être réservé au VFIO (il doit être disponible pour Docker).
- Sur un serveur headless (sans écran), la doc LinuxServer indique qu'un dummy plug HDMI/DP branché sur la carte est requis pour que DRM s'initialise correctement.
1.2 Paramètres noyau (Syslinux)
nvidia-drm.modeset=1 nvidia_drm.fbdev=1
Redémarrer le serveur, puis vérifier :
cat /proc/cmdline # les 2 paramètres doivent apparaître
cat /sys/module/nvidia_drm/parameters/modeset # doit renvoyer Y
nvidia-smi -L # liste le(s) GPU + UUID
Notez l'UUID du GPU (GPU-xxxxxxxx-...), il servira dans le template.
1.3 Limite inotify (optionnel mais recommandé)
Les images Selkies consomment beaucoup d'instances inotify. Pour éviter l'avertissement « Too many open files » :
sysctl -w fs.inotify.max_user_instances=1024
echo 'sysctl -w fs.inotify.max_user_instances=1024' >> /boot/config/go
2. ⚠️ Correctif indispensable : composantCorrectifs NVIDIA indispensables (Unraid)
Le runtime NVIDIA d'Unraid présente deux trous d'injection vers les conteneurs. Sans eux, l'émulateur tourne en rendu logiciel (très lent) ou affiche un écran noir. Les deux correctifs sont simples et persistants.
2.1 Composant egl-x11 (rendu OpenGL/EGL)
C'est le point qui fait échouer la plupart des installations (symptôme : interface Dolphin visible, mais zone de jeu noire avec le son, ou jeu qui rame énormément en rendu logiciel).
Le runtime NVIDIA d'Unraid injecte dans les conteneurs les plateformes EGL wayland, wayland2 et gbm, mais pas les deux plateformes X11 (xlib/xcb) — pourtant livrées par le driver et indispensables à Dolphin, qui crée son contexte OpenGL via EGL sur X11. Sans elles, l'EGL NVIDIA ne peut pas créer de surface et Dolphin retombe en rendu logiciel (ou écran noir via Zink : MESA: error: zink: could not create swapchain).
Vérifier que le driver de l'hôte fournit bien les fichiers :
ls /var/local/overlay/usr/lib64/ | grep egl-x
ls /var/local/overlay/usr/share/egl/egl_external_platform.d/ | grep -E "xlib|xcb"
Vous devez voir libnvidia-egl-xlib.so.1.X.X, libnvidia-egl-xcb.so.1.X.X, 20_nvidia_xlib.json et 20_nvidia_xcb.json. Notez le numéro de version exact des .so (ex. 1.0.5) : il est utilisé dans les montages ci-dessous, et il change à chaque mise à jour du driver (voir §7).
Le correctif consiste en 4 montages en lecture seule + 1 variable, intégrés au template Dolphin de la section suivante.
2.2 Nœud /dev/nvidia-modeset (présentation Vulkan)
Le toolkit injecte nvidia0, nvidiactl, nvidia-uvm, nvidia-uvm-tools et nvidia-caps… mais pas /dev/nvidia-modeset, qui est nécessaire à la présentation Vulkan (l'énumération des GPU, elle, fonctionne sans lui — d'où des diagnostics trompeurs).
Symptômes sans ce nœud : vulkaninfo liste bien la carte mais vkGetPhysicalDeviceSurfacePresentModesKHR échoue en ERROR_UNKNOWN ; vkcube sélectionne le GPU puis plante à la création de la swapchain ; Dolphin en backend Vulkan ou via Zink affiche un écran noir avec le son.
Vérification :
ls /dev/nvidia-modeset # sur l'hôte : présent
docker exec dolphin ls /dev/nvidia-modeset 2>&1 # dans le conteneur : absent
Correctif : ajouter --device /dev/nvidia-modeset aux Extra Parameters (voir §3.4).
3. Conteneur Dolphin
Ajouter un conteneur avec l'image lscr.io/linuxserver/dolphin et la configuration suivante.
3.1 Générer un secret partagé
Ce secret authentifie les échanges RomM ↔ broker. Générez-le une fois :
openssl rand -hex 32
3.2 Ports (host:container)
| Port hôte | Port conteneur | Rôle |
|---|---|---|
| 3000 | 3000 | Selkies HTTP (peu utile) |
| 3001 | 3001 | Selkies HTTPS (le flux de jeu) |
| 8000 | 8000 | Broker RomM |
Adaptez les ports hôte s'ils sont déjà pris par un autre conteneur (dans ce cas, reportez le port choisi dans le bloc streaming du §4.2).
3.3 Variables d'environnement
| Variable | Valeur | Remarque |
|---|---|---|
DOCKER_MODS |
ghcr.io/loneangelfayt/dolphin-romm-integration-mod:latest |
installe le broker |
ROM_ROOT |
/romm/library |
racine de la bibliothèque vue par le broker |
BROKER_SECRET |
(votre secret) | même valeur que côté RomM |
NVIDIA_VISIBLE_DEVICES |
(UUID du GPU) | ou all si un seul GPU |
NVIDIA_DRIVER_CAPABILITIES |
all |
|
DRINODE |
/dev/dri/renderD128 |
GPU de rendu (vérifier avec ls -l /dev/dri/by-path/ que c'est bien la carte NVIDIA) |
DRI_NODE |
/dev/dri/renderD128 |
GPU d'encodage — identique = mode Zero-Copy |
SELKIES_MANUAL_WIDTH |
1920 |
bride la résolution du flux |
SELKIES_MANUAL_HEIGHT |
1080 |
sinon elle suit la fenêtre du navigateur (coûteux) |
__EGL_VENDOR_LIBRARY_FILENAMES |
/usr/share/glvnd/egl_vendor.d/10_nvidia.json |
force l'EGL NVIDIA (fait partie du correctif §2) |
PUID / PGID |
99 / 100 |
standard Unraid |
3.4 Extra Parameters
--gpus all --runtime nvidia --shm-size=1gb --device /dev/nvidia-modeset --cpuset-cpus=0-5,12-17
--device /dev/nvidia-modeset : correctif §2.2.
--cpuset-cpus : épinglage CPU, obligatoire sur tout Ryzen multi-CCD — sans lui les performances sont fortement dégradées (voir §7). Adaptez impérativement la liste à votre processeur : la valeur ci-dessus correspond au premier CCD d'un 3900X et sera contre-productive sur une autre topologie. Sur un CPU mono-CCD ou Intel, retirez l'option.
3.5 Volumes
| Host Path | Container Path | Mode |
|---|---|---|
| (votre dossier de ROMs — le même que celui monté dans RomM) | /romm/library |
ro |
(votre appdata, ex. /mnt/user/appdata/dolphin) |
/config |
rw |
/var/local/overlay/usr/lib64/libnvidia-egl-xlib.so.1.X.X |
/usr/lib64/libnvidia-egl-xlib.so.1 |
ro |
/var/local/overlay/usr/lib64/libnvidia-egl-xcb.so.1.X.X |
/usr/lib64/libnvidia-egl-xcb.so.1 |
ro |
/var/local/overlay/usr/share/egl/egl_external_platform.d/20_nvidia_xlib.json |
/usr/share/egl/egl_external_platform.d/20_nvidia_xlib.json |
ro |
/var/local/overlay/usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json |
/usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json |
ro |
Remplacez
1.X.Xpar la version relevée au §2. Le Container Path des libs est volontairement le nom court.so.1: c'est celui que le loader EGL recherche (déclaré dans les JSON), ce qui évite d'avoir à créer des symlinks.
💡 Important : le chemin de la bibliothèque doit être identique dans RomM et dans Dolphin (
/romm/librarydes deux côtés), sinon le broker ne retrouvera pas les fichiers que RomM lui demande de lancer.
3.6 Vérifications après démarrage
docker logs dolphin 2>&1 | grep -iE "broker|NVENC|Zero-Copy"
Attendu : ROM broker listening on port 8000, Shared secret auth enabled, NVENC ... Initialized successfully, Decision: Zero-Copy path active.
curl -s http://localhost:8000/health # → {"status":"ok"}
docker exec dolphin sh -c 'ldconfig -p | grep egl-x' # → les 2 libs xlib/xcb
4. Côté RomM
4.1 Variable d'environnement
Ajouter au conteneur RomM :
| Variable | Valeur |
|---|---|
STREAMING_BROKER_SECRET |
(le même secret qu'au §3.1) |
4.2 config.yml
Dans le config.yml de RomM (dossier config), ajouter le bloc streaming (adapter l'IP du serveur et les ports choisis) :
streaming:
enabled: true
containers:
- platform: ngc
host: https://IP_DU_SERVEUR:3001
broker_host: http://IP_DU_SERVEUR:8000
label: Dolphin
memory_card_sync: true
- platform: wii
host: https://IP_DU_SERVEUR:3001
broker_host: http://IP_DU_SERVEUR:8000
label: Dolphin
Redémarrer RomM après modification.
4.3 Structure de la bibliothèque
- Le dossier de plateforme doit correspondre au fs_slug de RomM :
ngcpour la GameCube,wiipour la Wii (pasgc, pasgamecube) — sinon prévoir un mappage dansconfig.yml. - Les ROMs doivent être des fichiers directs (
.rvz,.iso) — pas d'archives.zip/.7z, Dolphin ne peut pas les lancer via le broker. - ⚠️ RomM supporte deux structures (
library/roms/<plateforme>/oulibrary/<plateforme>/roms/) mais la simple présence d'un dossierlibrary/roms/fait basculer toute la bibliothèque sur la première : ne mélangez pas les deux, ou toutes vos autres plateformes deviendront invisibles au scan.
Rescanner la plateforme dans RomM après tout changement.
5. Premier lancement
- Ouvrir une première fois
https://IP_DU_SERVEUR:3001et accepter le certificat auto-signé (sinon le flux ne se chargera pas dans RomM). - Dans RomM, ouvrir la fiche d'un jeu GameCube → bouton Play on Dolphin.
- Le jeu doit s'afficher, fluide, avec le son.
Vérifier que le GPU est bien utilisé (pendant qu'un jeu tourne) :
docker exec -u abc dolphin sh -c 'for p in /proc/[0-9]*; do ls -l $p/fd 2>/dev/null | grep -q nvidia && echo "$(basename $p) $(tr "\0" " " < $p/cmdline | cut -c1-60)"; done'
dolphin-emu doit apparaître dans la liste. S'il n'y a que selkies, labwc et Xwayland, Dolphin est en rendu logiciel → revoir le §2.
Note : lancez bien ce test avec
-u abc— en root, la lecture de/proc/<pid>/fddes processus de l'utilisateurabcéchoue silencieusement.
6. Réglages Dolphin utiles
Le fichier de configuration est <appdata>/.. Toujours éditer conteneur arrêté (Dolphin réécrit ses fichiers en se fermant), et savoir que le mod réimpose config/dolphin-emu/Dolphin.iniGFXBackend = OpenGL à chaque recréation du conteneur — c'est le bon backend ici (c'est le chemin EGL corrigé au §2), ne pas chercher à le changer.
⚠️ Après toute édition depuis l'hôte (
sed -i,cat >, redirection…), rétablissez le propriétaire :chown -R 99:100 <appdata>. Ces commandes peuvent recréer le fichier enroot:root, et l'émulateur ne peut alors plus enregistrer sa configuration — silencieusement, à part une ligne d'erreur dans son log.
6.1 Performances
Réglage recommandé (section [Core]) :
CPUThread = True
C'est le mode « Dual Core » de Dolphin ; selon les versions il peut être désactivé par défaut, et son absence coûte très cher en performances.
6.2 Jeux en français
La langue de la console émulée (celle que les jeux GameCube utilisent) se règle dans [Core] :
docker stop dolphin
F=<appdata>/.config/dolphin-emu/Dolphin.ini
sed -i '/^SelectedLanguage *=/d' "$F"
sed -i '/^\[Core\]/a SelectedLanguage = 2' "$F"
chown -R 99:100 <appdata>
docker start dolphin
grep -n "^SelectedLanguage" "$F"
Valeurs : 0 anglais, 1 allemand, 2 français, 3 espagnol, 4 italien, 5 néerlandais.
Cette clé survit aux redémarrages et aux recréations du conteneur : le mod ne la touche pas.
⚠️ N'ajoutez pas
[Interface] LanguageCodepour traduire l'interface de Dolphin : dans cette image, la clé provoque une boîte de dialogue d'erreur de langue à chaque démarrage. Les jeux sont de toute façon en français grâce àSelectedLanguage, ce qui est l'essentiel — l'interface de l'émulateur n'est presque jamais visible pour les joueurs (le broker lance directement le jeu en plein écran).
Jeux Wii : la langue ne vient pas de
Dolphin.inimais de la NAND Wii émulée. Elle se règle dans l'interface (Options → Configuration → Wii → Langue du système) et persiste dans l'appdata.
7. ⚠️ Épinglage CPU — obligatoire sur Ryzen multi-CCD
Sur les Ryzen à plusieurs CCD (3900X, 3950X, 5900X, 5950X, 7900X, 7950X…), les cœurs sont répartis en groupes ayant chacun son propre cache L3. Un émulateur dont les threads dialoguent en permanence perd beaucoup quand l'ordonnanceur les fait migrer d'un groupe à l'autre : les échanges passent alors par l'Infinity Fabric, bien plus lent.
Ce n'est pas une optimisation facultative : sans épinglage, comptez une perte de l'ordre d'un tiers des performances, suffisante pour rendre injouables les titres exigeants. Le symptôme est déroutant — performances médiocres alors que rien ne sature (CPU global bas, GPU à 10 %, aucun thread à 100 %) — parce que les threads n'attendent pas du calcul, mais la mémoire.
Identifiez vos groupes de cache :
lscpu -e=CPU,CORE,L3
Les CPU partageant le même numéro de L3 (ou deux L3 voisins d'un même CCD) forment un groupe. Exemple sur un 3900X : le premier CCD regroupe les CPU 0-5 et leurs hyperthreads 12-17.
Épinglez ensuite le conteneur sur un seul CCD via --cpuset-cpus=0-5,12-17 (Extra Parameters), ou l'onglet CPU Pinning du template Unraid.
Le gain observé sur ce type de configuration va de quelques pourcents à +50 %. C'est aussi ce qui explique qu'une VM avec vCPU épinglés paraisse bien plus rapide que le même émulateur en conteneur non épinglé, sur la même machine.
Multi-conteneurs : si Dolphin et Eden tournent simultanément, répartissez-les sur des groupes différents plutôt que de les faire cohabiter sur le même CCD.
8. Maintenance et limites connues
- À chaque mise à jour du driver NVIDIA de l'hôte, le nom des libs (
libnvidia-egl-*.so.1.X.X) change : mettre à jour les 2 Host Path correspondants dans le template Dolphin, sinon écran noir / rendu logiciel au retour. - Une seule session à la fois par conteneur : un conteneur = une instance Dolphin = un flux. Pour du multi-joueurs simultané, dupliquer le conteneur (autres ports, autre secret possible) et ajouter une entrée dans
streaming.containers. - Sessions fantômes : fermer l'onglet du navigateur ne tue pas Dolphin ; la session peut rester occupée. En attendant mieux :
docker exec dolphin pkill dolphin-emu. - Les paquets installés à la main dans le conteneur (
apt-get) ne survivent pas à une recréation. Pour des outils de diagnostic permanents, chaîner le moduniversal-package-install:DOCKER_MODS=ghcr.io/loneangelfayt/dolphin-romm-integration-mod:latest|linuxserver/mods:universal-package-install+INSTALL_PACKAGES=vulkan-tools|mesa-utils|x11-utils.
8.9. Dépannage rapide
| Symptôme | Cause probable | Solution |
|---|---|---|
| « ROMs not found » au scan | Nom de dossier ≠ fs_slug, ou structures mélangées | §4.3 |
| Pas de bouton « Play on Dolphin » | Bloc streaming absent/invalide, ou secret différent |
§4.1–4.2 |
| Flux ne se charge pas dans RomM | Certificat auto-signé jamais accepté | §5.1 |
Jeu très lent, dolphin-emu absent du test des fd |
Rendu logiciel (egl-x11 manquant) | § |
| Zone de jeu noire, interface et son OK | /dev/nvidia-modeset |
§2.2 |
MESA_LOADER_DRIVER_OVERRIDEGALLIUM_DRIVER%)
Threads migrant entre CCD
§7
Écran noir après une mise à jour du driver
Version des libs egl-x11 changée
§<appdata>/dolphin.log
ci-dessous
qt.qpa.xcb: could not connect to display :0 dans dolphin.log
Sockets X périmées accumulées dans /tmp/.X11-unix (le broker détecte un affichage mort)
Recréer le conteneur — un simple redémarrage conserve /tmp
Boîte d'erreur de langue au démarrage
Clé [Interface] LanguageCode présente
La supprimer (§6.2)
« Failed to initialize video backend »
Variables graphiques parasites ou backend forcé à Vulkan
Revenir à la config §3, GFXBackend = OpenGL