xref: /OK3568_Linux_fs/external/xserver/glamor/glamor_copy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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
use_copyarea(PixmapPtr dst,GCPtr gc,glamor_program * prog,void * arg)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
use_copyplane(PixmapPtr dst,GCPtr gc,glamor_program * prog,void * arg)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
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)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
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)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
glamor_copy_fbo_cpu(DrawablePtr src,DrawablePtr dst,GCPtr gc,BoxPtr box,int nbox,int dx,int dy,Bool reverse,Bool upsidedown,Pixel bitplane,void * closure)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
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)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     glamor_pixmap_invalid(dst_pixmap);
484 
485     ret = TRUE;
486 
487 bail_ctx:
488     if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
489         glDisable(GL_TILE_RASTER_ORDER_FIXED_MESA);
490     }
491     glDisable(GL_SCISSOR_TEST);
492     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
493 
494     return ret;
495 }
496 
497 /**
498  * Copies from the GPU to the GPU using a temporary pixmap in between,
499  * to correctly handle overlapping copies.
500  */
501 
502 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)503 glamor_copy_fbo_fbo_temp(DrawablePtr src,
504                          DrawablePtr dst,
505                          GCPtr gc,
506                          BoxPtr box,
507                          int nbox,
508                          int dx,
509                          int dy,
510                          Bool reverse,
511                          Bool upsidedown,
512                          Pixel bitplane,
513                          void *closure)
514 {
515     ScreenPtr screen = dst->pScreen;
516     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
517     PixmapPtr tmp_pixmap;
518     BoxRec bounds;
519     int n;
520     BoxPtr tmp_box;
521 
522     if (nbox == 0)
523         return TRUE;
524 
525     /* Sanity check state to avoid getting halfway through and bailing
526      * at the last second. Might be nice to have checks that didn't
527      * involve setting state.
528      */
529     glamor_make_current(glamor_priv);
530 
531     if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
532         goto bail_ctx;
533 
534     if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
535         goto bail_ctx;
536 
537     /* Find the size of the area to copy
538      */
539     bounds = box[0];
540     for (n = 1; n < nbox; n++) {
541         bounds.x1 = min(bounds.x1, box[n].x1);
542         bounds.x2 = max(bounds.x2, box[n].x2);
543         bounds.y1 = min(bounds.y1, box[n].y1);
544         bounds.y2 = max(bounds.y2, box[n].y2);
545     }
546 
547     /* Allocate a suitable temporary pixmap
548      */
549     tmp_pixmap = glamor_create_pixmap(screen,
550                                       bounds.x2 - bounds.x1,
551                                       bounds.y2 - bounds.y1,
552                                       src->depth, 0);
553     if (!tmp_pixmap)
554         goto bail;
555 
556     tmp_box = calloc(nbox, sizeof (BoxRec));
557     if (!tmp_box)
558         goto bail_pixmap;
559 
560     /* Convert destination boxes into tmp pixmap boxes
561      */
562     for (n = 0; n < nbox; n++) {
563         tmp_box[n].x1 = box[n].x1 - bounds.x1;
564         tmp_box[n].x2 = box[n].x2 - bounds.x1;
565         tmp_box[n].y1 = box[n].y1 - bounds.y1;
566         tmp_box[n].y2 = box[n].y2 - bounds.y1;
567     }
568 
569     if (!glamor_copy_fbo_fbo_draw(src,
570                                   &tmp_pixmap->drawable,
571                                   NULL,
572                                   tmp_box,
573                                   nbox,
574                                   dx + bounds.x1,
575                                   dy + bounds.y1,
576                                   FALSE, FALSE,
577                                   0, NULL))
578         goto bail_box;
579 
580     if (!glamor_copy_fbo_fbo_draw(&tmp_pixmap->drawable,
581                                   dst,
582                                   gc,
583                                   box,
584                                   nbox,
585                                   -bounds.x1,
586                                   -bounds.y1,
587                                   FALSE, FALSE,
588                                   bitplane, closure))
589         goto bail_box;
590 
591     free(tmp_box);
592 
593     glamor_destroy_pixmap(tmp_pixmap);
594 
595     return TRUE;
596 bail_box:
597     free(tmp_box);
598 bail_pixmap:
599     glamor_destroy_pixmap(tmp_pixmap);
600 bail:
601     return FALSE;
602 
603 bail_ctx:
604     return FALSE;
605 }
606 
607 /**
608  * Returns TRUE if the copy has to be implemented with
609  * glamor_copy_fbo_fbo_temp() instead of glamor_copy_fbo_fbo().
610  *
611  * If the src and dst are in the same pixmap, then glamor_copy_fbo_fbo()'s
612  * sampling would give undefined results (since the same texture would be
613  * bound as an FBO destination and as a texture source).  However, if we
614  * have GL_NV_texture_barrier, we can take advantage of the exception it
615  * added:
616  *
617  *    "- If a texel has been written, then in order to safely read the result
618  *       a texel fetch must be in a subsequent Draw separated by the command
619  *
620  *       void TextureBarrierNV(void);
621  *
622  *    TextureBarrierNV() will guarantee that writes have completed and caches
623  *    have been invalidated before subsequent Draws are executed."
624  */
625 static Bool
glamor_copy_needs_temp(DrawablePtr src,DrawablePtr dst,BoxPtr box,int nbox,int dx,int dy)626 glamor_copy_needs_temp(DrawablePtr src,
627                        DrawablePtr dst,
628                        BoxPtr box,
629                        int nbox,
630                        int dx,
631                        int dy)
632 {
633     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
634     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
635     ScreenPtr screen = dst->pScreen;
636     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
637     int n;
638     int dst_off_x, dst_off_y;
639     int src_off_x, src_off_y;
640     BoxRec bounds;
641 
642     if (src_pixmap != dst_pixmap)
643         return FALSE;
644 
645     if (nbox == 0)
646         return FALSE;
647 
648     if (!glamor_priv->has_nv_texture_barrier)
649         return TRUE;
650 
651     if (!glamor_priv->has_mesa_tile_raster_order) {
652         glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
653         glamor_get_drawable_deltas(dst, dst_pixmap, &dst_off_x, &dst_off_y);
654 
655         bounds = box[0];
656         for (n = 1; n < nbox; n++) {
657             bounds.x1 = min(bounds.x1, box[n].x1);
658             bounds.y1 = min(bounds.y1, box[n].y1);
659 
660             bounds.x2 = max(bounds.x2, box[n].x2);
661             bounds.y2 = max(bounds.y2, box[n].y2);
662         }
663 
664         /* Check to see if the pixmap-relative boxes overlap in both X and Y,
665          * in which case we can't rely on NV_texture_barrier and must
666          * make a temporary copy
667          *
668          *  dst.x1                     < src.x2 &&
669          *  src.x1                     < dst.x2 &&
670          *
671          *  dst.y1                     < src.y2 &&
672          *  src.y1                     < dst.y2
673          */
674         if (bounds.x1 + dst_off_x      < bounds.x2 + dx + src_off_x &&
675             bounds.x1 + dx + src_off_x < bounds.x2 + dst_off_x &&
676 
677             bounds.y1 + dst_off_y      < bounds.y2 + dy + src_off_y &&
678             bounds.y1 + dy + src_off_y < bounds.y2 + dst_off_y) {
679             return TRUE;
680         }
681     }
682 
683     glTextureBarrierNV();
684 
685     return FALSE;
686 }
687 
688 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)689 glamor_copy_gl(DrawablePtr src,
690                DrawablePtr dst,
691                GCPtr gc,
692                BoxPtr box,
693                int nbox,
694                int dx,
695                int dy,
696                Bool reverse,
697                Bool upsidedown,
698                Pixel bitplane,
699                void *closure)
700 {
701     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
702     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
703     glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
704     glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
705 
706 #ifdef GLAMOR_HAS_GBM_MAP
707     /* HACK for freerdp */
708     if (nbox == 1 && (box->x2 - box->x1) == 64 && (box->y2 - box->y1) == 64)
709         return FALSE;
710 #endif
711 
712     if (GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_priv)) {
713         if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv)) {
714             if (glamor_copy_needs_temp(src, dst, box, nbox, dx, dy))
715                 return glamor_copy_fbo_fbo_temp(src, dst, gc, box, nbox, dx, dy,
716                                                 reverse, upsidedown, bitplane, closure);
717             else
718                 return glamor_copy_fbo_fbo_draw(src, dst, gc, box, nbox, dx, dy,
719                                                 reverse, upsidedown, bitplane, closure);
720         }
721 
722         return glamor_copy_cpu_fbo(src, dst, gc, box, nbox, dx, dy,
723                                    reverse, upsidedown, bitplane, closure);
724     } else if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv) &&
725                dst_priv->type != GLAMOR_DRM_ONLY &&
726                bitplane == 0) {
727             return glamor_copy_fbo_cpu(src, dst, gc, box, nbox, dx, dy,
728                                        reverse, upsidedown, bitplane, closure);
729     }
730     return FALSE;
731 }
732 
733 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)734 glamor_copy(DrawablePtr src,
735             DrawablePtr dst,
736             GCPtr gc,
737             BoxPtr box,
738             int nbox,
739             int dx,
740             int dy,
741             Bool reverse,
742             Bool upsidedown,
743             Pixel bitplane,
744             void *closure)
745 {
746     if (nbox == 0)
747 	return;
748 
749     if (GLAMOR_PREFER_GL() &&
750         glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse,
751                        upsidedown, bitplane, closure))
752         return;
753     glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
754 }
755 
756 RegionPtr
glamor_copy_area(DrawablePtr src,DrawablePtr dst,GCPtr gc,int srcx,int srcy,int width,int height,int dstx,int dsty)757 glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
758                  int srcx, int srcy, int width, int height, int dstx, int dsty)
759 {
760     return miDoCopy(src, dst, gc,
761                     srcx, srcy, width, height,
762                     dstx, dsty, glamor_copy, 0, NULL);
763 }
764 
765 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)766 glamor_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
767                   int srcx, int srcy, int width, int height, int dstx, int dsty,
768                   unsigned long bitplane)
769 {
770     if ((bitplane & FbFullMask(src->depth)) == 0)
771         return miHandleExposures(src, dst, gc,
772                                  srcx, srcy, width, height, dstx, dsty);
773     return miDoCopy(src, dst, gc,
774                     srcx, srcy, width, height,
775                     dstx, dsty, glamor_copy, bitplane, NULL);
776 }
777 
778 void
glamor_copy_window(WindowPtr window,DDXPointRec old_origin,RegionPtr src_region)779 glamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region)
780 {
781     PixmapPtr pixmap = glamor_get_drawable_pixmap(&window->drawable);
782     DrawablePtr drawable = &pixmap->drawable;
783     RegionRec dst_region;
784     int dx, dy;
785 
786     dx = old_origin.x - window->drawable.x;
787     dy = old_origin.y - window->drawable.y;
788     RegionTranslate(src_region, -dx, -dy);
789 
790     RegionNull(&dst_region);
791 
792     RegionIntersect(&dst_region, &window->borderClip, src_region);
793 
794 #ifdef COMPOSITE
795     if (pixmap->screen_x || pixmap->screen_y)
796         RegionTranslate(&dst_region, -pixmap->screen_x, -pixmap->screen_y);
797 #endif
798 
799     miCopyRegion(drawable, drawable,
800                  0, &dst_region, dx, dy, glamor_copy, 0, 0);
801 
802     RegionUninit(&dst_region);
803 }
804