Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright (c) 2007-2008 Advanced Micro Devices, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     20  * DEALINGS IN THE SOFTWARE.
     21  *
     22  * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
     23  * contributors may be used to endorse or promote products derived from this
     24  * software without specific prior written permission.
     25  */
     26 
     27 /* TODO:
     28    Support a8 as a source or destination?
     29    convert !a8 or !a4 masks?
     30    support multiple pass operations?
     31 */
     32 
     33 /* To support PictOptAdd with a mask */
     34 
     35 #ifdef HAVE_CONFIG_H
     36 #include "config.h"
     37 #endif
     38 
     39 #include "xorg-server.h"
     40 
     41 #include "xf86.h"
     42 #include "exa.h"
     43 
     44 #include "geode.h"
     45 #include "cim_defs.h"
     46 #include "cim_regs.h"
     47 
     48 #include "geode_blend.h"
     49 
     50 #define F(x)    IntToxFixed(x)
     51 #define I(x)    xFixedToInt(x)
     52 
     53 #define GEODE_TRACE_FALL 0
     54 
     55 #if GEODE_TRACE_FALL
     56 #define GEODE_FALLBACK(x)               \
     57 do {                                    \
     58 	ErrorF("%s: ", __FUNCTION__);   \
     59 	ErrorF x;                       \
     60 	return FALSE;                   \
     61 } while (0)
     62 #else
     63 #define GEODE_FALLBACK(x) return FALSE
     64 #endif
     65 
     66 static const struct exa_format_t {
     67     int exa;
     68     int bpp;
     69     int fmt;
     70     int alphabits;
     71 } lx_exa_formats[] = {
     72     {
     73     PICT_a8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}, {
     74     PICT_x8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 0}, {
     75     PICT_x8b8g8r8, 32, CIMGP_SOURCE_FMT_32BPP_BGR, 0}, {
     76     PICT_a4r4g4b4, 16, CIMGP_SOURCE_FMT_4_4_4_4, 4}, {
     77     PICT_a1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 1}, {
     78     PICT_r5g6b5, 16, CIMGP_SOURCE_FMT_0_5_6_5, 0}, {
     79     PICT_b5g6r5, 16, CIMGP_SOURCE_FMT_16BPP_BGR, 0}, {
     80     PICT_x1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 0}, {
     81     PICT_x1b5g5r5, 16, CIMGP_SOURCE_FMT_15BPP_BGR, 0}, {
     82     PICT_r3g3b2, 8, CIMGP_SOURCE_FMT_3_3_2, 0}, {
     83     PICT_a8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}
     84 };
     85 
     86 /* This is a chunk of memory we use for scratch space */
     87 
     88 #define COMP_TYPE_MASK 0
     89 #define COMP_TYPE_ONEPASS 1
     90 #define COMP_TYPE_TWOPASS 3
     91 #define COMP_TYPE_ROTATE  5
     92 
     93 static struct {
     94     int type;
     95 
     96     unsigned int srcOffset;
     97     unsigned int srcPitch;
     98     unsigned int srcBpp;
     99     unsigned int srcWidth, srcHeight;
    100 
    101     unsigned int srcColor;
    102     int op;
    103     int repeat;
    104     int maskrepeat;
    105     unsigned int fourBpp;
    106     unsigned int bufferOffset;
    107     struct exa_format_t *srcFormat;
    108     struct exa_format_t *dstFormat;
    109 
    110     int rotate;
    111     PictTransform *transform;
    112 
    113 } exaScratch;
    114 
    115 static const int SDfn[16] = {
    116     0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE,
    117     0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF
    118 };
    119 
    120 static const int SDfn_PM[16] = {
    121     0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
    122     0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA
    123 };
    124 
    125 /* These functions check to see if we can safely prefetch the memory
    126  * for the blt, or if we have to wait the previous blt to complete.
    127  * One function is for the fill, and the other is for the copy because
    128  * they have different requirements based on ROP
    129  */
    130 
    131 static int lx0 = -1, ly0 = -1, lx1 = -1, ly1 = -1;
    132 
    133 static int
    134 lx_fill_flags(int x0, int y0, int w, int h, int rop)
    135 {
    136     int x1 = x0 + w, y1 = y0 + h;
    137     int n = ((rop ^ (rop >> 1)) & 0x55) == 0 || /* no dst */
    138         x0 >= lx1 || y0 >= ly1 ||       /* rght/below */
    139         x1 <= lx0 || y1 <= ly0 ?        /* left/above */
    140         0 : CIMGP_BLTFLAGS_HAZARD;
    141 
    142     lx0 = x0;
    143     ly0 = y0;
    144     lx1 = x1;
    145     ly1 = y1;
    146 
    147     return n;
    148 }
    149 
    150 static int
    151 lx_copy_flags(int x0, int y0, int x1, int y1, int w, int h, int rop)
    152 {
    153     int x2 = x1 + w, y2 = y1 + h;
    154 
    155     /* dst not hazzard and src not hazzard */
    156     int n = (((rop ^ (rop >> 1)) & 0x55) == 0 ||
    157              x1 >= lx1 || y1 >= ly1 ||
    158              x2 <= lx0 || y2 <= ly0) &&
    159         (((rop ^ (rop >> 2)) & 0x33) == 0 ||
    160          x0 >= lx1 || y0 >= ly1 ||
    161          x0 + w <= lx0 || y0 + h <= ly0) ? 0 : CIMGP_BLTFLAGS_HAZARD;
    162 
    163     lx0 = x1;
    164     ly0 = y1;
    165     lx1 = x2;
    166     ly1 = y2;
    167 
    168     return n;
    169 }
    170 
    171 /* These are borrowed from the exa engine - they should be made global
    172    and available to drivers, but until then....
    173 */
    174 
    175 /* exaGetPixelFromRGBA (exa_render.c) */
    176 
    177 static Bool
    178 _GetPixelFromRGBA(CARD32 *pixel,
    179                   CARD16 red, CARD16 green, CARD16 blue, CARD16 alpha,
    180                   CARD32 format)
    181 {
    182     int rbits, bbits, gbits, abits;
    183     int rshift, bshift, gshift, ashift;
    184 
    185     *pixel = 0;
    186 
    187     if (!PICT_FORMAT_COLOR(format))
    188         return FALSE;
    189 
    190     rbits = PICT_FORMAT_R(format);
    191     gbits = PICT_FORMAT_G(format);
    192     bbits = PICT_FORMAT_B(format);
    193     abits = PICT_FORMAT_A(format);
    194 
    195     if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
    196         bshift = 0;
    197         gshift = bbits;
    198         rshift = gshift + gbits;
    199         ashift = rshift + rbits;
    200     }
    201     else {                      /* PICT_TYPE_ABGR */
    202         rshift = 0;
    203         gshift = rbits;
    204         bshift = gshift + gbits;
    205         ashift = bshift + bbits;
    206     }
    207 
    208     *pixel |= (blue >> (16 - bbits)) << bshift;
    209     *pixel |= (red >> (16 - rbits)) << rshift;
    210     *pixel |= (green >> (16 - gbits)) << gshift;
    211     *pixel |= (alpha >> (16 - abits)) << ashift;
    212 
    213     return TRUE;
    214 }
    215 
    216 /* exaGetRGBAFromPixel (exa_render.c) */
    217 
    218 static Bool
    219 _GetRGBAFromPixel(CARD32 pixel,
    220                   CARD16 *red,
    221                   CARD16 *green, CARD16 *blue, CARD16 *alpha, CARD32 format)
    222 {
    223     int rbits, bbits, gbits, abits;
    224     int rshift, bshift, gshift, ashift;
    225 
    226     if (!PICT_FORMAT_COLOR(format))
    227         return FALSE;
    228 
    229     rbits = PICT_FORMAT_R(format);
    230     gbits = PICT_FORMAT_G(format);
    231     bbits = PICT_FORMAT_B(format);
    232     abits = PICT_FORMAT_A(format);
    233 
    234     if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
    235         bshift = 0;
    236         gshift = bbits;
    237         rshift = gshift + gbits;
    238         ashift = rshift + rbits;
    239     }
    240     else {                      /* PICT_TYPE_ABGR */
    241         rshift = 0;
    242         gshift = rbits;
    243         bshift = gshift + gbits;
    244         ashift = bshift + bbits;
    245     }
    246 
    247     *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
    248     while (rbits < 16) {
    249         *red |= *red >> rbits;
    250         rbits <<= 1;
    251     }
    252 
    253     *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
    254     while (gbits < 16) {
    255         *green |= *green >> gbits;
    256         gbits <<= 1;
    257     }
    258 
    259     *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
    260     while (bbits < 16) {
    261         *blue |= *blue >> bbits;
    262         bbits <<= 1;
    263     }
    264 
    265     if (abits) {
    266         *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
    267         while (abits < 16) {
    268             *alpha |= *alpha >> abits;
    269             abits <<= 1;
    270         }
    271     }
    272     else
    273         *alpha = 0xffff;
    274 
    275     return TRUE;
    276 }
    277 
    278 static unsigned int
    279 lx_get_source_color(PixmapPtr pSrc, int srcFormat, int dstFormat)
    280 {
    281     CARD32 in, out;
    282     CARD16 red = 0, green = 0, blue = 0, alpha = 0;
    283 
    284     /* Stall to avoid a race with the upload function */
    285     /* for 1.4 and newer, the problem will be resolved within
    286      * exaGetPixmapFirstPixel, so this should be adjusted so
    287      * the stall isn't run needlessly
    288      */
    289     /* FIXME: xserver-1.4 with a supposed fix for this is really old, so kill the stall? */
    290 
    291     gp_wait_until_idle();
    292     in = exaGetPixmapFirstPixel(pSrc);
    293 
    294     _GetRGBAFromPixel(in, &red, &blue, &green, &alpha, srcFormat);
    295     _GetPixelFromRGBA(&out, red, blue, green, alpha, dstFormat);
    296 
    297     return out;
    298 }
    299 
    300 static Bool
    301 lx_prepare_solid(PixmapPtr pxMap, int alu, Pixel planemask, Pixel fg)
    302 {
    303     int pitch = exaGetPixmapPitch(pxMap);
    304     int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
    305 
    306     gp_declare_blt(0);
    307     gp_set_bpp(pxMap->drawable.bitsPerPixel);
    308 
    309     gp_set_raster_operation(op);
    310 
    311     if (planemask != ~0U)
    312         gp_set_solid_pattern(planemask);
    313 
    314     exaScratch.op = op;
    315 
    316     gp_set_solid_source(fg);
    317 
    318     gp_set_strides(pitch, pitch);
    319     gp_write_parameters();
    320     return TRUE;
    321 }
    322 
    323 static void
    324 lx_do_solid(PixmapPtr pxMap, int x1, int y1, int x2, int y2)
    325 {
    326     int bpp = (pxMap->drawable.bitsPerPixel + 7) / 8;
    327     int pitch = exaGetPixmapPitch(pxMap);
    328     unsigned int offset = exaGetPixmapOffset(pxMap) + (pitch * y1) + (bpp * x1);
    329 
    330     gp_declare_blt(lx_fill_flags(x1, y1, x2 - x1, y2 - y1, exaScratch.op));
    331     gp_pattern_fill(offset, x2 - x1, y2 - y1);
    332 }
    333 
    334 static Bool
    335 lx_prepare_copy(PixmapPtr pxSrc, PixmapPtr pxDst, int dx, int dy,
    336                 int alu, Pixel planemask)
    337 {
    338     int dpitch = exaGetPixmapPitch(pxDst);
    339     int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
    340 
    341     gp_declare_blt(0);
    342     gp_set_bpp(pxDst->drawable.bitsPerPixel);
    343 
    344     gp_set_raster_operation(op);
    345 
    346     if (planemask != ~0U)
    347         gp_set_solid_pattern(planemask);
    348 
    349     exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
    350     exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
    351     exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
    352 
    353     exaScratch.op = op;
    354 
    355     gp_set_strides(dpitch, exaScratch.srcPitch);
    356     gp_write_parameters();
    357     return TRUE;
    358 }
    359 
    360 static void
    361 lx_do_copy(PixmapPtr pxDst, int srcX, int srcY,
    362            int dstX, int dstY, int w, int h)
    363 {
    364     int dstBpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
    365     int dstPitch = exaGetPixmapPitch(pxDst);
    366     unsigned int srcOffset, dstOffset;
    367     int flags = 0;
    368 
    369     gp_declare_blt(lx_copy_flags(srcX, srcY, dstX, dstY, w, h, exaScratch.op));
    370 
    371     srcOffset = exaScratch.srcOffset + (exaScratch.srcPitch * srcY) +
    372         (exaScratch.srcBpp) * srcX;
    373 
    374     dstOffset = exaGetPixmapOffset(pxDst) + (dstPitch * dstY) + (dstBpp * dstX);
    375 
    376     if (dstX > srcX)
    377         flags |= CIMGP_NEGXDIR;
    378 
    379     if (dstY > srcY)
    380         flags |= CIMGP_NEGYDIR;
    381 
    382     gp_screen_to_screen_blt(dstOffset, srcOffset, w, h, flags);
    383 }
    384 
    385 /* Composite operations
    386 
    387 These are the simplest - one pass operations - if there is no format or
    388 mask, the we can make these happen pretty fast
    389 
    390                        Operation  Type  Channel   Alpha
    391 PictOpClear            0          2     0         3
    392 PictOpSrc              0          3     0         3
    393 PictOpDst              0          3     1         3
    394 PictOpOver             2          0     0         3
    395 PictOpOverReverse      2          0     1         3
    396 PictOpIn               0          1     0         3
    397 PictOpInReverse        0          1     1         3
    398 PictOpOut              1          0     0         3
    399 PictOpOutReverse       1          0     1         3
    400 PictOpAdd              2          2     0         3
    401 
    402 The following require multiple passes
    403 PictOpAtop
    404 PictOpXor
    405 */
    406 
    407 struct blend_ops_t {
    408     int operation;
    409     int type;
    410     int channel;
    411 } lx_alpha_ops[] = {
    412     /* PictOpClear */
    413     {
    414     CIMGP_ALPHA_TIMES_A, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
    415     },
    416         /* PictOpSrc */
    417     {
    418     CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_SOURCE}, {
    419     },
    420         /* PictOpDst */
    421     {
    422     CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_DEST}, {
    423     },
    424         /* PictOpOver */
    425     {
    426     CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
    427     CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    428         /* PictOpOverReverse */
    429     {
    430     CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
    431     CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    432         /* PictOpIn */
    433     {
    434     CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
    435     CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    436         /* PictOpInReverse */
    437     {
    438     CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
    439     CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    440         /* PictOpOut */
    441     {
    442     CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
    443     CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    444         /* PictOpOutReverse */
    445     {
    446     CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
    447     CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    448         /* SrcAtop */
    449     {
    450     CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
    451     CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    452         /* SrcAtopReverse */
    453     {
    454     CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
    455     CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST},
    456         /* Xor */
    457     {
    458     CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
    459     CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
    460         /* PictOpAdd */
    461     {
    462     CIMGP_A_PLUS_BETA_B, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
    463     }
    464 };
    465 
    466 #ifndef ARRAY_SIZE
    467 #define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
    468 #endif
    469 
    470 static const struct exa_format_t *
    471 lx_get_format(PicturePtr p)
    472 {
    473     int i;
    474     unsigned int format = p->format;
    475 
    476     for (i = 0; i < ARRAY_SIZE(lx_exa_formats); i++)
    477         if (lx_exa_formats[i].exa == format)
    478             return (&lx_exa_formats[i]);
    479 
    480     return NULL;
    481 }
    482 
    483 static Bool
    484 lx_process_transform(PicturePtr pSrc)
    485 {
    486     PictTransformPtr t = pSrc->transform;
    487     xFixed c0 = t->matrix[0][0];
    488     xFixed s0 = t->matrix[0][1];
    489     xFixed s1 = t->matrix[1][0];
    490     xFixed c1 = t->matrix[1][1];
    491 
    492     /* If the transform doesn't have any rotation
    493      * or scaling components, then just grab the
    494      * translate coordinates */
    495 
    496     if (t->matrix[0][0] == 0 &&
    497         t->matrix[0][1] == 0 && t->matrix[1][0] == 0 && t->matrix[1][1] == 0) {
    498         exaScratch.transform = pSrc->transform;
    499         return TRUE;
    500     }
    501 
    502     /* Otherwise, see if this is a simple
    503      * rotate transform - if it isn't, then
    504      * we have to punt back to software */
    505 
    506     if (t->matrix[2][2] != F(1))
    507         return FALSE;
    508 
    509     /* The rotate matrix looks like this:
    510      * [ cos X   -sin x
    511      * sin X   cos X ]
    512      *
    513      * Where X is the angle.  We do a simple
    514      * check first - if [0,0] != [1,1], then
    515      * scaling was specified too, and we can
    516      * bail, and if [0,1] != -[1,1] then this
    517      * isn't scaling that we can handle.
    518      */
    519 
    520     if ((c0 != c1) || (s0 != -s1))
    521         return FALSE;
    522 
    523     /* Now, figure out what angle we want - we
    524      * can only accelerate right angle rotations,
    525      * so this turns into an easy set of if statements */
    526 
    527     if (c0 == F(1) && s1 == F(0))
    528         exaScratch.rotate = RR_Rotate_0;
    529     else if (c0 == F(0) && s1 == F(1))
    530         exaScratch.rotate = RR_Rotate_90;
    531     else if (c0 == F(-1) && s1 == F(0))
    532         exaScratch.rotate = RR_Rotate_180;
    533     else if (c0 == F(0) && s1 == F(-1))
    534         exaScratch.rotate = RR_Rotate_270;
    535     else
    536         return FALSE;
    537 
    538     exaScratch.transform = pSrc->transform;
    539 
    540     return TRUE;
    541 }
    542 
    543 static Bool
    544 lx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst)
    545 {
    546     GeodeRec *pGeode = GEODEPTR_FROM_PICTURE(pDst);
    547     const struct exa_format_t *srcFmt, *dstFmt;
    548 
    549     if (op > PictOpAdd)
    550         GEODE_FALLBACK(("Operation %d is not supported\n", op));
    551 
    552     /* XXX - don't know if we can do any hwaccel on solid fills or gradient types in generic cases */
    553     if (pMsk && pMsk->pSourcePict)
    554         GEODE_FALLBACK(("%s are not supported as a mask\n",
    555                         pMsk->pSourcePict->type ==
    556                         SourcePictTypeSolidFill ? "Solid pictures" :
    557                         "Gradients"));
    558 
    559     if (pSrc->pSourcePict && pSrc->pSourcePict->type != SourcePictTypeSolidFill)
    560         GEODE_FALLBACK(("Gradients are not supported as the source\n"));
    561 
    562     if (pMsk && op == PictOpAdd)
    563         GEODE_FALLBACK(("PictOpAdd with mask is not supported\n"));
    564 
    565     /* FIXME: Meet this conditions from the debug for PictOpAdd.
    566      * Any Other possibilities? Add a judge for the future supplement */
    567     if (op == PictOpAdd && pSrc->format == PICT_a8r8g8b8 &&
    568         pDst->format == PICT_a8)
    569         return TRUE;
    570 
    571     if (op == PictOpAdd && pSrc->format == PICT_x8r8g8b8 &&
    572         pDst->format == PICT_a8)
    573         return TRUE;
    574 
    575     if (op == PictOpAdd && pSrc->format == PICT_r5g6b5 &&
    576         pDst->format == PICT_a8)
    577         return TRUE;
    578 
    579     if (usesPasses(op)) {
    580         /* FIXME: Slightly misleading fallback msg when !pMsk */
    581         if (pGeode->exaBfrOffset == 0 || !pMsk)
    582             GEODE_FALLBACK(("Multipass operation requires off-screen buffer\n"));
    583     }
    584 
    585     /* Check that the filter matches what we support */
    586 
    587     switch (pSrc->filter) {
    588     case PictFilterNearest:
    589     case PictFilterFast:
    590     case PictFilterGood:
    591     case PictFilterBest:
    592         break;
    593 
    594     default:
    595         GEODE_FALLBACK(("Bilinear or convolution filters are not supported\n"));
    596     }
    597 
    598     if (pMsk && pMsk->transform)
    599         GEODE_FALLBACK(("Mask transforms are not supported\n"));
    600 
    601     /* Keep an eye out for source rotation transforms - those we can
    602      * do something about */
    603 
    604     exaScratch.rotate = RR_Rotate_0;
    605     exaScratch.transform = NULL;
    606 
    607     if (pSrc->transform && !lx_process_transform(pSrc))
    608         GEODE_FALLBACK(("Transform operation is non-trivial\n"));
    609 
    610     /* XXX - I don't understand PICT_a8 enough - so I'm punting */
    611     if ((op != PictOpAdd) && (pSrc->format == PICT_a8 ||
    612                               pDst->format == PICT_a8))
    613         GEODE_FALLBACK(("PICT_a8 as src or dst format is unsupported\n"));
    614 
    615     if (pMsk && op != PictOpClear) {
    616         struct blend_ops_t *opPtr = &lx_alpha_ops[op * 2];
    617         int direction = (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1;
    618 
    619         /* Direction 0 indicates src->dst, 1 indicates dst->src */
    620         if (((direction == 0) &&
    621              (pSrc->pDrawable && pSrc->pDrawable->bitsPerPixel < 16)) ||
    622             ((direction == 1) && (pDst->pDrawable->bitsPerPixel < 16))) {
    623             ErrorF("Mask blending unsupported with <16bpp\n");
    624             return FALSE;
    625         }
    626         if (pMsk->format != PICT_a8 && pMsk->format != PICT_a4)
    627             GEODE_FALLBACK(("Masks can be only done with a 8bpp or 4bpp depth\n"));
    628 
    629         /* The pSrc should be 1x1 pixel if the pMsk is not zero */
    630         if (pSrc->pDrawable &&
    631             (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1))
    632             GEODE_FALLBACK(("pSrc should be 1x1 pixel if pMsk is not zero\n"));
    633         /* FIXME: In lx_prepare_composite, there are no variables to record the
    634          * one pixel source's width and height when the mask is not zero.
    635          * That will lead to bigger region to render instead of one pixel in lx
    636          * _do_composite, so we should fallback currently to avoid this */
    637         /* Not an issue for solid pictures, because we'll treat it as 1x1R too */
    638         if (!pSrc->repeat &&
    639             !(pSrc->pSourcePict &&
    640               pSrc->pSourcePict->type == SourcePictTypeSolidFill)) {
    641             GEODE_FALLBACK(("FIXME: unzero mask might lead to bigger rendering region than 1x1 pixels\n"));
    642         }
    643     }
    644     else {
    645         if (pSrc->pSourcePict)
    646             GEODE_FALLBACK(("Solid source pictures without a mask are not supported\n"));
    647     }
    648 
    649     /* Get the formats for the source and destination */
    650 
    651     if ((srcFmt = lx_get_format(pSrc)) == NULL)
    652         GEODE_FALLBACK(("Unsupported source format %x\n", pSrc->format));
    653 
    654     if ((dstFmt = lx_get_format(pDst)) == NULL)
    655         GEODE_FALLBACK(("Unsupported destination format %x\n", pDst->format));
    656 
    657     /* Make sure operations that need alpha bits have them */
    658     /* If a mask is enabled, the alpha will come from there */
    659 
    660     if (!pMsk && (!srcFmt->alphabits && usesSrcAlpha(op)))
    661         GEODE_FALLBACK(("Operation requires src alpha, but alphabits is unset\n"));
    662 
    663     if (!pMsk && (!dstFmt->alphabits && usesDstAlpha(op)))
    664         GEODE_FALLBACK(("Operation requires dst alpha, but alphabits is unset\n"));
    665 
    666     /* FIXME: See a way around this! */
    667     if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0)
    668         GEODE_FALLBACK(("src_alphabits=0, dst_alphabits!=0\n"));
    669 
    670     /* If this is a rotate operation, then make sure the src and dst
    671      * formats are the same */
    672     if (exaScratch.rotate != RR_Rotate_0 && srcFmt != dstFmt) {
    673         ErrorF("EXA: Unable to rotate and convert formats at the same time\n");
    674         return FALSE;
    675     }
    676     return TRUE;
    677 }
    678 
    679 static Bool
    680 lx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk,
    681                      PicturePtr pDst, PixmapPtr pxSrc, PixmapPtr pxMsk,
    682                      PixmapPtr pxDst)
    683 {
    684     GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
    685     const struct exa_format_t *srcFmt, *dstFmt;
    686 
    687     /* Get the formats for the source and destination */
    688 
    689     srcFmt = lx_get_format(pSrc);
    690     dstFmt = lx_get_format(pDst);
    691 
    692     /* Set up the scratch buffer with the information we need */
    693 
    694     exaScratch.srcFormat = (struct exa_format_t *) srcFmt;
    695     exaScratch.dstFormat = (struct exa_format_t *) dstFmt;
    696     exaScratch.op = op;
    697     exaScratch.repeat = pSrc->repeat;
    698     exaScratch.bufferOffset = pGeode->exaBfrOffset;
    699 
    700     if (pMsk && op != PictOpClear) {
    701         /* Get the source color */
    702         if (pSrc->pSourcePict) {
    703             exaScratch.srcColor = pSrc->pSourcePict->solidFill.color;
    704         }
    705         else {
    706             /* If the op is PictOpOver(or PictOpOutReverse, PictOpInReverse,
    707              * PictOpIn, PictOpOut, PictOpOverReverse), we should get the
    708              * ARGB32 source format */
    709 
    710             if ((op == PictOpOver || op == PictOpOutReverse || op ==
    711                  PictOpInReverse || op == PictOpIn || op == PictOpOut ||
    712                  op == PictOpOverReverse) && (srcFmt->alphabits != 0))
    713                 exaScratch.srcColor = exaGetPixmapFirstPixel(pxSrc);
    714             else if ((op == PictOpOver || op == PictOpOutReverse || op ==
    715                       PictOpInReverse || op == PictOpIn || op == PictOpOut ||
    716                       op == PictOpOverReverse) && (srcFmt->alphabits == 0))
    717                 exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
    718                                                           PICT_a8r8g8b8);
    719             else
    720                 exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
    721                                                           pDst->format);
    722         }
    723 
    724         /* Save off the info we need (reuse the source values to save space) */
    725         exaScratch.type = COMP_TYPE_MASK;
    726         exaScratch.maskrepeat = pMsk->repeat;
    727 
    728         exaScratch.srcOffset = exaGetPixmapOffset(pxMsk);
    729         exaScratch.srcPitch = exaGetPixmapPitch(pxMsk);
    730         exaScratch.srcBpp = (pxMsk->drawable.bitsPerPixel + 7) / 8;
    731 
    732         exaScratch.srcWidth = pMsk->pDrawable->width;
    733         exaScratch.srcHeight = pMsk->pDrawable->height;
    734 
    735         /* Flag to indicate if this a 8BPP or a 4BPP mask */
    736         exaScratch.fourBpp = (pxMsk->drawable.bitsPerPixel == 4) ? 1 : 0;
    737     }
    738     else {
    739         if (usesPasses(op))
    740             exaScratch.type = COMP_TYPE_TWOPASS;
    741         else if (exaScratch.rotate != RR_Rotate_0)
    742             exaScratch.type = COMP_TYPE_ROTATE;
    743         else
    744             exaScratch.type = COMP_TYPE_ONEPASS;
    745 
    746         exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
    747         exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
    748         exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
    749 
    750         exaScratch.srcWidth = pSrc->pDrawable->width;
    751         exaScratch.srcHeight = pSrc->pDrawable->height;
    752     }
    753 
    754     return TRUE;
    755 }
    756 
    757 static int
    758 lx_get_bpp_from_format(int format)
    759 {
    760 
    761     switch (format) {
    762     case CIMGP_SOURCE_FMT_8_8_8_8:
    763     case CIMGP_SOURCE_FMT_32BPP_BGR:
    764         return 32;
    765 
    766     case CIMGP_SOURCE_FMT_4_4_4_4:
    767         return 12;
    768 
    769     case CIMGP_SOURCE_FMT_0_5_6_5:
    770     case CIMGP_SOURCE_FMT_16BPP_BGR:
    771         return 16;
    772 
    773     case CIMGP_SOURCE_FMT_1_5_5_5:
    774     case CIMGP_SOURCE_FMT_15BPP_BGR:
    775         return 15;
    776 
    777     case CIMGP_SOURCE_FMT_3_3_2:
    778         return 8;
    779     }
    780 
    781     return 0;
    782 }
    783 
    784 /* BGR needs to be set in the source for it to take - so adjust the source
    785  * to enable BGR if the two formats are different, and disable it if they
    786  * are the same
    787  */
    788 
    789 static void
    790 lx_set_source_format(int srcFormat, int dstFormat)
    791 {
    792     if (!(srcFormat & 0x10) && (dstFormat & 0x10))
    793         gp_set_source_format(srcFormat | 0x10);
    794     else if ((srcFormat & 0x10) && (dstFormat & 0x10))
    795         gp_set_source_format(srcFormat & ~0x10);
    796     else
    797         gp_set_source_format(srcFormat);
    798 }
    799 
    800 /* If we are converting colors and we need the channel A alpha,
    801  * then use a special alpha type that preserves the alpha before
    802  * converting the format
    803  */
    804 
    805 static inline int
    806 get_op_type(struct exa_format_t *src, struct exa_format_t *dst, int type)
    807 {
    808     return (type == CIMGP_CHANNEL_A_ALPHA &&
    809             src->alphabits != dst->alphabits) ? CIMGP_CONVERTED_ALPHA : type;
    810 }
    811 
    812 /* Note - this is the preferred onepass method.  The other will remain
    813  * ifdefed out until such time that we are sure its not needed
    814  */
    815 
    816 #define GetPixmapOffset(px, x, y) ( exaGetPixmapOffset((px)) + \
    817   (exaGetPixmapPitch((px)) * (y)) + \
    818   ((((px)->drawable.bitsPerPixel + 7) / 8) * (x)) )
    819 
    820 #define GetSrcOffset(_x, _y) (exaScratch.srcOffset + ((_y) * exaScratch.srcPitch) + \
    821 			      ((_x) * exaScratch.srcBpp))
    822 
    823 static void
    824 lx_composite_onepass_add_a8(PixmapPtr pxDst, unsigned long dstOffset,
    825                             unsigned long srcOffset, int width, int height,
    826                             int opX, int opY, int srcX, int srcY)
    827 {
    828     struct blend_ops_t *opPtr;
    829     int apply, type;
    830     int optempX, optempY;
    831     int i, j;
    832     unsigned long pixmapOffset, pixmapPitch, calBitsPixel;
    833 
    834     pixmapOffset = exaGetPixmapOffset(pxDst);
    835     pixmapPitch = exaGetPixmapPitch(pxDst);
    836     calBitsPixel = (pxDst->drawable.bitsPerPixel + 7) / 8;
    837 
    838     /* Keep this GP idle judge here. Otherwise the SW method has chance to
    839      * conflict with the HW rendering method */
    840     gp_wait_until_idle();
    841 
    842     if (opX % 4 == 0 && srcX % 4 == 0) {
    843         /* HW acceleration */
    844         opPtr = &lx_alpha_ops[exaScratch.op * 2];
    845         apply = CIMGP_APPLY_BLEND_TO_ALL;
    846         gp_declare_blt(0);
    847         gp_set_bpp(32);
    848         gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
    849         gp_set_source_format(8);
    850         type = opPtr->type;
    851         gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply,
    852                                0);
    853         gp_screen_to_screen_convert(dstOffset, srcOffset, width / 4, height, 0);
    854         /* Calculate the pixels in the tail of each line */
    855         for (j = srcY; j < srcY + height; j++)
    856             for (i = srcX + (width / 4) * 4; i < srcX + width; i++) {
    857                 srcOffset = GetSrcOffset(i, j);
    858                 optempX = opX + i - srcX;
    859                 optempY = opY + j - srcY;
    860                 dstOffset = pixmapOffset + pixmapPitch * optempY +
    861                     calBitsPixel * optempX;
    862                 *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset)
    863                                              + *(cim_fb_ptr + dstOffset) <=
    864                                              0xff) ? *(cim_fb_ptr + srcOffset) +
    865                     *(cim_fb_ptr + dstOffset) : 0xff;
    866             }
    867     }
    868     else {
    869         for (j = srcY; j < srcY + height; j++)
    870             for (i = srcX; i < srcX + width; i++) {
    871                 srcOffset = GetSrcOffset(i, j);
    872                 optempX = opX + i - srcX;
    873                 optempY = opY + j - srcY;
    874                 dstOffset = pixmapOffset + pixmapPitch * optempY +
    875                     calBitsPixel * optempX;
    876                 *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset) +
    877                                              *(cim_fb_ptr + dstOffset) <=
    878                                              0xff) ? *(cim_fb_ptr + srcOffset) +
    879                     *(cim_fb_ptr + dstOffset) : 0xff;
    880             }
    881     }
    882 }
    883 
    884 static void
    885 lx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset,
    886                      unsigned long srcOffset, int width, int height)
    887 {
    888     struct blend_ops_t *opPtr;
    889     int apply, type;
    890 
    891     opPtr = &lx_alpha_ops[exaScratch.op * 2];
    892 
    893     apply = (exaScratch.dstFormat->alphabits != 0 &&
    894              exaScratch.srcFormat->alphabits != 0) ?
    895         CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
    896 
    897     gp_declare_blt(0);
    898     gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
    899     gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
    900 
    901     lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
    902 
    903     type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
    904 
    905     gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
    906 
    907     gp_screen_to_screen_convert(dstOffset, srcOffset, width, height, 0);
    908 }
    909 
    910 static void
    911 lx_composite_all_black(unsigned long srcOffset, int width, int height)
    912 {
    913     struct blend_ops_t *opPtr;
    914     int apply, type;
    915 
    916     opPtr = &lx_alpha_ops[0];
    917     apply = (exaScratch.srcFormat->alphabits != 0) ?
    918         CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
    919     gp_declare_blt(0);
    920     gp_set_bpp(lx_get_bpp_from_format(exaScratch.srcFormat->fmt));
    921     gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
    922     lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.srcFormat->fmt);
    923     type = get_op_type(exaScratch.srcFormat, exaScratch.srcFormat, opPtr->type);
    924     gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
    925     gp_screen_to_screen_convert(srcOffset, srcOffset, width, height, 0);
    926 
    927 }
    928 
    929 static void
    930 lx_composite_onepass_special(PixmapPtr pxDst, int width, int height, int opX,
    931                              int opY, int srcX, int srcY)
    932 {
    933     struct blend_ops_t *opPtr;
    934     int apply, type;
    935     int opWidth, opHeight;
    936     int optempX, optempY;
    937     unsigned int dstOffset, srcOffset = 0;
    938 
    939     optempX = opX;
    940     optempY = opY;
    941 
    942     /* Make sure srcX and srcY are in source region */
    943     srcX = ((srcX % (int) exaScratch.srcWidth) + (int) exaScratch.srcWidth)
    944         % (int) exaScratch.srcWidth;
    945     srcY = ((srcY % (int) exaScratch.srcHeight) + (int) exaScratch.srcHeight)
    946         % (int) exaScratch.srcHeight;
    947 
    948     opWidth = exaScratch.srcWidth - srcX;
    949     opHeight = exaScratch.srcHeight - srcY;
    950 
    951     srcOffset = GetSrcOffset(srcX, srcY);
    952 
    953     if (width < opWidth)
    954         opWidth = width;
    955     if (height < opHeight)
    956         opHeight = height;
    957 
    958     while (1) {
    959         gp_wait_until_idle();
    960         dstOffset = GetPixmapOffset(pxDst, optempX, optempY);
    961         opPtr = &lx_alpha_ops[exaScratch.op * 2];
    962         apply = (exaScratch.dstFormat->alphabits != 0 &&
    963                  exaScratch.srcFormat->alphabits != 0) ?
    964             CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
    965         gp_declare_blt(0);
    966         gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
    967         gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
    968         lx_set_source_format(exaScratch.srcFormat->fmt,
    969                              exaScratch.dstFormat->fmt);
    970         type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat,
    971                            opPtr->type);
    972         gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
    973                                apply, 0);
    974         gp_screen_to_screen_convert(dstOffset, srcOffset, opWidth, opHeight, 0);
    975 
    976         optempX += opWidth;
    977         if (optempX >= opX + width) {
    978             optempX = opX;
    979             optempY += opHeight;
    980             if (optempY >= opY + height)
    981                 break;
    982         }
    983         if (optempX == opX) {
    984             srcOffset = GetSrcOffset(srcX, 0);
    985             opWidth = ((opX + width) - optempX) > (exaScratch.srcWidth - srcX)
    986                 ? (exaScratch.srcWidth - srcX) : ((opX + width) - optempX);
    987             opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
    988                 ? exaScratch.srcHeight : ((opY + height) - optempY);
    989         }
    990         else if (optempY == opY) {
    991             srcOffset = GetSrcOffset(0, srcY);
    992             opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
    993                 ? exaScratch.srcWidth : ((opX + width) - optempX);
    994             opHeight = ((opY + height) - optempY) > (exaScratch.srcHeight -
    995                                                      srcY)
    996                 ? (exaScratch.srcHeight - srcY) : ((opY + height)
    997                                                    - optempY);
    998         }
    999         else {
   1000             srcOffset = GetSrcOffset(0, 0);
   1001             opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
   1002                 ? exaScratch.srcWidth : ((opX + width) - optempX);
   1003             opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
   1004                 ? exaScratch.srcHeight : ((opY + height) - optempY);
   1005         }
   1006     }
   1007 }
   1008 
   1009 /* This function handles the multipass blend functions */
   1010 
   1011 static void
   1012 lx_composite_multipass(PixmapPtr pxDst, unsigned long dstOffset,
   1013                        unsigned long srcOffset, int width, int height)
   1014 {
   1015     struct blend_ops_t *opPtr;
   1016     int sbpp = lx_get_bpp_from_format(exaScratch.srcFormat->fmt);
   1017     int apply, type;
   1018 
   1019     /* Wait until the GP is idle - this will ensure that the scratch buffer
   1020      * isn't occupied */
   1021 
   1022     gp_wait_until_idle();
   1023 
   1024     /* Copy the destination to the scratch buffer, and convert it to the
   1025      * source format */
   1026 
   1027     gp_declare_blt(0);
   1028 
   1029     gp_set_bpp(sbpp);
   1030     gp_set_source_format(exaScratch.dstFormat->fmt);
   1031     gp_set_raster_operation(0xCC);
   1032     gp_set_strides(exaScratch.srcPitch, exaGetPixmapPitch(pxDst));
   1033     gp_screen_to_screen_convert(exaScratch.bufferOffset, dstOffset,
   1034                                 width, height, 0);
   1035 
   1036     /* Do the first blend from the source to the scratch buffer */
   1037 
   1038     gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
   1039     gp_set_bpp(sbpp);
   1040     gp_set_source_format(exaScratch.srcFormat->fmt);
   1041     gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
   1042 
   1043     opPtr = &lx_alpha_ops[exaScratch.op * 2];
   1044 
   1045     apply = (exaScratch.srcFormat->alphabits == 0) ?
   1046         CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
   1047 
   1048     /* If we're destroying the source alpha bits, then make sure we
   1049      * use the alpha before the color conversion
   1050      */
   1051 
   1052     gp_screen_to_screen_blt(exaScratch.bufferOffset, srcOffset, width, height,
   1053                             0);
   1054 
   1055     /* Finally, do the second blend back to the destination */
   1056 
   1057     opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
   1058 
   1059     apply = (exaScratch.dstFormat->alphabits == 0) ?
   1060         CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
   1061 
   1062     gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
   1063     gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
   1064 
   1065     lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
   1066 
   1067     type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
   1068 
   1069     gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
   1070 
   1071     gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
   1072                                 width, height, 0);
   1073 }
   1074 
   1075 static void
   1076 lx_composite_rotate(PixmapPtr pxDst, unsigned long dstOffset,
   1077                     unsigned int srcOffset, int width, int height)
   1078 {
   1079     int degrees = 0;
   1080 
   1081     gp_declare_blt(0);
   1082     gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
   1083     gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
   1084 
   1085     lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
   1086 
   1087     gp_set_raster_operation(0xCC);
   1088 
   1089     /* RandR rotation is counter-clockwise, our rotation
   1090      * is clockwise, so adjust the numbers accordingly */
   1091 
   1092     switch (exaScratch.rotate) {
   1093     case RR_Rotate_90:
   1094         degrees = 270;
   1095         break;
   1096     case RR_Rotate_180:
   1097         degrees = 180;
   1098         break;
   1099     case RR_Rotate_270:
   1100         degrees = 90;
   1101         break;
   1102     }
   1103 
   1104     gp_rotate_blt(dstOffset, srcOffset, width, height, degrees);
   1105 }
   1106 
   1107 static void
   1108 lx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset,
   1109                      unsigned int maskOffset, int width, int height)
   1110 {
   1111     struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2];
   1112 
   1113     gp_declare_blt(0);
   1114 
   1115     gp_set_source_format(exaScratch.srcFormat->fmt);
   1116     gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
   1117     gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
   1118     gp_set_solid_source(exaScratch.srcColor);
   1119 
   1120     gp_blend_mask_blt(dstOffset, 0, width, height, maskOffset,
   1121                       exaScratch.srcPitch, opPtr->operation,
   1122                       exaScratch.fourBpp);
   1123 }
   1124 
   1125 static void
   1126 lx_do_composite_mask_two_pass(PixmapPtr pxDst, unsigned long dstOffset,
   1127                               unsigned int maskOffset, int width, int height,
   1128                               int opX, int opY, xPointFixed srcPoint)
   1129 {
   1130     int apply, type;
   1131     struct blend_ops_t *opPtr;
   1132     int opWidth, opHeight;
   1133     int opoverX, opoverY;
   1134 
   1135     opoverX = opX;
   1136     opoverY = opY;
   1137 
   1138     /* The rendering region should not be bigger than off-screen memory size
   1139      * which equals to DEFAULT_EXA_SCRATCH_BFRSZ. If that happens, we split
   1140      * the PictOpOver rendering region into several 256KB chunks. And because
   1141      * of the Pitch(stride) parameter, so we use maximum width of mask picture.
   1142      * that is to say it is a scanline rendering process */
   1143     if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
   1144         opWidth = width;
   1145         opHeight = DEFAULT_EXA_SCRATCH_BFRSZ / (width * 4);
   1146     }
   1147     else {
   1148         opWidth = width;
   1149         opHeight = height;
   1150     }
   1151 
   1152     while (1) {
   1153 
   1154         /* Wait until the GP is idle - this will ensure that the scratch buffer
   1155          * isn't occupied */
   1156 
   1157         gp_wait_until_idle();
   1158 
   1159         /* Copy the source to the scratch buffer, and do a src * mask raster
   1160          * operation */
   1161 
   1162         gp_declare_blt(0);
   1163         opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
   1164         gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
   1165         gp_set_strides(opWidth * 4, exaScratch.srcPitch);
   1166         gp_set_bpp(lx_get_bpp_from_format(CIMGP_SOURCE_FMT_8_8_8_8));
   1167         gp_set_solid_source(exaScratch.srcColor);
   1168         gp_blend_mask_blt(exaScratch.bufferOffset, 0, opWidth, opHeight,
   1169                           maskOffset, exaScratch.srcPitch, opPtr->operation,
   1170                           exaScratch.fourBpp);
   1171 
   1172         /* Do a relative operation(refer rendercheck ops.c), and copy the
   1173          * operation result to destination */
   1174 
   1175         gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
   1176         opPtr = &lx_alpha_ops[exaScratch.op * 2];
   1177         apply = (exaScratch.dstFormat->alphabits == 0) ?
   1178             CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
   1179         gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
   1180         gp_set_strides(exaGetPixmapPitch(pxDst), opWidth * 4);
   1181         gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
   1182         type = CIMGP_CONVERTED_ALPHA;
   1183         gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
   1184                                apply, 0);
   1185         gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
   1186                                     opWidth, opHeight, 0);
   1187 
   1188         if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
   1189             /* Finish the rendering */
   1190             if (opoverY + opHeight == opY + height)
   1191                 break;
   1192             /* Recalculate the Dest and Mask rendering start point */
   1193             srcPoint.y = srcPoint.y + F(opHeight);
   1194             opoverY = opoverY + opHeight;
   1195             if (opoverY + opHeight > opY + height)
   1196                 opHeight = opY + height - opoverY;
   1197             dstOffset = GetPixmapOffset(pxDst, opoverX, opoverY);
   1198             maskOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
   1199         }
   1200         else
   1201             break;
   1202     }
   1203 }
   1204 
   1205 static void
   1206 transformPoint(PictTransform * t, xPointFixed * point)
   1207 {
   1208     PictVector v;
   1209 
   1210     v.vector[0] = point->x;
   1211     v.vector[1] = point->y;
   1212     v.vector[2] = xFixed1;
   1213 
   1214     if (t != NULL)
   1215         PictureTransformPoint(t, &v);
   1216 
   1217     point->x = v.vector[0];
   1218     point->y = v.vector[1];
   1219 }
   1220 
   1221 static void
   1222 lx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX,
   1223                 int maskY, int dstX, int dstY, int width, int height)
   1224 {
   1225     unsigned int dstOffset, srcOffset = 0;
   1226 
   1227     xPointFixed srcPoint;
   1228 
   1229     int opX = dstX;
   1230     int opY = dstY;
   1231     int opWidth = width;
   1232     int opHeight = height;
   1233 
   1234     /* Transform the source coordinates */
   1235 
   1236     if (exaScratch.type == COMP_TYPE_MASK) {
   1237         srcPoint.x = F(maskX);
   1238         srcPoint.y = F(maskY);
   1239     }
   1240     else {
   1241         srcPoint.x = F(srcX);
   1242         srcPoint.y = F(srcY);
   1243     }
   1244 
   1245     /* srcX, srcY point to the upper right side of the bounding box
   1246      * in the unrotated coordinate space.  Depending on the orientation,
   1247      * we have to translate the coordinates to point to the origin of
   1248      * the rectangle in the source pixmap */
   1249 
   1250     switch (exaScratch.rotate) {
   1251     case RR_Rotate_270:
   1252         srcPoint.x += F(width);
   1253 
   1254         opWidth = height;
   1255         opHeight = width;
   1256         break;
   1257 
   1258     case RR_Rotate_180:
   1259         srcPoint.x += F(width);
   1260         srcPoint.y += F(height);
   1261 
   1262         srcX += width;
   1263         srcY += height;
   1264         break;
   1265 
   1266     case RR_Rotate_90:
   1267         srcPoint.y += F(height);
   1268 
   1269         opWidth = height;
   1270         opHeight = width;
   1271         break;
   1272     }
   1273 
   1274     transformPoint(exaScratch.transform, &srcPoint);
   1275 
   1276     /* Adjust the point to fit into the pixmap */
   1277 
   1278     if (I(srcPoint.x) < 0) {
   1279         opWidth += I(srcPoint.x);
   1280         srcPoint.x = F(0);
   1281     }
   1282 
   1283     if (I(srcPoint.y) < 0) {
   1284         opHeight += I(srcPoint.y);
   1285         srcPoint.y = F(0);
   1286     }
   1287 
   1288     /* Get the source point offset position */
   1289 
   1290     srcOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
   1291 
   1292     /* When mask exists, exaScratch.srcWidth and exaScratch.srcHeight are
   1293      * the source width and source height; Otherwise, they are mask width
   1294      * and mask height */
   1295     /* exaScratch.repeat is the source repeat attribute
   1296      * exaScratch.maskrepeat is the mask repeat attribute */
   1297     /* If type is COMP_TYPE_MASK, maskX and maskY are not zero, we should
   1298      * subtract them to do the operation in the correct region */
   1299 
   1300     /* FIXME:  Please add the code to handle the condition when the maskX
   1301      * and maskY coordinate are negative or greater than
   1302      * exaScratch.srcWidth and exaScratch.srcHeight */
   1303 
   1304     if (exaScratch.type == COMP_TYPE_MASK) {
   1305         if ((exaScratch.srcWidth - maskX) < opWidth)
   1306             opWidth = exaScratch.srcWidth - maskX;
   1307         if ((exaScratch.srcHeight - maskY) < opHeight)
   1308             opHeight = exaScratch.srcHeight - maskY;
   1309     }
   1310     else {
   1311         if (exaScratch.type == COMP_TYPE_ONEPASS) {
   1312             /* This is the condition srcX or/and srcY is/are out of source
   1313              * region */
   1314             if (((srcY >= 0 && srcY >= exaScratch.srcHeight)
   1315                  || (srcX >= 0 && srcX >= exaScratch.srcWidth)) &&
   1316                 (exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)) {
   1317                 if (exaScratch.repeat == 1) {
   1318                     opWidth = width;
   1319                     opHeight = height;
   1320                 }
   1321                 else {
   1322                     if (exaScratch.op == PictOpOver)
   1323                         return;
   1324                     else {
   1325                         exaScratch.op = PictOpClear;
   1326                         opWidth = width;
   1327                         opHeight = height;
   1328                     }
   1329                 }
   1330                 /* This is the condition srcX or/and srcY is/are in the source
   1331                  * region */
   1332             }
   1333             else if (srcX >= 0 && srcY >= 0 &&
   1334                      (exaScratch.op == PictOpOver ||
   1335                       exaScratch.op == PictOpSrc)) {
   1336                 if (exaScratch.repeat == 1) {
   1337                     opWidth = width;
   1338                     opHeight = height;
   1339                 }
   1340                 else {
   1341                     if ((exaScratch.srcWidth - srcX) < opWidth)
   1342                         opWidth = exaScratch.srcWidth - srcX;
   1343                     if ((exaScratch.srcHeight - srcY) < opHeight)
   1344                         opHeight = exaScratch.srcHeight - srcY;
   1345                 }
   1346                 /* This is the condition srcX or/and srcY is/are negative */
   1347             }
   1348             else if ((srcX < 0 || srcY < 0) &&
   1349                      (exaScratch.op == PictOpOver ||
   1350                       exaScratch.op == PictOpSrc)) {
   1351                 if (exaScratch.repeat == 1) {
   1352                     opWidth = width;
   1353                     opHeight = height;
   1354                 }
   1355                 else {
   1356                     /* FIXME: We can't support negative srcX/Y for all corner cases in
   1357                      * a sane way without a bit bigger refactoring. So as to avoid
   1358                      * gross misrenderings (e.g missing tray icons) in current real-world
   1359                      * applications, just shift destination appropriately for now and
   1360                      * ignore out of bounds source pixmap zero-vector handling. This is
   1361                      * actually correct for PictOpOver, but PictOpSrc out of bounds regions
   1362                      * should be blacked out, but aren't - without this workaround however
   1363                      * it'd be simply all black instead, which is probably worse till a full
   1364                      * clean solution solves it for all cases. */
   1365                     if (srcX < 0) {
   1366                         opX -= srcX;
   1367                         srcX = 0;
   1368                     }
   1369 
   1370                     if (srcY < 0) {
   1371                         opY -= srcY;
   1372                         srcY = 0;
   1373                     }
   1374 
   1375                     /* EXA has taken care of adjusting srcWidth if it gets cut on the right */
   1376                     width = opWidth = exaScratch.srcWidth;
   1377                     /* EXA has taken care of adjusting srcHeight if it gets cut on the bottom */
   1378                     height = opHeight = exaScratch.srcHeight;
   1379                 }
   1380             }
   1381             else {
   1382                 if (exaScratch.srcWidth < opWidth)
   1383                     opWidth = exaScratch.srcWidth;
   1384                 if (exaScratch.srcHeight < opHeight)
   1385                     opHeight = exaScratch.srcHeight;
   1386             }
   1387         }
   1388         else {
   1389             if (exaScratch.rotate == RR_Rotate_180) {
   1390             }
   1391             else {
   1392                 if ((exaScratch.srcWidth - srcY) < opWidth)
   1393                     opWidth = exaScratch.srcWidth - srcY;
   1394                 if ((exaScratch.srcHeight - srcX) < opHeight)
   1395                     opHeight = exaScratch.srcHeight - srcX;
   1396             }
   1397         }
   1398     }
   1399 
   1400     while (1) {
   1401 
   1402         dstOffset = GetPixmapOffset(pxDst, opX, opY);
   1403 
   1404         switch (exaScratch.type) {
   1405 
   1406         case COMP_TYPE_MASK:{
   1407             if (exaScratch.op == PictOpOver || exaScratch.op ==
   1408                 PictOpOutReverse || exaScratch.op == PictOpInReverse ||
   1409                 exaScratch.op == PictOpIn || exaScratch.op == PictOpOut ||
   1410                 exaScratch.op == PictOpOverReverse)
   1411                 lx_do_composite_mask_two_pass(pxDst, dstOffset,
   1412                                               srcOffset, opWidth, opHeight, opX,
   1413                                               opY, srcPoint);
   1414             else
   1415                 lx_do_composite_mask(pxDst, dstOffset, srcOffset,
   1416                                      opWidth, opHeight);
   1417         }
   1418             break;
   1419 
   1420         case COMP_TYPE_ONEPASS:
   1421             if ((exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)
   1422                 && (exaScratch.repeat == 1)) {
   1423                 lx_composite_onepass_special(pxDst, opWidth, opHeight, opX, opY,
   1424                                              srcX, srcY);
   1425                 return;
   1426             }
   1427             else if ((exaScratch.op == PictOpAdd) && (exaScratch.srcFormat->exa
   1428                                                       == PICT_a8) &&
   1429                      (exaScratch.dstFormat->exa == PICT_a8))
   1430                 lx_composite_onepass_add_a8(pxDst, dstOffset, srcOffset,
   1431                                             opWidth, opHeight, opX, opY, srcX,
   1432                                             srcY);
   1433             else
   1434                 lx_composite_onepass(pxDst, dstOffset, srcOffset, opWidth,
   1435                                      opHeight);
   1436             break;
   1437 
   1438         case COMP_TYPE_TWOPASS:
   1439             lx_composite_multipass(pxDst, dstOffset, srcOffset, opWidth,
   1440                                    opHeight);
   1441 
   1442         case COMP_TYPE_ROTATE:
   1443             lx_composite_rotate(pxDst, dstOffset, srcOffset, opWidth, opHeight);
   1444             break;
   1445         }
   1446 
   1447         opX += opWidth;
   1448 
   1449         if (opX >= dstX + width) {
   1450             opX = dstX;
   1451             opY += opHeight;
   1452 
   1453             if (opY >= dstY + height)
   1454                 break;
   1455         }
   1456 
   1457         /* FIXME:  Please add the code to handle the condition when the maskX
   1458          * and maskY coordinate are negative or greater than
   1459          * exaScratch.srcWidth and exaScratch.srcHeight */
   1460 
   1461         if (exaScratch.type == COMP_TYPE_MASK) {
   1462             opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - maskX)
   1463                 ? (exaScratch.srcWidth - maskX) : (dstX + width) - opX;
   1464             opHeight = ((dstY + height) - opY) > (exaScratch.srcHeight - maskY)
   1465                 ? (exaScratch.srcHeight - maskY) : (dstY + height) - opY;
   1466             /* All black out of the mask */
   1467             if (!exaScratch.maskrepeat)
   1468                 exaScratch.srcColor = 0x0;
   1469         }
   1470         else {
   1471             if (exaScratch.type == COMP_TYPE_ONEPASS) {
   1472                 if (srcX >= 0 && srcY >= 0 && (exaScratch.op == PictOpOver ||
   1473                                                exaScratch.op == PictOpSrc ||
   1474                                                exaScratch.op == PictOpClear)) {
   1475                     opWidth =
   1476                         ((dstX + width) - opX) >
   1477                         (exaScratch.srcWidth - srcX) ? (exaScratch.srcWidth -
   1478                                                         srcX) : (dstX + width)
   1479                         - opX;
   1480                     opHeight = ((dstY + height) - opY) >
   1481                         (exaScratch.srcHeight - srcY) ?
   1482                         (exaScratch.srcHeight - srcY) : (dstY + height) - opY;
   1483                 }
   1484                 else {
   1485                     opWidth = ((dstX + width) - opX) > exaScratch.srcWidth ?
   1486                         exaScratch.srcWidth : (dstX + width) - opX;
   1487                     opHeight = ((dstY + height) - opY) > exaScratch.srcHeight ?
   1488                         exaScratch.srcHeight : (dstY + height) - opY;
   1489                 }
   1490             }
   1491             else {
   1492                 opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - srcY)
   1493                     ? (exaScratch.srcWidth - srcY) : (dstX + width) - opX;
   1494                 opHeight =
   1495                     ((dstY + height) - opY) >
   1496                     (exaScratch.srcHeight - srcX) ? (exaScratch.srcHeight -
   1497                                                      srcX) : (dstY + height) -
   1498                     opY;
   1499             }
   1500             /* All black out of the source */
   1501             if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ONEPASS)) {
   1502                 /* FIXME: We black out the source here, so that any further regions
   1503                  * in the loop get handled as a source that's a zero-vector (as
   1504                  * defined for out-of-bounds from source pixmap for RepeatModeNone),
   1505                  * but this will likely interfere with cases where srcX and/or srcY
   1506                  * is negative - as opposed to e.g width being larger than srcWidth,
   1507                  * which is exercised in rendercheck (always rectangle in top-left
   1508                  * corner).
   1509                  * Additionally it forces the drawing into tiles of srcWidth/srcHeight
   1510                  * for non-repeat modes too, where we don't really need to tile it like
   1511                  * this and could draw the out of bound regions all at once (or at most
   1512                  * in 4 operations without the big loop). */
   1513                 lx_composite_all_black(srcOffset, exaScratch.srcWidth,
   1514                                        exaScratch.srcHeight);
   1515             }
   1516             if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ROTATE))
   1517                 break;
   1518         }
   1519     }
   1520 }
   1521 
   1522 static void
   1523 lx_wait_marker(ScreenPtr PScreen, int marker)
   1524 {
   1525     gp_wait_until_idle();
   1526 }
   1527 
   1528 static void
   1529 lx_done(PixmapPtr ptr)
   1530 {
   1531 }
   1532 
   1533 #if 0
   1534 static void
   1535 lx_upload_to_screen(PixmapPtr pxDst, int x, int y, int w, int h,
   1536                     char *src, int src_pitch)
   1537 {
   1538     GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
   1539     int dst_pitch = exaGetPixmapPitch(pxDst);
   1540     int cpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
   1541 
   1542     char *dst;
   1543     int offset = exaGetPixmapOffset(pxDst);
   1544 
   1545     dst = (char *) (pGeode->FBBase + offset + (y * dst_pitch) + (x * cpp));
   1546     int i;
   1547 
   1548     for (i = 0; i < h; i++) {
   1549         memcpy(dst, src, w * cpp);
   1550         dst += dst_pitch;
   1551         src += src_pitch;
   1552     }
   1553 }
   1554 #endif
   1555 
   1556 #if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2)
   1557 
   1558 static Bool
   1559 lx_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
   1560 {
   1561     ScrnInfoPtr pScrni = xf86ScreenToScrn(pPixmap->drawable.pScreen);
   1562     GeodeRec *pGeode = GEODEPTR(pScrni);
   1563     void *start = (void *) (pGeode->FBBase);
   1564     void *end =
   1565         (void *) (pGeode->FBBase + pGeode->offscreenStart +
   1566                   pGeode->offscreenSize);
   1567 
   1568     if ((void *) pPixmap->devPrivate.ptr >= start &&
   1569         (void *) pPixmap->devPrivate.ptr < end)
   1570         return TRUE;
   1571 
   1572     return FALSE;
   1573 }
   1574 
   1575 #endif
   1576 
   1577 Bool
   1578 LXExaInit(ScreenPtr pScreen)
   1579 {
   1580     ScrnInfoPtr pScrni = xf86ScreenToScrn(pScreen);
   1581     GeodeRec *pGeode = GEODEPTR(pScrni);
   1582     ExaDriverPtr pExa = pGeode->pExa;
   1583 
   1584     pExa->exa_major = EXA_VERSION_MAJOR;
   1585     pExa->exa_minor = EXA_VERSION_MINOR;
   1586 
   1587     pExa->WaitMarker = lx_wait_marker;
   1588 
   1589     pExa->PrepareSolid = lx_prepare_solid;
   1590     pExa->Solid = lx_do_solid;
   1591     pExa->DoneSolid = lx_done;
   1592 
   1593     pExa->PrepareCopy = lx_prepare_copy;
   1594     pExa->Copy = lx_do_copy;
   1595     pExa->DoneCopy = lx_done;
   1596 
   1597     /* Composite */
   1598     pExa->CheckComposite = lx_check_composite;
   1599     pExa->PrepareComposite = lx_prepare_composite;
   1600     pExa->Composite = lx_do_composite;
   1601     pExa->DoneComposite = lx_done;
   1602     //pExa->UploadToScreen =  lx_upload_to_screen;
   1603 
   1604 #if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2)
   1605     pExa->PixmapIsOffscreen = lx_exa_pixmap_is_offscreen;
   1606 #endif
   1607 
   1608     //pExa->flags = EXA_OFFSCREEN_PIXMAPS;
   1609 
   1610     return exaDriverInit(pScreen, pGeode->pExa);
   1611 }
   1612