tgsi: rename fields of tgsi_full_instruction to avoid excessive verbosity
[mesa.git] / src / gallium / drivers / llvmpipe / lp_tile_cache.c
index 074d2dabb432f412185f57ee86919793b9e35b4c..ec3e002d6282697f2bba27c45581773cbc1516db 100644 (file)
 #include "lp_tile_cache.h"
 
 
+#define MAX_WIDTH 4096
+#define MAX_HEIGHT 4096
 
-/**
- * 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)
 
+enum llvmpipe_tile_status
+{
+   LP_TILE_STATUS_UNDEFINED = 0,
+   LP_TILE_STATUS_CLEAR = 1,
+   LP_TILE_STATUS_DEFINED = 2
+};
 
 
-/**
- * Is the tile at (x,y) in cleared state?
- */
-static INLINE uint
-is_clear_flag_set(const uint *bitvec, union tile_address addr)
+struct llvmpipe_cached_tile
 {
-   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;
-}
-   
+   enum llvmpipe_tile_status status;
 
-/**
- * Mark the tile at (x,y) as not cleared.
- */
-static INLINE void
-clear_clear_flag(uint *bitvec, union tile_address addr)
+   /** color in SOA format */
+   uint8_t *color;
+};
+
+
+struct llvmpipe_tile_cache
 {
-   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 pipe_screen *screen;
+   struct pipe_surface *surface;  /**< the surface we're caching */
+   struct pipe_transfer *transfer;
+   void *transfer_map;
+
+   struct llvmpipe_cached_tile entries[MAX_WIDTH/TILE_SIZE][MAX_HEIGHT/TILE_SIZE];
+
+   uint8_t clear_color[4];  /**< for color bufs */
+   uint clear_val;        /**< for z+stencil, or packed color clear value */
+
+   struct llvmpipe_cached_tile *last_tile;  /**< most recently retrieved tile */
+};
+
 
 struct llvmpipe_tile_cache *
 lp_create_tile_cache( struct pipe_screen *screen )
 {
    struct llvmpipe_tile_cache *tc;
-   uint pos;
-
-   tc = align_malloc( sizeof(struct llvmpipe_tile_cache), 16 );
-   if (tc) {
-      memset(tc, 0, sizeof *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 */
-   }
+   int maxLevels, maxTexSize;
+
+   /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
+   maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
+   maxTexSize = 1 << (maxLevels - 1);
+   assert(MAX_WIDTH >= maxTexSize);
+
+   tc = CALLOC_STRUCT( llvmpipe_tile_cache );
+   if(!tc)
+      return NULL;
+
+   tc->screen = screen;
+
    return tc;
 }
 
@@ -106,21 +106,23 @@ void
 lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
 {
    struct pipe_screen *screen;
-   uint pos;
+   unsigned x, y;
 
-   for (pos = 0; pos < NUM_ENTRIES; pos++) {
-      /*assert(tc->entries[pos].x < 0);*/
+   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];
+
+         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);
-   }
 
-   align_free( tc );
+   FREE( tc );
 }
 
 
@@ -131,8 +133,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;
 
@@ -152,11 +152,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);
+
+      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 );
+         }
+      }
    }
 }
 
@@ -176,9 +188,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);
 }
 
 
@@ -189,11 +198,6 @@ 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;
-   }
 }
 
 
@@ -219,54 +223,6 @@ clear_tile(struct llvmpipe_cached_tile *tile,
 }
 
 
-/**
- * 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;
-   struct pipe_screen *screen = pt->texture->screen;
-   const uint w = tc->transfer->width;
-   const uint h = tc->transfer->height;
-   uint x, y;
-   uint numCleared = 0;
-
-   /* 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)) {
-            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;
-
-            pipe_fill_rect(dst, &pt->block, pt->stride,
-                           x, y, tw,  th,
-                           tc->clear_val);
-
-            /* do this? */
-            clear_clear_flag(tc->clear_flags, addr);
-
-            numCleared++;
-         }
-      }
-   }
-#if 0
-   debug_printf("num cleared: %u\n", numCleared);
-#endif
-}
-
-
 /**
  * Flush the tile cache: write all dirty tiles back to the transfer.
  * any tiles "flagged" as cleared will be "really" cleared.
@@ -275,37 +231,49 @@ 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) {
-            lp_put_tile_rgba_soa(pt,
-                                 tile->addr.bits.x * TILE_SIZE,
-                                 tile->addr.bits.y * TILE_SIZE,
-                                 tile->color);
-            tile->addr.bits.invalid = 1;  /* mark as empty */
-            inuse++;
-         }
-      }
+   unsigned x, y;
 
-#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;
+   if(!pt)
+      return;
+
+   assert(tc->transfer_map);
+
+   /* 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];
+
+         if(tile->status != LP_TILE_STATUS_UNDEFINED) {
+            unsigned w = TILE_SIZE;
+            unsigned h = TILE_SIZE;
+
+            if (!pipe_clip_tile(x, y, &w, &h, pt)) {
+               switch(tile->status) {
+               case LP_TILE_STATUS_CLEAR:
+                  /* Actually clear the tiles which were flagged as being in a
+                   * clear state. */
+                  util_fill_rect(tc->transfer_map, &pt->block, pt->stride,
+                                 x, y, w, h,
+                                 tc->clear_val);
+                  break;
+
+               case LP_TILE_STATUS_DEFINED:
+                  lp_tile_write_4ub(pt->format,
+                                    tile->color,
+                                    tc->transfer_map, pt->stride,
+                                    x, y, w, h);
+                  break;
+
+               default:
+                  assert(0);
+                  break;
+               }
+            }
+
+            tile->status = LP_TILE_STATUS_UNDEFINED;
+         }
       }
-      tc->tex_face = -1;
    }
-
-#if 0
-   debug_printf("flushed tiles in use: %d\n", inuse);
-#endif
 }
 
 
@@ -314,68 +282,48 @@ lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
  * \param x, y  position of tile, in pixels
  */
 void *
-lp_find_cached_tile(struct llvmpipe_tile_cache *tc, 
-                    union tile_address addr )
+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 */
-         lp_put_tile_rgba_soa(pt,
-                              tile->addr.bits.x * TILE_SIZE,
-                              tile->addr.bits.y * TILE_SIZE,
-                              tile->color);
-      }
-
-      tile->addr = addr;
-
-      if (is_clear_flag_set(tc->clear_flags, addr)) {
-         /* don't get tile from framebuffer, just clear it */
-         clear_tile(tile, tc->clear_color);
-         clear_clear_flag(tc->clear_flags, addr);
-      }
-      else {
-         /* get new tile data from transfer */
-         lp_get_tile_rgba_soa(pt,
-                              tile->addr.bits.x * TILE_SIZE,
-                              tile->addr.bits.y * TILE_SIZE,
-                              tile->color);
-      }
+   assert(tc->surface);
+   assert(tc->transfer);
+
+   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;
+
+   case LP_TILE_STATUS_UNDEFINED: {
+      unsigned w = TILE_SIZE;
+      unsigned h = TILE_SIZE;
+
+      x &= ~(TILE_SIZE - 1);
+      y &= ~(TILE_SIZE - 1);
+
+      if (!pipe_clip_tile(x, y, &w, &h, tc->transfer))
+         lp_tile_read_4ub(pt->format,
+                          tile->color,
+                          tc->transfer_map, tc->transfer->stride,
+                          x, y, w, h);
+
+      tile->status = LP_TILE_STATUS_DEFINED;
+      break;
    }
 
-   tc->last_tile = tile;
+   case LP_TILE_STATUS_DEFINED:
+      /* nothing to do */
+      break;
+   }
 
    return tile->color;
 }
 
 
-/**
- * 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;
-}
-
-
 /**
  * When a whole surface is being cleared to a value we can avoid
  * fetching tiles above.
@@ -385,24 +333,21 @@ void
 lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
                     uint clearValue)
 {
-   unsigned chan;
-   uint pos;
+   struct pipe_transfer *pt = tc->transfer;
+   const unsigned w = pt->width;
+   const unsigned h = pt->height;
+   unsigned x, y, chan;
 
    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;
+      }
    }
 }