[PATCH xserver v2] randr: Add Border property support

Stéphane Marchesin stephane.marchesin at gmail.com
Mon Sep 19 19:31:07 PDT 2011


On Wed, Aug 31, 2011 at 18:27, Aaron Plattner <aplattner at nvidia.com> wrote:
> Add helpers to RandR to allow the DDX (or rather the driver loaded by
> the DDX, for xfree86) to specify how many dimensions of adjustments it
> supports.  Check for this property and adjust the CRTC raster size
> accordingly when computing the transformed framebuffer size read.
>
> This implements the properties described in
> http://lists.x.org/archives/xorg-devel/2011-August/024163.html
>
> Use these properties to adjust the effective size of the mode during
> modesets and when the shadow code is enabled.  Save the current
> effective border and mode dimesions in the xf86CrtcRec for driver use.
>
> Signed-off-by: Aaron Plattner <aplattner at nvidia.com>

Reviewed-by: Stéphane Marchesin <marcheu at chromium.org>

> ---
> v2: I tracked down all the places I could find where the DDX needs to take
> the border into account.  I made this easier (both for the DDX and the
> driver) by stashing the current border and effective mode dimensions into
> the xf86CrtcRec.  With this change, I can rotate, transform, and apply
> borders at the same time.
>
> I also applied your suggestion of explicitly disallowing num_dimensions ==
> 3.
>
> This patch now builds on [1], since they both add fields to xf86CrtcRec.
>
> [1] http://lists.x.org/archives/xorg-devel/2011-August/024624.html
>
>  hw/xfree86/modes/xf86Crtc.c    |   54 ++++++++++++++++++++++
>  hw/xfree86/modes/xf86Crtc.h    |   17 +++++++
>  hw/xfree86/modes/xf86Cursors.c |    3 +-
>  hw/xfree86/modes/xf86Rotate.c  |   21 +++++----
>  randr/randrstr.h               |   28 ++++++++++++
>  randr/rrcrtc.c                 |   26 +++++++++--
>  randr/rrproperty.c             |   96 ++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 229 insertions(+), 16 deletions(-)
>
> diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
> index c2814d4..6dd2206 100644
> --- a/hw/xfree86/modes/xf86Crtc.c
> +++ b/hw/xfree86/modes/xf86Crtc.c
> @@ -261,6 +261,9 @@ xf86CrtcSetModeTransform (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotati
>     Rotation           saved_rotation;
>     RRTransformRec     saved_transform;
>     Bool               saved_transform_present;
> +    RRBorderRec                saved_border;
> +    int                        saved_effective_width;
> +    int                        saved_effective_height;
>
>     crtc->enabled = xf86CrtcInUse (crtc);
>
> @@ -284,6 +287,9 @@ xf86CrtcSetModeTransform (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotati
>        RRTransformCopy (&saved_transform, &crtc->transform);
>     }
>     saved_transform_present = crtc->transformPresent;
> +    saved_border = crtc->border;
> +    saved_effective_width = crtc->effectiveModeWidth;
> +    saved_effective_height = crtc->effectiveModeHeight;
>
>     /* Update crtc values up front so the driver can rely on them for mode
>      * setting.
> @@ -298,6 +304,21 @@ xf86CrtcSetModeTransform (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotati
>     } else
>        crtc->transformPresent = FALSE;
>
> +    crtc->border = xf86CrtcGetBorder(crtc, TRUE);
> +    if (crtc->border.left + crtc->border.right >= crtc->mode.HDisplay) {
> +       crtc->border.left = 0;
> +       crtc->border.right = 0;
> +    }
> +    if (crtc->border.top + crtc->border.bottom >= crtc->mode.VDisplay) {
> +       crtc->border.top = 0;
> +       crtc->border.bottom = 0;
> +    }
> +
> +    crtc->effectiveModeWidth = crtc->mode.HDisplay - crtc->border.left -
> +                              crtc->border.right;
> +    crtc->effectiveModeHeight = crtc->mode.VDisplay - crtc->border.top -
> +                               crtc->border.bottom;
> +
>     if (crtc->funcs->set_mode_major) {
>        ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y);
>        goto done;
> @@ -381,6 +402,9 @@ done:
>        if (saved_transform_present)
>            RRTransformCopy (&crtc->transform, &saved_transform);
>        crtc->transformPresent = saved_transform_present;
> +       crtc->border = saved_border;
> +       crtc->effectiveModeWidth = saved_effective_width;
> +       crtc->effectiveModeHeight = saved_effective_height;
>     }
>
>     free(adjusted_mode->name);
> @@ -3235,3 +3259,33 @@ xf86_crtc_supports_gamma(ScrnInfoPtr pScrn)
>
>     return FALSE;
>  }
> +
> +RRBorderRec
> +xf86CrtcGetBorder(xf86CrtcPtr crtc, Bool pending)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> +    xf86OutputPtr output = NULL;
> +    RRBorderRec border = { };
> +    int i;
> +
> +    /*
> +     * RandR stores properties on outputs, not CRTCs, so find the first output
> +     * associated with this CRTC.
> +     *
> +     * Loop over the outputs in the config rather than looking at
> +     * crtc->randr_crtc->outputs because the latter is stale during modesets.
> +     */
> +    for (i = 0; i < xf86_config->num_output; i++) {
> +       output = xf86_config->output[i];
> +       if (output->crtc == crtc) {
> +           break;
> +       }
> +    }
> +
> +    if (i < xf86_config->num_output) {
> +       border = RROutputGetBorderDimensions(output->randr_output, pending);
> +    }
> +
> +    return border;
> +}
> diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
> index ffb2eff..71d5fb4 100644
> --- a/hw/xfree86/modes/xf86Crtc.h
> +++ b/hw/xfree86/modes/xf86Crtc.h
> @@ -375,6 +375,16 @@ struct _xf86Crtc {
>      * Added in ABI version 4
>      */
>     Bool           driverIsPerformingTransform;
> +
> +    RRBorderRec            border;
> +
> +    /**
> +     * Indicates the size of the mode not being covered by the border.  E.g.,
> +     * this is crtc->mode.HDisplay - totalBorderWidth or crtc->mode.VDisplay -
> +     * totalBorderHeight.
> +     */
> +    int                    effectiveModeWidth;
> +    int                    effectiveModeHeight;
>  };
>
>  typedef struct _xf86OutputFuncs {
> @@ -991,4 +1001,11 @@ xf86_crtc_notify(ScreenPtr pScreen);
>  extern _X_EXPORT Bool
>  xf86_crtc_supports_gamma(ScrnInfoPtr pScrn);
>
> +/*
> + * Get the border associated with a CRTC.  This can be used even during modesets
> + * where the randr_crtc->outputs array is stale.
> + */
> +extern _X_EXPORT RRBorderRec
> +xf86CrtcGetBorder(xf86CrtcPtr crtc, Bool pending);
> +
>  #endif /* _XF86CRTC_H_ */
> diff --git a/hw/xfree86/modes/xf86Cursors.c b/hw/xfree86/modes/xf86Cursors.c
> index 276bd27..db55732 100644
> --- a/hw/xfree86/modes/xf86Cursors.c
> +++ b/hw/xfree86/modes/xf86Cursors.c
> @@ -373,7 +373,6 @@ xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
>     ScrnInfoPtr                scrn = crtc->scrn;
>     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
>     xf86CursorInfoPtr  cursor_info = xf86_config->cursor_info;
> -    DisplayModePtr     mode = &crtc->mode;
>     Bool               in_range;
>
>     /*
> @@ -391,7 +390,7 @@ xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
>      * Disable the cursor when it is outside the viewport
>      */
>     in_range = TRUE;
> -    if (x >= mode->HDisplay || y >= mode->VDisplay ||
> +    if (x >= crtc->effectiveModeWidth || y >= crtc->effectiveModeHeight ||
>        x <= -cursor_info->MaxWidth || y <= -cursor_info->MaxHeight)
>     {
>        in_range = FALSE;
> diff --git a/hw/xfree86/modes/xf86Rotate.c b/hw/xfree86/modes/xf86Rotate.c
> index fcd2c7c..4ef0c5b 100644
> --- a/hw/xfree86/modes/xf86Rotate.c
> +++ b/hw/xfree86/modes/xf86Rotate.c
> @@ -121,7 +121,8 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
>        CompositePicture (PictOpSrc,
>                          src, NULL, dst,
>                          0, 0, 0, 0, 0, 0,
> -                         crtc->mode.HDisplay, crtc->mode.VDisplay);
> +                         crtc->effectiveModeWidth,
> +                         crtc->effectiveModeHeight);
>        crtc->shadowClear = FALSE;
>     }
>     else
> @@ -157,9 +158,9 @@ xf86CrtcDamageShadow (xf86CrtcPtr crtc)
>     ScreenPtr  pScreen = pScrn->pScreen;
>
>     damage_box.x1 = 0;
> -    damage_box.x2 = crtc->mode.HDisplay;
> +    damage_box.x2 = crtc->effectiveModeWidth;
>     damage_box.y1 = 0;
> -    damage_box.y2 = crtc->mode.VDisplay;
> +    damage_box.y2 = crtc->effectiveModeHeight;
>     if (!pixman_transform_bounds (&crtc->crtc_to_framebuffer, &damage_box))
>     {
>        damage_box.x1 = 0;
> @@ -193,8 +194,8 @@ xf86RotatePrepare (ScreenPtr pScreen)
>        {
>            crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc,
>                                                             crtc->rotatedData,
> -                                                            crtc->mode.HDisplay,
> -                                                            crtc->mode.VDisplay);
> +                                                            crtc->effectiveModeWidth,
> +                                                            crtc->effectiveModeHeight);
>            if (!xf86_config->rotation_damage_registered)
>            {
>                /* Hook damage to screen pixmap */
> @@ -389,12 +390,14 @@ xf86CrtcRotate (xf86CrtcPtr crtc)
>     int                        new_height = 0;
>     RRTransformPtr     transform = NULL;
>     Bool               damage = FALSE;
> +    const int          width = crtc->effectiveModeWidth;
> +    const int          height = crtc->effectiveModeHeight;
>
>     if (crtc->transformPresent)
>        transform = &crtc->transform;
>
>     if (!RRTransformCompute (crtc->x, crtc->y,
> -                            crtc->mode.HDisplay, crtc->mode.VDisplay,
> +                            width, height,
>                             crtc->rotation,
>                             transform,
>
> @@ -423,8 +426,6 @@ xf86CrtcRotate (xf86CrtcPtr crtc)
>         * matches the mode, not the pre-rotated copy in the
>         * frame buffer
>         */
> -       int         width = crtc->mode.HDisplay;
> -       int         height = crtc->mode.VDisplay;
>        void        *shadowData = crtc->rotatedData;
>        PixmapPtr   shadow = crtc->rotatedPixmap;
>        int         old_width = shadow ? shadow->drawable.width : 0;
> @@ -520,9 +521,9 @@ xf86CrtcRotate (xf86CrtcPtr crtc)
>     crtc->filter_width = new_width;
>     crtc->filter_height = new_height;
>     crtc->bounds.x1 = 0;
> -    crtc->bounds.x2 = crtc->mode.HDisplay;
> +    crtc->bounds.x2 = width;
>     crtc->bounds.y1 = 0;
> -    crtc->bounds.y2 = crtc->mode.VDisplay;
> +    crtc->bounds.y2 = height;
>     pixman_f_transform_bounds (&f_crtc_to_fb, &crtc->bounds);
>
>     if (damage)
> diff --git a/randr/randrstr.h b/randr/randrstr.h
> index d8dd37d..cc5c9b6 100644
> --- a/randr/randrstr.h
> +++ b/randr/randrstr.h
> @@ -78,6 +78,7 @@ typedef struct _rrPropertyValue       RRPropertyValueRec, *RRPropertyValuePtr;
>  typedef struct _rrProperty     RRPropertyRec, *RRPropertyPtr;
>  typedef struct _rrCrtc         RRCrtcRec, *RRCrtcPtr;
>  typedef struct _rrOutput       RROutputRec, *RROutputPtr;
> +typedef struct _rrBorder       RRBorderRec, *RRBorderPtr;
>
>  struct _rrMode {
>     int                    refcnt;
> @@ -150,6 +151,11 @@ struct _rrOutput {
>     RRPropertyPtr   properties;
>     Bool           pendingProperties;
>     void           *devPrivate;
> +    int                    numBorderDimensions;
> +};
> +
> +struct _rrBorder {
> +    uint16_t       left, top, right, bottom;
>  };
>
>  #if RANDR_12_INTERFACE
> @@ -875,6 +881,28 @@ extern _X_EXPORT int
>  RRConfigureOutputProperty (RROutputPtr output, Atom property,
>                           Bool pending, Bool range, Bool immutable,
>                           int num_values, INT32 *values);
> +
> +/*
> + * Create the RandR 1.4 "Border" and "BorderDimensions" properties with the
> + * specified number of supported dimensions.  num_dimensions should be one of 0,
> + * 1, 2, or 4.  This function is expected to be called by the DDX (or its
> + * drivers) that support border adjustments.
> + */
> +extern _X_EXPORT Bool
> +RRCreateBorderProperty (RROutputPtr output, int num_dimensions);
> +
> +/*
> + * Query the border dimensions requested by the client. This will always return
> + * all four dimensions, but some of them will be the same if the DDX called
> + * RRCreateBorderProperty with fewer than 4 dimensions.
> + *
> + * If 'pending' is TRUE, read the pending values of the property instead of the
> + * current values. This is necessary because the pending values are not promoted
> + * to current until after rrCrtcSet has completed.
> + */
> +extern _X_EXPORT RRBorderRec
> +RROutputGetBorderDimensions (RROutputPtr output, Bool pending);
> +
>  extern _X_EXPORT int
>  ProcRRChangeOutputProperty (ClientPtr client);
>
> diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
> index 0437795..07782b0 100644
> --- a/randr/rrcrtc.c
> +++ b/randr/rrcrtc.c
> @@ -605,10 +605,12 @@ RRCrtcGammaNotify (RRCrtcPtr      crtc)
>  }
>
>  static void
> -RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
> -                     int *width, int *height)
> +RRModeGetScanoutSize (RRModePtr mode, RRBorderRec border,
> +                     PictTransformPtr transform, int *width, int *height)
>  {
>     BoxRec  box;
> +    const int borderW = border.left + border.right;
> +    const int borderH = border.top + border.bottom;
>
>     if (mode == NULL) {
>        *width = 0;
> @@ -621,6 +623,13 @@ RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
>     box.x2 = mode->mode.width;
>     box.y2 = mode->mode.height;
>
> +    /* Adjust for borders */
> +
> +    if (borderW < box.x2)
> +       box.x2 -= borderW;
> +    if (borderH < box.y2)
> +       box.y2 -= borderH;
> +
>     pixman_transform_bounds (transform, &box);
>     *width = box.x2 - box.x1;
>     *height = box.y2 - box.y1;
> @@ -632,7 +641,11 @@ RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
>  void
>  RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
>  {
> -    RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height);
> +    RROutputPtr firstOutput = crtc->numOutputs > 0 ? crtc->outputs[0] : NULL;
> +
> +    RRModeGetScanoutSize (crtc->mode,
> +                         RROutputGetBorderDimensions(firstOutput, FALSE),
> +                         &crtc->transform, width, height);
>  }
>
>  /*
> @@ -1013,6 +1026,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
>            int source_height;
>            PictTransform transform;
>            struct pixman_f_transform f_transform, f_inverse;
> +           RROutputPtr firstOutput = outputs ? outputs[0] : NULL;
>
>            RRTransformCompute (stuff->x, stuff->y,
>                                mode->mode.width, mode->mode.height,
> @@ -1020,7 +1034,11 @@ ProcRRSetCrtcConfig (ClientPtr client)
>                                &crtc->client_pending_transform,
>                                &transform, &f_transform, &f_inverse);
>
> -           RRModeGetScanoutSize (mode, &transform, &source_width, &source_height);
> +           /* Because we're about to perform a modeset, we want the pending
> +            * value of the border and not the current value */
> +           RRModeGetScanoutSize (mode,
> +                                 RROutputGetBorderDimensions(firstOutput, TRUE),
> +                                 &transform, &source_width, &source_height);
>            if (stuff->x + source_width > pScreen->width)
>            {
>                client->errorValue = stuff->x;
> diff --git a/randr/rrproperty.c b/randr/rrproperty.c
> index 61e7bb4..336b6ac 100644
> --- a/randr/rrproperty.c
> +++ b/randr/rrproperty.c
> @@ -20,6 +20,8 @@
>  * OF THIS SOFTWARE.
>  */
>
> +#include <X11/Xatom.h>
> +
>  #include "randrstr.h"
>  #include "propertyst.h"
>  #include "swaprep.h"
> @@ -383,6 +385,100 @@ RRConfigureOutputProperty (RROutputPtr output, Atom property,
>     return Success;
>  }
>
> +Bool
> +RRCreateBorderProperty (RROutputPtr output, int num_dimensions)
> +{
> +    INT32 range[] = { 0, UINT16_MAX };
> +    CARD16 zeroes[4] = { 0 };
> +    Atom Border = MakeAtom(RR_PROPERTY_BORDER, strlen(RR_PROPERTY_BORDER),
> +                          TRUE);
> +    Atom BorderDims = MakeAtom(RR_PROPERTY_BORDER_DIMENSIONS,
> +                              strlen(RR_PROPERTY_BORDER_DIMENSIONS), TRUE);
> +
> +    if (num_dimensions < 0 || num_dimensions == 3 || num_dimensions > 4)
> +       return FALSE;
> +
> +    if (Border == None || BorderDims == None)
> +       return FALSE;
> +
> +    output->numBorderDimensions = num_dimensions;
> +
> +    RRConfigureOutputProperty(output, Border, TRUE, TRUE, TRUE, 2, range);
> +    RRChangeOutputProperty(output, Border, XA_CARDINAL, 16, PropModeReplace,
> +                          num_dimensions, zeroes, FALSE, FALSE);
> +
> +    RRConfigureOutputProperty(output, BorderDims, FALSE, FALSE, TRUE, 1,
> +                             &num_dimensions);
> +    RRChangeOutputProperty(output, BorderDims, XA_CARDINAL, 8, PropModeReplace,
> +                          1, &num_dimensions, FALSE, FALSE);
> +
> +    return TRUE;
> +}
> +
> +RRBorderRec
> +RROutputGetBorderDimensions (RROutputPtr output, Bool pending)
> +{
> +    RRBorderRec dims = { 0, 0, 0, 0 };
> +
> +    if (output) {
> +       Atom Border = MakeAtom(RR_PROPERTY_BORDER, strlen(RR_PROPERTY_BORDER),
> +                              TRUE);
> +       RRPropertyValuePtr prop_value;
> +       long prop_size = 0;
> +
> +       if (Border != None &&
> +           (prop_value = RRGetOutputProperty(output, Border, pending)) &&
> +           prop_value && prop_value->type == XA_CARDINAL &&
> +           prop_value->format == 16)
> +       {
> +           const uint16_t *data = (const uint16_t*)prop_value->data;
> +
> +           prop_size = prop_value->size;
> +
> +           switch (prop_size) {
> +           default:
> +           case 4:
> +               dims.bottom = data[3];
> +               /* fall through */
> +           case 3:
> +               dims.right = data[2];
> +               /* fall through */
> +           case 2:
> +               dims.top = data[1];
> +               /* fall through */
> +           case 1:
> +               dims.left = data[0];
> +               /* fall through */
> +           case 0:
> +               break;
> +           }
> +       }
> +
> +       /* If the client specified fewer than 4 adjustments or the driver
> +        * doesn't support all 4, propagate them to the remaining ones.   E.g.,
> +        * if a client specifies [ 1, 2, 3, 4 ] but only two dimensions are
> +        * supported, ignore the 3 & 4 values and return [ 1, 2, 1, 2 ]. */
> +       switch (min(prop_size, output->numBorderDimensions)) {
> +       case 0:
> +           dims.left = 0;
> +           /* fall through */
> +       case 1:
> +           dims.top = dims.left;
> +           /* fall through */
> +       case 2:
> +           dims.right = dims.left;
> +           /* fall through */
> +       case 3:
> +           dims.bottom = dims.top;
> +           break;
> +       default:
> +           break;
> +       }
> +    }
> +
> +    return dims;
> +}
> +
>  int
>  ProcRRListOutputProperties (ClientPtr client)
>  {
> --
> 1.7.4.1
>
>


More information about the xorg-devel mailing list