[PATCH 3/6] randr: Implement RRSetCrtcConfigs

Keith Packard keithp at keithp.com
Sun Dec 5 14:22:49 PST 2010


This provides a driver-independent implementation of the
RRSetCrtcConfigs API by simply using the existing interfaces.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 hw/xfree86/modes/xf86RandR12.c |    1 +
 randr/Makefile.am              |    4 +-
 randr/mirrcrtc.c               |  169 +++++++++++++
 randr/randrstr.h               |   90 +++++++
 randr/rrcrtc.c                 |  512 ++++++++++++++++++++++++++++++++++++----
 randr/rrscreen.c               |   18 ++
 6 files changed, 750 insertions(+), 44 deletions(-)
 create mode 100644 randr/mirrcrtc.c

diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index bbf28cd..ac58135 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1797,6 +1797,7 @@ xf86RandR12Init12 (ScreenPtr pScreen)
     pScrn->PointerMoved = xf86RandR12PointerMoved;
     pScrn->ChangeGamma = xf86RandR12ChangeGamma;
     rp->rrSetCrtcSpriteTransform = xf86RandR14SetCrtcSpriteTransform;
+    rp->rrSetCrtcConfigs = miRRSetCrtcConfigs;
 
     randrp->orig_EnterVT = pScrn->EnterVT;
     pScrn->EnterVT = xf86RandR12EnterVT;
diff --git a/randr/Makefile.am b/randr/Makefile.am
index 4b38e52..a1c88dc 100644
--- a/randr/Makefile.am
+++ b/randr/Makefile.am
@@ -22,7 +22,9 @@ librandr_la_SOURCES =	\
 	rrsdispatch.c	\
 	rrsprite.c	\
 	rrtransform.h	\
-	rrtransform.c
+	rrtransform.c	\
+	mirrcrtc.c
+
 
 if XINERAMA
 librandr_la_SOURCES += ${XINERAMA_SRCS}
diff --git a/randr/mirrcrtc.c b/randr/mirrcrtc.c
new file mode 100644
index 0000000..b1e2c9f
--- /dev/null
+++ b/randr/mirrcrtc.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright © 2010 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "randrstr.h"
+
+Bool
+miRRSetScreenConfig(ScreenPtr screen,
+		    RRScreenConfigPtr screen_config)
+{
+    RRScreenConfigRec	old_screen_config;
+
+    /* XXX deal with separate pixmap/screen sizes */
+    if (screen_config->screen_pixmap_width != screen_config->screen_width ||
+	screen_config->screen_pixmap_height != screen_config->screen_height)
+	return FALSE;
+
+    RRScreenCurrentConfig(screen, &old_screen_config);
+
+    /* Check and see if nothing has changed */
+    if (old_screen_config.screen_width == screen_config->screen_width &&
+	old_screen_config.screen_height == screen_config->screen_height &&
+	old_screen_config.screen_pixmap_width == screen_config->screen_pixmap_width &&
+	old_screen_config.screen_pixmap_height == screen_config->screen_pixmap_height &&
+	old_screen_config.mm_width == screen_config->mm_width &&
+	old_screen_config.mm_height == screen_config->mm_height)
+	return TRUE;
+
+    return RRScreenSizeSet(screen,
+			   screen_config->screen_width,
+			   screen_config->screen_height,
+			   screen_config->mm_width,
+			   screen_config->mm_height);
+}
+
+Bool
+miRRSetCrtcConfig(RRCrtcConfigPtr crtc_config)
+{
+    int	x = crtc_config->x, y = crtc_config->y;
+
+    if (crtc_config->pixmap) {
+	x = crtc_config->pixmap_x;
+	y = crtc_config->pixmap_y;
+    }
+    return RRCrtcSet(crtc_config->crtc,
+		     crtc_config->mode,
+		     x,
+		     y,
+		     crtc_config->rotation,
+		     crtc_config->numOutputs,
+		     crtc_config->outputs);
+}
+
+Bool
+miRRDisableCrtc(RRCrtcPtr crtc)
+{
+    RRCrtcConfigRec	off_config;
+
+    memset(&off_config, '\0', sizeof (RRCrtcConfigRec));
+    off_config.crtc = crtc;
+    return miRRSetCrtcConfig(&off_config);
+}
+
+/*
+ * If the current crtc configuration doesn't fit
+ * with the new screen config, disable it
+ */
+Bool
+miRRCheckDisableCrtc(RRScreenConfigPtr new_screen_config,
+		     RRCrtcConfigPtr old_crtc_config)
+{
+    RRCrtcPtr crtc = old_crtc_config->crtc;
+
+    /* If it's already disabled, we're done */
+    if (!old_crtc_config->mode)
+	return TRUE;
+
+    /* If the crtc isn't scanning from the screen pixmap,
+     * we're done
+     */
+    if (old_crtc_config->pixmap)
+	return TRUE;
+
+    /* If the new screen configuration covers the existing CRTC space,
+     * we're done
+     */
+    if (RRScreenCoversCrtc(new_screen_config, old_crtc_config,
+			   &crtc->client_current_transform, NULL))
+	return TRUE;
+
+    /* Disable the crtc and let it get re-enabled */
+    return miRRDisableCrtc(crtc);
+}
+
+Bool
+miRRSetCrtcConfigs(ScreenPtr screen,
+		   RRScreenConfigPtr screen_config,
+		   RRCrtcConfigPtr crtc_configs,
+		   int num_configs)
+{
+    RRScreenConfigRec	old_screen_config;
+    RRCrtcConfigPtr	old_crtc_configs;
+    int			i;
+
+    /*
+     * Save existing state
+     */
+
+    RRScreenCurrentConfig(screen, &old_screen_config);
+    old_crtc_configs = calloc(num_configs, sizeof (RRCrtcConfigRec));
+    if (!old_crtc_configs)
+	return FALSE;
+
+    for (i = 0; i < num_configs; i++)
+	if (!RRCrtcCurrentConfig(crtc_configs[i].crtc, &old_crtc_configs[i]))
+	    goto fail_save;
+    /*
+     * Set the new configuration. If anything goes wrong,
+     * bail and restore the old configuration
+     */
+    for (i = 0; i < num_configs; i++)
+	if (!miRRCheckDisableCrtc(screen_config, &old_crtc_configs[i]))
+	    goto fail_disable;
+
+    if (!miRRSetScreenConfig(screen, screen_config))
+	goto fail_set_screen;
+
+    for (i = 0; i < num_configs; i++)
+	if (!miRRSetCrtcConfig(&crtc_configs[i]))
+	    goto fail_set_crtc;
+
+    RRFreeCrtcConfigs(old_crtc_configs, num_configs);
+    return TRUE;
+
+fail_set_crtc:
+    /*
+     * Restore the previous configuration. Ignore any errors
+     * as we just need to hope that the driver can manage to
+     * get back to the previous state without trouble.
+     */
+    for (i = 0; i < num_configs; i++)
+	(void) miRRDisableCrtc(old_crtc_configs[i].crtc);
+    (void) miRRSetScreenConfig(screen, &old_screen_config);
+fail_set_screen:
+fail_disable:
+    for (i = 0; i < num_configs; i++)
+	(void) miRRSetCrtcConfig(&old_crtc_configs[i]);
+fail_save:
+    RRFreeCrtcConfigs(old_crtc_configs, num_configs);
+    return FALSE;
+}
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 5e2a351..2fe9602 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -78,6 +78,8 @@ typedef struct _rrMode		RRModeRec, *RRModePtr;
 typedef struct _rrPropertyValue	RRPropertyValueRec, *RRPropertyValuePtr;
 typedef struct _rrProperty	RRPropertyRec, *RRPropertyPtr;
 typedef struct _rrCrtc		RRCrtcRec, *RRCrtcPtr;
+typedef struct _rrScreenConfig	RRScreenConfigRec, *RRScreenConfigPtr;
+typedef struct _rrCrtcConfig	RRCrtcConfigRec, *RRCrtcConfigPtr;
 typedef struct _rrOutput	RROutputRec, *RROutputPtr;
 
 struct _rrMode {
@@ -135,6 +137,28 @@ struct _rrCrtc {
     struct pict_f_transform f_sprite_image_inverse;	/* image from crtc */
 };
 
+struct _rrScreenConfig {
+    CARD16			screen_pixmap_width;
+    CARD16			screen_pixmap_height;
+    CARD16			screen_width;
+    CARD16			screen_height;
+    CARD32			mm_width;
+    CARD32			mm_height;
+};
+
+struct _rrCrtcConfig {
+    RRCrtcPtr			crtc;
+    int				x, y;
+    RRModePtr			mode;
+    Rotation			rotation;
+    int				numOutputs;
+    RROutputPtr			*outputs;
+    struct pict_f_transform	sprite_position_transform;
+    struct pict_f_transform	sprite_image_transform;
+    PixmapPtr			pixmap;
+    int				pixmap_x, pixmap_y;
+};
+
 struct _rrOutput {
     RROutput	    id;
     ScreenPtr	    pScreen;
@@ -251,6 +275,11 @@ typedef void (*RRGetCrtcSpriteTransformPtr) (ScreenPtr pScreen,
 					     struct pict_f_transform *position_transform,
 					     struct pict_f_transform *image_transform);
 
+typedef Bool (*RRSetCrtcConfigsPtr) (ScreenPtr screen,
+				     RRScreenConfigPtr screen_config,
+				     RRCrtcConfigPtr crtc_configs,
+				     int num_configs);
+
 typedef struct _rrScrPriv {
     /*
      * 'public' part of the structure; DDXen fill this in
@@ -276,6 +305,7 @@ typedef struct _rrScrPriv {
 #endif
     RRSetCrtcSpriteTransformPtr	rrSetCrtcSpriteTransform;
     RRGetCrtcSpriteTransformPtr	rrGetCrtcSpriteTransform;
+    RRSetCrtcConfigsPtr rrSetCrtcConfigs;
 
     /*
      * Private part of the structure; not considered part of the ABI
@@ -428,6 +458,10 @@ RRScreenSizeSet (ScreenPtr  pScreen,
 		 CARD32	    mmWidth,
 		 CARD32	    mmHeight);
 
+extern _X_EXPORT void
+RRScreenCurrentConfig(ScreenPtr screen,
+		      RRScreenConfigPtr screen_config);
+
 /*
  * Send ConfigureNotify event to root window when 'something' happens
  */
@@ -671,6 +705,38 @@ extern _X_EXPORT void
 RRCrtcInitErrorValue (void);
 
 /*
+ * Free a set of crtc configs and their attached output arrays
+ */
+void
+RRFreeCrtcConfigs(RRCrtcConfigPtr configs, int num_configs);
+
+/*
+ * Convert the current crtc configuration into an RRCrtcConfig
+ */
+extern _X_EXPORT Bool
+RRCrtcCurrentConfig(RRCrtcPtr crtc,
+		    RRCrtcConfigPtr crtc_config);
+
+/*
+ * Figure out whether the specific crtc_config can fit
+ * within the screen_config
+ */
+Bool
+RRScreenCoversCrtc(RRScreenConfigPtr screen_config,
+		   RRCrtcConfigPtr crtc_config,
+		   RRTransformPtr client_transform,
+		   XID *errorValue);
+
+/*
+ * Set a screen and set of crtc configurations in one operation
+ */
+Bool
+RRSetCrtcConfigs(ScreenPtr screen,
+		 RRScreenConfigPtr screen_config,
+		 RRCrtcConfigPtr crtc_configs,
+		 int num_configs);
+
+/*
  * Crtc dispatch
  */
 
@@ -695,6 +761,9 @@ ProcRRSetCrtcTransform (ClientPtr client);
 extern _X_EXPORT int
 ProcRRGetCrtcTransform (ClientPtr client);
 
+extern _X_EXPORT int
+ProcRRSetCrtcConfigs (ClientPtr client);
+
 int
 ProcRRGetPanning (ClientPtr client);
 
@@ -916,6 +985,27 @@ extern _X_EXPORT void
 RRXineramaExtensionInit(void);
 #endif
 
+/* mirrcrtc.c */
+Bool
+miRRSetScreenConfig(ScreenPtr screen,
+		    RRScreenConfigPtr screen_config);
+
+Bool
+miRRSetCrtcConfig(RRCrtcConfigPtr crtc_config);
+
+Bool
+miRRDisableCrtc(RRCrtcPtr crtc);
+
+Bool
+miRRCheckDisableCrtc(RRScreenConfigPtr new_screen_config,
+		     RRCrtcConfigPtr old_crtc_config);
+
+Bool
+miRRSetCrtcConfigs(ScreenPtr screen,
+		   RRScreenConfigPtr screen_config,
+		   RRCrtcConfigPtr crtc_configs,
+		   int num_configs);
+
 #endif /* _RANDRSTR_H_ */
 
 /*
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index c2f6963..1f8f2e6 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -37,7 +37,7 @@ RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
     if (pScreen)
     {
 	rrScrPriv(pScreen);
-    
+
 	pScrPriv->changed = TRUE;
 	/*
 	 * Send ConfigureNotify on any layout change
@@ -59,19 +59,19 @@ RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
 
     if (!RRInit())
 	return NULL;
-    
+
     pScrPriv = rrGetScrPriv(pScreen);
 
     /* make space for the crtc pointer */
     if (pScrPriv->numCrtcs)
-	crtcs = realloc(pScrPriv->crtcs, 
+	crtcs = realloc(pScrPriv->crtcs,
 			  (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
     else
 	crtcs = malloc(sizeof (RRCrtcPtr));
     if (!crtcs)
 	return FALSE;
     pScrPriv->crtcs = crtcs;
-    
+
     crtc = calloc(1, sizeof (RRCrtcRec));
     if (!crtc)
 	return NULL;
@@ -90,6 +90,8 @@ RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
     crtc->devPrivate = devPrivate;
     RRTransformInit (&crtc->client_pending_transform);
     RRTransformInit (&crtc->client_current_transform);
+    pixman_transform_init_identity (&crtc->client_sprite_position_transform);
+    pixman_transform_init_identity (&crtc->client_sprite_image_transform);
     pixman_transform_init_identity (&crtc->transform);
     pixman_f_transform_init_identity (&crtc->f_transform);
     pixman_f_transform_init_identity (&crtc->f_inverse);
@@ -102,7 +104,7 @@ RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
     /* attach the screen and crtc together */
     crtc->pScreen = pScreen;
     pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
-    
+
     return crtc;
 }
 
@@ -139,7 +141,7 @@ RRCrtcNotify (RRCrtcPtr	    crtc,
 	      RROutputPtr   *outputs)
 {
     int	    i, j;
-    
+
     /*
      * Check to see if any of the new outputs were
      * not in the old list and mark them as changed
@@ -179,7 +181,7 @@ RRCrtcNotify (RRCrtcPtr	    crtc,
     if (numOutputs != crtc->numOutputs)
     {
 	RROutputPtr *newoutputs;
-	
+
 	if (numOutputs)
 	{
 	    if (crtc->numOutputs)
@@ -258,7 +260,7 @@ RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
     rrScrPriv (pScreen);
     xRRCrtcChangeNotifyEvent	ce;
     RRModePtr	mode = crtc->mode;
-    
+
     ce.type = RRNotify + RREventBase;
     ce.subCode = RRNotify_CrtcChange;
     ce.timestamp = pScrPriv->lastSetTime.milliseconds;
@@ -333,7 +335,7 @@ RRCrtcSet (RRCrtcPtr    crtc,
 #if RANDR_12_INTERFACE
 	if (pScrPriv->rrCrtcSet)
 	{
-	    ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 
+	    ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
 					  rotation, numOutputs, outputs);
 	}
 	else
@@ -392,6 +394,59 @@ RRCrtcSet (RRCrtcPtr    crtc,
     return ret;
 }
 
+void
+RRFreeCrtcConfigs(RRCrtcConfigPtr configs, int num_configs)
+{
+    int	i;
+
+    for (i = 0; i < num_configs; i++)
+	free(configs[i].outputs);
+    free(configs);
+}
+
+Bool
+RRCrtcCurrentConfig(RRCrtcPtr crtc,
+		    RRCrtcConfigPtr crtc_config)
+{
+    crtc_config->crtc = crtc;
+    crtc_config->x = crtc->x;
+    crtc_config->y = crtc->y;
+    crtc_config->mode = crtc->mode;
+    crtc_config->rotation = crtc->rotation;
+    crtc_config->numOutputs = crtc->numOutputs;
+    crtc_config->outputs = calloc(crtc->numOutputs, sizeof (RROutputPtr));
+    if (!crtc_config->outputs)
+	return FALSE;
+    memcpy(crtc_config->outputs, crtc->outputs, crtc->numOutputs * sizeof (RROutputPtr));
+    crtc_config->sprite_position_transform = crtc->client_sprite_f_position_transform;
+    crtc_config->sprite_image_transform = crtc->client_sprite_f_image_transform;
+
+    /* XXX add pixmap stuff */
+    crtc_config->pixmap = NULL;
+    crtc_config->pixmap_x = 0;
+    crtc_config->pixmap_y = 0;
+    return TRUE;
+}
+
+
+/*
+ * Request that a set of crtcs be configured at the same
+ * time on a single screen
+ */
+
+Bool
+RRSetCrtcConfigs(ScreenPtr screen,
+		 RRScreenConfigPtr screen_config,
+		 RRCrtcConfigPtr crtc_configs,
+		 int num_configs)
+{
+    rrScrPrivPtr	scr_priv = rrGetScrPriv(screen);
+
+    if (!scr_priv)
+	return FALSE;
+    return (*scr_priv->rrSetCrtcConfigs)(screen, screen_config, crtc_configs, num_configs);
+}
+
 /*
  * Return crtc transform
  */
@@ -435,7 +490,7 @@ RRCrtcDestroyResource (pointer value, XID pid)
     {
 	rrScrPriv(pScreen);
 	int		i;
-    
+
 	for (i = 0; i < pScrPriv->numCrtcs; i++)
 	{
 	    if (pScrPriv->crtcs[i] == crtc)
@@ -468,7 +523,7 @@ RRCrtcGammaSet (RRCrtcPtr   crtc,
 #if RANDR_12_INTERFACE
     ScreenPtr	pScreen = crtc->pScreen;
 #endif
-    
+
     memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
     memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
     memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
@@ -631,6 +686,44 @@ RRCrtcTransformSet (RRCrtcPtr		crtc,
 }
 
 /*
+ * Figure out whether the specific crtc_config can fit
+ * within the screen_config
+ */
+Bool
+RRScreenCoversCrtc(RRScreenConfigPtr screen_config,
+		   RRCrtcConfigPtr crtc_config,
+		   RRTransformPtr client_transform,
+		   XID *errorValue)
+{
+    int source_width;
+    int	source_height;
+    struct pixman_f_transform f_transform;
+
+    RRTransformCompute (crtc_config->x, crtc_config->y,
+			crtc_config->mode->mode.width, crtc_config->mode->mode.height,
+			crtc_config->rotation,
+			client_transform,
+			&crtc_config->sprite_position_transform,
+			&crtc_config->sprite_image_transform,
+			NULL, &f_transform, NULL, NULL, NULL, NULL);
+
+    RRModeGetScanoutSize (crtc_config->mode, &f_transform,
+			  &source_width, &source_height);
+    if (crtc_config->x + source_width > screen_config->screen_pixmap_width) {
+	if (errorValue)
+	    *errorValue = crtc_config->x;
+	return FALSE;
+    }
+
+    if (crtc_config->y + source_height > screen_config->screen_pixmap_height) {
+	if (errorValue)
+	    *errorValue = crtc_config->y;
+	return FALSE;
+    }
+    return TRUE;
+}
+
+/*
  * Initialize crtc type
  */
 Bool
@@ -639,7 +732,7 @@ RRCrtcInit (void)
     RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC");
     if (!RRCrtcType)
 	return FALSE;
-    
+
     return TRUE;
 }
 
@@ -668,7 +761,7 @@ ProcRRGetCrtcInfo (ClientPtr client)
     int				i, j, k, n;
     int				width, height;
     BoxRec			panned_area;
-    
+
     REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
@@ -679,7 +772,7 @@ ProcRRGetCrtcInfo (ClientPtr client)
     pScrPriv = rrGetScrPriv(pScreen);
 
     mode = crtc->mode;
-    
+
     rep.type = X_Reply;
     rep.status = RRSetConfigSuccess;
     rep.sequenceNumber = client->sequence;
@@ -712,7 +805,7 @@ ProcRRGetCrtcInfo (ClientPtr client)
 	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
 		k++;
     rep.nPossibleOutput = k;
-    
+
     rep.length = rep.nOutput + rep.nPossibleOutput;
 
     extraLen = rep.length << 2;
@@ -727,7 +820,7 @@ ProcRRGetCrtcInfo (ClientPtr client)
 
     outputs = (RROutput *) extra;
     possible = (RROutput *) (outputs + rep.nOutput);
-    
+
     for (i = 0; i < crtc->numOutputs; i++)
     {
 	outputs[i] = crtc->outputs[i]->id;
@@ -744,7 +837,7 @@ ProcRRGetCrtcInfo (ClientPtr client)
 		    swapl (&possible[k], n);
 		k++;
 	    }
-    
+
     if (client->swapped) {
 	swaps(&rep.sequenceNumber, n);
 	swapl(&rep.length, n);
@@ -765,7 +858,7 @@ ProcRRGetCrtcInfo (ClientPtr client)
 	WriteToClient (client, extraLen, (char *) extra);
 	free(extra);
     }
-    
+
     return Success;
 }
 
@@ -785,10 +878,10 @@ ProcRRSetCrtcConfig (ClientPtr client)
     TimeStamp		    time;
     Rotation		    rotation;
     int			    rc, i, j;
-    
+
     REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
     numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq)));
-    
+
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
 
     if (stuff->mode == None)
@@ -811,7 +904,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
     }
     else
 	outputs = NULL;
-    
+
     outputIds = (RROutput *) (stuff + 1);
     for (i = 0; i < numOutputs; i++)
     {
@@ -834,7 +927,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
 	/* validate mode for this output */
 	for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
 	{
-	    RRModePtr	m = (j < outputs[i]->numModes ? 
+	    RRModePtr	m = (j < outputs[i]->numModes ?
 			     outputs[i]->modes[j] :
 			     outputs[i]->userModes[j - outputs[i]->numModes]);
 	    if (m == mode)
@@ -869,17 +962,17 @@ ProcRRSetCrtcConfig (ClientPtr client)
 
     pScreen = crtc->pScreen;
     pScrPriv = rrGetScrPriv(pScreen);
-    
+
     time = ClientTimeToServerTime(stuff->timestamp);
     configTime = ClientTimeToServerTime(stuff->configTimestamp);
-    
+
     if (!pScrPriv)
     {
 	time = currentTime;
 	rep.status = RRSetConfigFailed;
 	goto sendReply;
     }
-    
+
     /*
      * Validate requested rotation
      */
@@ -912,7 +1005,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
 	    free(outputs);
 	    return BadMatch;
 	}
-    
+
 #ifdef RANDR_12_INTERFACE
 	/*
 	 * Check screen size bounds if the DDX provides a 1.2 interface
@@ -944,7 +1037,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
 		free(outputs);
 		return BadValue;
 	    }
-	    
+
 	    if (stuff->y + source_height > pScreen->height)
 	    {
 		client->errorValue = stuff->y;
@@ -954,7 +1047,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
 	}
 #endif
     }
-    
+
     if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
 		   rotation, numOutputs, outputs))
     {
@@ -963,17 +1056,17 @@ ProcRRSetCrtcConfig (ClientPtr client)
     }
     rep.status = RRSetConfigSuccess;
     pScrPriv->lastSetTime = time;
-    
+
 sendReply:
     free(outputs);
-    
+
     rep.type = X_Reply;
     /* rep.status has already been filled in */
     rep.length = 0;
     rep.sequenceNumber = client->sequence;
     rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
 
-    if (client->swapped) 
+    if (client->swapped)
     {
 	int n;
     	swaps(&rep.sequenceNumber, n);
@@ -981,7 +1074,7 @@ sendReply:
 	swapl(&rep.newTimestamp, n);
     }
     WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
-    
+
     return Success;
 }
 
@@ -997,7 +1090,7 @@ ProcRRGetPanning (ClientPtr client)
     BoxRec		tracking;
     INT16		border[4];
     int			n;
-    
+
     REQUEST_SIZE_MATCH(xRRGetPanningReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
@@ -1067,7 +1160,7 @@ ProcRRSetPanning (ClientPtr client)
     BoxRec		tracking;
     INT16		border[4];
     int			n;
-    
+
     REQUEST_SIZE_MATCH(xRRSetPanningReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
@@ -1082,9 +1175,9 @@ ProcRRSetPanning (ClientPtr client)
 	rep.status = RRSetConfigFailed;
 	goto sendReply;
     }
-    
+
     time = ClientTimeToServerTime(stuff->timestamp);
-    
+
     if (!pScrPriv->rrGetPanning)
 	return RRErrorBase + BadRRCrtc;
 
@@ -1160,7 +1253,7 @@ ProcRRGetCrtcGamma (ClientPtr client)
     int				n;
     unsigned long		len;
     char			*extra = NULL;
-    
+
     REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
@@ -1169,7 +1262,7 @@ ProcRRGetCrtcGamma (ClientPtr client)
         return RRErrorBase + BadRRCrtc;
 
     len = crtc->gammaSize * 3 * 2;
-    
+
     if (crtc->gammaSize) {
 	extra = malloc(len);
 	if (!extra)
@@ -1203,21 +1296,21 @@ ProcRRSetCrtcGamma (ClientPtr client)
     RRCrtcPtr			crtc;
     unsigned long		len;
     CARD16			*red, *green, *blue;
-    
+
     REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-    
+
     len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq));
     if (len < (stuff->size * 3 + 1) >> 1)
 	return BadLength;
 
     if (stuff->size != crtc->gammaSize)
 	return BadMatch;
-    
+
     red = (CARD16 *) (stuff + 1);
     green = red + crtc->gammaSize;
     blue = green + crtc->gammaSize;
-    
+
     RRCrtcGammaSet (crtc, red, green, blue);
 
     return Success;
@@ -1258,7 +1351,7 @@ ProcRRSetCrtcTransform (ClientPtr client)
 
 
 #define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
-				
+
 static int
 transform_filter_length (RRTransformPtr transform)
 {
@@ -1360,3 +1453,336 @@ ProcRRGetCrtcTransform (ClientPtr client)
     free(reply);
     return Success;
 }
+
+static void
+pixman_f_transform_from_xRenderTransform(struct pixman_f_transform *f_transform,
+					 xRenderTransform *x_transform)
+{
+    struct pixman_transform	transform;
+    PictTransform_from_xRenderTransform(&transform, x_transform);
+    pixman_f_transform_from_pixman_transform(f_transform, &transform);
+}
+
+static int
+RRConvertCrtcConfig(ClientPtr client, ScreenPtr screen,
+		    RRScreenConfigPtr screen_config,
+		    RRCrtcConfigPtr config, xRRCrtcConfig *x,
+		    RROutput *outputIds)
+{
+    RRCrtcPtr		crtc;
+    RROutputPtr		*outputs;
+    rrScrPrivPtr	scr_priv;
+    RRModePtr		mode;
+    PixmapPtr		pixmap;
+    int			rc, i, j;
+    Rotation		rotation;
+
+    VERIFY_RR_CRTC(x->crtc, crtc, DixSetAttrAccess);
+
+    if (x->mode == None)
+    {
+	mode = NULL;
+	if (x->nOutput > 0)
+	    return BadMatch;
+    }
+    else
+    {
+	VERIFY_RR_MODE(x->mode, mode, DixSetAttrAccess);
+	if (x->nOutput == 0)
+	    return BadMatch;
+    }
+    if (x->nOutput)
+    {
+	outputs = malloc(x->nOutput * sizeof (RROutputPtr));
+	if (!outputs)
+	    return BadAlloc;
+    }
+    else
+	outputs = NULL;
+
+    if (x->pixmap == None)
+	pixmap = NULL;
+    else
+    {
+	rc = dixLookupResourceByType((pointer *) &pixmap, x->pixmap,
+				     RT_PIXMAP, client, DixWriteAccess);
+	if (rc != Success) {
+	    free(outputs);
+	    return rc;
+	}
+	/* XXX check to make sure this is a scanout pixmap */
+    }
+
+    for (i = 0; i < x->nOutput; i++)
+    {
+	rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i],
+				     RROutputType, client, DixSetAttrAccess);
+	if (rc != Success)
+	{
+	    free(outputs);
+	    return rc;
+	}
+	/* 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)
+	{
+	    free(outputs);
+	    return BadMatch;
+	}
+	/* validate mode for this output */
+	for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
+	{
+	    RRModePtr	m = (j < outputs[i]->numModes ?
+			     outputs[i]->modes[j] :
+			     outputs[i]->userModes[j - outputs[i]->numModes]);
+	    if (m == mode)
+		break;
+	}
+	if (j == outputs[i]->numModes + outputs[i]->numUserModes)
+	{
+	    free(outputs);
+	    return BadMatch;
+	}
+    }
+    /* validate clones */
+    for (i = 0; i < x->nOutput; i++)
+    {
+	for (j = 0; j < x->nOutput; j++)
+	{
+	    int k;
+	    if (i == j)
+		continue;
+	    for (k = 0; k < outputs[i]->numClones; k++)
+	    {
+		if (outputs[i]->clones[k] == outputs[j])
+		    break;
+	    }
+	    if (k == outputs[i]->numClones)
+	    {
+		free(outputs);
+		return BadMatch;
+	    }
+	}
+    }
+
+    if (crtc->pScreen != screen)
+	return BadMatch;
+
+    scr_priv = rrGetScrPriv(screen);
+
+    config->crtc = crtc;
+    config->x = x->x;
+    config->y = x->y;
+    config->mode = mode;
+    config->rotation = x->rotation;
+    config->numOutputs = x->nOutput;
+    config->outputs = outputs;
+    pixman_f_transform_from_xRenderTransform(&config->sprite_position_transform,
+					     &x->spritePositionTransform);
+    pixman_f_transform_from_xRenderTransform(&config->sprite_image_transform,
+					     &x->spriteImageTransform);
+    config->pixmap = pixmap;
+    config->pixmap_x = x->xPixmap;
+    config->pixmap_y = x->yPixmap;
+
+    /*
+     * Validate requested rotation
+     */
+    rotation = (Rotation) x->rotation;
+
+    /* test the rotation bits only! */
+    switch (rotation & 0xf) {
+    case RR_Rotate_0:
+    case RR_Rotate_90:
+    case RR_Rotate_180:
+    case RR_Rotate_270:
+	break;
+    default:
+	/*
+	 * Invalid rotation
+	 */
+	client->errorValue = x->rotation;
+	free(outputs);
+	return BadValue;
+    }
+
+    if (mode)
+    {
+	if ((~crtc->rotations) & rotation)
+	{
+	    /*
+	     * requested rotation or reflection not supported by screen
+	     */
+	    client->errorValue = x->rotation;
+	    free(outputs);
+	    return BadMatch;
+	}
+
+	/*
+	 * If scanning out from another pixmap, make sure the mode
+	 * fits
+	 */
+	if (pixmap)
+	{
+	    if (x->xPixmap + mode->mode.width > pixmap->drawable.width) {
+		client->errorValue = x->xPixmap;
+		free(outputs);
+		return BadValue;
+	    }
+	    if (x->yPixmap + mode->mode.height > pixmap->drawable.height) {
+		client->errorValue = x->yPixmap;
+		free(outputs);
+		return BadValue;
+	    }
+	}
+	/*
+	 * 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. 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.
+	 */
+	else if (scr_priv->rrScreenSetSize && !crtc->transforms)
+	{
+	    if (!RRScreenCoversCrtc(screen_config, config,
+				    &crtc->client_pending_transform,
+				    &client->errorValue))
+	    {
+		free(outputs);
+		return BadValue;
+	    }
+	}
+    }
+
+    return Success;
+}
+
+int
+ProcRRSetCrtcConfigs (ClientPtr client)
+{
+    REQUEST(xRRSetCrtcConfigsReq);
+    xRRSetCrtcConfigsReply  rep;
+    DrawablePtr		    drawable;
+    ScreenPtr		    screen;
+    rrScrPrivPtr	    scr_priv;
+    xRRCrtcConfig	    *x_configs;
+    RRScreenConfigRec	    screen_config;
+    RRCrtcConfigPtr	    configs;
+    RROutput		    *output_ids;
+    int			    num_configs;
+    int			    rc, i;
+    int			    extra_len;
+    int			    num_output_ids;
+
+    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigsReq);
+
+    extra_len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcConfigsReq));
+
+    num_configs = stuff->nConfigs;
+
+    /* Check request length against number of configs specified */
+    if (num_configs * (sizeof (xRRCrtcConfig) >> 2) > extra_len)
+	return BadLength;
+
+    extra_len -= num_configs * (sizeof (xRRCrtcConfig) >> 2);
+    x_configs = (xRRCrtcConfig *) (stuff + 1);
+
+    /* Check remaining request length against number of outputs */
+    num_output_ids = 0;
+    for (i = 0; i < num_configs; i++)
+	num_output_ids += x_configs[i].nOutput;
+
+    if (extra_len != num_output_ids)
+	return BadLength;
+
+    rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixGetAttrAccess);
+    if (rc != Success)
+	return rc;
+
+    screen = drawable->pScreen;
+
+    scr_priv = rrGetScrPriv(screen);
+
+    if (!scr_priv)
+    {
+	rep.status = RRSetConfigFailed;
+	goto sendReply;
+    }
+
+    if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0)
+    {
+	client->errorValue = 0;
+	return BadValue;
+    }
+
+    if (stuff->screenPixmapWidth < scr_priv->minWidth ||
+	scr_priv->maxWidth < stuff->screenPixmapWidth)
+    {
+	client->errorValue = stuff->screenPixmapWidth;
+	return BadValue;
+    }
+    if (stuff->screenPixmapHeight < scr_priv->minHeight ||
+	scr_priv->maxHeight < stuff->screenPixmapHeight)
+    {
+	client->errorValue = stuff->screenPixmapHeight;
+	return BadValue;
+    }
+
+    screen_config.screen_pixmap_width = stuff->screenPixmapWidth;
+    screen_config.screen_pixmap_height = stuff->screenPixmapHeight;
+    screen_config.screen_width = stuff->screenWidth;
+    screen_config.screen_height = stuff->screenHeight;
+    screen_config.mm_width = stuff->widthInMillimeters;
+    screen_config.mm_height = stuff->heightInMillimeters;
+
+    if (num_configs == 0)
+	return Success;
+
+    output_ids = (RROutput *) (x_configs + num_configs);
+
+    /*
+     * Convert protocol crtc configurations into
+     * server crtc configurations
+     */
+    configs = calloc(num_configs, sizeof (RRCrtcConfigRec));
+    if (!configs)
+	return BadAlloc;
+    for (i = 0; i < num_configs; i++) {
+	rc = RRConvertCrtcConfig(client, screen, &screen_config,
+				 &configs[i],
+				 &x_configs[i], output_ids);
+	if (rc != Success) {
+	    rep.status = RRSetConfigFailed;
+	    goto sendReply;
+	}
+	output_ids += x_configs[i].nOutput;
+    }
+
+    if (!RRSetCrtcConfigs (screen, &screen_config, configs, num_configs))
+    {
+	rep.status = RRSetConfigFailed;
+	goto sendReply;
+    }
+    rep.status = RRSetConfigSuccess;
+    scr_priv->lastSetTime = currentTime;
+
+sendReply:
+    RRFreeCrtcConfigs(configs, num_configs);
+
+    rep.type = X_Reply;
+    /* rep.status has already been filled in */
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+
+    if (client->swapped)
+    {
+	int n;
+	swaps(&rep.sequenceNumber, n);
+	swapl(&rep.length, n);
+    }
+    WriteToClient(client, sizeof(xRRSetCrtcConfigsReply), (char *)&rep);
+
+    return Success;
+}
diff --git a/randr/rrscreen.c b/randr/rrscreen.c
index f58e657..62ea2b6 100644
--- a/randr/rrscreen.c
+++ b/randr/rrscreen.c
@@ -191,6 +191,24 @@ RRScreenSizeSet (ScreenPtr  pScreen,
 }
 
 /*
+ * Compute an RRScreenConfig from the current screen information
+ */
+void
+RRScreenCurrentConfig(ScreenPtr screen,
+		      RRScreenConfigPtr screen_config)
+{
+    PixmapPtr		screen_pixmap = screen->GetScreenPixmap(screen);
+    WindowPtr		root = screen->root;
+
+    screen_config->screen_pixmap_width = screen_pixmap->drawable.width;
+    screen_config->screen_pixmap_height = screen_pixmap->drawable.height;
+    screen_config->screen_width = root->drawable.width;
+    screen_config->screen_height = root->drawable.height;
+    screen_config->mm_width = screen->mmWidth;
+    screen_config->mm_height = screen->mmHeight;
+}
+
+/*
  * Retrieve valid screen size range
  */
 int
-- 
1.7.2.3



More information about the xorg-devel mailing list