1
0
Fork 0
forked from wry/wry

metal: implement tearing

This commit is contained in:
Julian Orth 2024-07-18 15:04:02 +02:00
parent d355059ad9
commit 49f6304716
31 changed files with 726 additions and 51 deletions

View file

@ -112,6 +112,9 @@ pub trait Connector {
fn set_vrr_enabled(&self, enabled: bool) {
let _ = enabled;
}
fn set_tearing_enabled(&self, enabled: bool) {
let _ = enabled;
}
}
#[derive(Debug)]

View file

@ -33,7 +33,8 @@ use {
DrmCrtc, DrmEncoder, DrmError, DrmEvent, DrmFramebuffer, DrmLease, DrmMaster,
DrmModeInfo, DrmObject, DrmPlane, DrmProperty, DrmPropertyDefinition,
DrmPropertyType, DrmVersion, PropBlob, DRM_CLIENT_CAP_ATOMIC,
DRM_MODE_ATOMIC_ALLOW_MODESET, DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
DRM_MODE_ATOMIC_ALLOW_MODESET, DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_ASYNC,
DRM_MODE_PAGE_FLIP_EVENT,
},
gbm::{GbmBo, GbmDevice, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT},
Modifier, INVALID_MODIFIER,
@ -89,6 +90,7 @@ pub struct MetalDrmDevice {
pub _max_height: u32,
pub cursor_width: u64,
pub cursor_height: u64,
pub supports_async_commit: bool,
pub gbm: GbmDevice,
pub handle_events: HandleEvents,
pub ctx: CloneCell<Rc<MetalRenderContext>>,
@ -456,6 +458,8 @@ pub struct MetalConnector {
pub active_framebuffer: RefCell<Option<PresentFb>>,
pub next_framebuffer: OpaqueCell<Option<PresentFb>>,
pub direct_scanout_active: Cell<bool>,
pub tearing_requested: Cell<bool>,
}
impl Debug for MetalConnector {
@ -947,6 +951,16 @@ impl MetalConnector {
let cursor = self.cursor_plane.get();
let mut new_fb = None;
let mut changes = self.master.change();
let mut try_async_flip = self.tearing_requested.get() && self.dev.supports_async_commit;
macro_rules! change {
($c:expr, $prop:expr, $new:expr) => {{
if $prop.value.get() != $new {
$c.change($prop.id, $new as u64);
try_async_flip = false;
$prop.pending_value.set(Some($new));
}
}};
}
if self.has_damage.get() {
if !self.backend.check_render_context(&self.dev) {
return Ok(());
@ -978,13 +992,13 @@ impl MetalConnector {
let in_fence = fb.sync_file.as_ref().map(|s| s.raw()).unwrap_or(-1);
changes.change_object(plane.id, |c| {
c.change(plane.fb_id, fb.fb.id().0 as _);
c.change(plane.src_w.id, (src_width as u64) << 16);
c.change(plane.src_h.id, (src_height as u64) << 16);
c.change(plane.crtc_x.id, crtc_x as u64);
c.change(plane.crtc_y.id, crtc_y as u64);
c.change(plane.crtc_w.id, crtc_w as u64);
c.change(plane.crtc_h.id, crtc_h as u64);
if !self.dev.is_nvidia {
change!(c, plane.src_w, (src_width as u32) << 16);
change!(c, plane.src_h, (src_height as u32) << 16);
change!(c, plane.crtc_x, crtc_x);
change!(c, plane.crtc_y, crtc_y);
change!(c, plane.crtc_w, crtc_w);
change!(c, plane.crtc_h, crtc_h);
if !try_async_flip && !self.dev.is_nvidia {
c.change(plane.in_fence_fd, in_fence as u64);
}
});
@ -1002,6 +1016,7 @@ impl MetalConnector {
let mut cursor_swap_buffer = false;
let mut cursor_sync_file = None;
if self.cursor_changed.get() && cursor.is_some() {
try_async_flip = false;
let plane = cursor.unwrap();
if self.cursor_enabled.get() {
cursor_swap_buffer = self.cursor_swap_buffer.get();
@ -1039,7 +1054,18 @@ impl MetalConnector {
});
}
}
if let Err(e) = changes.commit(DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, 0) {
let mut res;
'commit: {
const FLAGS: u32 = DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT;
if try_async_flip {
res = changes.commit(FLAGS | DRM_MODE_PAGE_FLIP_ASYNC, 0);
if res.is_ok() {
break 'commit;
}
}
res = changes.commit(FLAGS, 0);
}
if let Err(e) = res {
if let DrmError::Atomic(OsError(c::EACCES)) = e {
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
self.render_result
@ -1069,6 +1095,19 @@ impl MetalConnector {
.discard_presentation_feedback();
Err(MetalError::Commit(e))
} else {
macro_rules! apply_change {
($prop:expr) => {
if let Some(v) = $prop.pending_value.take() {
$prop.value.set(v);
}
};
}
apply_change!(plane.src_w);
apply_change!(plane.src_h);
apply_change!(plane.crtc_x);
apply_change!(plane.crtc_y);
apply_change!(plane.crtc_w);
apply_change!(plane.crtc_h);
node.schedule.presented();
self.perform_screencopies(&new_fb, &node);
if let Some(fb) = new_fb {
@ -1374,6 +1413,19 @@ impl Connector for MetalConnector {
crtc.vrr_enabled.value.set(new_enabled);
self.send_vrr_enabled();
}
fn set_tearing_enabled(&self, enabled: bool) {
if !self.dev.supports_async_commit {
return;
}
if self.tearing_requested.replace(enabled) != enabled {
let msg = match enabled {
true => "Enabling",
false => "Disabling",
};
log::debug!("{msg} tearing on output {}", self.kernel_id());
}
}
}
pub struct MetalCrtc {
@ -1524,6 +1576,7 @@ fn create_connector(
next_framebuffer: Default::default(),
direct_scanout_active: Cell::new(false),
next_flip_nsec: Cell::new(0),
tearing_requested: Cell::new(false),
});
let futures = ConnectorFutures {
_present: backend
@ -1810,6 +1863,7 @@ impl CollectedProperties {
Some((def, value)) => Ok(MutableProperty {
id: def.id,
value: Cell::new(*value),
pending_value: Cell::new(None),
}),
_ => Err(DrmError::MissingProperty(name.to_string().into_boxed_str())),
}
@ -1820,6 +1874,7 @@ impl CollectedProperties {
pub struct MutableProperty<T: Copy> {
pub id: DrmProperty,
pub value: Cell<T>,
pub pending_value: Cell<Option<T>>,
}
impl<T: Copy> MutableProperty<T> {
@ -1830,6 +1885,7 @@ impl<T: Copy> MutableProperty<T> {
MutableProperty {
id: self.id,
value: Cell::new(f(self.value.into_inner())),
pending_value: Cell::new(None),
}
}
}
@ -1987,6 +2043,7 @@ impl MetalBackend {
disconnect |= !old.is_same_monitor(&dd);
}
if disconnect {
c.tearing_requested.set(false);
if let Some(lease_id) = c.lease.get() {
if let Some(lease) = dev.dev.leases.remove(&lease_id) {
if !lease.try_revoke() {
@ -2152,6 +2209,7 @@ impl MetalBackend {
_max_height: resources.max_height,
cursor_width,
cursor_height,
supports_async_commit: master.supports_async_commit(),
gbm,
handle_events: HandleEvents {
handle_events: Cell::new(None),

View file

@ -8,7 +8,7 @@ use {
},
clap::{Args, Subcommand, ValueEnum},
isnt::std_1::vec::IsntVecExt,
jay_config::video::{Transform, VrrMode},
jay_config::video::{TearingMode, Transform, VrrMode},
std::{
cell::RefCell,
fmt::{Display, Formatter},
@ -120,6 +120,8 @@ pub enum OutputCommand {
NonDesktop(NonDesktopArgs),
/// Change VRR settings.
Vrr(VrrArgs),
/// Change tearing settings.
Tearing(TearingArgs),
}
#[derive(ValueEnum, Debug, Clone)]
@ -144,13 +146,13 @@ pub struct VrrArgs {
#[derive(Subcommand, Debug, Clone)]
pub enum VrrCommand {
/// Sets the mode that determines when VRR is enabled.
SetMode(SetModeArgs),
SetMode(SetVrrModeArgs),
/// Sets the maximum refresh rate of the cursor.
SetCursorHz(CursorHzArgs),
}
#[derive(Args, Debug, Clone)]
pub struct SetModeArgs {
pub struct SetVrrModeArgs {
#[clap(value_enum)]
pub mode: VrrModeArg,
}
@ -175,6 +177,41 @@ pub struct CursorHzArgs {
pub rate: String,
}
#[derive(Args, Debug, Clone)]
pub struct TearingArgs {
#[clap(subcommand)]
pub command: TearingCommand,
}
#[derive(Subcommand, Debug, Clone)]
pub enum TearingCommand {
/// Sets the mode that determines when tearing is enabled.
SetMode(SetTearingModeArgs),
}
#[derive(Args, Debug, Clone)]
pub struct SetTearingModeArgs {
#[clap(value_enum)]
pub mode: TearingModeArg,
}
#[derive(ValueEnum, Debug, Copy, Clone, Hash, PartialEq)]
pub enum TearingModeArg {
/// Tearing is never enabled.
Never,
/// Tearing is always enabled.
Always,
/// Tearing is enabled when one or more applications are displayed fullscreen.
Variant1,
/// Tearing is enabled when a single application is displayed fullscreen.
Variant2,
/// Tearing is enabled when a single application is displayed fullscreen and the
/// application has requested tearing.
///
/// This is the default.
Variant3,
}
#[derive(Args, Debug, Clone)]
pub struct PositionArgs {
/// The top-left x coordinate.
@ -280,6 +317,7 @@ struct Output {
pub vrr_enabled: bool,
pub vrr_mode: VrrMode,
pub vrr_cursor_hz: Option<f64>,
pub tearing_mode: TearingMode,
}
#[derive(Copy, Clone, Debug)]
@ -487,6 +525,27 @@ impl Randr {
}
}
}
OutputCommand::Tearing(a) => {
self.handle_error(randr, move |msg| {
eprintln!("Could not change the tearing setting: {}", msg);
});
match a.command {
TearingCommand::SetMode(a) => {
let mode = match a.mode {
TearingModeArg::Never => VrrMode::NEVER,
TearingModeArg::Always => VrrMode::ALWAYS,
TearingModeArg::Variant1 => VrrMode::VARIANT_1,
TearingModeArg::Variant2 => VrrMode::VARIANT_2,
TearingModeArg::Variant3 => VrrMode::VARIANT_3,
};
tc.send(jay_randr::SetTearingMode {
self_id: randr,
output: &args.output,
mode: mode.0,
});
}
}
}
}
tc.round_trip().await;
}
@ -621,6 +680,21 @@ impl Randr {
println!(" VRR cursor hz: {}", hz);
}
}
{
let mode_str;
let mode = match o.tearing_mode {
TearingMode::NEVER => "never",
TearingMode::ALWAYS => "always",
TearingMode::VARIANT_1 => "variant1",
TearingMode::VARIANT_2 => "variant2",
TearingMode::VARIANT_3 => "variant3",
_ => {
mode_str = format!("unknown ({})", o.vrr_mode.0);
&mode_str
}
};
println!(" Tearing mode: {}", mode);
}
println!(" position: {} x {}", o.x, o.y);
println!(" logical size: {} x {}", o.width, o.height);
if let Some(mode) = &o.current_mode {
@ -713,6 +787,7 @@ impl Randr {
vrr_enabled: false,
vrr_mode: VrrMode::NEVER,
vrr_cursor_hz: None,
tearing_mode: TearingMode::NEVER,
});
});
jay_randr::NonDesktopOutput::handle(tc, randr, data.clone(), |data, msg| {
@ -737,6 +812,7 @@ impl Randr {
vrr_enabled: false,
vrr_mode: VrrMode::NEVER,
vrr_cursor_hz: None,
tearing_mode: TearingMode::NEVER,
});
});
jay_randr::VrrState::handle(tc, randr, data.clone(), |data, msg| {
@ -753,6 +829,12 @@ impl Randr {
let output = c.output.as_mut().unwrap();
output.vrr_cursor_hz = Some(msg.hz);
});
jay_randr::TearingState::handle(tc, randr, data.clone(), |data, msg| {
let mut data = data.borrow_mut();
let c = data.connectors.last_mut().unwrap();
let output = c.output.as_mut().unwrap();
output.tearing_mode = TearingMode(msg.mode);
});
jay_randr::Mode::handle(tc, randr, data.clone(), |data, msg| {
let mut data = data.borrow_mut();
let c = data.connectors.last_mut().unwrap();

View file

@ -33,7 +33,8 @@ use {
tasks::{self, idle},
tree::{
container_layout, container_render_data, float_layout, float_titles,
output_render_data, DisplayNode, NodeIds, OutputNode, VrrMode, WorkspaceNode,
output_render_data, DisplayNode, NodeIds, OutputNode, TearingMode, VrrMode,
WorkspaceNode,
},
user_session::import_environment,
utils::{
@ -249,6 +250,7 @@ fn start_compositor2(
damage_visualizer: DamageVisualizer::new(&engine),
default_vrr_mode: Cell::new(VrrMode::NEVER),
default_vrr_cursor_hz: Cell::new(None),
default_tearing_mode: Cell::new(TearingMode::VARIANT_3),
});
state.tracker.register(ClientId::from_raw(0));
create_dummy_output(&state);
@ -425,6 +427,7 @@ fn create_dummy_output(state: &Rc<State>) {
pos: Default::default(),
vrr_mode: Cell::new(VrrMode::NEVER),
vrr_cursor_hz: Default::default(),
tearing_mode: Cell::new(&TearingMode::Never),
});
let connector = Rc::new(DummyOutput {
id: state.connector_ids.next(),

View file

@ -15,7 +15,7 @@ use {
theme::{Color, ThemeSized, DEFAULT_FONT},
tree::{
move_ws_to_output, ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase,
OutputNode, VrrMode, WsMoveConfig,
OutputNode, TearingMode, VrrMode, WsMoveConfig,
},
utils::{
asyncevent::AsyncEvent,
@ -48,7 +48,10 @@ use {
logging::LogLevel,
theme::{colors::Colorable, sized::Resizable},
timer::Timer as JayTimer,
video::{Connector, DrmDevice, GfxApi, Transform, VrrMode as ConfigVrrMode},
video::{
Connector, DrmDevice, GfxApi, TearingMode as ConfigTearingMode, Transform,
VrrMode as ConfigVrrMode,
},
Axis, Direction, Workspace,
},
libloading::Library,
@ -1045,7 +1048,7 @@ impl ConfigProxyHandler {
Some(c) => {
let connector = self.get_output_node(c)?;
connector.global.persistent.vrr_mode.set(mode);
connector.update_vrr_state();
connector.update_presentation_type();
}
_ => self.state.default_vrr_mode.set(mode),
}
@ -1072,6 +1075,25 @@ impl ConfigProxyHandler {
Ok(())
}
fn handle_set_tearing_mode(
&self,
connector: Option<Connector>,
mode: ConfigTearingMode,
) -> Result<(), CphError> {
let Some(mode) = TearingMode::from_config(mode) else {
return Err(CphError::UnknownTearingMode(mode));
};
match connector {
Some(c) => {
let connector = self.get_output_node(c)?;
connector.global.persistent.tearing_mode.set(mode);
connector.update_presentation_type();
}
_ => self.state.default_tearing_mode.set(mode),
}
Ok(())
}
fn handle_connector_set_transform(
&self,
connector: Connector,
@ -1872,6 +1894,9 @@ impl ConfigProxyHandler {
ClientMessage::SetVrrCursorHz { connector, hz } => self
.handle_set_vrr_cursor_hz(connector, hz)
.wrn("set_vrr_cursor_hz")?,
ClientMessage::SetTearingMode { connector, mode } => self
.handle_set_tearing_mode(connector, mode)
.wrn("set_tearing_mode")?,
}
Ok(())
}
@ -1937,6 +1962,8 @@ enum CphError {
UnknownVrrMode(ConfigVrrMode),
#[error("Invalid cursor hz {0}")]
InvalidCursorHz(f64),
#[error("Unknown tearing mode {0:?}")]
UnknownTearingMode(ConfigTearingMode),
}
trait WithRequestName {

View file

@ -66,7 +66,7 @@ impl Global for JayCompositorGlobal {
}
fn version(&self) -> u32 {
2
3
}
fn required_caps(&self) -> ClientCaps {

View file

@ -7,11 +7,13 @@ use {
object::{Object, Version},
scale::Scale,
state::{ConnectorData, DrmDevData, OutputData},
tree::{OutputNode, VrrMode},
tree::{OutputNode, TearingMode, VrrMode},
utils::{gfx_api_ext::GfxApiExt, transform_ext::TransformExt},
wire::{jay_randr::*, JayRandrId},
},
jay_config::video::{GfxApi, Transform, VrrMode as ConfigVrrMode},
jay_config::video::{
GfxApi, TearingMode as ConfigTearingMode, Transform, VrrMode as ConfigVrrMode,
},
std::rc::Rc,
thiserror::Error,
};
@ -24,6 +26,7 @@ pub struct JayRandr {
}
const VRR_CAPABLE_SINCE: Version = Version(2);
const TEARING_SINCE: Version = Version(3);
impl JayRandr {
pub fn new(id: JayRandrId, client: &Rc<Client>, version: Version) -> Self {
@ -116,6 +119,12 @@ impl JayRandr {
});
}
}
if self.version >= TEARING_SINCE {
self.client.event(TearingState {
self_id: self.id,
mode: node.global.persistent.tearing_mode.get().to_config().0,
});
}
let current_mode = global.mode.get();
for mode in &global.modes {
self.client.event(Mode {
@ -325,7 +334,7 @@ impl JayRandrRequestHandler for JayRandr {
return Ok(());
};
c.global.persistent.vrr_mode.set(mode);
c.update_vrr_state();
c.update_presentation_type();
return Ok(());
}
@ -340,6 +349,22 @@ impl JayRandrRequestHandler for JayRandr {
c.schedule.set_cursor_hz(req.hz);
Ok(())
}
fn set_tearing_mode(
&self,
req: SetTearingMode<'_>,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let Some(mode) = TearingMode::from_config(ConfigTearingMode(req.mode)) else {
return Err(JayRandrError::UnknownTearingMode(req.mode));
};
let Some(c) = self.get_output_node(req.output) else {
return Ok(());
};
c.global.persistent.tearing_mode.set(mode);
c.update_presentation_type();
return Ok(());
}
}
object_base! {
@ -357,5 +382,7 @@ pub enum JayRandrError {
ClientError(Box<ClientError>),
#[error("Unknown VRR mode {0}")]
UnknownVrrMode(u32),
#[error("Unknown tearing mode {0}")]
UnknownTearingMode(u32),
}
efrom!(JayRandrError, ClientError);

View file

@ -10,7 +10,7 @@ use {
object::{Object, Version},
rect::Rect,
state::{ConnectorData, State},
tree::{calculate_logical_size, OutputNode, VrrMode},
tree::{calculate_logical_size, OutputNode, TearingMode, VrrMode},
utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, transform_ext::TransformExt},
wire::{wl_output::*, WlOutputId, ZxdgOutputV1Id},
},
@ -93,6 +93,7 @@ pub struct PersistentOutputState {
pub pos: Cell<(i32, i32)>,
pub vrr_mode: Cell<&'static VrrMode>,
pub vrr_cursor_hz: Cell<Option<f64>>,
pub tearing_mode: Cell<&'static TearingMode>,
}
#[derive(Eq, PartialEq, Hash)]

View file

@ -287,7 +287,7 @@ pub struct WlSurface {
pub constraints: SmallMap<SeatId, Rc<SeatConstraint>, 1>,
xwayland_serial: Cell<Option<u64>>,
tearing_control: CloneCell<Option<Rc<WpTearingControlV1>>>,
tearing: Cell<bool>,
pub tearing: Cell<bool>,
version: Version,
pub has_content_type_manager: Cell<bool>,
pub content_type: Cell<Option<ContentType>>,
@ -1235,8 +1235,11 @@ impl WlSurface {
self.opaque_region.set(region);
}
}
let mut tearing_changed = false;
if let Some(tearing) = pending.tearing.take() {
self.tearing.set(tearing);
if self.tearing.replace(tearing) != tearing {
tearing_changed = true;
}
}
if let Some(content_type) = pending.content_type.take() {
self.content_type.set(content_type);
@ -1305,6 +1308,13 @@ impl WlSurface {
pending.buffer_damage.clear();
pending.surface_damage.clear();
pending.damage_full = false;
if tearing_changed {
if let Some(tl) = self.toplevel.get() {
if tl.tl_data().is_fullscreen.get() {
self.output.get().update_presentation_type();
}
}
}
Ok(())
}

View file

@ -64,8 +64,8 @@ use {
time::Time,
tree::{
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds,
NodeVisitorBase, OutputNode, PlaceholderNode, ToplevelNode, ToplevelNodeBase, VrrMode,
WorkspaceNode,
NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelNode,
ToplevelNodeBase, VrrMode, WorkspaceNode,
},
utils::{
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
@ -203,6 +203,7 @@ pub struct State {
pub damage_visualizer: DamageVisualizer,
pub default_vrr_mode: Cell<&'static VrrMode>,
pub default_vrr_cursor_hz: Cell<Option<f64>>,
pub default_tearing_mode: Cell<&'static TearingMode>,
}
// impl Drop for State {

View file

@ -125,6 +125,7 @@ impl ConnectorHandler {
pos: Cell::new((x1, 0)),
vrr_mode: Cell::new(self.state.default_vrr_mode.get()),
vrr_cursor_hz: Cell::new(self.state.default_vrr_cursor_hz.get()),
tearing_mode: Cell::new(self.state.default_tearing_mode.get()),
});
self.state
.persistent_output_states
@ -242,7 +243,7 @@ impl ConnectorHandler {
}
self.state.add_global(&global);
self.state.tree_changed();
on.update_vrr_state();
on.update_presentation_type();
'outer: loop {
while let Some(event) = self.data.connector.event() {
match event {

View file

@ -330,7 +330,7 @@ impl ToolClient {
self_id: s.registry,
name: s.jay_compositor.0,
interface: JayCompositor.name(),
version: s.jay_compositor.1.min(2),
version: s.jay_compositor.1.min(3),
id: id.into(),
});
self.jay_compositor.set(Some(id));

View file

@ -43,7 +43,7 @@ use {
wire::{JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id},
},
ahash::AHashMap,
jay_config::video::{Transform, VrrMode as ConfigVrrMode},
jay_config::video::{TearingMode as ConfigTearingMode, Transform, VrrMode as ConfigVrrMode},
smallvec::SmallVec,
std::{
cell::{Cell, RefCell},
@ -789,7 +789,12 @@ impl OutputNode {
self.state.tree_changed();
}
pub fn update_vrr_state(&self) {
pub fn update_presentation_type(&self) {
self.update_vrr_state();
self.update_tearing();
}
fn update_vrr_state(&self) {
let enabled = match self.global.persistent.vrr_mode.get() {
VrrMode::Never => false,
VrrMode::Always => true,
@ -821,6 +826,33 @@ impl OutputNode {
};
self.global.connector.connector.set_vrr_enabled(enabled);
}
fn update_tearing(&self) {
let enabled = match self.global.persistent.tearing_mode.get() {
TearingMode::Never => false,
TearingMode::Always => true,
TearingMode::Fullscreen { surface } => 'get: {
let Some(ws) = self.workspace.get() else {
break 'get false;
};
let Some(tl) = ws.fullscreen.get() else {
break 'get false;
};
if let Some(req) = surface {
let Some(surface) = tl.tl_scanout_surface() else {
break 'get false;
};
if req.tearing_requested {
if !surface.tearing.get() {
break 'get false;
}
}
}
true
}
};
self.global.connector.connector.set_tearing_enabled(enabled);
}
}
pub struct OutputTitle {
@ -1185,3 +1217,55 @@ impl VrrMode {
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TearingMode {
Never,
Always,
Fullscreen {
surface: Option<TearingSurfaceRequirements>,
},
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct TearingSurfaceRequirements {
tearing_requested: bool,
}
impl TearingMode {
pub const NEVER: &'static Self = &Self::Never;
pub const ALWAYS: &'static Self = &Self::Always;
pub const VARIANT_1: &'static Self = &Self::Fullscreen { surface: None };
pub const VARIANT_2: &'static Self = &Self::Fullscreen {
surface: Some(TearingSurfaceRequirements {
tearing_requested: false,
}),
};
pub const VARIANT_3: &'static Self = &Self::Fullscreen {
surface: Some(TearingSurfaceRequirements {
tearing_requested: true,
}),
};
pub fn from_config(mode: ConfigTearingMode) -> Option<&'static Self> {
let res = match mode {
ConfigTearingMode::NEVER => Self::NEVER,
ConfigTearingMode::ALWAYS => Self::ALWAYS,
ConfigTearingMode::VARIANT_1 => Self::VARIANT_1,
ConfigTearingMode::VARIANT_2 => Self::VARIANT_2,
ConfigTearingMode::VARIANT_3 => Self::VARIANT_3,
_ => return None,
};
Some(res)
}
pub fn to_config(&self) -> ConfigVrrMode {
match self {
Self::NEVER => ConfigVrrMode::NEVER,
Self::ALWAYS => ConfigVrrMode::ALWAYS,
Self::VARIANT_1 => ConfigVrrMode::VARIANT_1,
Self::VARIANT_2 => ConfigVrrMode::VARIANT_2,
Self::VARIANT_3 => ConfigVrrMode::VARIANT_3,
}
}
}

View file

@ -181,7 +181,7 @@ impl WorkspaceNode {
surface.send_feedback(&fb);
}
}
self.output.get().update_vrr_state();
self.output.get().update_presentation_type();
}
pub fn remove_fullscreen_node(&self) {
@ -195,7 +195,7 @@ impl WorkspaceNode {
surface.send_feedback(&fb);
}
}
self.output.get().update_vrr_state();
self.output.get().update_presentation_type();
}
}

View file

@ -41,14 +41,15 @@ use crate::{
dmabuf::DmaBuf,
drm::sys::{
auth_magic, drm_format_modifier, drm_format_modifier_blob, drop_master, get_version,
revoke_lease, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
revoke_lease, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, DRM_CAP_CURSOR_HEIGHT,
DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
},
Modifier, INVALID_MODIFIER,
},
};
pub use sys::{
drm_mode_modeinfo, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET,
DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_ASYNC, DRM_MODE_PAGE_FLIP_EVENT,
};
#[derive(Debug, Error)]
@ -339,6 +340,10 @@ impl DrmMaster {
Ok((width, height))
}
pub fn supports_async_commit(&self) -> bool {
self.get_cap(DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP) == Ok(1)
}
pub fn get_connector_info(
&self,
connector: DrmConnector,

View file

@ -238,6 +238,7 @@ const DRM_MODE_PROP_ATOMIC: u32 = 0x80000000;
pub const DRM_CAP_CURSOR_WIDTH: u64 = 0x8;
pub const DRM_CAP_CURSOR_HEIGHT: u64 = 0x9;
pub const DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP: u64 = 0x15;
#[repr(C)]
struct drm_mode_property_enum {
@ -865,6 +866,7 @@ struct drm_mode_atomic {
const DRM_IOCTL_MODE_ATOMIC: u64 = drm_iowr::<drm_mode_atomic>(0xbc);
pub const DRM_MODE_PAGE_FLIP_EVENT: u32 = 0x01;
pub const DRM_MODE_PAGE_FLIP_ASYNC: u32 = 0x02;
pub const DRM_MODE_ATOMIC_TEST_ONLY: u32 = 0x0100;
pub const DRM_MODE_ATOMIC_NONBLOCK: u32 = 0x0200;
pub const DRM_MODE_ATOMIC_ALLOW_MODESET: u32 = 0x0400;