1/*
2 *
3 * Copyright © 1999 Keith Packard
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include "uxa-priv.h"
25#include "uxa-damage.h"
26
27#ifdef RENDER
28#include "mipict.h"
29#endif
30
31/*
32 * These functions wrap the low-level fb rendering functions and
33 * synchronize framebuffer/accelerated drawing by stalling until
34 * the accelerator is idle
35 */
36
37/**
38 * Calls uxa_prepare_access with UXA_PREPARE_SRC for the tile, if that is the
39 * current fill style.
40 *
41 * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
42 * 1bpp and never in fb, so we don't worry about them.
43 * We should worry about them for completeness sake and going forward.
44 */
45Bool uxa_prepare_access_gc(GCPtr pGC)
46{
47	if (pGC->stipple)
48	    if (!uxa_prepare_access(&pGC->stipple->drawable, NULL, UXA_ACCESS_RO))
49			return FALSE;
50	if (pGC->fillStyle == FillTiled)
51		if (!uxa_prepare_access
52		    (&pGC->tile.pixmap->drawable, NULL, UXA_ACCESS_RO)) {
53			if (pGC->stipple)
54				uxa_finish_access(&pGC->stipple->drawable);
55			return FALSE;
56		}
57	return TRUE;
58}
59
60/**
61 * Finishes access to the tile in the GC, if used.
62 */
63void uxa_finish_access_gc(GCPtr pGC)
64{
65	if (pGC->fillStyle == FillTiled)
66		uxa_finish_access(&pGC->tile.pixmap->drawable);
67	if (pGC->stipple)
68		uxa_finish_access(&pGC->stipple->drawable);
69}
70
71char uxa_drawable_location(DrawablePtr pDrawable)
72{
73	return uxa_drawable_is_offscreen(pDrawable) ? 's' : 'm';
74}
75
76void
77uxa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
78		     DDXPointPtr ppt, int *pwidth, int fSorted)
79{
80	ScreenPtr screen = pDrawable->pScreen;
81	RegionRec region;
82
83	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
84	uxa_damage_fill_spans (&region, pDrawable, pGC, nspans,
85			       ppt, pwidth, fSorted);
86
87	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
88		      uxa_drawable_location(pDrawable)));
89	if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RW)) {
90		if (uxa_prepare_access_gc(pGC)) {
91			fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth,
92				    fSorted);
93			uxa_finish_access_gc(pGC);
94		}
95		uxa_finish_access(pDrawable);
96	}
97
98	REGION_UNINIT (screen, &region);
99}
100
101void
102uxa_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
103		    DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
104{
105	ScreenPtr screen = pDrawable->pScreen;
106
107	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
108		      uxa_drawable_location(pDrawable)));
109	if (uxa_prepare_access(pDrawable, NULL, UXA_ACCESS_RW)) {
110		fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
111		uxa_finish_access(pDrawable);
112	}
113}
114
115void
116uxa_check_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
117		    int x, int y, int w, int h, int leftPad, int format,
118		    char *bits)
119{
120	ScreenPtr screen = pDrawable->pScreen;
121
122	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
123		      uxa_drawable_location(pDrawable)));
124	if (uxa_prepare_access(pDrawable, NULL, UXA_ACCESS_RW)) {
125		fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
126			   bits);
127		uxa_finish_access(pDrawable);
128	}
129}
130
131RegionPtr
132uxa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
133		    int srcx, int srcy, int w, int h, int dstx, int dsty)
134{
135	ScreenPtr screen = pSrc->pScreen;
136	RegionPtr ret = NULL;
137	RegionRec src_region;
138	RegionRec dst_region;
139	BoxRec src_box = { srcx, srcy, srcx + w, srcy + h };
140	BoxRec dst_box = { dstx, dsty, dstx + w, dsty + h };
141
142	REGION_INIT (screen, &src_region, &src_box, 1);
143	REGION_INIT (screen, &dst_region, &dst_box, 1);
144
145	/* FIXME: Hmm, it's not totally clear what to do in this case. In fact,
146	 * all cases where more than one drawable can get prepare_access() called
147	 * on it multiple times is kinda bad.
148	 */
149
150	UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
151		      uxa_drawable_location(pSrc),
152		      uxa_drawable_location(pDst)));
153	if (uxa_prepare_access(pDst, &dst_region, UXA_ACCESS_RW)) {
154	    if (uxa_prepare_access(pSrc, &src_region, UXA_ACCESS_RO)) {
155			ret =
156			    fbCopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
157				       dsty);
158			uxa_finish_access(pSrc);
159		}
160		uxa_finish_access(pDst);
161	}
162
163	REGION_UNINIT (screen, &src_region);
164	REGION_UNINIT (screen, &dst_region);
165
166	return ret;
167}
168
169RegionPtr
170uxa_check_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
171		     int srcx, int srcy, int w, int h, int dstx, int dsty,
172		     unsigned long bitPlane)
173{
174	ScreenPtr screen = pSrc->pScreen;
175	RegionPtr ret = NULL;
176
177	UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
178		      uxa_drawable_location(pSrc),
179		      uxa_drawable_location(pDst)));
180	if (uxa_prepare_access(pDst, NULL, UXA_ACCESS_RW)) {
181	    if (uxa_prepare_access(pSrc, NULL, UXA_ACCESS_RO)) {
182			ret =
183			    fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
184					dsty, bitPlane);
185			uxa_finish_access(pSrc);
186		}
187		uxa_finish_access(pDst);
188	}
189	return ret;
190}
191
192void
193uxa_check_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
194		     DDXPointPtr pptInit)
195{
196	ScreenPtr screen = pDrawable->pScreen;
197
198	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
199		      uxa_drawable_location(pDrawable)));
200	if (uxa_prepare_access(pDrawable, NULL, UXA_ACCESS_RW)) {
201		fbPolyPoint(pDrawable, pGC, mode, npt, pptInit);
202		uxa_finish_access(pDrawable);
203	}
204}
205
206void
207uxa_check_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
208		     int mode, int npt, DDXPointPtr ppt)
209{
210	ScreenPtr screen = pDrawable->pScreen;
211	RegionRec region;
212
213	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
214	uxa_damage_poly_lines (&region, pDrawable, pGC, mode, npt, ppt);
215
216	UXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
217		      pDrawable, uxa_drawable_location(pDrawable),
218		      pGC->lineWidth, mode, npt));
219
220	if (pGC->lineWidth == 0) {
221		if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RW)) {
222			if (uxa_prepare_access_gc(pGC)) {
223				fbPolyLine(pDrawable, pGC, mode, npt, ppt);
224				uxa_finish_access_gc(pGC);
225			}
226			uxa_finish_access(pDrawable);
227		}
228		goto out;
229	}
230	/* fb calls mi functions in the lineWidth != 0 case. */
231	fbPolyLine(pDrawable, pGC, mode, npt, ppt);
232
233 out:
234	REGION_UNINIT (screen, &region);
235}
236
237void
238uxa_check_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
239		       int nsegInit, xSegment * pSegInit)
240{
241	ScreenPtr screen = pDrawable->pScreen;
242	RegionRec region;
243
244	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
245	uxa_damage_poly_segment (&region, pDrawable, pGC, nsegInit, pSegInit);
246
247	UXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
248		      uxa_drawable_location(pDrawable), pGC->lineWidth,
249		      nsegInit));
250	if (pGC->lineWidth == 0) {
251	    if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RW)) {
252			if (uxa_prepare_access_gc(pGC)) {
253				fbPolySegment(pDrawable, pGC, nsegInit,
254					      pSegInit);
255				uxa_finish_access_gc(pGC);
256			}
257			uxa_finish_access(pDrawable);
258		}
259	    goto out;
260	}
261
262	/* fb calls mi functions in the lineWidth != 0 case. */
263	fbPolySegment(pDrawable, pGC, nsegInit, pSegInit);
264
265out:
266	REGION_UNINIT (screen, &region);
267}
268
269void
270uxa_check_poly_arc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
271{
272	ScreenPtr screen = pDrawable->pScreen;
273
274	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
275		      uxa_drawable_location(pDrawable)));
276
277	/* Disable this as fbPolyArc can call miZeroPolyArc which in turn
278	 * can call accelerated functions, that as yet, haven't been notified
279	 * with uxa_finish_access().
280	 */
281#if 0
282	if (pGC->lineWidth == 0) {
283		if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
284			if (uxa_prepare_access_gc(pGC)) {
285				fbPolyArc(pDrawable, pGC, narcs, pArcs);
286				uxa_finish_access_gc(pGC);
287			}
288			uxa_finish_access(pDrawable);
289		}
290		return;
291	}
292#endif
293	miPolyArc(pDrawable, pGC, narcs, pArcs);
294}
295
296void
297uxa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
298			 int nrect, xRectangle * prect)
299{
300	ScreenPtr screen = pDrawable->pScreen;
301	RegionRec region;
302
303	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
304	uxa_damage_poly_fill_rect (&region, pDrawable, pGC, nrect, prect);
305
306	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
307		      uxa_drawable_location(pDrawable)));
308
309	if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RW)) {
310		if (uxa_prepare_access_gc(pGC)) {
311			fbPolyFillRect(pDrawable, pGC, nrect, prect);
312			uxa_finish_access_gc(pGC);
313		}
314		uxa_finish_access(pDrawable);
315	}
316
317	REGION_UNINIT (screen, &region);
318}
319
320void
321uxa_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
322			  int x, int y, unsigned int nglyph,
323			  CharInfoPtr * ppci, pointer pglyphBase)
324{
325	ScreenPtr screen = pDrawable->pScreen;
326	RegionRec region;
327
328	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
329	uxa_damage_image_glyph_blt (&region, pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
330
331	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
332		      uxa_drawable_location(pDrawable)));
333	if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RW)) {
334		if (uxa_prepare_access_gc(pGC)) {
335			fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
336					pglyphBase);
337			uxa_finish_access_gc(pGC);
338		}
339		uxa_finish_access(pDrawable);
340	}
341
342	REGION_UNINIT (screen, &region);
343}
344
345void
346uxa_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
347			 int x, int y, unsigned int nglyph,
348			 CharInfoPtr * ppci, pointer pglyphBase)
349{
350	ScreenPtr screen = pDrawable->pScreen;
351	RegionRec region;
352
353	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
354	uxa_damage_poly_glyph_blt (&region, pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
355
356	UXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
357		      uxa_drawable_location(pDrawable), pGC->fillStyle,
358		      pGC->alu));
359	if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RW)) {
360		if (uxa_prepare_access_gc(pGC)) {
361			fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
362				       pglyphBase);
363			uxa_finish_access_gc(pGC);
364		}
365		uxa_finish_access(pDrawable);
366	}
367
368	REGION_UNINIT (screen, &region);
369}
370
371void
372uxa_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
373		      DrawablePtr pDrawable, int w, int h, int x, int y)
374{
375	ScreenPtr screen = pDrawable->pScreen;
376	RegionRec region;
377
378	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
379	uxa_damage_push_pixels (&region, pGC, pBitmap, pDrawable, w, h, x, y);
380
381	UXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
382		      uxa_drawable_location(&pBitmap->drawable),
383		      uxa_drawable_location(pDrawable)));
384	if (uxa_prepare_access(pDrawable, &region, UXA_ACCESS_RW)) {
385	    if (uxa_prepare_access(&pBitmap->drawable, NULL, UXA_ACCESS_RO)) {
386			if (uxa_prepare_access_gc(pGC)) {
387				fbPushPixels(pGC, pBitmap, pDrawable, w, h, x,
388					     y);
389				uxa_finish_access_gc(pGC);
390			}
391			uxa_finish_access(&pBitmap->drawable);
392		}
393		uxa_finish_access(pDrawable);
394	}
395
396	REGION_UNINIT (screen, &region);
397}
398
399void
400uxa_check_get_spans(DrawablePtr pDrawable,
401		    int wMax,
402		    DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
403{
404	ScreenPtr screen = pDrawable->pScreen;
405
406	UXA_FALLBACK(("from %p (%c)\n", pDrawable,
407		      uxa_drawable_location(pDrawable)));
408	if (uxa_prepare_access(pDrawable, NULL, UXA_ACCESS_RO)) {
409		fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
410		uxa_finish_access(pDrawable);
411	}
412}
413
414void
415uxa_check_composite(CARD8 op,
416		    PicturePtr pSrc,
417		    PicturePtr pMask,
418		    PicturePtr pDst,
419		    INT16 xSrc, INT16 ySrc,
420		    INT16 xMask, INT16 yMask,
421		    INT16 xDst, INT16 yDst,
422		    CARD16 width, CARD16 height)
423{
424	ScreenPtr screen = pDst->pDrawable->pScreen;
425	RegionRec region;
426
427	UXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
428
429	REGION_INIT (screen, &region, (BoxPtr)NULL, 0);
430	uxa_damage_composite (&region, op, pSrc, pMask, pDst,
431			      xSrc, ySrc, xMask, yMask, xDst, yDst,
432			      width, height);
433
434#if 0
435	ErrorF ("destination: %p\n", pDst->pDrawable);
436	ErrorF ("source: %p\n", pSrc->pDrawable);
437	ErrorF ("mask: %p\n", pMask? pMask->pDrawable : NULL);
438#endif
439	if (uxa_prepare_access(pDst->pDrawable, &region, UXA_ACCESS_RW)) {
440		if (pSrc->pDrawable == NULL ||
441		    uxa_prepare_access(pSrc->pDrawable, NULL, UXA_ACCESS_RO)) {
442			if (!pMask || pMask->pDrawable == NULL ||
443			    uxa_prepare_access(pMask->pDrawable, NULL, UXA_ACCESS_RO))
444			{
445				fbComposite(op, pSrc, pMask, pDst,
446					    xSrc, ySrc,
447					    xMask, yMask,
448					    xDst, yDst,
449					    width, height);
450				if (pMask && pMask->pDrawable != NULL)
451					uxa_finish_access(pMask->pDrawable);
452			}
453			if (pSrc->pDrawable != NULL)
454				uxa_finish_access(pSrc->pDrawable);
455		}
456		uxa_finish_access(pDst->pDrawable);
457	}
458}
459
460void
461uxa_check_add_traps(PicturePtr pPicture,
462		    INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
463{
464	ScreenPtr screen = pPicture->pDrawable->pScreen;
465
466	UXA_FALLBACK(("to pict %p (%c)\n", pPicture,
467		      uxa_drawable_location(pPicture->pDrawable)));
468	if (uxa_prepare_access(pPicture->pDrawable, NULL, UXA_ACCESS_RW)) {
469		fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
470		uxa_finish_access(pPicture->pDrawable);
471	}
472}
473
474/**
475 * Gets the 0,0 pixel of a pixmap.  Used for doing solid fills of tiled pixmaps
476 * that happen to be 1x1.  Pixmap must be at least 8bpp.
477 *
478 * XXX This really belongs in fb, so it can be aware of tiling and etc.
479 */
480CARD32 uxa_get_pixmap_first_pixel(PixmapPtr pPixmap)
481{
482	CARD32 pixel;
483	void *fb;
484
485	if (!uxa_prepare_access(&pPixmap->drawable, NULL, UXA_ACCESS_RO))
486		return 0;
487
488	fb = pPixmap->devPrivate.ptr;
489
490	switch (pPixmap->drawable.bitsPerPixel) {
491	case 32:
492		pixel = *(CARD32 *) fb;
493		break;
494	case 16:
495		pixel = *(CARD16 *) fb;
496		break;
497	default:
498		pixel = *(CARD8 *) fb;
499		break;
500	}
501	uxa_finish_access(&pPixmap->drawable);
502
503	return pixel;
504}
505