nouveau: swizzle a single row or column, doing it one pixel at a time
authorPatrice Mandin <patmandin@gmail.com>
Mon, 27 Jul 2009 08:57:53 +0000 (10:57 +0200)
committerPatrice Mandin <patmandin@gmail.com>
Mon, 27 Jul 2009 08:58:11 +0000 (10:58 +0200)
src/gallium/drivers/nv04/nv04_surface_2d.c

index aba40cfaff7565f53fca99f6973d36d05bcb0c19..bbbcb54c467d7951050774264876e0a222ce88d6 100644 (file)
@@ -209,6 +209,43 @@ nv04_surface_copy_m2mf(struct nv04_surface_2d *ctx,
        return 0;
 }
 
+static int
+nv04_surface_copy_m2mf_swizzle(struct nv04_surface_2d *ctx,
+                              struct pipe_surface *dst, int dx, int dy,
+                              struct pipe_surface *src, int sx, int sy)
+{
+       struct nouveau_channel *chan = ctx->m2mf->channel;
+       struct nouveau_grobj *m2mf = ctx->m2mf;
+       struct nouveau_bo *src_bo = nouveau_bo(ctx->buf(src));
+       struct nouveau_bo *dst_bo = nouveau_bo(ctx->buf(dst));
+       unsigned src_pitch = ((struct nv04_surface *)src)->pitch;
+       unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch;
+       unsigned dst_offset = dst->offset + nv04_swizzle_bits(dx, dy) *
+                             dst->texture->block.size;
+       unsigned src_offset = src->offset + sy * src_pitch +
+                             sx * src->texture->block.size;
+
+       BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
+       OUT_RELOCo(chan, src_bo,
+                  NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+       OUT_RELOCo(chan, dst_bo,
+                  NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+
+       BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+       OUT_RELOCl(chan, src_bo, src_offset,
+                  NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD);
+       OUT_RELOCl(chan, dst_bo, dst_offset,
+                  NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR);
+       OUT_RING  (chan, src_pitch);
+       OUT_RING  (chan, dst_pitch);
+       OUT_RING  (chan, 1 * src->texture->block.size);
+       OUT_RING  (chan, 1);
+       OUT_RING  (chan, 0x0101);
+       OUT_RING  (chan, 0);
+
+       return 0;
+}
+
 static int
 nv04_surface_copy_blit(struct nv04_surface_2d *ctx, struct pipe_surface *dst,
                       int dx, int dy, struct pipe_surface *src, int sx, int sy,
@@ -258,42 +295,57 @@ nv04_surface_copy(struct nv04_surface_2d *ctx, struct pipe_surface *dst,
        assert(src->format == dst->format);
 
        /* Setup transfer to swizzle the texture to vram if needed */
-       if (src_linear && !dst_linear && w > 1 && h > 1) {
-               int potWidth = 1<<log2i(w);
-               int potHeight = 1<<log2i(h);
-               int remainWidth = w-potWidth;
-               int remainHeight = h-potHeight;
-               int squareDim = (potWidth>potHeight ? potHeight : potWidth);
+       if (src_linear && !dst_linear) {
                int x,y;
 
-               /* top left is always POT, but we can only swizzle squares */
-               for (y=0; y<potHeight; y+=squareDim) {
-                       for (x=0; x<potWidth; x+= squareDim) {
-                               nv04_surface_copy_swizzle(ctx, dst, dx+x, dy+y,
-                                                         src, sx+x, sy+y,
-                                                         squareDim, squareDim);
+               if ((w>1) && (h>1)) {
+                       int potWidth = 1<<log2i(w);
+                       int potHeight = 1<<log2i(h);
+                       int remainWidth = w-potWidth;
+                       int remainHeight = h-potHeight;
+                       int squareDim = (potWidth>potHeight ? potHeight : potWidth);
+
+                       /* top left is always POT, but we can only swizzle squares */
+                       for (y=0; y<potHeight; y+=squareDim) {
+                               for (x=0; x<potWidth; x+= squareDim) {
+                                       nv04_surface_copy_swizzle(ctx, dst, dx+x, dy+y,
+                                                                 src, sx+x, sy+y,
+                                                                 squareDim, squareDim);
+                               }
                        }
-               }
 
-               /* top right */
-               if (remainWidth>0) {
+                       /* top right */
+                       if (remainWidth>0) {
                        nv04_surface_copy(ctx, dst, dx+potWidth, dy,
-                                         src, sx+potWidth, sy,
-                                         remainWidth, potHeight);
-               }
+                                                 src, sx+potWidth, sy,
+                                                 remainWidth, potHeight);
+                       }
 
-               /* bottom left */
-               if (remainHeight>0) {
-                       nv04_surface_copy(ctx, dst, dx, dy+potHeight,
+                       /* bottom left */
+                       if (remainHeight>0) {
+                               nv04_surface_copy(ctx, dst, dx, dy+potHeight,
                                          src, sx, sy+potHeight,
-                                         potWidth, remainHeight);
-               }
+                                                 potWidth, remainHeight);
+                       }
 
-               /* bottom right */
-               if ((remainWidth>0) && (remainHeight>0)) {
-                       nv04_surface_copy(ctx, dst, dx+potWidth, dy+potHeight,
-                                         src, sx+potWidth, sy+potHeight,
-                                         remainWidth, remainHeight);
+                       /* bottom right */
+                       if ((remainWidth>0) && (remainHeight>0)) {
+                               nv04_surface_copy(ctx, dst, dx+potWidth, dy+potHeight,
+                                                 src, sx+potWidth, sy+potHeight,
+                                                 remainWidth, remainHeight);
+                       }
+               } else if (w==1) {
+                       /* We have a column to copy to a swizzled texture */
+                       for (y=0; y<h; y++) {
+                               nv04_surface_copy_m2mf_swizzle(ctx, dst, dx, dy+y,
+                                                              src, sx, sy+y);
+                       }
+               } else if (h==1) {
+                       /* We have a row to copy to a swizzled texture */
+                       for (x=0; x<w; x++) {
+                               nv04_surface_copy_m2mf_swizzle(ctx, dst, dx+x, dy,
+                                                              src, sx+x, sy);
+                       }
                }
 
                return;