1706f2543Smrg/*
2706f2543Smrg * Copyright © 2006 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
7706f2543Smrg * notice and this permission notice appear in supporting documentation, and
8706f2543Smrg * that the name of the copyright holders not be used in advertising or
9706f2543Smrg * publicity pertaining to distribution of the software without specific,
10706f2543Smrg * written prior permission.  The copyright holders make no representations
11706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
12706f2543Smrg * is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20706f2543Smrg * OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
24706f2543Smrg#include <xorg-config.h>
25706f2543Smrg#else
26706f2543Smrg#ifdef HAVE_CONFIG_H
27706f2543Smrg#include <config.h>
28706f2543Smrg#endif
29706f2543Smrg#endif
30706f2543Smrg
31706f2543Smrg#include <stddef.h>
32706f2543Smrg#include <string.h>
33706f2543Smrg#include <stdio.h>
34706f2543Smrg
35706f2543Smrg#include "xf86.h"
36706f2543Smrg#include "xf86DDC.h"
37706f2543Smrg#include "fb.h"
38706f2543Smrg#include "windowstr.h"
39706f2543Smrg#include "xf86Crtc.h"
40706f2543Smrg#include "xf86Modes.h"
41706f2543Smrg#include "xf86RandR12.h"
42706f2543Smrg#include "X11/extensions/render.h"
43706f2543Smrg#include "X11/extensions/dpmsconst.h"
44706f2543Smrg#include "X11/Xatom.h"
45706f2543Smrg
46706f2543Smrg/* borrowed from composite extension, move to Render and publish? */
47706f2543Smrg
48706f2543Smrgstatic VisualPtr
49706f2543SmrgcompGetWindowVisual (WindowPtr pWin)
50706f2543Smrg{
51706f2543Smrg    ScreenPtr	    pScreen = pWin->drawable.pScreen;
52706f2543Smrg    VisualID	    vid = wVisual (pWin);
53706f2543Smrg    int		    i;
54706f2543Smrg
55706f2543Smrg    for (i = 0; i < pScreen->numVisuals; i++)
56706f2543Smrg	if (pScreen->visuals[i].vid == vid)
57706f2543Smrg	    return &pScreen->visuals[i];
58706f2543Smrg    return 0;
59706f2543Smrg}
60706f2543Smrg
61706f2543Smrgstatic PictFormatPtr
62706f2543SmrgcompWindowFormat (WindowPtr pWin)
63706f2543Smrg{
64706f2543Smrg    ScreenPtr	pScreen = pWin->drawable.pScreen;
65706f2543Smrg
66706f2543Smrg    return PictureMatchVisual (pScreen, pWin->drawable.depth,
67706f2543Smrg			       compGetWindowVisual (pWin));
68706f2543Smrg}
69706f2543Smrg
70706f2543Smrg#define F(x)	IntToxFixed(x)
71706f2543Smrg
72706f2543Smrg#define toF(x)	((float) (x) / 65536.0f)
73706f2543Smrg
74706f2543Smrgstatic void
75706f2543Smrgxf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
76706f2543Smrg{
77706f2543Smrg    ScrnInfoPtr		scrn = crtc->scrn;
78706f2543Smrg    ScreenPtr		screen = scrn->pScreen;
79706f2543Smrg    WindowPtr		root = screen->root;
80706f2543Smrg    PixmapPtr		dst_pixmap = crtc->rotatedPixmap;
81706f2543Smrg    PictFormatPtr	format = compWindowFormat (screen->root);
82706f2543Smrg    int			error;
83706f2543Smrg    PicturePtr		src, dst;
84706f2543Smrg    int			n = RegionNumRects(region);
85706f2543Smrg    BoxPtr		b = RegionRects(region);
86706f2543Smrg    XID			include_inferiors = IncludeInferiors;
87706f2543Smrg
88706f2543Smrg    src = CreatePicture (None,
89706f2543Smrg			 &root->drawable,
90706f2543Smrg			 format,
91706f2543Smrg			 CPSubwindowMode,
92706f2543Smrg			 &include_inferiors,
93706f2543Smrg			 serverClient,
94706f2543Smrg			 &error);
95706f2543Smrg    if (!src)
96706f2543Smrg	return;
97706f2543Smrg
98706f2543Smrg    dst = CreatePicture (None,
99706f2543Smrg			 &dst_pixmap->drawable,
100706f2543Smrg			 format,
101706f2543Smrg			 0L,
102706f2543Smrg			 NULL,
103706f2543Smrg			 serverClient,
104706f2543Smrg			 &error);
105706f2543Smrg    if (!dst)
106706f2543Smrg	return;
107706f2543Smrg
108706f2543Smrg    error = SetPictureTransform (src, &crtc->crtc_to_framebuffer);
109706f2543Smrg    if (error)
110706f2543Smrg	return;
111706f2543Smrg    if (crtc->transform_in_use && crtc->filter)
112706f2543Smrg	SetPicturePictFilter (src, crtc->filter,
113706f2543Smrg			      crtc->params, crtc->nparams);
114706f2543Smrg
115706f2543Smrg    if (crtc->shadowClear)
116706f2543Smrg    {
117706f2543Smrg	CompositePicture (PictOpSrc,
118706f2543Smrg			  src, NULL, dst,
119706f2543Smrg			  0, 0, 0, 0, 0, 0,
120706f2543Smrg			  crtc->mode.HDisplay, crtc->mode.VDisplay);
121706f2543Smrg	crtc->shadowClear = FALSE;
122706f2543Smrg    }
123706f2543Smrg    else
124706f2543Smrg    {
125706f2543Smrg	while (n--)
126706f2543Smrg	{
127706f2543Smrg	    BoxRec	dst_box;
128706f2543Smrg
129706f2543Smrg	    dst_box = *b;
130706f2543Smrg	    dst_box.x1 -= crtc->filter_width >> 1;
131706f2543Smrg	    dst_box.x2 += crtc->filter_width >> 1;
132706f2543Smrg	    dst_box.y1 -= crtc->filter_height >> 1;
133706f2543Smrg	    dst_box.y2 += crtc->filter_height >> 1;
134706f2543Smrg	    pixman_f_transform_bounds (&crtc->f_framebuffer_to_crtc, &dst_box);
135706f2543Smrg	    CompositePicture (PictOpSrc,
136706f2543Smrg			      src, NULL, dst,
137706f2543Smrg			      dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1,
138706f2543Smrg			      dst_box.x2 - dst_box.x1,
139706f2543Smrg			      dst_box.y2 - dst_box.y1);
140706f2543Smrg	    b++;
141706f2543Smrg	}
142706f2543Smrg    }
143706f2543Smrg    FreePicture (src, None);
144706f2543Smrg    FreePicture (dst, None);
145706f2543Smrg}
146706f2543Smrg
147706f2543Smrgstatic void
148706f2543Smrgxf86CrtcDamageShadow (xf86CrtcPtr crtc)
149706f2543Smrg{
150706f2543Smrg    ScrnInfoPtr	pScrn = crtc->scrn;
151706f2543Smrg    BoxRec	damage_box;
152706f2543Smrg    RegionRec   damage_region;
153706f2543Smrg    ScreenPtr	pScreen = pScrn->pScreen;
154706f2543Smrg
155706f2543Smrg    damage_box.x1 = 0;
156706f2543Smrg    damage_box.x2 = crtc->mode.HDisplay;
157706f2543Smrg    damage_box.y1 = 0;
158706f2543Smrg    damage_box.y2 = crtc->mode.VDisplay;
159706f2543Smrg    if (!pixman_transform_bounds (&crtc->crtc_to_framebuffer, &damage_box))
160706f2543Smrg    {
161706f2543Smrg	damage_box.x1 = 0;
162706f2543Smrg	damage_box.y1 = 0;
163706f2543Smrg	damage_box.x2 = pScreen->width;
164706f2543Smrg	damage_box.y2 = pScreen->height;
165706f2543Smrg    }
166706f2543Smrg    if (damage_box.x1 < 0) damage_box.x1 = 0;
167706f2543Smrg    if (damage_box.y1 < 0) damage_box.y1 = 0;
168706f2543Smrg    if (damage_box.x2 > pScreen->width) damage_box.x2 = pScreen->width;
169706f2543Smrg    if (damage_box.y2 > pScreen->height) damage_box.y2 = pScreen->height;
170706f2543Smrg    RegionInit(&damage_region, &damage_box, 1);
171706f2543Smrg    DamageDamageRegion (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
172706f2543Smrg			&damage_region);
173706f2543Smrg    RegionUninit(&damage_region);
174706f2543Smrg    crtc->shadowClear = TRUE;
175706f2543Smrg}
176706f2543Smrg
177706f2543Smrgstatic void
178706f2543Smrgxf86RotatePrepare (ScreenPtr pScreen)
179706f2543Smrg{
180706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
181706f2543Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
182706f2543Smrg    int			c;
183706f2543Smrg
184706f2543Smrg    for (c = 0; c < xf86_config->num_crtc; c++)
185706f2543Smrg    {
186706f2543Smrg	xf86CrtcPtr crtc = xf86_config->crtc[c];
187706f2543Smrg
188706f2543Smrg	if (crtc->rotatedData && !crtc->rotatedPixmap)
189706f2543Smrg	{
190706f2543Smrg	    crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc,
191706f2543Smrg							     crtc->rotatedData,
192706f2543Smrg							     crtc->mode.HDisplay,
193706f2543Smrg							     crtc->mode.VDisplay);
194706f2543Smrg	    if (!xf86_config->rotation_damage_registered)
195706f2543Smrg	    {
196706f2543Smrg		/* Hook damage to screen pixmap */
197706f2543Smrg		DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
198706f2543Smrg				xf86_config->rotation_damage);
199706f2543Smrg		xf86_config->rotation_damage_registered = TRUE;
200706f2543Smrg		EnableLimitedSchedulingLatency();
201706f2543Smrg	    }
202706f2543Smrg
203706f2543Smrg	    xf86CrtcDamageShadow (crtc);
204706f2543Smrg	}
205706f2543Smrg    }
206706f2543Smrg}
207706f2543Smrg
208706f2543Smrgstatic Bool
209706f2543Smrgxf86RotateRedisplay(ScreenPtr pScreen)
210706f2543Smrg{
211706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
212706f2543Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
213706f2543Smrg    DamagePtr		damage = xf86_config->rotation_damage;
214706f2543Smrg    RegionPtr		region;
215706f2543Smrg
216706f2543Smrg    if (!damage)
217706f2543Smrg	return FALSE;
218706f2543Smrg    xf86RotatePrepare (pScreen);
219706f2543Smrg    region = DamageRegion(damage);
220706f2543Smrg    if (RegionNotEmpty(region))
221706f2543Smrg    {
222706f2543Smrg	int			c;
223706f2543Smrg	SourceValidateProcPtr	SourceValidate;
224706f2543Smrg
225706f2543Smrg	/*
226706f2543Smrg	 * SourceValidate is used by the software cursor code
227706f2543Smrg	 * to pull the cursor off of the screen when reading
228706f2543Smrg	 * bits from the frame buffer. Bypassing this function
229706f2543Smrg	 * leaves the software cursor in place
230706f2543Smrg	 */
231706f2543Smrg	SourceValidate = pScreen->SourceValidate;
232706f2543Smrg	pScreen->SourceValidate = NULL;
233706f2543Smrg
234706f2543Smrg	for (c = 0; c < xf86_config->num_crtc; c++)
235706f2543Smrg	{
236706f2543Smrg	    xf86CrtcPtr	    crtc = xf86_config->crtc[c];
237706f2543Smrg
238706f2543Smrg	    if (crtc->transform_in_use && crtc->enabled)
239706f2543Smrg	    {
240706f2543Smrg		RegionRec   crtc_damage;
241706f2543Smrg
242706f2543Smrg		/* compute portion of damage that overlaps crtc */
243706f2543Smrg		RegionInit(&crtc_damage, &crtc->bounds, 1);
244706f2543Smrg		RegionIntersect(&crtc_damage, &crtc_damage, region);
245706f2543Smrg
246706f2543Smrg		/* update damaged region */
247706f2543Smrg		if (RegionNotEmpty(&crtc_damage))
248706f2543Smrg    		    xf86RotateCrtcRedisplay (crtc, &crtc_damage);
249706f2543Smrg
250706f2543Smrg		RegionUninit(&crtc_damage);
251706f2543Smrg	    }
252706f2543Smrg	}
253706f2543Smrg	pScreen->SourceValidate = SourceValidate;
254706f2543Smrg	DamageEmpty(damage);
255706f2543Smrg    }
256706f2543Smrg    return TRUE;
257706f2543Smrg}
258706f2543Smrg
259706f2543Smrgstatic void
260706f2543Smrgxf86RotateBlockHandler(int screenNum, pointer blockData,
261706f2543Smrg		       pointer pTimeout, pointer pReadmask)
262706f2543Smrg{
263706f2543Smrg    ScreenPtr		pScreen = screenInfo.screens[screenNum];
264706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[screenNum];
265706f2543Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
266706f2543Smrg    Bool		rotation_active;
267706f2543Smrg
268706f2543Smrg    rotation_active = xf86RotateRedisplay(pScreen);
269706f2543Smrg    pScreen->BlockHandler = xf86_config->BlockHandler;
270706f2543Smrg    (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
271706f2543Smrg    /* cannot avoid re-wrapping until all wrapping is audited */
272706f2543Smrg    xf86_config->BlockHandler = pScreen->BlockHandler;
273706f2543Smrg    pScreen->BlockHandler = xf86RotateBlockHandler;
274706f2543Smrg}
275706f2543Smrg
276706f2543Smrgvoid
277706f2543Smrgxf86RotateDestroy (xf86CrtcPtr crtc)
278706f2543Smrg{
279706f2543Smrg    ScrnInfoPtr		pScrn = crtc->scrn;
280706f2543Smrg    ScreenPtr		pScreen = pScrn->pScreen;
281706f2543Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
282706f2543Smrg    int			c;
283706f2543Smrg
284706f2543Smrg    /* Free memory from rotation */
285706f2543Smrg    if (crtc->rotatedPixmap || crtc->rotatedData)
286706f2543Smrg    {
287706f2543Smrg	crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData);
288706f2543Smrg	crtc->rotatedPixmap = NULL;
289706f2543Smrg	crtc->rotatedData = NULL;
290706f2543Smrg    }
291706f2543Smrg
292706f2543Smrg    for (c = 0; c < xf86_config->num_crtc; c++)
293706f2543Smrg	if (xf86_config->crtc[c]->transform_in_use)
294706f2543Smrg	    return;
295706f2543Smrg
296706f2543Smrg    /*
297706f2543Smrg     * Clean up damage structures when no crtcs are rotated
298706f2543Smrg     */
299706f2543Smrg    if (xf86_config->rotation_damage)
300706f2543Smrg    {
301706f2543Smrg	/* Free damage structure */
302706f2543Smrg	if (xf86_config->rotation_damage_registered)
303706f2543Smrg	{
304706f2543Smrg	    DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
305706f2543Smrg			      xf86_config->rotation_damage);
306706f2543Smrg	    xf86_config->rotation_damage_registered = FALSE;
307706f2543Smrg	    DisableLimitedSchedulingLatency();
308706f2543Smrg	}
309706f2543Smrg	DamageDestroy (xf86_config->rotation_damage);
310706f2543Smrg	xf86_config->rotation_damage = NULL;
311706f2543Smrg    }
312706f2543Smrg}
313706f2543Smrg
314706f2543Smrgvoid
315706f2543Smrgxf86RotateFreeShadow(ScrnInfoPtr pScrn)
316706f2543Smrg{
317706f2543Smrg    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
318706f2543Smrg    int c;
319706f2543Smrg
320706f2543Smrg   for (c = 0; c < config->num_crtc; c++) {
321706f2543Smrg       xf86CrtcPtr crtc = config->crtc[c];
322706f2543Smrg
323706f2543Smrg       if (crtc->rotatedPixmap || crtc->rotatedData) {
324706f2543Smrg	   crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
325706f2543Smrg				crtc->rotatedData);
326706f2543Smrg	   crtc->rotatedPixmap = NULL;
327706f2543Smrg	   crtc->rotatedData = NULL;
328706f2543Smrg       }
329706f2543Smrg   }
330706f2543Smrg}
331706f2543Smrg
332706f2543Smrgvoid
333706f2543Smrgxf86RotateCloseScreen (ScreenPtr screen)
334706f2543Smrg{
335706f2543Smrg    ScrnInfoPtr		scrn = xf86Screens[screen->myNum];
336706f2543Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
337706f2543Smrg    int			c;
338706f2543Smrg
339706f2543Smrg    for (c = 0; c < xf86_config->num_crtc; c++)
340706f2543Smrg	xf86RotateDestroy (xf86_config->crtc[c]);
341706f2543Smrg}
342706f2543Smrg
343706f2543Smrgstatic Bool
344706f2543Smrgxf86CrtcFitsScreen (xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb)
345706f2543Smrg{
346706f2543Smrg    ScrnInfoPtr		pScrn = crtc->scrn;
347706f2543Smrg    BoxRec		b;
348706f2543Smrg
349706f2543Smrg    /* When called before PreInit, the driver is
350706f2543Smrg     * presumably doing load detect
351706f2543Smrg     */
352706f2543Smrg    if (pScrn->virtualX == 0 || pScrn->virtualY == 0)
353706f2543Smrg	return TRUE;
354706f2543Smrg
355706f2543Smrg    b.x1 = 0;
356706f2543Smrg    b.y1 = 0;
357706f2543Smrg    b.x2 = crtc->mode.HDisplay;
358706f2543Smrg    b.y2 = crtc->mode.VDisplay;
359706f2543Smrg    if (crtc_to_fb)
360706f2543Smrg	pixman_f_transform_bounds (crtc_to_fb, &b);
361706f2543Smrg    else {
362706f2543Smrg	b.x1 += crtc->x;
363706f2543Smrg	b.y1 += crtc->y;
364706f2543Smrg	b.x2 += crtc->x;
365706f2543Smrg	b.y2 += crtc->y;
366706f2543Smrg    }
367706f2543Smrg
368706f2543Smrg    return (0 <= b.x1 && b.x2 <= pScrn->virtualX &&
369706f2543Smrg	    0 <= b.y1 && b.y2 <= pScrn->virtualY);
370706f2543Smrg}
371706f2543Smrg
372706f2543SmrgBool
373706f2543Smrgxf86CrtcRotate (xf86CrtcPtr crtc)
374706f2543Smrg{
375706f2543Smrg    ScrnInfoPtr		pScrn = crtc->scrn;
376706f2543Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
377706f2543Smrg    /* if this is called during ScreenInit() we don't have pScrn->pScreen yet */
378706f2543Smrg    ScreenPtr		pScreen = screenInfo.screens[pScrn->scrnIndex];
379706f2543Smrg    PictTransform	crtc_to_fb;
380706f2543Smrg    struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
381706f2543Smrg    xFixed		*new_params = NULL;
382706f2543Smrg    int			new_nparams = 0;
383706f2543Smrg    PictFilterPtr	new_filter = NULL;
384706f2543Smrg    int			new_width = 0;
385706f2543Smrg    int			new_height = 0;
386706f2543Smrg    RRTransformPtr	transform = NULL;
387706f2543Smrg    Bool		damage = FALSE;
388706f2543Smrg
389706f2543Smrg    if (crtc->transformPresent)
390706f2543Smrg	transform = &crtc->transform;
391706f2543Smrg
392706f2543Smrg    if (!RRTransformCompute (crtc->x, crtc->y,
393706f2543Smrg			     crtc->mode.HDisplay, crtc->mode.VDisplay,
394706f2543Smrg			     crtc->rotation,
395706f2543Smrg			     transform,
396706f2543Smrg
397706f2543Smrg			     &crtc_to_fb,
398706f2543Smrg			     &f_crtc_to_fb,
399706f2543Smrg			     &f_fb_to_crtc) &&
400706f2543Smrg	xf86CrtcFitsScreen (crtc, &f_crtc_to_fb))
401706f2543Smrg    {
402706f2543Smrg	/*
403706f2543Smrg	 * If the untranslated transformation is the identity,
404706f2543Smrg	 * disable the shadow buffer
405706f2543Smrg	 */
406706f2543Smrg	xf86RotateDestroy (crtc);
407706f2543Smrg	crtc->transform_in_use = FALSE;
408706f2543Smrg	free(new_params);
409706f2543Smrg	new_params = NULL;
410706f2543Smrg	new_nparams = 0;
411706f2543Smrg	new_filter = NULL;
412706f2543Smrg	new_width = 0;
413706f2543Smrg	new_height = 0;
414706f2543Smrg    }
415706f2543Smrg    else
416706f2543Smrg    {
417706f2543Smrg	/*
418706f2543Smrg	 * these are the size of the shadow pixmap, which
419706f2543Smrg	 * matches the mode, not the pre-rotated copy in the
420706f2543Smrg	 * frame buffer
421706f2543Smrg	 */
422706f2543Smrg	int	    width = crtc->mode.HDisplay;
423706f2543Smrg	int	    height = crtc->mode.VDisplay;
424706f2543Smrg	void	    *shadowData = crtc->rotatedData;
425706f2543Smrg	PixmapPtr   shadow = crtc->rotatedPixmap;
426706f2543Smrg	int	    old_width = shadow ? shadow->drawable.width : 0;
427706f2543Smrg	int	    old_height = shadow ? shadow->drawable.height : 0;
428706f2543Smrg
429706f2543Smrg	/* Allocate memory for rotation */
430706f2543Smrg	if (old_width != width || old_height != height)
431706f2543Smrg	{
432706f2543Smrg	    if (shadow || shadowData)
433706f2543Smrg	    {
434706f2543Smrg		crtc->funcs->shadow_destroy (crtc, shadow, shadowData);
435706f2543Smrg		crtc->rotatedPixmap = NULL;
436706f2543Smrg		crtc->rotatedData = NULL;
437706f2543Smrg	    }
438706f2543Smrg	    shadowData = crtc->funcs->shadow_allocate (crtc, width, height);
439706f2543Smrg	    if (!shadowData)
440706f2543Smrg		goto bail1;
441706f2543Smrg	    crtc->rotatedData = shadowData;
442706f2543Smrg	    /* shadow will be damaged in xf86RotatePrepare */
443706f2543Smrg	}
444706f2543Smrg	else
445706f2543Smrg	{
446706f2543Smrg	    /* mark shadowed area as damaged so it will be repainted */
447706f2543Smrg	    damage = TRUE;
448706f2543Smrg	}
449706f2543Smrg
450706f2543Smrg	if (!xf86_config->rotation_damage)
451706f2543Smrg	{
452706f2543Smrg	    /* Create damage structure */
453706f2543Smrg	    xf86_config->rotation_damage = DamageCreate (NULL, NULL,
454706f2543Smrg						DamageReportNone,
455706f2543Smrg						TRUE, pScreen, pScreen);
456706f2543Smrg	    if (!xf86_config->rotation_damage)
457706f2543Smrg		goto bail2;
458706f2543Smrg
459706f2543Smrg	    /* Wrap block handler */
460706f2543Smrg	    if (!xf86_config->BlockHandler) {
461706f2543Smrg		xf86_config->BlockHandler = pScreen->BlockHandler;
462706f2543Smrg		pScreen->BlockHandler = xf86RotateBlockHandler;
463706f2543Smrg	    }
464706f2543Smrg	}
465706f2543Smrg#ifdef RANDR_12_INTERFACE
466706f2543Smrg	if (transform)
467706f2543Smrg	{
468706f2543Smrg	    if (transform->nparams) {
469706f2543Smrg		new_params = malloc(transform->nparams * sizeof (xFixed));
470706f2543Smrg		if (new_params) {
471706f2543Smrg		    memcpy (new_params, transform->params,
472706f2543Smrg			    transform->nparams * sizeof (xFixed));
473706f2543Smrg		    new_nparams = transform->nparams;
474706f2543Smrg		    new_filter = transform->filter;
475706f2543Smrg		}
476706f2543Smrg	    } else
477706f2543Smrg		new_filter = transform->filter;
478706f2543Smrg	    if (new_filter)
479706f2543Smrg	    {
480706f2543Smrg		new_width = new_filter->width;
481706f2543Smrg		new_height = new_filter->height;
482706f2543Smrg	    }
483706f2543Smrg	}
484706f2543Smrg#endif
485706f2543Smrg
486706f2543Smrg	if (0)
487706f2543Smrg	{
488706f2543Smrg    bail2:
489706f2543Smrg	    if (shadow || shadowData)
490706f2543Smrg	    {
491706f2543Smrg		crtc->funcs->shadow_destroy (crtc, shadow, shadowData);
492706f2543Smrg		crtc->rotatedPixmap = NULL;
493706f2543Smrg		crtc->rotatedData = NULL;
494706f2543Smrg	    }
495706f2543Smrg    bail1:
496706f2543Smrg	    if (old_width && old_height)
497706f2543Smrg		crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc,
498706f2543Smrg								  NULL,
499706f2543Smrg								  old_width,
500706f2543Smrg								  old_height);
501706f2543Smrg	    return FALSE;
502706f2543Smrg	}
503706f2543Smrg	crtc->transform_in_use = TRUE;
504706f2543Smrg    }
505706f2543Smrg    crtc->crtc_to_framebuffer = crtc_to_fb;
506706f2543Smrg    crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
507706f2543Smrg    crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
508706f2543Smrg    free(crtc->params);
509706f2543Smrg    crtc->params = new_params;
510706f2543Smrg    crtc->nparams = new_nparams;
511706f2543Smrg    crtc->filter = new_filter;
512706f2543Smrg    crtc->filter_width = new_width;
513706f2543Smrg    crtc->filter_height = new_height;
514706f2543Smrg    crtc->bounds.x1 = 0;
515706f2543Smrg    crtc->bounds.x2 = crtc->mode.HDisplay;
516706f2543Smrg    crtc->bounds.y1 = 0;
517706f2543Smrg    crtc->bounds.y2 = crtc->mode.VDisplay;
518706f2543Smrg    pixman_f_transform_bounds (&f_crtc_to_fb, &crtc->bounds);
519706f2543Smrg
520706f2543Smrg    if (damage)
521706f2543Smrg        xf86CrtcDamageShadow (crtc);
522706f2543Smrg
523706f2543Smrg    /* All done */
524706f2543Smrg    return TRUE;
525706f2543Smrg}
526