diff options
author | Francisco Jerez <[email protected]> | 2010-02-22 01:53:23 +0100 |
---|---|---|
committer | Francisco Jerez <[email protected]> | 2010-02-25 18:37:35 +0100 |
commit | 44602bb23ca7b67d4db586d9194c75cfe4a60962 (patch) | |
tree | ffff8bbf5232867d93f228f7d59cec0a70df2e8a /src/mesa/drivers/dri | |
parent | e59e5e3388c9561d58aa02bab20baca99ba86d15 (diff) |
dri/nouveau: Swizzle using the CPU when we hit a limitation of SIFM.
Diffstat (limited to 'src/mesa/drivers/dri')
-rw-r--r-- | src/mesa/drivers/dri/nouveau/nv04_surface.c | 96 |
1 files changed, 89 insertions, 7 deletions
diff --git a/src/mesa/drivers/dri/nouveau/nv04_surface.c b/src/mesa/drivers/dri/nouveau/nv04_surface.c index e8a5409fbde..e3febf7d2f7 100644 --- a/src/mesa/drivers/dri/nouveau/nv04_surface.c +++ b/src/mesa/drivers/dri/nouveau/nv04_surface.c @@ -321,6 +321,82 @@ nv04_surface_copy_m2mf(GLcontext *ctx, FIRE_RING(chan); } +typedef unsigned (*get_offset_t)(struct nouveau_surface *s, + unsigned x, unsigned y); + +static unsigned +get_linear_offset(struct nouveau_surface *s, unsigned x, unsigned y) +{ + return x * s->cpp + y * s->pitch; +} + +static unsigned +get_swizzled_offset(struct nouveau_surface *s, unsigned x, unsigned y) +{ + unsigned k = log2i(MIN2(s->width, s->height)); + + unsigned u = (x & 0x001) << 0 | + (x & 0x002) << 1 | + (x & 0x004) << 2 | + (x & 0x008) << 3 | + (x & 0x010) << 4 | + (x & 0x020) << 5 | + (x & 0x040) << 6 | + (x & 0x080) << 7 | + (x & 0x100) << 8 | + (x & 0x200) << 9 | + (x & 0x400) << 10 | + (x & 0x800) << 11; + + unsigned v = (y & 0x001) << 1 | + (y & 0x002) << 2 | + (y & 0x004) << 3 | + (y & 0x008) << 4 | + (y & 0x010) << 5 | + (y & 0x020) << 6 | + (y & 0x040) << 7 | + (y & 0x080) << 8 | + (y & 0x100) << 9 | + (y & 0x200) << 10 | + (y & 0x400) << 11 | + (y & 0x800) << 12; + + return s->cpp * (((u | v) & ~(~0 << 2*k)) | + (x & (~0 << k)) << k | + (y & (~0 << k)) << k); +} + +static void +nv04_surface_copy_cpu(GLcontext *ctx, + struct nouveau_surface *dst, + struct nouveau_surface *src, + int dx, int dy, int sx, int sy, + int w, int h) +{ + int x, y; + get_offset_t get_dst = (dst->layout == SWIZZLED ? + get_swizzled_offset : get_linear_offset); + get_offset_t get_src = (src->layout == SWIZZLED ? + get_swizzled_offset : get_linear_offset); + void *dp, *sp; + + nouveau_bo_map(dst->bo, NOUVEAU_BO_WR); + nouveau_bo_map(src->bo, NOUVEAU_BO_RD); + + dp = dst->bo->map + dst->offset; + sp = src->bo->map + src->offset; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + memcpy(dp + get_dst(dst, dx + x, dy + y), + sp + get_src(src, sx + x, sy + y), dst->cpp); + } + } + + nouveau_bo_unmap(src->bo); + nouveau_bo_unmap(dst->bo); +} + void nv04_surface_copy(GLcontext *ctx, struct nouveau_surface *dst, @@ -328,16 +404,22 @@ nv04_surface_copy(GLcontext *ctx, int dx, int dy, int sx, int sy, int w, int h) { - /* Setup transfer to swizzle the texture to vram if needed */ - if (src->layout != SWIZZLED && - dst->layout == SWIZZLED && - dst->width > 2 && dst->height > 1) { - nv04_surface_copy_swizzle(ctx, dst, src, - dx, dy, sx, sy, w, h); + /* Linear texture copy. */ + if ((src->layout == LINEAR && dst->layout == LINEAR) || + dst->width <= 2 || dst->height <= 1) { + nv04_surface_copy_m2mf(ctx, dst, src, dx, dy, sx, sy, w, h); + return; + } + + /* Swizzle using sifm+swzsurf. */ + if (src->layout == LINEAR && dst->layout == SWIZZLED && + dst->cpp != 1 && !(dst->offset & 63)) { + nv04_surface_copy_swizzle(ctx, dst, src, dx, dy, sx, sy, w, h); return; } - nv04_surface_copy_m2mf(ctx, dst, src, dx, dy, sx, sy, w, h); + /* Fallback to CPU copy. */ + nv04_surface_copy_cpu(ctx, dst, src, dx, dy, sx, sy, w, h); } void |