dri/nouveau: Swizzle using the CPU when we hit a limitation of SIFM.
authorFrancisco Jerez <currojerez@riseup.net>
Mon, 22 Feb 2010 00:53:23 +0000 (01:53 +0100)
committerFrancisco Jerez <currojerez@riseup.net>
Thu, 25 Feb 2010 17:37:35 +0000 (18:37 +0100)
src/mesa/drivers/dri/nouveau/nv04_surface.c

index e8a5409fbde5f2bc28ddb428102ef42ded6eb8ce..e3febf7d2f76540bcb7b323e0fbbebc1f10bd00d 100644 (file)
@@ -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