Merge the lp-surface-tiling branch into master.

This branch implemented dual representations of texture/drawing surfaces:
one in the conventional linear layout and the other the tiled layout which
is used by the fragment shader pipe.  Per-tile flags indicate the layout
of each image tile.  In many situations this lets us avoid converting
image data between the two layouts.

Squashed commit of the following:

commit 563a7e3cc552fdcfcaf9ac0d4b1683c3ba2ae732
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Apr 8 14:48:21 2010 -0600

    llvmpipe: convert points/lines to triangles with draw module

    This isn't the most efficient way to render points/lines but it allows us
    to run more tests.

commit a8aa763e8a717533f2b13bb6ea53cbccbede68c9
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Apr 8 14:47:28 2010 -0600

    llvmpipe: call llvmpipe_get_texture_tile() for depth/stencil

    The returned pointer isn't used, but the tile status/layout info
    gets updated.  Helps to fix glReadPixels(DEPTH / STENCIL).

commit 463bc64af266194acbea71cd52e26a79b8c8a260
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Apr 8 10:58:48 2010 -0600

    llvmpipe: add store_color to debug cmd_names list

commit 784cc73fb334a9d7b7c93cbd8a1445cdf742ff58
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Apr 8 10:57:43 2010 -0600

    llvmpipe: fix debug build

commit 792c93171ec075664f55720ffed397ac2834a4fc
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Apr 8 10:49:01 2010 -0600

    llvmpipe: fix cube mapping

commit 882b1035db88c3dd8aebe28dc971ac30a9ee39e3
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Apr 8 09:53:30 2010 -0600

    llvmpipe: remove some older/unused code

commit b807d32b23145301e8842824664d9f06b9c5502e
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Apr 8 09:29:50 2010 -0600

    llvmpipe: silence warning

commit 7b337e64fec92836ccdf9d96216289dd58418e35
Author: Brian Paul <brianp@vmware.com>
Date:   Wed Apr 7 17:06:08 2010 -0600

    llvmpipe: clean-up, comments in lp_surface_copy()

commit c52fa36f249cc652fa8d5fdd94d6574127c08c41
Author: Brian Paul <brianp@vmware.com>
Date:   Wed Apr 7 16:51:42 2010 -0600

    llvmpipe: overhaul tiled/linear memory management

    Now we keep per-tile layout info (linear vs. tiled (or neither or both)
    and convert from one layout to the other on demand.

commit 4a50ccfd470547c9be0704005818a87014e9c0e9
Author: Brian Paul <brianp@vmware.com>
Date:   Wed Apr 7 16:51:27 2010 -0600

    llvmpipe: added tile read/write counters

commit b7d0ea9c687ac8773b083791623826fa604adf21
Author: Brian Paul <brianp@vmware.com>
Date:   Mon Apr 5 14:54:04 2010 -0600

    llvmpipe: rename some functions

commit ee45c6e5b95cbd3c8cccc9aa4d45d8aef11e20c4
Author: Brian Paul <brianp@vmware.com>
Date:   Mon Apr 5 14:42:15 2010 -0600

    llvmpipe: re-org some get block/tile pointer code

commit 26ce97c16c0b6520ff1538803baa772d8c3b1280
Author: Brian Paul <brianp@vmware.com>
Date:   Mon Apr 5 14:34:13 2010 -0600

    llvmpipe: disable bad assertions

commit 5c670481248c4d46f87f13bf3af5655925e7002d
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Apr 2 16:36:11 2010 -0600

    llvmpipe: add a special-case optimization to lp_surface_copy()

    Be more efficient when copying tiled image to linear image.
    Before, the fallback path was always converting the whole source image
    to linear.  Now we can convert just a sub region.

commit faa684645e64d6024b3a11e4e08da825e8220b2e
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Apr 2 16:15:16 2010 -0600

    llvmpipe: assorted texture and tile/line conversion code change s

    The tiled/linear conversion functions take x/y positions now to
    allow converting only sub-regions.

    More texture-related helper functions.

commit baad81ec5318d44bfac1e37c7643afc0836607bb
Author: Brian Paul <brianp@vmware.com>
Date:   Tue Mar 30 13:18:40 2010 -0600

    llvmpipe: convert tiled->linear upon PIPE_FLUSH_SWAPBUFFERS

    If we know we're about to do a swapbuffers we should immediately
    convert the tiled color tiles to linear instead of later in
    llvmpipe_texture_unmap() since we can take advantage of threading/
    parallelism here.

commit 928dd41256811daeddb7506a49a34dbad04beaf8
Author: Brian Paul <brianp@vmware.com>
Date:   Tue Mar 30 09:16:58 2010 -0600

    llvmpipe: polish-up the llvmpipe_flush() code

commit dd6014abcf86c517d159b8175e0eaeb167ea2ef6
Author: Brian Paul <brianp@vmware.com>
Date:   Tue Mar 30 09:15:17 2010 -0600

    llvmpipe: SETUP_x enum clean-up

commit 0b1ce6da2b28a41f3389685ab93e10b43c950f5d
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Mar 26 10:43:37 2010 -0600

    llvmpipe: remove unused vars

commit 4562663480f88162ed4452cb05569eecb67f9f39
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Mar 26 10:31:55 2010 -0600

    llvmpipe: cope with non-existant color/depth buffers

    The fragment jit functions always grab these pointers, even if they're
    not used.

commit df4329edbaf204ed501f1eac0698b8198178f9af
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Mar 25 15:20:15 2010 -0600

    llvmpipe: do all render target surface mapping/unmapping in the rast code

commit 3d0c25d5ba8b8f61e8366d4c97324e45d526ff41
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Mar 25 14:31:21 2010 -0600

    llvmpipe: map z/stencil buffer on demand like color buffers

    Plus lots of code clean-up and loose ends taken care of.

commit c3b6fddd788aef09b4b84b843b7b1272231151e8
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Mar 25 13:15:03 2010 -0600

    llvmpipe: remove unused write_zstencil field

commit 63374d97836926a6357e9d6dd24a509a8e155c56
Author: Brian Paul <brianp@vmware.com>
Date:   Thu Mar 25 09:45:59 2010 -0600

    llvmpipe: add missing lp_rast_end() call

    Fixes crash on window resize when LP_NUM_THREADS=0.

commit 92fe9952161cc06f6edc58778e9e5a8b9ea447dc
Author: Brian Paul <brianp@vmware.com>
Date:   Wed Mar 24 10:15:19 2010 -0600

    llvmpipe: add tiled/linear conversion for 16-bit Z images

commit 6605fa28c147f30df351da0e4413cab33e4db5da
Author: Brian Paul <brianp@vmware.com>
Date:   Tue Mar 23 16:06:41 2010 -0600

    llvmpipe: implement tiled/linear conversion for Z/stencil images

commit 804528d84ffa292ef9d49d3666cdd3fa099ff3ff
Author: Brian Paul <brianp@vmware.com>
Date:   Tue Mar 23 16:05:45 2010 -0600

    llvmpipe: added texture stride comment

commit 66a88c012edf670c4ac887a912f02dcff93266dd
Author: Brian Paul <brianp@vmware.com>
Date:   Tue Mar 23 16:04:07 2010 -0600

    llvmpipe: remove unused vars

commit e2ca8d1328316dc8b36d5f688c16d109e49a6870
Author: Brian Paul <brianp@vmware.com>
Date:   Mon Mar 22 18:53:11 2010 -0600

    llvmpipe: checkpoint WIP: overhaul texture/surface mapping

    Conversion between tiled and linear surfaces is working everywhere now.
    The LP_TEXTURE_READ/READ_WRITE/WRITE_ALL flags let us avoid unnecessary
    image layout conversions.

    Still some loose ends, temporary/debug code, etc.
    Need to implement tiled/linear conversion for depth/stencil images.

commit f2730a03839ee8984c1f537b7cbebba24961397a
Author: Brian Paul <brianp@vmware.com>
Date:   Mon Mar 22 14:41:58 2010 -0600

    llvmpipe: rename/repurpose lp_rast_store_color()

commit e192a47552c5d20d2caef452ca7697e2cd852c9b
Author: Brian Paul <brianp@vmware.com>
Date:   Mon Mar 22 14:38:51 2010 -0600

    llvmpipe: remove lp_rast_load_color()

commit 3cff0bde4b4ab980e1c3e812700419091527c76b
Author: Brian Paul <brianp@vmware.com>
Date:   Mon Mar 22 14:11:38 2010 -0600

    llvmpipe: remove/consolidate texture image code

commit 3a2f08b6a550c69ef5e874f482be30252cbf8bfa
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Mar 19 17:03:14 2010 -0600

    llvmpipe: checkpoint WIP: directly render to tiled texture buffers

    We're now directly writing colors into the tiled texture image buffers.

    This is a checkpoint commit with lots of dead code and temporary hacks.
    Everything will get cleaned up eventually.

commit c5ca987e03870849514d4e3c99af143722a09695
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Mar 19 16:41:14 2010 -0600

    llvmpipe: refactor code, create tile_pixel_offset()

commit 2133e8273e937cbac09cd7264d6ce53af9764ddb
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Mar 19 14:55:11 2010 -0600

    llvmpipe: pass LP_TEXTURE_LINEAR/TILED flags around

commit b9b9d4b82b01f4588721fdc8444740f859b4a021
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Mar 19 14:51:05 2010 -0600

    llvmpipe: checkpoint WIP: hanlde co-existing tiled/linear texture data

    Cube maps are temporarily broken, maybe other things.

commit 4cd322e6889940b5f155fcb69041b685b9ef9273
Author: Brian Paul <brianp@vmware.com>
Date:   Fri Mar 19 11:34:43 2010 -0600

    progs/demos: add other modes/patterns to dissolve demo
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
index 61210de..7e4e4d5 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.c
+++ b/src/gallium/drivers/llvmpipe/lp_texture.c
@@ -30,64 +30,101 @@
   *   Michel Dänzer <michel@tungstengraphics.com>
   */
 
+#include <stdio.h>
+
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
-#include "util/u_inlines.h"
 
+#include "util/u_inlines.h"
 #include "util/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 #include "util/u_transfer.h"
 
 #include "lp_context.h"
-#include "lp_screen.h"
 #include "lp_flush.h"
+#include "lp_screen.h"
+#include "lp_tile_image.h"
 #include "lp_texture.h"
 #include "lp_setup.h"
 #include "lp_tile_size.h"
+
 #include "state_tracker/sw_winsys.h"
 
 
+static INLINE boolean
+resource_is_texture(const struct pipe_resource *resource)
+{
+   const unsigned tex_binds = (PIPE_BIND_DISPLAY_TARGET |
+                               PIPE_BIND_SCANOUT |
+                               PIPE_BIND_SHARED |
+                               PIPE_BIND_DEPTH_STENCIL |
+                               PIPE_BIND_SAMPLER_VIEW);
+   const struct llvmpipe_resource *lpt = llvmpipe_resource_const(resource);
+
+   return (lpt->base.bind & tex_binds) ? TRUE : FALSE;
+}
+
+
+
+/**
+ * Allocate storage for llvmpipe_texture::layout array.
+ * The number of elements is width_in_tiles * height_in_tiles.
+ */
+static enum lp_texture_layout *
+alloc_layout_array(unsigned width, unsigned height)
+{
+   const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE;
+   const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE;
+
+   assert(tx * ty > 0);
+   assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */
+
+   return (enum lp_texture_layout *)
+      calloc(tx * ty, sizeof(enum lp_texture_layout));
+}
+
+
+
 /**
  * Conventional allocation path for non-display textures:
- * Simple, maximally packed layout.
+ * Just compute row strides here.  Storage is allocated on demand later.
  */
 static boolean
-llvmpipe_resource_layout(struct llvmpipe_screen *screen,
+llvmpipe_texture_layout(struct llvmpipe_screen *screen,
                         struct llvmpipe_resource *lpt)
 {
    struct pipe_resource *pt = &lpt->base;
    unsigned level;
    unsigned width = pt->width0;
    unsigned height = pt->height0;
-   unsigned depth = pt->depth0;
-   unsigned buffer_size = 0;
+
+   assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
+   assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
 
    for (level = 0; level <= pt->last_level; level++) {
-      unsigned nblocksx, nblocksy;
+      const unsigned num_faces = lpt->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
+      unsigned nblocksx, face;
 
       /* Allocate storage for whole quads. This is particularly important
        * for depth surfaces, which are currently stored in a swizzled format.
        */
       nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
-      nblocksy = util_format_get_nblocksy(pt->format, align(height, TILE_SIZE));
 
-      lpt->stride[level] = align(nblocksx * util_format_get_blocksize(pt->format), 16);
+      lpt->stride[level] =
+         align(nblocksx * util_format_get_blocksize(pt->format), 16);
 
-      lpt->level_offset[level] = buffer_size;
+      lpt->tiles_per_row[level] = align(width, TILE_SIZE) / TILE_SIZE;
 
-      buffer_size += (nblocksy *
-                      ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
-                      lpt->stride[level]);
+      for (face = 0; face < num_faces; face++) {
+         lpt->layout[face][level] = alloc_layout_array(width, height);
+      }
 
       width = u_minify(width, 1);
       height = u_minify(height, 1);
-      depth = u_minify(depth, 1);
    }
 
-   lpt->data = align_malloc(buffer_size, 16);
-
-   return lpt->data != NULL;
+   return TRUE;
 }
 
 
@@ -104,6 +141,10 @@
    unsigned width = align(lpt->base.width0, TILE_SIZE);
    unsigned height = align(lpt->base.height0, TILE_SIZE);
 
+   lpt->tiles_per_row[0] = align(width, TILE_SIZE) / TILE_SIZE;
+
+   lpt->layout[0][0] = alloc_layout_array(width, height);
+
    lpt->dt = winsys->displaytarget_create(winsys,
                                           lpt->base.bind,
                                           lpt->base.format,
@@ -117,8 +158,9 @@
 
 static struct pipe_resource *
 llvmpipe_resource_create(struct pipe_screen *_screen,
-                        const struct pipe_resource *templat)
+                         const struct pipe_resource *templat)
 {
+   static unsigned id_counter = 0;
    struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
    struct llvmpipe_resource *lpt = CALLOC_STRUCT(llvmpipe_resource);
    if (!lpt)
@@ -128,17 +170,38 @@
    pipe_reference_init(&lpt->base.reference, 1);
    lpt->base.screen = &screen->base;
 
+   assert(lpt->base.bind);
+
    if (lpt->base.bind & (PIPE_BIND_DISPLAY_TARGET |
                          PIPE_BIND_SCANOUT |
                          PIPE_BIND_SHARED)) {
+      /* displayable surface */
       if (!llvmpipe_displaytarget_layout(screen, lpt))
          goto fail;
+      assert(lpt->layout[0][0][0] == LP_TEX_LAYOUT_NONE);
+   }
+   else if (lpt->base.bind & (PIPE_BIND_SAMPLER_VIEW |
+                              PIPE_BIND_DEPTH_STENCIL)) {
+      /* texture map */
+      if (!llvmpipe_texture_layout(screen, lpt))
+         goto fail;
+      assert(lpt->layout[0][0][0] == LP_TEX_LAYOUT_NONE);
    }
    else {
-      if (!llvmpipe_resource_layout(screen, lpt))
+      /* other data (vertex buffer, const buffer, etc) */
+      const enum pipe_format format = templat->format;
+      const uint w = templat->width0 / util_format_get_blockheight(format);
+      const uint h = templat->height0 / util_format_get_blockwidth(format);
+      const uint d = templat->depth0;
+      const uint bpp = util_format_get_blocksize(format);
+      const uint bytes = w * h * d * bpp;
+      lpt->data = align_malloc(bytes, 16);
+      if (!lpt->data)
          goto fail;
    }
 
+   lpt->id = id_counter++;
+
    return &lpt->base;
 
  fail:
@@ -159,8 +222,37 @@
       struct sw_winsys *winsys = screen->winsys;
       winsys->displaytarget_destroy(winsys, lpt->dt);
    }
-   else if (!lpt->userBuffer) {
+   else if (resource_is_texture(pt)) {
       /* regular texture */
+      const uint num_faces = pt->target == PIPE_TEXTURE_CUBE ? 6 : 1;
+      uint level, face;
+
+      /* free linear image data */
+      for (level = 0; level < Elements(lpt->linear); level++) {
+         if (lpt->linear[level].data) {
+            align_free(lpt->linear[level].data);
+            lpt->linear[level].data = NULL;
+         }
+      }
+
+      /* free tiled image data */
+      for (level = 0; level < Elements(lpt->tiled); level++) {
+         if (lpt->tiled[level].data) {
+            align_free(lpt->tiled[level].data);
+            lpt->tiled[level].data = NULL;
+         }
+      }
+
+      /* free layout flag arrays */
+      for (level = 0; level < Elements(lpt->tiled); level++) {
+         for (face = 0; face < num_faces; face++) {
+            free(lpt->layout[face][level]);
+            lpt->layout[face][level] = NULL;
+         }
+      }
+   }
+   else if (!lpt->userBuffer) {
+      assert(lpt->data);
       align_free(lpt->data);
    }
 
@@ -169,63 +261,88 @@
 
 
 /**
- * Map a texture. Without any synchronization.
+ * Map a texture for read/write (rendering).  Without any synchronization.
  */
 void *
 llvmpipe_resource_map(struct pipe_resource *texture,
-		      unsigned usage,
 		      unsigned face,
 		      unsigned level,
-		      unsigned zslice)
+		      unsigned zslice,
+                      enum lp_texture_usage tex_usage,
+                      enum lp_texture_layout layout)
 {
    struct llvmpipe_resource *lpt = llvmpipe_resource(texture);
    uint8_t *map;
 
+   assert(face < 6);
+   assert(level < LP_MAX_TEXTURE_LEVELS);
+
+   assert(tex_usage == LP_TEX_USAGE_READ ||
+          tex_usage == LP_TEX_USAGE_READ_WRITE ||
+          tex_usage == LP_TEX_USAGE_WRITE_ALL);
+
+   assert(layout == LP_TEX_LAYOUT_NONE ||
+          layout == LP_TEX_LAYOUT_TILED ||
+          layout == LP_TEX_LAYOUT_LINEAR);
+
    if (lpt->dt) {
       /* display target */
       struct llvmpipe_screen *screen = llvmpipe_screen(texture->screen);
       struct sw_winsys *winsys = screen->winsys;
+      unsigned dt_usage;
+
+      if (tex_usage == LP_TEX_USAGE_READ) {
+         dt_usage = PIPE_TRANSFER_READ;
+      }
+      else {
+         dt_usage = PIPE_TRANSFER_READ_WRITE;
+      }
 
       assert(face == 0);
       assert(level == 0);
       assert(zslice == 0);
 
       /* FIXME: keep map count? */
-      map = winsys->displaytarget_map(winsys, lpt->dt, usage);
+      map = winsys->displaytarget_map(winsys, lpt->dt, dt_usage);
+
+      /* install this linear image in texture data structure */
+      lpt->linear[level].data = map;
+
+      map = llvmpipe_get_texture_image(lpt, face, level, tex_usage, layout);
+      assert(map);
+
+      return map;
    }
-   else {
+   else if (resource_is_texture(texture)) {
       /* regular texture */
-      unsigned offset;
-      unsigned stride;
+      const unsigned tex_height = u_minify(texture->height0, level);
+      const unsigned nblocksy =
+         util_format_get_nblocksy(texture->format, tex_height);
+      const unsigned stride = lpt->stride[level];
+      unsigned offset = 0;
 
-      map = lpt->data;
-
-      assert(level < LP_MAX_TEXTURE_2D_LEVELS);
-
-      offset = lpt->level_offset[level];
-      stride = lpt->stride[level];
-
-      /* XXX shouldn't that rather be
-         tex_height = align(u_minify(texture->height0, level), 2)
-         to account for alignment done in llvmpipe_resource_layout ?
-      */
       if (texture->target == PIPE_TEXTURE_CUBE) {
-         unsigned tex_height = u_minify(texture->height0, level);
-         offset += face *  util_format_get_nblocksy(texture->format, tex_height) * stride;
+         /* XXX incorrect
+         offset = face * nblocksy * stride;
+         */
       }
       else if (texture->target == PIPE_TEXTURE_3D) {
-         unsigned tex_height = u_minify(texture->height0, level);
-         offset += zslice * util_format_get_nblocksy(texture->format, tex_height) * stride;
+         offset = zslice * nblocksy * stride;
       }
       else {
          assert(face == 0);
          assert(zslice == 0);
+         offset = 0;
       }
 
+      map = llvmpipe_get_texture_image(lpt, face, level, tex_usage, layout);
+      assert(map);
       map += offset;
+      return map;
    }
-
-   return map;
+   else {
+      return lpt->data;
+   }
 }
 
 
@@ -249,11 +366,30 @@
       assert(level == 0);
       assert(zslice == 0);
 
+      /* make sure linear image is up to date */
+      (void) llvmpipe_get_texture_image(lpt, 0, 0,
+                                        LP_TEX_USAGE_READ,
+                                        LP_TEX_LAYOUT_LINEAR);
+
       winsys->displaytarget_unmap(winsys, lpt->dt);
    }
 }
 
 
+void *
+llvmpipe_resource_data(struct pipe_resource *resource)
+{
+   struct llvmpipe_resource *lpt = llvmpipe_resource(resource);
+
+   assert((lpt->base.bind & (PIPE_BIND_DISPLAY_TARGET |
+                             PIPE_BIND_SCANOUT |
+                             PIPE_BIND_SHARED |
+                             PIPE_BIND_SAMPLER_VIEW)) == 0);
+
+   return lpt->data;
+}
+
+
 static struct pipe_resource *
 llvmpipe_resource_from_handle(struct pipe_screen *screen,
 			      const struct pipe_resource *template,
@@ -303,7 +439,7 @@
 llvmpipe_get_tex_surface(struct pipe_screen *screen,
                          struct pipe_resource *pt,
                          unsigned face, unsigned level, unsigned zslice,
-                         unsigned usage)
+                         enum lp_texture_usage usage)
 {
    struct pipe_surface *ps;
 
@@ -389,6 +525,34 @@
    ubyte *map;
    struct llvmpipe_resource *lpt;
    enum pipe_format format;
+   enum lp_texture_usage tex_usage;
+   const char *mode;
+
+   assert(transfer->sr.face < 6);
+   assert(transfer->sr.level < LP_MAX_TEXTURE_LEVELS);
+
+   /*
+   printf("tex_transfer_map(%d, %d  %d x %d of %d x %d,  usage %d )\n",
+          transfer->x, transfer->y, transfer->width, transfer->height,
+          transfer->texture->width0,
+          transfer->texture->height0,
+          transfer->usage);
+   */
+
+   if (transfer->usage == PIPE_TRANSFER_READ) {
+      tex_usage = LP_TEX_USAGE_READ;
+      mode = "read";
+   }
+   else {
+      tex_usage = LP_TEX_USAGE_READ_WRITE;
+      mode = "read/write";
+   }
+
+   if (0) {
+      struct llvmpipe_resource *lpt = llvmpipe_resource(transfer->resource);
+      printf("transfer map tex %u  mode %s\n", lpt->id, mode);
+   }
+
 
    assert(transfer->resource);
    lpt = llvmpipe_resource(transfer->resource);
@@ -408,12 +572,13 @@
                           FALSE); /* do_not_flush */
 
    map = llvmpipe_resource_map(transfer->resource,
-			       transfer->usage,
 			       transfer->sr.face,
 			       transfer->sr.level,
-			       transfer->box.z);
+			       transfer->box.z,
+                               tex_usage, LP_TEX_LAYOUT_LINEAR);
 
-   /* May want to different things here depending on read/write nature
+
+   /* May want to do different things here depending on read/write nature
     * of the map:
     */
    if (transfer->usage & PIPE_TRANSFER_WRITE) {
@@ -488,6 +653,395 @@
 }
 
 
+/**
+ * Compute size (in bytes) need to store a texture image / mipmap level,
+ * for just one cube face.
+ */
+static unsigned
+tex_image_face_size(const struct llvmpipe_resource *lpt, unsigned level,
+                    enum lp_texture_layout layout)
+{
+   /* for tiled layout, force a 32bpp format */
+   enum pipe_format format = layout == LP_TEX_LAYOUT_TILED
+      ? PIPE_FORMAT_B8G8R8A8_UNORM : lpt->base.format;
+   const unsigned height = u_minify(lpt->base.height0, level);
+   const unsigned depth = u_minify(lpt->base.depth0, level);
+   const unsigned nblocksy =
+      util_format_get_nblocksy(format, align(height, TILE_SIZE));
+   const unsigned buffer_size =
+      nblocksy * lpt->stride[level] *
+      (lpt->base.target == PIPE_TEXTURE_3D ? depth : 1);
+   return buffer_size;
+}
+
+
+/**
+ * Compute size (in bytes) need to store a texture image / mipmap level,
+ * including all cube faces.
+ */
+static unsigned
+tex_image_size(const struct llvmpipe_resource *lpt, unsigned level,
+               enum lp_texture_layout layout)
+{
+   const unsigned buf_size = tex_image_face_size(lpt, level, layout);
+   const unsigned num_faces = lpt->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
+   return buf_size * num_faces;
+}
+
+
+/**
+ * This function encapsulates some complicated logic for determining
+ * how to convert a tile of image data from linear layout to tiled
+ * layout, or vice versa.
+ * \param cur_layout  the current tile layout
+ * \param target_layout  the desired tile layout
+ * \param usage  how the tile will be accessed (R/W vs. read-only, etc)
+ * \param new_layout_return  returns the new layout mode
+ * \param convert_return  returns TRUE if image conversion is needed
+ */
+static void
+layout_logic(enum lp_texture_layout cur_layout,
+             enum lp_texture_layout target_layout,
+             enum lp_texture_usage usage,
+             enum lp_texture_layout *new_layout_return,
+             boolean *convert)
+{
+   enum lp_texture_layout other_layout, new_layout;
+
+   *convert = FALSE;
+
+   new_layout = 99; /* debug check */
+
+   if (target_layout == LP_TEX_LAYOUT_LINEAR) {
+      other_layout = LP_TEX_LAYOUT_TILED;
+   }
+   else {
+      assert(target_layout == LP_TEX_LAYOUT_TILED);
+      other_layout = LP_TEX_LAYOUT_LINEAR;
+   }
+
+   new_layout = target_layout;  /* may get changed below */
+
+   if (cur_layout == LP_TEX_LAYOUT_BOTH) {
+      if (usage == LP_TEX_USAGE_READ) {
+         new_layout = LP_TEX_LAYOUT_BOTH;
+      }
+   }
+   else if (cur_layout == other_layout) {
+      if (usage != LP_TEX_USAGE_WRITE_ALL) {
+         /* need to convert tiled data to linear or vice versa */
+         *convert = TRUE;
+
+         if (usage == LP_TEX_USAGE_READ)
+            new_layout = LP_TEX_LAYOUT_BOTH;
+      }
+   }
+   else {
+      assert(cur_layout == LP_TEX_LAYOUT_NONE ||
+             cur_layout == target_layout);
+   }
+
+   assert(new_layout == LP_TEX_LAYOUT_BOTH ||
+          new_layout == target_layout);
+
+   *new_layout_return = new_layout;
+}
+
+
+/**
+ * Return pointer to a texture image.  No tiled/linear conversion is done.
+ */
+void *
+llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpt,
+                                   unsigned face, unsigned level,
+                                   enum lp_texture_layout layout)
+{
+   struct llvmpipe_texture_image *img;
+   unsigned face_offset;
+
+   if (layout == LP_TEX_LAYOUT_LINEAR) {
+      img = &lpt->linear[level];
+   }
+   else {
+      assert (layout == LP_TEX_LAYOUT_TILED);
+      img = &lpt->tiled[level];
+   }
+
+   if (face > 0)
+      face_offset = face * tex_image_face_size(lpt, level, layout);
+   else
+      face_offset = 0;
+
+   return (ubyte *) img->data + face_offset;
+}
+
+
+
+/**
+ * Return pointer to texture image data (either linear or tiled layout).
+ * \param usage  one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE
+ * \param layout  either LP_TEX_LAYOUT_LINEAR or LP_TEX_LAYOUT_TILED
+ */
+void *
+llvmpipe_get_texture_image(struct llvmpipe_resource *lpt,
+                           unsigned face, unsigned level,
+                           enum lp_texture_usage usage,
+                           enum lp_texture_layout layout)
+{
+   /*
+    * 'target' refers to the image which we're retrieving (either in
+    * tiled or linear layout).
+    * 'other' refers to the same image but in the other layout. (it may
+    *  or may not exist.
+    */
+   struct llvmpipe_texture_image *target_img;
+   struct llvmpipe_texture_image *other_img;
+   void *target_data;
+   void *other_data;
+   const unsigned width = u_minify(lpt->base.width0, level);
+   const unsigned height = u_minify(lpt->base.height0, level);
+   const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
+   const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
+   enum lp_texture_layout other_layout;
+
+   assert(layout == LP_TEX_LAYOUT_NONE ||
+          layout == LP_TEX_LAYOUT_TILED ||
+          layout == LP_TEX_LAYOUT_LINEAR);
+
+   assert(usage == LP_TEX_USAGE_READ ||
+          usage == LP_TEX_USAGE_READ_WRITE ||
+          usage == LP_TEX_USAGE_WRITE_ALL);
+
+   if (lpt->dt) {
+      assert(lpt->linear[level].data);
+   }
+
+   /* which is target?  which is other? */
+   if (layout == LP_TEX_LAYOUT_LINEAR) {
+      target_img = &lpt->linear[level];
+      other_img = &lpt->tiled[level];
+      other_layout = LP_TEX_LAYOUT_TILED;
+   }
+   else {
+      target_img = &lpt->tiled[level];
+      other_img = &lpt->linear[level];
+      other_layout = LP_TEX_LAYOUT_LINEAR;
+   }
+
+   target_data = target_img->data;
+   other_data = other_img->data;
+
+   if (!target_data) {
+      /* allocate memory for the target image now */
+      unsigned buffer_size = tex_image_size(lpt, level, layout);
+      target_img->data = align_malloc(buffer_size, 16);
+      target_data = target_img->data;
+   }
+
+   if (face > 0) {
+      unsigned offset = face * tex_image_face_size(lpt, level, layout);
+      if (target_data) {
+         target_data = (uint8_t *) target_data + offset;
+      }
+      if (other_data) {
+         other_data = (uint8_t *) other_data + offset;
+      }
+   }
+
+   if (layout == LP_TEX_LAYOUT_NONE) {
+      /* just allocating memory */
+      return target_data;
+   }
+
+   if (other_data) {
+      /* may need to convert other data to the requested layout */
+      enum lp_texture_layout new_layout;
+      unsigned x, y, i = 0;
+
+      /* loop over all image tiles, doing layout conversion where needed */
+      for (y = 0; y < height_t; y++) {
+         for (x = 0; x < width_t; x++) {
+            enum lp_texture_layout cur_layout = lpt->layout[face][level][i];
+            boolean convert;
+
+            layout_logic(cur_layout, layout, usage, &new_layout, &convert);
+
+            if (convert) {
+               if (layout == LP_TEX_LAYOUT_TILED) {
+                  lp_linear_to_tiled(other_data, target_data,
+                                     x * TILE_SIZE, y * TILE_SIZE,
+                                     TILE_SIZE, TILE_SIZE,
+                                     lpt->base.format,
+                                     lpt->stride[level]);
+               }
+               else {
+                  lp_tiled_to_linear(other_data, target_data,
+                                     x * TILE_SIZE, y * TILE_SIZE,
+                                     TILE_SIZE, TILE_SIZE,
+                                     lpt->base.format,
+                                     lpt->stride[level]);
+               }
+            }
+
+            lpt->layout[face][level][i] = new_layout;
+            i++;
+         }
+      }
+   }
+   else {
+      /* no other data */
+      unsigned i;
+      for (i = 0; i < width_t * height_t; i++) {
+         lpt->layout[face][level][i] = layout;
+      }
+   }
+
+   assert(target_data);
+
+   return target_data;
+}
+
+
+static INLINE enum lp_texture_layout
+llvmpipe_get_texture_tile_layout(const struct llvmpipe_resource *lpt,
+                                 unsigned face, unsigned level,
+                                 unsigned x, unsigned y)
+{
+   uint i;
+   assert(resource_is_texture(&lpt->base));
+   assert(x < lpt->tiles_per_row[level]);
+   i = y * lpt->tiles_per_row[level] + x;
+   return lpt->layout[face][level][i];
+}
+
+
+static INLINE void
+llvmpipe_set_texture_tile_layout(struct llvmpipe_resource *lpt,
+                                 unsigned face, unsigned level,
+                                 unsigned x, unsigned y,
+                                 enum lp_texture_layout layout)
+{
+   uint i;
+   assert(resource_is_texture(&lpt->base));
+   assert(x < lpt->tiles_per_row[level]);
+   i = y * lpt->tiles_per_row[level] + x;
+   lpt->layout[face][level][i] = layout;
+}
+
+
+/**
+ * Get pointer to a linear image where the tile at (x,y) is known to be
+ * in linear layout.
+ * Conversion from tiled to linear will be done if necessary.
+ * \return pointer to start of image/face (not the tile)
+ */
+ubyte *
+llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpt,
+                                 unsigned face, unsigned level,
+                                 enum lp_texture_usage usage,
+                                 unsigned x, unsigned y)
+{
+   struct llvmpipe_texture_image *tiled_img = &lpt->tiled[level];
+   struct llvmpipe_texture_image *linear_img = &lpt->linear[level];
+   enum lp_texture_layout cur_layout, new_layout;
+   const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
+   boolean convert;
+
+   assert(resource_is_texture(&lpt->base));
+   assert(x % TILE_SIZE == 0);
+   assert(y % TILE_SIZE == 0);
+
+   if (!linear_img->data) {
+      /* allocate memory for the tiled image now */
+      unsigned buffer_size = tex_image_size(lpt, level, LP_TEX_LAYOUT_LINEAR);
+      linear_img->data = align_malloc(buffer_size, 16);
+   }
+
+   cur_layout = llvmpipe_get_texture_tile_layout(lpt, face, level, tx, ty);
+
+   layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage,
+                &new_layout, &convert);
+
+   if (convert) {
+      lp_tiled_to_linear(tiled_img->data, linear_img->data,
+                         x, y, TILE_SIZE, TILE_SIZE, lpt->base.format,
+                         lpt->stride[level]);
+   }
+
+   if (new_layout != cur_layout)
+      llvmpipe_set_texture_tile_layout(lpt, face, level, tx, ty, new_layout);
+
+   if (face > 0) {
+      unsigned offset
+         = face * tex_image_face_size(lpt, level, LP_TEX_LAYOUT_LINEAR);
+      return (ubyte *) linear_img->data + offset;
+   }
+   else {
+      return linear_img->data;
+   }
+}
+
+
+/**
+ * Get pointer to tiled data for rendering.
+ * \return pointer to the tiled data at the given tile position
+ */
+ubyte *
+llvmpipe_get_texture_tile(struct llvmpipe_resource *lpt,
+                          unsigned face, unsigned level,
+                          enum lp_texture_usage usage,
+                          unsigned x, unsigned y)
+{
+   const unsigned width = u_minify(lpt->base.width0, level);
+   struct llvmpipe_texture_image *tiled_img = &lpt->tiled[level];
+   struct llvmpipe_texture_image *linear_img = &lpt->linear[level];
+   enum lp_texture_layout cur_layout, new_layout;
+   const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
+   boolean convert;
+
+   assert(x % TILE_SIZE == 0);
+   assert(y % TILE_SIZE == 0);
+
+   if (!tiled_img->data) {
+      /* allocate memory for the tiled image now */
+      unsigned buffer_size = tex_image_size(lpt, level, LP_TEX_LAYOUT_TILED);
+      tiled_img->data = align_malloc(buffer_size, 16);
+   }
+
+   cur_layout = llvmpipe_get_texture_tile_layout(lpt, face, level, tx, ty);
+
+   layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert);
+   if (convert) {
+      lp_linear_to_tiled(linear_img->data, tiled_img->data,
+                         x, y, TILE_SIZE, TILE_SIZE, lpt->base.format,
+                         lpt->stride[level]);
+   }
+
+   if (new_layout != cur_layout)
+      llvmpipe_set_texture_tile_layout(lpt, face, level, tx, ty, new_layout);
+
+   /* compute, return address of the 64x64 tile */
+   {
+      unsigned tiles_per_row, tile_offset, face_offset;
+
+      tiles_per_row = align(width, TILE_SIZE) / TILE_SIZE;
+
+      assert(tiles_per_row == lpt->tiles_per_row[level]);
+
+      tile_offset = ty * tiles_per_row + tx;
+      tile_offset *= TILE_SIZE * TILE_SIZE * 4;
+
+      assert(tiled_img->data);
+
+      face_offset = (face > 0)
+         ? (face * tex_image_face_size(lpt, level, LP_TEX_LAYOUT_TILED))
+         : 0;
+
+      return (ubyte *) tiled_img->data + face_offset + tile_offset;
+   }
+}
+
+
 void
 llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
 {