diff --git a/src/PSLauncher.App/App.xaml.cs b/src/PSLauncher.App/App.xaml.cs index 26a2c9b..dcd5326 100644 --- a/src/PSLauncher.App/App.xaml.cs +++ b/src/PSLauncher.App/App.xaml.cs @@ -120,6 +120,19 @@ public partial class App : Application Log.Information("PSLauncher starting (logs in {Path})", LogsDirectory); + // RENDER MODE : sur certains environnements (RDP, VMs sans hardware accel, + // GPU émulé, Intel HD anciens, Windows Server sans Desktop Experience…) + // l'accélération matérielle WPF plante en silence : la fenêtre s'affiche + // toute blanche, aucun contenu ne rend, aucune exception ne remonte. C'est + // un bug classique non rattrapable côté .NET parce que le pipeline graphique + // tombe entre les mailles du try/catch. On force le rendu software dans 3 cas : + // 1. RenderCapability.Tier == 0 (WPF lui-même détecte aucune accel possible) + // 2. Session Bureau à distance (RDP) détectée + // 3. Var d'env PSLAUNCHER_SOFTWARE_RENDER=1 (override manuel pour debug) + // Trade-off : rendu software plus lent (~30% impact sur le scrolling de la + // liste des versions), mais au moins ça affiche QUELQUE CHOSE. + ApplyRenderModeFallback(); + AppDomain.CurrentDomain.UnhandledException += (_, args) => { // CRITIQUE : on flush AVANT que le process meure. Sans ça, sur les @@ -317,6 +330,55 @@ public partial class App : Application window.Show(); } + /// + /// Décide entre rendu hardware (par défaut WPF) et rendu software, en fonction + /// de l'environnement détecté + override par variable d'environnement. Log + /// la décision pour faciliter le debug si l'utilisateur reporte un écran blanc. + /// + private static void ApplyRenderModeFallback() + { + try + { + // Override manuel : PSLAUNCHER_SOFTWARE_RENDER=1 force le software. + // Le user peut le set dans les variables d'environnement Windows OU dans + // le raccourci .lnk (champ Cible : "cmd /c set PSLAUNCHER_SOFTWARE_RENDER=1 && start PS_Launcher.exe") + var envOverride = Environment.GetEnvironmentVariable("PSLAUNCHER_SOFTWARE_RENDER"); + var manualSoftware = !string.IsNullOrEmpty(envOverride) + && (envOverride == "1" || envOverride.Equals("true", StringComparison.OrdinalIgnoreCase)); + + // RenderCapability.Tier renvoie un int packed : (tier << 16). Tier 0 = pas + // d'accélération matérielle possible. Tier 1 = partielle. Tier 2 = complète. + var tier = System.Windows.Media.RenderCapability.Tier >> 16; + + // GetSystemMetrics(SM_REMOTESESSION) = 1 si la session est une session RDP. + // SM_REMOTESESSION constant = 0x1000 (4096). + var isRdp = GetSystemMetrics(0x1000) != 0; + + var shouldUseSoftware = manualSoftware || tier == 0 || isRdp; + + Log.Information("Render env : Tier={Tier} RDP={Rdp} EnvOverride={EnvOverride} → SoftwareOnly={Sw}", + tier, isRdp, manualSoftware, shouldUseSoftware); + + if (shouldUseSoftware) + { + System.Windows.Media.RenderOptions.ProcessRenderMode = + System.Windows.Interop.RenderMode.SoftwareOnly; + Log.Warning("WPF render mode forced to SoftwareOnly (cause: " + + (manualSoftware ? "env override" : tier == 0 ? "Tier=0 no GPU accel" : "RDP session") + ")"); + } + } + catch (Exception ex) + { + // Pas critique : si le fallback échoue, on continue avec le default + // hardware accel et on espère que ça marche. Le user verra un écran + // blanc si non, mais au moins l'app aura pas crashé. + Log.Warning(ex, "Failed to evaluate render-mode fallback, keeping default"); + } + } + + [DllImport("user32.dll")] + private static extern int GetSystemMetrics(int nIndex); + protected override void OnExit(ExitEventArgs e) { Log.Information("PSLauncher shutting down"); diff --git a/src/PSLauncher.App/PSLauncher.App.csproj b/src/PSLauncher.App/PSLauncher.App.csproj index 72c37ed..11f59dd 100644 --- a/src/PSLauncher.App/PSLauncher.App.csproj +++ b/src/PSLauncher.App/PSLauncher.App.csproj @@ -18,9 +18,9 @@ PROSERVE Launcher © 2026 ASTERION VR — All rights reserved PSLauncher.App - 1.0.2 - 1.0.2.0 - 1.0.2.0 + 1.0.3 + 1.0.3.0 + 1.0.3.0 true @@ -47,7 +47,7 @@ Le runtime est pré-installé sur Win11 et auto-mis-à-jour via Windows Update sur Win10 récent. Si absent, le contrôle affiche une erreur et on aiguille l'user vers https://go.microsoft.com/fwlink/p/?LinkId=2124703 --> - +