summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2011-09-21 14:13:37 -0700
committerAaron Plattner <aplattner@nvidia.com>2011-09-21 14:53:16 -0700
commitba5e560408c41dacf482b4b067697d83e3be5836 (patch)
treec6504284c48540b9fe2e93308c1ba9e029cbb348
parent1b2ffcd72d09cff84f2829c3fdaa2f048c1eb36d (diff)
randr: Add Border property supportrandr
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@nvidia.com> Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
-rw-r--r--hw/xfree86/modes/xf86Crtc.c54
-rw-r--r--hw/xfree86/modes/xf86Crtc.h17
-rw-r--r--hw/xfree86/modes/xf86Cursors.c3
-rw-r--r--hw/xfree86/modes/xf86Rotate.c21
-rw-r--r--randr/randrstr.h28
-rw-r--r--randr/rrcrtc.c26
-rw-r--r--randr/rrproperty.c96
7 files changed, 229 insertions, 16 deletions
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index c2814d4cd..6dd2206b0 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 ffb2efff4..0f49856dc 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 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 4a03428ea..b1337666c 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 45aabf025..22c2b9320 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,
@@ -426,8 +429,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;
@@ -519,9 +520,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 d8dd37d96..cc5c9b61c 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 e6a38ae60..493199be9 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 6ed24d3aa..d357bb10e 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)
{