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