Mesa (gallium-0.2): nv50: any cpu access to a texture is done on its backing images

Ben Skeggs darktama at kemper.freedesktop.org
Mon Jan 12 07:00:06 UTC 2009


Module: Mesa
Branch: gallium-0.2
Commit: 08b6534bc80925e4574d6b893f8aa14751b44a3f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=08b6534bc80925e4574d6b893f8aa14751b44a3f

Author: Ben Skeggs <skeggsb at gmail.com>
Date:   Mon Jan 12 14:10:24 2009 +1000

nv50: any cpu access to a texture is done on its backing images

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 |    3 +-
 src/gallium/drivers/nv50/nv50_miptree.c |   61 +++++++++++++++++++++++++++++--
 src/gallium/drivers/nv50/nv50_tex.c     |   15 ++++++--
 3 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/src/gallium/drivers/nv50/nv50_context.h b/src/gallium/drivers/nv50/nv50_context.h
index daa3efa..c1ff606 100644
--- a/src/gallium/drivers/nv50/nv50_context.h
+++ b/src/gallium/drivers/nv50/nv50_context.h
@@ -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 {
diff --git a/src/gallium/drivers/nv50/nv50_miptree.c b/src/gallium/drivers/nv50/nv50_miptree.c
index c72b0db..415080b 100644
--- a/src/gallium/drivers/nv50/nv50_miptree.c
+++ b/src/gallium/drivers/nv50/nv50_miptree.c
@@ -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;
 }
diff --git a/src/gallium/drivers/nv50/nv50_tex.c b/src/gallium/drivers/nv50/nv50_tex.c
index fde3c97..cc91c2d 100644
--- a/src/gallium/drivers/nv50/nv50_tex.c
+++ b/src/gallium/drivers/nv50/nv50_tex.c
@@ -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;




More information about the mesa-commit mailing list