largepixmap: Implement infrastructure for large pixmap.
authorZhigang Gong <zhigang.gong@linux.intel.com>
Sun, 10 Jun 2012 17:52:14 +0000 (01:52 +0800)
committerEric Anholt <eric@anholt.net>
Wed, 18 Dec 2013 19:23:51 +0000 (11:23 -0800)
Added infrastructure for largepixmap, this commit implemented:
1. Create/Destroy large pixmap.
2. Upload/Download large pixmap.
3. Implement basic repeat normal support.
3. tile/fill/copyarea large pixmap get supported.

The most complicated part glamor_composite still not implemented.

Signed-off-by: Zhigang Gong <zhigang.gong@linux.intel.com>
glamor/Makefile.am
glamor/glamor.c
glamor/glamor_copyarea.c
glamor/glamor_fbo.c
glamor/glamor_fill.c
glamor/glamor_largepixmap.c [new file with mode: 0644]
glamor/glamor_pixmap.c
glamor/glamor_priv.h
glamor/glamor_render.c
glamor/glamor_tile.c
glamor/glamor_utils.h

index 2e94ffd..421846c 100644 (file)
@@ -42,6 +42,7 @@ libglamor_la_SOURCES = \
        glamor_glyphblt.c\
        glamor_polyops.c\
        glamor_pixmap.c\
+       glamor_largepixmap.c\
        glamor_picture.c\
        glamor_window.c\
        glamor_gl_dispatch.c\
index a22f445..74b22d3 100644 (file)
@@ -141,9 +141,11 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
        if (w > 32767 || h > 32767)
                return NullPixmap;
 
-       if (usage == GLAMOR_CREATE_PIXMAP_CPU
-           || (w == 0 && h == 0)
-           || !glamor_check_pixmap_fbo_depth(depth))
+       if ((usage == GLAMOR_CREATE_PIXMAP_CPU
+               || (w == 0 && h == 0)
+               || !glamor_check_pixmap_fbo_depth(depth))
+           || (!GLAMOR_TEXTURED_LARGE_PIXMAP &&
+               !glamor_check_fbo_size(glamor_priv, w, h)))
                return fbCreatePixmap(screen, w, h, depth, usage);
        else
                pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
@@ -161,10 +163,24 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 
        pixmap_priv->base.pixmap = pixmap;
        pixmap_priv->base.glamor_priv = glamor_priv;
-       pixmap_priv->type = type;
 
        gl_iformat_for_depth(depth, &format);
-       fbo = glamor_create_fbo(glamor_priv, w, h, format, usage);
+
+       pitch = (((w * pixmap->drawable.bitsPerPixel + 7) / 8) + 3) & ~3;
+       screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, pitch, NULL);
+
+       if (type == GLAMOR_MEMORY_MAP || glamor_check_fbo_size(glamor_priv, w, h)) {
+               pixmap_priv->type = type;
+               fbo = glamor_create_fbo(glamor_priv, w, h, format, usage);
+       }
+       else {
+               DEBUGF("Create LARGE pixmap %p width %d height %d\n", pixmap, w, h);
+               pixmap_priv->type = GLAMOR_TEXTURE_LARGE;
+               fbo = glamor_create_fbo_array(glamor_priv, w, h, format, usage,
+                                             glamor_priv->max_fbo_size,
+                                             glamor_priv->max_fbo_size,
+                                             pixmap_priv);
+       }
 
        if (fbo == NULL) {
                fbDestroyPixmap(pixmap);
@@ -174,8 +190,6 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 
        glamor_pixmap_attach_fbo(pixmap, fbo);
 
-       pitch = (((w * pixmap->drawable.bitsPerPixel + 7) / 8) + 3) & ~3;
-       screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, pitch, NULL);
        return pixmap;
 }
 
@@ -186,13 +200,8 @@ glamor_destroy_textured_pixmap(PixmapPtr pixmap)
                glamor_pixmap_private *pixmap_priv;
 
                pixmap_priv = glamor_get_pixmap_private(pixmap);
-               if (pixmap_priv != NULL) {
-                       glamor_pixmap_fbo *fbo;
-                       fbo = glamor_pixmap_detach_fbo(pixmap_priv);
-                       if (fbo)
-                               glamor_destroy_fbo(fbo);
-                       free(pixmap_priv);
-               }
+               if (pixmap_priv != NULL)
+                       glamor_pixmap_destroy_fbo(pixmap_priv);
        }
 }
 
@@ -315,6 +324,9 @@ glamor_init(ScreenPtr screen, unsigned int flags)
            glamor_gl_has_extension("GL_EXT_framebuffer_blit");
        glamor_priv->_dispatch.glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE,
                                             &glamor_priv->max_fbo_size);
+#ifdef MAX_FBO_SIZE
+       glamor_priv->max_fbo_size = MAX_FBO_SIZE;
+#endif
 
        glamor_set_debug_level(&glamor_debug_level);
 
index 84a449c..4d68dbe 100644 (file)
@@ -40,11 +40,13 @@ glamor_copy_n_to_n_fbo_blit(DrawablePtr src,
        ScreenPtr screen = dst->pScreen;
        PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
        PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
-       glamor_pixmap_private *src_pixmap_priv;
+       glamor_pixmap_private *src_pixmap_priv, *dst_pixmap_priv;
        glamor_screen_private *glamor_priv =
            glamor_get_screen_private(screen);
        glamor_gl_dispatch *dispatch;
        int dst_x_off, dst_y_off, src_x_off, src_y_off, i;
+       int fbo_x_off, fbo_y_off;
+       int src_fbo_x_off, src_fbo_y_off;
 
        if (!glamor_priv->has_fbo_blit) {
                glamor_delayed_fallback(screen,
@@ -52,17 +54,13 @@ glamor_copy_n_to_n_fbo_blit(DrawablePtr src,
                return FALSE;
        }
        src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+       dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
 
        if (gc) {
                if (gc->alu != GXcopy) {
                        glamor_delayed_fallback(screen, "non-copy ALU\n");
                        return FALSE;
                }
-               if (!glamor_pm_is_solid(dst, gc->planemask)) {
-                       glamor_delayed_fallback(screen,
-                                               "non-solid planemask\n");
-                       return FALSE;
-               }
        }
 
        if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) {
@@ -73,6 +71,9 @@ glamor_copy_n_to_n_fbo_blit(DrawablePtr src,
        if (glamor_set_destination_pixmap(dst_pixmap))
                return FALSE;
 
+       pixmap_priv_get_fbo_off(dst_pixmap_priv, &fbo_x_off, &fbo_y_off);
+       pixmap_priv_get_fbo_off(src_pixmap_priv, &src_fbo_x_off, &src_fbo_y_off);
+
        dispatch = glamor_get_dispatch(glamor_priv);
        dispatch->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT,
                                    src_pixmap_priv->base.fbo->fb);
@@ -80,7 +81,10 @@ glamor_copy_n_to_n_fbo_blit(DrawablePtr src,
                                   &dst_y_off);
        glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
                                   &src_y_off);
-       src_y_off += dy;
+       dst_x_off += fbo_x_off;
+       dst_y_off += fbo_y_off;
+       src_y_off += dy + src_fbo_y_off;
+       src_x_off += src_fbo_x_off;
 
        for (i = 0; i < nbox; i++) {
                if (glamor_priv->yInverted) {
@@ -154,17 +158,11 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
        int src_x_off, src_y_off, dst_x_off, dst_y_off;
        enum glamor_pixmap_status src_status = GLAMOR_NONE;
        GLfloat dst_xscale, dst_yscale, src_xscale, src_yscale;
-       int alu = GXcopy;
 
        src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
        dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
 
-       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
-               glamor_delayed_fallback(dst->pScreen, "dst has no fbo.\n");
-               return FALSE;
-       }
-
-       if (!src_pixmap_priv || !src_pixmap_priv->base.gl_fbo) {
+       if (!src_pixmap_priv->base.gl_fbo) {
 #ifndef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
                glamor_delayed_fallback(dst->pScreen, "src has no fbo.\n");
                return FALSE;
@@ -177,11 +175,6 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
 #endif
        }
 
-       if (gc) {
-               if (!glamor_set_planemask(dst_pixmap, gc->planemask))
-                       return FALSE;
-               alu = gc->alu;
-       }
 
        pixmap_priv_get_dest_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
        pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);
@@ -191,10 +184,6 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
 
        dispatch = glamor_get_dispatch(glamor_priv);
 
-       if (!glamor_set_alu(dispatch, alu)) {
-               glamor_put_dispatch(glamor_priv);
-               return FALSE;
-       }
 
        glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
        dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
@@ -239,8 +228,8 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
 
        for (i = 0; i < nbox; i++) {
 
-               glamor_set_normalize_vcoords(dst_pixmap_priv, dst_xscale,
-                                            dst_yscale,
+               glamor_set_normalize_vcoords(dst_pixmap_priv,
+                                            dst_xscale, dst_yscale,
                                             box[i].x1 + dst_x_off,
                                             box[i].y1 + dst_y_off,
                                             box[i].x2 + dst_x_off,
@@ -248,7 +237,8 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
                                             glamor_priv->yInverted,
                                             vertices);
 
-               glamor_set_normalize_tcoords(src_pixmap_priv, src_xscale,
+               glamor_set_normalize_tcoords(src_pixmap_priv,
+                                            src_xscale,
                                             src_yscale,
                                             box[i].x1 + dx,
                                             box[i].y1 + dy,
@@ -270,19 +260,18 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
        return TRUE;
 }
 
-static Bool 
-_glamor_copy_n_to_n(DrawablePtr src,
-                   DrawablePtr dst,
-                   GCPtr gc,
-                   BoxPtr box,
-                   int nbox,
-                   int dx,
-                   int dy,
-                   Bool reverse,
-                   Bool upsidedown, Pixel bitplane, 
-                   void *closure, Bool fallback)
+static Bool
+__glamor_copy_n_to_n(DrawablePtr src,
+                    DrawablePtr dst,
+                    GCPtr gc,
+                    BoxPtr box,
+                    int nbox,
+                    int dx,
+                    int dy,
+                    Bool reverse,
+                    Bool upsidedown, Pixel bitplane,
+                    void *closure)
 {
-       glamor_access_t dst_access;
        PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL;
        DrawablePtr temp_src = src;
        glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
@@ -296,32 +285,20 @@ _glamor_copy_n_to_n(DrawablePtr src,
        int overlaped = 0;
        Bool ret = FALSE;
 
-       if (nbox == 0)
-               return TRUE;
        dst_pixmap = glamor_get_drawable_pixmap(dst);
        dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
        src_pixmap = glamor_get_drawable_pixmap(src);
        src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
        screen = dst_pixmap->drawable.pScreen;
        glamor_priv = glamor_get_screen_private(dst->pScreen);
-
-       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
-               glamor_fallback("dest pixmap %p has no fbo. \n",
-                               dst_pixmap);
-               goto fail;
-       }
-
-       if (!src_pixmap_priv) {
-               glamor_set_pixmap_type(src_pixmap, GLAMOR_MEMORY);
-               src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
-       }
-
        glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
                                   &src_y_off);
+
        glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
                                   &dst_y_off);
 
-       if (src_pixmap_priv->base.fbo && src_pixmap_priv->base.fbo->fb == dst_pixmap_priv->base.fbo->fb) {
+       if (src_pixmap_priv->base.fbo
+               && src_pixmap_priv->base.fbo->fb == dst_pixmap_priv->base.fbo->fb) {
                int x_shift = abs(src_x_off - dx - dst_x_off);
                int y_shift = abs(src_y_off - dy - dst_y_off);
                for (i = 0; i < nbox; i++) {
@@ -332,6 +309,11 @@ _glamor_copy_n_to_n(DrawablePtr src,
                        }
                }
        }
+       DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n",
+               box[0].x1, box[0].y1,
+               box[0].x2 - box[0].x1, box[0].y2 - box[0].y1,
+               dx, dy,
+               src_pixmap, dst_pixmap);
 #ifndef GLAMOR_GLES2
        if ((overlaped
             || !src_pixmap_priv->base.gl_tex || !dst_pixmap_priv->base.gl_tex)
@@ -345,10 +327,13 @@ _glamor_copy_n_to_n(DrawablePtr src,
 
        /*  Overlaped indicate the src and dst are the same pixmap. */
        if (overlaped || (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)
-                         && ((bound.x2 - bound.x1) * (bound.y2 - bound.y1)
+                         && (((bound.x2 - bound.x1) * (bound.y2 - bound.y1)
                              * 4 >
                              src_pixmap->drawable.width *
-                             src_pixmap->drawable.height))) {
+                             src_pixmap->drawable.height)
+                            || !(glamor_check_fbo_size(glamor_priv,
+                                       src_pixmap->drawable.width,
+                                       src_pixmap->drawable.height))))) {
 
                temp_pixmap = glamor_create_pixmap(screen,
                                                   bound.x2 - bound.x1,
@@ -357,9 +342,11 @@ _glamor_copy_n_to_n(DrawablePtr src,
                                                   drawable.depth,
                                                   overlaped ? 0 :
                                                   GLAMOR_CREATE_PIXMAP_CPU);
+               assert(bound.x2 - bound.x1 <= glamor_priv->max_fbo_size);
+               assert(bound.y2 - bound.y1 <= glamor_priv->max_fbo_size);
                if (!temp_pixmap)
-                       goto fail;
-               glamor_transform_boxes(box, nbox, -bound.x1, -bound.y1);
+                       goto done;
+               glamor_translate_boxes(box, nbox, -bound.x1, -bound.y1);
                temp_src = &temp_pixmap->drawable;
 
                if (overlaped)
@@ -371,7 +358,7 @@ _glamor_copy_n_to_n(DrawablePtr src,
                        fbCopyNtoN(src, temp_src, gc, box, nbox,
                                   temp_dx + bound.x1, temp_dy + bound.y1,
                                   reverse, upsidedown, bitplane, closure);
-               glamor_transform_boxes(box, nbox, bound.x1, bound.y1);
+               glamor_translate_boxes(box, nbox, bound.x1, bound.y1);
                temp_dx = -bound.x1;
                temp_dy = -bound.y1;
        } else {
@@ -383,13 +370,221 @@ _glamor_copy_n_to_n(DrawablePtr src,
        if (glamor_copy_n_to_n_textured
            (temp_src, dst, gc, box, nbox, temp_dx, temp_dy)) {
                ret = TRUE;
-               goto done;
+       }
+done:
+       if (temp_src != src)
+               glamor_destroy_pixmap(temp_pixmap);
+       return ret;
+}
+
+static Bool
+_glamor_copy_n_to_n(DrawablePtr src,
+                   DrawablePtr dst,
+                   GCPtr gc,
+                   BoxPtr box,
+                   int nbox,
+                   int dx,
+                   int dy,
+                   Bool reverse,
+                   Bool upsidedown, Pixel bitplane,
+                   void *closure, Bool fallback)
+{
+       glamor_access_t dst_access;
+       PixmapPtr dst_pixmap, src_pixmap;
+       glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
+       glamor_screen_private *glamor_priv;
+       glamor_gl_dispatch *dispatch;
+       BoxPtr extent;
+       RegionRec region;
+       ScreenPtr screen;
+       int src_x_off, src_y_off, dst_x_off, dst_y_off;
+       Bool ret = FALSE;
+       int ok = TRUE;
+       int force_clip = 0;
+
+       if (nbox == 0)
+               return TRUE;
+       dst_pixmap = glamor_get_drawable_pixmap(dst);
+       dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
+       src_pixmap = glamor_get_drawable_pixmap(src);
+       src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+       screen = dst_pixmap->drawable.pScreen;
+
+       glamor_priv = glamor_get_screen_private(dst->pScreen);
+
+       DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n",
+               box[0].x1, box[0].y1,
+               box[0].x2 - box[0].x1, box[0].y2 - box[0].y1,
+               dx, dy,
+               src_pixmap, dst_pixmap);
+
+       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv))
+               goto fall_back;
+
+       if (gc) {
+               if (!glamor_set_planemask(dst_pixmap, gc->planemask))
+                       goto fail;
+               dispatch = glamor_get_dispatch(glamor_priv);
+               if (!glamor_set_alu(dispatch, gc->alu)) {
+                       glamor_put_dispatch(glamor_priv);
+                       goto fail;
+               }
+               glamor_put_dispatch(glamor_priv);
+       }
+
+       if (!src_pixmap_priv) {
+               glamor_set_pixmap_type(src_pixmap, GLAMOR_MEMORY);
+               src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+       }
+
+       glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
+                                  &src_y_off);
+       glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
+                                  &dst_y_off);
+
+       RegionInitBoxes(&region, box, nbox);
+       extent = RegionExtents(&region);
+
+       if (!glamor_check_fbo_size(glamor_priv,
+               extent->x2 - extent->x1, extent->y2 - extent->y1)
+          && (src_pixmap_priv->type == GLAMOR_MEMORY
+               || (src_pixmap_priv == dst_pixmap_priv))) {
+               force_clip = 1;
        }
 
+       if (force_clip || dst_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
+           || src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+                       glamor_pixmap_clipped_regions *clipped_dst_regions;
+                       int n_dst_region, i, j;
+                       PixmapPtr temp_source_pixmap;
+                       glamor_pixmap_private *temp_source_priv = NULL;
+                       int temp_dx = 0, temp_dy = 0;
+
+                       RegionTranslate(&region, dst_x_off, dst_y_off);
+                       if (!force_clip)
+                               clipped_dst_regions = glamor_compute_clipped_regions(dst_pixmap_priv,
+                                                                                    &region, &n_dst_region, 0);
+                       else
+                               clipped_dst_regions = glamor_compute_clipped_regions_ext(dst_pixmap_priv,
+                                                                                        &region, &n_dst_region,
+                                                                                        glamor_priv->max_fbo_size,
+                                                                                        glamor_priv->max_fbo_size);
+                       for(i = 0; i < n_dst_region; i++)
+                       {
+                               int n_src_region;
+                               glamor_pixmap_clipped_regions *clipped_src_regions;
+                               BoxPtr current_boxes;
+                               int n_current_boxes;
+
+                               SET_PIXMAP_FBO_CURRENT(dst_pixmap_priv, clipped_dst_regions[i].block_idx);
+
+                               temp_source_pixmap = NULL;
+                               if (src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+                                       RegionTranslate(clipped_dst_regions[i].region,
+                                                       -dst_x_off + src_x_off + dx, -dst_y_off + src_y_off + dy);
+                                       clipped_src_regions = glamor_compute_clipped_regions(src_pixmap_priv,
+                                                                                            clipped_dst_regions[i].region,
+                                                                                            &n_src_region, 0);
+                                       DEBUGF("Source is large pixmap.\n");
+                                       for (j = 0; j < n_src_region; j++)
+                                       {
+                                               if (src_pixmap_priv != dst_pixmap_priv)
+                                                       SET_PIXMAP_FBO_CURRENT(src_pixmap_priv, clipped_src_regions[j].block_idx);
+                                               else if (src_pixmap_priv == dst_pixmap_priv &&
+                                                   clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx) {
+                                                       /* source and the dest are the same, but need different block_idx.
+                                                        * we create a empty pixmap and fill the required source fbo and box to
+                                                        * it. It's a little hacky, but avoid extra copy. */
+                                                       temp_source_pixmap = glamor_create_pixmap(src->pScreen, 0, 0,
+                                                                                                 src->depth, 0);
+                                                       if (!temp_source_pixmap)
+                                                               goto fail;
+                                                       src->pScreen->ModifyPixmapHeader(temp_source_pixmap,
+                                                                                     src_pixmap->drawable.width,
+                                                                                     src_pixmap->drawable.height,
+                                                                                     0, 0, src_pixmap->devKind, NULL);
+                                                       temp_source_priv = glamor_get_pixmap_private(temp_source_pixmap);
+                                                       *temp_source_priv = *src_pixmap_priv;
+                                                       temp_source_priv->large.box = src_pixmap_priv->large.box_array[clipped_src_regions[j].block_idx];
+                                                       temp_source_priv->base.fbo = src_pixmap_priv->large.fbo_array[clipped_src_regions[j].block_idx];
+                                                       /* XXX need revisit here. */
+                                                       temp_dx = dx/* - src_x_off*/;
+                                                       temp_dy = dy/* - src_y_off*/;
+                                               }
+                                               assert(temp_source_pixmap || !(src_pixmap_priv == dst_pixmap_priv
+                                                       && (clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx)));
+
+                                               RegionTranslate(clipped_src_regions[j].region,
+                                                               -src_x_off - dx,
+                                                               -src_y_off - dy);
+                                               current_boxes = RegionRects(clipped_src_regions[j].region);
+                                               n_current_boxes = RegionNumRects(clipped_src_regions[j].region);
+                                               DEBUGF("dst pixmap fbo idx %d src pixmap fbo idx %d \n",
+                                                       clipped_dst_regions[i].block_idx,
+                                                       clipped_src_regions[j].block_idx);
+                                               DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n",
+                                                       current_boxes[0].x1, current_boxes[0].y1,
+                                                       current_boxes[0].x2, current_boxes[0].y2,
+                                                       dx, dy, src_pixmap, dst_pixmap);
+                                               if (!temp_source_pixmap)
+                                                       ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes,
+                                                                                 n_current_boxes, dx, dy, reverse,
+                                                                                 upsidedown, bitplane, closure);
+                                               else {
+                                                       ok = __glamor_copy_n_to_n(&temp_source_pixmap->drawable, dst, gc, current_boxes,
+                                                                                 n_current_boxes, temp_dx, temp_dy, reverse,
+                                                                                 upsidedown, bitplane, closure);
+                                                       temp_source_priv->type = GLAMOR_MEMORY;
+                                                       temp_source_priv->base.fbo = NULL;
+                                                       glamor_destroy_pixmap(temp_source_pixmap);
+                                                       temp_source_pixmap = NULL;
+                                               }
+
+                                               RegionDestroy(clipped_src_regions[j].region);
+                                               if (!ok) {
+                                                       assert(0);
+                                                       goto fail;
+                                               }
+                                       }
+                                       free(clipped_src_regions);
+                               } else {
+                                       RegionTranslate(clipped_dst_regions[i].region,
+                                                       - dst_x_off,
+                                                       - dst_y_off);
+                                       current_boxes = RegionRects(clipped_dst_regions[i].region);
+                                       n_current_boxes = RegionNumRects(clipped_dst_regions[i].region);
+
+                                               DEBUGF("dest pixmap fbo idx %d \n",
+                                                       clipped_dst_regions[i].block_idx);
+                                               DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n",
+                                                       current_boxes[0].x1, current_boxes[0].y1,
+                                                       current_boxes[0].x2, current_boxes[0].y2,
+                                                       dx, dy, src_pixmap, dst_pixmap);
+
+                                       ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes,
+                                                                 n_current_boxes, dx, dy, reverse,
+                                                                 upsidedown, bitplane, closure);
+
+                               }
+                               RegionDestroy(clipped_dst_regions[i].region);
+                       }
+               free(clipped_dst_regions);
+               RegionUninit(&region);
+       } else {
+               ok = __glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, dy,
+                                         reverse, upsidedown, bitplane,
+                                         closure);
+       }
 
-      fail:
-       
-       if (!fallback 
+fail:
+       dispatch = glamor_get_dispatch(glamor_priv);
+       glamor_set_alu(dispatch, GXcopy);
+       glamor_put_dispatch(glamor_priv);
+
+       if (ok)
+               return TRUE;
+fall_back:
+       if (!fallback
            && glamor_ddx_fallback_check_pixmap(src)
            && glamor_ddx_fallback_check_pixmap(dst))
                goto done;
@@ -428,8 +623,6 @@ _glamor_copy_n_to_n(DrawablePtr src,
       done:
        glamor_clear_delayed_fallbacks(src->pScreen);
        glamor_clear_delayed_fallbacks(dst->pScreen);
-       if (temp_src != src)
-               glamor_destroy_pixmap(temp_pixmap);
        return ret;
 }
 
@@ -455,10 +648,10 @@ glamor_copy_n_to_n(DrawablePtr src,
                   int dx,
                   int dy,
                   Bool reverse,
-                  Bool upsidedown, Pixel bitplane, 
+                  Bool upsidedown, Pixel bitplane,
                   void *closure)
 {
-       _glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, 
+       _glamor_copy_n_to_n(src, dst, gc, box, nbox, dx,
                            dy, reverse, upsidedown, bitplane, closure, TRUE);
 }
 
@@ -471,10 +664,10 @@ glamor_copy_n_to_n_nf(DrawablePtr src,
                   int dx,
                   int dy,
                   Bool reverse,
-                  Bool upsidedown, Pixel bitplane, 
+                  Bool upsidedown, Pixel bitplane,
                   void *closure)
 {
-       return _glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, 
+       return _glamor_copy_n_to_n(src, dst, gc, box, nbox, dx,
                                    dy, reverse, upsidedown, bitplane, closure, FALSE);
 }
 
index 5337149..1ab7686 100644 (file)
@@ -175,7 +175,8 @@ glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo)
 
        if (fbo->fb == 0 || n_format == -1
           || fbo->glamor_priv->fbo_cache_watermark >= FBO_CACHE_THRESHOLD) {
-               fbo->glamor_priv->tick ++;
+               fbo->glamor_priv->tick += GLAMOR_CACHE_EXPIRE_MAX;
+               glamor_fbo_expire(fbo->glamor_priv);
                glamor_purge_fbo(fbo);
                return;
        }
@@ -404,6 +405,92 @@ no_tex:
        return fbo;
 }
 
+static glamor_pixmap_fbo *
+_glamor_create_fbo_array(glamor_screen_private *glamor_priv,
+                        int w, int h, GLenum format, int flag,
+                        int block_w, int block_h,
+                        glamor_pixmap_private *pixmap_priv,
+                        int has_fbo)
+{
+       int block_wcnt;
+       int block_hcnt;
+       glamor_pixmap_fbo **fbo_array;
+       BoxPtr box_array;
+       int i,j;
+       glamor_pixmap_private_large_t *priv;
+
+       priv = &pixmap_priv->large;
+
+       block_wcnt = (w + block_w - 1) / block_w;
+       block_hcnt = (h + block_h - 1) / block_h;
+
+       box_array = calloc(block_wcnt * block_hcnt, sizeof(box_array[0]));
+       if (box_array == NULL)
+               return NULL;
+
+       fbo_array = calloc(block_wcnt * block_hcnt, sizeof(glamor_pixmap_fbo*));
+       if (fbo_array == NULL) {
+               free(box_array);
+               return FALSE;
+       }
+       for(i = 0; i < block_hcnt; i++)
+       {
+               int block_y1, block_y2;
+               int fbo_w, fbo_h;
+
+               block_y1 = i * block_h;
+               block_y2 = (block_y1 + block_h) > h ? h : (block_y1 + block_h);
+               fbo_h = block_y2 - block_y1;
+
+               for (j = 0; j < block_wcnt; j++)
+               {
+                       box_array[i * block_wcnt + j].x1 = j * block_w;
+                       box_array[i * block_wcnt + j].y1 = block_y1;
+                       box_array[i * block_wcnt + j].x2 = (j + 1) * block_w > w ? w : (j + 1) * block_w;
+                       box_array[i * block_wcnt + j].y2 = block_y2;
+                       fbo_w = box_array[i * block_wcnt + j].x2 - box_array[i * block_wcnt + j].x1;
+                       if (!has_fbo)
+                               fbo_array[i * block_wcnt + j] = glamor_create_fbo(glamor_priv,
+                                                                                 fbo_w, fbo_h, format,
+                                                                                 GLAMOR_CREATE_PIXMAP_FIXUP);
+                       else
+                               fbo_array[i * block_wcnt + j] = priv->base.fbo;
+                       if (fbo_array[i * block_wcnt + j] == NULL)
+                               goto cleanup;
+               }
+       }
+
+       priv->box = box_array[0];
+       priv->box_array = box_array;
+       priv->fbo_array = fbo_array;
+       priv->block_wcnt = block_wcnt;
+       priv->block_hcnt = block_hcnt;
+       return fbo_array[0];
+
+cleanup:
+       for(i = 0; i < block_wcnt * block_hcnt; i++)
+               if ((fbo_array)[i])
+                       glamor_destroy_fbo((fbo_array)[i]);
+       free(box_array);
+       free(fbo_array);
+       return NULL;
+}
+
+
+/* Create a fbo array to cover the w*h region, by using block_w*block_h
+ * block.*/
+glamor_pixmap_fbo *
+glamor_create_fbo_array(glamor_screen_private *glamor_priv,
+                       int w, int h, GLenum format, int flag,
+                       int block_w, int block_h,
+                       glamor_pixmap_private *pixmap_priv)
+{
+       pixmap_priv->large.block_w = block_w;
+       pixmap_priv->large.block_h = block_h;
+       return _glamor_create_fbo_array(glamor_priv, w, h, format, flag,
+                                       block_w, block_h, pixmap_priv, 0);
+}
+
 glamor_pixmap_fbo *
 glamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv)
 {
@@ -428,23 +515,13 @@ glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo)
 
        pixmap_priv = glamor_get_pixmap_private(pixmap);
 
-       if (pixmap_priv == NULL) {
-               glamor_screen_private *glamor_priv;
-               glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
-               pixmap_priv = calloc(1, sizeof(*pixmap_priv));
-               dixSetPrivate(&pixmap->devPrivates,
-                             glamor_pixmap_private_key, pixmap_priv);
-               pixmap_priv->base.pixmap = pixmap;
-               pixmap_priv->base.glamor_priv = glamor_priv;
-               pixmap_priv->type = GLAMOR_MEMORY;
-       }
-
        if (pixmap_priv->base.fbo)
                return;
 
        pixmap_priv->base.fbo = fbo;
 
        switch (pixmap_priv->type) {
+       case GLAMOR_TEXTURE_LARGE:
        case GLAMOR_TEXTURE_ONLY:
        case GLAMOR_TEXTURE_DRM:
                pixmap_priv->base.gl_fbo = 1;
@@ -462,6 +539,23 @@ glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo)
        }
 }
 
+void
+glamor_pixmap_destroy_fbo(glamor_pixmap_private *priv)
+{
+       glamor_pixmap_fbo *fbo;
+       if (priv->type == GLAMOR_TEXTURE_LARGE) {
+               int i;
+               glamor_pixmap_private_large_t *large = &priv->large;
+               for(i = 0; i < large->block_wcnt * large->block_hcnt; i++)
+                       glamor_destroy_fbo(large->fbo_array[i]);
+               free(large->fbo_array);
+       } else {
+               fbo = glamor_pixmap_detach_fbo(priv);
+               if (fbo)
+                       glamor_destroy_fbo(fbo);
+               free(priv);
+       }
+}
 
 Bool
 glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag)
@@ -472,7 +566,7 @@ glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag)
 
        glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
        pixmap_priv = glamor_get_pixmap_private(pixmap);
-       if (pixmap_priv == NULL || pixmap_priv->base.fbo == NULL) {
+       if (pixmap_priv->base.fbo == NULL) {
 
                fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
                                        pixmap->drawable.height,
@@ -492,7 +586,6 @@ glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag)
                        glamor_pixmap_ensure_fb(pixmap_priv->base.fbo);
        }
 
-       pixmap_priv = glamor_get_pixmap_private(pixmap);
        return TRUE;
 }
 
index b63756d..5b84dd6 100644 (file)
@@ -180,10 +180,9 @@ glamor_fini_solid_shader(ScreenPtr screen)
        glamor_put_dispatch(glamor_priv);
 }
 
-Bool
-glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
-            unsigned char alu, unsigned long planemask,
-            unsigned long fg_pixel)
+static void
+_glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
+             float *color)
 {
        ScreenPtr screen = pixmap->drawable.pScreen;
        glamor_screen_private *glamor_priv =
@@ -195,14 +194,49 @@ glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
        int x2 = x + width;
        int y1 = y;
        int y2 = y + height;
-       GLfloat color[4];
        float vertices[8];
        GLfloat xscale, yscale;
 
-       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
-               glamor_fallback("dest %p has no fbo.\n", pixmap);
+       glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+
+       dispatch = glamor_get_dispatch(glamor_priv);
+       dispatch->glUseProgram(glamor_priv->solid_prog);
+
+       dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location,
+                              1, color);
+
+       dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+                                       GL_FALSE, 2 * sizeof(float),
+                                       vertices);
+       dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+       pixmap_priv_get_dest_scale(pixmap_priv, &xscale, &yscale);
+
+       glamor_set_normalize_vcoords(pixmap_priv, xscale, yscale,
+                                    x1, y1,
+                                    x2, y2,
+                                    glamor_priv->yInverted, vertices);
+       dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+       dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+       dispatch->glUseProgram(0);
+       glamor_put_dispatch(glamor_priv);
+}
+
+Bool
+glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
+            unsigned char alu, unsigned long planemask,
+            unsigned long fg_pixel)
+{
+       ScreenPtr screen = pixmap->drawable.pScreen;
+       glamor_screen_private *glamor_priv =
+           glamor_get_screen_private(screen);
+       glamor_pixmap_private *pixmap_priv;
+       glamor_gl_dispatch *dispatch;
+       GLfloat color[4];
+
+       pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
                return FALSE;
-       }
 
        if (!glamor_set_planemask(pixmap, planemask)) {
                glamor_fallback
@@ -216,8 +250,6 @@ glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
                                   &color[2],
                                   &color[3], format_for_pixmap(pixmap));
 
-       glamor_set_destination_pixmap_priv_nc(pixmap_priv);
-
        dispatch = glamor_get_dispatch(glamor_priv);
        if (!glamor_set_alu(dispatch, alu)) {
                if (alu == GXclear)
@@ -228,23 +260,47 @@ glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
                        return FALSE;
                }
        }
-       dispatch->glUseProgram(glamor_priv->solid_prog);
 
-       dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location,
-                              1, color);
+       if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+               RegionRec region;
+               BoxRec box;
+               int n_region;
+               glamor_pixmap_clipped_regions *clipped_regions;
+               int i,j;
 
-       dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
-                                       GL_FALSE, 2 * sizeof(float),
-                                       vertices);
-       dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
-       pixmap_priv_get_dest_scale(pixmap_priv, &xscale, &yscale);
+               box.x1 = x;
+               box.y1 = y;
+               box.x2 = x + width;
+               box.y2 = y + height;
+               RegionInitBoxes(&region, &box, 1);
+               clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0);
+               for(i = 0; i < n_region; i++)
+               {
+                       BoxPtr boxes;
+                       int nbox;
+                       SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
+
+                       boxes = RegionRects(clipped_regions[i].region);
+                       nbox = RegionNumRects(clipped_regions[i].region);
+                       for(j = 0; j < nbox; j++)
+                       {
+                               _glamor_solid(pixmap, boxes[j].x1, boxes[j].y1,
+                                             boxes[j].x2 - boxes[j].x1,
+                                             boxes[j].y2 - boxes[j].y1, color);
+                       }
+                       RegionDestroy(clipped_regions[i].region);
+               }
+               free(clipped_regions);
+               RegionUninit(&region);
+       } else
+               _glamor_solid(pixmap,
+                             x,
+                             y,
+                             width, height,
+                             color);
 
-       glamor_set_normalize_vcoords(pixmap_priv, xscale, yscale, x1, y1, x2, y2,
-                                    glamor_priv->yInverted, vertices);
-       dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-       dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
-       dispatch->glUseProgram(0);
        glamor_set_alu(dispatch, GXcopy);
        glamor_put_dispatch(glamor_priv);
+
        return TRUE;
 }
diff --git a/glamor/glamor_largepixmap.c b/glamor/glamor_largepixmap.c
new file mode 100644 (file)
index 0000000..e8c1030
--- /dev/null
@@ -0,0 +1,412 @@
+#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 repeat)
+{
+       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 i, j;
+       int width, height;
+       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;
+       }
+
+       width = end_x - start_x;
+       height = end_y - start_y;
+       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));
+
+       block_idx = (start_block_y - 1) * block_stride;
+
+       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);
+
+       for(j = start_block_y; j <= end_block_y; j++)
+       {
+               block_idx += block_stride;
+               temp_block_idx = block_idx + start_block_x;
+               for(i = start_block_x;
+                   i <= end_block_x; i++, temp_block_idx++)
+               {
+                       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)
+{
+       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, 0
+                                       );
+
+               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, 0);
+               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;
+}
+
+/**
+ * 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.
+ *
+ * XXX Not support repeatPad currently.
+ */
+
+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)
+{
+       glamor_pixmap_clipped_regions * clipped_regions;
+       BoxPtr extent;
+       int i, j;
+       int width, height;
+       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) {
+               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, 0
+                                                       );
+               return clipped_regions;
+       } else if (repeat_type != RepeatNormal) {
+               *n_region = 0;
+               return NULL;
+       }
+       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);
+       width = extent->x2 - extent->x1;
+       height = extent->y2 - extent->y1;
+       /* 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;
+                       RegionRec temp_region;
+
+                       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;
+                       else
+                               repeat_box.x2 = shift_x + priv->box_array[idx].x2;
+                       if (priv->block_hcnt == 1)
+                               repeat_box.y2 = extent->y2;
+                       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);
+                                       }
+                               }
+                       }
+                       DEBUGF("dx %d dy %d \n", dx, dy);
+
+                       if (RegionNumRects(current_region)) {
+
+                               if ((right_shift != 0 || down_shift != 0))
+                                       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)
+{
+       return _glamor_compute_clipped_regions(priv, region, n_region, repeat_type, 0);
+}
index fa05bed..ca38a2b 100644 (file)
@@ -83,9 +83,11 @@ glamor_set_destination_pixmap_fbo(glamor_pixmap_fbo * fbo, int x0, int y0, int w
 void
 glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
 {
+       int w,h;
+
+       PIXMAP_PRIV_GET_ACTUAL_SIZE(pixmap_priv, w, h);
        glamor_set_destination_pixmap_fbo(pixmap_priv->base.fbo, 0, 0,
-                                         pixmap_priv->base.pixmap->drawable.width,
-                                         pixmap_priv->base.pixmap->drawable.height);
+                                         w, h);
 }
 
 int
@@ -489,16 +491,23 @@ _glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, GLenum ty
        }
 
 ready_to_upload:
+
        /* Try fast path firstly, upload the pixmap to the texture attached
         * to the fbo directly. */
        if (no_alpha == 0
            && revert == REVERT_NONE
            && swap_rb == SWAP_NONE_UPLOADING
            && !need_flip) {
+               int fbo_x_off, fbo_y_off;
                assert(pixmap_priv->base.fbo->tex);
+               pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off);
+
+               assert(x + fbo_x_off >= 0 && y + fbo_y_off >= 0);
+               assert(x + fbo_x_off + w <= pixmap_priv->base.fbo->width);
+               assert(y + fbo_y_off + h <= pixmap_priv->base.fbo->height);
                __glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->base.fbo->tex,
                                                  format, type,
-                                                 x, y, w, h,
+                                                 x + fbo_x_off, y + fbo_y_off, w, h,
                                                  bits, pbo);
                return TRUE;
        }
@@ -515,7 +524,6 @@ ready_to_upload:
                                     x + w, y + h,
                                     glamor_priv->yInverted,
                                     vertices);
-
        /* Slow path, we need to flip y or wire alpha to 1. */
        dispatch = glamor_get_dispatch(glamor_priv);
        dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
@@ -586,6 +594,9 @@ glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int
        pixmap_priv = glamor_get_pixmap_private(pixmap);
        glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
 
+       if (pixmap_priv->base.gl_fbo)
+               return 0;
+
        if (pixmap_priv->base.fbo
             && (pixmap_priv->base.fbo->width < pixmap->drawable.width
            || pixmap_priv->base.fbo->height < pixmap->drawable.height)) {
@@ -605,8 +616,10 @@ glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int
                flag = GLAMOR_CREATE_FBO_NO_FBO;
        }
 
-       if ((flag == 0 && pixmap_priv && pixmap_priv->base.fbo && pixmap_priv->base.fbo->tex)
-           || (flag != 0 && pixmap_priv && pixmap_priv->base.fbo && pixmap_priv->base.fbo->fb))
+       if ((flag == GLAMOR_CREATE_FBO_NO_FBO
+               && pixmap_priv->base.fbo && pixmap_priv->base.fbo->tex)
+           || (flag == 0
+               && pixmap_priv->base.fbo && pixmap_priv->base.fbo->fb))
                return 0;
 
        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
@@ -614,35 +627,63 @@ glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int
        else
                iformat = format;
 
-       if (pixmap_priv == NULL || pixmap_priv->base.fbo == NULL) {
-
-               fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
-                                       pixmap->drawable.height,
-                                       iformat,
-                                       flag);
-               if (fbo == NULL) {
-                       glamor_fallback
-                           ("upload failed, depth %d x %d @depth %d \n",
-                            pixmap->drawable.width, pixmap->drawable.height,
-                            pixmap->drawable.depth);
-                       return -1;
-               }
+       if (!glamor_pixmap_ensure_fbo(pixmap, iformat, flag))
+               return -1;
 
-               glamor_pixmap_attach_fbo(pixmap, fbo);
-       } else {
-               /* We do have a fbo, but it may lack of fb or tex. */
-               glamor_pixmap_ensure_fbo(pixmap, iformat, flag);
+       return 0;
+}
+
+/*
+ * upload sub region to a large region.
+ * */
+static void
+glamor_put_bits(char *dst_bits, int dst_stride, char *src_bits,
+               int src_stride, int bpp,
+               int x, int y, int w, int h)
+{
+       int j;
+       int byte_per_pixel;
+
+       byte_per_pixel = bpp / 8;
+       src_bits += y * src_stride + (x * byte_per_pixel);
+
+       for(j = y; j < y + h; j++)
+       {
+               memcpy(dst_bits, src_bits, w * byte_per_pixel);
+               src_bits += src_stride;
+               dst_bits += dst_stride;
        }
+}
+/*
+ * download sub region from a large region.
+ */
+static void
+glamor_get_bits(char *dst_bits, int dst_stride, char *src_bits,
+               int src_stride, int bpp,
+               int x, int y, int w, int h)
+{
+       int j;
+       int byte_per_pixel;
 
-       return 0;
+       byte_per_pixel = bpp / 8;
+       dst_bits += y * dst_stride + x * byte_per_pixel;
+
+       for(j = y; j < y + h; j++)
+       {
+               memcpy(dst_bits, src_bits, w * byte_per_pixel);
+               src_bits += src_stride;
+               dst_bits += dst_stride;
+       }
 }
 
+
 Bool
 glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, int h,
                                    int stride, void *bits, int pbo)
 {
        GLenum format, type;
        int no_alpha, revert, swap_rb;
+       glamor_pixmap_private *pixmap_priv;
 
        if (glamor_get_tex_format_type_from_pixmap(pixmap,
                                                   &format,
@@ -657,7 +698,77 @@ glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, int h
        if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb))
                return FALSE;
 
-       return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha, revert, swap_rb,
+       pixmap_priv = glamor_get_pixmap_private(pixmap);
+       if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+               RegionRec region;
+               BoxRec box;
+               int n_region;
+               glamor_pixmap_clipped_regions *clipped_regions;
+               void *sub_bits;
+               int i,j;
+
+               sub_bits = malloc(h * stride);
+               if (sub_bits == NULL)
+                       return FALSE;
+               box.x1 = x;
+               box.y1 = y;
+               box.x2 = x + w;
+               box.y2 = y + h;
+               RegionInitBoxes(&region, &box, 1);
+               clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0);
+               DEBUGF("prepare upload %dx%d to a large pixmap %p\n", w, h, pixmap);
+               for(i = 0; i < n_region; i++)
+               {
+                       BoxPtr boxes;
+                       int nbox;
+                       int temp_stride;
+                       void *temp_bits;
+
+                       assert(pbo == 0);
+
+                       SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
+
+                       boxes = RegionRects(clipped_regions[i].region);
+                       nbox = RegionNumRects(clipped_regions[i].region);
+                       DEBUGF("split to %d boxes\n", nbox);
+                       for(j = 0; j < nbox; j++)
+                       {
+                               temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1,
+                                                           pixmap->drawable.depth);
+
+                               if (boxes[j].x1 == x && temp_stride == stride) {
+                                       temp_bits = (char*)bits + (boxes[j].y1 - y) * stride;
+                               } else {
+                                       temp_bits = sub_bits;
+                                       glamor_put_bits(temp_bits, temp_stride, bits, stride,
+                                                       pixmap->drawable.bitsPerPixel,
+                                                       boxes[j].x1 - x, boxes[j].y1 - y,
+                                                       boxes[j].x2 - boxes[j].x1,
+                                                       boxes[j].y2 - boxes[j].y1);
+                               }
+                               DEBUGF("upload x %d y %d w %d h %d temp stride %d \n",
+                                       boxes[j].x1 - x, boxes[j].y1 - y,
+                                       boxes[j].x2 - boxes[j].x1,
+                                       boxes[j].y2 - boxes[j].y1, temp_stride);
+                               if (_glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha,
+                                                                         revert, swap_rb, boxes[j].x1, boxes[j].y1,
+                                                                         boxes[j].x2 - boxes[j].x1,
+                                                                         boxes[j].y2 - boxes[j].y1,
+                                                                         temp_stride, temp_bits, pbo) == FALSE) {
+                                       RegionUninit(&region);
+                                       free(sub_bits);
+                                       assert(0);
+                                       return FALSE;
+                               }
+                       }
+                       RegionDestroy(clipped_regions[i].region);
+               }
+               free(sub_bits);
+               free(clipped_regions);
+               RegionUninit(&region);
+               return TRUE;
+       } else
+               return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha, revert, swap_rb,
                                                     x, y, w, h, stride, bits, pbo);
 }
 
@@ -671,8 +782,7 @@ glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
 
        pixmap_priv = glamor_get_pixmap_private(pixmap);
 
-       if (pixmap_priv
-           && (pixmap_priv->base.fbo)
+       if ((pixmap_priv->base.fbo)
            && (pixmap_priv->base.fbo->pbo_valid)) {
                data = NULL;
                pbo = pixmap_priv->base.fbo->pbo;
@@ -737,7 +847,7 @@ glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int y, int w, int h, GLe
        temp_xscale = 1.0 / w;
        temp_yscale = 1.0 / h;
 
-       glamor_set_normalize_vcoords((glamor_pixmap_private *)NULL, temp_xscale,
+       glamor_set_normalize_vcoords((struct glamor_pixmap_private*)NULL,temp_xscale,
                                     temp_yscale,
                                     0, 0,
                                     w, h,
@@ -793,13 +903,15 @@ glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int y, int w, int h, GLe
  * The pixmap must have a valid FBO, otherwise return a NULL.
  * */
 
-void *
-glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
-                                 int stride, void *bits, int pbo, glamor_access_t access)
+static void *
+_glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, GLenum format,
+                                  GLenum type, int no_alpha,
+                                  int revert, int swap_rb,
+                                  int x, int y, int w, int h,
+                                  int stride, void *bits, int pbo, glamor_access_t access)
 {
        glamor_pixmap_private *pixmap_priv;
-       GLenum format, type, gl_access = 0, gl_usage = 0;
-       int no_alpha, revert, swap_rb;
+       GLenum gl_access = 0, gl_usage = 0;
        void *data, *read;
        ScreenPtr screen;
        glamor_screen_private *glamor_priv =
@@ -808,6 +920,7 @@ glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
        glamor_pixmap_fbo *temp_fbo = NULL;
        int need_post_conversion = 0;
        int need_free_data = 0;
+       int fbo_x_off, fbo_y_off;
 
        data = bits;
        screen = pixmap->drawable.pScreen;
@@ -831,18 +944,6 @@ glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
                assert(0);
        }
 
-       if (glamor_get_tex_format_type_from_pixmap(pixmap,
-                                                  &format,
-                                                  &type,
-                                                  &no_alpha,
-                                                  &revert,
-                                                  &swap_rb, 0)) {
-               ErrorF("Unknown pixmap depth %d.\n",
-                      pixmap->drawable.depth);
-               assert(0);      // Should never happen.
-               return NULL;
-       }
-
        glamor_set_destination_pixmap_priv_nc(pixmap_priv);
 
        need_post_conversion = (revert > REVERT_NORMAL);
@@ -857,6 +958,8 @@ glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
                }
        }
 
+       pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off);
+
        if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
            && !need_post_conversion
            && (swap_rb != SWAP_NONE_DOWNLOADING || revert != REVERT_NONE)) {
@@ -868,6 +971,8 @@ glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
                }
                x = 0;
                y = 0;
+               fbo_x_off = 0;
+               fbo_y_off = 0;
        }
 
        dispatch = glamor_get_dispatch(glamor_priv);
@@ -890,7 +995,7 @@ glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
                                               NULL, gl_usage);
                }
 
-               dispatch->glReadPixels(x, y, w, h, format, type, data);
+               dispatch->glReadPixels(x + fbo_x_off, y + fbo_y_off, w, h, format, type, data);
 
                if (!glamor_priv->yInverted) {
                        assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
@@ -913,7 +1018,7 @@ glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
                                       stride *
                                       h,
                                       NULL, GL_STREAM_READ);
-               dispatch->glReadPixels(0, 0, w, h,
+               dispatch->glReadPixels(x + fbo_x_off, y + fbo_y_off, w, h,
                                       format, type, 0);
                read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
                                             GL_READ_ONLY);
@@ -946,6 +1051,107 @@ glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
        return bits;
 }
 
+void *
+glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
+                                 int stride, void *bits, int pbo, glamor_access_t access)
+{
+       GLenum format, type;
+       int no_alpha, revert, swap_rb;
+       glamor_pixmap_private *pixmap_priv;
+
+       if (glamor_get_tex_format_type_from_pixmap(pixmap,
+                                                  &format,
+                                                  &type,
+                                                  &no_alpha,
+                                                  &revert,
+                                                  &swap_rb, 1)) {
+               glamor_fallback("Unknown pixmap depth %d.\n",
+                               pixmap->drawable.depth);
+               return NULL;
+       }
+
+       pixmap_priv = glamor_get_pixmap_private(pixmap);
+       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+               return NULL;
+
+       if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+
+               RegionRec region;
+               BoxRec box;
+               int n_region;
+               glamor_pixmap_clipped_regions *clipped_regions;
+               void *sub_bits;
+               int i,j;
+
+               sub_bits = malloc(h * stride);
+               if (sub_bits == NULL)
+                       return FALSE;
+               box.x1 = x;
+               box.y1 = y;
+               box.x2 = x + w;
+               box.y2 = y + h;
+               RegionInitBoxes(&region, &box, 1);
+               clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0);
+               DEBUGF("start download large pixmap %p %dx%d \n", pixmap, w, h);
+               for(i = 0; i < n_region; i++)
+               {
+                       BoxPtr boxes;
+                       int nbox;
+                       int temp_stride;
+                       void *temp_bits;
+
+                       assert(pbo == 0);
+                       SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
+
+                       boxes = RegionRects(clipped_regions[i].region);
+                       nbox = RegionNumRects(clipped_regions[i].region);
+                       for(j = 0; j < nbox; j++)
+                       {
+                               temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1,
+                                                           pixmap->drawable.depth);
+
+                               if (boxes[j].x1 == x && temp_stride == stride) {
+                                       temp_bits = (char*)bits + (boxes[j].y1 - y) * stride;
+                               } else {
+                                       temp_bits = sub_bits;
+                               }
+                               DEBUGF("download x %d y %d w %d h %d temp stride %d \n",
+                                       boxes[j].x1, boxes[j].y1,
+                                       boxes[j].x2 - boxes[j].x1,
+                                       boxes[j].y2 - boxes[j].y1, temp_stride);
+
+                               /* For large pixmap, we don't support pbo currently.*/
+                               assert(pbo == 0);
+                               if (_glamor_download_sub_pixmap_to_cpu(pixmap, format, type, no_alpha,
+                                                                      revert, swap_rb, boxes[j].x1, boxes[j].y1,
+                                                                      boxes[j].x2 - boxes[j].x1,
+                                                                      boxes[j].y2 - boxes[j].y1,
+                                                                      temp_stride, temp_bits, pbo, access) == FALSE) {
+                                       RegionUninit(&region);
+                                       free(sub_bits);
+                                       assert(0);
+                                       return NULL;
+                               }
+                               if (boxes[j].x1 != x || temp_stride != stride)
+                                       glamor_get_bits(bits, stride, temp_bits, temp_stride,
+                                                       pixmap->drawable.bitsPerPixel,
+                                                       boxes[j].x1 - x , boxes[j].y1 - y,
+                                                       boxes[j].x2 - boxes[j].x1,
+                                                       boxes[j].y2 - boxes[j].y1);
+                       }
+
+                       RegionDestroy(clipped_regions[i].region);
+               }
+               free(sub_bits);
+               free(clipped_regions);
+               RegionUninit(&region);
+               return bits;
+       } else
+       return _glamor_download_sub_pixmap_to_cpu(pixmap, format, type, no_alpha, revert, swap_rb,
+                                                 x, y, w, h, stride,
+                                                 bits, pbo, access);
+}
+
 
 /**
  * Move a pixmap to CPU memory.
@@ -984,7 +1190,8 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 
        if (access == GLAMOR_ACCESS_WO
            || glamor_priv->gl_flavor == GLAMOR_GL_ES2
-           || (!glamor_priv->has_pack_invert && !glamor_priv->yInverted)) {
+           || (!glamor_priv->has_pack_invert && !glamor_priv->yInverted)
+           || pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
                data = malloc(stride * pixmap->drawable.height);
        } else {
                dispatch = glamor_get_dispatch(glamor_priv);
@@ -1024,6 +1231,7 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 }
 
 /* fixup a fbo to the exact size as the pixmap. */
+/* XXX LARGE pixmap? */
 Bool
 glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv)
 {
@@ -1038,8 +1246,7 @@ glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv)
 
        drawable = &pixmap_priv->base.pixmap->drawable;
 
-       if (pixmap_priv->base.pixmap->drawable.width == pixmap_priv->base.fbo->width
-           && pixmap_priv->base.pixmap->drawable.height == pixmap_priv->base.fbo->height)
+       if (!GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(pixmap_priv))
                return  TRUE;
 
        old_fbo = pixmap_priv->base.fbo;
@@ -1058,7 +1265,7 @@ glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv)
 
        scratch_priv = glamor_get_pixmap_private(scratch);
 
-       if (!scratch_priv || !scratch_priv->base.fbo)
+       if (!scratch_priv->base.fbo)
                goto fail;
 
        ValidateGC(&scratch->drawable, gc);
@@ -1111,14 +1318,13 @@ glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_acces
        void *data;
        int pbo;
        int flag;
-
-       assert(x >= 0 && y >= 0);
+       if (x < 0 || y < 0)
+               return NULL;
        w = (x + w) > pixmap->drawable.width ? (pixmap->drawable.width - x) : w;
        h = (y + h) > pixmap->drawable.height ? (pixmap->drawable.height - y) : h;
        if (access == GLAMOR_ACCESS_WO) {
                sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
                                                  pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
-               ErrorF("WO\n");
                return sub_pixmap;
        }
 
@@ -1127,7 +1333,7 @@ glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_acces
 
        if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
                return NULL;
-       if (glamor_priv->gl_flavor == GLAMOR_GL_ES2)
+       if (glamor_priv->gl_flavor == GLAMOR_GL_ES2 || pixmap_priv->type == GLAMOR_TEXTURE_LARGE)
                flag = GLAMOR_CREATE_PIXMAP_CPU;
        else
                flag = GLAMOR_CREATE_PIXMAP_MAP;
@@ -1141,17 +1347,16 @@ glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_acces
        sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
        pbo = sub_pixmap_priv ? (sub_pixmap_priv->base.fbo ? sub_pixmap_priv->base.fbo->pbo : 0): 0;
 
-       if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv)) {
+       if (pixmap_priv->base.is_picture) {
                sub_pixmap_priv->base.picture = pixmap_priv->base.picture;
                sub_pixmap_priv->base.is_picture = pixmap_priv->base.is_picture;
        }
 
        if (pbo)
                data = NULL;
-       else {
+       else
                data = sub_pixmap->devPrivate.ptr;
-               assert(flag != GLAMOR_CREATE_PIXMAP_MAP);
-       }
+
        data = glamor_download_sub_pixmap_to_cpu(pixmap, x, y, w, h, sub_pixmap->devKind,
                                                 data, pbo, access);
        if (pbo) {
@@ -1173,7 +1378,7 @@ glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_acces
 
        new_sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
                                              pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
-       glamor_copy_n_to_n(&pixmap->drawable, &new_sub_pixmap, NULL, &box, 1, dx, dy, 0, 0, 0, NULL);
+       glamor_copy_n_to_n(&pixmap->drawable, &new_sub_pixmap->drawable, NULL, &box, 1, dx, dy, 0, 0, 0, NULL);
        glamor_compare_pixmaps(new_sub_pixmap, sub_pixmap, 0, 0, w, h, 1, 1);
 #endif
 
@@ -1188,8 +1393,7 @@ glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y, int
        glamor_pixmap_private *sub_pixmap_priv;
        if (access != GLAMOR_ACCESS_RO) {
                sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
-               if (sub_pixmap_priv
-                   && sub_pixmap_priv->base.fbo
+               if (sub_pixmap_priv->base.fbo
                    && sub_pixmap_priv->base.fbo->pbo_valid) {
                        bits = NULL;
                        pbo = sub_pixmap_priv->base.fbo->pbo;
index 2172d17..d9f6438 100644 (file)
@@ -927,6 +927,9 @@ glamor_poly_line(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
 #ifndef GLAMOR_GLES2
 #define GLAMOR_GRADIENT_SHADER
 #endif
-#define GLAMOR_TEXTURED_LARGE_PIXMAP 1
+#define GLAMOR_TEXTURED_LARGE_PIXMAP 0
+#if 0
+#define MAX_FBO_SIZE 512 /* For test purpose only. */
+#endif
 
 #endif                         /* GLAMOR_PRIV_H */
index 6a584ba..48a5bb3 100644 (file)
 #ifdef RENDER
 #include "mipict.h"
 #include "fbpict.h"
-
+#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
 struct shader_key {
        enum shader_source source;
        enum shader_mask mask;
@@ -606,18 +611,20 @@ glamor_set_composite_texture(ScreenPtr screen, int unit,
 #endif
        /* XXX may be we can eaxctly check whether we need to touch
         * the out-of-box area then determine whether we need to fix.
-        * */
-       if (repeat_type != RepeatNone)
-               repeat_type += RepeatFix;
-       else if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
-               if (picture->transform
-                  || (GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(pixmap_priv)))
+        **/
+       /*if (pixmap_priv->type != GLAMOR_TEXTURE_LARGE)*/ {
+               if (repeat_type != RepeatNone)
                        repeat_type += RepeatFix;
-       }
-
-       if (repeat_type >= RepeatFix) {
-               glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap_priv);
-               dispatch->glUniform2fv(wh_location, 1, wh);
+               else if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
+                        || pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+                       if (picture->transform
+                          || (GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(pixmap_priv)))
+                               repeat_type += RepeatFix;
+               }
+               if (repeat_type >= RepeatFix) {
+                       glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap_priv);
+                       dispatch->glUniform2fv(wh_location, 1, wh);
+               }
        }
        dispatch->glUniform1i(repeat_location, repeat_type);
        glamor_put_dispatch(glamor_priv);
@@ -687,53 +694,44 @@ glamor_composite_with_copy(CARD8 op,
                           INT16 x_source,
                           INT16 y_source,
                           INT16 x_dest,
-                          INT16 y_dest, CARD16 width, CARD16 height)
+                          INT16 y_dest,
+                          RegionPtr region)
 {
-       RegionRec region;
        int ret = FALSE;
-
        if (!source->pDrawable)
                return FALSE;
 
        if (!compatible_formats(op, dest, source))
                return FALSE;
 
-       if (source->repeat || source->transform)
+       if (source->repeat || source->transform) {
                return FALSE;
+       }
 
        x_dest += dest->pDrawable->x;
        y_dest += dest->pDrawable->y;
        x_source += source->pDrawable->x;
        y_source += source->pDrawable->y;
-       if (!miComputeCompositeRegion(&region,
-                                     source, NULL, dest,
-                                     x_source, y_source,
-                                     0, 0, x_dest, y_dest, width, height))
-               return TRUE;
-
        if (PICT_FORMAT_A(source->format) == 0) {
                /* Fallback if we sample outside the source so that we
                 * swizzle the correct clear color for out-of-bounds texels.
                 */
-               if (region.extents.x1 + x_source - x_dest < 0)
+               if (region->extents.x1 + x_source - x_dest < 0)
                        goto cleanup_region;
-               if (region.extents.x2 + x_source - x_dest > source->pDrawable->width)
+               if (region->extents.x2 + x_source - x_dest > source->pDrawable->width)
                        goto cleanup_region;
 
-               if (region.extents.y1 + y_source - y_dest < 0)
+               if (region->extents.y1 + y_source - y_dest < 0)
                        goto cleanup_region;
-               if (region.extents.y2 + y_source - y_dest > source->pDrawable->height)
+               if (region->extents.y2 + y_source - y_dest > source->pDrawable->height)
                        goto cleanup_region;
        }
-
        ret = glamor_copy_n_to_n_nf(source->pDrawable,
                                    dest->pDrawable, NULL,
-                                   REGION_RECTS(&region),
-                                   REGION_NUM_RECTS(&region),
+                                   RegionRects(region), RegionNumRects(region),
                                    x_source - x_dest, y_source - y_dest,
                                    FALSE, FALSE, 0, NULL);
 cleanup_region:
-       REGION_UNINIT(dest->pDrawable->pScreen, &region);
        return ret;
 }
 
@@ -929,12 +927,44 @@ combine_pict_format(PictFormatShort * des, const PictFormatShort src,
        return FALSE;
 }
 
+static void
+glamor_set_normalize_tcoords_generic(glamor_pixmap_private *priv,
+                                    int repeat_type,
+                                    float *matrix,
+                                    float xscale, float yscale,
+                                    int x1, int y1, int x2, int y2,
+                                    int yInverted, float *texcoords)
+{
+       if (!matrix && repeat_type == RepeatNone)
+               glamor_set_normalize_tcoords(priv, xscale, yscale,
+                                            x1, y1,
+                                            x2, y2,
+                                            yInverted,
+                                            texcoords);
+       else if (matrix && repeat_type == RepeatNone)
+               glamor_set_transformed_normalize_tcoords(priv, matrix, xscale,
+                                                        yscale, x1, y1,
+                                                        x2, y2,
+                                                        yInverted,
+                                                        texcoords);
+       else if (!matrix && repeat_type != RepeatNone)
+               glamor_set_repeat_normalize_tcoords(priv, repeat_type,
+                                                   xscale, yscale,
+                                                   x1, y1,
+                                                   x2, y2,
+                                                   yInverted,
+                                                   texcoords);
+       else if (matrix && repeat_type != RepeatNone)
+               assert(0);
+}
+
 static Bool
 glamor_composite_with_shader(CARD8 op,
                             PicturePtr source,
                             PicturePtr mask,
                             PicturePtr dest,
-                            int nrect, glamor_composite_rect_t * rects)
+                            int nrect,
+                            glamor_composite_rect_t * rects)
 {
        ScreenPtr screen = dest->pDrawable->pScreen;
        glamor_screen_private *glamor_priv =
@@ -959,6 +989,7 @@ glamor_composite_with_shader(CARD8 op,
        enum glamor_pixmap_status mask_status = GLAMOR_NONE;
        PictFormatShort saved_source_format = 0;
        float src_matrix[9], mask_matrix[9];
+       float *psrc_matrix = NULL, *pmask_matrix = NULL;
        GLfloat source_solid_color[4], mask_solid_color[4];
        int vert_stride = 4;
        int nrect_max;
@@ -970,20 +1001,23 @@ glamor_composite_with_shader(CARD8 op,
                goto fail;
        }
        memset(&key, 0, sizeof(key));
-       if (!source->pDrawable) {
-               if (source->pSourcePict->type == SourcePictTypeSolidFill) {
-                       key.source = SHADER_SOURCE_SOLID;
-                       glamor_get_rgba_from_pixel(source->
-                                                  pSourcePict->solidFill.
-                                                  color,
-                                                  &source_solid_color[0],
-                                                  &source_solid_color[1],
-                                                  &source_solid_color[2],
-                                                  &source_solid_color[3],
-                                                  PICT_a8r8g8b8);
-               } else {
-                       glamor_fallback("gradient source\n");
-                       goto fail;
+       if (!source) {
+               key.source = SHADER_SOURCE_SOLID;
+               source_solid_color[0] = 0.0;
+               source_solid_color[1] = 0.0;
+               source_solid_color[2] = 0.0;
+               source_solid_color[3] = 0.0;
+       } else if (!source->pDrawable) {
+                       if (source->pSourcePict->type == SourcePictTypeSolidFill) {
+                               key.source = SHADER_SOURCE_SOLID;
+                               glamor_get_rgba_from_pixel(source->
+                                                          pSourcePict->solidFill.
+                                                          color,
+                                                          &source_solid_color[0],
+                                                          &source_solid_color[1],
+                                                          &source_solid_color[2],
+                                                          &source_solid_color[3],
+                                                          PICT_a8r8g8b8);
                }
        } else {
                key.source = SHADER_SOURCE_TEXTURE_ALPHA;
@@ -999,9 +1033,6 @@ glamor_composite_with_shader(CARD8 op,
                                     &mask_solid_color[1],
                                     &mask_solid_color[2],
                                     &mask_solid_color[3], PICT_a8r8g8b8);
-                       } else {
-                               glamor_fallback("gradient mask\n");
-                               goto fail;
                        }
                } else {
                        key.mask = SHADER_MASK_TEXTURE_ALPHA;
@@ -1029,7 +1060,7 @@ glamor_composite_with_shader(CARD8 op,
                key.in = SHADER_IN_SOURCE_ONLY;
        }
 
-       if (source->alphaMap) {
+       if (source && source->alphaMap) {
                glamor_fallback("source alphaMap\n");
                goto fail;
        }
@@ -1044,13 +1075,14 @@ glamor_composite_with_shader(CARD8 op,
                source_pixmap_priv =
                    glamor_get_pixmap_private(source_pixmap);
                if (source_pixmap == dest_pixmap) {
+                       /* XXX source and the dest share the same texture.
+                        * Does it need special handle? */
                        glamor_fallback("source == dest\n");
-                       goto fail;
                }
-               if (!source_pixmap_priv || source_pixmap_priv->base.gl_fbo == 0) {
-                       /* XXX in Xephyr, we may have gl_fbo equal to 1 but gl_tex 
+               if (source_pixmap_priv->base.gl_fbo == 0) {
+                       /* XXX in Xephyr, we may have gl_fbo equal to 1 but gl_tex
                         * equal to zero when the pixmap is screen pixmap. Then we may
-                        * refer the tex zero directly latter in the composition. 
+                        * refer the tex zero directly latter in the composition.
                         * It seems that it works fine, but it may have potential problem*/
 #ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
                        source_status = GLAMOR_UPLOAD_PENDING;
@@ -1068,7 +1100,7 @@ glamor_composite_with_shader(CARD8 op,
                        glamor_fallback("mask == dest\n");
                        goto fail;
                }
-               if (!mask_pixmap_priv || mask_pixmap_priv->base.gl_fbo == 0) {
+               if (mask_pixmap_priv->base.gl_fbo == 0) {
 #ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
                        mask_status = GLAMOR_UPLOAD_PENDING;
 #else
@@ -1095,20 +1127,20 @@ glamor_composite_with_shader(CARD8 op,
                        }
 
                        if (source->format != saved_source_format) {
-                               glamor_picture_format_fixup(source,
-                                                           source_pixmap_priv);
+                               //glamor_picture_format_fixup(source,
+                               //                          source_pixmap_priv);
                        }
-                       /* XXX  
+                       /* XXX
                         * By default, glamor_upload_picture_to_texture will wire alpha to 1
-                        * if one picture doesn't have alpha. So we don't do that again in 
+                        * if one picture doesn't have alpha. So we don't do that again in
                         * rendering function. But here is a special case, as source and
-                        * mask share the same texture but may have different formats. For 
+                        * mask share the same texture but may have different formats. For
                         * example, source doesn't have alpha, but mask has alpha. Then the
                         * texture will have the alpha value for the mask. And will not wire
                         * to 1 for the source. In this case, we have to use different shader
                         * to wire the source's alpha to 1.
                         *
-                        * But this may cause a potential problem if the source's repeat mode 
+                        * But this may cause a potential problem if the source's repeat mode
                         * is REPEAT_NONE, and if the source is smaller than the dest, then
                         * for the region not covered by the source may be painted incorrectly.
                         * because we wire the alpha to 1.
@@ -1156,13 +1188,15 @@ glamor_composite_with_shader(CARD8 op,
         * transformed source and mask, if the transform is not int translate. */
        if (key.source != SHADER_SOURCE_SOLID
            && source->transform
-           && !pixman_transform_is_int_translate(source->transform)) {
+           && !pixman_transform_is_int_translate(source->transform)
+           && source_pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
                if (!glamor_fixup_pixmap_priv(screen, source_pixmap_priv))
                        goto fail;
        }
        if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID
            && mask->transform
-           && !pixman_transform_is_int_translate(mask->transform)) {
+           && !pixman_transform_is_int_translate(mask->transform)
+           && mask_pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
                if (!glamor_fixup_pixmap_priv(screen, mask_pixmap_priv))
                        goto fail;
        }
@@ -1217,7 +1251,10 @@ glamor_composite_with_shader(CARD8 op,
                                           &source_y_off);
                pixmap_priv_get_scale(source_pixmap_priv, &src_xscale,
                                      &src_yscale);
-               glamor_picture_get_matrixf(source, src_matrix);
+               if (source->transform) {
+                       psrc_matrix = src_matrix;
+                       glamor_picture_get_matrixf(source, psrc_matrix);
+               }
                vert_stride += 4;
        }
 
@@ -1226,7 +1263,10 @@ glamor_composite_with_shader(CARD8 op,
                                           &mask_x_off, &mask_y_off);
                pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale,
                                      &mask_yscale);
-               glamor_picture_get_matrixf(mask, mask_matrix);
+               if (mask->transform) {
+                       pmask_matrix = mask_matrix;
+                       glamor_picture_get_matrixf(mask, pmask_matrix);
+               }
                vert_stride += 4;
        }
 
@@ -1252,13 +1292,16 @@ glamor_composite_with_shader(CARD8 op,
 
                        x_dest = rects->x_dst + dest_x_off;
                        y_dest = rects->y_dst + dest_y_off;
-                       x_source = rects->x_src + source_x_off;;
+                       x_source = rects->x_src + source_x_off;
                        y_source = rects->y_src + source_y_off;
                        x_mask = rects->x_mask + mask_x_off;
                        y_mask = rects->y_mask + mask_y_off;
                        width = rects->width;
                        height = rects->height;
 
+                       DEBUGF("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n",
+                               x_dest, y_dest, x_source, y_source,x_mask,y_mask,width,height);
+
                        glamor_set_normalize_vcoords(dest_pixmap_priv, dst_xscale,
                                                     dst_yscale,
                                                     x_dest, y_dest,
@@ -1266,41 +1309,21 @@ glamor_composite_with_shader(CARD8 op,
                                                     glamor_priv->yInverted,
                                                     vertices);
 
-                       if (key.source != SHADER_SOURCE_SOLID) {
-                               if (source->transform)
-                                       glamor_set_transformed_normalize_tcoords
-                                               (source_pixmap_priv, src_matrix, src_xscale,
-                                                src_yscale, x_source, y_source,
-                                                x_source + width, y_source + height,
-                                                glamor_priv->yInverted,
-                                                source_texcoords);
-                               else
-                                       glamor_set_normalize_tcoords
-                                               (source_pixmap_priv, src_xscale, src_yscale,
-                                                x_source, y_source,
-                                                x_source + width, y_source + height,
-                                                glamor_priv->yInverted,
-                                                source_texcoords);
-                       }
+                       if (key.source != SHADER_SOURCE_SOLID)
+                               glamor_set_normalize_tcoords_generic(
+                                       source_pixmap_priv, source->repeatType, psrc_matrix,
+                                       src_xscale, src_yscale, x_source, y_source,
+                                       x_source + width, y_source + height,
+                                       glamor_priv->yInverted, source_texcoords);
 
                        if (key.mask != SHADER_MASK_NONE
-                           && key.mask != SHADER_MASK_SOLID) {
-                               if (mask->transform)
-                                       glamor_set_transformed_normalize_tcoords
-                                               (mask_pixmap_priv, mask_matrix,
-                                                mask_xscale,
-                                                mask_yscale, x_mask, y_mask,
-                                                x_mask + width, y_mask + height,
-                                                glamor_priv->yInverted,
-                                                mask_texcoords);
-                               else
-                                       glamor_set_normalize_tcoords
-                                               (mask_pixmap_priv, mask_xscale,
-                                                mask_yscale, x_mask, y_mask,
-                                                x_mask + width, y_mask + height,
-                                                glamor_priv->yInverted,
-                                                mask_texcoords);
-                       }
+                           && key.mask != SHADER_MASK_SOLID)
+                               glamor_set_normalize_tcoords_generic(
+                                       mask_pixmap_priv, mask->repeatType, pmask_matrix,
+                                       mask_xscale, mask_yscale, x_mask, y_mask,
+                                       x_mask + width, y_mask + height,
+                                       glamor_priv->yInverted, mask_texcoords);
+
                        glamor_emit_composite_rect(screen,
                                                   source_texcoords,
                                                   mask_texcoords,
@@ -1323,6 +1346,7 @@ glamor_composite_with_shader(CARD8 op,
        dispatch->glActiveTexture(GL_TEXTURE1);
        dispatch->glDisable(GL_TEXTURE_2D);
 #endif
+       DEBUGF("finish rendering.\n");
        dispatch->glUseProgram(0);
        if (saved_source_format)
                source->format = saved_source_format;
@@ -1398,17 +1422,18 @@ glamor_convert_gradient_picture(ScreenPtr screen,
        return dst;
 }
 
-static Bool
-_glamor_composite(CARD8 op,
-                 PicturePtr source,
-                 PicturePtr mask,
-                 PicturePtr dest,
-                 INT16 x_source,
-                 INT16 y_source,
-                 INT16 x_mask,
-                 INT16 y_mask,
-                 INT16 x_dest, INT16 y_dest, 
-                 CARD16 width, CARD16 height, Bool fallback)
+Bool
+glamor_composite_clipped_region(CARD8 op,
+                               PicturePtr source,
+                               PicturePtr mask,
+                               PicturePtr dest,
+                               RegionPtr region,
+                               int x_source,
+                               int y_source,
+                               int x_mask,
+                               int y_mask,
+                               int x_dest,
+                               int y_dest)
 {
        ScreenPtr screen = dest->pDrawable->pScreen;
        glamor_pixmap_private *dest_pixmap_priv;
@@ -1419,80 +1444,63 @@ _glamor_composite(CARD8 op,
        PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
        PicturePtr temp_src = source, temp_mask = mask;
        int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask;
+
+       BoxPtr extent;
        glamor_composite_rect_t rect[10];
        glamor_composite_rect_t *prect = rect;
        int prect_size = ARRAY_SIZE(rect);
-       glamor_screen_private *glamor_priv =
-           glamor_get_screen_private(screen);
-       Bool ret = TRUE;
-       RegionRec region;
+       int ok = FALSE;
+       int i;
+       int width;
+       int height;
        BoxPtr box;
-       int nbox, i, ok = FALSE;
-       PixmapPtr sub_dest_pixmap = NULL;
-       PixmapPtr sub_source_pixmap = NULL;
-       PixmapPtr sub_mask_pixmap = NULL;
-       int dest_x_off, dest_y_off, saved_dest_x = 0, saved_dest_y = 0;
-       int source_x_off, source_y_off, saved_source_x = 0, saved_source_y = 0;
-       int mask_x_off, mask_y_off, saved_mask_x = 0, saved_mask_y = 0;
-       DrawablePtr saved_dest_drawable = NULL;
-       DrawablePtr saved_source_drawable = NULL;
-       DrawablePtr saved_mask_drawable = NULL;
+       int nbox;
+       extent = RegionExtents(region);
+       box = RegionRects(region);
+       nbox = RegionNumRects(region);
+       width = extent->x2 - extent->x1;
+       height = extent->y2 - extent->y1;
 
        x_temp_src = x_source;
        y_temp_src = y_source;
        x_temp_mask = x_mask;
        y_temp_mask = y_mask;
-
-       DEBUGF("Composite Src: (%d, %d)\n"
-              "         Mask: (%d, %d)\n"
-              "       to dst: (%d, %d), size: %d X %d \n",
-              x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
+       DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n",
+               x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
+       DEBUGF("dest pixmap %p ", dest_pixmap);
 
        dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
        /* Currently. Always fallback to cpu if destination is in CPU memory. */
 
-       if (source->pDrawable) {
+       if (source && source->pDrawable) {
                source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
                source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
-               if (source_pixmap_priv && source_pixmap_priv->type == GLAMOR_DRM_ONLY)
-                       goto fail;
        }
 
        if (mask && mask->pDrawable) {
                mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
                mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
-               if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_DRM_ONLY)
-                       goto fail;
-       }
-
-       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
-               goto fail;
        }
 
-       if (op >= ARRAY_SIZE(composite_op_info))
-               goto fail;
-
-       if ((!source->pDrawable
+       /* XXX is it possible source mask have non-zero drawable.x/y? */
+       if (source
+           && ((!source->pDrawable
             && (source->pSourcePict->type != SourcePictTypeSolidFill))
            || (source->pDrawable
                && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv)
-               &&
-               ((width * height * 4 <
-                 (source_pixmap->drawable.width *
-                  source_pixmap->drawable.height))
-                ||
-                !(glamor_check_fbo_size
-                  (glamor_priv, source_pixmap->drawable.width,
-                   source_pixmap->drawable.height))))) {
+               && (source_pixmap->drawable.width != width
+                   || source_pixmap->drawable.height != height)))) {
                temp_src =
                    glamor_convert_gradient_picture(screen, source,
-                                                   x_source, y_source,
+                                                   extent->x1 + x_source - x_dest,
+                                                   extent->y1 + y_source - y_dest,
                                                    width, height);
                if (!temp_src) {
                        temp_src = source;
-                       goto fail;
+                       goto out;
                }
-               x_temp_src = y_temp_src = 0;
+               x_temp_src = - extent->x1 + x_dest;
+               y_temp_src = - extent->y1 + y_dest;
        }
 
        if (mask
@@ -1500,26 +1508,22 @@ _glamor_composite(CARD8 op,
            ((!mask->pDrawable
              && (mask->pSourcePict->type != SourcePictTypeSolidFill))
             || (mask->pDrawable
-                && (!GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv))
-                &&
-                ((width * height * 4 <
-                  (mask_pixmap->drawable.width *
-                   mask_pixmap->drawable.height))
-                 ||
-                 !(glamor_check_fbo_size
-                   (glamor_priv, mask_pixmap->drawable.width,
-                    mask_pixmap->drawable.height)))))) {
+                && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv)
+                && (mask_pixmap->drawable.width != width
+                   || mask_pixmap->drawable.height != height)))) {
                /* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity
                 * to do reduce one convertion. */
                temp_mask =
                    glamor_convert_gradient_picture(screen, mask,
-                                                   x_mask, y_mask,
+                                                   extent->x1 + x_mask - x_dest,
+                                                   extent->y1 + y_mask - y_dest,
                                                    width, height);
                if (!temp_mask) {
                        temp_mask = mask;
-                       goto fail;
+                       goto out;
                }
-               x_temp_mask = y_temp_mask = 0;
+               x_temp_mask = - extent->x1 + x_dest;
+               y_temp_mask = - extent->y1 + y_dest;
        }
        /* Do two-pass PictOpOver componentAlpha, until we enable
         * dual source color blending.
@@ -1527,43 +1531,38 @@ _glamor_composite(CARD8 op,
 
        if (mask && mask->componentAlpha) {
                if (op == PictOpOver) {
-                       glamor_composite(PictOpOutReverse,
-                                        temp_src, temp_mask, dest,
-                                        x_temp_src, y_temp_src,
-                                        x_temp_mask, y_temp_mask,
-                                        x_dest, y_dest, width, height);
-                       glamor_composite(PictOpAdd,
-                                        temp_src, temp_mask, dest,
-                                        x_temp_src, y_temp_src,
-                                        x_temp_mask, y_temp_mask,
-                                        x_dest, y_dest, width, height);
-                       goto done;
-
-               } else if (op == PictOpAtop
-                          || op == PictOpAtopReverse
-                          || op == PictOpXor
-                          || op >= PictOpSaturate) {
-                               glamor_fallback
-                                       ("glamor_composite(): component alpha op %x\n", op);
-                               goto fail;
+                       glamor_composite_clipped_region(PictOpOutReverse,
+                                                       temp_src, temp_mask, dest,
+                                                       region,
+                                                       x_temp_src, y_temp_src,
+                                                       x_temp_mask, y_temp_mask,
+                                                       x_dest, y_dest);
+
+                       glamor_composite_clipped_region(PictOpAdd,
+                                                       temp_src, temp_mask, dest,
+                                                       region,
+                                                       x_temp_src, y_temp_src,
+                                                       x_temp_mask, y_temp_mask,
+                                                       x_dest, y_dest);
+                       ok = TRUE;
+                       goto out;
                }
        }
 
-       if (!mask) {
+       if (!mask && temp_src) {
                if (glamor_composite_with_copy(op, temp_src, dest,
                                               x_temp_src, y_temp_src,
-                                              x_dest, y_dest, width,
-                                              height))
-                       goto done;
+                                              x_dest, y_dest, region)) {
+                       ok = TRUE;
+                       goto out;
+               }
        }
 
-       /*XXXXX, maybe we can make a copy of dest pixmap.*/
-       if (source_pixmap == dest_pixmap)
-               goto full_fallback;
+       /*XXXXX, self copy?*/
 
        x_dest += dest->pDrawable->x;
        y_dest += dest->pDrawable->y;
-       if (temp_src->pDrawable) {
+       if (temp_src && temp_src->pDrawable) {
                x_temp_src += temp_src->pDrawable->x;
                y_temp_src += temp_src->pDrawable->y;
        }
@@ -1571,16 +1570,6 @@ _glamor_composite(CARD8 op,
                x_temp_mask += temp_mask->pDrawable->x;
                y_temp_mask += temp_mask->pDrawable->y;
        }
-       if (!miComputeCompositeRegion(&region,
-                                     temp_src, temp_mask, dest,
-                                     x_temp_src, y_temp_src,
-                                     x_temp_mask, y_temp_mask,
-                                     x_dest, y_dest, width,
-                                     height))
-               goto done;
-
-       box = REGION_RECTS(&region);
-       nbox = REGION_NUM_RECTS(&region);
 
        if (nbox > ARRAY_SIZE(rect)) {
                prect = calloc(nbox, sizeof(*prect));
@@ -1612,15 +1601,153 @@ _glamor_composite(CARD8 op,
                box += box_cnt;
        }
 
+       if (prect != rect)
+               free(prect);
+out:
+       if (temp_src != source)
+               FreePicture(temp_src, 0);
+       if (temp_mask != mask)
+               FreePicture(temp_mask, 0);
+
+       return ok;
+}
+
+static Bool
+_glamor_composite(CARD8 op,
+                 PicturePtr source,
+                 PicturePtr mask,
+                 PicturePtr dest,
+                 INT16 x_source,
+                 INT16 y_source,
+                 INT16 x_mask,
+                 INT16 y_mask,
+                 INT16 x_dest, INT16 y_dest,
+                 CARD16 width, CARD16 height, Bool fallback)
+{
+       ScreenPtr screen = dest->pDrawable->pScreen;
+       glamor_pixmap_private *dest_pixmap_priv;
+       glamor_pixmap_private *source_pixmap_priv =
+           NULL, *mask_pixmap_priv = NULL;
+       PixmapPtr dest_pixmap =
+           glamor_get_drawable_pixmap(dest->pDrawable);
+       PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
+       glamor_screen_private *glamor_priv =
+           glamor_get_screen_private(screen);
+       Bool ret = TRUE;
+       RegionRec region;
+       BoxPtr box, extent;
+       int nbox, ok = FALSE;
+       PixmapPtr sub_dest_pixmap = NULL;
+       PixmapPtr sub_source_pixmap = NULL;
+       PixmapPtr sub_mask_pixmap = NULL;
+       int dest_x_off, dest_y_off, saved_dest_x, saved_dest_y;
+       int source_x_off, source_y_off, saved_source_x, saved_source_y;
+       int mask_x_off, mask_y_off, saved_mask_x, saved_mask_y;
+       DrawablePtr saved_dest_drawable;
+       DrawablePtr saved_source_drawable;
+       DrawablePtr saved_mask_drawable;
+       int force_clip = 0;
+
+       dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+
+       if (source->pDrawable) {
+               source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
+               source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
+               if (source_pixmap_priv && source_pixmap_priv->type == GLAMOR_DRM_ONLY)
+                       goto fail;
+       }
+
+       if (mask && mask->pDrawable) {
+               mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
+               mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
+               if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_DRM_ONLY)
+                       goto fail;
+       }
+
+       DEBUGF("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n",
+               source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
+
+       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
+               goto fail;
+       }
+
+       if (op >= ARRAY_SIZE(composite_op_info))
+               goto fail;
+
+       if (mask && mask->componentAlpha) {
+               if (op == PictOpAtop
+                   || op == PictOpAtopReverse
+                   || op == PictOpXor
+                   || op >= PictOpSaturate) {
+                       glamor_fallback
+                               ("glamor_composite(): component alpha op %x\n", op);
+                       goto fail;
+               }
+       }
+
+       if (!miComputeCompositeRegion(&region,
+                                     source, mask, dest,
+                                     x_source + (source_pixmap ? source->pDrawable->x : 0),
+                                     y_source + (source_pixmap ? source->pDrawable->y : 0),
+                                     x_mask + (mask_pixmap ? mask->pDrawable->x : 0),
+                                     y_mask + (mask_pixmap ? mask->pDrawable->y : 0),
+                                     x_dest + dest->pDrawable->x,
+                                     y_dest + dest->pDrawable->y,
+                                     width,
+                                     height)) {
+               ret = TRUE;
+               goto done;
+       }
+
+       box = REGION_RECTS(&region);
+       nbox = REGION_NUM_RECTS(&region);
+       DEBUGF("first clipped when compositing.\n");
+       DEBUGRegionPrint(&region);
+       extent = RegionExtents(&region);
+       if (nbox == 0) {
+               ret = TRUE;
+               goto done;
+       }
+       /* If destination is not a large pixmap, but the region is larger
+        * than texture size limitation, and source or mask is memory pixmap,
+        * then there may be need to load a large memory pixmap to a
+        * texture, and this is not permitted. Then we force to clip the
+        * destination and make sure latter will not upload a large memory
+        * pixmap. */
+       if (!glamor_check_fbo_size(glamor_priv,
+               extent->x2 - extent->x1, extent->y2 - extent->y1)
+          && (dest_pixmap_priv->type != GLAMOR_TEXTURE_LARGE)
+           && ((source_pixmap_priv
+               && source_pixmap_priv->type == GLAMOR_MEMORY)
+            || (mask_pixmap_priv
+               && mask_pixmap_priv->type == GLAMOR_MEMORY)
+            || (!source_pixmap_priv
+                  && (source->pSourcePict->type != SourcePictTypeSolidFill))
+            || (!mask_pixmap_priv && mask
+                 && mask->pSourcePict->type != SourcePictTypeSolidFill)))
+               force_clip = 1;
+
+       if (force_clip || dest_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
+           || (source_pixmap_priv
+               && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE)
+           || (mask_pixmap_priv
+               && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE))
+               goto fail;
+       else
+               ok = glamor_composite_clipped_region(op, source,
+                                                    mask, dest, &region,
+                                                    x_source, y_source,
+                                                    x_mask, y_mask,
+                                                    x_dest, y_dest);
+
        REGION_UNINIT(dest->pDrawable->pScreen, &region);
        if (ok)
                goto done;
-
 fail:
 
        if (!fallback
            && glamor_ddx_fallback_check_pixmap(&dest_pixmap->drawable)
-           && (!source_pixmap 
+           && (!source_pixmap
                || glamor_ddx_fallback_check_pixmap(&source_pixmap->drawable))
            && (!mask_pixmap
                || glamor_ddx_fallback_check_pixmap(&mask_pixmap->drawable))) {
@@ -1662,13 +1789,11 @@ fail:
                x_ ##p = 0;                                                             \
                y_ ##p = 0;                                                             \
        } } while(0)
-
        GET_SUB_PICTURE(dest, GLAMOR_ACCESS_RW);
-       if (source->pDrawable)
+       if (source->pDrawable && !source->transform)
                GET_SUB_PICTURE(source, GLAMOR_ACCESS_RO);
-       if (mask && mask->pDrawable)
+       if (mask && mask->pDrawable && !mask->transform)
                GET_SUB_PICTURE(mask, GLAMOR_ACCESS_RO);
-
 full_fallback:
        if (glamor_prepare_access_picture(dest, GLAMOR_ACCESS_RW)) {
                if (source_pixmap == dest_pixmap || glamor_prepare_access_picture
@@ -1711,12 +1836,6 @@ full_fallback:
                PUT_SUB_PICTURE(source, GLAMOR_ACCESS_RO);
        PUT_SUB_PICTURE(dest, GLAMOR_ACCESS_RW);
       done:
-       if (temp_src != source)
-               FreePicture(temp_src, 0);
-       if (temp_mask != mask)
-               FreePicture(temp_mask, 0);
-       if (prect != rect)
-               free(prect);
        return ret;
 }
 
@@ -1754,9 +1873,6 @@ glamor_composite_nf(CARD8 op,
                                 FALSE);
 }
 
-
-
-
 /**
  * Creates an appropriate picture to upload our alpha mask into (which
  * we calculated in system memory)
@@ -1797,7 +1913,7 @@ glamor_create_mask_picture(ScreenPtr screen,
  * glamor_trapezoids is a copy of miTrapezoids that does all the trapezoid
  * accumulation in system memory.
  */
-static Bool 
+static Bool
 _glamor_trapezoids(CARD8 op,
                  PicturePtr src, PicturePtr dst,
                  PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
@@ -1885,7 +2001,7 @@ glamor_trapezoids(CARD8 op,
                  PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
                  int ntrap, xTrapezoid * traps)
 {
-       _glamor_trapezoids(op, src, dst, mask_format, x_src, 
+       _glamor_trapezoids(op, src, dst, mask_format, x_src,
                           y_src, ntrap, traps, TRUE);
 }
 
@@ -1895,7 +2011,7 @@ glamor_trapezoids_nf(CARD8 op,
                     PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
                     int ntrap, xTrapezoid * traps)
 {
-       return _glamor_trapezoids(op, src, dst, mask_format, x_src, 
+       return _glamor_trapezoids(op, src, dst, mask_format, x_src,
                                  y_src, ntrap, traps, FALSE);
 }
 
@@ -1912,8 +2028,12 @@ glamor_composite_glyph_rects(CARD8 op,
        ValidatePicture(src);
        ValidatePicture(dst);
 
-       if (glamor_composite_with_shader(op, src, mask, dst, nrect, rects))
-               return;
+       if (!(glamor_is_large_picture(src)
+           || (mask && glamor_is_large_picture(mask))
+           || glamor_is_large_picture(dst))) {
+               if (glamor_composite_with_shader(op, src, mask, dst, nrect, rects))
+                       return;
+       }
 
        n = nrect;
        r = rects;
index c6b88d2..871479b 100644 (file)
@@ -102,10 +102,9 @@ glamor_fini_tile_shader(ScreenPtr screen)
        glamor_put_dispatch(glamor_priv);
 }
 
-Bool
-glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
+static void
+_glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
            int x, int y, int width, int height,
-           unsigned char alu, unsigned long planemask,
            int tile_x, int tile_y)
 {
        ScreenPtr screen = pixmap->drawable.pScreen;
@@ -126,48 +125,17 @@ glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
        glamor_pixmap_private *src_pixmap_priv;
        glamor_pixmap_private *dst_pixmap_priv;
        float wh[2];
-
        src_pixmap_priv = glamor_get_pixmap_private(tile);
        dst_pixmap_priv = glamor_get_pixmap_private(pixmap);
 
-       if (src_pixmap_priv == NULL || dst_pixmap_priv == NULL)
-               goto fail;
-
-       if (glamor_priv->tile_prog == 0) {
-               glamor_fallback("Tiling unsupported\n");
-               goto fail;
-       }
-
-       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
-               glamor_fallback("dest has no fbo.\n");
-               goto fail;
-       }
-       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) {
-               /* XXX dynamic uploading candidate. */
-               glamor_fallback("Non-texture tile pixmap\n");
-               goto fail;
-       }
-
-       if (!glamor_set_planemask(pixmap, planemask)) {
-               glamor_fallback("unsupported planemask %lx\n", planemask);
-               goto fail;
-       }
-
        glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
        pixmap_priv_get_dest_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
-
-       dispatch = glamor_get_dispatch(glamor_priv);
-       if (!glamor_set_alu(dispatch, alu)) {
-               glamor_put_dispatch(glamor_priv);
-               goto fail;
-       }
-
        pixmap_priv_get_scale(src_pixmap_priv, &src_xscale,
                              &src_yscale);
+       dispatch = glamor_get_dispatch(glamor_priv);
        dispatch->glUseProgram(glamor_priv->tile_prog);
 
        glamor_pixmap_fbo_fix_wh_ratio(wh, src_pixmap_priv);
-
        dispatch->glUniform2fv(glamor_priv->tile_wh, 1, wh);
        dispatch->glActiveTexture(GL_TEXTURE0);
        dispatch->glBindTexture(GL_TEXTURE_2D,
@@ -185,21 +153,23 @@ glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
 #ifndef GLAMOR_GLES2
        dispatch->glEnable(GL_TEXTURE_2D);
 #endif
-       glamor_set_normalize_tcoords(src_pixmap_priv, src_xscale,
-                                    src_yscale,
-                                    tile_x1, tile_y1,
-                                    tile_x2, tile_y2,
-                                    glamor_priv->yInverted,
-                                    source_texcoords);
+       glamor_set_repeat_normalize_tcoords
+                       (src_pixmap_priv, RepeatNormal,
+                        src_xscale, src_yscale,
+                        tile_x1, tile_y1,
+                        tile_x2, tile_y2,
+                        glamor_priv->yInverted,
+                        source_texcoords);
+
        dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
                                        GL_FLOAT, GL_FALSE,
                                        2 * sizeof(float),
                                        source_texcoords);
        dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
 
-       glamor_set_normalize_vcoords(dst_pixmap_priv, dst_xscale,
-                                    dst_yscale,
-                                    x1, y1, x2, y2,
+       glamor_set_normalize_vcoords(dst_pixmap_priv, dst_xscale, dst_yscale,
+                                    x1, y1,
+                                    x2, y2,
                                     glamor_priv->yInverted, vertices);
 
        dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
@@ -214,11 +184,139 @@ glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
 #endif
        dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
        dispatch->glUseProgram(0);
+       glamor_put_dispatch(glamor_priv);
+}
+
+Bool
+glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
+           int x, int y, int width, int height,
+           unsigned char alu, unsigned long planemask,
+           int tile_x, int tile_y)
+{
+       ScreenPtr screen = pixmap->drawable.pScreen;
+       glamor_screen_private *glamor_priv =
+           glamor_get_screen_private(screen);
+       glamor_pixmap_private *dst_pixmap_priv;
+       glamor_pixmap_private *src_pixmap_priv;
+       glamor_gl_dispatch *dispatch;
+
+       dst_pixmap_priv = glamor_get_pixmap_private(pixmap);
+       src_pixmap_priv = glamor_get_pixmap_private(tile);
+
+       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv))
+               return FALSE;
+
+       if (glamor_priv->tile_prog == 0) {
+               glamor_fallback("Tiling unsupported\n");
+               goto fail;
+       }
+
+       if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) {
+               /* XXX dynamic uploading candidate. */
+               glamor_fallback("Non-texture tile pixmap\n");
+               goto fail;
+       }
+
+       if (!glamor_set_planemask(pixmap, planemask)) {
+               glamor_fallback("unsupported planemask %lx\n", planemask);
+               goto fail;
+       }
+
+       dispatch = glamor_get_dispatch(glamor_priv);
+       if (!glamor_set_alu(dispatch, alu)) {
+               glamor_fallback("unsupported alu %x\n", alu);
+               glamor_put_dispatch(glamor_priv);
+               goto fail;
+       }
+
+       if (dst_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
+           || src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+                       glamor_pixmap_clipped_regions *clipped_dst_regions;
+                       int n_dst_region, i, j, k;
+                       BoxRec box;
+                       RegionRec region;
+
+                       box.x1 = x;
+                       box.y1 = y;
+                       box.x2 = x + width;
+                       box.y2 = y + height;
+                       RegionInitBoxes(&region, &box, 1);
+                       clipped_dst_regions = glamor_compute_clipped_regions(dst_pixmap_priv,
+                                                                            &region, &n_dst_region, 0);
+                       for(i = 0; i < n_dst_region; i++)
+                       {
+                               int n_src_region;
+                               glamor_pixmap_clipped_regions *clipped_src_regions;
+                               BoxPtr current_boxes;
+                               int n_current_boxes;
+
+                               SET_PIXMAP_FBO_CURRENT(dst_pixmap_priv, clipped_dst_regions[i].block_idx);
+
+                               if (src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+                                       RegionTranslate(clipped_dst_regions[i].region,
+                                                       tile_x - x, tile_y - y);
+                                       DEBUGF("tiled a large src pixmap. %dx%d \n", tile->drawable.width, tile->drawable.height);
+                                       clipped_src_regions = glamor_compute_clipped_regions(src_pixmap_priv,
+                                                                                            clipped_dst_regions[i].region,
+                                                                                            &n_src_region, 1);
+                                       DEBUGF("got %d src regions %d \n", n_src_region);
+                                       for (j = 0; j < n_src_region; j++)
+                                       {
+
+                                               SET_PIXMAP_FBO_CURRENT(src_pixmap_priv, clipped_src_regions[j].block_idx);
+
+                                               RegionTranslate(clipped_src_regions[j].region,
+                                                               x - tile_x,
+                                                               y - tile_y);
+                                               current_boxes = RegionRects(clipped_src_regions[j].region);
+                                               n_current_boxes = RegionNumRects(clipped_src_regions[j].region);
+                                               for(k = 0; k < n_current_boxes; k++)
+                                               {
+                                                       DEBUGF("Tile on %d %d %d %d dst block id %d tile block id %d tilex %d tiley %d\n",
+                                                                    current_boxes[k].x1, current_boxes[k].y1,
+                                                                    current_boxes[k].x2 - current_boxes[k].x1,
+                                                                    current_boxes[k].y2 - current_boxes[k].y1,
+                                                                       clipped_dst_regions[i].block_idx,
+                                                                       clipped_src_regions[j].block_idx,
+                                                                    (tile_x + (current_boxes[k].x1 - x)),
+                                                                    tile_y + (current_boxes[k].y1 - y));
+
+                                                       _glamor_tile(pixmap, tile,
+                                                                    current_boxes[k].x1, current_boxes[k].y1,
+                                                                    current_boxes[k].x2 - current_boxes[k].x1,
+                                                                    current_boxes[k].y2 - current_boxes[k].y1,
+                                                                    (tile_x + (current_boxes[k].x1 - x)),
+                                                                    (tile_y + (current_boxes[k].y1 - y)));
+                                               }
+
+                                               RegionDestroy(clipped_src_regions[j].region);
+                                       }
+                                       free(clipped_src_regions);
+                               } else {
+                                       current_boxes = RegionRects(clipped_dst_regions[i].region);
+                                       n_current_boxes = RegionNumRects(clipped_dst_regions[i].region);
+                                       for(k = 0; k < n_current_boxes; k++)
+                                       {
+                                               _glamor_tile(pixmap, tile,
+                                                            current_boxes[k].x1, current_boxes[k].y1,
+                                                            current_boxes[k].x2 - current_boxes[k].x1,
+                                                            current_boxes[k].y2 - current_boxes[k].y1,
+                                                            (tile_x + (current_boxes[k].x1 - x)),
+                                                            (tile_y + (current_boxes[k].y1 - y)));
+                                       }
+                               }
+                               RegionDestroy(clipped_dst_regions[i].region);
+                       }
+                       free(clipped_dst_regions);
+                       RegionUninit(&region);
+       }
+       else
+               _glamor_tile(pixmap, tile, x, y, width, height, tile_x, tile_y);
+
        glamor_set_alu(dispatch, GXcopy);
-       glamor_set_planemask(pixmap, ~0);
        glamor_put_dispatch(glamor_priv);
        return TRUE;
-
-      fail:
+fail:
        return FALSE;
+
 }
index 90a1657..44c8175 100644 (file)
 
 #define pixmap_priv_get_dest_scale(_pixmap_priv_, _pxscale_, _pyscale_)        \
    do {                                                                        \
-    *(_pxscale_) = 1.0 / (_pixmap_priv_)->base.pixmap->drawable.width;                 \
-    *(_pyscale_) = 1.0 / (_pixmap_priv_)->base.pixmap->drawable.height;                        \
+    int w,h;                                                           \
+    PIXMAP_PRIV_GET_ACTUAL_SIZE(_pixmap_priv_, w, h);                  \
+    *(_pxscale_) = 1.0 / w;                                            \
+    *(_pyscale_) = 1.0 / h;                                            \
   } while(0)
 
 #define pixmap_priv_get_scale(_pixmap_priv_, _pxscale_, _pyscale_)     \
       }                                                                        \
   }  while(0)
 
+#define _glamor_get_repeat_coords(priv, repeat_type, tx1,      \
+                                 ty1, tx2, ty2,                \
+                                 _x1_, _y1_, _x2_,             \
+                                 _y2_, c, d, odd_x, odd_y)     \
+  do {                                                         \
+       if (repeat_type == RepeatReflect) {                     \
+               assert(0);                                      \
+       } else if (repeat_type == RepeatNormal) {               \
+               tx1 = (c - priv->box.x1);                       \
+               ty1 = (d - priv->box.y1);                       \
+               tx2 = tx1 + ((_x2_) - (_x1_));                  \
+               ty2 = ty1 + ((_y2_) - (_y1_));                  \
+       } else {                                                \
+               assert(0);                                      \
+       }                                                       \
+   } while(0)
+
+
+
+/* _x1_ ... _y2_ must be integer. */
+#define glamor_get_repeat_coords(priv, repeat_type, tx1,               \
+                                ty1, tx2, ty2, _x1_, _y1_, _x2_,       \
+                                _y2_)                                  \
+  do {                                                                 \
+       int c, d;                                                       \
+       int odd_x = 0, odd_y = 0;                                       \
+       DEBUGF("width %d box.x1 %d x2 %d y1 %d y2 %d\n",                \
+               (priv)->base.pixmap->drawable.width,                    \
+               priv->box.x1, priv->box.x2,                             \
+               priv->box.y1, priv->box.y2);                            \
+       modulus((_x1_), (priv)->base.pixmap->drawable.width, c);        \
+       modulus((_y1_), (priv)->base.pixmap->drawable.height, d);       \
+       DEBUGF("c %d d %d \n", c, d);                                   \
+       if (repeat_type == RepeatReflect) {                             \
+               odd_x = abs((_x1_ - c)                                  \
+                       / (priv->base.pixmap->drawable.width)) & 1;     \
+               odd_y = abs((_y1_ - d)                                  \
+                       / (priv->base.pixmap->drawable.height)) & 1;    \
+       }                                                               \
+       _glamor_get_repeat_coords(priv, repeat_type, tx1, ty1, tx2, ty2,\
+                                 _x1_, _y1_, _x2_, _y2_, c, d,         \
+                                 odd_x, odd_y);                        \
+   } while(0)
+
+
+
 #define glamor_transform_point(matrix, tx, ty, x, y)                   \
   do {                                                                 \
     int i;                                                             \
                                   tx2, ty2, yInverted, vertices);      \
  } while(0)
 
+#define glamor_set_repeat_normalize_tcoords(priv, repeat_type,         \
+                                           xscale, yscale,             \
+                                           _x1_, _y1_, _x2_, _y2_,     \
+                                           yInverted, vertices)        \
+  do {                                                                 \
+     float tx1, tx2, ty1, ty2;                                         \
+     if (priv->type == GLAMOR_TEXTURE_LARGE)                           \
+       glamor_get_repeat_coords((&priv->large), repeat_type,           \
+                                tx1, ty1, tx2, ty2,                    \
+                                _x1_, _y1_, _x2_, _y2_);               \
+     else {                                                            \
+       tx1 = _x1_; tx2 = _x2_; ty1 = _y1_; ty2 = _y2_;                 \
+     }                                                                 \
+     _glamor_set_normalize_tcoords(xscale, yscale, tx1, ty1,           \
+                                  tx2, ty2, yInverted, vertices);      \
+ } while(0)
+
+
 #define glamor_set_tcoords(width, height, x1, y1, x2, y2,      \
                           yInverted, vertices)                 \
     do {                                                       \
@@ -303,7 +369,7 @@ glamor_calculate_boxes_bound(BoxPtr bound, BoxPtr boxes, int nbox)
 }
 
 inline static void
-glamor_transform_boxes(BoxPtr boxes, int nbox, int dx, int dy)
+glamor_translate_boxes(BoxPtr boxes, int nbox, int dx, int dy)
 {
        int i;
        for (i = 0; i < nbox; i++) {