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