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:
parent
1677d5c0ae
commit
9656177bc0
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue