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 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
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)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
glamor_copy_needs_temp(DrawablePtr src,DrawablePtr dst,BoxPtr box,int nbox,int dx,int dy)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
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)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
glamor_copy(DrawablePtr src,DrawablePtr dst,GCPtr gc,BoxPtr box,int nbox,int dx,int dy,Bool reverse,Bool upsidedown,Pixel bitplane,void * closure)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
glamor_copy_area(DrawablePtr src,DrawablePtr dst,GCPtr gc,int srcx,int srcy,int width,int height,int dstx,int dsty)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
glamor_copy_plane(DrawablePtr src,DrawablePtr dst,GCPtr gc,int srcx,int srcy,int width,int height,int dstx,int dsty,unsigned long bitplane)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
glamor_copy_window(WindowPtr window,DDXPointRec old_origin,RegionPtr src_region)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 }
794