1/*
2 * Copyright ® 2001 Keith Packard
3 *
4 * Partly based on code that is Copyright ® The XFree86 Project Inc.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission.  Keith Packard makes no
13 * representations about the suitability of this software for any purpose.  It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Authors:
25 *    Eric Anholt <eric@anholt.net>
26 *    Michel Dänzer <michel@tungstengraphics.com>
27 *
28 */
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33#include "uxa-priv.h"
34#include "uxa.h"
35#include "mipict.h"
36
37static CARD32
38format_for_depth(int depth)
39{
40	switch (depth) {
41	case 1: return PICT_a1;
42	case 4: return PICT_a4;
43	case 8: return PICT_a8;
44	case 15: return PICT_x1r5g5b5;
45	case 16: return PICT_r5g6b5;
46	default:
47	case 24: return PICT_x8r8g8b8;
48	case 32: return PICT_a8r8g8b8;
49	}
50}
51
52static void
53uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n,
54	       DDXPointPtr ppt, int *pwidth, int fSorted)
55{
56	ScreenPtr screen = pDrawable->pScreen;
57	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
58	RegionPtr pClip = fbGetCompositeClip(pGC);
59	PixmapPtr dst_pixmap, src_pixmap = NULL;
60	BoxPtr pextent, pbox;
61	int nbox;
62	int extentX1, extentX2, extentY1, extentY2;
63	int fullX1, fullX2, fullY1;
64	int partX1, partX2;
65	int off_x, off_y;
66	xRenderColor color;
67	PictFormatPtr format;
68	PicturePtr dst, src;
69	int error;
70
71	if (uxa_screen->swappedOut || uxa_screen->force_fallback)
72		goto fallback;
73
74	if (pGC->fillStyle != FillSolid)
75		goto fallback;
76
77	dst_pixmap = uxa_get_offscreen_pixmap(pDrawable, &off_x, &off_y);
78	if (!dst_pixmap)
79		goto fallback;
80
81	if (pGC->alu != GXcopy || pGC->planemask != FB_ALLONES)
82		goto solid;
83
84	format = PictureMatchFormat(screen,
85				    dst_pixmap->drawable.depth,
86				    format_for_depth(dst_pixmap->drawable.depth));
87	dst = CreatePicture(0, &dst_pixmap->drawable, format, 0, 0, serverClient, &error);
88	if (!dst)
89		goto solid;
90
91	ValidatePicture(dst);
92
93	uxa_get_rgba_from_pixel(pGC->fgPixel,
94				&color.red,
95				&color.green,
96				&color.blue,
97				&color.alpha,
98				format_for_depth(dst_pixmap->drawable.depth));
99	src = CreateSolidPicture(0, &color, &error);
100	if (!src) {
101		FreePicture(dst, 0);
102		goto solid;
103	}
104
105	if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst, 0, 0)) {
106		FreePicture(src, 0);
107		FreePicture(dst, 0);
108		goto solid;
109	}
110
111	if (!uxa_screen->info->check_composite_texture ||
112	    !uxa_screen->info->check_composite_texture(screen, src)) {
113		PicturePtr solid;
114		int src_off_x, src_off_y;
115
116		solid = uxa_acquire_solid(screen, src->pSourcePict);
117		FreePicture(src, 0);
118
119		src = solid;
120		src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable,
121						      &src_off_x, &src_off_y);
122		if (!src_pixmap) {
123			FreePicture(src, 0);
124			FreePicture(dst, 0);
125			goto solid;
126		}
127	}
128
129	if (!uxa_screen->info->prepare_composite(PictOpSrc, src, NULL, dst, src_pixmap, NULL, dst_pixmap)) {
130		FreePicture(src, 0);
131		FreePicture(dst, 0);
132		goto solid;
133	}
134
135	pextent = REGION_EXTENTS(pGC->screen, pClip);
136	extentX1 = pextent->x1;
137	extentY1 = pextent->y1;
138	extentX2 = pextent->x2;
139	extentY2 = pextent->y2;
140	while (n--) {
141		fullX1 = ppt->x;
142		fullY1 = ppt->y;
143		fullX2 = fullX1 + (int)*pwidth;
144		ppt++;
145		pwidth++;
146
147		if (fullY1 < extentY1 || extentY2 <= fullY1)
148			continue;
149
150		if (fullX1 < extentX1)
151			fullX1 = extentX1;
152
153		if (fullX2 > extentX2)
154			fullX2 = extentX2;
155
156		if (fullX1 >= fullX2)
157			continue;
158
159		nbox = REGION_NUM_RECTS(pClip);
160		if (nbox == 1) {
161			uxa_screen->info->composite(dst_pixmap,
162						    0, 0, 0, 0,
163						    fullX1 + off_x,
164						    fullY1 + off_y,
165						    fullX2 - fullX1, 1);
166		} else {
167			pbox = REGION_RECTS(pClip);
168			while (nbox--) {
169				if (pbox->y1 > fullY1)
170					break;
171
172				if (pbox->y1 <= fullY1) {
173					partX1 = pbox->x1;
174					if (partX1 < fullX1)
175						partX1 = fullX1;
176
177					partX2 = pbox->x2;
178					if (partX2 > fullX2)
179						partX2 = fullX2;
180
181					if (partX2 > partX1) {
182						uxa_screen->info->composite(dst_pixmap,
183									    0, 0, 0, 0,
184									    partX1 + off_x,
185									    fullY1 + off_y,
186									    partX2 - partX1, 1);
187					}
188				}
189				pbox++;
190			}
191		}
192	}
193
194	uxa_screen->info->done_composite(dst_pixmap);
195	FreePicture(src, 0);
196	FreePicture(dst, 0);
197	return;
198
199solid:
200	if (uxa_screen->info->check_solid &&
201	    !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask))
202		goto fallback;
203
204	if (!(*uxa_screen->info->prepare_solid) (dst_pixmap,
205						 pGC->alu,
206						 pGC->planemask,
207						 pGC->fgPixel))
208		goto fallback;
209
210	pextent = REGION_EXTENTS(pGC->screen, pClip);
211	extentX1 = pextent->x1;
212	extentY1 = pextent->y1;
213	extentX2 = pextent->x2;
214	extentY2 = pextent->y2;
215	while (n--) {
216		fullX1 = ppt->x;
217		fullY1 = ppt->y;
218		fullX2 = fullX1 + (int)*pwidth;
219		ppt++;
220		pwidth++;
221
222		if (fullY1 < extentY1 || extentY2 <= fullY1)
223			continue;
224
225		if (fullX1 < extentX1)
226			fullX1 = extentX1;
227
228		if (fullX2 > extentX2)
229			fullX2 = extentX2;
230
231		if (fullX1 >= fullX2)
232			continue;
233
234		nbox = REGION_NUM_RECTS(pClip);
235		if (nbox == 1) {
236			(*uxa_screen->info->solid) (dst_pixmap,
237						    fullX1 + off_x,
238						    fullY1 + off_y,
239						    fullX2 + off_x,
240						    fullY1 + 1 + off_y);
241		} else {
242			pbox = REGION_RECTS(pClip);
243			while (nbox--) {
244				if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) {
245					partX1 = pbox->x1;
246					if (partX1 < fullX1)
247						partX1 = fullX1;
248					partX2 = pbox->x2;
249					if (partX2 > fullX2)
250						partX2 = fullX2;
251					if (partX2 > partX1) {
252						(*uxa_screen->info->
253						 solid) (dst_pixmap,
254							 partX1 + off_x,
255							 fullY1 + off_y,
256							 partX2 + off_x,
257							 fullY1 + 1 + off_y);
258					}
259				}
260				pbox++;
261			}
262		}
263	}
264	(*uxa_screen->info->done_solid) (dst_pixmap);
265
266	return;
267
268fallback:
269	uxa_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted);
270}
271
272static Bool
273uxa_do_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
274		 int w, int h, int format, char *bits, int src_stride)
275{
276	uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
277	PixmapPtr pPix;
278	RegionPtr pClip;
279	BoxPtr pbox;
280	int nbox;
281	int xoff, yoff;
282	int bpp = pDrawable->bitsPerPixel;
283
284	/* Don't bother with under 8bpp, XYPixmaps. */
285	if (format != ZPixmap || bpp < 8)
286		return FALSE;
287
288	if (uxa_screen->swappedOut || uxa_screen->force_fallback)
289		return FALSE;
290
291	if (!uxa_screen->info->put_image)
292		return FALSE;
293
294	/* Only accelerate copies: no rop or planemask. */
295	if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
296		return FALSE;
297
298	pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
299	if (!pPix)
300		return FALSE;
301
302	x += pDrawable->x;
303	y += pDrawable->y;
304
305	pClip = fbGetCompositeClip(pGC);
306	for (nbox = REGION_NUM_RECTS(pClip),
307	     pbox = REGION_RECTS(pClip); nbox--; pbox++) {
308		int x1 = x;
309		int y1 = y;
310		int x2 = x + w;
311		int y2 = y + h;
312		char *src;
313		Bool ok;
314
315		if (x1 < pbox->x1)
316			x1 = pbox->x1;
317		if (y1 < pbox->y1)
318			y1 = pbox->y1;
319		if (x2 > pbox->x2)
320			x2 = pbox->x2;
321		if (y2 > pbox->y2)
322			y2 = pbox->y2;
323		if (x1 >= x2 || y1 >= y2)
324			continue;
325
326		src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
327		ok = uxa_screen->info->put_image(pPix, x1 + xoff, y1 + yoff,
328						 x2 - x1, y2 - y1, src,
329						 src_stride);
330		/* If we fail to accelerate the upload, fall back to using
331		 * unaccelerated fb calls.
332		 */
333		if (!ok) {
334			FbStip *dst;
335			FbStride dst_stride;
336			int dstBpp;
337			int dstXoff, dstYoff;
338
339			if (!uxa_prepare_access(pDrawable, NULL, UXA_ACCESS_RW))
340				return FALSE;
341
342			fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
343					  dstXoff, dstYoff);
344
345			fbBltStip((FbStip *) bits +
346				  (y1 - y) * (src_stride / sizeof(FbStip)),
347				  src_stride / sizeof(FbStip),
348				  (x1 - x) * dstBpp,
349				  dst + (y1 + dstYoff) * dst_stride, dst_stride,
350				  (x1 + dstXoff) * dstBpp, (x2 - x1) * dstBpp,
351				  y2 - y1, GXcopy, FB_ALLONES, dstBpp);
352
353			uxa_finish_access(pDrawable);
354		}
355	}
356
357
358	return TRUE;
359}
360
361static void
362uxa_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
363	      int w, int h, int leftPad, int format, char *bits)
364{
365	if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits,
366			      PixmapBytePad(w, pDrawable->depth))) {
367		uxa_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad,
368				    format, bits);
369	}
370}
371
372static Bool inline
373uxa_copy_n_to_n_two_dir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
374			GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
375{
376	uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
377	PixmapPtr pSrcPixmap, pDstPixmap;
378	int src_off_x, src_off_y, dst_off_x, dst_off_y;
379	int dirsetup;
380
381	/* Need to get both pixmaps to call the driver routines */
382	pSrcPixmap =
383	    uxa_get_offscreen_pixmap(pSrcDrawable, &src_off_x, &src_off_y);
384	pDstPixmap =
385	    uxa_get_offscreen_pixmap(pDstDrawable, &dst_off_x, &dst_off_y);
386	if (!pSrcPixmap || !pDstPixmap)
387		return FALSE;
388
389	/*
390	 * Now the case of a chip that only supports xdir = ydir = 1 or
391	 * xdir = ydir = -1, but we have xdir != ydir.
392	 */
393	dirsetup = 0;		/* No direction set up yet. */
394	for (; nbox; pbox++, nbox--) {
395		if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
396			/* Do a xdir = ydir = -1 blit instead. */
397			if (dirsetup != -1) {
398				if (dirsetup != 0)
399					uxa_screen->info->done_copy(pDstPixmap);
400				dirsetup = -1;
401				if (!(*uxa_screen->info->prepare_copy)
402				    (pSrcPixmap, pDstPixmap, -1, -1,
403				     pGC ? pGC->alu : GXcopy,
404				     pGC ? pGC->planemask : FB_ALLONES))
405					return FALSE;
406			}
407			(*uxa_screen->info->copy) (pDstPixmap,
408						   src_off_x + pbox->x1 + dx,
409						   src_off_y + pbox->y1 + dy,
410						   dst_off_x + pbox->x1,
411						   dst_off_y + pbox->y1,
412						   pbox->x2 - pbox->x1,
413						   pbox->y2 - pbox->y1);
414		} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
415			/* Do a xdir = ydir = 1 blit instead. */
416			if (dirsetup != 1) {
417				if (dirsetup != 0)
418					uxa_screen->info->done_copy(pDstPixmap);
419				dirsetup = 1;
420				if (!(*uxa_screen->info->prepare_copy)
421				    (pSrcPixmap, pDstPixmap, 1, 1,
422				     pGC ? pGC->alu : GXcopy,
423				     pGC ? pGC->planemask : FB_ALLONES))
424					return FALSE;
425			}
426			(*uxa_screen->info->copy) (pDstPixmap,
427						   src_off_x + pbox->x1 + dx,
428						   src_off_y + pbox->y1 + dy,
429						   dst_off_x + pbox->x1,
430						   dst_off_y + pbox->y1,
431						   pbox->x2 - pbox->x1,
432						   pbox->y2 - pbox->y1);
433		} else if (dx >= 0) {
434			/*
435			 * xdir = 1, ydir = -1.
436			 * Perform line-by-line xdir = ydir = 1 blits, going up.
437			 */
438			int i;
439			if (dirsetup != 1) {
440				if (dirsetup != 0)
441					uxa_screen->info->done_copy(pDstPixmap);
442				dirsetup = 1;
443				if (!(*uxa_screen->info->prepare_copy)
444				    (pSrcPixmap, pDstPixmap, 1, 1,
445				     pGC ? pGC->alu : GXcopy,
446				     pGC ? pGC->planemask : FB_ALLONES))
447					return FALSE;
448			}
449			for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
450				(*uxa_screen->info->copy) (pDstPixmap,
451							   src_off_x +
452							   pbox->x1 + dx,
453							   src_off_y +
454							   pbox->y1 + dy + i,
455							   dst_off_x + pbox->x1,
456							   dst_off_y +
457							   pbox->y1 + i,
458							   pbox->x2 - pbox->x1,
459							   1);
460		} else {
461			/*
462			 * xdir = -1, ydir = 1.
463			 * Perform line-by-line xdir = ydir = -1 blits,
464			 * going down.
465			 */
466			int i;
467			if (dirsetup != -1) {
468				if (dirsetup != 0)
469					uxa_screen->info->done_copy(pDstPixmap);
470				dirsetup = -1;
471				if (!(*uxa_screen->info->prepare_copy)
472				    (pSrcPixmap, pDstPixmap, -1, -1,
473				     pGC ? pGC->alu : GXcopy,
474				     pGC ? pGC->planemask : FB_ALLONES))
475					return FALSE;
476			}
477			for (i = 0; i < pbox->y2 - pbox->y1; i++)
478				(*uxa_screen->info->copy) (pDstPixmap,
479							   src_off_x +
480							   pbox->x1 + dx,
481							   src_off_y +
482							   pbox->y1 + dy + i,
483							   dst_off_x + pbox->x1,
484							   dst_off_y +
485							   pbox->y1 + i,
486							   pbox->x2 - pbox->x1,
487							   1);
488		}
489	}
490	if (dirsetup != 0)
491		uxa_screen->info->done_copy(pDstPixmap);
492	return TRUE;
493}
494
495void
496uxa_copy_n_to_n(DrawablePtr pSrcDrawable,
497		DrawablePtr pDstDrawable,
498		GCPtr pGC,
499		BoxPtr pbox,
500		int nbox,
501		int dx,
502		int dy,
503		Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
504{
505	ScreenPtr screen = pDstDrawable->pScreen;
506	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
507	int src_off_x, src_off_y;
508	int dst_off_x, dst_off_y;
509	PixmapPtr pSrcPixmap, pDstPixmap;
510	RegionRec src_region;
511	RegionRec dst_region;
512
513	pSrcPixmap = uxa_get_drawable_pixmap(pSrcDrawable);
514	pDstPixmap = uxa_get_drawable_pixmap(pDstDrawable);
515	if (!pSrcPixmap || !pDstPixmap)
516		goto fallback;
517
518	if (uxa_screen->info->check_copy &&
519	    !uxa_screen->info->check_copy(pSrcPixmap, pDstPixmap,
520					  pGC ? pGC->alu : GXcopy,
521					  pGC ? pGC->planemask : FB_ALLONES))
522		goto fallback;
523
524	uxa_get_drawable_deltas(pSrcDrawable, pSrcPixmap, &src_off_x,
525				&src_off_y);
526	uxa_get_drawable_deltas(pDstDrawable, pDstPixmap, &dst_off_x,
527				&dst_off_y);
528
529	/* Mixed directions must be handled specially if the card is lame */
530	if ((uxa_screen->info->flags & UXA_TWO_BITBLT_DIRECTIONS) &&
531	    reverse != upsidedown) {
532		if (uxa_copy_n_to_n_two_dir
533		    (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy))
534			return;
535		goto fallback;
536	}
537
538	if (!uxa_pixmap_is_offscreen(pDstPixmap))
539	    goto fallback;
540
541	if (uxa_pixmap_is_offscreen(pSrcPixmap)) {
542	    if (!(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap,
543						reverse ? -1 : 1,
544						upsidedown ? -1 : 1,
545						pGC ? pGC->alu : GXcopy,
546						pGC ? pGC->
547						planemask : FB_ALLONES))
548		goto fallback;
549
550	    while (nbox--) {
551		(*uxa_screen->info->copy) (pDstPixmap,
552					   pbox->x1 + dx + src_off_x,
553					   pbox->y1 + dy + src_off_y,
554					   pbox->x1 + dst_off_x,
555					   pbox->y1 + dst_off_y,
556					   pbox->x2 - pbox->x1,
557					   pbox->y2 - pbox->y1);
558		pbox++;
559	    }
560
561	    (*uxa_screen->info->done_copy) (pDstPixmap);
562	} else {
563	    int stride, bpp;
564	    char *src;
565
566	    if (!uxa_screen->info->put_image)
567		goto fallback;
568
569	    /* Don't bother with under 8bpp, XYPixmaps. */
570	    bpp = pSrcPixmap->drawable.bitsPerPixel;
571	    if (bpp != pDstDrawable->bitsPerPixel || bpp < 8)
572		goto fallback;
573
574	    /* Only accelerate copies: no rop or planemask. */
575	    if (pGC && (!UXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask) || pGC->alu != GXcopy))
576		goto fallback;
577
578	    src = pSrcPixmap->devPrivate.ptr;
579	    stride = pSrcPixmap->devKind;
580	    bpp /= 8;
581	    while (nbox--) {
582		if (!uxa_screen->info->put_image(pDstPixmap,
583						 pbox->x1 + dst_off_x,
584						 pbox->y1 + dst_off_y,
585						 pbox->x2 - pbox->x1,
586						 pbox->y2 - pbox->y1,
587						 (char *) src +
588						 (pbox->y1 + dy + src_off_y) * stride +
589						 (pbox->x1 + dx + src_off_x) * bpp,
590						 stride))
591		    goto fallback;
592
593		pbox++;
594	    }
595	}
596
597	return;
598
599fallback:
600#if 0
601	ErrorF ("falling back: %d boxes\n", nbox);
602#endif
603
604	pixman_region_init_rects (&dst_region, pbox, nbox);
605	REGION_INIT (NULL, &src_region, (BoxPtr)NULL, 0);
606	REGION_COPY (NULL, &src_region, &dst_region);
607	REGION_TRANSLATE (NULL, &src_region, dx, dy);
608
609	UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
610		      uxa_drawable_location(pSrcDrawable),
611		      uxa_drawable_location(pDstDrawable)));
612	if (uxa_prepare_access(pDstDrawable, &dst_region, UXA_ACCESS_RW))
613	{
614	    if (uxa_prepare_access(pSrcDrawable, &src_region, UXA_ACCESS_RO))
615	    {
616		fbCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
617			   dx, dy, reverse, upsidedown, bitplane,
618			   closure);
619
620		uxa_finish_access(pSrcDrawable);
621	    }
622
623	    uxa_finish_access(pDstDrawable);
624	}
625
626	REGION_UNINIT (NULL, &src_region);
627	REGION_UNINIT (NULL, &dst_region);
628}
629
630RegionPtr
631uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
632	      int srcx, int srcy, int width, int height, int dstx, int dsty)
633{
634	uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
635
636	if (uxa_screen->swappedOut || uxa_screen->force_fallback) {
637		return uxa_check_copy_area(pSrcDrawable, pDstDrawable, pGC,
638					   srcx, srcy, width, height, dstx,
639					   dsty);
640	}
641
642	return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
643			srcx, srcy, width, height,
644			dstx, dsty, uxa_copy_n_to_n, 0, NULL);
645}
646
647static void
648uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
649	       DDXPointPtr ppt)
650{
651	int i;
652	xRectangle *prect;
653
654	/* If we can't reuse the current GC as is, don't bother accelerating the
655	 * points.
656	 */
657	if (pGC->fillStyle != FillSolid) {
658		uxa_check_poly_point(pDrawable, pGC, mode, npt, ppt);
659		return;
660	}
661
662	prect = malloc(sizeof(xRectangle) * npt);
663	if (!prect)
664		return;
665	for (i = 0; i < npt; i++) {
666		prect[i].x = ppt[i].x;
667		prect[i].y = ppt[i].y;
668		if (i > 0 && mode == CoordModePrevious) {
669			prect[i].x += prect[i - 1].x;
670			prect[i].y += prect[i - 1].y;
671		}
672		prect[i].width = 1;
673		prect[i].height = 1;
674	}
675	pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
676	free(prect);
677}
678
679/**
680 * uxa_poly_lines() checks if it can accelerate the lines as a group of
681 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
682 * acceleration if so.
683 */
684static void
685uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
686	       DDXPointPtr ppt)
687{
688	xRectangle *prect;
689	int x1, x2, y1, y2;
690	int i;
691
692	/* Don't try to do wide lines or non-solid fill style. */
693	if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
694	    pGC->fillStyle != FillSolid) {
695		uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
696		return;
697	}
698
699	prect = malloc(sizeof(xRectangle) * (npt - 1));
700	if (!prect)
701		return;
702	x1 = ppt[0].x;
703	y1 = ppt[0].y;
704	/* If we have any non-horizontal/vertical, fall back. */
705	for (i = 0; i < npt - 1; i++) {
706		if (mode == CoordModePrevious) {
707			x2 = x1 + ppt[i + 1].x;
708			y2 = y1 + ppt[i + 1].y;
709		} else {
710			x2 = ppt[i + 1].x;
711			y2 = ppt[i + 1].y;
712		}
713
714		if (x1 != x2 && y1 != y2) {
715			free(prect);
716			uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
717			return;
718		}
719
720		if (x1 < x2) {
721			prect[i].x = x1;
722			prect[i].width = x2 - x1 + 1;
723		} else {
724			prect[i].x = x2;
725			prect[i].width = x1 - x2 + 1;
726		}
727		if (y1 < y2) {
728			prect[i].y = y1;
729			prect[i].height = y2 - y1 + 1;
730		} else {
731			prect[i].y = y2;
732			prect[i].height = y1 - y2 + 1;
733		}
734
735		x1 = x2;
736		y1 = y2;
737	}
738	pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
739	free(prect);
740}
741
742/**
743 * uxa_poly_segment() checks if it can accelerate the lines as a group of
744 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
745 * acceleration if so.
746 */
747static void
748uxa_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg)
749{
750	xRectangle *prect;
751	int i;
752
753	/* Don't try to do wide lines or non-solid fill style. */
754	if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
755	    pGC->fillStyle != FillSolid) {
756		uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
757		return;
758	}
759
760	/* If we have any non-horizontal/vertical, fall back. */
761	for (i = 0; i < nseg; i++) {
762		if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
763			uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
764			return;
765		}
766	}
767
768	prect = malloc(sizeof(xRectangle) * nseg);
769	if (!prect)
770		return;
771	for (i = 0; i < nseg; i++) {
772		if (pSeg[i].x1 < pSeg[i].x2) {
773			prect[i].x = pSeg[i].x1;
774			prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
775		} else {
776			prect[i].x = pSeg[i].x2;
777			prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
778		}
779		if (pSeg[i].y1 < pSeg[i].y2) {
780			prect[i].y = pSeg[i].y1;
781			prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
782		} else {
783			prect[i].y = pSeg[i].y2;
784			prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
785		}
786
787		/* don't paint last pixel */
788		if (pGC->capStyle == CapNotLast) {
789			if (prect[i].width == 1)
790				prect[i].height--;
791			else
792				prect[i].width--;
793		}
794	}
795	pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
796	free(prect);
797}
798
799static Bool uxa_fill_region_solid(DrawablePtr pDrawable, RegionPtr pRegion,
800				  Pixel pixel, CARD32 planemask, CARD32 alu);
801
802static void
803uxa_poly_fill_rect(DrawablePtr pDrawable,
804		   GCPtr pGC, int nrect, xRectangle * prect)
805{
806	uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
807	RegionPtr pClip = fbGetCompositeClip(pGC);
808	PixmapPtr pPixmap;
809	register BoxPtr pbox;
810	BoxPtr pextent;
811	int extentX1, extentX2, extentY1, extentY2;
812	int fullX1, fullX2, fullY1, fullY2;
813	int partX1, partX2, partY1, partY2;
814	int xoff, yoff;
815	int xorg, yorg;
816	int n;
817	RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
818
819	/* Compute intersection of rects and clip region */
820	REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
821	REGION_INTERSECT(pScreen, pReg, pClip, pReg);
822
823	if (!REGION_NUM_RECTS(pReg))
824		goto out;
825
826	if (uxa_screen->swappedOut || uxa_screen->force_fallback)
827		goto fallback;
828
829	pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
830	if (!pPixmap)
831		goto fallback;
832
833	/* For ROPs where overlaps don't matter, convert rectangles to region
834	 * and call uxa_fill_region_{solid,tiled}.
835	 */
836	if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
837	    (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
838	     pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
839	     pGC->alu == GXset)) {
840		if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
841		     uxa_fill_region_solid(pDrawable, pReg,
842					   pGC->fillStyle ==
843					   FillSolid ? pGC->fgPixel : pGC->tile.
844					   pixel, pGC->planemask, pGC->alu))
845		    || (pGC->fillStyle == FillTiled && !pGC->tileIsPixel
846			&& uxa_fill_region_tiled(pDrawable, pReg,
847						 pGC->tile.pixmap, &pGC->patOrg,
848						 pGC->planemask, pGC->alu))) {
849			goto out;
850		}
851	}
852
853	if (pGC->fillStyle != FillSolid &&
854	    !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) {
855		goto fallback;
856	}
857
858	if (uxa_screen->info->check_solid &&
859	    !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask)) {
860		goto fallback;
861	}
862
863	if (!(*uxa_screen->info->prepare_solid) (pPixmap,
864						 pGC->alu,
865						 pGC->planemask,
866						 pGC->fgPixel)) {
867fallback:
868		uxa_check_poly_fill_rect(pDrawable, pGC, nrect, prect);
869		goto out;
870	}
871
872	xorg = pDrawable->x;
873	yorg = pDrawable->y;
874
875	pextent = REGION_EXTENTS(pGC->pScreen, pClip);
876	extentX1 = pextent->x1;
877	extentY1 = pextent->y1;
878	extentX2 = pextent->x2;
879	extentY2 = pextent->y2;
880	while (nrect--) {
881		fullX1 = prect->x + xorg;
882		fullY1 = prect->y + yorg;
883		fullX2 = fullX1 + (int)prect->width;
884		fullY2 = fullY1 + (int)prect->height;
885		prect++;
886
887		if (fullX1 < extentX1)
888			fullX1 = extentX1;
889
890		if (fullY1 < extentY1)
891			fullY1 = extentY1;
892
893		if (fullX2 > extentX2)
894			fullX2 = extentX2;
895
896		if (fullY2 > extentY2)
897			fullY2 = extentY2;
898
899		if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
900			continue;
901		n = REGION_NUM_RECTS(pClip);
902		if (n == 1) {
903			(*uxa_screen->info->solid) (pPixmap,
904						    fullX1 + xoff,
905						    fullY1 + yoff,
906						    fullX2 + xoff,
907						    fullY2 + yoff);
908		} else {
909			pbox = REGION_RECTS(pClip);
910			/*
911			 * clip the rectangle to each box in the clip region
912			 * this is logically equivalent to calling Intersect(),
913			 * but rectangles may overlap each other here.
914			 */
915			while (n--) {
916				partX1 = pbox->x1;
917				if (partX1 < fullX1)
918					partX1 = fullX1;
919				partY1 = pbox->y1;
920				if (partY1 < fullY1)
921					partY1 = fullY1;
922				partX2 = pbox->x2;
923				if (partX2 > fullX2)
924					partX2 = fullX2;
925				partY2 = pbox->y2;
926				if (partY2 > fullY2)
927					partY2 = fullY2;
928
929				pbox++;
930
931				if (partX1 < partX2 && partY1 < partY2) {
932					(*uxa_screen->info->solid) (pPixmap,
933								    partX1 +
934								    xoff,
935								    partY1 +
936								    yoff,
937								    partX2 +
938								    xoff,
939								    partY2 +
940								    yoff);
941				}
942			}
943		}
944	}
945	(*uxa_screen->info->done_solid) (pPixmap);
946
947out:
948	REGION_UNINIT(pScreen, pReg);
949	REGION_DESTROY(pScreen, pReg);
950}
951
952GCOps uxa_ops = {
953	uxa_fill_spans,
954	uxa_check_set_spans,
955	uxa_put_image,
956	uxa_copy_area,
957	uxa_check_copy_plane,
958	uxa_poly_point,
959	uxa_poly_lines,
960	uxa_poly_segment,
961	miPolyRectangle,
962	uxa_check_poly_arc,
963	miFillPolygon,
964	uxa_poly_fill_rect,
965	miPolyFillArc,
966	miPolyText8,
967	miPolyText16,
968	miImageText8,
969	miImageText16,
970	uxa_check_image_glyph_blt,
971	uxa_check_poly_glyph_blt,
972	uxa_check_push_pixels,
973};
974
975void uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
976{
977	RegionRec rgnDst;
978	int dx, dy;
979	PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
980
981	dx = ptOldOrg.x - pWin->drawable.x;
982	dy = ptOldOrg.y - pWin->drawable.y;
983	REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
984
985	REGION_INIT(pWin->drawable.pScreen, &rgnDst, NullBox, 0);
986
987	REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip,
988			 prgnSrc);
989#ifdef COMPOSITE
990	if (pPixmap->screen_x || pPixmap->screen_y)
991		REGION_TRANSLATE(pWin->drawable.pScreen, &rgnDst,
992				 -pPixmap->screen_x, -pPixmap->screen_y);
993#endif
994
995	miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
996		     NULL, &rgnDst, dx, dy, uxa_copy_n_to_n, 0, NULL);
997
998	REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
999}
1000
1001static Bool
1002uxa_fill_region_solid(DrawablePtr pDrawable,
1003		      RegionPtr pRegion,
1004		      Pixel pixel, CARD32 planemask, CARD32 alu)
1005{
1006	ScreenPtr screen = pDrawable->pScreen;
1007	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1008	PixmapPtr pixmap;
1009	int xoff, yoff;
1010	int nbox;
1011	BoxPtr pBox, extents;
1012	Bool ret = FALSE;
1013
1014	pixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
1015	if (!pixmap)
1016		return FALSE;
1017
1018	REGION_TRANSLATE(screen, pRegion, xoff, yoff);
1019
1020	nbox = REGION_NUM_RECTS(pRegion);
1021	pBox = REGION_RECTS(pRegion);
1022	extents = REGION_EXTENTS(screen, pRegion);
1023
1024	/* Using GEM, the relocation costs outweigh the advantages of the blitter */
1025	if (nbox == 1 || (alu != GXcopy && alu != GXclear) || planemask != FB_ALLONES) {
1026try_solid:
1027		if (uxa_screen->info->check_solid &&
1028		    !uxa_screen->info->check_solid(&pixmap->drawable, alu, planemask))
1029			goto err;
1030
1031		if (!uxa_screen->info->prepare_solid(pixmap, alu, planemask, pixel))
1032			goto err;
1033
1034		while (nbox--) {
1035			uxa_screen->info->solid(pixmap,
1036						pBox->x1, pBox->y1,
1037						pBox->x2, pBox->y2);
1038			pBox++;
1039		}
1040
1041		uxa_screen->info->done_solid(pixmap);
1042	} else {
1043		PicturePtr dst, src;
1044		PixmapPtr src_pixmap = NULL;
1045		xRenderColor color;
1046		int error;
1047
1048		dst = CreatePicture(0, &pixmap->drawable,
1049				    PictureMatchFormat(screen,
1050						       pixmap->drawable.depth,
1051						       format_for_depth(pixmap->drawable.depth)),
1052				    0, 0, serverClient, &error);
1053		if (!dst)
1054			goto err;
1055
1056		ValidatePicture(dst);
1057
1058		uxa_get_rgba_from_pixel(pixel,
1059					&color.red,
1060					&color.green,
1061					&color.blue,
1062					&color.alpha,
1063					format_for_depth(pixmap->drawable.depth));
1064		src = CreateSolidPicture(0, &color, &error);
1065		if (!src) {
1066			FreePicture(dst, 0);
1067			goto err;
1068		}
1069
1070		if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst,
1071						       extents->x2 - extents->x1,
1072						       extents->y2 - extents->y1)) {
1073			FreePicture(src, 0);
1074			FreePicture(dst, 0);
1075			goto try_solid;
1076		}
1077
1078		if (!uxa_screen->info->check_composite_texture ||
1079		    !uxa_screen->info->check_composite_texture(screen, src)) {
1080			PicturePtr solid;
1081			int src_off_x, src_off_y;
1082
1083			solid = uxa_acquire_solid(screen, src->pSourcePict);
1084			FreePicture(src, 0);
1085
1086			src = solid;
1087			src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable,
1088							      &src_off_x, &src_off_y);
1089			if (!src_pixmap) {
1090				FreePicture(src, 0);
1091				FreePicture(dst, 0);
1092				goto err;
1093			}
1094		}
1095
1096		if (!uxa_screen->info->prepare_composite(PictOpSrc, src, NULL, dst, src_pixmap, NULL, pixmap)) {
1097			FreePicture(src, 0);
1098			FreePicture(dst, 0);
1099			goto err;
1100		}
1101
1102		while (nbox--) {
1103			uxa_screen->info->composite(pixmap,
1104						    0, 0, 0, 0,
1105						    pBox->x1,
1106						    pBox->y1,
1107						    pBox->x2 - pBox->x1,
1108						    pBox->y2 - pBox->y1);
1109			pBox++;
1110		}
1111
1112		uxa_screen->info->done_composite(pixmap);
1113		FreePicture(src, 0);
1114		FreePicture(dst, 0);
1115	}
1116
1117	ret = TRUE;
1118
1119err:
1120	REGION_TRANSLATE(screen, pRegion, -xoff, -yoff);
1121	return ret;
1122}
1123
1124/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1125 * Based on fbFillRegionTiled(), fbTile().
1126 */
1127Bool
1128uxa_fill_region_tiled(DrawablePtr pDrawable,
1129		      RegionPtr pRegion,
1130		      PixmapPtr pTile,
1131		      DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu)
1132{
1133	uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
1134	PixmapPtr pPixmap;
1135	int xoff, yoff;
1136	int tileWidth, tileHeight;
1137	int nbox = REGION_NUM_RECTS(pRegion);
1138	BoxPtr pBox = REGION_RECTS(pRegion);
1139	Bool ret = FALSE;
1140	int i;
1141	tileWidth = pTile->drawable.width;
1142	tileHeight = pTile->drawable.height;
1143
1144	/* If we're filling with a solid color, grab it out and go to
1145	 * FillRegionsolid, saving numerous copies.
1146	 */
1147	if (tileWidth == 1 && tileHeight == 1)
1148		return uxa_fill_region_solid(pDrawable, pRegion,
1149					     uxa_get_pixmap_first_pixel(pTile),
1150					     planemask, alu);
1151
1152	pPixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
1153	if (!pPixmap || !uxa_pixmap_is_offscreen(pTile))
1154		goto out;
1155
1156	if (uxa_screen->info->check_copy &&
1157	    !uxa_screen->info->check_copy(pTile, pPixmap, alu, planemask))
1158		return FALSE;
1159
1160
1161	if ((*uxa_screen->info->prepare_copy) (pTile, pPixmap, 1, 1, alu,
1162					       planemask)) {
1163		if (xoff || yoff)
1164			REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
1165
1166		  for (i = 0; i < nbox; i++) {
1167			int height = pBox[i].y2 - pBox[i].y1;
1168			int dstY = pBox[i].y1;
1169			int tileY;
1170
1171			if (alu == GXcopy)
1172			    height = min(height, tileHeight);
1173
1174			modulus(dstY - yoff - pDrawable->y - pPatOrg->y,
1175				tileHeight, tileY);
1176
1177			while (height > 0) {
1178				int width = pBox[i].x2 - pBox[i].x1;
1179				int dstX = pBox[i].x1;
1180				int tileX;
1181				int h = tileHeight - tileY;
1182
1183				if (alu == GXcopy)
1184				    width = min(width, tileWidth);
1185				if (h > height)
1186					h = height;
1187				height -= h;
1188
1189				modulus(dstX - xoff - pDrawable->x - pPatOrg->x,
1190					tileWidth, tileX);
1191
1192				while (width > 0) {
1193					int w = tileWidth - tileX;
1194					if (w > width)
1195						w = width;
1196					width -= w;
1197
1198					(*uxa_screen->info->copy) (pPixmap,
1199								   tileX, tileY,
1200								   dstX, dstY,
1201								   w, h);
1202					dstX += w;
1203					tileX = 0;
1204				}
1205				dstY += h;
1206				tileY = 0;
1207			}
1208		}
1209		(*uxa_screen->info->done_copy) (pPixmap);
1210
1211		if (alu != GXcopy)
1212			ret = TRUE;
1213		else {
1214			Bool more_copy = FALSE;
1215
1216			for (i = 0; i < nbox; i++) {
1217				int dstX = pBox[i].x1 + tileWidth;
1218				int dstY = pBox[i].y1 + tileHeight;
1219
1220				if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
1221					more_copy = TRUE;
1222					break;
1223				}
1224			}
1225
1226			if (more_copy == FALSE)
1227				ret = TRUE;
1228
1229			if (more_copy && (*uxa_screen->info->prepare_copy) (pPixmap, pPixmap, 1, 1, alu, planemask)) {
1230				for (i = 0; i < nbox; i++) {
1231					int dstX = pBox[i].x1 + tileWidth;
1232					int dstY = pBox[i].y1 + tileHeight;
1233					int width = min(pBox[i].x2 - dstX, tileWidth);
1234					int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
1235
1236					while (dstX < pBox[i].x2) {
1237						(*uxa_screen->info->copy) (pPixmap,
1238									   pBox[i].x1, pBox[i].y1,
1239									   dstX, pBox[i].y1,
1240									   width, height);
1241						dstX += width;
1242						width = min(pBox[i].x2 - dstX, width * 2);
1243					}
1244
1245					width = pBox[i].x2 - pBox[i].x1;
1246					height = min(pBox[i].y2 - dstY, tileHeight);
1247
1248					while (dstY < pBox[i].y2) {
1249						(*uxa_screen->info->copy) (pPixmap,
1250									   pBox[i].x1, pBox[i].y1,
1251									   pBox[i].x1, dstY,
1252									   width, height);
1253						dstY += height;
1254						height = min(pBox[i].y2 - dstY, height * 2);
1255					}
1256				}
1257				(*uxa_screen->info->done_copy) (pPixmap);
1258				ret = TRUE;
1259			}
1260		}
1261
1262		if (xoff || yoff)
1263			REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
1264
1265	}
1266
1267out:
1268
1269	return ret;
1270}
1271
1272/**
1273 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1274 *
1275 * This is probably the only case we actually care about.  The rest fall through
1276 * to migration and fbGetImage, which hopefully will result in migration pushing
1277 * the pixmap out of framebuffer.
1278 */
1279void
1280uxa_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
1281	      unsigned int format, unsigned long planeMask, char *d)
1282{
1283	ScreenPtr screen = pDrawable->pScreen;
1284	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1285	BoxRec Box;
1286	PixmapPtr pPix = uxa_get_drawable_pixmap(pDrawable);
1287	int xoff, yoff;
1288	Bool ok;
1289	RegionRec region;
1290
1291	uxa_get_drawable_deltas(pDrawable, pPix, &xoff, &yoff);
1292
1293	Box.x1 = pDrawable->y + x + xoff;
1294	Box.y1 = pDrawable->y + y + yoff;
1295	Box.x2 = Box.x1 + w;
1296	Box.y2 = Box.y1 + h;
1297
1298	if (uxa_screen->swappedOut || uxa_screen->force_fallback)
1299		goto fallback;
1300
1301	pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
1302
1303	if (pPix == NULL || uxa_screen->info->get_image == NULL)
1304		goto fallback;
1305
1306	/* Only cover the ZPixmap, solid copy case. */
1307	if (format != ZPixmap || !UXA_PM_IS_SOLID(pDrawable, planeMask))
1308		goto fallback;
1309
1310	/* Only try to handle the 8bpp and up cases, since we don't want to
1311	 * think about <8bpp.
1312	 */
1313	if (pDrawable->bitsPerPixel < 8)
1314		goto fallback;
1315
1316	ok = uxa_screen->info->get_image(pPix, pDrawable->x + x + xoff,
1317					 pDrawable->y + y + yoff, w, h, d,
1318					 PixmapBytePad(w, pDrawable->depth));
1319	if (ok)
1320		return;
1321
1322fallback:
1323	UXA_FALLBACK(("from %p (%c)\n", pDrawable,
1324		      uxa_drawable_location(pDrawable)));
1325
1326	REGION_INIT(screen, &region, &Box, 1);
1327
1328	if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RO)) {
1329		fbGetImage(pDrawable, x, y, w, h, format, planeMask, d);
1330		uxa_finish_access(pDrawable);
1331	}
1332
1333	REGION_UNINIT(screen, &region);
1334
1335	return;
1336}
1337