1428d7b3dSmrg
2428d7b3dSmrg/*
3428d7b3dSmrg * Copyright ® 2001 Keith Packard
4428d7b3dSmrg *
5428d7b3dSmrg * Partly based on code that is Copyright ® The XFree86 Project Inc.
6428d7b3dSmrg *
7428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
8428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
9428d7b3dSmrg * the above copyright notice appear in all copies and that both that
10428d7b3dSmrg * copyright notice and this permission notice appear in supporting
11428d7b3dSmrg * documentation, and that the name of Keith Packard not be used in
12428d7b3dSmrg * advertising or publicity pertaining to distribution of the software without
13428d7b3dSmrg * specific, written prior permission.  Keith Packard makes no
14428d7b3dSmrg * representations about the suitability of this software for any purpose.  It
15428d7b3dSmrg * is provided "as is" without express or implied warranty.
16428d7b3dSmrg *
17428d7b3dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18428d7b3dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19428d7b3dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20428d7b3dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21428d7b3dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22428d7b3dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23428d7b3dSmrg * PERFORMANCE OF THIS SOFTWARE.
24428d7b3dSmrg *
25428d7b3dSmrg * Authors:
26428d7b3dSmrg *    Eric Anholt <eric@anholt.net>
27428d7b3dSmrg *    Michel Dänzer <michel@tungstengraphics.com>
28428d7b3dSmrg *
29428d7b3dSmrg */
30428d7b3dSmrg
31428d7b3dSmrg#ifdef HAVE_DIX_CONFIG_H
32428d7b3dSmrg#include <dix-config.h>
33428d7b3dSmrg#endif
34428d7b3dSmrg#include "uxa-priv.h"
35428d7b3dSmrg#include <X11/fonts/fontstruct.h>
36428d7b3dSmrg#include "dixfontstr.h"
37428d7b3dSmrg#include "uxa.h"
38428d7b3dSmrg
39428d7b3dSmrgstatic void
40428d7b3dSmrguxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n,
41428d7b3dSmrg	       DDXPointPtr ppt, int *pwidth, int fSorted)
42428d7b3dSmrg{
43428d7b3dSmrg	ScreenPtr screen = pDrawable->pScreen;
44428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
45428d7b3dSmrg	RegionPtr pClip = fbGetCompositeClip(pGC);
46428d7b3dSmrg	PixmapPtr dst_pixmap;
47428d7b3dSmrg	BoxPtr pbox;
48428d7b3dSmrg	int nbox;
49428d7b3dSmrg	int x1, x2, y;
50428d7b3dSmrg	int off_x, off_y;
51428d7b3dSmrg
52428d7b3dSmrg	if (uxa_screen->force_fallback)
53428d7b3dSmrg		goto fallback;
54428d7b3dSmrg
55428d7b3dSmrg	if (pGC->fillStyle != FillSolid)
56428d7b3dSmrg		goto fallback;
57428d7b3dSmrg
58428d7b3dSmrg	dst_pixmap = uxa_get_offscreen_pixmap(pDrawable, &off_x, &off_y);
59428d7b3dSmrg	if (!dst_pixmap)
60428d7b3dSmrg		goto fallback;
61428d7b3dSmrg
62428d7b3dSmrg	if (uxa_screen->info->check_solid &&
63428d7b3dSmrg	    !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask))
64428d7b3dSmrg		goto fallback;
65428d7b3dSmrg
66428d7b3dSmrg	if (!(*uxa_screen->info->prepare_solid) (dst_pixmap,
67428d7b3dSmrg						 pGC->alu,
68428d7b3dSmrg						 pGC->planemask,
69428d7b3dSmrg						 pGC->fgPixel))
70428d7b3dSmrg		goto fallback;
71428d7b3dSmrg
72428d7b3dSmrg	while (n--) {
73428d7b3dSmrg		x1 = ppt->x;
74428d7b3dSmrg		y = ppt->y;
75428d7b3dSmrg		x2 = x1 + (int)*pwidth;
76428d7b3dSmrg		ppt++;
77428d7b3dSmrg		pwidth++;
78428d7b3dSmrg
79428d7b3dSmrg		nbox = REGION_NUM_RECTS(pClip);
80428d7b3dSmrg		pbox = REGION_RECTS(pClip);
81428d7b3dSmrg		while (nbox--) {
82428d7b3dSmrg			int X1 = x1, X2 = x2;
83428d7b3dSmrg			if (X1 < pbox->x1)
84428d7b3dSmrg				X1 = pbox->x1;
85428d7b3dSmrg
86428d7b3dSmrg			if (X2 > pbox->x2)
87428d7b3dSmrg				X2 = pbox->x2;
88428d7b3dSmrg
89428d7b3dSmrg			if (X2 > X1 && pbox->y1 <= y && pbox->y2 > y)
90428d7b3dSmrg				(*uxa_screen->info->solid) (dst_pixmap,
91428d7b3dSmrg							    X1 + off_x, y + off_y,
92428d7b3dSmrg							    X2 + off_x, y + 1 + off_y);
93428d7b3dSmrg			pbox++;
94428d7b3dSmrg		}
95428d7b3dSmrg	}
96428d7b3dSmrg	(*uxa_screen->info->done_solid) (dst_pixmap);
97428d7b3dSmrg
98428d7b3dSmrg	return;
99428d7b3dSmrg
100428d7b3dSmrgfallback:
101428d7b3dSmrg	uxa_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted);
102428d7b3dSmrg}
103428d7b3dSmrg
104428d7b3dSmrgstatic Bool
105428d7b3dSmrguxa_do_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
106428d7b3dSmrg		 int w, int h, int format, char *bits, int src_stride)
107428d7b3dSmrg{
108428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
109428d7b3dSmrg	PixmapPtr pPix;
110428d7b3dSmrg	RegionPtr pClip;
111428d7b3dSmrg	BoxPtr pbox;
112428d7b3dSmrg	int nbox;
113428d7b3dSmrg	int xoff, yoff;
114428d7b3dSmrg	int bpp = pDrawable->bitsPerPixel;
115428d7b3dSmrg
116428d7b3dSmrg	/* Don't bother with under 8bpp, XYPixmaps. */
117428d7b3dSmrg	if (format != ZPixmap || bpp < 8)
118428d7b3dSmrg		return FALSE;
119428d7b3dSmrg
120428d7b3dSmrg	if (uxa_screen->force_fallback)
121428d7b3dSmrg		return FALSE;
122428d7b3dSmrg
123428d7b3dSmrg	if (!uxa_screen->info->put_image)
124428d7b3dSmrg		return FALSE;
125428d7b3dSmrg
126428d7b3dSmrg	/* Only accelerate copies: no rop or planemask. */
127428d7b3dSmrg	if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
128428d7b3dSmrg		return FALSE;
129428d7b3dSmrg
130428d7b3dSmrg	pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
131428d7b3dSmrg	if (!pPix)
132428d7b3dSmrg		return FALSE;
133428d7b3dSmrg
134428d7b3dSmrg	x += pDrawable->x;
135428d7b3dSmrg	y += pDrawable->y;
136428d7b3dSmrg
137428d7b3dSmrg	pClip = fbGetCompositeClip(pGC);
138428d7b3dSmrg	for (nbox = REGION_NUM_RECTS(pClip),
139428d7b3dSmrg	     pbox = REGION_RECTS(pClip); nbox--; pbox++) {
140428d7b3dSmrg		int x1 = x;
141428d7b3dSmrg		int y1 = y;
142428d7b3dSmrg		int x2 = x + w;
143428d7b3dSmrg		int y2 = y + h;
144428d7b3dSmrg		char *src;
145428d7b3dSmrg		Bool ok;
146428d7b3dSmrg
147428d7b3dSmrg		if (x1 < pbox->x1)
148428d7b3dSmrg			x1 = pbox->x1;
149428d7b3dSmrg		if (y1 < pbox->y1)
150428d7b3dSmrg			y1 = pbox->y1;
151428d7b3dSmrg		if (x2 > pbox->x2)
152428d7b3dSmrg			x2 = pbox->x2;
153428d7b3dSmrg		if (y2 > pbox->y2)
154428d7b3dSmrg			y2 = pbox->y2;
155428d7b3dSmrg		if (x1 >= x2 || y1 >= y2)
156428d7b3dSmrg			continue;
157428d7b3dSmrg
158428d7b3dSmrg		src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
159428d7b3dSmrg		ok = uxa_screen->info->put_image(pPix, x1 + xoff, y1 + yoff,
160428d7b3dSmrg						 x2 - x1, y2 - y1, src,
161428d7b3dSmrg						 src_stride);
162428d7b3dSmrg		/* If we fail to accelerate the upload, fall back to using
163428d7b3dSmrg		 * unaccelerated fb calls.
164428d7b3dSmrg		 */
165428d7b3dSmrg		if (!ok) {
166428d7b3dSmrg			FbStip *dst;
167428d7b3dSmrg			FbStride dst_stride;
168428d7b3dSmrg			int dstBpp;
169428d7b3dSmrg			int dstXoff, dstYoff;
170428d7b3dSmrg
171428d7b3dSmrg			if (!uxa_prepare_access(pDrawable, UXA_ACCESS_RW))
172428d7b3dSmrg				return FALSE;
173428d7b3dSmrg
174428d7b3dSmrg			fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
175428d7b3dSmrg					  dstXoff, dstYoff);
176428d7b3dSmrg
177428d7b3dSmrg			fbBltStip((FbStip *) bits +
178428d7b3dSmrg				  (y1 - y) * (src_stride / sizeof(FbStip)),
179428d7b3dSmrg				  src_stride / sizeof(FbStip),
180428d7b3dSmrg				  (x1 - x) * dstBpp,
181428d7b3dSmrg				  dst + (y1 + dstYoff) * dst_stride, dst_stride,
182428d7b3dSmrg				  (x1 + dstXoff) * dstBpp, (x2 - x1) * dstBpp,
183428d7b3dSmrg				  y2 - y1, GXcopy, FB_ALLONES, dstBpp);
184428d7b3dSmrg
185428d7b3dSmrg			uxa_finish_access(pDrawable, UXA_ACCESS_RW);
186428d7b3dSmrg		}
187428d7b3dSmrg	}
188428d7b3dSmrg
189428d7b3dSmrg
190428d7b3dSmrg	return TRUE;
191428d7b3dSmrg}
192428d7b3dSmrg
193428d7b3dSmrgstatic void
194428d7b3dSmrguxa_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
195428d7b3dSmrg	      int w, int h, int leftPad, int format, char *bits)
196428d7b3dSmrg{
197428d7b3dSmrg	if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits,
198428d7b3dSmrg			      PixmapBytePad(w, pDrawable->depth))) {
199428d7b3dSmrg		uxa_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad,
200428d7b3dSmrg				    format, bits);
201428d7b3dSmrg	}
202428d7b3dSmrg}
203428d7b3dSmrg
204428d7b3dSmrgstatic inline Bool
205428d7b3dSmrguxa_copy_n_to_n_two_dir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
206428d7b3dSmrg			GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
207428d7b3dSmrg{
208428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
209428d7b3dSmrg	PixmapPtr pSrcPixmap, pDstPixmap;
210428d7b3dSmrg	int src_off_x, src_off_y, dst_off_x, dst_off_y;
211428d7b3dSmrg	int dirsetup;
212428d7b3dSmrg
213428d7b3dSmrg	/* Need to get both pixmaps to call the driver routines */
214428d7b3dSmrg	pSrcPixmap =
215428d7b3dSmrg	    uxa_get_offscreen_pixmap(pSrcDrawable, &src_off_x, &src_off_y);
216428d7b3dSmrg	pDstPixmap =
217428d7b3dSmrg	    uxa_get_offscreen_pixmap(pDstDrawable, &dst_off_x, &dst_off_y);
218428d7b3dSmrg	if (!pSrcPixmap || !pDstPixmap)
219428d7b3dSmrg		return FALSE;
220428d7b3dSmrg
221428d7b3dSmrg	/*
222428d7b3dSmrg	 * Now the case of a chip that only supports xdir = ydir = 1 or
223428d7b3dSmrg	 * xdir = ydir = -1, but we have xdir != ydir.
224428d7b3dSmrg	 */
225428d7b3dSmrg	dirsetup = 0;		/* No direction set up yet. */
226428d7b3dSmrg	for (; nbox; pbox++, nbox--) {
227428d7b3dSmrg		if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
228428d7b3dSmrg			/* Do a xdir = ydir = -1 blit instead. */
229428d7b3dSmrg			if (dirsetup != -1) {
230428d7b3dSmrg				if (dirsetup != 0)
231428d7b3dSmrg					uxa_screen->info->done_copy(pDstPixmap);
232428d7b3dSmrg				dirsetup = -1;
233428d7b3dSmrg				if (!(*uxa_screen->info->prepare_copy)
234428d7b3dSmrg				    (pSrcPixmap, pDstPixmap, -1, -1,
235428d7b3dSmrg				     pGC ? pGC->alu : GXcopy,
236428d7b3dSmrg				     pGC ? pGC->planemask : FB_ALLONES))
237428d7b3dSmrg					return FALSE;
238428d7b3dSmrg			}
239428d7b3dSmrg			(*uxa_screen->info->copy) (pDstPixmap,
240428d7b3dSmrg						   src_off_x + pbox->x1 + dx,
241428d7b3dSmrg						   src_off_y + pbox->y1 + dy,
242428d7b3dSmrg						   dst_off_x + pbox->x1,
243428d7b3dSmrg						   dst_off_y + pbox->y1,
244428d7b3dSmrg						   pbox->x2 - pbox->x1,
245428d7b3dSmrg						   pbox->y2 - pbox->y1);
246428d7b3dSmrg		} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
247428d7b3dSmrg			/* Do a xdir = ydir = 1 blit instead. */
248428d7b3dSmrg			if (dirsetup != 1) {
249428d7b3dSmrg				if (dirsetup != 0)
250428d7b3dSmrg					uxa_screen->info->done_copy(pDstPixmap);
251428d7b3dSmrg				dirsetup = 1;
252428d7b3dSmrg				if (!(*uxa_screen->info->prepare_copy)
253428d7b3dSmrg				    (pSrcPixmap, pDstPixmap, 1, 1,
254428d7b3dSmrg				     pGC ? pGC->alu : GXcopy,
255428d7b3dSmrg				     pGC ? pGC->planemask : FB_ALLONES))
256428d7b3dSmrg					return FALSE;
257428d7b3dSmrg			}
258428d7b3dSmrg			(*uxa_screen->info->copy) (pDstPixmap,
259428d7b3dSmrg						   src_off_x + pbox->x1 + dx,
260428d7b3dSmrg						   src_off_y + pbox->y1 + dy,
261428d7b3dSmrg						   dst_off_x + pbox->x1,
262428d7b3dSmrg						   dst_off_y + pbox->y1,
263428d7b3dSmrg						   pbox->x2 - pbox->x1,
264428d7b3dSmrg						   pbox->y2 - pbox->y1);
265428d7b3dSmrg		} else if (dx >= 0) {
266428d7b3dSmrg			/*
267428d7b3dSmrg			 * xdir = 1, ydir = -1.
268428d7b3dSmrg			 * Perform line-by-line xdir = ydir = 1 blits, going up.
269428d7b3dSmrg			 */
270428d7b3dSmrg			int i;
271428d7b3dSmrg			if (dirsetup != 1) {
272428d7b3dSmrg				if (dirsetup != 0)
273428d7b3dSmrg					uxa_screen->info->done_copy(pDstPixmap);
274428d7b3dSmrg				dirsetup = 1;
275428d7b3dSmrg				if (!(*uxa_screen->info->prepare_copy)
276428d7b3dSmrg				    (pSrcPixmap, pDstPixmap, 1, 1,
277428d7b3dSmrg				     pGC ? pGC->alu : GXcopy,
278428d7b3dSmrg				     pGC ? pGC->planemask : FB_ALLONES))
279428d7b3dSmrg					return FALSE;
280428d7b3dSmrg			}
281428d7b3dSmrg			for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
282428d7b3dSmrg				(*uxa_screen->info->copy) (pDstPixmap,
283428d7b3dSmrg							   src_off_x +
284428d7b3dSmrg							   pbox->x1 + dx,
285428d7b3dSmrg							   src_off_y +
286428d7b3dSmrg							   pbox->y1 + dy + i,
287428d7b3dSmrg							   dst_off_x + pbox->x1,
288428d7b3dSmrg							   dst_off_y +
289428d7b3dSmrg							   pbox->y1 + i,
290428d7b3dSmrg							   pbox->x2 - pbox->x1,
291428d7b3dSmrg							   1);
292428d7b3dSmrg		} else {
293428d7b3dSmrg			/*
294428d7b3dSmrg			 * xdir = -1, ydir = 1.
295428d7b3dSmrg			 * Perform line-by-line xdir = ydir = -1 blits,
296428d7b3dSmrg			 * going down.
297428d7b3dSmrg			 */
298428d7b3dSmrg			int i;
299428d7b3dSmrg			if (dirsetup != -1) {
300428d7b3dSmrg				if (dirsetup != 0)
301428d7b3dSmrg					uxa_screen->info->done_copy(pDstPixmap);
302428d7b3dSmrg				dirsetup = -1;
303428d7b3dSmrg				if (!(*uxa_screen->info->prepare_copy)
304428d7b3dSmrg				    (pSrcPixmap, pDstPixmap, -1, -1,
305428d7b3dSmrg				     pGC ? pGC->alu : GXcopy,
306428d7b3dSmrg				     pGC ? pGC->planemask : FB_ALLONES))
307428d7b3dSmrg					return FALSE;
308428d7b3dSmrg			}
309428d7b3dSmrg			for (i = 0; i < pbox->y2 - pbox->y1; i++)
310428d7b3dSmrg				(*uxa_screen->info->copy) (pDstPixmap,
311428d7b3dSmrg							   src_off_x +
312428d7b3dSmrg							   pbox->x1 + dx,
313428d7b3dSmrg							   src_off_y +
314428d7b3dSmrg							   pbox->y1 + dy + i,
315428d7b3dSmrg							   dst_off_x + pbox->x1,
316428d7b3dSmrg							   dst_off_y +
317428d7b3dSmrg							   pbox->y1 + i,
318428d7b3dSmrg							   pbox->x2 - pbox->x1,
319428d7b3dSmrg							   1);
320428d7b3dSmrg		}
321428d7b3dSmrg	}
322428d7b3dSmrg	if (dirsetup != 0)
323428d7b3dSmrg		uxa_screen->info->done_copy(pDstPixmap);
324428d7b3dSmrg	return TRUE;
325428d7b3dSmrg}
326428d7b3dSmrg
327428d7b3dSmrgvoid
328428d7b3dSmrguxa_copy_n_to_n(DrawablePtr pSrcDrawable,
329428d7b3dSmrg		DrawablePtr pDstDrawable,
330428d7b3dSmrg		GCPtr pGC,
331428d7b3dSmrg		BoxPtr pbox,
332428d7b3dSmrg		int nbox,
333428d7b3dSmrg		int dx,
334428d7b3dSmrg		int dy,
335428d7b3dSmrg		Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
336428d7b3dSmrg{
337428d7b3dSmrg	ScreenPtr screen = pDstDrawable->pScreen;
338428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
339428d7b3dSmrg	int src_off_x, src_off_y;
340428d7b3dSmrg	int dst_off_x, dst_off_y;
341428d7b3dSmrg	PixmapPtr pSrcPixmap, pDstPixmap;
342428d7b3dSmrg
343428d7b3dSmrg	if (uxa_screen->force_fallback)
344428d7b3dSmrg		goto fallback;
345428d7b3dSmrg
346428d7b3dSmrg	pSrcPixmap = uxa_get_drawable_pixmap(pSrcDrawable);
347428d7b3dSmrg	pDstPixmap = uxa_get_drawable_pixmap(pDstDrawable);
348428d7b3dSmrg	if (!pSrcPixmap || !pDstPixmap)
349428d7b3dSmrg		goto fallback;
350428d7b3dSmrg
351428d7b3dSmrg	if (uxa_screen->info->check_copy &&
352428d7b3dSmrg	    !uxa_screen->info->check_copy(pSrcPixmap, pDstPixmap,
353428d7b3dSmrg					  pGC ? pGC->alu : GXcopy,
354428d7b3dSmrg					  pGC ? pGC->planemask : FB_ALLONES))
355428d7b3dSmrg		goto fallback;
356428d7b3dSmrg
357428d7b3dSmrg	uxa_get_drawable_deltas(pSrcDrawable, pSrcPixmap, &src_off_x,
358428d7b3dSmrg				&src_off_y);
359428d7b3dSmrg	uxa_get_drawable_deltas(pDstDrawable, pDstPixmap, &dst_off_x,
360428d7b3dSmrg				&dst_off_y);
361428d7b3dSmrg
362428d7b3dSmrg	/* Mixed directions must be handled specially if the card is lame */
363428d7b3dSmrg	if ((uxa_screen->info->flags & UXA_TWO_BITBLT_DIRECTIONS) &&
364428d7b3dSmrg	    reverse != upsidedown) {
365428d7b3dSmrg		if (uxa_copy_n_to_n_two_dir
366428d7b3dSmrg		    (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy))
367428d7b3dSmrg			return;
368428d7b3dSmrg		goto fallback;
369428d7b3dSmrg	}
370428d7b3dSmrg
371428d7b3dSmrg	if (!uxa_pixmap_is_offscreen(pDstPixmap)) {
372428d7b3dSmrg		int stride, bpp;
373428d7b3dSmrg		char *dst;
374428d7b3dSmrg
375428d7b3dSmrg		if (!uxa_pixmap_is_offscreen(pSrcPixmap))
376428d7b3dSmrg			goto fallback;
377428d7b3dSmrg
378428d7b3dSmrg		if (!uxa_screen->info->get_image)
379428d7b3dSmrg			goto fallback;
380428d7b3dSmrg
381428d7b3dSmrg		/* Don't bother with under 8bpp, XYPixmaps. */
382428d7b3dSmrg		bpp = pSrcPixmap->drawable.bitsPerPixel;
383428d7b3dSmrg		if (bpp != pDstDrawable->bitsPerPixel || bpp < 8)
384428d7b3dSmrg			goto fallback;
385428d7b3dSmrg
386428d7b3dSmrg		/* Only accelerate copies: no rop or planemask. */
387428d7b3dSmrg		if (pGC && (!UXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask) || pGC->alu != GXcopy))
388428d7b3dSmrg			goto fallback;
389428d7b3dSmrg
390428d7b3dSmrg		dst = pDstPixmap->devPrivate.ptr;
391428d7b3dSmrg		stride = pDstPixmap->devKind;
392428d7b3dSmrg		bpp /= 8;
393428d7b3dSmrg		while (nbox--) {
394428d7b3dSmrg			if (!uxa_screen->info->get_image(pSrcPixmap,
395428d7b3dSmrg							 pbox->x1 + dx + src_off_x,
396428d7b3dSmrg							 pbox->y1 + dy + src_off_y,
397428d7b3dSmrg							 pbox->x2 - pbox->x1,
398428d7b3dSmrg							 pbox->y2 - pbox->y1,
399428d7b3dSmrg							 (char *) dst +
400428d7b3dSmrg							 (pbox->y1 + dst_off_y) * stride +
401428d7b3dSmrg							 (pbox->x1 + dst_off_x) * bpp,
402428d7b3dSmrg							 stride))
403428d7b3dSmrg				goto fallback;
404428d7b3dSmrg
405428d7b3dSmrg			pbox++;
406428d7b3dSmrg		}
407428d7b3dSmrg
408428d7b3dSmrg		return;
409428d7b3dSmrg	}
410428d7b3dSmrg
411428d7b3dSmrg	if (uxa_pixmap_is_offscreen(pSrcPixmap)) {
412428d7b3dSmrg	    if (!(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap,
413428d7b3dSmrg						reverse ? -1 : 1,
414428d7b3dSmrg						upsidedown ? -1 : 1,
415428d7b3dSmrg						pGC ? pGC->alu : GXcopy,
416428d7b3dSmrg						pGC ? pGC->
417428d7b3dSmrg						planemask : FB_ALLONES))
418428d7b3dSmrg		goto fallback;
419428d7b3dSmrg
420428d7b3dSmrg	    while (nbox--) {
421428d7b3dSmrg		(*uxa_screen->info->copy) (pDstPixmap,
422428d7b3dSmrg					   pbox->x1 + dx + src_off_x,
423428d7b3dSmrg					   pbox->y1 + dy + src_off_y,
424428d7b3dSmrg					   pbox->x1 + dst_off_x,
425428d7b3dSmrg					   pbox->y1 + dst_off_y,
426428d7b3dSmrg					   pbox->x2 - pbox->x1,
427428d7b3dSmrg					   pbox->y2 - pbox->y1);
428428d7b3dSmrg		pbox++;
429428d7b3dSmrg	    }
430428d7b3dSmrg
431428d7b3dSmrg	    (*uxa_screen->info->done_copy) (pDstPixmap);
432428d7b3dSmrg	} else {
433428d7b3dSmrg	    int stride, bpp;
434428d7b3dSmrg	    char *src;
435428d7b3dSmrg
436428d7b3dSmrg	    if (!uxa_screen->info->put_image)
437428d7b3dSmrg		goto fallback;
438428d7b3dSmrg
439428d7b3dSmrg	    /* Don't bother with under 8bpp, XYPixmaps. */
440428d7b3dSmrg	    bpp = pSrcPixmap->drawable.bitsPerPixel;
441428d7b3dSmrg	    if (bpp != pDstDrawable->bitsPerPixel || bpp < 8)
442428d7b3dSmrg		goto fallback;
443428d7b3dSmrg
444428d7b3dSmrg	    /* Only accelerate copies: no rop or planemask. */
445428d7b3dSmrg	    if (pGC && (!UXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask) || pGC->alu != GXcopy))
446428d7b3dSmrg		goto fallback;
447428d7b3dSmrg
448428d7b3dSmrg	    src = pSrcPixmap->devPrivate.ptr;
449428d7b3dSmrg	    stride = pSrcPixmap->devKind;
450428d7b3dSmrg	    bpp /= 8;
451428d7b3dSmrg	    while (nbox--) {
452428d7b3dSmrg		if (!uxa_screen->info->put_image(pDstPixmap,
453428d7b3dSmrg						 pbox->x1 + dst_off_x,
454428d7b3dSmrg						 pbox->y1 + dst_off_y,
455428d7b3dSmrg						 pbox->x2 - pbox->x1,
456428d7b3dSmrg						 pbox->y2 - pbox->y1,
457428d7b3dSmrg						 (char *) src +
458428d7b3dSmrg						 (pbox->y1 + dy + src_off_y) * stride +
459428d7b3dSmrg						 (pbox->x1 + dx + src_off_x) * bpp,
460428d7b3dSmrg						 stride))
461428d7b3dSmrg		    goto fallback;
462428d7b3dSmrg
463428d7b3dSmrg		pbox++;
464428d7b3dSmrg	    }
465428d7b3dSmrg	}
466428d7b3dSmrg
467428d7b3dSmrg	return;
468428d7b3dSmrg
469428d7b3dSmrgfallback:
470428d7b3dSmrg	UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
471428d7b3dSmrg		      uxa_drawable_location(pSrcDrawable),
472428d7b3dSmrg		      uxa_drawable_location(pDstDrawable)));
473428d7b3dSmrg	if (uxa_prepare_access(pDstDrawable, UXA_ACCESS_RW)) {
474428d7b3dSmrg		if (pSrcDrawable == pDstDrawable ||
475428d7b3dSmrg		    uxa_prepare_access(pSrcDrawable, UXA_ACCESS_RO)) {
476428d7b3dSmrg			fbCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
477428d7b3dSmrg				   dx, dy, reverse, upsidedown, bitplane,
478428d7b3dSmrg				   closure);
479428d7b3dSmrg			if (pSrcDrawable != pDstDrawable)
480428d7b3dSmrg				uxa_finish_access(pSrcDrawable, UXA_ACCESS_RO);
481428d7b3dSmrg		}
482428d7b3dSmrg		uxa_finish_access(pDstDrawable, UXA_ACCESS_RW);
483428d7b3dSmrg	}
484428d7b3dSmrg}
485428d7b3dSmrg
486428d7b3dSmrgRegionPtr
487428d7b3dSmrguxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
488428d7b3dSmrg	      int srcx, int srcy, int width, int height, int dstx, int dsty)
489428d7b3dSmrg{
490428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
491428d7b3dSmrg
492428d7b3dSmrg	if (uxa_screen->force_fallback) {
493428d7b3dSmrg		return uxa_check_copy_area(pSrcDrawable, pDstDrawable, pGC,
494428d7b3dSmrg					   srcx, srcy, width, height, dstx,
495428d7b3dSmrg					   dsty);
496428d7b3dSmrg	}
497428d7b3dSmrg
498428d7b3dSmrg	return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
499428d7b3dSmrg			srcx, srcy, width, height,
500428d7b3dSmrg			dstx, dsty, uxa_copy_n_to_n, 0, NULL);
501428d7b3dSmrg}
502428d7b3dSmrg
503428d7b3dSmrgstatic void
504428d7b3dSmrguxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
505428d7b3dSmrg	       DDXPointPtr ppt)
506428d7b3dSmrg{
507428d7b3dSmrg	int i;
508428d7b3dSmrg	xRectangle *prect;
509428d7b3dSmrg
510428d7b3dSmrg	/* If we can't reuse the current GC as is, don't bother accelerating the
511428d7b3dSmrg	 * points.
512428d7b3dSmrg	 */
513428d7b3dSmrg	if (pGC->fillStyle != FillSolid) {
514428d7b3dSmrg		uxa_check_poly_point(pDrawable, pGC, mode, npt, ppt);
515428d7b3dSmrg		return;
516428d7b3dSmrg	}
517428d7b3dSmrg
518428d7b3dSmrg	prect = malloc(sizeof(xRectangle) * npt);
519428d7b3dSmrg	if (!prect)
520428d7b3dSmrg		return;
521428d7b3dSmrg	for (i = 0; i < npt; i++) {
522428d7b3dSmrg		prect[i].x = ppt[i].x;
523428d7b3dSmrg		prect[i].y = ppt[i].y;
524428d7b3dSmrg		if (i > 0 && mode == CoordModePrevious) {
525428d7b3dSmrg			prect[i].x += prect[i - 1].x;
526428d7b3dSmrg			prect[i].y += prect[i - 1].y;
527428d7b3dSmrg		}
528428d7b3dSmrg		prect[i].width = 1;
529428d7b3dSmrg		prect[i].height = 1;
530428d7b3dSmrg	}
531428d7b3dSmrg	pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
532428d7b3dSmrg	free(prect);
533428d7b3dSmrg}
534428d7b3dSmrg
535428d7b3dSmrg/**
536428d7b3dSmrg * uxa_poly_lines() checks if it can accelerate the lines as a group of
537428d7b3dSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
538428d7b3dSmrg * acceleration if so.
539428d7b3dSmrg */
540428d7b3dSmrgstatic void
541428d7b3dSmrguxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
542428d7b3dSmrg	       DDXPointPtr ppt)
543428d7b3dSmrg{
544428d7b3dSmrg	xRectangle *prect;
545428d7b3dSmrg	int x1, x2, y1, y2;
546428d7b3dSmrg	int i;
547428d7b3dSmrg
548428d7b3dSmrg	/* Don't try to do wide lines or non-solid fill style. */
549428d7b3dSmrg	if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
550428d7b3dSmrg	    pGC->fillStyle != FillSolid) {
551428d7b3dSmrg		uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
552428d7b3dSmrg		return;
553428d7b3dSmrg	}
554428d7b3dSmrg
555428d7b3dSmrg	prect = malloc(sizeof(xRectangle) * (npt - 1));
556428d7b3dSmrg	if (!prect)
557428d7b3dSmrg		return;
558428d7b3dSmrg	x1 = ppt[0].x;
559428d7b3dSmrg	y1 = ppt[0].y;
560428d7b3dSmrg	/* If we have any non-horizontal/vertical, fall back. */
561428d7b3dSmrg	for (i = 0; i < npt - 1; i++) {
562428d7b3dSmrg		if (mode == CoordModePrevious) {
563428d7b3dSmrg			x2 = x1 + ppt[i + 1].x;
564428d7b3dSmrg			y2 = y1 + ppt[i + 1].y;
565428d7b3dSmrg		} else {
566428d7b3dSmrg			x2 = ppt[i + 1].x;
567428d7b3dSmrg			y2 = ppt[i + 1].y;
568428d7b3dSmrg		}
569428d7b3dSmrg
570428d7b3dSmrg		if (x1 != x2 && y1 != y2) {
571428d7b3dSmrg			free(prect);
572428d7b3dSmrg			uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
573428d7b3dSmrg			return;
574428d7b3dSmrg		}
575428d7b3dSmrg
576428d7b3dSmrg		if (x1 < x2) {
577428d7b3dSmrg			prect[i].x = x1;
578428d7b3dSmrg			prect[i].width = x2 - x1 + 1;
579428d7b3dSmrg		} else {
580428d7b3dSmrg			prect[i].x = x2;
581428d7b3dSmrg			prect[i].width = x1 - x2 + 1;
582428d7b3dSmrg		}
583428d7b3dSmrg		if (y1 < y2) {
584428d7b3dSmrg			prect[i].y = y1;
585428d7b3dSmrg			prect[i].height = y2 - y1 + 1;
586428d7b3dSmrg		} else {
587428d7b3dSmrg			prect[i].y = y2;
588428d7b3dSmrg			prect[i].height = y1 - y2 + 1;
589428d7b3dSmrg		}
590428d7b3dSmrg
591428d7b3dSmrg		x1 = x2;
592428d7b3dSmrg		y1 = y2;
593428d7b3dSmrg	}
594428d7b3dSmrg	pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
595428d7b3dSmrg	free(prect);
596428d7b3dSmrg}
597428d7b3dSmrg
598428d7b3dSmrgstatic BoxRec box_from_seg(const xSegment *seg, GCPtr gc)
599428d7b3dSmrg{
600428d7b3dSmrg	BoxRec b;
601428d7b3dSmrg
602428d7b3dSmrg	if (seg->x1 == seg->x2) {
603428d7b3dSmrg		if (seg->y1 > seg->y2) {
604428d7b3dSmrg			b.y2 = seg->y1 + 1;
605428d7b3dSmrg			b.y1 = seg->y2 + 1;
606428d7b3dSmrg			if (gc->capStyle != CapNotLast)
607428d7b3dSmrg				b.y1--;
608428d7b3dSmrg		} else {
609428d7b3dSmrg			b.y1 = seg->y1;
610428d7b3dSmrg			b.y2 = seg->y2;
611428d7b3dSmrg			if (gc->capStyle != CapNotLast)
612428d7b3dSmrg				b.y2++;
613428d7b3dSmrg		}
614428d7b3dSmrg		b.x1 = seg->x1;
615428d7b3dSmrg		b.x2 = seg->x1 + 1;
616428d7b3dSmrg	} else {
617428d7b3dSmrg		if (seg->x1 > seg->x2) {
618428d7b3dSmrg			b.x2 = seg->x1 + 1;
619428d7b3dSmrg			b.x1 = seg->x2 + 1;
620428d7b3dSmrg			if (gc->capStyle != CapNotLast)
621428d7b3dSmrg				b.x1--;
622428d7b3dSmrg		} else {
623428d7b3dSmrg			b.x1 = seg->x1;
624428d7b3dSmrg			b.x2 = seg->x2;
625428d7b3dSmrg			if (gc->capStyle != CapNotLast)
626428d7b3dSmrg				b.x2++;
627428d7b3dSmrg		}
628428d7b3dSmrg		b.y1 = seg->y1;
629428d7b3dSmrg		b.y2 = seg->y1 + 1;
630428d7b3dSmrg	}
631428d7b3dSmrg
632428d7b3dSmrg	return b;
633428d7b3dSmrg}
634428d7b3dSmrg
635428d7b3dSmrg/**
636428d7b3dSmrg * uxa_poly_segment() checks if it can accelerate the lines as a group of
637428d7b3dSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
638428d7b3dSmrg * acceleration if so.
639428d7b3dSmrg */
640428d7b3dSmrgstatic void
641428d7b3dSmrguxa_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg)
642428d7b3dSmrg{
643428d7b3dSmrg	xRectangle *prect;
644428d7b3dSmrg	int i;
645428d7b3dSmrg
646428d7b3dSmrg	/* Don't try to do wide lines or non-solid fill style. */
647428d7b3dSmrg	if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
648428d7b3dSmrg	    pGC->fillStyle != FillSolid) {
649428d7b3dSmrg		uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
650428d7b3dSmrg		return;
651428d7b3dSmrg	}
652428d7b3dSmrg
653428d7b3dSmrg	/* If we have any non-horizontal/vertical, fall back. */
654428d7b3dSmrg	for (i = 0; i < nseg; i++) {
655428d7b3dSmrg		if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
656428d7b3dSmrg			uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
657428d7b3dSmrg			return;
658428d7b3dSmrg		}
659428d7b3dSmrg	}
660428d7b3dSmrg
661428d7b3dSmrg	prect = malloc(sizeof(xRectangle) * nseg);
662428d7b3dSmrg	if (!prect)
663428d7b3dSmrg		return;
664428d7b3dSmrg	for (i = 0; i < nseg; i++) {
665428d7b3dSmrg		BoxRec b = box_from_seg(&pSeg[i], pGC);
666428d7b3dSmrg		prect[i].x = b.x1;
667428d7b3dSmrg		prect[i].y = b.y1;
668428d7b3dSmrg		prect[i].width  = b.x2 - b.x1;
669428d7b3dSmrg		prect[i].height = b.y2 - b.y1;
670428d7b3dSmrg	}
671428d7b3dSmrg	pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
672428d7b3dSmrg	free(prect);
673428d7b3dSmrg}
674428d7b3dSmrg
675428d7b3dSmrgstatic Bool uxa_fill_region_solid(DrawablePtr pDrawable, RegionPtr pRegion,
676428d7b3dSmrg				  Pixel pixel, CARD32 planemask, CARD32 alu);
677428d7b3dSmrg
678428d7b3dSmrgstatic void
679428d7b3dSmrguxa_poly_fill_rect(DrawablePtr pDrawable,
680428d7b3dSmrg		   GCPtr pGC, int nrect, xRectangle * prect)
681428d7b3dSmrg{
682428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
683428d7b3dSmrg	RegionPtr pClip = fbGetCompositeClip(pGC);
684428d7b3dSmrg	PixmapPtr pPixmap;
685428d7b3dSmrg	RegionPtr pReg;
686428d7b3dSmrg	BoxPtr pbox;
687428d7b3dSmrg	int fullX1, fullX2, fullY1, fullY2;
688428d7b3dSmrg	int xoff, yoff;
689428d7b3dSmrg	int xorg, yorg;
690428d7b3dSmrg	int n;
691428d7b3dSmrg
692428d7b3dSmrg	/* Compute intersection of rects and clip region */
693428d7b3dSmrg	pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
694428d7b3dSmrg	REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
695428d7b3dSmrg	REGION_INTERSECT(pScreen, pReg, pClip, pReg);
696428d7b3dSmrg
697428d7b3dSmrg	if (!REGION_NUM_RECTS(pReg))
698428d7b3dSmrg		goto out;
699428d7b3dSmrg
700428d7b3dSmrg	if (uxa_screen->force_fallback)
701428d7b3dSmrg		goto fallback;
702428d7b3dSmrg
703428d7b3dSmrg	pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
704428d7b3dSmrg	if (!pPixmap)
705428d7b3dSmrg		goto fallback;
706428d7b3dSmrg
707428d7b3dSmrg	/* For ROPs where overlaps don't matter, convert rectangles to region
708428d7b3dSmrg	 * and call uxa_fill_region_{solid,tiled}.
709428d7b3dSmrg	 */
710428d7b3dSmrg	if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
711428d7b3dSmrg	    (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
712428d7b3dSmrg	     pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
713428d7b3dSmrg	     pGC->alu == GXset)) {
714428d7b3dSmrg		if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
715428d7b3dSmrg		     uxa_fill_region_solid(pDrawable, pReg,
716428d7b3dSmrg					   pGC->fillStyle ==
717428d7b3dSmrg					   FillSolid ? pGC->fgPixel : pGC->tile.
718428d7b3dSmrg					   pixel, pGC->planemask, pGC->alu))
719428d7b3dSmrg		    || (pGC->fillStyle == FillTiled && !pGC->tileIsPixel
720428d7b3dSmrg			&& uxa_fill_region_tiled(pDrawable, pReg,
721428d7b3dSmrg						 pGC->tile.pixmap, &pGC->patOrg,
722428d7b3dSmrg						 pGC->planemask, pGC->alu))) {
723428d7b3dSmrg			goto out;
724428d7b3dSmrg		}
725428d7b3dSmrg	}
726428d7b3dSmrg
727428d7b3dSmrg	if (pGC->fillStyle != FillSolid &&
728428d7b3dSmrg	    !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) {
729428d7b3dSmrg		goto fallback;
730428d7b3dSmrg	}
731428d7b3dSmrg
732428d7b3dSmrg	if (uxa_screen->info->check_solid &&
733428d7b3dSmrg	    !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask)) {
734428d7b3dSmrg		goto fallback;
735428d7b3dSmrg	}
736428d7b3dSmrg
737428d7b3dSmrg	if (!(*uxa_screen->info->prepare_solid) (pPixmap,
738428d7b3dSmrg						 pGC->alu,
739428d7b3dSmrg						 pGC->planemask,
740428d7b3dSmrg						 pGC->fgPixel)) {
741428d7b3dSmrgfallback:
742428d7b3dSmrg		uxa_check_poly_fill_rect(pDrawable, pGC, nrect, prect);
743428d7b3dSmrg		goto out;
744428d7b3dSmrg	}
745428d7b3dSmrg
746428d7b3dSmrg	xorg = pDrawable->x;
747428d7b3dSmrg	yorg = pDrawable->y;
748428d7b3dSmrg
749428d7b3dSmrg	while (nrect--) {
750428d7b3dSmrg		fullX1 = prect->x + xorg;
751428d7b3dSmrg		fullY1 = prect->y + yorg;
752428d7b3dSmrg		fullX2 = fullX1 + (int)prect->width;
753428d7b3dSmrg		fullY2 = fullY1 + (int)prect->height;
754428d7b3dSmrg		prect++;
755428d7b3dSmrg
756428d7b3dSmrg		n = REGION_NUM_RECTS(pClip);
757428d7b3dSmrg		pbox = REGION_RECTS(pClip);
758428d7b3dSmrg		/*
759428d7b3dSmrg		 * clip the rectangle to each box in the clip region
760428d7b3dSmrg		 * this is logically equivalent to calling Intersect(),
761428d7b3dSmrg		 * but rectangles may overlap each other here.
762428d7b3dSmrg		 */
763428d7b3dSmrg		while (n--) {
764428d7b3dSmrg			int x1 = fullX1;
765428d7b3dSmrg			int x2 = fullX2;
766428d7b3dSmrg			int y1 = fullY1;
767428d7b3dSmrg			int y2 = fullY2;
768428d7b3dSmrg
769428d7b3dSmrg			if (pbox->x1 > x1)
770428d7b3dSmrg				x1 = pbox->x1;
771428d7b3dSmrg			if (pbox->x2 < x2)
772428d7b3dSmrg				x2 = pbox->x2;
773428d7b3dSmrg			if (pbox->y1 > y1)
774428d7b3dSmrg				y1 = pbox->y1;
775428d7b3dSmrg			if (pbox->y2 < y2)
776428d7b3dSmrg				y2 = pbox->y2;
777428d7b3dSmrg			pbox++;
778428d7b3dSmrg
779428d7b3dSmrg			if (x1 >= x2 || y1 >= y2)
780428d7b3dSmrg				continue;
781428d7b3dSmrg
782428d7b3dSmrg			(*uxa_screen->info->solid) (pPixmap,
783428d7b3dSmrg						    x1 + xoff,
784428d7b3dSmrg						    y1 + yoff,
785428d7b3dSmrg						    x2 + xoff,
786428d7b3dSmrg						    y2 + yoff);
787428d7b3dSmrg		}
788428d7b3dSmrg	}
789428d7b3dSmrg	(*uxa_screen->info->done_solid) (pPixmap);
790428d7b3dSmrg
791428d7b3dSmrgout:
792428d7b3dSmrg	REGION_UNINIT(pScreen, pReg);
793428d7b3dSmrg	REGION_DESTROY(pScreen, pReg);
794428d7b3dSmrg}
795428d7b3dSmrg
796428d7b3dSmrgvoid
797428d7b3dSmrguxa_get_spans(DrawablePtr pDrawable,
798428d7b3dSmrg	      int wMax,
799428d7b3dSmrg	      DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
800428d7b3dSmrg{
801428d7b3dSmrg	uxa_check_get_spans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
802428d7b3dSmrg}
803428d7b3dSmrg
804428d7b3dSmrgstatic void
805428d7b3dSmrguxa_set_spans(DrawablePtr pDrawable, GCPtr gc, char *src,
806428d7b3dSmrg                 DDXPointPtr points, int *widths, int n, int sorted)
807428d7b3dSmrg{
808428d7b3dSmrg	uxa_check_set_spans(pDrawable, gc, src, points, widths, n, sorted);
809428d7b3dSmrg}
810428d7b3dSmrg
811428d7b3dSmrgstatic RegionPtr
812428d7b3dSmrguxa_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
813428d7b3dSmrg	       int srcx, int srcy, int w, int h, int dstx, int dsty,
814428d7b3dSmrg	       unsigned long bitPlane)
815428d7b3dSmrg{
816428d7b3dSmrg	return uxa_check_copy_plane(pSrc, pDst, pGC, srcx, srcy, w, h,
817428d7b3dSmrg				    dstx, dsty, bitPlane);
818428d7b3dSmrg}
819428d7b3dSmrg
820428d7b3dSmrgstatic void
821428d7b3dSmrguxa_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
822428d7b3dSmrg		    int x, int y, unsigned int nglyph,
823428d7b3dSmrg		    CharInfoPtr * ppci, pointer pglyphBase)
824428d7b3dSmrg{
825428d7b3dSmrg	uxa_check_image_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
826428d7b3dSmrg}
827428d7b3dSmrg
828428d7b3dSmrgstatic void
829428d7b3dSmrguxa_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
830428d7b3dSmrg		   int x, int y, unsigned int nglyph,
831428d7b3dSmrg		   CharInfoPtr * ppci, pointer pglyphBase)
832428d7b3dSmrg{
833428d7b3dSmrg	uxa_check_poly_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
834428d7b3dSmrg}
835428d7b3dSmrg
836428d7b3dSmrgstatic void
837428d7b3dSmrguxa_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
838428d7b3dSmrg		DrawablePtr pDrawable, int w, int h, int x, int y)
839428d7b3dSmrg{
840428d7b3dSmrg	uxa_check_push_pixels(pGC, pBitmap, pDrawable, w, h, x, y);
841428d7b3dSmrg}
842428d7b3dSmrg
843428d7b3dSmrgconst GCOps uxa_ops = {
844428d7b3dSmrg	uxa_fill_spans,
845428d7b3dSmrg	uxa_set_spans,
846428d7b3dSmrg	uxa_put_image,
847428d7b3dSmrg	uxa_copy_area,
848428d7b3dSmrg	uxa_copy_plane,
849428d7b3dSmrg	uxa_poly_point,
850428d7b3dSmrg	uxa_poly_lines,
851428d7b3dSmrg	uxa_poly_segment,
852428d7b3dSmrg	miPolyRectangle,
853428d7b3dSmrg	uxa_check_poly_arc,
854428d7b3dSmrg	miFillPolygon,
855428d7b3dSmrg	uxa_poly_fill_rect,
856428d7b3dSmrg	miPolyFillArc,
857428d7b3dSmrg	miPolyText8,
858428d7b3dSmrg	miPolyText16,
859428d7b3dSmrg	miImageText8,
860428d7b3dSmrg	miImageText16,
861428d7b3dSmrg	uxa_image_glyph_blt,
862428d7b3dSmrg	uxa_poly_glyph_blt,
863428d7b3dSmrg	uxa_push_pixels,
864428d7b3dSmrg};
865428d7b3dSmrg
866428d7b3dSmrgvoid uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
867428d7b3dSmrg{
868428d7b3dSmrg	RegionRec rgnDst;
869428d7b3dSmrg	int dx, dy;
870428d7b3dSmrg	PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
871428d7b3dSmrg
872428d7b3dSmrg	dx = ptOldOrg.x - pWin->drawable.x;
873428d7b3dSmrg	dy = ptOldOrg.y - pWin->drawable.y;
874428d7b3dSmrg	REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
875428d7b3dSmrg
876428d7b3dSmrg	REGION_INIT(pWin->drawable.pScreen, &rgnDst, NullBox, 0);
877428d7b3dSmrg
878428d7b3dSmrg	REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip,
879428d7b3dSmrg			 prgnSrc);
880428d7b3dSmrg#ifdef COMPOSITE
881428d7b3dSmrg	if (pPixmap->screen_x || pPixmap->screen_y)
882428d7b3dSmrg		REGION_TRANSLATE(pWin->drawable.pScreen, &rgnDst,
883428d7b3dSmrg				 -pPixmap->screen_x, -pPixmap->screen_y);
884428d7b3dSmrg#endif
885428d7b3dSmrg
886428d7b3dSmrg	miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
887428d7b3dSmrg		     NULL, &rgnDst, dx, dy, uxa_copy_n_to_n, 0, NULL);
888428d7b3dSmrg
889428d7b3dSmrg	REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
890428d7b3dSmrg}
891428d7b3dSmrg
892428d7b3dSmrgstatic Bool
893428d7b3dSmrguxa_fill_region_solid(DrawablePtr pDrawable,
894428d7b3dSmrg		      RegionPtr pRegion,
895428d7b3dSmrg		      Pixel pixel, CARD32 planemask, CARD32 alu)
896428d7b3dSmrg{
897428d7b3dSmrg	ScreenPtr screen = pDrawable->pScreen;
898428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
899428d7b3dSmrg	PixmapPtr pixmap;
900428d7b3dSmrg	int xoff, yoff;
901428d7b3dSmrg	int nbox;
902428d7b3dSmrg	BoxPtr pBox;
903428d7b3dSmrg	Bool ret = FALSE;
904428d7b3dSmrg
905428d7b3dSmrg	pixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
906428d7b3dSmrg	if (!pixmap)
907428d7b3dSmrg		return FALSE;
908428d7b3dSmrg
909428d7b3dSmrg	REGION_TRANSLATE(screen, pRegion, xoff, yoff);
910428d7b3dSmrg
911428d7b3dSmrg	nbox = REGION_NUM_RECTS(pRegion);
912428d7b3dSmrg	pBox = REGION_RECTS(pRegion);
913428d7b3dSmrg
914428d7b3dSmrg	if (uxa_screen->info->check_solid &&
915428d7b3dSmrg	    !uxa_screen->info->check_solid(&pixmap->drawable, alu, planemask))
916428d7b3dSmrg		goto err;
917428d7b3dSmrg
918428d7b3dSmrg	if (!uxa_screen->info->prepare_solid(pixmap, alu, planemask, pixel))
919428d7b3dSmrg		goto err;
920428d7b3dSmrg
921428d7b3dSmrg	while (nbox--) {
922428d7b3dSmrg		uxa_screen->info->solid(pixmap,
923428d7b3dSmrg					pBox->x1, pBox->y1,
924428d7b3dSmrg					pBox->x2, pBox->y2);
925428d7b3dSmrg		pBox++;
926428d7b3dSmrg	}
927428d7b3dSmrg	uxa_screen->info->done_solid(pixmap);
928428d7b3dSmrg	ret = TRUE;
929428d7b3dSmrg
930428d7b3dSmrgerr:
931428d7b3dSmrg	REGION_TRANSLATE(screen, pRegion, -xoff, -yoff);
932428d7b3dSmrg	return ret;
933428d7b3dSmrg}
934428d7b3dSmrg
935428d7b3dSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
936428d7b3dSmrg * Based on fbFillRegionTiled(), fbTile().
937428d7b3dSmrg */
938428d7b3dSmrgBool
939428d7b3dSmrguxa_fill_region_tiled(DrawablePtr pDrawable,
940428d7b3dSmrg		      RegionPtr pRegion,
941428d7b3dSmrg		      PixmapPtr pTile,
942428d7b3dSmrg		      DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu)
943428d7b3dSmrg{
944428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
945428d7b3dSmrg	PixmapPtr pPixmap;
946428d7b3dSmrg	int xoff, yoff;
947428d7b3dSmrg	int tileWidth, tileHeight;
948428d7b3dSmrg	int nbox = REGION_NUM_RECTS(pRegion);
949428d7b3dSmrg	BoxPtr pBox = REGION_RECTS(pRegion);
950428d7b3dSmrg	Bool ret = FALSE;
951428d7b3dSmrg
952428d7b3dSmrg	tileWidth = pTile->drawable.width;
953428d7b3dSmrg	tileHeight = pTile->drawable.height;
954428d7b3dSmrg
955428d7b3dSmrg	/* If we're filling with a solid color, grab it out and go to
956428d7b3dSmrg	 * FillRegionsolid, saving numerous copies.
957428d7b3dSmrg	 */
958428d7b3dSmrg	if (tileWidth == 1 && tileHeight == 1)
959428d7b3dSmrg		return uxa_fill_region_solid(pDrawable, pRegion,
960428d7b3dSmrg					     uxa_get_pixmap_first_pixel(pTile),
961428d7b3dSmrg					     planemask, alu);
962428d7b3dSmrg
963428d7b3dSmrg	pPixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
964428d7b3dSmrg	if (!pPixmap || !uxa_pixmap_is_offscreen(pTile))
965428d7b3dSmrg		goto out;
966428d7b3dSmrg
967428d7b3dSmrg	if (uxa_screen->info->check_copy &&
968428d7b3dSmrg	    !uxa_screen->info->check_copy(pTile, pPixmap, alu, planemask))
969428d7b3dSmrg		return FALSE;
970428d7b3dSmrg
971428d7b3dSmrg	REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
972428d7b3dSmrg
973428d7b3dSmrg	if ((*uxa_screen->info->prepare_copy) (pTile, pPixmap, 1, 1, alu,
974428d7b3dSmrg					       planemask)) {
975428d7b3dSmrg		while (nbox--) {
976428d7b3dSmrg			int height = pBox->y2 - pBox->y1;
977428d7b3dSmrg			int dstY = pBox->y1;
978428d7b3dSmrg			int tileY;
979428d7b3dSmrg
980428d7b3dSmrg			modulus(dstY - yoff - pDrawable->y - pPatOrg->y,
981428d7b3dSmrg				tileHeight, tileY);
982428d7b3dSmrg
983428d7b3dSmrg			while (height > 0) {
984428d7b3dSmrg				int width = pBox->x2 - pBox->x1;
985428d7b3dSmrg				int dstX = pBox->x1;
986428d7b3dSmrg				int tileX;
987428d7b3dSmrg				int h = tileHeight - tileY;
988428d7b3dSmrg
989428d7b3dSmrg				if (h > height)
990428d7b3dSmrg					h = height;
991428d7b3dSmrg				height -= h;
992428d7b3dSmrg
993428d7b3dSmrg				modulus(dstX - xoff - pDrawable->x - pPatOrg->x,
994428d7b3dSmrg					tileWidth, tileX);
995428d7b3dSmrg
996428d7b3dSmrg				while (width > 0) {
997428d7b3dSmrg					int w = tileWidth - tileX;
998428d7b3dSmrg					if (w > width)
999428d7b3dSmrg						w = width;
1000428d7b3dSmrg					width -= w;
1001428d7b3dSmrg
1002428d7b3dSmrg					(*uxa_screen->info->copy) (pPixmap,
1003428d7b3dSmrg								   tileX, tileY,
1004428d7b3dSmrg								   dstX, dstY,
1005428d7b3dSmrg								   w, h);
1006428d7b3dSmrg					dstX += w;
1007428d7b3dSmrg					tileX = 0;
1008428d7b3dSmrg				}
1009428d7b3dSmrg				dstY += h;
1010428d7b3dSmrg				tileY = 0;
1011428d7b3dSmrg			}
1012428d7b3dSmrg			pBox++;
1013428d7b3dSmrg		}
1014428d7b3dSmrg		(*uxa_screen->info->done_copy) (pPixmap);
1015428d7b3dSmrg
1016428d7b3dSmrg		ret = TRUE;
1017428d7b3dSmrg	}
1018428d7b3dSmrg
1019428d7b3dSmrgout:
1020428d7b3dSmrg	REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
1021428d7b3dSmrg
1022428d7b3dSmrg	return ret;
1023428d7b3dSmrg}
1024428d7b3dSmrg
1025428d7b3dSmrg/**
1026428d7b3dSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1027428d7b3dSmrg *
1028428d7b3dSmrg * This is probably the only case we actually care about.  The rest fall through
1029428d7b3dSmrg * to migration and fbGetImage, which hopefully will result in migration pushing
1030428d7b3dSmrg * the pixmap out of framebuffer.
1031428d7b3dSmrg */
1032428d7b3dSmrgvoid
1033428d7b3dSmrguxa_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
1034428d7b3dSmrg	      unsigned int format, unsigned long planeMask, char *d)
1035428d7b3dSmrg{
1036428d7b3dSmrg	ScreenPtr screen = pDrawable->pScreen;
1037428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1038428d7b3dSmrg	BoxRec Box;
1039428d7b3dSmrg	PixmapPtr pPix = uxa_get_drawable_pixmap(pDrawable);
1040428d7b3dSmrg	int xoff, yoff;
1041428d7b3dSmrg	Bool ok;
1042428d7b3dSmrg
1043428d7b3dSmrg	uxa_get_drawable_deltas(pDrawable, pPix, &xoff, &yoff);
1044428d7b3dSmrg
1045428d7b3dSmrg	Box.x1 = pDrawable->y + x + xoff;
1046428d7b3dSmrg	Box.y1 = pDrawable->y + y + yoff;
1047428d7b3dSmrg	Box.x2 = Box.x1 + w;
1048428d7b3dSmrg	Box.y2 = Box.y1 + h;
1049428d7b3dSmrg
1050428d7b3dSmrg	if (uxa_screen->force_fallback)
1051428d7b3dSmrg		goto fallback;
1052428d7b3dSmrg
1053428d7b3dSmrg	pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
1054428d7b3dSmrg
1055428d7b3dSmrg	if (pPix == NULL || uxa_screen->info->get_image == NULL)
1056428d7b3dSmrg		goto fallback;
1057428d7b3dSmrg
1058428d7b3dSmrg	/* Only cover the ZPixmap, solid copy case. */
1059428d7b3dSmrg	if (format != ZPixmap || !UXA_PM_IS_SOLID(pDrawable, planeMask))
1060428d7b3dSmrg		goto fallback;
1061428d7b3dSmrg
1062428d7b3dSmrg	/* Only try to handle the 8bpp and up cases, since we don't want to
1063428d7b3dSmrg	 * think about <8bpp.
1064428d7b3dSmrg	 */
1065428d7b3dSmrg	if (pDrawable->bitsPerPixel < 8)
1066428d7b3dSmrg		goto fallback;
1067428d7b3dSmrg
1068428d7b3dSmrg	ok = uxa_screen->info->get_image(pPix, pDrawable->x + x + xoff,
1069428d7b3dSmrg					 pDrawable->y + y + yoff, w, h, d,
1070428d7b3dSmrg					 PixmapBytePad(w, pDrawable->depth));
1071428d7b3dSmrg	if (ok)
1072428d7b3dSmrg		return;
1073428d7b3dSmrg
1074428d7b3dSmrgfallback:
1075428d7b3dSmrg	UXA_FALLBACK(("from %p (%c)\n", pDrawable,
1076428d7b3dSmrg		      uxa_drawable_location(pDrawable)));
1077428d7b3dSmrg
1078428d7b3dSmrg	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RO)) {
1079428d7b3dSmrg		fbGetImage(pDrawable, x, y, w, h, format, planeMask, d);
1080428d7b3dSmrg		uxa_finish_access(pDrawable, UXA_ACCESS_RO);
1081428d7b3dSmrg	}
1082428d7b3dSmrg
1083428d7b3dSmrg	return;
1084428d7b3dSmrg}
1085