nv50: any cpu access to a texture is done on its backing images
authorBen Skeggs <skeggsb@gmail.com>
Mon, 12 Jan 2009 04:10:24 +0000 (14:10 +1000)
committerBen Skeggs <skeggsb@gmail.com>
Mon, 12 Jan 2009 06:59:33 +0000 (16:59 +1000)
Still a little dodgy:
- RTT will hit an assertion (hopefully!) and fail
- 3D textures with depth >= 32 will cause bad things to happen

src/gallium/drivers/nv50/nv50_context.h
src/gallium/drivers/nv50/nv50_miptree.c
src/gallium/drivers/nv50/nv50_tex.c

index daa3efaa0a7c3b5b60557d9fbc6ea5c8d5e4edfd..c1ff6061e4dd9ed8ccb4fb1d0129acae58492f02 100644 (file)
@@ -70,7 +70,8 @@ struct nv50_rasterizer_stateobj {
 struct nv50_miptree_level {
        struct pipe_buffer **image;
        int *image_offset;
-       unsigned image_dirty;
+       unsigned image_dirty_cpu;
+       unsigned image_dirty_gpu;
 };
 
 struct nv50_miptree {
index c72b0db9ecae88a592ad4f9da7f300cb2ad062a1..415080bc98d6626a4e4c961bd65a6ce849b67737 100644 (file)
@@ -115,12 +115,50 @@ nv50_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt)
        }
 }
 
+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;
+
+       if (!lvl->image_dirty_cpu & (1 << image))
+               return;
+
+       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!
+        */
+       lvl->image_dirty_cpu &= ~(1 << image);
+
+       dst = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice,
+                                      PIPE_BUFFER_USAGE_GPU_WRITE);
+       /* 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);
+
+       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);
+}
+
 static struct pipe_surface *
 nv50_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
                         unsigned face, unsigned level, unsigned zslice,
                         unsigned flags)
 {
        struct nv50_miptree *mt = nv50_miptree(pt);
+       struct nv50_miptree_level *lvl = &mt->level[level];
        struct nv50_surface *s;
        struct pipe_surface *ps;
        int img;
@@ -147,12 +185,29 @@ nv50_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
        ps->nblocksx = pt->nblocksx[level];
        ps->nblocksy = pt->nblocksy[level];
        ps->stride = ps->width * ps->block.size;
-       ps->offset = mt->level[level].image_offset[img];
        ps->usage = flags;
        ps->status = PIPE_SURFACE_STATUS_DEFINED;
 
-       pipe_texture_reference(&ps->texture, pt);
-       pipe_buffer_reference(pscreen, &ps->buffer, mt->buffer);
+       if (flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE) {
+               assert(!(flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE));
+               assert(!(lvl->image_dirty_cpu & (1 << 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)
+                       lvl->image_dirty_cpu |= (1 << 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)
+                       lvl->image_dirty_gpu |= (1 << img);
+       }
 
        return ps;
 }
index fde3c97c059f9cebd4f4edb43d2af2ae1d4e87c8..cc91c2d92408d31e2086112278ead4e870975551 100644 (file)
@@ -105,14 +105,23 @@ nv50_tex_validate(struct nv50_context *nv50)
 {
        struct nouveau_grobj *tesla = nv50->screen->tesla;
        struct nouveau_stateobj *so;
-       int i;
+       int unit, level, image;
 
        so = so_new(nv50->miptree_nr * 8 + 3, nv50->miptree_nr * 2);
        so_method(so, tesla, 0x0f00, 1);
        so_data  (so, NV50_CB_TIC);
        so_method(so, tesla, 0x40000f04, nv50->miptree_nr * 8);
-       for (i = 0; i < nv50->miptree_nr; i++) {
-               if (nv50_tex_construct(so, nv50->miptree[i])) {
+       for (unit = 0; unit < nv50->miptree_nr; unit++) {
+               struct nv50_miptree *mt = nv50->miptree[unit];
+
+               for (level = 0; level <= mt->base.last_level; level++) {
+                       for (image = 0; image < mt->image_nr; image++) {
+                               nv50_miptree_sync(&nv50->screen->pipe, mt,
+                                                 level, image);
+                       }
+               }
+
+               if (nv50_tex_construct(so, mt)) {
                        NOUVEAU_ERR("failed tex validate\n");
                        so_ref(NULL, &so);
                        return;