"Fossies" - the Fresh Open Source Software Archive

Member "xorg-server-1.20.8/glamor/glamor_copy.c" (29 Mar 2020, 26314 Bytes) of package /linux/misc/xorg-server-1.20.8.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "glamor_copy.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.20.7_vs_1.20.8.

    1 /*
    2  * Copyright © 2014 Keith Packard
    3  *
    4  * Permission to use, copy, modify, distribute, and sell this software and its
    5  * documentation for any purpose is hereby granted without fee, provided that
    6  * the above copyright notice appear in all copies and that both that copyright
    7  * notice and this permission notice appear in supporting documentation, and
    8  * that the name of the copyright holders not be used in advertising or
    9  * publicity pertaining to distribution of the software without specific,
   10  * written prior permission.  The copyright holders make no representations
   11  * about the suitability of this software for any purpose.  It is provided "as
   12  * is" without express or implied warranty.
   13  *
   14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
   16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
   17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
   18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
   19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
   20  * OF THIS SOFTWARE.
   21  */
   22 
   23 #include "glamor_priv.h"
   24 #include "glamor_transfer.h"
   25 #include "glamor_prepare.h"
   26 #include "glamor_transform.h"
   27 
   28 struct copy_args {
   29     PixmapPtr           src_pixmap;
   30     glamor_pixmap_fbo   *src;
   31     uint32_t            bitplane;
   32     int                 dx, dy;
   33 };
   34 
   35 static Bool
   36 use_copyarea(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
   37 {
   38     struct copy_args *args = arg;
   39     glamor_pixmap_fbo *src = args->src;
   40 
   41     glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
   42                         GL_TEXTURE0, src, TRUE);
   43 
   44     glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
   45     glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
   46 
   47     return TRUE;
   48 }
   49 
   50 static const glamor_facet glamor_facet_copyarea = {
   51     "copy_area",
   52     .vs_vars = "attribute vec2 primitive;\n",
   53     .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy)
   54                 "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
   55     .fs_exec = "       gl_FragColor = texture2D(sampler, fill_pos);\n",
   56     .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
   57     .use = use_copyarea,
   58 };
   59 
   60 /*
   61  * Configure the copy plane program for the current operation
   62  */
   63 
   64 static Bool
   65 use_copyplane(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
   66 {
   67     struct copy_args *args = arg;
   68     glamor_pixmap_fbo *src = args->src;
   69 
   70     glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
   71                         GL_TEXTURE0, src, TRUE);
   72 
   73     glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
   74     glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
   75 
   76     glamor_set_color(dst, gc->fgPixel, prog->fg_uniform);
   77     glamor_set_color(dst, gc->bgPixel, prog->bg_uniform);
   78 
   79     /* XXX handle 2 10 10 10 and 1555 formats; presumably the pixmap private knows this? */
   80     switch (args->src_pixmap->drawable.depth) {
   81     case 30:
   82         glUniform4ui(prog->bitplane_uniform,
   83                      (args->bitplane >> 20) & 0x3ff,
   84                      (args->bitplane >> 10) & 0x3ff,
   85                      (args->bitplane      ) & 0x3ff,
   86                      0);
   87 
   88         glUniform4f(prog->bitmul_uniform, 0x3ff, 0x3ff, 0x3ff, 0);
   89         break;
   90     case 24:
   91         glUniform4ui(prog->bitplane_uniform,
   92                      (args->bitplane >> 16) & 0xff,
   93                      (args->bitplane >>  8) & 0xff,
   94                      (args->bitplane      ) & 0xff,
   95                      0);
   96 
   97         glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0);
   98         break;
   99     case 32:
  100         glUniform4ui(prog->bitplane_uniform,
  101                      (args->bitplane >> 16) & 0xff,
  102                      (args->bitplane >>  8) & 0xff,
  103                      (args->bitplane      ) & 0xff,
  104                      (args->bitplane >> 24) & 0xff);
  105 
  106         glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0xff);
  107         break;
  108     case 16:
  109         glUniform4ui(prog->bitplane_uniform,
  110                      (args->bitplane >> 11) & 0x1f,
  111                      (args->bitplane >>  5) & 0x3f,
  112                      (args->bitplane      ) & 0x1f,
  113                      0);
  114 
  115         glUniform4f(prog->bitmul_uniform, 0x1f, 0x3f, 0x1f, 0);
  116         break;
  117     case 15:
  118         glUniform4ui(prog->bitplane_uniform,
  119                      (args->bitplane >> 10) & 0x1f,
  120                      (args->bitplane >>  5) & 0x1f,
  121                      (args->bitplane      ) & 0x1f,
  122                      0);
  123 
  124         glUniform4f(prog->bitmul_uniform, 0x1f, 0x1f, 0x1f, 0);
  125         break;
  126     case 8:
  127         glUniform4ui(prog->bitplane_uniform,
  128                      0, 0, 0, args->bitplane);
  129         glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
  130         break;
  131     case 1:
  132         glUniform4ui(prog->bitplane_uniform,
  133                      0, 0, 0, args->bitplane);
  134         glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
  135         break;
  136     }
  137 
  138     return TRUE;
  139 }
  140 
  141 static const glamor_facet glamor_facet_copyplane = {
  142     "copy_plane",
  143     .version = 130,
  144     .vs_vars = "attribute vec2 primitive;\n",
  145     .vs_exec = (GLAMOR_POS(gl_Position, (primitive.xy))
  146                 "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
  147     .fs_exec = ("       uvec4 bits = uvec4(round(texture2D(sampler, fill_pos) * bitmul));\n"
  148                 "       if ((bits & bitplane) != uvec4(0,0,0,0))\n"
  149                 "               gl_FragColor = fg;\n"
  150                 "       else\n"
  151                 "               gl_FragColor = bg;\n"),
  152     .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane,
  153     .use = use_copyplane,
  154 };
  155 
  156 /*
  157  * When all else fails, pull the bits out of the GPU and do the
  158  * operation with fb
  159  */
  160 
  161 static void
  162 glamor_copy_bail(DrawablePtr src,
  163                  DrawablePtr dst,
  164                  GCPtr gc,
  165                  BoxPtr box,
  166                  int nbox,
  167                  int dx,
  168                  int dy,
  169                  Bool reverse,
  170                  Bool upsidedown,
  171                  Pixel bitplane,
  172                  void *closure)
  173 {
  174     if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) && glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
  175         if (bitplane) {
  176             if (src->bitsPerPixel > 1)
  177                 fbCopyNto1(src, dst, gc, box, nbox, dx, dy,
  178                            reverse, upsidedown, bitplane, closure);
  179             else
  180                 fbCopy1toN(src, dst, gc, box, nbox, dx, dy,
  181                            reverse, upsidedown, bitplane, closure);
  182         } else {
  183             fbCopyNtoN(src, dst, gc, box, nbox, dx, dy,
  184                        reverse, upsidedown, bitplane, closure);
  185         }
  186     }
  187     glamor_finish_access(dst);
  188     glamor_finish_access(src);
  189 }
  190 
  191 /**
  192  * Implements CopyPlane and CopyArea from the CPU to the GPU by using
  193  * the source as a texture and painting that into the destination.
  194  *
  195  * This requires that source and dest are different textures, or that
  196  * (if the copy area doesn't overlap), GL_NV_texture_barrier is used
  197  * to ensure that the caches are flushed at the right times.
  198  */
  199 static Bool
  200 glamor_copy_cpu_fbo(DrawablePtr src,
  201                     DrawablePtr dst,
  202                     GCPtr gc,
  203                     BoxPtr box,
  204                     int nbox,
  205                     int dx,
  206                     int dy,
  207                     Bool reverse,
  208                     Bool upsidedown,
  209                     Pixel bitplane,
  210                     void *closure)
  211 {
  212     ScreenPtr screen = dst->pScreen;
  213     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  214     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
  215     int dst_xoff, dst_yoff;
  216 
  217     if (gc && gc->alu != GXcopy)
  218         goto bail;
  219 
  220     if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
  221         goto bail;
  222 
  223     glamor_make_current(glamor_priv);
  224 
  225     if (!glamor_prepare_access(src, GLAMOR_ACCESS_RO))
  226         goto bail;
  227 
  228     glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_yoff);
  229 
  230     if (bitplane) {
  231         FbBits *tmp_bits;
  232         FbStride tmp_stride;
  233         int tmp_bpp;
  234         int tmp_xoff, tmp_yoff;
  235 
  236         PixmapPtr tmp_pix = fbCreatePixmap(screen, dst_pixmap->drawable.width,
  237                                            dst_pixmap->drawable.height,
  238                                            dst->depth, 0);
  239 
  240         if (!tmp_pix) {
  241             glamor_finish_access(src);
  242             goto bail;
  243         }
  244 
  245         tmp_pix->drawable.x = dst_xoff;
  246         tmp_pix->drawable.y = dst_yoff;
  247 
  248         fbGetDrawable(&tmp_pix->drawable, tmp_bits, tmp_stride, tmp_bpp, tmp_xoff,
  249                       tmp_yoff);
  250 
  251         if (src->bitsPerPixel > 1)
  252             fbCopyNto1(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
  253                        reverse, upsidedown, bitplane, closure);
  254         else
  255             fbCopy1toN(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
  256                        reverse, upsidedown, bitplane, closure);
  257 
  258         glamor_upload_boxes(dst_pixmap, box, nbox, tmp_xoff, tmp_yoff,
  259                             dst_xoff, dst_yoff, (uint8_t *) tmp_bits,
  260                             tmp_stride * sizeof(FbBits));
  261         fbDestroyPixmap(tmp_pix);
  262     } else {
  263         FbBits *src_bits;
  264         FbStride src_stride;
  265         int src_bpp;
  266         int src_xoff, src_yoff;
  267 
  268         fbGetDrawable(src, src_bits, src_stride, src_bpp, src_xoff, src_yoff);
  269         glamor_upload_boxes(dst_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
  270                             dst_xoff, dst_yoff,
  271                             (uint8_t *) src_bits, src_stride * sizeof (FbBits));
  272     }
  273     glamor_finish_access(src);
  274 
  275     return TRUE;
  276 
  277 bail:
  278     return FALSE;
  279 }
  280 
  281 /**
  282  * Implements CopyArea from the GPU to the CPU using glReadPixels from the
  283  * source FBO.
  284  */
  285 static Bool
  286 glamor_copy_fbo_cpu(DrawablePtr src,
  287                     DrawablePtr dst,
  288                     GCPtr gc,
  289                     BoxPtr box,
  290                     int nbox,
  291                     int dx,
  292                     int dy,
  293                     Bool reverse,
  294                     Bool upsidedown,
  295                     Pixel bitplane,
  296                     void *closure)
  297 {
  298     ScreenPtr screen = dst->pScreen;
  299     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  300     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
  301     FbBits *dst_bits;
  302     FbStride dst_stride;
  303     int dst_bpp;
  304     int src_xoff, src_yoff;
  305     int dst_xoff, dst_yoff;
  306 
  307     if (gc && gc->alu != GXcopy)
  308         goto bail;
  309 
  310     if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
  311         goto bail;
  312 
  313     glamor_make_current(glamor_priv);
  314 
  315     if (!glamor_prepare_access(dst, GLAMOR_ACCESS_RW))
  316         goto bail;
  317 
  318     glamor_get_drawable_deltas(src, src_pixmap, &src_xoff, &src_yoff);
  319 
  320     fbGetDrawable(dst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff);
  321 
  322     glamor_download_boxes(src_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
  323                           dst_xoff, dst_yoff,
  324                           (uint8_t *) dst_bits, dst_stride * sizeof (FbBits));
  325     glamor_finish_access(dst);
  326 
  327     return TRUE;
  328 
  329 bail:
  330     return FALSE;
  331 }
  332 
  333 /* Include the enums here for the moment, to keep from needing to bump epoxy. */
  334 #ifndef GL_TILE_RASTER_ORDER_FIXED_MESA
  335 #define GL_TILE_RASTER_ORDER_FIXED_MESA          0x8BB8
  336 #define GL_TILE_RASTER_ORDER_INCREASING_X_MESA   0x8BB9
  337 #define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA   0x8BBA
  338 #endif
  339 
  340 /*
  341  * Copy from GPU to GPU by using the source
  342  * as a texture and painting that into the destination
  343  */
  344 
  345 static Bool
  346 glamor_copy_fbo_fbo_draw(DrawablePtr src,
  347                          DrawablePtr dst,
  348                          GCPtr gc,
  349                          BoxPtr box,
  350                          int nbox,
  351                          int dx,
  352                          int dy,
  353                          Bool reverse,
  354                          Bool upsidedown,
  355                          Pixel bitplane,
  356                          void *closure)
  357 {
  358     ScreenPtr screen = dst->pScreen;
  359     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  360     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
  361     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
  362     glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
  363     glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
  364     int src_box_index, dst_box_index;
  365     int dst_off_x, dst_off_y;
  366     int src_off_x, src_off_y;
  367     GLshort *v;
  368     char *vbo_offset;
  369     struct copy_args args;
  370     glamor_program *prog;
  371     const glamor_facet *copy_facet;
  372     int n;
  373     Bool ret = FALSE;
  374     BoxRec bounds = glamor_no_rendering_bounds();
  375 
  376     glamor_make_current(glamor_priv);
  377 
  378     if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
  379         goto bail_ctx;
  380 
  381     if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
  382         goto bail_ctx;
  383 
  384     if (bitplane && !glamor_priv->can_copyplane)
  385         goto bail_ctx;
  386 
  387     if (bitplane) {
  388         prog = &glamor_priv->copy_plane_prog;
  389         copy_facet = &glamor_facet_copyplane;
  390     } else {
  391         prog = &glamor_priv->copy_area_prog;
  392         copy_facet = &glamor_facet_copyarea;
  393     }
  394 
  395     if (prog->failed)
  396         goto bail_ctx;
  397 
  398     if (!prog->prog) {
  399         if (!glamor_build_program(screen, prog,
  400                                   copy_facet, NULL, NULL, NULL))
  401             goto bail_ctx;
  402     }
  403 
  404     args.src_pixmap = src_pixmap;
  405     args.bitplane = bitplane;
  406 
  407     /* Set up the vertex buffers for the points */
  408 
  409     v = glamor_get_vbo_space(dst->pScreen, nbox * 8 * sizeof (int16_t), &vbo_offset);
  410 
  411     if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
  412         glEnable(GL_TILE_RASTER_ORDER_FIXED_MESA);
  413         if (dx >= 0)
  414             glEnable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
  415         else
  416             glDisable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
  417         if (dy >= 0)
  418             glEnable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
  419         else
  420             glDisable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
  421     }
  422 
  423     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
  424     glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
  425                           2 * sizeof (GLshort), vbo_offset);
  426 
  427     if (nbox < 100) {
  428         bounds = glamor_start_rendering_bounds();
  429         for (int i = 0; i < nbox; i++)
  430             glamor_bounds_union_box(&bounds, &box[i]);
  431     }
  432 
  433     for (n = 0; n < nbox; n++) {
  434         v[0] = box->x1; v[1] = box->y1;
  435         v[2] = box->x1; v[3] = box->y2;
  436         v[4] = box->x2; v[5] = box->y2;
  437         v[6] = box->x2; v[7] = box->y1;
  438 
  439         v += 8;
  440         box++;
  441     }
  442 
  443     glamor_put_vbo_space(screen);
  444 
  445     glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
  446 
  447     glEnable(GL_SCISSOR_TEST);
  448 
  449     glamor_pixmap_loop(src_priv, src_box_index) {
  450         BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_index);
  451 
  452         args.dx = dx + src_off_x - src_box->x1;
  453         args.dy = dy + src_off_y - src_box->y1;
  454         args.src = glamor_pixmap_fbo_at(src_priv, src_box_index);
  455 
  456         if (!glamor_use_program(dst_pixmap, gc, prog, &args))
  457             goto bail_ctx;
  458 
  459         glamor_pixmap_loop(dst_priv, dst_box_index) {
  460             BoxRec scissor = {
  461                 .x1 = max(-args.dx, bounds.x1),
  462                 .y1 = max(-args.dy, bounds.y1),
  463                 .x2 = min(-args.dx + src_box->x2 - src_box->x1, bounds.x2),
  464                 .y2 = min(-args.dy + src_box->y2 - src_box->y1, bounds.y2),
  465             };
  466             if (scissor.x1 >= scissor.x2 || scissor.y1 >= scissor.y2)
  467                 continue;
  468 
  469             if (!glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE,
  470                                                  prog->matrix_uniform,
  471                                                  &dst_off_x, &dst_off_y))
  472                 goto bail_ctx;
  473 
  474             glScissor(scissor.x1 + dst_off_x,
  475                       scissor.y1 + dst_off_y,
  476                       scissor.x2 - scissor.x1,
  477                       scissor.y2 - scissor.y1);
  478 
  479             glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox);
  480         }
  481     }
  482 
  483     ret = TRUE;
  484 
  485 bail_ctx:
  486     if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
  487         glDisable(GL_TILE_RASTER_ORDER_FIXED_MESA);
  488     }
  489     glDisable(GL_SCISSOR_TEST);
  490     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
  491 
  492     return ret;
  493 }
  494 
  495 /**
  496  * Copies from the GPU to the GPU using a temporary pixmap in between,
  497  * to correctly handle overlapping copies.
  498  */
  499 
  500 static Bool
  501 glamor_copy_fbo_fbo_temp(DrawablePtr src,
  502                          DrawablePtr dst,
  503                          GCPtr gc,
  504                          BoxPtr box,
  505                          int nbox,
  506                          int dx,
  507                          int dy,
  508                          Bool reverse,
  509                          Bool upsidedown,
  510                          Pixel bitplane,
  511                          void *closure)
  512 {
  513     ScreenPtr screen = dst->pScreen;
  514     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  515     PixmapPtr tmp_pixmap;
  516     BoxRec bounds;
  517     int n;
  518     BoxPtr tmp_box;
  519 
  520     if (nbox == 0)
  521         return TRUE;
  522 
  523     /* Sanity check state to avoid getting halfway through and bailing
  524      * at the last second. Might be nice to have checks that didn't
  525      * involve setting state.
  526      */
  527     glamor_make_current(glamor_priv);
  528 
  529     if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
  530         goto bail_ctx;
  531 
  532     if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
  533         goto bail_ctx;
  534 
  535     /* Find the size of the area to copy
  536      */
  537     bounds = box[0];
  538     for (n = 1; n < nbox; n++) {
  539         bounds.x1 = min(bounds.x1, box[n].x1);
  540         bounds.x2 = max(bounds.x2, box[n].x2);
  541         bounds.y1 = min(bounds.y1, box[n].y1);
  542         bounds.y2 = max(bounds.y2, box[n].y2);
  543     }
  544 
  545     /* Allocate a suitable temporary pixmap
  546      */
  547     tmp_pixmap = glamor_create_pixmap(screen,
  548                                       bounds.x2 - bounds.x1,
  549                                       bounds.y2 - bounds.y1,
  550                                       src->depth, 0);
  551     if (!tmp_pixmap)
  552         goto bail;
  553 
  554     tmp_box = calloc(nbox, sizeof (BoxRec));
  555     if (!tmp_box)
  556         goto bail_pixmap;
  557 
  558     /* Convert destination boxes into tmp pixmap boxes
  559      */
  560     for (n = 0; n < nbox; n++) {
  561         tmp_box[n].x1 = box[n].x1 - bounds.x1;
  562         tmp_box[n].x2 = box[n].x2 - bounds.x1;
  563         tmp_box[n].y1 = box[n].y1 - bounds.y1;
  564         tmp_box[n].y2 = box[n].y2 - bounds.y1;
  565     }
  566 
  567     if (!glamor_copy_fbo_fbo_draw(src,
  568                                   &tmp_pixmap->drawable,
  569                                   NULL,
  570                                   tmp_box,
  571                                   nbox,
  572                                   dx + bounds.x1,
  573                                   dy + bounds.y1,
  574                                   FALSE, FALSE,
  575                                   0, NULL))
  576         goto bail_box;
  577 
  578     if (!glamor_copy_fbo_fbo_draw(&tmp_pixmap->drawable,
  579                                   dst,
  580                                   gc,
  581                                   box,
  582                                   nbox,
  583                                   -bounds.x1,
  584                                   -bounds.y1,
  585                                   FALSE, FALSE,
  586                                   bitplane, closure))
  587         goto bail_box;
  588 
  589     free(tmp_box);
  590 
  591     glamor_destroy_pixmap(tmp_pixmap);
  592 
  593     return TRUE;
  594 bail_box:
  595     free(tmp_box);
  596 bail_pixmap:
  597     glamor_destroy_pixmap(tmp_pixmap);
  598 bail:
  599     return FALSE;
  600 
  601 bail_ctx:
  602     return FALSE;
  603 }
  604 
  605 /**
  606  * Returns TRUE if the copy has to be implemented with
  607  * glamor_copy_fbo_fbo_temp() instead of glamor_copy_fbo_fbo().
  608  *
  609  * If the src and dst are in the same pixmap, then glamor_copy_fbo_fbo()'s
  610  * sampling would give undefined results (since the same texture would be
  611  * bound as an FBO destination and as a texture source).  However, if we
  612  * have GL_NV_texture_barrier, we can take advantage of the exception it
  613  * added:
  614  *
  615  *    "- If a texel has been written, then in order to safely read the result
  616  *       a texel fetch must be in a subsequent Draw separated by the command
  617  *
  618  *       void TextureBarrierNV(void);
  619  *
  620  *    TextureBarrierNV() will guarantee that writes have completed and caches
  621  *    have been invalidated before subsequent Draws are executed."
  622  */
  623 static Bool
  624 glamor_copy_needs_temp(DrawablePtr src,
  625                        DrawablePtr dst,
  626                        BoxPtr box,
  627                        int nbox,
  628                        int dx,
  629                        int dy)
  630 {
  631     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
  632     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
  633     ScreenPtr screen = dst->pScreen;
  634     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  635     int n;
  636     int dst_off_x, dst_off_y;
  637     int src_off_x, src_off_y;
  638     BoxRec bounds;
  639 
  640     if (src_pixmap != dst_pixmap)
  641         return FALSE;
  642 
  643     if (nbox == 0)
  644         return FALSE;
  645 
  646     if (!glamor_priv->has_nv_texture_barrier)
  647         return TRUE;
  648 
  649     if (!glamor_priv->has_mesa_tile_raster_order) {
  650         glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
  651         glamor_get_drawable_deltas(dst, dst_pixmap, &dst_off_x, &dst_off_y);
  652 
  653         bounds = box[0];
  654         for (n = 1; n < nbox; n++) {
  655             bounds.x1 = min(bounds.x1, box[n].x1);
  656             bounds.y1 = min(bounds.y1, box[n].y1);
  657 
  658             bounds.x2 = max(bounds.x2, box[n].x2);
  659             bounds.y2 = max(bounds.y2, box[n].y2);
  660         }
  661 
  662         /* Check to see if the pixmap-relative boxes overlap in both X and Y,
  663          * in which case we can't rely on NV_texture_barrier and must
  664          * make a temporary copy
  665          *
  666          *  dst.x1                     < src.x2 &&
  667          *  src.x1                     < dst.x2 &&
  668          *
  669          *  dst.y1                     < src.y2 &&
  670          *  src.y1                     < dst.y2
  671          */
  672         if (bounds.x1 + dst_off_x      < bounds.x2 + dx + src_off_x &&
  673             bounds.x1 + dx + src_off_x < bounds.x2 + dst_off_x &&
  674 
  675             bounds.y1 + dst_off_y      < bounds.y2 + dy + src_off_y &&
  676             bounds.y1 + dy + src_off_y < bounds.y2 + dst_off_y) {
  677             return TRUE;
  678         }
  679     }
  680 
  681     glTextureBarrierNV();
  682 
  683     return FALSE;
  684 }
  685 
  686 static Bool
  687 glamor_copy_gl(DrawablePtr src,
  688                DrawablePtr dst,
  689                GCPtr gc,
  690                BoxPtr box,
  691                int nbox,
  692                int dx,
  693                int dy,
  694                Bool reverse,
  695                Bool upsidedown,
  696                Pixel bitplane,
  697                void *closure)
  698 {
  699     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
  700     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
  701     glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
  702     glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
  703 
  704     if (GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_priv)) {
  705         if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv)) {
  706             if (glamor_copy_needs_temp(src, dst, box, nbox, dx, dy))
  707                 return glamor_copy_fbo_fbo_temp(src, dst, gc, box, nbox, dx, dy,
  708                                                 reverse, upsidedown, bitplane, closure);
  709             else
  710                 return glamor_copy_fbo_fbo_draw(src, dst, gc, box, nbox, dx, dy,
  711                                                 reverse, upsidedown, bitplane, closure);
  712         }
  713 
  714         return glamor_copy_cpu_fbo(src, dst, gc, box, nbox, dx, dy,
  715                                    reverse, upsidedown, bitplane, closure);
  716     } else if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv) &&
  717                dst_priv->type != GLAMOR_DRM_ONLY &&
  718                bitplane == 0) {
  719             return glamor_copy_fbo_cpu(src, dst, gc, box, nbox, dx, dy,
  720                                        reverse, upsidedown, bitplane, closure);
  721     }
  722     return FALSE;
  723 }
  724 
  725 void
  726 glamor_copy(DrawablePtr src,
  727             DrawablePtr dst,
  728             GCPtr gc,
  729             BoxPtr box,
  730             int nbox,
  731             int dx,
  732             int dy,
  733             Bool reverse,
  734             Bool upsidedown,
  735             Pixel bitplane,
  736             void *closure)
  737 {
  738     if (nbox == 0)
  739     return;
  740 
  741     if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure))
  742         return;
  743     glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
  744 }
  745 
  746 RegionPtr
  747 glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
  748                  int srcx, int srcy, int width, int height, int dstx, int dsty)
  749 {
  750     return miDoCopy(src, dst, gc,
  751                     srcx, srcy, width, height,
  752                     dstx, dsty, glamor_copy, 0, NULL);
  753 }
  754 
  755 RegionPtr
  756 glamor_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
  757                   int srcx, int srcy, int width, int height, int dstx, int dsty,
  758                   unsigned long bitplane)
  759 {
  760     if ((bitplane & FbFullMask(src->depth)) == 0)
  761         return miHandleExposures(src, dst, gc,
  762                                  srcx, srcy, width, height, dstx, dsty);
  763     return miDoCopy(src, dst, gc,
  764                     srcx, srcy, width, height,
  765                     dstx, dsty, glamor_copy, bitplane, NULL);
  766 }
  767 
  768 void
  769 glamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region)
  770 {
  771     PixmapPtr pixmap = glamor_get_drawable_pixmap(&window->drawable);
  772     DrawablePtr drawable = &pixmap->drawable;
  773     RegionRec dst_region;
  774     int dx, dy;
  775 
  776     dx = old_origin.x - window->drawable.x;
  777     dy = old_origin.y - window->drawable.y;
  778     RegionTranslate(src_region, -dx, -dy);
  779 
  780     RegionNull(&dst_region);
  781 
  782     RegionIntersect(&dst_region, &window->borderClip, src_region);
  783 
  784 #ifdef COMPOSITE
  785     if (pixmap->screen_x || pixmap->screen_y)
  786         RegionTranslate(&dst_region, -pixmap->screen_x, -pixmap->screen_y);
  787 #endif
  788 
  789     miCopyRegion(drawable, drawable,
  790                  0, &dst_region, dx, dy, glamor_copy, 0, 0);
  791 
  792     RegionUninit(&dst_region);
  793 }