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