mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-26 23:40:10 +01:00
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:
parent
c475079ef2
commit
040e1d008f
4 changed files with 114 additions and 37 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue