nv50: fix mipmap offsets and tiling
The hardware expects a texture's tile mode to change with the mipmap level. Also, only multiply by block size once to obtain size.
This commit is contained in:
@@ -71,6 +71,7 @@ struct nv50_sampler_stateobj {
|
||||
struct nv50_miptree_level {
|
||||
int *image_offset;
|
||||
unsigned pitch;
|
||||
unsigned tile_mode;
|
||||
};
|
||||
|
||||
struct nv50_miptree {
|
||||
|
||||
@@ -87,20 +87,27 @@ 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->width[l] * pt->block.size, 64);
|
||||
lvl->tile_mode = tile_mode;
|
||||
|
||||
width = MAX2(1, width >> 1);
|
||||
height = MAX2(1, height >> 1);
|
||||
depth = MAX2(1, depth >> 1);
|
||||
|
||||
if (tile_mode && height <= (tile_h >> 1)) {
|
||||
tile_mode--;
|
||||
tile_h >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
tile_h = 1 << (lvl->tile_mode + 2);
|
||||
|
||||
size = align(pt->width[l], 8) * pt->block.size;
|
||||
size = align(size, 64);
|
||||
size *= align(pt->height[l], tile_h) * pt->block.size;
|
||||
size *= align(pt->height[l], tile_h);
|
||||
|
||||
lvl->image_offset[i] = mt->total_size;
|
||||
|
||||
@@ -109,7 +116,7 @@ nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp)
|
||||
}
|
||||
|
||||
ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 256, mt->total_size,
|
||||
tile_mode, tile_flags, &mt->bo);
|
||||
mt->level[0].tile_mode, tile_flags, &mt->bo);
|
||||
if (ret) {
|
||||
FREE(mt);
|
||||
return NULL;
|
||||
|
||||
@@ -8,6 +8,7 @@ struct nv50_transfer {
|
||||
struct pipe_transfer base;
|
||||
struct nouveau_bo *bo;
|
||||
unsigned level_offset;
|
||||
unsigned level_tiling;
|
||||
int level_pitch;
|
||||
int level_width;
|
||||
int level_height;
|
||||
@@ -16,11 +17,14 @@ struct nv50_transfer {
|
||||
};
|
||||
|
||||
static void
|
||||
nv50_transfer_rect_m2mf(struct pipe_screen *pscreen, struct nouveau_bo *src_bo,
|
||||
unsigned src_offset, int src_pitch, int sx, int sy,
|
||||
int sw, int sh, struct nouveau_bo *dst_bo,
|
||||
unsigned dst_offset, int dst_pitch, int dx, int dy,
|
||||
int dw, int dh, int cpp, int width, int height,
|
||||
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,
|
||||
struct nouveau_bo *dst_bo, unsigned dst_offset,
|
||||
int dst_pitch, unsigned dst_tile_mode,
|
||||
int dx, int dy, int dw, int dh,
|
||||
int cpp, int width, int height,
|
||||
unsigned src_reloc, unsigned dst_reloc)
|
||||
{
|
||||
struct nv50_screen *screen = nv50_screen(pscreen);
|
||||
@@ -41,7 +45,7 @@ nv50_transfer_rect_m2mf(struct pipe_screen *pscreen, struct nouveau_bo *src_bo,
|
||||
} else {
|
||||
BEGIN_RING(chan, m2mf, 0x0200, 6);
|
||||
OUT_RING (chan, 0);
|
||||
OUT_RING (chan, src_bo->tile_mode << 4);
|
||||
OUT_RING (chan, src_tile_mode << 4);
|
||||
OUT_RING (chan, sw * cpp);
|
||||
OUT_RING (chan, sh);
|
||||
OUT_RING (chan, 1);
|
||||
@@ -57,7 +61,7 @@ nv50_transfer_rect_m2mf(struct pipe_screen *pscreen, struct nouveau_bo *src_bo,
|
||||
} else {
|
||||
BEGIN_RING(chan, m2mf, 0x021c, 6);
|
||||
OUT_RING (chan, 0);
|
||||
OUT_RING (chan, dst_bo->tile_mode << 4);
|
||||
OUT_RING (chan, dst_tile_mode << 4);
|
||||
OUT_RING (chan, dw * cpp);
|
||||
OUT_RING (chan, dh);
|
||||
OUT_RING (chan, 1);
|
||||
@@ -136,6 +140,7 @@ nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
|
||||
tx->level_width = mt->base.width[level];
|
||||
tx->level_height = mt->base.height[level];
|
||||
tx->level_offset = lvl->image_offset[image];
|
||||
tx->level_tiling = lvl->tile_mode;
|
||||
tx->level_x = x;
|
||||
tx->level_y = y;
|
||||
ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
|
||||
@@ -147,9 +152,11 @@ nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
|
||||
|
||||
if (usage != PIPE_TRANSFER_WRITE) {
|
||||
nv50_transfer_rect_m2mf(pscreen, mt->bo, tx->level_offset,
|
||||
tx->level_pitch, x, y, tx->level_width,
|
||||
tx->level_height, tx->bo, 0,
|
||||
tx->base.stride, 0, 0,
|
||||
tx->level_pitch, tx->level_tiling,
|
||||
x, y,
|
||||
tx->level_width, tx->level_height,
|
||||
tx->bo, 0, tx->base.stride,
|
||||
tx->bo->tile_mode, 0, 0,
|
||||
tx->base.width, tx->base.height,
|
||||
tx->base.block.size, w, h,
|
||||
NOUVEAU_BO_VRAM | NOUVEAU_BO_GART,
|
||||
@@ -168,12 +175,14 @@ nv50_transfer_del(struct pipe_transfer *ptx)
|
||||
if (ptx->usage != PIPE_TRANSFER_READ) {
|
||||
struct pipe_screen *pscreen = ptx->texture->screen;
|
||||
nv50_transfer_rect_m2mf(pscreen, tx->bo, 0, tx->base.stride,
|
||||
0, 0, tx->base.width, tx->base.height,
|
||||
mt->bo, tx->level_offset,
|
||||
tx->level_pitch, tx->level_x,
|
||||
tx->level_y, tx->level_width,
|
||||
tx->level_height, tx->base.block.size,
|
||||
tx->bo->tile_mode, 0, 0,
|
||||
tx->base.width, tx->base.height,
|
||||
mt->bo, tx->level_offset,
|
||||
tx->level_pitch, tx->level_tiling,
|
||||
tx->level_x, tx->level_y,
|
||||
tx->level_width, tx->level_height,
|
||||
tx->base.block.size, tx->base.width,
|
||||
tx->base.height,
|
||||
NOUVEAU_BO_GART, NOUVEAU_BO_VRAM |
|
||||
NOUVEAU_BO_GART);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user