diff --git a/wayvr/src/backend/wayvr/comp.rs b/wayvr/src/backend/wayvr/comp.rs index 438de5ce..fd6261a2 100644 --- a/wayvr/src/backend/wayvr/comp.rs +++ b/wayvr/src/backend/wayvr/comp.rs @@ -9,7 +9,8 @@ use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_to use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration; use smithay::reexports::wayland_server::Resource; -use smithay::reexports::wayland_server::protocol::{wl_buffer, wl_output, wl_seat}; +use smithay::reexports::wayland_server::backend::ObjectId; +use smithay::reexports::wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_seat}; use smithay::reexports::wayland_server::{self, DisplayHandle}; use smithay::wayland::buffer::BufferHandler; use smithay::wayland::dmabuf::{ @@ -32,7 +33,7 @@ use smithay::{ delegate_primary_selection, delegate_seat, delegate_shm, delegate_single_pixel_buffer, delegate_xdg_decoration, delegate_xdg_shell, }; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::Write; use std::os::fd::OwnedFd; @@ -74,9 +75,10 @@ pub struct Application { pub wlr_data_control_state: selection_wlr::DataControlState, pub kde_decoration_state: KdeDecorationState, pub wayvr_tasks: SyncEventQueue, - pub redraw_requests: HashSet, pub popup_manager: PopupManager, pub display_handle: DisplayHandle, + pub redraw_requests: HashSet, + pub pending_frame_callbacks: HashMap>, } impl Application { @@ -133,6 +135,26 @@ impl Application { }); }); } + + pub fn send_frame_callbacks_for_surface_id(&mut self, surface_id: &ObjectId) { + let Some(callbacks) = self.pending_frame_callbacks.remove(surface_id) else { + return; + }; + + let t = time::get_millis() as u32; + for cb in callbacks { + cb.done(t); + } + } + + pub fn has_pending_frame_callbacks( + &self, + surface_id: wayland_server::backend::ObjectId, + ) -> bool { + self.pending_frame_callbacks + .get(&surface_id) + .is_some_and(|v| !v.is_empty()) + } } impl compositor::CompositorHandler for Application { @@ -231,10 +253,12 @@ impl compositor::CompositorHandler for Application { Some(BufferAssignment::Removed) | None => {} } - let t = time::get_millis() as u32; let callbacks = std::mem::take(&mut attrs.frame_callbacks); - for cb in callbacks { - cb.done(t); + if !callbacks.is_empty() { + self.pending_frame_callbacks + .entry(surface.id()) + .or_default() + .extend(callbacks); } }); diff --git a/wayvr/src/backend/wayvr/mod.rs b/wayvr/src/backend/wayvr/mod.rs index cb465221..8d54f449 100644 --- a/wayvr/src/backend/wayvr/mod.rs +++ b/wayvr/src/backend/wayvr/mod.rs @@ -238,9 +238,10 @@ impl WvrServerState { ext_data_control_state, kde_decoration_state, wayvr_tasks: tasks.clone(), - redraw_requests: HashSet::new(), dmabuf_state, popup_manager: PopupManager::default(), + redraw_requests: HashSet::new(), + pending_frame_callbacks: HashMap::new(), }; Ok(Self { diff --git a/wayvr/src/overlays/wayvr.rs b/wayvr/src/overlays/wayvr.rs index 9a223ed2..e761d881 100644 --- a/wayvr/src/overlays/wayvr.rs +++ b/wayvr/src/overlays/wayvr.rs @@ -1,9 +1,10 @@ use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3}; use smithay::{ desktop::PopupManager, + reexports::wayland_server::{Resource, backend::ObjectId}, wayland::{compositor::with_states, shell::xdg::XdgPopupSurfaceData}, }; -use std::{ops::RangeInclusive, sync::Arc}; +use std::{mem, ops::RangeInclusive, sync::Arc}; use vulkano::{ buffer::BufferUsage, image::view::ImageView, pipeline::graphics::color_blend::AttachmentBlend, }; @@ -107,7 +108,7 @@ pub struct WvrWindowBackend { popups_pipeline: Arc>, interaction_transform: Option, window: WindowHandle, - popups: Vec<(Arc, Vec2)>, + popups: Vec<(ObjectId, Arc, Vec2)>, just_resumed: bool, meta: Option, mouse: Option, @@ -293,6 +294,16 @@ impl OverlayBackend for WvrWindowBackend { return Ok(ShouldRender::Unable); }; + let surface_id = toplevel.wl_surface().id(); + let has_pending_callbacks = app + .wvr_server + .as_ref() + .unwrap() + .manager + .state + .has_pending_frame_callbacks(surface_id); + let force_render = mem::take(&mut self.just_resumed) | has_pending_callbacks; + let popups = PopupManager::popups_for_surface(toplevel.wl_surface()) .filter_map(|(popup, point)| { with_states(popup.wl_surface(), |states| { @@ -309,7 +320,11 @@ impl OverlayBackend for WvrWindowBackend { } if let Some(surf) = SurfaceBufWithImage::get_from_surface(states) { - Some((surf.image, vec2(point.x as _, point.y as _))) + Some(( + popup.wl_surface().id(), + surf.image, + vec2(point.x as _, point.y as _), + )) } else { None } @@ -386,6 +401,12 @@ impl OverlayBackend for WvrWindowBackend { self.mouse = mouse; self.popups = popups; self.meta = Some(meta); + + if force_render { + self.cur_image = Some(surf.image); + return Ok(ShouldRender::Should); + } + if self .cur_image .as_ref() @@ -430,7 +451,7 @@ impl OverlayBackend for WvrWindowBackend { .unwrap() .render(image, self.mouse.as_ref(), app, rdr)?; - for (popup_img, point) in &self.popups { + for (popup_surface_id, popup_img, point) in &self.popups { let meta = self.meta.as_ref().unwrap(); let extentf = [meta.extent[0] as f32, meta.extent[1] as f32]; let popup_extentf = popup_img.extent_f32(); @@ -466,6 +487,23 @@ impl OverlayBackend for WvrWindowBackend { for buf in &mut rdr.cmd_bufs { buf.run_ref(&pass)?; } + + app.wvr_server + .as_mut() + .unwrap() + .manager + .state + .send_frame_callbacks_for_surface_id(popup_surface_id); + } + + if let Some(wvr_server) = app.wvr_server.as_mut() { + if let Some(window) = wvr_server.wm.windows.get(&self.window) { + let surface_id = window.toplevel.wl_surface().id(); + wvr_server + .manager + .state + .send_frame_callbacks_for_surface_id(&surface_id); + } } Ok(())