1/* 2 * Copyright © 1998 Keith Packard 3 * Copyright © 2012 Intel Corporation 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Keith Packard not be used in 10 * advertising or publicity pertaining to distribution of the software without 11 * specific, written prior permission. Keith Packard makes no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#include "fb.h" 25 26#ifdef __clang__ 27/* shift overflow is intentional */ 28#pragma clang diagnostic ignored "-Wshift-overflow" 29#endif 30 31/* 32 * Example: srcX = 13 dstX = 8 (FB unit 32 dstBpp 8) 33 * 34 * **** **** **** **** **** **** **** **** 35 * ^ 36 * ******** ******** ******** ******** 37 * ^ 38 * leftShift = 12 39 * rightShift = 20 40 * 41 * Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8) 42 * 43 * **** **** **** **** **** **** **** **** 44 * ^ 45 * ******** ******** ******** ******** 46 * ^ 47 * 48 * leftShift = 24 49 * rightShift = 8 50 */ 51 52#define LoadBits {\ 53 if (leftShift) { \ 54 bitsRight = (src < srcEnd ? READ(src++) : 0); \ 55 bits = (FbStipLeft (bitsLeft, leftShift) | \ 56 FbStipRight(bitsRight, rightShift)); \ 57 bitsLeft = bitsRight; \ 58 } else \ 59 bits = (src < srcEnd ? READ(src++) : 0); \ 60} 61 62#define LaneCases1(n,a) case n: FbLaneCase(n,a); break 63#define LaneCases2(n,a) LaneCases1(n,a); LaneCases1(n+1,a) 64#define LaneCases4(n,a) LaneCases2(n,a); LaneCases2(n+2,a) 65#define LaneCases8(n,a) LaneCases4(n,a); LaneCases4(n+4,a) 66#define LaneCases16(n,a) LaneCases8(n,a); LaneCases8(n+8,a) 67#define LaneCases32(n,a) LaneCases16(n,a); LaneCases16(n+16,a) 68#define LaneCases64(n,a) LaneCases32(n,a); LaneCases32(n+32,a) 69#define LaneCases128(n,a) LaneCases64(n,a); LaneCases64(n+64,a) 70#define LaneCases256(n,a) LaneCases128(n,a); LaneCases128(n+128,a) 71 72#define LaneCases(a) LaneCases16(0,a) 73 74static const CARD8 fb8Lane[16] = { 75 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 76}; 77 78static const CARD8 fb16Lane[16] = { 79 0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80}; 81 82static const CARD8 fb32Lane[16] = { 83 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84}; 85 86static const CARD8 * const fbLaneTable[33] = { 87 0, 0, 0, 0, 0, 0, 0, 0, 88 fb8Lane, 0, 0, 0, 0, 0, 0, 0, 89 fb16Lane, 0, 0, 0, 0, 0, 0, 0, 90 0, 0, 0, 0, 0, 0, 0, 0, 91 fb32Lane 92}; 93 94void 95fbBltOne(FbStip * src, FbStride srcStride, /* FbStip units per scanline */ 96 int srcX, /* bit position of source */ 97 FbBits * dst, FbStride dstStride, /* FbBits units per scanline */ 98 int dstX, /* bit position of dest */ 99 int dstBpp, /* bits per destination unit */ 100 int width, /* width in bits of destination */ 101 int height, /* height in scanlines */ 102 FbBits fgand, /* rrop values */ 103 FbBits fgxor, FbBits bgand, FbBits bgxor) 104{ 105 const FbBits *fbBits; 106 FbBits *srcEnd; 107 int pixelsPerDst; /* dst pixels per FbBits */ 108 int unitsPerSrc; /* src patterns per FbStip */ 109 int leftShift, rightShift; /* align source with dest */ 110 FbBits startmask, endmask; /* dest scanline masks */ 111 FbStip bits = 0, bitsLeft, bitsRight; /* source bits */ 112 FbStip left; 113 FbBits mask; 114 int nDst; /* dest longwords (w.o. end) */ 115 int w; 116 int n, nmiddle; 117 int dstS; /* stipple-relative dst X coordinate */ 118 Bool copy; /* accelerate dest-invariant */ 119 Bool transparent; /* accelerate 0 nop */ 120 int srcinc; /* source units consumed */ 121 Bool endNeedsLoad = FALSE; /* need load for endmask */ 122 const CARD8 *fbLane; 123 int startbyte, endbyte; 124 125 /* 126 * Do not read past the end of the buffer! 127 */ 128 srcEnd = src + height * srcStride; 129 130 /* 131 * Number of destination units in FbBits == number of stipple pixels 132 * used each time 133 */ 134 pixelsPerDst = FB_UNIT / dstBpp; 135 136 /* 137 * Number of source stipple patterns in FbStip 138 */ 139 unitsPerSrc = FB_STIP_UNIT / pixelsPerDst; 140 141 copy = FALSE; 142 transparent = FALSE; 143 if (bgand == 0 && fgand == 0) 144 copy = TRUE; 145 else if (bgand == FB_ALLONES && bgxor == 0) 146 transparent = TRUE; 147 148 /* 149 * Adjust source and dest to nearest FbBits boundary 150 */ 151 src += srcX >> FB_STIP_SHIFT; 152 dst += dstX >> FB_SHIFT; 153 srcX &= FB_STIP_MASK; 154 dstX &= FB_MASK; 155 156 FbMaskBitsBytes(dstX, width, copy, 157 startmask, startbyte, nmiddle, endmask, endbyte); 158 159 /* 160 * Compute effective dest alignment requirement for 161 * source -- must align source to dest unit boundary 162 */ 163 dstS = dstX / dstBpp; 164 /* 165 * Compute shift constants for effective alignement 166 */ 167 if (srcX >= dstS) { 168 leftShift = srcX - dstS; 169 rightShift = FB_STIP_UNIT - leftShift; 170 } else { 171 rightShift = dstS - srcX; 172 leftShift = FB_STIP_UNIT - rightShift; 173 } 174 /* 175 * Get pointer to stipple mask array for this depth 176 */ 177 fbBits = 0; /* unused */ 178 if (pixelsPerDst <= 8) 179 fbBits = fbStippleTable[pixelsPerDst]; 180 fbLane = 0; 181 if (transparent && fgand == 0 && dstBpp >= 8) 182 fbLane = fbLaneTable[dstBpp]; 183 184 /* 185 * Compute total number of destination words written, but 186 * don't count endmask 187 */ 188 nDst = nmiddle; 189 if (startmask) 190 nDst++; 191 192 dstStride -= nDst; 193 194 /* 195 * Compute total number of source words consumed 196 */ 197 198 srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc; 199 200 if (srcX > dstS) 201 srcinc++; 202 if (endmask) { 203 endNeedsLoad = nDst % unitsPerSrc == 0; 204 if (endNeedsLoad) 205 srcinc++; 206 } 207 208 srcStride -= srcinc; 209 210 /* 211 * Copy rectangle 212 */ 213 while (height--) { 214 w = nDst; /* total units across scanline */ 215 n = unitsPerSrc; /* units avail in single stipple */ 216 if (n > w) 217 n = w; 218 219 bitsLeft = 0; 220 if (srcX > dstS) 221 bitsLeft = READ(src++); 222 if (n) { 223 /* 224 * Load first set of stipple bits 225 */ 226 LoadBits; 227 228 /* 229 * Consume stipple bits for startmask 230 */ 231 if (startmask) { 232 mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 233 if (fbLane) { 234 fbTransparentSpan(dst, mask & startmask, fgxor, 1); 235 } else { 236 if (mask || !transparent) 237 FbDoLeftMaskByteStippleRRop(dst, mask, 238 fgand, fgxor, bgand, bgxor, 239 startbyte, startmask); 240 } 241 bits = FbStipLeft(bits, pixelsPerDst); 242 dst++; 243 n--; 244 w--; 245 } 246 /* 247 * Consume stipple bits across scanline 248 */ 249 for (;;) { 250 w -= n; 251 if (copy) { 252 while (n--) { 253#if FB_UNIT > 32 254 if (pixelsPerDst == 16) 255 mask = FbStipple16Bits(FbLeftStipBits(bits, 16)); 256 else 257#endif 258 mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 259 WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor)); 260 dst++; 261 bits = FbStipLeft(bits, pixelsPerDst); 262 } 263 } 264 else { 265 if (fbLane) { 266 while (bits && n) { 267 switch (fbLane[FbLeftStipBits(bits, pixelsPerDst)]) { 268 LaneCases((CARD8 *) dst); 269 } 270 bits = FbStipLeft(bits, pixelsPerDst); 271 dst++; 272 n--; 273 } 274 dst += n; 275 } else { 276 while (n--) { 277 left = FbLeftStipBits(bits, pixelsPerDst); 278 if (left || !transparent) { 279 mask = fbBits[left]; 280 WRITE(dst, FbStippleRRop(READ(dst), mask, 281 fgand, fgxor, bgand, 282 bgxor)); 283 } 284 dst++; 285 bits = FbStipLeft(bits, pixelsPerDst); 286 } 287 } 288 } 289 if (!w) 290 break; 291 /* 292 * Load another set and reset number of available units 293 */ 294 LoadBits; 295 n = unitsPerSrc; 296 if (n > w) 297 n = w; 298 } 299 } 300 /* 301 * Consume stipple bits for endmask 302 */ 303 if (endmask) { 304 if (endNeedsLoad) { 305 LoadBits; 306 } 307 mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 308 if (fbLane) { 309 fbTransparentSpan(dst, mask & endmask, fgxor, 1); 310 } else { 311 if (mask || !transparent) 312 FbDoRightMaskByteStippleRRop(dst, mask, 313 fgand, fgxor, bgand, bgxor, 314 endbyte, endmask); 315 } 316 } 317 dst += dstStride; 318 src += srcStride; 319 } 320} 321 322/* 323 * Not very efficient, but simple -- copy a single plane 324 * from an N bit image to a 1 bit image 325 */ 326 327void 328fbBltPlane(FbBits * src, 329 FbStride srcStride, 330 int srcX, 331 int srcBpp, 332 FbStip * dst, 333 FbStride dstStride, 334 int dstX, 335 int width, 336 int height, 337 FbStip fgand, 338 FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask) 339{ 340 FbBits *s; 341 FbBits pm; 342 FbBits srcMask; 343 FbBits srcMaskFirst; 344 FbBits srcMask0 = 0; 345 FbBits srcBits; 346 347 FbStip dstBits; 348 FbStip *d; 349 FbStip dstMask; 350 FbStip dstMaskFirst; 351 FbStip dstUnion; 352 int w; 353 int wt; 354 355 if (!width) 356 return; 357 358 src += srcX >> FB_SHIFT; 359 srcX &= FB_MASK; 360 361 dst += dstX >> FB_STIP_SHIFT; 362 dstX &= FB_STIP_MASK; 363 364 w = width / srcBpp; 365 366 pm = fbReplicatePixel(planeMask, srcBpp); 367 srcMaskFirst = pm & FbBitsMask(srcX, srcBpp); 368 srcMask0 = pm & FbBitsMask(0, srcBpp); 369 370 dstMaskFirst = FbStipMask(dstX, 1); 371 while (height--) { 372 d = dst; 373 dst += dstStride; 374 s = src; 375 src += srcStride; 376 377 srcMask = srcMaskFirst; 378 srcBits = READ(s++); 379 380 dstMask = dstMaskFirst; 381 dstUnion = 0; 382 dstBits = 0; 383 384 wt = w; 385 386 while (wt--) { 387 if (!srcMask) { 388 srcBits = READ(s++); 389 srcMask = srcMask0; 390 } 391 if (!dstMask) { 392 WRITE(d, FbStippleRRopMask(READ(d), dstBits, 393 fgand, fgxor, bgand, bgxor, 394 dstUnion)); 395 d++; 396 dstMask = FbStipMask(0, 1); 397 dstUnion = 0; 398 dstBits = 0; 399 } 400 if (srcBits & srcMask) 401 dstBits |= dstMask; 402 dstUnion |= dstMask; 403 if (srcBpp == FB_UNIT) 404 srcMask = 0; 405 else 406 srcMask = FbScrRight(srcMask, srcBpp); 407 dstMask = FbStipRight(dstMask, 1); 408 } 409 if (dstUnion) 410 WRITE(d, FbStippleRRopMask(READ(d), dstBits, 411 fgand, fgxor, bgand, bgxor, dstUnion)); 412 } 413} 414