/* * Copyright © 2000 SuSE, Inc. * Copyright © 2007 Red Hat, Inc. * * 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 SuSE not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. SuSE makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * 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. * * Author: Keith Packard, SuSE, Inc. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "pixman.h" #include "pixman-private.h" #include "pixman-mmx.h" #define FbFullMask(n) ((n) == 32 ? (uint32_t)-1 : ((((uint32_t) 1) << n) - 1)) #undef READ #undef WRITE #define READ(img,x) (*(x)) #define WRITE(img,ptr,v) ((*(ptr)) = (v)) typedef void (* CompositeFunc) (pixman_op_t, pixman_image_t *, pixman_image_t *, pixman_image_t *, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, uint16_t, uint16_t); uint32_t fbOver (uint32_t x, uint32_t y) { uint16_t a = ~x >> 24; uint16_t t; uint32_t m,n,o,p; m = FbOverU(x,y,0,a,t); n = FbOverU(x,y,8,a,t); o = FbOverU(x,y,16,a,t); p = FbOverU(x,y,24,a,t); return m|n|o|p; } uint32_t fbOver24 (uint32_t x, uint32_t y) { uint16_t a = ~x >> 24; uint16_t t; uint32_t m,n,o; m = FbOverU(x,y,0,a,t); n = FbOverU(x,y,8,a,t); o = FbOverU(x,y,16,a,t); return m|n|o; } uint32_t fbIn (uint32_t x, uint8_t y) { uint16_t a = y; uint16_t t; uint32_t m,n,o,p; m = FbInU(x,0,a,t); n = FbInU(x,8,a,t); o = FbInU(x,16,a,t); p = FbInU(x,24,a,t); return m|n|o|p; } /* * Naming convention: * * opSRCxMASKxDST */ static void fbCompositeOver_x888x8x8888 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t *src, *srcLine; uint32_t *dst, *dstLine; uint8_t *mask, *maskLine; int srcStride, maskStride, dstStride; uint8_t m; uint32_t s, d; uint16_t w; fbComposeGetStart (pDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); fbComposeGetStart (pMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); fbComposeGetStart (pSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); while (height--) { src = srcLine; srcLine += srcStride; dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { m = READ(pMask, mask++); if (m) { s = READ(pSrc, src) | 0xff000000; if (m == 0xff) WRITE(pDst, dst, s); else { d = fbIn (s, m); WRITE(pDst, dst, fbOver (d, READ(pDst, dst))); } } src++; dst++; } } fbFinishAccess (pMask->pDrawable); fbFinishAccess (pDst->pDrawable); } static void fbCompositeSolidMaskIn_nx8x8 (pixman_op_t op, pixman_image_t *iSrc, pixman_image_t *iMask, pixman_image_t *iDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t src, srca; uint8_t *dstLine, *dst, dstMask; uint8_t *maskLine, *mask, m; int dstStride, maskStride; uint16_t w; uint16_t t; fbComposeGetSolid(iSrc, src, iDst->bits.format); dstMask = FbFullMask (PIXMAN_FORMAT_DEPTH (iDst->bits.format)); srca = src >> 24; fbComposeGetStart (iDst, xDst, yDst, uint8_t, dstStride, dstLine, 1); fbComposeGetStart (iMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); if (srca == 0xff) { while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { m = *mask++; if (m == 0) { *dst = 0; } else if (m != 0xff) { *dst = FbIntMult(m, *dst, t); } dst++; } } } else { while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { m = *mask++; m = FbIntMult(m, srca, t); if (m == 0) { *dst = 0; } else if (m != 0xff) { *dst = FbIntMult(m, *dst, t); } dst++; } } } } static void fbCompositeSrcIn_8x8 (pixman_op_t op, pixman_image_t *iSrc, pixman_image_t *iMask, pixman_image_t *iDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint8_t *dstLine, *dst; uint8_t *srcLine, *src; int dstStride, srcStride; uint16_t w; uint8_t s; uint16_t t; fbComposeGetStart (iSrc, xSrc, ySrc, uint8_t, srcStride, srcLine, 1); fbComposeGetStart (iDst, xDst, yDst, uint8_t, dstStride, dstLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; src = srcLine; srcLine += srcStride; w = width; while (w--) { s = *src++; if (s == 0) { *dst = 0; } else if (s != 0xff) { *dst = FbIntMult(s, *dst, t); } dst++; } } } void fbCompositeSolidMask_nx8x8888 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t src, srca; uint32_t *dstLine, *dst, d, dstMask; uint8_t *maskLine, *mask, m; int dstStride, maskStride; uint16_t w; fbComposeGetSolid(pSrc, src, pDst->bits.format); dstMask = FbFullMask (PIXMAN_FORMAT_DEPTH (pDst->bits.format)); srca = src >> 24; if (src == 0) return; fbComposeGetStart (pDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); fbComposeGetStart (pMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { m = READ(pMask, mask++); if (m == 0xff) { if (srca == 0xff) WRITE(pDst, dst, src & dstMask); else WRITE(pDst, dst, fbOver (src, READ(pDst, dst)) & dstMask); } else if (m) { d = fbIn (src, m); WRITE(pDst, dst, fbOver (d, READ(pDst, dst)) & dstMask); } dst++; } } fbFinishAccess (pMask->pDrawable); fbFinishAccess (pDst->pDrawable); } void fbCompositeSolidMask_nx8888x8888C (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t src, srca; uint32_t *dstLine, *dst, d, dstMask; uint32_t *maskLine, *mask, ma; int dstStride, maskStride; uint16_t w; uint32_t m, n, o, p; fbComposeGetSolid(pSrc, src, pDst->bits.format); dstMask = FbFullMask (PIXMAN_FORMAT_DEPTH (pDst->bits.format)); srca = src >> 24; if (src == 0) return; fbComposeGetStart (pDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); fbComposeGetStart (pMask, xMask, yMask, uint32_t, maskStride, maskLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { ma = READ(pMask, mask++); if (ma == 0xffffffff) { if (srca == 0xff) WRITE(pDst, dst, src & dstMask); else WRITE(pDst, dst, fbOver (src, READ(pDst, dst)) & dstMask); } else if (ma) { d = READ(pDst, dst); #define FbInOverC(src,srca,msk,dst,i,result) { \ uint16_t __a = FbGet8(msk,i); \ uint32_t __t, __ta; \ uint32_t __i; \ __t = FbIntMult (FbGet8(src,i), __a,__i); \ __ta = (uint8_t) ~FbIntMult (srca, __a,__i); \ __t = __t + FbIntMult(FbGet8(dst,i),__ta,__i); \ __t = (uint32_t) (uint8_t) (__t | (-(__t >> 8))); \ result = __t << (i); \ } FbInOverC (src, srca, ma, d, 0, m); FbInOverC (src, srca, ma, d, 8, n); FbInOverC (src, srca, ma, d, 16, o); FbInOverC (src, srca, ma, d, 24, p); WRITE(pDst, dst, m|n|o|p); } dst++; } } fbFinishAccess (pMask->pDrawable); fbFinishAccess (pDst->pDrawable); } void fbCompositeSolidMask_nx8x0888 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t src, srca; uint8_t *dstLine, *dst; uint32_t d; uint8_t *maskLine, *mask, m; int dstStride, maskStride; uint16_t w; fbComposeGetSolid(pSrc, src, pDst->bits.format); srca = src >> 24; if (src == 0) return; fbComposeGetStart (pDst, xDst, yDst, uint8_t, dstStride, dstLine, 3); fbComposeGetStart (pMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { m = READ(pMask, mask++); if (m == 0xff) { if (srca == 0xff) d = src; else { d = Fetch24(pDst, dst); d = fbOver24 (src, d); } Store24(pDst, dst,d); } else if (m) { d = fbOver24 (fbIn(src,m), Fetch24(pDst, dst)); Store24(pDst, dst, d); } dst += 3; } } fbFinishAccess (pMask->pDrawable); fbFinishAccess (pDst->pDrawable); } void fbCompositeSolidMask_nx8x0565 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t src, srca; uint16_t *dstLine, *dst; uint32_t d; uint8_t *maskLine, *mask, m; int dstStride, maskStride; uint16_t w; fbComposeGetSolid(pSrc, src, pDst->bits.format); srca = src >> 24; if (src == 0) return; fbComposeGetStart (pDst, xDst, yDst, uint16_t, dstStride, dstLine, 1); fbComposeGetStart (pMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { m = READ(pMask, mask++); if (m == 0xff) { if (srca == 0xff) d = src; else { d = READ(pDst, dst); d = fbOver24 (src, cvt0565to0888(d)); } WRITE(pDst, dst, cvt8888to0565(d)); } else if (m) { d = READ(pDst, dst); d = fbOver24 (fbIn(src,m), cvt0565to0888(d)); WRITE(pDst, dst, cvt8888to0565(d)); } dst++; } } fbFinishAccess (pMask->pDrawable); fbFinishAccess (pDst->pDrawable); } void fbCompositeSolidMask_nx8888x0565C (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t src, srca; uint16_t src16; uint16_t *dstLine, *dst; uint32_t d; uint32_t *maskLine, *mask, ma; int dstStride, maskStride; uint16_t w; uint32_t m, n, o; fbComposeGetSolid(pSrc, src, pDst->bits.format); srca = src >> 24; if (src == 0) return; src16 = cvt8888to0565(src); fbComposeGetStart (pDst, xDst, yDst, uint16_t, dstStride, dstLine, 1); fbComposeGetStart (pMask, xMask, yMask, uint32_t, maskStride, maskLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { ma = READ(pMask, mask++); if (ma == 0xffffffff) { if (srca == 0xff) { WRITE(pDst, dst, src16); } else { d = READ(pDst, dst); d = fbOver24 (src, cvt0565to0888(d)); WRITE(pDst, dst, cvt8888to0565(d)); } } else if (ma) { d = READ(pDst, dst); d = cvt0565to0888(d); FbInOverC (src, srca, ma, d, 0, m); FbInOverC (src, srca, ma, d, 8, n); FbInOverC (src, srca, ma, d, 16, o); d = m|n|o; WRITE(pDst, dst, cvt8888to0565(d)); } dst++; } } fbFinishAccess (pMask->pDrawable); fbFinishAccess (pDst->pDrawable); } void fbCompositeSrc_8888x8888 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t *dstLine, *dst, dstMask; uint32_t *srcLine, *src, s; int dstStride, srcStride; uint8_t a; uint16_t w; fbComposeGetStart (pDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); fbComposeGetStart (pSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); dstMask = FbFullMask (PIXMAN_FORMAT_DEPTH (pDst->bits.format)); while (height--) { dst = dstLine; dstLine += dstStride; src = srcLine; srcLine += srcStride; w = width; while (w--) { s = READ(pSrc, src++); a = s >> 24; if (a == 0xff) WRITE(pDst, dst, s & dstMask); else if (a) WRITE(pDst, dst, fbOver (s, READ(pDst, dst)) & dstMask); dst++; } } fbFinishAccess (pSrc->pDrawable); fbFinishAccess (pDst->pDrawable); } void fbCompositeSrc_8888x0888 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint8_t *dstLine, *dst; uint32_t d; uint32_t *srcLine, *src, s; uint8_t a; int dstStride, srcStride; uint16_t w; fbComposeGetStart (pDst, xDst, yDst, uint8_t, dstStride, dstLine, 3); fbComposeGetStart (pSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; src = srcLine; srcLine += srcStride; w = width; while (w--) { s = READ(pSrc, src++); a = s >> 24; if (a) { if (a == 0xff) d = s; else d = fbOver24 (s, Fetch24(pDst, dst)); Store24(pDst, dst, d); } dst += 3; } } fbFinishAccess (pSrc->pDrawable); fbFinishAccess (pDst->pDrawable); } void fbCompositeSrc_8888x0565 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint16_t *dstLine, *dst; uint32_t d; uint32_t *srcLine, *src, s; uint8_t a; int dstStride, srcStride; uint16_t w; fbComposeGetStart (pSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); fbComposeGetStart (pDst, xDst, yDst, uint16_t, dstStride, dstLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; src = srcLine; srcLine += srcStride; w = width; while (w--) { s = READ(pSrc, src++); a = s >> 24; if (a) { if (a == 0xff) d = s; else { d = READ(pDst, dst); d = fbOver24 (s, cvt0565to0888(d)); } WRITE(pDst, dst, cvt8888to0565(d)); } dst++; } } fbFinishAccess (pDst->pDrawable); fbFinishAccess (pSrc->pDrawable); } void fbCompositeSrcAdd_8000x8000 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint8_t *dstLine, *dst; uint8_t *srcLine, *src; int dstStride, srcStride; uint16_t w; uint8_t s, d; uint16_t t; fbComposeGetStart (pSrc, xSrc, ySrc, uint8_t, srcStride, srcLine, 1); fbComposeGetStart (pDst, xDst, yDst, uint8_t, dstStride, dstLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; src = srcLine; srcLine += srcStride; w = width; while (w--) { s = READ(pSrc, src++); if (s) { if (s != 0xff) { d = READ(pDst, dst); t = d + s; s = t | (0 - (t >> 8)); } WRITE(pDst, dst, s); } dst++; } } fbFinishAccess (pDst->pDrawable); fbFinishAccess (pSrc->pDrawable); } void fbCompositeSrcAdd_8888x8888 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t *dstLine, *dst; uint32_t *srcLine, *src; int dstStride, srcStride; uint16_t w; uint32_t s, d; uint16_t t; uint32_t m,n,o,p; fbComposeGetStart (pSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); fbComposeGetStart (pDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); while (height--) { dst = dstLine; dstLine += dstStride; src = srcLine; srcLine += srcStride; w = width; while (w--) { s = READ(pSrc, src++); if (s) { if (s != 0xffffffff) { d = READ(pDst, dst); if (d) { m = FbAdd(s,d,0,t); n = FbAdd(s,d,8,t); o = FbAdd(s,d,16,t); p = FbAdd(s,d,24,t); s = m|n|o|p; } } WRITE(pDst, dst, s); } dst++; } } fbFinishAccess (pDst->pDrawable); fbFinishAccess (pSrc->pDrawable); } static void fbCompositeSrcAdd_8888x8x8 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint8_t *dstLine, *dst; uint8_t *maskLine, *mask; int dstStride, maskStride; uint16_t w; uint32_t src; uint8_t sa; fbComposeGetStart (pDst, xDst, yDst, uint8_t, dstStride, dstLine, 1); fbComposeGetStart (pMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); fbComposeGetSolid (pSrc, src, pDst->bits.format); sa = (src >> 24); while (height--) { dst = dstLine; dstLine += dstStride; mask = maskLine; maskLine += maskStride; w = width; while (w--) { uint16_t tmp; uint16_t a; uint32_t m, d; uint32_t r; a = READ(pMask, mask++); d = READ(pDst, dst); m = FbInU (sa, 0, a, tmp); r = FbAdd (m, d, 0, tmp); WRITE(pDst, dst++, r); } } fbFinishAccess(pDst->pDrawable); fbFinishAccess(pMask->pDrawable); } void fbCompositeSrcAdd_1000x1000 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { /* FIXME */ #if 0 uint32_t *dstBits, *srcBits; int dstStride, srcStride; int dstBpp, srcBpp; int dstXoff, dstYoff; int srcXoff, srcYoff; fbGetDrawable(pSrc->pDrawable, srcBits, srcStride, srcBpp, srcXoff, srcYoff); fbGetDrawable(pDst->pDrawable, dstBits, dstStride, dstBpp, dstXoff, dstYoff); fbBlt (srcBits + srcStride * (ySrc + srcYoff), srcStride, xSrc + srcXoff, dstBits + dstStride * (yDst + dstYoff), dstStride, xDst + dstXoff, width, height, GXor, FB_ALLONES, srcBpp, FALSE, FALSE); fbFinishAccess(pDst->pDrawable); fbFinishAccess(pSrc->pDrawable); #endif } void fbCompositeSolidMask_nx1xn (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { /* FIXME */ #if 0 uint32_t *dstBits; uint32_t *maskBits; int dstStride, maskStride; int dstBpp, maskBpp; int dstXoff, dstYoff; int maskXoff, maskYoff; uint32_t src; fbComposeGetSolid(pSrc, src, pDst->bits.format); fbGetStipDrawable (pMask->pDrawable, maskBits, maskStride, maskBpp, maskXoff, maskYoff); fbGetDrawable (pDst->pDrawable, dstBits, dstStride, dstBpp, dstXoff, dstYoff); switch (dstBpp) { case 32: break; case 24: break; case 16: src = cvt8888to0565(src); break; } src = fbReplicatePixel (src, dstBpp); fbBltOne (maskBits + maskStride * (yMask + maskYoff), maskStride, xMask + maskXoff, dstBits + dstStride * (yDst + dstYoff), dstStride, (xDst + dstXoff) * dstBpp, dstBpp, width * dstBpp, height, 0x0, src, FB_ALLONES, 0x0); fbFinishAccess (pDst->pDrawable); fbFinishAccess (pMask->pDrawable); #endif } /* * Apply a constant alpha value in an over computation */ static void fbCompositeSrcSrc_nxn (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height); /* * Simple bitblt */ static void fbCompositeSrcSrc_nxn (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { /* FIXME */ #if 0 uint32_t *dst; uint32_t *src; int dstStride, srcStride; int srcXoff, srcYoff; int dstXoff, dstYoff; int srcBpp; int dstBpp; pixman_bool_t reverse = FALSE; pixman_bool_t upsidedown = FALSE; fbGetDrawable(pSrc->pDrawable,src,srcStride,srcBpp,srcXoff,srcYoff); fbGetDrawable(pDst->pDrawable,dst,dstStride,dstBpp,dstXoff,dstYoff); fbBlt (src + (ySrc + srcYoff) * srcStride, srcStride, (xSrc + srcXoff) * srcBpp, dst + (yDst + dstYoff) * dstStride, dstStride, (xDst + dstXoff) * dstBpp, (width) * dstBpp, (height), GXcopy, FB_ALLONES, dstBpp, reverse, upsidedown); fbFinishAccess(pSrc->pDrawable); fbFinishAccess(pDst->pDrawable); #endif } static void pixman_image_composite_rect (pixman_op_t op, pixman_image_t *src, pixman_image_t *mask, pixman_image_t *dest, int16_t src_x, int16_t src_y, int16_t mask_x, int16_t mask_y, int16_t dest_x, int16_t dest_y, uint16_t width, uint16_t height); void fbCompositeSolidFill (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t src; fbComposeGetSolid(pSrc, src, pDst->bits.format); if (pDst->bits.format == PIXMAN_a8) src = src >> 24; else if (pDst->bits.format == PIXMAN_r5g6b5 || pDst->bits.format == PIXMAN_b5g6r5) src = cvt8888to0565 (src); pixman_fill (pDst->bits.bits, pDst->bits.rowstride, PIXMAN_FORMAT_BPP (pDst->bits.format), xDst, yDst, width, height, src); } static void fbCompositeSrc_8888xx888 (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { uint32_t *dst; uint32_t *src; int dstStride, srcStride; uint32_t n_bytes = width * sizeof (uint32_t); fbComposeGetStart (pSrc, xSrc, ySrc, uint32_t, srcStride, src, 1); fbComposeGetStart (pDst, xDst, yDst, uint32_t, dstStride, dst, 1); while (height--) { memcpy (dst, src, n_bytes); dst += dstStride; src += srcStride; } fbFinishAccess(pSrc->pDrawable); fbFinishAccess(pDst->pDrawable); } static void pixman_walk_composite_region (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height, pixman_bool_t srcRepeat, pixman_bool_t maskRepeat, CompositeFunc compositeRect) { int n; const pixman_box16_t *pbox; int w, h, w_this, h_this; int x_msk, y_msk, x_src, y_src, x_dst, y_dst; pixman_region16_t reg; pixman_region16_t *region; pixman_region_init (®); if (!pixman_compute_composite_region (®, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) { return; } region = ® pbox = pixman_region_rectangles (region, &n); while (n--) { h = pbox->y2 - pbox->y1; y_src = pbox->y1 - yDst + ySrc; y_msk = pbox->y1 - yDst + yMask; y_dst = pbox->y1; while (h) { h_this = h; w = pbox->x2 - pbox->x1; x_src = pbox->x1 - xDst + xSrc; x_msk = pbox->x1 - xDst + xMask; x_dst = pbox->x1; if (maskRepeat) { y_msk = MOD (y_msk, pMask->bits.height); if (h_this > pMask->bits.height - y_msk) h_this = pMask->bits.height - y_msk; } if (srcRepeat) { y_src = MOD (y_src, pSrc->bits.height); if (h_this > pSrc->bits.height - y_src) h_this = pSrc->bits.height - y_src; } while (w) { w_this = w; if (maskRepeat) { x_msk = MOD (x_msk, pMask->bits.width); if (w_this > pMask->bits.width - x_msk) w_this = pMask->bits.width - x_msk; } if (srcRepeat) { x_src = MOD (x_src, pSrc->bits.width); if (w_this > pSrc->bits.width - x_src) w_this = pSrc->bits.width - x_src; } (*compositeRect) (op, pSrc, pMask, pDst, x_src, y_src, x_msk, y_msk, x_dst, y_dst, w_this, h_this); w -= w_this; x_src += w_this; x_msk += w_this; x_dst += w_this; } h -= h_this; y_src += h_this; y_msk += h_this; y_dst += h_this; } pbox++; } pixman_region_fini (®); } static pixman_bool_t can_get_solid (pixman_image_t *image) { if (image->type == SOLID) return TRUE; if (image->type != BITS || image->bits.width != 1 || image->bits.height != 1) { return FALSE; } if (image->common.repeat != PIXMAN_REPEAT_NORMAL) return FALSE; switch (image->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8: case PIXMAN_b8g8r8: case PIXMAN_r5g6b5: case PIXMAN_b5g6r5: return TRUE; default: return FALSE; } } #define SCANLINE_BUFFER_LENGTH 2048 static void pixman_image_composite_rect (pixman_op_t op, pixman_image_t *src, pixman_image_t *mask, pixman_image_t *dest, int16_t src_x, int16_t src_y, int16_t mask_x, int16_t mask_y, int16_t dest_x, int16_t dest_y, uint16_t width, uint16_t height) { FbComposeData compose_data; uint32_t _scanline_buffer[SCANLINE_BUFFER_LENGTH * 3]; uint32_t *scanline_buffer = _scanline_buffer; return_if_fail (src != NULL); return_if_fail (dest != NULL); if (width > SCANLINE_BUFFER_LENGTH) { scanline_buffer = (uint32_t *)pixman_malloc_abc (width, 3, sizeof (uint32_t)); if (!scanline_buffer) return; } compose_data.op = op; compose_data.src = src; compose_data.mask = mask; compose_data.dest = dest; compose_data.xSrc = src_x; compose_data.ySrc = src_y; compose_data.xMask = mask_x; compose_data.yMask = mask_y; compose_data.xDest = dest_x; compose_data.yDest = dest_y; compose_data.width = width; compose_data.height = height; pixman_composite_rect_general (&compose_data, scanline_buffer); if (scanline_buffer != _scanline_buffer) free (scanline_buffer); } void pixman_image_composite (pixman_op_t op, pixman_image_t * pSrc, pixman_image_t * pMask, pixman_image_t * pDst, int16_t xSrc, int16_t ySrc, int16_t xMask, int16_t yMask, int16_t xDst, int16_t yDst, uint16_t width, uint16_t height) { pixman_bool_t srcRepeat = pSrc->type == BITS && pSrc->common.repeat == PIXMAN_REPEAT_NORMAL; pixman_bool_t maskRepeat = FALSE; pixman_bool_t srcTransform = pSrc->common.transform != NULL; pixman_bool_t maskTransform = FALSE; pixman_bool_t srcAlphaMap = pSrc->common.alpha_map != NULL; pixman_bool_t maskAlphaMap = FALSE; pixman_bool_t dstAlphaMap = pDst->common.alpha_map != NULL; CompositeFunc func = NULL; #ifdef USE_MMX static pixman_bool_t mmx_setup = FALSE; if (!mmx_setup) { fbComposeSetupMMX(); mmx_setup = TRUE; } #endif if (srcRepeat && srcTransform && pSrc->bits.width == 1 && pSrc->bits.height == 1) srcTransform = FALSE; if (pMask && pMask->type == BITS) { maskRepeat = pMask->common.repeat == PIXMAN_REPEAT_NORMAL; maskTransform = pMask->common.transform != 0; if (pMask->common.filter == PIXMAN_FILTER_CONVOLUTION) maskTransform = TRUE; maskAlphaMap = pMask->common.alpha_map != 0; if (maskRepeat && maskTransform && pMask->bits.width == 1 && pMask->bits.height == 1) maskTransform = FALSE; } if ((pSrc->type == BITS || can_get_solid (pSrc)) && (!pMask || pMask->type == BITS) && !srcTransform && !maskTransform && !maskAlphaMap && !srcAlphaMap && !dstAlphaMap && (pSrc->common.filter != PIXMAN_FILTER_CONVOLUTION) && (!pMask || pMask->common.filter != PIXMAN_FILTER_CONVOLUTION) && !pSrc->common.read_func && !pSrc->common.write_func && !(pMask && pMask->common.read_func) && !(pMask && pMask->common.write_func) && !pDst->common.read_func && !pDst->common.write_func) switch (op) { case PIXMAN_OP_OVER: if (pMask) { if (can_get_solid(pSrc) && !maskRepeat) { if (pSrc->type == SOLID || PIXMAN_FORMAT_COLOR(pSrc->bits.format)) { switch (pMask->bits.format) { case PIXMAN_a8: switch (pDst->bits.format) { case PIXMAN_r5g6b5: case PIXMAN_b5g6r5: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSolidMask_nx8x0565mmx; else #endif func = fbCompositeSolidMask_nx8x0565; break; case PIXMAN_r8g8b8: case PIXMAN_b8g8r8: func = fbCompositeSolidMask_nx8x0888; break; case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSolidMask_nx8x8888mmx; else #endif func = fbCompositeSolidMask_nx8x8888; break; default: break; } break; case PIXMAN_a8r8g8b8: if (pMask->common.component_alpha) { switch (pDst->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSolidMask_nx8888x8888Cmmx; else #endif func = fbCompositeSolidMask_nx8888x8888C; break; case PIXMAN_r5g6b5: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSolidMask_nx8888x0565Cmmx; else #endif func = fbCompositeSolidMask_nx8888x0565C; break; default: break; } } break; case PIXMAN_a8b8g8r8: if (pMask->common.component_alpha) { switch (pDst->bits.format) { case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSolidMask_nx8888x8888Cmmx; else #endif func = fbCompositeSolidMask_nx8888x8888C; break; case PIXMAN_b5g6r5: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSolidMask_nx8888x0565Cmmx; else #endif func = fbCompositeSolidMask_nx8888x0565C; break; default: break; } } break; case PIXMAN_a1: switch (pDst->bits.format) { case PIXMAN_r5g6b5: case PIXMAN_b5g6r5: case PIXMAN_r8g8b8: case PIXMAN_b8g8r8: case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: { uint32_t src; #if 0 /* FIXME */ fbComposeGetSolid(pSrc, src, pDst->bits.format); if ((src & 0xff000000) == 0xff000000) func = fbCompositeSolidMask_nx1xn; #endif break; } default: break; } break; default: break; } } if (func) srcRepeat = FALSE; } else if (!srcRepeat) /* has mask and non-repeating source */ { if (pSrc->bits.bits == pMask->bits.bits && xSrc == xMask && ySrc == yMask && !pMask->common.component_alpha && !maskRepeat) { /* source == mask: non-premultiplied data */ switch (pSrc->bits.format) { case PIXMAN_x8b8g8r8: switch (pMask->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_a8b8g8r8: switch (pDst->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888RevNPx8888mmx; #endif break; case PIXMAN_r5g6b5: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888RevNPx0565mmx; #endif break; default: break; } break; default: break; } break; case PIXMAN_x8r8g8b8: switch (pMask->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_a8b8g8r8: switch (pDst->bits.format) { case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888RevNPx8888mmx; #endif break; case PIXMAN_r5g6b5: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888RevNPx0565mmx; #endif break; default: break; } break; default: break; } break; default: break; } break; } else if (maskRepeat && pMask->bits.width == 1 && pMask->bits.height == 1) { switch (pSrc->bits.format) { #ifdef USE_MMX case PIXMAN_x8r8g8b8: if ((pDst->bits.format == PIXMAN_a8r8g8b8 || pDst->bits.format == PIXMAN_x8r8g8b8) && pMask->bits.format == PIXMAN_a8 && pixman_have_mmx()) func = fbCompositeSrc_x888xnx8888mmx; break; case PIXMAN_x8b8g8r8: if ((pDst->bits.format == PIXMAN_a8b8g8r8 || pDst->bits.format == PIXMAN_x8b8g8r8) && pMask->bits.format == PIXMAN_a8 && pixman_have_mmx()) func = fbCompositeSrc_x888xnx8888mmx; break; case PIXMAN_a8r8g8b8: if ((pDst->bits.format == PIXMAN_a8r8g8b8 || pDst->bits.format == PIXMAN_x8r8g8b8) && pMask->bits.format == PIXMAN_a8 && pixman_have_mmx()) func = fbCompositeSrc_8888x8x8888mmx; break; case PIXMAN_a8b8g8r8: if ((pDst->bits.format == PIXMAN_a8b8g8r8 || pDst->bits.format == PIXMAN_x8b8g8r8) && pMask->bits.format == PIXMAN_a8 && pixman_have_mmx()) func = fbCompositeSrc_8888x8x8888mmx; break; #endif default: break; } if (func) maskRepeat = FALSE; } else { #if 0 /* FIXME: This code is commented out since it's apparently not * actually faster than the generic code. */ if (pMask->bits.format == PIXMAN_a8) { if ((pSrc->bits.format == PIXMAN_x8r8g8b8 && (pDst->bits.format == PIXMAN_x8r8g8b8 || pDst->bits.format == PIXMAN_a8r8g8b8)) || (pSrc->bits.format == PIXMAN_x8b8g8r8 && (pDst->bits.format == PIXMAN_x8b8g8r8 || pDst->bits.format == PIXMAN_a8b8g8r8))) { #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeOver_x888x8x8888mmx; else #endif func = fbCompositeOver_x888x8x8888; } } #endif } } } else /* no mask */ { if (can_get_solid(pSrc)) { /* no mask and repeating source */ if (pSrc->type == SOLID || pSrc->bits.format == PIXMAN_a8r8g8b8) { switch (pDst->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: #ifdef USE_MMX if (pixman_have_mmx()) { srcRepeat = FALSE; func = fbCompositeSolid_nx8888mmx; } #endif break; case PIXMAN_r5g6b5: #ifdef USE_MMX if (pixman_have_mmx()) { srcRepeat = FALSE; func = fbCompositeSolid_nx0565mmx; } #endif break; default: break; } break; } } else if (! srcRepeat) { /* * Formats without alpha bits are just Copy with Over */ if (pSrc->bits.format == pDst->bits.format && !PIXMAN_FORMAT_A(pSrc->bits.format)) { #ifdef USE_MMX if (pixman_have_mmx() && (pSrc->bits.format == PIXMAN_x8r8g8b8 || pSrc->bits.format == PIXMAN_x8b8g8r8)) func = fbCompositeCopyAreammx; else #endif #if 0 /* FIXME */ func = fbCompositeSrcSrc_nxn #endif ; } else switch (pSrc->bits.format) { case PIXMAN_a8r8g8b8: switch (pDst->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888x8888mmx; else #endif func = fbCompositeSrc_8888x8888; break; case PIXMAN_r8g8b8: func = fbCompositeSrc_8888x0888; break; case PIXMAN_r5g6b5: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888x0565mmx; else #endif func = fbCompositeSrc_8888x0565; break; default: break; } break; case PIXMAN_x8r8g8b8: switch (pDst->bits.format) { case PIXMAN_x8r8g8b8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeCopyAreammx; #endif break; default: break; } case PIXMAN_x8b8g8r8: switch (pDst->bits.format) { case PIXMAN_x8b8g8r8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeCopyAreammx; #endif break; default: break; } break; case PIXMAN_a8b8g8r8: switch (pDst->bits.format) { case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888x8888mmx; else #endif func = fbCompositeSrc_8888x8888; break; case PIXMAN_b8g8r8: func = fbCompositeSrc_8888x0888; break; case PIXMAN_b5g6r5: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrc_8888x0565mmx; else #endif func = fbCompositeSrc_8888x0565; break; default: break; } break; default: break; } } } break; case PIXMAN_OP_ADD: if (pMask == 0) { switch (pSrc->bits.format) { case PIXMAN_a8r8g8b8: switch (pDst->bits.format) { case PIXMAN_a8r8g8b8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrcAdd_8888x8888mmx; else #endif func = fbCompositeSrcAdd_8888x8888; break; default: break; } break; case PIXMAN_a8b8g8r8: switch (pDst->bits.format) { case PIXMAN_a8b8g8r8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrcAdd_8888x8888mmx; else #endif func = fbCompositeSrcAdd_8888x8888; break; default: break; } break; case PIXMAN_a8: switch (pDst->bits.format) { case PIXMAN_a8: #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrcAdd_8000x8000mmx; else #endif func = fbCompositeSrcAdd_8000x8000; break; default: break; } break; case PIXMAN_a1: switch (pDst->bits.format) { case PIXMAN_a1: #if 0 /* FIXME */ func = fbCompositeSrcAdd_1000x1000; #endif break; default: break; } break; default: break; } } else { if (can_get_solid (pSrc) && pMask->bits.format == PIXMAN_a8 && pDst->bits.format == PIXMAN_a8) { srcRepeat = FALSE; #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeSrcAdd_8888x8x8mmx; else #endif func = fbCompositeSrcAdd_8888x8x8; } } break; case PIXMAN_OP_SRC: if (pMask) { #ifdef USE_MMX if (can_get_solid (pSrc)) { if (pMask->bits.format == PIXMAN_a8) { switch (pDst->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: if (pixman_have_mmx()) { srcRepeat = FALSE; func = fbCompositeSolidMaskSrc_nx8x8888mmx; } break; default: break; } } } #endif } else { if (can_get_solid (pSrc)) { switch (pDst->bits.format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_a8: case PIXMAN_r5g6b5: func = fbCompositeSolidFill; srcRepeat = FALSE; break; default: break; } } else if (pSrc->bits.format == pDst->bits.format) { #ifdef USE_MMX if (pSrc->bits.bits != pDst->bits.bits && pixman_have_mmx() && (PIXMAN_FORMAT_BPP (pSrc->bits.format) == 16 || PIXMAN_FORMAT_BPP (pSrc->bits.format) == 32)) func = fbCompositeCopyAreammx; else #endif /* FIXME */ #if 0 func = fbCompositeSrcSrc_nxn #endif ; } else if (((pSrc->bits.format == PIXMAN_a8r8g8b8 || pSrc->bits.format == PIXMAN_x8r8g8b8) && pDst->bits.format == PIXMAN_x8r8g8b8) || ((pSrc->bits.format == PIXMAN_a8b8g8r8 || pSrc->bits.format == PIXMAN_x8b8g8r8) && pDst->bits.format == PIXMAN_x8b8g8r8)) { func = fbCompositeSrc_8888xx888; } } break; case PIXMAN_OP_IN: if (pSrc->bits.format == PIXMAN_a8 && pDst->bits.format == PIXMAN_a8 && !pMask) { #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeIn_8x8mmx; else #endif func = fbCompositeSrcIn_8x8; } else if (srcRepeat && pMask && !pMask->common.component_alpha && (pSrc->bits.format == PIXMAN_a8r8g8b8 || pSrc->bits.format == PIXMAN_a8b8g8r8) && (pMask->bits.format == PIXMAN_a8) && pDst->bits.format == PIXMAN_a8) { #ifdef USE_MMX if (pixman_have_mmx()) func = fbCompositeIn_nx8x8mmx; else #endif func = fbCompositeSolidMaskIn_nx8x8; srcRepeat = FALSE; } break; default: break; } if ((srcRepeat && pSrc->bits.width == 1 && pSrc->bits.height == 1) || (maskRepeat && pMask->bits.width == 1 && pMask->bits.height == 1)) { /* If src or mask are repeating 1x1 images and srcRepeat or * maskRepeat are still TRUE, it means the fast path we * selected does not actually handle repeating images. * * So rather than call the "fast path" with a zillion * 1x1 requests, we just use the general code (which does * do something sensible with 1x1 repeating images). */ func = NULL; } if (!func) { func = pixman_image_composite_rect; /* CompositeGeneral optimizes 1x1 repeating images itself */ if (pSrc->type == BITS && pSrc->bits.width == 1 && pSrc->bits.height == 1) { srcRepeat = FALSE; } if (pMask && pMask->type == BITS && pMask->bits.width == 1 && pMask->bits.height == 1) { maskRepeat = FALSE; } /* if we are transforming, repeats are handled in fbFetchTransformed */ if (srcTransform) srcRepeat = FALSE; if (maskTransform) maskTransform = FALSE; } pixman_walk_composite_region (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height, srcRepeat, maskRepeat, func); } #ifdef USE_MMX /* The CPU detection code needs to be in a file not compiled with * "-mmmx -msse", as gcc would generate CMOV instructions otherwise * that would lead to SIGILL instructions on old CPUs that don't have * it. */ #if !defined(__amd64__) && !defined(__x86_64__) #ifdef HAVE_GETISAX #include #endif enum CPUFeatures { NoFeatures = 0, MMX = 0x1, MMX_Extensions = 0x2, SSE = 0x6, SSE2 = 0x8, CMOV = 0x10 }; static unsigned int detectCPUFeatures(void) { unsigned int features = 0; unsigned int result = 0; #ifdef HAVE_GETISAX if (getisax(&result, 1)) { if (result & AV_386_CMOV) features |= CMOV; if (result & AV_386_MMX) features |= MMX; if (result & AV_386_AMD_MMX) features |= MMX_Extensions; if (result & AV_386_SSE) features |= SSE; if (result & AV_386_SSE2) features |= SSE2; } #else char vendor[13]; #ifdef _MSC_VER int vendor0 = 0, vendor1, vendor2; #endif vendor[0] = 0; vendor[12] = 0; #ifdef __GNUC__ /* see p. 118 of amd64 instruction set manual Vol3 */ /* We need to be careful about the handling of %ebx and * %esp here. We can't declare either one as clobbered * since they are special registers (%ebx is the "PIC * register" holding an offset to global data, %esp the * stack pointer), so we need to make sure they have their * original values when we access the output operands. */ __asm__ ("pushf\n" "pop %%eax\n" "mov %%eax, %%ecx\n" "xor $0x00200000, %%eax\n" "push %%eax\n" "popf\n" "pushf\n" "pop %%eax\n" "mov $0x0, %%edx\n" "xor %%ecx, %%eax\n" "jz 1f\n" "mov $0x00000000, %%eax\n" "push %%ebx\n" "cpuid\n" "mov %%ebx, %%eax\n" "pop %%ebx\n" "mov %%eax, %1\n" "mov %%edx, %2\n" "mov %%ecx, %3\n" "mov $0x00000001, %%eax\n" "push %%ebx\n" "cpuid\n" "pop %%ebx\n" "1:\n" "mov %%edx, %0\n" : "=r" (result), "=m" (vendor[0]), "=m" (vendor[4]), "=m" (vendor[8]) : : "%eax", "%ecx", "%edx" ); #elif defined (_MSC_VER) _asm { pushfd pop eax mov ecx, eax xor eax, 00200000h push eax popfd pushfd pop eax mov edx, 0 xor eax, ecx jz nocpuid mov eax, 0 push ebx cpuid mov eax, ebx pop ebx mov vendor0, eax mov vendor1, edx mov vendor2, ecx mov eax, 1 push ebx cpuid pop ebx nocpuid: mov result, edx } memmove (vendor+0, &vendor0, 4); memmove (vendor+4, &vendor1, 4); memmove (vendor+8, &vendor2, 4); #else # error unsupported compiler #endif features = 0; if (result) { /* result now contains the standard feature bits */ if (result & (1 << 15)) features |= CMOV; if (result & (1 << 23)) features |= MMX; if (result & (1 << 25)) features |= SSE; if (result & (1 << 26)) features |= SSE2; if ((features & MMX) && !(features & SSE) && (strcmp(vendor, "AuthenticAMD") == 0 || strcmp(vendor, "Geode by NSC") == 0)) { /* check for AMD MMX extensions */ #ifdef __GNUC__ __asm__("push %%ebx\n" "mov $0x80000000, %%eax\n" "cpuid\n" "xor %%edx, %%edx\n" "cmp $0x1, %%eax\n" "jge 2f\n" "mov $0x80000001, %%eax\n" "cpuid\n" "2:\n" "pop %%ebx\n" "mov %%edx, %0\n" : "=r" (result) : : "%eax", "%ecx", "%edx" ); #elif defined _MSC_VER _asm { push ebx mov eax, 80000000h cpuid xor edx, edx cmp eax, 1 jge notamd mov eax, 80000001h cpuid notamd: pop ebx mov result, edx } #endif if (result & (1<<22)) features |= MMX_Extensions; } } #endif /* HAVE_GETISAX */ return features; } pixman_bool_t pixman_have_mmx (void) { static pixman_bool_t initialized = FALSE; static pixman_bool_t mmx_present; if (!initialized) { unsigned int features = detectCPUFeatures(); mmx_present = (features & (MMX|MMX_Extensions)) == (MMX|MMX_Extensions); initialized = TRUE; } return mmx_present; } #endif /* __amd64__ */ #endif