Home | History | Annotate | Line # | Download | only in glamor
      1 #include <stdlib.h>
      2 #include <stdint.h> /* For INT16_MAX */
      3 
      4 #include "glamor_priv.h"
      5 
      6 static void
      7 glamor_get_transform_extent_from_box(struct pixman_box32 *box,
      8                                      struct pixman_transform *transform);
      9 
     10 static inline glamor_pixmap_private *
     11 __glamor_large(glamor_pixmap_private *pixmap_priv) {
     12     assert(glamor_pixmap_priv_is_large(pixmap_priv));
     13     return pixmap_priv;
     14 }
     15 
     16 /**
     17  * Clip the boxes regards to each pixmap's block array.
     18  *
     19  * Should translate the region to relative coords to the pixmap,
     20  * start at (0,0).
     21  */
     22 #if 0
     23 //#define DEBUGF(str, ...)  do {} while(0)
     24 #define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
     25 //#define DEBUGRegionPrint(x) do {} while (0)
     26 #define DEBUGRegionPrint RegionPrint
     27 #endif
     28 
     29 static glamor_pixmap_clipped_regions *
     30 __glamor_compute_clipped_regions(int block_w,
     31                                  int block_h,
     32                                  int block_stride,
     33                                  int x, int y,
     34                                  int w, int h,
     35                                  RegionPtr region,
     36                                  int *n_region, int reverse, int upsidedown)
     37 {
     38     glamor_pixmap_clipped_regions *clipped_regions;
     39     BoxPtr extent;
     40     int start_x, start_y, end_x, end_y;
     41     int start_block_x, start_block_y;
     42     int end_block_x, end_block_y;
     43     int loop_start_block_x, loop_start_block_y;
     44     int loop_end_block_x, loop_end_block_y;
     45     int loop_block_stride;
     46     int i, j, delta_i, delta_j;
     47     RegionRec temp_region;
     48     RegionPtr current_region;
     49     int block_idx;
     50     int k = 0;
     51     int temp_block_idx;
     52 
     53     extent = RegionExtents(region);
     54     start_x = MAX(x, extent->x1);
     55     start_y = MAX(y, extent->y1);
     56     end_x = MIN(x + w, extent->x2);
     57     end_y = MIN(y + h, extent->y2);
     58 
     59     DEBUGF("start compute clipped regions:\n");
     60     DEBUGF("block w %d h %d  x %d y %d w %d h %d, block_stride %d \n",
     61            block_w, block_h, x, y, w, h, block_stride);
     62     DEBUGRegionPrint(region);
     63 
     64     DEBUGF("start_x %d start_y %d end_x %d end_y %d \n", start_x, start_y,
     65            end_x, end_y);
     66 
     67     if (start_x >= end_x || start_y >= end_y) {
     68         *n_region = 0;
     69         return NULL;
     70     }
     71 
     72     start_block_x = (start_x - x) / block_w;
     73     start_block_y = (start_y - y) / block_h;
     74     end_block_x = (end_x - x) / block_w;
     75     end_block_y = (end_y - y) / block_h;
     76 
     77     clipped_regions = calloc((end_block_x - start_block_x + 1)
     78                              * (end_block_y - start_block_y + 1),
     79                              sizeof(*clipped_regions));
     80     if (clipped_regions == NULL) {
     81         *n_region = 0;
     82         return NULL;
     83     }
     84 
     85     DEBUGF("startx %d starty %d endx %d endy %d \n",
     86            start_x, start_y, end_x, end_y);
     87     DEBUGF("start_block_x %d end_block_x %d \n", start_block_x, end_block_x);
     88     DEBUGF("start_block_y %d end_block_y %d \n", start_block_y, end_block_y);
     89 
     90     if (!reverse) {
     91         loop_start_block_x = start_block_x;
     92         loop_end_block_x = end_block_x + 1;
     93         delta_i = 1;
     94     }
     95     else {
     96         loop_start_block_x = end_block_x;
     97         loop_end_block_x = start_block_x - 1;
     98         delta_i = -1;
     99     }
    100 
    101     if (!upsidedown) {
    102         loop_start_block_y = start_block_y;
    103         loop_end_block_y = end_block_y + 1;
    104         delta_j = 1;
    105     }
    106     else {
    107         loop_start_block_y = end_block_y;
    108         loop_end_block_y = start_block_y - 1;
    109         delta_j = -1;
    110     }
    111 
    112     loop_block_stride = delta_j * block_stride;
    113     block_idx = (loop_start_block_y - delta_j) * block_stride;
    114 
    115     for (j = loop_start_block_y; j != loop_end_block_y; j += delta_j) {
    116         block_idx += loop_block_stride;
    117         temp_block_idx = block_idx + loop_start_block_x;
    118         for (i = loop_start_block_x;
    119              i != loop_end_block_x; i += delta_i, temp_block_idx += delta_i) {
    120             BoxRec temp_box;
    121 
    122             temp_box.x1 = x + i * block_w;
    123             temp_box.y1 = y + j * block_h;
    124             temp_box.x2 = MIN(temp_box.x1 + block_w, end_x);
    125             temp_box.y2 = MIN(temp_box.y1 + block_h, end_y);
    126             RegionInitBoxes(&temp_region, &temp_box, 1);
    127             DEBUGF("block idx %d \n", temp_block_idx);
    128             DEBUGRegionPrint(&temp_region);
    129             current_region = RegionCreate(NULL, 4);
    130             RegionIntersect(current_region, &temp_region, region);
    131             DEBUGF("i %d j %d  region: \n", i, j);
    132             DEBUGRegionPrint(current_region);
    133             if (RegionNumRects(current_region)) {
    134                 clipped_regions[k].region = current_region;
    135                 clipped_regions[k].block_idx = temp_block_idx;
    136                 k++;
    137             }
    138             else
    139                 RegionDestroy(current_region);
    140             RegionUninit(&temp_region);
    141         }
    142     }
    143 
    144     *n_region = k;
    145     return clipped_regions;
    146 }
    147 
    148 /**
    149  * Do a two round clipping,
    150  * first is to clip the region regard to current pixmap's
    151  * block array. Then for each clipped region, do a inner
    152  * block clipping. This is to make sure the final result
    153  * will be shapped by inner_block_w and inner_block_h, and
    154  * the final region also will not cross the pixmap's block
    155  * boundary.
    156  *
    157  * This is mainly used by transformation support when do
    158  * compositing.
    159  */
    160 
    161 glamor_pixmap_clipped_regions *
    162 glamor_compute_clipped_regions_ext(PixmapPtr pixmap,
    163                                    RegionPtr region,
    164                                    int *n_region,
    165                                    int inner_block_w, int inner_block_h,
    166                                    int reverse, int upsidedown)
    167 {
    168     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
    169     glamor_pixmap_clipped_regions *clipped_regions, *inner_regions,
    170         *result_regions;
    171     int i, j, x, y, k, inner_n_regions;
    172     int width, height;
    173     BoxPtr box_array;
    174     BoxRec small_box;
    175     int block_w, block_h;
    176 
    177     DEBUGF("ext called \n");
    178 
    179     if (glamor_pixmap_priv_is_small(pixmap_priv)) {
    180         clipped_regions = calloc(1, sizeof(*clipped_regions));
    181         if (clipped_regions == NULL) {
    182             *n_region = 0;
    183             return NULL;
    184         }
    185         clipped_regions[0].region = RegionCreate(NULL, 1);
    186         clipped_regions[0].block_idx = 0;
    187         RegionCopy(clipped_regions[0].region, region);
    188         *n_region = 1;
    189         block_w = pixmap->drawable.width;
    190         block_h = pixmap->drawable.height;
    191         box_array = &small_box;
    192         small_box.x1 = small_box.y1 = 0;
    193         small_box.x2 = block_w;
    194         small_box.y2 = block_h;
    195     }
    196     else {
    197         glamor_pixmap_private *priv = __glamor_large(pixmap_priv);
    198 
    199         clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
    200                                                            priv->block_h,
    201                                                            priv->block_wcnt,
    202                                                            0, 0,
    203                                                            pixmap->drawable.width,
    204                                                            pixmap->drawable.height,
    205                                                            region, n_region,
    206                                                            reverse, upsidedown);
    207 
    208         if (clipped_regions == NULL) {
    209             *n_region = 0;
    210             return NULL;
    211         }
    212         block_w = priv->block_w;
    213         block_h = priv->block_h;
    214         box_array = priv->box_array;
    215     }
    216     if (inner_block_w >= block_w && inner_block_h >= block_h)
    217         return clipped_regions;
    218     result_regions = calloc(*n_region
    219                             * ((block_w + inner_block_w - 1) /
    220                                inner_block_w)
    221                             * ((block_h + inner_block_h - 1) /
    222                                inner_block_h), sizeof(*result_regions));
    223     if (result_regions == NULL) {
    224         *n_region = 0;
    225         free(clipped_regions);
    226         return NULL;
    227     }
    228     k = 0;
    229     for (i = 0; i < *n_region; i++) {
    230         x = box_array[clipped_regions[i].block_idx].x1;
    231         y = box_array[clipped_regions[i].block_idx].y1;
    232         width = box_array[clipped_regions[i].block_idx].x2 - x;
    233         height = box_array[clipped_regions[i].block_idx].y2 - y;
    234         inner_regions = __glamor_compute_clipped_regions(inner_block_w,
    235                                                          inner_block_h,
    236                                                          0, x, y,
    237                                                          width,
    238                                                          height,
    239                                                          clipped_regions[i].
    240                                                          region,
    241                                                          &inner_n_regions,
    242                                                          reverse, upsidedown);
    243         for (j = 0; j < inner_n_regions; j++) {
    244             result_regions[k].region = inner_regions[j].region;
    245             result_regions[k].block_idx = clipped_regions[i].block_idx;
    246             k++;
    247         }
    248         free(inner_regions);
    249     }
    250     *n_region = k;
    251     free(clipped_regions);
    252     return result_regions;
    253 }
    254 
    255 /*
    256  *
    257  * For the repeat pad mode, we can simply convert the region and
    258  * let the out-of-box region can cover the needed edge of the source/mask
    259  * Then apply a normal clip we can get what we want.
    260  */
    261 static RegionPtr
    262 _glamor_convert_pad_region(RegionPtr region, int w, int h)
    263 {
    264     RegionPtr pad_region;
    265     int nrect;
    266     BoxPtr box;
    267     int overlap;
    268 
    269     nrect = RegionNumRects(region);
    270     box = RegionRects(region);
    271     pad_region = RegionCreate(NULL, 4);
    272     if (pad_region == NULL)
    273         return NULL;
    274     while (nrect--) {
    275         BoxRec pad_box;
    276         RegionRec temp_region;
    277 
    278         pad_box = *box;
    279         if (pad_box.x1 < 0 && pad_box.x2 <= 0)
    280             pad_box.x2 = 1;
    281         else if (pad_box.x1 >= w && pad_box.x2 > w)
    282             pad_box.x1 = w - 1;
    283         if (pad_box.y1 < 0 && pad_box.y2 <= 0)
    284             pad_box.y2 = 1;
    285         else if (pad_box.y1 >= h && pad_box.y2 > h)
    286             pad_box.y1 = h - 1;
    287         RegionInitBoxes(&temp_region, &pad_box, 1);
    288         RegionAppend(pad_region, &temp_region);
    289         RegionUninit(&temp_region);
    290         box++;
    291     }
    292     RegionValidate(pad_region, &overlap);
    293     return pad_region;
    294 }
    295 
    296 /*
    297  * For one type of large pixmap, its one direction is not exceed the
    298  * size limitation, and in another word, on one direction it has only
    299  * one block.
    300  *
    301  * This case of reflect repeating, we can optimize it and avoid repeat
    302  * clip on that direction. We can just enlarge the repeat box and can
    303  * cover all the dest region on that direction. But latter, we need to
    304  * fixup the clipped result to get a correct coords for the subsequent
    305  * processing. This function is to do the coords correction.
    306  *
    307  * */
    308 static void
    309 _glamor_largepixmap_reflect_fixup(short *xy1, short *xy2, int wh)
    310 {
    311     int odd1, odd2;
    312     int c1, c2;
    313 
    314     if (*xy2 - *xy1 > wh) {
    315         *xy1 = 0;
    316         *xy2 = wh;
    317         return;
    318     }
    319     modulus(*xy1, wh, c1);
    320     odd1 = ((*xy1 - c1) / wh) & 0x1;
    321     modulus(*xy2, wh, c2);
    322     odd2 = ((*xy2 - c2) / wh) & 0x1;
    323 
    324     if (odd1 && odd2) {
    325         *xy1 = wh - c2;
    326         *xy2 = wh - c1;
    327     }
    328     else if (odd1 && !odd2) {
    329         *xy1 = 0;
    330         *xy2 = MAX(c2, wh - c1);
    331     }
    332     else if (!odd1 && odd2) {
    333         *xy2 = wh;
    334         *xy1 = MIN(c1, wh - c2);
    335     }
    336     else {
    337         *xy1 = c1;
    338         *xy2 = c2;
    339     }
    340 }
    341 
    342 /**
    343  * Clip the boxes regards to each pixmap's block array.
    344  *
    345  * Should translate the region to relative coords to the pixmap,
    346  * start at (0,0).
    347  *
    348  * @is_transform: if it is set, it has a transform matrix.
    349  *
    350  */
    351 static glamor_pixmap_clipped_regions *
    352 _glamor_compute_clipped_regions(PixmapPtr pixmap,
    353                                 glamor_pixmap_private *pixmap_priv,
    354                                 RegionPtr region, int *n_region,
    355                                 int repeat_type, int is_transform,
    356                                 int reverse, int upsidedown)
    357 {
    358     glamor_pixmap_clipped_regions *clipped_regions;
    359     BoxPtr extent;
    360     int i, j;
    361     RegionPtr current_region;
    362     int pixmap_width, pixmap_height;
    363     int m;
    364     BoxRec repeat_box;
    365     RegionRec repeat_region;
    366     int right_shift = 0;
    367     int down_shift = 0;
    368     int x_center_shift = 0, y_center_shift = 0;
    369     glamor_pixmap_private *priv;
    370 
    371     DEBUGRegionPrint(region);
    372     if (glamor_pixmap_priv_is_small(pixmap_priv)) {
    373         clipped_regions = calloc(1, sizeof(*clipped_regions));
    374         if (clipped_regions) {
    375             clipped_regions[0].region = RegionCreate(NULL, 1);
    376             clipped_regions[0].block_idx = 0;
    377             RegionCopy(clipped_regions[0].region, region);
    378             *n_region = 1;
    379         }
    380         else
    381             *n_region = 0;
    382         return clipped_regions;
    383     }
    384 
    385     priv = __glamor_large(pixmap_priv);
    386 
    387     pixmap_width = pixmap->drawable.width;
    388     pixmap_height = pixmap->drawable.height;
    389     if (repeat_type == 0 || repeat_type == RepeatPad) {
    390         RegionPtr saved_region = NULL;
    391 
    392         if (repeat_type == RepeatPad) {
    393             saved_region = region;
    394             region =
    395                 _glamor_convert_pad_region(saved_region, pixmap_width,
    396                                            pixmap_height);
    397             if (region == NULL) {
    398                 *n_region = 0;
    399                 return NULL;
    400             }
    401         }
    402         clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
    403                                                            priv->block_h,
    404                                                            priv->block_wcnt,
    405                                                            0, 0,
    406                                                            pixmap->drawable.width,
    407                                                            pixmap->drawable.height,
    408                                                            region, n_region,
    409                                                            reverse, upsidedown);
    410         if (saved_region)
    411             RegionDestroy(region);
    412         return clipped_regions;
    413     }
    414     extent = RegionExtents(region);
    415 
    416     x_center_shift = extent->x1 / pixmap_width;
    417     if (x_center_shift < 0)
    418         x_center_shift--;
    419     if (abs(x_center_shift) & 1)
    420         x_center_shift++;
    421     y_center_shift = extent->y1 / pixmap_height;
    422     if (y_center_shift < 0)
    423         y_center_shift--;
    424     if (abs(y_center_shift) & 1)
    425         y_center_shift++;
    426 
    427     if (extent->x1 < 0)
    428         right_shift = ((-extent->x1 + pixmap_width - 1) / pixmap_width);
    429     if (extent->y1 < 0)
    430         down_shift = ((-extent->y1 + pixmap_height - 1) / pixmap_height);
    431 
    432     if (right_shift != 0 || down_shift != 0) {
    433         if (repeat_type == RepeatReflect) {
    434             right_shift = (right_shift + 1) & ~1;
    435             down_shift = (down_shift + 1) & ~1;
    436         }
    437         RegionTranslate(region, right_shift * pixmap_width,
    438                         down_shift * pixmap_height);
    439     }
    440 
    441     extent = RegionExtents(region);
    442     /* Tile a large pixmap to another large pixmap.
    443      * We can't use the target large pixmap as the
    444      * loop variable, instead we need to loop for all
    445      * the blocks in the tile pixmap.
    446      *
    447      * simulate repeat each single block to cover the
    448      * target's blocks. Two special case:
    449      * a block_wcnt == 1 or block_hcnt ==1, then we
    450      * only need to loop one direction as the other
    451      * direction is fully included in the first block.
    452      *
    453      * For the other cases, just need to start
    454      * from a proper shiftx/shifty, and then increase
    455      * y by tile_height each time to walk trhough the
    456      * target block and then walk trhough the target
    457      * at x direction by increate tile_width each time.
    458      *
    459      * This way, we can consolidate all the sub blocks
    460      * of the target boxes into one tile source's block.
    461      *
    462      * */
    463     m = 0;
    464     clipped_regions = calloc(priv->block_wcnt * priv->block_hcnt,
    465                              sizeof(*clipped_regions));
    466     if (clipped_regions == NULL) {
    467         *n_region = 0;
    468         return NULL;
    469     }
    470     if (right_shift != 0 || down_shift != 0) {
    471         DEBUGF("region to be repeated shifted \n");
    472         DEBUGRegionPrint(region);
    473     }
    474     DEBUGF("repeat pixmap width %d height %d \n", pixmap_width, pixmap_height);
    475     DEBUGF("extent x1 %d y1 %d x2 %d y2 %d \n", extent->x1, extent->y1,
    476            extent->x2, extent->y2);
    477     for (j = 0; j < priv->block_hcnt; j++) {
    478         for (i = 0; i < priv->block_wcnt; i++) {
    479             int dx = pixmap_width;
    480             int dy = pixmap_height;
    481             int idx;
    482             int shift_x;
    483             int shift_y;
    484             int saved_y1, saved_y2;
    485             int x_idx = 0, y_idx = 0, saved_y_idx = 0;
    486             RegionRec temp_region;
    487             BoxRec reflect_repeat_box;
    488             BoxPtr valid_repeat_box;
    489 
    490             shift_x = (extent->x1 / pixmap_width) * pixmap_width;
    491             shift_y = (extent->y1 / pixmap_height) * pixmap_height;
    492             idx = j * priv->block_wcnt + i;
    493             if (repeat_type == RepeatReflect) {
    494                 x_idx = (extent->x1 / pixmap_width);
    495                 y_idx = (extent->y1 / pixmap_height);
    496             }
    497 
    498             /* Construct a rect to clip the target region. */
    499             repeat_box.x1 = shift_x + priv->box_array[idx].x1;
    500             repeat_box.y1 = shift_y + priv->box_array[idx].y1;
    501             if (priv->block_wcnt == 1) {
    502                 repeat_box.x2 = extent->x2;
    503                 dx = extent->x2 - repeat_box.x1;
    504             }
    505             else
    506                 repeat_box.x2 = shift_x + priv->box_array[idx].x2;
    507             if (priv->block_hcnt == 1) {
    508                 repeat_box.y2 = extent->y2;
    509                 dy = extent->y2 - repeat_box.y1;
    510             }
    511             else
    512                 repeat_box.y2 = shift_y + priv->box_array[idx].y2;
    513 
    514             current_region = RegionCreate(NULL, 4);
    515             RegionInit(&temp_region, NULL, 4);
    516             DEBUGF("init repeat box %d %d %d %d \n",
    517                    repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2);
    518 
    519             if (repeat_type == RepeatNormal) {
    520                 saved_y1 = repeat_box.y1;
    521                 saved_y2 = repeat_box.y2;
    522                 for (; repeat_box.x1 < extent->x2;
    523                      repeat_box.x1 += dx, repeat_box.x2 += dx) {
    524                     repeat_box.y1 = saved_y1;
    525                     repeat_box.y2 = saved_y2;
    526                     for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;
    527                          repeat_box.y1 < extent->y2;
    528                          repeat_box.y1 += dy, repeat_box.y2 += dy) {
    529 
    530                         RegionInitBoxes(&repeat_region, &repeat_box, 1);
    531                         DEBUGF("Start to clip repeat region: \n");
    532                         DEBUGRegionPrint(&repeat_region);
    533                         RegionIntersect(&temp_region, &repeat_region, region);
    534                         DEBUGF("clip result:\n");
    535                         DEBUGRegionPrint(&temp_region);
    536                         RegionAppend(current_region, &temp_region);
    537                         RegionUninit(&repeat_region);
    538                     }
    539                 }
    540             }
    541             else if (repeat_type == RepeatReflect) {
    542                 saved_y1 = repeat_box.y1;
    543                 saved_y2 = repeat_box.y2;
    544                 saved_y_idx = y_idx;
    545                 for (;; repeat_box.x1 += dx, repeat_box.x2 += dx) {
    546                     repeat_box.y1 = saved_y1;
    547                     repeat_box.y2 = saved_y2;
    548                     y_idx = saved_y_idx;
    549                     reflect_repeat_box.x1 = (x_idx & 1) ?
    550                         ((2 * x_idx + 1) * dx - repeat_box.x2) : repeat_box.x1;
    551                     reflect_repeat_box.x2 = (x_idx & 1) ?
    552                         ((2 * x_idx + 1) * dx - repeat_box.x1) : repeat_box.x2;
    553                     valid_repeat_box = &reflect_repeat_box;
    554 
    555                     if (valid_repeat_box->x1 >= extent->x2)
    556                         break;
    557                     for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;;
    558                          repeat_box.y1 += dy, repeat_box.y2 += dy) {
    559 
    560                         DEBUGF("x_idx %d y_idx %d dx %d dy %d\n", x_idx, y_idx,
    561                                dx, dy);
    562                         DEBUGF("repeat box %d %d %d %d \n", repeat_box.x1,
    563                                repeat_box.y1, repeat_box.x2, repeat_box.y2);
    564 
    565                         if (priv->block_hcnt > 1) {
    566                             reflect_repeat_box.y1 = (y_idx & 1) ?
    567                                 ((2 * y_idx + 1) * dy -
    568                                  repeat_box.y2) : repeat_box.y1;
    569                             reflect_repeat_box.y2 =
    570                                 (y_idx & 1) ? ((2 * y_idx + 1) * dy -
    571                                                repeat_box.y1) : repeat_box.y2;
    572                         }
    573                         else {
    574                             reflect_repeat_box.y1 = repeat_box.y1;
    575                             reflect_repeat_box.y2 = repeat_box.y2;
    576                         }
    577 
    578                         DEBUGF("valid_repeat_box x1 %d y1 %d \n",
    579                                valid_repeat_box->x1, valid_repeat_box->y1);
    580                         if (valid_repeat_box->y1 >= extent->y2)
    581                             break;
    582                         RegionInitBoxes(&repeat_region, valid_repeat_box, 1);
    583                         DEBUGF("start to clip repeat[reflect] region: \n");
    584                         DEBUGRegionPrint(&repeat_region);
    585                         RegionIntersect(&temp_region, &repeat_region, region);
    586                         DEBUGF("result:\n");
    587                         DEBUGRegionPrint(&temp_region);
    588                         if (is_transform && RegionNumRects(&temp_region)) {
    589                             BoxRec temp_box;
    590                             BoxPtr temp_extent;
    591 
    592                             temp_extent = RegionExtents(&temp_region);
    593                             if (priv->block_wcnt > 1) {
    594                                 if (x_idx & 1) {
    595                                     temp_box.x1 =
    596                                         ((2 * x_idx + 1) * dx -
    597                                          temp_extent->x2);
    598                                     temp_box.x2 =
    599                                         ((2 * x_idx + 1) * dx -
    600                                          temp_extent->x1);
    601                                 }
    602                                 else {
    603                                     temp_box.x1 = temp_extent->x1;
    604                                     temp_box.x2 = temp_extent->x2;
    605                                 }
    606                                 modulus(temp_box.x1, pixmap_width, temp_box.x1);
    607                                 modulus(temp_box.x2, pixmap_width, temp_box.x2);
    608                                 if (temp_box.x2 == 0)
    609                                     temp_box.x2 = pixmap_width;
    610                             }
    611                             else {
    612                                 temp_box.x1 = temp_extent->x1;
    613                                 temp_box.x2 = temp_extent->x2;
    614                                 _glamor_largepixmap_reflect_fixup(&temp_box.x1,
    615                                                                   &temp_box.x2,
    616                                                                   pixmap_width);
    617                             }
    618 
    619                             if (priv->block_hcnt > 1) {
    620                                 if (y_idx & 1) {
    621                                     temp_box.y1 =
    622                                         ((2 * y_idx + 1) * dy -
    623                                          temp_extent->y2);
    624                                     temp_box.y2 =
    625                                         ((2 * y_idx + 1) * dy -
    626                                          temp_extent->y1);
    627                                 }
    628                                 else {
    629                                     temp_box.y1 = temp_extent->y1;
    630                                     temp_box.y2 = temp_extent->y2;
    631                                 }
    632 
    633                                 modulus(temp_box.y1, pixmap_height,
    634                                         temp_box.y1);
    635                                 modulus(temp_box.y2, pixmap_height,
    636                                         temp_box.y2);
    637                                 if (temp_box.y2 == 0)
    638                                     temp_box.y2 = pixmap_height;
    639                             }
    640                             else {
    641                                 temp_box.y1 = temp_extent->y1;
    642                                 temp_box.y2 = temp_extent->y2;
    643                                 _glamor_largepixmap_reflect_fixup(&temp_box.y1,
    644                                                                   &temp_box.y2,
    645                                                                   pixmap_height);
    646                             }
    647 
    648                             RegionInitBoxes(&temp_region, &temp_box, 1);
    649                             RegionTranslate(&temp_region,
    650                                             x_center_shift * pixmap_width,
    651                                             y_center_shift * pixmap_height);
    652                             DEBUGF("for transform result:\n");
    653                             DEBUGRegionPrint(&temp_region);
    654                         }
    655                         RegionAppend(current_region, &temp_region);
    656                         RegionUninit(&repeat_region);
    657                         y_idx++;
    658                     }
    659                     x_idx++;
    660                 }
    661             }
    662             DEBUGF("dx %d dy %d \n", dx, dy);
    663 
    664             if (RegionNumRects(current_region)) {
    665 
    666                 if ((right_shift != 0 || down_shift != 0) &&
    667                     !(is_transform && repeat_type == RepeatReflect))
    668                     RegionTranslate(current_region, -right_shift * pixmap_width,
    669                                     -down_shift * pixmap_height);
    670                 clipped_regions[m].region = current_region;
    671                 clipped_regions[m].block_idx = idx;
    672                 m++;
    673             }
    674             else
    675                 RegionDestroy(current_region);
    676             RegionUninit(&temp_region);
    677         }
    678     }
    679 
    680     if (right_shift != 0 || down_shift != 0)
    681         RegionTranslate(region, -right_shift * pixmap_width,
    682                         -down_shift * pixmap_height);
    683     *n_region = m;
    684 
    685     return clipped_regions;
    686 }
    687 
    688 glamor_pixmap_clipped_regions *
    689 glamor_compute_clipped_regions(PixmapPtr pixmap,
    690                                RegionPtr region,
    691                                int *n_region, int repeat_type,
    692                                int reverse, int upsidedown)
    693 {
    694     glamor_pixmap_private       *priv = glamor_get_pixmap_private(pixmap);
    695     return _glamor_compute_clipped_regions(pixmap, priv, region, n_region, repeat_type,
    696                                            0, reverse, upsidedown);
    697 }
    698 
    699 /* XXX overflow still exist. maybe we need to change to use region32.
    700  * by default. Or just use region32 for repeat cases?
    701  **/
    702 static glamor_pixmap_clipped_regions *
    703 glamor_compute_transform_clipped_regions(PixmapPtr pixmap,
    704                                          struct pixman_transform *transform,
    705                                          RegionPtr region, int *n_region,
    706                                          int dx, int dy, int repeat_type,
    707                                          int reverse, int upsidedown)
    708 {
    709     glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
    710     BoxPtr temp_extent;
    711     struct pixman_box32 temp_box;
    712     struct pixman_box16 short_box;
    713     RegionPtr temp_region;
    714     glamor_pixmap_clipped_regions *ret;
    715 
    716     temp_region = RegionCreate(NULL, 4);
    717     temp_extent = RegionExtents(region);
    718     DEBUGF("dest region \n");
    719     DEBUGRegionPrint(region);
    720     /* dx/dy may exceed MAX SHORT. we have to use
    721      * a box32 to represent it.*/
    722     temp_box.x1 = temp_extent->x1 + dx;
    723     temp_box.x2 = temp_extent->x2 + dx;
    724     temp_box.y1 = temp_extent->y1 + dy;
    725     temp_box.y2 = temp_extent->y2 + dy;
    726 
    727     DEBUGF("source box %d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2,
    728            temp_box.y2);
    729     if (transform)
    730         glamor_get_transform_extent_from_box(&temp_box, transform);
    731     if (repeat_type == RepeatNone) {
    732         if (temp_box.x1 < 0)
    733             temp_box.x1 = 0;
    734         if (temp_box.y1 < 0)
    735             temp_box.y1 = 0;
    736         temp_box.x2 = MIN(temp_box.x2, pixmap->drawable.width);
    737         temp_box.y2 = MIN(temp_box.y2, pixmap->drawable.height);
    738     }
    739     /* Now copy back the box32 to a box16 box, avoiding overflow. */
    740     short_box.x1 = MIN(temp_box.x1, INT16_MAX);
    741     short_box.y1 = MIN(temp_box.y1, INT16_MAX);
    742     short_box.x2 = MIN(temp_box.x2, INT16_MAX);
    743     short_box.y2 = MIN(temp_box.y2, INT16_MAX);
    744     RegionInitBoxes(temp_region, &short_box, 1);
    745     DEBUGF("copy to temp source region \n");
    746     DEBUGRegionPrint(temp_region);
    747     ret = _glamor_compute_clipped_regions(pixmap,
    748                                           priv,
    749                                           temp_region,
    750                                           n_region,
    751                                           repeat_type, 1, reverse, upsidedown);
    752     DEBUGF("n_regions = %d \n", *n_region);
    753     RegionDestroy(temp_region);
    754 
    755     return ret;
    756 }
    757 
    758 /*
    759  * As transform and repeatpad mode.
    760  * We may get a clipped result which in multiple regions.
    761  * It's not easy to do a 2nd round clipping just as we do
    762  * without transform/repeatPad. As it's not easy to reverse
    763  * the 2nd round clipping result with a transform/repeatPad mode,
    764  * or even impossible for some transformation.
    765  *
    766  * So we have to merge the fragmental region into one region
    767  * if the clipped result cross the region boundary.
    768  */
    769 static void
    770 glamor_merge_clipped_regions(PixmapPtr pixmap,
    771                              glamor_pixmap_private *pixmap_priv,
    772                              int repeat_type,
    773                              glamor_pixmap_clipped_regions *clipped_regions,
    774                              int *n_regions, int *need_clean_fbo)
    775 {
    776     BoxRec temp_box, copy_box;
    777     RegionPtr temp_region;
    778     glamor_pixmap_private *temp_priv;
    779     PixmapPtr temp_pixmap;
    780     int overlap;
    781     int i;
    782     int pixmap_width, pixmap_height;
    783     glamor_pixmap_private *priv;
    784 
    785     priv = __glamor_large(pixmap_priv);
    786     pixmap_width = pixmap->drawable.width;
    787     pixmap_height =pixmap->drawable.height;
    788 
    789     temp_region = RegionCreate(NULL, 4);
    790     for (i = 0; i < *n_regions; i++) {
    791         DEBUGF("Region %d:\n", i);
    792         DEBUGRegionPrint(clipped_regions[i].region);
    793         RegionAppend(temp_region, clipped_regions[i].region);
    794     }
    795 
    796     RegionValidate(temp_region, &overlap);
    797     DEBUGF("temp region: \n");
    798     DEBUGRegionPrint(temp_region);
    799 
    800     temp_box = *RegionExtents(temp_region);
    801 
    802     DEBUGF("need copy region: \n");
    803     DEBUGF("%d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2,
    804            temp_box.y2);
    805     temp_pixmap =
    806         glamor_create_pixmap(pixmap->drawable.pScreen,
    807                              temp_box.x2 - temp_box.x1,
    808                              temp_box.y2 - temp_box.y1,
    809                              pixmap->drawable.depth,
    810                              GLAMOR_CREATE_PIXMAP_FIXUP);
    811     if (temp_pixmap == NULL) {
    812         assert(0);
    813         return;
    814     }
    815 
    816     temp_priv = glamor_get_pixmap_private(temp_pixmap);
    817     assert(glamor_pixmap_priv_is_small(temp_priv));
    818 
    819     priv->box = temp_box;
    820     if (temp_box.x1 >= 0 && temp_box.x2 <= pixmap_width
    821         && temp_box.y1 >= 0 && temp_box.y2 <= pixmap_height) {
    822         int dx, dy;
    823 
    824         copy_box.x1 = 0;
    825         copy_box.y1 = 0;
    826         copy_box.x2 = temp_box.x2 - temp_box.x1;
    827         copy_box.y2 = temp_box.y2 - temp_box.y1;
    828         dx = temp_box.x1;
    829         dy = temp_box.y1;
    830         glamor_copy(&pixmap->drawable,
    831                     &temp_pixmap->drawable,
    832                     NULL, &copy_box, 1, dx, dy, 0, 0, 0, NULL);
    833 //              glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
    834 //                             temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff00);
    835     }
    836     else {
    837         for (i = 0; i < *n_regions; i++) {
    838             BoxPtr box;
    839             int nbox;
    840 
    841             box = REGION_RECTS(clipped_regions[i].region);
    842             nbox = REGION_NUM_RECTS(clipped_regions[i].region);
    843             while (nbox--) {
    844                 int dx, dy, c, d;
    845 
    846                 DEBUGF("box x1 %d y1 %d x2 %d y2 %d \n",
    847                        box->x1, box->y1, box->x2, box->y2);
    848                 modulus(box->x1, pixmap_width, c);
    849                 dx = c - (box->x1 - temp_box.x1);
    850                 copy_box.x1 = box->x1 - temp_box.x1;
    851                 copy_box.x2 = box->x2 - temp_box.x1;
    852 
    853                 modulus(box->y1, pixmap_height, d);
    854                 dy = d - (box->y1 - temp_box.y1);
    855                 copy_box.y1 = box->y1 - temp_box.y1;
    856                 copy_box.y2 = box->y2 - temp_box.y1;
    857 
    858                 DEBUGF("copying box %d %d %d %d, dx %d dy %d\n",
    859                        copy_box.x1, copy_box.y1, copy_box.x2,
    860                        copy_box.y2, dx, dy);
    861 
    862                 glamor_copy(&pixmap->drawable,
    863                             &temp_pixmap->drawable,
    864                             NULL, &copy_box, 1, dx, dy, 0, 0, 0, NULL);
    865 
    866                 box++;
    867             }
    868         }
    869         //glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
    870         //             temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff);
    871     }
    872     /* The first region will be released at caller side. */
    873     for (i = 1; i < *n_regions; i++)
    874         RegionDestroy(clipped_regions[i].region);
    875     RegionDestroy(temp_region);
    876     priv->box = temp_box;
    877     priv->fbo = glamor_pixmap_detach_fbo(temp_priv);
    878     DEBUGF("priv box x1 %d y1 %d x2 %d y2 %d \n",
    879            priv->box.x1, priv->box.y1, priv->box.x2, priv->box.y2);
    880     glamor_destroy_pixmap(temp_pixmap);
    881     *need_clean_fbo = 1;
    882     *n_regions = 1;
    883 }
    884 
    885 /**
    886  * Given an expected transformed block width and block height,
    887  *
    888  * This function calculate a new block width and height which
    889  * guarantee the transform result will not exceed the given
    890  * block width and height.
    891  *
    892  * For large block width and height (> 2048), we choose a
    893  * smaller new width and height and to reduce the cross region
    894  * boundary and can avoid some overhead.
    895  *
    896  **/
    897 static Bool
    898 glamor_get_transform_block_size(struct pixman_transform *transform,
    899                                 int block_w, int block_h,
    900                                 int *transformed_block_w,
    901                                 int *transformed_block_h)
    902 {
    903     double a, b, c, d, e, f, g, h;
    904     double scale;
    905     int width, height;
    906 
    907     a = pixman_fixed_to_double(transform->matrix[0][0]);
    908     b = pixman_fixed_to_double(transform->matrix[0][1]);
    909     c = pixman_fixed_to_double(transform->matrix[1][0]);
    910     d = pixman_fixed_to_double(transform->matrix[1][1]);
    911     scale = pixman_fixed_to_double(transform->matrix[2][2]);
    912     if (block_w > 2048) {
    913         /* For large block size, we shrink it to smaller box,
    914          * thus latter we may get less cross boundary regions and
    915          * thus can avoid some extra copy.
    916          *
    917          **/
    918         width = block_w / 4;
    919         height = block_h / 4;
    920     }
    921     else {
    922         width = block_w - 2;
    923         height = block_h - 2;
    924     }
    925     e = a + b;
    926     f = c + d;
    927 
    928     g = a - b;
    929     h = c - d;
    930 
    931     e = MIN(block_w, floor(width * scale) / MAX(fabs(e), fabs(g)));
    932     f = MIN(block_h, floor(height * scale) / MAX(fabs(f), fabs(h)));
    933     *transformed_block_w = MIN(e, f) - 1;
    934     *transformed_block_h = *transformed_block_w;
    935     if (*transformed_block_w <= 0 || *transformed_block_h <= 0)
    936         return FALSE;
    937     DEBUGF("original block_w/h %d %d, fixed %d %d \n", block_w, block_h,
    938            *transformed_block_w, *transformed_block_h);
    939     return TRUE;
    940 }
    941 
    942 #define VECTOR_FROM_POINT(p, x, y) do {\
    943 	p.v[0] = x;  \
    944 	p.v[1] = y;  \
    945 	p.v[2] = 1.0; } while (0)
    946 static void
    947 glamor_get_transform_extent_from_box(struct pixman_box32 *box,
    948                                      struct pixman_transform *transform)
    949 {
    950     struct pixman_f_vector p0, p1, p2, p3;
    951     float min_x, min_y, max_x, max_y;
    952 
    953     struct pixman_f_transform ftransform;
    954 
    955     VECTOR_FROM_POINT(p0, box->x1, box->y1);
    956     VECTOR_FROM_POINT(p1, box->x2, box->y1);
    957     VECTOR_FROM_POINT(p2, box->x2, box->y2);
    958     VECTOR_FROM_POINT(p3, box->x1, box->y2);
    959 
    960     pixman_f_transform_from_pixman_transform(&ftransform, transform);
    961     pixman_f_transform_point(&ftransform, &p0);
    962     pixman_f_transform_point(&ftransform, &p1);
    963     pixman_f_transform_point(&ftransform, &p2);
    964     pixman_f_transform_point(&ftransform, &p3);
    965 
    966     min_x = MIN(p0.v[0], p1.v[0]);
    967     min_x = MIN(min_x, p2.v[0]);
    968     min_x = MIN(min_x, p3.v[0]);
    969 
    970     min_y = MIN(p0.v[1], p1.v[1]);
    971     min_y = MIN(min_y, p2.v[1]);
    972     min_y = MIN(min_y, p3.v[1]);
    973 
    974     max_x = MAX(p0.v[0], p1.v[0]);
    975     max_x = MAX(max_x, p2.v[0]);
    976     max_x = MAX(max_x, p3.v[0]);
    977 
    978     max_y = MAX(p0.v[1], p1.v[1]);
    979     max_y = MAX(max_y, p2.v[1]);
    980     max_y = MAX(max_y, p3.v[1]);
    981     box->x1 = floor(min_x) - 1;
    982     box->y1 = floor(min_y) - 1;
    983     box->x2 = ceil(max_x) + 1;
    984     box->y2 = ceil(max_y) + 1;
    985 }
    986 
    987 static void
    988 _glamor_process_transformed_clipped_region(PixmapPtr pixmap,
    989                                            glamor_pixmap_private *priv,
    990                                            int repeat_type,
    991                                            glamor_pixmap_clipped_regions *
    992                                            clipped_regions, int *n_regions,
    993                                            int *need_clean_fbo)
    994 {
    995     int shift_x, shift_y;
    996 
    997     if (*n_regions != 1) {
    998         /* Merge all source regions into one region. */
    999         glamor_merge_clipped_regions(pixmap, priv, repeat_type,
   1000                                      clipped_regions, n_regions,
   1001                                      need_clean_fbo);
   1002     }
   1003     else {
   1004         glamor_set_pixmap_fbo_current(priv, clipped_regions[0].block_idx);
   1005         if (repeat_type == RepeatReflect || repeat_type == RepeatNormal) {
   1006             /* The required source areas are in one region,
   1007              * we need to shift the corresponding box's coords to proper position,
   1008              * thus we can calculate the relative coords correctly.*/
   1009             BoxPtr temp_box;
   1010             int rem;
   1011 
   1012             temp_box = RegionExtents(clipped_regions[0].region);
   1013             modulus(temp_box->x1, pixmap->drawable.width, rem);
   1014             shift_x = (temp_box->x1 - rem) / pixmap->drawable.width;
   1015             modulus(temp_box->y1, pixmap->drawable.height, rem);
   1016             shift_y = (temp_box->y1 - rem) / pixmap->drawable.height;
   1017 
   1018             if (shift_x != 0) {
   1019                 __glamor_large(priv)->box.x1 +=
   1020                     shift_x * pixmap->drawable.width;
   1021                 __glamor_large(priv)->box.x2 +=
   1022                     shift_x * pixmap->drawable.width;
   1023             }
   1024             if (shift_y != 0) {
   1025                 __glamor_large(priv)->box.y1 +=
   1026                     shift_y * pixmap->drawable.height;
   1027                 __glamor_large(priv)->box.y2 +=
   1028                     shift_y * pixmap->drawable.height;
   1029             }
   1030         }
   1031     }
   1032 }
   1033 
   1034 Bool
   1035 glamor_composite_largepixmap_region(CARD8 op,
   1036                                     PicturePtr source,
   1037                                     PicturePtr mask,
   1038                                     PicturePtr dest,
   1039                                     PixmapPtr source_pixmap,
   1040                                     PixmapPtr mask_pixmap,
   1041                                     PixmapPtr dest_pixmap,
   1042                                     RegionPtr region, Bool force_clip,
   1043                                     INT16 x_source,
   1044                                     INT16 y_source,
   1045                                     INT16 x_mask,
   1046                                     INT16 y_mask,
   1047                                     INT16 x_dest, INT16 y_dest,
   1048                                     CARD16 width, CARD16 height)
   1049 {
   1050     ScreenPtr screen = dest_pixmap->drawable.pScreen;
   1051     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
   1052     glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
   1053     glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
   1054     glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
   1055     glamor_pixmap_clipped_regions *clipped_dest_regions;
   1056     glamor_pixmap_clipped_regions *clipped_source_regions;
   1057     glamor_pixmap_clipped_regions *clipped_mask_regions;
   1058     int n_dest_regions;
   1059     int n_mask_regions;
   1060     int n_source_regions;
   1061     int i, j, k;
   1062     int need_clean_source_fbo = 0;
   1063     int need_clean_mask_fbo = 0;
   1064     int is_normal_source_fbo = 0;
   1065     int is_normal_mask_fbo = 0;
   1066     int fixed_block_width, fixed_block_height;
   1067     int dest_block_width, dest_block_height;
   1068     int null_source, null_mask;
   1069     glamor_pixmap_private *need_free_source_pixmap_priv = NULL;
   1070     glamor_pixmap_private *need_free_mask_pixmap_priv = NULL;
   1071     int source_repeat_type = 0, mask_repeat_type = 0;
   1072     int ok = TRUE;
   1073 
   1074     if (source_pixmap == dest_pixmap) {
   1075         glamor_fallback("source and dest pixmaps are the same\n");
   1076         return FALSE;
   1077     }
   1078     if (mask_pixmap == dest_pixmap) {
   1079         glamor_fallback("mask and dest pixmaps are the same\n");
   1080         return FALSE;
   1081     }
   1082 
   1083     if (source->repeat)
   1084         source_repeat_type = source->repeatType;
   1085     else
   1086         source_repeat_type = RepeatNone;
   1087 
   1088     if (mask && mask->repeat)
   1089         mask_repeat_type = mask->repeatType;
   1090     else
   1091         mask_repeat_type = RepeatNone;
   1092 
   1093     if (glamor_pixmap_priv_is_large(dest_pixmap_priv)) {
   1094         dest_block_width = __glamor_large(dest_pixmap_priv)->block_w;
   1095         dest_block_height = __glamor_large(dest_pixmap_priv)->block_h;
   1096     } else {
   1097         dest_block_width = dest_pixmap->drawable.width;
   1098         dest_block_height = dest_pixmap->drawable.height;
   1099     }
   1100     fixed_block_width = dest_block_width;
   1101     fixed_block_height = dest_block_height;
   1102 
   1103     /* If we got an totally out-of-box region for a source or mask
   1104      * region without repeat, we need to set it as null_source and
   1105      * give it a solid color (0,0,0,0). */
   1106     null_source = 0;
   1107     null_mask = 0;
   1108     RegionTranslate(region, -dest->pDrawable->x, -dest->pDrawable->y);
   1109 
   1110     /* need to transform the dest region to the correct sourcei/mask region.
   1111      * it's a little complex, as one single edge of the
   1112      * target region may be transformed to cross a block boundary of the
   1113      * source or mask. Then it's impossible to handle it as usual way.
   1114      * We may have to split the original dest region to smaller region, and
   1115      * make sure each region's transformed region can fit into one texture,
   1116      * and then continue this loop again, and each time when a transformed region
   1117      * cross the bound, we need to copy it to a single pixmap and do the composition
   1118      * with the new pixmap. If the transformed region doesn't cross a source/mask's
   1119      * boundary then we don't need to copy.
   1120      *
   1121      */
   1122     if (source_pixmap_priv
   1123         && source->transform
   1124         && glamor_pixmap_priv_is_large(source_pixmap_priv)) {
   1125         int source_transformed_block_width, source_transformed_block_height;
   1126 
   1127         if (!glamor_get_transform_block_size(source->transform,
   1128                                              __glamor_large(source_pixmap_priv)->block_w,
   1129                                              __glamor_large(source_pixmap_priv)->block_h,
   1130                                              &source_transformed_block_width,
   1131                                              &source_transformed_block_height))
   1132         {
   1133             DEBUGF("source block size less than 1, fallback.\n");
   1134             RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y);
   1135             return FALSE;
   1136         }
   1137         fixed_block_width =
   1138             min(fixed_block_width, source_transformed_block_width);
   1139         fixed_block_height =
   1140             min(fixed_block_height, source_transformed_block_height);
   1141         DEBUGF("new source block size %d x %d \n", fixed_block_width,
   1142                fixed_block_height);
   1143     }
   1144 
   1145     if (mask_pixmap_priv
   1146         && mask->transform && glamor_pixmap_priv_is_large(mask_pixmap_priv)) {
   1147         int mask_transformed_block_width, mask_transformed_block_height;
   1148 
   1149         if (!glamor_get_transform_block_size(mask->transform,
   1150                                              __glamor_large(mask_pixmap_priv)->block_w,
   1151                                              __glamor_large(mask_pixmap_priv)->block_h,
   1152                                              &mask_transformed_block_width,
   1153                                              &mask_transformed_block_height)) {
   1154             DEBUGF("mask block size less than 1, fallback.\n");
   1155             RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y);
   1156             return FALSE;
   1157         }
   1158         fixed_block_width =
   1159             min(fixed_block_width, mask_transformed_block_width);
   1160         fixed_block_height =
   1161             min(fixed_block_height, mask_transformed_block_height);
   1162         DEBUGF("new mask block size %d x %d \n", fixed_block_width,
   1163                fixed_block_height);
   1164     }
   1165 
   1166     /*compute the correct block width and height whose transformed source/mask
   1167      *region can fit into one texture.*/
   1168     if (force_clip || fixed_block_width < dest_block_width
   1169         || fixed_block_height < dest_block_height)
   1170         clipped_dest_regions =
   1171             glamor_compute_clipped_regions_ext(dest_pixmap, region,
   1172                                                &n_dest_regions,
   1173                                                fixed_block_width,
   1174                                                fixed_block_height, 0, 0);
   1175     else
   1176         clipped_dest_regions = glamor_compute_clipped_regions(dest_pixmap,
   1177                                                               region,
   1178                                                               &n_dest_regions,
   1179                                                               0, 0, 0);
   1180     DEBUGF("dest clipped result %d region: \n", n_dest_regions);
   1181     if (source_pixmap_priv
   1182         && (source_pixmap_priv == dest_pixmap_priv ||
   1183             source_pixmap_priv == mask_pixmap_priv)
   1184         && glamor_pixmap_priv_is_large(source_pixmap_priv)) {
   1185         /* XXX self-copy... */
   1186         need_free_source_pixmap_priv = source_pixmap_priv;
   1187         source_pixmap_priv = malloc(sizeof(*source_pixmap_priv));
   1188         if (source_pixmap_priv == NULL)
   1189             return FALSE;
   1190         *source_pixmap_priv = *need_free_source_pixmap_priv;
   1191         need_free_source_pixmap_priv = source_pixmap_priv;
   1192     }
   1193     assert(mask_pixmap_priv != dest_pixmap_priv);
   1194 
   1195     for (i = 0; i < n_dest_regions; i++) {
   1196         DEBUGF("dest region %d  idx %d\n", i,
   1197                clipped_dest_regions[i].block_idx);
   1198         DEBUGRegionPrint(clipped_dest_regions[i].region);
   1199         glamor_set_pixmap_fbo_current(dest_pixmap_priv,
   1200                                clipped_dest_regions[i].block_idx);
   1201         if (source_pixmap_priv &&
   1202             glamor_pixmap_priv_is_large(source_pixmap_priv)) {
   1203             if (!source->transform && source_repeat_type != RepeatPad) {
   1204                 RegionTranslate(clipped_dest_regions[i].region,
   1205                                 x_source - x_dest, y_source - y_dest);
   1206                 clipped_source_regions =
   1207                     glamor_compute_clipped_regions(source_pixmap,
   1208                                                    clipped_dest_regions[i].
   1209                                                    region, &n_source_regions,
   1210                                                    source_repeat_type, 0, 0);
   1211                 is_normal_source_fbo = 1;
   1212             }
   1213             else {
   1214                 clipped_source_regions =
   1215                     glamor_compute_transform_clipped_regions(source_pixmap,
   1216                                                              source->transform,
   1217                                                              clipped_dest_regions
   1218                                                              [i].region,
   1219                                                              &n_source_regions,
   1220                                                              x_source - x_dest,
   1221                                                              y_source - y_dest,
   1222                                                              source_repeat_type,
   1223                                                              0, 0);
   1224                 is_normal_source_fbo = 0;
   1225                 if (n_source_regions == 0) {
   1226                     /* Pad the out-of-box region to (0,0,0,0). */
   1227                     null_source = 1;
   1228                     n_source_regions = 1;
   1229                 }
   1230                 else
   1231                     _glamor_process_transformed_clipped_region
   1232                         (source_pixmap, source_pixmap_priv, source_repeat_type,
   1233                          clipped_source_regions, &n_source_regions,
   1234                          &need_clean_source_fbo);
   1235             }
   1236             DEBUGF("source clipped result %d region: \n", n_source_regions);
   1237             for (j = 0; j < n_source_regions; j++) {
   1238                 if (is_normal_source_fbo)
   1239                     glamor_set_pixmap_fbo_current(source_pixmap_priv,
   1240                                            clipped_source_regions[j].block_idx);
   1241 
   1242                 if (mask_pixmap_priv &&
   1243                     glamor_pixmap_priv_is_large(mask_pixmap_priv)) {
   1244                     if (is_normal_mask_fbo && is_normal_source_fbo) {
   1245                         /* both mask and source are normal fbo box without transform or repeatpad.
   1246                          * The region is clipped against source and then we clip it against mask here.*/
   1247                         DEBUGF("source region %d  idx %d\n", j,
   1248                                clipped_source_regions[j].block_idx);
   1249                         DEBUGRegionPrint(clipped_source_regions[j].region);
   1250                         RegionTranslate(clipped_source_regions[j].region,
   1251                                         -x_source + x_mask, -y_source + y_mask);
   1252                         clipped_mask_regions =
   1253                             glamor_compute_clipped_regions(mask_pixmap,
   1254                                                            clipped_source_regions
   1255                                                            [j].region,
   1256                                                            &n_mask_regions,
   1257                                                            mask_repeat_type, 0,
   1258                                                            0);
   1259                         is_normal_mask_fbo = 1;
   1260                     }
   1261                     else if (is_normal_mask_fbo && !is_normal_source_fbo) {
   1262                         assert(n_source_regions == 1);
   1263                         /* The source fbo is not a normal fbo box, it has transform or repeatpad.
   1264                          * the valid clip region should be the clip dest region rather than the
   1265                          * clip source region.*/
   1266                         RegionTranslate(clipped_dest_regions[i].region,
   1267                                         -x_dest + x_mask, -y_dest + y_mask);
   1268                         clipped_mask_regions =
   1269                             glamor_compute_clipped_regions(mask_pixmap,
   1270                                                            clipped_dest_regions
   1271                                                            [i].region,
   1272                                                            &n_mask_regions,
   1273                                                            mask_repeat_type, 0,
   1274                                                            0);
   1275                         is_normal_mask_fbo = 1;
   1276                     }
   1277                     else {
   1278                         /* This mask region has transform or repeatpad, we need clip it against the previous
   1279                          * valid region rather than the mask region. */
   1280                         if (!is_normal_source_fbo)
   1281                             clipped_mask_regions =
   1282                                 glamor_compute_transform_clipped_regions
   1283                                 (mask_pixmap, mask->transform,
   1284                                  clipped_dest_regions[i].region,
   1285                                  &n_mask_regions, x_mask - x_dest,
   1286                                  y_mask - y_dest, mask_repeat_type, 0, 0);
   1287                         else
   1288                             clipped_mask_regions =
   1289                                 glamor_compute_transform_clipped_regions
   1290                                 (mask_pixmap, mask->transform,
   1291                                  clipped_source_regions[j].region,
   1292                                  &n_mask_regions, x_mask - x_source,
   1293                                  y_mask - y_source, mask_repeat_type, 0, 0);
   1294                         is_normal_mask_fbo = 0;
   1295                         if (n_mask_regions == 0) {
   1296                             /* Pad the out-of-box region to (0,0,0,0). */
   1297                             null_mask = 1;
   1298                             n_mask_regions = 1;
   1299                         }
   1300                         else
   1301                             _glamor_process_transformed_clipped_region
   1302                                 (mask_pixmap, mask_pixmap_priv, mask_repeat_type,
   1303                                  clipped_mask_regions, &n_mask_regions,
   1304                                  &need_clean_mask_fbo);
   1305                     }
   1306                     DEBUGF("mask clipped result %d region: \n", n_mask_regions);
   1307 
   1308 #define COMPOSITE_REGION(region) do {				\
   1309 	if (!glamor_composite_clipped_region(op,		\
   1310 			 null_source ? NULL : source,		\
   1311 			 null_mask ? NULL : mask, dest,		\
   1312 			 null_source ? NULL : source_pixmap,    \
   1313 			 null_mask ? NULL : mask_pixmap, 	\
   1314 			 dest_pixmap, region,		        \
   1315 			 x_source, y_source, x_mask, y_mask,	\
   1316 			 x_dest, y_dest)) {			\
   1317 		assert(0);					\
   1318 	}							\
   1319    } while(0)
   1320 
   1321                     for (k = 0; k < n_mask_regions; k++) {
   1322                         DEBUGF("mask region %d  idx %d\n", k,
   1323                                clipped_mask_regions[k].block_idx);
   1324                         DEBUGRegionPrint(clipped_mask_regions[k].region);
   1325                         if (is_normal_mask_fbo) {
   1326                             glamor_set_pixmap_fbo_current(mask_pixmap_priv,
   1327                                                    clipped_mask_regions[k].
   1328                                                    block_idx);
   1329                             DEBUGF("mask fbo off %d %d \n",
   1330                                    __glamor_large(mask_pixmap_priv)->box.x1,
   1331                                    __glamor_large(mask_pixmap_priv)->box.y1);
   1332                             DEBUGF("start composite mask hasn't transform.\n");
   1333                             RegionTranslate(clipped_mask_regions[k].region,
   1334                                             x_dest - x_mask +
   1335                                             dest->pDrawable->x,
   1336                                             y_dest - y_mask +
   1337                                             dest->pDrawable->y);
   1338                             COMPOSITE_REGION(clipped_mask_regions[k].region);
   1339                         }
   1340                         else if (!is_normal_mask_fbo && !is_normal_source_fbo) {
   1341                             DEBUGF
   1342                                 ("start composite both mask and source have transform.\n");
   1343                             RegionTranslate(clipped_dest_regions[i].region,
   1344                                             dest->pDrawable->x,
   1345                                             dest->pDrawable->y);
   1346                             COMPOSITE_REGION(clipped_dest_regions[i].region);
   1347                         }
   1348                         else {
   1349                             DEBUGF
   1350                                 ("start composite only mask has transform.\n");
   1351                             RegionTranslate(clipped_source_regions[j].region,
   1352                                             x_dest - x_source +
   1353                                             dest->pDrawable->x,
   1354                                             y_dest - y_source +
   1355                                             dest->pDrawable->y);
   1356                             COMPOSITE_REGION(clipped_source_regions[j].region);
   1357                         }
   1358                         RegionDestroy(clipped_mask_regions[k].region);
   1359                     }
   1360                     free(clipped_mask_regions);
   1361                     if (null_mask)
   1362                         null_mask = 0;
   1363                     if (need_clean_mask_fbo) {
   1364                         assert(is_normal_mask_fbo == 0);
   1365                         glamor_destroy_fbo(glamor_priv, mask_pixmap_priv->fbo);
   1366                         mask_pixmap_priv->fbo = NULL;
   1367                         need_clean_mask_fbo = 0;
   1368                     }
   1369                 }
   1370                 else {
   1371                     if (is_normal_source_fbo) {
   1372                         RegionTranslate(clipped_source_regions[j].region,
   1373                                         -x_source + x_dest + dest->pDrawable->x,
   1374                                         -y_source + y_dest +
   1375                                         dest->pDrawable->y);
   1376                         COMPOSITE_REGION(clipped_source_regions[j].region);
   1377                     }
   1378                     else {
   1379                         /* Source has transform or repeatPad. dest regions is the right
   1380                          * region to do the composite. */
   1381                         RegionTranslate(clipped_dest_regions[i].region,
   1382                                         dest->pDrawable->x, dest->pDrawable->y);
   1383                         COMPOSITE_REGION(clipped_dest_regions[i].region);
   1384                     }
   1385                 }
   1386                 if (clipped_source_regions && clipped_source_regions[j].region)
   1387                     RegionDestroy(clipped_source_regions[j].region);
   1388             }
   1389             free(clipped_source_regions);
   1390             if (null_source)
   1391                 null_source = 0;
   1392             if (need_clean_source_fbo) {
   1393                 assert(is_normal_source_fbo == 0);
   1394                 glamor_destroy_fbo(glamor_priv, source_pixmap_priv->fbo);
   1395                 source_pixmap_priv->fbo = NULL;
   1396                 need_clean_source_fbo = 0;
   1397             }
   1398         }
   1399         else {
   1400             if (mask_pixmap_priv &&
   1401                 glamor_pixmap_priv_is_large(mask_pixmap_priv)) {
   1402                 if (!mask->transform && mask_repeat_type != RepeatPad) {
   1403                     RegionTranslate(clipped_dest_regions[i].region,
   1404                                     x_mask - x_dest, y_mask - y_dest);
   1405                     clipped_mask_regions =
   1406                         glamor_compute_clipped_regions(mask_pixmap,
   1407                                                        clipped_dest_regions[i].
   1408                                                        region, &n_mask_regions,
   1409                                                        mask_repeat_type, 0, 0);
   1410                     is_normal_mask_fbo = 1;
   1411                 }
   1412                 else {
   1413                     clipped_mask_regions =
   1414                         glamor_compute_transform_clipped_regions
   1415                         (mask_pixmap, mask->transform,
   1416                          clipped_dest_regions[i].region, &n_mask_regions,
   1417                          x_mask - x_dest, y_mask - y_dest, mask_repeat_type, 0,
   1418                          0);
   1419                     is_normal_mask_fbo = 0;
   1420                     if (n_mask_regions == 0) {
   1421                         /* Pad the out-of-box region to (0,0,0,0). */
   1422                         null_mask = 1;
   1423                         n_mask_regions = 1;
   1424                     }
   1425                     else
   1426                         _glamor_process_transformed_clipped_region
   1427                             (mask_pixmap, mask_pixmap_priv, mask_repeat_type,
   1428                              clipped_mask_regions, &n_mask_regions,
   1429                              &need_clean_mask_fbo);
   1430                 }
   1431 
   1432                 for (k = 0; k < n_mask_regions; k++) {
   1433                     DEBUGF("mask region %d  idx %d\n", k,
   1434                            clipped_mask_regions[k].block_idx);
   1435                     DEBUGRegionPrint(clipped_mask_regions[k].region);
   1436                     if (is_normal_mask_fbo) {
   1437                         glamor_set_pixmap_fbo_current(mask_pixmap_priv,
   1438                                                clipped_mask_regions[k].
   1439                                                block_idx);
   1440                         RegionTranslate(clipped_mask_regions[k].region,
   1441                                         x_dest - x_mask + dest->pDrawable->x,
   1442                                         y_dest - y_mask + dest->pDrawable->y);
   1443                         COMPOSITE_REGION(clipped_mask_regions[k].region);
   1444                     }
   1445                     else {
   1446                         RegionTranslate(clipped_dest_regions[i].region,
   1447                                         dest->pDrawable->x, dest->pDrawable->y);
   1448                         COMPOSITE_REGION(clipped_dest_regions[i].region);
   1449                     }
   1450                     RegionDestroy(clipped_mask_regions[k].region);
   1451                 }
   1452                 free(clipped_mask_regions);
   1453                 if (null_mask)
   1454                     null_mask = 0;
   1455                 if (need_clean_mask_fbo) {
   1456                     glamor_destroy_fbo(glamor_priv, mask_pixmap_priv->fbo);
   1457                     mask_pixmap_priv->fbo = NULL;
   1458                     need_clean_mask_fbo = 0;
   1459                 }
   1460             }
   1461             else {
   1462                 RegionTranslate(clipped_dest_regions[i].region,
   1463                                 dest->pDrawable->x, dest->pDrawable->y);
   1464                 COMPOSITE_REGION(clipped_dest_regions[i].region);
   1465             }
   1466         }
   1467         RegionDestroy(clipped_dest_regions[i].region);
   1468     }
   1469     free(clipped_dest_regions);
   1470     free(need_free_source_pixmap_priv);
   1471     free(need_free_mask_pixmap_priv);
   1472     ok = TRUE;
   1473     return ok;
   1474 }
   1475