diff options
author | Keith Packard <keithp@keithp.com> | 2010-12-04 19:22:11 -0800 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2010-12-06 20:08:43 -0800 |
commit | d94a035ea9eb3167fc4f35b2d9f0d53f8807014c (patch) | |
tree | 2fb8a7dd45aab259a5570a17155cd5bc9d69d850 | |
parent | 66294afcab7b7a82f7dd897767e46c48a94b8ee8 (diff) |
randr: Implement RRSetCrtcConfigs
This provides a driver-independent implementation of the
RRSetCrtcConfigs API by simply using the existing interfaces.
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Aaron Plattner <aplattner@nvidia.com>
-rw-r--r-- | hw/xfree86/modes/xf86RandR12.c | 1 | ||||
-rw-r--r-- | randr/Makefile.am | 4 | ||||
-rw-r--r-- | randr/mirrcrtc.c | 169 | ||||
-rw-r--r-- | randr/randrstr.h | 90 | ||||
-rw-r--r-- | randr/rrcrtc.c | 512 | ||||
-rw-r--r-- | randr/rrscreen.c | 18 |
6 files changed, 750 insertions, 44 deletions
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c index bbf28cdb4..ac5813528 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 4b38e524b..a1c88dcb8 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 000000000..b1e2c9f34 --- /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 5e2a3518c..2fe960234 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 c2f696332..1f8f2e662 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 f58e6578a..62ea2b62f 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 |