rrcrtc.c revision 1b5d61b8
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 4041b5d61b8Smrg master->StopFlippingPixmapTracking(mrootdraw, 4051b5d61b8Smrg crtc->scanout_pixmap, 4061b5d61b8Smrg crtc->scanout_pixmap_back); 40735c4bbdfSmrg 4081b5d61b8Smrg rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back); 4091b5d61b8Smrg crtc->scanout_pixmap_back = NULL; 4101b5d61b8Smrg } 4111b5d61b8Smrg else { 4121b5d61b8Smrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL); 4131b5d61b8Smrg master->StopPixmapTracking(mrootdraw, 4141b5d61b8Smrg crtc->scanout_pixmap); 4151b5d61b8Smrg } 4161b5d61b8Smrg 4171b5d61b8Smrg rrDestroySharedPixmap(crtc, crtc->scanout_pixmap); 4181b5d61b8Smrg crtc->scanout_pixmap = NULL; 41935c4bbdfSmrg } 42035c4bbdfSmrg 4211b5d61b8Smrg RRCrtcChanged(crtc, TRUE); 4221b5d61b8Smrg} 4231b5d61b8Smrg 4241b5d61b8Smrgstatic PixmapPtr 4251b5d61b8SmrgrrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master, 4261b5d61b8Smrg int width, int height, int depth, 4271b5d61b8Smrg int x, int y, Rotation rotation) 4281b5d61b8Smrg{ 4291b5d61b8Smrg PixmapPtr mpix, spix; 4301b5d61b8Smrg 43135c4bbdfSmrg mpix = master->CreatePixmap(master, width, height, depth, 43235c4bbdfSmrg CREATE_PIXMAP_USAGE_SHARED); 43335c4bbdfSmrg if (!mpix) 4341b5d61b8Smrg return NULL; 43535c4bbdfSmrg 43635c4bbdfSmrg spix = PixmapShareToSlave(mpix, crtc->pScreen); 43735c4bbdfSmrg if (spix == NULL) { 43835c4bbdfSmrg master->DestroyPixmap(mpix); 4391b5d61b8Smrg return NULL; 4401b5d61b8Smrg } 4411b5d61b8Smrg 4421b5d61b8Smrg return spix; 4431b5d61b8Smrg} 4441b5d61b8Smrg 4451b5d61b8Smrgstatic Bool 4461b5d61b8SmrgrrGetPixmapSharingSyncProp(int numOutputs, RROutputPtr * outputs) 4471b5d61b8Smrg{ 4481b5d61b8Smrg /* Determine if the user wants prime syncing */ 4491b5d61b8Smrg int o; 4501b5d61b8Smrg const char *syncStr = PRIME_SYNC_PROP; 4511b5d61b8Smrg Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 4521b5d61b8Smrg if (syncProp == None) 4531b5d61b8Smrg return TRUE; 4541b5d61b8Smrg 4551b5d61b8Smrg /* If one output doesn't want sync, no sync */ 4561b5d61b8Smrg for (o = 0; o < numOutputs; o++) { 4571b5d61b8Smrg RRPropertyValuePtr val; 4581b5d61b8Smrg 4591b5d61b8Smrg /* Try pending value first, then current value */ 4601b5d61b8Smrg if ((val = RRGetOutputProperty(outputs[o], syncProp, TRUE)) && 4611b5d61b8Smrg val->data) { 4621b5d61b8Smrg if (!(*(char *) val->data)) 4631b5d61b8Smrg return FALSE; 4641b5d61b8Smrg continue; 4651b5d61b8Smrg } 4661b5d61b8Smrg 4671b5d61b8Smrg if ((val = RRGetOutputProperty(outputs[o], syncProp, FALSE)) && 4681b5d61b8Smrg val->data) { 4691b5d61b8Smrg if (!(*(char *) val->data)) 4701b5d61b8Smrg return FALSE; 4711b5d61b8Smrg continue; 4721b5d61b8Smrg } 4731b5d61b8Smrg } 4741b5d61b8Smrg 4751b5d61b8Smrg return TRUE; 4761b5d61b8Smrg} 4771b5d61b8Smrg 4781b5d61b8Smrgstatic void 4791b5d61b8SmrgrrSetPixmapSharingSyncProp(char val, int numOutputs, RROutputPtr * outputs) 4801b5d61b8Smrg{ 4811b5d61b8Smrg int o; 4821b5d61b8Smrg const char *syncStr = PRIME_SYNC_PROP; 4831b5d61b8Smrg Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 4841b5d61b8Smrg if (syncProp == None) 4851b5d61b8Smrg return; 4861b5d61b8Smrg 4871b5d61b8Smrg for (o = 0; o < numOutputs; o++) { 4881b5d61b8Smrg RRPropertyPtr prop = RRQueryOutputProperty(outputs[o], syncProp); 4891b5d61b8Smrg if (prop) 4901b5d61b8Smrg RRChangeOutputProperty(outputs[o], syncProp, XA_INTEGER, 4911b5d61b8Smrg 8, PropModeReplace, 1, &val, FALSE, TRUE); 4921b5d61b8Smrg } 4931b5d61b8Smrg} 4941b5d61b8Smrg 4951b5d61b8Smrgstatic Bool 4961b5d61b8SmrgrrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height, 4971b5d61b8Smrg int x, int y, Rotation rotation, Bool sync, 4981b5d61b8Smrg int numOutputs, RROutputPtr * outputs) 4991b5d61b8Smrg{ 5001b5d61b8Smrg ScreenPtr master = crtc->pScreen->current_master; 5011b5d61b8Smrg rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master); 5021b5d61b8Smrg rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen); 5031b5d61b8Smrg DrawablePtr mrootdraw = &master->root->drawable; 5041b5d61b8Smrg int depth = mrootdraw->depth; 5051b5d61b8Smrg PixmapPtr spix_front; 5061b5d61b8Smrg 5071b5d61b8Smrg /* Create a pixmap on the master screen, then get a shared handle for it. 5081b5d61b8Smrg Create a shared pixmap on the slave screen using the handle. 5091b5d61b8Smrg 5101b5d61b8Smrg If sync == FALSE -- 5111b5d61b8Smrg Set slave screen to scanout shared linear pixmap. 5121b5d61b8Smrg Set the master screen to do dirty updates to the shared pixmap 5131b5d61b8Smrg from the screen pixmap on its own accord. 5141b5d61b8Smrg 5151b5d61b8Smrg If sync == TRUE -- 5161b5d61b8Smrg If any of the below steps fail, clean up and fall back to sync == FALSE. 5171b5d61b8Smrg Create another shared pixmap on the slave screen using the handle. 5181b5d61b8Smrg Set slave screen to prepare for scanout and flipping between shared 5191b5d61b8Smrg linear pixmaps. 5201b5d61b8Smrg Set the master screen to do dirty updates to the shared pixmaps from the 5211b5d61b8Smrg screen pixmap when prompted to by us or the slave. 5221b5d61b8Smrg Prompt the master to do a dirty update on the first shared pixmap, then 5231b5d61b8Smrg defer to the slave. 5241b5d61b8Smrg */ 5251b5d61b8Smrg 5261b5d61b8Smrg if (crtc->scanout_pixmap) 5271b5d61b8Smrg RRCrtcDetachScanoutPixmap(crtc); 5281b5d61b8Smrg 5291b5d61b8Smrg if (width == 0 && height == 0) { 5301b5d61b8Smrg return TRUE; 5311b5d61b8Smrg } 5321b5d61b8Smrg 5331b5d61b8Smrg spix_front = rrCreateSharedPixmap(crtc, master, 5341b5d61b8Smrg width, height, depth, 5351b5d61b8Smrg x, y, rotation); 5361b5d61b8Smrg if (spix_front == NULL) { 5371b5d61b8Smrg ErrorF("randr: failed to create shared pixmap\n"); 53835c4bbdfSmrg return FALSE; 53935c4bbdfSmrg } 54035c4bbdfSmrg 5411b5d61b8Smrg /* Both source and sink must support required ABI funcs for flipping */ 5421b5d61b8Smrg if (sync && 5431b5d61b8Smrg pSlaveScrPriv->rrEnableSharedPixmapFlipping && 5441b5d61b8Smrg pSlaveScrPriv->rrDisableSharedPixmapFlipping && 5451b5d61b8Smrg pMasterScrPriv->rrStartFlippingPixmapTracking && 5461b5d61b8Smrg master->PresentSharedPixmap && 5471b5d61b8Smrg master->StopFlippingPixmapTracking) { 5481b5d61b8Smrg 5491b5d61b8Smrg PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master, 5501b5d61b8Smrg width, height, depth, 5511b5d61b8Smrg x, y, rotation); 5521b5d61b8Smrg if (spix_back == NULL) 5531b5d61b8Smrg goto fail; 5541b5d61b8Smrg 5551b5d61b8Smrg if (!pSlaveScrPriv->rrEnableSharedPixmapFlipping(crtc, 5561b5d61b8Smrg spix_front, spix_back)) 5571b5d61b8Smrg goto fail; 5581b5d61b8Smrg 5591b5d61b8Smrg crtc->scanout_pixmap = spix_front; 5601b5d61b8Smrg crtc->scanout_pixmap_back = spix_back; 5611b5d61b8Smrg 5621b5d61b8Smrg if (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc, 5631b5d61b8Smrg mrootdraw, 5641b5d61b8Smrg spix_front, 5651b5d61b8Smrg spix_back, 5661b5d61b8Smrg x, y, 0, 0, 5671b5d61b8Smrg rotation)) { 5681b5d61b8Smrg pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc); 5691b5d61b8Smrg goto fail; 5701b5d61b8Smrg } 5711b5d61b8Smrg 5721b5d61b8Smrg master->PresentSharedPixmap(spix_front); 5731b5d61b8Smrg 5741b5d61b8Smrg return TRUE; 5751b5d61b8Smrg 5761b5d61b8Smrgfail: /* If flipping funcs fail, just fall back to unsynchronized */ 5771b5d61b8Smrg if (spix_back) 5781b5d61b8Smrg rrDestroySharedPixmap(crtc, spix_back); 5791b5d61b8Smrg 5801b5d61b8Smrg crtc->scanout_pixmap = NULL; 5811b5d61b8Smrg crtc->scanout_pixmap_back = NULL; 5821b5d61b8Smrg } 5831b5d61b8Smrg 5841b5d61b8Smrg if (sync) { /* Wanted sync, didn't get it */ 5851b5d61b8Smrg ErrorF("randr: falling back to unsynchronized pixmap sharing\n"); 5861b5d61b8Smrg 5871b5d61b8Smrg /* Set output property to 0 to indicate to user */ 5881b5d61b8Smrg rrSetPixmapSharingSyncProp(0, numOutputs, outputs); 5891b5d61b8Smrg } 5901b5d61b8Smrg 5911b5d61b8Smrg if (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) { 5921b5d61b8Smrg rrDestroySharedPixmap(crtc, spix_front); 59335c4bbdfSmrg ErrorF("randr: failed to set shadow slave pixmap\n"); 59435c4bbdfSmrg return FALSE; 59535c4bbdfSmrg } 5961b5d61b8Smrg crtc->scanout_pixmap = spix_front; 59735c4bbdfSmrg 5981b5d61b8Smrg master->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation); 59935c4bbdfSmrg 60035c4bbdfSmrg return TRUE; 60135c4bbdfSmrg} 60235c4bbdfSmrg 60335c4bbdfSmrgstatic void crtc_to_box(BoxPtr box, RRCrtcPtr crtc) 60435c4bbdfSmrg{ 60535c4bbdfSmrg box->x1 = crtc->x; 60635c4bbdfSmrg box->y1 = crtc->y; 60735c4bbdfSmrg switch (crtc->rotation) { 60835c4bbdfSmrg case RR_Rotate_0: 60935c4bbdfSmrg case RR_Rotate_180: 61035c4bbdfSmrg default: 61135c4bbdfSmrg box->x2 = crtc->x + crtc->mode->mode.width; 61235c4bbdfSmrg box->y2 = crtc->y + crtc->mode->mode.height; 61335c4bbdfSmrg break; 61435c4bbdfSmrg case RR_Rotate_90: 61535c4bbdfSmrg case RR_Rotate_270: 61635c4bbdfSmrg box->x2 = crtc->x + crtc->mode->mode.height; 61735c4bbdfSmrg box->y2 = crtc->y + crtc->mode->mode.width; 61835c4bbdfSmrg break; 61935c4bbdfSmrg } 62035c4bbdfSmrg} 62135c4bbdfSmrg 62235c4bbdfSmrgstatic Bool 62335c4bbdfSmrgrrCheckPixmapBounding(ScreenPtr pScreen, 62435c4bbdfSmrg RRCrtcPtr rr_crtc, Rotation rotation, 62535c4bbdfSmrg int x, int y, int w, int h) 62635c4bbdfSmrg{ 62735c4bbdfSmrg RegionRec root_pixmap_region, total_region, new_crtc_region; 62835c4bbdfSmrg int c; 62935c4bbdfSmrg BoxRec newbox; 63035c4bbdfSmrg BoxPtr newsize; 63135c4bbdfSmrg ScreenPtr slave; 63235c4bbdfSmrg int new_width, new_height; 63335c4bbdfSmrg PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen); 63435c4bbdfSmrg rrScrPriv(pScreen); 63535c4bbdfSmrg 63635c4bbdfSmrg PixmapRegionInit(&root_pixmap_region, screen_pixmap); 63735c4bbdfSmrg RegionInit(&total_region, NULL, 0); 63835c4bbdfSmrg 63935c4bbdfSmrg /* have to iterate all the crtcs of the attached gpu masters 64035c4bbdfSmrg and all their output slaves */ 64135c4bbdfSmrg for (c = 0; c < pScrPriv->numCrtcs; c++) { 64235c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[c]; 64335c4bbdfSmrg 64435c4bbdfSmrg if (crtc == rr_crtc) { 64535c4bbdfSmrg newbox.x1 = x; 64635c4bbdfSmrg newbox.y1 = y; 64735c4bbdfSmrg if (rotation == RR_Rotate_90 || 64835c4bbdfSmrg rotation == RR_Rotate_270) { 64935c4bbdfSmrg newbox.x2 = x + h; 65035c4bbdfSmrg newbox.y2 = y + w; 65135c4bbdfSmrg } else { 65235c4bbdfSmrg newbox.x2 = x + w; 65335c4bbdfSmrg newbox.y2 = y + h; 65435c4bbdfSmrg } 65535c4bbdfSmrg } else { 65635c4bbdfSmrg if (!crtc->mode) 65735c4bbdfSmrg continue; 65835c4bbdfSmrg crtc_to_box(&newbox, crtc); 65935c4bbdfSmrg } 66035c4bbdfSmrg RegionInit(&new_crtc_region, &newbox, 1); 66135c4bbdfSmrg RegionUnion(&total_region, &total_region, &new_crtc_region); 66235c4bbdfSmrg } 66335c4bbdfSmrg 6641b5d61b8Smrg xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 66535c4bbdfSmrg rrScrPrivPtr slave_priv = rrGetScrPriv(slave); 6661b5d61b8Smrg 6671b5d61b8Smrg if (!slave->is_output_slave) 6681b5d61b8Smrg continue; 6691b5d61b8Smrg 67035c4bbdfSmrg for (c = 0; c < slave_priv->numCrtcs; c++) { 67135c4bbdfSmrg RRCrtcPtr slave_crtc = slave_priv->crtcs[c]; 67235c4bbdfSmrg 67335c4bbdfSmrg if (slave_crtc == rr_crtc) { 67435c4bbdfSmrg newbox.x1 = x; 67535c4bbdfSmrg newbox.y1 = y; 67635c4bbdfSmrg if (rotation == RR_Rotate_90 || 67735c4bbdfSmrg rotation == RR_Rotate_270) { 67835c4bbdfSmrg newbox.x2 = x + h; 67935c4bbdfSmrg newbox.y2 = y + w; 68035c4bbdfSmrg } else { 68135c4bbdfSmrg newbox.x2 = x + w; 68235c4bbdfSmrg newbox.y2 = y + h; 68335c4bbdfSmrg } 68435c4bbdfSmrg } 68535c4bbdfSmrg else { 68635c4bbdfSmrg if (!slave_crtc->mode) 68735c4bbdfSmrg continue; 68835c4bbdfSmrg crtc_to_box(&newbox, slave_crtc); 68935c4bbdfSmrg } 69035c4bbdfSmrg RegionInit(&new_crtc_region, &newbox, 1); 69135c4bbdfSmrg RegionUnion(&total_region, &total_region, &new_crtc_region); 69235c4bbdfSmrg } 69335c4bbdfSmrg } 69435c4bbdfSmrg 69535c4bbdfSmrg newsize = RegionExtents(&total_region); 6961b5d61b8Smrg new_width = newsize->x2; 6971b5d61b8Smrg new_height = newsize->y2; 6981b5d61b8Smrg 6991b5d61b8Smrg if (new_width < screen_pixmap->drawable.width) 7001b5d61b8Smrg new_width = screen_pixmap->drawable.width; 70135c4bbdfSmrg 7021b5d61b8Smrg if (new_height < screen_pixmap->drawable.height) 7031b5d61b8Smrg new_height = screen_pixmap->drawable.height; 7041b5d61b8Smrg 7051b5d61b8Smrg if (new_width <= screen_pixmap->drawable.width && 7061b5d61b8Smrg new_height <= screen_pixmap->drawable.height) { 70735c4bbdfSmrg } else { 70835c4bbdfSmrg pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0); 70935c4bbdfSmrg } 71035c4bbdfSmrg 71135c4bbdfSmrg /* set shatters TODO */ 71235c4bbdfSmrg return TRUE; 71305b261ecSmrg} 71405b261ecSmrg 71505b261ecSmrg/* 71605b261ecSmrg * Request that the Crtc be reconfigured 71705b261ecSmrg */ 71805b261ecSmrgBool 71935c4bbdfSmrgRRCrtcSet(RRCrtcPtr crtc, 72035c4bbdfSmrg RRModePtr mode, 72135c4bbdfSmrg int x, 72235c4bbdfSmrg int y, Rotation rotation, int numOutputs, RROutputPtr * outputs) 72305b261ecSmrg{ 72435c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 72535c4bbdfSmrg Bool ret = FALSE; 72635c4bbdfSmrg Bool recompute = TRUE; 72735c4bbdfSmrg Bool crtcChanged; 72835c4bbdfSmrg int o; 72935c4bbdfSmrg 73005b261ecSmrg rrScrPriv(pScreen); 73105b261ecSmrg 73235c4bbdfSmrg crtcChanged = FALSE; 73335c4bbdfSmrg for (o = 0; o < numOutputs; o++) { 73435c4bbdfSmrg if (outputs[o] && outputs[o]->crtc != crtc) { 73535c4bbdfSmrg crtcChanged = TRUE; 73635c4bbdfSmrg break; 73735c4bbdfSmrg } 73835c4bbdfSmrg } 73935c4bbdfSmrg 74005b261ecSmrg /* See if nothing changed */ 74105b261ecSmrg if (crtc->mode == mode && 74235c4bbdfSmrg crtc->x == x && 74335c4bbdfSmrg crtc->y == y && 74435c4bbdfSmrg crtc->rotation == rotation && 74535c4bbdfSmrg crtc->numOutputs == numOutputs && 74635c4bbdfSmrg !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) && 74735c4bbdfSmrg !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) && 74835c4bbdfSmrg !crtcChanged) { 74935c4bbdfSmrg recompute = FALSE; 75035c4bbdfSmrg ret = TRUE; 75105b261ecSmrg } 75235c4bbdfSmrg else { 75335c4bbdfSmrg if (pScreen->isGPU) { 75435c4bbdfSmrg ScreenPtr master = pScreen->current_master; 75535c4bbdfSmrg int width = 0, height = 0; 75635c4bbdfSmrg 75735c4bbdfSmrg if (mode) { 75835c4bbdfSmrg width = mode->mode.width; 75935c4bbdfSmrg height = mode->mode.height; 76035c4bbdfSmrg } 76135c4bbdfSmrg ret = rrCheckPixmapBounding(master, crtc, 76235c4bbdfSmrg rotation, x, y, width, height); 76335c4bbdfSmrg if (!ret) 76435c4bbdfSmrg return FALSE; 76535c4bbdfSmrg 76635c4bbdfSmrg if (pScreen->current_master) { 7671b5d61b8Smrg Bool sync = rrGetPixmapSharingSyncProp(numOutputs, outputs); 7681b5d61b8Smrg ret = rrSetupPixmapSharing(crtc, width, height, 7691b5d61b8Smrg x, y, rotation, sync, 7701b5d61b8Smrg numOutputs, outputs); 77135c4bbdfSmrg } 77235c4bbdfSmrg } 77305b261ecSmrg#if RANDR_12_INTERFACE 77435c4bbdfSmrg if (pScrPriv->rrCrtcSet) { 77535c4bbdfSmrg ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 77635c4bbdfSmrg rotation, numOutputs, outputs); 77735c4bbdfSmrg } 77835c4bbdfSmrg else 77905b261ecSmrg#endif 78035c4bbdfSmrg { 78105b261ecSmrg#if RANDR_10_INTERFACE 78235c4bbdfSmrg if (pScrPriv->rrSetConfig) { 78335c4bbdfSmrg RRScreenSize size; 78435c4bbdfSmrg RRScreenRate rate; 78535c4bbdfSmrg 78635c4bbdfSmrg if (!mode) { 78735c4bbdfSmrg RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL); 78835c4bbdfSmrg ret = TRUE; 78935c4bbdfSmrg } 79035c4bbdfSmrg else { 79135c4bbdfSmrg size.width = mode->mode.width; 79235c4bbdfSmrg size.height = mode->mode.height; 79335c4bbdfSmrg if (outputs[0]->mmWidth && outputs[0]->mmHeight) { 79435c4bbdfSmrg size.mmWidth = outputs[0]->mmWidth; 79535c4bbdfSmrg size.mmHeight = outputs[0]->mmHeight; 79635c4bbdfSmrg } 79735c4bbdfSmrg else { 79835c4bbdfSmrg size.mmWidth = pScreen->mmWidth; 79935c4bbdfSmrg size.mmHeight = pScreen->mmHeight; 80035c4bbdfSmrg } 80135c4bbdfSmrg size.nRates = 1; 80235c4bbdfSmrg rate.rate = RRVerticalRefresh(&mode->mode); 80335c4bbdfSmrg size.pRates = &rate; 80435c4bbdfSmrg ret = 80535c4bbdfSmrg (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, 80635c4bbdfSmrg &size); 80735c4bbdfSmrg /* 80835c4bbdfSmrg * Old 1.0 interface tied screen size to mode size 80935c4bbdfSmrg */ 81035c4bbdfSmrg if (ret) { 81135c4bbdfSmrg RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1, 81235c4bbdfSmrg outputs); 81335c4bbdfSmrg RRScreenSizeNotify(pScreen); 81435c4bbdfSmrg } 81535c4bbdfSmrg } 81635c4bbdfSmrg } 81705b261ecSmrg#endif 81835c4bbdfSmrg } 81935c4bbdfSmrg if (ret) { 82005b261ecSmrg 82135c4bbdfSmrg RRTellChanged(pScreen); 82235c4bbdfSmrg 82335c4bbdfSmrg for (o = 0; o < numOutputs; o++) 82435c4bbdfSmrg RRPostPendingProperties(outputs[o]); 82535c4bbdfSmrg } 82605b261ecSmrg } 82735c4bbdfSmrg 82835c4bbdfSmrg if (recompute) 82935c4bbdfSmrg RRComputeContiguity(pScreen); 83035c4bbdfSmrg 83105b261ecSmrg return ret; 83205b261ecSmrg} 83305b261ecSmrg 8344642e01fSmrg/* 8354642e01fSmrg * Return crtc transform 8364642e01fSmrg */ 8374642e01fSmrgRRTransformPtr 83835c4bbdfSmrgRRCrtcGetTransform(RRCrtcPtr crtc) 8394642e01fSmrg{ 84035c4bbdfSmrg RRTransformPtr transform = &crtc->client_pending_transform; 8414642e01fSmrg 84235c4bbdfSmrg if (pixman_transform_is_identity(&transform->transform)) 84335c4bbdfSmrg return NULL; 8444642e01fSmrg return transform; 8454642e01fSmrg} 8464642e01fSmrg 8474642e01fSmrg/* 8484642e01fSmrg * Check whether the pending and current transforms are the same 8494642e01fSmrg */ 8504642e01fSmrgBool 85135c4bbdfSmrgRRCrtcPendingTransform(RRCrtcPtr crtc) 8524642e01fSmrg{ 8531b5d61b8Smrg return !RRTransformEqual(&crtc->client_current_transform, 8541b5d61b8Smrg &crtc->client_pending_transform); 8554642e01fSmrg} 8564642e01fSmrg 85705b261ecSmrg/* 85805b261ecSmrg * Destroy a Crtc at shutdown 85905b261ecSmrg */ 86005b261ecSmrgvoid 86135c4bbdfSmrgRRCrtcDestroy(RRCrtcPtr crtc) 86205b261ecSmrg{ 86335c4bbdfSmrg FreeResource(crtc->id, 0); 86405b261ecSmrg} 86505b261ecSmrg 86605b261ecSmrgstatic int 86735c4bbdfSmrgRRCrtcDestroyResource(void *value, XID pid) 86805b261ecSmrg{ 86935c4bbdfSmrg RRCrtcPtr crtc = (RRCrtcPtr) value; 87035c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 87105b261ecSmrg 87235c4bbdfSmrg if (pScreen) { 87335c4bbdfSmrg rrScrPriv(pScreen); 87435c4bbdfSmrg int i; 8751b5d61b8Smrg RRLeasePtr lease, next; 8761b5d61b8Smrg 8771b5d61b8Smrg xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) { 8781b5d61b8Smrg int c; 8791b5d61b8Smrg for (c = 0; c < lease->numCrtcs; c++) { 8801b5d61b8Smrg if (lease->crtcs[c] == crtc) { 8811b5d61b8Smrg RRTerminateLease(lease); 8821b5d61b8Smrg break; 8831b5d61b8Smrg } 8841b5d61b8Smrg } 8851b5d61b8Smrg } 88635c4bbdfSmrg 88735c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 88835c4bbdfSmrg if (pScrPriv->crtcs[i] == crtc) { 88935c4bbdfSmrg memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, 89035c4bbdfSmrg (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr)); 89135c4bbdfSmrg --pScrPriv->numCrtcs; 89235c4bbdfSmrg break; 89335c4bbdfSmrg } 89435c4bbdfSmrg } 89535c4bbdfSmrg 89635c4bbdfSmrg RRResourcesChanged(pScreen); 89705b261ecSmrg } 89835c4bbdfSmrg 89935c4bbdfSmrg if (crtc->scanout_pixmap) 90035c4bbdfSmrg RRCrtcDetachScanoutPixmap(crtc); 9016747b715Smrg free(crtc->gammaRed); 90205b261ecSmrg if (crtc->mode) 90335c4bbdfSmrg RRModeDestroy(crtc->mode); 9041b5d61b8Smrg free(crtc->outputs); 9056747b715Smrg free(crtc); 90605b261ecSmrg return 1; 90705b261ecSmrg} 90805b261ecSmrg 90905b261ecSmrg/* 91005b261ecSmrg * Request that the Crtc gamma be changed 91105b261ecSmrg */ 91205b261ecSmrg 91305b261ecSmrgBool 91435c4bbdfSmrgRRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue) 91505b261ecSmrg{ 91635c4bbdfSmrg Bool ret = TRUE; 91735c4bbdfSmrg 91805b261ecSmrg#if RANDR_12_INTERFACE 91935c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 92005b261ecSmrg#endif 92135c4bbdfSmrg 92235c4bbdfSmrg memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16)); 92335c4bbdfSmrg memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16)); 92435c4bbdfSmrg memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16)); 92505b261ecSmrg#if RANDR_12_INTERFACE 92635c4bbdfSmrg if (pScreen) { 92735c4bbdfSmrg rrScrPriv(pScreen); 92835c4bbdfSmrg if (pScrPriv->rrCrtcSetGamma) 92935c4bbdfSmrg ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); 93005b261ecSmrg } 93105b261ecSmrg#endif 93205b261ecSmrg return ret; 93305b261ecSmrg} 93405b261ecSmrg 9356747b715Smrg/* 9366747b715Smrg * Request current gamma back from the DDX (if possible). 9376747b715Smrg * This includes gamma size. 9386747b715Smrg */ 9396747b715SmrgBool 9406747b715SmrgRRCrtcGammaGet(RRCrtcPtr crtc) 9416747b715Smrg{ 9426747b715Smrg Bool ret = TRUE; 94335c4bbdfSmrg 9446747b715Smrg#if RANDR_12_INTERFACE 94535c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 9466747b715Smrg#endif 9476747b715Smrg 9486747b715Smrg#if RANDR_12_INTERFACE 94935c4bbdfSmrg if (pScreen) { 9506747b715Smrg rrScrPriv(pScreen); 9516747b715Smrg if (pScrPriv->rrCrtcGetGamma) 9526747b715Smrg ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); 9536747b715Smrg } 9546747b715Smrg#endif 9556747b715Smrg return ret; 9566747b715Smrg} 9576747b715Smrg 95805b261ecSmrg/* 95905b261ecSmrg * Notify the extension that the Crtc gamma has been changed 96005b261ecSmrg * The driver calls this whenever it has changed the gamma values 96105b261ecSmrg * in the RRCrtcRec 96205b261ecSmrg */ 96305b261ecSmrg 96405b261ecSmrgBool 96535c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc) 96605b261ecSmrg{ 96735c4bbdfSmrg return TRUE; /* not much going on here */ 96805b261ecSmrg} 96905b261ecSmrg 9704642e01fSmrgstatic void 97135c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform, 97235c4bbdfSmrg int *width, int *height) 97305b261ecSmrg{ 97435c4bbdfSmrg BoxRec box; 9754642e01fSmrg 9764642e01fSmrg if (mode == NULL) { 97735c4bbdfSmrg *width = 0; 97835c4bbdfSmrg *height = 0; 97935c4bbdfSmrg return; 98005b261ecSmrg } 98105b261ecSmrg 9824642e01fSmrg box.x1 = 0; 9834642e01fSmrg box.y1 = 0; 9844642e01fSmrg box.x2 = mode->mode.width; 9854642e01fSmrg box.y2 = mode->mode.height; 9864642e01fSmrg 98735c4bbdfSmrg pixman_transform_bounds(transform, &box); 9884642e01fSmrg *width = box.x2 - box.x1; 9894642e01fSmrg *height = box.y2 - box.y1; 9904642e01fSmrg} 9914642e01fSmrg 9924642e01fSmrg/** 9934642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer 9944642e01fSmrg */ 9954642e01fSmrgvoid 9964642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 9974642e01fSmrg{ 99835c4bbdfSmrg RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height); 99905b261ecSmrg} 100005b261ecSmrg 100105b261ecSmrg/* 100205b261ecSmrg * Set the size of the gamma table at server startup time 100305b261ecSmrg */ 100405b261ecSmrg 100505b261ecSmrgBool 100635c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size) 100705b261ecSmrg{ 100835c4bbdfSmrg CARD16 *gamma; 100905b261ecSmrg 101005b261ecSmrg if (size == crtc->gammaSize) 101135c4bbdfSmrg return TRUE; 101235c4bbdfSmrg if (size) { 101335c4bbdfSmrg gamma = xallocarray(size, 3 * sizeof(CARD16)); 101435c4bbdfSmrg if (!gamma) 101535c4bbdfSmrg return FALSE; 101605b261ecSmrg } 101705b261ecSmrg else 101835c4bbdfSmrg gamma = NULL; 10196747b715Smrg free(crtc->gammaRed); 102005b261ecSmrg crtc->gammaRed = gamma; 102105b261ecSmrg crtc->gammaGreen = gamma + size; 102235c4bbdfSmrg crtc->gammaBlue = gamma + size * 2; 102305b261ecSmrg crtc->gammaSize = size; 102405b261ecSmrg return TRUE; 102505b261ecSmrg} 102605b261ecSmrg 10274642e01fSmrg/* 10284642e01fSmrg * Set the pending CRTC transformation 10294642e01fSmrg */ 10304642e01fSmrg 10314642e01fSmrgint 103235c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc, 103335c4bbdfSmrg PictTransformPtr transform, 103435c4bbdfSmrg struct pixman_f_transform *f_transform, 103535c4bbdfSmrg struct pixman_f_transform *f_inverse, 103635c4bbdfSmrg char *filter_name, 103735c4bbdfSmrg int filter_len, xFixed * params, int nparams) 10384642e01fSmrg{ 103935c4bbdfSmrg PictFilterPtr filter = NULL; 104035c4bbdfSmrg int width = 0, height = 0; 10414642e01fSmrg 10424642e01fSmrg if (!crtc->transforms) 104335c4bbdfSmrg return BadValue; 104435c4bbdfSmrg 104535c4bbdfSmrg if (filter_len) { 104635c4bbdfSmrg filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len); 104735c4bbdfSmrg if (!filter) 104835c4bbdfSmrg return BadName; 104935c4bbdfSmrg if (filter->ValidateParams) { 105035c4bbdfSmrg if (!filter->ValidateParams(crtc->pScreen, filter->id, 105135c4bbdfSmrg params, nparams, &width, &height)) 105235c4bbdfSmrg return BadMatch; 105335c4bbdfSmrg } 105435c4bbdfSmrg else { 105535c4bbdfSmrg width = filter->width; 105635c4bbdfSmrg height = filter->height; 105735c4bbdfSmrg } 10584642e01fSmrg } 105935c4bbdfSmrg else { 106035c4bbdfSmrg if (nparams) 106135c4bbdfSmrg return BadMatch; 10624642e01fSmrg } 106335c4bbdfSmrg if (!RRTransformSetFilter(&crtc->client_pending_transform, 106435c4bbdfSmrg filter, params, nparams, width, height)) 106535c4bbdfSmrg return BadAlloc; 10664642e01fSmrg 10674642e01fSmrg crtc->client_pending_transform.transform = *transform; 10684642e01fSmrg crtc->client_pending_transform.f_transform = *f_transform; 10694642e01fSmrg crtc->client_pending_transform.f_inverse = *f_inverse; 10704642e01fSmrg return Success; 10714642e01fSmrg} 10724642e01fSmrg 107305b261ecSmrg/* 107405b261ecSmrg * Initialize crtc type 107505b261ecSmrg */ 107605b261ecSmrgBool 107735c4bbdfSmrgRRCrtcInit(void) 107805b261ecSmrg{ 107935c4bbdfSmrg RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC"); 108005b261ecSmrg if (!RRCrtcType) 108135c4bbdfSmrg return FALSE; 108235c4bbdfSmrg 108305b261ecSmrg return TRUE; 108405b261ecSmrg} 108505b261ecSmrg 10866747b715Smrg/* 10876747b715Smrg * Initialize crtc type error value 10886747b715Smrg */ 10896747b715Smrgvoid 10906747b715SmrgRRCrtcInitErrorValue(void) 10916747b715Smrg{ 10926747b715Smrg SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 10936747b715Smrg} 10946747b715Smrg 109505b261ecSmrgint 109635c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client) 109705b261ecSmrg{ 109805b261ecSmrg REQUEST(xRRGetCrtcInfoReq); 109935c4bbdfSmrg xRRGetCrtcInfoReply rep; 110035c4bbdfSmrg RRCrtcPtr crtc; 11011b5d61b8Smrg CARD8 *extra = NULL; 110235c4bbdfSmrg unsigned long extraLen; 110335c4bbdfSmrg ScreenPtr pScreen; 110435c4bbdfSmrg rrScrPrivPtr pScrPriv; 110535c4bbdfSmrg RRModePtr mode; 110635c4bbdfSmrg RROutput *outputs; 110735c4bbdfSmrg RROutput *possible; 110835c4bbdfSmrg int i, j, k; 110935c4bbdfSmrg int width, height; 111035c4bbdfSmrg BoxRec panned_area; 11111b5d61b8Smrg Bool leased; 111235c4bbdfSmrg 111305b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 11146747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 111505b261ecSmrg 11161b5d61b8Smrg leased = RRCrtcIsLeased(crtc); 11171b5d61b8Smrg 111805b261ecSmrg /* All crtcs must be associated with screens before client 111905b261ecSmrg * requests are processed 112005b261ecSmrg */ 112105b261ecSmrg pScreen = crtc->pScreen; 112205b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 112305b261ecSmrg 112405b261ecSmrg mode = crtc->mode; 112535c4bbdfSmrg 112635c4bbdfSmrg rep = (xRRGetCrtcInfoReply) { 112735c4bbdfSmrg .type = X_Reply, 112835c4bbdfSmrg .status = RRSetConfigSuccess, 112935c4bbdfSmrg .sequenceNumber = client->sequence, 113035c4bbdfSmrg .length = 0, 113135c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 113235c4bbdfSmrg }; 11331b5d61b8Smrg if (leased) { 11341b5d61b8Smrg rep.x = rep.y = rep.width = rep.height = 0; 11351b5d61b8Smrg rep.mode = 0; 11361b5d61b8Smrg rep.rotation = RR_Rotate_0; 11371b5d61b8Smrg rep.rotations = RR_Rotate_0; 11381b5d61b8Smrg rep.nOutput = 0; 11391b5d61b8Smrg rep.nPossibleOutput = 0; 11401b5d61b8Smrg rep.length = 0; 11411b5d61b8Smrg extraLen = 0; 11421b5d61b8Smrg } else { 11431b5d61b8Smrg if (pScrPriv->rrGetPanning && 11441b5d61b8Smrg pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) && 11451b5d61b8Smrg (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 11461b5d61b8Smrg { 11471b5d61b8Smrg rep.x = panned_area.x1; 11481b5d61b8Smrg rep.y = panned_area.y1; 11491b5d61b8Smrg rep.width = panned_area.x2 - panned_area.x1; 11501b5d61b8Smrg rep.height = panned_area.y2 - panned_area.y1; 11511b5d61b8Smrg } 11521b5d61b8Smrg else { 11531b5d61b8Smrg RRCrtcGetScanoutSize(crtc, &width, &height); 11541b5d61b8Smrg rep.x = crtc->x; 11551b5d61b8Smrg rep.y = crtc->y; 11561b5d61b8Smrg rep.width = width; 11571b5d61b8Smrg rep.height = height; 11581b5d61b8Smrg } 11591b5d61b8Smrg rep.mode = mode ? mode->mode.id : 0; 11601b5d61b8Smrg rep.rotation = crtc->rotation; 11611b5d61b8Smrg rep.rotations = crtc->rotations; 11621b5d61b8Smrg rep.nOutput = crtc->numOutputs; 11631b5d61b8Smrg k = 0; 11641b5d61b8Smrg for (i = 0; i < pScrPriv->numOutputs; i++) { 11651b5d61b8Smrg if (!RROutputIsLeased(pScrPriv->outputs[i])) { 11661b5d61b8Smrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 11671b5d61b8Smrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) 11681b5d61b8Smrg k++; 116935c4bbdfSmrg } 11701b5d61b8Smrg } 11711b5d61b8Smrg 11721b5d61b8Smrg rep.nPossibleOutput = k; 11731b5d61b8Smrg 11741b5d61b8Smrg rep.length = rep.nOutput + rep.nPossibleOutput; 11751b5d61b8Smrg 11761b5d61b8Smrg extraLen = rep.length << 2; 11771b5d61b8Smrg if (extraLen) { 11781b5d61b8Smrg extra = malloc(extraLen); 11791b5d61b8Smrg if (!extra) 11801b5d61b8Smrg return BadAlloc; 11811b5d61b8Smrg } 11821b5d61b8Smrg 11831b5d61b8Smrg outputs = (RROutput *) extra; 11841b5d61b8Smrg possible = (RROutput *) (outputs + rep.nOutput); 11851b5d61b8Smrg 11861b5d61b8Smrg for (i = 0; i < crtc->numOutputs; i++) { 11871b5d61b8Smrg outputs[i] = crtc->outputs[i]->id; 11881b5d61b8Smrg if (client->swapped) 11891b5d61b8Smrg swapl(&outputs[i]); 11901b5d61b8Smrg } 11911b5d61b8Smrg k = 0; 11921b5d61b8Smrg for (i = 0; i < pScrPriv->numOutputs; i++) { 11931b5d61b8Smrg if (!RROutputIsLeased(pScrPriv->outputs[i])) { 11941b5d61b8Smrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 11951b5d61b8Smrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) { 11961b5d61b8Smrg possible[k] = pScrPriv->outputs[i]->id; 11971b5d61b8Smrg if (client->swapped) 11981b5d61b8Smrg swapl(&possible[k]); 11991b5d61b8Smrg k++; 12001b5d61b8Smrg } 12011b5d61b8Smrg } 12021b5d61b8Smrg } 12031b5d61b8Smrg } 120435c4bbdfSmrg 120505b261ecSmrg if (client->swapped) { 120635c4bbdfSmrg swaps(&rep.sequenceNumber); 120735c4bbdfSmrg swapl(&rep.length); 120835c4bbdfSmrg swapl(&rep.timestamp); 120935c4bbdfSmrg swaps(&rep.x); 121035c4bbdfSmrg swaps(&rep.y); 121135c4bbdfSmrg swaps(&rep.width); 121235c4bbdfSmrg swaps(&rep.height); 121335c4bbdfSmrg swapl(&rep.mode); 121435c4bbdfSmrg swaps(&rep.rotation); 121535c4bbdfSmrg swaps(&rep.rotations); 121635c4bbdfSmrg swaps(&rep.nOutput); 121735c4bbdfSmrg swaps(&rep.nPossibleOutput); 121835c4bbdfSmrg } 121935c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep); 122035c4bbdfSmrg if (extraLen) { 122135c4bbdfSmrg WriteToClient(client, extraLen, extra); 122235c4bbdfSmrg free(extra); 122305b261ecSmrg } 122435c4bbdfSmrg 12256747b715Smrg return Success; 122605b261ecSmrg} 122705b261ecSmrg 122805b261ecSmrgint 122935c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client) 123005b261ecSmrg{ 123105b261ecSmrg REQUEST(xRRSetCrtcConfigReq); 123235c4bbdfSmrg xRRSetCrtcConfigReply rep; 123335c4bbdfSmrg ScreenPtr pScreen; 123435c4bbdfSmrg rrScrPrivPtr pScrPriv; 123535c4bbdfSmrg RRCrtcPtr crtc; 123635c4bbdfSmrg RRModePtr mode; 123735c4bbdfSmrg int numOutputs; 123835c4bbdfSmrg RROutputPtr *outputs = NULL; 123935c4bbdfSmrg RROutput *outputIds; 124035c4bbdfSmrg TimeStamp time; 124135c4bbdfSmrg Rotation rotation; 124235c4bbdfSmrg int ret, i, j; 124335c4bbdfSmrg CARD8 status; 124435c4bbdfSmrg 124505b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 124635c4bbdfSmrg numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq))); 124735c4bbdfSmrg 12486747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 12496747b715Smrg 12501b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 12511b5d61b8Smrg return BadAccess; 12521b5d61b8Smrg 125335c4bbdfSmrg if (stuff->mode == None) { 125435c4bbdfSmrg mode = NULL; 125535c4bbdfSmrg if (numOutputs > 0) 125635c4bbdfSmrg return BadMatch; 125705b261ecSmrg } 125835c4bbdfSmrg else { 125935c4bbdfSmrg VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 126035c4bbdfSmrg if (numOutputs == 0) 126135c4bbdfSmrg return BadMatch; 126205b261ecSmrg } 126335c4bbdfSmrg if (numOutputs) { 126435c4bbdfSmrg outputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 126535c4bbdfSmrg if (!outputs) 126635c4bbdfSmrg return BadAlloc; 126705b261ecSmrg } 126805b261ecSmrg else 126935c4bbdfSmrg outputs = NULL; 127035c4bbdfSmrg 127105b261ecSmrg outputIds = (RROutput *) (stuff + 1); 127235c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 127335c4bbdfSmrg ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i], 127435c4bbdfSmrg RROutputType, client, DixSetAttrAccess); 127535c4bbdfSmrg if (ret != Success) { 127635c4bbdfSmrg free(outputs); 127735c4bbdfSmrg return ret; 127835c4bbdfSmrg } 12791b5d61b8Smrg 12801b5d61b8Smrg if (RROutputIsLeased(outputs[i])) { 12811b5d61b8Smrg free(outputs); 12821b5d61b8Smrg return BadAccess; 12831b5d61b8Smrg } 12841b5d61b8Smrg 128535c4bbdfSmrg /* validate crtc for this output */ 128635c4bbdfSmrg for (j = 0; j < outputs[i]->numCrtcs; j++) 128735c4bbdfSmrg if (outputs[i]->crtcs[j] == crtc) 128835c4bbdfSmrg break; 128935c4bbdfSmrg if (j == outputs[i]->numCrtcs) { 129035c4bbdfSmrg free(outputs); 129135c4bbdfSmrg return BadMatch; 129235c4bbdfSmrg } 129335c4bbdfSmrg /* validate mode for this output */ 129435c4bbdfSmrg for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) { 129535c4bbdfSmrg RRModePtr m = (j < outputs[i]->numModes ? 129635c4bbdfSmrg outputs[i]->modes[j] : 129735c4bbdfSmrg outputs[i]->userModes[j - outputs[i]->numModes]); 129835c4bbdfSmrg if (m == mode) 129935c4bbdfSmrg break; 130035c4bbdfSmrg } 130135c4bbdfSmrg if (j == outputs[i]->numModes + outputs[i]->numUserModes) { 130235c4bbdfSmrg free(outputs); 130335c4bbdfSmrg return BadMatch; 130435c4bbdfSmrg } 130505b261ecSmrg } 130605b261ecSmrg /* validate clones */ 130735c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 130835c4bbdfSmrg for (j = 0; j < numOutputs; j++) { 130935c4bbdfSmrg int k; 131035c4bbdfSmrg 131135c4bbdfSmrg if (i == j) 131235c4bbdfSmrg continue; 131335c4bbdfSmrg for (k = 0; k < outputs[i]->numClones; k++) { 131435c4bbdfSmrg if (outputs[i]->clones[k] == outputs[j]) 131535c4bbdfSmrg break; 131635c4bbdfSmrg } 131735c4bbdfSmrg if (k == outputs[i]->numClones) { 131835c4bbdfSmrg free(outputs); 131935c4bbdfSmrg return BadMatch; 132035c4bbdfSmrg } 132135c4bbdfSmrg } 132205b261ecSmrg } 132305b261ecSmrg 132405b261ecSmrg pScreen = crtc->pScreen; 132505b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 132635c4bbdfSmrg 132705b261ecSmrg time = ClientTimeToServerTime(stuff->timestamp); 132835c4bbdfSmrg 132935c4bbdfSmrg if (!pScrPriv) { 133035c4bbdfSmrg time = currentTime; 133135c4bbdfSmrg status = RRSetConfigFailed; 133235c4bbdfSmrg goto sendReply; 133305b261ecSmrg } 133435c4bbdfSmrg 133505b261ecSmrg /* 133605b261ecSmrg * Validate requested rotation 133705b261ecSmrg */ 133805b261ecSmrg rotation = (Rotation) stuff->rotation; 133905b261ecSmrg 134005b261ecSmrg /* test the rotation bits only! */ 134105b261ecSmrg switch (rotation & 0xf) { 134205b261ecSmrg case RR_Rotate_0: 134305b261ecSmrg case RR_Rotate_90: 134405b261ecSmrg case RR_Rotate_180: 134505b261ecSmrg case RR_Rotate_270: 134635c4bbdfSmrg break; 134705b261ecSmrg default: 134835c4bbdfSmrg /* 134935c4bbdfSmrg * Invalid rotation 135035c4bbdfSmrg */ 135135c4bbdfSmrg client->errorValue = stuff->rotation; 135235c4bbdfSmrg free(outputs); 135335c4bbdfSmrg return BadValue; 135405b261ecSmrg } 135505b261ecSmrg 135635c4bbdfSmrg if (mode) { 135735c4bbdfSmrg if ((~crtc->rotations) & rotation) { 135835c4bbdfSmrg /* 135935c4bbdfSmrg * requested rotation or reflection not supported by screen 136035c4bbdfSmrg */ 136135c4bbdfSmrg client->errorValue = stuff->rotation; 136235c4bbdfSmrg free(outputs); 136335c4bbdfSmrg return BadMatch; 136435c4bbdfSmrg } 136535c4bbdfSmrg 136605b261ecSmrg#ifdef RANDR_12_INTERFACE 136735c4bbdfSmrg /* 136835c4bbdfSmrg * Check screen size bounds if the DDX provides a 1.2 interface 136935c4bbdfSmrg * for setting screen size. Else, assume the CrtcSet sets 137035c4bbdfSmrg * the size along with the mode. If the driver supports transforms, 137135c4bbdfSmrg * then it must allow crtcs to display a subset of the screen, so 137235c4bbdfSmrg * only do this check for drivers without transform support. 137335c4bbdfSmrg */ 137435c4bbdfSmrg if (pScrPriv->rrScreenSetSize && !crtc->transforms) { 137535c4bbdfSmrg int source_width; 137635c4bbdfSmrg int source_height; 137735c4bbdfSmrg PictTransform transform; 137835c4bbdfSmrg struct pixman_f_transform f_transform, f_inverse; 137935c4bbdfSmrg int width, height; 138035c4bbdfSmrg 138135c4bbdfSmrg if (pScreen->isGPU) { 138235c4bbdfSmrg width = pScreen->current_master->width; 138335c4bbdfSmrg height = pScreen->current_master->height; 138435c4bbdfSmrg } 138535c4bbdfSmrg else { 138635c4bbdfSmrg width = pScreen->width; 138735c4bbdfSmrg height = pScreen->height; 138835c4bbdfSmrg } 138935c4bbdfSmrg 139035c4bbdfSmrg RRTransformCompute(stuff->x, stuff->y, 139135c4bbdfSmrg mode->mode.width, mode->mode.height, 139235c4bbdfSmrg rotation, 139335c4bbdfSmrg &crtc->client_pending_transform, 139435c4bbdfSmrg &transform, &f_transform, &f_inverse); 139535c4bbdfSmrg 139635c4bbdfSmrg RRModeGetScanoutSize(mode, &transform, &source_width, 139735c4bbdfSmrg &source_height); 139835c4bbdfSmrg if (stuff->x + source_width > width) { 139935c4bbdfSmrg client->errorValue = stuff->x; 140035c4bbdfSmrg free(outputs); 140135c4bbdfSmrg return BadValue; 140235c4bbdfSmrg } 140335c4bbdfSmrg 140435c4bbdfSmrg if (stuff->y + source_height > height) { 140535c4bbdfSmrg client->errorValue = stuff->y; 140635c4bbdfSmrg free(outputs); 140735c4bbdfSmrg return BadValue; 140835c4bbdfSmrg } 140935c4bbdfSmrg } 141005b261ecSmrg#endif 141105b261ecSmrg } 141235c4bbdfSmrg 141335c4bbdfSmrg if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y, 141435c4bbdfSmrg rotation, numOutputs, outputs)) { 141535c4bbdfSmrg status = RRSetConfigFailed; 141635c4bbdfSmrg goto sendReply; 141705b261ecSmrg } 141835c4bbdfSmrg status = RRSetConfigSuccess; 141952397711Smrg pScrPriv->lastSetTime = time; 142035c4bbdfSmrg 142135c4bbdfSmrg sendReply: 14226747b715Smrg free(outputs); 142335c4bbdfSmrg 142435c4bbdfSmrg rep = (xRRSetCrtcConfigReply) { 142535c4bbdfSmrg .type = X_Reply, 142635c4bbdfSmrg .status = status, 142735c4bbdfSmrg .sequenceNumber = client->sequence, 142835c4bbdfSmrg .length = 0, 142935c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 143035c4bbdfSmrg }; 143135c4bbdfSmrg 143235c4bbdfSmrg if (client->swapped) { 143335c4bbdfSmrg swaps(&rep.sequenceNumber); 143435c4bbdfSmrg swapl(&rep.length); 143535c4bbdfSmrg swapl(&rep.newTimestamp); 143605b261ecSmrg } 143735c4bbdfSmrg WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep); 143835c4bbdfSmrg 14396747b715Smrg return Success; 144005b261ecSmrg} 144105b261ecSmrg 14424642e01fSmrgint 144335c4bbdfSmrgProcRRGetPanning(ClientPtr client) 14444642e01fSmrg{ 14454642e01fSmrg REQUEST(xRRGetPanningReq); 144635c4bbdfSmrg xRRGetPanningReply rep; 144735c4bbdfSmrg RRCrtcPtr crtc; 144835c4bbdfSmrg ScreenPtr pScreen; 144935c4bbdfSmrg rrScrPrivPtr pScrPriv; 145035c4bbdfSmrg BoxRec total; 145135c4bbdfSmrg BoxRec tracking; 145235c4bbdfSmrg INT16 border[4]; 145335c4bbdfSmrg 14544642e01fSmrg REQUEST_SIZE_MATCH(xRRGetPanningReq); 14556747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 14564642e01fSmrg 14574642e01fSmrg /* All crtcs must be associated with screens before client 14584642e01fSmrg * requests are processed 14594642e01fSmrg */ 14604642e01fSmrg pScreen = crtc->pScreen; 14614642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 14624642e01fSmrg 14634642e01fSmrg if (!pScrPriv) 146435c4bbdfSmrg return RRErrorBase + BadRRCrtc; 14654642e01fSmrg 146635c4bbdfSmrg rep = (xRRGetPanningReply) { 146735c4bbdfSmrg .type = X_Reply, 146835c4bbdfSmrg .status = RRSetConfigSuccess, 146935c4bbdfSmrg .sequenceNumber = client->sequence, 147035c4bbdfSmrg .length = 1, 147135c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 147235c4bbdfSmrg }; 14734642e01fSmrg 14744642e01fSmrg if (pScrPriv->rrGetPanning && 147535c4bbdfSmrg pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) { 147635c4bbdfSmrg rep.left = total.x1; 147735c4bbdfSmrg rep.top = total.y1; 147835c4bbdfSmrg rep.width = total.x2 - total.x1; 147935c4bbdfSmrg rep.height = total.y2 - total.y1; 148035c4bbdfSmrg rep.track_left = tracking.x1; 148135c4bbdfSmrg rep.track_top = tracking.y1; 148235c4bbdfSmrg rep.track_width = tracking.x2 - tracking.x1; 148335c4bbdfSmrg rep.track_height = tracking.y2 - tracking.y1; 148435c4bbdfSmrg rep.border_left = border[0]; 148535c4bbdfSmrg rep.border_top = border[1]; 148635c4bbdfSmrg rep.border_right = border[2]; 148735c4bbdfSmrg rep.border_bottom = border[3]; 14884642e01fSmrg } 14894642e01fSmrg 14904642e01fSmrg if (client->swapped) { 149135c4bbdfSmrg swaps(&rep.sequenceNumber); 149235c4bbdfSmrg swapl(&rep.length); 149335c4bbdfSmrg swapl(&rep.timestamp); 149435c4bbdfSmrg swaps(&rep.left); 149535c4bbdfSmrg swaps(&rep.top); 149635c4bbdfSmrg swaps(&rep.width); 149735c4bbdfSmrg swaps(&rep.height); 149835c4bbdfSmrg swaps(&rep.track_left); 149935c4bbdfSmrg swaps(&rep.track_top); 150035c4bbdfSmrg swaps(&rep.track_width); 150135c4bbdfSmrg swaps(&rep.track_height); 150235c4bbdfSmrg swaps(&rep.border_left); 150335c4bbdfSmrg swaps(&rep.border_top); 150435c4bbdfSmrg swaps(&rep.border_right); 150535c4bbdfSmrg swaps(&rep.border_bottom); 150635c4bbdfSmrg } 150735c4bbdfSmrg WriteToClient(client, sizeof(xRRGetPanningReply), &rep); 15086747b715Smrg return Success; 15094642e01fSmrg} 15104642e01fSmrg 15114642e01fSmrgint 151235c4bbdfSmrgProcRRSetPanning(ClientPtr client) 15134642e01fSmrg{ 15144642e01fSmrg REQUEST(xRRSetPanningReq); 151535c4bbdfSmrg xRRSetPanningReply rep; 151635c4bbdfSmrg RRCrtcPtr crtc; 151735c4bbdfSmrg ScreenPtr pScreen; 151835c4bbdfSmrg rrScrPrivPtr pScrPriv; 151935c4bbdfSmrg TimeStamp time; 152035c4bbdfSmrg BoxRec total; 152135c4bbdfSmrg BoxRec tracking; 152235c4bbdfSmrg INT16 border[4]; 152335c4bbdfSmrg CARD8 status; 152435c4bbdfSmrg 15254642e01fSmrg REQUEST_SIZE_MATCH(xRRSetPanningReq); 15266747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 15274642e01fSmrg 15281b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 15291b5d61b8Smrg return BadAccess; 15301b5d61b8Smrg 15314642e01fSmrg /* All crtcs must be associated with screens before client 15324642e01fSmrg * requests are processed 15334642e01fSmrg */ 15344642e01fSmrg pScreen = crtc->pScreen; 15354642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 15364642e01fSmrg 15374642e01fSmrg if (!pScrPriv) { 153835c4bbdfSmrg time = currentTime; 153935c4bbdfSmrg status = RRSetConfigFailed; 154035c4bbdfSmrg goto sendReply; 15414642e01fSmrg } 154235c4bbdfSmrg 15434642e01fSmrg time = ClientTimeToServerTime(stuff->timestamp); 154435c4bbdfSmrg 15454642e01fSmrg if (!pScrPriv->rrGetPanning) 154635c4bbdfSmrg return RRErrorBase + BadRRCrtc; 15474642e01fSmrg 154835c4bbdfSmrg total.x1 = stuff->left; 154935c4bbdfSmrg total.y1 = stuff->top; 155035c4bbdfSmrg total.x2 = total.x1 + stuff->width; 155135c4bbdfSmrg total.y2 = total.y1 + stuff->height; 15524642e01fSmrg tracking.x1 = stuff->track_left; 15534642e01fSmrg tracking.y1 = stuff->track_top; 15544642e01fSmrg tracking.x2 = tracking.x1 + stuff->track_width; 15554642e01fSmrg tracking.y2 = tracking.y1 + stuff->track_height; 155635c4bbdfSmrg border[0] = stuff->border_left; 155735c4bbdfSmrg border[1] = stuff->border_top; 155835c4bbdfSmrg border[2] = stuff->border_right; 155935c4bbdfSmrg border[3] = stuff->border_bottom; 15604642e01fSmrg 156135c4bbdfSmrg if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border)) 156235c4bbdfSmrg return BadMatch; 15634642e01fSmrg 156452397711Smrg pScrPriv->lastSetTime = time; 156552397711Smrg 156635c4bbdfSmrg status = RRSetConfigSuccess; 15674642e01fSmrg 156835c4bbdfSmrg sendReply: 156935c4bbdfSmrg rep = (xRRSetPanningReply) { 157035c4bbdfSmrg .type = X_Reply, 157135c4bbdfSmrg .status = status, 157235c4bbdfSmrg .sequenceNumber = client->sequence, 157335c4bbdfSmrg .length = 0, 157435c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 157535c4bbdfSmrg }; 15764642e01fSmrg 15774642e01fSmrg if (client->swapped) { 157835c4bbdfSmrg swaps(&rep.sequenceNumber); 157935c4bbdfSmrg swapl(&rep.length); 158035c4bbdfSmrg swapl(&rep.newTimestamp); 15814642e01fSmrg } 158235c4bbdfSmrg WriteToClient(client, sizeof(xRRSetPanningReply), &rep); 15836747b715Smrg return Success; 15844642e01fSmrg} 15854642e01fSmrg 158605b261ecSmrgint 158735c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client) 158805b261ecSmrg{ 158905b261ecSmrg REQUEST(xRRGetCrtcGammaSizeReq); 159035c4bbdfSmrg xRRGetCrtcGammaSizeReply reply; 159135c4bbdfSmrg RRCrtcPtr crtc; 159205b261ecSmrg 159305b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 15946747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 15956747b715Smrg 15966747b715Smrg /* Gamma retrieval failed, any better error? */ 15976747b715Smrg if (!RRCrtcGammaGet(crtc)) 15986747b715Smrg return RRErrorBase + BadRRCrtc; 15996747b715Smrg 160035c4bbdfSmrg reply = (xRRGetCrtcGammaSizeReply) { 160135c4bbdfSmrg .type = X_Reply, 160235c4bbdfSmrg .sequenceNumber = client->sequence, 160335c4bbdfSmrg .length = 0, 160435c4bbdfSmrg .size = crtc->gammaSize 160535c4bbdfSmrg }; 160605b261ecSmrg if (client->swapped) { 160735c4bbdfSmrg swaps(&reply.sequenceNumber); 160835c4bbdfSmrg swapl(&reply.length); 160935c4bbdfSmrg swaps(&reply.size); 161005b261ecSmrg } 161135c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply); 16126747b715Smrg return Success; 161305b261ecSmrg} 161405b261ecSmrg 161505b261ecSmrgint 161635c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client) 161705b261ecSmrg{ 161805b261ecSmrg REQUEST(xRRGetCrtcGammaReq); 161935c4bbdfSmrg xRRGetCrtcGammaReply reply; 162035c4bbdfSmrg RRCrtcPtr crtc; 162135c4bbdfSmrg unsigned long len; 162235c4bbdfSmrg char *extra = NULL; 162335c4bbdfSmrg 162405b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 16256747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 16266747b715Smrg 16276747b715Smrg /* Gamma retrieval failed, any better error? */ 16286747b715Smrg if (!RRCrtcGammaGet(crtc)) 16296747b715Smrg return RRErrorBase + BadRRCrtc; 16306747b715Smrg 163105b261ecSmrg len = crtc->gammaSize * 3 * 2; 163235c4bbdfSmrg 16334642e01fSmrg if (crtc->gammaSize) { 163435c4bbdfSmrg extra = malloc(len); 163535c4bbdfSmrg if (!extra) 163635c4bbdfSmrg return BadAlloc; 16374642e01fSmrg } 16384642e01fSmrg 163935c4bbdfSmrg reply = (xRRGetCrtcGammaReply) { 164035c4bbdfSmrg .type = X_Reply, 164135c4bbdfSmrg .sequenceNumber = client->sequence, 164235c4bbdfSmrg .length = bytes_to_int32(len), 164335c4bbdfSmrg .size = crtc->gammaSize 164435c4bbdfSmrg }; 164505b261ecSmrg if (client->swapped) { 164635c4bbdfSmrg swaps(&reply.sequenceNumber); 164735c4bbdfSmrg swapl(&reply.length); 164835c4bbdfSmrg swaps(&reply.size); 164905b261ecSmrg } 165035c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply); 165135c4bbdfSmrg if (crtc->gammaSize) { 165235c4bbdfSmrg memcpy(extra, crtc->gammaRed, len); 165335c4bbdfSmrg client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 165435c4bbdfSmrg WriteSwappedDataToClient(client, len, extra); 165535c4bbdfSmrg free(extra); 165605b261ecSmrg } 16576747b715Smrg return Success; 165805b261ecSmrg} 165905b261ecSmrg 166005b261ecSmrgint 166135c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client) 166205b261ecSmrg{ 166305b261ecSmrg REQUEST(xRRSetCrtcGammaReq); 166435c4bbdfSmrg RRCrtcPtr crtc; 166535c4bbdfSmrg unsigned long len; 166635c4bbdfSmrg CARD16 *red, *green, *blue; 166735c4bbdfSmrg 166805b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 16696747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 167035c4bbdfSmrg 16711b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 16721b5d61b8Smrg return BadAccess; 16731b5d61b8Smrg 167435c4bbdfSmrg len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq)); 167505b261ecSmrg if (len < (stuff->size * 3 + 1) >> 1) 167635c4bbdfSmrg return BadLength; 167705b261ecSmrg 167805b261ecSmrg if (stuff->size != crtc->gammaSize) 167935c4bbdfSmrg return BadMatch; 168035c4bbdfSmrg 168105b261ecSmrg red = (CARD16 *) (stuff + 1); 168205b261ecSmrg green = red + crtc->gammaSize; 168305b261ecSmrg blue = green + crtc->gammaSize; 168435c4bbdfSmrg 168535c4bbdfSmrg RRCrtcGammaSet(crtc, red, green, blue); 168605b261ecSmrg 168705b261ecSmrg return Success; 168805b261ecSmrg} 168905b261ecSmrg 16904642e01fSmrg/* Version 1.3 additions */ 16914642e01fSmrg 16924642e01fSmrgint 169335c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client) 16944642e01fSmrg{ 16954642e01fSmrg REQUEST(xRRSetCrtcTransformReq); 169635c4bbdfSmrg RRCrtcPtr crtc; 169735c4bbdfSmrg PictTransform transform; 16984642e01fSmrg struct pixman_f_transform f_transform, f_inverse; 169935c4bbdfSmrg char *filter; 170035c4bbdfSmrg int nbytes; 170135c4bbdfSmrg xFixed *params; 170235c4bbdfSmrg int nparams; 17034642e01fSmrg 17044642e01fSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 17056747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 17064642e01fSmrg 17071b5d61b8Smrg if (RRCrtcIsLeased(crtc)) 17081b5d61b8Smrg return BadAccess; 17091b5d61b8Smrg 171035c4bbdfSmrg PictTransform_from_xRenderTransform(&transform, &stuff->transform); 171135c4bbdfSmrg pixman_f_transform_from_pixman_transform(&f_transform, &transform); 171235c4bbdfSmrg if (!pixman_f_transform_invert(&f_inverse, &f_transform)) 171335c4bbdfSmrg return BadMatch; 17144642e01fSmrg 17154642e01fSmrg filter = (char *) (stuff + 1); 17164642e01fSmrg nbytes = stuff->nbytesFilter; 17176747b715Smrg params = (xFixed *) (filter + pad_to_int32(nbytes)); 17184642e01fSmrg nparams = ((xFixed *) stuff + client->req_len) - params; 17194642e01fSmrg if (nparams < 0) 172035c4bbdfSmrg return BadLength; 17214642e01fSmrg 172235c4bbdfSmrg return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse, 172335c4bbdfSmrg filter, nbytes, params, nparams); 17244642e01fSmrg} 17254642e01fSmrg 17264642e01fSmrg#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 172735c4bbdfSmrg 17284642e01fSmrgstatic int 172935c4bbdfSmrgtransform_filter_length(RRTransformPtr transform) 17304642e01fSmrg{ 173135c4bbdfSmrg int nbytes, nparams; 17324642e01fSmrg 17334642e01fSmrg if (transform->filter == NULL) 173435c4bbdfSmrg return 0; 173535c4bbdfSmrg nbytes = strlen(transform->filter->name); 17364642e01fSmrg nparams = transform->nparams; 173735c4bbdfSmrg return pad_to_int32(nbytes) + (nparams * sizeof(xFixed)); 17384642e01fSmrg} 17394642e01fSmrg 17404642e01fSmrgstatic int 174135c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output, 174235c4bbdfSmrg CARD16 *nbytesFilter, 174335c4bbdfSmrg CARD16 *nparamsFilter, RRTransformPtr transform) 17444642e01fSmrg{ 174535c4bbdfSmrg int nbytes, nparams; 17464642e01fSmrg 17474642e01fSmrg if (transform->filter == NULL) { 174835c4bbdfSmrg *nbytesFilter = 0; 174935c4bbdfSmrg *nparamsFilter = 0; 175035c4bbdfSmrg return 0; 17514642e01fSmrg } 175235c4bbdfSmrg nbytes = strlen(transform->filter->name); 17534642e01fSmrg nparams = transform->nparams; 17544642e01fSmrg *nbytesFilter = nbytes; 17554642e01fSmrg *nparamsFilter = nparams; 175635c4bbdfSmrg memcpy(output, transform->filter->name, nbytes); 17574642e01fSmrg while ((nbytes & 3) != 0) 175835c4bbdfSmrg output[nbytes++] = 0; 175935c4bbdfSmrg memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed)); 17604642e01fSmrg if (client->swapped) { 176135c4bbdfSmrg swaps(nbytesFilter); 176235c4bbdfSmrg swaps(nparamsFilter); 176335c4bbdfSmrg SwapLongs((CARD32 *) (output + nbytes), nparams); 17644642e01fSmrg } 176535c4bbdfSmrg nbytes += nparams * sizeof(xFixed); 17664642e01fSmrg return nbytes; 17674642e01fSmrg} 17684642e01fSmrg 17694642e01fSmrgstatic void 177035c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire, 177135c4bbdfSmrg PictTransform * pict) 17724642e01fSmrg{ 177335c4bbdfSmrg xRenderTransform_from_PictTransform(wire, pict); 17744642e01fSmrg if (client->swapped) 177535c4bbdfSmrg SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 17764642e01fSmrg} 17774642e01fSmrg 17784642e01fSmrgint 177935c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client) 17804642e01fSmrg{ 17814642e01fSmrg REQUEST(xRRGetCrtcTransformReq); 178235c4bbdfSmrg xRRGetCrtcTransformReply *reply; 178335c4bbdfSmrg RRCrtcPtr crtc; 178435c4bbdfSmrg int nextra; 178535c4bbdfSmrg RRTransformPtr current, pending; 178635c4bbdfSmrg char *extra; 17874642e01fSmrg 178835c4bbdfSmrg REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq); 17896747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 17904642e01fSmrg 17914642e01fSmrg pending = &crtc->client_pending_transform; 17924642e01fSmrg current = &crtc->client_current_transform; 17934642e01fSmrg 179435c4bbdfSmrg nextra = (transform_filter_length(pending) + 179535c4bbdfSmrg transform_filter_length(current)); 17964642e01fSmrg 179735c4bbdfSmrg reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra); 17984642e01fSmrg if (!reply) 179935c4bbdfSmrg return BadAlloc; 18004642e01fSmrg 18014642e01fSmrg extra = (char *) (reply + 1); 18024642e01fSmrg reply->type = X_Reply; 18034642e01fSmrg reply->sequenceNumber = client->sequence; 18046747b715Smrg reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 18054642e01fSmrg 18064642e01fSmrg reply->hasTransforms = crtc->transforms; 18074642e01fSmrg 180835c4bbdfSmrg transform_encode(client, &reply->pendingTransform, &pending->transform); 180935c4bbdfSmrg extra += transform_filter_encode(client, extra, 181035c4bbdfSmrg &reply->pendingNbytesFilter, 181135c4bbdfSmrg &reply->pendingNparamsFilter, pending); 18124642e01fSmrg 181335c4bbdfSmrg transform_encode(client, &reply->currentTransform, ¤t->transform); 181435c4bbdfSmrg extra += transform_filter_encode(client, extra, 181535c4bbdfSmrg &reply->currentNbytesFilter, 181635c4bbdfSmrg &reply->currentNparamsFilter, current); 18174642e01fSmrg 18184642e01fSmrg if (client->swapped) { 181935c4bbdfSmrg swaps(&reply->sequenceNumber); 182035c4bbdfSmrg swapl(&reply->length); 18214642e01fSmrg } 182235c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply); 18236747b715Smrg free(reply); 18246747b715Smrg return Success; 18254642e01fSmrg} 182635c4bbdfSmrg 182735c4bbdfSmrgstatic Bool 182835c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y) 182935c4bbdfSmrg{ 183035c4bbdfSmrg rrScrPriv(pScreen); 183135c4bbdfSmrg int i; 183235c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 183335c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 183435c4bbdfSmrg 183535c4bbdfSmrg int left, right, top, bottom; 183635c4bbdfSmrg 18371b5d61b8Smrg if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 18381b5d61b8Smrg continue; 183935c4bbdfSmrg 184035c4bbdfSmrg if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom)) 184135c4bbdfSmrg return TRUE; 184235c4bbdfSmrg } 184335c4bbdfSmrg return FALSE; 184435c4bbdfSmrg} 184535c4bbdfSmrg 184635c4bbdfSmrgstatic Bool 184735c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y) 184835c4bbdfSmrg{ 184935c4bbdfSmrg rrScrPriv(pScreen); 185035c4bbdfSmrg int i; 185135c4bbdfSmrg 185235c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 185335c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 185435c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 185535c4bbdfSmrg int nx, ny; 185635c4bbdfSmrg int left, right, top, bottom; 185735c4bbdfSmrg 18581b5d61b8Smrg if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 18591b5d61b8Smrg continue; 186035c4bbdfSmrg 186135c4bbdfSmrg miPointerGetPosition(pDev, &nx, &ny); 186235c4bbdfSmrg 186335c4bbdfSmrg if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) { 186435c4bbdfSmrg if (*x < left) 186535c4bbdfSmrg *x = left; 186635c4bbdfSmrg if (*x >= right) 186735c4bbdfSmrg *x = right - 1; 186835c4bbdfSmrg if (*y < top) 186935c4bbdfSmrg *y = top; 187035c4bbdfSmrg if (*y >= bottom) 187135c4bbdfSmrg *y = bottom - 1; 187235c4bbdfSmrg 187335c4bbdfSmrg return TRUE; 187435c4bbdfSmrg } 187535c4bbdfSmrg } 187635c4bbdfSmrg return FALSE; 187735c4bbdfSmrg} 187835c4bbdfSmrg 187935c4bbdfSmrgvoid 188035c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, 188135c4bbdfSmrg int *y) 188235c4bbdfSmrg{ 188335c4bbdfSmrg rrScrPriv(pScreen); 188435c4bbdfSmrg Bool ret; 188535c4bbdfSmrg ScreenPtr slave; 188635c4bbdfSmrg 188735c4bbdfSmrg /* intentional dead space -> let it float */ 188835c4bbdfSmrg if (pScrPriv->discontiguous) 188935c4bbdfSmrg return; 189035c4bbdfSmrg 189135c4bbdfSmrg /* if we're moving inside a crtc, we're fine */ 189235c4bbdfSmrg ret = check_all_screen_crtcs(pScreen, x, y); 189335c4bbdfSmrg if (ret == TRUE) 189435c4bbdfSmrg return; 189535c4bbdfSmrg 18961b5d61b8Smrg xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 18971b5d61b8Smrg if (!slave->is_output_slave) 18981b5d61b8Smrg continue; 18991b5d61b8Smrg 190035c4bbdfSmrg ret = check_all_screen_crtcs(slave, x, y); 190135c4bbdfSmrg if (ret == TRUE) 190235c4bbdfSmrg return; 190335c4bbdfSmrg } 190435c4bbdfSmrg 190535c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 190635c4bbdfSmrg ret = constrain_all_screen_crtcs(pDev, pScreen, x, y); 190735c4bbdfSmrg if (ret == TRUE) 190835c4bbdfSmrg return; 190935c4bbdfSmrg 19101b5d61b8Smrg xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 19111b5d61b8Smrg if (!slave->is_output_slave) 19121b5d61b8Smrg continue; 19131b5d61b8Smrg 191435c4bbdfSmrg ret = constrain_all_screen_crtcs(pDev, slave, x, y); 191535c4bbdfSmrg if (ret == TRUE) 191635c4bbdfSmrg return; 191735c4bbdfSmrg } 191835c4bbdfSmrg} 191935c4bbdfSmrg 192035c4bbdfSmrgBool 192135c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable) 192235c4bbdfSmrg{ 192335c4bbdfSmrg rrScrPriv(pDrawable->pScreen); 192435c4bbdfSmrg Bool ret = TRUE; 192535c4bbdfSmrg PixmapPtr *saved_scanout_pixmap; 192635c4bbdfSmrg int i; 192735c4bbdfSmrg 192835c4bbdfSmrg saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs); 192935c4bbdfSmrg if (saved_scanout_pixmap == NULL) 193035c4bbdfSmrg return FALSE; 193135c4bbdfSmrg 193235c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 193335c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 193435c4bbdfSmrg Bool size_fits; 193535c4bbdfSmrg 193635c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 193735c4bbdfSmrg 193835c4bbdfSmrg if (!crtc->mode && enable) 193935c4bbdfSmrg continue; 194035c4bbdfSmrg if (!crtc->scanout_pixmap && !enable) 194135c4bbdfSmrg continue; 194235c4bbdfSmrg 19431b5d61b8Smrg /* not supported with double buffering, needs ABI change for 2 ppix */ 19441b5d61b8Smrg if (crtc->scanout_pixmap_back) { 19451b5d61b8Smrg ret = FALSE; 19461b5d61b8Smrg continue; 19471b5d61b8Smrg } 19481b5d61b8Smrg 194935c4bbdfSmrg size_fits = (crtc->mode && 195035c4bbdfSmrg crtc->x == pDrawable->x && 195135c4bbdfSmrg crtc->y == pDrawable->y && 195235c4bbdfSmrg crtc->mode->mode.width == pDrawable->width && 195335c4bbdfSmrg crtc->mode->mode.height == pDrawable->height); 195435c4bbdfSmrg 195535c4bbdfSmrg /* is the pixmap already set? */ 195635c4bbdfSmrg if (crtc->scanout_pixmap == pPixmap) { 195735c4bbdfSmrg /* if its a disable then don't care about size */ 195835c4bbdfSmrg if (enable == FALSE) { 195935c4bbdfSmrg /* set scanout to NULL */ 196035c4bbdfSmrg crtc->scanout_pixmap = NULL; 196135c4bbdfSmrg } 196235c4bbdfSmrg else if (!size_fits) { 196335c4bbdfSmrg /* if the size no longer fits then drop off */ 196435c4bbdfSmrg crtc->scanout_pixmap = NULL; 196535c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 196635c4bbdfSmrg 196735c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 196835c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 196935c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 197035c4bbdfSmrg ret = FALSE; 197135c4bbdfSmrg } 197235c4bbdfSmrg else { 197335c4bbdfSmrg /* if the size fits then we are already setup */ 197435c4bbdfSmrg } 197535c4bbdfSmrg } 197635c4bbdfSmrg else { 197735c4bbdfSmrg if (!size_fits) 197835c4bbdfSmrg ret = FALSE; 197935c4bbdfSmrg else if (enable) 198035c4bbdfSmrg crtc->scanout_pixmap = pPixmap; 198135c4bbdfSmrg else 198235c4bbdfSmrg /* reject an attempt to disable someone else's scanout_pixmap */ 198335c4bbdfSmrg ret = FALSE; 198435c4bbdfSmrg } 198535c4bbdfSmrg } 198635c4bbdfSmrg 198735c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 198835c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 198935c4bbdfSmrg 199035c4bbdfSmrg if (crtc->scanout_pixmap == saved_scanout_pixmap[i]) 199135c4bbdfSmrg continue; 199235c4bbdfSmrg 199335c4bbdfSmrg if (ret) { 199435c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 199535c4bbdfSmrg 199635c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 199735c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 199835c4bbdfSmrg } 199935c4bbdfSmrg else 200035c4bbdfSmrg crtc->scanout_pixmap = saved_scanout_pixmap[i]; 200135c4bbdfSmrg } 200235c4bbdfSmrg free(saved_scanout_pixmap); 200335c4bbdfSmrg 200435c4bbdfSmrg return ret; 200535c4bbdfSmrg} 20061b5d61b8Smrg 20071b5d61b8SmrgBool 20081b5d61b8SmrgRRHasScanoutPixmap(ScreenPtr pScreen) 20091b5d61b8Smrg{ 20101b5d61b8Smrg rrScrPriv(pScreen); 20111b5d61b8Smrg int i; 20121b5d61b8Smrg 20131b5d61b8Smrg if (!pScreen->is_output_slave) 20141b5d61b8Smrg return FALSE; 20151b5d61b8Smrg 20161b5d61b8Smrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 20171b5d61b8Smrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 20181b5d61b8Smrg 20191b5d61b8Smrg if (crtc->scanout_pixmap) 20201b5d61b8Smrg return TRUE; 20211b5d61b8Smrg } 20221b5d61b8Smrg 20231b5d61b8Smrg return FALSE; 20241b5d61b8Smrg} 2025