From cc9621f75ab29eb65e89aa3519c2db8eb7c31bbd Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Wed, 14 Jun 2023 22:59:27 -0400 Subject: [PATCH 1/3] Improve simple_layer example --- examples/simple_layer.rs | 124 +++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 36 deletions(-) diff --git a/examples/simple_layer.rs b/examples/simple_layer.rs index 0b35a0fb6..b62e86b50 100644 --- a/examples/simple_layer.rs +++ b/examples/simple_layer.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; +use calloop::{EventLoop, LoopSignal}; use smithay_client_toolkit::{ compositor::{CompositorHandler, CompositorState}, delegate_compositor, delegate_keyboard, delegate_layer, delegate_output, delegate_pointer, @@ -21,12 +22,15 @@ use smithay_client_toolkit::{ }, WaylandSurface, }, - shm::{slot::SlotPool, Shm, ShmHandler}, + shm::{ + slot::{Buffer, SlotPool}, + Shm, ShmHandler, + }, }; use wayland_client::{ globals::registry_queue_init, protocol::{wl_keyboard, wl_output, wl_pointer, wl_seat, wl_shm, wl_surface}, - Connection, QueueHandle, + Connection, QueueHandle, WaylandSource, }; use xkbcommon::xkb::keysyms; @@ -37,7 +41,7 @@ fn main() { let conn = Connection::connect_to_env().unwrap(); // Enumerate the list of globals to get the protocols the server implements. - let (globals, mut event_queue) = registry_queue_init(&conn).unwrap(); + let (globals, event_queue) = registry_queue_init(&conn).unwrap(); let qh = event_queue.handle(); // The compositor (not to be confused with the server which is commonly called the compositor) allows @@ -72,6 +76,7 @@ fn main() { // initial memory allocation. let pool = SlotPool::new(256 * 256 * 4, &shm).expect("Failed to create pool"); + let mut event_loop = EventLoop::try_new().unwrap(); let mut simple_layer = SimpleLayer { // Seats and outputs may be hotplugged at runtime, therefore we need to setup a registry state to // listen for seats and outputs. @@ -80,27 +85,25 @@ fn main() { output_state: OutputState::new(&globals, &qh), shm, - exit: false, + exit: event_loop.get_signal(), first_configure: true, pool, width: 256, height: 256, shift: None, + buffer: None, + animating: false, layer, keyboard: None, keyboard_focus: false, pointer: None, }; - // We don't draw immediately, the configure will notify us when to first draw. - loop { - event_queue.blocking_dispatch(&mut simple_layer).unwrap(); + let ws = WaylandSource::new(event_queue).unwrap(); - if simple_layer.exit { - println!("exiting example"); - break; - } - } + ws.insert(event_loop.handle()).unwrap(); + + event_loop.run(None, &mut simple_layer, |_| {}).unwrap(); } struct SimpleLayer { @@ -109,12 +112,14 @@ struct SimpleLayer { output_state: OutputState, shm: Shm, - exit: bool, + exit: LoopSignal, first_configure: bool, + animating: bool, pool: SlotPool, width: u32, height: u32, shift: Option, + buffer: Option, layer: LayerSurface, keyboard: Option, keyboard_focus: bool, @@ -175,7 +180,7 @@ impl OutputHandler for SimpleLayer { impl LayerShellHandler for SimpleLayer { fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle, _layer: &LayerSurface) { - self.exit = true; + self.exit.stop(); } fn configure( @@ -194,6 +199,9 @@ impl LayerShellHandler for SimpleLayer { self.height = configure.new_size.1; } + // Initializes our double buffer one we've configured the layer shell + self.buffer = Some(Buffers::new(&mut self.pool, self.width, self.height)); + // Initiate the first draw. if self.first_configure { self.first_configure = false; @@ -293,7 +301,7 @@ impl KeyboardHandler for SimpleLayer { println!("Key press: {event:?}"); // press 'esc' to exit if event.keysym == keysyms::KEY_Escape { - self.exit = true; + self.exit.stop(); } } @@ -324,7 +332,7 @@ impl PointerHandler for SimpleLayer { fn pointer_frame( &mut self, _conn: &Connection, - _qh: &QueueHandle, + qh: &QueueHandle, _pointer: &wl_pointer::WlPointer, events: &[PointerEvent], ) { @@ -345,6 +353,14 @@ impl PointerHandler for SimpleLayer { Press { button, .. } => { println!("Press {:x} @ {:?}", button, event.position); self.shift = self.shift.xor(Some(0)); + // If we initialize a frame twice in a row, it invalidates one + // of the buffers, so if we're animating, chances are there's + // a frame in the queue + if !self.animating { + self.layer.wl_surface().frame(qh, self.layer.wl_surface().clone()); + self.layer.commit(); + } + self.animating = !self.animating; } Release { button, .. } => { println!("Release {:x} @ {:?}", button, event.position); @@ -367,15 +383,9 @@ impl SimpleLayer { pub fn draw(&mut self, qh: &QueueHandle) { let width = self.width; let height = self.height; - let stride = self.width as i32 * 4; - - let (buffer, canvas) = self - .pool - .create_buffer(width as i32, height as i32, stride, wl_shm::Format::Argb8888) - .expect("create buffer"); - // Draw to the window: - { + if let Some(ref mut buffers) = self.buffer { + let canvas = buffers.canvas(&mut self.pool).unwrap(); let shift = self.shift.unwrap_or(0); canvas.chunks_exact_mut(4).enumerate().for_each(|(index, chunk)| { let x = ((index + shift as usize) % width as usize) as u32; @@ -394,21 +404,20 @@ impl SimpleLayer { if let Some(shift) = &mut self.shift { *shift = (*shift + 1) % width; } - } - // Damage the entire window - self.layer.wl_surface().damage_buffer(0, 0, width as i32, height as i32); + // Damage the entire window + self.layer.wl_surface().damage_buffer(0, 0, width as i32, height as i32); - // Request our next frame - self.layer.wl_surface().frame(qh, self.layer.wl_surface().clone()); - - // Attach and commit to present. - buffer.attach_to(self.layer.wl_surface()).expect("buffer attach"); - self.layer.commit(); + if self.animating { + // Request our next frame + self.layer.wl_surface().frame(qh, self.layer.wl_surface().clone()); + } - // TODO save and reuse buffer when the window size is unchanged. This is especially - // useful if you do damage tracking, since you don't need to redraw the undamaged parts - // of the canvas. + // Attach and commit to present. + buffers.buffer().attach_to(self.layer.wl_surface()).expect("buffer attach"); + self.layer.commit(); + buffers.flip(); + } } } @@ -430,3 +439,46 @@ impl ProvidesRegistryState for SimpleLayer { } registry_handlers![OutputState, SeatState]; } + +struct Buffers { + buffers: [Buffer; 2], + current: usize, +} + +impl Buffers { + fn new(pool: &mut SlotPool, width: u32, height: u32) -> Buffers { + Self { + buffers: [ + pool.create_buffer( + width as i32, + height as i32, + width as i32 * 4, + wl_shm::Format::Argb8888, + ) + .expect("create buffer") + .0, + pool.create_buffer( + width as i32, + height as i32, + width as i32 * 4, + wl_shm::Format::Argb8888, + ) + .expect("create buffer") + .0, + ], + current: 0, + } + } + + fn flip(&mut self) { + self.current = 1 - self.current + } + + fn buffer(&self) -> &Buffer { + &self.buffers[self.current] + } + + fn canvas<'a>(&'a self, pool: &'a mut SlotPool) -> Option<&mut [u8]> { + self.buffers[self.current].canvas(pool) + } +} From 30e1781855f3c1333acff1bb0dff3b45e3c72f35 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Wed, 14 Jun 2023 23:04:31 -0400 Subject: [PATCH 2/3] Improve simple_layer example --- examples/simple_layer.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/simple_layer.rs b/examples/simple_layer.rs index b62e86b50..ab6b38d83 100644 --- a/examples/simple_layer.rs +++ b/examples/simple_layer.rs @@ -91,7 +91,7 @@ fn main() { width: 256, height: 256, shift: None, - buffer: None, + buffers: None, animating: false, layer, keyboard: None, @@ -119,7 +119,7 @@ struct SimpleLayer { width: u32, height: u32, shift: Option, - buffer: Option, + buffers: Option, layer: LayerSurface, keyboard: Option, keyboard_focus: bool, @@ -200,7 +200,7 @@ impl LayerShellHandler for SimpleLayer { } // Initializes our double buffer one we've configured the layer shell - self.buffer = Some(Buffers::new(&mut self.pool, self.width, self.height)); + self.buffers = Some(Buffers::new(&mut self.pool, self.width, self.height)); // Initiate the first draw. if self.first_configure { @@ -384,7 +384,7 @@ impl SimpleLayer { let width = self.width; let height = self.height; // Draw to the window: - if let Some(ref mut buffers) = self.buffer { + if let Some(ref mut buffers) = self.buffers { let canvas = buffers.canvas(&mut self.pool).unwrap(); let shift = self.shift.unwrap_or(0); canvas.chunks_exact_mut(4).enumerate().for_each(|(index, chunk)| { From 5f8ec65bca8250c60f306e8e4513037b25d00124 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Wed, 14 Jun 2023 23:15:32 -0400 Subject: [PATCH 3/3] simple_layer example; double buffer takes a shm format --- examples/simple_layer.rs | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/examples/simple_layer.rs b/examples/simple_layer.rs index ab6b38d83..44fd9e003 100644 --- a/examples/simple_layer.rs +++ b/examples/simple_layer.rs @@ -200,7 +200,8 @@ impl LayerShellHandler for SimpleLayer { } // Initializes our double buffer one we've configured the layer shell - self.buffers = Some(Buffers::new(&mut self.pool, self.width, self.height)); + self.buffers = + Some(Buffers::new(&mut self.pool, self.width, self.height, wl_shm::Format::Argb8888)); // Initiate the first draw. if self.first_configure { @@ -446,25 +447,15 @@ struct Buffers { } impl Buffers { - fn new(pool: &mut SlotPool, width: u32, height: u32) -> Buffers { + fn new(pool: &mut SlotPool, width: u32, height: u32, format: wl_shm::Format) -> Buffers { Self { buffers: [ - pool.create_buffer( - width as i32, - height as i32, - width as i32 * 4, - wl_shm::Format::Argb8888, - ) - .expect("create buffer") - .0, - pool.create_buffer( - width as i32, - height as i32, - width as i32 * 4, - wl_shm::Format::Argb8888, - ) - .expect("create buffer") - .0, + pool.create_buffer(width as i32, height as i32, width as i32 * 4, format) + .expect("create buffer") + .0, + pool.create_buffer(width as i32, height as i32, width as i32 * 4, format) + .expect("create buffer") + .0, ], current: 0, }