gardesk/garterm / 254aec5

Browse files

add renderer config: auto/vulkan/gl/software to fix NVIDIA Xid 79 crashes

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
254aec5b381c131a5300ea9be7e07a2e96be6fb7
Parents
290229c
Tree
c0aa39d

6 changed files

StatusFile+-
M garterm/config/default.toml 7 0
M garterm/src/app.rs 1 0
M garterm/src/config/lua.rs 8 0
M garterm/src/config/mod.rs 26 0
M garterm/src/render/gpu.rs 12 4
M garterm/src/render/mod.rs 2 1
garterm/config/default.tomlmodified
@@ -25,6 +25,13 @@
2525
 #   true  = VSync/dirty-flag only (lower CPU, needs proper VSync support)
2626
 vsync = false
2727
 
28
+# GPU rendering backend: "auto", "vulkan", "gl", "software"
29
+#   auto     = Vulkan first, then GL (default)
30
+#   vulkan   = Force Vulkan
31
+#   gl       = Force OpenGL (recommended for NVIDIA + picom)
32
+#   software = CPU rendering (no GPU required, avoids all GPU crashes)
33
+# renderer = "auto"
34
+
2835
 # Log level: "error", "warn", "info", "debug", "trace"
2936
 # log_level = "info"
3037
 
garterm/src/app.rsmodified
@@ -120,6 +120,7 @@ impl App {
120120
             &config.font.family,
121121
             font_size,
122122
             colors,
123
+            &config.general.renderer,
123124
         ).await?;
124125
 
125126
         // Calculate actual cell size from loaded fonts
garterm/src/config/lua.rsmodified
@@ -113,6 +113,14 @@ fn parse_terminal_table(table: &mlua::Table) -> Config {
113113
     if let Ok(vsync) = table.get::<bool>("vsync") {
114114
         config.general.vsync = vsync;
115115
     }
116
+    if let Ok(renderer) = table.get::<String>("renderer") {
117
+        config.general.renderer = match renderer.as_str() {
118
+            "vulkan" => crate::config::Renderer::Vulkan,
119
+            "gl" | "opengl" => crate::config::Renderer::Gl,
120
+            "software" | "cpu" | "sw" => crate::config::Renderer::Software,
121
+            _ => crate::config::Renderer::Auto,
122
+        };
123
+    }
116124
     if let Ok(cwd) = table.get::<String>("working_directory") {
117125
         config.general.working_directory = Some(cwd.into());
118126
     }
garterm/src/config/mod.rsmodified
@@ -56,6 +56,26 @@ pub struct Config {
5656
     pub keybinds: keybinds::KeybindConfig,
5757
 }
5858
 
59
+/// GPU rendering backend selection
60
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
61
+#[serde(rename_all = "lowercase")]
62
+pub enum Renderer {
63
+    /// Auto-detect: Vulkan first, then GL (default)
64
+    Auto,
65
+    /// Force Vulkan backend
66
+    Vulkan,
67
+    /// Force OpenGL backend
68
+    Gl,
69
+    /// Force software rendering (CPU-based, no GPU required)
70
+    Software,
71
+}
72
+
73
+impl Default for Renderer {
74
+    fn default() -> Self {
75
+        Self::Auto
76
+    }
77
+}
78
+
5979
 /// General settings
6080
 #[derive(Debug, Clone, Serialize, Deserialize)]
6181
 #[serde(default)]
@@ -73,6 +93,11 @@ pub struct GeneralConfig {
7393
     /// Use VSync-based rendering (may not work on Asahi Linux)
7494
     pub vsync: bool,
7595
 
96
+    /// GPU rendering backend: "auto", "vulkan", "gl", "software"
97
+    /// Use "software" to avoid GPU crashes on NVIDIA (Xid 79) or when no GPU is available
98
+    /// Use "gl" to force OpenGL instead of Vulkan (more stable on some NVIDIA setups)
99
+    pub renderer: Renderer,
100
+
76101
     /// Log level: "error", "warn", "info", "debug", "trace"
77102
     pub log_level: String,
78103
 }
@@ -84,6 +109,7 @@ impl Default for GeneralConfig {
84109
             shell_args: vec![],
85110
             working_directory: None,
86111
             vsync: false,
112
+            renderer: Renderer::Auto,
87113
             log_level: "info".into(),
88114
         }
89115
     }
garterm/src/render/gpu.rsmodified
@@ -123,16 +123,24 @@ impl GpuContext {
123123
         window: u32,
124124
         width: u32,
125125
         height: u32,
126
+        renderer: &crate::config::Renderer,
126127
     ) -> Result<Self, GpuError> {
127128
         // Open Xlib display for wgpu
128129
         let xlib_display = XlibDisplay::open()?;
129130
         let display = xlib_display.display_ptr();
130131
         let screen = xlib_display.default_screen();
131132
 
132
-        // Try Vulkan first (higher texture limits), fall back to GL
133
-        // GL has a 2048 texture limit on some systems which breaks full-screen windows
133
+        use crate::config::Renderer;
134
+        let (backends, force_fallback) = match renderer {
135
+            Renderer::Vulkan => (wgpu::Backends::VULKAN, false),
136
+            Renderer::Gl => (wgpu::Backends::GL, false),
137
+            Renderer::Software => (wgpu::Backends::VULKAN | wgpu::Backends::GL, true),
138
+            Renderer::Auto => (wgpu::Backends::VULKAN | wgpu::Backends::GL, false),
139
+        };
140
+        tracing::info!("Renderer config: {:?} (backends: {:?}, fallback: {})", renderer, backends, force_fallback);
141
+
134142
         let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
135
-            backends: wgpu::Backends::VULKAN | wgpu::Backends::GL,
143
+            backends,
136144
             ..Default::default()
137145
         });
138146
 
@@ -144,7 +152,7 @@ impl GpuContext {
144152
             .request_adapter(&wgpu::RequestAdapterOptions {
145153
                 power_preference: wgpu::PowerPreference::LowPower,
146154
                 compatible_surface: Some(&surface),
147
-                force_fallback_adapter: false,
155
+                force_fallback_adapter: force_fallback,
148156
             })
149157
             .await
150158
             .ok_or(GpuError::NoAdapter)?;
garterm/src/render/mod.rsmodified
@@ -146,8 +146,9 @@ impl Renderer {
146146
         font_family: &str,
147147
         font_size: f32,
148148
         colors: ColorPalette,
149
+        renderer_config: &crate::config::Renderer,
149150
     ) -> Result<Self, GpuError> {
150
-        let gpu = GpuContext::new(window, width, height).await?;
151
+        let gpu = GpuContext::new(window, width, height, renderer_config).await?;
151152
         let fonts = FontCache::new(font_family, font_size).expect("Failed to load fonts");
152153
 
153154
         // Create glyph atlas