wayland: implement tearing-control-v1

Currently has no effect because there are no tearing atomic commits. But
by implementing this we make mesa expose VK_PRESENT_MODE_IMMEDIATE_KHR.
This commit is contained in:
Julian Orth 2022-11-18 19:42:59 +01:00
parent 0b46391789
commit cd47baa934
7 changed files with 235 additions and 1 deletions

View file

@ -22,6 +22,7 @@ use {
wl_surface::xwayland_shell_v1::XwaylandShellV1Global,
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
wp_presentation::WpPresentationGlobal,
wp_tearing_control_manager_v1::WpTearingControlManagerV1Global,
wp_viewporter::WpViewporterGlobal,
xdg_wm_base::XdgWmBaseGlobal,
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
@ -154,6 +155,7 @@ impl Globals {
add_singleton!(WpFractionalScaleManagerV1Global);
add_singleton!(ZwpPointerConstraintsV1Global);
add_singleton!(XwaylandShellV1Global);
add_singleton!(WpTearingControlManagerV1Global);
}
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {

View file

@ -30,6 +30,7 @@ pub mod wl_surface;
pub mod wp_fractional_scale_manager_v1;
pub mod wp_presentation;
pub mod wp_presentation_feedback;
pub mod wp_tearing_control_manager_v1;
pub mod wp_viewporter;
pub mod xdg_positioner;
pub mod xdg_wm_base;

View file

@ -2,6 +2,7 @@ pub mod cursor;
pub mod ext_session_lock_surface_v1;
pub mod wl_subsurface;
pub mod wp_fractional_scale_v1;
pub mod wp_tearing_control_v1;
pub mod wp_viewport;
pub mod x_surface;
pub mod xdg_surface;
@ -27,7 +28,8 @@ use {
},
wl_surface::{
cursor::CursorSurface, wl_subsurface::WlSubsurface,
wp_fractional_scale_v1::WpFractionalScaleV1, wp_viewport::WpViewport,
wp_fractional_scale_v1::WpFractionalScaleV1,
wp_tearing_control_v1::WpTearingControlV1, wp_viewport::WpViewport,
x_surface::XSurface, xdg_surface::XdgSurfaceError,
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error,
},
@ -261,6 +263,8 @@ pub struct WlSurface {
fractional_scale: CloneCell<Option<Rc<WpFractionalScaleV1>>>,
pub constraints: SmallMap<SeatId, Rc<SeatConstraint>, 1>,
xwayland_serial: Cell<Option<u64>>,
tearing_control: CloneCell<Option<Rc<WpTearingControlV1>>>,
tearing: Cell<bool>,
}
impl Debug for WlSurface {
@ -353,6 +357,7 @@ struct PendingState {
scale: Cell<Option<i32>>,
transform: Cell<Option<Transform>>,
xwayland_serial: Cell<Option<u64>>,
tearing: Cell<Option<bool>>,
}
#[derive(Default)]
@ -405,6 +410,8 @@ impl WlSurface {
fractional_scale: Default::default(),
constraints: Default::default(),
xwayland_serial: Default::default(),
tearing_control: Default::default(),
tearing: Cell::new(false),
}
}
@ -871,6 +878,9 @@ impl WlSurface {
self.opaque_region.set(region);
}
}
if let Some(tearing) = self.pending.tearing.take() {
self.tearing.set(tearing);
}
if let Some(xwayland_serial) = self.pending.xwayland_serial.take() {
self.xwayland_serial.set(Some(xwayland_serial));
self.client
@ -1080,6 +1090,7 @@ impl Object for WlSurface {
self.presentation_feedback.borrow_mut().clear();
self.viewporter.take();
self.fractional_scale.take();
self.tearing_control.take();
self.constraints.clear();
}
}

View file

@ -0,0 +1,82 @@
use {
crate::{
client::ClientError,
ifs::wl_surface::WlSurface,
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{wp_tearing_control_v1::*, WlSurfaceId, WpTearingControlV1Id},
},
std::{fmt::Debug, rc::Rc},
thiserror::Error,
};
const VSYNC: u32 = 0;
const ASYNC: u32 = 1;
pub struct WpTearingControlV1 {
pub id: WpTearingControlV1Id,
pub surface: Rc<WlSurface>,
pub tracker: Tracker<Self>,
}
impl WpTearingControlV1 {
pub fn install(self: &Rc<Self>) -> Result<(), WpTearingControlV1Error> {
if self.surface.tearing_control.get().is_some() {
return Err(WpTearingControlV1Error::AlreadyAttached(self.surface.id));
}
self.surface.tearing_control.set(Some(self.clone()));
Ok(())
}
fn set_presentation_hint(
&self,
parser: MsgParser<'_, '_>,
) -> Result<(), WpTearingControlV1Error> {
let req: SetPresentationHint = self.surface.client.parse(self, parser)?;
let tearing = match req.hint {
VSYNC => false,
ASYNC => true,
_ => return Err(WpTearingControlV1Error::UnknownPresentationHint(req.hint)),
};
self.surface.pending.tearing.set(Some(tearing));
Ok(())
}
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpTearingControlV1Error> {
let _req: Destroy = self.surface.client.parse(self, parser)?;
self.surface.pending.tearing.set(Some(false));
self.surface.tearing_control.take();
self.surface.client.remove_obj(self)?;
Ok(())
}
}
object_base! {
WpTearingControlV1;
SET_PRESENTATION_HINT => set_presentation_hint,
DESTROY => destroy,
}
impl Object for WpTearingControlV1 {
fn num_requests(&self) -> u32 {
DESTROY + 1
}
}
simple_add_obj!(WpTearingControlV1);
#[derive(Debug, Error)]
pub enum WpTearingControlV1Error {
#[error("Surface {0} already has a wp_tearing_control")]
AlreadyAttached(WlSurfaceId),
#[error("Unknown presentation hint {0}")]
UnknownPresentationHint(u32),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
}
efrom!(WpTearingControlV1Error, ClientError);
efrom!(WpTearingControlV1Error, MsgParserError);

View file

@ -0,0 +1,118 @@
use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName},
ifs::wl_surface::wp_tearing_control_v1::{WpTearingControlV1, WpTearingControlV1Error},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{
wp_tearing_control_manager_v1::{GET_TEARING_CONTROL, *},
WpTearingControlManagerV1Id,
},
},
std::rc::Rc,
thiserror::Error,
};
pub struct WpTearingControlManagerV1Global {
name: GlobalName,
}
impl WpTearingControlManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: WpTearingControlManagerV1Id,
client: &Rc<Client>,
_version: u32,
) -> Result<(), WpTearingControlManagerV1Error> {
let obj = Rc::new(WpTearingControlManagerV1 {
id,
client: client.clone(),
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}
global_base!(
WpTearingControlManagerV1Global,
WpTearingControlManagerV1,
WpTearingControlManagerV1Error
);
impl Global for WpTearingControlManagerV1Global {
fn singleton(&self) -> bool {
true
}
fn version(&self) -> u32 {
1
}
}
simple_add_global!(WpTearingControlManagerV1Global);
pub struct WpTearingControlManagerV1 {
pub id: WpTearingControlManagerV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
}
impl WpTearingControlManagerV1 {
pub fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpTearingControlManagerV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
self.client.remove_obj(self)?;
Ok(())
}
pub fn get_tearing_control(
&self,
parser: MsgParser<'_, '_>,
) -> Result<(), WpTearingControlManagerV1Error> {
let req: GetTearingControl = self.client.parse(self, parser)?;
let surface = self.client.lookup(req.surface)?;
let control = Rc::new(WpTearingControlV1 {
id: req.id,
surface,
tracker: Default::default(),
});
track!(self.client, control);
self.client.add_client_obj(&control)?;
control.install()?;
Ok(())
}
}
object_base! {
WpTearingControlManagerV1;
DESTROY => destroy,
GET_TEARING_CONTROL => get_tearing_control,
}
impl Object for WpTearingControlManagerV1 {
fn num_requests(&self) -> u32 {
GET_TEARING_CONTROL + 1
}
}
simple_add_obj!(WpTearingControlManagerV1);
#[derive(Debug, Error)]
pub enum WpTearingControlManagerV1Error {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error(transparent)]
WpTearingControlV1Error(#[from] WpTearingControlV1Error),
}
efrom!(WpTearingControlManagerV1Error, ClientError);
efrom!(WpTearingControlManagerV1Error, MsgParserError);

View file

@ -0,0 +1,11 @@
# requests
msg destroy = 0 {
}
msg get_tearing_control = 1 {
id: id(wp_tearing_control_v1),
surface: id(wl_surface),
}

View file

@ -0,0 +1,9 @@
# requests
msg set_presentation_hint = 0 {
hint: u32,
}
msg destroy = 1 {
}