nv50: add 3d texture tiling and mip-mapping
[mesa.git] / src / gallium / drivers / nv50 / nv50_transfer.c
index 9c008090b8df733d5a9b7b258a5bea747405eeba..ea61357aaa6bb8faa61747ffa56a5810375e834e 100644 (file)
@@ -12,6 +12,7 @@ struct nv50_transfer {
        int level_pitch;
        int level_width;
        int level_height;
+       int level_depth;
        int level_x;
        int level_y;
 };
@@ -20,10 +21,10 @@ static void
 nv50_transfer_rect_m2mf(struct pipe_screen *pscreen,
                        struct nouveau_bo *src_bo, unsigned src_offset,
                        int src_pitch, unsigned src_tile_mode,
-                       int sx, int sy, int sw, int sh,
+                       int sx, int sy, int sw, int sh, int sd,
                        struct nouveau_bo *dst_bo, unsigned dst_offset,
                        int dst_pitch, unsigned dst_tile_mode,
-                       int dx, int dy, int dw, int dh,
+                       int dx, int dy, int dw, int dh, int dd,
                        int cpp, int width, int height,
                        unsigned src_reloc, unsigned dst_reloc)
 {
@@ -51,7 +52,7 @@ nv50_transfer_rect_m2mf(struct pipe_screen *pscreen,
                OUT_RING  (chan, src_tile_mode << 4);
                OUT_RING  (chan, sw * cpp);
                OUT_RING  (chan, sh);
-               OUT_RING  (chan, 1);
+               OUT_RING  (chan, sd);
                OUT_RING  (chan, 0);
        }
 
@@ -70,7 +71,7 @@ nv50_transfer_rect_m2mf(struct pipe_screen *pscreen,
                OUT_RING  (chan, dst_tile_mode << 4);
                OUT_RING  (chan, dw * cpp);
                OUT_RING  (chan, dh);
-               OUT_RING  (chan, 1);
+               OUT_RING  (chan, dd);
                OUT_RING  (chan, 0);
        }
 
@@ -114,6 +115,20 @@ nv50_transfer_rect_m2mf(struct pipe_screen *pscreen,
        }
 }
 
+static INLINE unsigned
+get_zslice_offset(unsigned tile_mode, unsigned z, unsigned pitch, unsigned ny)
+{
+       unsigned tile_h = get_tile_height(tile_mode);
+       unsigned tile_d = get_tile_depth(tile_mode);
+
+       /* pitch_2d == to next slice within this volume-tile */
+       /* pitch_3d == to next slice in next 2D array of blocks */
+       unsigned pitch_2d = tile_h * 64;
+       unsigned pitch_3d = tile_d * align(ny, tile_h) * pitch;
+
+       return (z % tile_d) * pitch_2d + (z / tile_d) * pitch_3d;
+}
+
 static struct pipe_transfer *
 nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
                  unsigned face, unsigned level, unsigned zslice,
@@ -129,9 +144,6 @@ nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
 
        if (pt->target == PIPE_TEXTURE_CUBE)
                image = face;
-       else
-       if (pt->target == PIPE_TEXTURE_3D)
-               image = zslice;
 
        tx = CALLOC_STRUCT(nv50_transfer);
        if (!tx)
@@ -157,6 +169,7 @@ nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
        tx->level_pitch = lvl->pitch;
        tx->level_width = mt->base.base.width[level];
        tx->level_height = mt->base.base.height[level];
+       tx->level_depth = mt->base.base.depth[level];
        tx->level_offset = lvl->image_offset[image];
        tx->level_tiling = lvl->tile_mode;
        tx->level_x = pf_get_nblocksx(&tx->base.block, x);
@@ -168,6 +181,11 @@ nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
                return NULL;
        }
 
+       if (pt->target == PIPE_TEXTURE_3D)
+               tx->level_offset += get_zslice_offset(lvl->tile_mode, zslice,
+                                                     lvl->pitch,
+                                                     tx->base.nblocksy);
+
        if (usage & PIPE_TRANSFER_READ) {
                nx = pf_get_nblocksx(&tx->base.block, tx->base.width);
                ny = pf_get_nblocksy(&tx->base.block, tx->base.height);
@@ -176,10 +194,11 @@ nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
                                        tx->level_pitch, tx->level_tiling,
                                        x, y,
                                        tx->base.nblocksx, tx->base.nblocksy,
+                                       tx->level_depth,
                                        tx->bo, 0,
                                        tx->base.stride, tx->bo->tile_mode,
                                        0, 0,
-                                       tx->base.nblocksx, tx->base.nblocksy,
+                                       tx->base.nblocksx, tx->base.nblocksy, 1,
                                        tx->base.block.size, nx, ny,
                                        NOUVEAU_BO_VRAM | NOUVEAU_BO_GART,
                                        NOUVEAU_BO_GART);
@@ -199,14 +218,16 @@ nv50_transfer_del(struct pipe_transfer *ptx)
 
        if (ptx->usage & PIPE_TRANSFER_WRITE) {
                struct pipe_screen *pscreen = ptx->texture->screen;
+
                nv50_transfer_rect_m2mf(pscreen, tx->bo, 0,
                                        tx->base.stride, tx->bo->tile_mode,
                                        0, 0,
-                                       tx->base.nblocksx, tx->base.nblocksy,
+                                       tx->base.nblocksx, tx->base.nblocksy, 1,
                                        mt->base.bo, tx->level_offset,
                                        tx->level_pitch, tx->level_tiling,
                                        tx->level_x, tx->level_y,
                                        tx->base.nblocksx, tx->base.nblocksy,
+                                       tx->level_depth,
                                        tx->base.block.size, nx, ny,
                                        NOUVEAU_BO_GART, NOUVEAU_BO_VRAM |
                                        NOUVEAU_BO_GART);