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