dri/nouveau: Try to validate textures earlier.

This commit is contained in:
Francisco Jerez 2010-02-22 02:03:42 +01:00
parent 44602bb23c
commit 323e6bbb05
6 changed files with 189 additions and 110 deletions

View 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;
}

View 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;
if (pixels) {
/* Store the pixel data. */
nouveau_teximage_map(ctx, ti);
/* 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);
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);
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);
}
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)
{

View 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

View 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 &&

View 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

View 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