rrcrtc.c revision 25da500f
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 3035c4bbdfSmrgRESTYPE RRCrtcType; 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) { 37635c4bbdfSmrg ScreenPtr master = crtc->pScreen->current_master; 37735c4bbdfSmrg 3781b5d61b8Smrg if (master && pPixmap->master_pixmap) { 37935c4bbdfSmrg /* 38035c4bbdfSmrg * Unref the pixmap twice: once for the original reference, and once 38135c4bbdfSmrg * for the reference implicitly added by PixmapShareToSlave. 38235c4bbdfSmrg */ 3831b5d61b8Smrg PixmapUnshareSlavePixmap(pPixmap); 3841b5d61b8Smrg 3851b5d61b8Smrg master->DestroyPixmap(pPixmap->master_pixmap); 3861b5d61b8Smrg master->DestroyPixmap(pPixmap->master_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) { 3981b5d61b8Smrg ScreenPtr master = crtc->pScreen->current_master; 3991b5d61b8Smrg DrawablePtr mrootdraw = &master->root->drawable; 40035c4bbdfSmrg 4011b5d61b8Smrg if (crtc->scanout_pixmap_back) { 4021b5d61b8Smrg pScrPriv->rrDisableSharedPixmapFlipping(crtc); 40335c4bbdfSmrg 40425da500fSmrg if (mrootdraw) { 40525da500fSmrg master->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) { 41725da500fSmrg master->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 4301b5d61b8SmrgrrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master, 4311b5d61b8Smrg int width, int height, int depth, 4321b5d61b8Smrg int x, int y, Rotation rotation) 4331b5d61b8Smrg{ 4341b5d61b8Smrg PixmapPtr mpix, spix; 4351b5d61b8Smrg 43635c4bbdfSmrg mpix = master->CreatePixmap(master, width, height, depth, 43735c4bbdfSmrg CREATE_PIXMAP_USAGE_SHARED); 43835c4bbdfSmrg if (!mpix) 4391b5d61b8Smrg return NULL; 44035c4bbdfSmrg 44135c4bbdfSmrg spix = PixmapShareToSlave(mpix, crtc->pScreen); 44235c4bbdfSmrg if (spix == NULL) { 44335c4bbdfSmrg master->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{ 5051b5d61b8Smrg ScreenPtr master = crtc->pScreen->current_master; 5061b5d61b8Smrg rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master); 5071b5d61b8Smrg rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen); 5081b5d61b8Smrg DrawablePtr mrootdraw = &master->root->drawable; 5091b5d61b8Smrg int depth = mrootdraw->depth; 5101b5d61b8Smrg PixmapPtr spix_front; 5111b5d61b8Smrg 5121b5d61b8Smrg /* Create a pixmap on the master screen, then get a shared handle for it. 5131b5d61b8Smrg Create a shared pixmap on the slave screen using the handle. 5141b5d61b8Smrg 5151b5d61b8Smrg If sync == FALSE -- 5161b5d61b8Smrg Set slave screen to scanout shared linear pixmap. 5171b5d61b8Smrg Set the master 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. 5221b5d61b8Smrg Create another shared pixmap on the slave screen using the handle. 5231b5d61b8Smrg Set slave screen to prepare for scanout and flipping between shared 5241b5d61b8Smrg linear pixmaps. 5251b5d61b8Smrg Set the master screen to do dirty updates to the shared pixmaps from the 5261b5d61b8Smrg screen pixmap when prompted to by us or the slave. 5271b5d61b8Smrg Prompt the master to do a dirty update on the first shared pixmap, then 5281b5d61b8Smrg defer to the slave. 5291b5d61b8Smrg */ 5301b5d61b8Smrg 5311b5d61b8Smrg if (crtc->scanout_pixmap) 5321b5d61b8Smrg RRCrtcDetachScanoutPixmap(crtc); 5331b5d61b8Smrg 5341b5d61b8Smrg if (width == 0 && height == 0) { 5351b5d61b8Smrg return TRUE; 5361b5d61b8Smrg } 5371b5d61b8Smrg 5381b5d61b8Smrg spix_front = rrCreateSharedPixmap(crtc, master, 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 && 5481b5d61b8Smrg pSlaveScrPriv->rrEnableSharedPixmapFlipping && 5491b5d61b8Smrg pSlaveScrPriv->rrDisableSharedPixmapFlipping && 5501b5d61b8Smrg pMasterScrPriv->rrStartFlippingPixmapTracking && 5511b5d61b8Smrg master->PresentSharedPixmap && 5521b5d61b8Smrg master->StopFlippingPixmapTracking) { 5531b5d61b8Smrg 5541b5d61b8Smrg PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master, 5551b5d61b8Smrg width, height, depth, 5561b5d61b8Smrg x, y, rotation); 5571b5d61b8Smrg if (spix_back == NULL) 5581b5d61b8Smrg goto fail; 5591b5d61b8Smrg 5601b5d61b8Smrg if (!pSlaveScrPriv->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 5671b5d61b8Smrg if (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc, 5681b5d61b8Smrg mrootdraw, 5691b5d61b8Smrg spix_front, 5701b5d61b8Smrg spix_back, 5711b5d61b8Smrg x, y, 0, 0, 5721b5d61b8Smrg rotation)) { 5731b5d61b8Smrg pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc); 5741b5d61b8Smrg goto fail; 5751b5d61b8Smrg } 5761b5d61b8Smrg 5771b5d61b8Smrg master->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 5961b5d61b8Smrg if (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) { 5971b5d61b8Smrg rrDestroySharedPixmap(crtc, spix_front); 59835c4bbdfSmrg ErrorF("randr: failed to set shadow slave pixmap\n"); 59935c4bbdfSmrg return FALSE; 60035c4bbdfSmrg } 6011b5d61b8Smrg crtc->scanout_pixmap = spix_front; 60235c4bbdfSmrg 6031b5d61b8Smrg master->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; 63635c4bbdfSmrg ScreenPtr slave; 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 64435c4bbdfSmrg /* have to iterate all the crtcs of the attached gpu masters 64535c4bbdfSmrg and all their output slaves */ 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 6691b5d61b8Smrg xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 67035c4bbdfSmrg rrScrPrivPtr slave_priv = rrGetScrPriv(slave); 6711b5d61b8Smrg 6721b5d61b8Smrg if (!slave->is_output_slave) 6731b5d61b8Smrg continue; 6741b5d61b8Smrg 67535c4bbdfSmrg for (c = 0; c < slave_priv->numCrtcs; c++) { 67635c4bbdfSmrg RRCrtcPtr slave_crtc = slave_priv->crtcs[c]; 67735c4bbdfSmrg 67835c4bbdfSmrg if (slave_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 { 69135c4bbdfSmrg if (!slave_crtc->mode) 69235c4bbdfSmrg continue; 69335c4bbdfSmrg crtc_to_box(&newbox, slave_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) { 75935c4bbdfSmrg ScreenPtr master = pScreen->current_master; 76035c4bbdfSmrg int width = 0, height = 0; 76135c4bbdfSmrg 76235c4bbdfSmrg if (mode) { 76335c4bbdfSmrg width = mode->mode.width; 76435c4bbdfSmrg height = mode->mode.height; 76535c4bbdfSmrg } 76635c4bbdfSmrg ret = rrCheckPixmapBounding(master, crtc, 76735c4bbdfSmrg rotation, x, y, width, height); 76835c4bbdfSmrg if (!ret) 76935c4bbdfSmrg return FALSE; 77035c4bbdfSmrg 77135c4bbdfSmrg if (pScreen->current_master) { 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 96305b261ecSmrg/* 96405b261ecSmrg * Notify the extension that the Crtc gamma has been changed 96505b261ecSmrg * The driver calls this whenever it has changed the gamma values 96605b261ecSmrg * in the RRCrtcRec 96705b261ecSmrg */ 96805b261ecSmrg 96905b261ecSmrgBool 97035c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc) 97105b261ecSmrg{ 97235c4bbdfSmrg return TRUE; /* not much going on here */ 97305b261ecSmrg} 97405b261ecSmrg 9754642e01fSmrgstatic void 97635c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform, 97735c4bbdfSmrg int *width, int *height) 97805b261ecSmrg{ 97935c4bbdfSmrg BoxRec box; 9804642e01fSmrg 9814642e01fSmrg if (mode == NULL) { 98235c4bbdfSmrg *width = 0; 98335c4bbdfSmrg *height = 0; 98435c4bbdfSmrg return; 98505b261ecSmrg } 98605b261ecSmrg 9874642e01fSmrg box.x1 = 0; 9884642e01fSmrg box.y1 = 0; 9894642e01fSmrg box.x2 = mode->mode.width; 9904642e01fSmrg box.y2 = mode->mode.height; 9914642e01fSmrg 99235c4bbdfSmrg pixman_transform_bounds(transform, &box); 9934642e01fSmrg *width = box.x2 - box.x1; 9944642e01fSmrg *height = box.y2 - box.y1; 9954642e01fSmrg} 9964642e01fSmrg 9974642e01fSmrg/** 9984642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer 9994642e01fSmrg */ 10004642e01fSmrgvoid 10014642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 10024642e01fSmrg{ 100335c4bbdfSmrg RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height); 100405b261ecSmrg} 100505b261ecSmrg 100605b261ecSmrg/* 100705b261ecSmrg * Set the size of the gamma table at server startup time 100805b261ecSmrg */ 100905b261ecSmrg 101005b261ecSmrgBool 101135c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size) 101205b261ecSmrg{ 101335c4bbdfSmrg CARD16 *gamma; 101405b261ecSmrg 101505b261ecSmrg if (size == crtc->gammaSize) 101635c4bbdfSmrg return TRUE; 101735c4bbdfSmrg if (size) { 101835c4bbdfSmrg gamma = xallocarray(size, 3 * sizeof(CARD16)); 101935c4bbdfSmrg if (!gamma) 102035c4bbdfSmrg return FALSE; 102105b261ecSmrg } 102205b261ecSmrg else 102335c4bbdfSmrg gamma = NULL; 10246747b715Smrg free(crtc->gammaRed); 102505b261ecSmrg crtc->gammaRed = gamma; 102605b261ecSmrg crtc->gammaGreen = gamma + size; 102735c4bbdfSmrg crtc->gammaBlue = gamma + size * 2; 102805b261ecSmrg crtc->gammaSize = size; 102905b261ecSmrg return TRUE; 103005b261ecSmrg} 103105b261ecSmrg 10324642e01fSmrg/* 10334642e01fSmrg * Set the pending CRTC transformation 10344642e01fSmrg */ 10354642e01fSmrg 10364642e01fSmrgint 103735c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc, 103835c4bbdfSmrg PictTransformPtr transform, 103935c4bbdfSmrg struct pixman_f_transform *f_transform, 104035c4bbdfSmrg struct pixman_f_transform *f_inverse, 104135c4bbdfSmrg char *filter_name, 104235c4bbdfSmrg int filter_len, xFixed * params, int nparams) 10434642e01fSmrg{ 104435c4bbdfSmrg PictFilterPtr filter = NULL; 104535c4bbdfSmrg int width = 0, height = 0; 10464642e01fSmrg 10474642e01fSmrg if (!crtc->transforms) 104835c4bbdfSmrg return BadValue; 104935c4bbdfSmrg 105035c4bbdfSmrg if (filter_len) { 105135c4bbdfSmrg filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len); 105235c4bbdfSmrg if (!filter) 105335c4bbdfSmrg return BadName; 105435c4bbdfSmrg if (filter->ValidateParams) { 105535c4bbdfSmrg if (!filter->ValidateParams(crtc->pScreen, filter->id, 105635c4bbdfSmrg params, nparams, &width, &height)) 105735c4bbdfSmrg return BadMatch; 105835c4bbdfSmrg } 105935c4bbdfSmrg else { 106035c4bbdfSmrg width = filter->width; 106135c4bbdfSmrg height = filter->height; 106235c4bbdfSmrg } 10634642e01fSmrg } 106435c4bbdfSmrg else { 106535c4bbdfSmrg if (nparams) 106635c4bbdfSmrg return BadMatch; 10674642e01fSmrg } 106835c4bbdfSmrg if (!RRTransformSetFilter(&crtc->client_pending_transform, 106935c4bbdfSmrg filter, params, nparams, width, height)) 107035c4bbdfSmrg return BadAlloc; 10714642e01fSmrg 10724642e01fSmrg crtc->client_pending_transform.transform = *transform; 10734642e01fSmrg crtc->client_pending_transform.f_transform = *f_transform; 10744642e01fSmrg crtc->client_pending_transform.f_inverse = *f_inverse; 10754642e01fSmrg return Success; 10764642e01fSmrg} 10774642e01fSmrg 107805b261ecSmrg/* 107905b261ecSmrg * Initialize crtc type 108005b261ecSmrg */ 108105b261ecSmrgBool 108235c4bbdfSmrgRRCrtcInit(void) 108305b261ecSmrg{ 108435c4bbdfSmrg RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC"); 108505b261ecSmrg if (!RRCrtcType) 108635c4bbdfSmrg return FALSE; 108735c4bbdfSmrg 108805b261ecSmrg return TRUE; 108905b261ecSmrg} 109005b261ecSmrg 10916747b715Smrg/* 10926747b715Smrg * Initialize crtc type error value 10936747b715Smrg */ 10946747b715Smrgvoid 10956747b715SmrgRRCrtcInitErrorValue(void) 10966747b715Smrg{ 10976747b715Smrg SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 10986747b715Smrg} 10996747b715Smrg 110005b261ecSmrgint 110135c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client) 110205b261ecSmrg{ 110305b261ecSmrg REQUEST(xRRGetCrtcInfoReq); 110435c4bbdfSmrg xRRGetCrtcInfoReply rep; 110535c4bbdfSmrg RRCrtcPtr crtc; 11061b5d61b8Smrg CARD8 *extra = NULL; 110735c4bbdfSmrg unsigned long extraLen; 110835c4bbdfSmrg ScreenPtr pScreen; 110935c4bbdfSmrg rrScrPrivPtr pScrPriv; 111035c4bbdfSmrg RRModePtr mode; 111135c4bbdfSmrg RROutput *outputs; 111235c4bbdfSmrg RROutput *possible; 111335c4bbdfSmrg int i, j, k; 111435c4bbdfSmrg int width, height; 111535c4bbdfSmrg BoxRec panned_area; 11161b5d61b8Smrg Bool leased; 111735c4bbdfSmrg 111805b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 11196747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 112005b261ecSmrg 11211b5d61b8Smrg leased = RRCrtcIsLeased(crtc); 11221b5d61b8Smrg 112305b261ecSmrg /* All crtcs must be associated with screens before client 112405b261ecSmrg * requests are processed 112505b261ecSmrg */ 112605b261ecSmrg pScreen = crtc->pScreen; 112705b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 112805b261ecSmrg 112905b261ecSmrg mode = crtc->mode; 113035c4bbdfSmrg 113135c4bbdfSmrg rep = (xRRGetCrtcInfoReply) { 113235c4bbdfSmrg .type = X_Reply, 113335c4bbdfSmrg .status = RRSetConfigSuccess, 113435c4bbdfSmrg .sequenceNumber = client->sequence, 113535c4bbdfSmrg .length = 0, 113635c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 113735c4bbdfSmrg }; 11381b5d61b8Smrg if (leased) { 11391b5d61b8Smrg rep.x = rep.y = rep.width = rep.height = 0; 11401b5d61b8Smrg rep.mode = 0; 11411b5d61b8Smrg rep.rotation = RR_Rotate_0; 11421b5d61b8Smrg rep.rotations = RR_Rotate_0; 11431b5d61b8Smrg rep.nOutput = 0; 11441b5d61b8Smrg rep.nPossibleOutput = 0; 11451b5d61b8Smrg rep.length = 0; 11461b5d61b8Smrg extraLen = 0; 11471b5d61b8Smrg } else { 11481b5d61b8Smrg if (pScrPriv->rrGetPanning && 11491b5d61b8Smrg pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) && 11501b5d61b8Smrg (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 11511b5d61b8Smrg { 11521b5d61b8Smrg rep.x = panned_area.x1; 11531b5d61b8Smrg rep.y = panned_area.y1; 11541b5d61b8Smrg rep.width = panned_area.x2 - panned_area.x1; 11551b5d61b8Smrg rep.height = panned_area.y2 - panned_area.y1; 11561b5d61b8Smrg } 11571b5d61b8Smrg else { 11581b5d61b8Smrg RRCrtcGetScanoutSize(crtc, &width, &height); 11591b5d61b8Smrg rep.x = crtc->x; 11601b5d61b8Smrg rep.y = crtc->y; 11611b5d61b8Smrg rep.width = width; 11621b5d61b8Smrg rep.height = height; 11631b5d61b8Smrg } 11641b5d61b8Smrg rep.mode = mode ? mode->mode.id : 0; 11651b5d61b8Smrg rep.rotation = crtc->rotation; 11661b5d61b8Smrg rep.rotations = crtc->rotations; 11671b5d61b8Smrg rep.nOutput = crtc->numOutputs; 11681b5d61b8Smrg k = 0; 11691b5d61b8Smrg for (i = 0; i < pScrPriv->numOutputs; i++) { 11701b5d61b8Smrg if (!RROutputIsLeased(pScrPriv->outputs[i])) { 11711b5d61b8Smrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 11721b5d61b8Smrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) 11731b5d61b8Smrg k++; 117435c4bbdfSmrg } 11751b5d61b8Smrg } 11761b5d61b8Smrg 11771b5d61b8Smrg rep.nPossibleOutput = k; 11781b5d61b8Smrg 11791b5d61b8Smrg rep.length = rep.nOutput + rep.nPossibleOutput; 11801b5d61b8Smrg 11811b5d61b8Smrg extraLen = rep.length << 2; 11821b5d61b8Smrg if (extraLen) { 11831b5d61b8Smrg extra = malloc(extraLen); 11841b5d61b8Smrg if (!extra) 11851b5d61b8Smrg return BadAlloc; 11861b5d61b8Smrg } 11871b5d61b8Smrg 11881b5d61b8Smrg outputs = (RROutput *) extra; 11891b5d61b8Smrg possible = (RROutput *) (outputs + rep.nOutput); 11901b5d61b8Smrg 11911b5d61b8Smrg for (i = 0; i < crtc->numOutputs; i++) { 11921b5d61b8Smrg outputs[i] = crtc->outputs[i]->id; 11931b5d61b8Smrg if (client->swapped) 11941b5d61b8Smrg swapl(&outputs[i]); 11951b5d61b8Smrg } 11961b5d61b8Smrg k = 0; 11971b5d61b8Smrg for (i = 0; i < pScrPriv->numOutputs; i++) { 11981b5d61b8Smrg if (!RROutputIsLeased(pScrPriv->outputs[i])) { 11991b5d61b8Smrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 12001b5d61b8Smrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) { 12011b5d61b8Smrg possible[k] = pScrPriv->outputs[i]->id; 12021b5d61b8Smrg if (client->swapped) 12031b5d61b8Smrg swapl(&possible[k]); 12041b5d61b8Smrg k++; 12051b5d61b8Smrg } 12061b5d61b8Smrg } 12071b5d61b8Smrg } 12081b5d61b8Smrg } 120935c4bbdfSmrg 121005b261ecSmrg if (client->swapped) { 121135c4bbdfSmrg swaps(&rep.sequenceNumber); 121235c4bbdfSmrg swapl(&rep.length); 121335c4bbdfSmrg swapl(&rep.timestamp); 121435c4bbdfSmrg swaps(&rep.x); 121535c4bbdfSmrg swaps(&rep.y); 121635c4bbdfSmrg swaps(&rep.width); 121735c4bbdfSmrg swaps(&rep.height); 121835c4bbdfSmrg swapl(&rep.mode); 121935c4bbdfSmrg swaps(&rep.rotation); 122035c4bbdfSmrg swaps(&rep.rotations); 122135c4bbdfSmrg swaps(&rep.nOutput); 122235c4bbdfSmrg swaps(&rep.nPossibleOutput); 122335c4bbdfSmrg } 122435c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep); 122535c4bbdfSmrg if (extraLen) { 122635c4bbdfSmrg WriteToClient(client, extraLen, extra); 122735c4bbdfSmrg free(extra); 122805b261ecSmrg } 122935c4bbdfSmrg 12306747b715Smrg return Success; 123105b261ecSmrg} 123205b261ecSmrg 123305b261ecSmrgint 123435c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client) 123505b261ecSmrg{ 123605b261ecSmrg REQUEST(xRRSetCrtcConfigReq); 123735c4bbdfSmrg xRRSetCrtcConfigReply rep; 123835c4bbdfSmrg ScreenPtr pScreen; 123935c4bbdfSmrg rrScrPrivPtr pScrPriv; 124035c4bbdfSmrg RRCrtcPtr crtc; 124135c4bbdfSmrg RRModePtr mode; 124235c4bbdfSmrg int numOutputs; 124335c4bbdfSmrg RROutputPtr *outputs = NULL; 124435c4bbdfSmrg RROutput *outputIds; 124535c4bbdfSmrg TimeStamp time; 124635c4bbdfSmrg Rotation rotation; 124735c4bbdfSmrg int ret, i, j; 124835c4bbdfSmrg CARD8 status; 124935c4bbdfSmrg 125005b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 125135c4bbdfSmrg numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq))); 125235c4bbdfSmrg 12536747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 12546747b715Smrg 12551b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 12561b5d61b8Smrg return BadAccess; 12571b5d61b8Smrg 125835c4bbdfSmrg if (stuff->mode == None) { 125935c4bbdfSmrg mode = NULL; 126035c4bbdfSmrg if (numOutputs > 0) 126135c4bbdfSmrg return BadMatch; 126205b261ecSmrg } 126335c4bbdfSmrg else { 126435c4bbdfSmrg VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 126535c4bbdfSmrg if (numOutputs == 0) 126635c4bbdfSmrg return BadMatch; 126705b261ecSmrg } 126835c4bbdfSmrg if (numOutputs) { 126935c4bbdfSmrg outputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 127035c4bbdfSmrg if (!outputs) 127135c4bbdfSmrg return BadAlloc; 127205b261ecSmrg } 127305b261ecSmrg else 127435c4bbdfSmrg outputs = NULL; 127535c4bbdfSmrg 127605b261ecSmrg outputIds = (RROutput *) (stuff + 1); 127735c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 127835c4bbdfSmrg ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i], 127935c4bbdfSmrg RROutputType, client, DixSetAttrAccess); 128035c4bbdfSmrg if (ret != Success) { 128135c4bbdfSmrg free(outputs); 128235c4bbdfSmrg return ret; 128335c4bbdfSmrg } 12841b5d61b8Smrg 12851b5d61b8Smrg if (RROutputIsLeased(outputs[i])) { 12861b5d61b8Smrg free(outputs); 12871b5d61b8Smrg return BadAccess; 12881b5d61b8Smrg } 12891b5d61b8Smrg 129035c4bbdfSmrg /* validate crtc for this output */ 129135c4bbdfSmrg for (j = 0; j < outputs[i]->numCrtcs; j++) 129235c4bbdfSmrg if (outputs[i]->crtcs[j] == crtc) 129335c4bbdfSmrg break; 129435c4bbdfSmrg if (j == outputs[i]->numCrtcs) { 129535c4bbdfSmrg free(outputs); 129635c4bbdfSmrg return BadMatch; 129735c4bbdfSmrg } 129835c4bbdfSmrg /* validate mode for this output */ 129935c4bbdfSmrg for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) { 130035c4bbdfSmrg RRModePtr m = (j < outputs[i]->numModes ? 130135c4bbdfSmrg outputs[i]->modes[j] : 130235c4bbdfSmrg outputs[i]->userModes[j - outputs[i]->numModes]); 130335c4bbdfSmrg if (m == mode) 130435c4bbdfSmrg break; 130535c4bbdfSmrg } 130635c4bbdfSmrg if (j == outputs[i]->numModes + outputs[i]->numUserModes) { 130735c4bbdfSmrg free(outputs); 130835c4bbdfSmrg return BadMatch; 130935c4bbdfSmrg } 131005b261ecSmrg } 131105b261ecSmrg /* validate clones */ 131235c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 131335c4bbdfSmrg for (j = 0; j < numOutputs; j++) { 131435c4bbdfSmrg int k; 131535c4bbdfSmrg 131635c4bbdfSmrg if (i == j) 131735c4bbdfSmrg continue; 131835c4bbdfSmrg for (k = 0; k < outputs[i]->numClones; k++) { 131935c4bbdfSmrg if (outputs[i]->clones[k] == outputs[j]) 132035c4bbdfSmrg break; 132135c4bbdfSmrg } 132235c4bbdfSmrg if (k == outputs[i]->numClones) { 132335c4bbdfSmrg free(outputs); 132435c4bbdfSmrg return BadMatch; 132535c4bbdfSmrg } 132635c4bbdfSmrg } 132705b261ecSmrg } 132805b261ecSmrg 132905b261ecSmrg pScreen = crtc->pScreen; 133005b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 133135c4bbdfSmrg 133205b261ecSmrg time = ClientTimeToServerTime(stuff->timestamp); 133335c4bbdfSmrg 133435c4bbdfSmrg if (!pScrPriv) { 133535c4bbdfSmrg time = currentTime; 133635c4bbdfSmrg status = RRSetConfigFailed; 133735c4bbdfSmrg goto sendReply; 133805b261ecSmrg } 133935c4bbdfSmrg 134005b261ecSmrg /* 134105b261ecSmrg * Validate requested rotation 134205b261ecSmrg */ 134305b261ecSmrg rotation = (Rotation) stuff->rotation; 134405b261ecSmrg 134505b261ecSmrg /* test the rotation bits only! */ 134605b261ecSmrg switch (rotation & 0xf) { 134705b261ecSmrg case RR_Rotate_0: 134805b261ecSmrg case RR_Rotate_90: 134905b261ecSmrg case RR_Rotate_180: 135005b261ecSmrg case RR_Rotate_270: 135135c4bbdfSmrg break; 135205b261ecSmrg default: 135335c4bbdfSmrg /* 135435c4bbdfSmrg * Invalid rotation 135535c4bbdfSmrg */ 135635c4bbdfSmrg client->errorValue = stuff->rotation; 135735c4bbdfSmrg free(outputs); 135835c4bbdfSmrg return BadValue; 135905b261ecSmrg } 136005b261ecSmrg 136135c4bbdfSmrg if (mode) { 136235c4bbdfSmrg if ((~crtc->rotations) & rotation) { 136335c4bbdfSmrg /* 136435c4bbdfSmrg * requested rotation or reflection not supported by screen 136535c4bbdfSmrg */ 136635c4bbdfSmrg client->errorValue = stuff->rotation; 136735c4bbdfSmrg free(outputs); 136835c4bbdfSmrg return BadMatch; 136935c4bbdfSmrg } 137035c4bbdfSmrg 137105b261ecSmrg#ifdef RANDR_12_INTERFACE 137235c4bbdfSmrg /* 137335c4bbdfSmrg * Check screen size bounds if the DDX provides a 1.2 interface 137435c4bbdfSmrg * for setting screen size. Else, assume the CrtcSet sets 137535c4bbdfSmrg * the size along with the mode. If the driver supports transforms, 137635c4bbdfSmrg * then it must allow crtcs to display a subset of the screen, so 137735c4bbdfSmrg * only do this check for drivers without transform support. 137835c4bbdfSmrg */ 137935c4bbdfSmrg if (pScrPriv->rrScreenSetSize && !crtc->transforms) { 138035c4bbdfSmrg int source_width; 138135c4bbdfSmrg int source_height; 138235c4bbdfSmrg PictTransform transform; 138335c4bbdfSmrg struct pixman_f_transform f_transform, f_inverse; 138435c4bbdfSmrg int width, height; 138535c4bbdfSmrg 138635c4bbdfSmrg if (pScreen->isGPU) { 138735c4bbdfSmrg width = pScreen->current_master->width; 138835c4bbdfSmrg height = pScreen->current_master->height; 138935c4bbdfSmrg } 139035c4bbdfSmrg else { 139135c4bbdfSmrg width = pScreen->width; 139235c4bbdfSmrg height = pScreen->height; 139335c4bbdfSmrg } 139435c4bbdfSmrg 139535c4bbdfSmrg RRTransformCompute(stuff->x, stuff->y, 139635c4bbdfSmrg mode->mode.width, mode->mode.height, 139735c4bbdfSmrg rotation, 139835c4bbdfSmrg &crtc->client_pending_transform, 139935c4bbdfSmrg &transform, &f_transform, &f_inverse); 140035c4bbdfSmrg 140135c4bbdfSmrg RRModeGetScanoutSize(mode, &transform, &source_width, 140235c4bbdfSmrg &source_height); 140335c4bbdfSmrg if (stuff->x + source_width > width) { 140435c4bbdfSmrg client->errorValue = stuff->x; 140535c4bbdfSmrg free(outputs); 140635c4bbdfSmrg return BadValue; 140735c4bbdfSmrg } 140835c4bbdfSmrg 140935c4bbdfSmrg if (stuff->y + source_height > height) { 141035c4bbdfSmrg client->errorValue = stuff->y; 141135c4bbdfSmrg free(outputs); 141235c4bbdfSmrg return BadValue; 141335c4bbdfSmrg } 141435c4bbdfSmrg } 141505b261ecSmrg#endif 141605b261ecSmrg } 141735c4bbdfSmrg 141835c4bbdfSmrg if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y, 141935c4bbdfSmrg rotation, numOutputs, outputs)) { 142035c4bbdfSmrg status = RRSetConfigFailed; 142135c4bbdfSmrg goto sendReply; 142205b261ecSmrg } 142335c4bbdfSmrg status = RRSetConfigSuccess; 142452397711Smrg pScrPriv->lastSetTime = time; 142535c4bbdfSmrg 142635c4bbdfSmrg sendReply: 14276747b715Smrg free(outputs); 142835c4bbdfSmrg 142935c4bbdfSmrg rep = (xRRSetCrtcConfigReply) { 143035c4bbdfSmrg .type = X_Reply, 143135c4bbdfSmrg .status = status, 143235c4bbdfSmrg .sequenceNumber = client->sequence, 143335c4bbdfSmrg .length = 0, 143435c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 143535c4bbdfSmrg }; 143635c4bbdfSmrg 143735c4bbdfSmrg if (client->swapped) { 143835c4bbdfSmrg swaps(&rep.sequenceNumber); 143935c4bbdfSmrg swapl(&rep.length); 144035c4bbdfSmrg swapl(&rep.newTimestamp); 144105b261ecSmrg } 144235c4bbdfSmrg WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep); 144335c4bbdfSmrg 14446747b715Smrg return Success; 144505b261ecSmrg} 144605b261ecSmrg 14474642e01fSmrgint 144835c4bbdfSmrgProcRRGetPanning(ClientPtr client) 14494642e01fSmrg{ 14504642e01fSmrg REQUEST(xRRGetPanningReq); 145135c4bbdfSmrg xRRGetPanningReply rep; 145235c4bbdfSmrg RRCrtcPtr crtc; 145335c4bbdfSmrg ScreenPtr pScreen; 145435c4bbdfSmrg rrScrPrivPtr pScrPriv; 145535c4bbdfSmrg BoxRec total; 145635c4bbdfSmrg BoxRec tracking; 145735c4bbdfSmrg INT16 border[4]; 145835c4bbdfSmrg 14594642e01fSmrg REQUEST_SIZE_MATCH(xRRGetPanningReq); 14606747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 14614642e01fSmrg 14624642e01fSmrg /* All crtcs must be associated with screens before client 14634642e01fSmrg * requests are processed 14644642e01fSmrg */ 14654642e01fSmrg pScreen = crtc->pScreen; 14664642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 14674642e01fSmrg 14684642e01fSmrg if (!pScrPriv) 146935c4bbdfSmrg return RRErrorBase + BadRRCrtc; 14704642e01fSmrg 147135c4bbdfSmrg rep = (xRRGetPanningReply) { 147235c4bbdfSmrg .type = X_Reply, 147335c4bbdfSmrg .status = RRSetConfigSuccess, 147435c4bbdfSmrg .sequenceNumber = client->sequence, 147535c4bbdfSmrg .length = 1, 147635c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 147735c4bbdfSmrg }; 14784642e01fSmrg 14794642e01fSmrg if (pScrPriv->rrGetPanning && 148035c4bbdfSmrg pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) { 148135c4bbdfSmrg rep.left = total.x1; 148235c4bbdfSmrg rep.top = total.y1; 148335c4bbdfSmrg rep.width = total.x2 - total.x1; 148435c4bbdfSmrg rep.height = total.y2 - total.y1; 148535c4bbdfSmrg rep.track_left = tracking.x1; 148635c4bbdfSmrg rep.track_top = tracking.y1; 148735c4bbdfSmrg rep.track_width = tracking.x2 - tracking.x1; 148835c4bbdfSmrg rep.track_height = tracking.y2 - tracking.y1; 148935c4bbdfSmrg rep.border_left = border[0]; 149035c4bbdfSmrg rep.border_top = border[1]; 149135c4bbdfSmrg rep.border_right = border[2]; 149235c4bbdfSmrg rep.border_bottom = border[3]; 14934642e01fSmrg } 14944642e01fSmrg 14954642e01fSmrg if (client->swapped) { 149635c4bbdfSmrg swaps(&rep.sequenceNumber); 149735c4bbdfSmrg swapl(&rep.length); 149835c4bbdfSmrg swapl(&rep.timestamp); 149935c4bbdfSmrg swaps(&rep.left); 150035c4bbdfSmrg swaps(&rep.top); 150135c4bbdfSmrg swaps(&rep.width); 150235c4bbdfSmrg swaps(&rep.height); 150335c4bbdfSmrg swaps(&rep.track_left); 150435c4bbdfSmrg swaps(&rep.track_top); 150535c4bbdfSmrg swaps(&rep.track_width); 150635c4bbdfSmrg swaps(&rep.track_height); 150735c4bbdfSmrg swaps(&rep.border_left); 150835c4bbdfSmrg swaps(&rep.border_top); 150935c4bbdfSmrg swaps(&rep.border_right); 151035c4bbdfSmrg swaps(&rep.border_bottom); 151135c4bbdfSmrg } 151235c4bbdfSmrg WriteToClient(client, sizeof(xRRGetPanningReply), &rep); 15136747b715Smrg return Success; 15144642e01fSmrg} 15154642e01fSmrg 15164642e01fSmrgint 151735c4bbdfSmrgProcRRSetPanning(ClientPtr client) 15184642e01fSmrg{ 15194642e01fSmrg REQUEST(xRRSetPanningReq); 152035c4bbdfSmrg xRRSetPanningReply rep; 152135c4bbdfSmrg RRCrtcPtr crtc; 152235c4bbdfSmrg ScreenPtr pScreen; 152335c4bbdfSmrg rrScrPrivPtr pScrPriv; 152435c4bbdfSmrg TimeStamp time; 152535c4bbdfSmrg BoxRec total; 152635c4bbdfSmrg BoxRec tracking; 152735c4bbdfSmrg INT16 border[4]; 152835c4bbdfSmrg CARD8 status; 152935c4bbdfSmrg 15304642e01fSmrg REQUEST_SIZE_MATCH(xRRSetPanningReq); 15316747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 15324642e01fSmrg 15331b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 15341b5d61b8Smrg return BadAccess; 15351b5d61b8Smrg 15364642e01fSmrg /* All crtcs must be associated with screens before client 15374642e01fSmrg * requests are processed 15384642e01fSmrg */ 15394642e01fSmrg pScreen = crtc->pScreen; 15404642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 15414642e01fSmrg 15424642e01fSmrg if (!pScrPriv) { 154335c4bbdfSmrg time = currentTime; 154435c4bbdfSmrg status = RRSetConfigFailed; 154535c4bbdfSmrg goto sendReply; 15464642e01fSmrg } 154735c4bbdfSmrg 15484642e01fSmrg time = ClientTimeToServerTime(stuff->timestamp); 154935c4bbdfSmrg 15504642e01fSmrg if (!pScrPriv->rrGetPanning) 155135c4bbdfSmrg return RRErrorBase + BadRRCrtc; 15524642e01fSmrg 155335c4bbdfSmrg total.x1 = stuff->left; 155435c4bbdfSmrg total.y1 = stuff->top; 155535c4bbdfSmrg total.x2 = total.x1 + stuff->width; 155635c4bbdfSmrg total.y2 = total.y1 + stuff->height; 15574642e01fSmrg tracking.x1 = stuff->track_left; 15584642e01fSmrg tracking.y1 = stuff->track_top; 15594642e01fSmrg tracking.x2 = tracking.x1 + stuff->track_width; 15604642e01fSmrg tracking.y2 = tracking.y1 + stuff->track_height; 156135c4bbdfSmrg border[0] = stuff->border_left; 156235c4bbdfSmrg border[1] = stuff->border_top; 156335c4bbdfSmrg border[2] = stuff->border_right; 156435c4bbdfSmrg border[3] = stuff->border_bottom; 15654642e01fSmrg 156635c4bbdfSmrg if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border)) 156735c4bbdfSmrg return BadMatch; 15684642e01fSmrg 156952397711Smrg pScrPriv->lastSetTime = time; 157052397711Smrg 157135c4bbdfSmrg status = RRSetConfigSuccess; 15724642e01fSmrg 157335c4bbdfSmrg sendReply: 157435c4bbdfSmrg rep = (xRRSetPanningReply) { 157535c4bbdfSmrg .type = X_Reply, 157635c4bbdfSmrg .status = status, 157735c4bbdfSmrg .sequenceNumber = client->sequence, 157835c4bbdfSmrg .length = 0, 157935c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 158035c4bbdfSmrg }; 15814642e01fSmrg 15824642e01fSmrg if (client->swapped) { 158335c4bbdfSmrg swaps(&rep.sequenceNumber); 158435c4bbdfSmrg swapl(&rep.length); 158535c4bbdfSmrg swapl(&rep.newTimestamp); 15864642e01fSmrg } 158735c4bbdfSmrg WriteToClient(client, sizeof(xRRSetPanningReply), &rep); 15886747b715Smrg return Success; 15894642e01fSmrg} 15904642e01fSmrg 159105b261ecSmrgint 159235c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client) 159305b261ecSmrg{ 159405b261ecSmrg REQUEST(xRRGetCrtcGammaSizeReq); 159535c4bbdfSmrg xRRGetCrtcGammaSizeReply reply; 159635c4bbdfSmrg RRCrtcPtr crtc; 159705b261ecSmrg 159805b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 15996747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 16006747b715Smrg 16016747b715Smrg /* Gamma retrieval failed, any better error? */ 16026747b715Smrg if (!RRCrtcGammaGet(crtc)) 16036747b715Smrg return RRErrorBase + BadRRCrtc; 16046747b715Smrg 160535c4bbdfSmrg reply = (xRRGetCrtcGammaSizeReply) { 160635c4bbdfSmrg .type = X_Reply, 160735c4bbdfSmrg .sequenceNumber = client->sequence, 160835c4bbdfSmrg .length = 0, 160935c4bbdfSmrg .size = crtc->gammaSize 161035c4bbdfSmrg }; 161105b261ecSmrg if (client->swapped) { 161235c4bbdfSmrg swaps(&reply.sequenceNumber); 161335c4bbdfSmrg swapl(&reply.length); 161435c4bbdfSmrg swaps(&reply.size); 161505b261ecSmrg } 161635c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply); 16176747b715Smrg return Success; 161805b261ecSmrg} 161905b261ecSmrg 162005b261ecSmrgint 162135c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client) 162205b261ecSmrg{ 162305b261ecSmrg REQUEST(xRRGetCrtcGammaReq); 162435c4bbdfSmrg xRRGetCrtcGammaReply reply; 162535c4bbdfSmrg RRCrtcPtr crtc; 162635c4bbdfSmrg unsigned long len; 162735c4bbdfSmrg char *extra = NULL; 162835c4bbdfSmrg 162905b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 16306747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 16316747b715Smrg 16326747b715Smrg /* Gamma retrieval failed, any better error? */ 16336747b715Smrg if (!RRCrtcGammaGet(crtc)) 16346747b715Smrg return RRErrorBase + BadRRCrtc; 16356747b715Smrg 163605b261ecSmrg len = crtc->gammaSize * 3 * 2; 163735c4bbdfSmrg 16384642e01fSmrg if (crtc->gammaSize) { 163935c4bbdfSmrg extra = malloc(len); 164035c4bbdfSmrg if (!extra) 164135c4bbdfSmrg return BadAlloc; 16424642e01fSmrg } 16434642e01fSmrg 164435c4bbdfSmrg reply = (xRRGetCrtcGammaReply) { 164535c4bbdfSmrg .type = X_Reply, 164635c4bbdfSmrg .sequenceNumber = client->sequence, 164735c4bbdfSmrg .length = bytes_to_int32(len), 164835c4bbdfSmrg .size = crtc->gammaSize 164935c4bbdfSmrg }; 165005b261ecSmrg if (client->swapped) { 165135c4bbdfSmrg swaps(&reply.sequenceNumber); 165235c4bbdfSmrg swapl(&reply.length); 165335c4bbdfSmrg swaps(&reply.size); 165405b261ecSmrg } 165535c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply); 165635c4bbdfSmrg if (crtc->gammaSize) { 165735c4bbdfSmrg memcpy(extra, crtc->gammaRed, len); 165835c4bbdfSmrg client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 165935c4bbdfSmrg WriteSwappedDataToClient(client, len, extra); 166035c4bbdfSmrg free(extra); 166105b261ecSmrg } 16626747b715Smrg return Success; 166305b261ecSmrg} 166405b261ecSmrg 166505b261ecSmrgint 166635c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client) 166705b261ecSmrg{ 166805b261ecSmrg REQUEST(xRRSetCrtcGammaReq); 166935c4bbdfSmrg RRCrtcPtr crtc; 167035c4bbdfSmrg unsigned long len; 167135c4bbdfSmrg CARD16 *red, *green, *blue; 167235c4bbdfSmrg 167305b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 16746747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 167535c4bbdfSmrg 16761b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 16771b5d61b8Smrg return BadAccess; 16781b5d61b8Smrg 167935c4bbdfSmrg len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq)); 168005b261ecSmrg if (len < (stuff->size * 3 + 1) >> 1) 168135c4bbdfSmrg return BadLength; 168205b261ecSmrg 168305b261ecSmrg if (stuff->size != crtc->gammaSize) 168435c4bbdfSmrg return BadMatch; 168535c4bbdfSmrg 168605b261ecSmrg red = (CARD16 *) (stuff + 1); 168705b261ecSmrg green = red + crtc->gammaSize; 168805b261ecSmrg blue = green + crtc->gammaSize; 168935c4bbdfSmrg 169035c4bbdfSmrg RRCrtcGammaSet(crtc, red, green, blue); 169105b261ecSmrg 169205b261ecSmrg return Success; 169305b261ecSmrg} 169405b261ecSmrg 16954642e01fSmrg/* Version 1.3 additions */ 16964642e01fSmrg 16974642e01fSmrgint 169835c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client) 16994642e01fSmrg{ 17004642e01fSmrg REQUEST(xRRSetCrtcTransformReq); 170135c4bbdfSmrg RRCrtcPtr crtc; 170235c4bbdfSmrg PictTransform transform; 17034642e01fSmrg struct pixman_f_transform f_transform, f_inverse; 170435c4bbdfSmrg char *filter; 170535c4bbdfSmrg int nbytes; 170635c4bbdfSmrg xFixed *params; 170735c4bbdfSmrg int nparams; 17084642e01fSmrg 17094642e01fSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 17106747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 17114642e01fSmrg 17121b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 17131b5d61b8Smrg return BadAccess; 17141b5d61b8Smrg 171535c4bbdfSmrg PictTransform_from_xRenderTransform(&transform, &stuff->transform); 171635c4bbdfSmrg pixman_f_transform_from_pixman_transform(&f_transform, &transform); 171735c4bbdfSmrg if (!pixman_f_transform_invert(&f_inverse, &f_transform)) 171835c4bbdfSmrg return BadMatch; 17194642e01fSmrg 17204642e01fSmrg filter = (char *) (stuff + 1); 17214642e01fSmrg nbytes = stuff->nbytesFilter; 17226747b715Smrg params = (xFixed *) (filter + pad_to_int32(nbytes)); 17234642e01fSmrg nparams = ((xFixed *) stuff + client->req_len) - params; 17244642e01fSmrg if (nparams < 0) 172535c4bbdfSmrg return BadLength; 17264642e01fSmrg 172735c4bbdfSmrg return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse, 172835c4bbdfSmrg filter, nbytes, params, nparams); 17294642e01fSmrg} 17304642e01fSmrg 17314642e01fSmrg#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 173235c4bbdfSmrg 17334642e01fSmrgstatic int 173435c4bbdfSmrgtransform_filter_length(RRTransformPtr transform) 17354642e01fSmrg{ 173635c4bbdfSmrg int nbytes, nparams; 17374642e01fSmrg 17384642e01fSmrg if (transform->filter == NULL) 173935c4bbdfSmrg return 0; 174035c4bbdfSmrg nbytes = strlen(transform->filter->name); 17414642e01fSmrg nparams = transform->nparams; 174235c4bbdfSmrg return pad_to_int32(nbytes) + (nparams * sizeof(xFixed)); 17434642e01fSmrg} 17444642e01fSmrg 17454642e01fSmrgstatic int 174635c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output, 174735c4bbdfSmrg CARD16 *nbytesFilter, 174835c4bbdfSmrg CARD16 *nparamsFilter, RRTransformPtr transform) 17494642e01fSmrg{ 175035c4bbdfSmrg int nbytes, nparams; 17514642e01fSmrg 17524642e01fSmrg if (transform->filter == NULL) { 175335c4bbdfSmrg *nbytesFilter = 0; 175435c4bbdfSmrg *nparamsFilter = 0; 175535c4bbdfSmrg return 0; 17564642e01fSmrg } 175735c4bbdfSmrg nbytes = strlen(transform->filter->name); 17584642e01fSmrg nparams = transform->nparams; 17594642e01fSmrg *nbytesFilter = nbytes; 17604642e01fSmrg *nparamsFilter = nparams; 176135c4bbdfSmrg memcpy(output, transform->filter->name, nbytes); 17624642e01fSmrg while ((nbytes & 3) != 0) 176335c4bbdfSmrg output[nbytes++] = 0; 176435c4bbdfSmrg memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed)); 17654642e01fSmrg if (client->swapped) { 176635c4bbdfSmrg swaps(nbytesFilter); 176735c4bbdfSmrg swaps(nparamsFilter); 176835c4bbdfSmrg SwapLongs((CARD32 *) (output + nbytes), nparams); 17694642e01fSmrg } 177035c4bbdfSmrg nbytes += nparams * sizeof(xFixed); 17714642e01fSmrg return nbytes; 17724642e01fSmrg} 17734642e01fSmrg 17744642e01fSmrgstatic void 177535c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire, 177635c4bbdfSmrg PictTransform * pict) 17774642e01fSmrg{ 177835c4bbdfSmrg xRenderTransform_from_PictTransform(wire, pict); 17794642e01fSmrg if (client->swapped) 178035c4bbdfSmrg SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 17814642e01fSmrg} 17824642e01fSmrg 17834642e01fSmrgint 178435c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client) 17854642e01fSmrg{ 17864642e01fSmrg REQUEST(xRRGetCrtcTransformReq); 178735c4bbdfSmrg xRRGetCrtcTransformReply *reply; 178835c4bbdfSmrg RRCrtcPtr crtc; 178935c4bbdfSmrg int nextra; 179035c4bbdfSmrg RRTransformPtr current, pending; 179135c4bbdfSmrg char *extra; 17924642e01fSmrg 179335c4bbdfSmrg REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq); 17946747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 17954642e01fSmrg 17964642e01fSmrg pending = &crtc->client_pending_transform; 17974642e01fSmrg current = &crtc->client_current_transform; 17984642e01fSmrg 179935c4bbdfSmrg nextra = (transform_filter_length(pending) + 180035c4bbdfSmrg transform_filter_length(current)); 18014642e01fSmrg 180235c4bbdfSmrg reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra); 18034642e01fSmrg if (!reply) 180435c4bbdfSmrg return BadAlloc; 18054642e01fSmrg 18064642e01fSmrg extra = (char *) (reply + 1); 18074642e01fSmrg reply->type = X_Reply; 18084642e01fSmrg reply->sequenceNumber = client->sequence; 18096747b715Smrg reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 18104642e01fSmrg 18114642e01fSmrg reply->hasTransforms = crtc->transforms; 18124642e01fSmrg 181335c4bbdfSmrg transform_encode(client, &reply->pendingTransform, &pending->transform); 181435c4bbdfSmrg extra += transform_filter_encode(client, extra, 181535c4bbdfSmrg &reply->pendingNbytesFilter, 181635c4bbdfSmrg &reply->pendingNparamsFilter, pending); 18174642e01fSmrg 181835c4bbdfSmrg transform_encode(client, &reply->currentTransform, ¤t->transform); 181935c4bbdfSmrg extra += transform_filter_encode(client, extra, 182035c4bbdfSmrg &reply->currentNbytesFilter, 182135c4bbdfSmrg &reply->currentNparamsFilter, current); 18224642e01fSmrg 18234642e01fSmrg if (client->swapped) { 182435c4bbdfSmrg swaps(&reply->sequenceNumber); 182535c4bbdfSmrg swapl(&reply->length); 18264642e01fSmrg } 182735c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply); 18286747b715Smrg free(reply); 18296747b715Smrg return Success; 18304642e01fSmrg} 183135c4bbdfSmrg 183235c4bbdfSmrgstatic Bool 183335c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y) 183435c4bbdfSmrg{ 183535c4bbdfSmrg rrScrPriv(pScreen); 183635c4bbdfSmrg int i; 183735c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 183835c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 183935c4bbdfSmrg 184035c4bbdfSmrg int left, right, top, bottom; 184135c4bbdfSmrg 18421b5d61b8Smrg if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 18431b5d61b8Smrg continue; 184435c4bbdfSmrg 184535c4bbdfSmrg if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom)) 184635c4bbdfSmrg return TRUE; 184735c4bbdfSmrg } 184835c4bbdfSmrg return FALSE; 184935c4bbdfSmrg} 185035c4bbdfSmrg 185135c4bbdfSmrgstatic Bool 185235c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y) 185335c4bbdfSmrg{ 185435c4bbdfSmrg rrScrPriv(pScreen); 185535c4bbdfSmrg int i; 185635c4bbdfSmrg 185735c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 185835c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 185935c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 186035c4bbdfSmrg int nx, ny; 186135c4bbdfSmrg int left, right, top, bottom; 186235c4bbdfSmrg 18631b5d61b8Smrg if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 18641b5d61b8Smrg continue; 186535c4bbdfSmrg 186635c4bbdfSmrg miPointerGetPosition(pDev, &nx, &ny); 186735c4bbdfSmrg 186835c4bbdfSmrg if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) { 186935c4bbdfSmrg if (*x < left) 187035c4bbdfSmrg *x = left; 187135c4bbdfSmrg if (*x >= right) 187235c4bbdfSmrg *x = right - 1; 187335c4bbdfSmrg if (*y < top) 187435c4bbdfSmrg *y = top; 187535c4bbdfSmrg if (*y >= bottom) 187635c4bbdfSmrg *y = bottom - 1; 187735c4bbdfSmrg 187835c4bbdfSmrg return TRUE; 187935c4bbdfSmrg } 188035c4bbdfSmrg } 188135c4bbdfSmrg return FALSE; 188235c4bbdfSmrg} 188335c4bbdfSmrg 188435c4bbdfSmrgvoid 188535c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, 188635c4bbdfSmrg int *y) 188735c4bbdfSmrg{ 188835c4bbdfSmrg rrScrPriv(pScreen); 188935c4bbdfSmrg Bool ret; 189035c4bbdfSmrg ScreenPtr slave; 189135c4bbdfSmrg 189235c4bbdfSmrg /* intentional dead space -> let it float */ 189335c4bbdfSmrg if (pScrPriv->discontiguous) 189435c4bbdfSmrg return; 189535c4bbdfSmrg 189635c4bbdfSmrg /* if we're moving inside a crtc, we're fine */ 189735c4bbdfSmrg ret = check_all_screen_crtcs(pScreen, x, y); 189835c4bbdfSmrg if (ret == TRUE) 189935c4bbdfSmrg return; 190035c4bbdfSmrg 19011b5d61b8Smrg xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 19021b5d61b8Smrg if (!slave->is_output_slave) 19031b5d61b8Smrg continue; 19041b5d61b8Smrg 190535c4bbdfSmrg ret = check_all_screen_crtcs(slave, x, y); 190635c4bbdfSmrg if (ret == TRUE) 190735c4bbdfSmrg return; 190835c4bbdfSmrg } 190935c4bbdfSmrg 191035c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 191135c4bbdfSmrg ret = constrain_all_screen_crtcs(pDev, pScreen, x, y); 191235c4bbdfSmrg if (ret == TRUE) 191335c4bbdfSmrg return; 191435c4bbdfSmrg 19151b5d61b8Smrg xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 19161b5d61b8Smrg if (!slave->is_output_slave) 19171b5d61b8Smrg continue; 19181b5d61b8Smrg 191935c4bbdfSmrg ret = constrain_all_screen_crtcs(pDev, slave, x, y); 192035c4bbdfSmrg if (ret == TRUE) 192135c4bbdfSmrg return; 192235c4bbdfSmrg } 192335c4bbdfSmrg} 192435c4bbdfSmrg 192535c4bbdfSmrgBool 192635c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable) 192735c4bbdfSmrg{ 192835c4bbdfSmrg rrScrPriv(pDrawable->pScreen); 192935c4bbdfSmrg Bool ret = TRUE; 193035c4bbdfSmrg PixmapPtr *saved_scanout_pixmap; 193135c4bbdfSmrg int i; 193235c4bbdfSmrg 193335c4bbdfSmrg saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs); 193435c4bbdfSmrg if (saved_scanout_pixmap == NULL) 193535c4bbdfSmrg return FALSE; 193635c4bbdfSmrg 193735c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 193835c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 193935c4bbdfSmrg Bool size_fits; 194035c4bbdfSmrg 194135c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 194235c4bbdfSmrg 194335c4bbdfSmrg if (!crtc->mode && enable) 194435c4bbdfSmrg continue; 194535c4bbdfSmrg if (!crtc->scanout_pixmap && !enable) 194635c4bbdfSmrg continue; 194735c4bbdfSmrg 19481b5d61b8Smrg /* not supported with double buffering, needs ABI change for 2 ppix */ 19491b5d61b8Smrg if (crtc->scanout_pixmap_back) { 19501b5d61b8Smrg ret = FALSE; 19511b5d61b8Smrg continue; 19521b5d61b8Smrg } 19531b5d61b8Smrg 195435c4bbdfSmrg size_fits = (crtc->mode && 195535c4bbdfSmrg crtc->x == pDrawable->x && 195635c4bbdfSmrg crtc->y == pDrawable->y && 195735c4bbdfSmrg crtc->mode->mode.width == pDrawable->width && 195835c4bbdfSmrg crtc->mode->mode.height == pDrawable->height); 195935c4bbdfSmrg 196035c4bbdfSmrg /* is the pixmap already set? */ 196135c4bbdfSmrg if (crtc->scanout_pixmap == pPixmap) { 196235c4bbdfSmrg /* if its a disable then don't care about size */ 196335c4bbdfSmrg if (enable == FALSE) { 196435c4bbdfSmrg /* set scanout to NULL */ 196535c4bbdfSmrg crtc->scanout_pixmap = NULL; 196635c4bbdfSmrg } 196735c4bbdfSmrg else if (!size_fits) { 196835c4bbdfSmrg /* if the size no longer fits then drop off */ 196935c4bbdfSmrg crtc->scanout_pixmap = NULL; 197035c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 197135c4bbdfSmrg 197235c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 197335c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 197435c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 197535c4bbdfSmrg ret = FALSE; 197635c4bbdfSmrg } 197735c4bbdfSmrg else { 197835c4bbdfSmrg /* if the size fits then we are already setup */ 197935c4bbdfSmrg } 198035c4bbdfSmrg } 198135c4bbdfSmrg else { 198235c4bbdfSmrg if (!size_fits) 198335c4bbdfSmrg ret = FALSE; 198435c4bbdfSmrg else if (enable) 198535c4bbdfSmrg crtc->scanout_pixmap = pPixmap; 198635c4bbdfSmrg else 198735c4bbdfSmrg /* reject an attempt to disable someone else's scanout_pixmap */ 198835c4bbdfSmrg ret = FALSE; 198935c4bbdfSmrg } 199035c4bbdfSmrg } 199135c4bbdfSmrg 199235c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 199335c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 199435c4bbdfSmrg 199535c4bbdfSmrg if (crtc->scanout_pixmap == saved_scanout_pixmap[i]) 199635c4bbdfSmrg continue; 199735c4bbdfSmrg 199835c4bbdfSmrg if (ret) { 199935c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 200035c4bbdfSmrg 200135c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 200235c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 200335c4bbdfSmrg } 200435c4bbdfSmrg else 200535c4bbdfSmrg crtc->scanout_pixmap = saved_scanout_pixmap[i]; 200635c4bbdfSmrg } 200735c4bbdfSmrg free(saved_scanout_pixmap); 200835c4bbdfSmrg 200935c4bbdfSmrg return ret; 201035c4bbdfSmrg} 20111b5d61b8Smrg 20121b5d61b8SmrgBool 20131b5d61b8SmrgRRHasScanoutPixmap(ScreenPtr pScreen) 20141b5d61b8Smrg{ 20151b5d61b8Smrg rrScrPriv(pScreen); 20161b5d61b8Smrg int i; 20171b5d61b8Smrg 20181b5d61b8Smrg if (!pScreen->is_output_slave) 20191b5d61b8Smrg return FALSE; 20201b5d61b8Smrg 20211b5d61b8Smrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 20221b5d61b8Smrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 20231b5d61b8Smrg 20241b5d61b8Smrg if (crtc->scanout_pixmap) 20251b5d61b8Smrg return TRUE; 20261b5d61b8Smrg } 20271b5d61b8Smrg 20281b5d61b8Smrg return FALSE; 20291b5d61b8Smrg} 2030