feat(wayland): WIP implement wp_presentation_time
Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
@@ -337,6 +337,7 @@ fn bevy_loop(
|
|||||||
if args.overlay_priority.is_some() {
|
if args.overlay_priority.is_some() {
|
||||||
exts.enable_extx_overlay();
|
exts.enable_extx_overlay();
|
||||||
}
|
}
|
||||||
|
exts.khr_convert_timespec_time = true;
|
||||||
exts
|
exts
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::{
|
|||||||
wayland::{
|
wayland::{
|
||||||
Message, MessageSink,
|
Message, MessageSink,
|
||||||
core::buffer::BufferUsage,
|
core::buffer::BufferUsage,
|
||||||
|
presentation::{MonotonicTimestamp, PresentationFeedback},
|
||||||
util::{ClientExt, DoubleBuffer},
|
util::{ClientExt, DoubleBuffer},
|
||||||
xdg::{popup::Popup, toplevel::Toplevel},
|
xdg::{popup::Popup, toplevel::Toplevel},
|
||||||
},
|
},
|
||||||
@@ -22,7 +23,10 @@ use std::sync::{Arc, OnceLock};
|
|||||||
use waynest::{
|
use waynest::{
|
||||||
server::{
|
server::{
|
||||||
Client, Dispatcher, Result,
|
Client, Dispatcher, Result,
|
||||||
protocol::core::wayland::{wl_output::Transform, wl_surface::*},
|
protocol::{
|
||||||
|
core::wayland::{wl_output::Transform, wl_surface::*},
|
||||||
|
stable::presentation_time::wp_presentation_feedback::{Kind, WpPresentationFeedback},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
wire::ObjectId,
|
wire::ObjectId,
|
||||||
};
|
};
|
||||||
@@ -71,10 +75,12 @@ pub struct Surface {
|
|||||||
pub id: ObjectId,
|
pub id: ObjectId,
|
||||||
state: Mutex<DoubleBuffer<SurfaceState>>,
|
state: Mutex<DoubleBuffer<SurfaceState>>,
|
||||||
pub message_sink: MessageSink,
|
pub message_sink: MessageSink,
|
||||||
|
// TODO: This should probably be a OnceLock? wayland doesn't support changing the surface role
|
||||||
pub role: Mutex<Option<SurfaceRole>>,
|
pub role: Mutex<Option<SurfaceRole>>,
|
||||||
on_commit_handlers: Mutex<Vec<OnCommitCallback>>,
|
on_commit_handlers: Mutex<Vec<OnCommitCallback>>,
|
||||||
material: OnceLock<Handle<BevyMaterial>>,
|
material: OnceLock<Handle<BevyMaterial>>,
|
||||||
pending_material_applications: Registry<ModelPart>,
|
pending_material_applications: Registry<ModelPart>,
|
||||||
|
presentation_feedback: Mutex<Vec<Arc<PresentationFeedback>>>,
|
||||||
}
|
}
|
||||||
impl std::fmt::Debug for Surface {
|
impl std::fmt::Debug for Surface {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@@ -100,6 +106,7 @@ impl Surface {
|
|||||||
on_commit_handlers: Mutex::new(Vec::new()),
|
on_commit_handlers: Mutex::new(Vec::new()),
|
||||||
material: OnceLock::new(),
|
material: OnceLock::new(),
|
||||||
pending_material_applications: Registry::new(),
|
pending_material_applications: Registry::new(),
|
||||||
|
presentation_feedback: Mutex::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +219,60 @@ impl Surface {
|
|||||||
|
|
||||||
// Ok(())
|
// Ok(())
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
|
pub fn add_presentation_feedback(&self, feedback: Arc<PresentationFeedback>) {
|
||||||
|
self.presentation_feedback.lock().push(feedback);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn submit_presentation_feedback(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
display_timestamp: MonotonicTimestamp,
|
||||||
|
refresh_cycle: u64,
|
||||||
|
) {
|
||||||
|
self.message_sink
|
||||||
|
.send(Message::SendPresentationFeedback {
|
||||||
|
surface: self.clone(),
|
||||||
|
display_timestamp,
|
||||||
|
refresh_cycle,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
|
pub async fn send_presentation_feedback(
|
||||||
|
&self,
|
||||||
|
client: &mut Client,
|
||||||
|
display_timestamp: MonotonicTimestamp,
|
||||||
|
refresh_cycle: u64,
|
||||||
|
) -> Result<()> {
|
||||||
|
let feedbacks = self
|
||||||
|
.presentation_feedback
|
||||||
|
.lock()
|
||||||
|
.drain(..)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for feedback in feedbacks {
|
||||||
|
feedback
|
||||||
|
.sync_output(client, feedback.0, client.display().output.get().unwrap().0)
|
||||||
|
.await?;
|
||||||
|
let cycle_lo = refresh_cycle as u32;
|
||||||
|
let cycle_hi = (refresh_cycle >> 32) as u32;
|
||||||
|
feedback
|
||||||
|
.presented(
|
||||||
|
client,
|
||||||
|
feedback.0,
|
||||||
|
display_timestamp.secs_hi(),
|
||||||
|
display_timestamp.secs_lo(),
|
||||||
|
display_timestamp.subsec_nanos(),
|
||||||
|
0,
|
||||||
|
cycle_hi,
|
||||||
|
cycle_lo,
|
||||||
|
Kind::empty(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl WlSurface for Surface {
|
impl WlSurface for Surface {
|
||||||
/// https://wayland.app/protocols/wayland#wl_surface:request:attach
|
/// https://wayland.app/protocols/wayland#wl_surface:request:attach
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ mod core;
|
|||||||
mod display;
|
mod display;
|
||||||
mod dmabuf;
|
mod dmabuf;
|
||||||
mod mesa_drm;
|
mod mesa_drm;
|
||||||
|
mod presentation;
|
||||||
mod registry;
|
mod registry;
|
||||||
mod util;
|
mod util;
|
||||||
mod vulkano_data;
|
mod vulkano_data;
|
||||||
@@ -10,6 +11,8 @@ mod xdg;
|
|||||||
use crate::core::registry::OwnedRegistry;
|
use crate::core::registry::OwnedRegistry;
|
||||||
use crate::nodes::drawable::model::ModelNodeSystemSet;
|
use crate::nodes::drawable::model::ModelNodeSystemSet;
|
||||||
use crate::wayland::core::seat::SeatMessage;
|
use crate::wayland::core::seat::SeatMessage;
|
||||||
|
use crate::wayland::core::surface::Surface;
|
||||||
|
use crate::wayland::presentation::MonotonicTimestamp;
|
||||||
use crate::{
|
use crate::{
|
||||||
BevyMaterial,
|
BevyMaterial,
|
||||||
core::{
|
core::{
|
||||||
@@ -18,13 +21,15 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bevy::app::{App, Plugin, Update};
|
use bevy::app::{App, Plugin, Update};
|
||||||
|
use bevy::diagnostic::FrameCount;
|
||||||
use bevy::ecs::schedule::IntoScheduleConfigs;
|
use bevy::ecs::schedule::IntoScheduleConfigs;
|
||||||
use bevy::ecs::system::{Res, ResMut};
|
use bevy::ecs::system::{Local, Res, ResMut};
|
||||||
use bevy::prelude::{Deref, DerefMut};
|
use bevy::prelude::{Deref, DerefMut};
|
||||||
use bevy::render::renderer::RenderDevice;
|
use bevy::render::renderer::RenderDevice;
|
||||||
use bevy::render::{Render, RenderApp};
|
use bevy::render::{Render, RenderApp};
|
||||||
use bevy::{asset::Assets, ecs::resource::Resource, image::Image};
|
use bevy::{asset::Assets, ecs::resource::Resource, image::Image};
|
||||||
use bevy_dmabuf::import::ImportedDmatexs;
|
use bevy_dmabuf::import::ImportedDmatexs;
|
||||||
|
use bevy_mod_openxr::render::end_frame;
|
||||||
use bevy_mod_xr::session::XrRenderSet;
|
use bevy_mod_xr::session::XrRenderSet;
|
||||||
use cluFlock::{FlockLock, ToFlock};
|
use cluFlock::{FlockLock, ToFlock};
|
||||||
use core::buffer::BufferUsage;
|
use core::buffer::BufferUsage;
|
||||||
@@ -124,6 +129,11 @@ pub enum Message {
|
|||||||
active: bool,
|
active: bool,
|
||||||
},
|
},
|
||||||
Seat(SeatMessage),
|
Seat(SeatMessage),
|
||||||
|
SendPresentationFeedback {
|
||||||
|
surface: Arc<Surface>,
|
||||||
|
display_timestamp: MonotonicTimestamp,
|
||||||
|
refresh_cycle: u64,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type MessageSink = mpsc::UnboundedSender<Message>;
|
pub type MessageSink = mpsc::UnboundedSender<Message>;
|
||||||
@@ -234,6 +244,15 @@ impl WaylandClient {
|
|||||||
seat.handle_message(client, seat_message).await?;
|
seat.handle_message(client, seat_message).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::SendPresentationFeedback {
|
||||||
|
surface,
|
||||||
|
display_timestamp,
|
||||||
|
refresh_cycle,
|
||||||
|
} => {
|
||||||
|
surface
|
||||||
|
.send_presentation_feedback(client, display_timestamp, refresh_cycle)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
@@ -310,7 +329,13 @@ impl Plugin for WaylandPlugin {
|
|||||||
app.sub_app_mut(RenderApp)
|
app.sub_app_mut(RenderApp)
|
||||||
.add_systems(Render, setup_vulkano_context)
|
.add_systems(Render, setup_vulkano_context)
|
||||||
.add_systems(Render, before_render.in_set(XrRenderSet::PreRender))
|
.add_systems(Render, before_render.in_set(XrRenderSet::PreRender))
|
||||||
.add_systems(Render, after_render.in_set(XrRenderSet::PostRender));
|
.add_systems(Render, after_render.in_set(XrRenderSet::PostRender))
|
||||||
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
submit_frame_timings
|
||||||
|
.in_set(XrRenderSet::PostRender)
|
||||||
|
.after(end_frame),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,3 +379,13 @@ fn update_graphics(
|
|||||||
surface.update_graphics(&dmatexes, &mut materials, &mut images);
|
surface.update_graphics(&dmatexes, &mut materials, &mut images);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", name = "Wayland frame", skip_all)]
|
||||||
|
fn submit_frame_timings(mut frame_count: Local<u64>) {
|
||||||
|
*frame_count += 1;
|
||||||
|
for surface in WL_SURFACE_REGISTRY.get_valid_contents() {
|
||||||
|
let display_timestamp =
|
||||||
|
rustix::time::clock_gettime(rustix::time::ClockId::Monotonic).into();
|
||||||
|
surface.submit_presentation_feedback(display_timestamp, *frame_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,20 +5,15 @@ use crate::wayland::{
|
|||||||
output::{Output, WlOutput},
|
output::{Output, WlOutput},
|
||||||
seat::{Seat, WlSeat},
|
seat::{Seat, WlSeat},
|
||||||
shm::{Shm, WlShm},
|
shm::{Shm, WlShm},
|
||||||
},
|
}, dmabuf::Dmabuf, mesa_drm::MesaDrm, presentation::Presentation, util::ClientExt, xdg::wm_base::{WmBase, XdgWmBase}
|
||||||
dmabuf::Dmabuf,
|
|
||||||
mesa_drm::MesaDrm,
|
|
||||||
util::ClientExt,
|
|
||||||
xdg::wm_base::{WmBase, XdgWmBase},
|
|
||||||
};
|
};
|
||||||
use waynest::{
|
use waynest::{
|
||||||
server::{
|
server::{
|
||||||
Client, Dispatcher, Error, Result,
|
|
||||||
protocol::{
|
protocol::{
|
||||||
core::wayland::{wl_data_device_manager::WlDataDeviceManager, wl_registry::*},
|
core::wayland::{wl_data_device_manager::WlDataDeviceManager, wl_registry::*},
|
||||||
external::drm::wl_drm::WlDrm,
|
external::drm::wl_drm::WlDrm,
|
||||||
stable::linux_dmabuf_v1::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
stable::{linux_dmabuf_v1::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1, presentation_time::wp_presentation::WpPresentation},
|
||||||
},
|
}, Client, Dispatcher, Error, Result
|
||||||
},
|
},
|
||||||
wire::{NewId, ObjectId},
|
wire::{NewId, ObjectId},
|
||||||
};
|
};
|
||||||
@@ -33,6 +28,7 @@ impl RegistryGlobals {
|
|||||||
pub const OUTPUT: u32 = 5;
|
pub const OUTPUT: u32 = 5;
|
||||||
pub const DMABUF: u32 = 6;
|
pub const DMABUF: u32 = 6;
|
||||||
pub const WL_DRM: u32 = 7;
|
pub const WL_DRM: u32 = 7;
|
||||||
|
pub const PRESENTATION: u32 = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Dispatcher, Default)]
|
#[derive(Debug, Dispatcher, Default)]
|
||||||
@@ -112,6 +108,15 @@ impl Registry {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
self.global(
|
||||||
|
client,
|
||||||
|
sender_id,
|
||||||
|
RegistryGlobals::PRESENTATION,
|
||||||
|
Presentation::INTERFACE.to_string(),
|
||||||
|
Presentation::VERSION,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,6 +175,12 @@ impl WlRegistry for Registry {
|
|||||||
let drm = MesaDrm::new(client, new_id.object_id, new_id.version).await?;
|
let drm = MesaDrm::new(client, new_id.object_id, new_id.version).await?;
|
||||||
client.insert(new_id.object_id, drm);
|
client.insert(new_id.object_id, drm);
|
||||||
}
|
}
|
||||||
|
RegistryGlobals::PRESENTATION => {
|
||||||
|
tracing::info!("Binding wp_presentation");
|
||||||
|
|
||||||
|
let presentation = Presentation::new(new_id.version);
|
||||||
|
client.insert(new_id.object_id, presentation);
|
||||||
|
}
|
||||||
id => {
|
id => {
|
||||||
tracing::error!(id, "Wayland: failed to bind to registry global");
|
tracing::error!(id, "Wayland: failed to bind to registry global");
|
||||||
return Err(Error::MissingObject(unsafe { ObjectId::from_raw(name) }));
|
return Err(Error::MissingObject(unsafe { ObjectId::from_raw(name) }));
|
||||||
|
|||||||
Reference in New Issue
Block a user