nouveau: Fix glTexSubImage on swizzled surfaces on <=NV40

Currently in nvXX_transfer_new a temporary as large as the surface is created.
If the subrectangle is not the whole texture we would need to read
back the whole texture, but we aren't.
Thus, everything but the subrectangle specified is loaded as garbage.
This can be seen in progs/demos/ray.

This patch fixes the problem by creating a temporary that covers only
the desired subrectangle.

That makes us hit an alignment assert in nv04_surface_2d.c. Fix it
using the point registers instead of manipulating the swizzled surface
offset to account for the destination coordinates (which do not seem
to have a 1024 limit).

Signed-off-by: Francisco Jerez <currojerez@riseup.net>
This commit is contained in:
Luca Barbieri 2009-12-30 02:54:39 +01:00 committed by Francisco Jerez
parent 1677d5c0ae
commit 9656177bc0
6 changed files with 74 additions and 55 deletions

View File

@ -167,20 +167,19 @@ nv04_surface_copy_swizzle(struct nv04_surface_2d *ctx,
for (x = 0; x < w; x += sub_w) {
sub_w = MIN2(sub_w, w - x);
/* Must be 64-byte aligned */
assert(!((dst->offset + nv04_swizzle_bits(dx+x, dy+y, w, h) * util_format_get_blocksize(dst->texture->format)) & 63));
assert(!(dst->offset & 63));
BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_OFFSET, 1);
OUT_RELOCl(chan, dst_bo, dst->offset + nv04_swizzle_bits(dx+x, dy+y, w, h) * util_format_get_blocksize(dst->texture->format),
OUT_RELOCl(chan, dst_bo, dst->offset,
NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 9);
OUT_RING (chan, NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE);
OUT_RING (chan, nv04_scaled_image_format(src->format));
OUT_RING (chan, NV04_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
OUT_RING (chan, 0);
OUT_RING (chan, (x + dx) | ((y + dy) << NV04_SCALED_IMAGE_FROM_MEMORY_CLIP_POINT_Y_SHIFT));
OUT_RING (chan, sub_h << NV04_SCALED_IMAGE_FROM_MEMORY_CLIP_SIZE_H_SHIFT | sub_w);
OUT_RING (chan, 0);
OUT_RING (chan, (x + dx) | ((y + dy) << NV04_SCALED_IMAGE_FROM_MEMORY_OUT_POINT_Y_SHIFT));
OUT_RING (chan, sub_h << NV04_SCALED_IMAGE_FROM_MEMORY_OUT_SIZE_H_SHIFT | sub_w);
OUT_RING (chan, 1 << 20);
OUT_RING (chan, 1 << 20);

View File

@ -16,14 +16,14 @@ struct nv04_transfer {
};
static void
nv04_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
nv04_compatible_transfer_tex(struct pipe_texture *pt, unsigned width, unsigned height,
struct pipe_texture *template)
{
memset(template, 0, sizeof(struct pipe_texture));
template->target = pt->target;
template->format = pt->format;
template->width0 = u_minify(pt->width0, level);
template->height0 = u_minify(pt->height0, level);
template->width0 = width;
template->height0 = height;
template->depth0 = 1;
template->last_level = 0;
template->nr_samples = pt->nr_samples;
@ -71,7 +71,7 @@ nv04_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
tx->direct = false;
nv04_compatible_transfer_tex(pt, level, &tx_tex_template);
nv04_compatible_transfer_tex(pt, w, h, &tx_tex_template);
tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
if (!tx_tex)
@ -80,6 +80,8 @@ nv04_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
return NULL;
}
tx->base.stride = ((struct nv04_miptree*)tx_tex)->level[0].pitch;
tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
face, level, zslice,
pipe_transfer_buffer_flags(&tx->base));
@ -105,8 +107,8 @@ nv04_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
/* TODO: Check if SIFM can un-swizzle */
nvscreen->eng2d->copy(nvscreen->eng2d,
tx->surface, 0, 0,
src, 0, 0,
src->width, src->height);
src, x, y,
w, h);
pipe_surface_reference(&src, NULL);
}
@ -130,9 +132,9 @@ nv04_transfer_del(struct pipe_transfer *ptx)
/* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
nvscreen->eng2d->copy(nvscreen->eng2d,
dst, 0, 0,
dst, tx->base.x, tx->base.y,
tx->surface, 0, 0,
dst->width, dst->height);
tx->base.width, tx->base.height);
pipe_surface_reference(&dst, NULL);
}
@ -151,8 +153,10 @@ nv04_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
void *map = pipe_buffer_map(pscreen, mt->buffer,
pipe_transfer_buffer_flags(ptx));
return map + ns->base.offset +
ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
if(!tx->direct)
return map + ns->base.offset;
else
return map + ns->base.offset + ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
}
static void

View File

@ -16,14 +16,14 @@ struct nv10_transfer {
};
static void
nv10_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
nv10_compatible_transfer_tex(struct pipe_texture *pt, unsigned width, unsigned height,
struct pipe_texture *template)
{
memset(template, 0, sizeof(struct pipe_texture));
template->target = pt->target;
template->format = pt->format;
template->width0 = u_minify(pt->width0, level);
template->height0 = u_minify(pt->height0, level);
template->width0 = width;
template->height0 = height;
template->depth0 = 1;
template->last_level = 0;
template->nr_samples = pt->nr_samples;
@ -71,7 +71,7 @@ nv10_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
tx->direct = false;
nv10_compatible_transfer_tex(pt, level, &tx_tex_template);
nv10_compatible_transfer_tex(pt, w, h, &tx_tex_template);
tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
if (!tx_tex)
@ -80,6 +80,8 @@ nv10_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
return NULL;
}
tx->base.stride = ((struct nv10_miptree*)tx_tex)->level[0].pitch;
tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
face, level, zslice,
pipe_transfer_buffer_flags(&tx->base));
@ -105,8 +107,8 @@ nv10_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
/* TODO: Check if SIFM can un-swizzle */
nvscreen->eng2d->copy(nvscreen->eng2d,
tx->surface, 0, 0,
src, 0, 0,
src->width, src->height);
src, x, y,
w, h);
pipe_surface_reference(&src, NULL);
}
@ -130,9 +132,9 @@ nv10_transfer_del(struct pipe_transfer *ptx)
/* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
nvscreen->eng2d->copy(nvscreen->eng2d,
dst, 0, 0,
dst, tx->base.x, tx->base.y,
tx->surface, 0, 0,
dst->width, dst->height);
tx->base.width, tx->base.height);
pipe_surface_reference(&dst, NULL);
}
@ -151,8 +153,10 @@ nv10_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
void *map = pipe_buffer_map(pscreen, mt->buffer,
pipe_transfer_buffer_flags(ptx));
return map + ns->base.offset +
ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
if(!tx->direct)
return map + ns->base.offset;
else
return map + ns->base.offset + ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
}
static void

View File

@ -16,14 +16,14 @@ struct nv20_transfer {
};
static void
nv20_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
nv20_compatible_transfer_tex(struct pipe_texture *pt, unsigned width, unsigned height,
struct pipe_texture *template)
{
memset(template, 0, sizeof(struct pipe_texture));
template->target = pt->target;
template->format = pt->format;
template->width0 = u_minify(pt->width0, level);
template->height0 = u_minify(pt->height0, level);
template->width0 = width;
template->height0 = height;
template->depth0 = 1;
template->last_level = 0;
template->nr_samples = pt->nr_samples;
@ -71,7 +71,7 @@ nv20_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
tx->direct = false;
nv20_compatible_transfer_tex(pt, level, &tx_tex_template);
nv20_compatible_transfer_tex(pt, w, h, &tx_tex_template);
tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
if (!tx_tex)
@ -80,6 +80,8 @@ nv20_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
return NULL;
}
tx->base.stride = ((struct nv20_miptree*)tx_tex)->level[0].pitch;
tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
face, level, zslice,
pipe_transfer_buffer_flags(&tx->base));
@ -105,8 +107,8 @@ nv20_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
/* TODO: Check if SIFM can un-swizzle */
nvscreen->eng2d->copy(nvscreen->eng2d,
tx->surface, 0, 0,
src, 0, 0,
src->width, src->height);
src, x, y,
w, h);
pipe_surface_reference(&src, NULL);
}
@ -130,9 +132,9 @@ nv20_transfer_del(struct pipe_transfer *ptx)
/* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
nvscreen->eng2d->copy(nvscreen->eng2d,
dst, 0, 0,
dst, tx->base.x, tx->base.y,
tx->surface, 0, 0,
dst->width, dst->height);
tx->base.width, tx->base.height);
pipe_surface_reference(&dst, NULL);
}
@ -151,8 +153,10 @@ nv20_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
void *map = pipe_buffer_map(pscreen, mt->buffer,
pipe_transfer_buffer_flags(ptx));
return map + ns->base.offset +
ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
if(!tx->direct)
return map + ns->base.offset;
else
return map + ns->base.offset + ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
}
static void

View File

@ -16,14 +16,14 @@ struct nv30_transfer {
};
static void
nv30_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
nv30_compatible_transfer_tex(struct pipe_texture *pt, unsigned width, unsigned height,
struct pipe_texture *template)
{
memset(template, 0, sizeof(struct pipe_texture));
template->target = pt->target;
template->format = pt->format;
template->width0 = u_minify(pt->width0, level);
template->height0 = u_minify(pt->height0, level);
template->width0 = width;
template->height0 = height;
template->depth0 = 1;
template->last_level = 0;
template->nr_samples = pt->nr_samples;
@ -71,7 +71,7 @@ nv30_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
tx->direct = false;
nv30_compatible_transfer_tex(pt, level, &tx_tex_template);
nv30_compatible_transfer_tex(pt, w, h, &tx_tex_template);
tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
if (!tx_tex)
@ -80,6 +80,8 @@ nv30_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
return NULL;
}
tx->base.stride = ((struct nv30_miptree*)tx_tex)->level[0].pitch;
tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
0, 0, 0,
pipe_transfer_buffer_flags(&tx->base));
@ -105,8 +107,8 @@ nv30_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
/* TODO: Check if SIFM can un-swizzle */
nvscreen->eng2d->copy(nvscreen->eng2d,
tx->surface, 0, 0,
src, 0, 0,
src->width, src->height);
src, x, y,
w, h);
pipe_surface_reference(&src, NULL);
}
@ -130,9 +132,9 @@ nv30_transfer_del(struct pipe_transfer *ptx)
/* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
nvscreen->eng2d->copy(nvscreen->eng2d,
dst, 0, 0,
dst, tx->base.x, tx->base.y,
tx->surface, 0, 0,
dst->width, dst->height);
tx->base.width, tx->base.height);
pipe_surface_reference(&dst, NULL);
}
@ -151,8 +153,10 @@ nv30_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
void *map = pipe_buffer_map(pscreen, mt->buffer,
pipe_transfer_buffer_flags(ptx));
return map + ns->base.offset +
ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
if(!tx->direct)
return map + ns->base.offset;
else
return map + ns->base.offset + ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
}
static void

View File

@ -16,14 +16,14 @@ struct nv40_transfer {
};
static void
nv40_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
nv40_compatible_transfer_tex(struct pipe_texture *pt, unsigned width, unsigned height,
struct pipe_texture *template)
{
memset(template, 0, sizeof(struct pipe_texture));
template->target = pt->target;
template->format = pt->format;
template->width0 = u_minify(pt->width0, level);
template->height0 = u_minify(pt->height0, level);
template->width0 = width;
template->height0 = height;
template->depth0 = 1;
template->last_level = 0;
template->nr_samples = pt->nr_samples;
@ -71,7 +71,7 @@ nv40_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
tx->direct = false;
nv40_compatible_transfer_tex(pt, level, &tx_tex_template);
nv40_compatible_transfer_tex(pt, w, h, &tx_tex_template);
tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
if (!tx_tex)
@ -80,6 +80,8 @@ nv40_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
return NULL;
}
tx->base.stride = ((struct nv40_miptree*)tx_tex)->level[0].pitch;
tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
0, 0, 0,
pipe_transfer_buffer_flags(&tx->base));
@ -105,8 +107,8 @@ nv40_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
/* TODO: Check if SIFM can un-swizzle */
nvscreen->eng2d->copy(nvscreen->eng2d,
tx->surface, 0, 0,
src, 0, 0,
src->width, src->height);
src, x, y,
w, h);
pipe_surface_reference(&src, NULL);
}
@ -130,9 +132,9 @@ nv40_transfer_del(struct pipe_transfer *ptx)
/* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
nvscreen->eng2d->copy(nvscreen->eng2d,
dst, 0, 0,
dst, tx->base.x, tx->base.y,
tx->surface, 0, 0,
dst->width, dst->height);
tx->base.width, tx->base.height);
pipe_surface_reference(&dst, NULL);
}
@ -151,8 +153,10 @@ nv40_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
void *map = pipe_buffer_map(pscreen, mt->buffer,
pipe_transfer_buffer_flags(ptx));
return map + ns->base.offset +
ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
if(!tx->direct)
return map + ns->base.offset;
else
return map + ns->base.offset + ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
}
static void