wvr_server: callbacks after render, force render cases

This commit is contained in:
galister 2026-07-04 11:39:17 +09:00
parent c98791aeb7
commit 052253f7f4
3 changed files with 74 additions and 11 deletions

View File

@ -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<WayVRTask>,
pub redraw_requests: HashSet<wayland_server::backend::ObjectId>,
pub popup_manager: PopupManager,
pub display_handle: DisplayHandle,
pub redraw_requests: HashSet<ObjectId>,
pub pending_frame_callbacks: HashMap<ObjectId, Vec<wl_callback::WlCallback>>,
}
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);
}
});

View File

@ -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 {

View File

@ -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<WGfxPipeline<Vert2Uv>>,
interaction_transform: Option<Affine2>,
window: WindowHandle,
popups: Vec<(Arc<ImageView>, Vec2)>,
popups: Vec<(ObjectId, Arc<ImageView>, Vec2)>,
just_resumed: bool,
meta: Option<FrameMeta>,
mouse: Option<MouseMeta>,
@ -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(())