aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/randr/rrcrtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/Xserver/randr/rrcrtc.c')
-rw-r--r--nx-X11/programs/Xserver/randr/rrcrtc.c1298
1 files changed, 1147 insertions, 151 deletions
diff --git a/nx-X11/programs/Xserver/randr/rrcrtc.c b/nx-X11/programs/Xserver/randr/rrcrtc.c
index 76b4c64f9..d69b5ec08 100644
--- a/nx-X11/programs/Xserver/randr/rrcrtc.c
+++ b/nx-X11/programs/Xserver/randr/rrcrtc.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2006 Keith Packard
+ * Copyright 2010 Red Hat, Inc
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -39,7 +40,7 @@
#include "randrstr.h"
#include "swaprep.h"
-#include "registry.h"
+#include "mipointer.h"
RESTYPE RRCrtcType;
@@ -55,7 +56,7 @@ RRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged)
if (pScreen) {
rrScrPriv(pScreen);
- pScrPriv->changed = TRUE;
+ RRSetChanged(pScreen);
/*
* Send ConfigureNotify on any layout change
*/
@@ -81,8 +82,13 @@ RRCrtcCreate(ScreenPtr pScreen, void *devPrivate)
/* make space for the crtc pointer */
if (pScrPriv->numCrtcs)
+#ifndef NXAGENT_SERVER
+ crtcs = reallocarray(pScrPriv->crtcs,
+ pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr));
+#else /* !defined(NXAGENT_SERVER) */
crtcs = xrealloc(pScrPriv->crtcs,
(pScrPriv->numCrtcs + 1) * sizeof(RRCrtcPtr));
+#endif /* !defined(NXAGENT_SERVER) */
else
crtcs = xalloc(sizeof(RRCrtcPtr));
if (!crtcs)
@@ -105,6 +111,11 @@ RRCrtcCreate(ScreenPtr pScreen, void *devPrivate)
crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
crtc->changed = FALSE;
crtc->devPrivate = devPrivate;
+ RRTransformInit(&crtc->client_pending_transform);
+ RRTransformInit(&crtc->client_current_transform);
+ pixman_transform_init_identity(&crtc->transform);
+ pixman_f_transform_init_identity(&crtc->f_transform);
+ pixman_f_transform_init_identity(&crtc->f_inverse);
if (!AddResource(crtc->id, RRCrtcType, (void *) crtc))
return NULL;
@@ -113,6 +124,8 @@ RRCrtcCreate(ScreenPtr pScreen, void *devPrivate)
crtc->pScreen = pScreen;
pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
+ RRResourcesChanged(pScreen);
+
return crtc;
}
@@ -126,6 +139,15 @@ RRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations)
}
/*
+ * Set whether transforms are allowed on a CRTC
+ */
+void
+RRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms)
+{
+ crtc->transforms = transforms;
+}
+
+/*
* Notify the extension that the Crtc has been reconfigured,
* the driver calls this whenever it has updated the mode
*/
@@ -133,7 +155,9 @@ Bool
RRCrtcNotify(RRCrtcPtr crtc,
RRModePtr mode,
int x,
- int y, Rotation rotation, int numOutputs, RROutputPtr * outputs)
+ int y,
+ Rotation rotation,
+ RRTransformPtr transform, int numOutputs, RROutputPtr * outputs)
{
int i, j;
@@ -174,16 +198,24 @@ RRCrtcNotify(RRCrtcPtr crtc,
if (numOutputs) {
if (crtc->numOutputs)
+#ifndef NXAGENT_SERVER
+ newoutputs = reallocarray(crtc->outputs,
+ numOutputs, sizeof(RROutputPtr));
+#else /* !defined(NXAGENT_SERVER) */
newoutputs = xrealloc(crtc->outputs,
numOutputs * sizeof(RROutputPtr));
+#endif /* !defined(NXAGENT_SERVER) */
else
+#ifndef NXAGENT_SERVER
+ newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr));
+#else /* !defined(NXAGENT_SERVER) */
newoutputs = xalloc(numOutputs * sizeof(RROutputPtr));
+#endif /* !defined(NXAGENT_SERVER) */
if (!newoutputs)
return FALSE;
}
else {
- if (crtc->outputs)
- xfree(crtc->outputs);
+ xfree(crtc->outputs);
newoutputs = NULL;
}
crtc->outputs = newoutputs;
@@ -216,6 +248,18 @@ RRCrtcNotify(RRCrtcPtr crtc,
crtc->rotation = rotation;
RRCrtcChanged(crtc, TRUE);
}
+ if (!RRTransformEqual(transform, &crtc->client_current_transform)) {
+ RRTransformCopy(&crtc->client_current_transform, transform);
+ RRCrtcChanged(crtc, TRUE);
+ }
+ if (crtc->changed && mode) {
+ RRTransformCompute(x, y,
+ mode->mode.width, mode->mode.height,
+ rotation,
+ &crtc->client_current_transform,
+ &crtc->transform, &crtc->f_transform,
+ &crtc->f_inverse);
+ }
return TRUE;
}
@@ -225,30 +269,24 @@ RRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
ScreenPtr pScreen = pWin->drawable.pScreen;
rrScrPriv(pScreen);
- xRRCrtcChangeNotifyEvent ce;
RRModePtr mode = crtc->mode;
- ce.type = RRNotify + RREventBase;
- ce.subCode = RRNotify_CrtcChange;
- ce.sequenceNumber = client->sequence;
- ce.timestamp = pScrPriv->lastSetTime.milliseconds;
- ce.window = pWin->drawable.id;
- ce.crtc = crtc->id;
- ce.rotation = crtc->rotation;
- if (mode) {
- ce.mode = mode->mode.id;
- ce.x = crtc->x;
- ce.y = crtc->y;
- ce.width = mode->mode.width;
- ce.height = mode->mode.height;
- }
- else {
- ce.mode = None;
- ce.x = 0;
- ce.y = 0;
- ce.width = 0;
- ce.height = 0;
- }
+ xRRCrtcChangeNotifyEvent ce = {
+ .type = RRNotify + RREventBase,
+ .subCode = RRNotify_CrtcChange,
+#ifdef NXAGENT_SERVER
+ .sequenceNumber = client->sequence,
+#endif
+ .timestamp = pScrPriv->lastSetTime.milliseconds,
+ .window = pWin->drawable.id,
+ .crtc = crtc->id,
+ .mode = mode ? mode->mode.id : None,
+ .rotation = crtc->rotation,
+ .x = mode ? crtc->x : 0,
+ .y = mode ? crtc->y : 0,
+ .width = mode ? mode->mode.width : 0,
+ .height = mode ? mode->mode.height : 0
+ };
WriteEventsToClient(client, 1, (xEvent *) &ce);
}
@@ -269,6 +307,302 @@ RRCrtcPendingProperties(RRCrtcPtr crtc)
return FALSE;
}
+static void
+crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
+{
+ *left = crtc->x;
+ *top = crtc->y;
+
+ switch (crtc->rotation) {
+ case RR_Rotate_0:
+ case RR_Rotate_180:
+ default:
+ *right = crtc->x + crtc->mode->mode.width;
+ *bottom = crtc->y + crtc->mode->mode.height;
+ return;
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ *right = crtc->x + crtc->mode->mode.height;
+ *bottom = crtc->y + crtc->mode->mode.width;
+ return;
+ }
+}
+
+/* overlapping counts as adjacent */
+static Bool
+crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
+{
+ /* left, right, top, bottom... */
+ int al, ar, at, ab;
+ int bl, br, bt, bb;
+ int cl, cr, ct, cb; /* the overlap, if any */
+
+ crtc_bounds(a, &al, &ar, &at, &ab);
+ crtc_bounds(b, &bl, &br, &bt, &bb);
+
+ cl = max(al, bl);
+ cr = min(ar, br);
+ ct = max(at, bt);
+ cb = min(ab, bb);
+
+ return (cl <= cr) && (ct <= cb);
+}
+
+/* Depth-first search and mark all CRTCs reachable from cur */
+static void
+mark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur)
+{
+ int i;
+
+ reachable[cur] = TRUE;
+ for (i = 0; i < pScrPriv->numCrtcs; ++i) {
+ if (reachable[i] || !pScrPriv->crtcs[i]->mode)
+ continue;
+ if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
+ mark_crtcs(pScrPriv, reachable, i);
+ }
+}
+
+static void
+RRComputeContiguity(ScreenPtr pScreen)
+{
+ rrScrPriv(pScreen);
+ Bool discontiguous = TRUE;
+ int i, n = pScrPriv->numCrtcs;
+
+ int *reachable = xcalloc(n, sizeof(int));
+
+ if (!reachable)
+ goto out;
+
+ /* Find first enabled CRTC and start search for reachable CRTCs from it */
+ for (i = 0; i < n; ++i) {
+ if (pScrPriv->crtcs[i]->mode) {
+ mark_crtcs(pScrPriv, reachable, i);
+ break;
+ }
+ }
+
+ /* Check that all enabled CRTCs were marked as reachable */
+ for (i = 0; i < n; ++i)
+ if (pScrPriv->crtcs[i]->mode && !reachable[i])
+ goto out;
+
+ discontiguous = FALSE;
+
+ out:
+ xfree(reachable);
+ pScrPriv->discontiguous = discontiguous;
+}
+
+static void
+rrDestroySharedPixmap(RRCrtcPtr crtc, PixmapPtr pPixmap) {
+#ifndef NXAGENT_SERVER
+ ScreenPtr master = crtc->pScreen->current_master;
+
+ if (master && pPixmap->master_pixmap) {
+ PixmapPtr mscreenpix = master->GetScreenPixmap(master);
+
+ master->StopPixmapTracking(mscreenpix, pPixmap);
+ /*
+ * Unref the pixmap twice: once for the original reference, and once
+ * for the reference implicitly added by PixmapShareToSlave.
+ */
+ master->DestroyPixmap(pPixmap->master_pixmap);
+ master->DestroyPixmap(pPixmap->master_pixmap);
+ }
+#endif
+
+ crtc->pScreen->DestroyPixmap(pPixmap);
+}
+
+void
+RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
+{
+ rrScrPriv(crtc->pScreen);
+
+ pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
+ if (crtc->scanout_pixmap) {
+ rrDestroySharedPixmap(crtc, crtc->scanout_pixmap);
+ }
+ crtc->scanout_pixmap = NULL;
+ RRCrtcChanged(crtc, TRUE);
+}
+
+#ifndef NXAGENT_SERVER
+static PixmapPtr
+rrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master,
+ int width, int height, int depth,
+ int x, int y, Rotation rotation)
+{
+ Bool ret;
+ PixmapPtr mpix, spix;
+ rrScrPriv(crtc->pScreen);
+
+ mpix = master->CreatePixmap(master, width, height, depth,
+ CREATE_PIXMAP_USAGE_SHARED);
+ if (!mpix)
+ return NULL;
+
+ spix = PixmapShareToSlave(mpix, crtc->pScreen);
+ if (spix == NULL) {
+ master->DestroyPixmap(mpix);
+ return NULL;
+ }
+
+ ret = pScrPriv->rrCrtcSetScanoutPixmap(crtc, spix);
+ if (ret == FALSE) {
+ rrDestroySharedPixmap(crtc, spix);
+ ErrorF("randr: failed to set shadow slave pixmap\n");
+ return NULL;
+ }
+
+ return spix;
+}
+
+static Bool
+rrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height,
+ int x, int y, Rotation rotation)
+{
+ ScreenPtr master = crtc->pScreen->current_master;
+ int depth;
+ PixmapPtr mscreenpix;
+ PixmapPtr spix;
+
+ /* create a pixmap on the master screen,
+ then get a shared handle for it
+ create a shared pixmap on the slave screen using the handle
+ set the master screen to do dirty updates to the shared pixmap
+ from the screen pixmap.
+ set slave screen to scanout shared linear pixmap
+ */
+
+ mscreenpix = master->GetScreenPixmap(master);
+ depth = mscreenpix->drawable.depth;
+
+ if (crtc->scanout_pixmap)
+ RRCrtcDetachScanoutPixmap(crtc);
+
+ if (width == 0 && height == 0) {
+ return TRUE;
+ }
+
+ spix = rrCreateSharedPixmap(crtc, master,
+ width, height, depth,
+ x, y, rotation);
+ if (spix == NULL) {
+ return FALSE;
+ }
+
+ crtc->scanout_pixmap = spix;
+
+ master->StartPixmapTracking(mscreenpix, spix, x, y, 0, 0, rotation);
+ return TRUE;
+}
+
+static void crtc_to_box(BoxPtr box, RRCrtcPtr crtc)
+{
+ box->x1 = crtc->x;
+ box->y1 = crtc->y;
+ switch (crtc->rotation) {
+ case RR_Rotate_0:
+ case RR_Rotate_180:
+ default:
+ box->x2 = crtc->x + crtc->mode->mode.width;
+ box->y2 = crtc->y + crtc->mode->mode.height;
+ break;
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ box->x2 = crtc->x + crtc->mode->mode.height;
+ box->y2 = crtc->y + crtc->mode->mode.width;
+ break;
+ }
+}
+
+static Bool
+rrCheckPixmapBounding(ScreenPtr pScreen,
+ RRCrtcPtr rr_crtc, Rotation rotation,
+ int x, int y, int w, int h)
+{
+ RegionRec root_pixmap_region, total_region, new_crtc_region;
+ int c;
+ BoxRec newbox;
+ BoxPtr newsize;
+ ScreenPtr slave;
+ int new_width, new_height;
+ PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
+ rrScrPriv(pScreen);
+
+ PixmapRegionInit(&root_pixmap_region, screen_pixmap);
+ RegionInit(&total_region, NULL, 0);
+
+ /* have to iterate all the crtcs of the attached gpu masters
+ and all their output slaves */
+ for (c = 0; c < pScrPriv->numCrtcs; c++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[c];
+
+ if (crtc == rr_crtc) {
+ newbox.x1 = x;
+ newbox.y1 = y;
+ if (rotation == RR_Rotate_90 ||
+ rotation == RR_Rotate_270) {
+ newbox.x2 = x + h;
+ newbox.y2 = y + w;
+ } else {
+ newbox.x2 = x + w;
+ newbox.y2 = y + h;
+ }
+ } else {
+ if (!crtc->mode)
+ continue;
+ crtc_to_box(&newbox, crtc);
+ }
+ RegionInit(&new_crtc_region, &newbox, 1);
+ RegionUnion(&total_region, &total_region, &new_crtc_region);
+ }
+
+ xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
+ rrScrPrivPtr slave_priv = rrGetScrPriv(slave);
+ for (c = 0; c < slave_priv->numCrtcs; c++) {
+ RRCrtcPtr slave_crtc = slave_priv->crtcs[c];
+
+ if (slave_crtc == rr_crtc) {
+ newbox.x1 = x;
+ newbox.y1 = y;
+ if (rotation == RR_Rotate_90 ||
+ rotation == RR_Rotate_270) {
+ newbox.x2 = x + h;
+ newbox.y2 = y + w;
+ } else {
+ newbox.x2 = x + w;
+ newbox.y2 = y + h;
+ }
+ }
+ else {
+ if (!slave_crtc->mode)
+ continue;
+ crtc_to_box(&newbox, slave_crtc);
+ }
+ RegionInit(&new_crtc_region, &newbox, 1);
+ RegionUnion(&total_region, &total_region, &new_crtc_region);
+ }
+ }
+
+ newsize = RegionExtents(&total_region);
+ new_width = newsize->x2 - newsize->x1;
+ new_height = newsize->y2 - newsize->y1;
+
+ if (new_width == screen_pixmap->drawable.width &&
+ new_height == screen_pixmap->drawable.height) {
+ } else {
+ pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0);
+ }
+
+ /* set shatters TODO */
+ return TRUE;
+}
+#endif /* !defined(NXAGENT_SERVER) */
+
/*
* Request that the Crtc be reconfigured
*/
@@ -280,9 +614,20 @@ RRCrtcSet(RRCrtcPtr crtc,
{
ScreenPtr pScreen = crtc->pScreen;
Bool ret = FALSE;
+ Bool recompute = TRUE;
+ Bool crtcChanged;
+ int o;
rrScrPriv(pScreen);
+ crtcChanged = FALSE;
+ for (o = 0; o < numOutputs; o++) {
+ if (outputs[o] && outputs[o]->crtc != crtc) {
+ crtcChanged = TRUE;
+ break;
+ }
+ }
+
/* See if nothing changed */
if (crtc->mode == mode &&
crtc->x == x &&
@@ -290,10 +635,31 @@ RRCrtcSet(RRCrtcPtr crtc,
crtc->rotation == rotation &&
crtc->numOutputs == numOutputs &&
!memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) &&
- !RRCrtcPendingProperties(crtc)) {
+ !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) &&
+ !crtcChanged) {
+ recompute = FALSE;
ret = TRUE;
}
else {
+#ifndef NXAGENT_SERVER
+ if (pScreen->isGPU) {
+ ScreenPtr master = pScreen->current_master;
+ int width = 0, height = 0;
+
+ if (mode) {
+ width = mode->mode.width;
+ height = mode->mode.height;
+ }
+ ret = rrCheckPixmapBounding(master, crtc,
+ rotation, x, y, width, height);
+ if (!ret)
+ return FALSE;
+
+ if (pScreen->current_master) {
+ ret = rrSetupPixmapSharing(crtc, width, height, x, y, rotation);
+ }
+ }
+#endif
#if RANDR_12_INTERFACE
if (pScrPriv->rrCrtcSet) {
ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
@@ -308,7 +674,7 @@ RRCrtcSet(RRCrtcPtr crtc,
RRScreenRate rate;
if (!mode) {
- RRCrtcNotify(crtc, NULL, x, y, rotation, 0, NULL);
+ RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL);
ret = TRUE;
}
else {
@@ -332,7 +698,8 @@ RRCrtcSet(RRCrtcPtr crtc,
* Old 1.0 interface tied screen size to mode size
*/
if (ret) {
- RRCrtcNotify(crtc, mode, x, y, rotation, 1, outputs);
+ RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1,
+ outputs);
RRScreenSizeNotify(pScreen);
}
}
@@ -340,7 +707,6 @@ RRCrtcSet(RRCrtcPtr crtc,
#endif
}
if (ret) {
- int o;
RRTellChanged(pScreen);
@@ -348,10 +714,38 @@ RRCrtcSet(RRCrtcPtr crtc,
RRPostPendingProperties(outputs[o]);
}
}
+
+ if (recompute)
+ RRComputeContiguity(pScreen);
+
return ret;
}
/*
+ * Return crtc transform
+ */
+RRTransformPtr
+RRCrtcGetTransform(RRCrtcPtr crtc)
+{
+ RRTransformPtr transform = &crtc->client_pending_transform;
+
+ if (pixman_transform_is_identity(&transform->transform))
+ return NULL;
+ return transform;
+}
+
+/*
+ * Check whether the pending and current transforms are the same
+ */
+Bool
+RRCrtcPendingTransform(RRCrtcPtr crtc)
+{
+ return memcmp(&crtc->client_current_transform.transform,
+ &crtc->client_pending_transform.transform,
+ sizeof(PictTransform)) != 0;
+}
+
+/*
* Destroy a Crtc at shutdown
*/
void
@@ -378,9 +772,13 @@ RRCrtcDestroyResource(void *value, XID pid)
break;
}
}
+
+ RRResourcesChanged(pScreen);
}
- if (crtc->gammaRed)
- xfree(crtc->gammaRed);
+
+ if (crtc->scanout_pixmap)
+ RRCrtcDetachScanoutPixmap(crtc);
+ xfree(crtc->gammaRed);
if (crtc->mode)
RRModeDestroy(crtc->mode);
xfree(crtc);
@@ -414,6 +812,29 @@ RRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue)
}
/*
+ * Request current gamma back from the DDX (if possible).
+ * This includes gamma size.
+ */
+Bool
+RRCrtcGammaGet(RRCrtcPtr crtc)
+{
+ Bool ret = TRUE;
+
+#if RANDR_12_INTERFACE
+ ScreenPtr pScreen = crtc->pScreen;
+#endif
+
+#if RANDR_12_INTERFACE
+ if (pScreen) {
+ rrScrPriv(pScreen);
+ if (pScrPriv->rrCrtcGetGamma)
+ ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
+ }
+#endif
+ return ret;
+}
+
+/*
* Notify the extension that the Crtc gamma has been changed
* The driver calls this whenever it has changed the gamma values
* in the RRCrtcRec
@@ -425,30 +846,35 @@ RRCrtcGammaNotify(RRCrtcPtr crtc)
return TRUE; /* not much going on here */
}
-/**
- * Returns the width/height that the crtc scans out from the framebuffer
- */
-void
-RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
+static void
+RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
+ int *width, int *height)
{
- if (crtc->mode == NULL) {
+ BoxRec box;
+
+ if (mode == NULL) {
*width = 0;
*height = 0;
return;
}
- switch (crtc->rotation & 0xf) {
- case RR_Rotate_0:
- case RR_Rotate_180:
- *width = crtc->mode->mode.width;
- *height = crtc->mode->mode.height;
- break;
- case RR_Rotate_90:
- case RR_Rotate_270:
- *width = crtc->mode->mode.height;
- *height = crtc->mode->mode.width;
- break;
- }
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = mode->mode.width;
+ box.y2 = mode->mode.height;
+
+ pixman_transform_bounds(transform, &box);
+ *width = box.x2 - box.x1;
+ *height = box.y2 - box.y1;
+}
+
+/**
+ * Returns the width/height that the crtc scans out from the framebuffer
+ */
+void
+RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
+{
+ RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
}
/*
@@ -463,14 +889,17 @@ RRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
if (size == crtc->gammaSize)
return TRUE;
if (size) {
+#ifndef NXAGENT_SERVER
+ gamma = xallocarray(size, 3 * sizeof(CARD16));
+#else /* !defined(NXAGENT_SERVER) */
gamma = xalloc(size * 3 * sizeof(CARD16));
+#endif /* !defined(NXAGENT_SERVER) */
if (!gamma)
return FALSE;
}
else
gamma = NULL;
- if (crtc->gammaRed)
- xfree(crtc->gammaRed);
+ xfree(crtc->gammaRed);
crtc->gammaRed = gamma;
crtc->gammaGreen = gamma + size;
crtc->gammaBlue = gamma + size * 2;
@@ -479,18 +908,79 @@ RRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
}
/*
+ * Set the pending CRTC transformation
+ */
+
+int
+RRCrtcTransformSet(RRCrtcPtr crtc,
+ PictTransformPtr transform,
+ struct pixman_f_transform *f_transform,
+ struct pixman_f_transform *f_inverse,
+ char *filter_name,
+ int filter_len, xFixed * params, int nparams)
+{
+ PictFilterPtr filter = NULL;
+ int width = 0, height = 0;
+
+ if (!crtc->transforms)
+ return BadValue;
+
+ if (filter_len) {
+ filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
+ if (!filter)
+ return BadName;
+ if (filter->ValidateParams) {
+ if (!filter->ValidateParams(crtc->pScreen, filter->id,
+ params, nparams, &width, &height))
+ return BadMatch;
+ }
+ else {
+ width = filter->width;
+ height = filter->height;
+ }
+ }
+ else {
+ if (nparams)
+ return BadMatch;
+ }
+ if (!RRTransformSetFilter(&crtc->client_pending_transform,
+ filter, params, nparams, width, height))
+ return BadAlloc;
+
+ crtc->client_pending_transform.transform = *transform;
+ crtc->client_pending_transform.f_transform = *f_transform;
+ crtc->client_pending_transform.f_inverse = *f_inverse;
+ return Success;
+}
+
+/*
* Initialize crtc type
*/
Bool
RRCrtcInit(void)
{
- RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource);
+ RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource
+#ifndef NXAGENT_SERVER
+ , "CRTC"
+#endif
+ );
if (!RRCrtcType)
return FALSE;
- RegisterResourceName(RRCrtcType, "CRTC");
+
return TRUE;
}
+/*
+ * Initialize crtc type error value
+ */
+void
+RRCrtcInitErrorValue(void)
+{
+#ifndef NXAGENT_SERVER
+ SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
+#endif
+}
+
int
ProcRRGetCrtcInfo(ClientPtr client)
{
@@ -504,14 +994,13 @@ ProcRRGetCrtcInfo(ClientPtr client)
RRModePtr mode;
RROutput *outputs;
RROutput *possible;
- int i, j, k, n;
+ int i, j, k;
int width, height;
+ BoxRec panned_area;
+ int n;
REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
- crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
-
- if (!crtc)
- return RRErrorBase + BadRRCrtc;
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
/* All crtcs must be associated with screens before client
* requests are processed
@@ -521,16 +1010,28 @@ ProcRRGetCrtcInfo(ClientPtr client)
mode = crtc->mode;
- rep.type = X_Reply;
- rep.status = RRSetConfigSuccess;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.timestamp = pScrPriv->lastSetTime.milliseconds;
- rep.x = crtc->x;
- rep.y = crtc->y;
- RRCrtcGetScanoutSize(crtc, &width, &height);
- rep.width = width;
- rep.height = height;
+ rep = (xRRGetCrtcInfoReply) {
+ .type = X_Reply,
+ .status = RRSetConfigSuccess,
+ .sequenceNumber = client->sequence,
+ .length = 0,
+ .timestamp = pScrPriv->lastSetTime.milliseconds
+ };
+ if (pScrPriv->rrGetPanning &&
+ pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
+ (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) {
+ rep.x = panned_area.x1;
+ rep.y = panned_area.y1;
+ rep.width = panned_area.x2 - panned_area.x1;
+ rep.height = panned_area.y2 - panned_area.y1;
+ }
+ else {
+ RRCrtcGetScanoutSize(crtc, &width, &height);
+ rep.x = crtc->x;
+ rep.y = crtc->y;
+ rep.width = width;
+ rep.height = height;
+ }
rep.mode = mode ? mode->mode.id : 0;
rep.rotation = crtc->rotation;
rep.rotations = crtc->rotations;
@@ -591,7 +1092,7 @@ ProcRRGetCrtcInfo(ClientPtr client)
xfree(extra);
}
- return client->noClientException;
+ return Success;
}
int
@@ -608,32 +1109,35 @@ ProcRRSetCrtcConfig(ClientPtr client)
RROutput *outputIds;
TimeStamp time;
Rotation rotation;
- int i, j;
+ int
+#ifndef NXAGENT_SERVER
+ ret,
+#endif
+ i, j;
+ CARD8 status;
+ int n;
REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
- numOutputs = (stuff->length - (SIZEOF(xRRSetCrtcConfigReq) >> 2));
+ numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
+
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
- crtc = LookupIDByType(stuff->crtc, RRCrtcType);
- if (!crtc) {
- client->errorValue = stuff->crtc;
- return RRErrorBase + BadRRCrtc;
- }
if (stuff->mode == None) {
mode = NULL;
if (numOutputs > 0)
return BadMatch;
}
else {
- mode = LookupIDByType(stuff->mode, RRModeType);
- if (!mode) {
- client->errorValue = stuff->mode;
- return RRErrorBase + BadRRMode;
- }
+ VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
if (numOutputs == 0)
return BadMatch;
}
if (numOutputs) {
+#ifndef NXAGENT_SERVER
+ outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
+#else /* !defined(NXAGENT_SERVER) */
outputs = xalloc(numOutputs * sizeof(RROutputPtr));
+#endif /* !defined(NXAGENT_SERVER) */
if (!outputs)
return BadAlloc;
}
@@ -642,6 +1146,15 @@ ProcRRSetCrtcConfig(ClientPtr client)
outputIds = (RROutput *) (stuff + 1);
for (i = 0; i < numOutputs; i++) {
+#ifndef NXAGENT_SERVER
+ ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
+ RROutputType, client, DixSetAttrAccess);
+
+ if (ret != Success) {
+ xfree(outputs);
+ return ret;
+ }
+#else /* !defined(NXAGENT_SERVER) */
outputs[i] = (RROutputPtr) LookupIDByType(outputIds[i], RROutputType);
if (!outputs[i]) {
client->errorValue = outputIds[i];
@@ -649,13 +1162,13 @@ ProcRRSetCrtcConfig(ClientPtr client)
xfree(outputs);
return RRErrorBase + BadRROutput;
}
+#endif /* !defined(NXAGENT_SERVER) */
/* validate crtc for this output */
for (j = 0; j < outputs[i]->numCrtcs; j++)
if (outputs[i]->crtcs[j] == crtc)
break;
if (j == outputs[i]->numCrtcs) {
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
return BadMatch;
}
/* validate mode for this output */
@@ -667,8 +1180,7 @@ ProcRRSetCrtcConfig(ClientPtr client)
break;
}
if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
return BadMatch;
}
}
@@ -684,8 +1196,7 @@ ProcRRSetCrtcConfig(ClientPtr client)
break;
}
if (k == outputs[i]->numClones) {
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
return BadMatch;
}
}
@@ -698,7 +1209,7 @@ ProcRRSetCrtcConfig(ClientPtr client)
if (!pScrPriv) {
time = currentTime;
- rep.status = RRSetConfigFailed;
+ status = RRSetConfigFailed;
goto sendReply;
}
@@ -719,8 +1230,7 @@ ProcRRSetCrtcConfig(ClientPtr client)
* Invalid rotation
*/
client->errorValue = stuff->rotation;
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
return BadValue;
}
@@ -730,8 +1240,7 @@ ProcRRSetCrtcConfig(ClientPtr client)
* requested rotation or reflection not supported by screen
*/
client->errorValue = stuff->rotation;
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
return BadMatch;
}
@@ -739,71 +1248,220 @@ ProcRRSetCrtcConfig(ClientPtr client)
/*
* Check screen size bounds if the DDX provides a 1.2 interface
* for setting screen size. Else, assume the CrtcSet sets
- * the size along with the mode
+ * the size along with the mode. If the driver supports transforms,
+ * then it must allow crtcs to display a subset of the screen, so
+ * only do this check for drivers without transform support.
*/
- if (pScrPriv->rrScreenSetSize) {
- int source_width = mode->mode.width;
- int source_height = mode->mode.height;
-
- if ((rotation & 0xf) == RR_Rotate_90 ||
- (rotation & 0xf) == RR_Rotate_270) {
- source_width = mode->mode.height;
- source_height = mode->mode.width;
+ if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
+ int source_width;
+ int source_height;
+ PictTransform transform;
+ struct pixman_f_transform f_transform, f_inverse;
+ int width, height;
+
+#ifndef NXAGENT_SERVER
+ if (pScreen->isGPU) {
+ width = pScreen->current_master->width;
+ height = pScreen->current_master->height;
}
- if (stuff->x + source_width > pScreen->width) {
+ else
+#else /* !defined(NXAGENT_SERVER) */
+ {
+ width = pScreen->width;
+ height = pScreen->height;
+ }
+#endif /* !defined(NXAGENT_SERVER) */
+
+ RRTransformCompute(stuff->x, stuff->y,
+ mode->mode.width, mode->mode.height,
+ rotation,
+ &crtc->client_pending_transform,
+ &transform, &f_transform, &f_inverse);
+
+ RRModeGetScanoutSize(mode, &transform, &source_width,
+ &source_height);
+ if (stuff->x + source_width > width) {
client->errorValue = stuff->x;
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
return BadValue;
}
- if (stuff->y + source_height > pScreen->height) {
+ if (stuff->y + source_height > height) {
client->errorValue = stuff->y;
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
return BadValue;
}
}
#endif
}
- /*
- * Make sure the requested set-time is not older than
- * the last set-time
- */
- if (CompareTimeStamps(time, pScrPriv->lastSetTime) < 0) {
- rep.status = RRSetConfigInvalidTime;
- goto sendReply;
- }
-
if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
rotation, numOutputs, outputs)) {
- rep.status = RRSetConfigFailed;
+ status = RRSetConfigFailed;
goto sendReply;
}
- rep.status = RRSetConfigSuccess;
+ status = RRSetConfigSuccess;
pScrPriv->lastSetTime = time;
sendReply:
- if (outputs)
- xfree(outputs);
+ xfree(outputs);
+
+ rep = (xRRSetCrtcConfigReply) {
+ .type = X_Reply,
+ .status = status,
+ .sequenceNumber = client->sequence,
+ .length = 0,
+ .newTimestamp = pScrPriv->lastSetTime.milliseconds
+ };
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.newTimestamp, n);
+ }
+ WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *) &rep);
- rep.type = X_Reply;
- /* rep.status has already been filled in */
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
- rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
+ return Success;
+}
+
+int
+ProcRRGetPanning(ClientPtr client)
+{
+ REQUEST(xRRGetPanningReq);
+ xRRGetPanningReply rep;
+ RRCrtcPtr crtc;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ BoxRec total;
+ BoxRec tracking;
+ INT16 border[4];
+ int n;
+
+ REQUEST_SIZE_MATCH(xRRGetPanningReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* All crtcs must be associated with screens before client
+ * requests are processed
+ */
+ pScreen = crtc->pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ if (!pScrPriv)
+ return RRErrorBase + BadRRCrtc;
+
+ rep = (xRRGetPanningReply) {
+ .type = X_Reply,
+ .status = RRSetConfigSuccess,
+ .sequenceNumber = client->sequence,
+ .length = 1,
+ .timestamp = pScrPriv->lastSetTime.milliseconds
+ };
+ if (pScrPriv->rrGetPanning &&
+ pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
+ rep.left = total.x1;
+ rep.top = total.y1;
+ rep.width = total.x2 - total.x1;
+ rep.height = total.y2 - total.y1;
+ rep.track_left = tracking.x1;
+ rep.track_top = tracking.y1;
+ rep.track_width = tracking.x2 - tracking.x1;
+ rep.track_height = tracking.y2 - tracking.y1;
+ rep.border_left = border[0];
+ rep.border_top = border[1];
+ rep.border_right = border[2];
+ rep.border_bottom = border[3];
+ }
if (client->swapped) {
- int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.timestamp, n);
+ swaps(&rep.left, n);
+ swaps(&rep.top, n);
+ swaps(&rep.width, n);
+ swaps(&rep.height, n);
+ swaps(&rep.track_left, n);
+ swaps(&rep.track_top, n);
+ swaps(&rep.track_width, n);
+ swaps(&rep.track_height, n);
+ swaps(&rep.border_left, n);
+ swaps(&rep.border_top, n);
+ swaps(&rep.border_right, n);
+ swaps(&rep.border_bottom, n);
+ }
+ WriteToClient(client, sizeof(xRRGetPanningReply), (char *) &rep);
+ return Success;
+}
+
+int
+ProcRRSetPanning(ClientPtr client)
+{
+ REQUEST(xRRSetPanningReq);
+ xRRSetPanningReply rep;
+ RRCrtcPtr crtc;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ TimeStamp time;
+ BoxRec total;
+ BoxRec tracking;
+ INT16 border[4];
+ CARD8 status;
+ int n;
+
+ REQUEST_SIZE_MATCH(xRRSetPanningReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* All crtcs must be associated with screens before client
+ * requests are processed
+ */
+ pScreen = crtc->pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ if (!pScrPriv) {
+ time = currentTime;
+ status = RRSetConfigFailed;
+ goto sendReply;
+ }
+
+ time = ClientTimeToServerTime(stuff->timestamp);
+
+ if (!pScrPriv->rrGetPanning)
+ return RRErrorBase + BadRRCrtc;
+
+ total.x1 = stuff->left;
+ total.y1 = stuff->top;
+ total.x2 = total.x1 + stuff->width;
+ total.y2 = total.y1 + stuff->height;
+ tracking.x1 = stuff->track_left;
+ tracking.y1 = stuff->track_top;
+ tracking.x2 = tracking.x1 + stuff->track_width;
+ tracking.y2 = tracking.y1 + stuff->track_height;
+ border[0] = stuff->border_left;
+ border[1] = stuff->border_top;
+ border[2] = stuff->border_right;
+ border[3] = stuff->border_bottom;
+
+ if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
+ return BadMatch;
+
+ pScrPriv->lastSetTime = time;
+ status = RRSetConfigSuccess;
+
+ sendReply:
+ rep = (xRRSetPanningReply) {
+ .type = X_Reply,
+ .status = status,
+ .sequenceNumber = client->sequence,
+ .length = 0,
+ .newTimestamp = pScrPriv->lastSetTime.milliseconds
+ };
+ if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.newTimestamp, n);
}
- WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *) &rep);
-
- return client->noClientException;
+ WriteToClient(client, sizeof(xRRSetPanningReply), (char *) &rep);
+ return Success;
}
int
@@ -815,21 +1473,25 @@ ProcRRGetCrtcGammaSize(ClientPtr client)
int n;
REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
- crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
- if (!crtc)
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* Gamma retrieval failed, any better error? */
+ if (!RRCrtcGammaGet(crtc))
return RRErrorBase + BadRRCrtc;
- reply.type = X_Reply;
- reply.sequenceNumber = client->sequence;
- reply.length = 0;
- reply.size = crtc->gammaSize;
+ reply = (xRRGetCrtcGammaSizeReply) {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ .length = 0,
+ .size = crtc->gammaSize
+ };
if (client->swapped) {
swaps(&reply.sequenceNumber, n);
swapl(&reply.length, n);
swaps(&reply.size, n);
}
WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), (char *) &reply);
- return client->noClientException;
+ return Success;
}
int
@@ -838,13 +1500,15 @@ ProcRRGetCrtcGamma(ClientPtr client)
REQUEST(xRRGetCrtcGammaReq);
xRRGetCrtcGammaReply reply;
RRCrtcPtr crtc;
- int n;
unsigned long len;
- char *extra;
+ char *extra = NULL;
+ int n;
REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
- crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
- if (!crtc)
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* Gamma retrieval failed, any better error? */
+ if (!RRCrtcGammaGet(crtc))
return RRErrorBase + BadRRCrtc;
len = crtc->gammaSize * 3 * 2;
@@ -855,10 +1519,12 @@ ProcRRGetCrtcGamma(ClientPtr client)
return BadAlloc;
}
- reply.type = X_Reply;
- reply.sequenceNumber = client->sequence;
- reply.length = (len + 3) >> 2;
- reply.size = crtc->gammaSize;
+ reply = (xRRGetCrtcGammaReply) {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ .length = bytes_to_int32(len),
+ .size = crtc->gammaSize
+ };
if (client->swapped) {
swaps(&reply.sequenceNumber, n);
swapl(&reply.length, n);
@@ -871,7 +1537,7 @@ ProcRRGetCrtcGamma(ClientPtr client)
WriteSwappedDataToClient(client, len, extra);
xfree(extra);
}
- return client->noClientException;
+ return Success;
}
int
@@ -883,11 +1549,9 @@ ProcRRSetCrtcGamma(ClientPtr client)
CARD16 *red, *green, *blue;
REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
- crtc = LookupCrtc(client, stuff->crtc, DixWriteAccess);
- if (!crtc)
- return RRErrorBase + BadRRCrtc;
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
- len = client->req_len - (sizeof(xRRSetCrtcGammaReq) >> 2);
+ len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
if (len < (stuff->size * 3 + 1) >> 1)
return BadLength;
@@ -902,3 +1566,335 @@ ProcRRSetCrtcGamma(ClientPtr client)
return Success;
}
+
+/* Version 1.3 additions */
+
+int
+ProcRRSetCrtcTransform(ClientPtr client)
+{
+ REQUEST(xRRSetCrtcTransformReq);
+ RRCrtcPtr crtc;
+ PictTransform transform;
+ struct pixman_f_transform f_transform, f_inverse;
+ char *filter;
+ int nbytes;
+ xFixed *params;
+ int nparams;
+
+ REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ PictTransform_from_xRenderTransform(&transform, &stuff->transform);
+ pixman_f_transform_from_pixman_transform(&f_transform, &transform);
+ if (!pixman_f_transform_invert(&f_inverse, &f_transform))
+ return BadMatch;
+
+ filter = (char *) (stuff + 1);
+ nbytes = stuff->nbytesFilter;
+ params = (xFixed *) (filter + pad_to_int32(nbytes));
+ nparams = ((xFixed *) stuff + client->req_len) - params;
+ if (nparams < 0)
+ return BadLength;
+
+ return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
+ filter, nbytes, params, nparams);
+}
+
+#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32)
+
+static int
+transform_filter_length(RRTransformPtr transform)
+{
+ int nbytes, nparams;
+
+ if (transform->filter == NULL)
+ return 0;
+ nbytes = strlen(transform->filter->name);
+ nparams = transform->nparams;
+ return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
+}
+
+static int
+transform_filter_encode(ClientPtr client, char *output,
+ CARD16 *nbytesFilter,
+ CARD16 *nparamsFilter, RRTransformPtr transform)
+{
+ int nbytes, nparams;
+ int n;
+
+ if (transform->filter == NULL) {
+ *nbytesFilter = 0;
+ *nparamsFilter = 0;
+ return 0;
+ }
+ nbytes = strlen(transform->filter->name);
+ nparams = transform->nparams;
+ *nbytesFilter = nbytes;
+ *nparamsFilter = nparams;
+ memcpy(output, transform->filter->name, nbytes);
+ while ((nbytes & 3) != 0)
+ output[nbytes++] = 0;
+ memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
+ if (client->swapped) {
+ swaps(nbytesFilter, n);
+ swaps(nparamsFilter, n);
+ SwapLongs((CARD32 *) (output + nbytes), nparams);
+ }
+ nbytes += nparams * sizeof(xFixed);
+ return nbytes;
+}
+
+static void
+transform_encode(ClientPtr client, xRenderTransform * wire,
+ PictTransform * pict)
+{
+ xRenderTransform_from_PictTransform(wire, pict);
+ if (client->swapped)
+ SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
+}
+
+int
+ProcRRGetCrtcTransform(ClientPtr client)
+{
+ REQUEST(xRRGetCrtcTransformReq);
+ xRRGetCrtcTransformReply *reply;
+ RRCrtcPtr crtc;
+ int nextra;
+ RRTransformPtr current, pending;
+ char *extra;
+ int n;
+
+ REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ pending = &crtc->client_pending_transform;
+ current = &crtc->client_current_transform;
+
+ nextra = (transform_filter_length(pending) +
+ transform_filter_length(current));
+
+ reply = xcalloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
+ if (!reply)
+ return BadAlloc;
+
+ extra = (char *) (reply + 1);
+ reply->type = X_Reply;
+ reply->sequenceNumber = client->sequence;
+ reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
+
+ reply->hasTransforms = crtc->transforms;
+
+ transform_encode(client, &reply->pendingTransform, &pending->transform);
+ extra += transform_filter_encode(client, extra,
+ &reply->pendingNbytesFilter,
+ &reply->pendingNparamsFilter, pending);
+
+ transform_encode(client, &reply->currentTransform, &current->transform);
+ extra += transform_filter_encode(client, extra,
+ &reply->currentNbytesFilter,
+ &reply->currentNparamsFilter, current);
+
+ if (client->swapped) {
+ swaps(&reply->sequenceNumber, n);
+ swapl(&reply->length, n);
+ }
+ WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra,
+ (char *) reply);
+ xfree(reply);
+ return Success;
+}
+
+static Bool
+check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
+{
+ rrScrPriv(pScreen);
+ int i;
+ for (i = 0; i < pScrPriv->numCrtcs; i++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[i];
+
+ int left, right, top, bottom;
+
+ if (!crtc->mode)
+ continue;
+
+ crtc_bounds(crtc, &left, &right, &top, &bottom);
+
+ if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static Bool
+constrain_all_screen_crtcs(
+#ifndef NXAGENT_SERVER
+ DeviceIntPtr pDev,
+#endif /* !defined(NXAGENT_SERVER) */
+ ScreenPtr pScreen, int *x, int *y)
+{
+ rrScrPriv(pScreen);
+ int i;
+
+ /* if we're trying to escape, clamp to the CRTC we're coming from */
+ for (i = 0; i < pScrPriv->numCrtcs; i++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[i];
+ int nx, ny;
+ int left, right, top, bottom;
+
+ if (!crtc->mode)
+ continue;
+
+ crtc_bounds(crtc, &left, &right, &top, &bottom);
+#ifndef NXAGENT_SERVER
+ miPointerGetPosition(pDev, &nx, &ny);
+#else /* !defined(NXAGENT_SERVER) */
+
+ miPointerPosition(&nx, &ny);
+#endif /* !defined(NXAGENT_SERVER) */
+
+ if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
+ if (*x < left)
+ *x = left;
+ if (*x >= right)
+ *x = right - 1;
+ if (*y < top)
+ *y = top;
+ if (*y >= bottom)
+ *y = bottom - 1;
+
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void
+RRConstrainCursorHarder(
+#ifndef NXAGENT_SERVER
+ DeviceIntPtr pDev,
+#endif /* !defined(NXAGENT_SERVER) */
+ ScreenPtr pScreen, int mode, int *x,
+ int *y)
+{
+ rrScrPriv(pScreen);
+ Bool ret;
+#ifndef NXAGENT_SERVER
+ ScreenPtr slave;
+#endif
+
+ /* intentional dead space -> let it float */
+ if (pScrPriv->discontiguous)
+ return;
+
+ /* if we're moving inside a crtc, we're fine */
+ ret = check_all_screen_crtcs(pScreen, x, y);
+ if (ret == TRUE)
+ return;
+
+#ifndef NXAGENT_SERVER
+ xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
+ ret = check_all_screen_crtcs(slave, x, y);
+ if (ret == TRUE)
+ return;
+ }
+#endif /* !defined(NXAGENT_SERVER) */
+
+ /* if we're trying to escape, clamp to the CRTC we're coming from */
+ ret = constrain_all_screen_crtcs(
+#ifndef NXAGENT_SERVER
+ pDev,
+#endif /* !defined(NXAGENT_SERVER) */
+ pScreen, x, y);
+ if (ret == TRUE)
+ return;
+
+#ifndef NXAGENT_SERVER
+ xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
+ ret = constrain_all_screen_crtcs(pDev, slave, x, y);
+ if (ret == TRUE)
+ return;
+ }
+#endif /* !defined(NXAGENT_SERVER) */
+}
+
+Bool
+RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
+{
+ rrScrPriv(pDrawable->pScreen);
+ Bool ret = TRUE;
+ PixmapPtr *saved_scanout_pixmap;
+ int i;
+
+ saved_scanout_pixmap = xalloc(sizeof(PixmapPtr) * pScrPriv->numCrtcs);
+ if (saved_scanout_pixmap == NULL)
+ return FALSE;
+
+ for (i = 0; i < pScrPriv->numCrtcs; i++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[i];
+ Bool size_fits;
+
+ saved_scanout_pixmap[i] = crtc->scanout_pixmap;
+
+ if (!crtc->mode && enable)
+ continue;
+ if (!crtc->scanout_pixmap && !enable)
+ continue;
+
+ size_fits = (crtc->mode &&
+ crtc->x == pDrawable->x &&
+ crtc->y == pDrawable->y &&
+ crtc->mode->mode.width == pDrawable->width &&
+ crtc->mode->mode.height == pDrawable->height);
+
+ /* is the pixmap already set? */
+ if (crtc->scanout_pixmap == pPixmap) {
+ /* if its a disable then don't care about size */
+ if (enable == FALSE) {
+ /* set scanout to NULL */
+ crtc->scanout_pixmap = NULL;
+ }
+ else if (!size_fits) {
+ /* if the size no longer fits then drop off */
+ crtc->scanout_pixmap = NULL;
+ pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
+
+ (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
+ crtc->rotation, crtc->numOutputs, crtc->outputs);
+ saved_scanout_pixmap[i] = crtc->scanout_pixmap;
+ ret = FALSE;
+ }
+ else {
+ /* if the size fits then we are already setup */
+ }
+ }
+ else {
+ if (!size_fits)
+ ret = FALSE;
+ else if (enable)
+ crtc->scanout_pixmap = pPixmap;
+ else
+ /* reject an attempt to disable someone else's scanout_pixmap */
+ ret = FALSE;
+ }
+ }
+
+ for (i = 0; i < pScrPriv->numCrtcs; i++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[i];
+
+ if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
+ continue;
+
+ if (ret) {
+ pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
+
+ (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode,
+ crtc->x, crtc->y, crtc->rotation,
+ crtc->numOutputs, crtc->outputs);
+ }
+ else
+ crtc->scanout_pixmap = saved_scanout_pixmap[i];
+ }
+ xfree(saved_scanout_pixmap);
+
+ return ret;
+}