Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / gallium / drivers / i915simple / i915_texture.c
index 3e23e540f9d57e432a8ae19c0c983173e163dfc1..2f5459af67f70aad34fd1adde23791bc95345f62 100644 (file)
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
 #include "pipe/p_inlines.h"
-#include "pipe/p_util.h"
 #include "pipe/p_winsys.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
 
 #include "i915_context.h"
 #include "i915_texture.h"
 #include "i915_debug.h"
 #include "i915_screen.h"
 
+/*
+ * Helper function and arrays
+ */
+
+/**
+ * Initial offset for Cube map.
+ */
+static const int initial_offsets[6][2] = {
+   {0, 0},
+   {0, 2},
+   {1, 0},
+   {1, 2},
+   {1, 1},
+   {1, 3}
+};
+
+/**
+ * Step offsets for Cube map.
+ */
+static const int step_offsets[6][2] = {
+   {0, 2},
+   {0, 2},
+   {-1, 2},
+   {-1, 2},
+   {-1, 1},
+   {-1, 1}
+};
 
 static unsigned minify( unsigned d )
 {
    return MAX2(1, d>>1);
 }
 
+static unsigned
+power_of_two(unsigned x)
+{
+   unsigned value = 1;
+   while (value < x)
+      value = value << 1;
+   return value;
+}
+
+static unsigned
+round_up(unsigned n, unsigned multiple)
+{
+   return (n + multiple - 1) & ~(multiple - 1);
+}
+
+
+/*
+ * More advanced helper funcs
+ */
 
 
 static void
 i915_miptree_set_level_info(struct i915_texture *tex,
                              unsigned level,
                              unsigned nr_images,
-                             unsigned x, unsigned y, unsigned w, unsigned h, unsigned d)
+                             unsigned w, unsigned h, unsigned d)
 {
    struct pipe_texture *pt = &tex->base;
 
@@ -63,8 +110,10 @@ i915_miptree_set_level_info(struct i915_texture *tex,
    pt->width[level] = w;
    pt->height[level] = h;
    pt->depth[level] = d;
+   
+   pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w);
+   pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h);
 
-   tex->level_offset[level] = (x + y * tex->pitch) * pt->cpp;
    tex->nr_images[level] = nr_images;
 
    /*
@@ -86,7 +135,6 @@ i915_miptree_set_level_info(struct i915_texture *tex,
    tex->image_offset[level][0] = 0;
 }
 
-
 static void
 i915_miptree_set_image_offset(struct i915_texture *tex,
                              unsigned level, unsigned img, unsigned x, unsigned y)
@@ -96,72 +144,76 @@ i915_miptree_set_image_offset(struct i915_texture *tex,
 
    assert(img < tex->nr_images[level]);
 
-   tex->image_offset[level][img] = (x + y * tex->pitch);
+   tex->image_offset[level][img] = y * tex->stride + x * tex->base.block.size;
 
    /*
-   DBG("%s level %d img %d pos %d,%d image_offset %x\n",
+   printf("%s level %d img %d pos %d,%d image_offset %x\n",
        __FUNCTION__, level, img, x, y, tex->image_offset[level][img]);
    */
 }
 
 
-/* Hack it up to use the old winsys->surface_alloc_storage()
- * method for now:
+/*
+ * Layout functions
+ */
+
+
+/**
+ * Special case to deal with display targets.
  */
 static boolean
-i915_displaytarget_layout(struct pipe_screen *screen,
-                          struct i915_texture *tex)
+i915_displaytarget_layout(struct i915_texture *tex)
 {
-   struct pipe_winsys *ws = screen->winsys;
-   struct pipe_surface surf;
-   unsigned flags = (PIPE_BUFFER_USAGE_CPU_READ |
-                     PIPE_BUFFER_USAGE_CPU_WRITE |
-                     PIPE_BUFFER_USAGE_GPU_READ |
-                     PIPE_BUFFER_USAGE_GPU_WRITE);
-
-
-   memset(&surf, 0, sizeof(surf));
-
-   ws->surface_alloc_storage( ws, 
-                              &surf,
-                              tex->base.width[0], 
-                              tex->base.height[0],
-                              tex->base.format,
-                              flags,
-                              tex->base.tex_usage);
-      
-   /* Now extract the goodies: 
-    */
-   i915_miptree_set_image_offset( tex, 0, 0, 0, 0 );
-   i915_miptree_set_level_info( tex, 0, 0, 0, 0, 
+   struct pipe_texture *pt = &tex->base;
+
+   if (pt->last_level > 0 || pt->block.size != 4)
+      return 0;
+
+   i915_miptree_set_level_info( tex, 0, 1,
                                 tex->base.width[0],
                                 tex->base.height[0],
                                 1 );
+   i915_miptree_set_image_offset( tex, 0, 0, 0, 0 );
 
-   tex->buffer = surf.buffer;
-   tex->pitch = surf.pitch;
-   tex->total_height = 0;
+   if (tex->base.width[0] >= 128) {
+      tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
+      tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
+#if 0 /* used for tiled display targets */
+      tex->tiled = 1;
+#endif
+   } else {
+      tex->stride = round_up(tex->base.nblocksx[0] * pt->block.size, 64);
+      tex->total_nblocksy = tex->base.nblocksy[0];
+   }
 
+   /*
+   printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
+      tex->base.width[0], tex->base.height[0], pt->block.size,
+      tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
+   */
 
-   return tex->buffer != NULL;
+   return 1;
 }
 
-
-
-
-
 static void
 i945_miptree_layout_2d( struct i915_texture *tex )
 {
    struct pipe_texture *pt = &tex->base;
-   int align_h = 2, align_w = 4;
+   const int align_x = 2, align_y = 4;
    unsigned level;
    unsigned x = 0;
    unsigned y = 0;
    unsigned width = pt->width[0];
    unsigned height = pt->height[0];
+   unsigned nblocksx = pt->nblocksx[0];
+   unsigned nblocksy = pt->nblocksy[0];
+
+   /* used for tiled display targets */
+   if (0)
+      if (i915_displaytarget_layout(tex))
+        return;
 
-   tex->pitch = pt->width[0];
+   tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
 
    /* May need to adjust pitch to accomodate the placement of
     * the 2nd mipmap level.  This occurs when the alignment
@@ -169,68 +221,146 @@ i945_miptree_layout_2d( struct i915_texture *tex )
     * 2nd mipmap level out past the width of its parent.
     */
    if (pt->last_level > 0) {
-      unsigned mip1_width = align_int(minify(pt->width[0]), align_w)
-                       + minify(minify(pt->width[0]));
+      unsigned mip1_nblocksx 
+        = align(pf_get_nblocksx(&pt->block, minify(width)), align_x)
+         + pf_get_nblocksx(&pt->block, minify(minify(width)));
 
-      if (mip1_width > pt->width[0])
-        tex->pitch = mip1_width;
+      if (mip1_nblocksx > nblocksx)
+        tex->stride = mip1_nblocksx * pt->block.size;
    }
 
-   /* Pitch must be a whole number of dwords, even though we
-    * express it in texels.
+   /* Pitch must be a whole number of dwords
     */
-   tex->pitch = align_int(tex->pitch * pt->cpp, 4) / pt->cpp;
-   tex->total_height = 0;
+   tex->stride = align(tex->stride, 64);
+   tex->total_nblocksy = 0;
 
    for (level = 0; level <= pt->last_level; level++) {
-      unsigned img_height;
-
-      i915_miptree_set_level_info(tex, level, 1, x, y, width, height, 1);
-
-      if (pt->compressed)
-        img_height = MAX2(1, height/4);
-      else
-        img_height = align_int(height, align_h);
+      i915_miptree_set_level_info(tex, level, 1, width, height, 1);
+      i915_miptree_set_image_offset(tex, level, 0, x, y);
 
+      nblocksy = align(nblocksy, align_y);
 
       /* Because the images are packed better, the final offset
        * might not be the maximal one:
        */
-      tex->total_height = MAX2(tex->total_height, y + img_height);
+      tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
 
       /* Layout_below: step right after second mipmap level.
        */
       if (level == 1) {
-        x += align_int(width, align_w);
+        x += align(nblocksx, align_x);
       }
       else {
-        y += img_height;
+        y += nblocksy;
       }
 
       width  = minify(width);
       height = minify(height);
+      nblocksx = pf_get_nblocksx(&pt->block, width);
+      nblocksy = pf_get_nblocksy(&pt->block, height);
    }
 }
 
+static void
+i945_miptree_layout_cube(struct i915_texture *tex)
+{
+   struct pipe_texture *pt = &tex->base;
+   unsigned level;
 
-static const int initial_offsets[6][2] = {
-   {0, 0},
-   {0, 2},
-   {1, 0},
-   {1, 2},
-   {1, 1},
-   {1, 3}
-};
+   const unsigned nblocks = pt->nblocksx[0];
+   unsigned face;
+   unsigned width = pt->width[0];
+   unsigned height = pt->height[0];
 
-static const int step_offsets[6][2] = {
-   {0, 2},
-   {0, 2},
-   {-1, 2},
-   {-1, 2},
-   {-1, 1},
-   {-1, 1}
-};
+   /*
+   printf("%s %i, %i\n", __FUNCTION__, pt->width[0], pt->height[0]);
+   */
+
+   assert(width == height); /* cubemap images are square */
 
+   /*
+    * XXX Should only be used for compressed formats. But lets
+    * keep this code active just in case.
+    *
+    * Depending on the size of the largest images, pitch can be
+    * determined either by the old-style packing of cubemap faces,
+    * or the final row of 4x4, 2x2 and 1x1 faces below this.
+    */
+   if (nblocks > 32)
+      tex->stride = round_up(nblocks * pt->block.size * 2, 4);
+   else
+      tex->stride = 14 * 8 * pt->block.size;
+
+   tex->total_nblocksy = nblocks * 4;
+
+   /* Set all the levels to effectively occupy the whole rectangular region.
+   */
+   for (level = 0; level <= pt->last_level; level++) {
+      i915_miptree_set_level_info(tex, level, 6, width, height, 1);
+      width /= 2;
+      height /= 2;
+   }
+
+   for (face = 0; face < 6; face++) {
+      unsigned x = initial_offsets[face][0] * nblocks;
+      unsigned y = initial_offsets[face][1] * nblocks;
+      unsigned d = nblocks;
+
+#if 0 /* Fix and enable this code for compressed formats */
+      if (nblocks == 4 && face >= 4) {
+         y = tex->total_height - 4;
+         x = (face - 4) * 8;
+      }
+      else if (nblocks < 4 && (face > 0)) {
+         y = tex->total_height - 4;
+         x = face * 8;
+      }
+#endif
+
+      for (level = 0; level <= pt->last_level; level++) {
+         i915_miptree_set_image_offset(tex, level, face, x, y);
+
+         d >>= 1;
+
+#if 0 /* Fix and enable this code for compressed formats */
+         switch (d) {
+            case 4:
+               switch (face) {
+                  case PIPE_TEX_FACE_POS_X:
+                  case PIPE_TEX_FACE_NEG_X:
+                     x += step_offsets[face][0] * d;
+                     y += step_offsets[face][1] * d;
+                     break;
+                  case PIPE_TEX_FACE_POS_Y:
+                  case PIPE_TEX_FACE_NEG_Y:
+                     y += 12;
+                     x -= 8;
+                     break;
+                  case PIPE_TEX_FACE_POS_Z:
+                  case PIPE_TEX_FACE_NEG_Z:
+                     y = tex->total_height - 4;
+                     x = (face - 4) * 8;
+                     break;
+               }
+            case 2:
+               y = tex->total_height - 4;
+               x = 16 + face * 8;
+               break;
+
+            case 1:
+               x += 48;
+               break;
+            default:
+#endif
+               x += step_offsets[face][0] * d;
+               y += step_offsets[face][1] * d;
+#if 0
+               break;
+         }
+#endif
+      }
+   }
+}
 
 static boolean
 i915_miptree_layout(struct i915_texture * tex)
@@ -240,30 +370,28 @@ i915_miptree_layout(struct i915_texture * tex)
 
    switch (pt->target) {
    case PIPE_TEXTURE_CUBE: {
-         const unsigned dim = pt->width[0];
+         const unsigned nblocks = pt->nblocksx[0];
          unsigned face;
-         unsigned lvlWidth = pt->width[0], lvlHeight = pt->height[0];
+         unsigned width = pt->width[0], height = pt->height[0];
 
-         assert(lvlWidth == lvlHeight); /* cubemap images are square */
+         assert(width == height); /* cubemap images are square */
 
          /* double pitch for cube layouts */
-         tex->pitch = ((dim * pt->cpp * 2 + 3) & ~3) / pt->cpp;
-         tex->total_height = dim * 4;
+         tex->stride = round_up(nblocks * pt->block.size * 2, 4);
+         tex->total_nblocksy = nblocks * 4;
 
          for (level = 0; level <= pt->last_level; level++) {
             i915_miptree_set_level_info(tex, level, 6,
-                                         0, 0,
-                                         /*OLD: tex->pitch, tex->total_height,*/
-                                         lvlWidth, lvlHeight,
+                                         width, height,
                                          1);
-            lvlWidth /= 2;
-            lvlHeight /= 2;
+            width /= 2;
+            height /= 2;
          }
 
          for (face = 0; face < 6; face++) {
-            unsigned x = initial_offsets[face][0] * dim;
-            unsigned y = initial_offsets[face][1] * dim;
-            unsigned d = dim;
+            unsigned x = initial_offsets[face][0] * nblocks;
+            unsigned y = initial_offsets[face][1] * nblocks;
+            unsigned d = nblocks;
 
             for (level = 0; level <= pt->last_level; level++) {
                i915_miptree_set_image_offset(tex, level, face, x, y);
@@ -278,25 +406,29 @@ i915_miptree_layout(struct i915_texture * tex)
          unsigned width = pt->width[0];
          unsigned height = pt->height[0];
          unsigned depth = pt->depth[0];
-         unsigned stack_height = 0;
+         unsigned nblocksx = pt->nblocksx[0];
+         unsigned nblocksy = pt->nblocksy[0];
+         unsigned stack_nblocksy = 0;
 
          /* Calculate the size of a single slice. 
           */
-         tex->pitch = ((pt->width[0] * pt->cpp + 3) & ~3) / pt->cpp;
+         tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
 
          /* XXX: hardware expects/requires 9 levels at minimum.
           */
          for (level = 0; level <= MAX2(8, pt->last_level);
               level++) {
-            i915_miptree_set_level_info(tex, level, depth, 0, tex->total_height,
-                                         width, height, depth);
+            i915_miptree_set_level_info(tex, level, depth,
+                                        width, height, depth);
 
 
-            stack_height += MAX2(2, height);
+            stack_nblocksy += MAX2(2, nblocksy);
 
             width = minify(width);
             height = minify(height);
             depth = minify(depth);
+            nblocksx = pf_get_nblocksx(&pt->block, width);
+            nblocksy = pf_get_nblocksy(&pt->block, height);
          }
 
          /* Fixup depth image_offsets: 
@@ -306,7 +438,7 @@ i915_miptree_layout(struct i915_texture * tex)
             unsigned i;
             for (i = 0; i < depth; i++) 
                i915_miptree_set_image_offset(tex, level, i,
-                                              0, i * stack_height);
+                                             0, i * stack_nblocksy);
 
             depth = minify(depth);
          }
@@ -316,32 +448,33 @@ i915_miptree_layout(struct i915_texture * tex)
           * remarkable how wasteful of memory the i915 texture layouts
           * are.  They are largely fixed in the i945.
           */
-         tex->total_height = stack_height * pt->depth[0];
+         tex->total_nblocksy = stack_nblocksy * pt->depth[0];
          break;
       }
 
    default:{
          unsigned width = pt->width[0];
          unsigned height = pt->height[0];
-        unsigned img_height;
+         unsigned nblocksx = pt->nblocksx[0];
+         unsigned nblocksy = pt->nblocksy[0];
 
-         tex->pitch = ((pt->width[0] * pt->cpp + 3) & ~3) / pt->cpp;
-         tex->total_height = 0;
+         tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
+         tex->total_nblocksy = 0;
 
          for (level = 0; level <= pt->last_level; level++) {
             i915_miptree_set_level_info(tex, level, 1,
-                                         0, tex->total_height,
-                                         width, height, 1);
+                                        width, height, 1);
+            i915_miptree_set_image_offset(tex, level, 0,
+                                          0, tex->total_nblocksy);
 
-            if (pt->compressed)
-               img_height = MAX2(1, height / 4);
-            else
-               img_height = (MAX2(2, height) + 1) & ~1;
+            nblocksy = round_up(MAX2(2, nblocksy), 2);
 
-           tex->total_height += img_height;
+           tex->total_nblocksy += nblocksy;
 
             width = minify(width);
             height = minify(height);
+            nblocksx = pf_get_nblocksx(&pt->block, width);
+            nblocksy = pf_get_nblocksy(&pt->block, height);
          }
          break;
       }
@@ -349,7 +482,7 @@ i915_miptree_layout(struct i915_texture * tex)
    /*
    DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
        tex->pitch,
-       tex->total_height, pt->cpp, tex->pitch * tex->total_height * pt->cpp);
+       tex->total_nblocksy, pt->block.size, tex->stride * tex->total_nblocksy);
    */
 
    return TRUE;
@@ -363,105 +496,23 @@ i945_miptree_layout(struct i915_texture * tex)
    unsigned level;
 
    switch (pt->target) {
-   case PIPE_TEXTURE_CUBE:{
-         const unsigned dim = pt->width[0];
-         unsigned face;
-         unsigned lvlWidth = pt->width[0], lvlHeight = pt->height[0];
-
-         assert(lvlWidth == lvlHeight); /* cubemap images are square */
-
-         /* Depending on the size of the largest images, pitch can be
-          * determined either by the old-style packing of cubemap faces,
-          * or the final row of 4x4, 2x2 and 1x1 faces below this. 
-          */
-         if (dim > 32)
-            tex->pitch = ((dim * pt->cpp * 2 + 3) & ~3) / pt->cpp;
-         else
-            tex->pitch = 14 * 8;
-
-         tex->total_height = dim * 4 + 4;
-
-         /* Set all the levels to effectively occupy the whole rectangular region. 
-          */
-         for (level = 0; level <= pt->last_level; level++) {
-            i915_miptree_set_level_info(tex, level, 6,
-                                         0, 0,
-                                         lvlWidth, lvlHeight, 1);
-           lvlWidth /= 2;
-           lvlHeight /= 2;
-        }
-
-
-         for (face = 0; face < 6; face++) {
-            unsigned x = initial_offsets[face][0] * dim;
-            unsigned y = initial_offsets[face][1] * dim;
-            unsigned d = dim;
-
-            if (dim == 4 && face >= 4) {
-               y = tex->total_height - 4;
-               x = (face - 4) * 8;
-            }
-            else if (dim < 4 && (face > 0)) {
-               y = tex->total_height - 4;
-               x = face * 8;
-            }
-
-            for (level = 0; level <= pt->last_level; level++) {
-               i915_miptree_set_image_offset(tex, level, face, x, y);
-
-               d >>= 1;
-
-               switch (d) {
-               case 4:
-                  switch (face) {
-                  case PIPE_TEX_FACE_POS_X:
-                  case PIPE_TEX_FACE_NEG_X:
-                     x += step_offsets[face][0] * d;
-                     y += step_offsets[face][1] * d;
-                     break;
-                  case PIPE_TEX_FACE_POS_Y:
-                  case PIPE_TEX_FACE_NEG_Y:
-                     y += 12;
-                     x -= 8;
-                     break;
-                  case PIPE_TEX_FACE_POS_Z:
-                  case PIPE_TEX_FACE_NEG_Z:
-                     y = tex->total_height - 4;
-                     x = (face - 4) * 8;
-                     break;
-                  }
-
-               case 2:
-                  y = tex->total_height - 4;
-                  x = 16 + face * 8;
-                  break;
-
-               case 1:
-                  x += 48;
-                  break;
-
-               default:
-                  x += step_offsets[face][0] * d;
-                  y += step_offsets[face][1] * d;
-                  break;
-               }
-            }
-         }
-         break;
-      }
+   case PIPE_TEXTURE_CUBE:
+      i945_miptree_layout_cube(tex);
+      break;
    case PIPE_TEXTURE_3D:{
          unsigned width = pt->width[0];
          unsigned height = pt->height[0];
          unsigned depth = pt->depth[0];
+         unsigned nblocksx = pt->nblocksx[0];
+         unsigned nblocksy = pt->nblocksy[0];
          unsigned pack_x_pitch, pack_x_nr;
          unsigned pack_y_pitch;
-         unsigned level;
 
-         tex->pitch = ((pt->width[0] * pt->cpp + 3) & ~3) / pt->cpp;
-         tex->total_height = 0;
+         tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
+         tex->total_nblocksy = 0;
 
-         pack_y_pitch = MAX2(pt->height[0], 2);
-         pack_x_pitch = tex->pitch;
+         pack_y_pitch = MAX2(pt->nblocksy[0], 2);
+         pack_x_pitch = tex->stride / pt->block.size;
          pack_x_nr = 1;
 
          for (level = 0; level <= pt->last_level; level++) {
@@ -471,12 +522,11 @@ i945_miptree_layout(struct i915_texture * tex)
             unsigned q, j;
 
             i915_miptree_set_level_info(tex, level, nr_images,
-                                         0, tex->total_height,
-                                         width, height, depth);
+                                        width, height, depth);
 
             for (q = 0; q < nr_images;) {
                for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
-                  i915_miptree_set_image_offset(tex, level, q, x, y);
+                  i915_miptree_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
                   x += pack_x_pitch;
                }
 
@@ -485,12 +535,12 @@ i945_miptree_layout(struct i915_texture * tex)
             }
 
 
-            tex->total_height += y;
+            tex->total_nblocksy += y;
 
             if (pack_x_pitch > 4) {
                pack_x_pitch >>= 1;
                pack_x_nr <<= 1;
-               assert(pack_x_pitch * pack_x_nr <= tex->pitch);
+               assert(pack_x_pitch * pack_x_nr * pt->block.size <= tex->stride);
             }
 
             if (pack_y_pitch > 2) {
@@ -500,6 +550,8 @@ i945_miptree_layout(struct i915_texture * tex)
             width = minify(width);
             height = minify(height);
             depth = minify(depth);
+            nblocksx = pf_get_nblocksx(&pt->block, width);
+            nblocksy = pf_get_nblocksy(&pt->block, height);
          }
          break;
       }
@@ -517,7 +569,7 @@ i945_miptree_layout(struct i915_texture * tex)
    /*
    DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
        tex->pitch,
-       tex->total_height, pt->cpp, tex->pitch * tex->total_height * pt->cpp);
+       tex->total_nblocksy, pt->block.size, tex->stride * tex->total_nblocksy);
    */
 
    return TRUE;
@@ -525,54 +577,59 @@ i945_miptree_layout(struct i915_texture * tex)
 
 
 static struct pipe_texture *
-i915_texture_create_screen(struct pipe_screen *screen,
-                           const struct pipe_texture *templat)
+i915_texture_create(struct pipe_screen *screen,
+                    const struct pipe_texture *templat)
 {
    struct i915_screen *i915screen = i915_screen(screen);
    struct pipe_winsys *ws = screen->winsys;
    struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
+   size_t tex_size;
 
-   if (!tex) 
+   if (!tex)
       return NULL;
 
    tex->base = *templat;
    tex->base.refcount = 1;
    tex->base.screen = screen;
 
-   if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET) {
-      if (!i915_displaytarget_layout(screen, tex))
-         goto fail;
-   }
-   else {
-      if (i915screen->is_i945) {
-         if (!i945_miptree_layout(tex))
-            goto fail;
-      }
-      else {
-         if (!i915_miptree_layout(tex))
-            goto fail;
-      }
-      
-      tex->buffer = ws->buffer_create(ws, 64,
-                                      PIPE_BUFFER_USAGE_PIXEL,
-                                      tex->pitch * tex->base.cpp *
-                                      tex->total_height);
-
-      if (!tex->buffer) 
-         goto fail;
+   tex->base.nblocksx[0] = pf_get_nblocksx(&tex->base.block, tex->base.width[0]);
+   tex->base.nblocksy[0] = pf_get_nblocksy(&tex->base.block, tex->base.height[0]);
+   
+   if (i915screen->is_i945) {
+      if (!i945_miptree_layout(tex))
+        goto fail;
+   } else {
+      if (!i915_miptree_layout(tex))
+        goto fail;
    }
 
+   tex_size = tex->stride * tex->total_nblocksy;
+
+   tex->buffer = ws->buffer_create(ws, 64,
+                                  PIPE_BUFFER_USAGE_PIXEL,
+                                  tex_size);
+
+   if (!tex->buffer)
+      goto fail;
+
+#if 0
+   void *ptr = ws->buffer_map(ws, tex->buffer,
+      PIPE_BUFFER_USAGE_CPU_WRITE);
+   memset(ptr, 0x80, tex_size);
+   ws->buffer_unmap(ws, tex->buffer);
+#endif
+
    return &tex->base;
 
- fail:
+fail:
    FREE(tex);
    return NULL;
 }
 
 
 static void
-i915_texture_release_screen(struct pipe_screen *screen,
-                            struct pipe_texture **pt)
+i915_texture_release(struct pipe_screen *screen,
+                     struct pipe_texture **pt)
 {
    if (!*pt)
       return;
@@ -589,7 +646,7 @@ i915_texture_release_screen(struct pipe_screen *screen,
       DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
       */
 
-      pipe_buffer_reference(screen->winsys, &tex->buffer, NULL);
+      pipe_buffer_reference(screen, &tex->buffer, NULL);
 
       for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
          if (tex->image_offset[i])
@@ -600,51 +657,82 @@ i915_texture_release_screen(struct pipe_screen *screen,
    *pt = NULL;
 }
 
-
-
-/*
- * XXX note: same as code in sp_surface.c
- */
 static struct pipe_surface *
-i915_get_tex_surface_screen(struct pipe_screen *screen,
-                            struct pipe_texture *pt,
-                            unsigned face, unsigned level, unsigned zslice,
-                            unsigned flags)
+i915_get_tex_surface(struct pipe_screen *screen,
+                     struct pipe_texture *pt,
+                     unsigned face, unsigned level, unsigned zslice,
+                     unsigned flags)
 {
    struct i915_texture *tex = (struct i915_texture *)pt;
    struct pipe_winsys *ws = screen->winsys;
    struct pipe_surface *ps;
    unsigned offset;  /* in bytes */
 
-   offset = tex->level_offset[level];
-
    if (pt->target == PIPE_TEXTURE_CUBE) {
-      offset += tex->image_offset[level][face] * pt->cpp;
+      offset = tex->image_offset[level][face];
    }
    else if (pt->target == PIPE_TEXTURE_3D) {
-      offset += tex->image_offset[level][zslice] * pt->cpp;
+      offset = tex->image_offset[level][zslice];
    }
    else {
+      offset = tex->image_offset[level][0];
       assert(face == 0);
       assert(zslice == 0);
    }
 
-   ps = ws->surface_alloc(ws);
+   ps = CALLOC_STRUCT(pipe_surface);
    if (ps) {
-      assert(ps->refcount);
-      assert(ps->winsys);
-      pipe_buffer_reference(ws, &ps->buffer, tex->buffer);
+      ps->refcount = 1;
+      ps->winsys = ws;
+      pipe_texture_reference(&ps->texture, pt);
+      pipe_buffer_reference(screen, &ps->buffer, tex->buffer);
       ps->format = pt->format;
-      ps->cpp = pt->cpp;
       ps->width = pt->width[level];
       ps->height = pt->height[level];
-      ps->pitch = tex->pitch;
+      ps->block = pt->block;
+      ps->nblocksx = pt->nblocksx[level];
+      ps->nblocksy = pt->nblocksy[level];
+      ps->stride = tex->stride;
       ps->offset = offset;
       ps->usage = flags;
+      ps->status = PIPE_SURFACE_STATUS_DEFINED;
    }
    return ps;
 }
 
+static struct pipe_texture *
+i915_texture_blanket(struct pipe_screen * screen,
+                     const struct pipe_texture *base,
+                     const unsigned *stride,
+                     struct pipe_buffer *buffer)
+{
+   struct i915_texture *tex;
+   assert(screen);
+
+   /* Only supports one type */
+   if (base->target != PIPE_TEXTURE_2D ||
+       base->last_level != 0 ||
+       base->depth[0] != 1) {
+      return NULL;
+   }
+
+   tex = CALLOC_STRUCT(i915_texture);
+   if (!tex)
+      return NULL;
+
+   tex->base = *base;
+   tex->base.refcount = 1;
+   tex->base.screen = screen;
+
+   tex->stride = stride[0];
+
+   i915_miptree_set_level_info(tex, 0, 1, base->width[0], base->height[0], 1);
+   i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
+
+   pipe_buffer_reference(screen, &tex->buffer, buffer);
+
+   return &tex->base;
+}
 
 void
 i915_init_texture_functions(struct i915_context *i915)
@@ -652,11 +740,36 @@ i915_init_texture_functions(struct i915_context *i915)
 //   i915->pipe.texture_update = i915_texture_update;
 }
 
+static void
+i915_tex_surface_release(struct pipe_screen *screen,
+                         struct pipe_surface **surface)
+{
+   struct pipe_surface *surf = *surface;
+
+   if (--surf->refcount == 0) {
+
+      /* This really should not be possible, but it's actually
+       * happening quite a bit...  Will fix.
+       */
+      if (surf->status == PIPE_SURFACE_STATUS_CLEAR) {
+         debug_printf("XXX destroying a surface with pending clears...\n");
+         assert(0);
+      }
+
+      pipe_texture_reference(&surf->texture, NULL);
+      pipe_buffer_reference(screen, &surf->buffer, NULL);
+      FREE(surf);
+   }
+
+   *surface = NULL;
+}
 
 void
 i915_init_screen_texture_functions(struct pipe_screen *screen)
 {
-   screen->texture_create = i915_texture_create_screen;
-   screen->texture_release = i915_texture_release_screen;
-   screen->get_tex_surface = i915_get_tex_surface_screen;
+   screen->texture_create = i915_texture_create;
+   screen->texture_release = i915_texture_release;
+   screen->get_tex_surface = i915_get_tex_surface;
+   screen->texture_blanket = i915_texture_blanket;
+   screen->tex_surface_release = i915_tex_surface_release;
 }