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

DPMS with wlr-output-power-management-unstable-v1 protocol #741

Merged
merged 1 commit into from
Oct 25, 2024
Merged

Conversation

ids1024
Copy link
Member

@ids1024 ids1024 commented Aug 17, 2024

This works to set DPMS on or off. It still needs to track the DPMS state and send events to clients when the mode changes. And otherwise be cleaned up a bit.

Components like cosmic-greeter may make use of this.

This can be tested with the below code (which also works on Sway):

use std::{env, process};
use wayland_client::{
    delegate_noop,
    globals::{registry_queue_init, GlobalListContents},
    protocol::{wl_output, wl_registry},
    Connection, Dispatch, Proxy, QueueHandle,
};
use wayland_protocols_wlr::output_power_management::v1::client::{
    zwlr_output_power_manager_v1, zwlr_output_power_v1,
};

struct State;

fn main() {
    let mode = match env::args().skip(1).next().as_ref().map(|x| x.as_str()) {
        Some("on") => zwlr_output_power_v1::Mode::On,
        Some("off") => zwlr_output_power_v1::Mode::Off,
        _ => {
            eprintln!("Usage: dpms on|off");
            process::exit(1);
        }
    };

    let connection = Connection::connect_to_env().unwrap();
    let (globals, mut event_queue) = registry_queue_init::<State>(&connection).unwrap();
    let qh = event_queue.handle();

    let outputs = globals.contents().with_list(|list| {
        list.iter()
            .filter(|global| global.interface == wl_output::WlOutput::interface().name)
            .map(|global| globals.registry().bind(global.name, global.version, &qh, ()))
            .collect::<Vec<wl_output::WlOutput>>()
    });

    let output_power_manager = globals
        .bind::<zwlr_output_power_manager_v1::ZwlrOutputPowerManagerV1, _, _>(&qh, 1..=1, ())
        .unwrap();

    for output in &outputs {
        let output_power = output_power_manager.get_output_power(output, &qh, ());
        output_power.set_mode(mode);
    }
    event_queue.roundtrip(&mut State).unwrap();
}

impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
    fn event(
        _: &mut Self,
        _: &wl_registry::WlRegistry,
        _: wl_registry::Event,
        _: &GlobalListContents,
        _: &Connection,
        _: &QueueHandle<Self>,
    ) {
    }
}

delegate_noop!(State: ignore wl_output::WlOutput);
delegate_noop!(State: zwlr_output_power_manager_v1::ZwlrOutputPowerManagerV1);
delegate_noop!(State: ignore zwlr_output_power_v1::ZwlrOutputPowerV1);

@ids1024
Copy link
Member Author

ids1024 commented Aug 26, 2024

With this current, simple, way of settings the DPMS state, it does seem to spend .5 to 1 second in the call for some reason... seems excessive, but definitely should be handled in the render thread of that surface anyway.

I also see page flip errors. Presumably we just shouldn't attempt page flips when we have DPMS set to off. (And also disable/throttle frame callbacks. And don't actually try to render.)

@ids1024
Copy link
Member Author

ids1024 commented Aug 27, 2024

Looking at wlroots/mutter/kwin and DRM documentation, I guess we shouldn't set the DPMS property (unless we're using legacy modesetting) and should set ACTIVE as part of an atomic modeset.

DPMS:

Legacy property for setting the power state of the connector. For atomic drivers this is only provided for backwards compatibility with existing drivers, it remaps to controlling the “ACTIVE” property on the CRTC the connector is linked to. Drivers should never set this property directly, it is handled by the DRM core by calling the drm_connector_funcs.dpms callback. For atomic drivers the remapping to the “ACTIVE” property is implemented in the DRM core. This is the only standard connector property that userspace can change.

Note that this property cannot be set through the MODE_ATOMIC ioctl, userspace must use “ACTIVE” on the CRTC instead.

@ids1024 ids1024 changed the title WIP DPMS with wlr-output-power-management-unstable-v1 protocol DPMS with wlr-output-power-management-unstable-v1 protocol Oct 18, 2024
@ids1024 ids1024 marked this pull request as ready for review October 18, 2024 01:01
Copy link
Member

@Drakulix Drakulix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on mattermost, this needs a way for the compositor to clear the suspension, when the user isn't idling anymore, but otherwise this looks good and quite straight-forward!

state.loop_handle.remove(estimated_vblank);
state.loop_handle.remove(queued_render);
}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, at some point we might want to refactor this into a reset method, but that is fine for now.

@ids1024
Copy link
Member Author

ids1024 commented Oct 25, 2024

Trying to test mirroring here, I ran into a few unrelated issues with cosmic-randr/mirroring (pop-os/cosmic-randr#33, pop-os/cosmic-randr#34).

I think this should be good now, after changing a few things:

  • Store the Mode that was last sent to each zwlr_output_power_v1 instance so it can update only when there's a change.
  • set_dpms now also sets the DPMS state for any outputs mirroring the output
  • On any input events (which is when notify_activity is called for idle notifier), set DPMS on for all outputs
    • Probably not an issue, but I made sure this is done in an efficient way that avoids multiple loops when there's nothing to change.
  • Added an OutputPowerState:refresh function, called when it does change the DPMS state on an input event, to send the mode to clients.
  • Updated OutputPowerHandler to take Output instead of WlOutput

@ids1024 ids1024 requested a review from Drakulix October 25, 2024 04:04
@Drakulix Drakulix merged commit ea27ec5 into master Oct 25, 2024
7 checks passed
@Drakulix Drakulix deleted the dpms branch October 25, 2024 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants