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
28struct copy_args {
29    PixmapPtr           src_pixmap;
30    glamor_pixmap_fbo   *src;
31    uint32_t            bitplane;
32    int                 dx, dy;
33};
34
35static Bool
36use_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
50static 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
64static Bool
65use_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
141static 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
161static void
162glamor_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 */
199static Bool
200glamor_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
277bail:
278    return FALSE;
279}
280
281/**
282 * Implements CopyArea from the GPU to the CPU using glReadPixels from the
283 * source FBO.
284 */
285static Bool
286glamor_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
329bail:
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
345static Bool
346glamor_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
485bail_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
500static Bool
501glamor_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;
594bail_box:
595    free(tmp_box);
596bail_pixmap:
597    glamor_destroy_pixmap(tmp_pixmap);
598bail:
599    return FALSE;
600
601bail_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 */
623static Bool
624glamor_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
686static Bool
687glamor_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
725void
726glamor_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
746RegionPtr
747glamor_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
755RegionPtr
756glamor_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
768void
769glamor_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}
794