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