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