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