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();
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);
let window = xdg_shell_state.create_window(surface, WindowDecorations::ServerDefault, &qh);
window.set_title("wgpu wayland window");
window.set_app_id("io.github.smithay.client-toolkit.WgpuExample");
window.set_min_size(Some((256, 256)));
window.commit();
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
..Default::default()
});
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()
};
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,
};
loop {
event_queue.blocking_dispatch(&mut wgpu).unwrap();
if wgpu.exit {
println!("exiting example");
break;
}
}
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<Self>,
_surface: &wl_surface::WlSurface,
_new_factor: i32,
) {
}
fn transform_changed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_new_transform: wl_output::Transform,
) {
}
fn frame(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_time: u32,
) {
}
fn surface_enter(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_output: &wl_output::WlOutput,
) {
}
fn surface_leave(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_output: &wl_output::WlOutput,
) {
}
}
impl OutputHandler for Wgpu {
fn output_state(&mut self) -> &mut OutputState {
&mut self.output_state
}
fn new_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
fn update_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
fn output_destroyed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
}
impl WindowHandler for Wgpu {
fn request_close(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &Window) {
self.exit = true;
}
fn configure(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_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,
present_mode: wgpu::PresentMode::Mailbox,
};
surface.configure(&self.device, &surface_config);
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,
});
}
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<Self>, _: wl_seat::WlSeat) {}
fn new_capability(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_seat: wl_seat::WlSeat,
_capability: Capability,
) {
}
fn remove_capability(
&mut self,
_conn: &Connection,
_: &QueueHandle<Self>,
_: wl_seat::WlSeat,
_capability: Capability,
) {
}
fn remove_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: 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];
}