1
2#ifdef HAVE_XORG_CONFIG_H
3#include <xorg-config.h>
4#endif
5
6#include "misc.h"
7#include "xf86.h"
8#include "xf86_OSproc.h"
9
10#include <X11/X.h>
11#include "scrnintstr.h"
12#include "xf86str.h"
13#include "xaa.h"
14#include "xaalocal.h"
15#include "migc.h"
16#include "gcstruct.h"
17#include "pixmapstr.h"
18
19/*
20  Written mostly by Harm Hanemaayer (H.Hanemaayer@inter.nl.net).
21 */
22
23
24RegionPtr
25XAACopyArea(
26    DrawablePtr pSrcDrawable,
27    DrawablePtr pDstDrawable,
28    GC *pGC,
29    int srcx, int srcy,
30    int width, int height,
31    int dstx, int dsty )
32{
33    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
34
35    if(pDstDrawable->type == DRAWABLE_WINDOW) {
36	if((pSrcDrawable->type == DRAWABLE_WINDOW) ||
37		IS_OFFSCREEN_PIXMAP(pSrcDrawable)){
38	    if(infoRec->ScreenToScreenBitBlt &&
39	     CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) &&
40	     CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) &&
41	     CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags))
42            return (XAABitBlt( pSrcDrawable, pDstDrawable,
43		pGC, srcx, srcy, width, height, dstx, dsty,
44		XAADoBitBlt, 0L));
45	} else {
46	    if(infoRec->WritePixmap &&
47	     ((pDstDrawable->bitsPerPixel == pSrcDrawable->bitsPerPixel) ||
48		((pDstDrawable->bitsPerPixel == 24) &&
49		(pSrcDrawable->bitsPerPixel == 32) &&
50		(infoRec->WritePixmapFlags & CONVERT_32BPP_TO_24BPP))) &&
51	     CHECK_ROP(pGC,infoRec->WritePixmapFlags) &&
52	     CHECK_ROPSRC(pGC,infoRec->WritePixmapFlags) &&
53	     CHECK_PLANEMASK(pGC,infoRec->WritePixmapFlags) &&
54	     CHECK_NO_GXCOPY(pGC,infoRec->WritePixmapFlags))
55            return (XAABitBlt( pSrcDrawable, pDstDrawable,
56		pGC, srcx, srcy, width, height, dstx, dsty,
57		XAADoImageWrite, 0L));
58	}
59    } else if(IS_OFFSCREEN_PIXMAP(pDstDrawable)){
60	if((pSrcDrawable->type == DRAWABLE_WINDOW) ||
61		IS_OFFSCREEN_PIXMAP(pSrcDrawable)){
62	    if(infoRec->ScreenToScreenBitBlt &&
63	     CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) &&
64	     CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) &&
65	     CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags))
66            return (XAABitBlt( pSrcDrawable, pDstDrawable,
67		pGC, srcx, srcy, width, height, dstx, dsty,
68		XAADoBitBlt, 0L));
69	}
70    }
71
72    return (XAAFallbackOps.CopyArea(pSrcDrawable, pDstDrawable, pGC,
73   	    srcx, srcy, width, height, dstx, dsty));
74}
75
76
77void
78XAADoBitBlt(
79    DrawablePtr	    pSrc,
80    DrawablePtr	    pDst,
81    GC		    *pGC,
82    RegionPtr	    prgnDst,
83    DDXPointPtr	    pptSrc )
84{
85    int nbox, careful;
86    BoxPtr pbox, pboxTmp, pboxNext, pboxBase, pboxNew1, pboxNew2;
87    DDXPointPtr pptTmp, pptNew1, pptNew2;
88    int xdir, ydir;
89    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
90
91    /* XXX we have to err on the side of safety when both are windows,
92     * because we don't know if IncludeInferiors is being used.
93     */
94    careful = ((pSrc == pDst) ||
95               ((pSrc->type == DRAWABLE_WINDOW) &&
96                (pDst->type == DRAWABLE_WINDOW)));
97
98    pbox = RegionRects(prgnDst);
99    nbox = RegionNumRects(prgnDst);
100
101    pboxNew1 = NULL;
102    pptNew1 = NULL;
103    pboxNew2 = NULL;
104    pptNew2 = NULL;
105    if (careful && (pptSrc->y < pbox->y1)) {
106        /* walk source botttom to top */
107	ydir = -1;
108
109	if (nbox > 1) {
110	    /* keep ordering in each band, reverse order of bands */
111	    pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec) * nbox);
112	    if(!pboxNew1)
113		return;
114	    pptNew1 = (DDXPointPtr)malloc(sizeof(DDXPointRec) * nbox);
115	    if(!pptNew1) {
116	        free(pboxNew1);
117	        return;
118	    }
119	    pboxBase = pboxNext = pbox+nbox-1;
120	    while (pboxBase >= pbox) {
121	        while ((pboxNext >= pbox) &&
122		       (pboxBase->y1 == pboxNext->y1))
123		    pboxNext--;
124	        pboxTmp = pboxNext+1;
125	        pptTmp = pptSrc + (pboxTmp - pbox);
126	        while (pboxTmp <= pboxBase) {
127		    *pboxNew1++ = *pboxTmp++;
128		    *pptNew1++ = *pptTmp++;
129	        }
130	        pboxBase = pboxNext;
131	    }
132	    pboxNew1 -= nbox;
133	    pbox = pboxNew1;
134	    pptNew1 -= nbox;
135	    pptSrc = pptNew1;
136        }
137    } else {
138	/* walk source top to bottom */
139	ydir = 1;
140    }
141
142    if (careful && (pptSrc->x < pbox->x1)) {
143	/* walk source right to left */
144        xdir = -1;
145
146	if (nbox > 1) {
147	    /* reverse order of rects in each band */
148	    pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec) * nbox);
149	    pptNew2 = (DDXPointPtr)malloc(sizeof(DDXPointRec) * nbox);
150	    if(!pboxNew2 || !pptNew2) {
151		free(pptNew2);
152		free(pboxNew2);
153		if (pboxNew1) {
154		    free(pptNew1);
155		    free(pboxNew1);
156		}
157	        return;
158	    }
159	    pboxBase = pboxNext = pbox;
160	    while (pboxBase < pbox+nbox) {
161	        while ((pboxNext < pbox+nbox) &&
162		       (pboxNext->y1 == pboxBase->y1))
163		    pboxNext++;
164	        pboxTmp = pboxNext;
165	        pptTmp = pptSrc + (pboxTmp - pbox);
166	        while (pboxTmp != pboxBase) {
167		    *pboxNew2++ = *--pboxTmp;
168		    *pptNew2++ = *--pptTmp;
169	        }
170	        pboxBase = pboxNext;
171	    }
172	    pboxNew2 -= nbox;
173	    pbox = pboxNew2;
174	    pptNew2 -= nbox;
175	    pptSrc = pptNew2;
176	}
177    } else {
178	/* walk source left to right */
179        xdir = 1;
180    }
181
182    (*infoRec->ScreenToScreenBitBlt)(infoRec->pScrn, nbox, pptSrc, pbox,
183	xdir, ydir, pGC->alu, pGC->planemask);
184
185    if (pboxNew2) {
186	free(pptNew2);
187	free(pboxNew2);
188    }
189    if (pboxNew1) {
190	free(pptNew1);
191	free(pboxNew1);
192    }
193
194}
195
196void
197XAADoImageWrite(
198    DrawablePtr	    pSrc,
199    DrawablePtr	    pDst,
200    GC		    *pGC,
201    RegionPtr	    prgnDst,
202    DDXPointPtr	    pptSrc )
203{
204    int srcwidth;
205    unsigned char* psrcBase;			/* start of image */
206    unsigned char* srcPntr;			/* index into the image */
207    BoxPtr pbox = RegionRects(prgnDst);
208    int nbox = RegionNumRects(prgnDst);
209    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
210    int Bpp = pSrc->bitsPerPixel >> 3;
211
212    psrcBase = (unsigned char *)((PixmapPtr)pSrc)->devPrivate.ptr;
213    srcwidth = (int)((PixmapPtr)pSrc)->devKind;
214
215    for(; nbox; pbox++, pptSrc++, nbox--) {
216        srcPntr = psrcBase + (pptSrc->y * srcwidth) + (pptSrc->x * Bpp);
217
218	(*infoRec->WritePixmap)(infoRec->pScrn, pbox->x1, pbox->y1,
219		pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, srcPntr, srcwidth,
220		pGC->alu, pGC->planemask, -1, pSrc->bitsPerPixel, pSrc->depth);
221    }
222}
223
224
225void
226XAADoImageRead(
227    DrawablePtr	    pSrc,
228    DrawablePtr	    pDst,
229    GC		    *pGC,
230    RegionPtr	    prgnDst,
231    DDXPointPtr	    pptSrc )
232{
233    int dstwidth;
234    unsigned char* pdstBase;			/* start of image */
235    unsigned char* dstPntr;			/* index into the image */
236    BoxPtr pbox = RegionRects(prgnDst);
237    int nbox = RegionNumRects(prgnDst);
238    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
239    int Bpp = pSrc->bitsPerPixel >> 3;  /* wouldn't get here unless both
240                                           src and dst have same bpp */
241
242    pdstBase = (unsigned char *)((PixmapPtr)pDst)->devPrivate.ptr;
243    dstwidth = (int)((PixmapPtr)pDst)->devKind;
244
245    for(; nbox; pbox++, pptSrc++, nbox--) {
246        dstPntr = pdstBase + (pbox->y1 * dstwidth) + (pbox->x1 * Bpp);
247
248	(*infoRec->ReadPixmap)(infoRec->pScrn, pptSrc->x, pptSrc->y,
249		pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, dstPntr, dstwidth,
250		pSrc->bitsPerPixel, pSrc->depth);
251    }
252}
253
254
255void
256XAAScreenToScreenBitBlt(
257    ScrnInfoPtr pScrn,
258    int nbox,
259    DDXPointPtr pptSrc,
260    BoxPtr pbox,
261    int xdir, int ydir,
262    int alu,
263    unsigned int planemask )
264{
265    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
266    int dirsetup;
267
268    if ((!(infoRec->CopyAreaFlags & ONLY_TWO_BITBLT_DIRECTIONS)
269    || (xdir == ydir)) &&
270    (!(infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT)
271    || (xdir == 1))) {
272        (*infoRec->SetupForScreenToScreenCopy)(pScrn,
273            xdir, ydir, alu, planemask, -1);
274        for (; nbox; pbox++, pptSrc++, nbox--)
275            (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y,
276                pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
277        SET_SYNC_FLAG(infoRec);
278        return;
279    }
280
281   if (infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT) {
282        /*
283         * This is the case of a chip that only supports xdir = 1,
284         * with ydir = 1 or ydir = -1, but we have xdir = -1.
285         */
286        (*infoRec->SetupForScreenToScreenCopy)(pScrn,
287            1, ydir, alu, planemask, -1);
288        for (; nbox; pbox++, pptSrc++, nbox--)
289            if (pptSrc->y != pbox->y1 || pptSrc->x >= pbox->x1)
290                /* No problem. Do a xdir = 1 blit instead. */
291                (*infoRec->SubsequentScreenToScreenCopy)(pScrn,
292                    pptSrc->x, pptSrc->y, pbox->x1, pbox->y1,
293                    pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
294            else
295            {
296                /*
297                 * This is the difficult case. Needs striping into
298                 * non-overlapping horizontal chunks.
299                 */
300                int stripeWidth, w, fullStripes, extra, i;
301                stripeWidth = 16;
302                w = pbox->x2 - pbox->x1;
303                if (pbox->x1 - pptSrc->x < stripeWidth)
304                    stripeWidth = pbox->x1 - pptSrc->x;
305                fullStripes = w / stripeWidth;
306                extra = w % stripeWidth;
307
308                /* First, take care of the little bit on the far right */
309                if (extra)
310                    (*infoRec->SubsequentScreenToScreenCopy)(pScrn,
311                        pptSrc->x + fullStripes * stripeWidth, pptSrc->y,
312                        pbox->x1 + fullStripes * stripeWidth, pbox->y1,
313                        extra, pbox->y2 - pbox->y1);
314
315                /* Now, take care of the rest of the blit */
316                for (i = fullStripes - 1; i >= 0; i--)
317                    (*infoRec->SubsequentScreenToScreenCopy)(pScrn,
318                        pptSrc->x + i * stripeWidth, pptSrc->y,
319                        pbox->x1 + i * stripeWidth, pbox->y1,
320                        stripeWidth, pbox->y2 - pbox->y1);
321            }
322        SET_SYNC_FLAG(infoRec);
323        return;
324    }
325
326    /*
327     * Now the case of a chip that only supports xdir = ydir = 1 or
328     * xdir = ydir = -1, but we have xdir != ydir.
329     */
330    dirsetup = 0;	/* No direction set up yet. */
331    for (; nbox; pbox++, pptSrc++, nbox--) {
332        if (xdir == 1 && pptSrc->y != pbox->y1) {
333            /* Do a xdir = ydir = -1 blit instead. */
334            if (dirsetup != -1) {
335                (*infoRec->SetupForScreenToScreenCopy)(pScrn,
336                    -1, -1, alu, planemask, -1);
337                dirsetup = -1;
338            }
339            (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y,
340                pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
341        }
342        else if (xdir == -1 && pptSrc->y != pbox->y1) {
343            /* Do a xdir = ydir = 1 blit instead. */
344            if (dirsetup != 1) {
345                (*infoRec->SetupForScreenToScreenCopy)(pScrn,
346                    1, 1, alu, planemask, -1);
347                dirsetup = 1;
348            }
349            (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y,
350                pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
351        }
352        else
353            if (xdir == 1) {
354                /*
355                 * xdir = 1, ydir = -1.
356                 * Perform line-by-line xdir = ydir = 1 blits, going up.
357                 */
358                int i;
359                if (dirsetup != 1) {
360                    (*infoRec->SetupForScreenToScreenCopy)(pScrn,
361                        1, 1, alu, planemask, -1);
362                    dirsetup = 1;
363                }
364                for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
365                    (*infoRec->SubsequentScreenToScreenCopy)(pScrn,
366                        pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i,
367                        pbox->x2 - pbox->x1, 1);
368            }
369            else {
370                /*
371                 * xdir = -1, ydir = 1.
372                 * Perform line-by-line xdir = ydir = -1 blits, going down.
373                 */
374                int i;
375                if (dirsetup != -1) {
376                    (*infoRec->SetupForScreenToScreenCopy)(pScrn,
377                        -1, -1, alu, planemask, -1);
378                    dirsetup = -1;
379                }
380                for (i = 0; i < pbox->y2 - pbox->y1; i++)
381                    (*infoRec->SubsequentScreenToScreenCopy)(pScrn,
382                        pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i,
383                        pbox->x2 - pbox->x1, 1);
384            }
385    } /* next box */
386    SET_SYNC_FLAG(infoRec);
387}
388