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