nouveau: Fix glTexSubImage on swizzled surfaces on <=NV40
authorLuca Barbieri <luca@luca-barbieri.com>
Wed, 30 Dec 2009 01:54:39 +0000 (02:54 +0100)
committerFrancisco Jerez <currojerez@riseup.net>
Wed, 30 Dec 2009 13:37:19 +0000 (14:37 +0100)
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>
src/gallium/drivers/nv04/nv04_surface_2d.c
src/gallium/drivers/nv04/nv04_transfer.c
src/gallium/drivers/nv10/nv10_transfer.c
src/gallium/drivers/nv20/nv20_transfer.c
src/gallium/drivers/nv30/nv30_transfer.c
src/gallium/drivers/nv40/nv40_transfer.c

index 40b538fd71b8bbc976846bbdb8bdcc2cf1284662..b24a9cee5aec64c963707d7d9586f068e19d3a00 100644 (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);
index 8446073ae8023dd9bc9417e6ae9a07a6223f1c16..2dd2e146a8f30f22e6f0c7184de98b1791c8fcd6 100644 (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
index c664973e90463c8cfaeab56c28f7310980c37192..eb04af9782eed62b06782f956fda3e178fc942b0 100644 (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
index 7b5118863577de37bf425dbd21a8095a6514fd8f..699773e8e6f99146e087dc8a7add07b448c38ec2 100644 (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
index 68047c47ec52f7f64d00d8f22f0a3c786d6147f0..65598991c689c1a242a7c0d4eb3b8efe9ce70a0f 100644 (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
index adfd0356213534ea2a2cbb8ed304f2ee35521fab..791ee6823d332ab3dd9ec36846995b92fa365073 100644 (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