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 
39 static void
uxa_fill_spans(DrawablePtr pDrawable,GCPtr pGC,int n,DDXPointPtr ppt,int * pwidth,int fSorted)40 uxa_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 
100 fallback:
101 	uxa_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted);
102 }
103 
104 static Bool
uxa_do_put_image(DrawablePtr pDrawable,GCPtr pGC,int depth,int x,int y,int w,int h,int format,char * bits,int src_stride)105 uxa_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 
193 static void
uxa_put_image(DrawablePtr pDrawable,GCPtr pGC,int depth,int x,int y,int w,int h,int leftPad,int format,char * bits)194 uxa_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 
204 static inline Bool
uxa_copy_n_to_n_two_dir(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,BoxPtr pbox,int nbox,int dx,int dy)205 uxa_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 
327 void
uxa_copy_n_to_n(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,BoxPtr pbox,int nbox,int dx,int dy,Bool reverse,Bool upsidedown,Pixel bitplane,void * closure)328 uxa_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 
469 fallback:
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 
486 RegionPtr
uxa_copy_area(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,int srcx,int srcy,int width,int height,int dstx,int dsty)487 uxa_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 
503 static void
uxa_poly_point(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,DDXPointPtr ppt)504 uxa_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  */
540 static void
uxa_poly_lines(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,DDXPointPtr ppt)541 uxa_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 
box_from_seg(const xSegment * seg,GCPtr gc)598 static 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  */
640 static void
uxa_poly_segment(DrawablePtr pDrawable,GCPtr pGC,int nseg,xSegment * pSeg)641 uxa_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 
675 static Bool uxa_fill_region_solid(DrawablePtr pDrawable, RegionPtr pRegion,
676 				  Pixel pixel, CARD32 planemask, CARD32 alu);
677 
678 static void
uxa_poly_fill_rect(DrawablePtr pDrawable,GCPtr pGC,int nrect,xRectangle * prect)679 uxa_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)) {
741 fallback:
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 
791 out:
792 	REGION_UNINIT(pScreen, pReg);
793 	REGION_DESTROY(pScreen, pReg);
794 }
795 
796 void
uxa_get_spans(DrawablePtr pDrawable,int wMax,DDXPointPtr ppt,int * pwidth,int nspans,char * pdstStart)797 uxa_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 
804 static void
uxa_set_spans(DrawablePtr pDrawable,GCPtr gc,char * src,DDXPointPtr points,int * widths,int n,int sorted)805 uxa_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 
811 static RegionPtr
uxa_copy_plane(DrawablePtr pSrc,DrawablePtr pDst,GCPtr pGC,int srcx,int srcy,int w,int h,int dstx,int dsty,unsigned long bitPlane)812 uxa_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 
820 static void
uxa_image_glyph_blt(DrawablePtr pDrawable,GCPtr pGC,int x,int y,unsigned int nglyph,CharInfoPtr * ppci,pointer pglyphBase)821 uxa_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 
828 static void
uxa_poly_glyph_blt(DrawablePtr pDrawable,GCPtr pGC,int x,int y,unsigned int nglyph,CharInfoPtr * ppci,pointer pglyphBase)829 uxa_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 
836 static void
uxa_push_pixels(GCPtr pGC,PixmapPtr pBitmap,DrawablePtr pDrawable,int w,int h,int x,int y)837 uxa_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 
843 const 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 
uxa_copy_window(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)866 void 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 
892 static Bool
uxa_fill_region_solid(DrawablePtr pDrawable,RegionPtr pRegion,Pixel pixel,CARD32 planemask,CARD32 alu)893 uxa_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 
930 err:
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  */
938 Bool
uxa_fill_region_tiled(DrawablePtr pDrawable,RegionPtr pRegion,PixmapPtr pTile,DDXPointPtr pPatOrg,CARD32 planemask,CARD32 alu)939 uxa_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 
1019 out:
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  */
1032 void
uxa_get_image(DrawablePtr pDrawable,int x,int y,int w,int h,unsigned int format,unsigned long planeMask,char * d)1033 uxa_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 
1074 fallback:
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