Mesa (master): nv50: add 3d texture tiling and mip-mapping

Christoph Bumiller chrisbmr at kemper.freedesktop.org
Tue Nov 3 23:54:09 UTC 2009


Module: Mesa
Branch: master
Commit: 040e1d008f8f8258f1b0ee0fcdf4906e0979fb66
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=040e1d008f8f8258f1b0ee0fcdf4906e0979fb66

Author: Christoph Bumiller <e0425955 at student.tuwien.ac.at>
Date:   Tue Nov  3 23:19:56 2009 +0100

nv50: add 3d texture tiling and mip-mapping

Mip-mapped 3D textures are not arrays of 2D layers
with a mip-map layout like 2D textures, therefore we
cannot use image_nr == depth for them.

Making use of "volume tiling" modes now, the allowed
modes are 0xZY where Z <= 5 and y <= 5.

---

 src/gallium/drivers/nv50/nv50_context.h  |   12 ++++++
 src/gallium/drivers/nv50/nv50_miptree.c  |   63 +++++++++++++++++++----------
 src/gallium/drivers/nv50/nv50_tex.c      |   37 +++++++++++++++---
 src/gallium/drivers/nv50/nv50_transfer.c |   39 ++++++++++++++----
 4 files changed, 114 insertions(+), 37 deletions(-)

diff --git a/src/gallium/drivers/nv50/nv50_context.h b/src/gallium/drivers/nv50/nv50_context.h
index 890defb..4b0f062 100644
--- a/src/gallium/drivers/nv50/nv50_context.h
+++ b/src/gallium/drivers/nv50/nv50_context.h
@@ -69,6 +69,18 @@ struct nv50_sampler_stateobj {
 	unsigned tsc[8];
 };
 
+static INLINE unsigned
+get_tile_height(uint32_t tile_mode)
+{
+        return 1 << ((tile_mode & 0xf) + 2);
+}
+
+static INLINE unsigned
+get_tile_depth(uint32_t tile_mode)
+{
+        return 1 << (tile_mode >> 4);
+}
+
 struct nv50_miptree_level {
 	int *image_offset;
 	unsigned pitch;
diff --git a/src/gallium/drivers/nv50/nv50_miptree.c b/src/gallium/drivers/nv50/nv50_miptree.c
index 229a59c..9c20c5c 100644
--- a/src/gallium/drivers/nv50/nv50_miptree.c
+++ b/src/gallium/drivers/nv50/nv50_miptree.c
@@ -26,14 +26,33 @@
 
 #include "nv50_context.h"
 
+/* The restrictions in tile mode selection probably aren't necessary. */
 static INLINE uint32_t
-get_tile_mode(unsigned ny)
+get_tile_mode(unsigned ny, unsigned d)
 {
-	if (ny > 32) return 4;
-	if (ny > 16) return 3;
-	if (ny >  8) return 2;
-	if (ny >  4) return 1;
-	return 0;
+	uint32_t tile_mode = 0x00;
+
+	if (ny > 32) tile_mode = 0x04; /* height 64 tiles */
+	else
+	if (ny > 16) tile_mode = 0x03; /* height 32 tiles */
+	else
+	if (ny >  8) tile_mode = 0x02; /* height 16 tiles */
+	else
+	if (ny >  4) tile_mode = 0x01; /* height 8 tiles */
+
+	if (d == 1)
+		return tile_mode;
+	else
+	if (tile_mode > 0x02)
+		tile_mode = 0x02;
+
+	if (d > 16 && tile_mode < 0x02)
+		return tile_mode | 0x50; /* depth 32 tiles */
+	if (d >  8) return tile_mode | 0x40; /* depth 16 tiles */
+	if (d >  4) return tile_mode | 0x30; /* depth 8 tiles */
+	if (d >  2) return tile_mode | 0x20; /* depth 4 tiles */
+
+	return tile_mode | 0x10;
 }
 
 static struct pipe_texture *
@@ -43,7 +62,7 @@ nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp)
 	struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
 	struct pipe_texture *pt = &mt->base.base;
 	unsigned width = tmp->width[0], height = tmp->height[0];
-	unsigned depth = tmp->depth[0];
+	unsigned depth = tmp->depth[0], image_alignment;
 	uint32_t tile_flags;
 	int ret, i, l;
 
@@ -67,17 +86,8 @@ nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp)
 		break;
 	}
 
-	switch (pt->target) {
-	case PIPE_TEXTURE_3D:
-		mt->image_nr = pt->depth[0];
-		break;
-	case PIPE_TEXTURE_CUBE:
-		mt->image_nr = 6;
-		break;
-	default:
-		mt->image_nr = 1;
-		break;
-	}
+	/* XXX: texture arrays */
+	mt->image_nr = (pt->target == PIPE_TEXTURE_CUBE) ? 6 : 1;
 
 	for (l = 0; l <= pt->last_level; l++) {
 		struct nv50_miptree_level *lvl = &mt->level[l];
@@ -90,26 +100,35 @@ nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp)
 
 		lvl->image_offset = CALLOC(mt->image_nr, sizeof(int));
 		lvl->pitch = align(pt->nblocksx[l] * pt->block.size, 64);
-		lvl->tile_mode = get_tile_mode(pt->nblocksy[l]);
+		lvl->tile_mode = get_tile_mode(pt->nblocksy[l], depth);
 
 		width = MAX2(1, width >> 1);
 		height = MAX2(1, height >> 1);
 		depth = MAX2(1, depth >> 1);
 	}
 
+	image_alignment  = get_tile_height(mt->level[0].tile_mode) * 64;
+	image_alignment *= get_tile_depth(mt->level[0].tile_mode);
+
+	/* NOTE the distinction between arrays of mip-mapped 2D textures and
+	 * mip-mapped 3D textures. We can't use image_nr == depth for 3D mip.
+	 */
 	for (i = 0; i < mt->image_nr; i++) {
 		for (l = 0; l <= pt->last_level; l++) {
 			struct nv50_miptree_level *lvl = &mt->level[l];
 			int size;
-			unsigned tile_ny = 1 << (lvl->tile_mode + 2);
+			unsigned tile_h = get_tile_height(lvl->tile_mode);
+			unsigned tile_d = get_tile_depth(lvl->tile_mode);
 
-			size  = align(pt->nblocksx[l] * pt->block.size, 64);
-			size *= align(pt->nblocksy[l], tile_ny);
+			size  = lvl->pitch;
+			size *= align(pt->nblocksy[l], tile_h);
+			size *= align(pt->depth[l], tile_d);
 
 			lvl->image_offset[i] = mt->total_size;
 
 			mt->total_size += size;
 		}
+		mt->total_size = align(mt->total_size, image_alignment);
 	}
 
 	ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 256, mt->total_size,
diff --git a/src/gallium/drivers/nv50/nv50_tex.c b/src/gallium/drivers/nv50/nv50_tex.c
index 52ccdaa..2813f54 100644
--- a/src/gallium/drivers/nv50/nv50_tex.c
+++ b/src/gallium/drivers/nv50/nv50_tex.c
@@ -96,19 +96,44 @@ nv50_tex_construct(struct nv50_context *nv50, struct nouveau_stateobj *so,
 	if (i == NV50_TEX_FORMAT_LIST_SIZE)
                 return 1;
 
-	mode = (nv50->sampler[unit]->normalized ? 0xd0005000 : 0x5001d000) |
-	       (mt->base.bo->tile_mode << 22);
+	if (nv50->sampler[unit]->normalized)
+		mode = 0x50001000 | (1 << 31);
+	else {
+		mode = 0x50001000 | (7 << 14);
+		assert(mt->base.base.target == PIPE_TEXTURE_2D);
+	}
+
+	mode |= ((mt->base.bo->tile_mode & 0x0f) << 22) |
+		((mt->base.bo->tile_mode & 0xf0) << 21);
+
 	if (pf_type(mt->base.base.format) == PIPE_FORMAT_TYPE_SRGB)
 		mode |= 0x0400;
 
+	switch (mt->base.base.target) {
+	case PIPE_TEXTURE_1D:
+		break;
+	case PIPE_TEXTURE_2D:
+		mode |= (1 << 14);
+		break;
+	case PIPE_TEXTURE_3D:
+		mode |= (2 << 14);
+		break;
+	case PIPE_TEXTURE_CUBE:
+		mode |= (3 << 14);
+		break;
+	default:
+		assert(!"unsupported texture target");
+		break;
+	}
+
 	so_data (so, nv50_tex_format_list[i].hw);
 	so_reloc(so, mt->base.bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_LOW |
-		     NOUVEAU_BO_RD, 0, 0);
+		 NOUVEAU_BO_RD, 0, 0);
 	so_data (so, mode);
 	so_data (so, 0x00300000);
-	so_data (so, mt->base.base.width[0]);
+	so_data (so, mt->base.base.width[0] | (1 << 31));
 	so_data (so, (mt->base.base.last_level << 28) |
-		     (mt->base.base.depth[0] << 16) | mt->base.base.height[0]);
+		 (mt->base.base.depth[0] << 16) | mt->base.base.height[0]);
 	so_data (so, 0x03000000);
 	so_data (so, mt->base.base.last_level << 4);
 
@@ -124,7 +149,7 @@ nv50_tex_validate(struct nv50_context *nv50)
 	unsigned i, unit, push;
 
 	push = MAX2(nv50->miptree_nr, nv50->state.miptree_nr) * 2 + 23 + 6;
-	so = so_new(nv50->miptree_nr * 9 + push, nv50->miptree_nr + 2);
+	so = so_new(nv50->miptree_nr * 9 + push, nv50->miptree_nr * 2 + 2);
 
 	nv50_so_init_sifc(nv50, so, nv50->screen->tic, NOUVEAU_BO_VRAM,
 			  nv50->miptree_nr * 8 * 4);
diff --git a/src/gallium/drivers/nv50/nv50_transfer.c b/src/gallium/drivers/nv50/nv50_transfer.c
index 9c00809..ea61357 100644
--- a/src/gallium/drivers/nv50/nv50_transfer.c
+++ b/src/gallium/drivers/nv50/nv50_transfer.c
@@ -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);




More information about the mesa-commit mailing list