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