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