135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2014 Keith Packard
335c4bbdfSmrg *
435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
935c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1035c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1135c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1235c4bbdfSmrg * is" without express or implied warranty.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2035c4bbdfSmrg * OF THIS SOFTWARE.
2135c4bbdfSmrg */
2235c4bbdfSmrg
2335c4bbdfSmrg#include "glamor_priv.h"
2435c4bbdfSmrg#include "glamor_transfer.h"
2535c4bbdfSmrg#include "glamor_prepare.h"
2635c4bbdfSmrg#include "glamor_transform.h"
2735c4bbdfSmrg
2835c4bbdfSmrgstruct copy_args {
2935c4bbdfSmrg    PixmapPtr           src_pixmap;
3035c4bbdfSmrg    glamor_pixmap_fbo   *src;
3135c4bbdfSmrg    uint32_t            bitplane;
3235c4bbdfSmrg    int                 dx, dy;
3335c4bbdfSmrg};
3435c4bbdfSmrg
3535c4bbdfSmrgstatic Bool
3635c4bbdfSmrguse_copyarea(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
3735c4bbdfSmrg{
3835c4bbdfSmrg    struct copy_args *args = arg;
3935c4bbdfSmrg    glamor_pixmap_fbo *src = args->src;
4035c4bbdfSmrg
4135c4bbdfSmrg    glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
4235c4bbdfSmrg                        GL_TEXTURE0, src, TRUE);
4335c4bbdfSmrg
4435c4bbdfSmrg    glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
4535c4bbdfSmrg    glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
4635c4bbdfSmrg
4735c4bbdfSmrg    return TRUE;
4835c4bbdfSmrg}
4935c4bbdfSmrg
5035c4bbdfSmrgstatic const glamor_facet glamor_facet_copyarea = {
5135c4bbdfSmrg    "copy_area",
5235c4bbdfSmrg    .vs_vars = "attribute vec2 primitive;\n",
5335c4bbdfSmrg    .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy)
5435c4bbdfSmrg                "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
5535c4bbdfSmrg    .fs_exec = "       gl_FragColor = texture2D(sampler, fill_pos);\n",
5635c4bbdfSmrg    .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
5735c4bbdfSmrg    .use = use_copyarea,
5835c4bbdfSmrg};
5935c4bbdfSmrg
6035c4bbdfSmrg/*
6135c4bbdfSmrg * Configure the copy plane program for the current operation
6235c4bbdfSmrg */
6335c4bbdfSmrg
6435c4bbdfSmrgstatic Bool
6535c4bbdfSmrguse_copyplane(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
6635c4bbdfSmrg{
6735c4bbdfSmrg    struct copy_args *args = arg;
6835c4bbdfSmrg    glamor_pixmap_fbo *src = args->src;
6935c4bbdfSmrg
7035c4bbdfSmrg    glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
7135c4bbdfSmrg                        GL_TEXTURE0, src, TRUE);
7235c4bbdfSmrg
7335c4bbdfSmrg    glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
7435c4bbdfSmrg    glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
7535c4bbdfSmrg
7635c4bbdfSmrg    glamor_set_color(dst, gc->fgPixel, prog->fg_uniform);
7735c4bbdfSmrg    glamor_set_color(dst, gc->bgPixel, prog->bg_uniform);
7835c4bbdfSmrg
7935c4bbdfSmrg    /* XXX handle 2 10 10 10 and 1555 formats; presumably the pixmap private knows this? */
8035c4bbdfSmrg    switch (args->src_pixmap->drawable.depth) {
811b5d61b8Smrg    case 30:
821b5d61b8Smrg        glUniform4ui(prog->bitplane_uniform,
831b5d61b8Smrg                     (args->bitplane >> 20) & 0x3ff,
841b5d61b8Smrg                     (args->bitplane >> 10) & 0x3ff,
851b5d61b8Smrg                     (args->bitplane      ) & 0x3ff,
861b5d61b8Smrg                     0);
871b5d61b8Smrg
881b5d61b8Smrg        glUniform4f(prog->bitmul_uniform, 0x3ff, 0x3ff, 0x3ff, 0);
891b5d61b8Smrg        break;
9035c4bbdfSmrg    case 24:
9135c4bbdfSmrg        glUniform4ui(prog->bitplane_uniform,
9235c4bbdfSmrg                     (args->bitplane >> 16) & 0xff,
9335c4bbdfSmrg                     (args->bitplane >>  8) & 0xff,
9435c4bbdfSmrg                     (args->bitplane      ) & 0xff,
9535c4bbdfSmrg                     0);
9635c4bbdfSmrg
9735c4bbdfSmrg        glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0);
9835c4bbdfSmrg        break;
9935c4bbdfSmrg    case 32:
10035c4bbdfSmrg        glUniform4ui(prog->bitplane_uniform,
10135c4bbdfSmrg                     (args->bitplane >> 16) & 0xff,
10235c4bbdfSmrg                     (args->bitplane >>  8) & 0xff,
10335c4bbdfSmrg                     (args->bitplane      ) & 0xff,
10435c4bbdfSmrg                     (args->bitplane >> 24) & 0xff);
10535c4bbdfSmrg
10635c4bbdfSmrg        glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0xff);
10735c4bbdfSmrg        break;
10835c4bbdfSmrg    case 16:
10935c4bbdfSmrg        glUniform4ui(prog->bitplane_uniform,
11035c4bbdfSmrg                     (args->bitplane >> 11) & 0x1f,
11135c4bbdfSmrg                     (args->bitplane >>  5) & 0x3f,
11235c4bbdfSmrg                     (args->bitplane      ) & 0x1f,
11335c4bbdfSmrg                     0);
11435c4bbdfSmrg
11535c4bbdfSmrg        glUniform4f(prog->bitmul_uniform, 0x1f, 0x3f, 0x1f, 0);
11635c4bbdfSmrg        break;
11735c4bbdfSmrg    case 15:
11835c4bbdfSmrg        glUniform4ui(prog->bitplane_uniform,
11935c4bbdfSmrg                     (args->bitplane >> 10) & 0x1f,
12035c4bbdfSmrg                     (args->bitplane >>  5) & 0x1f,
12135c4bbdfSmrg                     (args->bitplane      ) & 0x1f,
12235c4bbdfSmrg                     0);
12335c4bbdfSmrg
12435c4bbdfSmrg        glUniform4f(prog->bitmul_uniform, 0x1f, 0x1f, 0x1f, 0);
12535c4bbdfSmrg        break;
12635c4bbdfSmrg    case 8:
12735c4bbdfSmrg        glUniform4ui(prog->bitplane_uniform,
12835c4bbdfSmrg                     0, 0, 0, args->bitplane);
12935c4bbdfSmrg        glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
13035c4bbdfSmrg        break;
13135c4bbdfSmrg    case 1:
13235c4bbdfSmrg        glUniform4ui(prog->bitplane_uniform,
13335c4bbdfSmrg                     0, 0, 0, args->bitplane);
13435c4bbdfSmrg        glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
13535c4bbdfSmrg        break;
13635c4bbdfSmrg    }
13735c4bbdfSmrg
13835c4bbdfSmrg    return TRUE;
13935c4bbdfSmrg}
14035c4bbdfSmrg
14135c4bbdfSmrgstatic const glamor_facet glamor_facet_copyplane = {
14235c4bbdfSmrg    "copy_plane",
14335c4bbdfSmrg    .version = 130,
14435c4bbdfSmrg    .vs_vars = "attribute vec2 primitive;\n",
14535c4bbdfSmrg    .vs_exec = (GLAMOR_POS(gl_Position, (primitive.xy))
14635c4bbdfSmrg                "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
14735c4bbdfSmrg    .fs_exec = ("       uvec4 bits = uvec4(round(texture2D(sampler, fill_pos) * bitmul));\n"
14835c4bbdfSmrg                "       if ((bits & bitplane) != uvec4(0,0,0,0))\n"
14935c4bbdfSmrg                "               gl_FragColor = fg;\n"
15035c4bbdfSmrg                "       else\n"
15135c4bbdfSmrg                "               gl_FragColor = bg;\n"),
15235c4bbdfSmrg    .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane,
15335c4bbdfSmrg    .use = use_copyplane,
15435c4bbdfSmrg};
15535c4bbdfSmrg
15635c4bbdfSmrg/*
15735c4bbdfSmrg * When all else fails, pull the bits out of the GPU and do the
15835c4bbdfSmrg * operation with fb
15935c4bbdfSmrg */
16035c4bbdfSmrg
16135c4bbdfSmrgstatic void
16235c4bbdfSmrgglamor_copy_bail(DrawablePtr src,
16335c4bbdfSmrg                 DrawablePtr dst,
16435c4bbdfSmrg                 GCPtr gc,
16535c4bbdfSmrg                 BoxPtr box,
16635c4bbdfSmrg                 int nbox,
16735c4bbdfSmrg                 int dx,
16835c4bbdfSmrg                 int dy,
16935c4bbdfSmrg                 Bool reverse,
17035c4bbdfSmrg                 Bool upsidedown,
17135c4bbdfSmrg                 Pixel bitplane,
17235c4bbdfSmrg                 void *closure)
17335c4bbdfSmrg{
17435c4bbdfSmrg    if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) && glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
17535c4bbdfSmrg        if (bitplane) {
17635c4bbdfSmrg            if (src->bitsPerPixel > 1)
17735c4bbdfSmrg                fbCopyNto1(src, dst, gc, box, nbox, dx, dy,
17835c4bbdfSmrg                           reverse, upsidedown, bitplane, closure);
17935c4bbdfSmrg            else
18035c4bbdfSmrg                fbCopy1toN(src, dst, gc, box, nbox, dx, dy,
18135c4bbdfSmrg                           reverse, upsidedown, bitplane, closure);
18235c4bbdfSmrg        } else {
18335c4bbdfSmrg            fbCopyNtoN(src, dst, gc, box, nbox, dx, dy,
18435c4bbdfSmrg                       reverse, upsidedown, bitplane, closure);
18535c4bbdfSmrg        }
18635c4bbdfSmrg    }
18735c4bbdfSmrg    glamor_finish_access(dst);
18835c4bbdfSmrg    glamor_finish_access(src);
18935c4bbdfSmrg}
19035c4bbdfSmrg
19135c4bbdfSmrg/**
1921b5d61b8Smrg * Implements CopyPlane and CopyArea from the CPU to the GPU by using
19335c4bbdfSmrg * the source as a texture and painting that into the destination.
19435c4bbdfSmrg *
19535c4bbdfSmrg * This requires that source and dest are different textures, or that
19635c4bbdfSmrg * (if the copy area doesn't overlap), GL_NV_texture_barrier is used
19735c4bbdfSmrg * to ensure that the caches are flushed at the right times.
19835c4bbdfSmrg */
19935c4bbdfSmrgstatic Bool
20035c4bbdfSmrgglamor_copy_cpu_fbo(DrawablePtr src,
20135c4bbdfSmrg                    DrawablePtr dst,
20235c4bbdfSmrg                    GCPtr gc,
20335c4bbdfSmrg                    BoxPtr box,
20435c4bbdfSmrg                    int nbox,
20535c4bbdfSmrg                    int dx,
20635c4bbdfSmrg                    int dy,
20735c4bbdfSmrg                    Bool reverse,
20835c4bbdfSmrg                    Bool upsidedown,
20935c4bbdfSmrg                    Pixel bitplane,
21035c4bbdfSmrg                    void *closure)
21135c4bbdfSmrg{
21235c4bbdfSmrg    ScreenPtr screen = dst->pScreen;
21335c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
21435c4bbdfSmrg    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
21535c4bbdfSmrg    int dst_xoff, dst_yoff;
21635c4bbdfSmrg
21735c4bbdfSmrg    if (gc && gc->alu != GXcopy)
21835c4bbdfSmrg        goto bail;
21935c4bbdfSmrg
22035c4bbdfSmrg    if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
22135c4bbdfSmrg        goto bail;
22235c4bbdfSmrg
22335c4bbdfSmrg    glamor_make_current(glamor_priv);
2245a7dfde8Smrg
2255a7dfde8Smrg    if (!glamor_prepare_access(src, GLAMOR_ACCESS_RO))
2265a7dfde8Smrg        goto bail;
22735c4bbdfSmrg
22835c4bbdfSmrg    glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_yoff);
22935c4bbdfSmrg
2301b5d61b8Smrg    if (bitplane) {
2311b5d61b8Smrg        FbBits *tmp_bits;
2321b5d61b8Smrg        FbStride tmp_stride;
2331b5d61b8Smrg        int tmp_bpp;
2341b5d61b8Smrg        int tmp_xoff, tmp_yoff;
2351b5d61b8Smrg
2361b5d61b8Smrg        PixmapPtr tmp_pix = fbCreatePixmap(screen, dst_pixmap->drawable.width,
2371b5d61b8Smrg                                           dst_pixmap->drawable.height,
2381b5d61b8Smrg                                           dst->depth, 0);
2391b5d61b8Smrg
2401b5d61b8Smrg        if (!tmp_pix) {
2411b5d61b8Smrg            glamor_finish_access(src);
2421b5d61b8Smrg            goto bail;
2431b5d61b8Smrg        }
2441b5d61b8Smrg
2451b5d61b8Smrg        tmp_pix->drawable.x = dst_xoff;
2461b5d61b8Smrg        tmp_pix->drawable.y = dst_yoff;
2471b5d61b8Smrg
2481b5d61b8Smrg        fbGetDrawable(&tmp_pix->drawable, tmp_bits, tmp_stride, tmp_bpp, tmp_xoff,
2491b5d61b8Smrg                      tmp_yoff);
2501b5d61b8Smrg
2511b5d61b8Smrg        if (src->bitsPerPixel > 1)
2521b5d61b8Smrg            fbCopyNto1(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
2531b5d61b8Smrg                       reverse, upsidedown, bitplane, closure);
2541b5d61b8Smrg        else
2551b5d61b8Smrg            fbCopy1toN(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
2561b5d61b8Smrg                       reverse, upsidedown, bitplane, closure);
25735c4bbdfSmrg
2581b5d61b8Smrg        glamor_upload_boxes(dst_pixmap, box, nbox, tmp_xoff, tmp_yoff,
2591b5d61b8Smrg                            dst_xoff, dst_yoff, (uint8_t *) tmp_bits,
2601b5d61b8Smrg                            tmp_stride * sizeof(FbBits));
2611b5d61b8Smrg        fbDestroyPixmap(tmp_pix);
2621b5d61b8Smrg    } else {
2631b5d61b8Smrg        FbBits *src_bits;
2641b5d61b8Smrg        FbStride src_stride;
2651b5d61b8Smrg        int src_bpp;
2661b5d61b8Smrg        int src_xoff, src_yoff;
2671b5d61b8Smrg
2681b5d61b8Smrg        fbGetDrawable(src, src_bits, src_stride, src_bpp, src_xoff, src_yoff);
2691b5d61b8Smrg        glamor_upload_boxes(dst_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
2701b5d61b8Smrg                            dst_xoff, dst_yoff,
2711b5d61b8Smrg                            (uint8_t *) src_bits, src_stride * sizeof (FbBits));
2721b5d61b8Smrg    }
27335c4bbdfSmrg    glamor_finish_access(src);
27435c4bbdfSmrg
27535c4bbdfSmrg    return TRUE;
27635c4bbdfSmrg
27735c4bbdfSmrgbail:
27835c4bbdfSmrg    return FALSE;
27935c4bbdfSmrg}
28035c4bbdfSmrg
28135c4bbdfSmrg/**
28235c4bbdfSmrg * Implements CopyArea from the GPU to the CPU using glReadPixels from the
28335c4bbdfSmrg * source FBO.
28435c4bbdfSmrg */
28535c4bbdfSmrgstatic Bool
28635c4bbdfSmrgglamor_copy_fbo_cpu(DrawablePtr src,
28735c4bbdfSmrg                    DrawablePtr dst,
28835c4bbdfSmrg                    GCPtr gc,
28935c4bbdfSmrg                    BoxPtr box,
29035c4bbdfSmrg                    int nbox,
29135c4bbdfSmrg                    int dx,
29235c4bbdfSmrg                    int dy,
29335c4bbdfSmrg                    Bool reverse,
29435c4bbdfSmrg                    Bool upsidedown,
29535c4bbdfSmrg                    Pixel bitplane,
29635c4bbdfSmrg                    void *closure)
29735c4bbdfSmrg{
29835c4bbdfSmrg    ScreenPtr screen = dst->pScreen;
29935c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
30035c4bbdfSmrg    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
30135c4bbdfSmrg    FbBits *dst_bits;
30235c4bbdfSmrg    FbStride dst_stride;
30335c4bbdfSmrg    int dst_bpp;
30435c4bbdfSmrg    int src_xoff, src_yoff;
30535c4bbdfSmrg    int dst_xoff, dst_yoff;
30635c4bbdfSmrg
30735c4bbdfSmrg    if (gc && gc->alu != GXcopy)
30835c4bbdfSmrg        goto bail;
30935c4bbdfSmrg
31035c4bbdfSmrg    if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
31135c4bbdfSmrg        goto bail;
31235c4bbdfSmrg
31335c4bbdfSmrg    glamor_make_current(glamor_priv);
3145a7dfde8Smrg
3155a7dfde8Smrg    if (!glamor_prepare_access(dst, GLAMOR_ACCESS_RW))
3165a7dfde8Smrg        goto bail;
31735c4bbdfSmrg
31835c4bbdfSmrg    glamor_get_drawable_deltas(src, src_pixmap, &src_xoff, &src_yoff);
31935c4bbdfSmrg
32035c4bbdfSmrg    fbGetDrawable(dst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff);
32135c4bbdfSmrg
32235c4bbdfSmrg    glamor_download_boxes(src_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
32335c4bbdfSmrg                          dst_xoff, dst_yoff,
32435c4bbdfSmrg                          (uint8_t *) dst_bits, dst_stride * sizeof (FbBits));
32535c4bbdfSmrg    glamor_finish_access(dst);
32635c4bbdfSmrg
32735c4bbdfSmrg    return TRUE;
32835c4bbdfSmrg
32935c4bbdfSmrgbail:
33035c4bbdfSmrg    return FALSE;
33135c4bbdfSmrg}
33235c4bbdfSmrg
3331b5d61b8Smrg/* Include the enums here for the moment, to keep from needing to bump epoxy. */
3341b5d61b8Smrg#ifndef GL_TILE_RASTER_ORDER_FIXED_MESA
3351b5d61b8Smrg#define GL_TILE_RASTER_ORDER_FIXED_MESA          0x8BB8
3361b5d61b8Smrg#define GL_TILE_RASTER_ORDER_INCREASING_X_MESA   0x8BB9
3371b5d61b8Smrg#define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA   0x8BBA
3381b5d61b8Smrg#endif
3391b5d61b8Smrg
34035c4bbdfSmrg/*
34135c4bbdfSmrg * Copy from GPU to GPU by using the source
34235c4bbdfSmrg * as a texture and painting that into the destination
34335c4bbdfSmrg */
34435c4bbdfSmrg
34535c4bbdfSmrgstatic Bool
34635c4bbdfSmrgglamor_copy_fbo_fbo_draw(DrawablePtr src,
34735c4bbdfSmrg                         DrawablePtr dst,
34835c4bbdfSmrg                         GCPtr gc,
34935c4bbdfSmrg                         BoxPtr box,
35035c4bbdfSmrg                         int nbox,
35135c4bbdfSmrg                         int dx,
35235c4bbdfSmrg                         int dy,
35335c4bbdfSmrg                         Bool reverse,
35435c4bbdfSmrg                         Bool upsidedown,
35535c4bbdfSmrg                         Pixel bitplane,
35635c4bbdfSmrg                         void *closure)
35735c4bbdfSmrg{
35835c4bbdfSmrg    ScreenPtr screen = dst->pScreen;
35935c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
36035c4bbdfSmrg    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
36135c4bbdfSmrg    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
36235c4bbdfSmrg    glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
36335c4bbdfSmrg    glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
36435c4bbdfSmrg    int src_box_index, dst_box_index;
36535c4bbdfSmrg    int dst_off_x, dst_off_y;
36635c4bbdfSmrg    int src_off_x, src_off_y;
36735c4bbdfSmrg    GLshort *v;
36835c4bbdfSmrg    char *vbo_offset;
36935c4bbdfSmrg    struct copy_args args;
37035c4bbdfSmrg    glamor_program *prog;
37135c4bbdfSmrg    const glamor_facet *copy_facet;
37235c4bbdfSmrg    int n;
3731b5d61b8Smrg    Bool ret = FALSE;
3741b5d61b8Smrg    BoxRec bounds = glamor_no_rendering_bounds();
37535c4bbdfSmrg
37635c4bbdfSmrg    glamor_make_current(glamor_priv);
37735c4bbdfSmrg
37835c4bbdfSmrg    if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
37935c4bbdfSmrg        goto bail_ctx;
38035c4bbdfSmrg
38135c4bbdfSmrg    if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
38235c4bbdfSmrg        goto bail_ctx;
38335c4bbdfSmrg
3841b5d61b8Smrg    if (bitplane && !glamor_priv->can_copyplane)
3851b5d61b8Smrg        goto bail_ctx;
3861b5d61b8Smrg
38735c4bbdfSmrg    if (bitplane) {
38835c4bbdfSmrg        prog = &glamor_priv->copy_plane_prog;
38935c4bbdfSmrg        copy_facet = &glamor_facet_copyplane;
39035c4bbdfSmrg    } else {
39135c4bbdfSmrg        prog = &glamor_priv->copy_area_prog;
39235c4bbdfSmrg        copy_facet = &glamor_facet_copyarea;
39335c4bbdfSmrg    }
39435c4bbdfSmrg
39535c4bbdfSmrg    if (prog->failed)
39635c4bbdfSmrg        goto bail_ctx;
39735c4bbdfSmrg
39835c4bbdfSmrg    if (!prog->prog) {
39935c4bbdfSmrg        if (!glamor_build_program(screen, prog,
40035c4bbdfSmrg                                  copy_facet, NULL, NULL, NULL))
40135c4bbdfSmrg            goto bail_ctx;
40235c4bbdfSmrg    }
40335c4bbdfSmrg
40435c4bbdfSmrg    args.src_pixmap = src_pixmap;
40535c4bbdfSmrg    args.bitplane = bitplane;
40635c4bbdfSmrg
40735c4bbdfSmrg    /* Set up the vertex buffers for the points */
40835c4bbdfSmrg
40935c4bbdfSmrg    v = glamor_get_vbo_space(dst->pScreen, nbox * 8 * sizeof (int16_t), &vbo_offset);
41035c4bbdfSmrg
4111b5d61b8Smrg    if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
4121b5d61b8Smrg        glEnable(GL_TILE_RASTER_ORDER_FIXED_MESA);
4131b5d61b8Smrg        if (dx >= 0)
4141b5d61b8Smrg            glEnable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
4151b5d61b8Smrg        else
4161b5d61b8Smrg            glDisable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
4171b5d61b8Smrg        if (dy >= 0)
4181b5d61b8Smrg            glEnable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
4191b5d61b8Smrg        else
4201b5d61b8Smrg            glDisable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
4211b5d61b8Smrg    }
4221b5d61b8Smrg
42335c4bbdfSmrg    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
42435c4bbdfSmrg    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
42535c4bbdfSmrg                          2 * sizeof (GLshort), vbo_offset);
42635c4bbdfSmrg
4271b5d61b8Smrg    if (nbox < 100) {
4281b5d61b8Smrg        bounds = glamor_start_rendering_bounds();
4291b5d61b8Smrg        for (int i = 0; i < nbox; i++)
4301b5d61b8Smrg            glamor_bounds_union_box(&bounds, &box[i]);
4311b5d61b8Smrg    }
4321b5d61b8Smrg
43335c4bbdfSmrg    for (n = 0; n < nbox; n++) {
43435c4bbdfSmrg        v[0] = box->x1; v[1] = box->y1;
43535c4bbdfSmrg        v[2] = box->x1; v[3] = box->y2;
43635c4bbdfSmrg        v[4] = box->x2; v[5] = box->y2;
43735c4bbdfSmrg        v[6] = box->x2; v[7] = box->y1;
4381b5d61b8Smrg
43935c4bbdfSmrg        v += 8;
44035c4bbdfSmrg        box++;
44135c4bbdfSmrg    }
44235c4bbdfSmrg
44335c4bbdfSmrg    glamor_put_vbo_space(screen);
44435c4bbdfSmrg
44535c4bbdfSmrg    glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
44635c4bbdfSmrg
44735c4bbdfSmrg    glEnable(GL_SCISSOR_TEST);
44835c4bbdfSmrg
44935c4bbdfSmrg    glamor_pixmap_loop(src_priv, src_box_index) {
45035c4bbdfSmrg        BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_index);
45135c4bbdfSmrg
45235c4bbdfSmrg        args.dx = dx + src_off_x - src_box->x1;
45335c4bbdfSmrg        args.dy = dy + src_off_y - src_box->y1;
45435c4bbdfSmrg        args.src = glamor_pixmap_fbo_at(src_priv, src_box_index);
45535c4bbdfSmrg
45635c4bbdfSmrg        if (!glamor_use_program(dst_pixmap, gc, prog, &args))
45735c4bbdfSmrg            goto bail_ctx;
45835c4bbdfSmrg
45935c4bbdfSmrg        glamor_pixmap_loop(dst_priv, dst_box_index) {
4601b5d61b8Smrg            BoxRec scissor = {
4611b5d61b8Smrg                .x1 = max(-args.dx, bounds.x1),
4621b5d61b8Smrg                .y1 = max(-args.dy, bounds.y1),
4631b5d61b8Smrg                .x2 = min(-args.dx + src_box->x2 - src_box->x1, bounds.x2),
4641b5d61b8Smrg                .y2 = min(-args.dy + src_box->y2 - src_box->y1, bounds.y2),
4651b5d61b8Smrg            };
4661b5d61b8Smrg            if (scissor.x1 >= scissor.x2 || scissor.y1 >= scissor.y2)
4671b5d61b8Smrg                continue;
4681b5d61b8Smrg
4691b5d61b8Smrg            if (!glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE,
4701b5d61b8Smrg                                                 prog->matrix_uniform,
4711b5d61b8Smrg                                                 &dst_off_x, &dst_off_y))
4721b5d61b8Smrg                goto bail_ctx;
4731b5d61b8Smrg
4741b5d61b8Smrg            glScissor(scissor.x1 + dst_off_x,
4751b5d61b8Smrg                      scissor.y1 + dst_off_y,
4761b5d61b8Smrg                      scissor.x2 - scissor.x1,
4771b5d61b8Smrg                      scissor.y2 - scissor.y1);
47835c4bbdfSmrg
47935c4bbdfSmrg            glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox);
48035c4bbdfSmrg        }
48135c4bbdfSmrg    }
48235c4bbdfSmrg
4831b5d61b8Smrg    ret = TRUE;
48435c4bbdfSmrg
48535c4bbdfSmrgbail_ctx:
4861b5d61b8Smrg    if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
4871b5d61b8Smrg        glDisable(GL_TILE_RASTER_ORDER_FIXED_MESA);
4881b5d61b8Smrg    }
4891b5d61b8Smrg    glDisable(GL_SCISSOR_TEST);
4901b5d61b8Smrg    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
4911b5d61b8Smrg
4921b5d61b8Smrg    return ret;
49335c4bbdfSmrg}
49435c4bbdfSmrg
49535c4bbdfSmrg/**
49635c4bbdfSmrg * Copies from the GPU to the GPU using a temporary pixmap in between,
49735c4bbdfSmrg * to correctly handle overlapping copies.
49835c4bbdfSmrg */
49935c4bbdfSmrg
50035c4bbdfSmrgstatic Bool
50135c4bbdfSmrgglamor_copy_fbo_fbo_temp(DrawablePtr src,
50235c4bbdfSmrg                         DrawablePtr dst,
50335c4bbdfSmrg                         GCPtr gc,
50435c4bbdfSmrg                         BoxPtr box,
50535c4bbdfSmrg                         int nbox,
50635c4bbdfSmrg                         int dx,
50735c4bbdfSmrg                         int dy,
50835c4bbdfSmrg                         Bool reverse,
50935c4bbdfSmrg                         Bool upsidedown,
51035c4bbdfSmrg                         Pixel bitplane,
51135c4bbdfSmrg                         void *closure)
51235c4bbdfSmrg{
51335c4bbdfSmrg    ScreenPtr screen = dst->pScreen;
51435c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
51535c4bbdfSmrg    PixmapPtr tmp_pixmap;
51635c4bbdfSmrg    BoxRec bounds;
51735c4bbdfSmrg    int n;
51835c4bbdfSmrg    BoxPtr tmp_box;
51935c4bbdfSmrg
52035c4bbdfSmrg    if (nbox == 0)
52135c4bbdfSmrg        return TRUE;
52235c4bbdfSmrg
52335c4bbdfSmrg    /* Sanity check state to avoid getting halfway through and bailing
52435c4bbdfSmrg     * at the last second. Might be nice to have checks that didn't
52535c4bbdfSmrg     * involve setting state.
52635c4bbdfSmrg     */
52735c4bbdfSmrg    glamor_make_current(glamor_priv);
52835c4bbdfSmrg
52935c4bbdfSmrg    if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
53035c4bbdfSmrg        goto bail_ctx;
53135c4bbdfSmrg
53235c4bbdfSmrg    if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
53335c4bbdfSmrg        goto bail_ctx;
53435c4bbdfSmrg
53535c4bbdfSmrg    /* Find the size of the area to copy
53635c4bbdfSmrg     */
53735c4bbdfSmrg    bounds = box[0];
53835c4bbdfSmrg    for (n = 1; n < nbox; n++) {
53935c4bbdfSmrg        bounds.x1 = min(bounds.x1, box[n].x1);
54035c4bbdfSmrg        bounds.x2 = max(bounds.x2, box[n].x2);
54135c4bbdfSmrg        bounds.y1 = min(bounds.y1, box[n].y1);
54235c4bbdfSmrg        bounds.y2 = max(bounds.y2, box[n].y2);
54335c4bbdfSmrg    }
54435c4bbdfSmrg
54535c4bbdfSmrg    /* Allocate a suitable temporary pixmap
54635c4bbdfSmrg     */
54735c4bbdfSmrg    tmp_pixmap = glamor_create_pixmap(screen,
54835c4bbdfSmrg                                      bounds.x2 - bounds.x1,
54935c4bbdfSmrg                                      bounds.y2 - bounds.y1,
55035c4bbdfSmrg                                      src->depth, 0);
55135c4bbdfSmrg    if (!tmp_pixmap)
55235c4bbdfSmrg        goto bail;
55335c4bbdfSmrg
55435c4bbdfSmrg    tmp_box = calloc(nbox, sizeof (BoxRec));
55535c4bbdfSmrg    if (!tmp_box)
55635c4bbdfSmrg        goto bail_pixmap;
55735c4bbdfSmrg
55835c4bbdfSmrg    /* Convert destination boxes into tmp pixmap boxes
55935c4bbdfSmrg     */
56035c4bbdfSmrg    for (n = 0; n < nbox; n++) {
56135c4bbdfSmrg        tmp_box[n].x1 = box[n].x1 - bounds.x1;
56235c4bbdfSmrg        tmp_box[n].x2 = box[n].x2 - bounds.x1;
56335c4bbdfSmrg        tmp_box[n].y1 = box[n].y1 - bounds.y1;
56435c4bbdfSmrg        tmp_box[n].y2 = box[n].y2 - bounds.y1;
56535c4bbdfSmrg    }
56635c4bbdfSmrg
56735c4bbdfSmrg    if (!glamor_copy_fbo_fbo_draw(src,
56835c4bbdfSmrg                                  &tmp_pixmap->drawable,
56935c4bbdfSmrg                                  NULL,
57035c4bbdfSmrg                                  tmp_box,
57135c4bbdfSmrg                                  nbox,
57235c4bbdfSmrg                                  dx + bounds.x1,
57335c4bbdfSmrg                                  dy + bounds.y1,
57435c4bbdfSmrg                                  FALSE, FALSE,
57535c4bbdfSmrg                                  0, NULL))
57635c4bbdfSmrg        goto bail_box;
57735c4bbdfSmrg
57835c4bbdfSmrg    if (!glamor_copy_fbo_fbo_draw(&tmp_pixmap->drawable,
57935c4bbdfSmrg                                  dst,
58035c4bbdfSmrg                                  gc,
58135c4bbdfSmrg                                  box,
58235c4bbdfSmrg                                  nbox,
58335c4bbdfSmrg                                  -bounds.x1,
58435c4bbdfSmrg                                  -bounds.y1,
58535c4bbdfSmrg                                  FALSE, FALSE,
58635c4bbdfSmrg                                  bitplane, closure))
58735c4bbdfSmrg        goto bail_box;
58835c4bbdfSmrg
58935c4bbdfSmrg    free(tmp_box);
59035c4bbdfSmrg
59135c4bbdfSmrg    glamor_destroy_pixmap(tmp_pixmap);
59235c4bbdfSmrg
59335c4bbdfSmrg    return TRUE;
59435c4bbdfSmrgbail_box:
59535c4bbdfSmrg    free(tmp_box);
59635c4bbdfSmrgbail_pixmap:
59735c4bbdfSmrg    glamor_destroy_pixmap(tmp_pixmap);
59835c4bbdfSmrgbail:
59935c4bbdfSmrg    return FALSE;
60035c4bbdfSmrg
60135c4bbdfSmrgbail_ctx:
60235c4bbdfSmrg    return FALSE;
60335c4bbdfSmrg}
60435c4bbdfSmrg
60535c4bbdfSmrg/**
60635c4bbdfSmrg * Returns TRUE if the copy has to be implemented with
60735c4bbdfSmrg * glamor_copy_fbo_fbo_temp() instead of glamor_copy_fbo_fbo().
60835c4bbdfSmrg *
60935c4bbdfSmrg * If the src and dst are in the same pixmap, then glamor_copy_fbo_fbo()'s
61035c4bbdfSmrg * sampling would give undefined results (since the same texture would be
61135c4bbdfSmrg * bound as an FBO destination and as a texture source).  However, if we
61235c4bbdfSmrg * have GL_NV_texture_barrier, we can take advantage of the exception it
61335c4bbdfSmrg * added:
61435c4bbdfSmrg *
61535c4bbdfSmrg *    "- If a texel has been written, then in order to safely read the result
61635c4bbdfSmrg *       a texel fetch must be in a subsequent Draw separated by the command
61735c4bbdfSmrg *
61835c4bbdfSmrg *       void TextureBarrierNV(void);
61935c4bbdfSmrg *
62035c4bbdfSmrg *    TextureBarrierNV() will guarantee that writes have completed and caches
62135c4bbdfSmrg *    have been invalidated before subsequent Draws are executed."
62235c4bbdfSmrg */
62335c4bbdfSmrgstatic Bool
62435c4bbdfSmrgglamor_copy_needs_temp(DrawablePtr src,
62535c4bbdfSmrg                       DrawablePtr dst,
62635c4bbdfSmrg                       BoxPtr box,
62735c4bbdfSmrg                       int nbox,
62835c4bbdfSmrg                       int dx,
62935c4bbdfSmrg                       int dy)
63035c4bbdfSmrg{
63135c4bbdfSmrg    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
63235c4bbdfSmrg    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
63335c4bbdfSmrg    ScreenPtr screen = dst->pScreen;
63435c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
63535c4bbdfSmrg    int n;
63635c4bbdfSmrg    int dst_off_x, dst_off_y;
63735c4bbdfSmrg    int src_off_x, src_off_y;
63835c4bbdfSmrg    BoxRec bounds;
63935c4bbdfSmrg
64035c4bbdfSmrg    if (src_pixmap != dst_pixmap)
64135c4bbdfSmrg        return FALSE;
64235c4bbdfSmrg
64335c4bbdfSmrg    if (nbox == 0)
64435c4bbdfSmrg        return FALSE;
64535c4bbdfSmrg
64635c4bbdfSmrg    if (!glamor_priv->has_nv_texture_barrier)
64735c4bbdfSmrg        return TRUE;
64835c4bbdfSmrg
6491b5d61b8Smrg    if (!glamor_priv->has_mesa_tile_raster_order) {
6501b5d61b8Smrg        glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
6511b5d61b8Smrg        glamor_get_drawable_deltas(dst, dst_pixmap, &dst_off_x, &dst_off_y);
65235c4bbdfSmrg
6531b5d61b8Smrg        bounds = box[0];
6541b5d61b8Smrg        for (n = 1; n < nbox; n++) {
6551b5d61b8Smrg            bounds.x1 = min(bounds.x1, box[n].x1);
6561b5d61b8Smrg            bounds.y1 = min(bounds.y1, box[n].y1);
65735c4bbdfSmrg
6581b5d61b8Smrg            bounds.x2 = max(bounds.x2, box[n].x2);
6591b5d61b8Smrg            bounds.y2 = max(bounds.y2, box[n].y2);
6601b5d61b8Smrg        }
66135c4bbdfSmrg
6621b5d61b8Smrg        /* Check to see if the pixmap-relative boxes overlap in both X and Y,
6631b5d61b8Smrg         * in which case we can't rely on NV_texture_barrier and must
6641b5d61b8Smrg         * make a temporary copy
6651b5d61b8Smrg         *
6661b5d61b8Smrg         *  dst.x1                     < src.x2 &&
6671b5d61b8Smrg         *  src.x1                     < dst.x2 &&
6681b5d61b8Smrg         *
6691b5d61b8Smrg         *  dst.y1                     < src.y2 &&
6701b5d61b8Smrg         *  src.y1                     < dst.y2
6711b5d61b8Smrg         */
6721b5d61b8Smrg        if (bounds.x1 + dst_off_x      < bounds.x2 + dx + src_off_x &&
6731b5d61b8Smrg            bounds.x1 + dx + src_off_x < bounds.x2 + dst_off_x &&
6741b5d61b8Smrg
6751b5d61b8Smrg            bounds.y1 + dst_off_y      < bounds.y2 + dy + src_off_y &&
6761b5d61b8Smrg            bounds.y1 + dy + src_off_y < bounds.y2 + dst_off_y) {
6771b5d61b8Smrg            return TRUE;
6781b5d61b8Smrg        }
67935c4bbdfSmrg    }
68035c4bbdfSmrg
68135c4bbdfSmrg    glTextureBarrierNV();
68235c4bbdfSmrg
68335c4bbdfSmrg    return FALSE;
68435c4bbdfSmrg}
68535c4bbdfSmrg
68635c4bbdfSmrgstatic Bool
68735c4bbdfSmrgglamor_copy_gl(DrawablePtr src,
68835c4bbdfSmrg               DrawablePtr dst,
68935c4bbdfSmrg               GCPtr gc,
69035c4bbdfSmrg               BoxPtr box,
69135c4bbdfSmrg               int nbox,
69235c4bbdfSmrg               int dx,
69335c4bbdfSmrg               int dy,
69435c4bbdfSmrg               Bool reverse,
69535c4bbdfSmrg               Bool upsidedown,
69635c4bbdfSmrg               Pixel bitplane,
69735c4bbdfSmrg               void *closure)
69835c4bbdfSmrg{
69935c4bbdfSmrg    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
70035c4bbdfSmrg    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
70135c4bbdfSmrg    glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
70235c4bbdfSmrg    glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
70335c4bbdfSmrg
70435c4bbdfSmrg    if (GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_priv)) {
70535c4bbdfSmrg        if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv)) {
70635c4bbdfSmrg            if (glamor_copy_needs_temp(src, dst, box, nbox, dx, dy))
70735c4bbdfSmrg                return glamor_copy_fbo_fbo_temp(src, dst, gc, box, nbox, dx, dy,
70835c4bbdfSmrg                                                reverse, upsidedown, bitplane, closure);
70935c4bbdfSmrg            else
71035c4bbdfSmrg                return glamor_copy_fbo_fbo_draw(src, dst, gc, box, nbox, dx, dy,
71135c4bbdfSmrg                                                reverse, upsidedown, bitplane, closure);
71235c4bbdfSmrg        }
7131b5d61b8Smrg
7141b5d61b8Smrg        return glamor_copy_cpu_fbo(src, dst, gc, box, nbox, dx, dy,
7151b5d61b8Smrg                                   reverse, upsidedown, bitplane, closure);
71635c4bbdfSmrg    } else if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv) &&
71735c4bbdfSmrg               dst_priv->type != GLAMOR_DRM_ONLY &&
71835c4bbdfSmrg               bitplane == 0) {
71935c4bbdfSmrg            return glamor_copy_fbo_cpu(src, dst, gc, box, nbox, dx, dy,
72035c4bbdfSmrg                                       reverse, upsidedown, bitplane, closure);
72135c4bbdfSmrg    }
72235c4bbdfSmrg    return FALSE;
72335c4bbdfSmrg}
72435c4bbdfSmrg
72535c4bbdfSmrgvoid
72635c4bbdfSmrgglamor_copy(DrawablePtr src,
72735c4bbdfSmrg            DrawablePtr dst,
72835c4bbdfSmrg            GCPtr gc,
72935c4bbdfSmrg            BoxPtr box,
73035c4bbdfSmrg            int nbox,
73135c4bbdfSmrg            int dx,
73235c4bbdfSmrg            int dy,
73335c4bbdfSmrg            Bool reverse,
73435c4bbdfSmrg            Bool upsidedown,
73535c4bbdfSmrg            Pixel bitplane,
73635c4bbdfSmrg            void *closure)
73735c4bbdfSmrg{
73835c4bbdfSmrg    if (nbox == 0)
73935c4bbdfSmrg	return;
74035c4bbdfSmrg
74135c4bbdfSmrg    if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure))
74235c4bbdfSmrg        return;
74335c4bbdfSmrg    glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
74435c4bbdfSmrg}
74535c4bbdfSmrg
74635c4bbdfSmrgRegionPtr
74735c4bbdfSmrgglamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
74835c4bbdfSmrg                 int srcx, int srcy, int width, int height, int dstx, int dsty)
74935c4bbdfSmrg{
75035c4bbdfSmrg    return miDoCopy(src, dst, gc,
75135c4bbdfSmrg                    srcx, srcy, width, height,
75235c4bbdfSmrg                    dstx, dsty, glamor_copy, 0, NULL);
75335c4bbdfSmrg}
75435c4bbdfSmrg
75535c4bbdfSmrgRegionPtr
75635c4bbdfSmrgglamor_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
75735c4bbdfSmrg                  int srcx, int srcy, int width, int height, int dstx, int dsty,
75835c4bbdfSmrg                  unsigned long bitplane)
75935c4bbdfSmrg{
76035c4bbdfSmrg    if ((bitplane & FbFullMask(src->depth)) == 0)
76135c4bbdfSmrg        return miHandleExposures(src, dst, gc,
76235c4bbdfSmrg                                 srcx, srcy, width, height, dstx, dsty);
76335c4bbdfSmrg    return miDoCopy(src, dst, gc,
76435c4bbdfSmrg                    srcx, srcy, width, height,
76535c4bbdfSmrg                    dstx, dsty, glamor_copy, bitplane, NULL);
76635c4bbdfSmrg}
76735c4bbdfSmrg
76835c4bbdfSmrgvoid
76935c4bbdfSmrgglamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region)
77035c4bbdfSmrg{
77135c4bbdfSmrg    PixmapPtr pixmap = glamor_get_drawable_pixmap(&window->drawable);
77235c4bbdfSmrg    DrawablePtr drawable = &pixmap->drawable;
77335c4bbdfSmrg    RegionRec dst_region;
77435c4bbdfSmrg    int dx, dy;
77535c4bbdfSmrg
77635c4bbdfSmrg    dx = old_origin.x - window->drawable.x;
77735c4bbdfSmrg    dy = old_origin.y - window->drawable.y;
77835c4bbdfSmrg    RegionTranslate(src_region, -dx, -dy);
77935c4bbdfSmrg
78035c4bbdfSmrg    RegionNull(&dst_region);
78135c4bbdfSmrg
78235c4bbdfSmrg    RegionIntersect(&dst_region, &window->borderClip, src_region);
78335c4bbdfSmrg
78435c4bbdfSmrg#ifdef COMPOSITE
78535c4bbdfSmrg    if (pixmap->screen_x || pixmap->screen_y)
78635c4bbdfSmrg        RegionTranslate(&dst_region, -pixmap->screen_x, -pixmap->screen_y);
78735c4bbdfSmrg#endif
78835c4bbdfSmrg
78935c4bbdfSmrg    miCopyRegion(drawable, drawable,
79035c4bbdfSmrg                 0, &dst_region, dx, dy, glamor_copy, 0, 0);
79135c4bbdfSmrg
79235c4bbdfSmrg    RegionUninit(&dst_region);
79335c4bbdfSmrg}
794