Skip to content

Commit

Permalink
DPMS with wlr-output-power-management-unstable-v1 protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 authored and Drakulix committed Oct 25, 2024
1 parent 65a5470 commit ea27ec5
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 5 deletions.
23 changes: 22 additions & 1 deletion Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ profiling = { version = "1.0" }
rustix = { version = "0.38.32", features = ["process"] }
smallvec = "1.13.2"
rand = "0.8.5"
drm-ffi = "0.8.0"

[dependencies.id_tree]
branch = "feature/copy_clone"
Expand Down Expand Up @@ -117,4 +118,4 @@ inherits = "release"
lto = "fat"

[patch."https://github.com/Smithay/smithay.git"]
smithay = { git = "https://github.com/smithay//smithay", rev = "df79eeb" }
smithay = { git = "https://github.com/smithay//smithay", rev = "05c49f7" }
1 change: 1 addition & 0 deletions src/backend/kms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ mod drm_helpers;
pub mod render;
mod socket;
mod surface;
pub(crate) use surface::Surface;

use device::*;
pub use surface::Timings;
Expand Down
51 changes: 48 additions & 3 deletions src/backend/kms/surface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ static NVIDIA_LOGO: &'static [u8] = include_bytes!("../../../../resources/icons/

#[derive(Debug)]
pub struct Surface {
pub(super) connector: connector::Handle,
pub(crate) connector: connector::Handle,
pub(super) crtc: crtc::Handle,
pub(super) output: Output,
pub(crate) output: Output,
known_nodes: HashSet<DrmNode>,

active: Arc<AtomicBool>,
Expand All @@ -114,6 +114,8 @@ pub struct Surface {
loop_handle: LoopHandle<'static, State>,
thread_command: Sender<ThreadCommand>,
thread_token: RegistrationToken,

dpms: bool,
}

pub struct SurfaceThreadState {
Expand Down Expand Up @@ -238,6 +240,7 @@ pub enum ThreadCommand {
ScheduleRender,
SetMode(Mode, SyncSender<Result<()>>),
End,
DpmsOff,
}

#[derive(Debug)]
Expand Down Expand Up @@ -350,6 +353,7 @@ impl Surface {
loop_handle: evlh.clone(),
thread_command: tx,
thread_token,
dpms: true,
})
}

Expand Down Expand Up @@ -380,7 +384,9 @@ impl Surface {
}

pub fn schedule_render(&self) {
let _ = self.thread_command.send(ThreadCommand::ScheduleRender);
if self.dpms {
let _ = self.thread_command.send(ThreadCommand::ScheduleRender);
}
}

pub fn set_mirroring(&mut self, output: Option<Output>) {
Expand Down Expand Up @@ -431,6 +437,21 @@ impl Surface {

rx.recv().context("Surface thread died")?
}

pub fn get_dpms(&mut self) -> bool {
self.dpms
}

pub fn set_dpms(&mut self, on: bool) {
if self.dpms != on {
self.dpms = on;
if on {
self.schedule_render();
} else {
let _ = self.thread_command.send(ThreadCommand::DpmsOff);
}
}
}
}

impl Drop for Surface {
Expand Down Expand Up @@ -540,6 +561,30 @@ fn surface_thread(
let _ = result.send(Err(anyhow::anyhow!("Set mode with inactive surface")));
}
}
Event::Msg(ThreadCommand::DpmsOff) => {
if let Some(compositor) = state.compositor.as_mut() {
if let Err(err) = compositor.clear() {
error!("Failed to set DPMS off: {:?}", err);
}
match std::mem::replace(&mut state.state, QueueState::Idle) {
QueueState::Idle => {}
QueueState::Queued(token)
| QueueState::WaitingForEstimatedVBlank(token) => {
state.loop_handle.remove(token);
}
QueueState::WaitingForVBlank { .. } => {
state.timings.discard_current_frame()
}
QueueState::WaitingForEstimatedVBlankAndQueued {
estimated_vblank,
queued_render,
} => {
state.loop_handle.remove(estimated_vblank);
state.loop_handle.remove(queued_render);
}
};
}
}
Event::Closed | Event::Msg(ThreadCommand::End) => {
signal.stop();
signal.wakeup();
Expand Down
2 changes: 2 additions & 0 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ impl State {
where
<B as InputBackend>::Device: 'static,
{
crate::wayland::handlers::output_power::set_all_surfaces_dpms_on(self);

use smithay::backend::input::Event;
match event {
InputEvent::DeviceAdded { device } => {
Expand Down
4 changes: 4 additions & 0 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
drm::WlDrmState,
image_source::ImageSourceState,
output_configuration::OutputConfigurationState,
output_power::OutputPowerState,
screencopy::ScreencopyState,
toplevel_info::ToplevelInfoState,
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
Expand Down Expand Up @@ -198,6 +199,7 @@ pub struct Common {
pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState,
pub output_state: OutputManagerState,
pub output_configuration_state: OutputConfigurationState<State>,
pub output_power_state: OutputPowerState,
pub presentation_state: PresentationState,
pub primary_selection_state: PrimarySelectionState,
pub data_control_state: Option<DataControlState>,
Expand Down Expand Up @@ -487,6 +489,7 @@ impl State {
let keyboard_shortcuts_inhibit_state = KeyboardShortcutsInhibitState::new::<Self>(dh);
let output_state = OutputManagerState::new_with_xdg_output::<Self>(dh);
let output_configuration_state = OutputConfigurationState::new(dh, client_is_privileged);
let output_power_state = OutputPowerState::new::<Self, _>(dh, client_is_privileged);
let presentation_state = PresentationState::new::<Self>(dh, clock.id() as u32);
let primary_selection_state = PrimarySelectionState::new::<Self>(dh);
let image_source_state = ImageSourceState::new::<Self, _>(dh, client_is_privileged);
Expand Down Expand Up @@ -593,6 +596,7 @@ impl State {
keyboard_shortcuts_inhibit_state,
output_state,
output_configuration_state,
output_power_state,
presentation_state,
primary_selection_state,
data_control_state,
Expand Down
1 change: 1 addition & 0 deletions src/wayland/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod keyboard_shortcuts_inhibit;
pub mod layer_shell;
pub mod output;
pub mod output_configuration;
pub mod output_power;
pub mod pointer_constraints;
pub mod pointer_gestures;
pub mod presentation;
Expand Down
78 changes: 78 additions & 0 deletions src/wayland/handlers/output_power.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-3.0-only

use smithay::output::Output;

use crate::{
backend::kms::Surface,
state::{BackendData, State},
utils::prelude::OutputExt,
wayland::protocols::output_power::{
delegate_output_power, OutputPowerHandler, OutputPowerState,
},
};

pub fn set_all_surfaces_dpms_on(state: &mut State) {
let mut changed = false;
for surface in kms_surfaces(state) {
if !surface.get_dpms() {
surface.set_dpms(true);
changed = true;
}
}

if changed {
OutputPowerState::refresh(state);
}
}

fn kms_surfaces(state: &mut State) -> impl Iterator<Item = &mut Surface> {
if let BackendData::Kms(ref mut kms_state) = &mut state.backend {
Some(
kms_state
.drm_devices
.values_mut()
.flat_map(|device| device.surfaces.values_mut()),
)
} else {
None
}
.into_iter()
.flatten()
}

// Get KMS `Surface` for output, and for all outputs mirroring it
fn kms_surfaces_for_output<'a>(
state: &'a mut State,
output: &'a Output,
) -> impl Iterator<Item = &'a mut Surface> + 'a {
kms_surfaces(state).filter(move |surface| {
surface.output == *output || surface.output.mirroring().as_ref() == Some(&output)
})
}

// Get KMS `Surface` for output
fn primary_kms_surface_for_output<'a>(
state: &'a mut State,
output: &Output,
) -> Option<&'a mut Surface> {
kms_surfaces(state).find(|surface| surface.output == *output)
}

impl OutputPowerHandler for State {
fn output_power_state(&mut self) -> &mut OutputPowerState {
&mut self.common.output_power_state
}

fn get_dpms(&mut self, output: &Output) -> Option<bool> {
let surface = primary_kms_surface_for_output(self, output)?;
Some(surface.get_dpms())
}

fn set_dpms(&mut self, output: &Output, on: bool) {
for surface in kms_surfaces_for_output(self, output) {
surface.set_dpms(on);
}
}
}

delegate_output_power!(State);
1 change: 1 addition & 0 deletions src/wayland/protocols/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod drm;
pub mod image_source;
pub mod output_configuration;
pub mod output_power;
pub mod overlap_notify;
pub mod screencopy;
pub mod toplevel_info;
Expand Down
Loading

0 comments on commit ea27ec5

Please sign in to comment.