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() {
|
||||
exts.enable_extx_overlay();
|
||||
}
|
||||
exts.khr_convert_timespec_time = true;
|
||||
exts
|
||||
},
|
||||
..default()
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
wayland::{
|
||||
Message, MessageSink,
|
||||
core::buffer::BufferUsage,
|
||||
presentation::{MonotonicTimestamp, PresentationFeedback},
|
||||
util::{ClientExt, DoubleBuffer},
|
||||
xdg::{popup::Popup, toplevel::Toplevel},
|
||||
},
|
||||
@@ -22,7 +23,10 @@ use std::sync::{Arc, OnceLock};
|
||||
use waynest::{
|
||||
server::{
|
||||
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,
|
||||
};
|
||||
@@ -71,10 +75,12 @@ pub struct Surface {
|
||||
pub id: ObjectId,
|
||||
state: Mutex<DoubleBuffer<SurfaceState>>,
|
||||
pub message_sink: MessageSink,
|
||||
// TODO: This should probably be a OnceLock? wayland doesn't support changing the surface role
|
||||
pub role: Mutex<Option<SurfaceRole>>,
|
||||
on_commit_handlers: Mutex<Vec<OnCommitCallback>>,
|
||||
material: OnceLock<Handle<BevyMaterial>>,
|
||||
pending_material_applications: Registry<ModelPart>,
|
||||
presentation_feedback: Mutex<Vec<Arc<PresentationFeedback>>>,
|
||||
}
|
||||
impl std::fmt::Debug for Surface {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -100,6 +106,7 @@ impl Surface {
|
||||
on_commit_handlers: Mutex::new(Vec::new()),
|
||||
material: OnceLock::new(),
|
||||
pending_material_applications: Registry::new(),
|
||||
presentation_feedback: Mutex::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +219,60 @@ impl Surface {
|
||||
|
||||
// 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 {
|
||||
/// https://wayland.app/protocols/wayland#wl_surface:request:attach
|
||||
|
||||
@@ -2,6 +2,7 @@ mod core;
|
||||
mod display;
|
||||
mod dmabuf;
|
||||
mod mesa_drm;
|
||||
mod presentation;
|
||||
mod registry;
|
||||
mod util;
|
||||
mod vulkano_data;
|
||||
@@ -10,6 +11,8 @@ mod xdg;
|
||||
use crate::core::registry::OwnedRegistry;
|
||||
use crate::nodes::drawable::model::ModelNodeSystemSet;
|
||||
use crate::wayland::core::seat::SeatMessage;
|
||||
use crate::wayland::core::surface::Surface;
|
||||
use crate::wayland::presentation::MonotonicTimestamp;
|
||||
use crate::{
|
||||
BevyMaterial,
|
||||
core::{
|
||||
@@ -18,13 +21,15 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use bevy::app::{App, Plugin, Update};
|
||||
use bevy::diagnostic::FrameCount;
|
||||
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::render::renderer::RenderDevice;
|
||||
use bevy::render::{Render, RenderApp};
|
||||
use bevy::{asset::Assets, ecs::resource::Resource, image::Image};
|
||||
use bevy_dmabuf::import::ImportedDmatexs;
|
||||
use bevy_mod_openxr::render::end_frame;
|
||||
use bevy_mod_xr::session::XrRenderSet;
|
||||
use cluFlock::{FlockLock, ToFlock};
|
||||
use core::buffer::BufferUsage;
|
||||
@@ -124,6 +129,11 @@ pub enum Message {
|
||||
active: bool,
|
||||
},
|
||||
Seat(SeatMessage),
|
||||
SendPresentationFeedback {
|
||||
surface: Arc<Surface>,
|
||||
display_timestamp: MonotonicTimestamp,
|
||||
refresh_cycle: u64,
|
||||
},
|
||||
}
|
||||
|
||||
pub type MessageSink = mpsc::UnboundedSender<Message>;
|
||||
@@ -234,6 +244,15 @@ impl WaylandClient {
|
||||
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)
|
||||
}
|
||||
@@ -310,7 +329,13 @@ impl Plugin for WaylandPlugin {
|
||||
app.sub_app_mut(RenderApp)
|
||||
.add_systems(Render, setup_vulkano_context)
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
#[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},
|
||||
seat::{Seat, WlSeat},
|
||||
shm::{Shm, WlShm},
|
||||
},
|
||||
dmabuf::Dmabuf,
|
||||
mesa_drm::MesaDrm,
|
||||
util::ClientExt,
|
||||
xdg::wm_base::{WmBase, XdgWmBase},
|
||||
}, dmabuf::Dmabuf, mesa_drm::MesaDrm, presentation::Presentation, util::ClientExt, xdg::wm_base::{WmBase, XdgWmBase}
|
||||
};
|
||||
use waynest::{
|
||||
server::{
|
||||
Client, Dispatcher, Error, Result,
|
||||
protocol::{
|
||||
core::wayland::{wl_data_device_manager::WlDataDeviceManager, wl_registry::*},
|
||||
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},
|
||||
};
|
||||
@@ -33,6 +28,7 @@ impl RegistryGlobals {
|
||||
pub const OUTPUT: u32 = 5;
|
||||
pub const DMABUF: u32 = 6;
|
||||
pub const WL_DRM: u32 = 7;
|
||||
pub const PRESENTATION: u32 = 8;
|
||||
}
|
||||
|
||||
#[derive(Debug, Dispatcher, Default)]
|
||||
@@ -112,6 +108,15 @@ impl Registry {
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.global(
|
||||
client,
|
||||
sender_id,
|
||||
RegistryGlobals::PRESENTATION,
|
||||
Presentation::INTERFACE.to_string(),
|
||||
Presentation::VERSION,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -170,6 +175,12 @@ impl WlRegistry for Registry {
|
||||
let drm = MesaDrm::new(client, new_id.object_id, new_id.version).await?;
|
||||
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 => {
|
||||
tracing::error!(id, "Wayland: failed to bind to registry global");
|
||||
return Err(Error::MissingObject(unsafe { ObjectId::from_raw(name) }));
|
||||
|
||||
Reference in New Issue
Block a user