Merge branch 'mesa_7_5_branch' into mesa_7_6_branch
[mesa.git] / src / gallium / drivers / llvmpipe / lp_tile_cache.c
index 94908f601c2e288183071eafe9c7985cedc5a7f2..143afec3d35313da6335383dc518980854ebea50 100644 (file)
@@ -36,6 +36,7 @@
 #include "util/u_memory.h"
 #include "util/u_math.h"
 #include "util/u_tile.h"
+#include "util/u_rect.h"
 #include "lp_context.h"
 #include "lp_surface.h"
 #include "lp_texture.h"
 #include "lp_tile_cache.h"
 
 
-
-/**
- * Return the position in the cache for the tile that contains win pos (x,y).
- * We currently use a direct mapped cache so this is like a hack key.
- * At some point we should investige something more sophisticated, like
- * a LRU replacement policy.
- */
-#define CACHE_POS(x, y) \
-   (((x) + (y) * 5) % NUM_ENTRIES)
-
-
-
-/**
- * Is the tile at (x,y) in cleared state?
- */
-static INLINE uint
-is_clear_flag_set(const uint *bitvec, union tile_address addr)
-{
-   int pos, bit;
-   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;
-}
-   
-
-/**
- * Mark the tile at (x,y) as not cleared.
- */
-static INLINE void
-clear_clear_flag(uint *bitvec, union tile_address addr)
-{
-   int pos;
-   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 llvmpipe_tile_cache *
 lp_create_tile_cache( struct pipe_screen *screen )
 {
    struct llvmpipe_tile_cache *tc;
-   uint pos;
 
    tc = CALLOC_STRUCT( llvmpipe_tile_cache );
-   if (tc) {
-      tc->screen = screen;
-      for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         tc->entries[pos].addr.bits.invalid = 1;
-      }
-      tc->last_tile = &tc->entries[0]; /* any tile */
-   }
+   if(!tc)
+      return NULL;
+
+   tc->screen = screen;
+
    return tc;
 }
 
@@ -104,19 +63,21 @@ void
 lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
 {
    struct pipe_screen *screen;
-   uint pos;
+   unsigned x, y;
+
+   for (y = 0; y < MAX_HEIGHT; y += TILE_SIZE) {
+      for (x = 0; x < MAX_WIDTH; x += TILE_SIZE) {
+         struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
 
-   for (pos = 0; pos < NUM_ENTRIES; pos++) {
-      /*assert(tc->entries[pos].x < 0);*/
+         if(tile->color)
+            align_free(tile->color);
+      }
    }
+
    if (tc->transfer) {
       screen = tc->transfer->texture->screen;
       screen->tex_transfer_destroy(tc->transfer);
    }
-   if (tc->tex_trans) {
-      screen = tc->tex_trans->texture->screen;
-      screen->tex_transfer_destroy(tc->tex_trans);
-   }
 
    FREE( tc );
 }
@@ -129,8 +90,6 @@ void
 lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
                           struct pipe_surface *ps)
 {
-   assert(!tc->texture);
-
    if (tc->transfer) {
       struct pipe_screen *screen = tc->transfer->texture->screen;
 
@@ -150,19 +109,23 @@ lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
 
    if (ps) {
       struct pipe_screen *screen = ps->texture->screen;
+      unsigned x, y;
 
       tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
                                               ps->level, ps->zslice,
                                               PIPE_TRANSFER_READ_WRITE,
                                               0, 0, ps->width, ps->height);
 
-      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);
+      for (y = 0; y < ps->height; y += TILE_SIZE) {
+         for (x = 0; x < ps->width; x += TILE_SIZE) {
+            struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
+
+            tile->status = LP_TILE_STATUS_UNDEFINED;
+
+            if(!tile->color)
+               tile->color = align_malloc( TILE_SIZE*TILE_SIZE*NUM_CHANNELS, 16 );
+         }
+      }
    }
 }
 
@@ -182,9 +145,6 @@ lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
 {
    if (tc->transfer && !tc->transfer_map)
       tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
-
-   if (tc->tex_trans && !tc->tex_trans_map)
-      tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
 }
 
 
@@ -195,120 +155,28 @@ lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
       tc->screen->transfer_unmap(tc->screen, tc->transfer);
       tc->transfer_map = NULL;
    }
-
-   if (tc->tex_trans_map) {
-      tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
-      tc->tex_trans_map = NULL;
-   }
 }
 
 
 /**
- * Set pixels in a tile to the given clear color/value, float.
+ * Set a tile to a solid color.
  */
 static void
-clear_tile_rgba(struct llvmpipe_cached_tile *tile,
-                enum pipe_format format,
-                const float clear_value[4])
+clear_tile(struct llvmpipe_cached_tile *tile,
+           uint8_t clear_color[4])
 {
-   if (clear_value[0] == 0.0 &&
-       clear_value[1] == 0.0 &&
-       clear_value[2] == 0.0 &&
-       clear_value[3] == 0.0) {
-      memset(tile->data.color, 0, sizeof(tile->data.color));
+   if (clear_color[0] == clear_color[1] &&
+       clear_color[1] == clear_color[2] &&
+       clear_color[2] == clear_color[3]) {
+      memset(tile->color, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
    }
    else {
-      uint8_t c[4];
-      uint x, y, i;
-      for (i = 0; i < 4; ++i)
-         c[i] = float_to_ubyte(clear_value[i]);
+      uint x, y, chan;
       for (y = 0; y < TILE_SIZE; y++)
          for (x = 0; x < TILE_SIZE; x++)
-            for (i = 0; i < 4; ++i)
-               TILE_PIXEL(tile->data.color, x, y, i) = c[i];
-   }
-}
-
-
-/**
- * Set a tile to a solid value/color.
- */
-static void
-clear_tile(struct llvmpipe_cached_tile *tile,
-           enum pipe_format format,
-           uint clear_value)
-{
-   uint i, j;
-
-   switch (pf_get_size(format)) {
-   case 1:
-      memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
-      break;
-   case 2:
-      if (clear_value == 0) {
-         memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
-      }
-      else {
-         for (i = 0; i < TILE_SIZE; i++) {
-            for (j = 0; j < TILE_SIZE; j++) {
-               tile->data.depth16[i][j] = (ushort) clear_value;
-            }
-         }
-      }
-      break;
-   case 4:
-      if (clear_value == 0) {
-         memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
-      }
-      else {
-         for (i = 0; i < TILE_SIZE; i++) {
-            for (j = 0; j < TILE_SIZE; j++) {
-               tile->data.color32[i][j] = clear_value;
-            }
-         }
-      }
-      break;
-   default:
-      assert(0);
-   }
-}
-
-
-/**
- * Actually clear the tiles which were flagged as being in a clear state.
- */
-static void
-lp_tile_cache_flush_clear(struct llvmpipe_tile_cache *tc)
-{
-   struct pipe_transfer *pt = tc->transfer;
-   const uint w = tc->transfer->width;
-   const uint h = tc->transfer->height;
-   uint x, y;
-   uint numCleared = 0;
-
-   /* clear the scratch tile to the clear value */
-   clear_tile(&tc->tile, pt->format, tc->clear_val);
-
-   /* 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) {
-         union tile_address addr = tile_address(x, y, 0, 0, 0);
-
-         if (is_clear_flag_set(tc->clear_flags, addr)) {
-            pipe_put_tile_raw(pt,
-                              x, y, TILE_SIZE, TILE_SIZE,
-                              tc->tile.data.color32, 0/*STRIDE*/);
-
-            /* do this? */
-            clear_clear_flag(tc->clear_flags, addr);
-
-            numCleared++;
-         }
-      }
+            for (chan = 0; chan < 4; ++chan)
+               TILE_PIXEL(tile->color, x, y, chan) = clear_color[chan];
    }
-#if 0
-   debug_printf("num cleared: %u\n", numCleared);
-#endif
 }
 
 
@@ -320,46 +188,52 @@ void
 lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
 {
    struct pipe_transfer *pt = tc->transfer;
-   int inuse = 0, pos;
-
-   if (pt) {
-      /* caching a drawing transfer */
-      for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         struct llvmpipe_cached_tile *tile = tc->entries + pos;
-         if (!tile->addr.bits.invalid) {
-            if (tc->depth_stencil) {
-               pipe_put_tile_raw(pt,
-                                 tile->addr.bits.x * TILE_SIZE, 
-                                 tile->addr.bits.y * TILE_SIZE, 
-                                 TILE_SIZE, TILE_SIZE,
-                                 tile->data.depth32, 0/*STRIDE*/);
-            }
-            else {
-               lp_put_tile_rgba_soa(pt,
-                                    tile->addr.bits.x * TILE_SIZE,
-                                    tile->addr.bits.y * TILE_SIZE,
-                                    tile->data.color);
-            }
-            tile->addr.bits.invalid = 1;  /* mark as empty */
-            inuse++;
+   unsigned x, y;
+
+   if(!pt)
+      return;
+
+   /* push the tile to all positions marked as clear */
+   for (y = 0; y < pt->height; y += TILE_SIZE) {
+      for (x = 0; x < pt->width; x += TILE_SIZE) {
+         struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
+
+         switch(tile->status) {
+         case LP_TILE_STATUS_UNDEFINED:
+            break;
+
+         case LP_TILE_STATUS_CLEAR: {
+            /**
+             * Actually clear the tiles which were flagged as being in a clear state.
+             */
+
+            struct pipe_screen *screen = pt->texture->screen;
+            unsigned tw = TILE_SIZE;
+            unsigned th = TILE_SIZE;
+            void *dst;
+
+            if (pipe_clip_tile(x, y, &tw, &th, pt))
+               continue;
+
+            dst = screen->transfer_map(screen, pt);
+            assert(dst);
+            if(!dst)
+               continue;
+
+            util_fill_rect(dst, &pt->block, pt->stride,
+                           x, y, tw,  th,
+                           tc->clear_val);
+
+            screen->transfer_unmap(screen, pt);
+            break;
          }
-      }
 
-#if TILE_CLEAR_OPTIMIZATION
-      lp_tile_cache_flush_clear(tc);
-#endif
-   }
-   else if (tc->texture) {
-      /* caching a texture, mark all entries as empty */
-      for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         tc->entries[pos].addr.bits.invalid = 1;
+         case LP_TILE_STATUS_DEFINED:
+            lp_put_tile_rgba_soa(pt, x, y, tile->color);
+            break;
+         }
       }
-      tc->tex_face = -1;
    }
-
-#if 0
-   debug_printf("flushed tiles in use: %d\n", inuse);
-#endif
 }
 
 
@@ -367,88 +241,32 @@ lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
  * Get a tile from the cache.
  * \param x, y  position of tile, in pixels
  */
-struct llvmpipe_cached_tile *
-lp_find_cached_tile(struct llvmpipe_tile_cache *tc, 
-                    union tile_address addr )
+void *
+lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
+                   unsigned x, unsigned y )
 {
+   struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
    struct pipe_transfer *pt = tc->transfer;
    
-   /* cache pos/entry: */
-   const int pos = CACHE_POS(addr.bits.x,
-                             addr.bits.y);
-   struct llvmpipe_cached_tile *tile = tc->entries + pos;
-
-   if (addr.value != tile->addr.value) {
-
-      if (tile->addr.bits.invalid == 0) {
-         /* put dirty tile back in framebuffer */
-         if (tc->depth_stencil) {
-            pipe_put_tile_raw(pt,
-                              tile->addr.bits.x * TILE_SIZE,
-                              tile->addr.bits.y * TILE_SIZE,
-                              TILE_SIZE, TILE_SIZE,
-                              tile->data.depth32, 0/*STRIDE*/);
-         }
-         else {
-            lp_put_tile_rgba_soa(pt,
-                                 tile->addr.bits.x * TILE_SIZE,
-                                 tile->addr.bits.y * TILE_SIZE,
-                                 tile->data.color);
-         }
-      }
+   switch(tile->status) {
+   case LP_TILE_STATUS_CLEAR:
+      /* don't get tile from framebuffer, just clear it */
+      clear_tile(tile, tc->clear_color);
+      tile->status = LP_TILE_STATUS_DEFINED;
+      break;
 
-      tile->addr = addr;
+   case LP_TILE_STATUS_UNDEFINED:
+      /* get new tile data from transfer */
+      lp_get_tile_rgba_soa(pt, x, y, tile->color);
+      tile->status = LP_TILE_STATUS_DEFINED;
+      break;
 
-      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, pt->format, tc->clear_val);
-         }
-         else {
-            clear_tile_rgba(tile, pt->format, tc->clear_color);
-         }
-         clear_clear_flag(tc->clear_flags, addr);
-      }
-      else {
-         /* get new tile data from transfer */
-         if (tc->depth_stencil) {
-            pipe_get_tile_raw(pt,
-                              tile->addr.bits.x * TILE_SIZE, 
-                              tile->addr.bits.y * TILE_SIZE, 
-                              TILE_SIZE, TILE_SIZE,
-                              tile->data.depth32, 0/*STRIDE*/);
-         }
-         else {
-            lp_get_tile_rgba_soa(pt,
-                                 tile->addr.bits.x * TILE_SIZE,
-                                 tile->addr.bits.y * TILE_SIZE,
-                                 tile->data.color);
-         }
-      }
+   case LP_TILE_STATUS_DEFINED:
+      /* nothing to do */
+      break;
    }
 
-   tc->last_tile = tile;
-   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( union tile_address addr )
-{
-   uint entry = (addr.bits.x + 
-                 addr.bits.y * 9 + 
-                 addr.bits.z * 3 + 
-                 addr.bits.face + 
-                 addr.bits.level * 7);
-
-   return entry % NUM_ENTRIES;
+   return tile->color;
 }
 
 
@@ -461,25 +279,21 @@ void
 lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
                     uint clearValue)
 {
-   uint pos;
+   struct pipe_transfer *pt = tc->transfer;
+   const unsigned w = pt->width;
+   const unsigned h = pt->height;
+   unsigned x, y, chan;
 
-   tc->clear_color[0] = rgba[0];
-   tc->clear_color[1] = rgba[1];
-   tc->clear_color[2] = rgba[2];
-   tc->clear_color[3] = rgba[3];
+   for(chan = 0; chan < 4; ++chan)
+      tc->clear_color[chan] = float_to_ubyte(rgba[chan]);
 
    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 llvmpipe_cached_tile *tile = tc->entries + pos;
-      tile->addr.bits.invalid = 1;
+   /* 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) {
+         struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
+         tile->status = LP_TILE_STATUS_CLEAR;
+      }
    }
 }