dri/nouveau: Try to validate textures earlier.
authorFrancisco Jerez <currojerez@riseup.net>
Mon, 22 Feb 2010 01:03:42 +0000 (02:03 +0100)
committerFrancisco Jerez <currojerez@riseup.net>
Thu, 25 Feb 2010 17:37:36 +0000 (18:37 +0100)
src/mesa/drivers/dri/nouveau/nouveau_state.c
src/mesa/drivers/dri/nouveau/nouveau_texture.c
src/mesa/drivers/dri/nouveau/nouveau_texture.h
src/mesa/drivers/dri/nouveau/nv04_state_tex.c
src/mesa/drivers/dri/nouveau/nv10_state_tex.c
src/mesa/drivers/dri/nouveau/nv20_state_tex.c

index d7278221754297d1a21ebf00807d65063426ea38..5d593ed4dd0e14429a1d97b0616f87af716c43e1 100644 (file)
@@ -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;
        }
index ab6e93cceb41a1d1921902ecb75fedc41324ed32..32603ab66d66e5fb30e4b8726c18e23c0f3fe081 100644 (file)
@@ -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)
 {
index 695c0897b590d03c5ce9f4080901829a45c7ce0b..75d8190e8828b66ad899195dc9834381869a8458 100644 (file)
@@ -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
index 99ea310c65fc9efb329414407eeafb4bbc49473a..684a19e703f580b672301cb2ad60265b2abd9cde 100644 (file)
@@ -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 &&
index e5d4f3d18d8853e109af389e6e063d8cbb668406..d732a5335bc3a8c9eaa7fd2b7facf011da5d9599 100644 (file)
@@ -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
index d01e91f8ee19da1a97c450c31e9fa9237d3e279c..2bf760d3b08bf0fab5acd50823896e7e3fa7b7b8 100644 (file)
@@ -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