diff --git a/neomacs-display-runtime/src/backend/wgpu/backend.rs b/neomacs-display-runtime/src/backend/wgpu/backend.rs index 36374b9a17..fdece9c527 100644 --- a/neomacs-display-runtime/src/backend/wgpu/backend.rs +++ b/neomacs-display-runtime/src/backend/wgpu/backend.rs @@ -159,8 +159,7 @@ impl WinitBackend { } // Create wgpu instance - let mut instance_descriptor = wgpu::InstanceDescriptor::new_without_display_handle(); - instance_descriptor.backends = wgpu::Backends::all(); + let instance_descriptor = crate::wgpu_instance_descriptor_from_env(); let instance = wgpu::Instance::new(instance_descriptor); // Request adapter without a surface (headless) @@ -349,8 +348,8 @@ impl WinitBackend { self.height = size.height; // Create wgpu instance - let mut instance_descriptor = wgpu::InstanceDescriptor::new_without_display_handle(); - instance_descriptor.backends = wgpu::Backends::all(); + let instance_descriptor = + crate::wgpu_instance_descriptor_with_display(event_loop.owned_display_handle()); let instance = wgpu::Instance::new(instance_descriptor); // Create surface - we need to use unsafe to create a surface from the window diff --git a/neomacs-display-runtime/src/lib.rs b/neomacs-display-runtime/src/lib.rs index 255a762f09..ba8e46a6a3 100644 --- a/neomacs-display-runtime/src/lib.rs +++ b/neomacs-display-runtime/src/lib.rs @@ -72,6 +72,16 @@ pub fn gpu_power_preference() -> wgpu::PowerPreference { } } +pub(crate) fn wgpu_instance_descriptor_from_env() -> wgpu::InstanceDescriptor { + wgpu::InstanceDescriptor::new_without_display_handle_from_env() +} + +pub(crate) fn wgpu_instance_descriptor_with_display( + display: winit::event_loop::OwnedDisplayHandle, +) -> wgpu::InstanceDescriptor { + wgpu::InstanceDescriptor::new_with_display_handle_from_env(Box::new(display)) +} + /// Initialize the display engine. /// /// Logging is initialized separately by the binary entry point via diff --git a/neomacs-display-runtime/src/render_thread/bootstrap.rs b/neomacs-display-runtime/src/render_thread/bootstrap.rs index 4e7f18af17..b0bb8fddad 100644 --- a/neomacs-display-runtime/src/render_thread/bootstrap.rs +++ b/neomacs-display-runtime/src/render_thread/bootstrap.rs @@ -1,10 +1,11 @@ use super::{ RenderApp, RenderUserEvent, SharedImageDimensions, SharedMonitorInfo, surface_readback, }; +use crate::render_thread::state::RenderGpuContext; use crate::thread_comm::{InputEvent, RenderComms}; use neomacs_renderer_wgpu::{WgpuGlyphAtlas, WgpuRenderer}; use std::sync::Arc; -use winit::event_loop::{ControlFlow, EventLoop}; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; #[cfg(target_os = "linux")] use winit::platform::wayland::EventLoopBuilderExtWayland; #[cfg(target_os = "linux")] @@ -20,12 +21,16 @@ use crate::backend::wpe::sys::platform as plat; impl RenderApp { /// Initialize wgpu with the window - pub(super) fn init_wgpu(&mut self, window: Arc) { + pub(super) fn init_wgpu(&mut self, event_loop: &ActiveEventLoop, window: Arc) { tracing::info!("Initializing wgpu for render thread"); - // Create wgpu instance - let mut instance_descriptor = wgpu::InstanceDescriptor::new_without_display_handle(); - instance_descriptor.backends = wgpu::Backends::all(); + // GLES presentation needs the compositor/display handle, especially on Wayland. + let instance_descriptor = + crate::wgpu_instance_descriptor_with_display(event_loop.owned_display_handle()); + tracing::info!( + "wgpu requested backends: {:?}", + instance_descriptor.backends + ); let instance = wgpu::Instance::new(instance_descriptor); // Create surface from window @@ -135,11 +140,14 @@ impl RenderApp { format ); - self.adapter = Some(adapter); + self.gpu = Some(RenderGpuContext { + instance, + adapter, + device: device.clone(), + queue: queue.clone(), + }); self.surface = Some(surface); self.surface_config = Some(config); - self.device = Some(device.clone()); - self.queue = Some(queue); self.renderer = Some(renderer); self.glyph_atlas = Some(glyph_atlas); @@ -183,12 +191,12 @@ impl RenderApp { self.height = height; // Reconfigure surface - if let (Some(surface), Some(config), Some(device)) = - (&self.surface, &mut self.surface_config, &self.device) + if let (Some(surface), Some(config), Some(gpu)) = + (&self.surface, &mut self.surface_config, &self.gpu) { config.width = width; config.height = height; - surface.configure(device, config); + surface.configure(&gpu.device, config); } // Resize renderer diff --git a/neomacs-display-runtime/src/render_thread/lifecycle.rs b/neomacs-display-runtime/src/render_thread/lifecycle.rs index d6f0705fb6..d4edf9fcda 100644 --- a/neomacs-display-runtime/src/render_thread/lifecycle.rs +++ b/neomacs-display-runtime/src/render_thread/lifecycle.rs @@ -1,5 +1,7 @@ use super::RenderApp; -use super::state::{effective_window_scale_factor, window_size_from_emacs_pixels}; +use super::state::{ + RenderGpuContext, effective_window_scale_factor, window_size_from_emacs_pixels, +}; use super::x11_hints::apply_window_geometry_hints; use crate::thread_comm::InputEvent; use std::sync::Arc; @@ -125,7 +127,7 @@ impl RenderApp { ); // Initialize wgpu with the window - self.init_wgpu(window.clone()); + self.init_wgpu(event_loop, window.clone()); // Enable IME input for CJK and compose support window.set_ime_allowed(true); @@ -164,9 +166,13 @@ impl RenderApp { } // Process multi-window creates/destroys - if let (Some(device), Some(adapter)) = (&self.device, &self.adapter) { - self.multi_windows - .process_creates(event_loop, device, adapter); + if let Some(gpu) = &self.gpu { + self.multi_windows.process_creates( + event_loop, + &gpu.instance, + &gpu.device, + &gpu.adapter, + ); } self.multi_windows.process_destroys(); @@ -336,16 +342,22 @@ impl RenderApp { // Drop surface (holds wl_surface proxy if on Wayland) drop(self.surface.take()); self.surface_config = None; - // Drop device and queue - drop(self.device.take()); - drop(self.queue.take()); // Drop multi-window state (secondary surfaces) self.multi_windows.destroy_all(); // Leak the adapter to prevent eglTerminate crash on Wayland. // The adapter's Drop triggers eglTerminate → dri2_teardown_wayland which // SEGVs if the Wayland connection is already gone. Since we're exiting, // the OS will reclaim all GPU/EGL resources. - if let Some(adapter) = self.adapter.take() { + if let Some(gpu) = self.gpu.take() { + let RenderGpuContext { + instance, + adapter, + device, + queue, + } = gpu; + drop(device); + drop(queue); + drop(instance); std::mem::forget(adapter); } diff --git a/neomacs-display-runtime/src/render_thread/multi_window.rs b/neomacs-display-runtime/src/render_thread/multi_window.rs index 883202828e..9232c73321 100644 --- a/neomacs-display-runtime/src/render_thread/multi_window.rs +++ b/neomacs-display-runtime/src/render_thread/multi_window.rs @@ -120,6 +120,7 @@ impl MultiWindowManager { pub fn process_creates( &mut self, event_loop: &ActiveEventLoop, + instance: &wgpu::Instance, device: &wgpu::Device, adapter: &wgpu::Adapter, ) { @@ -143,11 +144,7 @@ impl MultiWindowManager { let scale_factor = effective_window_scale_factor(raw_scale_factor); let phys = window.inner_size(); - // Create surface for this window - let mut instance_descriptor = - wgpu::InstanceDescriptor::new_without_display_handle(); - instance_descriptor.backends = wgpu::Backends::all(); - let instance = wgpu::Instance::new(instance_descriptor); + // Create surface for this window using the primary display-bound instance. let surface = match instance.create_surface(window.clone()) { Ok(s) => s, Err(e) => { diff --git a/neomacs-display-runtime/src/render_thread/state.rs b/neomacs-display-runtime/src/render_thread/state.rs index d460e276f5..1804647cd9 100644 --- a/neomacs-display-runtime/src/render_thread/state.rs +++ b/neomacs-display-runtime/src/render_thread/state.rs @@ -186,6 +186,13 @@ pub(super) struct ImeCursorArea { pub(super) height: u32, } +pub(super) struct RenderGpuContext { + pub(super) instance: wgpu::Instance, + pub(super) adapter: wgpu::Adapter, + pub(super) device: Arc, + pub(super) queue: Arc, +} + pub(super) struct RenderApp { pub(super) comms: RenderComms, pub(super) window: Option>, @@ -195,12 +202,11 @@ pub(super) struct RenderApp { pub(super) title: String, pub(super) primary_geometry_hints: Option, - // wgpu state + // Shared wgpu context used by the primary surface and secondary windows. + pub(super) gpu: Option, pub(super) renderer: Option, pub(super) surface: Option>, pub(super) surface_config: Option, - pub(super) device: Option>, - pub(super) queue: Option>, pub(super) glyph_atlas: Option, // Face cache built from frame data @@ -256,9 +262,6 @@ pub(super) struct RenderApp { // Multi-window manager (secondary OS windows for top-level frames) pub(super) multi_windows: MultiWindowManager, - // wgpu adapter (needed for creating surfaces on new windows) - pub(super) adapter: Option, - // Child frames (posframe, which-key-posframe, etc.) pub(super) child_frames: ChildFrameManager, // Child frame visual style @@ -375,11 +378,10 @@ impl RenderApp { title, primary_geometry_hints: None, scale_factor: 1.0, + gpu: None, renderer: None, surface: None, surface_config: None, - device: None, - queue: None, glyph_atlas: None, faces: HashMap::new(), modifiers: 0, @@ -404,7 +406,6 @@ impl RenderApp { #[cfg(feature = "neo-term")] shared_terminals, multi_windows: MultiWindowManager::new(), - adapter: None, child_frames: ChildFrameManager::new(), child_frame_corner_radius: 8.0, child_frame_shadow_enabled: true, diff --git a/neomacs-display-runtime/src/render_thread/window_events.rs b/neomacs-display-runtime/src/render_thread/window_events.rs index e4f8ce74d2..70bacc9247 100644 --- a/neomacs-display-runtime/src/render_thread/window_events.rs +++ b/neomacs-display-runtime/src/render_thread/window_events.rs @@ -54,7 +54,7 @@ impl RenderApp { height: emacs_h, emacs_frame_id: 0, }); - } else if let Some(device) = self.device.clone() { + } else if let Some(device) = self.gpu.as_ref().map(|gpu| gpu.device.clone()) { if let Some(ws) = self.multi_windows.get_mut(emacs_fid) { ws.handle_resize(&device, size.width, size.height); let (emacs_w, emacs_h) = diff --git a/neomacs-renderer-wgpu/src/renderer/mod.rs b/neomacs-renderer-wgpu/src/renderer/mod.rs index 5bf6e409e1..6e6f894078 100644 --- a/neomacs-renderer-wgpu/src/renderer/mod.rs +++ b/neomacs-renderer-wgpu/src/renderer/mod.rs @@ -1295,8 +1295,7 @@ impl WgpuRenderer { height: u32, ) -> Result { // Create wgpu instance - let mut instance_descriptor = wgpu::InstanceDescriptor::new_without_display_handle(); - instance_descriptor.backends = wgpu::Backends::all(); + let instance_descriptor = wgpu::InstanceDescriptor::new_without_display_handle_from_env(); let instance = wgpu::Instance::new(instance_descriptor); // Request adapter