1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 1998 Keith Packard 3428d7b3dSmrg * Copyright © 2012 Intel Corporation 4428d7b3dSmrg * 5428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 6428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that 7428d7b3dSmrg * the above copyright notice appear in all copies and that both that 8428d7b3dSmrg * copyright notice and this permission notice appear in supporting 9428d7b3dSmrg * documentation, and that the name of Keith Packard not be used in 10428d7b3dSmrg * advertising or publicity pertaining to distribution of the software without 11428d7b3dSmrg * specific, written prior permission. Keith Packard makes no 12428d7b3dSmrg * representations about the suitability of this software for any purpose. It 13428d7b3dSmrg * is provided "as is" without express or implied warranty. 14428d7b3dSmrg * 15428d7b3dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16428d7b3dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17428d7b3dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18428d7b3dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19428d7b3dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20428d7b3dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21428d7b3dSmrg * PERFORMANCE OF THIS SOFTWARE. 22428d7b3dSmrg */ 23428d7b3dSmrg 24428d7b3dSmrg#include "fb.h" 25428d7b3dSmrg 26428d7b3dSmrg#ifdef __clang__ 27428d7b3dSmrg/* shift overflow is intentional */ 28428d7b3dSmrg#pragma clang diagnostic ignored "-Wshift-overflow" 29428d7b3dSmrg#endif 30428d7b3dSmrg 31428d7b3dSmrg/* 32428d7b3dSmrg * Example: srcX = 13 dstX = 8 (FB unit 32 dstBpp 8) 33428d7b3dSmrg * 34428d7b3dSmrg * **** **** **** **** **** **** **** **** 35428d7b3dSmrg * ^ 36428d7b3dSmrg * ******** ******** ******** ******** 37428d7b3dSmrg * ^ 38428d7b3dSmrg * leftShift = 12 39428d7b3dSmrg * rightShift = 20 40428d7b3dSmrg * 41428d7b3dSmrg * Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8) 42428d7b3dSmrg * 43428d7b3dSmrg * **** **** **** **** **** **** **** **** 44428d7b3dSmrg * ^ 45428d7b3dSmrg * ******** ******** ******** ******** 46428d7b3dSmrg * ^ 47428d7b3dSmrg * 48428d7b3dSmrg * leftShift = 24 49428d7b3dSmrg * rightShift = 8 50428d7b3dSmrg */ 51428d7b3dSmrg 52428d7b3dSmrg#define LoadBits {\ 53428d7b3dSmrg if (leftShift) { \ 54428d7b3dSmrg bitsRight = (src < srcEnd ? READ(src++) : 0); \ 55428d7b3dSmrg bits = (FbStipLeft (bitsLeft, leftShift) | \ 56428d7b3dSmrg FbStipRight(bitsRight, rightShift)); \ 57428d7b3dSmrg bitsLeft = bitsRight; \ 58428d7b3dSmrg } else \ 59428d7b3dSmrg bits = (src < srcEnd ? READ(src++) : 0); \ 60428d7b3dSmrg} 61428d7b3dSmrg 62428d7b3dSmrg#define LaneCases1(n,a) case n: FbLaneCase(n,a); break 63428d7b3dSmrg#define LaneCases2(n,a) LaneCases1(n,a); LaneCases1(n+1,a) 64428d7b3dSmrg#define LaneCases4(n,a) LaneCases2(n,a); LaneCases2(n+2,a) 65428d7b3dSmrg#define LaneCases8(n,a) LaneCases4(n,a); LaneCases4(n+4,a) 66428d7b3dSmrg#define LaneCases16(n,a) LaneCases8(n,a); LaneCases8(n+8,a) 67428d7b3dSmrg#define LaneCases32(n,a) LaneCases16(n,a); LaneCases16(n+16,a) 68428d7b3dSmrg#define LaneCases64(n,a) LaneCases32(n,a); LaneCases32(n+32,a) 69428d7b3dSmrg#define LaneCases128(n,a) LaneCases64(n,a); LaneCases64(n+64,a) 70428d7b3dSmrg#define LaneCases256(n,a) LaneCases128(n,a); LaneCases128(n+128,a) 71428d7b3dSmrg 72428d7b3dSmrg#define LaneCases(a) LaneCases16(0,a) 73428d7b3dSmrg 74428d7b3dSmrgstatic const CARD8 fb8Lane[16] = { 75428d7b3dSmrg 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 76428d7b3dSmrg}; 77428d7b3dSmrg 78428d7b3dSmrgstatic const CARD8 fb16Lane[16] = { 79428d7b3dSmrg 0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80428d7b3dSmrg}; 81428d7b3dSmrg 82428d7b3dSmrgstatic const CARD8 fb32Lane[16] = { 83428d7b3dSmrg 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84428d7b3dSmrg}; 85428d7b3dSmrg 86428d7b3dSmrgstatic const CARD8 * const fbLaneTable[33] = { 87428d7b3dSmrg 0, 0, 0, 0, 0, 0, 0, 0, 88428d7b3dSmrg fb8Lane, 0, 0, 0, 0, 0, 0, 0, 89428d7b3dSmrg fb16Lane, 0, 0, 0, 0, 0, 0, 0, 90428d7b3dSmrg 0, 0, 0, 0, 0, 0, 0, 0, 91428d7b3dSmrg fb32Lane 92428d7b3dSmrg}; 93428d7b3dSmrg 94428d7b3dSmrgvoid 95428d7b3dSmrgfbBltOne(FbStip * src, FbStride srcStride, /* FbStip units per scanline */ 96428d7b3dSmrg int srcX, /* bit position of source */ 97428d7b3dSmrg FbBits * dst, FbStride dstStride, /* FbBits units per scanline */ 98428d7b3dSmrg int dstX, /* bit position of dest */ 99428d7b3dSmrg int dstBpp, /* bits per destination unit */ 100428d7b3dSmrg int width, /* width in bits of destination */ 101428d7b3dSmrg int height, /* height in scanlines */ 102428d7b3dSmrg FbBits fgand, /* rrop values */ 103428d7b3dSmrg FbBits fgxor, FbBits bgand, FbBits bgxor) 104428d7b3dSmrg{ 105428d7b3dSmrg const FbBits *fbBits; 106428d7b3dSmrg FbBits *srcEnd; 107428d7b3dSmrg int pixelsPerDst; /* dst pixels per FbBits */ 108428d7b3dSmrg int unitsPerSrc; /* src patterns per FbStip */ 109428d7b3dSmrg int leftShift, rightShift; /* align source with dest */ 110428d7b3dSmrg FbBits startmask, endmask; /* dest scanline masks */ 111428d7b3dSmrg FbStip bits = 0, bitsLeft, bitsRight; /* source bits */ 112428d7b3dSmrg FbStip left; 113428d7b3dSmrg FbBits mask; 114428d7b3dSmrg int nDst; /* dest longwords (w.o. end) */ 115428d7b3dSmrg int w; 116428d7b3dSmrg int n, nmiddle; 117428d7b3dSmrg int dstS; /* stipple-relative dst X coordinate */ 118428d7b3dSmrg Bool copy; /* accelerate dest-invariant */ 119428d7b3dSmrg Bool transparent; /* accelerate 0 nop */ 120428d7b3dSmrg int srcinc; /* source units consumed */ 121428d7b3dSmrg Bool endNeedsLoad = FALSE; /* need load for endmask */ 122428d7b3dSmrg const CARD8 *fbLane; 123428d7b3dSmrg int startbyte, endbyte; 124428d7b3dSmrg 125428d7b3dSmrg /* 126428d7b3dSmrg * Do not read past the end of the buffer! 127428d7b3dSmrg */ 128428d7b3dSmrg srcEnd = src + height * srcStride; 129428d7b3dSmrg 130428d7b3dSmrg /* 131428d7b3dSmrg * Number of destination units in FbBits == number of stipple pixels 132428d7b3dSmrg * used each time 133428d7b3dSmrg */ 134428d7b3dSmrg pixelsPerDst = FB_UNIT / dstBpp; 135428d7b3dSmrg 136428d7b3dSmrg /* 137428d7b3dSmrg * Number of source stipple patterns in FbStip 138428d7b3dSmrg */ 139428d7b3dSmrg unitsPerSrc = FB_STIP_UNIT / pixelsPerDst; 140428d7b3dSmrg 141428d7b3dSmrg copy = FALSE; 142428d7b3dSmrg transparent = FALSE; 143428d7b3dSmrg if (bgand == 0 && fgand == 0) 144428d7b3dSmrg copy = TRUE; 145428d7b3dSmrg else if (bgand == FB_ALLONES && bgxor == 0) 146428d7b3dSmrg transparent = TRUE; 147428d7b3dSmrg 148428d7b3dSmrg /* 149428d7b3dSmrg * Adjust source and dest to nearest FbBits boundary 150428d7b3dSmrg */ 151428d7b3dSmrg src += srcX >> FB_STIP_SHIFT; 152428d7b3dSmrg dst += dstX >> FB_SHIFT; 153428d7b3dSmrg srcX &= FB_STIP_MASK; 154428d7b3dSmrg dstX &= FB_MASK; 155428d7b3dSmrg 156428d7b3dSmrg FbMaskBitsBytes(dstX, width, copy, 157428d7b3dSmrg startmask, startbyte, nmiddle, endmask, endbyte); 158428d7b3dSmrg 159428d7b3dSmrg /* 160428d7b3dSmrg * Compute effective dest alignment requirement for 161428d7b3dSmrg * source -- must align source to dest unit boundary 162428d7b3dSmrg */ 163428d7b3dSmrg dstS = dstX / dstBpp; 164428d7b3dSmrg /* 165428d7b3dSmrg * Compute shift constants for effective alignement 166428d7b3dSmrg */ 167428d7b3dSmrg if (srcX >= dstS) { 168428d7b3dSmrg leftShift = srcX - dstS; 169428d7b3dSmrg rightShift = FB_STIP_UNIT - leftShift; 170428d7b3dSmrg } else { 171428d7b3dSmrg rightShift = dstS - srcX; 172428d7b3dSmrg leftShift = FB_STIP_UNIT - rightShift; 173428d7b3dSmrg } 174428d7b3dSmrg /* 175428d7b3dSmrg * Get pointer to stipple mask array for this depth 176428d7b3dSmrg */ 177428d7b3dSmrg fbBits = 0; /* unused */ 178428d7b3dSmrg if (pixelsPerDst <= 8) 179428d7b3dSmrg fbBits = fbStippleTable[pixelsPerDst]; 180428d7b3dSmrg fbLane = 0; 181428d7b3dSmrg if (transparent && fgand == 0 && dstBpp >= 8) 182428d7b3dSmrg fbLane = fbLaneTable[dstBpp]; 183428d7b3dSmrg 184428d7b3dSmrg /* 185428d7b3dSmrg * Compute total number of destination words written, but 186428d7b3dSmrg * don't count endmask 187428d7b3dSmrg */ 188428d7b3dSmrg nDst = nmiddle; 189428d7b3dSmrg if (startmask) 190428d7b3dSmrg nDst++; 191428d7b3dSmrg 192428d7b3dSmrg dstStride -= nDst; 193428d7b3dSmrg 194428d7b3dSmrg /* 195428d7b3dSmrg * Compute total number of source words consumed 196428d7b3dSmrg */ 197428d7b3dSmrg 198428d7b3dSmrg srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc; 199428d7b3dSmrg 200428d7b3dSmrg if (srcX > dstS) 201428d7b3dSmrg srcinc++; 202428d7b3dSmrg if (endmask) { 203428d7b3dSmrg endNeedsLoad = nDst % unitsPerSrc == 0; 204428d7b3dSmrg if (endNeedsLoad) 205428d7b3dSmrg srcinc++; 206428d7b3dSmrg } 207428d7b3dSmrg 208428d7b3dSmrg srcStride -= srcinc; 209428d7b3dSmrg 210428d7b3dSmrg /* 211428d7b3dSmrg * Copy rectangle 212428d7b3dSmrg */ 213428d7b3dSmrg while (height--) { 214428d7b3dSmrg w = nDst; /* total units across scanline */ 215428d7b3dSmrg n = unitsPerSrc; /* units avail in single stipple */ 216428d7b3dSmrg if (n > w) 217428d7b3dSmrg n = w; 218428d7b3dSmrg 219428d7b3dSmrg bitsLeft = 0; 220428d7b3dSmrg if (srcX > dstS) 221428d7b3dSmrg bitsLeft = READ(src++); 222428d7b3dSmrg if (n) { 223428d7b3dSmrg /* 224428d7b3dSmrg * Load first set of stipple bits 225428d7b3dSmrg */ 226428d7b3dSmrg LoadBits; 227428d7b3dSmrg 228428d7b3dSmrg /* 229428d7b3dSmrg * Consume stipple bits for startmask 230428d7b3dSmrg */ 231428d7b3dSmrg if (startmask) { 232428d7b3dSmrg mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 233428d7b3dSmrg if (fbLane) { 234428d7b3dSmrg fbTransparentSpan(dst, mask & startmask, fgxor, 1); 235428d7b3dSmrg } else { 236428d7b3dSmrg if (mask || !transparent) 237428d7b3dSmrg FbDoLeftMaskByteStippleRRop(dst, mask, 238428d7b3dSmrg fgand, fgxor, bgand, bgxor, 239428d7b3dSmrg startbyte, startmask); 240428d7b3dSmrg } 241428d7b3dSmrg bits = FbStipLeft(bits, pixelsPerDst); 242428d7b3dSmrg dst++; 243428d7b3dSmrg n--; 244428d7b3dSmrg w--; 245428d7b3dSmrg } 246428d7b3dSmrg /* 247428d7b3dSmrg * Consume stipple bits across scanline 248428d7b3dSmrg */ 249428d7b3dSmrg for (;;) { 250428d7b3dSmrg w -= n; 251428d7b3dSmrg if (copy) { 252428d7b3dSmrg while (n--) { 253428d7b3dSmrg#if FB_UNIT > 32 254428d7b3dSmrg if (pixelsPerDst == 16) 255428d7b3dSmrg mask = FbStipple16Bits(FbLeftStipBits(bits, 16)); 256428d7b3dSmrg else 257428d7b3dSmrg#endif 258428d7b3dSmrg mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 259428d7b3dSmrg WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor)); 260428d7b3dSmrg dst++; 261428d7b3dSmrg bits = FbStipLeft(bits, pixelsPerDst); 262428d7b3dSmrg } 263428d7b3dSmrg } 264428d7b3dSmrg else { 265428d7b3dSmrg if (fbLane) { 266428d7b3dSmrg while (bits && n) { 267428d7b3dSmrg switch (fbLane[FbLeftStipBits(bits, pixelsPerDst)]) { 268428d7b3dSmrg LaneCases((CARD8 *) dst); 269428d7b3dSmrg } 270428d7b3dSmrg bits = FbStipLeft(bits, pixelsPerDst); 271428d7b3dSmrg dst++; 272428d7b3dSmrg n--; 273428d7b3dSmrg } 274428d7b3dSmrg dst += n; 275428d7b3dSmrg } else { 276428d7b3dSmrg while (n--) { 277428d7b3dSmrg left = FbLeftStipBits(bits, pixelsPerDst); 278428d7b3dSmrg if (left || !transparent) { 279428d7b3dSmrg mask = fbBits[left]; 280428d7b3dSmrg WRITE(dst, FbStippleRRop(READ(dst), mask, 281428d7b3dSmrg fgand, fgxor, bgand, 282428d7b3dSmrg bgxor)); 283428d7b3dSmrg } 284428d7b3dSmrg dst++; 285428d7b3dSmrg bits = FbStipLeft(bits, pixelsPerDst); 286428d7b3dSmrg } 287428d7b3dSmrg } 288428d7b3dSmrg } 289428d7b3dSmrg if (!w) 290428d7b3dSmrg break; 291428d7b3dSmrg /* 292428d7b3dSmrg * Load another set and reset number of available units 293428d7b3dSmrg */ 294428d7b3dSmrg LoadBits; 295428d7b3dSmrg n = unitsPerSrc; 296428d7b3dSmrg if (n > w) 297428d7b3dSmrg n = w; 298428d7b3dSmrg } 299428d7b3dSmrg } 300428d7b3dSmrg /* 301428d7b3dSmrg * Consume stipple bits for endmask 302428d7b3dSmrg */ 303428d7b3dSmrg if (endmask) { 304428d7b3dSmrg if (endNeedsLoad) { 305428d7b3dSmrg LoadBits; 306428d7b3dSmrg } 307428d7b3dSmrg mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 308428d7b3dSmrg if (fbLane) { 309428d7b3dSmrg fbTransparentSpan(dst, mask & endmask, fgxor, 1); 310428d7b3dSmrg } else { 311428d7b3dSmrg if (mask || !transparent) 312428d7b3dSmrg FbDoRightMaskByteStippleRRop(dst, mask, 313428d7b3dSmrg fgand, fgxor, bgand, bgxor, 314428d7b3dSmrg endbyte, endmask); 315428d7b3dSmrg } 316428d7b3dSmrg } 317428d7b3dSmrg dst += dstStride; 318428d7b3dSmrg src += srcStride; 319428d7b3dSmrg } 320428d7b3dSmrg} 321428d7b3dSmrg 322428d7b3dSmrg/* 323428d7b3dSmrg * Not very efficient, but simple -- copy a single plane 324428d7b3dSmrg * from an N bit image to a 1 bit image 325428d7b3dSmrg */ 326428d7b3dSmrg 327428d7b3dSmrgvoid 328428d7b3dSmrgfbBltPlane(FbBits * src, 329428d7b3dSmrg FbStride srcStride, 330428d7b3dSmrg int srcX, 331428d7b3dSmrg int srcBpp, 332428d7b3dSmrg FbStip * dst, 333428d7b3dSmrg FbStride dstStride, 334428d7b3dSmrg int dstX, 335428d7b3dSmrg int width, 336428d7b3dSmrg int height, 337428d7b3dSmrg FbStip fgand, 338428d7b3dSmrg FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask) 339428d7b3dSmrg{ 340428d7b3dSmrg FbBits *s; 341428d7b3dSmrg FbBits pm; 342428d7b3dSmrg FbBits srcMask; 343428d7b3dSmrg FbBits srcMaskFirst; 344428d7b3dSmrg FbBits srcMask0 = 0; 345428d7b3dSmrg FbBits srcBits; 346428d7b3dSmrg 347428d7b3dSmrg FbStip dstBits; 348428d7b3dSmrg FbStip *d; 349428d7b3dSmrg FbStip dstMask; 350428d7b3dSmrg FbStip dstMaskFirst; 351428d7b3dSmrg FbStip dstUnion; 352428d7b3dSmrg int w; 353428d7b3dSmrg int wt; 354428d7b3dSmrg 355428d7b3dSmrg if (!width) 356428d7b3dSmrg return; 357428d7b3dSmrg 358428d7b3dSmrg src += srcX >> FB_SHIFT; 359428d7b3dSmrg srcX &= FB_MASK; 360428d7b3dSmrg 361428d7b3dSmrg dst += dstX >> FB_STIP_SHIFT; 362428d7b3dSmrg dstX &= FB_STIP_MASK; 363428d7b3dSmrg 364428d7b3dSmrg w = width / srcBpp; 365428d7b3dSmrg 366428d7b3dSmrg pm = fbReplicatePixel(planeMask, srcBpp); 367428d7b3dSmrg srcMaskFirst = pm & FbBitsMask(srcX, srcBpp); 368428d7b3dSmrg srcMask0 = pm & FbBitsMask(0, srcBpp); 369428d7b3dSmrg 370428d7b3dSmrg dstMaskFirst = FbStipMask(dstX, 1); 371428d7b3dSmrg while (height--) { 372428d7b3dSmrg d = dst; 373428d7b3dSmrg dst += dstStride; 374428d7b3dSmrg s = src; 375428d7b3dSmrg src += srcStride; 376428d7b3dSmrg 377428d7b3dSmrg srcMask = srcMaskFirst; 378428d7b3dSmrg srcBits = READ(s++); 379428d7b3dSmrg 380428d7b3dSmrg dstMask = dstMaskFirst; 381428d7b3dSmrg dstUnion = 0; 382428d7b3dSmrg dstBits = 0; 383428d7b3dSmrg 384428d7b3dSmrg wt = w; 385428d7b3dSmrg 386428d7b3dSmrg while (wt--) { 387428d7b3dSmrg if (!srcMask) { 388428d7b3dSmrg srcBits = READ(s++); 389428d7b3dSmrg srcMask = srcMask0; 390428d7b3dSmrg } 391428d7b3dSmrg if (!dstMask) { 392428d7b3dSmrg WRITE(d, FbStippleRRopMask(READ(d), dstBits, 393428d7b3dSmrg fgand, fgxor, bgand, bgxor, 394428d7b3dSmrg dstUnion)); 395428d7b3dSmrg d++; 396428d7b3dSmrg dstMask = FbStipMask(0, 1); 397428d7b3dSmrg dstUnion = 0; 398428d7b3dSmrg dstBits = 0; 399428d7b3dSmrg } 400428d7b3dSmrg if (srcBits & srcMask) 401428d7b3dSmrg dstBits |= dstMask; 402428d7b3dSmrg dstUnion |= dstMask; 403428d7b3dSmrg if (srcBpp == FB_UNIT) 404428d7b3dSmrg srcMask = 0; 405428d7b3dSmrg else 406428d7b3dSmrg srcMask = FbScrRight(srcMask, srcBpp); 407428d7b3dSmrg dstMask = FbStipRight(dstMask, 1); 408428d7b3dSmrg } 409428d7b3dSmrg if (dstUnion) 410428d7b3dSmrg WRITE(d, FbStippleRRopMask(READ(d), dstBits, 411428d7b3dSmrg fgand, fgxor, bgand, bgxor, dstUnion)); 412428d7b3dSmrg } 413428d7b3dSmrg} 414