Mesa (master): llvmpipe: fix rendering to 3D textures

Brian Paul brianp at kemper.freedesktop.org
Mon Apr 19 23:08:49 UTC 2010


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

Author: Brian Paul <brianp at vmware.com>
Date:   Mon Apr 19 16:42:47 2010 -0600

llvmpipe: fix rendering to 3D textures

Treat cube faces and 3D texture slices in the same manner (they're layed
out out continuously in memory).  Additional clean-ups and improvements
coming.

---

 src/gallium/drivers/llvmpipe/lp_rast.c    |    6 +-
 src/gallium/drivers/llvmpipe/lp_setup.c   |    4 +-
 src/gallium/drivers/llvmpipe/lp_texture.c |  168 +++++++++++++++++------------
 src/gallium/drivers/llvmpipe/lp_texture.h |   12 ++-
 4 files changed, 114 insertions(+), 76 deletions(-)

diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c
index 4574f41..527103c 100644
--- a/src/gallium/drivers/llvmpipe/lp_rast.c
+++ b/src/gallium/drivers/llvmpipe/lp_rast.c
@@ -162,7 +162,7 @@ lp_rast_tile_begin(struct lp_rasterizer_task *task,
       assert(cbuf);
       lpt = llvmpipe_resource(cbuf->texture);
       task->color_tiles[buf] = llvmpipe_get_texture_tile(lpt,
-                                                         cbuf->face,
+                                                         cbuf->face + cbuf->zslice,
                                                          cbuf->level,
                                                          usage,
                                                          x, y);
@@ -184,7 +184,7 @@ lp_rast_tile_begin(struct lp_rasterizer_task *task,
           * and update the tile's layout info.
           */
          (void) llvmpipe_get_texture_tile(lpt,
-                                          zsbuf->face,
+                                          zsbuf->face + zsbuf->zslice,
                                           zsbuf->level,
                                           usage,
                                           x, y);
@@ -344,7 +344,7 @@ lp_rast_load_color(struct lp_rasterizer_task *task,
       assert(cbuf);
       lpt = llvmpipe_texture(cbuf->texture);
       task->color_tiles[buf] = llvmpipe_get_texture_tile(lpt,
-                                                         cbuf->face,
+                                                         cbuf->face + cbuf->zslice,
                                                          cbuf->level,
                                                          usage,
                                                          task->x, task->y);
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
index ffbc7fc..065b4b6 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup.c
@@ -531,8 +531,8 @@ lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
                   (ubyte *) lp_tex->data + lp_tex->level_offset[j];
 #else
                jit_tex->data[j] =
-                  llvmpipe_get_texture_image(lp_tex, 0, j, LP_TEX_USAGE_READ,
-                                             LP_TEX_LAYOUT_LINEAR);
+                  llvmpipe_get_texture_image_all(lp_tex, j, LP_TEX_USAGE_READ,
+                                                 LP_TEX_LAYOUT_LINEAR);
 #endif
                jit_tex->row_stride[j] = lp_tex->stride[j];
             }
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
index fd2d5b0..5da67ba 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.c
+++ b/src/gallium/drivers/llvmpipe/lp_texture.c
@@ -72,16 +72,16 @@ resource_is_texture(const struct pipe_resource *resource)
  * The number of elements is width_in_tiles * height_in_tiles.
  */
 static enum lp_texture_layout *
-alloc_layout_array(unsigned width, unsigned height)
+alloc_layout_array(unsigned num_slices, unsigned width, unsigned height)
 {
    const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE;
    const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE;
 
-   assert(tx * ty > 0);
+   assert(num_slices * tx * ty > 0);
    assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */
 
    return (enum lp_texture_layout *)
-      calloc(tx * ty, sizeof(enum lp_texture_layout));
+      calloc(num_slices * tx * ty, sizeof(enum lp_texture_layout));
 }
 
 
@@ -98,13 +98,22 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
    unsigned level;
    unsigned width = pt->width0;
    unsigned height = pt->height0;
+   unsigned depth = pt->depth0;
 
    assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
    assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
 
    for (level = 0; level <= pt->last_level; level++) {
-      const unsigned num_faces = lpr->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
-      unsigned nblocksx, face;
+      const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
+      const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
+      unsigned nblocksx, num_slices;
+
+      if (lpr->base.target == PIPE_TEXTURE_CUBE)
+         num_slices = 6;
+      else if (lpr->base.target == PIPE_TEXTURE_3D)
+         num_slices = depth;
+      else
+         num_slices = 1;
 
       /* Allocate storage for whole quads. This is particularly important
        * for depth surfaces, which are currently stored in a swizzled format.
@@ -114,14 +123,14 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
       lpr->stride[level] =
          align(nblocksx * util_format_get_blocksize(pt->format), 16);
 
-      lpr->tiles_per_row[level] = align(width, TILE_SIZE) / TILE_SIZE;
-
-      for (face = 0; face < num_faces; face++) {
-         lpr->layout[level][face] = alloc_layout_array(width, height);
-      }
+      lpr->tiles_per_row[level] = width_t;
+      lpr->tiles_per_image[level] = width_t * height_t;
+      lpr->num_slices_faces[level] = num_slices;
+      lpr->layout[level] = alloc_layout_array(num_slices, width, height);
 
       width = u_minify(width, 1);
       height = u_minify(height, 1);
+      depth = u_minify(depth, 1);
    }
 
    return TRUE;
@@ -138,12 +147,16 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
    /* Round up the surface size to a multiple of the tile size to
     * avoid tile clipping.
     */
-   unsigned width = align(lpr->base.width0, TILE_SIZE);
-   unsigned height = align(lpr->base.height0, TILE_SIZE);
+   const unsigned width = align(lpr->base.width0, TILE_SIZE);
+   const unsigned height = align(lpr->base.height0, TILE_SIZE);
+   const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
+   const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
 
-   lpr->tiles_per_row[0] = align(width, TILE_SIZE) / TILE_SIZE;
+   lpr->tiles_per_row[0] = width_t;
+   lpr->tiles_per_image[0] = width_t * height_t;
+   lpr->num_slices_faces[0] = 1;
 
-   lpr->layout[0][0] = alloc_layout_array(width, height);
+   lpr->layout[0] = alloc_layout_array(1, width, height);
 
    lpr->dt = winsys->displaytarget_create(winsys,
                                           lpr->base.bind,
@@ -178,14 +191,14 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
       /* displayable surface */
       if (!llvmpipe_displaytarget_layout(screen, lpr))
          goto fail;
-      assert(lpr->layout[0][0][0] == LP_TEX_LAYOUT_NONE);
+      assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
    }
    else if (lpr->base.bind & (PIPE_BIND_SAMPLER_VIEW |
                               PIPE_BIND_DEPTH_STENCIL)) {
       /* texture map */
       if (!llvmpipe_texture_layout(screen, lpr))
          goto fail;
-      assert(lpr->layout[0][0][0] == LP_TEX_LAYOUT_NONE);
+      assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
    }
    else {
       /* other data (vertex buffer, const buffer, etc) */
@@ -201,7 +214,7 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
    }
 
    if (resource_is_texture(&lpr->base)) {
-      assert(lpr->layout[0][0]);
+      assert(lpr->layout[0]);
    }
 
    lpr->id = id_counter++;
@@ -228,8 +241,7 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen,
    }
    else if (resource_is_texture(pt)) {
       /* regular texture */
-      const uint num_faces = pt->target == PIPE_TEXTURE_CUBE ? 6 : 1;
-      uint level, face;
+      uint level;
 
       /* free linear image data */
       for (level = 0; level < Elements(lpr->linear); level++) {
@@ -249,10 +261,8 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen,
 
       /* free layout flag arrays */
       for (level = 0; level < Elements(lpr->tiled); level++) {
-         for (face = 0; face < num_faces; face++) {
-            free(lpr->layout[level][face]);
-            lpr->layout[level][face] = NULL;
-         }
+         free(lpr->layout[level]);
+         lpr->layout[level] = NULL;
       }
    }
    else if (!lpr->userBuffer) {
@@ -312,36 +322,24 @@ llvmpipe_resource_map(struct pipe_resource *resource,
       /* install this linear image in texture data structure */
       lpr->linear[level].data = map;
 
-      map = llvmpipe_get_texture_image(lpr, face, level, tex_usage, layout);
+      map = llvmpipe_get_texture_image(lpr, face + zslice, level,
+                                       tex_usage, layout);
       assert(map);
 
       return map;
    }
    else if (resource_is_texture(resource)) {
       /* regular texture */
-      const unsigned tex_height = u_minify(resource->height0, level);
-      const unsigned nblocksy =
-         util_format_get_nblocksy(resource->format, tex_height);
-      const unsigned stride = lpr->stride[level];
-      unsigned offset = 0;
-
-      if (resource->target == PIPE_TEXTURE_CUBE) {
-         /* XXX incorrect
-         offset = face * nblocksy * stride;
-         */
-      }
-      else if (resource->target == PIPE_TEXTURE_3D) {
-         offset = zslice * nblocksy * stride;
-      }
-      else {
+      if (resource->target != PIPE_TEXTURE_CUBE) {
          assert(face == 0);
+      }
+      if (resource->target != PIPE_TEXTURE_3D) {
          assert(zslice == 0);
-         offset = 0;
       }
 
-      map = llvmpipe_get_texture_image(lpr, face, level, tex_usage, layout);
+      map = llvmpipe_get_texture_image(lpr, face + zslice, level,
+                                       tex_usage, layout);
       assert(map);
-      map += offset;
       return map;
    }
    else {
@@ -371,7 +369,7 @@ llvmpipe_resource_unmap(struct pipe_resource *resource,
       assert(zslice == 0);
 
       /* make sure linear image is up to date */
-      (void) llvmpipe_get_texture_image(lpr, 0, 0,
+      (void) llvmpipe_get_texture_image(lpr, face + zslice, level,
                                         LP_TEX_USAGE_READ,
                                         LP_TEX_LAYOUT_LINEAR);
 
@@ -659,7 +657,7 @@ llvmpipe_user_buffer_create(struct pipe_screen *screen,
 
 /**
  * Compute size (in bytes) need to store a texture image / mipmap level,
- * for just one cube face.
+ * for just one cube face or one 3D texture slice
  */
 static unsigned
 tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level,
@@ -667,7 +665,6 @@ tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level,
 {
    const unsigned width = u_minify(lpr->base.width0, level);
    const unsigned height = u_minify(lpr->base.height0, level);
-   const unsigned depth = u_minify(lpr->base.depth0, level);
 
    assert(layout == LP_TEX_LAYOUT_TILED ||
           layout == LP_TEX_LAYOUT_LINEAR);
@@ -680,18 +677,14 @@ tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level,
          util_format_get_nblocksy(format, align(height, TILE_SIZE));
       const unsigned nblocksx =
          util_format_get_nblocksx(format, align(width, TILE_SIZE));
-      const unsigned buffer_size =
-         block_size * nblocksy * nblocksx *
-         (lpr->base.target == PIPE_TEXTURE_3D ? depth : 1);
+      const unsigned buffer_size = block_size * nblocksy * nblocksx;
       return buffer_size;
    }
    else {
       const enum pipe_format format = lpr->base.format;
       const unsigned nblocksy =
          util_format_get_nblocksy(format, align(height, TILE_SIZE));
-      const unsigned buffer_size =
-         nblocksy * lpr->stride[level] *
-         (lpr->base.target == PIPE_TEXTURE_3D ? depth : 1);
+      const unsigned buffer_size = nblocksy * lpr->stride[level];
       return buffer_size;
    }
 }
@@ -699,15 +692,14 @@ tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level,
 
 /**
  * Compute size (in bytes) need to store a texture image / mipmap level,
- * including all cube faces.
+ * including all cube faces or 3D image slices
  */
 static unsigned
 tex_image_size(const struct llvmpipe_resource *lpr, unsigned level,
                enum lp_texture_layout layout)
 {
    const unsigned buf_size = tex_image_face_size(lpr, level, layout);
-   const unsigned num_faces = lpr->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
-   return buf_size * num_faces;
+   return buf_size * lpr->num_slices_faces[level];
 }
 
 
@@ -806,8 +798,9 @@ llvmpipe_get_texture_tile_layout(const struct llvmpipe_resource *lpr,
    uint i;
    assert(resource_is_texture(&lpr->base));
    assert(x < lpr->tiles_per_row[level]);
-   i = y * lpr->tiles_per_row[level] + x;
-   return lpr->layout[level][face_slice][i];
+   i = face_slice * lpr->tiles_per_image[level]
+      + y * lpr->tiles_per_row[level] + x;
+   return lpr->layout[level][i];
 }
 
 
@@ -820,13 +813,17 @@ llvmpipe_set_texture_tile_layout(struct llvmpipe_resource *lpr,
    uint i;
    assert(resource_is_texture(&lpr->base));
    assert(x < lpr->tiles_per_row[level]);
-   i = y * lpr->tiles_per_row[level] + x;
-   lpr->layout[level][face_slice][i] = layout;
+   i = face_slice * lpr->tiles_per_image[level]
+      + y * lpr->tiles_per_row[level] + x;
+   lpr->layout[level][i] = layout;
 }
 
 
 /**
- * Return pointer to texture image data (either linear or tiled layout).
+ * Return pointer to texture image data (either linear or tiled layout)
+ * for a particular cube face or 3D texture slice.
+ *
+ * \param face_slice  the cube face or 3D slice of interest
  * \param usage  one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE
  * \param layout  either LP_TEX_LAYOUT_LINEAR or _TILED or _NONE
  */
@@ -897,26 +894,32 @@ llvmpipe_get_texture_image(struct llvmpipe_resource *lpr,
    }
 
    if (face_slice > 0) {
-      unsigned offset;
-      if (layout == LP_TEX_LAYOUT_LINEAR)
-         offset = tex_image_face_size(lpr, level, LP_TEX_LAYOUT_LINEAR);
-      else
-         offset = tex_image_face_size(lpr, level, LP_TEX_LAYOUT_TILED);
-
-      offset *= face_slice;
+      unsigned target_offset, other_offset;
 
+      target_offset = face_slice * tex_image_face_size(lpr, level, layout);
+      other_offset = face_slice * tex_image_face_size(lpr, level, other_layout);
       if (target_data) {
-         target_data = (uint8_t *) target_data + offset;
+         target_data = (uint8_t *) target_data + target_offset;
       }
       if (other_data) {
-         other_data = (uint8_t *) other_data + offset;
+         other_data = (uint8_t *) other_data + other_offset;
       }
    }
 
    if (only_allocate) {
-      /* Just allocating tiled memory.  Don't initialize it from the the
+      /* Just allocating tiled memory.  Don't initialize it from the
        * linear data if it exists.
        */
+      {
+         unsigned x, y;
+         for (y = 0; y < height_t; y++) {
+            for (x = 0; x < width_t; x++) {
+               llvmpipe_set_texture_tile_layout(lpr, face_slice, level,
+                                                x, y, layout);
+            }
+         }
+      }
+
       return target_data;
    }
 
@@ -974,6 +977,33 @@ llvmpipe_get_texture_image(struct llvmpipe_resource *lpr,
 
 
 /**
+ * Return pointer to start of a texture image (1D, 2D, 3D, CUBE).
+ * All cube faces and 3D slices will be converted to the requested
+ * layout if needed.
+ * This is typically used when we're about to sample from a texture.
+ */
+void *
+llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr,
+                               unsigned level,
+                               enum lp_texture_usage usage,
+                               enum lp_texture_layout layout)
+{
+   const int slices = lpr->num_slices_faces[level];
+   int slice;
+   void *map;
+
+   assert(slices > 0);
+
+   for (slice = slices - 1; slice >= 0; slice--) {
+      map = llvmpipe_get_texture_image(lpr, slice, level, usage, layout);
+   }
+
+   return map;
+}
+
+
+
+/**
  * Get pointer to a linear image where the tile at (x,y) is known to be
  * in linear layout.
  * Conversion from tiled to linear will be done if necessary.
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.h b/src/gallium/drivers/llvmpipe/lp_texture.h
index dd54e17..57f3e0f 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.h
+++ b/src/gallium/drivers/llvmpipe/lp_texture.h
@@ -94,6 +94,9 @@ struct llvmpipe_resource
    /** Row stride in bytes */
    unsigned stride[LP_MAX_TEXTURE_LEVELS];
    unsigned tiles_per_row[LP_MAX_TEXTURE_LEVELS];
+   unsigned tiles_per_image[LP_MAX_TEXTURE_LEVELS];
+   /** Number of 3D slices or cube faces per level */
+   unsigned num_slices_faces[LP_MAX_TEXTURE_LEVELS];
 
    /**
     * Display target, for textures with the PIPE_BIND_DISPLAY_TARGET
@@ -112,8 +115,8 @@ struct llvmpipe_resource
     */
    void *data;
 
-   /** array [level][face or slice][tile] of layout values) */
-   enum lp_texture_layout *layout[LP_MAX_TEXTURE_LEVELS][PIPE_TEX_FACE_MAX];
+   /** array [level][face or slice][tile_y][tile_x] of layout values) */
+   enum lp_texture_layout *layout[LP_MAX_TEXTURE_LEVELS];
 
    boolean userBuffer;  /** Is this a user-space buffer? */
    unsigned timestamp;
@@ -195,6 +198,11 @@ llvmpipe_get_texture_image(struct llvmpipe_resource *resource,
                             enum lp_texture_usage usage,
                             enum lp_texture_layout layout);
 
+void *
+llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr,
+                               unsigned level,
+                               enum lp_texture_usage usage,
+                               enum lp_texture_layout layout);
 
 ubyte *
 llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr,




More information about the mesa-commit mailing list