aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/glamor/glamor_largepixmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/glamor/glamor_largepixmap.c')
-rw-r--r--xorg-server/glamor/glamor_largepixmap.c1324
1 files changed, 1324 insertions, 0 deletions
diff --git a/xorg-server/glamor/glamor_largepixmap.c b/xorg-server/glamor/glamor_largepixmap.c
new file mode 100644
index 000000000..91ee8f2df
--- /dev/null
+++ b/xorg-server/glamor/glamor_largepixmap.c
@@ -0,0 +1,1324 @@
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+
+/**
+ * Clip the boxes regards to each pixmap's block array.
+ *
+ * Should translate the region to relative coords to the pixmap,
+ * start at (0,0).
+ */
+#if 0
+//#define DEBUGF(str, ...) do {} while(0)
+#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
+//#define DEBUGRegionPrint(x) do {} while (0)
+#define DEBUGRegionPrint RegionPrint
+#endif
+
+static glamor_pixmap_clipped_regions *
+__glamor_compute_clipped_regions(int block_w,
+ int block_h,
+ int block_stride,
+ int x, int y,
+ int w, int h,
+ RegionPtr region,
+ int *n_region,
+ int reverse,
+ int upsidedown)
+{
+ glamor_pixmap_clipped_regions * clipped_regions;
+ BoxPtr extent;
+ int start_x, start_y, end_x, end_y;
+ int start_block_x, start_block_y;
+ int end_block_x, end_block_y;
+ int loop_start_block_x, loop_start_block_y;
+ int loop_end_block_x, loop_end_block_y;
+ int loop_block_stride;
+ int i, j, delta_i, delta_j;
+ RegionRec temp_region;
+ RegionPtr current_region;
+ int block_idx;
+ int k = 0;
+ int temp_block_idx;
+
+ extent = RegionExtents(region);
+ start_x = MAX(x, extent->x1);
+ start_y = MAX(y, extent->y1);
+ end_x = MIN(x + w, extent->x2);
+ end_y = MIN(y + h, extent->y2);
+
+ DEBUGF("start compute clipped regions:\n");
+ DEBUGF("block w %d h %d x %d y %d w %d h %d, block_stride %d \n",
+ block_w, block_h, x, y, w, h, block_stride);
+ DEBUGRegionPrint(region);
+
+ DEBUGF("start_x %d start_y %d end_x %d end_y %d \n", start_x, start_y, end_x, end_y);
+
+ if (start_x >= end_x || start_y >= end_y) {
+ *n_region = 0;
+ return NULL;
+ }
+
+ start_block_x = (start_x - x)/ block_w;
+ start_block_y = (start_y - y)/ block_h;
+ end_block_x = (end_x - x)/ block_w;
+ end_block_y = (end_y - y)/ block_h;
+
+ clipped_regions = calloc((end_block_x - start_block_x + 1)
+ * (end_block_y - start_block_y + 1),
+ sizeof(*clipped_regions));
+
+
+ DEBUGF("startx %d starty %d endx %d endy %d \n",
+ start_x, start_y, end_x, end_y);
+ DEBUGF("start_block_x %d end_block_x %d \n", start_block_x, end_block_x);
+ DEBUGF("start_block_y %d end_block_y %d \n", start_block_y, end_block_y);
+
+ if (!reverse) {
+ loop_start_block_x = start_block_x;
+ loop_end_block_x = end_block_x + 1;
+ delta_i = 1;
+ } else {
+ loop_start_block_x = end_block_x;
+ loop_end_block_x = start_block_x - 1;
+ delta_i = -1;
+ }
+
+ if (!upsidedown) {
+ loop_start_block_y = start_block_y;
+ loop_end_block_y = end_block_y + 1;
+ delta_j = 1;
+ } else {
+ loop_start_block_y = end_block_y;
+ loop_end_block_y = start_block_y - 1;
+ delta_j = -1;
+ }
+
+ loop_block_stride = delta_j * block_stride;
+ block_idx = (loop_start_block_y - delta_j) * block_stride;
+
+ for(j = loop_start_block_y; j != loop_end_block_y; j += delta_j)
+ {
+ block_idx += loop_block_stride;
+ temp_block_idx = block_idx + loop_start_block_x;
+ for(i = loop_start_block_x;
+ i != loop_end_block_x; i += delta_i, temp_block_idx += delta_i)
+ {
+ BoxRec temp_box;
+ temp_box.x1 = x + i * block_w;
+ temp_box.y1 = y + j * block_h;
+ temp_box.x2 = MIN(temp_box.x1 + block_w, end_x);
+ temp_box.y2 = MIN(temp_box.y1 + block_h, end_y);
+ RegionInitBoxes(&temp_region, &temp_box, 1);
+ DEBUGF("block idx %d \n",temp_block_idx);
+ DEBUGRegionPrint(&temp_region);
+ current_region = RegionCreate(NULL, 4);
+ RegionIntersect(current_region, &temp_region, region);
+ DEBUGF("i %d j %d region: \n",i ,j);
+ DEBUGRegionPrint(current_region);
+ if (RegionNumRects(current_region)) {
+ clipped_regions[k].region = current_region;
+ clipped_regions[k].block_idx = temp_block_idx;
+ k++;
+ } else
+ RegionDestroy(current_region);
+ RegionUninit(&temp_region);
+ }
+ }
+
+ *n_region = k;
+ return clipped_regions;
+}
+
+/**
+ * Do a two round clipping,
+ * first is to clip the region regard to current pixmap's
+ * block array. Then for each clipped region, do a inner
+ * block clipping. This is to make sure the final result
+ * will be shapped by inner_block_w and inner_block_h, and
+ * the final region also will not cross the pixmap's block
+ * boundary.
+ *
+ * This is mainly used by transformation support when do
+ * compositing.
+ */
+
+glamor_pixmap_clipped_regions *
+glamor_compute_clipped_regions_ext(glamor_pixmap_private *pixmap_priv,
+ RegionPtr region,
+ int *n_region,
+ int inner_block_w, int inner_block_h,
+ int reverse, int upsidedown)
+{
+ glamor_pixmap_clipped_regions * clipped_regions, *inner_regions, *result_regions;
+ int i, j, x, y, k, inner_n_regions;
+ int width, height;
+ glamor_pixmap_private_large_t *priv;
+ priv = &pixmap_priv->large;
+
+ DEBUGF("ext called \n");
+
+ if (pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ clipped_regions = calloc(1, sizeof(*clipped_regions));
+ if (clipped_regions == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ clipped_regions[0].region = RegionCreate(NULL, 1);
+ clipped_regions[0].block_idx = 0;
+ RegionCopy(clipped_regions[0].region, region);
+ *n_region = 1;
+ priv->block_w = priv->base.pixmap->drawable.width;
+ priv->block_h = priv->base.pixmap->drawable.height;
+ priv->box_array = &priv->box;
+ priv->box.x1 = priv->box.y1 = 0;
+ priv->box.x2 = priv->block_w;
+ priv->box.y2 = priv->block_h;
+ } else {
+ clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
+ priv->block_h,
+ priv->block_wcnt,
+ 0, 0,
+ priv->base.pixmap->drawable.width,
+ priv->base.pixmap->drawable.height,
+ region, n_region, reverse, upsidedown
+ );
+
+ if (clipped_regions == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ }
+ if (inner_block_w >= priv->block_w
+ && inner_block_h >= priv->block_h)
+ return clipped_regions;
+ result_regions = calloc(*n_region
+ * ((priv->block_w + inner_block_w - 1)/inner_block_w)
+ * ((priv->block_h + inner_block_h - 1)/ inner_block_h),
+ sizeof(*result_regions));
+ k = 0;
+ for(i = 0; i < *n_region; i++)
+ {
+ x = priv->box_array[clipped_regions[i].block_idx].x1;
+ y = priv->box_array[clipped_regions[i].block_idx].y1;
+ width = priv->box_array[clipped_regions[i].block_idx].x2 - x;
+ height = priv->box_array[clipped_regions[i].block_idx].y2 - y;
+ inner_regions = __glamor_compute_clipped_regions(inner_block_w,
+ inner_block_h,
+ 0, x, y,
+ width,
+ height,
+ clipped_regions[i].region,
+ &inner_n_regions, reverse, upsidedown);
+ for(j = 0; j < inner_n_regions; j++)
+ {
+ result_regions[k].region = inner_regions[j].region;
+ result_regions[k].block_idx = clipped_regions[i].block_idx;
+ k++;
+ }
+ free(inner_regions);
+ }
+ *n_region = k;
+ free(clipped_regions);
+ return result_regions;
+}
+
+/*
+ *
+ * For the repeat pad mode, we can simply convert the region and
+ * let the out-of-box region can cover the needed edge of the source/mask
+ * Then apply a normal clip we can get what we want.
+ */
+static RegionPtr
+_glamor_convert_pad_region(RegionPtr region, int w, int h)
+{
+ RegionPtr pad_region;
+ int nrect;
+ BoxPtr box;
+ int overlap;
+
+ nrect = RegionNumRects(region);
+ box = RegionRects(region);
+ pad_region = RegionCreate(NULL, 4);
+ if (pad_region == NULL)
+ return NULL;
+ while(nrect--) {
+ BoxRec pad_box;
+ RegionRec temp_region;
+ pad_box = *box;
+ if (pad_box.x1 < 0 && pad_box.x2 <= 0)
+ pad_box.x2 = 1;
+ else if (pad_box.x1 >= w && pad_box.x2 > w)
+ pad_box.x1 = w - 1;
+ if (pad_box.y1 < 0 && pad_box.y2 <=0)
+ pad_box.y2 = 1;
+ else if (pad_box.y1 >= h && pad_box.y2 > h)
+ pad_box.y1 = h - 1;
+ RegionInitBoxes(&temp_region, &pad_box, 1);
+ RegionAppend(pad_region, &temp_region);
+ RegionUninit(&temp_region);
+ box++;
+ }
+ RegionValidate(pad_region, &overlap);
+ return pad_region;
+}
+
+/*
+ * For one type of large pixmap, its one direction is not exceed the
+ * size limitation, and in another word, on one direction it has only
+ * one block.
+ *
+ * This case of reflect repeating, we can optimize it and avoid repeat
+ * clip on that direction. We can just enlarge the repeat box and can
+ * cover all the dest region on that direction. But latter, we need to
+ * fixup the clipped result to get a correct coords for the subsequent
+ * processing. This function is to do the coords correction.
+ *
+ * */
+static void
+_glamor_largepixmap_reflect_fixup(short *xy1, short *xy2, int wh)
+{
+ int odd1, odd2;
+ int c1, c2;
+
+ if (*xy2 - *xy1 > wh) {
+ *xy1 = 0;
+ *xy2 = wh;
+ return;
+ }
+ modulus(*xy1, wh, c1);
+ odd1 = ((*xy1 - c1) / wh) & 0x1;
+ modulus(*xy2, wh, c2);
+ odd2 = ((*xy2 - c2) / wh) & 0x1;
+
+ if (odd1 && odd2) {
+ *xy1 = wh - c2;
+ *xy2 = wh - c1;
+ } else if (odd1 && !odd2) {
+ *xy1 = 0;
+ *xy2 = MAX(c2, wh - c1);
+ } else if (!odd1 && odd2) {
+ *xy2 = wh;
+ *xy1 = MIN(c1, wh - c2);
+ } else {
+ *xy1 = c1;
+ *xy2 = c2;
+ }
+}
+
+/**
+ * Clip the boxes regards to each pixmap's block array.
+ *
+ * Should translate the region to relative coords to the pixmap,
+ * start at (0,0).
+ *
+ * @is_transform: if it is set, it has a transform matrix.
+ *
+ */
+static glamor_pixmap_clipped_regions *
+_glamor_compute_clipped_regions(glamor_pixmap_private *pixmap_priv,
+ RegionPtr region, int *n_region,
+ int repeat_type, int is_transform,
+ int reverse, int upsidedown)
+{
+ glamor_pixmap_clipped_regions * clipped_regions;
+ BoxPtr extent;
+ int i, j;
+ RegionPtr current_region;
+ int pixmap_width, pixmap_height;
+ int m;
+ BoxRec repeat_box;
+ RegionRec repeat_region;
+ int right_shift = 0;
+ int down_shift = 0;
+ int x_center_shift = 0, y_center_shift = 0;
+ glamor_pixmap_private_large_t *priv;
+ priv = &pixmap_priv->large;
+
+ DEBUGRegionPrint(region);
+ if (pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ clipped_regions = calloc(1, sizeof(*clipped_regions));
+ clipped_regions[0].region = RegionCreate(NULL, 1);
+ clipped_regions[0].block_idx = 0;
+ RegionCopy(clipped_regions[0].region, region);
+ *n_region = 1;
+ return clipped_regions;
+ }
+
+ pixmap_width = priv->base.pixmap->drawable.width;
+ pixmap_height = priv->base.pixmap->drawable.height;
+ if (repeat_type == 0 || repeat_type == RepeatPad) {
+ RegionPtr saved_region = NULL;
+ if (repeat_type == RepeatPad) {
+ saved_region = region;
+ region = _glamor_convert_pad_region(saved_region, pixmap_width, pixmap_height);
+ if (region == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ }
+ clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
+ priv->block_h,
+ priv->block_wcnt,
+ 0, 0,
+ priv->base.pixmap->drawable.width,
+ priv->base.pixmap->drawable.height,
+ region, n_region, reverse, upsidedown
+ );
+ if (saved_region)
+ RegionDestroy(region);
+ return clipped_regions;
+ }
+ extent = RegionExtents(region);
+
+ x_center_shift = extent->x1 / pixmap_width;
+ if (x_center_shift < 0)
+ x_center_shift--;
+ if (abs(x_center_shift) & 1)
+ x_center_shift++;
+ y_center_shift = extent->y1 / pixmap_height;
+ if (y_center_shift < 0)
+ y_center_shift--;
+ if (abs(y_center_shift) & 1)
+ y_center_shift++;
+
+ if (extent->x1 < 0)
+ right_shift = ((-extent->x1 + pixmap_width - 1) / pixmap_width );
+ if (extent->y1 < 0)
+ down_shift = ((-extent->y1 + pixmap_height - 1) / pixmap_height );
+
+ if (right_shift != 0 || down_shift != 0) {
+ if (repeat_type == RepeatReflect) {
+ right_shift = (right_shift + 1)&~1;
+ down_shift = (down_shift + 1)&~1;
+ }
+ RegionTranslate(region, right_shift * pixmap_width, down_shift * pixmap_height);
+ }
+
+ extent = RegionExtents(region);
+ /* Tile a large pixmap to another large pixmap.
+ * We can't use the target large pixmap as the
+ * loop variable, instead we need to loop for all
+ * the blocks in the tile pixmap.
+ *
+ * simulate repeat each single block to cover the
+ * target's blocks. Two special case:
+ * a block_wcnt == 1 or block_hcnt ==1, then we
+ * only need to loop one direction as the other
+ * direction is fully included in the first block.
+ *
+ * For the other cases, just need to start
+ * from a proper shiftx/shifty, and then increase
+ * y by tile_height each time to walk trhough the
+ * target block and then walk trhough the target
+ * at x direction by increate tile_width each time.
+ *
+ * This way, we can consolidate all the sub blocks
+ * of the target boxes into one tile source's block.
+ *
+ * */
+ m = 0;
+ clipped_regions = calloc(priv->block_wcnt * priv->block_hcnt,
+ sizeof(*clipped_regions));
+ if (clipped_regions == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ if (right_shift != 0 || down_shift != 0) {
+ DEBUGF("region to be repeated shifted \n");
+ DEBUGRegionPrint(region);
+ }
+ DEBUGF("repeat pixmap width %d height %d \n", pixmap_width, pixmap_height);
+ DEBUGF("extent x1 %d y1 %d x2 %d y2 %d \n", extent->x1, extent->y1, extent->x2, extent->y2);
+ for(j = 0; j < priv->block_hcnt; j++)
+ {
+ for(i = 0; i < priv->block_wcnt; i++)
+ {
+ int dx = pixmap_width;
+ int dy = pixmap_height;
+ int idx;
+ int shift_x;
+ int shift_y;
+ int saved_y1, saved_y2;
+ int x_idx = 0, y_idx = 0, saved_y_idx = 0;
+ RegionRec temp_region;
+ BoxRec reflect_repeat_box;
+ BoxPtr valid_repeat_box;
+
+ shift_x = (extent->x1 / pixmap_width) * pixmap_width;
+ shift_y = (extent->y1 / pixmap_height) * pixmap_height;
+ idx = j * priv->block_wcnt + i;
+ if (repeat_type == RepeatReflect) {
+ x_idx = (extent->x1 / pixmap_width);
+ y_idx = (extent->y1 / pixmap_height);
+ }
+
+ /* Construct a rect to clip the target region. */
+ repeat_box.x1 = shift_x + priv->box_array[idx].x1;
+ repeat_box.y1 = shift_y + priv->box_array[idx].y1;
+ if (priv->block_wcnt == 1) {
+ repeat_box.x2 = extent->x2;
+ dx = extent->x2 - repeat_box.x1;
+ } else
+ repeat_box.x2 = shift_x + priv->box_array[idx].x2;
+ if (priv->block_hcnt == 1) {
+ repeat_box.y2 = extent->y2;
+ dy = extent->y2 - repeat_box.y1;
+ } else
+ repeat_box.y2 = shift_y + priv->box_array[idx].y2;
+
+ current_region = RegionCreate(NULL, 4);
+ RegionInit(&temp_region, NULL, 4);
+ DEBUGF("init repeat box %d %d %d %d \n",
+ repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2);
+
+ if (repeat_type == RepeatNormal) {
+ saved_y1 = repeat_box.y1;
+ saved_y2 = repeat_box.y2;
+ for(; repeat_box.x1 < extent->x2;
+ repeat_box.x1 += dx, repeat_box.x2 += dx)
+ {
+ repeat_box.y1 = saved_y1;
+ repeat_box.y2 = saved_y2;
+ for( repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;
+ repeat_box.y1 < extent->y2;
+ repeat_box.y1 += dy, repeat_box.y2 += dy)
+ {
+
+ RegionInitBoxes(&repeat_region, &repeat_box, 1);
+ DEBUGF("Start to clip repeat region: \n");
+ DEBUGRegionPrint(&repeat_region);
+ RegionIntersect(&temp_region, &repeat_region, region);
+ DEBUGF("clip result:\n");
+ DEBUGRegionPrint(&temp_region);
+ RegionAppend(current_region, &temp_region);
+ RegionUninit(&repeat_region);
+ }
+ }
+ } else if (repeat_type == RepeatReflect) {
+ saved_y1 = repeat_box.y1;
+ saved_y2 = repeat_box.y2;
+ saved_y_idx = y_idx;
+ for(; ; repeat_box.x1 += dx, repeat_box.x2 += dx)
+ {
+ repeat_box.y1 = saved_y1;
+ repeat_box.y2 = saved_y2;
+ y_idx = saved_y_idx;
+ reflect_repeat_box.x1 = (x_idx & 1) ?
+ ((2 * x_idx + 1) * dx - repeat_box.x2) : repeat_box.x1;
+ reflect_repeat_box.x2 = (x_idx & 1) ?
+ ((2 * x_idx + 1) * dx - repeat_box.x1) : repeat_box.x2;
+ valid_repeat_box = &reflect_repeat_box;
+
+ if (valid_repeat_box->x1 >= extent->x2)
+ break;
+ for( repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;
+ ;
+ repeat_box.y1 += dy, repeat_box.y2 += dy)
+ {
+
+ DEBUGF("x_idx %d y_idx %d dx %d dy %d\n", x_idx, y_idx, dx, dy);
+ DEBUGF("repeat box %d %d %d %d \n",
+ repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2);
+
+ if (priv->block_hcnt > 1) {
+ reflect_repeat_box.y1 = (y_idx & 1) ?
+ ((2 * y_idx + 1) * dy - repeat_box.y2) : repeat_box.y1;
+ reflect_repeat_box.y2 = (y_idx & 1) ?
+ ((2 * y_idx + 1) * dy - repeat_box.y1) : repeat_box.y2;
+ } else {
+ reflect_repeat_box.y1 = repeat_box.y1;
+ reflect_repeat_box.y2 = repeat_box.y2;
+ }
+
+ DEBUGF("valid_repeat_box x1 %d y1 %d \n",
+ valid_repeat_box->x1, valid_repeat_box->y1);
+ if (valid_repeat_box->y1 >= extent->y2)
+ break;
+ RegionInitBoxes(&repeat_region, valid_repeat_box, 1);
+ DEBUGF("start to clip repeat[reflect] region: \n");
+ DEBUGRegionPrint(&repeat_region);
+ RegionIntersect(&temp_region, &repeat_region, region);
+ DEBUGF("result:\n");
+ DEBUGRegionPrint(&temp_region);
+ if (is_transform && RegionNumRects(&temp_region)) {
+ BoxRec temp_box;
+ BoxPtr temp_extent;
+ temp_extent = RegionExtents(&temp_region);
+ if (priv->block_wcnt > 1) {
+ if (x_idx & 1) {
+ temp_box.x1 = ((2 * x_idx + 1)*dx - temp_extent->x2);
+ temp_box.x2 = ((2 * x_idx + 1)*dx - temp_extent->x1);
+ } else {
+ temp_box.x1 = temp_extent->x1;
+ temp_box.x2 = temp_extent->x2;
+ }
+ modulus(temp_box.x1, pixmap_width, temp_box.x1);
+ modulus(temp_box.x2, pixmap_width, temp_box.x2);
+ if (temp_box.x2 == 0) temp_box.x2 = pixmap_width;
+ } else {
+ temp_box.x1 = temp_extent->x1;
+ temp_box.x2 = temp_extent->x2;
+ _glamor_largepixmap_reflect_fixup(&temp_box.x1, &temp_box.x2, pixmap_width);
+ }
+
+ if (priv->block_hcnt > 1) {
+ if (y_idx & 1) {
+ temp_box.y1 = ((2 * y_idx + 1)*dy - temp_extent->y2);
+ temp_box.y2 = ((2 * y_idx + 1)*dy - temp_extent->y1);
+ } else {
+ temp_box.y1 = temp_extent->y1;
+ temp_box.y2 = temp_extent->y2;
+ }
+
+ modulus(temp_box.y1, pixmap_height, temp_box.y1);
+ modulus(temp_box.y2, pixmap_height, temp_box.y2);
+ if (temp_box.y2 == 0) temp_box.y2 = pixmap_height;
+ } else {
+ temp_box.y1 = temp_extent->y1;
+ temp_box.y2 = temp_extent->y2;
+ _glamor_largepixmap_reflect_fixup(&temp_box.y1, &temp_box.y2, pixmap_height);
+ }
+
+ RegionInitBoxes(&temp_region, &temp_box, 1);
+ RegionTranslate(&temp_region, x_center_shift * pixmap_width, y_center_shift * pixmap_height);
+ DEBUGF("for transform result:\n");
+ DEBUGRegionPrint(&temp_region);
+ }
+ RegionAppend(current_region, &temp_region);
+ RegionUninit(&repeat_region);
+ y_idx++;
+ }
+ x_idx++;
+ }
+ }
+ DEBUGF("dx %d dy %d \n", dx, dy);
+
+ if (RegionNumRects(current_region)) {
+
+ if ((right_shift != 0 || down_shift != 0) && !(is_transform && repeat_type == RepeatReflect))
+ RegionTranslate(current_region,
+ -right_shift * pixmap_width,
+ -down_shift * pixmap_height);
+ clipped_regions[m].region = current_region;
+ clipped_regions[m].block_idx = idx;
+ m++;
+ } else
+ RegionDestroy(current_region);
+ RegionUninit(&temp_region);
+ }
+ }
+
+ if (right_shift != 0 || down_shift != 0)
+ RegionTranslate(region, -right_shift * pixmap_width, -down_shift * pixmap_height);
+ *n_region = m;
+
+ return clipped_regions;
+}
+
+glamor_pixmap_clipped_regions *
+glamor_compute_clipped_regions(glamor_pixmap_private *priv, RegionPtr region,
+ int *n_region, int repeat_type,
+ int reverse, int upsidedown)
+{
+ return _glamor_compute_clipped_regions(priv, region, n_region, repeat_type, 0, reverse, upsidedown);
+}
+
+/* XXX overflow still exist. maybe we need to change to use region32.
+ * by default. Or just use region32 for repeat cases?
+ **/
+glamor_pixmap_clipped_regions *
+glamor_compute_transform_clipped_regions(glamor_pixmap_private *priv, struct pixman_transform *transform,
+ RegionPtr region, int *n_region, int dx, int dy, int repeat_type,
+ int reverse, int upsidedown)
+{
+ BoxPtr temp_extent;
+ struct pixman_box32 temp_box;
+ struct pixman_box16 short_box;
+ RegionPtr temp_region;
+ glamor_pixmap_clipped_regions *ret;
+
+ temp_region = RegionCreate(NULL, 4);
+ temp_extent = RegionExtents(region);
+ DEBUGF("dest region \n");
+ DEBUGRegionPrint(region);
+ /* dx/dy may exceed MAX SHORT. we have to use
+ * a box32 to represent it.*/
+ temp_box.x1 = temp_extent->x1 + dx;
+ temp_box.x2 = temp_extent->x2 + dx;
+ temp_box.y1 = temp_extent->y1 + dy;
+ temp_box.y2 = temp_extent->y2 + dy;
+
+ DEBUGF("source box %d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2, temp_box.y2);
+ if (transform)
+ glamor_get_transform_extent_from_box(&temp_box, transform);
+ if (repeat_type == RepeatNone) {
+ if (temp_box.x1 < 0) temp_box.x1 = 0;
+ if (temp_box.y1 < 0) temp_box.y1 = 0;
+ temp_box.x2 = MIN(temp_box.x2, priv->base.pixmap->drawable.width);
+ temp_box.y2 = MIN(temp_box.y2, priv->base.pixmap->drawable.height);
+ }
+ /* Now copy back the box32 to a box16 box. */
+ short_box.x1 = temp_box.x1;
+ short_box.y1 = temp_box.y1;
+ short_box.x2 = temp_box.x2;
+ short_box.y2 = temp_box.y2;
+ RegionInitBoxes(temp_region, &short_box, 1);
+ DEBUGF("copy to temp source region \n");
+ DEBUGRegionPrint(temp_region);
+ ret = _glamor_compute_clipped_regions(priv,
+ temp_region,
+ n_region,
+ repeat_type,
+ 1, reverse,
+ upsidedown);
+ DEBUGF("n_regions = %d \n", *n_region);
+ RegionDestroy(temp_region);
+
+ return ret;
+}
+/*
+ * As transform and repeatpad mode.
+ * We may get a clipped result which in multipe regions.
+ * It's not easy to do a 2nd round clipping just as we do
+ * without transform/repeatPad. As it's not easy to reverse
+ * the 2nd round clipping result with a transform/repeatPad mode,
+ * or even impossible for some transformation.
+ *
+ * So we have to merge the fragmental region into one region
+ * if the clipped result cross the region boundary.
+ */
+static void
+glamor_merge_clipped_regions(glamor_pixmap_private *pixmap_priv, int repeat_type,
+ glamor_pixmap_clipped_regions *clipped_regions,
+ int *n_regions, int *need_clean_fbo)
+{
+ BoxPtr temp_extent;
+ BoxRec temp_box, copy_box;
+ RegionPtr temp_region;
+ glamor_pixmap_private *temp_priv;
+ PixmapPtr temp_pixmap;
+ int overlap;
+ int i;
+ int pixmap_width, pixmap_height;
+ glamor_pixmap_private_large_t *priv;
+
+ priv = &pixmap_priv->large;
+ pixmap_width = priv->base.pixmap->drawable.width;
+ pixmap_height = priv->base.pixmap->drawable.height;
+
+ temp_region = RegionCreate(NULL, 4);
+ for(i = 0; i < *n_regions; i++)
+ {
+ DEBUGF("Region %d:\n", i);
+ DEBUGRegionPrint(clipped_regions[i].region);
+ RegionAppend(temp_region, clipped_regions[i].region);
+ }
+
+ RegionValidate(temp_region, &overlap);
+ DEBUGF("temp region: \n");
+ DEBUGRegionPrint(temp_region);
+ temp_extent = RegionExtents(temp_region);
+
+ temp_box = *temp_extent;
+
+ DEBUGF("need copy region: \n");
+ DEBUGF("%d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2, temp_box.y2);
+ temp_pixmap = glamor_create_pixmap(priv->base.pixmap->drawable.pScreen,
+ temp_box.x2 - temp_box.x1,
+ temp_box.y2 - temp_box.y1,
+ priv->base.pixmap->drawable.depth,
+ GLAMOR_CREATE_PIXMAP_FIXUP);
+ if (temp_pixmap == NULL) {
+ assert(0);
+ return;
+ }
+
+ temp_priv = glamor_get_pixmap_private(temp_pixmap);
+ assert(temp_priv->type != GLAMOR_TEXTURE_LARGE);
+
+ priv->box = temp_box;
+ if (temp_extent->x1 >= 0 && temp_extent->x2 <= pixmap_width
+ && temp_extent->y1 >= 0 && temp_extent->y2 <= pixmap_height) {
+ int dx, dy;
+ copy_box.x1 = 0;
+ copy_box.y1 = 0;
+ copy_box.x2 = temp_extent->x2 - temp_extent->x1;
+ copy_box.y2 = temp_extent->y2 - temp_extent->y1;
+ dx = temp_extent->x1;
+ dy = temp_extent->y1;
+ glamor_copy_n_to_n(&priv->base.pixmap->drawable,
+ &temp_pixmap->drawable,
+ NULL, &copy_box, 1, dx,
+ dy, 0, 0, 0, NULL);
+// glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
+// temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff00);
+ } else {
+ for (i = 0; i < *n_regions; i++)
+ {
+ BoxPtr box;
+ int nbox;
+ box = REGION_RECTS(clipped_regions[i].region);
+ nbox = REGION_NUM_RECTS(clipped_regions[i].region);
+ while(nbox--) {
+ int dx, dy, c, d;
+ DEBUGF("box x1 %d y1 %d x2 %d y2 %d \n",
+ box->x1, box->y1, box->x2, box->y2);
+ modulus(box->x1, pixmap_width, c);
+ dx = c - (box->x1 - temp_box.x1);
+ copy_box.x1 = box->x1 - temp_box.x1;
+ copy_box.x2 = box->x2 - temp_box.x1;
+
+ modulus(box->y1, pixmap_height, d);
+ dy = d - (box->y1 - temp_box.y1);
+ copy_box.y1 = box->y1 - temp_box.y1;
+ copy_box.y2 = box->y2 - temp_box.y1;
+
+ DEBUGF("copying box %d %d %d %d, dx %d dy %d\n",
+ copy_box.x1, copy_box.y1, copy_box.x2,
+ copy_box.y2, dx, dy);
+
+ glamor_copy_n_to_n(&priv->base.pixmap->drawable,
+ &temp_pixmap->drawable,
+ NULL, &copy_box, 1, dx,
+ dy, 0, 0, 0, NULL);
+ box++;
+ }
+ }
+ //glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
+ // temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff);
+ }
+ /* The first region will be released at caller side. */
+ for(i = 1; i < *n_regions; i++)
+ RegionDestroy(clipped_regions[i].region);
+ RegionDestroy(temp_region);
+ priv->box = temp_box;
+ priv->base.fbo = glamor_pixmap_detach_fbo(temp_priv);
+ DEBUGF("priv box x1 %d y1 %d x2 %d y2 %d \n",
+ priv->box.x1, priv->box.y1, priv->box.x2, priv->box.y2);
+ glamor_destroy_pixmap(temp_pixmap);
+ *need_clean_fbo = 1;
+ *n_regions = 1;
+}
+
+
+
+/**
+ * Given an expected transformed block width and block height,
+ *
+ * This function calculate a new block width and height which
+ * guarantee the transform result will not exceed the given
+ * block width and height.
+ *
+ * For large block width and height (> 2048), we choose a
+ * smaller new width and height and to reduce the cross region
+ * boundary and can avoid some overhead.
+ *
+ **/
+Bool
+glamor_get_transform_block_size(struct pixman_transform *transform,
+ int block_w, int block_h,
+ int *transformed_block_w,
+ int *transformed_block_h)
+{
+ double a,b,c,d,e,f,g,h;
+ double scale;
+ int width, height;
+ a = pixman_fixed_to_double(transform->matrix[0][0]);
+ b = pixman_fixed_to_double(transform->matrix[0][1]);
+ c = pixman_fixed_to_double(transform->matrix[1][0]);
+ d = pixman_fixed_to_double(transform->matrix[1][1]);
+ scale = pixman_fixed_to_double(transform->matrix[2][2]);
+ if (block_w > 2048) {
+ /* For large block size, we shrink it to smaller box,
+ * thus latter we may get less cross boundary regions and
+ * thus can avoid some extra copy.
+ *
+ **/
+ width = block_w / 4;
+ height = block_h / 4;
+ } else {
+ width = block_w - 2;
+ height = block_h - 2;
+ }
+ e = a + b;
+ f = c + d;
+
+ g = a - b;
+ h = c - d;
+
+ e = MIN(block_w, floor(width * scale) / MAX(fabs(e), fabs(g)));
+ f = MIN(block_h, floor(height * scale) / MAX(fabs(f), fabs(h)));
+ *transformed_block_w = MIN(e, f) - 1;
+ *transformed_block_h = *transformed_block_w;
+ if (*transformed_block_w <= 0 || *transformed_block_h <= 0)
+ return FALSE;
+ DEBUGF("original block_w/h %d %d, fixed %d %d \n", block_w, block_h,
+ *transformed_block_w, *transformed_block_h);
+ return TRUE;
+}
+
+#define VECTOR_FROM_POINT(p, x, y) \
+ p.v[0] = x; \
+ p.v[1] = y; \
+ p.v[2] = 1.0;
+void
+glamor_get_transform_extent_from_box(struct pixman_box32 *box,
+ struct pixman_transform *transform)
+{
+ struct pixman_f_vector p0, p1, p2, p3;
+ float min_x, min_y, max_x, max_y;
+
+ struct pixman_f_transform ftransform;
+
+ VECTOR_FROM_POINT(p0, box->x1, box->y1)
+ VECTOR_FROM_POINT(p1, box->x2, box->y1)
+ VECTOR_FROM_POINT(p2, box->x2, box->y2)
+ VECTOR_FROM_POINT(p3, box->x1, box->y2)
+
+ pixman_f_transform_from_pixman_transform(&ftransform, transform);
+ pixman_f_transform_point(&ftransform, &p0);
+ pixman_f_transform_point(&ftransform, &p1);
+ pixman_f_transform_point(&ftransform, &p2);
+ pixman_f_transform_point(&ftransform, &p3);
+
+ min_x = MIN(p0.v[0], p1.v[0]);
+ min_x = MIN(min_x, p2.v[0]);
+ min_x = MIN(min_x, p3.v[0]);
+
+ min_y = MIN(p0.v[1], p1.v[1]);
+ min_y = MIN(min_y, p2.v[1]);
+ min_y = MIN(min_y, p3.v[1]);
+
+ max_x = MAX(p0.v[0], p1.v[0]);
+ max_x = MAX(max_x, p2.v[0]);
+ max_x = MAX(max_x, p3.v[0]);
+
+ max_y = MAX(p0.v[1], p1.v[1]);
+ max_y = MAX(max_y, p2.v[1]);
+ max_y = MAX(max_y, p3.v[1]);
+ box->x1 = floor(min_x) - 1;
+ box->y1 = floor(min_y) - 1;
+ box->x2 = ceil(max_x) + 1;
+ box->y2 = ceil(max_y) + 1;
+}
+
+static void
+_glamor_process_transformed_clipped_region(glamor_pixmap_private *priv,
+ int repeat_type,
+ glamor_pixmap_clipped_regions *clipped_regions,
+ int *n_regions, int *need_clean_fbo)
+{
+ int shift_x, shift_y;
+ if (*n_regions != 1) {
+ /* Merge all source regions into one region. */
+ glamor_merge_clipped_regions(priv, repeat_type,
+ clipped_regions, n_regions,
+ need_clean_fbo);
+ } else {
+ SET_PIXMAP_FBO_CURRENT(priv,
+ clipped_regions[0].block_idx);
+ if (repeat_type == RepeatReflect || repeat_type == RepeatNormal) {
+ /* The required source areas are in one region,
+ * we need to shift the corresponding box's coords to proper position,
+ * thus we can calculate the relative coords correctly.*/
+ BoxPtr temp_box;
+ int rem;
+ temp_box = RegionExtents(clipped_regions[0].region);
+ modulus(temp_box->x1, priv->base.pixmap->drawable.width, rem);
+ shift_x = (temp_box->x1 - rem) / priv->base.pixmap->drawable.width;
+ modulus(temp_box->y1, priv->base.pixmap->drawable.height, rem);
+ shift_y = (temp_box->y1 - rem) / priv->base.pixmap->drawable.height;
+
+ if (shift_x != 0) {
+ priv->large.box.x1 += shift_x * priv->base.pixmap->drawable.width;
+ priv->large.box.x2 += shift_x * priv->base.pixmap->drawable.width;
+ }
+ if (shift_y != 0) {
+ priv->large.box.y1 += shift_y * priv->base.pixmap->drawable.height;
+ priv->large.box.y2 += shift_y * priv->base.pixmap->drawable.height;
+ }
+ }
+ }
+}
+
+
+Bool
+glamor_composite_largepixmap_region(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private * source_pixmap_priv,
+ glamor_pixmap_private * mask_pixmap_priv,
+ glamor_pixmap_private * dest_pixmap_priv,
+ RegionPtr region, Bool force_clip,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_pixmap_clipped_regions *clipped_dest_regions;
+ glamor_pixmap_clipped_regions *clipped_source_regions;
+ glamor_pixmap_clipped_regions *clipped_mask_regions;
+ int n_dest_regions;
+ int n_mask_regions;
+ int n_source_regions;
+ int i,j,k;
+ int need_clean_source_fbo = 0;
+ int need_clean_mask_fbo = 0;
+ int is_normal_source_fbo = 0;
+ int is_normal_mask_fbo = 0;
+ int fixed_block_width, fixed_block_height;
+ int null_source, null_mask;
+ glamor_pixmap_private * need_free_source_pixmap_priv = NULL;
+ glamor_pixmap_private * need_free_mask_pixmap_priv = NULL;
+ int source_repeat_type = 0, mask_repeat_type = 0;
+ int ok = TRUE;
+
+ if (source->repeat)
+ source_repeat_type = source->repeatType;
+ else
+ source_repeat_type = RepeatNone;
+
+ if (mask && mask->repeat)
+ mask_repeat_type = mask->repeatType;
+ else
+ mask_repeat_type = RepeatNone;
+
+ glamor_priv = dest_pixmap_priv->base.glamor_priv;
+ fixed_block_width = glamor_priv->max_fbo_size;
+ fixed_block_height = glamor_priv->max_fbo_size;
+ /* If we got an totally out-of-box region for a source or mask
+ * region without repeat, we need to set it as null_source and
+ * give it a solid color (0,0,0,0). */
+ null_source = 0;
+ null_mask = 0;
+ RegionTranslate(region, -dest->pDrawable->x,
+ -dest->pDrawable->y);
+
+ /* need to transform the dest region to the correct sourcei/mask region.
+ * it's a little complex, as one single edge of the
+ * target region may be transformed to cross a block boundary of the
+ * source or mask. Then it's impossible to handle it as usual way.
+ * We may have to split the original dest region to smaller region, and
+ * make sure each region's transformed region can fit into one texture,
+ * and then continue this loop again, and each time when a transformed region
+ * cross the bound, we need to copy it to a single pixmap and do the composition
+ * with the new pixmap. If the transformed region doesn't cross a source/mask's
+ * boundary then we don't need to copy.
+ *
+ */
+ if (source_pixmap_priv
+ && source->transform
+ && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ int source_transformed_block_width, source_transformed_block_height;
+ if (!glamor_get_transform_block_size(source->transform,
+ source_pixmap_priv->large.block_w,
+ source_pixmap_priv->large.block_h,
+ &source_transformed_block_width,
+ &source_transformed_block_height)) {
+ DEBUGF("source block size less than 1, fallback.\n");
+ RegionTranslate(region, dest->pDrawable->x,
+ dest->pDrawable->y);
+ return FALSE;
+ }
+ fixed_block_width = min(fixed_block_width , source_transformed_block_width);
+ fixed_block_height = min(fixed_block_height , source_transformed_block_height);
+ DEBUGF("new source block size %d x %d \n", fixed_block_width, fixed_block_height);
+ }
+
+ if (mask_pixmap_priv
+ && mask->transform
+ && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ int mask_transformed_block_width, mask_transformed_block_height;
+ if (!glamor_get_transform_block_size(mask->transform,
+ mask_pixmap_priv->large.block_w,
+ mask_pixmap_priv->large.block_h,
+ &mask_transformed_block_width,
+ &mask_transformed_block_height)) {
+ DEBUGF("mask block size less than 1, fallback.\n");
+ RegionTranslate(region, dest->pDrawable->x,
+ dest->pDrawable->y);
+ return FALSE;
+ }
+ fixed_block_width = min(fixed_block_width , mask_transformed_block_width);
+ fixed_block_height = min(fixed_block_height , mask_transformed_block_height);
+ DEBUGF("new mask block size %d x %d \n", fixed_block_width, fixed_block_height);
+ }
+
+ /*compute the correct block width and height whose transformed source/mask
+ *region can fit into one texture.*/
+ if (force_clip || fixed_block_width < glamor_priv->max_fbo_size
+ || fixed_block_height < glamor_priv->max_fbo_size)
+ clipped_dest_regions = glamor_compute_clipped_regions_ext(dest_pixmap_priv,
+ region,
+ &n_dest_regions,
+ fixed_block_width,
+ fixed_block_height,
+ 0, 0);
+ else
+ clipped_dest_regions = glamor_compute_clipped_regions(dest_pixmap_priv,
+ region,
+ &n_dest_regions,
+ 0, 0, 0);
+ DEBUGF("dest clipped result %d region: \n", n_dest_regions);
+ if (source_pixmap_priv
+ && (source_pixmap_priv == dest_pixmap_priv || source_pixmap_priv == mask_pixmap_priv)
+ && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ /* XXX self-copy...*/
+ need_free_source_pixmap_priv = source_pixmap_priv;
+ source_pixmap_priv = malloc(sizeof(*source_pixmap_priv));
+ *source_pixmap_priv = *need_free_source_pixmap_priv;
+ need_free_source_pixmap_priv = source_pixmap_priv;
+ }
+ assert(mask_pixmap_priv != dest_pixmap_priv);
+
+ for(i = 0; i < n_dest_regions; i++)
+ {
+ DEBUGF("dest region %d idx %d\n", i, clipped_dest_regions[i].block_idx);
+ DEBUGRegionPrint(clipped_dest_regions[i].region);
+ SET_PIXMAP_FBO_CURRENT(dest_pixmap_priv, clipped_dest_regions[i].block_idx);
+ if ( source_pixmap_priv && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (!source->transform && source_repeat_type != RepeatPad) {
+ RegionTranslate(clipped_dest_regions[i].region,
+ x_source - x_dest,
+ y_source - y_dest);
+ clipped_source_regions = glamor_compute_clipped_regions(source_pixmap_priv,
+ clipped_dest_regions[i].region,
+ &n_source_regions, source_repeat_type,
+ 0, 0);
+ is_normal_source_fbo = 1;
+ }
+ else {
+ clipped_source_regions = glamor_compute_transform_clipped_regions(source_pixmap_priv,
+ source->transform,
+ clipped_dest_regions[i].region,
+ &n_source_regions,
+ x_source - x_dest, y_source - y_dest,
+ source_repeat_type, 0, 0);
+ is_normal_source_fbo = 0;
+ if (n_source_regions == 0) {
+ /* Pad the out-of-box region to (0,0,0,0). */
+ null_source = 1;
+ n_source_regions = 1;
+ } else
+ _glamor_process_transformed_clipped_region(source_pixmap_priv,
+ source_repeat_type, clipped_source_regions, &n_source_regions,
+ &need_clean_source_fbo);
+ }
+ DEBUGF("source clipped result %d region: \n", n_source_regions);
+ for(j = 0; j < n_source_regions; j++)
+ {
+ if (is_normal_source_fbo)
+ SET_PIXMAP_FBO_CURRENT(source_pixmap_priv,
+ clipped_source_regions[j].block_idx);
+
+ if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (is_normal_mask_fbo && is_normal_source_fbo) {
+ /* both mask and source are normal fbo box without transform or repeatpad.
+ * The region is clipped against source and then we clip it against mask here.*/
+ DEBUGF("source region %d idx %d\n", j, clipped_source_regions[j].block_idx);
+ DEBUGRegionPrint(clipped_source_regions[j].region);
+ RegionTranslate(clipped_source_regions[j].region,
+ - x_source + x_mask,
+ - y_source + y_mask);
+ clipped_mask_regions = glamor_compute_clipped_regions(mask_pixmap_priv,
+ clipped_source_regions[j].region,
+ &n_mask_regions, mask_repeat_type,
+ 0, 0);
+ is_normal_mask_fbo = 1;
+ } else if (is_normal_mask_fbo && !is_normal_source_fbo) {
+ assert(n_source_regions == 1);
+ /* The source fbo is not a normal fbo box, it has transform or repeatpad.
+ * the valid clip region should be the clip dest region rather than the
+ * clip source region.*/
+ RegionTranslate(clipped_dest_regions[i].region,
+ - x_dest + x_mask,
+ - y_dest + y_mask);
+ clipped_mask_regions = glamor_compute_clipped_regions(mask_pixmap_priv,
+ clipped_dest_regions[i].region,
+ &n_mask_regions, mask_repeat_type,
+ 0, 0);
+ is_normal_mask_fbo = 1;
+ } else {
+ /* This mask region has transform or repeatpad, we need clip it agains the previous
+ * valid region rather than the mask region. */
+ if (!is_normal_source_fbo)
+ clipped_mask_regions = glamor_compute_transform_clipped_regions(mask_pixmap_priv,
+ mask->transform,
+ clipped_dest_regions[i].region,
+ &n_mask_regions,
+ x_mask - x_dest,
+ y_mask - y_dest,
+ mask_repeat_type, 0, 0);
+ else
+ clipped_mask_regions = glamor_compute_transform_clipped_regions(mask_pixmap_priv,
+ mask->transform,
+ clipped_source_regions[j].region,
+ &n_mask_regions,
+ x_mask - x_source, y_mask - y_source,
+ mask_repeat_type, 0, 0);
+ is_normal_mask_fbo = 0;
+ if (n_mask_regions == 0) {
+ /* Pad the out-of-box region to (0,0,0,0). */
+ null_mask = 1;
+ n_mask_regions = 1;
+ } else
+ _glamor_process_transformed_clipped_region(mask_pixmap_priv,
+ mask_repeat_type, clipped_mask_regions, &n_mask_regions,
+ &need_clean_mask_fbo);
+ }
+ DEBUGF("mask clipped result %d region: \n", n_mask_regions);
+
+#define COMPOSITE_REGION(region) do { \
+ if (!glamor_composite_clipped_region(op, \
+ null_source ? NULL : source, \
+ null_mask ? NULL : mask, dest, \
+ null_source ? NULL : source_pixmap_priv, \
+ null_mask ? NULL : mask_pixmap_priv, \
+ dest_pixmap_priv, region, \
+ x_source, y_source, x_mask, y_mask, \
+ x_dest, y_dest)) { \
+ assert(0); \
+ } \
+ } while(0)
+
+ for(k = 0; k < n_mask_regions; k++)
+ {
+ DEBUGF("mask region %d idx %d\n", k, clipped_mask_regions[k].block_idx);
+ DEBUGRegionPrint(clipped_mask_regions[k].region);
+ if (is_normal_mask_fbo) {
+ SET_PIXMAP_FBO_CURRENT(mask_pixmap_priv,
+ clipped_mask_regions[k].block_idx);
+ DEBUGF("mask fbo off %d %d \n",
+ mask_pixmap_priv->large.box.x1,
+ mask_pixmap_priv->large.box.y1);
+ DEBUGF("start composite mask hasn't transform.\n");
+ RegionTranslate(clipped_mask_regions[k].region,
+ x_dest - x_mask + dest->pDrawable->x,
+ y_dest - y_mask + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_mask_regions[k].region);
+ } else if (!is_normal_mask_fbo && !is_normal_source_fbo) {
+ DEBUGF("start composite both mask and source have transform.\n");
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ } else {
+ DEBUGF("start composite only mask has transform.\n");
+ RegionTranslate(clipped_source_regions[j].region,
+ x_dest - x_source + dest->pDrawable->x,
+ y_dest - y_source + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_source_regions[j].region);
+ }
+ RegionDestroy(clipped_mask_regions[k].region);
+ }
+ free(clipped_mask_regions);
+ if (null_mask) null_mask = 0;
+ if (need_clean_mask_fbo) {
+ assert(is_normal_mask_fbo == 0);
+ glamor_destroy_fbo(mask_pixmap_priv->base.fbo);
+ mask_pixmap_priv->base.fbo = NULL;
+ need_clean_mask_fbo = 0;
+ }
+ } else {
+ if (is_normal_source_fbo) {
+ RegionTranslate(clipped_source_regions[j].region,
+ -x_source + x_dest + dest->pDrawable->x,
+ -y_source + y_dest + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_source_regions[j].region);
+ } else {
+ /* Source has transform or repeatPad. dest regions is the right
+ * region to do the composite. */
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ }
+ }
+ if (clipped_source_regions && clipped_source_regions[j].region)
+ RegionDestroy(clipped_source_regions[j].region);
+ }
+ free(clipped_source_regions);
+ if (null_source) null_source = 0;
+ if (need_clean_source_fbo) {
+ assert(is_normal_source_fbo == 0);
+ glamor_destroy_fbo(source_pixmap_priv->base.fbo);
+ source_pixmap_priv->base.fbo = NULL;
+ need_clean_source_fbo = 0;
+ }
+ }
+ else {
+ if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (!mask->transform && mask_repeat_type != RepeatPad) {
+ RegionTranslate(clipped_dest_regions[i].region,
+ x_mask - x_dest,
+ y_mask - y_dest);
+ clipped_mask_regions = glamor_compute_clipped_regions(mask_pixmap_priv,
+ clipped_dest_regions[i].region,
+ &n_mask_regions, mask_repeat_type, 0, 0);
+ is_normal_mask_fbo = 1;
+ }
+ else {
+ clipped_mask_regions = glamor_compute_transform_clipped_regions(mask_pixmap_priv,
+ mask->transform,
+ clipped_dest_regions[i].region,
+ &n_mask_regions,
+ x_mask - x_dest, y_mask - y_dest,
+ mask_repeat_type, 0, 0);
+ is_normal_mask_fbo = 0;
+ if (n_mask_regions == 0) {
+ /* Pad the out-of-box region to (0,0,0,0). */
+ null_mask = 1;
+ n_mask_regions = 1;
+ } else
+ _glamor_process_transformed_clipped_region(mask_pixmap_priv,
+ mask_repeat_type, clipped_mask_regions, &n_mask_regions,
+ &need_clean_mask_fbo);
+ }
+
+ for(k = 0; k < n_mask_regions; k++)
+ {
+ DEBUGF("mask region %d idx %d\n", k, clipped_mask_regions[k].block_idx);
+ DEBUGRegionPrint(clipped_mask_regions[k].region);
+ if (is_normal_mask_fbo) {
+ SET_PIXMAP_FBO_CURRENT(mask_pixmap_priv,
+ clipped_mask_regions[k].block_idx);
+ RegionTranslate(clipped_mask_regions[k].region,
+ x_dest - x_mask + dest->pDrawable->x,
+ y_dest - y_mask + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_mask_regions[k].region);
+ } else {
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ }
+ RegionDestroy(clipped_mask_regions[k].region);
+ }
+ free(clipped_mask_regions);
+ if (null_mask) null_mask = 0;
+ if (need_clean_mask_fbo) {
+ glamor_destroy_fbo(mask_pixmap_priv->base.fbo);
+ mask_pixmap_priv->base.fbo = NULL;
+ need_clean_mask_fbo = 0;
+ }
+ }
+ else {
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ }
+ }
+ RegionDestroy(clipped_dest_regions[i].region);
+ }
+ free(clipped_dest_regions);
+ free(need_free_source_pixmap_priv);
+ free(need_free_mask_pixmap_priv);
+ ok = TRUE;
+ return ok;
+}