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.
This commit is contained in:
Christoph Bumiller 2009-11-03 23:19:56 +01:00
parent c475079ef2
commit 040e1d008f
4 changed files with 114 additions and 37 deletions

View file

@ -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;

View file

@ -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,

View file

@ -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);

View 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);