|
|
|
@@ -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)
|
|
|
|
|
{
|
|
|
|
|