rrcrtc.c revision 35c4bbdf
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 2835c4bbdfSmrgRESTYPE RRCrtcType; 2905b261ecSmrg 3005b261ecSmrg/* 3105b261ecSmrg * Notify the CRTC of some change 3205b261ecSmrg */ 3305b261ecSmrgvoid 3435c4bbdfSmrgRRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged) 3505b261ecSmrg{ 3635c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 3705b261ecSmrg 3805b261ecSmrg crtc->changed = TRUE; 3935c4bbdfSmrg if (pScreen) { 4035c4bbdfSmrg rrScrPriv(pScreen); 4135c4bbdfSmrg 4235c4bbdfSmrg RRSetChanged(pScreen); 4335c4bbdfSmrg /* 4435c4bbdfSmrg * Send ConfigureNotify on any layout change 4535c4bbdfSmrg */ 4635c4bbdfSmrg if (layoutChanged) 4735c4bbdfSmrg pScrPriv->layoutChanged = TRUE; 4805b261ecSmrg } 4905b261ecSmrg} 5005b261ecSmrg 5105b261ecSmrg/* 5205b261ecSmrg * Create a CRTC 5305b261ecSmrg */ 5405b261ecSmrgRRCrtcPtr 5535c4bbdfSmrgRRCrtcCreate(ScreenPtr pScreen, void *devPrivate) 5605b261ecSmrg{ 5735c4bbdfSmrg RRCrtcPtr crtc; 5835c4bbdfSmrg RRCrtcPtr *crtcs; 5935c4bbdfSmrg rrScrPrivPtr pScrPriv; 6005b261ecSmrg 6105b261ecSmrg if (!RRInit()) 6235c4bbdfSmrg return NULL; 6335c4bbdfSmrg 6405b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 6505b261ecSmrg 6605b261ecSmrg /* make space for the crtc pointer */ 6705b261ecSmrg if (pScrPriv->numCrtcs) 6835c4bbdfSmrg crtcs = reallocarray(pScrPriv->crtcs, 6935c4bbdfSmrg pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr)); 7005b261ecSmrg else 7135c4bbdfSmrg crtcs = malloc(sizeof(RRCrtcPtr)); 7205b261ecSmrg if (!crtcs) 7335c4bbdfSmrg return FALSE; 7405b261ecSmrg pScrPriv->crtcs = crtcs; 7535c4bbdfSmrg 7635c4bbdfSmrg crtc = calloc(1, sizeof(RRCrtcRec)); 7705b261ecSmrg if (!crtc) 7835c4bbdfSmrg return NULL; 7935c4bbdfSmrg crtc->id = FakeClientID(0); 8005b261ecSmrg crtc->pScreen = pScreen; 8105b261ecSmrg crtc->mode = NULL; 8205b261ecSmrg crtc->x = 0; 8305b261ecSmrg crtc->y = 0; 8405b261ecSmrg crtc->rotation = RR_Rotate_0; 8505b261ecSmrg crtc->rotations = RR_Rotate_0; 8605b261ecSmrg crtc->outputs = NULL; 8705b261ecSmrg crtc->numOutputs = 0; 8805b261ecSmrg crtc->gammaSize = 0; 8905b261ecSmrg crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL; 9005b261ecSmrg crtc->changed = FALSE; 9105b261ecSmrg crtc->devPrivate = devPrivate; 9235c4bbdfSmrg RRTransformInit(&crtc->client_pending_transform); 9335c4bbdfSmrg RRTransformInit(&crtc->client_current_transform); 9435c4bbdfSmrg pixman_transform_init_identity(&crtc->transform); 9535c4bbdfSmrg pixman_f_transform_init_identity(&crtc->f_transform); 9635c4bbdfSmrg pixman_f_transform_init_identity(&crtc->f_inverse); 9705b261ecSmrg 9835c4bbdfSmrg if (!AddResource(crtc->id, RRCrtcType, (void *) crtc)) 9935c4bbdfSmrg return NULL; 10005b261ecSmrg 10105b261ecSmrg /* attach the screen and crtc together */ 10205b261ecSmrg crtc->pScreen = pScreen; 10305b261ecSmrg pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc; 10435c4bbdfSmrg 10535c4bbdfSmrg RRResourcesChanged(pScreen); 10635c4bbdfSmrg 10705b261ecSmrg return crtc; 10805b261ecSmrg} 10905b261ecSmrg 11005b261ecSmrg/* 11105b261ecSmrg * Set the allowed rotations on a CRTC 11205b261ecSmrg */ 11305b261ecSmrgvoid 11435c4bbdfSmrgRRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations) 11505b261ecSmrg{ 11605b261ecSmrg crtc->rotations = rotations; 11705b261ecSmrg} 11805b261ecSmrg 1194642e01fSmrg/* 1204642e01fSmrg * Set whether transforms are allowed on a CRTC 1214642e01fSmrg */ 1224642e01fSmrgvoid 12335c4bbdfSmrgRRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms) 1244642e01fSmrg{ 1254642e01fSmrg crtc->transforms = transforms; 1264642e01fSmrg} 1274642e01fSmrg 12805b261ecSmrg/* 12905b261ecSmrg * Notify the extension that the Crtc has been reconfigured, 13005b261ecSmrg * the driver calls this whenever it has updated the mode 13105b261ecSmrg */ 13205b261ecSmrgBool 13335c4bbdfSmrgRRCrtcNotify(RRCrtcPtr crtc, 13435c4bbdfSmrg RRModePtr mode, 13535c4bbdfSmrg int x, 13635c4bbdfSmrg int y, 13735c4bbdfSmrg Rotation rotation, 13835c4bbdfSmrg RRTransformPtr transform, int numOutputs, RROutputPtr * outputs) 13905b261ecSmrg{ 14035c4bbdfSmrg int i, j; 14135c4bbdfSmrg 14205b261ecSmrg /* 14305b261ecSmrg * Check to see if any of the new outputs were 14405b261ecSmrg * not in the old list and mark them as changed 14505b261ecSmrg */ 14635c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 14735c4bbdfSmrg for (j = 0; j < crtc->numOutputs; j++) 14835c4bbdfSmrg if (outputs[i] == crtc->outputs[j]) 14935c4bbdfSmrg break; 15035c4bbdfSmrg if (j == crtc->numOutputs) { 15135c4bbdfSmrg outputs[i]->crtc = crtc; 15235c4bbdfSmrg RROutputChanged(outputs[i], FALSE); 15335c4bbdfSmrg RRCrtcChanged(crtc, FALSE); 15435c4bbdfSmrg } 15505b261ecSmrg } 15605b261ecSmrg /* 15705b261ecSmrg * Check to see if any of the old outputs are 15805b261ecSmrg * not in the new list and mark them as changed 15905b261ecSmrg */ 16035c4bbdfSmrg for (j = 0; j < crtc->numOutputs; j++) { 16135c4bbdfSmrg for (i = 0; i < numOutputs; i++) 16235c4bbdfSmrg if (outputs[i] == crtc->outputs[j]) 16335c4bbdfSmrg break; 16435c4bbdfSmrg if (i == numOutputs) { 16535c4bbdfSmrg if (crtc->outputs[j]->crtc == crtc) 16635c4bbdfSmrg crtc->outputs[j]->crtc = NULL; 16735c4bbdfSmrg RROutputChanged(crtc->outputs[j], FALSE); 16835c4bbdfSmrg RRCrtcChanged(crtc, FALSE); 16935c4bbdfSmrg } 17005b261ecSmrg } 17105b261ecSmrg /* 17205b261ecSmrg * Reallocate the crtc output array if necessary 17305b261ecSmrg */ 17435c4bbdfSmrg if (numOutputs != crtc->numOutputs) { 17535c4bbdfSmrg RROutputPtr *newoutputs; 17635c4bbdfSmrg 17735c4bbdfSmrg if (numOutputs) { 17835c4bbdfSmrg if (crtc->numOutputs) 17935c4bbdfSmrg newoutputs = reallocarray(crtc->outputs, 18035c4bbdfSmrg numOutputs, sizeof(RROutputPtr)); 18135c4bbdfSmrg else 18235c4bbdfSmrg newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 18335c4bbdfSmrg if (!newoutputs) 18435c4bbdfSmrg return FALSE; 18535c4bbdfSmrg } 18635c4bbdfSmrg else { 18735c4bbdfSmrg free(crtc->outputs); 18835c4bbdfSmrg newoutputs = NULL; 18935c4bbdfSmrg } 19035c4bbdfSmrg crtc->outputs = newoutputs; 19135c4bbdfSmrg crtc->numOutputs = numOutputs; 19205b261ecSmrg } 19305b261ecSmrg /* 19405b261ecSmrg * Copy the new list of outputs into the crtc 19505b261ecSmrg */ 19635c4bbdfSmrg memcpy(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)); 19705b261ecSmrg /* 19805b261ecSmrg * Update remaining crtc fields 19905b261ecSmrg */ 20035c4bbdfSmrg if (mode != crtc->mode) { 20135c4bbdfSmrg if (crtc->mode) 20235c4bbdfSmrg RRModeDestroy(crtc->mode); 20335c4bbdfSmrg crtc->mode = mode; 20435c4bbdfSmrg if (mode != NULL) 20535c4bbdfSmrg mode->refcnt++; 20635c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 20705b261ecSmrg } 20835c4bbdfSmrg if (x != crtc->x) { 20935c4bbdfSmrg crtc->x = x; 21035c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 21105b261ecSmrg } 21235c4bbdfSmrg if (y != crtc->y) { 21335c4bbdfSmrg crtc->y = y; 21435c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 21505b261ecSmrg } 21635c4bbdfSmrg if (rotation != crtc->rotation) { 21735c4bbdfSmrg crtc->rotation = rotation; 21835c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 2194642e01fSmrg } 22035c4bbdfSmrg if (!RRTransformEqual(transform, &crtc->client_current_transform)) { 22135c4bbdfSmrg RRTransformCopy(&crtc->client_current_transform, transform); 22235c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 22335c4bbdfSmrg } 22435c4bbdfSmrg if (crtc->changed && mode) { 22535c4bbdfSmrg RRTransformCompute(x, y, 22635c4bbdfSmrg mode->mode.width, mode->mode.height, 22735c4bbdfSmrg rotation, 22835c4bbdfSmrg &crtc->client_current_transform, 22935c4bbdfSmrg &crtc->transform, &crtc->f_transform, 23035c4bbdfSmrg &crtc->f_inverse); 2314642e01fSmrg } 23205b261ecSmrg return TRUE; 23305b261ecSmrg} 23405b261ecSmrg 23505b261ecSmrgvoid 23635c4bbdfSmrgRRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc) 23705b261ecSmrg{ 23805b261ecSmrg ScreenPtr pScreen = pWin->drawable.pScreen; 23935c4bbdfSmrg 24035c4bbdfSmrg rrScrPriv(pScreen); 24135c4bbdfSmrg RRModePtr mode = crtc->mode; 24235c4bbdfSmrg 24335c4bbdfSmrg xRRCrtcChangeNotifyEvent ce = { 24435c4bbdfSmrg .type = RRNotify + RREventBase, 24535c4bbdfSmrg .subCode = RRNotify_CrtcChange, 24635c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds, 24735c4bbdfSmrg .window = pWin->drawable.id, 24835c4bbdfSmrg .crtc = crtc->id, 24935c4bbdfSmrg .mode = mode ? mode->mode.id : None, 25035c4bbdfSmrg .rotation = crtc->rotation, 25135c4bbdfSmrg .x = mode ? crtc->x : 0, 25235c4bbdfSmrg .y = mode ? crtc->y : 0, 25335c4bbdfSmrg .width = mode ? mode->mode.width : 0, 25435c4bbdfSmrg .height = mode ? mode->mode.height : 0 25535c4bbdfSmrg }; 25635c4bbdfSmrg WriteEventsToClient(client, 1, (xEvent *) &ce); 25735c4bbdfSmrg} 25835c4bbdfSmrg 25935c4bbdfSmrgstatic Bool 26035c4bbdfSmrgRRCrtcPendingProperties(RRCrtcPtr crtc) 26135c4bbdfSmrg{ 26235c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 26335c4bbdfSmrg 26435c4bbdfSmrg rrScrPriv(pScreen); 26535c4bbdfSmrg int o; 26635c4bbdfSmrg 26735c4bbdfSmrg for (o = 0; o < pScrPriv->numOutputs; o++) { 26835c4bbdfSmrg RROutputPtr output = pScrPriv->outputs[o]; 26935c4bbdfSmrg 27035c4bbdfSmrg if (output->crtc == crtc && output->pendingProperties) 27135c4bbdfSmrg return TRUE; 27205b261ecSmrg } 27335c4bbdfSmrg return FALSE; 27435c4bbdfSmrg} 27535c4bbdfSmrg 27635c4bbdfSmrgstatic void 27735c4bbdfSmrgcrtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom) 27835c4bbdfSmrg{ 27935c4bbdfSmrg *left = crtc->x; 28035c4bbdfSmrg *top = crtc->y; 28135c4bbdfSmrg 28235c4bbdfSmrg switch (crtc->rotation) { 28335c4bbdfSmrg case RR_Rotate_0: 28435c4bbdfSmrg case RR_Rotate_180: 28535c4bbdfSmrg default: 28635c4bbdfSmrg *right = crtc->x + crtc->mode->mode.width; 28735c4bbdfSmrg *bottom = crtc->y + crtc->mode->mode.height; 28835c4bbdfSmrg return; 28935c4bbdfSmrg case RR_Rotate_90: 29035c4bbdfSmrg case RR_Rotate_270: 29135c4bbdfSmrg *right = crtc->x + crtc->mode->mode.height; 29235c4bbdfSmrg *bottom = crtc->y + crtc->mode->mode.width; 29335c4bbdfSmrg return; 29405b261ecSmrg } 29505b261ecSmrg} 29605b261ecSmrg 29735c4bbdfSmrg/* overlapping counts as adjacent */ 29805b261ecSmrgstatic Bool 29935c4bbdfSmrgcrtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b) 30035c4bbdfSmrg{ 30135c4bbdfSmrg /* left, right, top, bottom... */ 30235c4bbdfSmrg int al, ar, at, ab; 30335c4bbdfSmrg int bl, br, bt, bb; 30435c4bbdfSmrg int cl, cr, ct, cb; /* the overlap, if any */ 30535c4bbdfSmrg 30635c4bbdfSmrg crtc_bounds(a, &al, &ar, &at, &ab); 30735c4bbdfSmrg crtc_bounds(b, &bl, &br, &bt, &bb); 30835c4bbdfSmrg 30935c4bbdfSmrg cl = max(al, bl); 31035c4bbdfSmrg cr = min(ar, br); 31135c4bbdfSmrg ct = max(at, bt); 31235c4bbdfSmrg cb = min(ab, bb); 31335c4bbdfSmrg 31435c4bbdfSmrg return (cl <= cr) && (ct <= cb); 31535c4bbdfSmrg} 31635c4bbdfSmrg 31735c4bbdfSmrg/* Depth-first search and mark all CRTCs reachable from cur */ 31835c4bbdfSmrgstatic void 31935c4bbdfSmrgmark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur) 32035c4bbdfSmrg{ 32135c4bbdfSmrg int i; 32235c4bbdfSmrg 32335c4bbdfSmrg reachable[cur] = TRUE; 32435c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; ++i) { 32535c4bbdfSmrg if (reachable[i] || !pScrPriv->crtcs[i]->mode) 32635c4bbdfSmrg continue; 32735c4bbdfSmrg if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i])) 32835c4bbdfSmrg mark_crtcs(pScrPriv, reachable, i); 32935c4bbdfSmrg } 33035c4bbdfSmrg} 33135c4bbdfSmrg 33235c4bbdfSmrgstatic void 33335c4bbdfSmrgRRComputeContiguity(ScreenPtr pScreen) 33405b261ecSmrg{ 33505b261ecSmrg rrScrPriv(pScreen); 33635c4bbdfSmrg Bool discontiguous = TRUE; 33735c4bbdfSmrg int i, n = pScrPriv->numCrtcs; 33805b261ecSmrg 33935c4bbdfSmrg int *reachable = calloc(n, sizeof(int)); 34035c4bbdfSmrg 34135c4bbdfSmrg if (!reachable) 34235c4bbdfSmrg goto out; 34335c4bbdfSmrg 34435c4bbdfSmrg /* Find first enabled CRTC and start search for reachable CRTCs from it */ 34535c4bbdfSmrg for (i = 0; i < n; ++i) { 34635c4bbdfSmrg if (pScrPriv->crtcs[i]->mode) { 34735c4bbdfSmrg mark_crtcs(pScrPriv, reachable, i); 34835c4bbdfSmrg break; 34935c4bbdfSmrg } 35005b261ecSmrg } 35135c4bbdfSmrg 35235c4bbdfSmrg /* Check that all enabled CRTCs were marked as reachable */ 35335c4bbdfSmrg for (i = 0; i < n; ++i) 35435c4bbdfSmrg if (pScrPriv->crtcs[i]->mode && !reachable[i]) 35535c4bbdfSmrg goto out; 35635c4bbdfSmrg 35735c4bbdfSmrg discontiguous = FALSE; 35835c4bbdfSmrg 35935c4bbdfSmrg out: 36035c4bbdfSmrg free(reachable); 36135c4bbdfSmrg pScrPriv->discontiguous = discontiguous; 36235c4bbdfSmrg} 36335c4bbdfSmrg 36435c4bbdfSmrgvoid 36535c4bbdfSmrgRRCrtcDetachScanoutPixmap(RRCrtcPtr crtc) 36635c4bbdfSmrg{ 36735c4bbdfSmrg ScreenPtr master = crtc->pScreen->current_master; 36835c4bbdfSmrg PixmapPtr mscreenpix; 36935c4bbdfSmrg rrScrPriv(crtc->pScreen); 37035c4bbdfSmrg 37135c4bbdfSmrg mscreenpix = master->GetScreenPixmap(master); 37235c4bbdfSmrg 37335c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL); 37435c4bbdfSmrg if (crtc->scanout_pixmap) { 37535c4bbdfSmrg master->StopPixmapTracking(mscreenpix, crtc->scanout_pixmap); 37635c4bbdfSmrg /* 37735c4bbdfSmrg * Unref the pixmap twice: once for the original reference, and once 37835c4bbdfSmrg * for the reference implicitly added by PixmapShareToSlave. 37935c4bbdfSmrg */ 38035c4bbdfSmrg master->DestroyPixmap(crtc->scanout_pixmap->master_pixmap); 38135c4bbdfSmrg master->DestroyPixmap(crtc->scanout_pixmap->master_pixmap); 38235c4bbdfSmrg crtc->pScreen->DestroyPixmap(crtc->scanout_pixmap); 38335c4bbdfSmrg } 38435c4bbdfSmrg crtc->scanout_pixmap = NULL; 38535c4bbdfSmrg RRCrtcChanged(crtc, TRUE); 38635c4bbdfSmrg} 38735c4bbdfSmrg 38835c4bbdfSmrgstatic Bool 38935c4bbdfSmrgrrCreateSharedPixmap(RRCrtcPtr crtc, int width, int height, 39035c4bbdfSmrg int x, int y, Rotation rotation) 39135c4bbdfSmrg{ 39235c4bbdfSmrg PixmapPtr mpix, spix; 39335c4bbdfSmrg ScreenPtr master = crtc->pScreen->current_master; 39435c4bbdfSmrg Bool ret; 39535c4bbdfSmrg int depth; 39635c4bbdfSmrg PixmapPtr mscreenpix; 39735c4bbdfSmrg PixmapPtr protopix = master->GetScreenPixmap(master); 39835c4bbdfSmrg rrScrPriv(crtc->pScreen); 39935c4bbdfSmrg 40035c4bbdfSmrg /* create a pixmap on the master screen, 40135c4bbdfSmrg then get a shared handle for it 40235c4bbdfSmrg create a shared pixmap on the slave screen using the handle 40335c4bbdfSmrg set the master screen to do dirty updates to the shared pixmap 40435c4bbdfSmrg from the screen pixmap. 40535c4bbdfSmrg set slave screen to scanout shared linear pixmap 40635c4bbdfSmrg */ 40735c4bbdfSmrg 40835c4bbdfSmrg mscreenpix = master->GetScreenPixmap(master); 40935c4bbdfSmrg depth = protopix->drawable.depth; 41035c4bbdfSmrg 41135c4bbdfSmrg if (crtc->scanout_pixmap) 41235c4bbdfSmrg RRCrtcDetachScanoutPixmap(crtc); 41335c4bbdfSmrg 41435c4bbdfSmrg if (width == 0 && height == 0) { 41535c4bbdfSmrg return TRUE; 41635c4bbdfSmrg } 41735c4bbdfSmrg 41835c4bbdfSmrg mpix = master->CreatePixmap(master, width, height, depth, 41935c4bbdfSmrg CREATE_PIXMAP_USAGE_SHARED); 42035c4bbdfSmrg if (!mpix) 42135c4bbdfSmrg return FALSE; 42235c4bbdfSmrg 42335c4bbdfSmrg spix = PixmapShareToSlave(mpix, crtc->pScreen); 42435c4bbdfSmrg if (spix == NULL) { 42535c4bbdfSmrg master->DestroyPixmap(mpix); 42635c4bbdfSmrg return FALSE; 42735c4bbdfSmrg } 42835c4bbdfSmrg 42935c4bbdfSmrg ret = pScrPriv->rrCrtcSetScanoutPixmap(crtc, spix); 43035c4bbdfSmrg if (ret == FALSE) { 43135c4bbdfSmrg ErrorF("randr: failed to set shadow slave pixmap\n"); 43235c4bbdfSmrg return FALSE; 43335c4bbdfSmrg } 43435c4bbdfSmrg 43535c4bbdfSmrg crtc->scanout_pixmap = spix; 43635c4bbdfSmrg 43735c4bbdfSmrg master->StartPixmapTracking(mscreenpix, spix, x, y, 0, 0, rotation); 43835c4bbdfSmrg return TRUE; 43935c4bbdfSmrg} 44035c4bbdfSmrg 44135c4bbdfSmrgstatic void crtc_to_box(BoxPtr box, RRCrtcPtr crtc) 44235c4bbdfSmrg{ 44335c4bbdfSmrg box->x1 = crtc->x; 44435c4bbdfSmrg box->y1 = crtc->y; 44535c4bbdfSmrg switch (crtc->rotation) { 44635c4bbdfSmrg case RR_Rotate_0: 44735c4bbdfSmrg case RR_Rotate_180: 44835c4bbdfSmrg default: 44935c4bbdfSmrg box->x2 = crtc->x + crtc->mode->mode.width; 45035c4bbdfSmrg box->y2 = crtc->y + crtc->mode->mode.height; 45135c4bbdfSmrg break; 45235c4bbdfSmrg case RR_Rotate_90: 45335c4bbdfSmrg case RR_Rotate_270: 45435c4bbdfSmrg box->x2 = crtc->x + crtc->mode->mode.height; 45535c4bbdfSmrg box->y2 = crtc->y + crtc->mode->mode.width; 45635c4bbdfSmrg break; 45735c4bbdfSmrg } 45835c4bbdfSmrg} 45935c4bbdfSmrg 46035c4bbdfSmrgstatic Bool 46135c4bbdfSmrgrrCheckPixmapBounding(ScreenPtr pScreen, 46235c4bbdfSmrg RRCrtcPtr rr_crtc, Rotation rotation, 46335c4bbdfSmrg int x, int y, int w, int h) 46435c4bbdfSmrg{ 46535c4bbdfSmrg RegionRec root_pixmap_region, total_region, new_crtc_region; 46635c4bbdfSmrg int c; 46735c4bbdfSmrg BoxRec newbox; 46835c4bbdfSmrg BoxPtr newsize; 46935c4bbdfSmrg ScreenPtr slave; 47035c4bbdfSmrg int new_width, new_height; 47135c4bbdfSmrg PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen); 47235c4bbdfSmrg rrScrPriv(pScreen); 47335c4bbdfSmrg 47435c4bbdfSmrg PixmapRegionInit(&root_pixmap_region, screen_pixmap); 47535c4bbdfSmrg RegionInit(&total_region, NULL, 0); 47635c4bbdfSmrg 47735c4bbdfSmrg /* have to iterate all the crtcs of the attached gpu masters 47835c4bbdfSmrg and all their output slaves */ 47935c4bbdfSmrg for (c = 0; c < pScrPriv->numCrtcs; c++) { 48035c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[c]; 48135c4bbdfSmrg 48235c4bbdfSmrg if (crtc == rr_crtc) { 48335c4bbdfSmrg newbox.x1 = x; 48435c4bbdfSmrg newbox.y1 = y; 48535c4bbdfSmrg if (rotation == RR_Rotate_90 || 48635c4bbdfSmrg rotation == RR_Rotate_270) { 48735c4bbdfSmrg newbox.x2 = x + h; 48835c4bbdfSmrg newbox.y2 = y + w; 48935c4bbdfSmrg } else { 49035c4bbdfSmrg newbox.x2 = x + w; 49135c4bbdfSmrg newbox.y2 = y + h; 49235c4bbdfSmrg } 49335c4bbdfSmrg } else { 49435c4bbdfSmrg if (!crtc->mode) 49535c4bbdfSmrg continue; 49635c4bbdfSmrg crtc_to_box(&newbox, crtc); 49735c4bbdfSmrg } 49835c4bbdfSmrg RegionInit(&new_crtc_region, &newbox, 1); 49935c4bbdfSmrg RegionUnion(&total_region, &total_region, &new_crtc_region); 50035c4bbdfSmrg } 50135c4bbdfSmrg 50235c4bbdfSmrg xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) { 50335c4bbdfSmrg rrScrPrivPtr slave_priv = rrGetScrPriv(slave); 50435c4bbdfSmrg for (c = 0; c < slave_priv->numCrtcs; c++) { 50535c4bbdfSmrg RRCrtcPtr slave_crtc = slave_priv->crtcs[c]; 50635c4bbdfSmrg 50735c4bbdfSmrg if (slave_crtc == rr_crtc) { 50835c4bbdfSmrg newbox.x1 = x; 50935c4bbdfSmrg newbox.y1 = y; 51035c4bbdfSmrg if (rotation == RR_Rotate_90 || 51135c4bbdfSmrg rotation == RR_Rotate_270) { 51235c4bbdfSmrg newbox.x2 = x + h; 51335c4bbdfSmrg newbox.y2 = y + w; 51435c4bbdfSmrg } else { 51535c4bbdfSmrg newbox.x2 = x + w; 51635c4bbdfSmrg newbox.y2 = y + h; 51735c4bbdfSmrg } 51835c4bbdfSmrg } 51935c4bbdfSmrg else { 52035c4bbdfSmrg if (!slave_crtc->mode) 52135c4bbdfSmrg continue; 52235c4bbdfSmrg crtc_to_box(&newbox, slave_crtc); 52335c4bbdfSmrg } 52435c4bbdfSmrg RegionInit(&new_crtc_region, &newbox, 1); 52535c4bbdfSmrg RegionUnion(&total_region, &total_region, &new_crtc_region); 52635c4bbdfSmrg } 52735c4bbdfSmrg } 52835c4bbdfSmrg 52935c4bbdfSmrg newsize = RegionExtents(&total_region); 53035c4bbdfSmrg new_width = newsize->x2 - newsize->x1; 53135c4bbdfSmrg new_height = newsize->y2 - newsize->y1; 53235c4bbdfSmrg 53335c4bbdfSmrg if (new_width == screen_pixmap->drawable.width && 53435c4bbdfSmrg new_height == screen_pixmap->drawable.height) { 53535c4bbdfSmrg } else { 53635c4bbdfSmrg pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0); 53735c4bbdfSmrg } 53835c4bbdfSmrg 53935c4bbdfSmrg /* set shatters TODO */ 54035c4bbdfSmrg return TRUE; 54105b261ecSmrg} 54205b261ecSmrg 54305b261ecSmrg/* 54405b261ecSmrg * Request that the Crtc be reconfigured 54505b261ecSmrg */ 54605b261ecSmrgBool 54735c4bbdfSmrgRRCrtcSet(RRCrtcPtr crtc, 54835c4bbdfSmrg RRModePtr mode, 54935c4bbdfSmrg int x, 55035c4bbdfSmrg int y, Rotation rotation, int numOutputs, RROutputPtr * outputs) 55105b261ecSmrg{ 55235c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 55335c4bbdfSmrg Bool ret = FALSE; 55435c4bbdfSmrg Bool recompute = TRUE; 55535c4bbdfSmrg Bool crtcChanged; 55635c4bbdfSmrg int o; 55735c4bbdfSmrg 55805b261ecSmrg rrScrPriv(pScreen); 55905b261ecSmrg 56035c4bbdfSmrg crtcChanged = FALSE; 56135c4bbdfSmrg for (o = 0; o < numOutputs; o++) { 56235c4bbdfSmrg if (outputs[o] && outputs[o]->crtc != crtc) { 56335c4bbdfSmrg crtcChanged = TRUE; 56435c4bbdfSmrg break; 56535c4bbdfSmrg } 56635c4bbdfSmrg } 56735c4bbdfSmrg 56805b261ecSmrg /* See if nothing changed */ 56905b261ecSmrg if (crtc->mode == mode && 57035c4bbdfSmrg crtc->x == x && 57135c4bbdfSmrg crtc->y == y && 57235c4bbdfSmrg crtc->rotation == rotation && 57335c4bbdfSmrg crtc->numOutputs == numOutputs && 57435c4bbdfSmrg !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) && 57535c4bbdfSmrg !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) && 57635c4bbdfSmrg !crtcChanged) { 57735c4bbdfSmrg recompute = FALSE; 57835c4bbdfSmrg ret = TRUE; 57905b261ecSmrg } 58035c4bbdfSmrg else { 58135c4bbdfSmrg if (pScreen->isGPU) { 58235c4bbdfSmrg ScreenPtr master = pScreen->current_master; 58335c4bbdfSmrg int width = 0, height = 0; 58435c4bbdfSmrg 58535c4bbdfSmrg if (mode) { 58635c4bbdfSmrg width = mode->mode.width; 58735c4bbdfSmrg height = mode->mode.height; 58835c4bbdfSmrg } 58935c4bbdfSmrg ret = rrCheckPixmapBounding(master, crtc, 59035c4bbdfSmrg rotation, x, y, width, height); 59135c4bbdfSmrg if (!ret) 59235c4bbdfSmrg return FALSE; 59335c4bbdfSmrg 59435c4bbdfSmrg if (pScreen->current_master) { 59535c4bbdfSmrg ret = rrCreateSharedPixmap(crtc, width, height, x, y, rotation); 59635c4bbdfSmrg } 59735c4bbdfSmrg } 59805b261ecSmrg#if RANDR_12_INTERFACE 59935c4bbdfSmrg if (pScrPriv->rrCrtcSet) { 60035c4bbdfSmrg ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 60135c4bbdfSmrg rotation, numOutputs, outputs); 60235c4bbdfSmrg } 60335c4bbdfSmrg else 60405b261ecSmrg#endif 60535c4bbdfSmrg { 60605b261ecSmrg#if RANDR_10_INTERFACE 60735c4bbdfSmrg if (pScrPriv->rrSetConfig) { 60835c4bbdfSmrg RRScreenSize size; 60935c4bbdfSmrg RRScreenRate rate; 61035c4bbdfSmrg 61135c4bbdfSmrg if (!mode) { 61235c4bbdfSmrg RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL); 61335c4bbdfSmrg ret = TRUE; 61435c4bbdfSmrg } 61535c4bbdfSmrg else { 61635c4bbdfSmrg size.width = mode->mode.width; 61735c4bbdfSmrg size.height = mode->mode.height; 61835c4bbdfSmrg if (outputs[0]->mmWidth && outputs[0]->mmHeight) { 61935c4bbdfSmrg size.mmWidth = outputs[0]->mmWidth; 62035c4bbdfSmrg size.mmHeight = outputs[0]->mmHeight; 62135c4bbdfSmrg } 62235c4bbdfSmrg else { 62335c4bbdfSmrg size.mmWidth = pScreen->mmWidth; 62435c4bbdfSmrg size.mmHeight = pScreen->mmHeight; 62535c4bbdfSmrg } 62635c4bbdfSmrg size.nRates = 1; 62735c4bbdfSmrg rate.rate = RRVerticalRefresh(&mode->mode); 62835c4bbdfSmrg size.pRates = &rate; 62935c4bbdfSmrg ret = 63035c4bbdfSmrg (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, 63135c4bbdfSmrg &size); 63235c4bbdfSmrg /* 63335c4bbdfSmrg * Old 1.0 interface tied screen size to mode size 63435c4bbdfSmrg */ 63535c4bbdfSmrg if (ret) { 63635c4bbdfSmrg RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1, 63735c4bbdfSmrg outputs); 63835c4bbdfSmrg RRScreenSizeNotify(pScreen); 63935c4bbdfSmrg } 64035c4bbdfSmrg } 64135c4bbdfSmrg } 64205b261ecSmrg#endif 64335c4bbdfSmrg } 64435c4bbdfSmrg if (ret) { 64505b261ecSmrg 64635c4bbdfSmrg RRTellChanged(pScreen); 64735c4bbdfSmrg 64835c4bbdfSmrg for (o = 0; o < numOutputs; o++) 64935c4bbdfSmrg RRPostPendingProperties(outputs[o]); 65035c4bbdfSmrg } 65105b261ecSmrg } 65235c4bbdfSmrg 65335c4bbdfSmrg if (recompute) 65435c4bbdfSmrg RRComputeContiguity(pScreen); 65535c4bbdfSmrg 65605b261ecSmrg return ret; 65705b261ecSmrg} 65805b261ecSmrg 6594642e01fSmrg/* 6604642e01fSmrg * Return crtc transform 6614642e01fSmrg */ 6624642e01fSmrgRRTransformPtr 66335c4bbdfSmrgRRCrtcGetTransform(RRCrtcPtr crtc) 6644642e01fSmrg{ 66535c4bbdfSmrg RRTransformPtr transform = &crtc->client_pending_transform; 6664642e01fSmrg 66735c4bbdfSmrg if (pixman_transform_is_identity(&transform->transform)) 66835c4bbdfSmrg return NULL; 6694642e01fSmrg return transform; 6704642e01fSmrg} 6714642e01fSmrg 6724642e01fSmrg/* 6734642e01fSmrg * Check whether the pending and current transforms are the same 6744642e01fSmrg */ 6754642e01fSmrgBool 67635c4bbdfSmrgRRCrtcPendingTransform(RRCrtcPtr crtc) 6774642e01fSmrg{ 67835c4bbdfSmrg return memcmp(&crtc->client_current_transform.transform, 67935c4bbdfSmrg &crtc->client_pending_transform.transform, 68035c4bbdfSmrg sizeof(PictTransform)) != 0; 6814642e01fSmrg} 6824642e01fSmrg 68305b261ecSmrg/* 68405b261ecSmrg * Destroy a Crtc at shutdown 68505b261ecSmrg */ 68605b261ecSmrgvoid 68735c4bbdfSmrgRRCrtcDestroy(RRCrtcPtr crtc) 68805b261ecSmrg{ 68935c4bbdfSmrg FreeResource(crtc->id, 0); 69005b261ecSmrg} 69105b261ecSmrg 69205b261ecSmrgstatic int 69335c4bbdfSmrgRRCrtcDestroyResource(void *value, XID pid) 69405b261ecSmrg{ 69535c4bbdfSmrg RRCrtcPtr crtc = (RRCrtcPtr) value; 69635c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 69705b261ecSmrg 69835c4bbdfSmrg if (pScreen) { 69935c4bbdfSmrg rrScrPriv(pScreen); 70035c4bbdfSmrg int i; 70135c4bbdfSmrg 70235c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 70335c4bbdfSmrg if (pScrPriv->crtcs[i] == crtc) { 70435c4bbdfSmrg memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, 70535c4bbdfSmrg (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr)); 70635c4bbdfSmrg --pScrPriv->numCrtcs; 70735c4bbdfSmrg break; 70835c4bbdfSmrg } 70935c4bbdfSmrg } 71035c4bbdfSmrg 71135c4bbdfSmrg RRResourcesChanged(pScreen); 71205b261ecSmrg } 71335c4bbdfSmrg 71435c4bbdfSmrg if (crtc->scanout_pixmap) 71535c4bbdfSmrg RRCrtcDetachScanoutPixmap(crtc); 7166747b715Smrg free(crtc->gammaRed); 71705b261ecSmrg if (crtc->mode) 71835c4bbdfSmrg RRModeDestroy(crtc->mode); 7196747b715Smrg free(crtc); 72005b261ecSmrg return 1; 72105b261ecSmrg} 72205b261ecSmrg 72305b261ecSmrg/* 72405b261ecSmrg * Request that the Crtc gamma be changed 72505b261ecSmrg */ 72605b261ecSmrg 72705b261ecSmrgBool 72835c4bbdfSmrgRRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue) 72905b261ecSmrg{ 73035c4bbdfSmrg Bool ret = TRUE; 73135c4bbdfSmrg 73205b261ecSmrg#if RANDR_12_INTERFACE 73335c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 73405b261ecSmrg#endif 73535c4bbdfSmrg 73635c4bbdfSmrg memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16)); 73735c4bbdfSmrg memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16)); 73835c4bbdfSmrg memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16)); 73905b261ecSmrg#if RANDR_12_INTERFACE 74035c4bbdfSmrg if (pScreen) { 74135c4bbdfSmrg rrScrPriv(pScreen); 74235c4bbdfSmrg if (pScrPriv->rrCrtcSetGamma) 74335c4bbdfSmrg ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); 74405b261ecSmrg } 74505b261ecSmrg#endif 74605b261ecSmrg return ret; 74705b261ecSmrg} 74805b261ecSmrg 7496747b715Smrg/* 7506747b715Smrg * Request current gamma back from the DDX (if possible). 7516747b715Smrg * This includes gamma size. 7526747b715Smrg */ 7536747b715SmrgBool 7546747b715SmrgRRCrtcGammaGet(RRCrtcPtr crtc) 7556747b715Smrg{ 7566747b715Smrg Bool ret = TRUE; 75735c4bbdfSmrg 7586747b715Smrg#if RANDR_12_INTERFACE 75935c4bbdfSmrg ScreenPtr pScreen = crtc->pScreen; 7606747b715Smrg#endif 7616747b715Smrg 7626747b715Smrg#if RANDR_12_INTERFACE 76335c4bbdfSmrg if (pScreen) { 7646747b715Smrg rrScrPriv(pScreen); 7656747b715Smrg if (pScrPriv->rrCrtcGetGamma) 7666747b715Smrg ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); 7676747b715Smrg } 7686747b715Smrg#endif 7696747b715Smrg return ret; 7706747b715Smrg} 7716747b715Smrg 77205b261ecSmrg/* 77305b261ecSmrg * Notify the extension that the Crtc gamma has been changed 77405b261ecSmrg * The driver calls this whenever it has changed the gamma values 77505b261ecSmrg * in the RRCrtcRec 77605b261ecSmrg */ 77705b261ecSmrg 77805b261ecSmrgBool 77935c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc) 78005b261ecSmrg{ 78135c4bbdfSmrg return TRUE; /* not much going on here */ 78205b261ecSmrg} 78305b261ecSmrg 7844642e01fSmrgstatic void 78535c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform, 78635c4bbdfSmrg int *width, int *height) 78705b261ecSmrg{ 78835c4bbdfSmrg BoxRec box; 7894642e01fSmrg 7904642e01fSmrg if (mode == NULL) { 79135c4bbdfSmrg *width = 0; 79235c4bbdfSmrg *height = 0; 79335c4bbdfSmrg return; 79405b261ecSmrg } 79505b261ecSmrg 7964642e01fSmrg box.x1 = 0; 7974642e01fSmrg box.y1 = 0; 7984642e01fSmrg box.x2 = mode->mode.width; 7994642e01fSmrg box.y2 = mode->mode.height; 8004642e01fSmrg 80135c4bbdfSmrg pixman_transform_bounds(transform, &box); 8024642e01fSmrg *width = box.x2 - box.x1; 8034642e01fSmrg *height = box.y2 - box.y1; 8044642e01fSmrg} 8054642e01fSmrg 8064642e01fSmrg/** 8074642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer 8084642e01fSmrg */ 8094642e01fSmrgvoid 8104642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 8114642e01fSmrg{ 81235c4bbdfSmrg RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height); 81305b261ecSmrg} 81405b261ecSmrg 81505b261ecSmrg/* 81605b261ecSmrg * Set the size of the gamma table at server startup time 81705b261ecSmrg */ 81805b261ecSmrg 81905b261ecSmrgBool 82035c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size) 82105b261ecSmrg{ 82235c4bbdfSmrg CARD16 *gamma; 82305b261ecSmrg 82405b261ecSmrg if (size == crtc->gammaSize) 82535c4bbdfSmrg return TRUE; 82635c4bbdfSmrg if (size) { 82735c4bbdfSmrg gamma = xallocarray(size, 3 * sizeof(CARD16)); 82835c4bbdfSmrg if (!gamma) 82935c4bbdfSmrg return FALSE; 83005b261ecSmrg } 83105b261ecSmrg else 83235c4bbdfSmrg gamma = NULL; 8336747b715Smrg free(crtc->gammaRed); 83405b261ecSmrg crtc->gammaRed = gamma; 83505b261ecSmrg crtc->gammaGreen = gamma + size; 83635c4bbdfSmrg crtc->gammaBlue = gamma + size * 2; 83705b261ecSmrg crtc->gammaSize = size; 83805b261ecSmrg return TRUE; 83905b261ecSmrg} 84005b261ecSmrg 8414642e01fSmrg/* 8424642e01fSmrg * Set the pending CRTC transformation 8434642e01fSmrg */ 8444642e01fSmrg 8454642e01fSmrgint 84635c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc, 84735c4bbdfSmrg PictTransformPtr transform, 84835c4bbdfSmrg struct pixman_f_transform *f_transform, 84935c4bbdfSmrg struct pixman_f_transform *f_inverse, 85035c4bbdfSmrg char *filter_name, 85135c4bbdfSmrg int filter_len, xFixed * params, int nparams) 8524642e01fSmrg{ 85335c4bbdfSmrg PictFilterPtr filter = NULL; 85435c4bbdfSmrg int width = 0, height = 0; 8554642e01fSmrg 8564642e01fSmrg if (!crtc->transforms) 85735c4bbdfSmrg return BadValue; 85835c4bbdfSmrg 85935c4bbdfSmrg if (filter_len) { 86035c4bbdfSmrg filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len); 86135c4bbdfSmrg if (!filter) 86235c4bbdfSmrg return BadName; 86335c4bbdfSmrg if (filter->ValidateParams) { 86435c4bbdfSmrg if (!filter->ValidateParams(crtc->pScreen, filter->id, 86535c4bbdfSmrg params, nparams, &width, &height)) 86635c4bbdfSmrg return BadMatch; 86735c4bbdfSmrg } 86835c4bbdfSmrg else { 86935c4bbdfSmrg width = filter->width; 87035c4bbdfSmrg height = filter->height; 87135c4bbdfSmrg } 8724642e01fSmrg } 87335c4bbdfSmrg else { 87435c4bbdfSmrg if (nparams) 87535c4bbdfSmrg return BadMatch; 8764642e01fSmrg } 87735c4bbdfSmrg if (!RRTransformSetFilter(&crtc->client_pending_transform, 87835c4bbdfSmrg filter, params, nparams, width, height)) 87935c4bbdfSmrg return BadAlloc; 8804642e01fSmrg 8814642e01fSmrg crtc->client_pending_transform.transform = *transform; 8824642e01fSmrg crtc->client_pending_transform.f_transform = *f_transform; 8834642e01fSmrg crtc->client_pending_transform.f_inverse = *f_inverse; 8844642e01fSmrg return Success; 8854642e01fSmrg} 8864642e01fSmrg 88705b261ecSmrg/* 88805b261ecSmrg * Initialize crtc type 88905b261ecSmrg */ 89005b261ecSmrgBool 89135c4bbdfSmrgRRCrtcInit(void) 89205b261ecSmrg{ 89335c4bbdfSmrg RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC"); 89405b261ecSmrg if (!RRCrtcType) 89535c4bbdfSmrg return FALSE; 89635c4bbdfSmrg 89705b261ecSmrg return TRUE; 89805b261ecSmrg} 89905b261ecSmrg 9006747b715Smrg/* 9016747b715Smrg * Initialize crtc type error value 9026747b715Smrg */ 9036747b715Smrgvoid 9046747b715SmrgRRCrtcInitErrorValue(void) 9056747b715Smrg{ 9066747b715Smrg SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 9076747b715Smrg} 9086747b715Smrg 90905b261ecSmrgint 91035c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client) 91105b261ecSmrg{ 91205b261ecSmrg REQUEST(xRRGetCrtcInfoReq); 91335c4bbdfSmrg xRRGetCrtcInfoReply rep; 91435c4bbdfSmrg RRCrtcPtr crtc; 91535c4bbdfSmrg CARD8 *extra; 91635c4bbdfSmrg unsigned long extraLen; 91735c4bbdfSmrg ScreenPtr pScreen; 91835c4bbdfSmrg rrScrPrivPtr pScrPriv; 91935c4bbdfSmrg RRModePtr mode; 92035c4bbdfSmrg RROutput *outputs; 92135c4bbdfSmrg RROutput *possible; 92235c4bbdfSmrg int i, j, k; 92335c4bbdfSmrg int width, height; 92435c4bbdfSmrg BoxRec panned_area; 92535c4bbdfSmrg 92605b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 9276747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 92805b261ecSmrg 92905b261ecSmrg /* All crtcs must be associated with screens before client 93005b261ecSmrg * requests are processed 93105b261ecSmrg */ 93205b261ecSmrg pScreen = crtc->pScreen; 93305b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 93405b261ecSmrg 93505b261ecSmrg mode = crtc->mode; 93635c4bbdfSmrg 93735c4bbdfSmrg rep = (xRRGetCrtcInfoReply) { 93835c4bbdfSmrg .type = X_Reply, 93935c4bbdfSmrg .status = RRSetConfigSuccess, 94035c4bbdfSmrg .sequenceNumber = client->sequence, 94135c4bbdfSmrg .length = 0, 94235c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 94335c4bbdfSmrg }; 9444642e01fSmrg if (pScrPriv->rrGetPanning && 94535c4bbdfSmrg pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) && 94635c4bbdfSmrg (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 9474642e01fSmrg { 94835c4bbdfSmrg rep.x = panned_area.x1; 94935c4bbdfSmrg rep.y = panned_area.y1; 95035c4bbdfSmrg rep.width = panned_area.x2 - panned_area.x1; 95135c4bbdfSmrg rep.height = panned_area.y2 - panned_area.y1; 9524642e01fSmrg } 95335c4bbdfSmrg else { 95435c4bbdfSmrg RRCrtcGetScanoutSize(crtc, &width, &height); 95535c4bbdfSmrg rep.x = crtc->x; 95635c4bbdfSmrg rep.y = crtc->y; 95735c4bbdfSmrg rep.width = width; 95835c4bbdfSmrg rep.height = height; 9594642e01fSmrg } 96005b261ecSmrg rep.mode = mode ? mode->mode.id : 0; 96105b261ecSmrg rep.rotation = crtc->rotation; 96205b261ecSmrg rep.rotations = crtc->rotations; 96305b261ecSmrg rep.nOutput = crtc->numOutputs; 96405b261ecSmrg k = 0; 96505b261ecSmrg for (i = 0; i < pScrPriv->numOutputs; i++) 96635c4bbdfSmrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 96735c4bbdfSmrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) 96835c4bbdfSmrg k++; 96905b261ecSmrg rep.nPossibleOutput = k; 97035c4bbdfSmrg 97105b261ecSmrg rep.length = rep.nOutput + rep.nPossibleOutput; 97205b261ecSmrg 97305b261ecSmrg extraLen = rep.length << 2; 97435c4bbdfSmrg if (extraLen) { 97535c4bbdfSmrg extra = malloc(extraLen); 97635c4bbdfSmrg if (!extra) 97735c4bbdfSmrg return BadAlloc; 97805b261ecSmrg } 97905b261ecSmrg else 98035c4bbdfSmrg extra = NULL; 98105b261ecSmrg 98205b261ecSmrg outputs = (RROutput *) extra; 98305b261ecSmrg possible = (RROutput *) (outputs + rep.nOutput); 98435c4bbdfSmrg 98535c4bbdfSmrg for (i = 0; i < crtc->numOutputs; i++) { 98635c4bbdfSmrg outputs[i] = crtc->outputs[i]->id; 98735c4bbdfSmrg if (client->swapped) 98835c4bbdfSmrg swapl(&outputs[i]); 98905b261ecSmrg } 99005b261ecSmrg k = 0; 99105b261ecSmrg for (i = 0; i < pScrPriv->numOutputs; i++) 99235c4bbdfSmrg for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 99335c4bbdfSmrg if (pScrPriv->outputs[i]->crtcs[j] == crtc) { 99435c4bbdfSmrg possible[k] = pScrPriv->outputs[i]->id; 99535c4bbdfSmrg if (client->swapped) 99635c4bbdfSmrg swapl(&possible[k]); 99735c4bbdfSmrg k++; 99835c4bbdfSmrg } 99935c4bbdfSmrg 100005b261ecSmrg if (client->swapped) { 100135c4bbdfSmrg swaps(&rep.sequenceNumber); 100235c4bbdfSmrg swapl(&rep.length); 100335c4bbdfSmrg swapl(&rep.timestamp); 100435c4bbdfSmrg swaps(&rep.x); 100535c4bbdfSmrg swaps(&rep.y); 100635c4bbdfSmrg swaps(&rep.width); 100735c4bbdfSmrg swaps(&rep.height); 100835c4bbdfSmrg swapl(&rep.mode); 100935c4bbdfSmrg swaps(&rep.rotation); 101035c4bbdfSmrg swaps(&rep.rotations); 101135c4bbdfSmrg swaps(&rep.nOutput); 101235c4bbdfSmrg swaps(&rep.nPossibleOutput); 101335c4bbdfSmrg } 101435c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep); 101535c4bbdfSmrg if (extraLen) { 101635c4bbdfSmrg WriteToClient(client, extraLen, extra); 101735c4bbdfSmrg free(extra); 101805b261ecSmrg } 101935c4bbdfSmrg 10206747b715Smrg return Success; 102105b261ecSmrg} 102205b261ecSmrg 102305b261ecSmrgint 102435c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client) 102505b261ecSmrg{ 102605b261ecSmrg REQUEST(xRRSetCrtcConfigReq); 102735c4bbdfSmrg xRRSetCrtcConfigReply rep; 102835c4bbdfSmrg ScreenPtr pScreen; 102935c4bbdfSmrg rrScrPrivPtr pScrPriv; 103035c4bbdfSmrg RRCrtcPtr crtc; 103135c4bbdfSmrg RRModePtr mode; 103235c4bbdfSmrg int numOutputs; 103335c4bbdfSmrg RROutputPtr *outputs = NULL; 103435c4bbdfSmrg RROutput *outputIds; 103535c4bbdfSmrg TimeStamp time; 103635c4bbdfSmrg Rotation rotation; 103735c4bbdfSmrg int ret, i, j; 103835c4bbdfSmrg CARD8 status; 103935c4bbdfSmrg 104005b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 104135c4bbdfSmrg numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq))); 104235c4bbdfSmrg 10436747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 10446747b715Smrg 104535c4bbdfSmrg if (stuff->mode == None) { 104635c4bbdfSmrg mode = NULL; 104735c4bbdfSmrg if (numOutputs > 0) 104835c4bbdfSmrg return BadMatch; 104905b261ecSmrg } 105035c4bbdfSmrg else { 105135c4bbdfSmrg VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 105235c4bbdfSmrg if (numOutputs == 0) 105335c4bbdfSmrg return BadMatch; 105405b261ecSmrg } 105535c4bbdfSmrg if (numOutputs) { 105635c4bbdfSmrg outputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 105735c4bbdfSmrg if (!outputs) 105835c4bbdfSmrg return BadAlloc; 105905b261ecSmrg } 106005b261ecSmrg else 106135c4bbdfSmrg outputs = NULL; 106235c4bbdfSmrg 106305b261ecSmrg outputIds = (RROutput *) (stuff + 1); 106435c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 106535c4bbdfSmrg ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i], 106635c4bbdfSmrg RROutputType, client, DixSetAttrAccess); 106735c4bbdfSmrg if (ret != Success) { 106835c4bbdfSmrg free(outputs); 106935c4bbdfSmrg return ret; 107035c4bbdfSmrg } 107135c4bbdfSmrg /* validate crtc for this output */ 107235c4bbdfSmrg for (j = 0; j < outputs[i]->numCrtcs; j++) 107335c4bbdfSmrg if (outputs[i]->crtcs[j] == crtc) 107435c4bbdfSmrg break; 107535c4bbdfSmrg if (j == outputs[i]->numCrtcs) { 107635c4bbdfSmrg free(outputs); 107735c4bbdfSmrg return BadMatch; 107835c4bbdfSmrg } 107935c4bbdfSmrg /* validate mode for this output */ 108035c4bbdfSmrg for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) { 108135c4bbdfSmrg RRModePtr m = (j < outputs[i]->numModes ? 108235c4bbdfSmrg outputs[i]->modes[j] : 108335c4bbdfSmrg outputs[i]->userModes[j - outputs[i]->numModes]); 108435c4bbdfSmrg if (m == mode) 108535c4bbdfSmrg break; 108635c4bbdfSmrg } 108735c4bbdfSmrg if (j == outputs[i]->numModes + outputs[i]->numUserModes) { 108835c4bbdfSmrg free(outputs); 108935c4bbdfSmrg return BadMatch; 109035c4bbdfSmrg } 109105b261ecSmrg } 109205b261ecSmrg /* validate clones */ 109335c4bbdfSmrg for (i = 0; i < numOutputs; i++) { 109435c4bbdfSmrg for (j = 0; j < numOutputs; j++) { 109535c4bbdfSmrg int k; 109635c4bbdfSmrg 109735c4bbdfSmrg if (i == j) 109835c4bbdfSmrg continue; 109935c4bbdfSmrg for (k = 0; k < outputs[i]->numClones; k++) { 110035c4bbdfSmrg if (outputs[i]->clones[k] == outputs[j]) 110135c4bbdfSmrg break; 110235c4bbdfSmrg } 110335c4bbdfSmrg if (k == outputs[i]->numClones) { 110435c4bbdfSmrg free(outputs); 110535c4bbdfSmrg return BadMatch; 110635c4bbdfSmrg } 110735c4bbdfSmrg } 110805b261ecSmrg } 110905b261ecSmrg 111005b261ecSmrg pScreen = crtc->pScreen; 111105b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 111235c4bbdfSmrg 111305b261ecSmrg time = ClientTimeToServerTime(stuff->timestamp); 111435c4bbdfSmrg 111535c4bbdfSmrg if (!pScrPriv) { 111635c4bbdfSmrg time = currentTime; 111735c4bbdfSmrg status = RRSetConfigFailed; 111835c4bbdfSmrg goto sendReply; 111905b261ecSmrg } 112035c4bbdfSmrg 112105b261ecSmrg /* 112205b261ecSmrg * Validate requested rotation 112305b261ecSmrg */ 112405b261ecSmrg rotation = (Rotation) stuff->rotation; 112505b261ecSmrg 112605b261ecSmrg /* test the rotation bits only! */ 112705b261ecSmrg switch (rotation & 0xf) { 112805b261ecSmrg case RR_Rotate_0: 112905b261ecSmrg case RR_Rotate_90: 113005b261ecSmrg case RR_Rotate_180: 113105b261ecSmrg case RR_Rotate_270: 113235c4bbdfSmrg break; 113305b261ecSmrg default: 113435c4bbdfSmrg /* 113535c4bbdfSmrg * Invalid rotation 113635c4bbdfSmrg */ 113735c4bbdfSmrg client->errorValue = stuff->rotation; 113835c4bbdfSmrg free(outputs); 113935c4bbdfSmrg return BadValue; 114005b261ecSmrg } 114105b261ecSmrg 114235c4bbdfSmrg if (mode) { 114335c4bbdfSmrg if ((~crtc->rotations) & rotation) { 114435c4bbdfSmrg /* 114535c4bbdfSmrg * requested rotation or reflection not supported by screen 114635c4bbdfSmrg */ 114735c4bbdfSmrg client->errorValue = stuff->rotation; 114835c4bbdfSmrg free(outputs); 114935c4bbdfSmrg return BadMatch; 115035c4bbdfSmrg } 115135c4bbdfSmrg 115205b261ecSmrg#ifdef RANDR_12_INTERFACE 115335c4bbdfSmrg /* 115435c4bbdfSmrg * Check screen size bounds if the DDX provides a 1.2 interface 115535c4bbdfSmrg * for setting screen size. Else, assume the CrtcSet sets 115635c4bbdfSmrg * the size along with the mode. If the driver supports transforms, 115735c4bbdfSmrg * then it must allow crtcs to display a subset of the screen, so 115835c4bbdfSmrg * only do this check for drivers without transform support. 115935c4bbdfSmrg */ 116035c4bbdfSmrg if (pScrPriv->rrScreenSetSize && !crtc->transforms) { 116135c4bbdfSmrg int source_width; 116235c4bbdfSmrg int source_height; 116335c4bbdfSmrg PictTransform transform; 116435c4bbdfSmrg struct pixman_f_transform f_transform, f_inverse; 116535c4bbdfSmrg int width, height; 116635c4bbdfSmrg 116735c4bbdfSmrg if (pScreen->isGPU) { 116835c4bbdfSmrg width = pScreen->current_master->width; 116935c4bbdfSmrg height = pScreen->current_master->height; 117035c4bbdfSmrg } 117135c4bbdfSmrg else { 117235c4bbdfSmrg width = pScreen->width; 117335c4bbdfSmrg height = pScreen->height; 117435c4bbdfSmrg } 117535c4bbdfSmrg 117635c4bbdfSmrg RRTransformCompute(stuff->x, stuff->y, 117735c4bbdfSmrg mode->mode.width, mode->mode.height, 117835c4bbdfSmrg rotation, 117935c4bbdfSmrg &crtc->client_pending_transform, 118035c4bbdfSmrg &transform, &f_transform, &f_inverse); 118135c4bbdfSmrg 118235c4bbdfSmrg RRModeGetScanoutSize(mode, &transform, &source_width, 118335c4bbdfSmrg &source_height); 118435c4bbdfSmrg if (stuff->x + source_width > width) { 118535c4bbdfSmrg client->errorValue = stuff->x; 118635c4bbdfSmrg free(outputs); 118735c4bbdfSmrg return BadValue; 118835c4bbdfSmrg } 118935c4bbdfSmrg 119035c4bbdfSmrg if (stuff->y + source_height > height) { 119135c4bbdfSmrg client->errorValue = stuff->y; 119235c4bbdfSmrg free(outputs); 119335c4bbdfSmrg return BadValue; 119435c4bbdfSmrg } 119535c4bbdfSmrg } 119605b261ecSmrg#endif 119705b261ecSmrg } 119835c4bbdfSmrg 119935c4bbdfSmrg if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y, 120035c4bbdfSmrg rotation, numOutputs, outputs)) { 120135c4bbdfSmrg status = RRSetConfigFailed; 120235c4bbdfSmrg goto sendReply; 120305b261ecSmrg } 120435c4bbdfSmrg status = RRSetConfigSuccess; 120552397711Smrg pScrPriv->lastSetTime = time; 120635c4bbdfSmrg 120735c4bbdfSmrg sendReply: 12086747b715Smrg free(outputs); 120935c4bbdfSmrg 121035c4bbdfSmrg rep = (xRRSetCrtcConfigReply) { 121135c4bbdfSmrg .type = X_Reply, 121235c4bbdfSmrg .status = status, 121335c4bbdfSmrg .sequenceNumber = client->sequence, 121435c4bbdfSmrg .length = 0, 121535c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 121635c4bbdfSmrg }; 121735c4bbdfSmrg 121835c4bbdfSmrg if (client->swapped) { 121935c4bbdfSmrg swaps(&rep.sequenceNumber); 122035c4bbdfSmrg swapl(&rep.length); 122135c4bbdfSmrg swapl(&rep.newTimestamp); 122205b261ecSmrg } 122335c4bbdfSmrg WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep); 122435c4bbdfSmrg 12256747b715Smrg return Success; 122605b261ecSmrg} 122705b261ecSmrg 12284642e01fSmrgint 122935c4bbdfSmrgProcRRGetPanning(ClientPtr client) 12304642e01fSmrg{ 12314642e01fSmrg REQUEST(xRRGetPanningReq); 123235c4bbdfSmrg xRRGetPanningReply rep; 123335c4bbdfSmrg RRCrtcPtr crtc; 123435c4bbdfSmrg ScreenPtr pScreen; 123535c4bbdfSmrg rrScrPrivPtr pScrPriv; 123635c4bbdfSmrg BoxRec total; 123735c4bbdfSmrg BoxRec tracking; 123835c4bbdfSmrg INT16 border[4]; 123935c4bbdfSmrg 12404642e01fSmrg REQUEST_SIZE_MATCH(xRRGetPanningReq); 12416747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 12424642e01fSmrg 12434642e01fSmrg /* All crtcs must be associated with screens before client 12444642e01fSmrg * requests are processed 12454642e01fSmrg */ 12464642e01fSmrg pScreen = crtc->pScreen; 12474642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 12484642e01fSmrg 12494642e01fSmrg if (!pScrPriv) 125035c4bbdfSmrg return RRErrorBase + BadRRCrtc; 12514642e01fSmrg 125235c4bbdfSmrg rep = (xRRGetPanningReply) { 125335c4bbdfSmrg .type = X_Reply, 125435c4bbdfSmrg .status = RRSetConfigSuccess, 125535c4bbdfSmrg .sequenceNumber = client->sequence, 125635c4bbdfSmrg .length = 1, 125735c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds 125835c4bbdfSmrg }; 12594642e01fSmrg 12604642e01fSmrg if (pScrPriv->rrGetPanning && 126135c4bbdfSmrg pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) { 126235c4bbdfSmrg rep.left = total.x1; 126335c4bbdfSmrg rep.top = total.y1; 126435c4bbdfSmrg rep.width = total.x2 - total.x1; 126535c4bbdfSmrg rep.height = total.y2 - total.y1; 126635c4bbdfSmrg rep.track_left = tracking.x1; 126735c4bbdfSmrg rep.track_top = tracking.y1; 126835c4bbdfSmrg rep.track_width = tracking.x2 - tracking.x1; 126935c4bbdfSmrg rep.track_height = tracking.y2 - tracking.y1; 127035c4bbdfSmrg rep.border_left = border[0]; 127135c4bbdfSmrg rep.border_top = border[1]; 127235c4bbdfSmrg rep.border_right = border[2]; 127335c4bbdfSmrg rep.border_bottom = border[3]; 12744642e01fSmrg } 12754642e01fSmrg 12764642e01fSmrg if (client->swapped) { 127735c4bbdfSmrg swaps(&rep.sequenceNumber); 127835c4bbdfSmrg swapl(&rep.length); 127935c4bbdfSmrg swapl(&rep.timestamp); 128035c4bbdfSmrg swaps(&rep.left); 128135c4bbdfSmrg swaps(&rep.top); 128235c4bbdfSmrg swaps(&rep.width); 128335c4bbdfSmrg swaps(&rep.height); 128435c4bbdfSmrg swaps(&rep.track_left); 128535c4bbdfSmrg swaps(&rep.track_top); 128635c4bbdfSmrg swaps(&rep.track_width); 128735c4bbdfSmrg swaps(&rep.track_height); 128835c4bbdfSmrg swaps(&rep.border_left); 128935c4bbdfSmrg swaps(&rep.border_top); 129035c4bbdfSmrg swaps(&rep.border_right); 129135c4bbdfSmrg swaps(&rep.border_bottom); 129235c4bbdfSmrg } 129335c4bbdfSmrg WriteToClient(client, sizeof(xRRGetPanningReply), &rep); 12946747b715Smrg return Success; 12954642e01fSmrg} 12964642e01fSmrg 12974642e01fSmrgint 129835c4bbdfSmrgProcRRSetPanning(ClientPtr client) 12994642e01fSmrg{ 13004642e01fSmrg REQUEST(xRRSetPanningReq); 130135c4bbdfSmrg xRRSetPanningReply rep; 130235c4bbdfSmrg RRCrtcPtr crtc; 130335c4bbdfSmrg ScreenPtr pScreen; 130435c4bbdfSmrg rrScrPrivPtr pScrPriv; 130535c4bbdfSmrg TimeStamp time; 130635c4bbdfSmrg BoxRec total; 130735c4bbdfSmrg BoxRec tracking; 130835c4bbdfSmrg INT16 border[4]; 130935c4bbdfSmrg CARD8 status; 131035c4bbdfSmrg 13114642e01fSmrg REQUEST_SIZE_MATCH(xRRSetPanningReq); 13126747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 13134642e01fSmrg 13144642e01fSmrg /* All crtcs must be associated with screens before client 13154642e01fSmrg * requests are processed 13164642e01fSmrg */ 13174642e01fSmrg pScreen = crtc->pScreen; 13184642e01fSmrg pScrPriv = rrGetScrPriv(pScreen); 13194642e01fSmrg 13204642e01fSmrg if (!pScrPriv) { 132135c4bbdfSmrg time = currentTime; 132235c4bbdfSmrg status = RRSetConfigFailed; 132335c4bbdfSmrg goto sendReply; 13244642e01fSmrg } 132535c4bbdfSmrg 13264642e01fSmrg time = ClientTimeToServerTime(stuff->timestamp); 132735c4bbdfSmrg 13284642e01fSmrg if (!pScrPriv->rrGetPanning) 132935c4bbdfSmrg return RRErrorBase + BadRRCrtc; 13304642e01fSmrg 133135c4bbdfSmrg total.x1 = stuff->left; 133235c4bbdfSmrg total.y1 = stuff->top; 133335c4bbdfSmrg total.x2 = total.x1 + stuff->width; 133435c4bbdfSmrg total.y2 = total.y1 + stuff->height; 13354642e01fSmrg tracking.x1 = stuff->track_left; 13364642e01fSmrg tracking.y1 = stuff->track_top; 13374642e01fSmrg tracking.x2 = tracking.x1 + stuff->track_width; 13384642e01fSmrg tracking.y2 = tracking.y1 + stuff->track_height; 133935c4bbdfSmrg border[0] = stuff->border_left; 134035c4bbdfSmrg border[1] = stuff->border_top; 134135c4bbdfSmrg border[2] = stuff->border_right; 134235c4bbdfSmrg border[3] = stuff->border_bottom; 13434642e01fSmrg 134435c4bbdfSmrg if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border)) 134535c4bbdfSmrg return BadMatch; 13464642e01fSmrg 134752397711Smrg pScrPriv->lastSetTime = time; 134852397711Smrg 134935c4bbdfSmrg status = RRSetConfigSuccess; 13504642e01fSmrg 135135c4bbdfSmrg sendReply: 135235c4bbdfSmrg rep = (xRRSetPanningReply) { 135335c4bbdfSmrg .type = X_Reply, 135435c4bbdfSmrg .status = status, 135535c4bbdfSmrg .sequenceNumber = client->sequence, 135635c4bbdfSmrg .length = 0, 135735c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds 135835c4bbdfSmrg }; 13594642e01fSmrg 13604642e01fSmrg if (client->swapped) { 136135c4bbdfSmrg swaps(&rep.sequenceNumber); 136235c4bbdfSmrg swapl(&rep.length); 136335c4bbdfSmrg swapl(&rep.newTimestamp); 13644642e01fSmrg } 136535c4bbdfSmrg WriteToClient(client, sizeof(xRRSetPanningReply), &rep); 13666747b715Smrg return Success; 13674642e01fSmrg} 13684642e01fSmrg 136905b261ecSmrgint 137035c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client) 137105b261ecSmrg{ 137205b261ecSmrg REQUEST(xRRGetCrtcGammaSizeReq); 137335c4bbdfSmrg xRRGetCrtcGammaSizeReply reply; 137435c4bbdfSmrg RRCrtcPtr crtc; 137505b261ecSmrg 137605b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 13776747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 13786747b715Smrg 13796747b715Smrg /* Gamma retrieval failed, any better error? */ 13806747b715Smrg if (!RRCrtcGammaGet(crtc)) 13816747b715Smrg return RRErrorBase + BadRRCrtc; 13826747b715Smrg 138335c4bbdfSmrg reply = (xRRGetCrtcGammaSizeReply) { 138435c4bbdfSmrg .type = X_Reply, 138535c4bbdfSmrg .sequenceNumber = client->sequence, 138635c4bbdfSmrg .length = 0, 138735c4bbdfSmrg .size = crtc->gammaSize 138835c4bbdfSmrg }; 138905b261ecSmrg if (client->swapped) { 139035c4bbdfSmrg swaps(&reply.sequenceNumber); 139135c4bbdfSmrg swapl(&reply.length); 139235c4bbdfSmrg swaps(&reply.size); 139305b261ecSmrg } 139435c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply); 13956747b715Smrg return Success; 139605b261ecSmrg} 139705b261ecSmrg 139805b261ecSmrgint 139935c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client) 140005b261ecSmrg{ 140105b261ecSmrg REQUEST(xRRGetCrtcGammaReq); 140235c4bbdfSmrg xRRGetCrtcGammaReply reply; 140335c4bbdfSmrg RRCrtcPtr crtc; 140435c4bbdfSmrg unsigned long len; 140535c4bbdfSmrg char *extra = NULL; 140635c4bbdfSmrg 140705b261ecSmrg REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 14086747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 14096747b715Smrg 14106747b715Smrg /* Gamma retrieval failed, any better error? */ 14116747b715Smrg if (!RRCrtcGammaGet(crtc)) 14126747b715Smrg return RRErrorBase + BadRRCrtc; 14136747b715Smrg 141405b261ecSmrg len = crtc->gammaSize * 3 * 2; 141535c4bbdfSmrg 14164642e01fSmrg if (crtc->gammaSize) { 141735c4bbdfSmrg extra = malloc(len); 141835c4bbdfSmrg if (!extra) 141935c4bbdfSmrg return BadAlloc; 14204642e01fSmrg } 14214642e01fSmrg 142235c4bbdfSmrg reply = (xRRGetCrtcGammaReply) { 142335c4bbdfSmrg .type = X_Reply, 142435c4bbdfSmrg .sequenceNumber = client->sequence, 142535c4bbdfSmrg .length = bytes_to_int32(len), 142635c4bbdfSmrg .size = crtc->gammaSize 142735c4bbdfSmrg }; 142805b261ecSmrg if (client->swapped) { 142935c4bbdfSmrg swaps(&reply.sequenceNumber); 143035c4bbdfSmrg swapl(&reply.length); 143135c4bbdfSmrg swaps(&reply.size); 143205b261ecSmrg } 143335c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply); 143435c4bbdfSmrg if (crtc->gammaSize) { 143535c4bbdfSmrg memcpy(extra, crtc->gammaRed, len); 143635c4bbdfSmrg client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 143735c4bbdfSmrg WriteSwappedDataToClient(client, len, extra); 143835c4bbdfSmrg free(extra); 143905b261ecSmrg } 14406747b715Smrg return Success; 144105b261ecSmrg} 144205b261ecSmrg 144305b261ecSmrgint 144435c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client) 144505b261ecSmrg{ 144605b261ecSmrg REQUEST(xRRSetCrtcGammaReq); 144735c4bbdfSmrg RRCrtcPtr crtc; 144835c4bbdfSmrg unsigned long len; 144935c4bbdfSmrg CARD16 *red, *green, *blue; 145035c4bbdfSmrg 145105b261ecSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 14526747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 145335c4bbdfSmrg 145435c4bbdfSmrg len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq)); 145505b261ecSmrg if (len < (stuff->size * 3 + 1) >> 1) 145635c4bbdfSmrg return BadLength; 145705b261ecSmrg 145805b261ecSmrg if (stuff->size != crtc->gammaSize) 145935c4bbdfSmrg return BadMatch; 146035c4bbdfSmrg 146105b261ecSmrg red = (CARD16 *) (stuff + 1); 146205b261ecSmrg green = red + crtc->gammaSize; 146305b261ecSmrg blue = green + crtc->gammaSize; 146435c4bbdfSmrg 146535c4bbdfSmrg RRCrtcGammaSet(crtc, red, green, blue); 146605b261ecSmrg 146705b261ecSmrg return Success; 146805b261ecSmrg} 146905b261ecSmrg 14704642e01fSmrg/* Version 1.3 additions */ 14714642e01fSmrg 14724642e01fSmrgint 147335c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client) 14744642e01fSmrg{ 14754642e01fSmrg REQUEST(xRRSetCrtcTransformReq); 147635c4bbdfSmrg RRCrtcPtr crtc; 147735c4bbdfSmrg PictTransform transform; 14784642e01fSmrg struct pixman_f_transform f_transform, f_inverse; 147935c4bbdfSmrg char *filter; 148035c4bbdfSmrg int nbytes; 148135c4bbdfSmrg xFixed *params; 148235c4bbdfSmrg int nparams; 14834642e01fSmrg 14844642e01fSmrg REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 14856747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 14864642e01fSmrg 148735c4bbdfSmrg PictTransform_from_xRenderTransform(&transform, &stuff->transform); 148835c4bbdfSmrg pixman_f_transform_from_pixman_transform(&f_transform, &transform); 148935c4bbdfSmrg if (!pixman_f_transform_invert(&f_inverse, &f_transform)) 149035c4bbdfSmrg return BadMatch; 14914642e01fSmrg 14924642e01fSmrg filter = (char *) (stuff + 1); 14934642e01fSmrg nbytes = stuff->nbytesFilter; 14946747b715Smrg params = (xFixed *) (filter + pad_to_int32(nbytes)); 14954642e01fSmrg nparams = ((xFixed *) stuff + client->req_len) - params; 14964642e01fSmrg if (nparams < 0) 149735c4bbdfSmrg return BadLength; 14984642e01fSmrg 149935c4bbdfSmrg return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse, 150035c4bbdfSmrg filter, nbytes, params, nparams); 15014642e01fSmrg} 15024642e01fSmrg 15034642e01fSmrg#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 150435c4bbdfSmrg 15054642e01fSmrgstatic int 150635c4bbdfSmrgtransform_filter_length(RRTransformPtr transform) 15074642e01fSmrg{ 150835c4bbdfSmrg int nbytes, nparams; 15094642e01fSmrg 15104642e01fSmrg if (transform->filter == NULL) 151135c4bbdfSmrg return 0; 151235c4bbdfSmrg nbytes = strlen(transform->filter->name); 15134642e01fSmrg nparams = transform->nparams; 151435c4bbdfSmrg return pad_to_int32(nbytes) + (nparams * sizeof(xFixed)); 15154642e01fSmrg} 15164642e01fSmrg 15174642e01fSmrgstatic int 151835c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output, 151935c4bbdfSmrg CARD16 *nbytesFilter, 152035c4bbdfSmrg CARD16 *nparamsFilter, RRTransformPtr transform) 15214642e01fSmrg{ 152235c4bbdfSmrg int nbytes, nparams; 15234642e01fSmrg 15244642e01fSmrg if (transform->filter == NULL) { 152535c4bbdfSmrg *nbytesFilter = 0; 152635c4bbdfSmrg *nparamsFilter = 0; 152735c4bbdfSmrg return 0; 15284642e01fSmrg } 152935c4bbdfSmrg nbytes = strlen(transform->filter->name); 15304642e01fSmrg nparams = transform->nparams; 15314642e01fSmrg *nbytesFilter = nbytes; 15324642e01fSmrg *nparamsFilter = nparams; 153335c4bbdfSmrg memcpy(output, transform->filter->name, nbytes); 15344642e01fSmrg while ((nbytes & 3) != 0) 153535c4bbdfSmrg output[nbytes++] = 0; 153635c4bbdfSmrg memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed)); 15374642e01fSmrg if (client->swapped) { 153835c4bbdfSmrg swaps(nbytesFilter); 153935c4bbdfSmrg swaps(nparamsFilter); 154035c4bbdfSmrg SwapLongs((CARD32 *) (output + nbytes), nparams); 15414642e01fSmrg } 154235c4bbdfSmrg nbytes += nparams * sizeof(xFixed); 15434642e01fSmrg return nbytes; 15444642e01fSmrg} 15454642e01fSmrg 15464642e01fSmrgstatic void 154735c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire, 154835c4bbdfSmrg PictTransform * pict) 15494642e01fSmrg{ 155035c4bbdfSmrg xRenderTransform_from_PictTransform(wire, pict); 15514642e01fSmrg if (client->swapped) 155235c4bbdfSmrg SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 15534642e01fSmrg} 15544642e01fSmrg 15554642e01fSmrgint 155635c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client) 15574642e01fSmrg{ 15584642e01fSmrg REQUEST(xRRGetCrtcTransformReq); 155935c4bbdfSmrg xRRGetCrtcTransformReply *reply; 156035c4bbdfSmrg RRCrtcPtr crtc; 156135c4bbdfSmrg int nextra; 156235c4bbdfSmrg RRTransformPtr current, pending; 156335c4bbdfSmrg char *extra; 15644642e01fSmrg 156535c4bbdfSmrg REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq); 15666747b715Smrg VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 15674642e01fSmrg 15684642e01fSmrg pending = &crtc->client_pending_transform; 15694642e01fSmrg current = &crtc->client_current_transform; 15704642e01fSmrg 157135c4bbdfSmrg nextra = (transform_filter_length(pending) + 157235c4bbdfSmrg transform_filter_length(current)); 15734642e01fSmrg 157435c4bbdfSmrg reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra); 15754642e01fSmrg if (!reply) 157635c4bbdfSmrg return BadAlloc; 15774642e01fSmrg 15784642e01fSmrg extra = (char *) (reply + 1); 15794642e01fSmrg reply->type = X_Reply; 15804642e01fSmrg reply->sequenceNumber = client->sequence; 15816747b715Smrg reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 15824642e01fSmrg 15834642e01fSmrg reply->hasTransforms = crtc->transforms; 15844642e01fSmrg 158535c4bbdfSmrg transform_encode(client, &reply->pendingTransform, &pending->transform); 158635c4bbdfSmrg extra += transform_filter_encode(client, extra, 158735c4bbdfSmrg &reply->pendingNbytesFilter, 158835c4bbdfSmrg &reply->pendingNparamsFilter, pending); 15894642e01fSmrg 159035c4bbdfSmrg transform_encode(client, &reply->currentTransform, ¤t->transform); 159135c4bbdfSmrg extra += transform_filter_encode(client, extra, 159235c4bbdfSmrg &reply->currentNbytesFilter, 159335c4bbdfSmrg &reply->currentNparamsFilter, current); 15944642e01fSmrg 15954642e01fSmrg if (client->swapped) { 159635c4bbdfSmrg swaps(&reply->sequenceNumber); 159735c4bbdfSmrg swapl(&reply->length); 15984642e01fSmrg } 159935c4bbdfSmrg WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply); 16006747b715Smrg free(reply); 16016747b715Smrg return Success; 16024642e01fSmrg} 160335c4bbdfSmrg 160435c4bbdfSmrgstatic Bool 160535c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y) 160635c4bbdfSmrg{ 160735c4bbdfSmrg rrScrPriv(pScreen); 160835c4bbdfSmrg int i; 160935c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 161035c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 161135c4bbdfSmrg 161235c4bbdfSmrg int left, right, top, bottom; 161335c4bbdfSmrg 161435c4bbdfSmrg if (!crtc->mode) 161535c4bbdfSmrg continue; 161635c4bbdfSmrg 161735c4bbdfSmrg crtc_bounds(crtc, &left, &right, &top, &bottom); 161835c4bbdfSmrg 161935c4bbdfSmrg if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom)) 162035c4bbdfSmrg return TRUE; 162135c4bbdfSmrg } 162235c4bbdfSmrg return FALSE; 162335c4bbdfSmrg} 162435c4bbdfSmrg 162535c4bbdfSmrgstatic Bool 162635c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y) 162735c4bbdfSmrg{ 162835c4bbdfSmrg rrScrPriv(pScreen); 162935c4bbdfSmrg int i; 163035c4bbdfSmrg 163135c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 163235c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 163335c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 163435c4bbdfSmrg int nx, ny; 163535c4bbdfSmrg int left, right, top, bottom; 163635c4bbdfSmrg 163735c4bbdfSmrg if (!crtc->mode) 163835c4bbdfSmrg continue; 163935c4bbdfSmrg 164035c4bbdfSmrg crtc_bounds(crtc, &left, &right, &top, &bottom); 164135c4bbdfSmrg miPointerGetPosition(pDev, &nx, &ny); 164235c4bbdfSmrg 164335c4bbdfSmrg if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) { 164435c4bbdfSmrg if (*x < left) 164535c4bbdfSmrg *x = left; 164635c4bbdfSmrg if (*x >= right) 164735c4bbdfSmrg *x = right - 1; 164835c4bbdfSmrg if (*y < top) 164935c4bbdfSmrg *y = top; 165035c4bbdfSmrg if (*y >= bottom) 165135c4bbdfSmrg *y = bottom - 1; 165235c4bbdfSmrg 165335c4bbdfSmrg return TRUE; 165435c4bbdfSmrg } 165535c4bbdfSmrg } 165635c4bbdfSmrg return FALSE; 165735c4bbdfSmrg} 165835c4bbdfSmrg 165935c4bbdfSmrgvoid 166035c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, 166135c4bbdfSmrg int *y) 166235c4bbdfSmrg{ 166335c4bbdfSmrg rrScrPriv(pScreen); 166435c4bbdfSmrg Bool ret; 166535c4bbdfSmrg ScreenPtr slave; 166635c4bbdfSmrg 166735c4bbdfSmrg /* intentional dead space -> let it float */ 166835c4bbdfSmrg if (pScrPriv->discontiguous) 166935c4bbdfSmrg return; 167035c4bbdfSmrg 167135c4bbdfSmrg /* if we're moving inside a crtc, we're fine */ 167235c4bbdfSmrg ret = check_all_screen_crtcs(pScreen, x, y); 167335c4bbdfSmrg if (ret == TRUE) 167435c4bbdfSmrg return; 167535c4bbdfSmrg 167635c4bbdfSmrg xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) { 167735c4bbdfSmrg ret = check_all_screen_crtcs(slave, x, y); 167835c4bbdfSmrg if (ret == TRUE) 167935c4bbdfSmrg return; 168035c4bbdfSmrg } 168135c4bbdfSmrg 168235c4bbdfSmrg /* if we're trying to escape, clamp to the CRTC we're coming from */ 168335c4bbdfSmrg ret = constrain_all_screen_crtcs(pDev, pScreen, x, y); 168435c4bbdfSmrg if (ret == TRUE) 168535c4bbdfSmrg return; 168635c4bbdfSmrg 168735c4bbdfSmrg xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) { 168835c4bbdfSmrg ret = constrain_all_screen_crtcs(pDev, slave, x, y); 168935c4bbdfSmrg if (ret == TRUE) 169035c4bbdfSmrg return; 169135c4bbdfSmrg } 169235c4bbdfSmrg} 169335c4bbdfSmrg 169435c4bbdfSmrgBool 169535c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable) 169635c4bbdfSmrg{ 169735c4bbdfSmrg rrScrPriv(pDrawable->pScreen); 169835c4bbdfSmrg Bool ret = TRUE; 169935c4bbdfSmrg PixmapPtr *saved_scanout_pixmap; 170035c4bbdfSmrg int i; 170135c4bbdfSmrg 170235c4bbdfSmrg saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs); 170335c4bbdfSmrg if (saved_scanout_pixmap == NULL) 170435c4bbdfSmrg return FALSE; 170535c4bbdfSmrg 170635c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 170735c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 170835c4bbdfSmrg Bool size_fits; 170935c4bbdfSmrg 171035c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 171135c4bbdfSmrg 171235c4bbdfSmrg if (!crtc->mode && enable) 171335c4bbdfSmrg continue; 171435c4bbdfSmrg if (!crtc->scanout_pixmap && !enable) 171535c4bbdfSmrg continue; 171635c4bbdfSmrg 171735c4bbdfSmrg size_fits = (crtc->mode && 171835c4bbdfSmrg crtc->x == pDrawable->x && 171935c4bbdfSmrg crtc->y == pDrawable->y && 172035c4bbdfSmrg crtc->mode->mode.width == pDrawable->width && 172135c4bbdfSmrg crtc->mode->mode.height == pDrawable->height); 172235c4bbdfSmrg 172335c4bbdfSmrg /* is the pixmap already set? */ 172435c4bbdfSmrg if (crtc->scanout_pixmap == pPixmap) { 172535c4bbdfSmrg /* if its a disable then don't care about size */ 172635c4bbdfSmrg if (enable == FALSE) { 172735c4bbdfSmrg /* set scanout to NULL */ 172835c4bbdfSmrg crtc->scanout_pixmap = NULL; 172935c4bbdfSmrg } 173035c4bbdfSmrg else if (!size_fits) { 173135c4bbdfSmrg /* if the size no longer fits then drop off */ 173235c4bbdfSmrg crtc->scanout_pixmap = NULL; 173335c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 173435c4bbdfSmrg 173535c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 173635c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 173735c4bbdfSmrg saved_scanout_pixmap[i] = crtc->scanout_pixmap; 173835c4bbdfSmrg ret = FALSE; 173935c4bbdfSmrg } 174035c4bbdfSmrg else { 174135c4bbdfSmrg /* if the size fits then we are already setup */ 174235c4bbdfSmrg } 174335c4bbdfSmrg } 174435c4bbdfSmrg else { 174535c4bbdfSmrg if (!size_fits) 174635c4bbdfSmrg ret = FALSE; 174735c4bbdfSmrg else if (enable) 174835c4bbdfSmrg crtc->scanout_pixmap = pPixmap; 174935c4bbdfSmrg else 175035c4bbdfSmrg /* reject an attempt to disable someone else's scanout_pixmap */ 175135c4bbdfSmrg ret = FALSE; 175235c4bbdfSmrg } 175335c4bbdfSmrg } 175435c4bbdfSmrg 175535c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 175635c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 175735c4bbdfSmrg 175835c4bbdfSmrg if (crtc->scanout_pixmap == saved_scanout_pixmap[i]) 175935c4bbdfSmrg continue; 176035c4bbdfSmrg 176135c4bbdfSmrg if (ret) { 176235c4bbdfSmrg pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 176335c4bbdfSmrg 176435c4bbdfSmrg (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 176535c4bbdfSmrg crtc->rotation, crtc->numOutputs, crtc->outputs); 176635c4bbdfSmrg } 176735c4bbdfSmrg else 176835c4bbdfSmrg crtc->scanout_pixmap = saved_scanout_pixmap[i]; 176935c4bbdfSmrg } 177035c4bbdfSmrg free(saved_scanout_pixmap); 177135c4bbdfSmrg 177235c4bbdfSmrg return ret; 177335c4bbdfSmrg} 1774