saa_unaccel.c revision 591e32d7
1/*
2 * Copyright © 1999 Keith Packard
3 * Copyright 2011 VMWare, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Author: Based on "exa_unaccel.c"
26 * Author: Thomas Hellstrom <thellstrom@vmware.com>
27 */
28
29#include "saa_priv.h"
30#include "saa.h"
31#include "mipict.h"
32
33/**
34 * Calls saa_prepare_access with SAA_ACCESS_R for the tile, if that is the
35 * current fill style.
36 *
37 * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
38 * 1bpp and never in fb, so we don't worry about them.
39 * We should worry about them for completeness sake and going forward.
40 */
41static Bool
42saa_prepare_access_gc(GCPtr pGC)
43{
44    if (pGC->stipple)
45	if (!saa_pad_read(&pGC->stipple->drawable))
46	    return FALSE;
47    if (pGC->fillStyle == FillTiled)
48	if (!saa_pad_read(&pGC->tile.pixmap->drawable)) {
49	    if (pGC->stipple)
50		saa_fad_read(&pGC->stipple->drawable);
51	    return FALSE;
52	}
53    return TRUE;
54}
55
56/**
57 * Finishes access to the tile in the GC, if used.
58 */
59static void
60saa_finish_access_gc(GCPtr pGC)
61{
62    if (pGC->fillStyle == FillTiled)
63	saa_fad_read(&pGC->tile.pixmap->drawable);
64    if (pGC->stipple)
65	saa_fad_read(&pGC->stipple->drawable);
66}
67
68void
69saa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
70		     DDXPointPtr ppt, int *pwidth, int fSorted)
71{
72    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
73    struct saa_gc_priv *sgc = saa_gc(pGC);
74    saa_access_t access;
75
76    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_location(pDrawable)));
77
78    sscreen->fallback_count++;
79    if (saa_pad_write(pDrawable, NULL, FALSE, &access)) {
80	if (saa_prepare_access_gc(pGC)) {
81	    saa_swap(sgc, pGC, ops);
82	    pGC->ops->FillSpans(pDrawable, pGC, nspans, ppt, pwidth, fSorted);
83	    saa_swap(sgc, pGC, ops);
84	    saa_finish_access_gc(pGC);
85	}
86	saa_fad_write(pDrawable, access);
87    }
88    sscreen->fallback_count--;
89}
90
91static void
92saa_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
93		    DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
94{
95    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
96    struct saa_gc_priv *sgc = saa_gc(pGC);
97    saa_access_t access
98	SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
99
100    sscreen->fallback_count++;
101    if (saa_pad_write(pDrawable, NULL, FALSE, &access)) {
102	saa_swap(sgc, pGC, ops);
103	pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
104	saa_swap(sgc, pGC, ops);
105	saa_fad_write(pDrawable, access);
106    }
107    sscreen->fallback_count--;
108}
109
110static void
111saa_check_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
112		    int x, int y, int w, int h, int leftPad, int format,
113		    char *bits)
114{
115    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
116    struct saa_gc_priv *sgc = saa_gc(pGC);
117    saa_access_t access;
118
119    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
120    sscreen->fallback_count++;
121    if (saa_pad_write(pDrawable, pGC, TRUE, &access)) {
122	saa_swap(sgc, pGC, ops);
123	pGC->ops->PutImage(pDrawable, pGC, depth, x, y, w, h, leftPad,
124			   format, bits);
125	saa_swap(sgc, pGC, ops);
126	saa_fad_write(pDrawable, access);
127    }
128    sscreen->fallback_count--;
129}
130
131RegionPtr
132saa_boxes_to_region(ScreenPtr pScreen, int nbox, BoxPtr pbox, int ordering)
133{
134    xRectangle *rects = malloc(nbox * sizeof(*rects));
135    int i;
136    RegionPtr reg;
137
138    if (!rects)
139	return NULL;
140
141    for (i = 0; i < nbox; i++) {
142	rects[i].x = pbox[i].x1;
143	rects[i].y = pbox[i].y1;
144	rects[i].width = pbox[i].x2 - pbox[i].x1;
145	rects[i].height = pbox[i].y2 - pbox[i].y1;
146    }
147
148    reg = RECTS_TO_REGION(pScreen, nbox, rects, ordering);
149    free(rects);
150    return reg;
151}
152
153void
154saa_check_copy_nton(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
155		    BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
156		    Bool upsidedown, Pixel bitplane, void *closure)
157{
158    ScreenPtr pScreen = pSrc->pScreen;
159    struct saa_screen_priv *sscreen = saa_screen(pScreen);
160    RegionPtr reg, readback;
161    int src_xoff, src_yoff, dst_xoff, dst_yoff;
162    struct saa_gc_priv *sgc = saa_gc(pGC);
163    PixmapPtr src_pixmap;
164    PixmapPtr dst_pixmap;
165    saa_access_t access = SAA_ACCESS_R;
166    int ordering;
167
168    sscreen->fallback_count++;
169    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
170		  saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
171
172    src_pixmap = saa_get_pixmap(pSrc, &src_xoff, &src_yoff);
173    dst_pixmap = saa_get_pixmap(pDst, &dst_xoff, &dst_yoff);
174
175    ordering = (nbox == 1 || (dx > 0 && dy > 0) ||
176		(pDst != pSrc &&
177		 (pDst->type != DRAWABLE_WINDOW ||
178		  pSrc->type != DRAWABLE_WINDOW))) ? CT_YXBANDED : CT_UNSORTED;
179
180    reg = saa_boxes_to_region(pScreen, nbox, pbox, ordering);
181    if (!reg)
182	return;
183
184    REGION_TRANSLATE(pScreen, reg, src_xoff + dx, src_yoff + dy);
185    if (!saa_prepare_access_pixmap(src_pixmap, SAA_ACCESS_R, reg))
186	goto out_no_access;
187
188    REGION_TRANSLATE(pScreen, reg, dst_xoff - dx - src_xoff,
189		     dst_yoff - dy - src_yoff);
190
191    if (saa_gc_reads_destination(pDst, pGC)) {
192	readback = reg;
193	access = SAA_ACCESS_RW;
194    } else {
195	readback = NULL;
196	access = SAA_ACCESS_W;
197    }
198
199    if (!saa_prepare_access_pixmap(dst_pixmap, access, readback))
200	goto out_no_dst;
201
202    saa_swap(sgc, pGC, ops);
203    while (nbox--) {
204	pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx,
205			   pbox->y1 - pSrc->y + dy,
206			   pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
207			   pbox->x1 - pDst->x, pbox->y1 - pDst->y);
208	pbox++;
209    }
210
211    saa_swap(sgc, pGC, ops);
212    saa_finish_access_pixmap(dst_pixmap, access);
213    saa_pixmap_dirty(dst_pixmap, FALSE, reg);
214 out_no_dst:
215    saa_fad_read(pSrc);
216 out_no_access:
217    sscreen->fallback_count--;
218    REGION_DESTROY(pScreen, reg);
219}
220
221RegionPtr
222saa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
223		    int srcx, int srcy, int w, int h, int dstx, int dsty)
224{
225    RegionPtr ret = NULL;
226    struct saa_gc_priv *sgc = saa_gc(pGC);
227    saa_access_t access;
228    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
229
230    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
231		  saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
232    sscreen->fallback_count++;
233    if (!saa_pad_read_box(pSrc, srcx, srcy, w, h))
234	goto out_no_access;
235    if (!saa_pad_write(pDst, pGC, TRUE, &access))
236	goto out_no_dst;
237
238    saa_swap(sgc, pGC, ops);
239    ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
240    saa_swap(sgc, pGC, ops);
241
242    saa_fad_write(pDst, access);
243 out_no_dst:
244    saa_fad_read(pSrc);
245 out_no_access:
246    sscreen->fallback_count--;
247
248    return ret;
249}
250
251static RegionPtr
252saa_check_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
253		     int srcx, int srcy, int w, int h, int dstx, int dsty,
254		     unsigned long bitplane)
255{
256    RegionPtr ret = NULL;
257    struct saa_gc_priv *sgc = saa_gc(pGC);
258    saa_access_t access;
259    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
260
261    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
262		  saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
263    sscreen->fallback_count++;
264    if (!saa_pad_read_box(pSrc, srcx, srcy, w, h))
265	goto out_no_src;
266    if (!saa_pad_write(pDst, pGC, TRUE, &access))
267	goto out_no_dst;
268
269    saa_swap(sgc, pGC, ops);
270    ret = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
271			      bitplane);
272    saa_swap(sgc, pGC, ops);
273
274    saa_fad_write(pDst, access);
275 out_no_dst:
276    saa_fad_read(pSrc);
277 out_no_src:
278    sscreen->fallback_count--;
279
280    return ret;
281}
282
283static void
284saa_check_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
285		     DDXPointPtr pptInit)
286{
287    struct saa_gc_priv *sgc = saa_gc(pGC);
288    saa_access_t access;
289    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
290
291    sscreen->fallback_count++;
292    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
293    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
294	goto out_no_access;
295    saa_swap(sgc, pGC, ops);
296    pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit);
297    saa_swap(sgc, pGC, ops);
298    saa_fad_write(pDrawable, access);
299
300 out_no_access:
301    sscreen->fallback_count--;
302}
303
304static void
305saa_check_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
306		     int mode, int npt, DDXPointPtr ppt)
307{
308    struct saa_gc_priv *sgc = saa_gc(pGC);
309    saa_access_t access;
310    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
311
312    SAA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
313		  pDrawable, saa_drawable_loc(pDrawable),
314		  pGC->lineWidth, mode, npt));
315
316    sscreen->fallback_count++;
317    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
318	goto out_no_access;
319    if (!saa_prepare_access_gc(pGC))
320	goto out_no_gc;
321    saa_swap(sgc, pGC, ops);
322    pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt);
323    saa_swap(sgc, pGC, ops);
324    saa_finish_access_gc(pGC);
325 out_no_gc:
326    saa_fad_write(pDrawable, access);
327 out_no_access:
328    sscreen->fallback_count--;
329}
330
331static void
332saa_check_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
333		       int nsegInit, xSegment * pSegInit)
334{
335    struct saa_gc_priv *sgc = saa_gc(pGC);
336    saa_access_t access;
337    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
338
339    SAA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
340		  saa_drawable_loc(pDrawable), pGC->lineWidth, nsegInit));
341
342    sscreen->fallback_count++;
343    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
344	goto out_no_access;;
345    if (!saa_prepare_access_gc(pGC))
346	goto out_no_gc;
347    saa_swap(sgc, pGC, ops);
348    pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit);
349    saa_swap(sgc, pGC, ops);
350    saa_finish_access_gc(pGC);
351 out_no_gc:
352    saa_fad_write(pDrawable, access);
353 out_no_access:
354    sscreen->fallback_count--;
355}
356
357static void
358saa_check_poly_arc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
359{
360    struct saa_gc_priv *sgc = saa_gc(pGC);
361    saa_access_t access;
362    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
363
364    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
365
366    sscreen->fallback_count++;
367    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
368	goto out_no_access;;
369    if (!saa_prepare_access_gc(pGC))
370	goto out_no_gc;
371    saa_swap(sgc, pGC, ops);
372    pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs);
373    saa_swap(sgc, pGC, ops);
374    saa_finish_access_gc(pGC);
375 out_no_gc:
376    saa_fad_write(pDrawable, access);
377 out_no_access:
378    sscreen->fallback_count--;
379}
380
381
382/**
383 * saa_check_poly_fill_rect_noreadback - PolyFillRect avoiding unnecessary readbacks.
384 *
385 * @pDrawable: The drawable on which to fill.
386 * @pGC: Pointer to the GC to use.
387 * @nrect: Number of rectangles to fill.
388 * @xRectangle: Pointer to rectangles to fill.
389 *
390 * During a standard saa polyFillRect, the damage region is usually the bounding
391 * box of all rectangles. Since we mark the software pixmap dirty based on that
392 * damage region, we need to read all of it back first, even if the fill operation
393 * itself doesn't read anything. This version of polyFillRect improves on that by
394 * only damaging the area we actually fill. If it's a non-reading fill we thus don't
395 * need to read back anything, but this may come at the cost of increased dirty
396 * region fragmentation. In any case, this greatly improves on the performance of
397 * shaped windows on top of accelerated contents, for example unscaled OSD in xine.
398 */
399static Bool
400saa_check_poly_fill_rect_noreadback(DrawablePtr pDrawable, GCPtr pGC,
401				    int nrect, xRectangle *prect)
402{
403    struct saa_gc_priv *sgc = saa_gc(pGC);
404    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
405    RegionPtr region;
406    saa_access_t access;
407    Bool ret;
408    PixmapPtr pPixmap;
409    xRectangle *prect_save = prect;
410    int xoff, yoff;
411    struct saa_pixmap *spix;
412
413    if (!nrect)
414	return TRUE;
415
416    sscreen->fallback_count++;
417
418    pPixmap = saa_get_pixmap(pDrawable, &xoff, &yoff);
419    spix = saa_get_saa_pixmap(pPixmap);
420    region = RECTS_TO_REGION(pGC->pScreen, nrect, prect, CT_UNSORTED);
421    if (!region)
422	goto out_no_region;
423
424    REGION_TRANSLATE(pGC->pScreen, region, pDrawable->x, pDrawable->y);
425    REGION_INTERSECT(pGC->pScreen, region, fbGetCompositeClip(pGC), region);
426    REGION_TRANSLATE(pGC->pScreen, region, xoff, yoff);
427
428    access = SAA_ACCESS_W;
429    if (saa_gc_reads_destination(pDrawable, pGC)) {
430	/*
431	 * We need to do a readback anyway. In case of more than an
432	 * ad hoc number of say 4 rectangles, we might as well do a
433	 * readback of the whole damage area to avoid fragmentation.
434	 */
435	if (REGION_NUM_RECTS(region) > 4)
436	    goto out_no_access;
437
438	access |= SAA_ACCESS_R;
439	ret = saa_prepare_access_pixmap(pPixmap, access, region);
440    } else
441	ret = saa_prepare_access_pixmap(pPixmap, access, NULL);
442
443    if (!ret)
444	goto out_no_access;
445
446    if (!saa_prepare_access_gc(pGC))
447	goto out_no_gc;
448
449    saa_swap(sgc, pGC, ops);
450    pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect_save);
451    saa_swap(sgc, pGC, ops);
452
453    saa_finish_access_gc(pGC);
454    saa_finish_access_pixmap(pPixmap, access);
455
456    if (spix->damage) {
457	REGION_INTERSECT(pGC->pScreen, region, region,
458			 saa_pix_damage_pending(spix));
459	saa_pixmap_dirty(pPixmap, FALSE, region);
460    }
461
462    REGION_DESTROY(pGC->pScreen, region);
463
464    sscreen->fallback_count--;
465
466    return TRUE;
467
468  out_no_gc:
469    saa_finish_access_pixmap(pPixmap, access);
470  out_no_access:
471    REGION_DESTROY(pGC->pScreen, region);
472  out_no_region:
473    sscreen->fallback_count--;
474
475    return FALSE;
476}
477
478void
479saa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
480			 int nrect, xRectangle * prect)
481{
482    struct saa_gc_priv *sgc = saa_gc(pGC);
483    saa_access_t access;
484    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
485
486    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
487
488    if (saa_check_poly_fill_rect_noreadback(pDrawable, pGC, nrect, prect))
489	return;
490
491    sscreen->fallback_count++;
492
493    /*
494     * TODO: Use @prect for readback / damaging instead of
495     * the damage region. This may fragment the dirty regions more
496     * but should avoid unnecessary readbacks.
497     */
498    if (!saa_pad_write(pDrawable, pGC, FALSE, &access))
499	goto out_no_access;;
500    if (!saa_prepare_access_gc(pGC))
501	goto out_no_gc;
502    saa_swap(sgc, pGC, ops);
503    pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect);
504    saa_swap(sgc, pGC, ops);
505    saa_finish_access_gc(pGC);
506 out_no_gc:
507    saa_fad_write(pDrawable, access);
508 out_no_access:
509    sscreen->fallback_count--;
510}
511
512static void
513saa_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
514			  int x, int y, unsigned int nglyph,
515			  CharInfoPtr * ppci, pointer pglyphBase)
516{
517    struct saa_gc_priv *sgc = saa_gc(pGC);
518    saa_access_t access;
519    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
520
521    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
522
523    sscreen->fallback_count++;
524    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
525	goto out_no_access;;
526    if (!saa_prepare_access_gc(pGC))
527	goto out_no_gc;
528    saa_swap(sgc, pGC, ops);
529    pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
530    saa_swap(sgc, pGC, ops);
531    saa_finish_access_gc(pGC);
532 out_no_gc:
533    saa_fad_write(pDrawable, access);
534 out_no_access:
535    sscreen->fallback_count--;
536}
537
538static void
539saa_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
540			 int x, int y, unsigned int nglyph,
541			 CharInfoPtr * ppci, pointer pglyphBase)
542{
543    struct saa_gc_priv *sgc = saa_gc(pGC);
544    saa_access_t access;
545    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
546
547    SAA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
548		  saa_drawable_loc(pDrawable), pGC->fillStyle, pGC->alu));
549
550    sscreen->fallback_count++;
551    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
552	goto out_no_access;;
553    if (!saa_prepare_access_gc(pGC))
554	goto out_no_gc;
555    saa_swap(sgc, pGC, ops);
556    pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
557    saa_swap(sgc, pGC, ops);
558    saa_finish_access_gc(pGC);
559 out_no_gc:
560    saa_fad_write(pDrawable, access);
561 out_no_access:
562    sscreen->fallback_count--;
563}
564
565static void
566saa_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
567		      DrawablePtr pDrawable, int w, int h, int x, int y)
568{
569    struct saa_gc_priv *sgc = saa_gc(pGC);
570    saa_access_t access;
571    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
572
573    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
574		  saa_drawable_loc(&pBitmap->drawable),
575		  saa_drawable_loc(pDrawable)));
576
577    sscreen->fallback_count++;
578    if (!saa_pad_write(pDrawable, pGC, TRUE, &access))
579	goto out_no_access;;
580    if (!saa_pad_read_box(&pBitmap->drawable, 0, 0, w, h))
581	goto out_no_src;
582    if (!saa_prepare_access_gc(pGC))
583	goto out_no_gc;
584    saa_swap(sgc, pGC, ops);
585    pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
586    saa_swap(sgc, pGC, ops);
587    saa_finish_access_gc(pGC);
588 out_no_gc:
589    saa_fad_read(&pBitmap->drawable);
590 out_no_src:
591    saa_fad_write(pDrawable, access);
592 out_no_access:
593    sscreen->fallback_count--;
594}
595
596static void
597saa_check_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
598{
599    DrawablePtr pDrawable = &pWin->drawable;
600    ScreenPtr pScreen = pDrawable->pScreen;
601    struct saa_screen_priv *sscreen = saa_screen(pScreen);
602    int xoff, yoff;
603    PixmapPtr pPixmap = saa_get_pixmap(&pWin->drawable, &xoff, &yoff);
604    Bool ret;
605
606    SAA_FALLBACK(("from %p\n", pWin));
607
608    /* Only need the source bits, the destination region will be overwritten */
609
610    sscreen->fallback_count++;
611    REGION_TRANSLATE(pScreen, prgnSrc, xoff, yoff);
612    ret = saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_R, prgnSrc);
613    REGION_TRANSLATE(pScreen, prgnSrc, -xoff, -yoff);
614    if (!ret)
615	goto out_no_access;;
616
617    if (saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_W, NULL)) {
618	struct saa_pixmap *spix;
619	RegionRec rgnDst;
620
621	REGION_NULL(pScreen, &rgnDst);
622	REGION_COPY(pScreen, &rgnDst, prgnSrc);
623
624	saa_swap(sscreen, pScreen, CopyWindow);
625	pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
626	saa_swap(sscreen, pScreen, CopyWindow);
627	saa_finish_access_pixmap(pPixmap, SAA_ACCESS_W);
628
629	spix = saa_get_saa_pixmap(pPixmap);
630	if (spix->damage) {
631	    int dx, dy;
632
633	    dx = ptOldOrg.x - pWin->drawable.x;
634	    dy = ptOldOrg.y - pWin->drawable.y;
635	    REGION_TRANSLATE(pScreen, &rgnDst, -dx, -dy);
636	    REGION_INTERSECT(pSreen, &rgnDst, &pWin->borderClip, &rgnDst);
637	    REGION_TRANSLATE(pScreen, &rgnDst, xoff, yoff);
638
639	    REGION_INTERSECT(pScreen, &rgnDst, &rgnDst,
640			     saa_pix_damage_pending(spix));
641	    saa_pixmap_dirty(pPixmap, FALSE, &rgnDst);
642	}
643	REGION_UNINIT(pScreen, &rgnDst);
644    }
645    saa_fad_read(pDrawable);
646 out_no_access:
647    sscreen->fallback_count--;
648}
649
650#ifdef RENDER
651
652#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10)
653static void
654saa_src_validate(DrawablePtr pDrawable,
655		 int x,
656		 int y, int width, int height, unsigned int subWindowMode)
657#else
658static void
659saa_src_validate(DrawablePtr pDrawable, int x, int y, int width, int height)
660#endif
661{
662    ScreenPtr pScreen = pDrawable->pScreen;
663    struct saa_screen_priv *sscreen = saa_screen(pScreen);
664    int xoff, yoff;
665    BoxRec box;
666    RegionRec reg;
667    RegionPtr dst;
668
669    (void) saa_get_pixmap(pDrawable, &xoff, &yoff);
670    box.x1 = x + xoff;
671    box.y1 = y + yoff;
672    box.x2 = box.x1 + width;
673    box.y2 = box.y1 + height;
674
675    dst = (sscreen->srcDraw == pDrawable) ?
676	&sscreen->srcReg : &sscreen->maskReg;
677
678    REGION_INIT(pScreen, &reg, &box, 1);
679    REGION_UNION(pScreen, dst, dst, &reg);
680    REGION_UNINIT(pScreen, &reg);
681
682    if (sscreen->saved_SourceValidate) {
683	saa_swap(sscreen, pScreen, SourceValidate);
684	pScreen->SourceValidate(pDrawable, x, y, width, height
685#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10)
686				, subWindowMode
687#endif
688	    );
689	saa_swap(sscreen, pScreen, SourceValidate);
690    }
691}
692
693static void
694saa_check_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
695		    unsigned int format, unsigned long planeMask, char *d)
696{
697    ScreenPtr pScreen = pDrawable->pScreen;
698    struct saa_screen_priv *sscreen = saa_screen(pScreen);
699
700    SAA_FALLBACK(("from %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
701
702    sscreen->fallback_count++;
703    if (!saa_pad_read_box(pDrawable, x, y, w, h))
704	goto out_no_access;;
705    saa_swap(sscreen, pScreen, GetImage);
706    pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d);
707    saa_swap(sscreen, pScreen, GetImage);
708    saa_fad_read(pDrawable);
709 out_no_access:
710    sscreen->fallback_count--;
711}
712
713static void
714saa_check_get_spans(DrawablePtr pDrawable,
715		    int wMax,
716		    DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
717{
718    ScreenPtr pScreen = pDrawable->pScreen;
719    struct saa_screen_priv *sscreen = saa_screen(pScreen);
720
721    SAA_FALLBACK(("from %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
722
723    sscreen->fallback_count++;
724    if (!saa_pad_read(pDrawable))
725	goto out_no_access;;
726    saa_swap(sscreen, pScreen, GetSpans);
727    pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
728    saa_swap(sscreen, pScreen, GetSpans);
729    saa_fad_read(pDrawable);
730 out_no_access:
731    sscreen->fallback_count--;
732}
733
734/*
735 * Compute composite regions taking transforms into account.
736 * The caller must provide a pointer to an initialized dst_reg,
737 * and the function returns pointers to set up source- and mask regions.
738 * The source and mask regions must be uninitialized after use.
739 */
740
741Bool
742saa_compute_composite_regions(ScreenPtr pScreen,
743			      PicturePtr pSrc,
744			      PicturePtr pMask,
745			      PicturePtr pDst,
746			      INT16 xSrc, INT16 ySrc, INT16 xMask,
747			      INT16 yMask, INT16 xDst,
748			      INT16 yDst, INT16 width, INT16 height,
749			      RegionPtr dst_reg,
750			      RegionPtr *src_reg,
751			      RegionPtr *mask_reg)
752{
753    struct saa_screen_priv *sscreen = saa_screen(pScreen);
754    RegionPtr srcReg = NULL;
755    RegionPtr maskReg = NULL;
756    Bool ret;
757    int xoff, yoff;
758
759    *src_reg = NULL;
760    *mask_reg = NULL;
761
762    if (pSrc->pDrawable) {
763	REGION_NULL(pScreen, &sscreen->srcReg);
764	srcReg = &sscreen->srcReg;
765	sscreen->srcDraw = pSrc->pDrawable;
766	if (pSrc != pDst)
767	    REGION_TRANSLATE(pScreen, pSrc->pCompositeClip,
768			     -pSrc->pDrawable->x, -pSrc->pDrawable->y);
769    }
770
771    if (pMask && pMask->pDrawable) {
772	REGION_NULL(pScreen, &sscreen->maskReg);
773	maskReg = &sscreen->maskReg;
774	if (pMask != pDst && pMask != pSrc)
775	    REGION_TRANSLATE(pScreen, pMask->pCompositeClip,
776			     -pMask->pDrawable->x, -pMask->pDrawable->y);
777    }
778
779    REGION_TRANSLATE(pScreen, pDst->pCompositeClip,
780		     -pDst->pDrawable->x, -pDst->pDrawable->y);
781
782    sscreen->saved_SourceValidate = saa_src_validate;
783    saa_swap(sscreen, pScreen, SourceValidate);
784    ret = miComputeCompositeRegion(dst_reg, pSrc, pMask, pDst,
785				   xSrc, ySrc, xMask, yMask,
786				   xDst, yDst, width, height);
787    saa_swap(sscreen, pScreen, SourceValidate);
788
789    REGION_TRANSLATE(pScreen, pDst->pCompositeClip,
790		     pDst->pDrawable->x, pDst->pDrawable->y);
791    if (pSrc->pDrawable && pSrc != pDst)
792	REGION_TRANSLATE(pScreen, pSrc->pCompositeClip,
793			 pSrc->pDrawable->x, pSrc->pDrawable->y);
794    if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc)
795	REGION_TRANSLATE(pScreen, pMask->pCompositeClip,
796			 pMask->pDrawable->x, pMask->pDrawable->y);
797
798    if (!ret) {
799	if (srcReg)
800	    REGION_UNINIT(pScreen, srcReg);
801	if (maskReg)
802	    REGION_UNINIT(pScreen, maskReg);
803
804	return FALSE;
805    }
806
807    *src_reg = srcReg;
808    *mask_reg = maskReg;
809
810    /*
811     * Translate dst region to pixmap space.
812     */
813    (void) saa_get_pixmap(pDst->pDrawable, &xoff, &yoff);
814    REGION_TRANSLATE(pScreen, dst_reg, pDst->pDrawable->x + xoff,
815		     pDst->pDrawable->y + yoff);
816
817
818    return TRUE;
819}
820
821static Bool
822saa_prepare_composite_reg(ScreenPtr pScreen,
823			  CARD8 op,
824			  PicturePtr pSrc,
825			  PicturePtr pMask,
826			  PicturePtr pDst,
827			  INT16 xSrc,
828			  INT16 ySrc,
829			  INT16 xMask,
830			  INT16 yMask,
831			  INT16 xDst,
832			  INT16 yDst,
833			  CARD16 width,
834			  CARD16 height,
835			  RegionPtr src_region,
836			  RegionPtr mask_region,
837			  RegionPtr dst_region,
838			  saa_access_t * access)
839{
840    RegionPtr dstReg = NULL;
841    PixmapPtr pSrcPix = NULL;
842    PixmapPtr pMaskPix = NULL;
843    PixmapPtr pDstPix;
844    struct saa_pixmap *dst_spix;
845
846    *access = SAA_ACCESS_W;
847
848    if (pSrc->pDrawable)
849	pSrcPix = saa_get_drawable_pixmap(pSrc->pDrawable);
850    if (pMask && pMask->pDrawable)
851	pMaskPix = saa_get_drawable_pixmap(pMask->pDrawable);
852
853    /*
854     * Don't limit alphamaps readbacks for now until we've figured out how that
855     * should be done.
856     */
857
858    if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
859	if (!saa_pad_read(pSrc->alphaMap->pDrawable))
860	    goto out_no_src_alpha;
861    if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
862	if (!saa_pad_read(pMask->alphaMap->pDrawable))
863	    goto out_no_mask_alpha;
864    if (pSrcPix)
865	if (!saa_prepare_access_pixmap(pSrcPix, SAA_ACCESS_R, src_region))
866	    goto out_no_src;
867    if (pMaskPix)
868	if (!saa_prepare_access_pixmap(pMaskPix, SAA_ACCESS_R, mask_region))
869	    goto out_no_mask;
870
871    pDstPix = saa_get_drawable_pixmap(pDst->pDrawable);
872    dst_spix = saa_get_saa_pixmap(pDstPix);
873
874    if (dst_spix->damage && saa_op_reads_destination(op)) {
875	dstReg = dst_region;
876	*access |= SAA_ACCESS_R;
877    }
878
879    if (pDst->alphaMap && pDst->alphaMap->pDrawable)
880	if (!saa_prepare_access_pixmap
881	    (saa_get_drawable_pixmap(pDst->alphaMap->pDrawable),
882	     *access, dstReg))
883	    goto out_no_dst_alpha;
884
885    if (!saa_prepare_access_pixmap(pDstPix, *access, dstReg))
886	goto out_no_dst;
887
888    return TRUE;
889
890 out_no_dst:
891    LogMessage(X_ERROR, "No dst\n");
892    saa_finish_access_pixmap
893	(saa_get_drawable_pixmap(pDst->alphaMap->pDrawable), *access);
894 out_no_dst_alpha:
895    LogMessage(X_ERROR, "No dst alpha\n");
896    if (pMaskPix)
897	saa_finish_access_pixmap(pMaskPix, SAA_ACCESS_R);
898 out_no_mask:
899    LogMessage(X_ERROR, "No mask\n");
900    if (pSrcPix)
901	saa_finish_access_pixmap(pSrcPix, SAA_ACCESS_R);
902 out_no_src:
903    LogMessage(X_ERROR, "No src\n");
904    if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
905	saa_fad_read(pMask->alphaMap->pDrawable);
906 out_no_mask_alpha:
907    LogMessage(X_ERROR, "No mask alpha\n");
908    if (pSrc && pSrc->alphaMap && pSrc->alphaMap->pDrawable)
909	saa_fad_read(pSrc->alphaMap->pDrawable);
910 out_no_src_alpha:
911    LogMessage(X_ERROR, "No src alpha\n");
912    return FALSE;
913
914}
915
916void
917saa_check_composite(CARD8 op,
918		    PicturePtr pSrc,
919		    PicturePtr pMask,
920		    PicturePtr pDst,
921		    INT16 xSrc,
922		    INT16 ySrc,
923		    INT16 xMask,
924		    INT16 yMask,
925		    INT16 xDst, INT16 yDst, CARD16 width, CARD16 height,
926		    RegionPtr src_region,
927		    RegionPtr mask_region,
928		    RegionPtr dst_region)
929{
930    ScreenPtr pScreen = pDst->pDrawable->pScreen;
931    PictureScreenPtr ps = GetPictureScreen(pScreen);
932    struct saa_screen_priv *sscreen = saa_screen(pScreen);
933    saa_access_t access;
934    PixmapPtr pixmap;
935
936    sscreen->fallback_count++;
937    if (!saa_prepare_composite_reg(pScreen, op, pSrc, pMask, pDst, xSrc,
938				   ySrc, xMask, yMask, xDst, yDst, width,
939				   height,
940				   src_region,
941				   mask_region,
942				   dst_region,
943				   &access)) {
944	goto out_no_access;;
945    }
946
947    saa_swap(sscreen, ps, Composite);
948    ps->Composite(op,
949		  pSrc,
950		  pMask,
951		  pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
952    saa_swap(sscreen, ps, Composite);
953    if (pMask && pMask->pDrawable != NULL)
954	saa_fad_read(pMask->pDrawable);
955    if (pSrc->pDrawable != NULL)
956	saa_fad_read(pSrc->pDrawable);
957    pixmap = saa_get_drawable_pixmap(pDst->pDrawable);
958    saa_finish_access_pixmap(pixmap, access);
959    saa_pixmap_dirty(pixmap, FALSE, dst_region);
960    if (pDst->alphaMap && pDst->alphaMap->pDrawable) {
961	pixmap = saa_get_drawable_pixmap(pDst->alphaMap->pDrawable);
962	saa_finish_access_pixmap(pixmap, access);
963	saa_pixmap_dirty(pixmap, FALSE, dst_region);
964    }
965    if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
966	saa_fad_read(pSrc->alphaMap->pDrawable);
967    if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
968	saa_fad_read(pMask->alphaMap->pDrawable);
969 out_no_access:
970    sscreen->fallback_count--;
971}
972
973static void
974saa_check_add_traps(PicturePtr pPicture,
975		    INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
976{
977    ScreenPtr pScreen = pPicture->pDrawable->pScreen;
978    PictureScreenPtr ps = GetPictureScreen(pScreen);
979    struct saa_screen_priv *sscreen = saa_screen(pScreen);
980    saa_access_t access;
981
982    SAA_FALLBACK(("to pict %p (%c)\n", saa_drawable_loc(pPicture->pDrawable)));
983
984    sscreen->fallback_count++;
985    if (!saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access))
986	goto out_no_access;
987    saa_swap(sscreen, ps, AddTraps);
988    ps->AddTraps(pPicture, x_off, y_off, ntrap, traps);
989    saa_swap(sscreen, ps, AddTraps);
990    saa_fad_write(pPicture->pDrawable, access);
991 out_no_access:
992    sscreen->fallback_count--;
993}
994
995#endif
996
997void
998saa_unaccel_setup(ScreenPtr pScreen)
999{
1000#ifdef RENDER
1001    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
1002#endif
1003    struct saa_screen_priv *sscreen = saa_screen(pScreen);
1004
1005    saa_wrap(sscreen, pScreen, GetImage, saa_check_get_image);
1006    saa_wrap(sscreen, pScreen, GetSpans, saa_check_get_spans);
1007    saa_wrap(sscreen, pScreen, CopyWindow, saa_check_copy_window);
1008
1009#ifdef RENDER
1010    if (ps) {
1011	saa_wrap(sscreen, ps, AddTraps, saa_check_add_traps);
1012    }
1013#endif
1014}
1015
1016void
1017saa_unaccel_takedown(ScreenPtr pScreen)
1018{
1019#ifdef RENDER
1020    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
1021#endif
1022    struct saa_screen_priv *sscreen = saa_screen(pScreen);
1023
1024    saa_unwrap(sscreen, pScreen, GetImage);
1025    saa_unwrap(sscreen, pScreen, GetSpans);
1026    saa_unwrap(sscreen, pScreen, CopyWindow);
1027
1028#ifdef RENDER
1029    if (ps) {
1030	saa_unwrap(sscreen, ps, AddTraps);
1031    }
1032#endif
1033}
1034
1035GCOps saa_gc_ops = {
1036    saa_check_fill_spans,
1037    saa_check_set_spans,
1038    saa_check_put_image,
1039    saa_copy_area,
1040    saa_check_copy_plane,
1041    saa_check_poly_point,
1042    saa_check_poly_lines,
1043    saa_check_poly_segment,
1044    miPolyRectangle,
1045    saa_check_poly_arc,
1046    miFillPolygon,
1047    saa_check_poly_fill_rect,
1048    miPolyFillArc,
1049    miPolyText8,
1050    miPolyText16,
1051    miImageText8,
1052    miImageText16,
1053    saa_check_image_glyph_blt,
1054    saa_check_poly_glyph_blt,
1055    saa_check_push_pixels,
1056};
1057