use raw_window_handle::{ RawDisplayHandle, RawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle, }; use smithay_client_toolkit::{ compositor::{CompositorHandler, CompositorState}, delegate_compositor, delegate_output, delegate_registry, delegate_seat, delegate_xdg_shell, delegate_xdg_window, output::{OutputHandler, OutputState}, registry::{ProvidesRegistryState, RegistryState}, registry_handlers, seat::{Capability, SeatHandler, SeatState}, shell::{ xdg::{ window::{Window, WindowConfigure, WindowDecorations, WindowHandler}, XdgShell, }, WaylandSurface, }, }; use std::ptr::NonNull; use wayland_client::{ globals::registry_queue_init, protocol::{wl_output, wl_seat, wl_surface}, Connection, Proxy, QueueHandle, }; fn main() { env_logger::init(); let conn = Connection::connect_to_env().unwrap(); let (globals, mut event_queue) = registry_queue_init(&conn).unwrap(); let qh = event_queue.handle(); // Initialize xdg_shell handlers so we can select the correct adapter let compositor_state = CompositorState::bind(&globals, &qh).expect("wl_compositor not available"); let xdg_shell_state = XdgShell::bind(&globals, &qh).expect("xdg shell not available"); let surface = compositor_state.create_surface(&qh); // Create the window for adapter selection let window = xdg_shell_state.create_window(surface, WindowDecorations::ServerDefault, &qh); window.set_title("wgpu wayland window"); // GitHub does not let projects use the `org.github` domain but the `io.github` domain is fine. window.set_app_id("io.github.smithay.client-toolkit.WgpuExample"); window.set_min_size(Some((256, 256))); window.commit(); // Initialize wgpu let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { backends: wgpu::Backends::all(), ..Default::default() }); // Create the raw window handle for the surface. let raw_display_handle = RawDisplayHandle::Wayland(WaylandDisplayHandle::new( NonNull::new(conn.backend().display_ptr() as *mut _).unwrap(), )); let raw_window_handle = RawWindowHandle::Wayland(WaylandWindowHandle::new( NonNull::new(window.wl_surface().id().as_ptr() as *mut _).unwrap(), )); let surface = unsafe { instance .create_surface_unsafe(wgpu::SurfaceTargetUnsafe::RawHandle { raw_display_handle, raw_window_handle, }) .unwrap() }; // Pick a supported adapter let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { compatible_surface: Some(&surface), ..Default::default() })) .expect("Failed to find suitable adapter"); let (device, queue) = pollster::block_on(adapter.request_device(&Default::default(), None)) .expect("Failed to request device"); let mut wgpu = Wgpu { registry_state: RegistryState::new(&globals), seat_state: SeatState::new(&globals, &qh), output_state: OutputState::new(&globals, &qh), exit: false, width: 256, height: 256, window, device, surface, adapter, queue, }; // We don't draw immediately, the configure will notify us when to first draw. loop { event_queue.blocking_dispatch(&mut wgpu).unwrap(); if wgpu.exit { println!("exiting example"); break; } } // On exit we must destroy the surface before the window is destroyed. drop(wgpu.surface); drop(wgpu.window); } struct Wgpu { registry_state: RegistryState, seat_state: SeatState, output_state: OutputState, exit: bool, width: u32, height: u32, window: Window, adapter: wgpu::Adapter, device: wgpu::Device, queue: wgpu::Queue, surface: wgpu::Surface<'static>, } impl CompositorHandler for Wgpu { fn scale_factor_changed( &mut self, _conn: &Connection, _qh: &QueueHandle, _surface: &wl_surface::WlSurface, _new_factor: i32, ) { // Not needed for this example. } fn transform_changed( &mut self, _conn: &Connection, _qh: &QueueHandle, _surface: &wl_surface::WlSurface, _new_transform: wl_output::Transform, ) { // Not needed for this example. } fn frame( &mut self, _conn: &Connection, _qh: &QueueHandle, _surface: &wl_surface::WlSurface, _time: u32, ) { } } impl OutputHandler for Wgpu { fn output_state(&mut self) -> &mut OutputState { &mut self.output_state } fn new_output( &mut self, _conn: &Connection, _qh: &QueueHandle, _output: wl_output::WlOutput, ) { } fn update_output( &mut self, _conn: &Connection, _qh: &QueueHandle, _output: wl_output::WlOutput, ) { } fn output_destroyed( &mut self, _conn: &Connection, _qh: &QueueHandle, _output: wl_output::WlOutput, ) { } } impl WindowHandler for Wgpu { fn request_close(&mut self, _: &Connection, _: &QueueHandle, _: &Window) { self.exit = true; } fn configure( &mut self, _conn: &Connection, _qh: &QueueHandle, _window: &Window, configure: WindowConfigure, _serial: u32, ) { let (new_width, new_height) = configure.new_size; self.width = new_width.map_or(256, |v| v.get()); self.height = new_height.map_or(256, |v| v.get()); let adapter = &self.adapter; let surface = &self.surface; let device = &self.device; let queue = &self.queue; let cap = surface.get_capabilities(&adapter); let surface_config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: cap.formats[0], view_formats: vec![cap.formats[0]], alpha_mode: wgpu::CompositeAlphaMode::Auto, width: self.width, height: self.height, desired_maximum_frame_latency: 2, // Wayland is inherently a mailbox system. present_mode: wgpu::PresentMode::Mailbox, }; surface.configure(&self.device, &surface_config); // We don't plan to render much in this example, just clear the surface. let surface_texture = surface.get_current_texture().expect("failed to acquire next swapchain texture"); let texture_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()); let mut encoder = device.create_command_encoder(&Default::default()); { let _renderpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: None, color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &texture_view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color::BLUE), store: wgpu::StoreOp::Store, }, })], depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, }); } // Submit the command in the queue to execute queue.submit(Some(encoder.finish())); surface_texture.present(); } } impl SeatHandler for Wgpu { fn seat_state(&mut self) -> &mut SeatState { &mut self.seat_state } fn new_seat(&mut self, _: &Connection, _: &QueueHandle, _: wl_seat::WlSeat) {} fn new_capability( &mut self, _conn: &Connection, _qh: &QueueHandle, _seat: wl_seat::WlSeat, _capability: Capability, ) { } fn remove_capability( &mut self, _conn: &Connection, _: &QueueHandle, _: wl_seat::WlSeat, _capability: Capability, ) { } fn remove_seat(&mut self, _: &Connection, _: &QueueHandle, _: wl_seat::WlSeat) {} } delegate_compositor!(Wgpu); delegate_output!(Wgpu); delegate_seat!(Wgpu); delegate_xdg_shell!(Wgpu); delegate_xdg_window!(Wgpu); delegate_registry!(Wgpu); impl ProvidesRegistryState for Wgpu { fn registry(&mut self) -> &mut RegistryState { &mut self.registry_state } registry_handlers![OutputState]; }