fbpixmap.c revision 05b261ec
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
31PixmapPtr
32fbCreatePixmapBpp (ScreenPtr pScreen, int width, int height, int depth, int bpp)
33{
34    PixmapPtr	pPixmap;
35    size_t	datasize;
36    size_t	paddedWidth;
37    int		adjust;
38    int		base;
39
40    paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits);
41    if (paddedWidth / 4 > 32767 || height > 32767)
42	return NullPixmap;
43    datasize = height * paddedWidth;
44    base = pScreen->totalPixmapSize;
45    adjust = 0;
46    if (base & 7)
47	adjust = 8 - (base & 7);
48    datasize += adjust;
49#ifdef FB_DEBUG
50    datasize += 2 * paddedWidth;
51#endif
52    pPixmap = AllocatePixmap(pScreen, datasize);
53    if (!pPixmap)
54	return NullPixmap;
55    pPixmap->drawable.type = DRAWABLE_PIXMAP;
56    pPixmap->drawable.class = 0;
57    pPixmap->drawable.pScreen = pScreen;
58    pPixmap->drawable.depth = depth;
59    pPixmap->drawable.bitsPerPixel = bpp;
60    pPixmap->drawable.id = 0;
61    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
62    pPixmap->drawable.x = 0;
63    pPixmap->drawable.y = 0;
64    pPixmap->drawable.width = width;
65    pPixmap->drawable.height = height;
66    pPixmap->devKind = paddedWidth;
67    pPixmap->refcnt = 1;
68    pPixmap->devPrivate.ptr = (pointer) ((char *)pPixmap + base + adjust);
69#ifdef FB_DEBUG
70    pPixmap->devPrivate.ptr = (void *) ((char *) pPixmap->devPrivate.ptr + paddedWidth);
71    fbInitializeDrawable (&pPixmap->drawable);
72#endif
73
74#ifdef COMPOSITE
75    pPixmap->screen_x = 0;
76    pPixmap->screen_y = 0;
77#endif
78
79    return pPixmap;
80}
81
82PixmapPtr
83fbCreatePixmap (ScreenPtr pScreen, int width, int height, int depth)
84{
85    int	bpp;
86    bpp = BitsPerPixel (depth);
87#ifdef FB_SCREEN_PRIVATE
88    if (bpp == 32 && depth <= 24)
89	bpp = fbGetScreenPrivate(pScreen)->pix32bpp;
90#endif
91    return fbCreatePixmapBpp (pScreen, width, height, depth, bpp);
92}
93
94Bool
95fbDestroyPixmap (PixmapPtr pPixmap)
96{
97    if(--pPixmap->refcnt)
98	return TRUE;
99    xfree(pPixmap);
100    return TRUE;
101}
102
103#define ADDRECT(reg,r,fr,rx1,ry1,rx2,ry2)			\
104if (((rx1) < (rx2)) && ((ry1) < (ry2)) &&			\
105    (!((reg)->data->numRects &&					\
106       ((r-1)->y1 == (ry1)) &&					\
107       ((r-1)->y2 == (ry2)) &&					\
108       ((r-1)->x1 <= (rx1)) &&					\
109       ((r-1)->x2 >= (rx2)))))					\
110{								\
111    if ((reg)->data->numRects == (reg)->data->size)		\
112    {								\
113	miRectAlloc(reg, 1);					\
114	fr = REGION_BOXPTR(reg);				\
115	r = fr + (reg)->data->numRects;				\
116    }								\
117    r->x1 = (rx1);						\
118    r->y1 = (ry1);						\
119    r->x2 = (rx2);						\
120    r->y2 = (ry2);						\
121    (reg)->data->numRects++;					\
122    if(r->x1 < (reg)->extents.x1)				\
123	(reg)->extents.x1 = r->x1;				\
124    if(r->x2 > (reg)->extents.x2)				\
125	(reg)->extents.x2 = r->x2;				\
126    r++;							\
127}
128
129/* Convert bitmap clip mask into clipping region.
130 * First, goes through each line and makes boxes by noting the transitions
131 * from 0 to 1 and 1 to 0.
132 * Then it coalesces the current line with the previous if they have boxes
133 * at the same X coordinates.
134 */
135RegionPtr
136fbPixmapToRegion(PixmapPtr pPix)
137{
138    register RegionPtr	pReg;
139    FbBits		*pw, w;
140    register int	ib;
141    int			width, h, base, rx1 = 0, crects;
142    FbBits		*pwLineEnd;
143    int			irectPrevStart, irectLineStart;
144    register BoxPtr	prectO, prectN;
145    BoxPtr		FirstRect, rects, prectLineStart;
146    Bool		fInBox, fSame;
147    register FbBits	mask0 = FB_ALLONES & ~FbScrRight(FB_ALLONES, 1);
148    FbBits		*pwLine;
149    int			nWidth;
150
151    pReg = REGION_CREATE(pPix->drawable.pScreen, NULL, 1);
152    if(!pReg)
153	return NullRegion;
154    FirstRect = REGION_BOXPTR(pReg);
155    rects = FirstRect;
156
157    fbPrepareAccess(&pPix->drawable);
158
159    pwLine = (FbBits *) pPix->devPrivate.ptr;
160    nWidth = pPix->devKind >> (FB_SHIFT-3);
161
162    width = pPix->drawable.width;
163    pReg->extents.x1 = width - 1;
164    pReg->extents.x2 = 0;
165    irectPrevStart = -1;
166    for(h = 0; h < pPix->drawable.height; h++)
167    {
168	pw = pwLine;
169	pwLine += nWidth;
170	irectLineStart = rects - FirstRect;
171	/* If the Screen left most bit of the word is set, we're starting in
172	 * a box */
173	if(READ(pw) & mask0)
174	{
175	    fInBox = TRUE;
176	    rx1 = 0;
177	}
178	else
179	    fInBox = FALSE;
180	/* Process all words which are fully in the pixmap */
181	pwLineEnd = pw + (width >> FB_SHIFT);
182	for (base = 0; pw < pwLineEnd; base += FB_UNIT)
183	{
184	    w = READ(pw++);
185	    if (fInBox)
186	    {
187		if (!~w)
188		    continue;
189	    }
190	    else
191	    {
192		if (!w)
193		    continue;
194	    }
195	    for(ib = 0; ib < FB_UNIT; ib++)
196	    {
197	        /* If the Screen left most bit of the word is set, we're
198		 * starting a box */
199		if(w & mask0)
200		{
201		    if(!fInBox)
202		    {
203			rx1 = base + ib;
204			/* start new box */
205			fInBox = TRUE;
206		    }
207		}
208		else
209		{
210		    if(fInBox)
211		    {
212			/* end box */
213			ADDRECT(pReg, rects, FirstRect,
214				rx1, h, base + ib, h + 1);
215			fInBox = FALSE;
216		    }
217		}
218		/* Shift the word VISUALLY left one. */
219		w = FbScrLeft(w, 1);
220	    }
221	}
222	if(width & FB_MASK)
223	{
224	    /* Process final partial word on line */
225	    w = READ(pw++);
226	    for(ib = 0; ib < (width & FB_MASK); ib++)
227	    {
228	        /* If the Screen left most bit of the word is set, we're
229		 * starting a box */
230		if(w & mask0)
231		{
232		    if(!fInBox)
233		    {
234			rx1 = base + ib;
235			/* start new box */
236			fInBox = TRUE;
237		    }
238		}
239		else
240		{
241		    if(fInBox)
242		    {
243			/* end box */
244			ADDRECT(pReg, rects, FirstRect,
245				rx1, h, base + ib, h + 1);
246			fInBox = FALSE;
247		    }
248		}
249		/* Shift the word VISUALLY left one. */
250		w = FbScrLeft(w, 1);
251	    }
252	}
253	/* If scanline ended with last bit set, end the box */
254	if(fInBox)
255	{
256	    ADDRECT(pReg, rects, FirstRect,
257		    rx1, h, base + (width & FB_MASK), h + 1);
258	}
259	/* if all rectangles on this line have the same x-coords as
260	 * those on the previous line, then add 1 to all the previous  y2s and
261	 * throw away all the rectangles from this line
262	 */
263	fSame = FALSE;
264	if(irectPrevStart != -1)
265	{
266	    crects = irectLineStart - irectPrevStart;
267	    if(crects == ((rects - FirstRect) - irectLineStart))
268	    {
269	        prectO = FirstRect + irectPrevStart;
270	        prectN = prectLineStart = FirstRect + irectLineStart;
271		fSame = TRUE;
272	        while(prectO < prectLineStart)
273		{
274		    if((prectO->x1 != prectN->x1) || (prectO->x2 != prectN->x2))
275		    {
276			  fSame = FALSE;
277			  break;
278		    }
279		    prectO++;
280		    prectN++;
281		}
282		if (fSame)
283		{
284		    prectO = FirstRect + irectPrevStart;
285		    while(prectO < prectLineStart)
286		    {
287			prectO->y2 += 1;
288			prectO++;
289		    }
290		    rects -= crects;
291		    pReg->data->numRects -= crects;
292		}
293	    }
294	}
295	if(!fSame)
296	    irectPrevStart = irectLineStart;
297    }
298    if (!pReg->data->numRects)
299	pReg->extents.x1 = pReg->extents.x2 = 0;
300    else
301    {
302	pReg->extents.y1 = REGION_BOXPTR(pReg)->y1;
303	pReg->extents.y2 = REGION_END(pReg)->y2;
304	if (pReg->data->numRects == 1)
305	{
306	    xfree(pReg->data);
307	    pReg->data = (RegDataPtr)NULL;
308	}
309    }
310
311    fbFinishAccess(&pPix->drawable);
312#ifdef DEBUG
313    if (!miValidRegion(pReg))
314	FatalError("Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__);
315#endif
316    return(pReg);
317}
318
319#ifdef FB_DEBUG
320
321#ifndef WIN32
322#include <stdio.h>
323#else
324#include <dbg.h>
325#endif
326
327static Bool
328fbValidateBits (FbStip *bits, int stride, FbStip data)
329{
330    while (stride--)
331    {
332	if (*bits != data)
333	{
334#ifdef WIN32
335	    NCD_DEBUG ((DEBUG_FAILURE, "fdValidateBits failed at 0x%x (is 0x%x want 0x%x)",
336			bits, *bits, data));
337#else
338	    fprintf (stderr, "fbValidateBits failed\n");
339#endif
340	    return FALSE;
341	}
342	bits++;
343    }
344}
345
346void
347fbValidateDrawable (DrawablePtr pDrawable)
348{
349    FbStip	*bits, *first, *last;
350    int		stride, bpp;
351    int		xoff, yoff;
352    int		height;
353    Bool	failed;
354
355    if (pDrawable->type != DRAWABLE_PIXMAP)
356	pDrawable = (DrawablePtr) fbGetWindowPixmap(pDrawable);
357    fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
358    first = bits - stride;
359    last = bits + stride * pDrawable->height;
360    if (!fbValidateBits (first, stride, FB_HEAD_BITS) ||
361	!fbValidateBits (last, stride, FB_TAIL_BITS))
362	fbInitializeDrawable(pDrawable);
363    fbFinishAccess (pDrawable);
364}
365
366void
367fbSetBits (FbStip *bits, int stride, FbStip data)
368{
369    while (stride--)
370	*bits++ = data;
371}
372
373void
374fbInitializeDrawable (DrawablePtr pDrawable)
375{
376    FbStip  *bits, *first, *last;
377    int	    stride, bpp;
378    int	    xoff, yoff;
379
380    fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
381    first = bits - stride;
382    last = bits + stride * pDrawable->height;
383    fbSetBits (first, stride, FB_HEAD_BITS);
384    fbSetBits (last, stride, FB_TAIL_BITS);
385    fbFinishAccess (pDrawable);
386}
387#endif /* FB_DEBUG */
388