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