/* * Copyright © 1998 Keith Packard * Copyright © 2012 Intel Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include #include "fb.h" typedef struct _mergeRopBits { FbBits ca1, cx1, ca2, cx2; } FbMergeRopRec, *FbMergeRopPtr; #define O 0 #define I FB_ALLONES static const FbMergeRopRec FbMergeRopBits[16] = { {O, O, O, O}, /* clear 0x0 0 */ {I, O, O, O}, /* and 0x1 src AND dst */ {I, O, I, O}, /* andReverse 0x2 src AND NOT dst */ {O, O, I, O}, /* copy 0x3 src */ {I, I, O, O}, /* andInverted 0x4 NOT src AND dst */ {O, I, O, O}, /* noop 0x5 dst */ {O, I, I, O}, /* xor 0x6 src XOR dst */ {I, I, I, O}, /* or 0x7 src OR dst */ {I, I, I, I}, /* nor 0x8 NOT src AND NOT dst */ {O, I, I, I}, /* equiv 0x9 NOT src XOR dst */ {O, I, O, I}, /* invert 0xa NOT dst */ {I, I, O, I}, /* orReverse 0xb src OR NOT dst */ {O, O, I, I}, /* copyInverted 0xc NOT src */ {I, O, I, I}, /* orInverted 0xd NOT src OR dst */ {I, O, O, I}, /* nand 0xe NOT src OR NOT dst */ {O, O, O, I}, /* set 0xf 1 */ }; #undef O #undef I #define FbDeclareMergeRop() FbBits _ca1, _cx1, _ca2, _cx2; #define FbDeclarePrebuiltMergeRop() FbBits _cca, _ccx; #define FbInitializeMergeRop(alu,pm) {\ const FbMergeRopRec *_bits; \ _bits = &FbMergeRopBits[alu]; \ _ca1 = _bits->ca1 & pm; \ _cx1 = _bits->cx1 | ~pm; \ _ca2 = _bits->ca2 & pm; \ _cx2 = _bits->cx2 & pm; \ } #define InitializeShifts(sx,dx,ls,rs) { \ if (sx != dx) { \ if (sx > dx) { \ ls = sx - dx; \ rs = FB_UNIT - ls; \ } else { \ rs = dx - sx; \ ls = FB_UNIT - rs; \ } \ } \ } static void fbBlt__rop(FbBits *srcLine, FbStride srcStride, int srcX, FbBits *dstLine, FbStride dstStride, int dstX, int width, int height, int alu, FbBits pm, int bpp, Bool reverse, Bool upsidedown) { FbBits *src, *dst; int leftShift, rightShift; FbBits startmask, endmask; FbBits bits, bits1; int n, nmiddle; Bool destInvarient; int startbyte, endbyte; FbDeclareMergeRop(); FbInitializeMergeRop(alu, pm); destInvarient = FbDestInvarientMergeRop(); if (upsidedown) { srcLine += (height - 1) * (srcStride); dstLine += (height - 1) * (dstStride); srcStride = -srcStride; dstStride = -dstStride; } FbMaskBitsBytes(dstX, width, destInvarient, startmask, startbyte, nmiddle, endmask, endbyte); if (reverse) { srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1; dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1; srcX = (srcX + width - 1) & FB_MASK; dstX = (dstX + width - 1) & FB_MASK; } else { srcLine += srcX >> FB_SHIFT; dstLine += dstX >> FB_SHIFT; srcX &= FB_MASK; dstX &= FB_MASK; } if (srcX == dstX) { while (height--) { src = srcLine; srcLine += srcStride; dst = dstLine; dstLine += dstStride; if (reverse) { if (endmask) { bits = READ(--src); --dst; FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); } n = nmiddle; if (destInvarient) { while (n--) WRITE(--dst, FbDoDestInvarientMergeRop(READ(--src))); } else { while (n--) { bits = READ(--src); --dst; WRITE(dst, FbDoMergeRop(bits, READ(dst))); } } if (startmask) { bits = READ(--src); --dst; FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); } } else { if (startmask) { bits = READ(src++); FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); dst++; } n = nmiddle; if (destInvarient) { while (n--) WRITE(dst++, FbDoDestInvarientMergeRop(READ(src++))); } else { while (n--) { bits = READ(src++); WRITE(dst, FbDoMergeRop(bits, READ(dst))); dst++; } } if (endmask) { bits = READ(src); FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); } } } } else { if (srcX > dstX) { leftShift = srcX - dstX; rightShift = FB_UNIT - leftShift; } else { rightShift = dstX - srcX; leftShift = FB_UNIT - rightShift; } while (height--) { src = srcLine; srcLine += srcStride; dst = dstLine; dstLine += dstStride; bits1 = 0; if (reverse) { if (srcX < dstX) bits1 = READ(--src); if (endmask) { bits = FbScrRight(bits1, rightShift); if (FbScrRight(endmask, leftShift)) { bits1 = READ(--src); bits |= FbScrLeft(bits1, leftShift); } --dst; FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); } n = nmiddle; if (destInvarient) { while (n--) { bits = FbScrRight(bits1, rightShift); bits1 = READ(--src); bits |= FbScrLeft(bits1, leftShift); --dst; WRITE(dst, FbDoDestInvarientMergeRop(bits)); } } else { while (n--) { bits = FbScrRight(bits1, rightShift); bits1 = READ(--src); bits |= FbScrLeft(bits1, leftShift); --dst; WRITE(dst, FbDoMergeRop(bits, READ(dst))); } } if (startmask) { bits = FbScrRight(bits1, rightShift); if (FbScrRight(startmask, leftShift)) { bits1 = READ(--src); bits |= FbScrLeft(bits1, leftShift); } --dst; FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); } } else { if (srcX > dstX) bits1 = READ(src++); if (startmask) { bits = FbScrLeft(bits1, leftShift); if (FbScrLeft(startmask, rightShift)) { bits1 = READ(src++); bits |= FbScrRight(bits1, rightShift); } FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); dst++; } n = nmiddle; if (destInvarient) { while (n--) { bits = FbScrLeft(bits1, leftShift); bits1 = READ(src++); bits |= FbScrRight(bits1, rightShift); WRITE(dst, FbDoDestInvarientMergeRop(bits)); dst++; } } else { while (n--) { bits = FbScrLeft(bits1, leftShift); bits1 = READ(src++); bits |= FbScrRight(bits1, rightShift); WRITE(dst, FbDoMergeRop(bits, READ(dst))); dst++; } } if (endmask) { bits = FbScrLeft(bits1, leftShift); if (FbScrLeft(endmask, rightShift)) { bits1 = READ(src); bits |= FbScrRight(bits1, rightShift); } FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); } } } } } void fbBlt(FbBits *srcLine, FbStride srcStride, int srcX, FbBits *dstLine, FbStride dstStride, int dstX, int width, int height, int alu, FbBits pm, int bpp, Bool reverse, Bool upsidedown) { DBG(("%s %dx%d, alu=%d, pm=%x, bpp=%d (reverse=%d, upsidedown=%d)\n", __FUNCTION__, width, height, alu, pm, bpp, reverse, upsidedown)); if (alu == GXcopy && pm == FB_ALLONES && ((srcX|dstX|width) & 7) == 0) { CARD8 *s = (CARD8 *) srcLine; CARD8 *d = (CARD8 *) dstLine; void *(*func)(void *, const void *, size_t); int i; srcStride *= sizeof(FbBits); dstStride *= sizeof(FbBits); width >>= 3; s += srcX >> 3; d += dstX >> 3; DBG(("%s fast blt, src_stride=%d, dst_stride=%d, width=%d (offset=%ld)\n", __FUNCTION__, srcStride, dstStride, width, (long)(s - d))); if (width == srcStride && width == dstStride) { width *= height; height = 1; } if ((s < d && s + width > d) || (d < s && d + width > s)) func = memmove; else func = memcpy; if (!upsidedown) { for (i = 0; i < height; i++) func(d + i * dstStride, s + i * srcStride, width); } else { for (i = height; i--; ) func(d + i * dstStride, s + i * srcStride, width); } return; } fbBlt__rop(srcLine, srcStride, srcX, dstLine, dstStride, dstX, width, height, alu, pm, bpp, reverse, upsidedown); }