llvmpipe: fix (potentially) broken AA points, AA lines
[mesa.git] / src / gallium / drivers / softpipe / sp_tile_cache.c
index bd5a672f77e59d683595f4a5c5ace5b37183d57a..112a6fe0cf36cf09425a953fbf6538b3a04e8a05 100644 (file)
  **************************************************************************/
 
 /**
- * Framebuffer/surface tile caching.
+ * Render target tile caching.
  *
  * Author:
  *    Brian Paul
  */
 
 #include "pipe/p_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 50
-
-
-/** 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 */
-};
 
 
 /**
@@ -75,7 +47,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 +55,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,12 +69,10 @@ 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));
 }
@@ -115,14 +83,30 @@ sp_create_tile_cache( struct pipe_screen *screen )
 {
    struct softpipe_tile_cache *tc;
    uint pos;
+   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( softpipe_tile_cache );
    if (tc) {
       tc->screen = screen;
       for (pos = 0; pos < NUM_ENTRIES; pos++) {
-         tc->entries[pos].x =
-         tc->entries[pos].y = -1;
+         tc->entries[pos].addr.bits.invalid = 1;
       }
+      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.
+       * However, it breaks clearing in other situations (such as in
+       * progs/tests/drawbuffers, see bug 24402).
+       */
+#if 0 && TILE_CLEAR_OPTIMIZATION
+      /* set flags to indicate all the tiles are cleared */
+      memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
+#endif
    }
    return tc;
 }
@@ -131,16 +115,15 @@ sp_create_tile_cache( struct pipe_screen *screen )
 void
 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
 {
+   struct pipe_screen *screen;
    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);
+   if (tc->transfer) {
+      screen = tc->transfer->texture->screen;
+      screen->tex_transfer_destroy(tc->transfer);
    }
 
    FREE( tc );
@@ -154,20 +137,30 @@ void
 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
                           struct pipe_surface *ps)
 {
-   assert(!tc->texture);
+   if (tc->transfer) {
+      struct pipe_screen *screen = tc->transfer->texture->screen;
+
+      if (ps == tc->surface)
+         return;
+
+      if (tc->transfer_map) {
+         screen->transfer_unmap(screen, tc->transfer);
+         tc->transfer_map = NULL;
+      }
 
-   if (tc->surface_map) {
-      tc->screen->surface_unmap(tc->screen, tc->surface);
-      tc->surface_map = NULL;
+      screen->tex_transfer_destroy(tc->transfer);
+      tc->transfer = NULL;
    }
 
-   pipe_surface_reference(&tc->surface, ps);
+   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);
+   if (ps) {
+      struct pipe_screen *screen = ps->texture->screen;
+
+      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 ||
@@ -181,7 +174,7 @@ sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
 
 
 /**
- * Return the surface being cached.
+ * Return the transfer being cached.
  */
 struct pipe_surface *
 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
@@ -191,64 +184,23 @@ sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
 
 
 void
-sp_tile_cache_map_surfaces(struct softpipe_tile_cache *tc)
+sp_tile_cache_map_transfers(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);
+   if (tc->transfer && !tc->transfer_map)
+      tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
 }
 
 
 void
-sp_tile_cache_unmap_surfaces(struct softpipe_tile_cache *tc)
+sp_tile_cache_unmap_transfers(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;
+   if (tc->transfer_map) {
+      tc->screen->transfer_unmap(tc->screen, tc->transfer);
+      tc->transfer_map = NULL;
    }
 }
 
 
-/**
- * Specify the texture to cache.
- */
-void
-sp_tile_cache_set_texture(struct pipe_context *pipe,
-                          struct softpipe_tile_cache *tc,
-                          struct pipe_texture *texture)
-{
-   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 */
-}
-
-
 /**
  * Set pixels in a tile to the given clear color/value, float.
  */
@@ -287,9 +239,9 @@ clear_tile(struct softpipe_cached_tile *tile,
 {
    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) {
@@ -325,28 +277,30 @@ 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->width;
+   const uint h = tc->transfer->height;
    uint x, y;
    uint numCleared = 0;
 
+   assert(pt->texture);
    /* clear the scratch tile to the clear value */
-   clear_tile(&tc->tile, ps->format, tc->clear_val);
+   clear_tile(&tc->tile, pt->texture->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) {
-         if (is_clear_flag_set(tc->clear_flags, x, y)) {
-            pipe_put_tile_raw(ps,
+         union tile_address addr = tile_address(x, y);
+
+         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, x, y);
+            clear_clear_flag(tc->clear_flags, addr);
 
             numCleared++;
          }
@@ -359,47 +313,43 @@ sp_tile_cache_flush_clear(struct pipe_context *pipe,
 
 
 /**
- * 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) {
-      /* 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 (!tile->addr.bits.invalid) {
             if (tc->depth_stencil) {
-               pipe_put_tile_raw(ps,
-                                 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+               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 {
-               pipe_put_tile_rgba(ps,
-                                  tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+               pipe_put_tile_rgba(pt,
+                                  tile->addr.bits.x * TILE_SIZE, 
+                                  tile->addr.bits.y * TILE_SIZE, 
+                                  TILE_SIZE, TILE_SIZE,
                                   (float *) tile->data.color);
             }
-            tile->x = tile->y = -1;  /* mark as empty */
+            tile->addr.bits.invalid = 1;  /* mark as empty */
             inuse++;
          }
       }
 
 #if TILE_CLEAR_OPTIMIZATION
-      sp_tile_cache_flush_clear(&softpipe->pipe, tc);
+      sp_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].x = -1;
-      }
-      tc->tex_face = -1;
-   }
 
 #if 0
    debug_printf("flushed tiles in use: %d\n", inuse);
@@ -412,158 +362,74 @@ sp_flush_tile_cache(struct softpipe_context *softpipe,
  * \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);
+   const int pos = CACHE_POS(addr.bits.x,
+                             addr.bits.y);
    struct softpipe_cached_tile *tile = tc->entries + pos;
 
-   if (tile_x != tile->x ||
-       tile_y != tile->y) {
+   if (addr.value != tile->addr.value) {
 
-      if (tile->x != -1) {
+      assert(pt->texture);
+      if (tile->addr.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,
+                              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(ps,
-                               tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+            pipe_put_tile_rgba(pt,
+                               tile->addr.bits.x * TILE_SIZE,
+                               tile->addr.bits.y * TILE_SIZE,
+                               TILE_SIZE, TILE_SIZE,
                                (float *) tile->data.color);
          }
       }
 
-      tile->x = tile_x;
-      tile->y = tile_y;
+      tile->addr = 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->texture->format, tc->clear_val);
          }
          else {
-            clear_tile_rgba(tile, ps->format, tc->clear_color);
+            clear_tile_rgba(tile, pt->texture->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,
+                              tile->addr.bits.x * TILE_SIZE, 
+                              tile->addr.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,
+            pipe_get_tile_rgba(pt,
+                               tile->addr.bits.x * TILE_SIZE, 
+                               tile->addr.bits.y * TILE_SIZE,
+                               TILE_SIZE, TILE_SIZE,
                                (float *) tile->data.color);
          }
       }
    }
 
+   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(int x, int y, int z, int face, int level)
-{
-   uint entry = x + y * 9 + z * 3 + face + level * 7;
-   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, invalidate all cached tiles */
-         uint p;
-         for (p = 0; p < NUM_ENTRIES; p++) {
-            tile = tc->entries + p;
-            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 */
-
-#if 0
-      printf("miss at %u  x=%d y=%d z=%d face=%d level=%d\n", pos,
-             x/TILE_SIZE, y/TILE_SIZE, z, face, level);
-#endif
-      /* 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;
-}
 
 
 /**
@@ -572,40 +438,17 @@ 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 float *rgba,
+                    uint clearValue)
 {
-   uint r, g, b, a;
    uint pos;
 
-   tc->clear_val = clearValue;
+   tc->clear_color[0] = rgba[0];
+   tc->clear_color[1] = rgba[1];
+   tc->clear_color[2] = rgba[2];
+   tc->clear_color[3] = rgba[3];
 
-   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[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 */
@@ -617,6 +460,6 @@ sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue)
 
    for (pos = 0; pos < NUM_ENTRIES; pos++) {
       struct softpipe_cached_tile *tile = tc->entries + pos;
-      tile->x = tile->y = -1;
+      tile->addr.bits.invalid = 1;
    }
 }