794 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			794 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Copyright © 2014 Keith Packard
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that copyright
 | 
						|
 * notice and this permission notice appear in supporting documentation, and
 | 
						|
 * that the name of the copyright holders not be used in advertising or
 | 
						|
 * publicity pertaining to distribution of the software without specific,
 | 
						|
 * written prior permission.  The copyright holders make no representations
 | 
						|
 * about the suitability of this software for any purpose.  It is provided "as
 | 
						|
 * is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
						|
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
						|
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
						|
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | 
						|
 * OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#include "glamor_priv.h"
 | 
						|
#include "glamor_transfer.h"
 | 
						|
#include "glamor_prepare.h"
 | 
						|
#include "glamor_transform.h"
 | 
						|
 | 
						|
struct copy_args {
 | 
						|
    PixmapPtr           src_pixmap;
 | 
						|
    glamor_pixmap_fbo   *src;
 | 
						|
    uint32_t            bitplane;
 | 
						|
    int                 dx, dy;
 | 
						|
};
 | 
						|
 | 
						|
static Bool
 | 
						|
use_copyarea(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
 | 
						|
{
 | 
						|
    struct copy_args *args = arg;
 | 
						|
    glamor_pixmap_fbo *src = args->src;
 | 
						|
 | 
						|
    glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
 | 
						|
                        GL_TEXTURE0, src, TRUE);
 | 
						|
 | 
						|
    glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
 | 
						|
    glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static const glamor_facet glamor_facet_copyarea = {
 | 
						|
    "copy_area",
 | 
						|
    .vs_vars = "attribute vec2 primitive;\n",
 | 
						|
    .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy)
 | 
						|
                "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
 | 
						|
    .fs_exec = "       gl_FragColor = texture2D(sampler, fill_pos);\n",
 | 
						|
    .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
 | 
						|
    .use = use_copyarea,
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * Configure the copy plane program for the current operation
 | 
						|
 */
 | 
						|
 | 
						|
static Bool
 | 
						|
use_copyplane(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
 | 
						|
{
 | 
						|
    struct copy_args *args = arg;
 | 
						|
    glamor_pixmap_fbo *src = args->src;
 | 
						|
 | 
						|
    glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
 | 
						|
                        GL_TEXTURE0, src, TRUE);
 | 
						|
 | 
						|
    glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
 | 
						|
    glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
 | 
						|
 | 
						|
    glamor_set_color(dst, gc->fgPixel, prog->fg_uniform);
 | 
						|
    glamor_set_color(dst, gc->bgPixel, prog->bg_uniform);
 | 
						|
 | 
						|
    /* XXX handle 2 10 10 10 and 1555 formats; presumably the pixmap private knows this? */
 | 
						|
    switch (args->src_pixmap->drawable.depth) {
 | 
						|
    case 30:
 | 
						|
        glUniform4ui(prog->bitplane_uniform,
 | 
						|
                     (args->bitplane >> 20) & 0x3ff,
 | 
						|
                     (args->bitplane >> 10) & 0x3ff,
 | 
						|
                     (args->bitplane      ) & 0x3ff,
 | 
						|
                     0);
 | 
						|
 | 
						|
        glUniform4f(prog->bitmul_uniform, 0x3ff, 0x3ff, 0x3ff, 0);
 | 
						|
        break;
 | 
						|
    case 24:
 | 
						|
        glUniform4ui(prog->bitplane_uniform,
 | 
						|
                     (args->bitplane >> 16) & 0xff,
 | 
						|
                     (args->bitplane >>  8) & 0xff,
 | 
						|
                     (args->bitplane      ) & 0xff,
 | 
						|
                     0);
 | 
						|
 | 
						|
        glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0);
 | 
						|
        break;
 | 
						|
    case 32:
 | 
						|
        glUniform4ui(prog->bitplane_uniform,
 | 
						|
                     (args->bitplane >> 16) & 0xff,
 | 
						|
                     (args->bitplane >>  8) & 0xff,
 | 
						|
                     (args->bitplane      ) & 0xff,
 | 
						|
                     (args->bitplane >> 24) & 0xff);
 | 
						|
 | 
						|
        glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0xff);
 | 
						|
        break;
 | 
						|
    case 16:
 | 
						|
        glUniform4ui(prog->bitplane_uniform,
 | 
						|
                     (args->bitplane >> 11) & 0x1f,
 | 
						|
                     (args->bitplane >>  5) & 0x3f,
 | 
						|
                     (args->bitplane      ) & 0x1f,
 | 
						|
                     0);
 | 
						|
 | 
						|
        glUniform4f(prog->bitmul_uniform, 0x1f, 0x3f, 0x1f, 0);
 | 
						|
        break;
 | 
						|
    case 15:
 | 
						|
        glUniform4ui(prog->bitplane_uniform,
 | 
						|
                     (args->bitplane >> 10) & 0x1f,
 | 
						|
                     (args->bitplane >>  5) & 0x1f,
 | 
						|
                     (args->bitplane      ) & 0x1f,
 | 
						|
                     0);
 | 
						|
 | 
						|
        glUniform4f(prog->bitmul_uniform, 0x1f, 0x1f, 0x1f, 0);
 | 
						|
        break;
 | 
						|
    case 8:
 | 
						|
        glUniform4ui(prog->bitplane_uniform,
 | 
						|
                     0, 0, 0, args->bitplane);
 | 
						|
        glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
 | 
						|
        break;
 | 
						|
    case 1:
 | 
						|
        glUniform4ui(prog->bitplane_uniform,
 | 
						|
                     0, 0, 0, args->bitplane);
 | 
						|
        glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static const glamor_facet glamor_facet_copyplane = {
 | 
						|
    "copy_plane",
 | 
						|
    .version = 130,
 | 
						|
    .vs_vars = "attribute vec2 primitive;\n",
 | 
						|
    .vs_exec = (GLAMOR_POS(gl_Position, (primitive.xy))
 | 
						|
                "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
 | 
						|
    .fs_exec = ("       uvec4 bits = uvec4(round(texture2D(sampler, fill_pos) * bitmul));\n"
 | 
						|
                "       if ((bits & bitplane) != uvec4(0,0,0,0))\n"
 | 
						|
                "               gl_FragColor = fg;\n"
 | 
						|
                "       else\n"
 | 
						|
                "               gl_FragColor = bg;\n"),
 | 
						|
    .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane,
 | 
						|
    .use = use_copyplane,
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * When all else fails, pull the bits out of the GPU and do the
 | 
						|
 * operation with fb
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
glamor_copy_bail(DrawablePtr src,
 | 
						|
                 DrawablePtr dst,
 | 
						|
                 GCPtr gc,
 | 
						|
                 BoxPtr box,
 | 
						|
                 int nbox,
 | 
						|
                 int dx,
 | 
						|
                 int dy,
 | 
						|
                 Bool reverse,
 | 
						|
                 Bool upsidedown,
 | 
						|
                 Pixel bitplane,
 | 
						|
                 void *closure)
 | 
						|
{
 | 
						|
    if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) && glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
 | 
						|
        if (bitplane) {
 | 
						|
            if (src->bitsPerPixel > 1)
 | 
						|
                fbCopyNto1(src, dst, gc, box, nbox, dx, dy,
 | 
						|
                           reverse, upsidedown, bitplane, closure);
 | 
						|
            else
 | 
						|
                fbCopy1toN(src, dst, gc, box, nbox, dx, dy,
 | 
						|
                           reverse, upsidedown, bitplane, closure);
 | 
						|
        } else {
 | 
						|
            fbCopyNtoN(src, dst, gc, box, nbox, dx, dy,
 | 
						|
                       reverse, upsidedown, bitplane, closure);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    glamor_finish_access(dst);
 | 
						|
    glamor_finish_access(src);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements CopyPlane and CopyArea from the CPU to the GPU by using
 | 
						|
 * the source as a texture and painting that into the destination.
 | 
						|
 *
 | 
						|
 * This requires that source and dest are different textures, or that
 | 
						|
 * (if the copy area doesn't overlap), GL_NV_texture_barrier is used
 | 
						|
 * to ensure that the caches are flushed at the right times.
 | 
						|
 */
 | 
						|
static Bool
 | 
						|
glamor_copy_cpu_fbo(DrawablePtr src,
 | 
						|
                    DrawablePtr dst,
 | 
						|
                    GCPtr gc,
 | 
						|
                    BoxPtr box,
 | 
						|
                    int nbox,
 | 
						|
                    int dx,
 | 
						|
                    int dy,
 | 
						|
                    Bool reverse,
 | 
						|
                    Bool upsidedown,
 | 
						|
                    Pixel bitplane,
 | 
						|
                    void *closure)
 | 
						|
{
 | 
						|
    ScreenPtr screen = dst->pScreen;
 | 
						|
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | 
						|
    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | 
						|
    int dst_xoff, dst_yoff;
 | 
						|
 | 
						|
    if (gc && gc->alu != GXcopy)
 | 
						|
        goto bail;
 | 
						|
 | 
						|
    if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
 | 
						|
        goto bail;
 | 
						|
 | 
						|
    glamor_make_current(glamor_priv);
 | 
						|
 | 
						|
    if (!glamor_prepare_access(src, GLAMOR_ACCESS_RO))
 | 
						|
        goto bail;
 | 
						|
 | 
						|
    glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_yoff);
 | 
						|
 | 
						|
    if (bitplane) {
 | 
						|
        FbBits *tmp_bits;
 | 
						|
        FbStride tmp_stride;
 | 
						|
        int tmp_bpp;
 | 
						|
        int tmp_xoff, tmp_yoff;
 | 
						|
 | 
						|
        PixmapPtr tmp_pix = fbCreatePixmap(screen, dst_pixmap->drawable.width,
 | 
						|
                                           dst_pixmap->drawable.height,
 | 
						|
                                           dst->depth, 0);
 | 
						|
 | 
						|
        if (!tmp_pix) {
 | 
						|
            glamor_finish_access(src);
 | 
						|
            goto bail;
 | 
						|
        }
 | 
						|
 | 
						|
        tmp_pix->drawable.x = dst_xoff;
 | 
						|
        tmp_pix->drawable.y = dst_yoff;
 | 
						|
 | 
						|
        fbGetDrawable(&tmp_pix->drawable, tmp_bits, tmp_stride, tmp_bpp, tmp_xoff,
 | 
						|
                      tmp_yoff);
 | 
						|
 | 
						|
        if (src->bitsPerPixel > 1)
 | 
						|
            fbCopyNto1(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
 | 
						|
                       reverse, upsidedown, bitplane, closure);
 | 
						|
        else
 | 
						|
            fbCopy1toN(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
 | 
						|
                       reverse, upsidedown, bitplane, closure);
 | 
						|
 | 
						|
        glamor_upload_boxes(dst_pixmap, box, nbox, tmp_xoff, tmp_yoff,
 | 
						|
                            dst_xoff, dst_yoff, (uint8_t *) tmp_bits,
 | 
						|
                            tmp_stride * sizeof(FbBits));
 | 
						|
        fbDestroyPixmap(tmp_pix);
 | 
						|
    } else {
 | 
						|
        FbBits *src_bits;
 | 
						|
        FbStride src_stride;
 | 
						|
        int src_bpp;
 | 
						|
        int src_xoff, src_yoff;
 | 
						|
 | 
						|
        fbGetDrawable(src, src_bits, src_stride, src_bpp, src_xoff, src_yoff);
 | 
						|
        glamor_upload_boxes(dst_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
 | 
						|
                            dst_xoff, dst_yoff,
 | 
						|
                            (uint8_t *) src_bits, src_stride * sizeof (FbBits));
 | 
						|
    }
 | 
						|
    glamor_finish_access(src);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
bail:
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements CopyArea from the GPU to the CPU using glReadPixels from the
 | 
						|
 * source FBO.
 | 
						|
 */
 | 
						|
static Bool
 | 
						|
glamor_copy_fbo_cpu(DrawablePtr src,
 | 
						|
                    DrawablePtr dst,
 | 
						|
                    GCPtr gc,
 | 
						|
                    BoxPtr box,
 | 
						|
                    int nbox,
 | 
						|
                    int dx,
 | 
						|
                    int dy,
 | 
						|
                    Bool reverse,
 | 
						|
                    Bool upsidedown,
 | 
						|
                    Pixel bitplane,
 | 
						|
                    void *closure)
 | 
						|
{
 | 
						|
    ScreenPtr screen = dst->pScreen;
 | 
						|
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | 
						|
    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | 
						|
    FbBits *dst_bits;
 | 
						|
    FbStride dst_stride;
 | 
						|
    int dst_bpp;
 | 
						|
    int src_xoff, src_yoff;
 | 
						|
    int dst_xoff, dst_yoff;
 | 
						|
 | 
						|
    if (gc && gc->alu != GXcopy)
 | 
						|
        goto bail;
 | 
						|
 | 
						|
    if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
 | 
						|
        goto bail;
 | 
						|
 | 
						|
    glamor_make_current(glamor_priv);
 | 
						|
 | 
						|
    if (!glamor_prepare_access(dst, GLAMOR_ACCESS_RW))
 | 
						|
        goto bail;
 | 
						|
 | 
						|
    glamor_get_drawable_deltas(src, src_pixmap, &src_xoff, &src_yoff);
 | 
						|
 | 
						|
    fbGetDrawable(dst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff);
 | 
						|
 | 
						|
    glamor_download_boxes(src_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
 | 
						|
                          dst_xoff, dst_yoff,
 | 
						|
                          (uint8_t *) dst_bits, dst_stride * sizeof (FbBits));
 | 
						|
    glamor_finish_access(dst);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
bail:
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/* Include the enums here for the moment, to keep from needing to bump epoxy. */
 | 
						|
#ifndef GL_TILE_RASTER_ORDER_FIXED_MESA
 | 
						|
#define GL_TILE_RASTER_ORDER_FIXED_MESA          0x8BB8
 | 
						|
#define GL_TILE_RASTER_ORDER_INCREASING_X_MESA   0x8BB9
 | 
						|
#define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA   0x8BBA
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Copy from GPU to GPU by using the source
 | 
						|
 * as a texture and painting that into the destination
 | 
						|
 */
 | 
						|
 | 
						|
static Bool
 | 
						|
glamor_copy_fbo_fbo_draw(DrawablePtr src,
 | 
						|
                         DrawablePtr dst,
 | 
						|
                         GCPtr gc,
 | 
						|
                         BoxPtr box,
 | 
						|
                         int nbox,
 | 
						|
                         int dx,
 | 
						|
                         int dy,
 | 
						|
                         Bool reverse,
 | 
						|
                         Bool upsidedown,
 | 
						|
                         Pixel bitplane,
 | 
						|
                         void *closure)
 | 
						|
{
 | 
						|
    ScreenPtr screen = dst->pScreen;
 | 
						|
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | 
						|
    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | 
						|
    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | 
						|
    glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
 | 
						|
    glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
 | 
						|
    int src_box_index, dst_box_index;
 | 
						|
    int dst_off_x, dst_off_y;
 | 
						|
    int src_off_x, src_off_y;
 | 
						|
    GLshort *v;
 | 
						|
    char *vbo_offset;
 | 
						|
    struct copy_args args;
 | 
						|
    glamor_program *prog;
 | 
						|
    const glamor_facet *copy_facet;
 | 
						|
    int n;
 | 
						|
    Bool ret = FALSE;
 | 
						|
    BoxRec bounds = glamor_no_rendering_bounds();
 | 
						|
 | 
						|
    glamor_make_current(glamor_priv);
 | 
						|
 | 
						|
    if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
 | 
						|
        goto bail_ctx;
 | 
						|
 | 
						|
    if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
 | 
						|
        goto bail_ctx;
 | 
						|
 | 
						|
    if (bitplane && !glamor_priv->can_copyplane)
 | 
						|
        goto bail_ctx;
 | 
						|
 | 
						|
    if (bitplane) {
 | 
						|
        prog = &glamor_priv->copy_plane_prog;
 | 
						|
        copy_facet = &glamor_facet_copyplane;
 | 
						|
    } else {
 | 
						|
        prog = &glamor_priv->copy_area_prog;
 | 
						|
        copy_facet = &glamor_facet_copyarea;
 | 
						|
    }
 | 
						|
 | 
						|
    if (prog->failed)
 | 
						|
        goto bail_ctx;
 | 
						|
 | 
						|
    if (!prog->prog) {
 | 
						|
        if (!glamor_build_program(screen, prog,
 | 
						|
                                  copy_facet, NULL, NULL, NULL))
 | 
						|
            goto bail_ctx;
 | 
						|
    }
 | 
						|
 | 
						|
    args.src_pixmap = src_pixmap;
 | 
						|
    args.bitplane = bitplane;
 | 
						|
 | 
						|
    /* Set up the vertex buffers for the points */
 | 
						|
 | 
						|
    v = glamor_get_vbo_space(dst->pScreen, nbox * 8 * sizeof (int16_t), &vbo_offset);
 | 
						|
 | 
						|
    if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
 | 
						|
        glEnable(GL_TILE_RASTER_ORDER_FIXED_MESA);
 | 
						|
        if (dx >= 0)
 | 
						|
            glEnable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
 | 
						|
        else
 | 
						|
            glDisable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
 | 
						|
        if (dy >= 0)
 | 
						|
            glEnable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
 | 
						|
        else
 | 
						|
            glDisable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
 | 
						|
    }
 | 
						|
 | 
						|
    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
 | 
						|
    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
 | 
						|
                          2 * sizeof (GLshort), vbo_offset);
 | 
						|
 | 
						|
    if (nbox < 100) {
 | 
						|
        bounds = glamor_start_rendering_bounds();
 | 
						|
        for (int i = 0; i < nbox; i++)
 | 
						|
            glamor_bounds_union_box(&bounds, &box[i]);
 | 
						|
    }
 | 
						|
 | 
						|
    for (n = 0; n < nbox; n++) {
 | 
						|
        v[0] = box->x1; v[1] = box->y1;
 | 
						|
        v[2] = box->x1; v[3] = box->y2;
 | 
						|
        v[4] = box->x2; v[5] = box->y2;
 | 
						|
        v[6] = box->x2; v[7] = box->y1;
 | 
						|
 | 
						|
        v += 8;
 | 
						|
        box++;
 | 
						|
    }
 | 
						|
 | 
						|
    glamor_put_vbo_space(screen);
 | 
						|
 | 
						|
    glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
 | 
						|
 | 
						|
    glEnable(GL_SCISSOR_TEST);
 | 
						|
 | 
						|
    glamor_pixmap_loop(src_priv, src_box_index) {
 | 
						|
        BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_index);
 | 
						|
 | 
						|
        args.dx = dx + src_off_x - src_box->x1;
 | 
						|
        args.dy = dy + src_off_y - src_box->y1;
 | 
						|
        args.src = glamor_pixmap_fbo_at(src_priv, src_box_index);
 | 
						|
 | 
						|
        if (!glamor_use_program(dst_pixmap, gc, prog, &args))
 | 
						|
            goto bail_ctx;
 | 
						|
 | 
						|
        glamor_pixmap_loop(dst_priv, dst_box_index) {
 | 
						|
            BoxRec scissor = {
 | 
						|
                .x1 = max(-args.dx, bounds.x1),
 | 
						|
                .y1 = max(-args.dy, bounds.y1),
 | 
						|
                .x2 = min(-args.dx + src_box->x2 - src_box->x1, bounds.x2),
 | 
						|
                .y2 = min(-args.dy + src_box->y2 - src_box->y1, bounds.y2),
 | 
						|
            };
 | 
						|
            if (scissor.x1 >= scissor.x2 || scissor.y1 >= scissor.y2)
 | 
						|
                continue;
 | 
						|
 | 
						|
            if (!glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE,
 | 
						|
                                                 prog->matrix_uniform,
 | 
						|
                                                 &dst_off_x, &dst_off_y))
 | 
						|
                goto bail_ctx;
 | 
						|
 | 
						|
            glScissor(scissor.x1 + dst_off_x,
 | 
						|
                      scissor.y1 + dst_off_y,
 | 
						|
                      scissor.x2 - scissor.x1,
 | 
						|
                      scissor.y2 - scissor.y1);
 | 
						|
 | 
						|
            glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    ret = TRUE;
 | 
						|
 | 
						|
bail_ctx:
 | 
						|
    if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
 | 
						|
        glDisable(GL_TILE_RASTER_ORDER_FIXED_MESA);
 | 
						|
    }
 | 
						|
    glDisable(GL_SCISSOR_TEST);
 | 
						|
    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Copies from the GPU to the GPU using a temporary pixmap in between,
 | 
						|
 * to correctly handle overlapping copies.
 | 
						|
 */
 | 
						|
 | 
						|
static Bool
 | 
						|
glamor_copy_fbo_fbo_temp(DrawablePtr src,
 | 
						|
                         DrawablePtr dst,
 | 
						|
                         GCPtr gc,
 | 
						|
                         BoxPtr box,
 | 
						|
                         int nbox,
 | 
						|
                         int dx,
 | 
						|
                         int dy,
 | 
						|
                         Bool reverse,
 | 
						|
                         Bool upsidedown,
 | 
						|
                         Pixel bitplane,
 | 
						|
                         void *closure)
 | 
						|
{
 | 
						|
    ScreenPtr screen = dst->pScreen;
 | 
						|
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | 
						|
    PixmapPtr tmp_pixmap;
 | 
						|
    BoxRec bounds;
 | 
						|
    int n;
 | 
						|
    BoxPtr tmp_box;
 | 
						|
 | 
						|
    if (nbox == 0)
 | 
						|
        return TRUE;
 | 
						|
 | 
						|
    /* Sanity check state to avoid getting halfway through and bailing
 | 
						|
     * at the last second. Might be nice to have checks that didn't
 | 
						|
     * involve setting state.
 | 
						|
     */
 | 
						|
    glamor_make_current(glamor_priv);
 | 
						|
 | 
						|
    if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
 | 
						|
        goto bail_ctx;
 | 
						|
 | 
						|
    if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
 | 
						|
        goto bail_ctx;
 | 
						|
 | 
						|
    /* Find the size of the area to copy
 | 
						|
     */
 | 
						|
    bounds = box[0];
 | 
						|
    for (n = 1; n < nbox; n++) {
 | 
						|
        bounds.x1 = min(bounds.x1, box[n].x1);
 | 
						|
        bounds.x2 = max(bounds.x2, box[n].x2);
 | 
						|
        bounds.y1 = min(bounds.y1, box[n].y1);
 | 
						|
        bounds.y2 = max(bounds.y2, box[n].y2);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Allocate a suitable temporary pixmap
 | 
						|
     */
 | 
						|
    tmp_pixmap = glamor_create_pixmap(screen,
 | 
						|
                                      bounds.x2 - bounds.x1,
 | 
						|
                                      bounds.y2 - bounds.y1,
 | 
						|
                                      src->depth, 0);
 | 
						|
    if (!tmp_pixmap)
 | 
						|
        goto bail;
 | 
						|
 | 
						|
    tmp_box = calloc(nbox, sizeof (BoxRec));
 | 
						|
    if (!tmp_box)
 | 
						|
        goto bail_pixmap;
 | 
						|
 | 
						|
    /* Convert destination boxes into tmp pixmap boxes
 | 
						|
     */
 | 
						|
    for (n = 0; n < nbox; n++) {
 | 
						|
        tmp_box[n].x1 = box[n].x1 - bounds.x1;
 | 
						|
        tmp_box[n].x2 = box[n].x2 - bounds.x1;
 | 
						|
        tmp_box[n].y1 = box[n].y1 - bounds.y1;
 | 
						|
        tmp_box[n].y2 = box[n].y2 - bounds.y1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!glamor_copy_fbo_fbo_draw(src,
 | 
						|
                                  &tmp_pixmap->drawable,
 | 
						|
                                  NULL,
 | 
						|
                                  tmp_box,
 | 
						|
                                  nbox,
 | 
						|
                                  dx + bounds.x1,
 | 
						|
                                  dy + bounds.y1,
 | 
						|
                                  FALSE, FALSE,
 | 
						|
                                  0, NULL))
 | 
						|
        goto bail_box;
 | 
						|
 | 
						|
    if (!glamor_copy_fbo_fbo_draw(&tmp_pixmap->drawable,
 | 
						|
                                  dst,
 | 
						|
                                  gc,
 | 
						|
                                  box,
 | 
						|
                                  nbox,
 | 
						|
                                  -bounds.x1,
 | 
						|
                                  -bounds.y1,
 | 
						|
                                  FALSE, FALSE,
 | 
						|
                                  bitplane, closure))
 | 
						|
        goto bail_box;
 | 
						|
 | 
						|
    free(tmp_box);
 | 
						|
 | 
						|
    glamor_destroy_pixmap(tmp_pixmap);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
bail_box:
 | 
						|
    free(tmp_box);
 | 
						|
bail_pixmap:
 | 
						|
    glamor_destroy_pixmap(tmp_pixmap);
 | 
						|
bail:
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
bail_ctx:
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns TRUE if the copy has to be implemented with
 | 
						|
 * glamor_copy_fbo_fbo_temp() instead of glamor_copy_fbo_fbo().
 | 
						|
 *
 | 
						|
 * If the src and dst are in the same pixmap, then glamor_copy_fbo_fbo()'s
 | 
						|
 * sampling would give undefined results (since the same texture would be
 | 
						|
 * bound as an FBO destination and as a texture source).  However, if we
 | 
						|
 * have GL_NV_texture_barrier, we can take advantage of the exception it
 | 
						|
 * added:
 | 
						|
 *
 | 
						|
 *    "- If a texel has been written, then in order to safely read the result
 | 
						|
 *       a texel fetch must be in a subsequent Draw separated by the command
 | 
						|
 *
 | 
						|
 *       void TextureBarrierNV(void);
 | 
						|
 *
 | 
						|
 *    TextureBarrierNV() will guarantee that writes have completed and caches
 | 
						|
 *    have been invalidated before subsequent Draws are executed."
 | 
						|
 */
 | 
						|
static Bool
 | 
						|
glamor_copy_needs_temp(DrawablePtr src,
 | 
						|
                       DrawablePtr dst,
 | 
						|
                       BoxPtr box,
 | 
						|
                       int nbox,
 | 
						|
                       int dx,
 | 
						|
                       int dy)
 | 
						|
{
 | 
						|
    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | 
						|
    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | 
						|
    ScreenPtr screen = dst->pScreen;
 | 
						|
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | 
						|
    int n;
 | 
						|
    int dst_off_x, dst_off_y;
 | 
						|
    int src_off_x, src_off_y;
 | 
						|
    BoxRec bounds;
 | 
						|
 | 
						|
    if (src_pixmap != dst_pixmap)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    if (nbox == 0)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    if (!glamor_priv->has_nv_texture_barrier)
 | 
						|
        return TRUE;
 | 
						|
 | 
						|
    if (!glamor_priv->has_mesa_tile_raster_order) {
 | 
						|
        glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
 | 
						|
        glamor_get_drawable_deltas(dst, dst_pixmap, &dst_off_x, &dst_off_y);
 | 
						|
 | 
						|
        bounds = box[0];
 | 
						|
        for (n = 1; n < nbox; n++) {
 | 
						|
            bounds.x1 = min(bounds.x1, box[n].x1);
 | 
						|
            bounds.y1 = min(bounds.y1, box[n].y1);
 | 
						|
 | 
						|
            bounds.x2 = max(bounds.x2, box[n].x2);
 | 
						|
            bounds.y2 = max(bounds.y2, box[n].y2);
 | 
						|
        }
 | 
						|
 | 
						|
        /* Check to see if the pixmap-relative boxes overlap in both X and Y,
 | 
						|
         * in which case we can't rely on NV_texture_barrier and must
 | 
						|
         * make a temporary copy
 | 
						|
         *
 | 
						|
         *  dst.x1                     < src.x2 &&
 | 
						|
         *  src.x1                     < dst.x2 &&
 | 
						|
         *
 | 
						|
         *  dst.y1                     < src.y2 &&
 | 
						|
         *  src.y1                     < dst.y2
 | 
						|
         */
 | 
						|
        if (bounds.x1 + dst_off_x      < bounds.x2 + dx + src_off_x &&
 | 
						|
            bounds.x1 + dx + src_off_x < bounds.x2 + dst_off_x &&
 | 
						|
 | 
						|
            bounds.y1 + dst_off_y      < bounds.y2 + dy + src_off_y &&
 | 
						|
            bounds.y1 + dy + src_off_y < bounds.y2 + dst_off_y) {
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    glTextureBarrierNV();
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
glamor_copy_gl(DrawablePtr src,
 | 
						|
               DrawablePtr dst,
 | 
						|
               GCPtr gc,
 | 
						|
               BoxPtr box,
 | 
						|
               int nbox,
 | 
						|
               int dx,
 | 
						|
               int dy,
 | 
						|
               Bool reverse,
 | 
						|
               Bool upsidedown,
 | 
						|
               Pixel bitplane,
 | 
						|
               void *closure)
 | 
						|
{
 | 
						|
    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | 
						|
    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | 
						|
    glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
 | 
						|
    glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
 | 
						|
 | 
						|
    if (GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_priv)) {
 | 
						|
        if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv)) {
 | 
						|
            if (glamor_copy_needs_temp(src, dst, box, nbox, dx, dy))
 | 
						|
                return glamor_copy_fbo_fbo_temp(src, dst, gc, box, nbox, dx, dy,
 | 
						|
                                                reverse, upsidedown, bitplane, closure);
 | 
						|
            else
 | 
						|
                return glamor_copy_fbo_fbo_draw(src, dst, gc, box, nbox, dx, dy,
 | 
						|
                                                reverse, upsidedown, bitplane, closure);
 | 
						|
        }
 | 
						|
 | 
						|
        return glamor_copy_cpu_fbo(src, dst, gc, box, nbox, dx, dy,
 | 
						|
                                   reverse, upsidedown, bitplane, closure);
 | 
						|
    } else if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv) &&
 | 
						|
               dst_priv->type != GLAMOR_DRM_ONLY &&
 | 
						|
               bitplane == 0) {
 | 
						|
            return glamor_copy_fbo_cpu(src, dst, gc, box, nbox, dx, dy,
 | 
						|
                                       reverse, upsidedown, bitplane, closure);
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
glamor_copy(DrawablePtr src,
 | 
						|
            DrawablePtr dst,
 | 
						|
            GCPtr gc,
 | 
						|
            BoxPtr box,
 | 
						|
            int nbox,
 | 
						|
            int dx,
 | 
						|
            int dy,
 | 
						|
            Bool reverse,
 | 
						|
            Bool upsidedown,
 | 
						|
            Pixel bitplane,
 | 
						|
            void *closure)
 | 
						|
{
 | 
						|
    if (nbox == 0)
 | 
						|
	return;
 | 
						|
 | 
						|
    if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure))
 | 
						|
        return;
 | 
						|
    glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
 | 
						|
}
 | 
						|
 | 
						|
RegionPtr
 | 
						|
glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 | 
						|
                 int srcx, int srcy, int width, int height, int dstx, int dsty)
 | 
						|
{
 | 
						|
    return miDoCopy(src, dst, gc,
 | 
						|
                    srcx, srcy, width, height,
 | 
						|
                    dstx, dsty, glamor_copy, 0, NULL);
 | 
						|
}
 | 
						|
 | 
						|
RegionPtr
 | 
						|
glamor_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 | 
						|
                  int srcx, int srcy, int width, int height, int dstx, int dsty,
 | 
						|
                  unsigned long bitplane)
 | 
						|
{
 | 
						|
    if ((bitplane & FbFullMask(src->depth)) == 0)
 | 
						|
        return miHandleExposures(src, dst, gc,
 | 
						|
                                 srcx, srcy, width, height, dstx, dsty);
 | 
						|
    return miDoCopy(src, dst, gc,
 | 
						|
                    srcx, srcy, width, height,
 | 
						|
                    dstx, dsty, glamor_copy, bitplane, NULL);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
glamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region)
 | 
						|
{
 | 
						|
    PixmapPtr pixmap = glamor_get_drawable_pixmap(&window->drawable);
 | 
						|
    DrawablePtr drawable = &pixmap->drawable;
 | 
						|
    RegionRec dst_region;
 | 
						|
    int dx, dy;
 | 
						|
 | 
						|
    dx = old_origin.x - window->drawable.x;
 | 
						|
    dy = old_origin.y - window->drawable.y;
 | 
						|
    RegionTranslate(src_region, -dx, -dy);
 | 
						|
 | 
						|
    RegionNull(&dst_region);
 | 
						|
 | 
						|
    RegionIntersect(&dst_region, &window->borderClip, src_region);
 | 
						|
 | 
						|
#ifdef COMPOSITE
 | 
						|
    if (pixmap->screen_x || pixmap->screen_y)
 | 
						|
        RegionTranslate(&dst_region, -pixmap->screen_x, -pixmap->screen_y);
 | 
						|
#endif
 | 
						|
 | 
						|
    miCopyRegion(drawable, drawable,
 | 
						|
                 0, &dst_region, dx, dy, glamor_copy, 0, 0);
 | 
						|
 | 
						|
    RegionUninit(&dst_region);
 | 
						|
}
 |