802 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			802 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2014 Keith Packard
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that copyright
 | |
|  * notice and this permission notice appear in supporting documentation, and
 | |
|  * that the name of the copyright holders not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  The copyright holders make no representations
 | |
|  * about the suitability of this software for any purpose.  It is provided "as
 | |
|  * is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #include "os/bug_priv.h"
 | |
| 
 | |
| #include "glamor_priv.h"
 | |
| #include "glamor_transfer.h"
 | |
| #include "glamor_prepare.h"
 | |
| #include "glamor_transform.h"
 | |
| 
 | |
| struct copy_args {
 | |
|     DrawablePtr         src_drawable;
 | |
|     glamor_pixmap_fbo   *src;
 | |
|     uint32_t            bitplane;
 | |
|     int                 dx, dy;
 | |
| };
 | |
| 
 | |
| static Bool
 | |
| use_copyarea(DrawablePtr drawable, GCPtr gc, glamor_program *prog, void *arg)
 | |
| {
 | |
|     struct copy_args *args = arg;
 | |
|     glamor_pixmap_fbo *src = args->src;
 | |
| 
 | |
|     glamor_bind_texture(glamor_get_screen_private(drawable->pScreen),
 | |
|                         GL_TEXTURE0, src, TRUE);
 | |
| 
 | |
|     glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
 | |
|     glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static const glamor_facet glamor_facet_copyarea = {
 | |
|     "copy_area",
 | |
|     .vs_vars = "in vec2 primitive;\n",
 | |
|     .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy)
 | |
|                 "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
 | |
|     .fs_exec = "       frag_color = texture(sampler, fill_pos);\n",
 | |
|     .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
 | |
|     .use = use_copyarea,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Configure the copy plane program for the current operation
 | |
|  */
 | |
| 
 | |
| static Bool
 | |
| use_copyplane(DrawablePtr drawable, GCPtr gc, glamor_program *prog, void *arg)
 | |
| {
 | |
|     struct copy_args *args = arg;
 | |
|     glamor_pixmap_fbo *src = args->src;
 | |
| 
 | |
|     glamor_bind_texture(glamor_get_screen_private(drawable->pScreen),
 | |
|                         GL_TEXTURE0, src, TRUE);
 | |
| 
 | |
|     glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
 | |
|     glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
 | |
| 
 | |
|     glamor_set_color(drawable, gc->fgPixel, prog->fg_uniform);
 | |
|     glamor_set_color(drawable, gc->bgPixel, prog->bg_uniform);
 | |
| 
 | |
|     /* XXX handle 2 10 10 10 and 1555 formats; presumably the pixmap private knows this? */
 | |
|     switch (glamor_drawable_effective_depth(args->src_drawable)) {
 | |
|     case 30:
 | |
|         glUniform4ui(prog->bitplane_uniform,
 | |
|                      (args->bitplane >> 20) & 0x3ff,
 | |
|                      (args->bitplane >> 10) & 0x3ff,
 | |
|                      (args->bitplane      ) & 0x3ff,
 | |
|                      0);
 | |
| 
 | |
|         glUniform4f(prog->bitmul_uniform, 0x3ff, 0x3ff, 0x3ff, 0);
 | |
|         break;
 | |
|     case 24:
 | |
|         glUniform4ui(prog->bitplane_uniform,
 | |
|                      (args->bitplane >> 16) & 0xff,
 | |
|                      (args->bitplane >>  8) & 0xff,
 | |
|                      (args->bitplane      ) & 0xff,
 | |
|                      0);
 | |
| 
 | |
|         glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0);
 | |
|         break;
 | |
|     case 32:
 | |
|         glUniform4ui(prog->bitplane_uniform,
 | |
|                      (args->bitplane >> 16) & 0xff,
 | |
|                      (args->bitplane >>  8) & 0xff,
 | |
|                      (args->bitplane      ) & 0xff,
 | |
|                      (args->bitplane >> 24) & 0xff);
 | |
| 
 | |
|         glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0xff);
 | |
|         break;
 | |
|     case 16:
 | |
|         glUniform4ui(prog->bitplane_uniform,
 | |
|                      (args->bitplane >> 11) & 0x1f,
 | |
|                      (args->bitplane >>  5) & 0x3f,
 | |
|                      (args->bitplane      ) & 0x1f,
 | |
|                      0);
 | |
| 
 | |
|         glUniform4f(prog->bitmul_uniform, 0x1f, 0x3f, 0x1f, 0);
 | |
|         break;
 | |
|     case 15:
 | |
|         glUniform4ui(prog->bitplane_uniform,
 | |
|                      (args->bitplane >> 10) & 0x1f,
 | |
|                      (args->bitplane >>  5) & 0x1f,
 | |
|                      (args->bitplane      ) & 0x1f,
 | |
|                      0);
 | |
| 
 | |
|         glUniform4f(prog->bitmul_uniform, 0x1f, 0x1f, 0x1f, 0);
 | |
|         break;
 | |
|     case 8:
 | |
|         glUniform4ui(prog->bitplane_uniform,
 | |
|                      0, 0, 0, args->bitplane);
 | |
|         glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
 | |
|         break;
 | |
|     case 1:
 | |
|         glUniform4ui(prog->bitplane_uniform,
 | |
|                      0, 0, 0, args->bitplane);
 | |
|         glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static const glamor_facet glamor_facet_copyplane = {
 | |
|     "copy_plane",
 | |
|     .version = 130,
 | |
|     .vs_vars = "in vec2 primitive;\n",
 | |
|     .vs_exec = (GLAMOR_POS(gl_Position, (primitive.xy))
 | |
|                 "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
 | |
|     .fs_exec = ("       uvec4 bits = uvec4(round(texture(sampler, fill_pos) * bitmul));\n"
 | |
|                 "       if ((bits & bitplane) != uvec4(0,0,0,0))\n"
 | |
|                 "               frag_color = fg;\n"
 | |
|                 "       else\n"
 | |
|                 "               frag_color = bg;\n"),
 | |
|     .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane,
 | |
|     .use = use_copyplane,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * When all else fails, pull the bits out of the GPU and do the
 | |
|  * operation with fb
 | |
|  */
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) && glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
 | |
|         if (bitplane) {
 | |
|             if (src->bitsPerPixel > 1)
 | |
|                 fbCopyNto1(src, dst, gc, box, nbox, dx, dy,
 | |
|                            reverse, upsidedown, bitplane, closure);
 | |
|             else
 | |
|                 fbCopy1toN(src, dst, gc, box, nbox, dx, dy,
 | |
|                            reverse, upsidedown, bitplane, closure);
 | |
|         } else {
 | |
|             fbCopyNtoN(src, dst, gc, box, nbox, dx, dy,
 | |
|                        reverse, upsidedown, bitplane, closure);
 | |
|         }
 | |
|     }
 | |
|     glamor_finish_access(dst);
 | |
|     glamor_finish_access(src);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements CopyPlane and CopyArea from the CPU to the GPU by using
 | |
|  * the source as a texture and painting that into the destination.
 | |
|  *
 | |
|  * This requires that source and dest are different textures, or that
 | |
|  * (if the copy area doesn't overlap), GL_NV_texture_barrier is used
 | |
|  * to ensure that the caches are flushed at the right times.
 | |
|  */
 | |
| 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)
 | |
| {
 | |
|     ScreenPtr screen = dst->pScreen;
 | |
|     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | |
|     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | |
|     int dst_xoff, dst_yoff;
 | |
| 
 | |
|     if (gc && gc->alu != GXcopy)
 | |
|         goto bail;
 | |
| 
 | |
|     if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
 | |
|         goto bail;
 | |
| 
 | |
|     glamor_make_current(glamor_priv);
 | |
| 
 | |
|     if (!glamor_prepare_access(src, GLAMOR_ACCESS_RO))
 | |
|         goto bail;
 | |
| 
 | |
|     glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_yoff);
 | |
| 
 | |
|     if (bitplane) {
 | |
|         FbBits *tmp_bits;
 | |
|         FbStride tmp_stride;
 | |
|         int tmp_bpp;
 | |
|         int tmp_xoff, tmp_yoff;
 | |
| 
 | |
|         PixmapPtr tmp_pix = fbCreatePixmap(screen, dst_pixmap->drawable.width,
 | |
|                                            dst_pixmap->drawable.height,
 | |
|                                            glamor_drawable_effective_depth(dst), 0);
 | |
| 
 | |
|         if (!tmp_pix) {
 | |
|             glamor_finish_access(src);
 | |
|             goto bail;
 | |
|         }
 | |
| 
 | |
|         tmp_pix->drawable.x = dst_xoff;
 | |
|         tmp_pix->drawable.y = dst_yoff;
 | |
| 
 | |
|         fbGetDrawable(&tmp_pix->drawable, tmp_bits, tmp_stride, tmp_bpp, tmp_xoff,
 | |
|                       tmp_yoff);
 | |
| 
 | |
|         if (src->bitsPerPixel > 1)
 | |
|             fbCopyNto1(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
 | |
|                        reverse, upsidedown, bitplane, closure);
 | |
|         else
 | |
|             fbCopy1toN(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
 | |
|                        reverse, upsidedown, bitplane, closure);
 | |
| 
 | |
|         glamor_upload_boxes(dst, box, nbox, tmp_xoff, tmp_yoff,
 | |
|                             dst_xoff, dst_yoff, (uint8_t *) tmp_bits,
 | |
|                             tmp_stride * sizeof(FbBits));
 | |
|         fbDestroyPixmap(tmp_pix);
 | |
|     } else {
 | |
|         FbBits *src_bits;
 | |
|         FbStride src_stride;
 | |
|         int src_bpp;
 | |
|         int src_xoff, src_yoff;
 | |
| 
 | |
|         fbGetDrawable(src, src_bits, src_stride, src_bpp, src_xoff, src_yoff);
 | |
|         glamor_upload_boxes(dst, box, nbox, src_xoff + dx, src_yoff + dy,
 | |
|                             dst_xoff, dst_yoff,
 | |
|                             (uint8_t *) src_bits, src_stride * sizeof (FbBits));
 | |
|     }
 | |
|     glamor_finish_access(src);
 | |
| 
 | |
|     return TRUE;
 | |
| 
 | |
| bail:
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Implements CopyArea from the GPU to the CPU using glReadPixels from the
 | |
|  * source FBO.
 | |
|  */
 | |
| 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)
 | |
| {
 | |
|     ScreenPtr screen = dst->pScreen;
 | |
|     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | |
|     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | |
|     FbBits *dst_bits;
 | |
|     FbStride dst_stride;
 | |
|     int dst_bpp;
 | |
|     int src_xoff, src_yoff;
 | |
|     int dst_xoff, dst_yoff;
 | |
| 
 | |
|     if (gc && gc->alu != GXcopy)
 | |
|         goto bail;
 | |
| 
 | |
|     if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
 | |
|         goto bail;
 | |
| 
 | |
|     glamor_make_current(glamor_priv);
 | |
| 
 | |
|     if (!glamor_prepare_access(dst, GLAMOR_ACCESS_RW))
 | |
|         goto bail;
 | |
| 
 | |
|     glamor_get_drawable_deltas(src, src_pixmap, &src_xoff, &src_yoff);
 | |
| 
 | |
|     fbGetDrawable(dst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff);
 | |
| 
 | |
|     glamor_download_boxes(src, box, nbox, src_xoff + dx, src_yoff + dy,
 | |
|                           dst_xoff, dst_yoff,
 | |
|                           (uint8_t *) dst_bits, dst_stride * sizeof (FbBits));
 | |
|     glamor_finish_access(dst);
 | |
| 
 | |
|     return TRUE;
 | |
| 
 | |
| bail:
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /* Include the enums here for the moment, to keep from needing to bump epoxy. */
 | |
| #ifndef GL_TILE_RASTER_ORDER_FIXED_MESA
 | |
| #define GL_TILE_RASTER_ORDER_FIXED_MESA          0x8BB8
 | |
| #define GL_TILE_RASTER_ORDER_INCREASING_X_MESA   0x8BB9
 | |
| #define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA   0x8BBA
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * Copy from GPU to GPU by using the source
 | |
|  * as a texture and painting that into the destination
 | |
|  */
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     ScreenPtr screen = dst->pScreen;
 | |
|     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | |
|     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | |
|     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | |
|     glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
 | |
|     glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
 | |
|     int src_box_index, dst_box_index;
 | |
|     int dst_off_x, dst_off_y;
 | |
|     int src_off_x, src_off_y;
 | |
|     GLshort *v;
 | |
|     char *vbo_offset;
 | |
|     struct copy_args args;
 | |
|     glamor_program *prog;
 | |
|     const glamor_facet *copy_facet;
 | |
|     int n;
 | |
|     Bool ret = FALSE;
 | |
|     BoxRec bounds = glamor_no_rendering_bounds();
 | |
| 
 | |
|     glamor_make_current(glamor_priv);
 | |
| 
 | |
|     if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
 | |
|         goto bail_ctx;
 | |
| 
 | |
|     if (!glamor_set_alu(dst, gc ? gc->alu : GXcopy))
 | |
|         goto bail_ctx;
 | |
| 
 | |
|     if (bitplane && !glamor_priv->can_copyplane)
 | |
|         goto bail_ctx;
 | |
| 
 | |
|     if (bitplane) {
 | |
|         prog = &glamor_priv->copy_plane_prog;
 | |
|         copy_facet = &glamor_facet_copyplane;
 | |
|     } else {
 | |
|         prog = &glamor_priv->copy_area_prog;
 | |
|         copy_facet = &glamor_facet_copyarea;
 | |
|     }
 | |
| 
 | |
|     if (prog->failed)
 | |
|         goto bail_ctx;
 | |
| 
 | |
|     if (!prog->prog) {
 | |
|         if (!glamor_build_program(screen, prog,
 | |
|                                   copy_facet, NULL, NULL, NULL))
 | |
|             goto bail_ctx;
 | |
|     }
 | |
| 
 | |
|     args.src_drawable = src;
 | |
|     args.bitplane = bitplane;
 | |
| 
 | |
|     /* Set up the vertex buffers for the points */
 | |
| 
 | |
|     v = glamor_get_vbo_space(dst->pScreen, nbox * 8 * sizeof (int16_t), &vbo_offset);
 | |
| 
 | |
|     if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
 | |
|         glEnable(GL_TILE_RASTER_ORDER_FIXED_MESA);
 | |
|         if (dx >= 0)
 | |
|             glEnable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
 | |
|         else
 | |
|             glDisable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
 | |
|         if (dy >= 0)
 | |
|             glEnable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
 | |
|         else
 | |
|             glDisable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
 | |
|     }
 | |
| 
 | |
|     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
 | |
|     glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
 | |
|                           2 * sizeof (GLshort), vbo_offset);
 | |
| 
 | |
|     if (nbox < 100) {
 | |
|         bounds = glamor_start_rendering_bounds();
 | |
|         for (int i = 0; i < nbox; i++)
 | |
|             glamor_bounds_union_box(&bounds, &box[i]);
 | |
|     }
 | |
| 
 | |
|     for (n = 0; n < nbox; n++) {
 | |
|         v[0] = box->x1; v[1] = box->y1;
 | |
|         v[2] = box->x1; v[3] = box->y2;
 | |
|         v[4] = box->x2; v[5] = box->y2;
 | |
|         v[6] = box->x2; v[7] = box->y1;
 | |
| 
 | |
|         v += 8;
 | |
|         box++;
 | |
|     }
 | |
| 
 | |
|     glamor_put_vbo_space(screen);
 | |
| 
 | |
|     glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
 | |
| 
 | |
|     glEnable(GL_SCISSOR_TEST);
 | |
| 
 | |
|     BUG_RETURN_VAL(!src_priv, FALSE);
 | |
| 
 | |
|     glamor_pixmap_loop(src_priv, src_box_index) {
 | |
|         BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_index);
 | |
| 
 | |
|         args.dx = dx + src_off_x - src_box->x1;
 | |
|         args.dy = dy + src_off_y - src_box->y1;
 | |
|         args.src = glamor_pixmap_fbo_at(src_priv, src_box_index);
 | |
| 
 | |
|         if (!glamor_use_program(dst, gc, prog, &args))
 | |
|             goto bail_ctx;
 | |
| 
 | |
|         BUG_RETURN_VAL(!dst_priv, FALSE);
 | |
| 
 | |
|         glamor_pixmap_loop(dst_priv, dst_box_index) {
 | |
|             BoxRec scissor = {
 | |
|                 .x1 = max(-args.dx, bounds.x1),
 | |
|                 .y1 = max(-args.dy, bounds.y1),
 | |
|                 .x2 = min(-args.dx + src_box->x2 - src_box->x1, bounds.x2),
 | |
|                 .y2 = min(-args.dy + src_box->y2 - src_box->y1, bounds.y2),
 | |
|             };
 | |
|             if (scissor.x1 >= scissor.x2 || scissor.y1 >= scissor.y2)
 | |
|                 continue;
 | |
| 
 | |
|             if (!glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE,
 | |
|                                                  prog->matrix_uniform,
 | |
|                                                  &dst_off_x, &dst_off_y))
 | |
|                 goto bail_ctx;
 | |
| 
 | |
|             glScissor(scissor.x1 + dst_off_x,
 | |
|                       scissor.y1 + dst_off_y,
 | |
|                       scissor.x2 - scissor.x1,
 | |
|                       scissor.y2 - scissor.y1);
 | |
| 
 | |
|             glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ret = TRUE;
 | |
| 
 | |
| bail_ctx:
 | |
|     if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
 | |
|         glDisable(GL_TILE_RASTER_ORDER_FIXED_MESA);
 | |
|     }
 | |
|     glDisable(GL_SCISSOR_TEST);
 | |
|     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Copies from the GPU to the GPU using a temporary pixmap in between,
 | |
|  * to correctly handle overlapping copies.
 | |
|  */
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     ScreenPtr screen = dst->pScreen;
 | |
|     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | |
|     PixmapPtr tmp_pixmap;
 | |
|     BoxRec bounds;
 | |
|     int n;
 | |
|     BoxPtr tmp_box;
 | |
| 
 | |
|     if (nbox == 0)
 | |
|         return TRUE;
 | |
| 
 | |
|     /* Sanity check state to avoid getting halfway through and bailing
 | |
|      * at the last second. Might be nice to have checks that didn't
 | |
|      * involve setting state.
 | |
|      */
 | |
|     glamor_make_current(glamor_priv);
 | |
| 
 | |
|     if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
 | |
|         goto bail_ctx;
 | |
| 
 | |
|     if (!glamor_set_alu(dst, gc ? gc->alu : GXcopy))
 | |
|         goto bail_ctx;
 | |
| 
 | |
|     /* Find the size of the area to copy
 | |
|      */
 | |
|     bounds = box[0];
 | |
|     for (n = 1; n < nbox; n++) {
 | |
|         bounds.x1 = min(bounds.x1, box[n].x1);
 | |
|         bounds.x2 = max(bounds.x2, box[n].x2);
 | |
|         bounds.y1 = min(bounds.y1, box[n].y1);
 | |
|         bounds.y2 = max(bounds.y2, box[n].y2);
 | |
|     }
 | |
| 
 | |
|     /* Allocate a suitable temporary pixmap
 | |
|      */
 | |
|     tmp_pixmap = glamor_create_pixmap(screen,
 | |
|                                       bounds.x2 - bounds.x1,
 | |
|                                       bounds.y2 - bounds.y1,
 | |
|                                       glamor_drawable_effective_depth(src), 0);
 | |
|     if (!tmp_pixmap)
 | |
|         goto bail;
 | |
| 
 | |
|     tmp_box = calloc(nbox, sizeof (BoxRec));
 | |
|     if (!tmp_box)
 | |
|         goto bail_pixmap;
 | |
| 
 | |
|     /* Convert destination boxes into tmp pixmap boxes
 | |
|      */
 | |
|     for (n = 0; n < nbox; n++) {
 | |
|         tmp_box[n].x1 = box[n].x1 - bounds.x1;
 | |
|         tmp_box[n].x2 = box[n].x2 - bounds.x1;
 | |
|         tmp_box[n].y1 = box[n].y1 - bounds.y1;
 | |
|         tmp_box[n].y2 = box[n].y2 - bounds.y1;
 | |
|     }
 | |
| 
 | |
|     if (!glamor_copy_fbo_fbo_draw(src,
 | |
|                                   &tmp_pixmap->drawable,
 | |
|                                   NULL,
 | |
|                                   tmp_box,
 | |
|                                   nbox,
 | |
|                                   dx + bounds.x1,
 | |
|                                   dy + bounds.y1,
 | |
|                                   FALSE, FALSE,
 | |
|                                   0, NULL))
 | |
|         goto bail_box;
 | |
| 
 | |
|     if (!glamor_copy_fbo_fbo_draw(&tmp_pixmap->drawable,
 | |
|                                   dst,
 | |
|                                   gc,
 | |
|                                   box,
 | |
|                                   nbox,
 | |
|                                   -bounds.x1,
 | |
|                                   -bounds.y1,
 | |
|                                   FALSE, FALSE,
 | |
|                                   bitplane, closure))
 | |
|         goto bail_box;
 | |
| 
 | |
|     free(tmp_box);
 | |
| 
 | |
|     glamor_destroy_pixmap(tmp_pixmap);
 | |
| 
 | |
|     return TRUE;
 | |
| bail_box:
 | |
|     free(tmp_box);
 | |
| bail_pixmap:
 | |
|     glamor_destroy_pixmap(tmp_pixmap);
 | |
| bail:
 | |
|     return FALSE;
 | |
| 
 | |
| bail_ctx:
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns TRUE if the copy has to be implemented with
 | |
|  * glamor_copy_fbo_fbo_temp() instead of glamor_copy_fbo_fbo().
 | |
|  *
 | |
|  * If the src and dst are in the same pixmap, then glamor_copy_fbo_fbo()'s
 | |
|  * sampling would give undefined results (since the same texture would be
 | |
|  * bound as an FBO destination and as a texture source).  However, if we
 | |
|  * have GL_NV_texture_barrier, we can take advantage of the exception it
 | |
|  * added:
 | |
|  *
 | |
|  *    "- If a texel has been written, then in order to safely read the result
 | |
|  *       a texel fetch must be in a subsequent Draw separated by the command
 | |
|  *
 | |
|  *       void TextureBarrierNV(void);
 | |
|  *
 | |
|  *    TextureBarrierNV() will guarantee that writes have completed and caches
 | |
|  *    have been invalidated before subsequent Draws are executed."
 | |
|  */
 | |
| static Bool
 | |
| glamor_copy_needs_temp(DrawablePtr src,
 | |
|                        DrawablePtr dst,
 | |
|                        BoxPtr box,
 | |
|                        int nbox,
 | |
|                        int dx,
 | |
|                        int dy)
 | |
| {
 | |
|     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | |
|     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | |
|     ScreenPtr screen = dst->pScreen;
 | |
|     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 | |
|     int n;
 | |
|     int dst_off_x, dst_off_y;
 | |
|     int src_off_x, src_off_y;
 | |
|     BoxRec bounds;
 | |
| 
 | |
|     if (src_pixmap != dst_pixmap)
 | |
|         return FALSE;
 | |
| 
 | |
|     if (nbox == 0)
 | |
|         return FALSE;
 | |
| 
 | |
|     if (!glamor_priv->has_nv_texture_barrier)
 | |
|         return TRUE;
 | |
| 
 | |
|     if (!glamor_priv->has_mesa_tile_raster_order) {
 | |
|         glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
 | |
|         glamor_get_drawable_deltas(dst, dst_pixmap, &dst_off_x, &dst_off_y);
 | |
| 
 | |
|         bounds = box[0];
 | |
|         for (n = 1; n < nbox; n++) {
 | |
|             bounds.x1 = min(bounds.x1, box[n].x1);
 | |
|             bounds.y1 = min(bounds.y1, box[n].y1);
 | |
| 
 | |
|             bounds.x2 = max(bounds.x2, box[n].x2);
 | |
|             bounds.y2 = max(bounds.y2, box[n].y2);
 | |
|         }
 | |
| 
 | |
|         /* Check to see if the pixmap-relative boxes overlap in both X and Y,
 | |
|          * in which case we can't rely on NV_texture_barrier and must
 | |
|          * make a temporary copy
 | |
|          *
 | |
|          *  dst.x1                     < src.x2 &&
 | |
|          *  src.x1                     < dst.x2 &&
 | |
|          *
 | |
|          *  dst.y1                     < src.y2 &&
 | |
|          *  src.y1                     < dst.y2
 | |
|          */
 | |
|         if (bounds.x1 + dst_off_x      < bounds.x2 + dx + src_off_x &&
 | |
|             bounds.x1 + dx + src_off_x < bounds.x2 + dst_off_x &&
 | |
| 
 | |
|             bounds.y1 + dst_off_y      < bounds.y2 + dy + src_off_y &&
 | |
|             bounds.y1 + dy + src_off_y < bounds.y2 + dst_off_y) {
 | |
|             return TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     glTextureBarrierNV();
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
 | |
|     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
 | |
|     glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
 | |
|     glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
 | |
| 
 | |
|     BUG_RETURN_VAL(!dst_priv, FALSE);
 | |
|     BUG_RETURN_VAL(!src_priv, FALSE);
 | |
| 
 | |
|     if (GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_priv)) {
 | |
|         if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv)) {
 | |
|             if (glamor_copy_needs_temp(src, dst, box, nbox, dx, dy))
 | |
|                 return glamor_copy_fbo_fbo_temp(src, dst, gc, box, nbox, dx, dy,
 | |
|                                                 reverse, upsidedown, bitplane, closure);
 | |
|             else
 | |
|                 return glamor_copy_fbo_fbo_draw(src, dst, gc, box, nbox, dx, dy,
 | |
|                                                 reverse, upsidedown, bitplane, closure);
 | |
|         }
 | |
| 
 | |
|         return glamor_copy_cpu_fbo(src, dst, gc, box, nbox, dx, dy,
 | |
|                                    reverse, upsidedown, bitplane, closure);
 | |
|     } else if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv) &&
 | |
|                dst_priv->type != GLAMOR_DRM_ONLY &&
 | |
|                bitplane == 0) {
 | |
|             return glamor_copy_fbo_cpu(src, dst, gc, box, nbox, dx, dy,
 | |
|                                        reverse, upsidedown, bitplane, closure);
 | |
|     }
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     if (nbox == 0)
 | |
| 	return;
 | |
| 
 | |
|     if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure))
 | |
|         return;
 | |
|     glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
 | |
| }
 | |
| 
 | |
| RegionPtr
 | |
| glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 | |
|                  int srcx, int srcy, int width, int height, int dstx, int dsty)
 | |
| {
 | |
|     return miDoCopy(src, dst, gc,
 | |
|                     srcx, srcy, width, height,
 | |
|                     dstx, dsty, glamor_copy, 0, NULL);
 | |
| }
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     if ((bitplane & FbFullMask(glamor_drawable_effective_depth(src))) == 0)
 | |
|         return miHandleExposures(src, dst, gc,
 | |
|                                  srcx, srcy, width, height, dstx, dsty);
 | |
|     return miDoCopy(src, dst, gc,
 | |
|                     srcx, srcy, width, height,
 | |
|                     dstx, dsty, glamor_copy, bitplane, NULL);
 | |
| }
 | |
| 
 | |
| void
 | |
| glamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region)
 | |
| {
 | |
|     PixmapPtr pixmap = glamor_get_drawable_pixmap(&window->drawable);
 | |
|     DrawablePtr drawable = &pixmap->drawable;
 | |
|     RegionRec dst_region;
 | |
|     int dx, dy;
 | |
| 
 | |
|     dx = old_origin.x - window->drawable.x;
 | |
|     dy = old_origin.y - window->drawable.y;
 | |
|     RegionTranslate(src_region, -dx, -dy);
 | |
| 
 | |
|     RegionNull(&dst_region);
 | |
| 
 | |
|     RegionIntersect(&dst_region, &window->borderClip, src_region);
 | |
| 
 | |
|     if (pixmap->screen_x || pixmap->screen_y)
 | |
|         RegionTranslate(&dst_region, -pixmap->screen_x, -pixmap->screen_y);
 | |
| 
 | |
|     miCopyRegion(drawable, drawable,
 | |
|                  0, &dst_region, dx, dy, glamor_copy, 0, 0);
 | |
| 
 | |
|     RegionUninit(&dst_region);
 | |
| }
 |