static struct pipe_texture *
nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp)
{
- struct pipe_winsys *ws = pscreen->winsys;
+ struct nouveau_device *dev = nouveau_screen(pscreen)->device;
struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
- struct pipe_texture *pt = &mt->base;
- unsigned usage, width = tmp->width[0], height = tmp->height[0];
+ struct pipe_texture *pt = &mt->base.base;
+ unsigned width = tmp->width[0], height = tmp->height[0];
unsigned depth = tmp->depth[0];
- int i, l;
+ uint32_t tile_mode, tile_flags, tile_h;
+ int ret, i, l;
- mt->base = *tmp;
- mt->base.refcount = 1;
- mt->base.screen = pscreen;
+ *pt = *tmp;
+ pipe_reference_init(&pt->reference, 1);
+ pt->screen = pscreen;
- usage = PIPE_BUFFER_USAGE_PIXEL;
switch (pt->format) {
+ case PIPE_FORMAT_Z32_FLOAT:
+ tile_flags = 0x4800;
+ break;
case PIPE_FORMAT_Z24S8_UNORM:
- case PIPE_FORMAT_Z16_UNORM:
- usage |= NOUVEAU_BUFFER_USAGE_ZETA;
+ tile_flags = 0x1800;
+ break;
+ case PIPE_FORMAT_X8Z24_UNORM:
+ case PIPE_FORMAT_S8Z24_UNORM:
+ tile_flags = 0x2800;
break;
default:
+ tile_flags = 0x7000;
break;
}
+ if (pt->height[0] > 32) tile_mode = 4;
+ else if (pt->height[0] > 16) tile_mode = 3;
+ else if (pt->height[0] > 8) tile_mode = 2;
+ else if (pt->height[0] > 4) tile_mode = 1;
+ else tile_mode = 0;
+ tile_h = 1 << (tile_mode + 2);
+
switch (pt->target) {
case PIPE_TEXTURE_3D:
mt->image_nr = pt->depth[0];
pt->nblocksy[l] = pf_get_nblocksy(&pt->block, height);
lvl->image_offset = CALLOC(mt->image_nr, sizeof(int));
- lvl->image = CALLOC(mt->image_nr, sizeof(struct pipe_buffer *));
+ 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], 8) * pt->block.size;
+ size *= align(pt->height[l], tile_h);
- lvl->image[i] = ws->_buffer_create(ws, 256, 0, size);
lvl->image_offset[i] = mt->total_size;
mt->total_size += size;
}
}
- mt->buffer = ws->_buffer_create(ws, 256, usage, mt->total_size);
- if (!mt->buffer) {
+ ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 256, mt->total_size,
+ mt->level[0].tile_mode, tile_flags,
+ &mt->base.bo);
+ if (ret) {
FREE(mt);
return NULL;
}
- return &mt->base;
-}
-
-static INLINE void
-mark_dirty(uint32_t *flags, unsigned image)
-{
- flags[image / 32] |= (1 << (image % 32));
-}
-
-static INLINE void
-mark_clean(uint32_t *flags, unsigned image)
-{
- flags[image / 32] &= ~(1 << (image % 32));
+ return pt;
}
-static INLINE int
-is_dirty(uint32_t *flags, unsigned image)
-{
- return !!(flags[image / 32] & (1 << (image % 32)));
-}
-
-static void
-nv50_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt)
+static struct pipe_texture *
+nv50_miptree_blanket(struct pipe_screen *pscreen, const struct pipe_texture *pt,
+ const unsigned *stride, struct pipe_buffer *pb)
{
- struct pipe_texture *pt = *ppt;
-
- *ppt = NULL;
-
- if (--pt->refcount <= 0) {
- struct nv50_miptree *mt = nv50_miptree(pt);
+ struct nouveau_bo *bo = nouveau_bo(pb);
+ struct nv50_miptree *mt;
- pipe_buffer_reference(pscreen, &mt->buffer, NULL);
- FREE(mt);
- }
-}
+ /* Only supports 2D, non-mipmapped textures for the moment */
+ if (pt->target != PIPE_TEXTURE_2D || pt->last_level != 0 ||
+ pt->depth[0] != 1)
+ return NULL;
-void
-nv50_miptree_sync(struct pipe_screen *pscreen, struct nv50_miptree *mt,
- unsigned level, unsigned image)
-{
- struct nouveau_winsys *nvws = nv50_screen(pscreen)->nvws;
- struct nv50_miptree_level *lvl = &mt->level[level];
- struct pipe_surface *dst, *src;
- unsigned face = 0, zslice = 0;
+ mt = CALLOC_STRUCT(nv50_miptree);
+ if (!mt)
+ return NULL;
- if (!is_dirty(lvl->image_dirty_cpu, image))
- return;
+ mt->base.base = *pt;
+ pipe_reference_init(&mt->base.base.reference, 1);
+ mt->base.base.screen = pscreen;
+ mt->image_nr = 1;
+ mt->level[0].pitch = *stride;
+ mt->level[0].image_offset = CALLOC(1, sizeof(unsigned));
+ mt->level[0].tile_mode = bo->tile_mode;
- if (mt->base.target == PIPE_TEXTURE_CUBE)
- face = image;
- else
- if (mt->base.target == PIPE_TEXTURE_3D)
- zslice = image;
-
- /* Mark as clean already - so we don't continually call this function
- * trying to get a GPU_WRITE pipe_surface!
- */
- mark_clean(lvl->image_dirty_cpu, image);
-
- /* Pretend we're doing CPU access so we get the backing pipe_surface
- * and not a view into the larger miptree.
- */
- src = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice,
- PIPE_BUFFER_USAGE_CPU_READ);
-
- /* Pretend we're only reading with the GPU so surface doesn't get marked
- * as dirtied by the GPU.
- */
- dst = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice,
- PIPE_BUFFER_USAGE_GPU_READ);
-
- nvws->surface_copy(nvws, dst, 0, 0, src, 0, 0, dst->width, dst->height);
-
- pscreen->tex_surface_release(pscreen, &dst);
- pscreen->tex_surface_release(pscreen, &src);
+ nouveau_bo_ref(bo, &mt->base.bo);
+ return &mt->base.base;
}
-/* The reverse of the above */
-void
-nv50_miptree_sync_cpu(struct pipe_screen *pscreen, struct nv50_miptree *mt,
- unsigned level, unsigned image)
+static void
+nv50_miptree_destroy(struct pipe_texture *pt)
{
- struct nouveau_winsys *nvws = nv50_screen(pscreen)->nvws;
- struct nv50_miptree_level *lvl = &mt->level[level];
- struct pipe_surface *dst, *src;
- unsigned face = 0, zslice = 0;
-
- if (!is_dirty(lvl->image_dirty_gpu, image))
- return;
-
- if (mt->base.target == PIPE_TEXTURE_CUBE)
- face = image;
- else
- if (mt->base.target == PIPE_TEXTURE_3D)
- zslice = image;
-
- mark_clean(lvl->image_dirty_gpu, image);
-
- src = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice,
- PIPE_BUFFER_USAGE_GPU_READ);
- dst = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice,
- PIPE_BUFFER_USAGE_CPU_READ);
-
- nvws->surface_copy(nvws, dst, 0, 0, src, 0, 0, dst->width, dst->height);
+ struct nv50_miptree *mt = nv50_miptree(pt);
- pscreen->tex_surface_release(pscreen, &dst);
- pscreen->tex_surface_release(pscreen, &src);
+ nouveau_bo_ref(NULL, &mt->base.bo);
+ FREE(mt);
}
static struct pipe_surface *
if (!ps)
return NULL;
pipe_texture_reference(&ps->texture, pt);
- pipe_buffer_reference(pscreen, &ps->buffer, mt->buffer);
ps->format = pt->format;
ps->width = pt->width[level];
ps->height = pt->height[level];
- ps->block = pt->block;
- ps->nblocksx = pt->nblocksx[level];
- ps->nblocksy = pt->nblocksy[level];
- ps->stride = ps->width * ps->block.size;
ps->usage = flags;
- ps->status = PIPE_SURFACE_STATUS_DEFINED;
- ps->refcount = 1;
+ pipe_reference_init(&ps->reference, 1);
ps->face = face;
ps->level = level;
ps->zslice = zslice;
-
- if (flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE) {
- assert(!(flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE));
- nv50_miptree_sync_cpu(pscreen, mt, level, img);
-
- ps->offset = 0;
- pipe_texture_reference(&ps->texture, pt);
- pipe_buffer_reference(pscreen, &ps->buffer, lvl->image[img]);
-
- if (flags & PIPE_BUFFER_USAGE_CPU_WRITE)
- mark_dirty(lvl->image_dirty_cpu, img);
- } else {
- nv50_miptree_sync(pscreen, mt, level, img);
-
- ps->offset = lvl->image_offset[img];
- pipe_texture_reference(&ps->texture, pt);
- pipe_buffer_reference(pscreen, &ps->buffer, mt->buffer);
-
- if (flags & PIPE_BUFFER_USAGE_GPU_WRITE)
- mark_dirty(lvl->image_dirty_gpu, img);
- }
+ ps->offset = lvl->image_offset[img];
return ps;
}
static void
-nv50_miptree_surface_del(struct pipe_screen *pscreen,
- struct pipe_surface **psurface)
+nv50_miptree_surface_del(struct pipe_surface *ps)
{
- struct pipe_surface *ps = *psurface;
struct nv50_surface *s = nv50_surface(ps);
- *psurface = NULL;
-
- if (--ps->refcount <= 0) {
- pipe_texture_reference(&ps->texture, NULL);
- pipe_buffer_reference(pscreen, &ps->buffer, NULL);
- FREE(s);
- }
+ pipe_texture_reference(&ps->texture, NULL);
+ FREE(s);
}
void
nv50_screen_init_miptree_functions(struct pipe_screen *pscreen)
{
pscreen->texture_create = nv50_miptree_create;
- pscreen->texture_release = nv50_miptree_release;
+ pscreen->texture_blanket = nv50_miptree_blanket;
+ pscreen->texture_destroy = nv50_miptree_destroy;
pscreen->get_tex_surface = nv50_miptree_surface_new;
- pscreen->tex_surface_release = nv50_miptree_surface_del;
+ pscreen->tex_surface_destroy = nv50_miptree_surface_del;
}