[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