[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