Mesa (master): cell: overhaul cell teximage code

Brian Paul brianp at kemper.freedesktop.org
Wed Feb 25 04:10:23 UTC 2009


Module: Mesa
Branch: master
Commit: 192b7f20ebbe6e5ed7d7c8d8cb25ace019723689
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=192b7f20ebbe6e5ed7d7c8d8cb25ace019723689

Author: Brian Paul <brianp at vmware.com>
Date:   Tue Feb 24 20:58:46 2009 -0700

cell: overhaul cell teximage code

Updated to use the new pipe_transfer functions, etc.
Texturing is working again.  Though there's some bugs in mipmap texturing
but I believe those predate the pipe_transfer changes.

---

 src/gallium/drivers/cell/ppu/cell_context.h    |    6 -
 src/gallium/drivers/cell/ppu/cell_fence.c      |   12 +-
 src/gallium/drivers/cell/ppu/cell_state_emit.c |   18 +-
 src/gallium/drivers/cell/ppu/cell_texture.c    |  332 +++++++-----------------
 src/gallium/drivers/cell/ppu/cell_texture.h    |   17 +-
 5 files changed, 119 insertions(+), 266 deletions(-)

diff --git a/src/gallium/drivers/cell/ppu/cell_context.h b/src/gallium/drivers/cell/ppu/cell_context.h
index ca03dc1..5c3188e 100644
--- a/src/gallium/drivers/cell/ppu/cell_context.h
+++ b/src/gallium/drivers/cell/ppu/cell_context.h
@@ -127,15 +127,9 @@ struct cell_context
    struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS];
    uint num_vertex_elements;
 
-   struct pipe_transfer *cbuf_transfer[PIPE_MAX_COLOR_BUFS];
-   struct pipe_transfer *zsbuf_transfer;
-
    ubyte *cbuf_map[PIPE_MAX_COLOR_BUFS];
    ubyte *zsbuf_map;
 
-   struct pipe_surface *tex_surf;
-   uint *tex_map;
-
    uint dirty;
    uint dirty_textures;  /* bitmask of texture units */
    uint dirty_samplers;  /* bitmask of sampler units */
diff --git a/src/gallium/drivers/cell/ppu/cell_fence.c b/src/gallium/drivers/cell/ppu/cell_fence.c
index 867b5dc..32dbf57 100644
--- a/src/gallium/drivers/cell/ppu/cell_fence.c
+++ b/src/gallium/drivers/cell/ppu/cell_fence.c
@@ -153,16 +153,12 @@ cell_add_fenced_textures(struct cell_context *cell)
    for (i = 0; i < cell->num_textures; i++) {
       struct cell_texture *ct = cell->texture[i];
       if (ct) {
-         uint level;
-         for (level = 0; level < CELL_MAX_TEXTURE_LEVELS; level++) {
-            if (ct->tiled_buffer[level]) {
 #if 0
-               printf("Adding texture %p buffer %p to list\n",
-                      ct, ct->tiled_buffer[level]);
+         printf("Adding texture %p buffer %p to list\n",
+                ct, ct->tiled_buffer[level]);
 #endif
-               cell_add_buffer_to_list(cell, list, ct->tiled_buffer[level]);
-            }
-         }
+         if (ct->buffer)
+            cell_add_buffer_to_list(cell, list, ct->buffer);
       }
    }
 }
diff --git a/src/gallium/drivers/cell/ppu/cell_state_emit.c b/src/gallium/drivers/cell/ppu/cell_state_emit.c
index ff529fe..9479c08 100644
--- a/src/gallium/drivers/cell/ppu/cell_state_emit.c
+++ b/src/gallium/drivers/cell/ppu/cell_state_emit.c
@@ -287,19 +287,23 @@ cell_emit_state(struct cell_context *cell)
       for (i = 0;i < CELL_MAX_SAMPLERS; i++) {
          if (cell->dirty_textures & (1 << i)) {
             STATIC_ASSERT(sizeof(struct cell_command_texture) % 16 == 0);
-            struct cell_command_texture *texture
-               =  (struct cell_command_texture *)cell_batch_alloc16(cell, sizeof(*texture));
+            struct cell_command_texture *texture =
+               (struct cell_command_texture *)
+               cell_batch_alloc16(cell, sizeof(*texture));
+
             texture->opcode[0] = CELL_CMD_STATE_TEXTURE;
             texture->unit = i;
             if (cell->texture[i]) {
+               struct cell_texture *ct = cell->texture[i];
                uint level;
                for (level = 0; level < CELL_MAX_TEXTURE_LEVELS; level++) {
-                  texture->start[level] = cell->texture[i]->tiled_mapped[level];
-                  texture->width[level] = cell->texture[i]->base.width[level];
-                  texture->height[level] = cell->texture[i]->base.height[level];
-                  texture->depth[level] = cell->texture[i]->base.depth[level];
+                  texture->start[level] = (ct->mapped +
+                                           ct->level_offset[level]);
+                  texture->width[level] = ct->base.width[level];
+                  texture->height[level] = ct->base.height[level];
+                  texture->depth[level] = ct->base.depth[level];
                }
-               texture->target = cell->texture[i]->base.target;
+               texture->target = ct->base.target;
             }
             else {
                uint level;
diff --git a/src/gallium/drivers/cell/ppu/cell_texture.c b/src/gallium/drivers/cell/ppu/cell_texture.c
index fa52e2c..7472439 100644
--- a/src/gallium/drivers/cell/ppu/cell_texture.c
+++ b/src/gallium/drivers/cell/ppu/cell_texture.c
@@ -62,7 +62,7 @@ cell_texture_layout(struct cell_texture *ct)
 
    ct->buffer_size = 0;
 
-   for ( level = 0 ; level <= pt->last_level ; level++ ) {
+   for (level = 0; level <= pt->last_level; level++) {
       unsigned size;
       unsigned w_tile, h_tile;
 
@@ -90,7 +90,7 @@ cell_texture_layout(struct cell_texture *ct)
 
       ct->buffer_size += size;
 
-      width  = minify(width);
+      width = minify(width);
       height = minify(height);
       depth = minify(depth);
    }
@@ -131,33 +131,19 @@ cell_texture_release(struct pipe_screen *screen,
    if (!*pt)
       return;
 
-   /*
-   DBG("%s %p refcount will be %d\n",
-       __FUNCTION__, (void *) *pt, (*pt)->refcount - 1);
-   */
    if (--(*pt)->refcount <= 0) {
       /* Delete this texture now.
        * But note that the underlying pipe_buffer may linger...
        */
       struct cell_texture *ct = cell_texture(*pt);
-      uint i;
 
-      /*
-      DBG("%s deleting %p\n", __FUNCTION__, (void *) ct);
-      */
+      if (ct->mapped) {
+         pipe_buffer_unmap(screen, ct->buffer);
+         ct->mapped = NULL;
+      }
 
       pipe_buffer_reference(screen, &ct->buffer, NULL);
 
-      for (i = 0; i < CELL_MAX_TEXTURE_LEVELS; i++) {
-         /* Unreference the tiled image buffer.
-          * It may not actually be deleted until a fence is hit.
-          */
-         if (ct->tiled_buffer[i]) {
-            ct->tiled_mapped[i] = NULL;
-            pipe_buffer_reference(screen, &ct->tiled_buffer[i], NULL);
-         }
-      }
-
       FREE(ct);
    }
    *pt = NULL;
@@ -294,107 +280,6 @@ untwiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
 }
 
 
-/**
- * Convert linear texture image data to tiled format for SPU usage.
- */
-static void
-cell_twiddle_texture(struct pipe_screen *screen,
-                     struct pipe_surface *surface)
-{
-#if 0 // XXX fix me
-   struct cell_texture *ct = cell_texture(surface->texture);
-   const uint level = surface->level;
-   const uint texWidth = ct->base.width[level];
-   const uint texHeight = ct->base.height[level];
-   const uint bufWidth = align(texWidth, TILE_SIZE);
-   const uint bufHeight = align(texHeight, TILE_SIZE);
-   const void *map = screen->surface_map(screen, surface, PIPE_BUFFER_USAGE_CPU_READ);
-   const uint *src = (const uint *) map;
-
-   switch (ct->base.format) {
-   case PIPE_FORMAT_A8R8G8B8_UNORM:
-   case PIPE_FORMAT_B8G8R8A8_UNORM:
-   case PIPE_FORMAT_S8Z24_UNORM:
-      {
-         int numFaces = ct->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
-         int offset = bufWidth * bufHeight * 4 * surface->face;
-         uint *dst;
-
-         if (!ct->tiled_buffer[level]) {
-            /* allocate buffer for tiled data now */
-            struct pipe_winsys *ws = screen->winsys;
-            uint bytes = bufWidth * bufHeight * 4 * numFaces;
-            ct->tiled_buffer[level] =
-               ws->buffer_create(ws, 16, PIPE_BUFFER_USAGE_PIXEL, bytes);
-            /* and map it */
-            ct->tiled_mapped[level] =
-               ws->buffer_map(ws, ct->tiled_buffer[level],
-                              PIPE_BUFFER_USAGE_GPU_READ);
-         }
-         dst = (uint *) ((ubyte *) ct->tiled_mapped[level] + offset);
-
-         twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst,
-                            surface->stride, src);
-      }
-      break;
-   default:
-      printf("Cell: twiddle unsupported texture format %s\n",
-             pf_name(ct->base.format));
-   }
-
-   screen->surface_unmap(screen, surface);
-#endif
-}
-
-
-/**
- * Convert SPU tiled texture image data to linear format for app usage.
- */
-static void
-cell_untwiddle_texture(struct pipe_screen *screen,
-                     struct pipe_surface *surface)
-{
-#if 0 // XXX fix me
-   struct cell_texture *ct = cell_texture(surface->texture);
-   const uint level = surface->level;
-   const uint texWidth = ct->base.width[level];
-   const uint texHeight = ct->base.height[level];
-   const void *map = screen->surface_map(screen, surface, PIPE_BUFFER_USAGE_CPU_READ);
-   const uint *src = (const uint *) ((const ubyte *) map + surface->offset);
-
-   switch (ct->base.format) {
-   case PIPE_FORMAT_A8R8G8B8_UNORM:
-   case PIPE_FORMAT_B8G8R8A8_UNORM:
-   case PIPE_FORMAT_S8Z24_UNORM:
-      {
-         int numFaces = ct->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
-         int offset = surface->stride * texHeight * 4 * surface->face;
-         uint *dst;
-
-         if (!ct->untiled_data[level]) {
-            ct->untiled_data[level] =
-               align_malloc(surface->stride * texHeight * 4 * numFaces, 16);
-         }
-
-         dst = (uint *) ((ubyte *) ct->untiled_data[level] + offset);
-
-         untwiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst,
-                              surface->stride, src);
-      }
-      break;
-   default:
-      {
-         ct->untiled_data[level] = NULL;
-         printf("Cell: untwiddle unsupported texture format %s\n",
-                pf_name(ct->base.format));
-      }
-   }
-
-   screen->surface_unmap(screen, surface);
-#endif
-}
-
-
 static struct pipe_surface *
 cell_get_tex_surface(struct pipe_screen *screen,
                      struct pipe_texture *pt,
@@ -409,38 +294,25 @@ cell_get_tex_surface(struct pipe_screen *screen,
       ps->refcount = 1;
       pipe_texture_reference(&ps->texture, pt);
       ps->format = pt->format;
-      //ps->block = pt->block;
       ps->width = pt->width[level];
       ps->height = pt->height[level];
-      //ps->nblocksx = pt->nblocksx[level];
-      //ps->nblocksy = pt->nblocksy[level];
-      //ps->stride = ct->stride[level];
       ps->offset = ct->level_offset[level];
-      ps->usage = usage;
-
       /* XXX may need to override usage flags (see sp_texture.c) */
-
-      pipe_texture_reference(&ps->texture, pt); 
+      ps->usage = usage;
       ps->face = face;
       ps->level = level;
       ps->zslice = zslice;
 
-      if (pt->target == PIPE_TEXTURE_CUBE || pt->target == PIPE_TEXTURE_3D) {
-#if 0 // XXX fix me
-         ps->offset += ((pt->target == PIPE_TEXTURE_CUBE) ? face : zslice) *
-            ps->nblocksy *
-            ps->stride;
-#endif
+      if (pt->target == PIPE_TEXTURE_CUBE) {
+         ps->offset += face * pt->nblocksy[level] * ct->stride[level];
+      }
+      else if (pt->target == PIPE_TEXTURE_3D) {
+         ps->offset += zslice * pt->nblocksy[level] * ct->stride[level];
       }
       else {
          assert(face == 0);
          assert(zslice == 0);
       }
-
-      if (ps->usage & PIPE_BUFFER_USAGE_CPU_READ) {
-         /* convert from tiled to linear layout */
-         cell_untwiddle_texture(screen, ps);
-      }
    }
    return ps;
 }
@@ -450,24 +322,8 @@ static void
 cell_tex_surface_release(struct pipe_screen *screen, 
                          struct pipe_surface **s)
 {
-   struct cell_texture *ct = cell_texture((*s)->texture);
-   const uint level = (*s)->level;
    struct pipe_surface *surf = *s;
 
-   if ((surf->usage & PIPE_BUFFER_USAGE_CPU_READ) && (ct->untiled_data[level]))
-   {
-      align_free(ct->untiled_data[level]);
-      ct->untiled_data[level] = NULL;
-   }
-
-   if ((ct->base.tex_usage & PIPE_TEXTURE_USAGE_SAMPLER) &&
-       (surf->usage & PIPE_BUFFER_USAGE_CPU_WRITE)) {
-      /* convert from linear to tiled layout */
-      cell_twiddle_texture(screen, surf);
-   }
-
-   /* XXX if done rendering to teximage, re-tile */
-
    if (--surf->refcount == 0) {
       pipe_texture_reference(&surf->texture, NULL);
       FREE(surf);
@@ -476,6 +332,11 @@ cell_tex_surface_release(struct pipe_screen *screen,
 }
 
 
+/**
+ * Create new pipe_transfer object.
+ * This is used by the user to put tex data into a texture (and get it
+ * back out for glGetTexImage).
+ */
 static struct pipe_transfer *
 cell_get_tex_transfer(struct pipe_screen *screen,
                       struct pipe_texture *texture,
@@ -485,14 +346,13 @@ cell_get_tex_transfer(struct pipe_screen *screen,
 {
    struct cell_texture *ct = cell_texture(texture);
    struct cell_transfer *ctrans;
-   struct pipe_transfer *pt;
 
    assert(texture);
    assert(level <= texture->last_level);
 
    ctrans = CALLOC_STRUCT(cell_transfer);
-   pt = &ctrans->base;
    if (ctrans) {
+      struct pipe_transfer *pt = &ctrans->base;
       pt->refcount = 1;
       pipe_texture_reference(&pt->texture, texture);
       pt->format = texture->format;
@@ -504,23 +364,26 @@ cell_get_tex_transfer(struct pipe_screen *screen,
       pt->nblocksx = texture->nblocksx[level];
       pt->nblocksy = texture->nblocksy[level];
       pt->stride = ct->stride[level];
-      ctrans->offset = ct->level_offset[level];
       pt->usage = usage;
       pt->face = face;
       pt->level = level;
       pt->zslice = zslice;
 
-      if (texture->target == PIPE_TEXTURE_CUBE ||
-          texture->target == PIPE_TEXTURE_3D) {
-         ctrans->offset += ((texture->target == PIPE_TEXTURE_CUBE) ? face :
-                         zslice) * pt->nblocksy * pt->stride;
+      ctrans->offset = ct->level_offset[level];
+
+      if (texture->target == PIPE_TEXTURE_CUBE) {
+         ctrans->offset += face * pt->nblocksy * pt->stride;
+      }
+      else if (texture->target == PIPE_TEXTURE_3D) {
+         ctrans->offset += zslice * pt->nblocksy * pt->stride;
       }
       else {
          assert(face == 0);
          assert(zslice == 0);
       }
+      return pt;
    }
-   return pt;
+   return NULL;
 }
 
 
@@ -542,16 +405,23 @@ cell_tex_transfer_release(struct pipe_screen *screen,
 }
 
 
+/**
+ * Return pointer to texture image data in linear layout.
+ */
 static void *
-cell_transfer_map( struct pipe_screen *screen,
-                       struct pipe_transfer *transfer )
+cell_transfer_map(struct pipe_screen *screen, struct pipe_transfer *transfer)
 {
-   ubyte *map;
-   struct cell_texture *spt;
-   unsigned flags = 0;
+   struct cell_transfer *ctrans = cell_transfer(transfer);
+   struct pipe_texture *pt = transfer->texture;
+   struct cell_texture *ct = cell_texture(pt);
+   const uint level = ctrans->base.level;
+   const uint texWidth = pt->width[level];
+   const uint texHeight = pt->height[level];
+   const uint stride = ct->stride[level];
+   unsigned flags = 0x0;
+   unsigned size;
 
    assert(transfer->texture);
-   spt = cell_texture(transfer->texture);
 
    if (transfer->usage != PIPE_TRANSFER_READ) {
       flags |= PIPE_BUFFER_USAGE_CPU_WRITE;
@@ -561,89 +431,82 @@ cell_transfer_map( struct pipe_screen *screen,
       flags |= PIPE_BUFFER_USAGE_CPU_READ;
    }
 
-   map = pipe_buffer_map(screen, spt->buffer, flags);
-   if (map == NULL)
-      return NULL;
+   if (!ct->mapped) {
+      /* map now */
+      ct->mapped = pipe_buffer_map(screen, ct->buffer, flags);
+   }
 
-   /* May want to different things here depending on read/write nature
-    * of the map:
+   /*
+    * Create a buffer of ordinary memory for the linear texture.
+    * This is the memory that the user will read/write.
     */
-   if (transfer->texture && transfer->usage != PIPE_TRANSFER_READ) 
-   {
-      /* Do something to notify sharing contexts of a texture change.
-       * In cell, that would mean flushing the texture cache.
-       */
-#if 00
-      cell_screen(screen)->timestamp++;
-#endif
+   size = pt->nblocksx[level] * pt->nblocksy[level] * pt->block.size;
+
+   ctrans->map = align_malloc(size, 16);
+   if (!ctrans->map)
+      return NULL; /* out of memory */
+
+   if (transfer->usage & PIPE_TRANSFER_READ) {
+      /* need to untwiddle the texture to make a linear version */
+      const uint bpp = pf_get_size(ct->base.format);
+      if (bpp == 4) {
+         const uint *src = (uint *) (ct->mapped + ctrans->offset);
+         uint *dst = ctrans->map;
+         untwiddle_image_uint(texWidth, texHeight, TILE_SIZE,
+                              dst, stride, src);
+      }
+      else {
+         // xxx fix
+      }
    }
-   
-   return map + cell_transfer(transfer)->offset +
-      transfer->y / transfer->block.height * transfer->stride +
-      transfer->x / transfer->block.width * transfer->block.size;
+
+   return ctrans->map;
 }
 
 
+/**
+ * Called when user is done reading/writing texture data.
+ * If new data was written, this is where we convert the linear data
+ * to tiled data.
+ */
 static void
 cell_transfer_unmap(struct pipe_screen *screen,
-                       struct pipe_transfer *transfer)
+                    struct pipe_transfer *transfer)
 {
-   struct cell_texture *spt;
-
-   assert(transfer->texture);
-   spt = cell_texture(transfer->texture);
-
-   pipe_buffer_unmap( screen, spt->buffer );
-}
-
-
-static void *
-cell_surface_map(struct pipe_screen *screen,
-                 struct pipe_surface *surface,
-                 unsigned flags)
-{
-   ubyte *map;
-   struct cell_texture *ct = cell_texture(surface->texture);
-   const uint level = surface->level;
-
-   assert(ct);
-
-#if 0
-   if (flags & ~surface->usage) {
-      assert(0);
-      return NULL;
+   struct cell_transfer *ctrans = cell_transfer(transfer);
+   struct pipe_texture *pt = transfer->texture;
+   struct cell_texture *ct = cell_texture(pt);
+   const uint level = ctrans->base.level;
+   const uint texWidth = pt->width[level];
+   const uint texHeight = pt->height[level];
+   const uint stride = ct->stride[level];
+
+   if (!ct->mapped) {
+      /* map now */
+      ct->mapped = pipe_buffer_map(screen, ct->buffer,
+                                   PIPE_BUFFER_USAGE_CPU_READ);
    }
-#endif
 
-   map = pipe_buffer_map( screen, ct->buffer, flags );
-   if (map == NULL) {
-      return NULL;
-   }
-   else {
-      if ((surface->usage & PIPE_BUFFER_USAGE_CPU_READ) &&
-          (ct->untiled_data[level])) {
-         return (void *) ((ubyte *) ct->untiled_data[level] + surface->offset);
+   if (transfer->usage & PIPE_TRANSFER_WRITE) {
+      /* The user wrote new texture data into the mapped buffer.
+       * We need to convert the new linear data into the twiddled/tiled format.
+       */
+      const uint bpp = pf_get_size(ct->base.format);
+      if (bpp == 4) {
+         const uint *src = ctrans->map;
+         uint *dst = (uint *) (ct->mapped + ctrans->offset);
+         twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst, stride, src);
       }
       else {
-         return (void *) (map + surface->offset);
+         // xxx fix
       }
    }
-}
-
-
-static void
-cell_surface_unmap(struct pipe_screen *screen,
-                   struct pipe_surface *surface)
-{
-   struct cell_texture *ct = cell_texture(surface->texture);
-
-   assert(ct);
 
-   pipe_buffer_unmap( screen, ct->buffer );
+   align_free(ctrans->map);
+   ctrans->map = NULL;
 }
 
 
-
 void
 cell_init_screen_texture_funcs(struct pipe_screen *screen)
 {
@@ -655,6 +518,7 @@ cell_init_screen_texture_funcs(struct pipe_screen *screen)
 
    screen->get_tex_transfer = cell_get_tex_transfer;
    screen->tex_transfer_release = cell_tex_transfer_release;
+
    screen->transfer_map = cell_transfer_map;
    screen->transfer_unmap = cell_transfer_unmap;
 }
diff --git a/src/gallium/drivers/cell/ppu/cell_texture.h b/src/gallium/drivers/cell/ppu/cell_texture.h
index fc6486a..3ffc0bf 100644
--- a/src/gallium/drivers/cell/ppu/cell_texture.h
+++ b/src/gallium/drivers/cell/ppu/cell_texture.h
@@ -43,20 +43,14 @@ struct cell_texture
    unsigned long level_offset[CELL_MAX_TEXTURE_LEVELS];
    unsigned long stride[CELL_MAX_TEXTURE_LEVELS];
 
-   /* The data is held here:
-    */
+   /** The tiled texture data is held in this buffer */
    struct pipe_buffer *buffer;
    unsigned long buffer_size;
 
-   /** Texture data in tiled layout is held here */
-   struct pipe_buffer *tiled_buffer[CELL_MAX_TEXTURE_LEVELS];
-   /** Mapped, tiled texture data */
-   void *tiled_mapped[CELL_MAX_TEXTURE_LEVELS];
-
-   struct pipe_transfer *transfer;
-
-   /** The original, linear texture data */
-   void *untiled_data[CELL_MAX_TEXTURE_LEVELS];
+   /** The buffer above, mapped.  This is the memory from which the
+    * SPUs will fetch texels.  This texture data is in the tiled layout.
+    */
+   ubyte *mapped;
 };
 
 
@@ -65,6 +59,7 @@ struct cell_transfer
    struct pipe_transfer base;
 
    unsigned long offset;
+   void *map;
 };
 
 




More information about the mesa-commit mailing list