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