Display Configuration in wayland

Problem

gnome-settings-daemon is currently in charge of keeping the display configuration in GNOME, and it does so with X Resize, Rotate and Reflect extension (XRandR). With X11 out of the way, a new mechanism must be designed.

In wayland, the compositor has the ability to communicate the desired display configuration to the kernel driver directly, through the KMS interface in libdrm, so it's only necessary that gnome-settings-daemon and gnome-control-center talk with gnome-shell.

Requirements

  • The API user must have a complete view of all hardware, including that not in use - this immediately rules out the wl_output interface, which only exposes active monitors
  • The API user must have knowledge of the HW limitations, in terms of CRTCs (which themselves abstract the encoder HW), supported modes and supported transforms
  • The API must allow for non HW properties to be configured, such as "this output is primary" or "this output is for presentation only, and no regular windows should be mapped there"
  • The API must be atomic (although the effect might not be, if the driver does not support atomic modesetting)

Proposed solution

Given that it is not expected that the existing wayland protocol for display configuration (wl_output) will have the necessary extensions to replace the functionality currently exposed by XRandR, we designed a new protocol. It uses DBus so that it can be used right now, before the move to wayland, by mapping the DBus calls to XRandR calls in mutter.

The protocol exposes one object, at org.gnome.Mutter.DisplayConfig /org/gnome/Mutter/DisplayConfig and uses two calls:

  • GetResources() to acquire the list of CRTCs, outputs and modes present and supported by the hardware

  • ApplyConfiguration() to configure the display, as well as generate a configuration that can be saved persistently on disk and applied at the next possible occasion

The protocol calls are coupled by a serial argument, to ensure that the new configuration is based on an updated view of hardware.

Implementation

  <interface name="org.gnome.Mutter.DisplayConfig">

    <!--
        GetResources:
        @serial: configuration serial
        @crtcs: available CRTCs
        @outputs: available outputs
        @modes: available modes
        @max_screen_width:
        @max_screen_height:

        Retrieves the current layout of the hardware.

        @serial is an unique identifier representing the current state
        of the screen. It must be passed back to ApplyConfiguration()
        and will be increased for every configuration change (so that
        mutter can detect that the new configuration is based on old
        state).

        A CRTC (CRT controller) is a logical monitor, ie a portion
        of the compositor coordinate space. It might correspond
        to multiple monitors, when in clone mode, but not that
        it is possible to implement clone mode also by setting different
        CRTCs to the same coordinates.

        The number of CRTCs represent the maximum number of monitors
        that can be set to expand and it is a HW constraint; if more
        monitors are connected, then necessarily some will clone. This
        is complementary to the concept of the encoder (not exposed in
        the API), which groups outputs that necessarily will show the
        same image (again a HW constraint).

        A CRTC is represented by a DBus structure with the following
        layout:
        * u ID: the ID in the API of this CRTC
        * x winsys_id: the low-level ID of this CRTC (which might
                       be a XID, a KMS handle or something entirely
                       different)
        * i x, y, width, height: the geometry of this CRTC
                                 (might be invalid if the CRTC is not in
                                 use)
        * i current_mode: the current mode of the CRTC, or -1 if this
                          CRTC is not used
                          Note: the size of the mode will always correspond
                          to the width and height of the CRTC
        * u current_transform: the current transform (espressed according
                               to the wayland protocol)
        * au transforms: all possible transforms
        * a{sv} properties: other high-level properties that affect this
                            CRTC; they are not necessarily reflected in
                            the hardware.
                            No property is specified in this version of the API.

        Note: all geometry information refers to the untransformed
        display.

        An output represents a physical screen, connected somewhere to
        the computer. Floating connectors are not exposed in the API.
        An output is a DBus struct with the following fields:
        * u ID: the ID in the API
        * x winsys_id: the low-level ID of this output (XID or KMS handle)
        * i current_crtc: the CRTC that is currently driving this output,
                          or -1 if the output is disabled
        * au possible_crtcs: all CRTCs that can control this output
        * s name: the name of the connector to which the output is attached
                  (like VGA1 or HDMI)
        * au modes: valid modes for this output
        * au clones: valid clones for this output, ie other outputs that
                     can be assigned the same CRTC as this one; if you
                     want to mirror two outputs that don't have each other
                     in the clone list, you must configure two different
                     CRTCs for the same geometry
        * a{sv} properties: other high-level properties that affect this
                            output; they are not necessarily reflected in
                            the hardware.
                            Known properties:
                            - "vendor" (s): (readonly) the human readable name
                                            of the manufacturer
                            - "product" (s): (readonly) the human readable name
                                             of the display model
                            - "serial" (s): (readonly) the serial number of this
                                            particular hardware part
                            - "display-name" (s): (readonly) a human readable name
                                                  of this output, to be shown in the UI
                            - "backlight" (i): (readonly, use the specific interface)
                                               the backlight value as a percentage
                                               (-1 if not supported)
                            - "primary" (b): whether this output is primary
                                             or not
                            - "presentation" (b): whether this output is
                                                  for presentation only
                            Note: properties might be ignored if not consistenly
                            applied to all outputs in the same clone group. In
                            general, it's expected that presentation or primary
                            outputs will not be cloned.

        A mode represents a set of parameters that are applied to
        each output, such as resolution and refresh rate. It is a separate
        object so that it can be referenced by CRTCs and outputs.
        Multiple outputs in the same CRTCs must all have the same mode.
        A mode is exposed as:
        * u ID: the ID in the API
        * x winsys_id: the low-level ID of this mode
        * u width, height: the resolution
        * d frequency: refresh rate

        Output and modes are read-only objects (except for output properties),
        they can change only in accordance to HW changes (such as hotplugging
        a monitor), while CRTCs can be changed with ApplyConfiguration().

        XXX: actually, if you insist enough, you can add new modes
        through xrandr command line or the KMS API, overriding what the
        kernel driver and the EDID say.
        Usually, it only matters with old cards with broken drivers, or
        old monitors with broken EDIDs, but it happens more often with
        projectors (if for example the kernel driver doesn't add the
        640x480 - 800x600 - 1024x768 default modes). Probably something
        that we need to handle in mutter anyway.
    -->
    <method name="GetResources">
      <arg name="serial" direction="out" type="u" />
      <arg name="crtcs" direction="out" type="a(uxiiiiiuaua{sv})" />
      <arg name="outputs" direction="out" type="a(uxiausauaua{sv})" />
      <arg name="modes" direction="out" type="a(uxuud)" />
      <arg name="max_screen_width" direction="out" type="i" />
      <arg name="max_screen_height" direction="out" type="i" />
    </method>

    <!--
        ApplyConfiguration:
        @serial: configuration serial
        @persistent: whether this configuration should be saved on disk
        @crtcs: new data for CRTCs
        @outputs: new data for outputs

        Applies the requested configuration changes.

        @serial must match the serial from the last GetResources() call,
        or org.freedesktop.DBus.AccessDenied will be generated.

        If @persistent is true, mutter will attempt to replicate this
        configuration the next time this HW layout appears.

        @crtcs represents the new logical configuration, as a list
        of structures containing:
        - u ID: the API ID from the corresponding GetResources() call
        - i new_mode: the API ID of the new mode to configure the CRTC
                      with, or -1 if the CRTC should be disabled
        - i x, y: the new coordinates of the top left corner
                  the geometry will be completed with the size information
                  from @new_mode
        - u transform: the desired transform
        - au outputs: the API ID of outputs that should be assigned to
                      this CRTC
        - a{sv} properties: properties whose value should be changed

        Note: CRTCs not referenced in the array will be disabled.

        @outputs represent the output property changes as:
        - u ID: the API ID of the output to change
        - a{sv} properties: properties whose value should be changed

        Note: both for CRTCs and outputs, properties not included in
        the dictionary will not be changed.

        Note: unrecognized properties will have no effect, but if the
        configuration change succeeds the property will be reported
        by the next GetResources() call, and if @persistent is true,
        it will also be saved to disk.

        If the configuration is invalid according to the previous
        GetResources() call, for example because a CRTC references
        an output it cannot drive, or not all outputs support the
        chosen mode, the error org.freedesktop.DBus.InvalidArgs will
        be generated.

        If the configuration cannot be applied for any other reason
        (eg. the screen size would exceed texture limits), the error
        org.freedesktop.DBus.Error.LimitsExceeded will be generated.
    -->
    <method name="ApplyConfiguration">
      <arg name="serial" direction="in" type="u" />
      <arg name="persistent" direction="in" type="b" />
      <arg name="crtcs" direction="in" type="a(uiiiuaua{sv})" />
      <arg name="outputs" direction="in" type="a(ua{sv})" />
    </method>

    <!--
        ChangeBacklight:
        @serial: configuration serial
        @output: the API id of the output
        @value: the new backlight value

        Changes the backlight of @output to @value, which is
        expressed as a percentage and rounded to the HW limits.
    -->
    <method name="ChangeBacklight">
      <arg name="serial" direction="in" type="u" />
      <arg name="output" direction="in" type="u" />
      <arg name="value" direction="in" type="i" />
    </method>

    <!--
        GetCrtcGamma:
        @serial: configuration serial
        @crtc: API id of the crtc
        @red: red gamma ramp
        @green: green gamma ramp
        @blue: blue gamma ramp

        Requests the current gamma ramps of @crtc.
    -->
    <method name="GetCrtcGamma">
      <arg name="serial" direction="in" type="u" />
      <arg name="crtc" direction="in" type="u" />
      <arg name="red" direction="out" type="aq" />
      <arg name="green" direction="out" type="aq" />
      <arg name="blue" direction="out" type="aq" />
    </method>

    <!--
        SetCrtcGamma:
        @serial: configuration serial
        @crtc: API id of the crtc
        @red: red gamma ramp
        @green: green gamma ramp
        @blue: blue gamma ramp

        Changes the gamma ramps of @crtc.
    -->
    <method name="SetCrtcGamma">
      <arg name="serial" direction="in" type="u" />
      <arg name="crtc" direction="in" type="u" />
      <arg name="red" direction="in" type="aq" />
      <arg name="green" direction="in" type="aq" />
      <arg name="blue" direction="in" type="aq" />
    </method>

    <!--
        PowerSaveMode:

        Contains the current power saving mode for the screen, and
        allows changing it.

        Possible values:
        - 0: on
        - 1: standby
        - 2: suspend
        - 3: off
        - -1: unknown (unsupported)

        A client should not attempt to change the powersave mode
        from -1 (unknown) to any other value, and viceversa.
        Note that the actual effects of the different values
        depend on the hardware and the kernel driver in use, and
        it's perfectly possible that all values different than on
        have the same effect.
        Also, setting the PowerSaveMode to 3 (off) may or may
        not have the same effect as disabling all outputs by
        setting no CRTC on them with ApplyConfiguration(), and
        may or may not cause a configuration change.

        Also note that this property might become out of date
        if changed through different means (for example using the
        XRandR interface directly).
    -->
    <property name="PowerSaveMode" type="i" access="readwrite" />
  </interface>

The interface is implemented by mutter 3.9.90.

Note that this interface is considered semi-private and may change in the future. If you want to modify display configuration, you should use the GnomeRR API in gnome-desktop.

Out of scope

Although it is desirable and probably necessary to use HW transforms to implement screen rotation, the proposed API is by far too complex for that.

Rather, a new Rotate() interface might be added, which would also take care of the necessary animation and only at the end apply the HW transform (possibly triggering the apps to provide transformed buffers).

Initiatives/Wayland/Gaps/DisplayConfig (last edited 2013-11-22 20:55:33 by WilliamJonMcCann)