fbcopy.c revision 4642e01f
1/*
2 * Copyright © 1998 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include <stdlib.h>
28
29#include "fb.h"
30
31void
32fbCopyNtoN (DrawablePtr	pSrcDrawable,
33	    DrawablePtr	pDstDrawable,
34	    GCPtr	pGC,
35	    BoxPtr	pbox,
36	    int		nbox,
37	    int		dx,
38	    int		dy,
39	    Bool	reverse,
40	    Bool	upsidedown,
41	    Pixel	bitplane,
42	    void	*closure)
43{
44    CARD8	alu = pGC ? pGC->alu : GXcopy;
45    FbBits	pm = pGC ? fbGetGCPrivate(pGC)->pm : FB_ALLONES;
46    FbBits	*src;
47    FbStride	srcStride;
48    int		srcBpp;
49    int		srcXoff, srcYoff;
50    FbBits	*dst;
51    FbStride	dstStride;
52    int		dstBpp;
53    int		dstXoff, dstYoff;
54
55    fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
56    fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
57
58    while (nbox--)
59    {
60#ifndef FB_ACCESS_WRAPPER /* pixman_blt() doesn't support accessors yet */
61	if (pm == FB_ALLONES && alu == GXcopy && !reverse &&
62	    !upsidedown)
63	{
64	    if (!pixman_blt ((uint32_t *)src, (uint32_t *)dst, srcStride, dstStride, srcBpp, dstBpp,
65			     (pbox->x1 + dx + srcXoff),
66			     (pbox->y1 + dy + srcYoff),
67			     (pbox->x1 + dstXoff),
68			     (pbox->y1 + dstYoff),
69			     (pbox->x2 - pbox->x1),
70			     (pbox->y2 - pbox->y1)))
71		goto fallback;
72	    else
73		goto next;
74	}
75    fallback:
76#endif
77	fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride,
78	       srcStride,
79	       (pbox->x1 + dx + srcXoff) * srcBpp,
80
81	       dst + (pbox->y1 + dstYoff) * dstStride,
82	       dstStride,
83	       (pbox->x1 + dstXoff) * dstBpp,
84
85	       (pbox->x2 - pbox->x1) * dstBpp,
86	       (pbox->y2 - pbox->y1),
87
88	       alu,
89	       pm,
90	       dstBpp,
91
92	       reverse,
93	       upsidedown);
94#ifndef FB_ACCESS_WRAPPER
95    next:
96#endif
97	pbox++;
98    }
99    fbFinishAccess (pDstDrawable);
100    fbFinishAccess (pSrcDrawable);
101}
102
103void
104fbCopy1toN (DrawablePtr	pSrcDrawable,
105	    DrawablePtr	pDstDrawable,
106	    GCPtr	pGC,
107	    BoxPtr	pbox,
108	    int		nbox,
109	    int		dx,
110	    int		dy,
111	    Bool	reverse,
112	    Bool	upsidedown,
113	    Pixel	bitplane,
114	    void	*closure)
115{
116    FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
117    FbBits	*src;
118    FbStride	srcStride;
119    int		srcBpp;
120    int		srcXoff, srcYoff;
121    FbBits	*dst;
122    FbStride	dstStride;
123    int		dstBpp;
124    int		dstXoff, dstYoff;
125
126    fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
127    fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
128
129    while (nbox--)
130    {
131	if (dstBpp == 1)
132	{
133	    fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride,
134		   srcStride,
135		   (pbox->x1 + dx + srcXoff) * srcBpp,
136
137		   dst + (pbox->y1 + dstYoff) * dstStride,
138		   dstStride,
139		   (pbox->x1 + dstXoff) * dstBpp,
140
141		   (pbox->x2 - pbox->x1) * dstBpp,
142		   (pbox->y2 - pbox->y1),
143
144		   FbOpaqueStipple1Rop(pGC->alu,
145				       pGC->fgPixel,pGC->bgPixel),
146		   pPriv->pm,
147		   dstBpp,
148
149		   reverse,
150		   upsidedown);
151	}
152	else
153	{
154	    fbBltOne ((FbStip *) (src + (pbox->y1 + dy + srcYoff) * srcStride),
155		      srcStride*(FB_UNIT/FB_STIP_UNIT),
156		      (pbox->x1 + dx + srcXoff),
157
158		      dst + (pbox->y1 + dstYoff) * dstStride,
159		      dstStride,
160		      (pbox->x1 + dstXoff) * dstBpp,
161		      dstBpp,
162
163		      (pbox->x2 - pbox->x1) * dstBpp,
164		      (pbox->y2 - pbox->y1),
165
166		      pPriv->and, pPriv->xor,
167		      pPriv->bgand, pPriv->bgxor);
168	}
169	pbox++;
170    }
171
172    fbFinishAccess (pDstDrawable);
173    fbFinishAccess (pSrcDrawable);
174}
175
176void
177fbCopyNto1 (DrawablePtr	pSrcDrawable,
178	    DrawablePtr	pDstDrawable,
179	    GCPtr	pGC,
180	    BoxPtr	pbox,
181	    int		nbox,
182	    int		dx,
183	    int		dy,
184	    Bool	reverse,
185	    Bool	upsidedown,
186	    Pixel	bitplane,
187	    void	*closure)
188{
189    FbGCPrivPtr	pPriv = fbGetGCPrivate (pGC);
190
191    while (nbox--)
192    {
193	if (pDstDrawable->bitsPerPixel == 1)
194	{
195	    FbBits	*src;
196	    FbStride    srcStride;
197	    int		srcBpp;
198	    int		srcXoff, srcYoff;
199
200	    FbStip	*dst;
201	    FbStride    dstStride;
202	    int		dstBpp;
203	    int		dstXoff, dstYoff;
204
205	    fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
206	    fbGetStipDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
207	    fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride,
208			srcStride,
209			(pbox->x1 + dx + srcXoff) * srcBpp,
210			srcBpp,
211
212			dst + (pbox->y1 + dstYoff) * dstStride,
213			dstStride,
214			(pbox->x1 + dstXoff) * dstBpp,
215
216			(pbox->x2 - pbox->x1) * srcBpp,
217			(pbox->y2 - pbox->y1),
218
219			(FbStip) pPriv->and, (FbStip) pPriv->xor,
220			(FbStip) pPriv->bgand, (FbStip) pPriv->bgxor,
221			bitplane);
222	    fbFinishAccess (pDstDrawable);
223	    fbFinishAccess (pSrcDrawable);
224	}
225	else
226	{
227	    FbBits	*src;
228	    FbStride    srcStride;
229	    int		srcBpp;
230	    int         srcXoff, srcYoff;
231
232	    FbBits	*dst;
233	    FbStride    dstStride;
234	    int		dstBpp;
235	    int		dstXoff, dstYoff;
236
237	    FbStip	*tmp;
238	    FbStride    tmpStride;
239	    int		width, height;
240
241	    width = pbox->x2 - pbox->x1;
242	    height = pbox->y2 - pbox->y1;
243
244	    tmpStride = ((width + FB_STIP_MASK) >> FB_STIP_SHIFT);
245	    tmp = xalloc (tmpStride * height * sizeof (FbStip));
246	    if (!tmp)
247		return;
248
249	    fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff);
250	    fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
251
252	    fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride,
253			srcStride,
254			(pbox->x1 + dx + srcXoff) * srcBpp,
255			srcBpp,
256
257			tmp,
258			tmpStride,
259			0,
260
261			width * srcBpp,
262			height,
263
264			fbAndStip(GXcopy,FB_ALLONES,FB_ALLONES),
265			fbXorStip(GXcopy,FB_ALLONES,FB_ALLONES),
266			fbAndStip(GXcopy,0,FB_ALLONES),
267			fbXorStip(GXcopy,0,FB_ALLONES),
268			bitplane);
269	    fbBltOne (tmp,
270		      tmpStride,
271		      0,
272
273		      dst + (pbox->y1 + dstYoff) * dstStride,
274		      dstStride,
275		      (pbox->x1 + dstXoff) * dstBpp,
276		      dstBpp,
277
278		      width * dstBpp,
279		      height,
280
281		      pPriv->and, pPriv->xor,
282		      pPriv->bgand, pPriv->bgxor);
283	    xfree (tmp);
284
285	    fbFinishAccess (pDstDrawable);
286	    fbFinishAccess (pSrcDrawable);
287	}
288	pbox++;
289    }
290}
291
292void
293fbCopyRegion (DrawablePtr   pSrcDrawable,
294	      DrawablePtr   pDstDrawable,
295	      GCPtr	    pGC,
296	      RegionPtr	    pDstRegion,
297	      int	    dx,
298	      int	    dy,
299	      fbCopyProc    copyProc,
300	      Pixel	    bitPlane,
301	      void	    *closure)
302{
303    int		careful;
304    Bool	reverse;
305    Bool	upsidedown;
306    BoxPtr	pbox;
307    int		nbox;
308    BoxPtr	pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp;
309
310    pbox = REGION_RECTS(pDstRegion);
311    nbox = REGION_NUM_RECTS(pDstRegion);
312
313    /* XXX we have to err on the side of safety when both are windows,
314     * because we don't know if IncludeInferiors is being used.
315     */
316    careful = ((pSrcDrawable == pDstDrawable) ||
317	       ((pSrcDrawable->type == DRAWABLE_WINDOW) &&
318		(pDstDrawable->type == DRAWABLE_WINDOW)));
319
320    pboxNew1 = NULL;
321    pboxNew2 = NULL;
322    if (careful && dy < 0)
323    {
324	upsidedown = TRUE;
325
326	if (nbox > 1)
327	{
328	    /* keep ordering in each band, reverse order of bands */
329	    pboxNew1 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox);
330	    if(!pboxNew1)
331		return;
332	    pboxBase = pboxNext = pbox+nbox-1;
333	    while (pboxBase >= pbox)
334	    {
335		while ((pboxNext >= pbox) &&
336		       (pboxBase->y1 == pboxNext->y1))
337		    pboxNext--;
338		pboxTmp = pboxNext+1;
339		while (pboxTmp <= pboxBase)
340		{
341		    *pboxNew1++ = *pboxTmp++;
342		}
343		pboxBase = pboxNext;
344	    }
345	    pboxNew1 -= nbox;
346	    pbox = pboxNew1;
347	}
348    }
349    else
350    {
351	/* walk source top to bottom */
352	upsidedown = FALSE;
353    }
354
355    if (careful && dx < 0)
356    {
357	/* walk source right to left */
358	if (dy <= 0)
359	    reverse = TRUE;
360	else
361	    reverse = FALSE;
362
363	if (nbox > 1)
364	{
365	    /* reverse order of rects in each band */
366	    pboxNew2 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox);
367	    if(!pboxNew2)
368	    {
369		if (pboxNew1)
370		    xfree(pboxNew1);
371		return;
372	    }
373	    pboxBase = pboxNext = pbox;
374	    while (pboxBase < pbox+nbox)
375	    {
376		while ((pboxNext < pbox+nbox) &&
377		       (pboxNext->y1 == pboxBase->y1))
378		    pboxNext++;
379		pboxTmp = pboxNext;
380		while (pboxTmp != pboxBase)
381		{
382		    *pboxNew2++ = *--pboxTmp;
383		}
384		pboxBase = pboxNext;
385	    }
386	    pboxNew2 -= nbox;
387	    pbox = pboxNew2;
388	}
389    }
390    else
391    {
392	/* walk source left to right */
393	reverse = FALSE;
394    }
395
396    (*copyProc) (pSrcDrawable,
397		 pDstDrawable,
398		 pGC,
399		 pbox,
400		 nbox,
401		 dx, dy,
402		 reverse, upsidedown, bitPlane, closure);
403
404    if (pboxNew1)
405	xfree (pboxNew1);
406    if (pboxNew2)
407	xfree (pboxNew2);
408}
409
410RegionPtr
411fbDoCopy (DrawablePtr	pSrcDrawable,
412	  DrawablePtr	pDstDrawable,
413	  GCPtr		pGC,
414	  int		xIn,
415	  int		yIn,
416	  int		widthSrc,
417	  int		heightSrc,
418	  int		xOut,
419	  int		yOut,
420	  fbCopyProc	copyProc,
421	  Pixel		bitPlane,
422	  void		*closure)
423{
424    RegionPtr	prgnSrcClip = NULL; /* may be a new region, or just a copy */
425    Bool	freeSrcClip = FALSE;
426    RegionPtr	prgnExposed = NULL;
427    RegionRec	rgnDst;
428    int		dx;
429    int		dy;
430    int		numRects;
431    int         box_x1;
432    int         box_y1;
433    int         box_x2;
434    int         box_y2;
435    Bool	fastSrc = FALSE;    /* for fast clipping with pixmap source */
436    Bool	fastDst = FALSE;    /* for fast clipping with one rect dest */
437    Bool	fastExpose = FALSE; /* for fast exposures with pixmap source */
438
439    /* Short cut for unmapped windows */
440
441    if (pDstDrawable->type == DRAWABLE_WINDOW &&
442	!((WindowPtr)pDstDrawable)->realized)
443    {
444	return NULL;
445    }
446
447    if ((pSrcDrawable != pDstDrawable) &&
448	pSrcDrawable->pScreen->SourceValidate)
449    {
450	(*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc);
451    }
452
453    /* Compute source clip region */
454    if (pSrcDrawable->type == DRAWABLE_PIXMAP)
455    {
456	if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE))
457	    prgnSrcClip = fbGetCompositeClip(pGC);
458	else
459	    fastSrc = TRUE;
460    }
461    else
462    {
463	if (pGC->subWindowMode == IncludeInferiors)
464	{
465	    /*
466	     * XFree86 DDX empties the border clip when the
467	     * VT is inactive, make sure the region isn't empty
468	     */
469	    if (!((WindowPtr) pSrcDrawable)->parent &&
470		REGION_NOTEMPTY (pSrcDrawable->pScreen,
471				 &((WindowPtr) pSrcDrawable)->borderClip))
472	    {
473		/*
474		 * special case bitblt from root window in
475		 * IncludeInferiors mode; just like from a pixmap
476		 */
477		fastSrc = TRUE;
478	    }
479	    else if ((pSrcDrawable == pDstDrawable) &&
480		     (pGC->clientClipType == CT_NONE))
481	    {
482		prgnSrcClip = fbGetCompositeClip(pGC);
483	    }
484	    else
485	    {
486		prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
487		freeSrcClip = TRUE;
488	    }
489	}
490	else
491	{
492	    prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
493	}
494    }
495
496    xIn += pSrcDrawable->x;
497    yIn += pSrcDrawable->y;
498
499    xOut += pDstDrawable->x;
500    yOut += pDstDrawable->y;
501
502    box_x1 = xIn;
503    box_y1 = yIn;
504    box_x2 = xIn + widthSrc;
505    box_y2 = yIn + heightSrc;
506
507    dx = xIn - xOut;
508    dy = yIn - yOut;
509
510    /* Don't create a source region if we are doing a fast clip */
511    if (fastSrc)
512    {
513	RegionPtr cclip;
514
515	fastExpose = TRUE;
516	/*
517	 * clip the source; if regions extend beyond the source size,
518 	 * make sure exposure events get sent
519	 */
520	if (box_x1 < pSrcDrawable->x)
521	{
522	    box_x1 = pSrcDrawable->x;
523	    fastExpose = FALSE;
524	}
525	if (box_y1 < pSrcDrawable->y)
526	{
527	    box_y1 = pSrcDrawable->y;
528	    fastExpose = FALSE;
529	}
530	if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
531	{
532	    box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
533	    fastExpose = FALSE;
534	}
535	if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
536	{
537	    box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
538	    fastExpose = FALSE;
539	}
540
541	/* Translate and clip the dst to the destination composite clip */
542        box_x1 -= dx;
543        box_x2 -= dx;
544        box_y1 -= dy;
545        box_y2 -= dy;
546
547	/* If the destination composite clip is one rectangle we can
548	   do the clip directly.  Otherwise we have to create a full
549	   blown region and call intersect */
550
551	cclip = fbGetCompositeClip(pGC);
552        if (REGION_NUM_RECTS(cclip) == 1)
553        {
554	    BoxPtr pBox = REGION_RECTS(cclip);
555
556	    if (box_x1 < pBox->x1) box_x1 = pBox->x1;
557	    if (box_x2 > pBox->x2) box_x2 = pBox->x2;
558	    if (box_y1 < pBox->y1) box_y1 = pBox->y1;
559	    if (box_y2 > pBox->y2) box_y2 = pBox->y2;
560	    fastDst = TRUE;
561	}
562    }
563
564    /* Check to see if the region is empty */
565    if (box_x1 >= box_x2 || box_y1 >= box_y2)
566    {
567	REGION_NULL(pGC->pScreen, &rgnDst);
568    }
569    else
570    {
571        BoxRec	box;
572	box.x1 = box_x1;
573	box.y1 = box_y1;
574	box.x2 = box_x2;
575	box.y2 = box_y2;
576	REGION_INIT(pGC->pScreen, &rgnDst, &box, 1);
577    }
578
579    /* Clip against complex source if needed */
580    if (!fastSrc)
581    {
582	REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip);
583	REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy);
584    }
585
586    /* Clip against complex dest if needed */
587    if (!fastDst)
588    {
589	REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst,
590			 fbGetCompositeClip(pGC));
591    }
592
593    /* Do bit blitting */
594    numRects = REGION_NUM_RECTS(&rgnDst);
595    if (numRects && widthSrc && heightSrc)
596	fbCopyRegion (pSrcDrawable, pDstDrawable, pGC,
597		      &rgnDst, dx, dy, copyProc, bitPlane, closure);
598
599    /* Pixmap sources generate a NoExposed (we return NULL to do this) */
600    if (!fastExpose && pGC->fExpose)
601	prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
602					xIn - pSrcDrawable->x,
603					yIn - pSrcDrawable->y,
604					widthSrc, heightSrc,
605					xOut - pDstDrawable->x,
606					yOut - pDstDrawable->y,
607					(unsigned long) bitPlane);
608    REGION_UNINIT(pGC->pScreen, &rgnDst);
609    if (freeSrcClip)
610	REGION_DESTROY(pGC->pScreen, prgnSrcClip);
611    fbValidateDrawable (pDstDrawable);
612    return prgnExposed;
613}
614
615RegionPtr
616fbCopyArea (DrawablePtr	pSrcDrawable,
617	    DrawablePtr	pDstDrawable,
618	    GCPtr	pGC,
619	    int		xIn,
620	    int		yIn,
621	    int		widthSrc,
622	    int		heightSrc,
623	    int		xOut,
624	    int		yOut)
625{
626    fbCopyProc	copy;
627
628#ifdef FB_24_32BIT
629    if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
630	copy = fb24_32CopyMtoN;
631    else
632#endif
633	copy = fbCopyNtoN;
634    return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
635		     widthSrc, heightSrc, xOut, yOut, copy, 0, 0);
636}
637
638RegionPtr
639fbCopyPlane (DrawablePtr    pSrcDrawable,
640	     DrawablePtr    pDstDrawable,
641	     GCPtr	    pGC,
642	     int	    xIn,
643	     int	    yIn,
644	     int	    widthSrc,
645	     int	    heightSrc,
646	     int	    xOut,
647	     int	    yOut,
648	     unsigned long  bitplane)
649{
650    if (pSrcDrawable->bitsPerPixel > 1)
651	return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
652			 xIn, yIn, widthSrc, heightSrc,
653			 xOut, yOut, fbCopyNto1, (Pixel) bitplane, 0);
654    else if (bitplane & 1)
655	return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
656			 widthSrc, heightSrc, xOut, yOut, fbCopy1toN,
657			 (Pixel) bitplane, 0);
658    else
659	return miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
660				 xIn, yIn,
661				 widthSrc,
662				 heightSrc,
663				 xOut, yOut, bitplane);
664}
665