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