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