105b261ecSmrg/* 205b261ecSmrg * Copyright © 2006 Keith Packard 335c4bbdfSmrg * Copyright 2010 Red Hat, Inc 405b261ecSmrg * 505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 705b261ecSmrg * the above copyright notice appear in all copies and that both that copyright 805b261ecSmrg * notice and this permission notice appear in supporting documentation, and 905b261ecSmrg * that the name of the copyright holders not be used in advertising or 1005b261ecSmrg * publicity pertaining to distribution of the software without specific, 1105b261ecSmrg * written prior permission. The copyright holders make no representations 1205b261ecSmrg * about the suitability of this software for any purpose. It is provided "as 1305b261ecSmrg * is" without express or implied warranty. 1405b261ecSmrg * 1505b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1705b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2105b261ecSmrg * OF THIS SOFTWARE. 2205b261ecSmrg */ 2305b261ecSmrg 2405b261ecSmrg#include "randrstr.h" 2505b261ecSmrg#include "swaprep.h" 2635c4bbdfSmrg#include "mipointer.h" 2705b261ecSmrg 281b5d61b8Smrg#include <X11/Xatom.h> 291b5d61b8Smrg 30a035e2b2SmrgRESTYPE RRCrtcType = 0; 3105b261ecSmrg 3205b261ecSmrg/* 3305b261ecSmrg * Notify the CRTC of some change 3405b261ecSmrg */ 3505b261ecSmrgvoid 3635c4bbdfSmrgRRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged) 3705b261ecSmrg{ 3835c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 3905b261ecSmrg 4005b261ecSmrg crtc->changed = TRUE; 4135c4bbdfSmrg if (pScreen) { 4235c4bbdfSmrg rrScrPriv(pScreen); 4335c4bbdfSmrg 4435c4bbdfSmrg RRSetChanged(pScreen); 4535c4bbdfSmrg /* 4635c4bbdfSmrg * Send ConfigureNotify on any layout change 4735c4bbdfSmrg */ 4835c4bbdfSmrg if (layoutChanged) 4935c4bbdfSmrg pScrPriv->layoutChanged = TRUE; 5005b261ecSmrg } 5105b261ecSmrg} 5205b261ecSmrg 5305b261ecSmrg/* 5405b261ecSmrg * Create a CRTC 5505b261ecSmrg */ 5605b261ecSmrgRRCrtcPtr 5735c4bbdfSmrgRRCrtcCreate(ScreenPtr pScreen, void *devPrivate) 5805b261ecSmrg{ 5935c4bbdfSmrg RRCrtcPtr crtc; 6035c4bbdfSmrg RRCrtcPtr *crtcs; 6135c4bbdfSmrg rrScrPrivPtr pScrPriv; 6205b261ecSmrg 6305b261ecSmrg if (!RRInit()) 6435c4bbdfSmrg return NULL; 6535c4bbdfSmrg 6605b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 6705b261ecSmrg 6805b261ecSmrg /* make space for the crtc pointer */ 691b5d61b8Smrg crtcs = reallocarray(pScrPriv->crtcs, 701b5d61b8Smrg pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr)); 7105b261ecSmrg if (!crtcs) 721b5d61b8Smrg return NULL; 7305b261ecSmrg pScrPriv->crtcs = crtcs; 7435c4bbdfSmrg 7535c4bbdfSmrg crtc = calloc(1, sizeof(RRCrtcRec)); 7605b261ecSmrg if (!crtc) 7735c4bbdfSmrg return NULL; 7835c4bbdfSmrg crtc->id = FakeClientID(0); 7905b261ecSmrg crtc->pScreen = pScreen; 8005b261ecSmrg crtc->mode = NULL; 8105b261ecSmrg crtc->x = 0; 8205b261ecSmrg crtc->y = 0; 8305b261ecSmrg crtc->rotation = RR_Rotate_0; 8405b261ecSmrg crtc->rotations = RR_Rotate_0; 8505b261ecSmrg crtc->outputs = NULL; 8605b261ecSmrg crtc->numOutputs = 0; 8705b261ecSmrg crtc->gammaSize = 0; 8805b261ecSmrg crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL; 8905b261ecSmrg crtc->changed = FALSE; 9005b261ecSmrg crtc->devPrivate = devPrivate; 9135c4bbdfSmrg RRTransformInit(&crtc->client_pending_transform); 9235c4bbdfSmrg RRTransformInit(&crtc->client_current_transform); 9335c4bbdfSmrg pixman_transform_init_identity(&crtc->transform); 9435c4bbdfSmrg pixman_f_transform_init_identity(&crtc->f_transform); 9535c4bbdfSmrg pixman_f_transform_init_identity(&crtc->f_inverse); 9605b261ecSmrg 9735c4bbdfSmrg if (!AddResource(crtc->id, RRCrtcType, (void *) crtc)) 9835c4bbdfSmrg return NULL; 9905b261ecSmrg 10005b261ecSmrg /* attach the screen and crtc together */ 10105b261ecSmrg crtc->pScreen = pScreen; 10205b261ecSmrg pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc; 10335c4bbdfSmrg 10435c4bbdfSmrg RRResourcesChanged(pScreen); 10535c4bbdfSmrg 10605b261ecSmrg return crtc; 10705b261ecSmrg} 10805b261ecSmrg 10905b261ecSmrg/* 11005b261ecSmrg * Set the allowed rotations on a CRTC 11105b261ecSmrg */ 11205b261ecSmrgvoid 11335c4bbdfSmrgRRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations) 11405b261ecSmrg{ 11505b261ecSmrg crtc->rotations = rotations; 11605b261ecSmrg} 11705b261ecSmrg 1184642e01fSmrg/* 1194642e01fSmrg * Set whether transforms are allowed on a CRTC 1204642e01fSmrg */ 1214642e01fSmrgvoid 12235c4bbdfSmrgRRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms) 1234642e01fSmrg{ 1244642e01fSmrg crtc->transforms = transforms; 1254642e01fSmrg} 1264642e01fSmrg 12705b261ecSmrg/* 12805b261ecSmrg * Notify the extension that the Crtc has been reconfigured, 12905b261ecSmrg * the driver calls this whenever it has updated the mode 13005b261ecSmrg */ 13105b261ecSmrgBool 13235c4bbdfSmrgRRCrtcNotify(RRCrtcPtr crtc, 13335c4bbdfSmrg RRModePtr mode, 13435c4bbdfSmrg int x, 13535c4bbdfSmrg int y, 13635c4bbdfSmrg Rotation rotation, 13735c4bbdfSmrg RRTransformPtr transform, int numOutputs, RROutputPtr * outputs) 13805b261ecSmrg{ 13935c4bbdfSmrg int i, j; 14035c4bbdfSmrg 14105b261ecSmrg /* 14205b261ecSmrg * Check to see if any of the new outputs were 14305b261ecSmrg * not in the old list and mark them as changed 14405b261ecSmrg */ 14535c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 14635c4bbdfSmrg for (j = 0; j < crtc->numOutputs; j++) 14735c4bbdfSmrg if (outputs[i] == crtc->outputs[j]) 14835c4bbdfSmrg break; 14935c4bbdfSmrg if (j == crtc->numOutputs) { 15035c4bbdfSmrg outputs[i]->crtc = crtc; 15135c4bbdfSmrg RROutputChanged(outputs[i], FALSE); 15235c4bbdfSmrg RRCrtcChanged(crtc, FALSE); 15335c4bbdfSmrg } 15405b261ecSmrg } 15505b261ecSmrg /* 15605b261ecSmrg * Check to see if any of the old outputs are 15705b261ecSmrg * not in the new list and mark them as changed 15805b261ecSmrg */ 15935c4bbdfSmrg for (j = 0; j < crtc->numOutputs; j++) { 16035c4bbdfSmrg for (i = 0; i < numOutputs; i++) 16135c4bbdfSmrg if (outputs[i] == crtc->outputs[j]) 16235c4bbdfSmrg break; 16335c4bbdfSmrg if (i == numOutputs) { 16435c4bbdfSmrg if (crtc->outputs[j]->crtc == crtc) 16535c4bbdfSmrg crtc->outputs[j]->crtc = NULL; 16635c4bbdfSmrg RROutputChanged(crtc->outputs[j], FALSE); 16735c4bbdfSmrg RRCrtcChanged(crtc, FALSE); 16835c4bbdfSmrg } 16905b261ecSmrg } 17005b261ecSmrg /* 17105b261ecSmrg * Reallocate the crtc output array if necessary 17205b261ecSmrg */ 17335c4bbdfSmrg if (numOutputs != crtc->numOutputs) { 17435c4bbdfSmrg RROutputPtr *newoutputs; 17535c4bbdfSmrg 17635c4bbdfSmrg if (numOutputs) { 17735c4bbdfSmrg if (crtc->numOutputs) 17835c4bbdfSmrg newoutputs = reallocarray(crtc->outputs, 17935c4bbdfSmrg numOutputs, sizeof(RROutputPtr)); 18035c4bbdfSmrg else 18135c4bbdfSmrg newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 18235c4bbdfSmrg if (!newoutputs) 18335c4bbdfSmrg return FALSE; 18435c4bbdfSmrg } 18535c4bbdfSmrg else { 18635c4bbdfSmrg free(crtc->outputs); 18735c4bbdfSmrg newoutputs = NULL; 18835c4bbdfSmrg } 18935c4bbdfSmrg crtc->outputs = newoutputs; 19035c4bbdfSmrg crtc->numOutputs = numOutputs; 19105b261ecSmrg } 19205b261ecSmrg /* 19305b261ecSmrg * Copy the new list of outputs into the crtc 19405b261ecSmrg */ 19535c4bbdfSmrg memcpy(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)); 19605b261ecSmrg /* 19705b261ecSmrg * Update remaining crtc fields 19805b261ecSmrg */ 19935c4bbdfSmrg if (mode != crtc->mode) { 20035c4bbdfSmrg if (crtc->mode) 20135c4bbdfSmrg RRModeDestroy(crtc->mode); 20235c4bbdfSmrg crtc->mode = mode; 20335c4bbdfSmrg if (mode != NULL) 20435c4bbdfSmrg mode->refcnt++; 20535c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 20605b261ecSmrg } 20735c4bbdfSmrg if (x != crtc->x) { 20835c4bbdfSmrg crtc->x = x; 20935c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 21005b261ecSmrg } 21135c4bbdfSmrg if (y != crtc->y) { 21235c4bbdfSmrg crtc->y = y; 21335c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 21405b261ecSmrg } 21535c4bbdfSmrg if (rotation != crtc->rotation) { 21635c4bbdfSmrg crtc->rotation = rotation; 21735c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 2184642e01fSmrg } 21935c4bbdfSmrg if (!RRTransformEqual(transform, &crtc->client_current_transform)) { 22035c4bbdfSmrg RRTransformCopy(&crtc->client_current_transform, transform); 22135c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 22235c4bbdfSmrg } 22335c4bbdfSmrg if (crtc->changed && mode) { 22435c4bbdfSmrg RRTransformCompute(x, y, 22535c4bbdfSmrg mode->mode.width, mode->mode.height, 22635c4bbdfSmrg rotation, 22735c4bbdfSmrg &crtc->client_current_transform, 22835c4bbdfSmrg &crtc->transform, &crtc->f_transform, 22935c4bbdfSmrg &crtc->f_inverse); 2304642e01fSmrg } 23105b261ecSmrg return TRUE; 23205b261ecSmrg} 23305b261ecSmrg 23405b261ecSmrgvoid 23535c4bbdfSmrgRRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc) 23605b261ecSmrg{ 23705b261ecSmrg ScreenPtr pScreen = pWin->drawable.pScreen; 23835c4bbdfSmrg 23935c4bbdfSmrg rrScrPriv(pScreen); 24035c4bbdfSmrg RRModePtr mode = crtc->mode; 24135c4bbdfSmrg 24235c4bbdfSmrg xRRCrtcChangeNotifyEvent ce = { 24335c4bbdfSmrg .type = RRNotify + RREventBase, 24435c4bbdfSmrg .subCode = RRNotify_CrtcChange, 24535c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds, 24635c4bbdfSmrg .window = pWin->drawable.id, 24735c4bbdfSmrg .crtc = crtc->id, 24835c4bbdfSmrg .mode = mode ? mode->mode.id : None, 24935c4bbdfSmrg .rotation = crtc->rotation, 25035c4bbdfSmrg .x = mode ? crtc->x : 0, 25135c4bbdfSmrg .y = mode ? crtc->y : 0, 25235c4bbdfSmrg .width = mode ? mode->mode.width : 0, 25335c4bbdfSmrg .height = mode ? mode->mode.height : 0 25435c4bbdfSmrg }; 25535c4bbdfSmrg WriteEventsToClient(client, 1, (xEvent *) &ce); 25635c4bbdfSmrg} 25735c4bbdfSmrg 25835c4bbdfSmrgstatic Bool 25935c4bbdfSmrgRRCrtcPendingProperties(RRCrtcPtr crtc) 26035c4bbdfSmrg{ 26135c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 26235c4bbdfSmrg 26335c4bbdfSmrg rrScrPriv(pScreen); 26435c4bbdfSmrg int o; 26535c4bbdfSmrg 26635c4bbdfSmrg for (o = 0; o < pScrPriv->numOutputs; o++) { 26735c4bbdfSmrg RROutputPtr output = pScrPriv->outputs[o]; 26835c4bbdfSmrg 26935c4bbdfSmrg if (output->crtc == crtc && output->pendingProperties) 27035c4bbdfSmrg return TRUE; 27105b261ecSmrg } 27235c4bbdfSmrg return FALSE; 27335c4bbdfSmrg} 27435c4bbdfSmrg 2751b5d61b8Smrgstatic Bool 2761b5d61b8Smrgcursor_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom) 27735c4bbdfSmrg{ 2781b5d61b8Smrg rrScrPriv(crtc->pScreen); 2791b5d61b8Smrg BoxRec bounds; 28035c4bbdfSmrg 2811b5d61b8Smrg if (crtc->mode == NULL) 2821b5d61b8Smrg return FALSE; 2831b5d61b8Smrg 2841b5d61b8Smrg memset(&bounds, 0, sizeof(bounds)); 2851b5d61b8Smrg if (pScrPriv->rrGetPanning) 2861b5d61b8Smrg pScrPriv->rrGetPanning(crtc->pScreen, crtc, NULL, &bounds, NULL); 2871b5d61b8Smrg 2881b5d61b8Smrg if (bounds.y2 <= bounds.y1 || bounds.x2 <= bounds.x1) { 2891b5d61b8Smrg bounds.x1 = 0; 2901b5d61b8Smrg bounds.y1 = 0; 2911b5d61b8Smrg bounds.x2 = crtc->mode->mode.width; 2921b5d61b8Smrg bounds.y2 = crtc->mode->mode.height; 29305b261ecSmrg } 2941b5d61b8Smrg 2951b5d61b8Smrg pixman_f_transform_bounds(&crtc->f_transform, &bounds); 2961b5d61b8Smrg 2971b5d61b8Smrg *left = bounds.x1; 2981b5d61b8Smrg *right = bounds.x2; 2991b5d61b8Smrg *top = bounds.y1; 3001b5d61b8Smrg *bottom = bounds.y2; 3011b5d61b8Smrg 3021b5d61b8Smrg return TRUE; 30305b261ecSmrg} 30405b261ecSmrg 30535c4bbdfSmrg/* overlapping counts as adjacent */ 30605b261ecSmrgstatic Bool 30735c4bbdfSmrgcrtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b) 30835c4bbdfSmrg{ 30935c4bbdfSmrg /* left, right, top, bottom... */ 31035c4bbdfSmrg int al, ar, at, ab; 31135c4bbdfSmrg int bl, br, bt, bb; 31235c4bbdfSmrg int cl, cr, ct, cb; /* the overlap, if any */ 31335c4bbdfSmrg 3141b5d61b8Smrg if (!cursor_bounds(a, &al, &ar, &at, &ab)) 3151b5d61b8Smrg return FALSE; 3161b5d61b8Smrg if (!cursor_bounds(b, &bl, &br, &bt, &bb)) 3171b5d61b8Smrg return FALSE; 31835c4bbdfSmrg 31935c4bbdfSmrg cl = max(al, bl); 32035c4bbdfSmrg cr = min(ar, br); 32135c4bbdfSmrg ct = max(at, bt); 32235c4bbdfSmrg cb = min(ab, bb); 32335c4bbdfSmrg 32435c4bbdfSmrg return (cl <= cr) && (ct <= cb); 32535c4bbdfSmrg} 32635c4bbdfSmrg 32735c4bbdfSmrg/* Depth-first search and mark all CRTCs reachable from cur */ 32835c4bbdfSmrgstatic void 32935c4bbdfSmrgmark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur) 33035c4bbdfSmrg{ 33135c4bbdfSmrg int i; 33235c4bbdfSmrg 33335c4bbdfSmrg reachable[cur] = TRUE; 33435c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; ++i) { 3351b5d61b8Smrg if (reachable[i]) 33635c4bbdfSmrg continue; 33735c4bbdfSmrg if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i])) 33835c4bbdfSmrg mark_crtcs(pScrPriv, reachable, i); 33935c4bbdfSmrg } 34035c4bbdfSmrg} 34135c4bbdfSmrg 34235c4bbdfSmrgstatic void 34335c4bbdfSmrgRRComputeContiguity(ScreenPtr pScreen) 34405b261ecSmrg{ 34505b261ecSmrg rrScrPriv(pScreen); 34635c4bbdfSmrg Bool discontiguous = TRUE; 34735c4bbdfSmrg int i, n = pScrPriv->numCrtcs; 34805b261ecSmrg 34935c4bbdfSmrg int *reachable = calloc(n, sizeof(int)); 35035c4bbdfSmrg 35135c4bbdfSmrg if (!reachable) 35235c4bbdfSmrg goto out; 35335c4bbdfSmrg 35435c4bbdfSmrg /* Find first enabled CRTC and start search for reachable CRTCs from it */ 35535c4bbdfSmrg for (i = 0; i < n; ++i) { 35635c4bbdfSmrg if (pScrPriv->crtcs[i]->mode) { 35735c4bbdfSmrg mark_crtcs(pScrPriv, reachable, i); 35835c4bbdfSmrg break; 35935c4bbdfSmrg } 36005b261ecSmrg } 36135c4bbdfSmrg 36235c4bbdfSmrg /* Check that all enabled CRTCs were marked as reachable */ 36335c4bbdfSmrg for (i = 0; i < n; ++i) 36435c4bbdfSmrg if (pScrPriv->crtcs[i]->mode && !reachable[i]) 36535c4bbdfSmrg goto out; 36635c4bbdfSmrg 36735c4bbdfSmrg discontiguous = FALSE; 36835c4bbdfSmrg 36935c4bbdfSmrg out: 37035c4bbdfSmrg free(reachable); 37135c4bbdfSmrg pScrPriv->discontiguous = discontiguous; 37235c4bbdfSmrg} 37335c4bbdfSmrg 3741b5d61b8Smrgstatic void 3751b5d61b8SmrgrrDestroySharedPixmap(RRCrtcPtr crtc, PixmapPtr pPixmap) { 376ed6184dfSmrg ScreenPtr primary = crtc->pScreen->current_primary; 37735c4bbdfSmrg 378ed6184dfSmrg if (primary && pPixmap->primary_pixmap) { 37935c4bbdfSmrg /* 38035c4bbdfSmrg * Unref the pixmap twice: once for the original reference, and once 381ed6184dfSmrg * for the reference implicitly added by PixmapShareToSecondary. 38235c4bbdfSmrg */ 383ed6184dfSmrg PixmapUnshareSecondaryPixmap(pPixmap); 3841b5d61b8Smrg 385ed6184dfSmrg primary->DestroyPixmap(pPixmap->primary_pixmap); 386ed6184dfSmrg primary->DestroyPixmap(pPixmap->primary_pixmap); 38735c4bbdfSmrg } 3881b5d61b8Smrg 3891b5d61b8Smrg crtc->pScreen->DestroyPixmap(pPixmap); 39035c4bbdfSmrg} 39135c4bbdfSmrg 3921b5d61b8Smrgvoid 3931b5d61b8SmrgRRCrtcDetachScanoutPixmap(RRCrtcPtr crtc) 39435c4bbdfSmrg{ 39535c4bbdfSmrg rrScrPriv(crtc->pScreen); 39635c4bbdfSmrg 3971b5d61b8Smrg if (crtc->scanout_pixmap) { 398ed6184dfSmrg ScreenPtr primary = crtc->pScreen->current_primary; 399ed6184dfSmrg DrawablePtr mrootdraw = &primary->root->drawable; 40035c4bbdfSmrg 4011b5d61b8Smrg if (crtc->scanout_pixmap_back) { 4021b5d61b8Smrg pScrPriv->rrDisableSharedPixmapFlipping(crtc); 40335c4bbdfSmrg 40425da500fSmrg if (mrootdraw) { 405ed6184dfSmrg primary->StopFlippingPixmapTracking(mrootdraw, 40625da500fSmrg crtc->scanout_pixmap, 40725da500fSmrg crtc->scanout_pixmap_back); 40825da500fSmrg } 40935c4bbdfSmrg 4101b5d61b8Smrg rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back); 4111b5d61b8Smrg crtc->scanout_pixmap_back = NULL; 4121b5d61b8Smrg } 4131b5d61b8Smrg else { 4141b5d61b8Smrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL); 41525da500fSmrg 41625da500fSmrg if (mrootdraw) { 417ed6184dfSmrg primary->StopPixmapTracking(mrootdraw, 41825da500fSmrg crtc->scanout_pixmap); 41925da500fSmrg } 4201b5d61b8Smrg } 4211b5d61b8Smrg 4221b5d61b8Smrg rrDestroySharedPixmap(crtc, crtc->scanout_pixmap); 4231b5d61b8Smrg crtc->scanout_pixmap = NULL; 42435c4bbdfSmrg } 42535c4bbdfSmrg 4261b5d61b8Smrg RRCrtcChanged(crtc, TRUE); 4271b5d61b8Smrg} 4281b5d61b8Smrg 4291b5d61b8Smrgstatic PixmapPtr 430ed6184dfSmrgrrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr primary, 4311b5d61b8Smrg int width, int height, int depth, 4321b5d61b8Smrg int x, int y, Rotation rotation) 4331b5d61b8Smrg{ 4341b5d61b8Smrg PixmapPtr mpix, spix; 4351b5d61b8Smrg 436ed6184dfSmrg mpix = primary->CreatePixmap(primary, width, height, depth, 43735c4bbdfSmrg CREATE_PIXMAP_USAGE_SHARED); 43835c4bbdfSmrg if (!mpix) 4391b5d61b8Smrg return NULL; 44035c4bbdfSmrg 441ed6184dfSmrg spix = PixmapShareToSecondary(mpix, crtc->pScreen); 44235c4bbdfSmrg if (spix == NULL) { 443ed6184dfSmrg primary->DestroyPixmap(mpix); 4441b5d61b8Smrg return NULL; 4451b5d61b8Smrg } 4461b5d61b8Smrg 4471b5d61b8Smrg return spix; 4481b5d61b8Smrg} 4491b5d61b8Smrg 4501b5d61b8Smrgstatic Bool 4511b5d61b8SmrgrrGetPixmapSharingSyncProp(int numOutputs, RROutputPtr * outputs) 4521b5d61b8Smrg{ 4531b5d61b8Smrg /* Determine if the user wants prime syncing */ 4541b5d61b8Smrg int o; 4551b5d61b8Smrg const char *syncStr = PRIME_SYNC_PROP; 4561b5d61b8Smrg Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 4571b5d61b8Smrg if (syncProp == None) 4581b5d61b8Smrg return TRUE; 4591b5d61b8Smrg 4601b5d61b8Smrg /* If one output doesn't want sync, no sync */ 4611b5d61b8Smrg for (o = 0; o < numOutputs; o++) { 4621b5d61b8Smrg RRPropertyValuePtr val; 4631b5d61b8Smrg 4641b5d61b8Smrg /* Try pending value first, then current value */ 4651b5d61b8Smrg if ((val = RRGetOutputProperty(outputs[o], syncProp, TRUE)) && 4661b5d61b8Smrg val->data) { 4671b5d61b8Smrg if (!(*(char *) val->data)) 4681b5d61b8Smrg return FALSE; 4691b5d61b8Smrg continue; 4701b5d61b8Smrg } 4711b5d61b8Smrg 4721b5d61b8Smrg if ((val = RRGetOutputProperty(outputs[o], syncProp, FALSE)) && 4731b5d61b8Smrg val->data) { 4741b5d61b8Smrg if (!(*(char *) val->data)) 4751b5d61b8Smrg return FALSE; 4761b5d61b8Smrg continue; 4771b5d61b8Smrg } 4781b5d61b8Smrg } 4791b5d61b8Smrg 4801b5d61b8Smrg return TRUE; 4811b5d61b8Smrg} 4821b5d61b8Smrg 4831b5d61b8Smrgstatic void 4841b5d61b8SmrgrrSetPixmapSharingSyncProp(char val, int numOutputs, RROutputPtr * outputs) 4851b5d61b8Smrg{ 4861b5d61b8Smrg int o; 4871b5d61b8Smrg const char *syncStr = PRIME_SYNC_PROP; 4881b5d61b8Smrg Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 4891b5d61b8Smrg if (syncProp == None) 4901b5d61b8Smrg return; 4911b5d61b8Smrg 4921b5d61b8Smrg for (o = 0; o < numOutputs; o++) { 4931b5d61b8Smrg RRPropertyPtr prop = RRQueryOutputProperty(outputs[o], syncProp); 4941b5d61b8Smrg if (prop) 4951b5d61b8Smrg RRChangeOutputProperty(outputs[o], syncProp, XA_INTEGER, 4961b5d61b8Smrg 8, PropModeReplace, 1, &val, FALSE, TRUE); 4971b5d61b8Smrg } 4981b5d61b8Smrg} 4991b5d61b8Smrg 5001b5d61b8Smrgstatic Bool 5011b5d61b8SmrgrrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height, 5021b5d61b8Smrg int x, int y, Rotation rotation, Bool sync, 5031b5d61b8Smrg int numOutputs, RROutputPtr * outputs) 5041b5d61b8Smrg{ 505ed6184dfSmrg ScreenPtr primary = crtc->pScreen->current_primary; 506ed6184dfSmrg rrScrPrivPtr pPrimaryScrPriv = rrGetScrPriv(primary); 507ed6184dfSmrg rrScrPrivPtr pSecondaryScrPriv = rrGetScrPriv(crtc->pScreen); 508ed6184dfSmrg DrawablePtr mrootdraw = &primary->root->drawable; 5091b5d61b8Smrg int depth = mrootdraw->depth; 5101b5d61b8Smrg PixmapPtr spix_front; 5111b5d61b8Smrg 512ed6184dfSmrg /* Create a pixmap on the primary screen, then get a shared handle for it. 513ed6184dfSmrg Create a shared pixmap on the secondary screen using the handle. 5141b5d61b8Smrg 5151b5d61b8Smrg If sync == FALSE -- 516ed6184dfSmrg Set secondary screen to scanout shared linear pixmap. 517ed6184dfSmrg Set the primary screen to do dirty updates to the shared pixmap 5181b5d61b8Smrg from the screen pixmap on its own accord. 5191b5d61b8Smrg 5201b5d61b8Smrg If sync == TRUE -- 5211b5d61b8Smrg If any of the below steps fail, clean up and fall back to sync == FALSE. 522ed6184dfSmrg Create another shared pixmap on the secondary screen using the handle. 523ed6184dfSmrg Set secondary screen to prepare for scanout and flipping between shared 5241b5d61b8Smrg linear pixmaps. 525ed6184dfSmrg Set the primary screen to do dirty updates to the shared pixmaps from the 526ed6184dfSmrg screen pixmap when prompted to by us or the secondary. 527ed6184dfSmrg Prompt the primary to do a dirty update on the first shared pixmap, then 528ed6184dfSmrg defer to the secondary. 5291b5d61b8Smrg */ 5301b5d61b8Smrg 5311b5d61b8Smrg if (crtc->scanout_pixmap) 5321b5d61b8Smrg RRCrtcDetachScanoutPixmap(crtc); 5331b5d61b8Smrg 5341b5d61b8Smrg if (width == 0 && height == 0) { 5351b5d61b8Smrg return TRUE; 5361b5d61b8Smrg } 5371b5d61b8Smrg 538ed6184dfSmrg spix_front = rrCreateSharedPixmap(crtc, primary, 5391b5d61b8Smrg width, height, depth, 5401b5d61b8Smrg x, y, rotation); 5411b5d61b8Smrg if (spix_front == NULL) { 5421b5d61b8Smrg ErrorF("randr: failed to create shared pixmap\n"); 54335c4bbdfSmrg return FALSE; 54435c4bbdfSmrg } 54535c4bbdfSmrg 5461b5d61b8Smrg /* Both source and sink must support required ABI funcs for flipping */ 5471b5d61b8Smrg if (sync && 548ed6184dfSmrg pSecondaryScrPriv->rrEnableSharedPixmapFlipping && 549ed6184dfSmrg pSecondaryScrPriv->rrDisableSharedPixmapFlipping && 550ed6184dfSmrg pPrimaryScrPriv->rrStartFlippingPixmapTracking && 551ed6184dfSmrg primary->PresentSharedPixmap && 552ed6184dfSmrg primary->StopFlippingPixmapTracking) { 5531b5d61b8Smrg 554ed6184dfSmrg PixmapPtr spix_back = rrCreateSharedPixmap(crtc, primary, 5551b5d61b8Smrg width, height, depth, 5561b5d61b8Smrg x, y, rotation); 5571b5d61b8Smrg if (spix_back == NULL) 5581b5d61b8Smrg goto fail; 5591b5d61b8Smrg 560ed6184dfSmrg if (!pSecondaryScrPriv->rrEnableSharedPixmapFlipping(crtc, 5611b5d61b8Smrg spix_front, spix_back)) 5621b5d61b8Smrg goto fail; 5631b5d61b8Smrg 5641b5d61b8Smrg crtc->scanout_pixmap = spix_front; 5651b5d61b8Smrg crtc->scanout_pixmap_back = spix_back; 5661b5d61b8Smrg 567ed6184dfSmrg if (!pPrimaryScrPriv->rrStartFlippingPixmapTracking(crtc, 5681b5d61b8Smrg mrootdraw, 5691b5d61b8Smrg spix_front, 5701b5d61b8Smrg spix_back, 5711b5d61b8Smrg x, y, 0, 0, 5721b5d61b8Smrg rotation)) { 573ed6184dfSmrg pSecondaryScrPriv->rrDisableSharedPixmapFlipping(crtc); 5741b5d61b8Smrg goto fail; 5751b5d61b8Smrg } 5761b5d61b8Smrg 577ed6184dfSmrg primary->PresentSharedPixmap(spix_front); 5781b5d61b8Smrg 5791b5d61b8Smrg return TRUE; 5801b5d61b8Smrg 5811b5d61b8Smrgfail: /* If flipping funcs fail, just fall back to unsynchronized */ 5821b5d61b8Smrg if (spix_back) 5831b5d61b8Smrg rrDestroySharedPixmap(crtc, spix_back); 5841b5d61b8Smrg 5851b5d61b8Smrg crtc->scanout_pixmap = NULL; 5861b5d61b8Smrg crtc->scanout_pixmap_back = NULL; 5871b5d61b8Smrg } 5881b5d61b8Smrg 5891b5d61b8Smrg if (sync) { /* Wanted sync, didn't get it */ 5901b5d61b8Smrg ErrorF("randr: falling back to unsynchronized pixmap sharing\n"); 5911b5d61b8Smrg 5921b5d61b8Smrg /* Set output property to 0 to indicate to user */ 5931b5d61b8Smrg rrSetPixmapSharingSyncProp(0, numOutputs, outputs); 5941b5d61b8Smrg } 5951b5d61b8Smrg 596ed6184dfSmrg if (!pSecondaryScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) { 5971b5d61b8Smrg rrDestroySharedPixmap(crtc, spix_front); 598ed6184dfSmrg ErrorF("randr: failed to set shadow secondary pixmap\n"); 59935c4bbdfSmrg return FALSE; 60035c4bbdfSmrg } 6011b5d61b8Smrg crtc->scanout_pixmap = spix_front; 60235c4bbdfSmrg 603ed6184dfSmrg primary->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation); 60435c4bbdfSmrg 60535c4bbdfSmrg return TRUE; 60635c4bbdfSmrg} 60735c4bbdfSmrg 60835c4bbdfSmrgstatic void crtc_to_box(BoxPtr box, RRCrtcPtr crtc) 60935c4bbdfSmrg{ 61035c4bbdfSmrg box->x1 = crtc->x; 61135c4bbdfSmrg box->y1 = crtc->y; 61235c4bbdfSmrg switch (crtc->rotation) { 61335c4bbdfSmrg case RR_Rotate_0: 61435c4bbdfSmrg case RR_Rotate_180: 61535c4bbdfSmrg default: 61635c4bbdfSmrg box->x2 = crtc->x + crtc->mode->mode.width; 61735c4bbdfSmrg box->y2 = crtc->y + crtc->mode->mode.height; 61835c4bbdfSmrg break; 61935c4bbdfSmrg case RR_Rotate_90: 62035c4bbdfSmrg case RR_Rotate_270: 62135c4bbdfSmrg box->x2 = crtc->x + crtc->mode->mode.height; 62235c4bbdfSmrg box->y2 = crtc->y + crtc->mode->mode.width; 62335c4bbdfSmrg break; 62435c4bbdfSmrg } 62535c4bbdfSmrg} 62635c4bbdfSmrg 62735c4bbdfSmrgstatic Bool 62835c4bbdfSmrgrrCheckPixmapBounding(ScreenPtr pScreen, 62935c4bbdfSmrg RRCrtcPtr rr_crtc, Rotation rotation, 63035c4bbdfSmrg int x, int y, int w, int h) 63135c4bbdfSmrg{ 63235c4bbdfSmrg RegionRec root_pixmap_region, total_region, new_crtc_region; 63335c4bbdfSmrg int c; 63435c4bbdfSmrg BoxRec newbox; 63535c4bbdfSmrg BoxPtr newsize; 636ed6184dfSmrg ScreenPtr secondary; 63735c4bbdfSmrg int new_width, new_height; 63835c4bbdfSmrg PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen); 63935c4bbdfSmrg rrScrPriv(pScreen); 64035c4bbdfSmrg 64135c4bbdfSmrg PixmapRegionInit(&root_pixmap_region, screen_pixmap); 64235c4bbdfSmrg RegionInit(&total_region, NULL, 0); 64335c4bbdfSmrg 644ed6184dfSmrg /* have to iterate all the crtcs of the attached gpu primarys 645ed6184dfSmrg and all their output secondarys */ 64635c4bbdfSmrg for (c = 0; c < pScrPriv->numCrtcs; c++) { 64735c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[c]; 64835c4bbdfSmrg 64935c4bbdfSmrg if (crtc == rr_crtc) { 65035c4bbdfSmrg newbox.x1 = x; 65135c4bbdfSmrg newbox.y1 = y; 65235c4bbdfSmrg if (rotation == RR_Rotate_90 || 65335c4bbdfSmrg rotation == RR_Rotate_270) { 65435c4bbdfSmrg newbox.x2 = x + h; 65535c4bbdfSmrg newbox.y2 = y + w; 65635c4bbdfSmrg } else { 65735c4bbdfSmrg newbox.x2 = x + w; 65835c4bbdfSmrg newbox.y2 = y + h; 65935c4bbdfSmrg } 66035c4bbdfSmrg } else { 66135c4bbdfSmrg if (!crtc->mode) 66235c4bbdfSmrg continue; 66335c4bbdfSmrg crtc_to_box(&newbox, crtc); 66435c4bbdfSmrg } 66535c4bbdfSmrg RegionInit(&new_crtc_region, &newbox, 1); 66635c4bbdfSmrg RegionUnion(&total_region, &total_region, &new_crtc_region); 66735c4bbdfSmrg } 66835c4bbdfSmrg 669ed6184dfSmrg xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 670ed6184dfSmrg rrScrPrivPtr secondary_priv = rrGetScrPriv(secondary); 6711b5d61b8Smrg 672ed6184dfSmrg if (!secondary->is_output_secondary) 6731b5d61b8Smrg continue; 6741b5d61b8Smrg 675ed6184dfSmrg for (c = 0; c < secondary_priv->numCrtcs; c++) { 676ed6184dfSmrg RRCrtcPtr secondary_crtc = secondary_priv->crtcs[c]; 67735c4bbdfSmrg 678ed6184dfSmrg if (secondary_crtc == rr_crtc) { 67935c4bbdfSmrg newbox.x1 = x; 68035c4bbdfSmrg newbox.y1 = y; 68135c4bbdfSmrg if (rotation == RR_Rotate_90 || 68235c4bbdfSmrg rotation == RR_Rotate_270) { 68335c4bbdfSmrg newbox.x2 = x + h; 68435c4bbdfSmrg newbox.y2 = y + w; 68535c4bbdfSmrg } else { 68635c4bbdfSmrg newbox.x2 = x + w; 68735c4bbdfSmrg newbox.y2 = y + h; 68835c4bbdfSmrg } 68935c4bbdfSmrg } 69035c4bbdfSmrg else { 691ed6184dfSmrg if (!secondary_crtc->mode) 69235c4bbdfSmrg continue; 693ed6184dfSmrg crtc_to_box(&newbox, secondary_crtc); 69435c4bbdfSmrg } 69535c4bbdfSmrg RegionInit(&new_crtc_region, &newbox, 1); 69635c4bbdfSmrg RegionUnion(&total_region, &total_region, &new_crtc_region); 69735c4bbdfSmrg } 69835c4bbdfSmrg } 69935c4bbdfSmrg 70035c4bbdfSmrg newsize = RegionExtents(&total_region); 7011b5d61b8Smrg new_width = newsize->x2; 7021b5d61b8Smrg new_height = newsize->y2; 7031b5d61b8Smrg 7041b5d61b8Smrg if (new_width < screen_pixmap->drawable.width) 7051b5d61b8Smrg new_width = screen_pixmap->drawable.width; 70635c4bbdfSmrg 7071b5d61b8Smrg if (new_height < screen_pixmap->drawable.height) 7081b5d61b8Smrg new_height = screen_pixmap->drawable.height; 7091b5d61b8Smrg 7101b5d61b8Smrg if (new_width <= screen_pixmap->drawable.width && 7111b5d61b8Smrg new_height <= screen_pixmap->drawable.height) { 71235c4bbdfSmrg } else { 71335c4bbdfSmrg pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0); 71435c4bbdfSmrg } 71535c4bbdfSmrg 71635c4bbdfSmrg /* set shatters TODO */ 71735c4bbdfSmrg return TRUE; 71805b261ecSmrg} 71905b261ecSmrg 72005b261ecSmrg/* 72105b261ecSmrg * Request that the Crtc be reconfigured 72205b261ecSmrg */ 72305b261ecSmrgBool 72435c4bbdfSmrgRRCrtcSet(RRCrtcPtr crtc, 72535c4bbdfSmrg RRModePtr mode, 72635c4bbdfSmrg int x, 72735c4bbdfSmrg int y, Rotation rotation, int numOutputs, RROutputPtr * outputs) 72805b261ecSmrg{ 72935c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 73035c4bbdfSmrg Bool ret = FALSE; 73135c4bbdfSmrg Bool recompute = TRUE; 73235c4bbdfSmrg Bool crtcChanged; 73335c4bbdfSmrg int o; 73435c4bbdfSmrg 73505b261ecSmrg rrScrPriv(pScreen); 73605b261ecSmrg 73735c4bbdfSmrg crtcChanged = FALSE; 73835c4bbdfSmrg for (o = 0; o < numOutputs; o++) { 73935c4bbdfSmrg if (outputs[o] && outputs[o]->crtc != crtc) { 74035c4bbdfSmrg crtcChanged = TRUE; 74135c4bbdfSmrg break; 74235c4bbdfSmrg } 74335c4bbdfSmrg } 74435c4bbdfSmrg 74505b261ecSmrg /* See if nothing changed */ 74605b261ecSmrg if (crtc->mode == mode && 74735c4bbdfSmrg crtc->x == x && 74835c4bbdfSmrg crtc->y == y && 74935c4bbdfSmrg crtc->rotation == rotation && 75035c4bbdfSmrg crtc->numOutputs == numOutputs && 75135c4bbdfSmrg !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) && 75235c4bbdfSmrg !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) && 75335c4bbdfSmrg !crtcChanged) { 75435c4bbdfSmrg recompute = FALSE; 75535c4bbdfSmrg ret = TRUE; 75605b261ecSmrg } 75735c4bbdfSmrg else { 75835c4bbdfSmrg if (pScreen->isGPU) { 759ed6184dfSmrg ScreenPtr primary = pScreen->current_primary; 76035c4bbdfSmrg int width = 0, height = 0; 76135c4bbdfSmrg 76235c4bbdfSmrg if (mode) { 76335c4bbdfSmrg width = mode->mode.width; 76435c4bbdfSmrg height = mode->mode.height; 76535c4bbdfSmrg } 766ed6184dfSmrg ret = rrCheckPixmapBounding(primary, crtc, 76735c4bbdfSmrg rotation, x, y, width, height); 76835c4bbdfSmrg if (!ret) 76935c4bbdfSmrg return FALSE; 77035c4bbdfSmrg 771ed6184dfSmrg if (pScreen->current_primary) { 7721b5d61b8Smrg Bool sync = rrGetPixmapSharingSyncProp(numOutputs, outputs); 7731b5d61b8Smrg ret = rrSetupPixmapSharing(crtc, width, height, 7741b5d61b8Smrg x, y, rotation, sync, 7751b5d61b8Smrg numOutputs, outputs); 77635c4bbdfSmrg } 77735c4bbdfSmrg } 77805b261ecSmrg#if RANDR_12_INTERFACE 77935c4bbdfSmrg if (pScrPriv->rrCrtcSet) { 78035c4bbdfSmrg ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 78135c4bbdfSmrg rotation, numOutputs, outputs); 78235c4bbdfSmrg } 78335c4bbdfSmrg else 78405b261ecSmrg#endif 78535c4bbdfSmrg { 78605b261ecSmrg#if RANDR_10_INTERFACE 78735c4bbdfSmrg if (pScrPriv->rrSetConfig) { 78835c4bbdfSmrg RRScreenSize size; 78935c4bbdfSmrg RRScreenRate rate; 79035c4bbdfSmrg 79135c4bbdfSmrg if (!mode) { 79235c4bbdfSmrg RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL); 79335c4bbdfSmrg ret = TRUE; 79435c4bbdfSmrg } 79535c4bbdfSmrg else { 79635c4bbdfSmrg size.width = mode->mode.width; 79735c4bbdfSmrg size.height = mode->mode.height; 79835c4bbdfSmrg if (outputs[0]->mmWidth && outputs[0]->mmHeight) { 79935c4bbdfSmrg size.mmWidth = outputs[0]->mmWidth; 80035c4bbdfSmrg size.mmHeight = outputs[0]->mmHeight; 80135c4bbdfSmrg } 80235c4bbdfSmrg else { 80335c4bbdfSmrg size.mmWidth = pScreen->mmWidth; 80435c4bbdfSmrg size.mmHeight = pScreen->mmHeight; 80535c4bbdfSmrg } 80635c4bbdfSmrg size.nRates = 1; 80735c4bbdfSmrg rate.rate = RRVerticalRefresh(&mode->mode); 80835c4bbdfSmrg size.pRates = &rate; 80935c4bbdfSmrg ret = 81035c4bbdfSmrg (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, 81135c4bbdfSmrg &size); 81235c4bbdfSmrg /* 81335c4bbdfSmrg * Old 1.0 interface tied screen size to mode size 81435c4bbdfSmrg */ 81535c4bbdfSmrg if (ret) { 81635c4bbdfSmrg RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1, 81735c4bbdfSmrg outputs); 81835c4bbdfSmrg RRScreenSizeNotify(pScreen); 81935c4bbdfSmrg } 82035c4bbdfSmrg } 82135c4bbdfSmrg } 82205b261ecSmrg#endif 82335c4bbdfSmrg } 82435c4bbdfSmrg if (ret) { 82505b261ecSmrg 82635c4bbdfSmrg RRTellChanged(pScreen); 82735c4bbdfSmrg 82835c4bbdfSmrg for (o = 0; o < numOutputs; o++) 82935c4bbdfSmrg RRPostPendingProperties(outputs[o]); 83035c4bbdfSmrg } 83105b261ecSmrg } 83235c4bbdfSmrg 83335c4bbdfSmrg if (recompute) 83435c4bbdfSmrg RRComputeContiguity(pScreen); 83535c4bbdfSmrg 83605b261ecSmrg return ret; 83705b261ecSmrg} 83805b261ecSmrg 8394642e01fSmrg/* 8404642e01fSmrg * Return crtc transform 8414642e01fSmrg */ 8424642e01fSmrgRRTransformPtr 84335c4bbdfSmrgRRCrtcGetTransform(RRCrtcPtr crtc) 8444642e01fSmrg{ 84535c4bbdfSmrg RRTransformPtr transform = &crtc->client_pending_transform; 8464642e01fSmrg 84735c4bbdfSmrg if (pixman_transform_is_identity(&transform->transform)) 84835c4bbdfSmrg return NULL; 8494642e01fSmrg return transform; 8504642e01fSmrg} 8514642e01fSmrg 8524642e01fSmrg/* 8534642e01fSmrg * Check whether the pending and current transforms are the same 8544642e01fSmrg */ 8554642e01fSmrgBool 85635c4bbdfSmrgRRCrtcPendingTransform(RRCrtcPtr crtc) 8574642e01fSmrg{ 8581b5d61b8Smrg return !RRTransformEqual(&crtc->client_current_transform, 8591b5d61b8Smrg &crtc->client_pending_transform); 8604642e01fSmrg} 8614642e01fSmrg 86205b261ecSmrg/* 86305b261ecSmrg * Destroy a Crtc at shutdown 86405b261ecSmrg */ 86505b261ecSmrgvoid 86635c4bbdfSmrgRRCrtcDestroy(RRCrtcPtr crtc) 86705b261ecSmrg{ 86835c4bbdfSmrg FreeResource(crtc->id, 0); 86905b261ecSmrg} 87005b261ecSmrg 87105b261ecSmrgstatic int 87235c4bbdfSmrgRRCrtcDestroyResource(void *value, XID pid) 87305b261ecSmrg{ 87435c4bbdfSmrg RRCrtcPtr crtc = (RRCrtcPtr) value; 87535c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 87605b261ecSmrg 87735c4bbdfSmrg if (pScreen) { 87835c4bbdfSmrg rrScrPriv(pScreen); 87935c4bbdfSmrg int i; 8801b5d61b8Smrg RRLeasePtr lease, next; 8811b5d61b8Smrg 8821b5d61b8Smrg xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) { 8831b5d61b8Smrg int c; 8841b5d61b8Smrg for (c = 0; c < lease->numCrtcs; c++) { 8851b5d61b8Smrg if (lease->crtcs[c] == crtc) { 8861b5d61b8Smrg RRTerminateLease(lease); 8871b5d61b8Smrg break; 8881b5d61b8Smrg } 8891b5d61b8Smrg } 8901b5d61b8Smrg } 89135c4bbdfSmrg 89235c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 89335c4bbdfSmrg if (pScrPriv->crtcs[i] == crtc) { 89435c4bbdfSmrg memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, 89535c4bbdfSmrg (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr)); 89635c4bbdfSmrg --pScrPriv->numCrtcs; 89735c4bbdfSmrg break; 89835c4bbdfSmrg } 89935c4bbdfSmrg } 90035c4bbdfSmrg 90135c4bbdfSmrg RRResourcesChanged(pScreen); 90205b261ecSmrg } 90335c4bbdfSmrg 90435c4bbdfSmrg if (crtc->scanout_pixmap) 90535c4bbdfSmrg RRCrtcDetachScanoutPixmap(crtc); 9066747b715Smrg free(crtc->gammaRed); 90705b261ecSmrg if (crtc->mode) 90835c4bbdfSmrg RRModeDestroy(crtc->mode); 9091b5d61b8Smrg free(crtc->outputs); 9106747b715Smrg free(crtc); 91105b261ecSmrg return 1; 91205b261ecSmrg} 91305b261ecSmrg 91405b261ecSmrg/* 91505b261ecSmrg * Request that the Crtc gamma be changed 91605b261ecSmrg */ 91705b261ecSmrg 91805b261ecSmrgBool 91935c4bbdfSmrgRRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue) 92005b261ecSmrg{ 92135c4bbdfSmrg Bool ret = TRUE; 92235c4bbdfSmrg 92305b261ecSmrg#if RANDR_12_INTERFACE 92435c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 92505b261ecSmrg#endif 92635c4bbdfSmrg 92735c4bbdfSmrg memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16)); 92835c4bbdfSmrg memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16)); 92935c4bbdfSmrg memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16)); 93005b261ecSmrg#if RANDR_12_INTERFACE 93135c4bbdfSmrg if (pScreen) { 93235c4bbdfSmrg rrScrPriv(pScreen); 93335c4bbdfSmrg if (pScrPriv->rrCrtcSetGamma) 93435c4bbdfSmrg ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); 93505b261ecSmrg } 93605b261ecSmrg#endif 93705b261ecSmrg return ret; 93805b261ecSmrg} 93905b261ecSmrg 9406747b715Smrg/* 9416747b715Smrg * Request current gamma back from the DDX (if possible). 9426747b715Smrg * This includes gamma size. 9436747b715Smrg */ 9446747b715SmrgBool 9456747b715SmrgRRCrtcGammaGet(RRCrtcPtr crtc) 9466747b715Smrg{ 9476747b715Smrg Bool ret = TRUE; 94835c4bbdfSmrg 9496747b715Smrg#if RANDR_12_INTERFACE 95035c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 9516747b715Smrg#endif 9526747b715Smrg 9536747b715Smrg#if RANDR_12_INTERFACE 95435c4bbdfSmrg if (pScreen) { 9556747b715Smrg rrScrPriv(pScreen); 9566747b715Smrg if (pScrPriv->rrCrtcGetGamma) 9576747b715Smrg ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); 9586747b715Smrg } 9596747b715Smrg#endif 9606747b715Smrg return ret; 9616747b715Smrg} 9626747b715Smrg 963a035e2b2Smrgstatic Bool RRCrtcInScreen(ScreenPtr pScreen, RRCrtcPtr findCrtc) 964a035e2b2Smrg{ 965a035e2b2Smrg rrScrPrivPtr pScrPriv; 966a035e2b2Smrg int c; 967a035e2b2Smrg 968a035e2b2Smrg if (pScreen == NULL) 969a035e2b2Smrg return FALSE; 970a035e2b2Smrg 971a035e2b2Smrg if (findCrtc == NULL) 972a035e2b2Smrg return FALSE; 973a035e2b2Smrg 974a035e2b2Smrg if (!dixPrivateKeyRegistered(rrPrivKey)) 975a035e2b2Smrg return FALSE; 976a035e2b2Smrg 977a035e2b2Smrg pScrPriv = rrGetScrPriv(pScreen); 978a035e2b2Smrg for (c = 0; c < pScrPriv->numCrtcs; c++) { 979a035e2b2Smrg if (pScrPriv->crtcs[c] == findCrtc) 980a035e2b2Smrg return TRUE; 981a035e2b2Smrg } 982a035e2b2Smrg 983a035e2b2Smrg return FALSE; 984a035e2b2Smrg} 985a035e2b2Smrg 986a035e2b2SmrgBool RRCrtcExists(ScreenPtr pScreen, RRCrtcPtr findCrtc) 987a035e2b2Smrg{ 988ed6184dfSmrg ScreenPtr secondary= NULL; 989a035e2b2Smrg 990a035e2b2Smrg if (RRCrtcInScreen(pScreen, findCrtc)) 991a035e2b2Smrg return TRUE; 992a035e2b2Smrg 993ed6184dfSmrg xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 994ed6184dfSmrg if (!secondary->is_output_secondary) 995a035e2b2Smrg continue; 996ed6184dfSmrg if (RRCrtcInScreen(secondary, findCrtc)) 997a035e2b2Smrg return TRUE; 998a035e2b2Smrg } 999a035e2b2Smrg 1000a035e2b2Smrg return FALSE; 1001a035e2b2Smrg} 1002a035e2b2Smrg 1003a035e2b2Smrg 100405b261ecSmrg/* 100505b261ecSmrg * Notify the extension that the Crtc gamma has been changed 100605b261ecSmrg * The driver calls this whenever it has changed the gamma values 100705b261ecSmrg * in the RRCrtcRec 100805b261ecSmrg */ 100905b261ecSmrg 101005b261ecSmrgBool 101135c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc) 101205b261ecSmrg{ 101335c4bbdfSmrg return TRUE; /* not much going on here */ 101405b261ecSmrg} 101505b261ecSmrg 10164642e01fSmrgstatic void 101735c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform, 101835c4bbdfSmrg int *width, int *height) 101905b261ecSmrg{ 102035c4bbdfSmrg BoxRec box; 10214642e01fSmrg 10224642e01fSmrg if (mode == NULL) { 102335c4bbdfSmrg *width = 0; 102435c4bbdfSmrg *height = 0; 102535c4bbdfSmrg return; 102605b261ecSmrg } 102705b261ecSmrg 10284642e01fSmrg box.x1 = 0; 10294642e01fSmrg box.y1 = 0; 10304642e01fSmrg box.x2 = mode->mode.width; 10314642e01fSmrg box.y2 = mode->mode.height; 10324642e01fSmrg 103335c4bbdfSmrg pixman_transform_bounds(transform, &box); 10344642e01fSmrg *width = box.x2 - box.x1; 10354642e01fSmrg *height = box.y2 - box.y1; 10364642e01fSmrg} 10374642e01fSmrg 10384642e01fSmrg/** 10394642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer 10404642e01fSmrg */ 10414642e01fSmrgvoid 10424642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 10434642e01fSmrg{ 104435c4bbdfSmrg RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height); 104505b261ecSmrg} 104605b261ecSmrg 104705b261ecSmrg/* 104805b261ecSmrg * Set the size of the gamma table at server startup time 104905b261ecSmrg */ 105005b261ecSmrg 105105b261ecSmrgBool 105235c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size) 105305b261ecSmrg{ 105435c4bbdfSmrg CARD16 *gamma; 105505b261ecSmrg 105605b261ecSmrg if (size == crtc->gammaSize) 105735c4bbdfSmrg return TRUE; 105835c4bbdfSmrg if (size) { 105935c4bbdfSmrg gamma = xallocarray(size, 3 * sizeof(CARD16)); 106035c4bbdfSmrg if (!gamma) 106135c4bbdfSmrg return FALSE; 106205b261ecSmrg } 106305b261ecSmrg else 106435c4bbdfSmrg gamma = NULL; 10656747b715Smrg free(crtc->gammaRed); 106605b261ecSmrg crtc->gammaRed = gamma; 106705b261ecSmrg crtc->gammaGreen = gamma + size; 106835c4bbdfSmrg crtc->gammaBlue = gamma + size * 2; 106905b261ecSmrg crtc->gammaSize = size; 107005b261ecSmrg return TRUE; 107105b261ecSmrg} 107205b261ecSmrg 10734642e01fSmrg/* 10744642e01fSmrg * Set the pending CRTC transformation 10754642e01fSmrg */ 10764642e01fSmrg 10774642e01fSmrgint 107835c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc, 107935c4bbdfSmrg PictTransformPtr transform, 108035c4bbdfSmrg struct pixman_f_transform *f_transform, 108135c4bbdfSmrg struct pixman_f_transform *f_inverse, 108235c4bbdfSmrg char *filter_name, 108335c4bbdfSmrg int filter_len, xFixed * params, int nparams) 10844642e01fSmrg{ 108535c4bbdfSmrg PictFilterPtr filter = NULL; 108635c4bbdfSmrg int width = 0, height = 0; 10874642e01fSmrg 10884642e01fSmrg if (!crtc->transforms) 108935c4bbdfSmrg return BadValue; 109035c4bbdfSmrg 109135c4bbdfSmrg if (filter_len) { 109235c4bbdfSmrg filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len); 109335c4bbdfSmrg if (!filter) 109435c4bbdfSmrg return BadName; 109535c4bbdfSmrg if (filter->ValidateParams) { 109635c4bbdfSmrg if (!filter->ValidateParams(crtc->pScreen, filter->id, 109735c4bbdfSmrg params, nparams, &width, &height)) 109835c4bbdfSmrg return BadMatch; 109935c4bbdfSmrg } 110035c4bbdfSmrg else { 110135c4bbdfSmrg width = filter->width; 110235c4bbdfSmrg height = filter->height; 110335c4bbdfSmrg } 11044642e01fSmrg } 110535c4bbdfSmrg else { 110635c4bbdfSmrg if (nparams) 110735c4bbdfSmrg return BadMatch; 11084642e01fSmrg } 110935c4bbdfSmrg if (!RRTransformSetFilter(&crtc->client_pending_transform, 111035c4bbdfSmrg filter, params, nparams, width, height)) 111135c4bbdfSmrg return BadAlloc; 11124642e01fSmrg 11134642e01fSmrg crtc->client_pending_transform.transform = *transform; 11144642e01fSmrg crtc->client_pending_transform.f_transform = *f_transform; 11154642e01fSmrg crtc->client_pending_transform.f_inverse = *f_inverse; 11164642e01fSmrg return Success; 11174642e01fSmrg} 11184642e01fSmrg 111905b261ecSmrg/* 112005b261ecSmrg * Initialize crtc type 112105b261ecSmrg */ 112205b261ecSmrgBool 112335c4bbdfSmrgRRCrtcInit(void) 112405b261ecSmrg{ 112535c4bbdfSmrg RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC"); 112605b261ecSmrg if (!RRCrtcType) 112735c4bbdfSmrg return FALSE; 112835c4bbdfSmrg 112905b261ecSmrg return TRUE; 113005b261ecSmrg} 113105b261ecSmrg 11326747b715Smrg/* 11336747b715Smrg * Initialize crtc type error value 11346747b715Smrg */ 11356747b715Smrgvoid 11366747b715SmrgRRCrtcInitErrorValue(void) 11376747b715Smrg{ 11386747b715Smrg SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 11396747b715Smrg} 11406747b715Smrg 114105b261ecSmrgint 114235c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client) 114305b261ecSmrg{ 114405b261ecSmrg REQUEST(xRRGetCrtcInfoReq); 114535c4bbdfSmrg xRRGetCrtcInfoReply rep; 114635c4bbdfSmrg RRCrtcPtr crtc; 11471b5d61b8Smrg CARD8 *extra = NULL; 114835c4bbdfSmrg unsigned long extraLen; 114935c4bbdfSmrg ScreenPtr pScreen; 115035c4bbdfSmrg rrScrPrivPtr pScrPriv; 115135c4bbdfSmrg RRModePtr mode; 115235c4bbdfSmrg RROutput *outputs; 115335c4bbdfSmrg RROutput *possible; 115435c4bbdfSmrg int i, j, k; 115535c4bbdfSmrg int width, height; 115635c4bbdfSmrg BoxRec panned_area; 11571b5d61b8Smrg Bool leased; 115835c4bbdfSmrg 115905b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 11606747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 116105b261ecSmrg 11621b5d61b8Smrg leased = RRCrtcIsLeased(crtc); 11631b5d61b8Smrg 116405b261ecSmrg /* All crtcs must be associated with screens before client 116505b261ecSmrg * requests are processed 116605b261ecSmrg */ 116705b261ecSmrg pScreen = crtc->pScreen; 116805b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 116905b261ecSmrg 117005b261ecSmrg mode = crtc->mode; 117135c4bbdfSmrg 117235c4bbdfSmrg rep = (xRRGetCrtcInfoReply) { 117335c4bbdfSmrg .type = X_Reply, 117435c4bbdfSmrg .status = RRSetConfigSuccess, 117535c4bbdfSmrg .sequenceNumber = client->sequence, 117635c4bbdfSmrg .length = 0, 117735c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 117835c4bbdfSmrg }; 11791b5d61b8Smrg if (leased) { 11801b5d61b8Smrg rep.x = rep.y = rep.width = rep.height = 0; 11811b5d61b8Smrg rep.mode = 0; 11821b5d61b8Smrg rep.rotation = RR_Rotate_0; 11831b5d61b8Smrg rep.rotations = RR_Rotate_0; 11841b5d61b8Smrg rep.nOutput = 0; 11851b5d61b8Smrg rep.nPossibleOutput = 0; 11861b5d61b8Smrg rep.length = 0; 11871b5d61b8Smrg extraLen = 0; 11881b5d61b8Smrg } else { 11891b5d61b8Smrg if (pScrPriv->rrGetPanning && 11901b5d61b8Smrg pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) && 11911b5d61b8Smrg (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 11921b5d61b8Smrg { 11931b5d61b8Smrg rep.x = panned_area.x1; 11941b5d61b8Smrg rep.y = panned_area.y1; 11951b5d61b8Smrg rep.width = panned_area.x2 - panned_area.x1; 11961b5d61b8Smrg rep.height = panned_area.y2 - panned_area.y1; 11971b5d61b8Smrg } 11981b5d61b8Smrg else { 11991b5d61b8Smrg RRCrtcGetScanoutSize(crtc, &width, &height); 12001b5d61b8Smrg rep.x = crtc->x; 12011b5d61b8Smrg rep.y = crtc->y; 12021b5d61b8Smrg rep.width = width; 12031b5d61b8Smrg rep.height = height; 12041b5d61b8Smrg } 12051b5d61b8Smrg rep.mode = mode ? mode->mode.id : 0; 12061b5d61b8Smrg rep.rotation = crtc->rotation; 12071b5d61b8Smrg rep.rotations = crtc->rotations; 12081b5d61b8Smrg rep.nOutput = crtc->numOutputs; 12091b5d61b8Smrg k = 0; 12101b5d61b8Smrg for (i = 0; i < pScrPriv->numOutputs; i++) { 12111b5d61b8Smrg if (!RROutputIsLeased(pScrPriv->outputs[i])) { 12121b5d61b8Smrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 12131b5d61b8Smrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) 12141b5d61b8Smrg k++; 121535c4bbdfSmrg } 12161b5d61b8Smrg } 12171b5d61b8Smrg 12181b5d61b8Smrg rep.nPossibleOutput = k; 12191b5d61b8Smrg 12201b5d61b8Smrg rep.length = rep.nOutput + rep.nPossibleOutput; 12211b5d61b8Smrg 12221b5d61b8Smrg extraLen = rep.length << 2; 12231b5d61b8Smrg if (extraLen) { 12241b5d61b8Smrg extra = malloc(extraLen); 12251b5d61b8Smrg if (!extra) 12261b5d61b8Smrg return BadAlloc; 12271b5d61b8Smrg } 12281b5d61b8Smrg 12291b5d61b8Smrg outputs = (RROutput *) extra; 12301b5d61b8Smrg possible = (RROutput *) (outputs + rep.nOutput); 12311b5d61b8Smrg 12321b5d61b8Smrg for (i = 0; i < crtc->numOutputs; i++) { 12331b5d61b8Smrg outputs[i] = crtc->outputs[i]->id; 12341b5d61b8Smrg if (client->swapped) 12351b5d61b8Smrg swapl(&outputs[i]); 12361b5d61b8Smrg } 12371b5d61b8Smrg k = 0; 12381b5d61b8Smrg for (i = 0; i < pScrPriv->numOutputs; i++) { 12391b5d61b8Smrg if (!RROutputIsLeased(pScrPriv->outputs[i])) { 12401b5d61b8Smrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 12411b5d61b8Smrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) { 12421b5d61b8Smrg possible[k] = pScrPriv->outputs[i]->id; 12431b5d61b8Smrg if (client->swapped) 12441b5d61b8Smrg swapl(&possible[k]); 12451b5d61b8Smrg k++; 12461b5d61b8Smrg } 12471b5d61b8Smrg } 12481b5d61b8Smrg } 12491b5d61b8Smrg } 125035c4bbdfSmrg 125105b261ecSmrg if (client->swapped) { 125235c4bbdfSmrg swaps(&rep.sequenceNumber); 125335c4bbdfSmrg swapl(&rep.length); 125435c4bbdfSmrg swapl(&rep.timestamp); 125535c4bbdfSmrg swaps(&rep.x); 125635c4bbdfSmrg swaps(&rep.y); 125735c4bbdfSmrg swaps(&rep.width); 125835c4bbdfSmrg swaps(&rep.height); 125935c4bbdfSmrg swapl(&rep.mode); 126035c4bbdfSmrg swaps(&rep.rotation); 126135c4bbdfSmrg swaps(&rep.rotations); 126235c4bbdfSmrg swaps(&rep.nOutput); 126335c4bbdfSmrg swaps(&rep.nPossibleOutput); 126435c4bbdfSmrg } 126535c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep); 126635c4bbdfSmrg if (extraLen) { 126735c4bbdfSmrg WriteToClient(client, extraLen, extra); 126835c4bbdfSmrg free(extra); 126905b261ecSmrg } 127035c4bbdfSmrg 12716747b715Smrg return Success; 127205b261ecSmrg} 127305b261ecSmrg 127405b261ecSmrgint 127535c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client) 127605b261ecSmrg{ 127705b261ecSmrg REQUEST(xRRSetCrtcConfigReq); 127835c4bbdfSmrg xRRSetCrtcConfigReply rep; 127935c4bbdfSmrg ScreenPtr pScreen; 128035c4bbdfSmrg rrScrPrivPtr pScrPriv; 128135c4bbdfSmrg RRCrtcPtr crtc; 128235c4bbdfSmrg RRModePtr mode; 1283ed6184dfSmrg unsigned int numOutputs; 128435c4bbdfSmrg RROutputPtr *outputs = NULL; 128535c4bbdfSmrg RROutput *outputIds; 128635c4bbdfSmrg TimeStamp time; 128735c4bbdfSmrg Rotation rotation; 128835c4bbdfSmrg int ret, i, j; 128935c4bbdfSmrg CARD8 status; 129035c4bbdfSmrg 129105b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 129235c4bbdfSmrg numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq))); 129335c4bbdfSmrg 12946747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 12956747b715Smrg 12961b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 12971b5d61b8Smrg return BadAccess; 12981b5d61b8Smrg 129935c4bbdfSmrg if (stuff->mode == None) { 130035c4bbdfSmrg mode = NULL; 130135c4bbdfSmrg if (numOutputs > 0) 130235c4bbdfSmrg return BadMatch; 130305b261ecSmrg } 130435c4bbdfSmrg else { 130535c4bbdfSmrg VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 130635c4bbdfSmrg if (numOutputs == 0) 130735c4bbdfSmrg return BadMatch; 130805b261ecSmrg } 130935c4bbdfSmrg if (numOutputs) { 131035c4bbdfSmrg outputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 131135c4bbdfSmrg if (!outputs) 131235c4bbdfSmrg return BadAlloc; 131305b261ecSmrg } 131405b261ecSmrg else 131535c4bbdfSmrg outputs = NULL; 131635c4bbdfSmrg 131705b261ecSmrg outputIds = (RROutput *) (stuff + 1); 131835c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 131935c4bbdfSmrg ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i], 132035c4bbdfSmrg RROutputType, client, DixSetAttrAccess); 132135c4bbdfSmrg if (ret != Success) { 132235c4bbdfSmrg free(outputs); 132335c4bbdfSmrg return ret; 132435c4bbdfSmrg } 13251b5d61b8Smrg 13261b5d61b8Smrg if (RROutputIsLeased(outputs[i])) { 13271b5d61b8Smrg free(outputs); 13281b5d61b8Smrg return BadAccess; 13291b5d61b8Smrg } 13301b5d61b8Smrg 133135c4bbdfSmrg /* validate crtc for this output */ 133235c4bbdfSmrg for (j = 0; j < outputs[i]->numCrtcs; j++) 133335c4bbdfSmrg if (outputs[i]->crtcs[j] == crtc) 133435c4bbdfSmrg break; 133535c4bbdfSmrg if (j == outputs[i]->numCrtcs) { 133635c4bbdfSmrg free(outputs); 133735c4bbdfSmrg return BadMatch; 133835c4bbdfSmrg } 133935c4bbdfSmrg /* validate mode for this output */ 134035c4bbdfSmrg for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) { 134135c4bbdfSmrg RRModePtr m = (j < outputs[i]->numModes ? 134235c4bbdfSmrg outputs[i]->modes[j] : 134335c4bbdfSmrg outputs[i]->userModes[j - outputs[i]->numModes]); 134435c4bbdfSmrg if (m == mode) 134535c4bbdfSmrg break; 134635c4bbdfSmrg } 134735c4bbdfSmrg if (j == outputs[i]->numModes + outputs[i]->numUserModes) { 134835c4bbdfSmrg free(outputs); 134935c4bbdfSmrg return BadMatch; 135035c4bbdfSmrg } 135105b261ecSmrg } 135205b261ecSmrg /* validate clones */ 135335c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 135435c4bbdfSmrg for (j = 0; j < numOutputs; j++) { 135535c4bbdfSmrg int k; 135635c4bbdfSmrg 135735c4bbdfSmrg if (i == j) 135835c4bbdfSmrg continue; 135935c4bbdfSmrg for (k = 0; k < outputs[i]->numClones; k++) { 136035c4bbdfSmrg if (outputs[i]->clones[k] == outputs[j]) 136135c4bbdfSmrg break; 136235c4bbdfSmrg } 136335c4bbdfSmrg if (k == outputs[i]->numClones) { 136435c4bbdfSmrg free(outputs); 136535c4bbdfSmrg return BadMatch; 136635c4bbdfSmrg } 136735c4bbdfSmrg } 136805b261ecSmrg } 136905b261ecSmrg 137005b261ecSmrg pScreen = crtc->pScreen; 137105b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 137235c4bbdfSmrg 137305b261ecSmrg time = ClientTimeToServerTime(stuff->timestamp); 137435c4bbdfSmrg 137535c4bbdfSmrg if (!pScrPriv) { 137635c4bbdfSmrg time = currentTime; 137735c4bbdfSmrg status = RRSetConfigFailed; 137835c4bbdfSmrg goto sendReply; 137905b261ecSmrg } 138035c4bbdfSmrg 138105b261ecSmrg /* 138205b261ecSmrg * Validate requested rotation 138305b261ecSmrg */ 138405b261ecSmrg rotation = (Rotation) stuff->rotation; 138505b261ecSmrg 138605b261ecSmrg /* test the rotation bits only! */ 138705b261ecSmrg switch (rotation & 0xf) { 138805b261ecSmrg case RR_Rotate_0: 138905b261ecSmrg case RR_Rotate_90: 139005b261ecSmrg case RR_Rotate_180: 139105b261ecSmrg case RR_Rotate_270: 139235c4bbdfSmrg break; 139305b261ecSmrg default: 139435c4bbdfSmrg /* 139535c4bbdfSmrg * Invalid rotation 139635c4bbdfSmrg */ 139735c4bbdfSmrg client->errorValue = stuff->rotation; 139835c4bbdfSmrg free(outputs); 139935c4bbdfSmrg return BadValue; 140005b261ecSmrg } 140105b261ecSmrg 140235c4bbdfSmrg if (mode) { 140335c4bbdfSmrg if ((~crtc->rotations) & rotation) { 140435c4bbdfSmrg /* 140535c4bbdfSmrg * requested rotation or reflection not supported by screen 140635c4bbdfSmrg */ 140735c4bbdfSmrg client->errorValue = stuff->rotation; 140835c4bbdfSmrg free(outputs); 140935c4bbdfSmrg return BadMatch; 141035c4bbdfSmrg } 141135c4bbdfSmrg 141205b261ecSmrg#ifdef RANDR_12_INTERFACE 141335c4bbdfSmrg /* 141435c4bbdfSmrg * Check screen size bounds if the DDX provides a 1.2 interface 141535c4bbdfSmrg * for setting screen size. Else, assume the CrtcSet sets 141635c4bbdfSmrg * the size along with the mode. If the driver supports transforms, 141735c4bbdfSmrg * then it must allow crtcs to display a subset of the screen, so 141835c4bbdfSmrg * only do this check for drivers without transform support. 141935c4bbdfSmrg */ 142035c4bbdfSmrg if (pScrPriv->rrScreenSetSize && !crtc->transforms) { 142135c4bbdfSmrg int source_width; 142235c4bbdfSmrg int source_height; 142335c4bbdfSmrg PictTransform transform; 142435c4bbdfSmrg struct pixman_f_transform f_transform, f_inverse; 142535c4bbdfSmrg int width, height; 142635c4bbdfSmrg 142735c4bbdfSmrg if (pScreen->isGPU) { 1428ed6184dfSmrg width = pScreen->current_primary->width; 1429ed6184dfSmrg height = pScreen->current_primary->height; 143035c4bbdfSmrg } 143135c4bbdfSmrg else { 143235c4bbdfSmrg width = pScreen->width; 143335c4bbdfSmrg height = pScreen->height; 143435c4bbdfSmrg } 143535c4bbdfSmrg 143635c4bbdfSmrg RRTransformCompute(stuff->x, stuff->y, 143735c4bbdfSmrg mode->mode.width, mode->mode.height, 143835c4bbdfSmrg rotation, 143935c4bbdfSmrg &crtc->client_pending_transform, 144035c4bbdfSmrg &transform, &f_transform, &f_inverse); 144135c4bbdfSmrg 144235c4bbdfSmrg RRModeGetScanoutSize(mode, &transform, &source_width, 144335c4bbdfSmrg &source_height); 144435c4bbdfSmrg if (stuff->x + source_width > width) { 144535c4bbdfSmrg client->errorValue = stuff->x; 144635c4bbdfSmrg free(outputs); 144735c4bbdfSmrg return BadValue; 144835c4bbdfSmrg } 144935c4bbdfSmrg 145035c4bbdfSmrg if (stuff->y + source_height > height) { 145135c4bbdfSmrg client->errorValue = stuff->y; 145235c4bbdfSmrg free(outputs); 145335c4bbdfSmrg return BadValue; 145435c4bbdfSmrg } 145535c4bbdfSmrg } 145605b261ecSmrg#endif 145705b261ecSmrg } 145835c4bbdfSmrg 145935c4bbdfSmrg if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y, 146035c4bbdfSmrg rotation, numOutputs, outputs)) { 146135c4bbdfSmrg status = RRSetConfigFailed; 146235c4bbdfSmrg goto sendReply; 146305b261ecSmrg } 146435c4bbdfSmrg status = RRSetConfigSuccess; 146552397711Smrg pScrPriv->lastSetTime = time; 146635c4bbdfSmrg 146735c4bbdfSmrg sendReply: 14686747b715Smrg free(outputs); 146935c4bbdfSmrg 147035c4bbdfSmrg rep = (xRRSetCrtcConfigReply) { 147135c4bbdfSmrg .type = X_Reply, 147235c4bbdfSmrg .status = status, 147335c4bbdfSmrg .sequenceNumber = client->sequence, 147435c4bbdfSmrg .length = 0, 147535c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 147635c4bbdfSmrg }; 147735c4bbdfSmrg 147835c4bbdfSmrg if (client->swapped) { 147935c4bbdfSmrg swaps(&rep.sequenceNumber); 148035c4bbdfSmrg swapl(&rep.length); 148135c4bbdfSmrg swapl(&rep.newTimestamp); 148205b261ecSmrg } 148335c4bbdfSmrg WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep); 148435c4bbdfSmrg 14856747b715Smrg return Success; 148605b261ecSmrg} 148705b261ecSmrg 14884642e01fSmrgint 148935c4bbdfSmrgProcRRGetPanning(ClientPtr client) 14904642e01fSmrg{ 14914642e01fSmrg REQUEST(xRRGetPanningReq); 149235c4bbdfSmrg xRRGetPanningReply rep; 149335c4bbdfSmrg RRCrtcPtr crtc; 149435c4bbdfSmrg ScreenPtr pScreen; 149535c4bbdfSmrg rrScrPrivPtr pScrPriv; 149635c4bbdfSmrg BoxRec total; 149735c4bbdfSmrg BoxRec tracking; 149835c4bbdfSmrg INT16 border[4]; 149935c4bbdfSmrg 15004642e01fSmrg REQUEST_SIZE_MATCH(xRRGetPanningReq); 15016747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 15024642e01fSmrg 15034642e01fSmrg /* All crtcs must be associated with screens before client 15044642e01fSmrg * requests are processed 15054642e01fSmrg */ 15064642e01fSmrg pScreen = crtc->pScreen; 15074642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 15084642e01fSmrg 15094642e01fSmrg if (!pScrPriv) 151035c4bbdfSmrg return RRErrorBase + BadRRCrtc; 15114642e01fSmrg 151235c4bbdfSmrg rep = (xRRGetPanningReply) { 151335c4bbdfSmrg .type = X_Reply, 151435c4bbdfSmrg .status = RRSetConfigSuccess, 151535c4bbdfSmrg .sequenceNumber = client->sequence, 151635c4bbdfSmrg .length = 1, 151735c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 151835c4bbdfSmrg }; 15194642e01fSmrg 15204642e01fSmrg if (pScrPriv->rrGetPanning && 152135c4bbdfSmrg pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) { 152235c4bbdfSmrg rep.left = total.x1; 152335c4bbdfSmrg rep.top = total.y1; 152435c4bbdfSmrg rep.width = total.x2 - total.x1; 152535c4bbdfSmrg rep.height = total.y2 - total.y1; 152635c4bbdfSmrg rep.track_left = tracking.x1; 152735c4bbdfSmrg rep.track_top = tracking.y1; 152835c4bbdfSmrg rep.track_width = tracking.x2 - tracking.x1; 152935c4bbdfSmrg rep.track_height = tracking.y2 - tracking.y1; 153035c4bbdfSmrg rep.border_left = border[0]; 153135c4bbdfSmrg rep.border_top = border[1]; 153235c4bbdfSmrg rep.border_right = border[2]; 153335c4bbdfSmrg rep.border_bottom = border[3]; 15344642e01fSmrg } 15354642e01fSmrg 15364642e01fSmrg if (client->swapped) { 153735c4bbdfSmrg swaps(&rep.sequenceNumber); 153835c4bbdfSmrg swapl(&rep.length); 153935c4bbdfSmrg swapl(&rep.timestamp); 154035c4bbdfSmrg swaps(&rep.left); 154135c4bbdfSmrg swaps(&rep.top); 154235c4bbdfSmrg swaps(&rep.width); 154335c4bbdfSmrg swaps(&rep.height); 154435c4bbdfSmrg swaps(&rep.track_left); 154535c4bbdfSmrg swaps(&rep.track_top); 154635c4bbdfSmrg swaps(&rep.track_width); 154735c4bbdfSmrg swaps(&rep.track_height); 154835c4bbdfSmrg swaps(&rep.border_left); 154935c4bbdfSmrg swaps(&rep.border_top); 155035c4bbdfSmrg swaps(&rep.border_right); 155135c4bbdfSmrg swaps(&rep.border_bottom); 155235c4bbdfSmrg } 155335c4bbdfSmrg WriteToClient(client, sizeof(xRRGetPanningReply), &rep); 15546747b715Smrg return Success; 15554642e01fSmrg} 15564642e01fSmrg 15574642e01fSmrgint 155835c4bbdfSmrgProcRRSetPanning(ClientPtr client) 15594642e01fSmrg{ 15604642e01fSmrg REQUEST(xRRSetPanningReq); 156135c4bbdfSmrg xRRSetPanningReply rep; 156235c4bbdfSmrg RRCrtcPtr crtc; 156335c4bbdfSmrg ScreenPtr pScreen; 156435c4bbdfSmrg rrScrPrivPtr pScrPriv; 156535c4bbdfSmrg TimeStamp time; 156635c4bbdfSmrg BoxRec total; 156735c4bbdfSmrg BoxRec tracking; 156835c4bbdfSmrg INT16 border[4]; 156935c4bbdfSmrg CARD8 status; 157035c4bbdfSmrg 15714642e01fSmrg REQUEST_SIZE_MATCH(xRRSetPanningReq); 15726747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 15734642e01fSmrg 15741b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 15751b5d61b8Smrg return BadAccess; 15761b5d61b8Smrg 15774642e01fSmrg /* All crtcs must be associated with screens before client 15784642e01fSmrg * requests are processed 15794642e01fSmrg */ 15804642e01fSmrg pScreen = crtc->pScreen; 15814642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 15824642e01fSmrg 15834642e01fSmrg if (!pScrPriv) { 158435c4bbdfSmrg time = currentTime; 158535c4bbdfSmrg status = RRSetConfigFailed; 158635c4bbdfSmrg goto sendReply; 15874642e01fSmrg } 158835c4bbdfSmrg 15894642e01fSmrg time = ClientTimeToServerTime(stuff->timestamp); 159035c4bbdfSmrg 15914642e01fSmrg if (!pScrPriv->rrGetPanning) 159235c4bbdfSmrg return RRErrorBase + BadRRCrtc; 15934642e01fSmrg 159435c4bbdfSmrg total.x1 = stuff->left; 159535c4bbdfSmrg total.y1 = stuff->top; 159635c4bbdfSmrg total.x2 = total.x1 + stuff->width; 159735c4bbdfSmrg total.y2 = total.y1 + stuff->height; 15984642e01fSmrg tracking.x1 = stuff->track_left; 15994642e01fSmrg tracking.y1 = stuff->track_top; 16004642e01fSmrg tracking.x2 = tracking.x1 + stuff->track_width; 16014642e01fSmrg tracking.y2 = tracking.y1 + stuff->track_height; 160235c4bbdfSmrg border[0] = stuff->border_left; 160335c4bbdfSmrg border[1] = stuff->border_top; 160435c4bbdfSmrg border[2] = stuff->border_right; 160535c4bbdfSmrg border[3] = stuff->border_bottom; 16064642e01fSmrg 160735c4bbdfSmrg if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border)) 160835c4bbdfSmrg return BadMatch; 16094642e01fSmrg 161052397711Smrg pScrPriv->lastSetTime = time; 161152397711Smrg 161235c4bbdfSmrg status = RRSetConfigSuccess; 16134642e01fSmrg 161435c4bbdfSmrg sendReply: 161535c4bbdfSmrg rep = (xRRSetPanningReply) { 161635c4bbdfSmrg .type = X_Reply, 161735c4bbdfSmrg .status = status, 161835c4bbdfSmrg .sequenceNumber = client->sequence, 161935c4bbdfSmrg .length = 0, 162035c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 162135c4bbdfSmrg }; 16224642e01fSmrg 16234642e01fSmrg if (client->swapped) { 162435c4bbdfSmrg swaps(&rep.sequenceNumber); 162535c4bbdfSmrg swapl(&rep.length); 162635c4bbdfSmrg swapl(&rep.newTimestamp); 16274642e01fSmrg } 162835c4bbdfSmrg WriteToClient(client, sizeof(xRRSetPanningReply), &rep); 16296747b715Smrg return Success; 16304642e01fSmrg} 16314642e01fSmrg 163205b261ecSmrgint 163335c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client) 163405b261ecSmrg{ 163505b261ecSmrg REQUEST(xRRGetCrtcGammaSizeReq); 163635c4bbdfSmrg xRRGetCrtcGammaSizeReply reply; 163735c4bbdfSmrg RRCrtcPtr crtc; 163805b261ecSmrg 163905b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 16406747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 16416747b715Smrg 16426747b715Smrg /* Gamma retrieval failed, any better error? */ 16436747b715Smrg if (!RRCrtcGammaGet(crtc)) 16446747b715Smrg return RRErrorBase + BadRRCrtc; 16456747b715Smrg 164635c4bbdfSmrg reply = (xRRGetCrtcGammaSizeReply) { 164735c4bbdfSmrg .type = X_Reply, 164835c4bbdfSmrg .sequenceNumber = client->sequence, 164935c4bbdfSmrg .length = 0, 165035c4bbdfSmrg .size = crtc->gammaSize 165135c4bbdfSmrg }; 165205b261ecSmrg if (client->swapped) { 165335c4bbdfSmrg swaps(&reply.sequenceNumber); 165435c4bbdfSmrg swapl(&reply.length); 165535c4bbdfSmrg swaps(&reply.size); 165605b261ecSmrg } 165735c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply); 16586747b715Smrg return Success; 165905b261ecSmrg} 166005b261ecSmrg 166105b261ecSmrgint 166235c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client) 166305b261ecSmrg{ 166405b261ecSmrg REQUEST(xRRGetCrtcGammaReq); 166535c4bbdfSmrg xRRGetCrtcGammaReply reply; 166635c4bbdfSmrg RRCrtcPtr crtc; 166735c4bbdfSmrg unsigned long len; 166835c4bbdfSmrg char *extra = NULL; 166935c4bbdfSmrg 167005b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 16716747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 16726747b715Smrg 16736747b715Smrg /* Gamma retrieval failed, any better error? */ 16746747b715Smrg if (!RRCrtcGammaGet(crtc)) 16756747b715Smrg return RRErrorBase + BadRRCrtc; 16766747b715Smrg 167705b261ecSmrg len = crtc->gammaSize * 3 * 2; 167835c4bbdfSmrg 16794642e01fSmrg if (crtc->gammaSize) { 168035c4bbdfSmrg extra = malloc(len); 168135c4bbdfSmrg if (!extra) 168235c4bbdfSmrg return BadAlloc; 16834642e01fSmrg } 16844642e01fSmrg 168535c4bbdfSmrg reply = (xRRGetCrtcGammaReply) { 168635c4bbdfSmrg .type = X_Reply, 168735c4bbdfSmrg .sequenceNumber = client->sequence, 168835c4bbdfSmrg .length = bytes_to_int32(len), 168935c4bbdfSmrg .size = crtc->gammaSize 169035c4bbdfSmrg }; 169105b261ecSmrg if (client->swapped) { 169235c4bbdfSmrg swaps(&reply.sequenceNumber); 169335c4bbdfSmrg swapl(&reply.length); 169435c4bbdfSmrg swaps(&reply.size); 169505b261ecSmrg } 169635c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply); 169735c4bbdfSmrg if (crtc->gammaSize) { 169835c4bbdfSmrg memcpy(extra, crtc->gammaRed, len); 169935c4bbdfSmrg client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 170035c4bbdfSmrg WriteSwappedDataToClient(client, len, extra); 170135c4bbdfSmrg free(extra); 170205b261ecSmrg } 17036747b715Smrg return Success; 170405b261ecSmrg} 170505b261ecSmrg 170605b261ecSmrgint 170735c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client) 170805b261ecSmrg{ 170905b261ecSmrg REQUEST(xRRSetCrtcGammaReq); 171035c4bbdfSmrg RRCrtcPtr crtc; 171135c4bbdfSmrg unsigned long len; 171235c4bbdfSmrg CARD16 *red, *green, *blue; 171335c4bbdfSmrg 171405b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 17156747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 171635c4bbdfSmrg 17171b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 17181b5d61b8Smrg return BadAccess; 17191b5d61b8Smrg 172035c4bbdfSmrg len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq)); 172105b261ecSmrg if (len < (stuff->size * 3 + 1) >> 1) 172235c4bbdfSmrg return BadLength; 172305b261ecSmrg 172405b261ecSmrg if (stuff->size != crtc->gammaSize) 172535c4bbdfSmrg return BadMatch; 172635c4bbdfSmrg 172705b261ecSmrg red = (CARD16 *) (stuff + 1); 172805b261ecSmrg green = red + crtc->gammaSize; 172905b261ecSmrg blue = green + crtc->gammaSize; 173035c4bbdfSmrg 173135c4bbdfSmrg RRCrtcGammaSet(crtc, red, green, blue); 173205b261ecSmrg 173305b261ecSmrg return Success; 173405b261ecSmrg} 173505b261ecSmrg 17364642e01fSmrg/* Version 1.3 additions */ 17374642e01fSmrg 17384642e01fSmrgint 173935c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client) 17404642e01fSmrg{ 17414642e01fSmrg REQUEST(xRRSetCrtcTransformReq); 174235c4bbdfSmrg RRCrtcPtr crtc; 174335c4bbdfSmrg PictTransform transform; 17444642e01fSmrg struct pixman_f_transform f_transform, f_inverse; 174535c4bbdfSmrg char *filter; 174635c4bbdfSmrg int nbytes; 174735c4bbdfSmrg xFixed *params; 174835c4bbdfSmrg int nparams; 17494642e01fSmrg 17504642e01fSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 17516747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 17524642e01fSmrg 17531b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 17541b5d61b8Smrg return BadAccess; 17551b5d61b8Smrg 175635c4bbdfSmrg PictTransform_from_xRenderTransform(&transform, &stuff->transform); 175735c4bbdfSmrg pixman_f_transform_from_pixman_transform(&f_transform, &transform); 175835c4bbdfSmrg if (!pixman_f_transform_invert(&f_inverse, &f_transform)) 175935c4bbdfSmrg return BadMatch; 17604642e01fSmrg 17614642e01fSmrg filter = (char *) (stuff + 1); 17624642e01fSmrg nbytes = stuff->nbytesFilter; 17636747b715Smrg params = (xFixed *) (filter + pad_to_int32(nbytes)); 17644642e01fSmrg nparams = ((xFixed *) stuff + client->req_len) - params; 17654642e01fSmrg if (nparams < 0) 176635c4bbdfSmrg return BadLength; 17674642e01fSmrg 176835c4bbdfSmrg return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse, 176935c4bbdfSmrg filter, nbytes, params, nparams); 17704642e01fSmrg} 17714642e01fSmrg 17724642e01fSmrg#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 177335c4bbdfSmrg 17744642e01fSmrgstatic int 177535c4bbdfSmrgtransform_filter_length(RRTransformPtr transform) 17764642e01fSmrg{ 177735c4bbdfSmrg int nbytes, nparams; 17784642e01fSmrg 17794642e01fSmrg if (transform->filter == NULL) 178035c4bbdfSmrg return 0; 178135c4bbdfSmrg nbytes = strlen(transform->filter->name); 17824642e01fSmrg nparams = transform->nparams; 178335c4bbdfSmrg return pad_to_int32(nbytes) + (nparams * sizeof(xFixed)); 17844642e01fSmrg} 17854642e01fSmrg 17864642e01fSmrgstatic int 178735c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output, 178835c4bbdfSmrg CARD16 *nbytesFilter, 178935c4bbdfSmrg CARD16 *nparamsFilter, RRTransformPtr transform) 17904642e01fSmrg{ 179135c4bbdfSmrg int nbytes, nparams; 17924642e01fSmrg 17934642e01fSmrg if (transform->filter == NULL) { 179435c4bbdfSmrg *nbytesFilter = 0; 179535c4bbdfSmrg *nparamsFilter = 0; 179635c4bbdfSmrg return 0; 17974642e01fSmrg } 179835c4bbdfSmrg nbytes = strlen(transform->filter->name); 17994642e01fSmrg nparams = transform->nparams; 18004642e01fSmrg *nbytesFilter = nbytes; 18014642e01fSmrg *nparamsFilter = nparams; 180235c4bbdfSmrg memcpy(output, transform->filter->name, nbytes); 18034642e01fSmrg while ((nbytes & 3) != 0) 180435c4bbdfSmrg output[nbytes++] = 0; 180535c4bbdfSmrg memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed)); 18064642e01fSmrg if (client->swapped) { 180735c4bbdfSmrg swaps(nbytesFilter); 180835c4bbdfSmrg swaps(nparamsFilter); 180935c4bbdfSmrg SwapLongs((CARD32 *) (output + nbytes), nparams); 18104642e01fSmrg } 181135c4bbdfSmrg nbytes += nparams * sizeof(xFixed); 18124642e01fSmrg return nbytes; 18134642e01fSmrg} 18144642e01fSmrg 18154642e01fSmrgstatic void 181635c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire, 181735c4bbdfSmrg PictTransform * pict) 18184642e01fSmrg{ 181935c4bbdfSmrg xRenderTransform_from_PictTransform(wire, pict); 18204642e01fSmrg if (client->swapped) 182135c4bbdfSmrg SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 18224642e01fSmrg} 18234642e01fSmrg 18244642e01fSmrgint 182535c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client) 18264642e01fSmrg{ 18274642e01fSmrg REQUEST(xRRGetCrtcTransformReq); 182835c4bbdfSmrg xRRGetCrtcTransformReply *reply; 182935c4bbdfSmrg RRCrtcPtr crtc; 183035c4bbdfSmrg int nextra; 183135c4bbdfSmrg RRTransformPtr current, pending; 183235c4bbdfSmrg char *extra; 18334642e01fSmrg 183435c4bbdfSmrg REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq); 18356747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 18364642e01fSmrg 18374642e01fSmrg pending = &crtc->client_pending_transform; 18384642e01fSmrg current = &crtc->client_current_transform; 18394642e01fSmrg 184035c4bbdfSmrg nextra = (transform_filter_length(pending) + 184135c4bbdfSmrg transform_filter_length(current)); 18424642e01fSmrg 184335c4bbdfSmrg reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra); 18444642e01fSmrg if (!reply) 184535c4bbdfSmrg return BadAlloc; 18464642e01fSmrg 18474642e01fSmrg extra = (char *) (reply + 1); 18484642e01fSmrg reply->type = X_Reply; 18494642e01fSmrg reply->sequenceNumber = client->sequence; 18506747b715Smrg reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 18514642e01fSmrg 18524642e01fSmrg reply->hasTransforms = crtc->transforms; 18534642e01fSmrg 185435c4bbdfSmrg transform_encode(client, &reply->pendingTransform, &pending->transform); 185535c4bbdfSmrg extra += transform_filter_encode(client, extra, 185635c4bbdfSmrg &reply->pendingNbytesFilter, 185735c4bbdfSmrg &reply->pendingNparamsFilter, pending); 18584642e01fSmrg 185935c4bbdfSmrg transform_encode(client, &reply->currentTransform, ¤t->transform); 186035c4bbdfSmrg extra += transform_filter_encode(client, extra, 186135c4bbdfSmrg &reply->currentNbytesFilter, 186235c4bbdfSmrg &reply->currentNparamsFilter, current); 18634642e01fSmrg 18644642e01fSmrg if (client->swapped) { 186535c4bbdfSmrg swaps(&reply->sequenceNumber); 186635c4bbdfSmrg swapl(&reply->length); 18674642e01fSmrg } 186835c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply); 18696747b715Smrg free(reply); 18706747b715Smrg return Success; 18714642e01fSmrg} 187235c4bbdfSmrg 187335c4bbdfSmrgstatic Bool 187435c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y) 187535c4bbdfSmrg{ 187635c4bbdfSmrg rrScrPriv(pScreen); 187735c4bbdfSmrg int i; 187835c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 187935c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 188035c4bbdfSmrg 188135c4bbdfSmrg int left, right, top, bottom; 188235c4bbdfSmrg 18831b5d61b8Smrg if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 18841b5d61b8Smrg continue; 188535c4bbdfSmrg 188635c4bbdfSmrg if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom)) 188735c4bbdfSmrg return TRUE; 188835c4bbdfSmrg } 188935c4bbdfSmrg return FALSE; 189035c4bbdfSmrg} 189135c4bbdfSmrg 189235c4bbdfSmrgstatic Bool 189335c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y) 189435c4bbdfSmrg{ 189535c4bbdfSmrg rrScrPriv(pScreen); 189635c4bbdfSmrg int i; 189735c4bbdfSmrg 189835c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 189935c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 190035c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 190135c4bbdfSmrg int nx, ny; 190235c4bbdfSmrg int left, right, top, bottom; 190335c4bbdfSmrg 19041b5d61b8Smrg if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 19051b5d61b8Smrg continue; 190635c4bbdfSmrg 190735c4bbdfSmrg miPointerGetPosition(pDev, &nx, &ny); 190835c4bbdfSmrg 190935c4bbdfSmrg if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) { 191035c4bbdfSmrg if (*x < left) 191135c4bbdfSmrg *x = left; 191235c4bbdfSmrg if (*x >= right) 191335c4bbdfSmrg *x = right - 1; 191435c4bbdfSmrg if (*y < top) 191535c4bbdfSmrg *y = top; 191635c4bbdfSmrg if (*y >= bottom) 191735c4bbdfSmrg *y = bottom - 1; 191835c4bbdfSmrg 191935c4bbdfSmrg return TRUE; 192035c4bbdfSmrg } 192135c4bbdfSmrg } 192235c4bbdfSmrg return FALSE; 192335c4bbdfSmrg} 192435c4bbdfSmrg 192535c4bbdfSmrgvoid 192635c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, 192735c4bbdfSmrg int *y) 192835c4bbdfSmrg{ 192935c4bbdfSmrg rrScrPriv(pScreen); 193035c4bbdfSmrg Bool ret; 1931ed6184dfSmrg ScreenPtr secondary; 193235c4bbdfSmrg 193335c4bbdfSmrg /* intentional dead space -> let it float */ 193435c4bbdfSmrg if (pScrPriv->discontiguous) 193535c4bbdfSmrg return; 193635c4bbdfSmrg 193735c4bbdfSmrg /* if we're moving inside a crtc, we're fine */ 193835c4bbdfSmrg ret = check_all_screen_crtcs(pScreen, x, y); 193935c4bbdfSmrg if (ret == TRUE) 194035c4bbdfSmrg return; 194135c4bbdfSmrg 1942ed6184dfSmrg xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 1943ed6184dfSmrg if (!secondary->is_output_secondary) 19441b5d61b8Smrg continue; 19451b5d61b8Smrg 1946ed6184dfSmrg ret = check_all_screen_crtcs(secondary, x, y); 194735c4bbdfSmrg if (ret == TRUE) 194835c4bbdfSmrg return; 194935c4bbdfSmrg } 195035c4bbdfSmrg 195135c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 195235c4bbdfSmrg ret = constrain_all_screen_crtcs(pDev, pScreen, x, y); 195335c4bbdfSmrg if (ret == TRUE) 195435c4bbdfSmrg return; 195535c4bbdfSmrg 1956ed6184dfSmrg xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 1957ed6184dfSmrg if (!secondary->is_output_secondary) 19581b5d61b8Smrg continue; 19591b5d61b8Smrg 1960ed6184dfSmrg ret = constrain_all_screen_crtcs(pDev, secondary, x, y); 196135c4bbdfSmrg if (ret == TRUE) 196235c4bbdfSmrg return; 196335c4bbdfSmrg } 196435c4bbdfSmrg} 196535c4bbdfSmrg 196635c4bbdfSmrgBool 196735c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable) 196835c4bbdfSmrg{ 196935c4bbdfSmrg rrScrPriv(pDrawable->pScreen); 197035c4bbdfSmrg Bool ret = TRUE; 197135c4bbdfSmrg PixmapPtr *saved_scanout_pixmap; 197235c4bbdfSmrg int i; 197335c4bbdfSmrg 197435c4bbdfSmrg saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs); 197535c4bbdfSmrg if (saved_scanout_pixmap == NULL) 197635c4bbdfSmrg return FALSE; 197735c4bbdfSmrg 197835c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 197935c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 198035c4bbdfSmrg Bool size_fits; 198135c4bbdfSmrg 198235c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 198335c4bbdfSmrg 198435c4bbdfSmrg if (!crtc->mode && enable) 198535c4bbdfSmrg continue; 198635c4bbdfSmrg if (!crtc->scanout_pixmap && !enable) 198735c4bbdfSmrg continue; 198835c4bbdfSmrg 19891b5d61b8Smrg /* not supported with double buffering, needs ABI change for 2 ppix */ 19901b5d61b8Smrg if (crtc->scanout_pixmap_back) { 19911b5d61b8Smrg ret = FALSE; 19921b5d61b8Smrg continue; 19931b5d61b8Smrg } 19941b5d61b8Smrg 199535c4bbdfSmrg size_fits = (crtc->mode && 199635c4bbdfSmrg crtc->x == pDrawable->x && 199735c4bbdfSmrg crtc->y == pDrawable->y && 199835c4bbdfSmrg crtc->mode->mode.width == pDrawable->width && 199935c4bbdfSmrg crtc->mode->mode.height == pDrawable->height); 200035c4bbdfSmrg 200135c4bbdfSmrg /* is the pixmap already set? */ 200235c4bbdfSmrg if (crtc->scanout_pixmap == pPixmap) { 200335c4bbdfSmrg /* if its a disable then don't care about size */ 200435c4bbdfSmrg if (enable == FALSE) { 200535c4bbdfSmrg /* set scanout to NULL */ 200635c4bbdfSmrg crtc->scanout_pixmap = NULL; 200735c4bbdfSmrg } 200835c4bbdfSmrg else if (!size_fits) { 200935c4bbdfSmrg /* if the size no longer fits then drop off */ 201035c4bbdfSmrg crtc->scanout_pixmap = NULL; 201135c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 201235c4bbdfSmrg 201335c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 201435c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 201535c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 201635c4bbdfSmrg ret = FALSE; 201735c4bbdfSmrg } 201835c4bbdfSmrg else { 201935c4bbdfSmrg /* if the size fits then we are already setup */ 202035c4bbdfSmrg } 202135c4bbdfSmrg } 202235c4bbdfSmrg else { 202335c4bbdfSmrg if (!size_fits) 202435c4bbdfSmrg ret = FALSE; 202535c4bbdfSmrg else if (enable) 202635c4bbdfSmrg crtc->scanout_pixmap = pPixmap; 202735c4bbdfSmrg else 202835c4bbdfSmrg /* reject an attempt to disable someone else's scanout_pixmap */ 202935c4bbdfSmrg ret = FALSE; 203035c4bbdfSmrg } 203135c4bbdfSmrg } 203235c4bbdfSmrg 203335c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 203435c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 203535c4bbdfSmrg 203635c4bbdfSmrg if (crtc->scanout_pixmap == saved_scanout_pixmap[i]) 203735c4bbdfSmrg continue; 203835c4bbdfSmrg 203935c4bbdfSmrg if (ret) { 204035c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 204135c4bbdfSmrg 204235c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 204335c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 204435c4bbdfSmrg } 204535c4bbdfSmrg else 204635c4bbdfSmrg crtc->scanout_pixmap = saved_scanout_pixmap[i]; 204735c4bbdfSmrg } 204835c4bbdfSmrg free(saved_scanout_pixmap); 204935c4bbdfSmrg 205035c4bbdfSmrg return ret; 205135c4bbdfSmrg} 20521b5d61b8Smrg 20531b5d61b8SmrgBool 20541b5d61b8SmrgRRHasScanoutPixmap(ScreenPtr pScreen) 20551b5d61b8Smrg{ 20565a7dfde8Smrg rrScrPrivPtr pScrPriv; 20571b5d61b8Smrg int i; 20581b5d61b8Smrg 20595a7dfde8Smrg /* Bail out if RandR wasn't initialized. */ 20605a7dfde8Smrg if (!dixPrivateKeyRegistered(rrPrivKey)) 20615a7dfde8Smrg return FALSE; 20625a7dfde8Smrg 20635a7dfde8Smrg pScrPriv = rrGetScrPriv(pScreen); 20645a7dfde8Smrg 2065ed6184dfSmrg if (!pScreen->is_output_secondary) 20661b5d61b8Smrg return FALSE; 20671b5d61b8Smrg 20681b5d61b8Smrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 20691b5d61b8Smrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 20701b5d61b8Smrg 20711b5d61b8Smrg if (crtc->scanout_pixmap) 20721b5d61b8Smrg return TRUE; 20731b5d61b8Smrg } 20741b5d61b8Smrg 20751b5d61b8Smrg return FALSE; 20761b5d61b8Smrg} 2077