[PATCH xserver v2] randr: Add Border property support

Aaron Plattner aplattner at nvidia.com
Wed Aug 31 18:27:23 PDT 2011


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>
---
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