[Mesa-dev] [PATCH] softpipe: allocate tile data on demand (v2)

Luca Barbieri luca at luca-barbieri.com
Fri Sep 24 11:39:03 PDT 2010


Changes in v2:
- Invalidate last_tile_addr on any change, fixing regressions
- Correct coding style

Currently softpipe ends up allocating more than 200 MB of memory
for each context due to the tile caches.

Even worse, this memory is all explicitly cleared, which means that the
kernel must actually back it with physical RAM right away.

This change allocates tile memory on demand.
---
 src/gallium/drivers/softpipe/sp_tile_cache.c |  145 +++++++++++++++++++-------
 src/gallium/drivers/softpipe/sp_tile_cache.h |    9 +-
 2 files changed, 112 insertions(+), 42 deletions(-)

diff --git a/src/gallium/drivers/softpipe/sp_tile_cache.c b/src/gallium/drivers/softpipe/sp_tile_cache.c
index bf33fd9..7ed1052 100644
--- a/src/gallium/drivers/softpipe/sp_tile_cache.c
+++ b/src/gallium/drivers/softpipe/sp_tile_cache.c
@@ -38,6 +38,8 @@
 #include "util/u_tile.h"
 #include "sp_tile_cache.h"
 
+static struct softpipe_cached_tile *
+sp_alloc_tile(struct softpipe_tile_cache *tc);
 
 
 /**
@@ -94,9 +96,19 @@ sp_create_tile_cache( struct pipe_context *pipe )
    if (tc) {
       tc->pipe = pipe;
       for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         tc->entries[pos].addr.bits.invalid = 1;
+         tc->tile_addrs[pos].bits.invalid = 1;
+      }
+      tc->last_tile_addr.bits.invalid = 1;
+
+      /* this allocation allows us to guarantee that allocation
+       * failures are never fatal later
+       */
+      tc->tile = MALLOC_STRUCT( softpipe_cached_tile );
+      if (!tc->tile)
+      {
+         FREE(tc);
+         return NULL;
       }
-      tc->last_tile = &tc->entries[0]; /* any tile */
 
       /* XXX this code prevents valgrind warnings about use of uninitialized
        * memory in programs that don't clear the surface before rendering.
@@ -120,7 +132,10 @@ sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
 
       for (pos = 0; pos < NUM_ENTRIES; pos++) {
          /*assert(tc->entries[pos].x < 0);*/
+         FREE( tc->entries[pos] );
       }
+      FREE( tc->tile );
+
       if (tc->transfer) {
          tc->pipe->transfer_destroy(tc->pipe, tc->transfer);
       }
@@ -285,11 +300,14 @@ sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc)
    uint numCleared = 0;
 
    assert(pt->resource);
+   if (!tc->tile)
+      tc->tile = sp_alloc_tile(tc);
+
    /* clear the scratch tile to the clear value */
    if (tc->depth_stencil) {
-      clear_tile(&tc->tile, pt->resource->format, tc->clear_val);
+      clear_tile(tc->tile, pt->resource->format, tc->clear_val);
    } else {
-      clear_tile_rgba(&tc->tile, pt->resource->format, tc->clear_color);
+      clear_tile_rgba(tc->tile, pt->resource->format, tc->clear_color);
    }
 
    /* push the tile to all positions marked as clear */
@@ -303,12 +321,12 @@ sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc)
                pipe_put_tile_raw(tc->pipe,
                                  pt,
                                  x, y, TILE_SIZE, TILE_SIZE,
-                                 tc->tile.data.any, 0/*STRIDE*/);
+                                 tc->tile->data.any, 0/*STRIDE*/);
             }
             else {
                pipe_put_tile_rgba(tc->pipe, pt,
                                   x, y, TILE_SIZE, TILE_SIZE,
-                                  (float *) tc->tile.data.color);
+                                  (float *) tc->tile->data.color);
             }
             numCleared++;
          }
@@ -323,6 +341,27 @@ sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc)
 #endif
 }
 
+static void
+sp_flush_tile(struct softpipe_tile_cache* tc, unsigned pos)
+{
+   if (!tc->tile_addrs[pos].bits.invalid) {
+      if (tc->depth_stencil) {
+         pipe_put_tile_raw(tc->pipe, tc->transfer,
+                           tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                           tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                           TILE_SIZE, TILE_SIZE,
+                           tc->entries[pos]->data.depth32, 0/*STRIDE*/);
+      }
+      else {
+         pipe_put_tile_rgba(tc->pipe, tc->transfer,
+                            tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                            tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                            TILE_SIZE, TILE_SIZE,
+                            (float *) tc->entries[pos]->data.color);
+      }
+      tc->tile_addrs[pos].bits.invalid = 1;  /* mark as empty */
+   }
+}
 
 /**
  * Flush the tile cache: write all dirty tiles back to the transfer.
@@ -337,28 +376,20 @@ sp_flush_tile_cache(struct softpipe_tile_cache *tc)
    if (pt) {
       /* caching a drawing transfer */
       for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         struct softpipe_cached_tile *tile = tc->entries + pos;
-         if (!tile->addr.bits.invalid) {
-            if (tc->depth_stencil) {
-               pipe_put_tile_raw(tc->pipe, pt,
-                                 tile->addr.bits.x * TILE_SIZE, 
-                                 tile->addr.bits.y * TILE_SIZE, 
-                                 TILE_SIZE, TILE_SIZE,
-                                 tile->data.depth32, 0/*STRIDE*/);
-            }
-            else {
-               pipe_put_tile_rgba(tc->pipe, pt,
-                                  tile->addr.bits.x * TILE_SIZE, 
-                                  tile->addr.bits.y * TILE_SIZE, 
-                                  TILE_SIZE, TILE_SIZE,
-                                  (float *) tile->data.color);
-            }
-            tile->addr.bits.invalid = 1;  /* mark as empty */
-            inuse++;
+         struct softpipe_cached_tile *tile = tc->entries[pos];
+         if (!tile)
+         {
+            assert(tc->tile_addrs[pos].bits.invalid);
+            continue;
          }
+
+         sp_flush_tile(tc, pos);
+         ++inuse;
       }
 
       sp_tile_cache_flush_clear(tc);
+
+      tc->last_tile_addr.bits.invalid = 1;
    }
 
 #if 0
@@ -366,6 +397,38 @@ sp_flush_tile_cache(struct softpipe_tile_cache *tc)
 #endif
 }
 
+static struct softpipe_cached_tile *
+sp_alloc_tile(struct softpipe_tile_cache *tc)
+{
+   struct softpipe_cached_tile * tile = MALLOC_STRUCT(softpipe_cached_tile);
+   if (!tile)
+   {
+      /* in this case, steal an existing tile */
+      if (!tc->tile)
+      {
+         unsigned pos;
+         for (pos = 0; pos < NUM_ENTRIES; ++pos) {
+            if (!tc->entries[pos])
+               continue;
+
+            sp_flush_tile(tc, pos);
+            tc->tile = tc->entries[pos];
+            tc->entries[pos] = NULL;
+            break;
+         }
+
+         /* this should never happen */
+         if (!tc->tile)
+            abort();
+      }
+
+      tile = tc->tile;
+      tc->tile = NULL;
+
+      tc->last_tile_addr.bits.invalid = 1;
+   }
+   return tile;
+}
 
 /**
  * Get a tile from the cache.
@@ -380,30 +443,35 @@ sp_find_cached_tile(struct softpipe_tile_cache *tc,
    /* cache pos/entry: */
    const int pos = CACHE_POS(addr.bits.x,
                              addr.bits.y);
-   struct softpipe_cached_tile *tile = tc->entries + pos;
+   struct softpipe_cached_tile *tile = tc->entries[pos];
+
+   if (!tile) {
+      tile = sp_alloc_tile(tc);
+      tc->entries[pos] = tile;
+   }
 
-   if (addr.value != tile->addr.value) {
+   if (addr.value != tc->tile_addrs[pos].value) {
 
       assert(pt->resource);
-      if (tile->addr.bits.invalid == 0) {
+      if (tc->tile_addrs[pos].bits.invalid == 0) {
          /* put dirty tile back in framebuffer */
          if (tc->depth_stencil) {
             pipe_put_tile_raw(tc->pipe, pt,
-                              tile->addr.bits.x * TILE_SIZE,
-                              tile->addr.bits.y * TILE_SIZE,
+                              tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                              tc->tile_addrs[pos].bits.y * TILE_SIZE,
                               TILE_SIZE, TILE_SIZE,
                               tile->data.depth32, 0/*STRIDE*/);
          }
          else {
             pipe_put_tile_rgba(tc->pipe, pt,
-                               tile->addr.bits.x * TILE_SIZE,
-                               tile->addr.bits.y * TILE_SIZE,
+                               tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                               tc->tile_addrs[pos].bits.y * TILE_SIZE,
                                TILE_SIZE, TILE_SIZE,
                                (float *) tile->data.color);
          }
       }
 
-      tile->addr = addr;
+      tc->tile_addrs[pos] = addr;
 
       if (is_clear_flag_set(tc->clear_flags, addr)) {
          /* don't get tile from framebuffer, just clear it */
@@ -419,15 +487,15 @@ sp_find_cached_tile(struct softpipe_tile_cache *tc,
          /* get new tile data from transfer */
          if (tc->depth_stencil) {
             pipe_get_tile_raw(tc->pipe, pt,
-                              tile->addr.bits.x * TILE_SIZE, 
-                              tile->addr.bits.y * TILE_SIZE, 
+                              tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                              tc->tile_addrs[pos].bits.y * TILE_SIZE,
                               TILE_SIZE, TILE_SIZE,
                               tile->data.depth32, 0/*STRIDE*/);
          }
          else {
             pipe_get_tile_rgba(tc->pipe, pt,
-                               tile->addr.bits.x * TILE_SIZE, 
-                               tile->addr.bits.y * TILE_SIZE,
+                               tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                               tc->tile_addrs[pos].bits.y * TILE_SIZE,
                                TILE_SIZE, TILE_SIZE,
                                (float *) tile->data.color);
          }
@@ -435,6 +503,7 @@ sp_find_cached_tile(struct softpipe_tile_cache *tc,
    }
 
    tc->last_tile = tile;
+   tc->last_tile_addr = addr;
    return tile;
 }
 
@@ -464,7 +533,7 @@ sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float *rgba,
    memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
 
    for (pos = 0; pos < NUM_ENTRIES; pos++) {
-      struct softpipe_cached_tile *tile = tc->entries + pos;
-      tile->addr.bits.invalid = 1;
+      tc->tile_addrs[pos].bits.invalid = 1;
    }
+   tc->last_tile_addr.bits.invalid = 1;
 }
diff --git a/src/gallium/drivers/softpipe/sp_tile_cache.h b/src/gallium/drivers/softpipe/sp_tile_cache.h
index e03d53e..031c7c1 100644
--- a/src/gallium/drivers/softpipe/sp_tile_cache.h
+++ b/src/gallium/drivers/softpipe/sp_tile_cache.h
@@ -57,7 +57,6 @@ union tile_address {
 
 struct softpipe_cached_tile
 {
-   union tile_address addr;
    union {
       float color[TILE_SIZE][TILE_SIZE][4];
       uint color32[TILE_SIZE][TILE_SIZE];
@@ -83,14 +82,16 @@ struct softpipe_tile_cache
    struct pipe_transfer *transfer;
    void *transfer_map;
 
-   struct softpipe_cached_tile entries[NUM_ENTRIES];
+   union tile_address tile_addrs[NUM_ENTRIES];
+   struct softpipe_cached_tile *entries[NUM_ENTRIES];
    uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32];
    float clear_color[4];  /**< for color bufs */
    uint clear_val;        /**< for z+stencil, or packed color clear value */
    boolean depth_stencil; /**< Is the surface a depth/stencil format? */
 
-   struct softpipe_cached_tile tile;  /**< scratch tile for clears */
+   struct softpipe_cached_tile *tile;  /**< scratch tile for clears */
 
+   union tile_address last_tile_addr;
    struct softpipe_cached_tile *last_tile;  /**< most recently retrieved tile */
 };
 
@@ -147,7 +148,7 @@ sp_get_cached_tile(struct softpipe_tile_cache *tc,
 {
    union tile_address addr = tile_address( x, y );
 
-   if (tc->last_tile->addr.value == addr.value)
+   if (tc->last_tile_addr.value == addr.value)
       return tc->last_tile;
 
    return sp_find_cached_tile( tc, addr );
-- 
1.7.0.4



More information about the mesa-dev mailing list