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