diff options
Diffstat (limited to 'src/gallium/drivers/llvmpipe/lp_surface.c')
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_surface.c | 104 |
1 files changed, 101 insertions, 3 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_surface.c b/src/gallium/drivers/llvmpipe/lp_surface.c index ca3d62c3613..381c58ecee5 100644 --- a/src/gallium/drivers/llvmpipe/lp_surface.c +++ b/src/gallium/drivers/llvmpipe/lp_surface.c @@ -29,16 +29,35 @@ #include "lp_context.h" #include "lp_flush.h" #include "lp_surface.h" +#include "lp_texture.h" +#include "lp_tile_image.h" +#include "lp_tile_size.h" + + +/** + * Adjust x, y, width, height to lie on tile bounds. + */ +static void +adjust_to_tile_bounds(unsigned x, unsigned y, unsigned width, unsigned height, + unsigned *x_tile, unsigned *y_tile, + unsigned *w_tile, unsigned *h_tile) +{ + *x_tile = x & ~(TILE_SIZE - 1); + *y_tile = y & ~(TILE_SIZE - 1); + *w_tile = ((x + width + TILE_SIZE - 1) & ~(TILE_SIZE - 1)) - *x_tile; + *h_tile = ((y + height + TILE_SIZE - 1) & ~(TILE_SIZE - 1)) - *y_tile; +} + static void lp_surface_copy(struct pipe_context *pipe, - struct pipe_surface *dest, unsigned destx, unsigned desty, + struct pipe_surface *dst, unsigned dstx, unsigned dsty, struct pipe_surface *src, unsigned srcx, unsigned srcy, unsigned width, unsigned height) { llvmpipe_flush_texture(pipe, - dest->texture, dest->face, dest->level, + dst->texture, dst->face, dst->level, 0, /* flush_flags */ FALSE, /* read_only */ FALSE, /* cpu_access */ @@ -51,8 +70,87 @@ lp_surface_copy(struct pipe_context *pipe, FALSE, /* cpu_access */ FALSE); /* do_not_flush */ + /* Look for special case in which we're copying from a tiled image + * to a linear image. + */ + { + struct llvmpipe_resource *src_tex = llvmpipe_resource(src->texture); + struct llvmpipe_resource *dst_tex = llvmpipe_resource(dst->texture); + enum pipe_format format = src_tex->base.format; + + /* + printf("surface copy from %u to %u: %u,%u to %u,%u %u x %u\n", + src_tex->id, dst_tex->id, + srcx, srcy, dstx, dsty, width, height); + */ + + /* set src tiles to linear layout */ + { + unsigned tx, ty, tw, th; + unsigned x, y; + + adjust_to_tile_bounds(srcx, srcy, width, height, &tx, &ty, &tw, &th); + + for (y = 0; y < th; y += TILE_SIZE) { + for (x = 0; x < tw; x += TILE_SIZE) { + (void) llvmpipe_get_texture_tile_linear(src_tex, + src->face, src->level, + LP_TEX_USAGE_READ, + tx + x, ty + y); + } + } + } + + /* set dst tiles to linear layout */ + { + unsigned tx, ty, tw, th; + unsigned x, y; + enum lp_texture_usage usage; + + /* XXX for the tiles which are completely contained by the + * dest rectangle, we could set the usage mode to WRITE_ALL. + * Just test for the case of replacing the whole dest region for now. + */ + if (width == dst_tex->base.width0 && height == dst_tex->base.height0) + usage = LP_TEX_USAGE_WRITE_ALL; + else + usage = LP_TEX_USAGE_READ_WRITE; + + adjust_to_tile_bounds(dstx, dsty, width, height, &tx, &ty, &tw, &th); + + for (y = 0; y < th; y += TILE_SIZE) { + for (x = 0; x < tw; x += TILE_SIZE) { + (void) llvmpipe_get_texture_tile_linear(dst_tex, + dst->face, dst->level, + usage, + tx + x, ty + y); + } + } + } + + /* copy */ + { + const ubyte *src_linear_ptr + = llvmpipe_get_texture_image_address(src_tex, src->face, + src->level, + LP_TEX_LAYOUT_LINEAR); + ubyte *dst_linear_ptr + = llvmpipe_get_texture_image_address(dst_tex, dst->face, + dst->level, + LP_TEX_LAYOUT_LINEAR); + + util_copy_rect(dst_linear_ptr, format, + dst_tex->stride[dst->level], + dstx, dsty, + width, height, + src_linear_ptr, src_tex->stride[src->level], + srcx, srcy); + } + return; + } + util_surface_copy(pipe, FALSE, - dest, destx, desty, + dst, dstx, dsty, src, srcx, srcy, width, height); } |