gallium: remove pipe_surface::usage
[mesa.git] / src / gallium / drivers / softpipe / sp_tile_cache.c
index 78b0efa46d27c879d74d15c67df909b4c32bc240..8d581112fcd7cd40f566fa4e26c2db8906104f92 100644 (file)
  **************************************************************************/
 
 /**
- * Framebuffer/surface tile caching.
+ * Render target tile caching.
  *
  * Author:
  *    Brian Paul
  */
 
-#include "pipe/p_inlines.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
 #include "util/u_memory.h"
 #include "util/u_tile.h"
-#include "sp_context.h"
-#include "sp_surface.h"
-#include "sp_texture.h"
 #include "sp_tile_cache.h"
 
-#define NUM_ENTRIES 32
-
-
-/** XXX move these */
-#define MAX_WIDTH 2048
-#define MAX_HEIGHT 2048
-
-
-struct softpipe_tile_cache
-{
-   struct pipe_screen *screen;
-   struct pipe_surface *surface;  /**< the surface we're caching */
-   void *surface_map;
-   struct pipe_texture *texture;  /**< if caching a texture */
-   struct softpipe_cached_tile entries[NUM_ENTRIES];
-   uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32];
-   float clear_color[4];
-   uint clear_val;
-   boolean depth_stencil; /** Is the surface a depth/stencil format? */
-
-   struct pipe_surface *tex_surf;
-   void *tex_surf_map;
-   int tex_face, tex_level, tex_z;
-
-   struct softpipe_cached_tile tile;  /**< scratch tile for clears */
-};
+static struct softpipe_cached_tile *
+sp_alloc_tile(struct softpipe_tile_cache *tc);
 
 
 /**
@@ -75,7 +49,7 @@ struct softpipe_tile_cache
  * a LRU replacement policy.
  */
 #define CACHE_POS(x, y) \
-   (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
+   (((x) + (y) * 5) % NUM_ENTRIES)
 
 
 
@@ -83,12 +57,10 @@ struct softpipe_tile_cache
  * Is the tile at (x,y) in cleared state?
  */
 static INLINE uint
-is_clear_flag_set(const uint *bitvec, int x, int y)
+is_clear_flag_set(const uint *bitvec, union tile_address addr)
 {
    int pos, bit;
-   x /= TILE_SIZE;
-   y /= TILE_SIZE;
-   pos = y * (MAX_WIDTH / TILE_SIZE) + x;
+   pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
    assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
    bit = bitvec[pos / 32] & (1 << (pos & 31));
    return bit;
@@ -99,30 +71,58 @@ is_clear_flag_set(const uint *bitvec, int x, int y)
  * Mark the tile at (x,y) as not cleared.
  */
 static INLINE void
-clear_clear_flag(uint *bitvec, int x, int y)
+clear_clear_flag(uint *bitvec, union tile_address addr)
 {
    int pos;
-   x /= TILE_SIZE;
-   y /= TILE_SIZE;
-   pos = y * (MAX_WIDTH / TILE_SIZE) + x;
+   pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
    assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
    bitvec[pos / 32] &= ~(1 << (pos & 31));
 }
    
 
 struct softpipe_tile_cache *
-sp_create_tile_cache( struct pipe_screen *screen )
+sp_create_tile_cache( struct pipe_context *pipe )
 {
    struct softpipe_tile_cache *tc;
    uint pos;
+   int maxLevels, maxTexSize;
+
+   /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
+   maxLevels = pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
+   maxTexSize = 1 << (maxLevels - 1);
+   assert(MAX_WIDTH >= maxTexSize);
+
+   assert(sizeof(union tile_address) == 4);
+
+   assert((TILE_SIZE << TILE_ADDR_BITS) >= MAX_WIDTH);
 
    tc = CALLOC_STRUCT( softpipe_tile_cache );
    if (tc) {
-      tc->screen = screen;
+      tc->pipe = pipe;
       for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         tc->entries[pos].x =
-         tc->entries[pos].y = -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;
+      }
+
+      /* XXX this code prevents valgrind warnings about use of uninitialized
+       * memory in programs that don't clear the surface before rendering.
+       * However, it breaks clearing in other situations (such as in
+       * progs/tests/drawbuffers, see bug 24402).
+       */
+#if 0
+      /* set flags to indicate all the tiles are cleared */
+      memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
+#endif
    }
    return tc;
 }
@@ -131,19 +131,21 @@ sp_create_tile_cache( struct pipe_screen *screen )
 void
 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
 {
-   uint pos;
+   if (tc) {
+      uint pos;
 
-   for (pos = 0; pos < NUM_ENTRIES; pos++) {
-      /*assert(tc->entries[pos].x < 0);*/
-   }
-   if (tc->surface) {
-      pipe_surface_reference(&tc->surface, NULL);
-   }
-   if (tc->tex_surf) {
-      pipe_surface_reference(&tc->tex_surf, NULL);
-   }
+      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_unmap(tc->pipe, tc->transfer);
+      }
 
-   FREE( tc );
+      FREE( tc );
+   }
 }
 
 
@@ -154,98 +156,39 @@ void
 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
                           struct pipe_surface *ps)
 {
-   assert(!tc->texture);
+   struct pipe_context *pipe = tc->pipe;
 
-   if (tc->surface_map) {
-      tc->screen->surface_unmap(tc->screen, tc->surface);
-      tc->surface_map = NULL;
-   }
+   if (tc->transfer_map) {
+      if (ps == tc->surface)
+         return;
 
-   pipe_surface_reference(&tc->surface, ps);
-
-   if (tc->surface) {
-      if (tc->surface_map) /* XXX: this is always NULL!? */
-        tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface,
-                                                   PIPE_BUFFER_USAGE_CPU_READ | 
-                                                   PIPE_BUFFER_USAGE_CPU_WRITE);
-
-      tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM ||
-                           ps->format == PIPE_FORMAT_X8Z24_UNORM ||
-                           ps->format == PIPE_FORMAT_Z24S8_UNORM ||
-                           ps->format == PIPE_FORMAT_Z24X8_UNORM ||
-                           ps->format == PIPE_FORMAT_Z16_UNORM ||
-                           ps->format == PIPE_FORMAT_Z32_UNORM ||
-                           ps->format == PIPE_FORMAT_S8_UNORM);
+      pipe->transfer_unmap(pipe, tc->transfer);
+      tc->transfer = NULL;
+      tc->transfer_map = NULL;
    }
-}
 
+   tc->surface = ps;
 
-/**
- * Return the surface being cached.
- */
-struct pipe_surface *
-sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
-{
-   return tc->surface;
-}
+   if (ps) {
+      tc->transfer_map = pipe_transfer_map(pipe, ps->texture,
+                                           ps->u.tex.level, ps->u.tex.first_layer,
+                                           PIPE_TRANSFER_READ_WRITE |
+                                           PIPE_TRANSFER_UNSYNCHRONIZED,
+                                           0, 0, ps->width, ps->height,
+                                           &tc->transfer);
 
-
-void
-sp_tile_cache_map_surfaces(struct softpipe_tile_cache *tc)
-{
-   if (tc->surface && !tc->surface_map)
-      tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface,
-                                                PIPE_BUFFER_USAGE_CPU_WRITE |
-                                                PIPE_BUFFER_USAGE_CPU_READ);
-
-   if (tc->tex_surf && !tc->tex_surf_map)
-      tc->tex_surf_map = tc->screen->surface_map(tc->screen, tc->tex_surf,
-                                                 PIPE_BUFFER_USAGE_CPU_READ);
-}
-
-
-void
-sp_tile_cache_unmap_surfaces(struct softpipe_tile_cache *tc)
-{
-   if (tc->surface_map) {
-      tc->screen->surface_unmap(tc->screen, tc->surface);
-      tc->surface_map = NULL;
-   }
-
-   if (tc->tex_surf_map) {
-      tc->screen->surface_unmap(tc->screen, tc->tex_surf);
-      tc->tex_surf_map = NULL;
+      tc->depth_stencil = util_format_is_depth_or_stencil(ps->format);
    }
 }
 
 
 /**
- * Specify the texture to cache.
+ * Return the transfer being cached.
  */
-void
-sp_tile_cache_set_texture(struct pipe_context *pipe,
-                          struct softpipe_tile_cache *tc,
-                          struct pipe_texture *texture)
+struct pipe_surface *
+sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
 {
-   uint i;
-
-   assert(!tc->surface);
-
-   pipe_texture_reference(&tc->texture, texture);
-
-   if (tc->tex_surf_map) {
-      tc->screen->surface_unmap(tc->screen, tc->tex_surf);
-      tc->tex_surf_map = NULL;
-   }
-   pipe_surface_reference(&tc->tex_surf, NULL);
-
-   /* mark as entries as invalid/empty */
-   /* XXX we should try to avoid this when the teximage hasn't changed */
-   for (i = 0; i < NUM_ENTRIES; i++) {
-      tc->entries[i].x = -1;
-   }
-
-   tc->tex_face = -1; /* any invalid value here */
+   return tc->surface;
 }
 
 
@@ -255,22 +198,43 @@ sp_tile_cache_set_texture(struct pipe_context *pipe,
 static void
 clear_tile_rgba(struct softpipe_cached_tile *tile,
                 enum pipe_format format,
-                const float clear_value[4])
+                const union pipe_color_union *clear_value)
 {
-   if (clear_value[0] == 0.0 &&
-       clear_value[1] == 0.0 &&
-       clear_value[2] == 0.0 &&
-       clear_value[3] == 0.0) {
+   if (clear_value->f[0] == 0.0 &&
+       clear_value->f[1] == 0.0 &&
+       clear_value->f[2] == 0.0 &&
+       clear_value->f[3] == 0.0) {
       memset(tile->data.color, 0, sizeof(tile->data.color));
    }
    else {
       uint i, j;
-      for (i = 0; i < TILE_SIZE; i++) {
-         for (j = 0; j < TILE_SIZE; j++) {
-            tile->data.color[i][j][0] = clear_value[0];
-            tile->data.color[i][j][1] = clear_value[1];
-            tile->data.color[i][j][2] = clear_value[2];
-            tile->data.color[i][j][3] = clear_value[3];
+
+      if (util_format_is_pure_uint(format)) {
+         for (i = 0; i < TILE_SIZE; i++) {
+            for (j = 0; j < TILE_SIZE; j++) {
+               tile->data.colorui128[i][j][0] = clear_value->ui[0];
+               tile->data.colorui128[i][j][1] = clear_value->ui[1];
+               tile->data.colorui128[i][j][2] = clear_value->ui[2];
+               tile->data.colorui128[i][j][3] = clear_value->ui[3];
+            }
+         }
+      } else if (util_format_is_pure_sint(format)) {
+         for (i = 0; i < TILE_SIZE; i++) {
+            for (j = 0; j < TILE_SIZE; j++) {
+               tile->data.colori128[i][j][0] = clear_value->i[0];
+               tile->data.colori128[i][j][1] = clear_value->i[1];
+               tile->data.colori128[i][j][2] = clear_value->i[2];
+               tile->data.colori128[i][j][3] = clear_value->i[3];
+            }
+         }
+      } else {
+         for (i = 0; i < TILE_SIZE; i++) {
+            for (j = 0; j < TILE_SIZE; j++) {
+               tile->data.color[i][j][0] = clear_value->f[0];
+               tile->data.color[i][j][1] = clear_value->f[1];
+               tile->data.color[i][j][2] = clear_value->f[2];
+               tile->data.color[i][j][3] = clear_value->f[3];
+            }
          }
       }
    }
@@ -283,13 +247,13 @@ clear_tile_rgba(struct softpipe_cached_tile *tile,
 static void
 clear_tile(struct softpipe_cached_tile *tile,
            enum pipe_format format,
-           uint clear_value)
+           uint64_t clear_value)
 {
    uint i, j;
 
-   switch (pf_get_size(format)) {
+   switch (util_format_get_blocksize(format)) {
    case 1:
-      memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
+      memset(tile->data.any, clear_value, TILE_SIZE * TILE_SIZE);
       break;
    case 2:
       if (clear_value == 0) {
@@ -310,7 +274,19 @@ clear_tile(struct softpipe_cached_tile *tile,
       else {
          for (i = 0; i < TILE_SIZE; i++) {
             for (j = 0; j < TILE_SIZE; j++) {
-               tile->data.color32[i][j] = clear_value;
+               tile->data.depth32[i][j] = clear_value;
+            }
+         }
+      }
+      break;
+   case 8:
+      if (clear_value == 0) {
+         memset(tile->data.any, 0, 8 * TILE_SIZE * TILE_SIZE);
+      }
+      else {
+         for (i = 0; i < TILE_SIZE; i++) {
+            for (j = 0; j < TILE_SIZE; j++) {
+               tile->data.depth64[i][j] = clear_value;
             }
          }
       }
@@ -325,80 +301,134 @@ clear_tile(struct softpipe_cached_tile *tile,
  * Actually clear the tiles which were flagged as being in a clear state.
  */
 static void
-sp_tile_cache_flush_clear(struct pipe_context *pipe,
-                          struct softpipe_tile_cache *tc)
+sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc)
 {
-   struct pipe_surface *ps = tc->surface;
-   const uint w = tc->surface->width;
-   const uint h = tc->surface->height;
+   struct pipe_transfer *pt = tc->transfer;
+   const uint w = tc->transfer->box.width;
+   const uint h = tc->transfer->box.height;
    uint x, y;
    uint numCleared = 0;
 
+   assert(pt->resource);
+   if (!tc->tile)
+      tc->tile = sp_alloc_tile(tc);
+
    /* clear the scratch tile to the clear value */
-   clear_tile(&tc->tile, ps->format, tc->clear_val);
+   if (tc->depth_stencil) {
+      clear_tile(tc->tile, pt->resource->format, tc->clear_val);
+   } else {
+      clear_tile_rgba(tc->tile, pt->resource->format, &tc->clear_color);
+   }
 
    /* push the tile to all positions marked as clear */
    for (y = 0; y < h; y += TILE_SIZE) {
       for (x = 0; x < w; x += TILE_SIZE) {
-         if (is_clear_flag_set(tc->clear_flags, x, y)) {
-            pipe_put_tile_raw(ps,
-                              x, y, TILE_SIZE, TILE_SIZE,
-                              tc->tile.data.color32, 0/*STRIDE*/);
-
-            /* do this? */
-            clear_clear_flag(tc->clear_flags, x, y);
+         union tile_address addr = tile_address(x, y);
 
+         if (is_clear_flag_set(tc->clear_flags, addr)) {
+            /* write the scratch tile to the surface */
+            if (tc->depth_stencil) {
+               pipe_put_tile_raw(pt, tc->transfer_map,
+                                 x, y, TILE_SIZE, TILE_SIZE,
+                                 tc->tile->data.any, 0/*STRIDE*/);
+            }
+            else {
+               if (util_format_is_pure_uint(tc->surface->format)) {
+                  pipe_put_tile_ui_format(pt, tc->transfer_map,
+                                          x, y, TILE_SIZE, TILE_SIZE,
+                                          pt->resource->format,
+                                          (unsigned *) tc->tile->data.colorui128);
+               } else if (util_format_is_pure_sint(tc->surface->format)) {
+                  pipe_put_tile_i_format(pt, tc->transfer_map,
+                                         x, y, TILE_SIZE, TILE_SIZE,
+                                         pt->resource->format,
+                                         (int *) tc->tile->data.colori128);
+               } else {
+                  pipe_put_tile_rgba(pt, tc->transfer_map,
+                                     x, y, TILE_SIZE, TILE_SIZE,
+                                     (float *) tc->tile->data.color);
+               }
+            }
             numCleared++;
          }
       }
    }
+
+   /* reset all clear flags to zero */
+   memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
+
 #if 0
    debug_printf("num cleared: %u\n", numCleared);
 #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->transfer, tc->transfer_map,
+                           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 {
+         if (util_format_is_pure_uint(tc->surface->format)) {
+            pipe_put_tile_ui_format(tc->transfer, tc->transfer_map,
+                                    tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                    tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                    TILE_SIZE, TILE_SIZE,
+                                    tc->surface->format,
+                                    (unsigned *) tc->entries[pos]->data.colorui128);
+         } else if (util_format_is_pure_sint(tc->surface->format)) {
+            pipe_put_tile_i_format(tc->transfer, tc->transfer_map,
+                                   tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                   tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                   TILE_SIZE, TILE_SIZE,
+                                   tc->surface->format,
+                                   (int *) tc->entries[pos]->data.colori128);
+         } else {
+            pipe_put_tile_rgba_format(tc->transfer, tc->transfer_map,
+                                      tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                      tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                      TILE_SIZE, TILE_SIZE,
+                                      tc->surface->format,
+                                      (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 surface.
+ * Flush the tile cache: write all dirty tiles back to the transfer.
  * any tiles "flagged" as cleared will be "really" cleared.
  */
 void
-sp_flush_tile_cache(struct softpipe_context *softpipe,
-                    struct softpipe_tile_cache *tc)
+sp_flush_tile_cache(struct softpipe_tile_cache *tc)
 {
-   struct pipe_surface *ps = tc->surface;
+   struct pipe_transfer *pt = tc->transfer;
    int inuse = 0, pos;
 
-   if (ps && ps->buffer) {
-      /* caching a drawing surface */
+   if (pt) {
+      /* caching a drawing transfer */
       for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         struct softpipe_cached_tile *tile = tc->entries + pos;
-         if (tile->x >= 0) {
-            if (tc->depth_stencil) {
-               pipe_put_tile_raw(ps,
-                                 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
-                                 tile->data.depth32, 0/*STRIDE*/);
-            }
-            else {
-               pipe_put_tile_rgba(ps,
-                                  tile->x, tile->y, TILE_SIZE, TILE_SIZE,
-                                  (float *) tile->data.color);
-            }
-            tile->x = tile->y = -1;  /* mark as empty */
-            inuse++;
+         struct softpipe_cached_tile *tile = tc->entries[pos];
+         if (!tile)
+         {
+            assert(tc->tile_addrs[pos].bits.invalid);
+            continue;
          }
-      }
 
-#if TILE_CLEAR_OPTIMIZATION
-      sp_tile_cache_flush_clear(&softpipe->pipe, tc);
-#endif
-   }
-   else if (tc->texture) {
-      /* caching a texture, mark all entries as empty */
-      for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         tc->entries[pos].x = -1;
+         sp_flush_tile(tc, pos);
+         ++inuse;
       }
-      tc->tex_face = -1;
+
+      sp_tile_cache_flush_clear(tc);
+
+
+      tc->last_tile_addr.bits.invalid = 1;
    }
 
 #if 0
@@ -406,157 +436,152 @@ sp_flush_tile_cache(struct softpipe_context *softpipe,
 #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.
  * \param x, y  position of tile, in pixels
  */
 struct softpipe_cached_tile *
-sp_get_cached_tile(struct softpipe_context *softpipe,
-                   struct softpipe_tile_cache *tc, int x, int y)
+sp_find_cached_tile(struct softpipe_tile_cache *tc, 
+                    union tile_address addr )
 {
-   struct pipe_surface *ps = tc->surface;
-
-   /* tile pos in framebuffer: */
-   const int tile_x = x & ~(TILE_SIZE - 1);
-   const int tile_y = y & ~(TILE_SIZE - 1);
-
+   struct pipe_transfer *pt = tc->transfer;
    /* cache pos/entry: */
-   const int pos = CACHE_POS(x, y);
-   struct softpipe_cached_tile *tile = tc->entries + pos;
+   const int pos = CACHE_POS(addr.bits.x,
+                             addr.bits.y);
+   struct softpipe_cached_tile *tile = tc->entries[pos];
+
+   if (!tile) {
+      tile = sp_alloc_tile(tc);
+      tc->entries[pos] = tile;
+   }
 
-   if (tile_x != tile->x ||
-       tile_y != tile->y) {
+   if (addr.value != tc->tile_addrs[pos].value) {
 
-      if (tile->x != -1) {
+      assert(pt->resource);
+      if (tc->tile_addrs[pos].bits.invalid == 0) {
          /* put dirty tile back in framebuffer */
          if (tc->depth_stencil) {
-            pipe_put_tile_raw(ps,
-                              tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+            pipe_put_tile_raw(pt, tc->transfer_map,
+                              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(ps,
-                               tile->x, tile->y, TILE_SIZE, TILE_SIZE,
-                               (float *) tile->data.color);
+            if (util_format_is_pure_uint(tc->surface->format)) {
+               pipe_put_tile_ui_format(pt, tc->transfer_map,
+                                      tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                      tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                      TILE_SIZE, TILE_SIZE,
+                                      tc->surface->format,
+                                      (unsigned *) tile->data.colorui128);
+            } else if (util_format_is_pure_sint(tc->surface->format)) {
+               pipe_put_tile_i_format(pt, tc->transfer_map,
+                                      tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                      tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                      TILE_SIZE, TILE_SIZE,
+                                      tc->surface->format,
+                                      (int *) tile->data.colori128);
+            } else {
+               pipe_put_tile_rgba_format(pt, tc->transfer_map,
+                                         tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                         tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                         TILE_SIZE, TILE_SIZE,
+                                         tc->surface->format,
+                                         (float *) tile->data.color);
+            }
          }
       }
 
-      tile->x = tile_x;
-      tile->y = tile_y;
+      tc->tile_addrs[pos] = addr;
 
-      if (is_clear_flag_set(tc->clear_flags, x, y)) {
+      if (is_clear_flag_set(tc->clear_flags, addr)) {
          /* don't get tile from framebuffer, just clear it */
          if (tc->depth_stencil) {
-            clear_tile(tile, ps->format, tc->clear_val);
+            clear_tile(tile, pt->resource->format, tc->clear_val);
          }
          else {
-            clear_tile_rgba(tile, ps->format, tc->clear_color);
+            clear_tile_rgba(tile, pt->resource->format, &tc->clear_color);
          }
-         clear_clear_flag(tc->clear_flags, x, y);
+         clear_clear_flag(tc->clear_flags, addr);
       }
       else {
-         /* get new tile data from surface */
+         /* get new tile data from transfer */
          if (tc->depth_stencil) {
-            pipe_get_tile_raw(ps,
-                              tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+            pipe_get_tile_raw(pt, tc->transfer_map,
+                              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(ps,
-                               tile->x, tile->y, TILE_SIZE, TILE_SIZE,
-                               (float *) tile->data.color);
+            if (util_format_is_pure_uint(tc->surface->format)) {
+               pipe_get_tile_ui_format(pt, tc->transfer_map,
+                                         tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                         tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                         TILE_SIZE, TILE_SIZE,
+                                         tc->surface->format,
+                                         (unsigned *) tile->data.colorui128);
+            } else if (util_format_is_pure_sint(tc->surface->format)) {
+               pipe_get_tile_i_format(pt, tc->transfer_map,
+                                         tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                         tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                         TILE_SIZE, TILE_SIZE,
+                                         tc->surface->format,
+                                         (int *) tile->data.colori128);
+            } else {
+               pipe_get_tile_rgba_format(pt, tc->transfer_map,
+                                         tc->tile_addrs[pos].bits.x * TILE_SIZE,
+                                         tc->tile_addrs[pos].bits.y * TILE_SIZE,
+                                         TILE_SIZE, TILE_SIZE,
+                                         tc->surface->format,
+                                         (float *) tile->data.color);
+            }
          }
       }
    }
 
+   tc->last_tile = tile;
+   tc->last_tile_addr = addr;
    return tile;
 }
 
 
-/**
- * Given the texture face, level, zslice, x and y values, compute
- * the cache entry position/index where we'd hope to find the
- * cached texture tile.
- * This is basically a direct-map cache.
- * XXX There's probably lots of ways in which we can improve this.
- */
-static INLINE uint
-tex_cache_pos(int x, int y, int z, int face, int level)
-{
-   uint entry = x + y * 5 + z * 4 + face + level;
-   return entry % NUM_ENTRIES;
-}
 
 
-/**
- * Similar to sp_get_cached_tile() but for textures.
- * Tiles are read-only and indexed with more params.
- */
-const struct softpipe_cached_tile *
-sp_get_cached_tile_tex(struct softpipe_context *sp,
-                       struct softpipe_tile_cache *tc, int x, int y, int z,
-                       int face, int level)
-{
-   struct pipe_screen *screen = sp->pipe.screen;
-   /* tile pos in framebuffer: */
-   const int tile_x = x & ~(TILE_SIZE - 1);
-   const int tile_y = y & ~(TILE_SIZE - 1);
-   /* cache pos/entry: */
-   const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
-                                  face, level);
-   struct softpipe_cached_tile *tile = tc->entries + pos;
-
-   if (tc->texture) {
-      struct softpipe_texture *spt = softpipe_texture(tc->texture);
-      if (spt->modified) {
-         /* texture was modified, force a cache reload */
-         tile->x = -1;
-         spt->modified = FALSE;
-      }
-   }
-
-   if (tile_x != tile->x ||
-       tile_y != tile->y ||
-       z != tile->z ||
-       face != tile->face ||
-       level != tile->level) {
-      /* cache miss */
-
-      /* check if we need to get a new surface */
-      if (!tc->tex_surf ||
-          tc->tex_face != face ||
-          tc->tex_level != level ||
-          tc->tex_z != z) {
-         /* get new surface (view into texture) */
-
-        if (tc->tex_surf_map)
-            tc->screen->surface_unmap(tc->screen, tc->tex_surf);
-
-         tc->tex_surf = screen->get_tex_surface(screen, tc->texture, face, level, z, 
-                                                PIPE_BUFFER_USAGE_CPU_READ);
-         tc->tex_surf_map = screen->surface_map(screen, tc->tex_surf,
-                                                PIPE_BUFFER_USAGE_CPU_READ);
-
-         tc->tex_face = face;
-         tc->tex_level = level;
-         tc->tex_z = z;
-      }
-
-      /* get tile from the surface (view into texture) */
-      pipe_get_tile_rgba(tc->tex_surf,
-                         tile_x, tile_y, TILE_SIZE, TILE_SIZE,
-                         (float *) tile->data.color);
-      tile->x = tile_x;
-      tile->y = tile_y;
-      tile->z = z;
-      tile->face = face;
-      tile->level = level;
-   }
-
-   return tile;
-}
-
 
 /**
  * When a whole surface is being cleared to a value we can avoid
@@ -564,51 +589,21 @@ sp_get_cached_tile_tex(struct softpipe_context *sp,
  * Save the color and set a 'clearflag' for each tile of the screen.
  */
 void
-sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue)
+sp_tile_cache_clear(struct softpipe_tile_cache *tc,
+                    const union pipe_color_union *color,
+                    uint64_t clearValue)
 {
-   uint r, g, b, a;
    uint pos;
 
-   tc->clear_val = clearValue;
-
-   switch (tc->surface->format) {
-   case PIPE_FORMAT_R8G8B8A8_UNORM:
-      r = (clearValue >> 24) & 0xff;
-      g = (clearValue >> 16) & 0xff;
-      b = (clearValue >>  8) & 0xff;
-      a = (clearValue      ) & 0xff;
-      break;
-   case PIPE_FORMAT_A8R8G8B8_UNORM:
-      r = (clearValue >> 16) & 0xff;
-      g = (clearValue >>  8) & 0xff;
-      b = (clearValue      ) & 0xff;
-      a = (clearValue >> 24) & 0xff;
-      break;
-   case PIPE_FORMAT_B8G8R8A8_UNORM:
-      r = (clearValue >>  8) & 0xff;
-      g = (clearValue >> 16) & 0xff;
-      b = (clearValue >> 24) & 0xff;
-      a = (clearValue      ) & 0xff;
-      break;
-   default:
-      r = g = b = a = 0;
-   }
+   tc->clear_color = *color;
 
-   tc->clear_color[0] = r / 255.0f;
-   tc->clear_color[1] = g / 255.0f;
-   tc->clear_color[2] = b / 255.0f;
-   tc->clear_color[3] = a / 255.0f;
+   tc->clear_val = clearValue;
 
-#if TILE_CLEAR_OPTIMIZATION
    /* set flags to indicate all the tiles are cleared */
    memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
-#else
-   /* disable the optimization */
-   memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
-#endif
 
    for (pos = 0; pos < NUM_ENTRIES; pos++) {
-      struct softpipe_cached_tile *tile = tc->entries + pos;
-      tile->x = tile->y = -1;
+      tc->tile_addrs[pos].bits.invalid = 1;
    }
+   tc->last_tile_addr.bits.invalid = 1;
 }