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 @@
25
 #   true  = VSync/dirty-flag only (lower CPU, needs proper VSync support)
25
 #   true  = VSync/dirty-flag only (lower CPU, needs proper VSync support)
26
 vsync = false
26
 vsync = false
27
 
27
 
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
+
28
 # Log level: "error", "warn", "info", "debug", "trace"
35
 # Log level: "error", "warn", "info", "debug", "trace"
29
 # log_level = "info"
36
 # log_level = "info"
30
 
37
 
garterm/src/app.rsmodified
@@ -120,6 +120,7 @@ impl App {
120
             &config.font.family,
120
             &config.font.family,
121
             font_size,
121
             font_size,
122
             colors,
122
             colors,
123
+            &config.general.renderer,
123
         ).await?;
124
         ).await?;
124
 
125
 
125
         // Calculate actual cell size from loaded fonts
126
         // Calculate actual cell size from loaded fonts
garterm/src/config/lua.rsmodified
@@ -113,6 +113,14 @@ fn parse_terminal_table(table: &mlua::Table) -> Config {
113
     if let Ok(vsync) = table.get::<bool>("vsync") {
113
     if let Ok(vsync) = table.get::<bool>("vsync") {
114
         config.general.vsync = vsync;
114
         config.general.vsync = vsync;
115
     }
115
     }
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
+    }
116
     if let Ok(cwd) = table.get::<String>("working_directory") {
124
     if let Ok(cwd) = table.get::<String>("working_directory") {
117
         config.general.working_directory = Some(cwd.into());
125
         config.general.working_directory = Some(cwd.into());
118
     }
126
     }
garterm/src/config/mod.rsmodified
@@ -56,6 +56,26 @@ pub struct Config {
56
     pub keybinds: keybinds::KeybindConfig,
56
     pub keybinds: keybinds::KeybindConfig,
57
 }
57
 }
58
 
58
 
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
+
59
 /// General settings
79
 /// General settings
60
 #[derive(Debug, Clone, Serialize, Deserialize)]
80
 #[derive(Debug, Clone, Serialize, Deserialize)]
61
 #[serde(default)]
81
 #[serde(default)]
@@ -73,6 +93,11 @@ pub struct GeneralConfig {
73
     /// Use VSync-based rendering (may not work on Asahi Linux)
93
     /// Use VSync-based rendering (may not work on Asahi Linux)
74
     pub vsync: bool,
94
     pub vsync: bool,
75
 
95
 
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
+
76
     /// Log level: "error", "warn", "info", "debug", "trace"
101
     /// Log level: "error", "warn", "info", "debug", "trace"
77
     pub log_level: String,
102
     pub log_level: String,
78
 }
103
 }
@@ -84,6 +109,7 @@ impl Default for GeneralConfig {
84
             shell_args: vec![],
109
             shell_args: vec![],
85
             working_directory: None,
110
             working_directory: None,
86
             vsync: false,
111
             vsync: false,
112
+            renderer: Renderer::Auto,
87
             log_level: "info".into(),
113
             log_level: "info".into(),
88
         }
114
         }
89
     }
115
     }
garterm/src/render/gpu.rsmodified
@@ -123,16 +123,24 @@ impl GpuContext {
123
         window: u32,
123
         window: u32,
124
         width: u32,
124
         width: u32,
125
         height: u32,
125
         height: u32,
126
+        renderer: &crate::config::Renderer,
126
     ) -> Result<Self, GpuError> {
127
     ) -> Result<Self, GpuError> {
127
         // Open Xlib display for wgpu
128
         // Open Xlib display for wgpu
128
         let xlib_display = XlibDisplay::open()?;
129
         let xlib_display = XlibDisplay::open()?;
129
         let display = xlib_display.display_ptr();
130
         let display = xlib_display.display_ptr();
130
         let screen = xlib_display.default_screen();
131
         let screen = xlib_display.default_screen();
131
 
132
 
132
-        // Try Vulkan first (higher texture limits), fall back to GL
133
+        use crate::config::Renderer;
133
-        // GL has a 2048 texture limit on some systems which breaks full-screen windows
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
+
134
         let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
142
         let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
135
-            backends: wgpu::Backends::VULKAN | wgpu::Backends::GL,
143
+            backends,
136
             ..Default::default()
144
             ..Default::default()
137
         });
145
         });
138
 
146
 
@@ -144,7 +152,7 @@ impl GpuContext {
144
             .request_adapter(&wgpu::RequestAdapterOptions {
152
             .request_adapter(&wgpu::RequestAdapterOptions {
145
                 power_preference: wgpu::PowerPreference::LowPower,
153
                 power_preference: wgpu::PowerPreference::LowPower,
146
                 compatible_surface: Some(&surface),
154
                 compatible_surface: Some(&surface),
147
-                force_fallback_adapter: false,
155
+                force_fallback_adapter: force_fallback,
148
             })
156
             })
149
             .await
157
             .await
150
             .ok_or(GpuError::NoAdapter)?;
158
             .ok_or(GpuError::NoAdapter)?;
garterm/src/render/mod.rsmodified
@@ -146,8 +146,9 @@ impl Renderer {
146
         font_family: &str,
146
         font_family: &str,
147
         font_size: f32,
147
         font_size: f32,
148
         colors: ColorPalette,
148
         colors: ColorPalette,
149
+        renderer_config: &crate::config::Renderer,
149
     ) -> Result<Self, GpuError> {
150
     ) -> Result<Self, GpuError> {
150
-        let gpu = GpuContext::new(window, width, height).await?;
151
+        let gpu = GpuContext::new(window, width, height, renderer_config).await?;
151
         let fonts = FontCache::new(font_family, font_size).expect("Failed to load fonts");
152
         let fonts = FontCache::new(font_family, font_size).expect("Failed to load fonts");
152
 
153
 
153
         // Create glyph atlas
154
         // Create glyph atlas