Mesa (master): dri/nouveau: Try to validate textures earlier.

Francisco Jerez currojerez at kemper.freedesktop.org
Thu Feb 25 10:33:38 PST 2010


Module: Mesa
Branch: master
Commit: 323e6bbb052f37f91c7340e16c2352bb780a43d8
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=323e6bbb052f37f91c7340e16c2352bb780a43d8

Author: Francisco Jerez <currojerez at riseup.net>
Date:   Mon Feb 22 02:03:42 2010 +0100

dri/nouveau: Try to validate textures earlier.

---

 src/mesa/drivers/dri/nouveau/nouveau_state.c   |    4 +-
 src/mesa/drivers/dri/nouveau/nouveau_texture.c |  284 +++++++++++++++---------
 src/mesa/drivers/dri/nouveau/nouveau_texture.h |    5 +-
 src/mesa/drivers/dri/nouveau/nv04_state_tex.c  |    4 +-
 src/mesa/drivers/dri/nouveau/nv10_state_tex.c  |    3 +-
 src/mesa/drivers/dri/nouveau/nv20_state_tex.c  |    3 +-
 6 files changed, 191 insertions(+), 112 deletions(-)

diff --git a/src/mesa/drivers/dri/nouveau/nouveau_state.c b/src/mesa/drivers/dri/nouveau/nouveau_state.c
index d727822..5d593ed 100644
--- a/src/mesa/drivers/dri/nouveau/nouveau_state.c
+++ b/src/mesa/drivers/dri/nouveau/nouveau_state.c
@@ -396,7 +396,6 @@ nouveau_tex_parameter(GLcontext *ctx, GLenum target,
 		      const GLfloat *params)
 {
 	switch (pname) {
-	case GL_TEXTURE_MIN_FILTER:
 	case GL_TEXTURE_MAG_FILTER:
 	case GL_TEXTURE_WRAP_S:
 	case GL_TEXTURE_WRAP_T:
@@ -408,9 +407,10 @@ nouveau_tex_parameter(GLcontext *ctx, GLenum target,
 		context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
 		break;
 
+	case GL_TEXTURE_MIN_FILTER:
 	case GL_TEXTURE_BASE_LEVEL:
 	case GL_TEXTURE_MAX_LEVEL:
-		texture_dirty(t);
+		nouveau_texture_reallocate(ctx, t);
 		context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
 		break;
 	}
diff --git a/src/mesa/drivers/dri/nouveau/nouveau_texture.c b/src/mesa/drivers/dri/nouveau/nouveau_texture.c
index ab6e93c..32603ab 100644
--- a/src/mesa/drivers/dri/nouveau/nouveau_texture.c
+++ b/src/mesa/drivers/dri/nouveau/nouveau_texture.c
@@ -171,6 +171,148 @@ nouveau_choose_tex_format(GLcontext *ctx, GLint internalFormat,
 	}
 }
 
+static GLboolean
+teximage_fits(struct gl_texture_object *t, int level,
+	      struct gl_texture_image *ti)
+{
+	struct nouveau_surface *s = &to_nouveau_texture(t)->surfaces[level];
+
+	return s->bo && s->width == ti->Width &&
+		s->height == ti->Height &&
+		s->format == ti->TexFormat;
+}
+
+static GLboolean
+validate_teximage(GLcontext *ctx, struct gl_texture_object *t,
+		  int level, int x, int y, int z,
+		  int width, int height, int depth)
+{
+	struct gl_texture_image *ti = t->Image[0][level];
+
+	if (ti && teximage_fits(t, level, ti)) {
+		struct nouveau_surface *ss = to_nouveau_texture(t)->surfaces;
+		struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
+
+		context_drv(ctx)->surface_copy(ctx, &ss[level], s,
+					       x, y, x, y,
+					       width, height);
+
+		return GL_TRUE;
+	}
+
+	return GL_FALSE;
+}
+
+static int
+get_last_level(struct gl_texture_object *t)
+{
+	struct gl_texture_image *base = t->Image[0][t->BaseLevel];
+
+	if (t->MinFilter == GL_NEAREST ||
+	    t->MinFilter == GL_LINEAR || !base)
+		return t->BaseLevel;
+	else
+		return MIN2(t->BaseLevel + base->MaxLog2, t->MaxLevel);
+}
+
+static void
+relayout_texture(GLcontext *ctx, struct gl_texture_object *t)
+{
+	struct gl_texture_image *base = t->Image[0][t->BaseLevel];
+
+	if (base) {
+		struct nouveau_surface *ss = to_nouveau_texture(t)->surfaces;
+		struct nouveau_surface *s = &to_nouveau_teximage(base)->surface;
+		int i, ret, last = get_last_level(t);
+		unsigned size, offset = 0,
+			width = s->width,
+			height = s->height;
+
+		/* Deallocate the old storage. */
+		for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
+			nouveau_bo_ref(NULL, &ss[i].bo);
+
+		/* Relayout the mipmap tree. */
+		for (i = t->BaseLevel; i <= last; i++) {
+			size = width * height * s->cpp;
+
+			/* Images larger than 16B have to be aligned. */
+			if (size > 16)
+				offset = align(offset, 64);
+
+			ss[i] = (struct nouveau_surface) {
+				.offset = offset,
+				.layout = SWIZZLED,
+				.format = s->format,
+				.width = width,
+				.height = height,
+				.cpp = s->cpp,
+				.pitch = width * s->cpp,
+			};
+
+			offset += size;
+			width = MAX2(1, width / 2);
+			height = MAX2(1, height / 2);
+		}
+
+		/* Get new storage. */
+		size = align(offset, 64);
+
+		ret = nouveau_bo_new(context_dev(ctx), NOUVEAU_BO_MAP |
+				     NOUVEAU_BO_GART | NOUVEAU_BO_VRAM,
+				     0, size, &ss[last].bo);
+		assert(!ret);
+
+		for (i = t->BaseLevel; i < last; i++)
+			nouveau_bo_ref(ss[last].bo, &ss[i].bo);
+	}
+}
+
+GLboolean
+nouveau_texture_validate(GLcontext *ctx, struct gl_texture_object *t)
+{
+	struct nouveau_texture *nt = to_nouveau_texture(t);
+	int i, last = get_last_level(t);
+
+	if (!nt->surfaces[last].bo)
+		return GL_FALSE;
+
+	if (nt->dirty) {
+		nt->dirty = GL_FALSE;
+
+		/* Copy the teximages to the actual miptree. */
+		for (i = t->BaseLevel; i <= last; i++) {
+			struct nouveau_surface *s = &nt->surfaces[i];
+
+			validate_teximage(ctx, t, i, 0, 0, 0,
+					  s->width, s->height, 1);
+		}
+	}
+
+	return GL_TRUE;
+}
+
+void
+nouveau_texture_reallocate(GLcontext *ctx, struct gl_texture_object *t)
+{
+	texture_dirty(t);
+	relayout_texture(ctx, t);
+	nouveau_texture_validate(ctx, t);
+}
+
+static unsigned
+get_teximage_placement(struct gl_texture_image *ti)
+{
+	if (ti->TexFormat == MESA_FORMAT_A8 ||
+	    ti->TexFormat == MESA_FORMAT_L8 ||
+	    ti->TexFormat == MESA_FORMAT_I8)
+		/* 1 cpp formats will have to be swizzled by the CPU,
+		 * so leave them in system RAM for now. */
+		return NOUVEAU_BO_MAP;
+	else
+		return NOUVEAU_BO_GART | NOUVEAU_BO_MAP;
+}
+
 static void
 nouveau_teximage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
 		 GLint internalFormat,
@@ -181,37 +323,45 @@ nouveau_teximage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
 		 struct gl_texture_image *ti)
 {
 	struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
-	unsigned bo_flags = NOUVEAU_BO_GART | NOUVEAU_BO_RDWR | NOUVEAU_BO_MAP;
 	int ret;
 
 	/* Allocate a new bo for the image. */
-	nouveau_surface_alloc(ctx, s, LINEAR, bo_flags, ti->TexFormat,
-			      width, height);
+	nouveau_surface_alloc(ctx, s, LINEAR, get_teximage_placement(ti),
+			      ti->TexFormat, width, height);
 	ti->RowStride = s->pitch / s->cpp;
 
 	pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, depth,
 					     format, type, pixels, packing,
 					     "glTexImage");
-	if (!pixels)
-		return;
-
-	/* Store the pixel data. */
-	nouveau_teximage_map(ctx, ti);
-
-	ret = _mesa_texstore(ctx, dims, ti->_BaseFormat,
-			     ti->TexFormat, ti->Data,
-			     0, 0, 0, s->pitch,
-			     ti->ImageOffsets,
-			     width, height, depth,
-			     format, type, pixels, packing);
-	assert(ret);
+	if (pixels) {
+		/* Store the pixel data. */
+		nouveau_teximage_map(ctx, ti);
+
+		ret = _mesa_texstore(ctx, dims, ti->_BaseFormat,
+				     ti->TexFormat, ti->Data,
+				     0, 0, 0, s->pitch,
+				     ti->ImageOffsets,
+				     width, height, depth,
+				     format, type, pixels, packing);
+		assert(ret);
+
+		nouveau_teximage_unmap(ctx, ti);
+		_mesa_unmap_teximage_pbo(ctx, packing);
+
+		if (!validate_teximage(ctx, t, level, 0, 0, 0,
+				       width, height, depth))
+			/* It doesn't fit, mark it as dirty. */
+			texture_dirty(t);
+	}
 
-	nouveau_teximage_unmap(ctx, ti);
-	_mesa_unmap_teximage_pbo(ctx, packing);
+	if (level == t->BaseLevel) {
+		if (!teximage_fits(t, level, ti))
+			relayout_texture(ctx, t);
+		nouveau_texture_validate(ctx, t);
+	}
 
 	context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
 	context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
-	texture_dirty(t);
 }
 
 static void
@@ -271,8 +421,9 @@ nouveau_texsubimage_3d(GLcontext *ctx, GLenum target, GLint level,
 				  packing, t, ti);
 	nouveau_teximage_unmap(ctx, ti);
 
-	context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
-	texture_dirty(t);
+	if (!to_nouveau_texture(t)->dirty)
+		validate_teximage(ctx, t, level, xoffset, yoffset, zoffset,
+				  width, height, depth);
 }
 
 static void
@@ -290,8 +441,9 @@ nouveau_texsubimage_2d(GLcontext *ctx, GLenum target, GLint level,
 				  packing, t, ti);
 	nouveau_teximage_unmap(ctx, ti);
 
-	context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
-	texture_dirty(t);
+	if (!to_nouveau_texture(t)->dirty)
+		validate_teximage(ctx, t, level, xoffset, yoffset, 0,
+				  width, height, 1);
 }
 
 static void
@@ -308,8 +460,9 @@ nouveau_texsubimage_1d(GLcontext *ctx, GLenum target, GLint level,
 				  packing, t, ti);
 	nouveau_teximage_unmap(ctx, ti);
 
-	context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
-	texture_dirty(t);
+	if (!to_nouveau_texture(t)->dirty)
+		validate_teximage(ctx, t, level, xoffset, 0, 0,
+				  width, 1, 1);
 }
 
 static void
@@ -354,87 +507,6 @@ nouveau_texture_unmap(GLcontext *ctx, struct gl_texture_object *t)
 	}
 }
 
-static void
-relayout_miptree(GLcontext *ctx, struct gl_texture_object *t)
-{
-	struct nouveau_surface *ss = to_nouveau_texture(t)->surfaces;
-	unsigned last_level, offset = 0;
-	unsigned size;
-	int i, ret;
-
-	if (t->MinFilter == GL_NEAREST ||
-	    t->MinFilter == GL_LINEAR)
-		last_level = t->BaseLevel;
-	else
-		last_level = t->_MaxLevel;
-
-	/* Deallocate the old storage. */
-	for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
-		nouveau_bo_ref(NULL, &ss[i].bo);
-
-	/* Relayout the mipmap tree. */
-	for (i = t->BaseLevel; i <= last_level; i++) {
-		struct nouveau_surface *s =
-			&to_nouveau_teximage(t->Image[0][i])->surface;
-
-		size = s->width * s->height * s->cpp;
-
-		/* Images larger than 16B have to be aligned. */
-		if (size > 16)
-			offset = align(offset, 64);
-
-		ss[i] = (struct nouveau_surface) {
-			.offset = offset,
-			.layout = SWIZZLED,
-			.format = s->format,
-			.width = s->width,
-			.height = s->height,
-			.cpp = s->cpp,
-			.pitch = s->width * s->cpp,
-		};
-
-		offset += size;
-	}
-
-	/* Get new storage. */
-	size = align(offset, 64);
-
-	ret = nouveau_bo_new(context_dev(ctx),
-			     NOUVEAU_BO_GART | NOUVEAU_BO_VRAM,
-			     0, size, &ss[last_level].bo);
-	assert(!ret);
-
-	for (i = t->BaseLevel; i < last_level; i++)
-		nouveau_bo_ref(ss[last_level].bo, &ss[i].bo);
-}
-
-void
-nouveau_texture_validate(GLcontext *ctx, struct gl_texture_object *t)
-{
-	struct nouveau_texture *nt = to_nouveau_texture(t);
-	int i;
-
-	if (!nt->dirty)
-		return;
-
-	nt->dirty = GL_FALSE;
-
-	relayout_miptree(ctx, t);
-
-	/* Copy the teximages to the actual swizzled miptree. */
-	for (i = t->BaseLevel; i < MAX_TEXTURE_LEVELS; i++) {
-		struct gl_texture_image *ti = t->Image[0][i];
-		struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
-
-		if (!nt->surfaces[i].bo)
-			break;
-
-		context_drv(ctx)->surface_copy(ctx, &nt->surfaces[i], s,
-					       0, 0, 0, 0,
-					       s->width, s->height);
-	}
-}
-
 void
 nouveau_texture_functions_init(struct dd_function_table *functions)
 {
diff --git a/src/mesa/drivers/dri/nouveau/nouveau_texture.h b/src/mesa/drivers/dri/nouveau/nouveau_texture.h
index 695c089..75d8190 100644
--- a/src/mesa/drivers/dri/nouveau/nouveau_texture.h
+++ b/src/mesa/drivers/dri/nouveau/nouveau_texture.h
@@ -43,7 +43,10 @@ struct nouveau_texture {
 #define texture_dirty(t) \
 	to_nouveau_texture(t)->dirty = GL_TRUE;
 
-void
+GLboolean
 nouveau_texture_validate(GLcontext *ctx, struct gl_texture_object *t);
 
+void
+nouveau_texture_reallocate(GLcontext *ctx, struct gl_texture_object *t);
+
 #endif
diff --git a/src/mesa/drivers/dri/nouveau/nv04_state_tex.c b/src/mesa/drivers/dri/nouveau/nv04_state_tex.c
index 99ea310..684a19e 100644
--- a/src/mesa/drivers/dri/nouveau/nv04_state_tex.c
+++ b/src/mesa/drivers/dri/nouveau/nv04_state_tex.c
@@ -89,7 +89,9 @@ nv04_emit_tex_obj(GLcontext *ctx, int emit)
 		struct gl_texture_image *ti = t->Image[0][t->BaseLevel];
 		int lod_max = 1, lod_bias = 0;
 
-		nouveau_texture_validate(ctx, t);
+		if (!nouveau_texture_validate(ctx, t))
+			return;
+
 		s = &to_nouveau_texture(t)->surfaces[t->BaseLevel];
 
 		if (t->MinFilter != GL_NEAREST &&
diff --git a/src/mesa/drivers/dri/nouveau/nv10_state_tex.c b/src/mesa/drivers/dri/nouveau/nv10_state_tex.c
index e5d4f3d..d732a53 100644
--- a/src/mesa/drivers/dri/nouveau/nv10_state_tex.c
+++ b/src/mesa/drivers/dri/nouveau/nv10_state_tex.c
@@ -90,7 +90,8 @@ nv10_emit_tex_obj(GLcontext *ctx, int emit)
 	s = &to_nouveau_texture(t)->surfaces[t->BaseLevel];
 	ti = t->Image[0][t->BaseLevel];
 
-	nouveau_texture_validate(ctx, t);
+	if (!nouveau_texture_validate(ctx, t))
+		return;
 
 	/* Recompute the texturing registers. */
 	tx_format = nvgl_wrap_mode(t->WrapT) << 28
diff --git a/src/mesa/drivers/dri/nouveau/nv20_state_tex.c b/src/mesa/drivers/dri/nouveau/nv20_state_tex.c
index d01e91f..2bf760d 100644
--- a/src/mesa/drivers/dri/nouveau/nv20_state_tex.c
+++ b/src/mesa/drivers/dri/nouveau/nv20_state_tex.c
@@ -87,7 +87,8 @@ nv20_emit_tex_obj(GLcontext *ctx, int emit)
 	s = &to_nouveau_texture(t)->surfaces[t->BaseLevel];
 	ti = t->Image[0][t->BaseLevel];
 
-	nouveau_texture_validate(ctx, t);
+	if (!nouveau_texture_validate(ctx, t))
+		return;
 
 	/* Recompute the texturing registers. */
 	tx_format = ti->DepthLog2 << 28



More information about the mesa-commit mailing list