fbpixmap.c revision 35c4bbdf
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                  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 = (void *) ((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
88PixmapPtr
89fbCreatePixmap(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
100Bool
101fbDestroyPixmap(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)			\
110if (((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 */
141RegionPtr
142fbPixmapToRegion(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
310static Bool
311fbValidateBits(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
328void
329fbValidateDrawable(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
348void
349fbSetBits(FbStip * bits, int stride, FbStip data)
350{
351    while (stride--)
352        *bits++ = data;
353}
354
355void
356fbInitializeDrawable(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 */
370