diff options
-rw-r--r-- | src/mesa/drivers/dri/nouveau/nouveau_state.c | 4 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau/nouveau_texture.c | 284 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau/nouveau_texture.h | 5 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau/nv04_state_tex.c | 4 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau/nv10_state_tex.c | 3 | ||||
-rw-r--r-- | 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 d7278221754..5d593ed4dd0 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 ab6e93cceb4..32603ab66d6 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 695c0897b59..75d8190e882 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 99ea310c65f..684a19e703f 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 e5d4f3d18d8..d732a5335bc 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 d01e91f8ee1..2bf760d3b08 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 |