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
26/*
27 * These functions wrap the low-level fb rendering functions and
28 * synchronize framebuffer/accelerated drawing by stalling until
29 * the accelerator is idle
30 */
31
32/**
33 * Calls uxa_prepare_access with UXA_PREPARE_SRC for the tile, if that is the
34 * current fill style.
35 *
36 * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
37 * 1bpp and never in fb, so we don't worry about them.
38 * We should worry about them for completeness sake and going forward.
39 */
40Bool uxa_prepare_access_gc(GCPtr pGC)
41{
42	if (pGC->stipple)
43		if (!uxa_prepare_access(&pGC->stipple->drawable, UXA_ACCESS_RO))
44			return FALSE;
45	if (pGC->fillStyle == FillTiled)
46		if (!uxa_prepare_access
47		    (&pGC->tile.pixmap->drawable, UXA_ACCESS_RO)) {
48			if (pGC->stipple)
49				uxa_finish_access(&pGC->stipple->drawable, UXA_ACCESS_RO);
50			return FALSE;
51		}
52	return TRUE;
53}
54
55/**
56 * Finishes access to the tile in the GC, if used.
57 */
58void uxa_finish_access_gc(GCPtr pGC)
59{
60	if (pGC->fillStyle == FillTiled)
61		uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_ACCESS_RO);
62	if (pGC->stipple)
63		uxa_finish_access(&pGC->stipple->drawable, UXA_ACCESS_RO);
64}
65
66Bool uxa_picture_prepare_access(PicturePtr picture, int mode)
67{
68	if (picture->pDrawable == NULL)
69		return TRUE;
70
71	if (!uxa_prepare_access(picture->pDrawable, mode))
72		return FALSE;
73
74	if (picture->alphaMap &&
75	    !uxa_prepare_access(picture->alphaMap->pDrawable, mode)) {
76		uxa_finish_access(picture->pDrawable, mode);
77		return FALSE;
78	}
79
80	return TRUE;
81}
82
83void uxa_picture_finish_access(PicturePtr picture, int mode)
84{
85	if (picture->pDrawable == NULL)
86		return;
87
88	uxa_finish_access(picture->pDrawable, mode);
89	if (picture->alphaMap)
90		uxa_finish_access(picture->alphaMap->pDrawable, mode);
91}
92
93
94char uxa_drawable_location(DrawablePtr pDrawable)
95{
96	return uxa_drawable_is_offscreen(pDrawable) ? 's' : 'm';
97}
98
99void
100uxa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
101		     DDXPointPtr ppt, int *pwidth, int fSorted)
102{
103	ScreenPtr screen = pDrawable->pScreen;
104
105	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
106		      uxa_drawable_location(pDrawable)));
107	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
108		if (uxa_prepare_access_gc(pGC)) {
109			fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth,
110				    fSorted);
111			uxa_finish_access_gc(pGC);
112		}
113		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
114	}
115}
116
117void
118uxa_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
119		    DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
120{
121	ScreenPtr screen = pDrawable->pScreen;
122
123	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
124		      uxa_drawable_location(pDrawable)));
125	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
126		fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
127		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
128	}
129}
130
131void
132uxa_check_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
133		    int x, int y, int w, int h, int leftPad, int format,
134		    char *bits)
135{
136	ScreenPtr screen = pDrawable->pScreen;
137
138	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
139		      uxa_drawable_location(pDrawable)));
140	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
141		fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
142			   bits);
143		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
144	}
145}
146
147RegionPtr
148uxa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
149		    int srcx, int srcy, int w, int h, int dstx, int dsty)
150{
151	ScreenPtr screen = pSrc->pScreen;
152	RegionPtr ret = NULL;
153
154	UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
155		      uxa_drawable_location(pSrc),
156		      uxa_drawable_location(pDst)));
157	if (uxa_prepare_access(pDst, UXA_ACCESS_RW)) {
158		if (uxa_prepare_access(pSrc, UXA_ACCESS_RO)) {
159			ret =
160			    fbCopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
161				       dsty);
162			uxa_finish_access(pSrc, UXA_ACCESS_RO);
163		}
164		uxa_finish_access(pDst, UXA_ACCESS_RW);
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, UXA_ACCESS_RW)) {
181		if (uxa_prepare_access(pSrc, UXA_ACCESS_RO)) {
182			ret =
183			    fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
184					dsty, bitPlane);
185			uxa_finish_access(pSrc, UXA_ACCESS_RO);
186		}
187		uxa_finish_access(pDst, UXA_ACCESS_RW);
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, UXA_ACCESS_RW)) {
201		fbPolyPoint(pDrawable, pGC, mode, npt, pptInit);
202		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
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
212	UXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
213		      pDrawable, uxa_drawable_location(pDrawable),
214		      pGC->lineWidth, mode, npt));
215
216	if (pGC->lineWidth == 0) {
217		if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
218			if (uxa_prepare_access_gc(pGC)) {
219				fbPolyLine(pDrawable, pGC, mode, npt, ppt);
220				uxa_finish_access_gc(pGC);
221			}
222			uxa_finish_access(pDrawable, UXA_ACCESS_RW);
223		}
224		return;
225	}
226	/* fb calls mi functions in the lineWidth != 0 case. */
227	fbPolyLine(pDrawable, pGC, mode, npt, ppt);
228}
229
230void
231uxa_check_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
232		       int nsegInit, xSegment * pSegInit)
233{
234	ScreenPtr screen = pDrawable->pScreen;
235
236	UXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
237		      uxa_drawable_location(pDrawable), pGC->lineWidth,
238		      nsegInit));
239	if (pGC->lineWidth == 0) {
240		if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
241			if (uxa_prepare_access_gc(pGC)) {
242				fbPolySegment(pDrawable, pGC, nsegInit,
243					      pSegInit);
244				uxa_finish_access_gc(pGC);
245			}
246			uxa_finish_access(pDrawable, UXA_ACCESS_RW);
247		}
248		return;
249	}
250	/* fb calls mi functions in the lineWidth != 0 case. */
251	fbPolySegment(pDrawable, pGC, nsegInit, pSegInit);
252}
253
254void
255uxa_check_poly_arc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
256{
257	ScreenPtr screen = pDrawable->pScreen;
258
259	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
260		      uxa_drawable_location(pDrawable)));
261
262	/* Disable this as fbPolyArc can call miZeroPolyArc which in turn
263	 * can call accelerated functions, that as yet, haven't been notified
264	 * with uxa_finish_access().
265	 */
266#if 0
267	if (pGC->lineWidth == 0) {
268		if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
269			if (uxa_prepare_access_gc(pGC)) {
270				fbPolyArc(pDrawable, pGC, narcs, pArcs);
271				uxa_finish_access_gc(pGC);
272			}
273			uxa_finish_access(pDrawable, UXA_ACCESS_RW);
274		}
275		return;
276	}
277#endif
278	miPolyArc(pDrawable, pGC, narcs, pArcs);
279}
280
281void
282uxa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
283			 int nrect, xRectangle * prect)
284{
285	ScreenPtr screen = pDrawable->pScreen;
286
287	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
288		      uxa_drawable_location(pDrawable)));
289
290	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
291		if (uxa_prepare_access_gc(pGC)) {
292			fbPolyFillRect(pDrawable, pGC, nrect, prect);
293			uxa_finish_access_gc(pGC);
294		}
295		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
296	}
297}
298
299void
300uxa_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
301			  int x, int y, unsigned int nglyph,
302			  CharInfoPtr * ppci, pointer pglyphBase)
303{
304	ScreenPtr screen = pDrawable->pScreen;
305
306	UXA_FALLBACK(("to %p (%c)\n", pDrawable,
307		      uxa_drawable_location(pDrawable)));
308	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
309		if (uxa_prepare_access_gc(pGC)) {
310			fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
311					pglyphBase);
312			uxa_finish_access_gc(pGC);
313		}
314		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
315	}
316}
317
318void
319uxa_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
320			 int x, int y, unsigned int nglyph,
321			 CharInfoPtr * ppci, pointer pglyphBase)
322{
323	ScreenPtr screen = pDrawable->pScreen;
324
325	UXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
326		      uxa_drawable_location(pDrawable), pGC->fillStyle,
327		      pGC->alu));
328	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
329		if (uxa_prepare_access_gc(pGC)) {
330			fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
331				       pglyphBase);
332			uxa_finish_access_gc(pGC);
333		}
334		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
335	}
336}
337
338void
339uxa_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
340		      DrawablePtr pDrawable, int w, int h, int x, int y)
341{
342	ScreenPtr screen = pDrawable->pScreen;
343
344	UXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
345		      uxa_drawable_location(&pBitmap->drawable),
346		      uxa_drawable_location(pDrawable)));
347	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
348		if (uxa_prepare_access(&pBitmap->drawable, UXA_ACCESS_RO)) {
349			if (uxa_prepare_access_gc(pGC)) {
350				fbPushPixels(pGC, pBitmap, pDrawable, w, h, x,
351					     y);
352				uxa_finish_access_gc(pGC);
353			}
354			uxa_finish_access(&pBitmap->drawable, UXA_ACCESS_RO);
355		}
356		uxa_finish_access(pDrawable, UXA_ACCESS_RW);
357	}
358}
359
360void
361uxa_check_get_spans(DrawablePtr pDrawable,
362		    int wMax,
363		    DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
364{
365	ScreenPtr screen = pDrawable->pScreen;
366
367	UXA_FALLBACK(("from %p (%c)\n", pDrawable,
368		      uxa_drawable_location(pDrawable)));
369	if (uxa_prepare_access(pDrawable, UXA_ACCESS_RO)) {
370		fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
371		uxa_finish_access(pDrawable, UXA_ACCESS_RO);
372	}
373}
374
375void
376uxa_check_composite(CARD8 op,
377		    PicturePtr pSrc,
378		    PicturePtr pMask,
379		    PicturePtr pDst,
380		    INT16 xSrc, INT16 ySrc,
381		    INT16 xMask, INT16 yMask,
382		    INT16 xDst, INT16 yDst,
383		    CARD16 width, CARD16 height)
384{
385	ScreenPtr screen = pDst->pDrawable->pScreen;
386
387	UXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
388
389	if (uxa_picture_prepare_access(pDst, UXA_ACCESS_RW)) {
390		if (uxa_picture_prepare_access(pSrc, UXA_ACCESS_RO)) {
391			if (!pMask || uxa_picture_prepare_access(pMask, UXA_ACCESS_RO)) {
392				fbComposite(op, pSrc, pMask, pDst,
393					    xSrc, ySrc,
394					    xMask, yMask,
395					    xDst, yDst,
396					    width, height);
397				if (pMask)
398					uxa_picture_finish_access(pMask, UXA_ACCESS_RO);
399			}
400			uxa_picture_finish_access(pSrc, UXA_ACCESS_RO);
401		}
402		uxa_picture_finish_access(pDst, UXA_ACCESS_RW);
403	}
404}
405
406void
407uxa_check_add_traps(PicturePtr pPicture,
408		    INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
409{
410	ScreenPtr screen = pPicture->pDrawable->pScreen;
411
412	UXA_FALLBACK(("to pict %p (%c)\n", pPicture,
413		      uxa_drawable_location(pPicture->pDrawable)));
414	if (uxa_picture_prepare_access(pPicture, UXA_ACCESS_RW)) {
415		fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
416		uxa_picture_finish_access(pPicture, UXA_ACCESS_RW);
417	}
418}
419
420/**
421 * Gets the 0,0 pixel of a pixmap.  Used for doing solid fills of tiled pixmaps
422 * that happen to be 1x1.  Pixmap must be at least 8bpp.
423 *
424 * XXX This really belongs in fb, so it can be aware of tiling and etc.
425 */
426CARD32 uxa_get_pixmap_first_pixel(PixmapPtr pPixmap)
427{
428	CARD32 pixel;
429	void *fb;
430
431	if (!uxa_prepare_access(&pPixmap->drawable, UXA_ACCESS_RO))
432		return 0;
433
434	fb = pPixmap->devPrivate.ptr;
435
436	switch (pPixmap->drawable.bitsPerPixel) {
437	case 32:
438		pixel = *(CARD32 *) fb;
439		break;
440	case 16:
441		pixel = *(CARD16 *) fb;
442		break;
443	default:
444		pixel = *(CARD8 *) fb;
445		break;
446	}
447	uxa_finish_access(&pPixmap->drawable, UXA_ACCESS_RO);
448
449	return pixel;
450}
451