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