summaryrefslogtreecommitdiff
path: root/glamor/glamor_copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'glamor/glamor_copy.c')
-rw-r--r--glamor/glamor_copy.c693
1 files changed, 693 insertions, 0 deletions
diff --git a/glamor/glamor_copy.c b/glamor/glamor_copy.c
new file mode 100644
index 000000000..bfcde43db
--- /dev/null
+++ b/glamor/glamor_copy.c
@@ -0,0 +1,693 @@
+/*
+ * 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;
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, src->tex);
+
+ glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
+ glUniform2f(prog->fill_size_uniform, src->width, 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;\n"),
+ .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n",
+ .locations = glamor_program_location_fill,
+ .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;
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, src->tex);
+
+ glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
+ glUniform2f(prog->fill_size_uniform, src->width, 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 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;\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_fill|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 GPU 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);
+ FbBits *src_bits;
+ FbStride src_stride;
+ int src_bpp;
+ int src_xoff, src_yoff;
+ int dst_xoff, dst_yoff;
+
+ if (gc && gc->alu != GXcopy)
+ goto bail;
+
+ if (gc && !glamor_pm_is_solid(dst, gc->planemask))
+ goto bail;
+
+ glamor_make_current(glamor_priv);
+ glamor_prepare_access(src, GLAMOR_ACCESS_RO);
+
+ glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_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;
+}
+
+/*
+ * 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_x, src_box_y, dst_box_x, dst_box_y;
+ 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;
+ Bool set_scissor;
+ int n;
+
+ glamor_make_current(glamor_priv);
+
+ if (gc && !glamor_set_planemask(dst_pixmap, gc->planemask))
+ goto bail_ctx;
+
+ if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
+ 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))
+ 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);
+
+ glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
+ 2 * sizeof (GLshort), vbo_offset);
+
+ 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);
+
+ set_scissor = src_priv->type == GLAMOR_TEXTURE_LARGE;
+ if (set_scissor)
+ glEnable(GL_SCISSOR_TEST);
+
+ glamor_pixmap_loop(src_priv, src_box_x, src_box_y) {
+ BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_x, src_box_y);
+
+ 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_x, src_box_y);
+
+ if (!glamor_use_program(dst_pixmap, gc, prog, &args))
+ goto bail_ctx;
+
+ glamor_pixmap_loop(dst_priv, dst_box_x, dst_box_y) {
+ glamor_set_destination_drawable(dst, dst_box_x, dst_box_y, FALSE, FALSE,
+ prog->matrix_uniform, &dst_off_x, &dst_off_y);
+
+ if (set_scissor)
+ glScissor(dst_off_x - args.dx,
+ dst_off_y - args.dy,
+ src_box->x2 - src_box->x1,
+ src_box->y2 - src_box->y1);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ glDrawArrays(GL_QUADS, 0, nbox * 4);
+ else {
+ int i;
+ for (i = 0; i < nbox; i++)
+ glDrawArrays(GL_TRIANGLE_FAN, i*4, 4);
+ }
+ }
+ }
+ if (set_scissor)
+ glDisable(GL_SCISSOR_TEST);
+ glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+ glDisable(GL_COLOR_LOGIC_OP);
+ return TRUE;
+
+bail_ctx:
+ glDisable(GL_COLOR_LOGIC_OP);
+ return FALSE;
+}
+
+/**
+ * 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 dst_pixmap = glamor_get_drawable_pixmap(dst);
+ 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(dst_pixmap, gc->planemask))
+ goto bail_ctx;
+
+ if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
+ goto bail_ctx;
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ /* 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:
+ glDisable(GL_COLOR_LOGIC_OP);
+ 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;
+
+ 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);
+ }
+ if (bitplane == 0)
+ return glamor_copy_cpu_fbo(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 (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,
+ bitplane);
+ 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);
+}
+
+Bool
+glamor_copy_n_to_n_nf(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc,
+ BoxPtr box,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown, Pixel bitplane,
+ void *closure)
+{
+ if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure))
+ return TRUE;
+ if (glamor_ddx_fallback_check_pixmap(src) && glamor_ddx_fallback_check_pixmap(dst))
+ return FALSE;
+ glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
+ return TRUE;
+}
+
+Bool
+glamor_copy_plane_nf(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitplane, RegionPtr *region)
+{
+ if (glamor_ddx_fallback_check_pixmap(src) &&
+ glamor_ddx_fallback_check_pixmap(dst) &&
+ glamor_ddx_fallback_check_gc(gc))
+ return FALSE;
+
+ *region = glamor_copy_plane(src, dst, gc,
+ srcx, srcy, w, h, dstx, dsty,
+ bitplane);
+ return TRUE;
+}