Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adaptive VRR support #1004

Merged
merged 4 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,4 @@ inherits = "release"
lto = "fat"

[patch."https://github.com/Smithay/smithay.git"]
smithay = { git = "https://github.com/smithay//smithay", rev = "ace2e6a" }
smithay = { git = "https://github.com/smithay//smithay", rev = "bc1d732" }
14 changes: 9 additions & 5 deletions src/backend/kms/device.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only

use crate::{
config::{OutputConfig, OutputState},
config::{AdaptiveSync, OutputConfig, OutputState},
shell::Shell,
utils::prelude::*,
};
Expand Down Expand Up @@ -253,8 +253,6 @@ impl State {
self.backend.kms().drm_devices.insert(drm_node, device);
}

self.backend.kms().refresh_used_devices()?;

self.common
.output_configuration_state
.add_heads(wl_outputs.iter());
Expand All @@ -267,6 +265,8 @@ impl State {
&self.common.xdg_activation_state,
self.common.startup_done.clone(),
);

self.backend.kms().refresh_used_devices()?;
self.common.refresh();

Ok(())
Expand Down Expand Up @@ -349,8 +349,6 @@ impl State {
}
}

self.backend.kms().refresh_used_devices()?;

self.common
.output_configuration_state
.remove_heads(outputs_removed.iter());
Expand All @@ -376,6 +374,8 @@ impl State {
self.common.refresh();
}

self.backend.kms().refresh_used_devices()?;

Ok(())
}

Expand Down Expand Up @@ -664,6 +664,10 @@ fn populate_modes(
max_bpc,
scale,
transform,
// Try opportunistic VRR by default,
// if not supported this will be turned off on `resume`,
// when we have the `Surface` to actually check for support.
vrr: AdaptiveSync::Enabled,
..std::mem::take(&mut *output_config)
};

Expand Down
34 changes: 0 additions & 34 deletions src/backend/kms/drm_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,40 +349,6 @@ pub fn calculate_refresh_rate(mode: Mode) -> u32 {
refresh as u32
}

pub fn supports_vrr(dev: &impl ControlDevice, conn: connector::Handle) -> Result<bool> {
get_property_val(dev, conn, "vrr_capable").map(|(val_type, val)| {
match val_type.convert_value(val) {
property::Value::UnsignedRange(res) => res == 1,
property::Value::Boolean(res) => res,
_ => false,
}
})
}

pub fn set_vrr(
dev: &impl ControlDevice,
crtc: crtc::Handle,
conn: connector::Handle,
vrr: bool,
) -> Result<bool> {
if supports_vrr(dev, conn)? {
dev.set_property(
conn,
get_prop(dev, crtc, "VRR_ENABLED")?,
property::Value::UnsignedRange(if vrr { 1 } else { 0 }).into(),
)
.map_err(Into::<anyhow::Error>::into)
.and_then(|_| get_property_val(dev, crtc, "VRR_ENABLED"))
.map(|(val_type, val)| match val_type.convert_value(val) {
property::Value::UnsignedRange(vrr) => vrr == 1,
property::Value::Boolean(vrr) => vrr,
_ => false,
})
} else {
Ok(false)
}
}

pub fn get_max_bpc(
dev: &impl ControlDevice,
conn: connector::Handle,
Expand Down
117 changes: 77 additions & 40 deletions src/backend/kms/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-only

use crate::{config::OutputState, shell::Shell, state::BackendData, utils::prelude::*};
use crate::{
config::{AdaptiveSync, OutputState},
shell::Shell,
state::BackendData,
utils::prelude::*,
};

use anyhow::{Context, Result};
use calloop::LoopSignal;
Expand Down Expand Up @@ -528,7 +533,6 @@ impl KmsState {
return Ok(Vec::new());
}

let mut all_outputs = Vec::new();
for device in self.drm_devices.values_mut() {
// we only want outputs exposed to wayland - not leased ones
// but that is also not all surface, because that doesn't contain all detected, but unmapped outputs
Expand Down Expand Up @@ -587,7 +591,7 @@ impl KmsState {
.flat_map(|encoder_handle| device.drm.get_encoder(*encoder_handle))
{
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
if !free_crtcs.contains(&crtc) {
if free_crtcs.contains(&crtc) {
new_pairings.insert(conn, crtc);
break 'outer;
}
Expand All @@ -607,7 +611,34 @@ impl KmsState {
}
}

// reconfigure existing
// add new ones
let mut w = shell.read().unwrap().global_space().size.w as u32;
if !test_only {
for (conn, crtc) in new_pairings {
let (output, _) = device.connector_added(
self.primary_node.as_ref(),
conn,
Some(crtc),
(w, 0),
loop_handle,
shell.clone(),
startup_done.clone(),
)?;
if output.mirroring().is_none() {
w += output.config().transformed_size().w as u32;
}
}
}
}

if !test_only {
self.refresh_used_devices()
.context("Failed to enable devices")?;
}

let mut all_outputs = Vec::new();
for device in self.drm_devices.values_mut() {
// reconfigure
for (crtc, surface) in device.surfaces.iter_mut() {
let output_config = surface.output.config();

Expand Down Expand Up @@ -637,10 +668,6 @@ impl KmsState {
let gbm = device.gbm.clone();
let cursor_size = drm.cursor_size();

let vrr = drm_helpers::set_vrr(drm, *crtc, conn, output_config.vrr)
.unwrap_or(false);
surface.output.set_adaptive_sync(vrr);

if let Some(bpc) = output_config.max_bpc {
if let Err(err) = drm_helpers::set_max_bpc(drm, conn, bpc) {
warn!(
Expand All @@ -652,48 +679,58 @@ impl KmsState {
}
}

let vrr = output_config.vrr;
std::mem::drop(output_config);
surface
.resume(drm_surface, gbm, cursor_size, vrr)
.context("Failed to create surface")?;
} else {
if output_config.vrr != surface.output.adaptive_sync() {
surface.output.set_adaptive_sync(drm_helpers::set_vrr(
drm,
surface.crtc,
surface.connector,
output_config.vrr,
)?);

match surface.resume(drm_surface, gbm, cursor_size) {
Ok(_) => {
surface.output.set_adaptive_sync_support(
surface.adaptive_sync_support().ok(),
);
if surface.use_adaptive_sync(vrr)? {
surface.output.set_adaptive_sync(vrr);
} else {
surface.output.config_mut().vrr = AdaptiveSync::Disabled;
surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
}
}
Err(err) => {
surface.output.config_mut().enabled = OutputState::Disabled;
return Err(err).context("Failed to create surface");
}
}
} else {
let vrr = output_config.vrr;
std::mem::drop(output_config);
if vrr != surface.output.adaptive_sync() {
if surface.use_adaptive_sync(vrr)? {
surface.output.set_adaptive_sync(vrr);
} else if vrr != AdaptiveSync::Disabled {
anyhow::bail!("Requested VRR mode unsupported");
} else {
surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
}
}
surface
.set_mode(*mode)
.context("Failed to apply new mode")?;
}
}
}

// add new ones
let mut w = shell.read().unwrap().global_space().size.w as u32;
if !test_only {
for (conn, crtc) in new_pairings {
let (output, _) = device.connector_added(
self.primary_node.as_ref(),
conn,
Some(crtc),
(0, w),
loop_handle,
shell.clone(),
startup_done.clone(),
)?;
if output.mirroring().is_none() {
w += output.config().transformed_size().w as u32;
}
all_outputs.push(output);
}
}

all_outputs.extend(outputs);
all_outputs.extend(
device
.outputs
.iter()
.filter(|(conn, _)| {
!device
.leased_connectors
.iter()
.any(|(leased_conn, _)| *conn == leased_conn)
})
.map(|(_, output)| output.clone())
.collect::<Vec<_>>(),
);
}

// we need to handle mirroring, after all outputs have been enabled
Expand Down
Loading
Loading