new texture functions
authorBrian <brian@i915.localnet.net>
Mon, 6 Aug 2007 21:48:42 +0000 (15:48 -0600)
committerBrian <brian@i915.localnet.net>
Mon, 6 Aug 2007 21:48:42 +0000 (15:48 -0600)
src/mesa/state_tracker/st_cb_texture.c [new file with mode: 0644]
src/mesa/state_tracker/st_cb_texture.h [new file with mode: 0644]

diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
new file mode 100644 (file)
index 0000000..a0245b5
--- /dev/null
@@ -0,0 +1,1763 @@
+/**************************************************************************
+ * 
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * 
+ **************************************************************************/
+
+#include "main/imports.h"
+#include "main/convolve.h"
+#include "main/enums.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "main/texcompress.h"
+#include "main/texformat.h"
+#include "main/teximage.h"
+#include "main/texobj.h"
+#include "main/texstore.h"
+
+#include "state_tracker/st_context.h"
+#include "state_tracker/st_cb_texture.h"
+#include "state_tracker/st_mipmap_tree.h"
+
+#include "pipe/p_context.h"
+
+
+#define DBG if (0) printf
+
+
+struct st_texture_object
+{
+   struct gl_texture_object base;       /* The "parent" object */
+
+   /* The mipmap tree must include at least these levels once
+    * validated:
+    */
+   GLuint firstLevel;
+   GLuint lastLevel;
+
+   /* Offset for firstLevel image:
+    */
+   GLuint textureOffset;
+
+   /* On validation any active images held in main memory or in other
+    * regions will be copied to this region and the old storage freed.
+    */
+   struct pipe_mipmap_tree *mt;
+
+   GLboolean imageOverride;
+   GLint depthOverride;
+   GLuint pitchOverride;
+};
+
+
+
+struct st_texture_image
+{
+   struct gl_texture_image base;
+
+   /* These aren't stored in gl_texture_image 
+    */
+   GLuint level;
+   GLuint face;
+
+   /* If stImage->mt != NULL, image data is stored here.
+    * Else if stImage->base.Data != NULL, image is stored there.
+    * Else there is no image data.
+    */
+   struct pipe_mipmap_tree *mt;
+};
+
+
+
+
+static INLINE struct st_texture_object *
+st_texture_object(struct gl_texture_object *obj)
+{
+   return (struct st_texture_object *) obj;
+}
+
+static INLINE struct st_texture_image *
+st_texture_image(struct gl_texture_image *img)
+{
+   return (struct st_texture_image *) img;
+}
+
+
+static int
+intel_compressed_num_bytes(GLuint mesaFormat)
+{
+   int bytes = 0;
+   switch(mesaFormat) {
+     
+   case MESA_FORMAT_RGB_FXT1:
+   case MESA_FORMAT_RGBA_FXT1:
+   case MESA_FORMAT_RGB_DXT1:
+   case MESA_FORMAT_RGBA_DXT1:
+     bytes = 2;
+     break;
+     
+   case MESA_FORMAT_RGBA_DXT3:
+   case MESA_FORMAT_RGBA_DXT5:
+     bytes = 4;
+   default:
+     break;
+   }
+   
+   return bytes;
+}
+
+
+/* It works out that this function is fine for all the supported
+ * hardware.  However, there is still a need to map the formats onto
+ * hardware descriptors.
+ */
+/* Note that the i915 can actually support many more formats than
+ * these if we take the step of simply swizzling the colors
+ * immediately after sampling...
+ */
+static const struct gl_texture_format *
+st_ChooseTextureFormat(GLcontext * ctx, GLint internalFormat,
+                         GLenum format, GLenum type)
+{
+#if 0
+   struct intel_context *intel = intel_context(ctx);
+   const GLboolean do32bpt = (intel->intelScreen->front.cpp == 4);
+#else
+   const GLboolean do32bpt = 1;
+#endif
+
+   switch (internalFormat) {
+   case 4:
+   case GL_RGBA:
+   case GL_COMPRESSED_RGBA:
+      if (format == GL_BGRA) {
+         if (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) {
+            return &_mesa_texformat_argb8888;
+         }
+         else if (type == GL_UNSIGNED_SHORT_4_4_4_4_REV) {
+            return &_mesa_texformat_argb4444;
+         }
+         else if (type == GL_UNSIGNED_SHORT_1_5_5_5_REV) {
+            return &_mesa_texformat_argb1555;
+         }
+      }
+      return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+
+   case 3:
+   case GL_RGB:
+   case GL_COMPRESSED_RGB:
+      if (format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5) {
+         return &_mesa_texformat_rgb565;
+      }
+      return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
+
+   case GL_RGBA8:
+   case GL_RGB10_A2:
+   case GL_RGBA12:
+   case GL_RGBA16:
+      return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+
+   case GL_RGBA4:
+   case GL_RGBA2:
+      return &_mesa_texformat_argb4444;
+
+   case GL_RGB5_A1:
+      return &_mesa_texformat_argb1555;
+
+   case GL_RGB8:
+   case GL_RGB10:
+   case GL_RGB12:
+   case GL_RGB16:
+      return &_mesa_texformat_argb8888;
+
+   case GL_RGB5:
+   case GL_RGB4:
+   case GL_R3_G3_B2:
+      return &_mesa_texformat_rgb565;
+
+   case GL_ALPHA:
+   case GL_ALPHA4:
+   case GL_ALPHA8:
+   case GL_ALPHA12:
+   case GL_ALPHA16:
+   case GL_COMPRESSED_ALPHA:
+      return &_mesa_texformat_a8;
+
+   case 1:
+   case GL_LUMINANCE:
+   case GL_LUMINANCE4:
+   case GL_LUMINANCE8:
+   case GL_LUMINANCE12:
+   case GL_LUMINANCE16:
+   case GL_COMPRESSED_LUMINANCE:
+      return &_mesa_texformat_l8;
+
+   case 2:
+   case GL_LUMINANCE_ALPHA:
+   case GL_LUMINANCE4_ALPHA4:
+   case GL_LUMINANCE6_ALPHA2:
+   case GL_LUMINANCE8_ALPHA8:
+   case GL_LUMINANCE12_ALPHA4:
+   case GL_LUMINANCE12_ALPHA12:
+   case GL_LUMINANCE16_ALPHA16:
+   case GL_COMPRESSED_LUMINANCE_ALPHA:
+      return &_mesa_texformat_al88;
+
+   case GL_INTENSITY:
+   case GL_INTENSITY4:
+   case GL_INTENSITY8:
+   case GL_INTENSITY12:
+   case GL_INTENSITY16:
+   case GL_COMPRESSED_INTENSITY:
+      return &_mesa_texformat_i8;
+
+   case GL_YCBCR_MESA:
+      if (type == GL_UNSIGNED_SHORT_8_8_MESA || type == GL_UNSIGNED_BYTE)
+         return &_mesa_texformat_ycbcr;
+      else
+         return &_mesa_texformat_ycbcr_rev;
+
+   case GL_COMPRESSED_RGB_FXT1_3DFX:
+      return &_mesa_texformat_rgb_fxt1;
+   case GL_COMPRESSED_RGBA_FXT1_3DFX:
+      return &_mesa_texformat_rgba_fxt1;
+
+   case GL_RGB_S3TC:
+   case GL_RGB4_S3TC:
+   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+      return &_mesa_texformat_rgb_dxt1;
+
+   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+      return &_mesa_texformat_rgba_dxt1;
+
+   case GL_RGBA_S3TC:
+   case GL_RGBA4_S3TC:
+   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+      return &_mesa_texformat_rgba_dxt3;
+
+   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+      return &_mesa_texformat_rgba_dxt5;
+
+   case GL_DEPTH_COMPONENT:
+   case GL_DEPTH_COMPONENT16:
+   case GL_DEPTH_COMPONENT24:
+   case GL_DEPTH_COMPONENT32:
+      return &_mesa_texformat_z16;
+
+   case GL_DEPTH_STENCIL_EXT:
+   case GL_DEPTH24_STENCIL8_EXT:
+      return &_mesa_texformat_z24_s8;
+
+   default:
+      fprintf(stderr, "unexpected texture format %s in %s\n",
+              _mesa_lookup_enum_by_nr(internalFormat), __FUNCTION__);
+      return NULL;
+   }
+
+   return NULL;                 /* never get here */
+}
+
+
+static GLboolean
+st_IsTextureResident(GLcontext * ctx, struct gl_texture_object *texObj)
+{
+#if 0
+   struct intel_context *intel = intel_context(ctx);
+   struct st_texture_object *stObj = st_texture_object(texObj);
+
+   return
+      stObj->mt &&
+      stObj->mt->region &&
+      intel_is_region_resident(intel, stObj->mt->region);
+#endif
+   return 1;
+}
+
+
+
+static struct gl_texture_image *
+st_NewTextureImage(GLcontext * ctx)
+{
+   DBG("%s\n", __FUNCTION__);
+   (void) ctx;
+   return (struct gl_texture_image *) CALLOC_STRUCT(st_texture_image);
+}
+
+
+static struct gl_texture_object *
+st_NewTextureObject(GLcontext * ctx, GLuint name, GLenum target)
+{
+   struct st_texture_object *obj = CALLOC_STRUCT(st_texture_object);
+
+   DBG("%s\n", __FUNCTION__);
+   _mesa_initialize_texture_object(&obj->base, name, target);
+
+   return &obj->base;
+}
+
+static void 
+st_DeleteTextureObject(GLcontext *ctx,
+                        struct gl_texture_object *texObj)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct st_texture_object *stObj = st_texture_object(texObj);
+
+   if (stObj->mt)
+      st_miptree_release(pipe, &stObj->mt);
+
+   _mesa_delete_texture_object(ctx, texObj);
+}
+
+
+static void
+st_FreeTextureImageData(GLcontext * ctx, struct gl_texture_image *texImage)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct st_texture_image *stImage = st_texture_image(texImage);
+
+   DBG("%s\n", __FUNCTION__);
+
+   if (stImage->mt) {
+      st_miptree_release(pipe, &stImage->mt);
+   }
+
+   if (texImage->Data) {
+      free(texImage->Data);
+      texImage->Data = NULL;
+   }
+}
+
+
+
+
+/* ================================================================
+ * From linux kernel i386 header files, copes with odd sizes better
+ * than COPY_DWORDS would:
+ * XXX Put this in src/mesa/main/imports.h ???
+ */
+#if defined(i386) || defined(__i386__)
+static INLINE void *
+__memcpy(void *to, const void *from, size_t n)
+{
+   int d0, d1, d2;
+   __asm__ __volatile__("rep ; movsl\n\t"
+                        "testb $2,%b4\n\t"
+                        "je 1f\n\t"
+                        "movsw\n"
+                        "1:\ttestb $1,%b4\n\t"
+                        "je 2f\n\t"
+                        "movsb\n" "2:":"=&c"(d0), "=&D"(d1), "=&S"(d2)
+                        :"0"(n / 4), "q"(n), "1"((long) to), "2"((long) from)
+                        :"memory");
+   return (to);
+}
+#else
+#define __memcpy(a,b,c) memcpy(a,b,c)
+#endif
+
+
+/* The system memcpy (at least on ubuntu 5.10) has problems copying
+ * to agp (writecombined) memory from a source which isn't 64-byte
+ * aligned - there is a 4x performance falloff.
+ *
+ * The x86 __memcpy is immune to this but is slightly slower
+ * (10%-ish) than the system memcpy.
+ *
+ * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but
+ * isn't much faster than x86_memcpy for agp copies.
+ * 
+ * TODO: switch dynamically.
+ */
+static void *
+do_memcpy(void *dest, const void *src, size_t n)
+{
+   if ((((unsigned) src) & 63) || (((unsigned) dest) & 63)) {
+      return __memcpy(dest, src, n);
+   }
+   else
+      return memcpy(dest, src, n);
+}
+
+
+/* Functions to store texture images.  Where possible, mipmap_tree's
+ * will be created or further instantiated with image data, otherwise
+ * images will be stored in malloc'd memory.  A validation step is
+ * required to pull those images into a mipmap tree, or otherwise
+ * decide a fallback is required.
+ */
+
+
+static int
+logbase2(int n)
+{
+   GLint i = 1;
+   GLint log2 = 0;
+
+   while (n > i) {
+      i *= 2;
+      log2++;
+   }
+
+   return log2;
+}
+
+
+/* Otherwise, store it in memory if (Border != 0) or (any dimension ==
+ * 1).
+ *    
+ * Otherwise, if max_level >= level >= min_level, create tree with
+ * space for textures from min_level down to max_level.
+ *
+ * Otherwise, create tree with space for textures from (level
+ * 0)..(1x1).  Consider pruning this tree at a validation if the
+ * saving is worth it.
+ */
+static void
+guess_and_alloc_mipmap_tree(struct pipe_context *pipe,
+                            struct st_texture_object *intelObj,
+                            struct st_texture_image *intelImage)
+{
+   GLuint firstLevel;
+   GLuint lastLevel;
+   GLuint width = intelImage->base.Width;
+   GLuint height = intelImage->base.Height;
+   GLuint depth = intelImage->base.Depth;
+   GLuint l2width, l2height, l2depth;
+   GLuint i, comp_byte = 0;
+
+   DBG("%s\n", __FUNCTION__);
+
+   if (intelImage->base.Border)
+      return;
+
+   if (intelImage->level > intelObj->base.BaseLevel &&
+       (intelImage->base.Width == 1 ||
+        (intelObj->base.Target != GL_TEXTURE_1D &&
+         intelImage->base.Height == 1) ||
+        (intelObj->base.Target == GL_TEXTURE_3D &&
+         intelImage->base.Depth == 1)))
+      return;
+
+   /* If this image disrespects BaseLevel, allocate from level zero.
+    * Usually BaseLevel == 0, so it's unlikely to happen.
+    */
+   if (intelImage->level < intelObj->base.BaseLevel)
+      firstLevel = 0;
+   else
+      firstLevel = intelObj->base.BaseLevel;
+
+
+   /* Figure out image dimensions at start level. 
+    */
+   for (i = intelImage->level; i > firstLevel; i--) {
+      width <<= 1;
+      if (height != 1)
+         height <<= 1;
+      if (depth != 1)
+         depth <<= 1;
+   }
+
+   /* Guess a reasonable value for lastLevel.  This is probably going
+    * to be wrong fairly often and might mean that we have to look at
+    * resizable buffers, or require that buffers implement lazy
+    * pagetable arrangements.
+    */
+   if ((intelObj->base.MinFilter == GL_NEAREST ||
+        intelObj->base.MinFilter == GL_LINEAR) &&
+       intelImage->level == firstLevel) {
+      lastLevel = firstLevel;
+   }
+   else {
+      l2width = logbase2(width);
+      l2height = logbase2(height);
+      l2depth = logbase2(depth);
+      lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth);
+   }
+
+   assert(!intelObj->mt);
+   if (intelImage->base.IsCompressed)
+      comp_byte = intel_compressed_num_bytes(intelImage->base.TexFormat->MesaFormat);
+   intelObj->mt = st_miptree_create(pipe,
+                                       intelObj->base.Target,
+                                       intelImage->base.InternalFormat,
+                                       firstLevel,
+                                       lastLevel,
+                                       width,
+                                       height,
+                                       depth,
+                                       intelImage->base.TexFormat->TexelBytes,
+                                       comp_byte);
+
+   DBG("%s - success\n", __FUNCTION__);
+}
+
+
+
+
+static GLuint
+target_to_face(GLenum target)
+{
+   switch (target) {
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
+      return ((GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
+   default:
+      return 0;
+   }
+}
+
+
+
+/* There are actually quite a few combinations this will work for,
+ * more than what I've listed here.
+ */
+static GLboolean
+check_pbo_format(GLint internalFormat,
+                 GLenum format, GLenum type,
+                 const struct gl_texture_format *mesa_format)
+{
+   switch (internalFormat) {
+   case 4:
+   case GL_RGBA:
+      return (format == GL_BGRA &&
+              (type == GL_UNSIGNED_BYTE ||
+               type == GL_UNSIGNED_INT_8_8_8_8_REV) &&
+              mesa_format == &_mesa_texformat_argb8888);
+   case 3:
+   case GL_RGB:
+      return (format == GL_RGB &&
+              type == GL_UNSIGNED_SHORT_5_6_5 &&
+              mesa_format == &_mesa_texformat_rgb565);
+   case GL_YCBCR_MESA:
+      return (type == GL_UNSIGNED_SHORT_8_8_MESA || type == GL_UNSIGNED_BYTE);
+   default:
+      return GL_FALSE;
+   }
+}
+
+
+/* XXX: Do this for TexSubImage also:
+ */
+static GLboolean
+try_pbo_upload(GLcontext *ctx,
+               struct st_texture_image *intelImage,
+               const struct gl_pixelstore_attrib *unpack,
+               GLint internalFormat,
+               GLint width, GLint height,
+               GLenum format, GLenum type, const void *pixels)
+{
+   return GL_FALSE;  /* XXX fix flushing/locking/blitting below */
+#if 000
+   struct intel_context *intel = intel_context(ctx);
+   struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
+   GLuint src_offset, src_stride;
+   GLuint dst_offset, dst_stride;
+
+   if (!pbo ||
+       ctx._ImageTransferState ||
+       unpack->SkipPixels || unpack->SkipRows) {
+      _mesa_printf("%s: failure 1\n", __FUNCTION__);
+      return GL_FALSE;
+   }
+
+   src_offset = (GLuint) pixels;
+
+   if (unpack->RowLength > 0)
+      src_stride = unpack->RowLength;
+   else
+      src_stride = width;
+
+   dst_offset = st_miptree_image_offset(intelImage->mt,
+                                           intelImage->face,
+                                           intelImage->level);
+
+   dst_stride = intelImage->mt->pitch;
+
+   intelFlush(&intel->ctx);
+   LOCK_HARDWARE(intel);
+   {
+      struct _DriBufferObject *src_buffer =
+         intel_bufferobj_buffer(intel, pbo, INTEL_READ);
+
+      /* Temporary hack: cast to _DriBufferObject:
+       */
+      struct _DriBufferObject *dst_buffer =
+         (struct _DriBufferObject *)intelImage->mt->region->buffer;
+
+
+      intelEmitCopyBlit(intel,
+                        intelImage->mt->cpp,
+                        src_stride, src_buffer, src_offset,
+                        dst_stride, dst_buffer, dst_offset,
+                        0, 0, 0, 0, width, height,
+                       GL_COPY);
+
+      intel_batchbuffer_flush(intel->batch);
+   }
+   UNLOCK_HARDWARE(intel);
+
+   return GL_TRUE;
+#endif
+}
+
+
+
+static GLboolean
+try_pbo_zcopy(GLcontext *ctx,
+              struct st_texture_image *intelImage,
+              const struct gl_pixelstore_attrib *unpack,
+              GLint internalFormat,
+              GLint width, GLint height,
+              GLenum format, GLenum type, const void *pixels)
+{
+   return GL_FALSE;
+}
+
+
+
+
+
+
+static void
+st_TexImage(GLcontext * ctx,
+              GLint dims,
+              GLenum target, GLint level,
+              GLint internalFormat,
+              GLint width, GLint height, GLint depth,
+              GLint border,
+              GLenum format, GLenum type, const void *pixels,
+              const struct gl_pixelstore_attrib *unpack,
+              struct gl_texture_object *texObj,
+              struct gl_texture_image *texImage, GLsizei imageSize, int compressed)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct st_texture_object *intelObj = st_texture_object(texObj);
+   struct st_texture_image *intelImage = st_texture_image(texImage);
+   GLint postConvWidth = width;
+   GLint postConvHeight = height;
+   GLint texelBytes, sizeInBytes;
+   GLuint dstRowStride;
+
+
+   DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
+       _mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
+
+#if 0
+   intelFlush(ctx);
+#endif
+
+   intelImage->face = target_to_face(target);
+   intelImage->level = level;
+
+   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
+      _mesa_adjust_image_for_convolution(ctx, dims, &postConvWidth,
+                                         &postConvHeight);
+   }
+
+   /* choose the texture format */
+   texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat,
+                                                  format, type);
+
+   _mesa_set_fetch_functions(texImage, dims);
+
+   if (texImage->TexFormat->TexelBytes == 0) {
+      /* must be a compressed format */
+      texelBytes = 0;
+      texImage->IsCompressed = GL_TRUE;
+      texImage->CompressedSize =
+        ctx->Driver.CompressedTextureSize(ctx, texImage->Width,
+                                          texImage->Height, texImage->Depth,
+                                          texImage->TexFormat->MesaFormat);
+   } else {
+      texelBytes = texImage->TexFormat->TexelBytes;
+      
+      /* Minimum pitch of 32 bytes */
+      if (postConvWidth * texelBytes < 32) {
+        postConvWidth = 32 / texelBytes;
+        texImage->RowStride = postConvWidth;
+      }
+      
+      assert(texImage->RowStride == postConvWidth);
+   }
+
+   /* Release the reference to a potentially orphaned buffer.   
+    * Release any old malloced memory.
+    */
+   if (intelImage->mt) {
+      st_miptree_release(pipe, &intelImage->mt);
+      assert(!texImage->Data);
+   }
+   else if (texImage->Data) {
+      _mesa_align_free(texImage->Data);
+   }
+
+   /* If this is the only texture image in the tree, could call
+    * bmBufferData with NULL data to free the old block and avoid
+    * waiting on any outstanding fences.
+    */
+   if (intelObj->mt &&
+       intelObj->mt->first_level == level &&
+       intelObj->mt->last_level == level &&
+       intelObj->mt->target != GL_TEXTURE_CUBE_MAP_ARB &&
+       !st_miptree_match_image(intelObj->mt, &intelImage->base,
+                                  intelImage->face, intelImage->level)) {
+
+      DBG("release it\n");
+      st_miptree_release(pipe, &intelObj->mt);
+      assert(!intelObj->mt);
+   }
+
+   if (!intelObj->mt) {
+      guess_and_alloc_mipmap_tree(pipe, intelObj, intelImage);
+      if (!intelObj->mt) {
+        DBG("guess_and_alloc_mipmap_tree: failed\n");
+      }
+   }
+
+   assert(!intelImage->mt);
+
+   if (intelObj->mt &&
+       st_miptree_match_image(intelObj->mt, &intelImage->base,
+                                 intelImage->face, intelImage->level)) {
+
+      st_miptree_reference(&intelImage->mt, intelObj->mt);
+      assert(intelImage->mt);
+   }
+
+   if (!intelImage->mt)
+      DBG("XXX: Image did not fit into tree - storing in local memory!\n");
+
+#if 0 /* XXX FIX when st_buffer_objects are in place */
+   /* PBO fastpaths:
+    */
+   if (dims <= 2 &&
+       intelImage->mt &&
+       intel_buffer_object(unpack->BufferObj) &&
+       check_pbo_format(internalFormat, format,
+                        type, intelImage->base.TexFormat)) {
+
+      DBG("trying pbo upload\n");
+
+      /* Attempt to texture directly from PBO data (zero copy upload).
+       *
+       * Currently disable as it can lead to worse as well as better
+       * performance (in particular when pipe_region_cow() is
+       * required).
+       */
+      if (intelObj->mt == intelImage->mt &&
+          intelObj->mt->first_level == level &&
+          intelObj->mt->last_level == level) {
+
+         if (try_pbo_zcopy(intel, intelImage, unpack,
+                           internalFormat,
+                           width, height, format, type, pixels)) {
+
+            DBG("pbo zcopy upload succeeded\n");
+            return;
+         }
+      }
+
+
+      /* Otherwise, attempt to use the blitter for PBO image uploads.
+       */
+      if (try_pbo_upload(intel, intelImage, unpack,
+                         internalFormat,
+                         width, height, format, type, pixels)) {
+         DBG("pbo upload succeeded\n");
+         return;
+      }
+
+      DBG("pbo upload failed\n");
+   }
+#else
+   (void) try_pbo_upload;
+   (void) check_pbo_format;
+   (void) try_pbo_zcopy;
+#endif
+
+
+   /* intelCopyTexImage calls this function with pixels == NULL, with
+    * the expectation that the mipmap tree will be set up but nothing
+    * more will be done.  This is where those calls return:
+    */
+   if (compressed) {
+      pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels,
+                                                     unpack,
+                                                     "glCompressedTexImage");
+   } else {
+      pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1,
+                                          format, type,
+                                          pixels, unpack, "glTexImage");
+   }
+   if (!pixels)
+      return;
+
+
+   if (intelImage->mt)
+      pipe->region_idle(pipe, intelImage->mt->region);
+
+#if 0
+   LOCK_HARDWARE(intel);
+#endif
+
+   if (intelImage->mt) {
+      texImage->Data = st_miptree_image_map(pipe,
+                                               intelImage->mt,
+                                               intelImage->face,
+                                               intelImage->level,
+                                               &dstRowStride,
+                                               intelImage->base.ImageOffsets);
+   }
+   else {
+      /* Allocate regular memory and store the image there temporarily.   */
+      if (texImage->IsCompressed) {
+         sizeInBytes = texImage->CompressedSize;
+         dstRowStride =
+            _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat, width);
+         assert(dims != 3);
+      }
+      else {
+         dstRowStride = postConvWidth * texelBytes;
+         sizeInBytes = depth * dstRowStride * postConvHeight;
+      }
+
+      texImage->Data = malloc(sizeInBytes);
+   }
+
+   DBG("Upload image %dx%dx%d row_len %x pitch %x\n",
+       width, height, depth, width * texelBytes, dstRowStride);
+
+   /* Copy data.  Would like to know when it's ok for us to eg. use
+    * the blitter to copy.  Or, use the hardware to do the format
+    * conversion and copy:
+    */
+   if (compressed) {
+     memcpy(texImage->Data, pixels, imageSize);
+   }
+   else if (!texImage->TexFormat->StoreImage(ctx, dims, 
+                                             texImage->_BaseFormat, 
+                                             texImage->TexFormat, 
+                                             texImage->Data,
+                                             0, 0, 0, /* dstX/Y/Zoffset */
+                                             dstRowStride,
+                                             texImage->ImageOffsets,
+                                             width, height, depth,
+                                             format, type, pixels, unpack)) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
+   }
+
+   _mesa_unmap_teximage_pbo(ctx, unpack);
+
+   if (intelImage->mt) {
+      st_miptree_image_unmap(pipe, intelImage->mt);
+      texImage->Data = NULL;
+   }
+
+#if 0
+   UNLOCK_HARDWARE(intel);
+#endif
+
+#if 0
+   /* GL_SGIS_generate_mipmap -- this can be accelerated now.
+    */
+   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+      intel_generate_mipmap(ctx, target,
+                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+                            texObj);
+   }
+#endif
+}
+
+
+static void
+st_TexImage3D(GLcontext * ctx,
+                GLenum target, GLint level,
+                GLint internalFormat,
+                GLint width, GLint height, GLint depth,
+                GLint border,
+                GLenum format, GLenum type, const void *pixels,
+                const struct gl_pixelstore_attrib *unpack,
+                struct gl_texture_object *texObj,
+                struct gl_texture_image *texImage)
+{
+   st_TexImage(ctx, 3, target, level,
+                 internalFormat, width, height, depth, border,
+                 format, type, pixels, unpack, texObj, texImage, 0, 0);
+}
+
+
+static void
+st_TexImage2D(GLcontext * ctx,
+                GLenum target, GLint level,
+                GLint internalFormat,
+                GLint width, GLint height, GLint border,
+                GLenum format, GLenum type, const void *pixels,
+                const struct gl_pixelstore_attrib *unpack,
+                struct gl_texture_object *texObj,
+                struct gl_texture_image *texImage)
+{
+   st_TexImage(ctx, 2, target, level,
+                 internalFormat, width, height, 1, border,
+                 format, type, pixels, unpack, texObj, texImage, 0, 0);
+}
+
+
+static void
+st_TexImage1D(GLcontext * ctx,
+                GLenum target, GLint level,
+                GLint internalFormat,
+                GLint width, GLint border,
+                GLenum format, GLenum type, const void *pixels,
+                const struct gl_pixelstore_attrib *unpack,
+                struct gl_texture_object *texObj,
+                struct gl_texture_image *texImage)
+{
+   st_TexImage(ctx, 1, target, level,
+                 internalFormat, width, 1, 1, border,
+                 format, type, pixels, unpack, texObj, texImage, 0, 0);
+}
+
+
+static void
+st_CompressedTexImage2D( GLcontext *ctx, GLenum target, GLint level,
+                               GLint internalFormat,
+                               GLint width, GLint height, GLint border,
+                               GLsizei imageSize, const GLvoid *data,
+                               struct gl_texture_object *texObj,
+                               struct gl_texture_image *texImage )
+{
+   st_TexImage(ctx, 2, target, level,
+                internalFormat, width, height, 1, border,
+                0, 0, data, &ctx->Unpack, texObj, texImage, imageSize, 1);
+}
+
+
+/**
+ * Need to map texture image into memory before copying image data,
+ * then unmap it.
+ */
+static void
+st_get_tex_image(GLcontext * ctx, GLenum target, GLint level,
+                 GLenum format, GLenum type, GLvoid * pixels,
+                 struct gl_texture_object *texObj,
+                 struct gl_texture_image *texImage, int compressed)
+{
+   /*
+   struct intel_context *intel = intel_context(ctx);
+   */
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct st_texture_image *stImage = st_texture_image(texImage);
+
+   /* Map */
+   if (stImage->mt) {
+      /* Image is stored in hardware format in a buffer managed by the
+       * kernel.  Need to explicitly map and unmap it.
+       */
+      stImage->base.Data =
+         st_miptree_image_map(pipe,
+                                 stImage->mt,
+                                 stImage->face,
+                                 stImage->level,
+                                 &stImage->base.RowStride,
+                                 stImage->base.ImageOffsets);
+      stImage->base.RowStride /= stImage->mt->cpp;
+   }
+   else {
+      /* Otherwise, the image should actually be stored in
+       * stImage->base.Data.  This is pretty confusing for
+       * everybody, I'd much prefer to separate the two functions of
+       * texImage->Data - storage for texture images in main memory
+       * and access (ie mappings) of images.  In other words, we'd
+       * create a new texImage->Map field and leave Data simply for
+       * storage.
+       */
+      assert(stImage->base.Data);
+   }
+
+
+   if (compressed) {
+      _mesa_get_compressed_teximage(ctx, target, level, pixels,
+                                   texObj, texImage);
+   } else {
+      _mesa_get_teximage(ctx, target, level, format, type, pixels,
+                        texObj, texImage);
+   }
+     
+
+   /* Unmap */
+   if (stImage->mt) {
+      st_miptree_image_unmap(pipe, stImage->mt);
+      stImage->base.Data = NULL;
+   }
+}
+
+
+static void
+st_GetTexImage(GLcontext * ctx, GLenum target, GLint level,
+                 GLenum format, GLenum type, GLvoid * pixels,
+                 struct gl_texture_object *texObj,
+                 struct gl_texture_image *texImage)
+{
+   st_get_tex_image(ctx, target, level, format, type, pixels,
+                    texObj, texImage, 0);
+}
+
+
+static void
+st_GetCompressedTexImage(GLcontext *ctx, GLenum target, GLint level,
+                          GLvoid *pixels,
+                          const struct gl_texture_object *texObj,
+                          const struct gl_texture_image *texImage)
+{
+   st_get_tex_image(ctx, target, level, 0, 0, pixels,
+                    (struct gl_texture_object *) texObj,
+                    (struct gl_texture_image *) texImage, 1);
+}
+
+
+
+static void
+st_TexSubimage(GLcontext * ctx,
+                 GLint dims,
+                 GLenum target, GLint level,
+                 GLint xoffset, GLint yoffset, GLint zoffset,
+                 GLint width, GLint height, GLint depth,
+                 GLenum format, GLenum type, const void *pixels,
+                 const struct gl_pixelstore_attrib *packing,
+                 struct gl_texture_object *texObj,
+                 struct gl_texture_image *texImage)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct st_texture_image *stImage = st_texture_image(texImage);
+   GLuint dstRowStride;
+
+   DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__,
+       _mesa_lookup_enum_by_nr(target),
+       level, xoffset, yoffset, width, height);
+
+#if 0
+   intelFlush(ctx);
+#endif
+
+   pixels =
+      _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format,
+                                  type, pixels, packing, "glTexSubImage2D");
+   if (!pixels)
+      return;
+
+   if (stImage->mt)
+      pipe->region_idle(pipe, stImage->mt->region);
+
+#if 0
+   LOCK_HARDWARE(intel);
+#endif
+
+   /* Map buffer if necessary.  Need to lock to prevent other contexts
+    * from uploading the buffer under us.
+    */
+   if (stImage->mt) 
+      texImage->Data = st_miptree_image_map(pipe,
+                                               stImage->mt,
+                                               stImage->face,
+                                               stImage->level,
+                                               &dstRowStride,
+                                               texImage->ImageOffsets);
+
+   assert(dstRowStride);
+
+   if (!texImage->TexFormat->StoreImage(ctx, dims, texImage->_BaseFormat,
+                                        texImage->TexFormat,
+                                        texImage->Data,
+                                        xoffset, yoffset, zoffset,
+                                        dstRowStride,
+                                        texImage->ImageOffsets,
+                                        width, height, depth,
+                                        format, type, pixels, packing)) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "intelTexSubImage");
+   }
+
+#if 0
+   /* GL_SGIS_generate_mipmap */
+   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+      _mesa_generate_mipmap(ctx, target,
+                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+                            texObj);
+   }
+#endif
+
+   _mesa_unmap_teximage_pbo(ctx, packing);
+
+   if (stImage->mt) {
+      st_miptree_image_unmap(pipe, stImage->mt);
+      texImage->Data = NULL;
+   }
+
+#if 0
+   UNLOCK_HARDWARE(intel);
+#endif
+}
+
+
+
+static void
+st_TexSubImage3D(GLcontext * ctx,
+                   GLenum target,
+                   GLint level,
+                   GLint xoffset, GLint yoffset, GLint zoffset,
+                   GLsizei width, GLsizei height, GLsizei depth,
+                   GLenum format, GLenum type,
+                   const GLvoid * pixels,
+                   const struct gl_pixelstore_attrib *packing,
+                   struct gl_texture_object *texObj,
+                   struct gl_texture_image *texImage)
+{
+   st_TexSubimage(ctx, 3,
+                    target, level,
+                    xoffset, yoffset, zoffset,
+                    width, height, depth,
+                    format, type, pixels, packing, texObj, texImage);
+}
+
+
+
+static void
+st_TexSubImage2D(GLcontext * ctx,
+                   GLenum target,
+                   GLint level,
+                   GLint xoffset, GLint yoffset,
+                   GLsizei width, GLsizei height,
+                   GLenum format, GLenum type,
+                   const GLvoid * pixels,
+                   const struct gl_pixelstore_attrib *packing,
+                   struct gl_texture_object *texObj,
+                   struct gl_texture_image *texImage)
+{
+   st_TexSubimage(ctx, 2,
+                    target, level,
+                    xoffset, yoffset, 0,
+                    width, height, 1,
+                    format, type, pixels, packing, texObj, texImage);
+}
+
+
+static void
+st_TexSubImage1D(GLcontext * ctx,
+                   GLenum target,
+                   GLint level,
+                   GLint xoffset,
+                   GLsizei width,
+                   GLenum format, GLenum type,
+                   const GLvoid * pixels,
+                   const struct gl_pixelstore_attrib *packing,
+                   struct gl_texture_object *texObj,
+                   struct gl_texture_image *texImage)
+{
+   st_TexSubimage(ctx, 1,
+                    target, level,
+                    xoffset, 0, 0,
+                    width, 1, 1,
+                    format, type, pixels, packing, texObj, texImage);
+}
+
+
+
+/**
+ * Get the pipe_region which is the source for any glCopyTex[Sub]Image call.
+ *
+ * Do the best we can using the blitter.  A future project is to use
+ * the texture engine and fragment programs for these copies.
+ */
+static const struct pipe_region *
+get_teximage_source(GLcontext *ctx, GLenum internalFormat)
+{
+#if 00
+   struct intel_renderbuffer *irb;
+
+   DBG("%s %s\n", __FUNCTION__,
+       _mesa_lookup_enum_by_nr(internalFormat));
+
+   switch (internalFormat) {
+   case GL_DEPTH_COMPONENT:
+   case GL_DEPTH_COMPONENT16_ARB:
+      irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH);
+      if (irb && irb->region && irb->region->cpp == 2)
+         return irb->region;
+      return NULL;
+   case GL_DEPTH24_STENCIL8_EXT:
+   case GL_DEPTH_STENCIL_EXT:
+      irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH);
+      if (irb && irb->region && irb->region->cpp == 4)
+         return irb->region;
+      return NULL;
+   case GL_RGBA:
+   case GL_RGBA8:
+      return intel_readbuf_region(intel);
+   case GL_RGB:
+      if (intel->intelScreen->front.cpp == 2)
+         return intel_readbuf_region(intel);
+      return NULL;
+   default:
+      return NULL;
+   }
+#else
+   return NULL;
+#endif
+}
+
+
+static GLboolean
+do_copy_texsubimage(GLcontext *ctx,
+                    struct st_texture_image *stImage,
+                    GLenum internalFormat,
+                    GLint dstx, GLint dsty,
+                    GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   const struct pipe_region *src =
+      get_teximage_source(ctx, internalFormat);
+
+   if (!stImage->mt || !src) {
+      DBG("%s fail %p %p\n", __FUNCTION__, stImage->mt, src);
+      return GL_FALSE;
+   }
+
+#if 00 /* XXX FIX flush/locking */
+   intelFlush(ctx);
+   /* XXX still need the lock ? */
+   LOCK_HARDWARE(intel);
+#endif
+
+   {
+      GLuint image_offset = st_miptree_image_offset(stImage->mt,
+                                                       stImage->face,
+                                                       stImage->level);
+      const GLint orig_x = x;
+      const GLint orig_y = y;
+      const struct gl_framebuffer *fb = ctx->DrawBuffer;
+
+      if (_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax,
+                               &x, &y, &width, &height)) {
+         /* Update dst for clipped src.  Need to also clip the source rect.
+          */
+         dstx += x - orig_x;
+         dsty += y - orig_y;
+
+         if (!(ctx->ReadBuffer->Name == 0)) {
+           /* XXX this looks bogus ? */
+           /* FBO: invert Y */
+           y = ctx->ReadBuffer->Height - y - 1;
+         }
+
+         /* A bit of fiddling to get the blitter to work with -ve
+          * pitches.  But we get a nice inverted blit this way, so it's
+          * worth it:
+          */
+#if 0
+         intelEmitCopyBlit(intel,
+                           stImage->mt->cpp,
+                           -src->pitch,
+                           src->buffer,
+                           src->height * src->pitch * src->cpp,
+                           stImage->mt->pitch,
+                           stImage->mt->region->buffer,
+                           image_offset,
+                           x, y + height, dstx, dsty, width, height,
+                          GL_COPY); /* ? */
+         intel_batchbuffer_flush(intel->batch);
+#else
+         /* XXX use pipe->region_copy() ??? */
+         (void) image_offset;
+#endif
+      }
+   }
+
+#if 0
+   UNLOCK_HARDWARE(intel);
+#endif
+
+#if 0
+   /* GL_SGIS_generate_mipmap -- this can be accelerated now.
+    * XXX Add a ctx->Driver.GenerateMipmaps() function?
+    */
+   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+      intel_generate_mipmap(ctx, target,
+                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+                            texObj);
+   }
+#endif
+
+   return GL_TRUE;
+}
+
+
+static void
+st_CopyTexImage1D(GLcontext * ctx, GLenum target, GLint level,
+                  GLenum internalFormat,
+                  GLint x, GLint y, GLsizei width, GLint border)
+{
+   struct gl_texture_unit *texUnit =
+      &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   struct gl_texture_object *texObj =
+      _mesa_select_tex_object(ctx, texUnit, target);
+   struct gl_texture_image *texImage =
+      _mesa_select_tex_image(ctx, texObj, target, level);
+
+   if (border)
+      goto fail;
+
+   /* Setup or redefine the texture object, mipmap tree and texture
+    * image.  Don't populate yet.  
+    */
+   ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
+                          width, border,
+                          GL_RGBA, CHAN_TYPE, NULL,
+                          &ctx->DefaultPacking, texObj, texImage);
+
+   if (!do_copy_texsubimage(ctx,
+                            st_texture_image(texImage),
+                            internalFormat, 0, 0, x, y, width, 1))
+      goto fail;
+
+   return;
+
+ fail:
+#if 0
+   _swrast_copy_teximage1d(ctx, target, level, internalFormat, x, y,
+                           width, border);
+#endif
+   ;
+}
+
+
+static void
+st_CopyTexImage2D(GLcontext * ctx, GLenum target, GLint level,
+                  GLenum internalFormat,
+                  GLint x, GLint y, GLsizei width, GLsizei height,
+                  GLint border)
+{
+   struct gl_texture_unit *texUnit =
+      &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   struct gl_texture_object *texObj =
+      _mesa_select_tex_object(ctx, texUnit, target);
+   struct gl_texture_image *texImage =
+      _mesa_select_tex_image(ctx, texObj, target, level);
+
+   if (border)
+      goto fail;
+
+   /* Setup or redefine the texture object, mipmap tree and texture
+    * image.  Don't populate yet.  
+    */
+   ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
+                          width, height, border,
+                          GL_RGBA, CHAN_TYPE, NULL,
+                          &ctx->DefaultPacking, texObj, texImage);
+
+
+   if (!do_copy_texsubimage(ctx,
+                            st_texture_image(texImage),
+                            internalFormat, 0, 0, x, y, width, height))
+      goto fail;
+
+   return;
+
+ fail:
+#if 0
+   _swrast_copy_teximage2d(ctx, target, level, internalFormat, x, y,
+                           width, height, border);
+#endif
+   assert(0);
+}
+
+
+static void
+st_CopyTexSubImage1D(GLcontext * ctx, GLenum target, GLint level,
+                     GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+   struct gl_texture_unit *texUnit =
+      &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   struct gl_texture_object *texObj =
+      _mesa_select_tex_object(ctx, texUnit, target);
+   struct gl_texture_image *texImage =
+      _mesa_select_tex_image(ctx, texObj, target, level);
+   GLenum internalFormat = texImage->InternalFormat;
+
+   /* XXX need to check <border> as in above function? */
+
+   /* Need to check texture is compatible with source format. 
+    */
+
+   if (!do_copy_texsubimage(ctx,
+                            st_texture_image(texImage),
+                            internalFormat, xoffset, 0, x, y, width, 1)) {
+#if 0
+      _swrast_copy_texsubimage1d(ctx, target, level, xoffset, x, y, width);
+#endif
+      assert(0);
+   }
+}
+
+
+static void
+st_CopyTexSubImage2D(GLcontext * ctx, GLenum target, GLint level,
+                     GLint xoffset, GLint yoffset,
+                     GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_unit *texUnit =
+      &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   struct gl_texture_object *texObj =
+      _mesa_select_tex_object(ctx, texUnit, target);
+   struct gl_texture_image *texImage =
+      _mesa_select_tex_image(ctx, texObj, target, level);
+   GLenum internalFormat = texImage->InternalFormat;
+
+
+   /* Need to check texture is compatible with source format. 
+    */
+
+   if (!do_copy_texsubimage(ctx,
+                            st_texture_image(texImage),
+                            internalFormat,
+                            xoffset, yoffset, x, y, width, height)) {
+#if 0
+      _swrast_copy_texsubimage2d(ctx, target, level,
+                                 xoffset, yoffset, x, y, width, height);
+#endif
+      assert(0);
+   }
+}
+
+
+
+
+/**
+ * Compute which mipmap levels that really need to be sent to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ */
+static void
+intel_calculate_first_last_level(struct st_texture_object *intelObj)
+{
+   struct gl_texture_object *tObj = &intelObj->base;
+   const struct gl_texture_image *const baseImage =
+      tObj->Image[0][tObj->BaseLevel];
+
+   /* These must be signed values.  MinLod and MaxLod can be negative numbers,
+    * and having firstLevel and lastLevel as signed prevents the need for
+    * extra sign checks.
+    */
+   int firstLevel;
+   int lastLevel;
+
+   /* Yes, this looks overly complicated, but it's all needed.
+    */
+   switch (tObj->Target) {
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_3D:
+   case GL_TEXTURE_CUBE_MAP:
+      if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
+         /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
+          */
+         firstLevel = lastLevel = tObj->BaseLevel;
+      }
+      else {
+         firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5);
+         firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+         lastLevel = tObj->BaseLevel + (GLint) (tObj->MaxLod + 0.5);
+         lastLevel = MAX2(lastLevel, tObj->BaseLevel);
+         lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+         lastLevel = MIN2(lastLevel, tObj->MaxLevel);
+         lastLevel = MAX2(firstLevel, lastLevel);       /* need at least one level */
+      }
+      break;
+   case GL_TEXTURE_RECTANGLE_NV:
+   case GL_TEXTURE_4D_SGIS:
+      firstLevel = lastLevel = 0;
+      break;
+   default:
+      return;
+   }
+
+   /* save these values */
+   intelObj->firstLevel = firstLevel;
+   intelObj->lastLevel = lastLevel;
+}
+
+
+static void
+copy_image_data_to_tree(struct pipe_context *pipe,
+                        struct st_texture_object *intelObj,
+                        struct st_texture_image *stImage)
+{
+   if (stImage->mt) {
+      /* Copy potentially with the blitter:
+       */
+      st_miptree_image_copy(pipe,
+                               intelObj->mt,
+                               stImage->face,
+                               stImage->level, stImage->mt);
+
+      st_miptree_release(pipe, &stImage->mt);
+   }
+   else {
+      assert(stImage->base.Data != NULL);
+
+      /* More straightforward upload.  
+       */
+      st_miptree_image_data(pipe,
+                               intelObj->mt,
+                               stImage->face,
+                               stImage->level,
+                               stImage->base.Data,
+                               stImage->base.RowStride,
+                               stImage->base.RowStride *
+                               stImage->base.Height);
+      _mesa_align_free(stImage->base.Data);
+      stImage->base.Data = NULL;
+   }
+
+   st_miptree_reference(&stImage->mt, intelObj->mt);
+}
+
+
+/*  
+ */
+GLuint
+st_finalize_mipmap_tree(GLcontext *ctx,
+                        struct pipe_context *pipe, GLuint unit,
+                        GLboolean *needFlush)
+{
+   struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current;
+   struct st_texture_object *intelObj = st_texture_object(tObj);
+   int comp_byte = 0;
+   int cpp;
+
+   GLuint face, i;
+   GLuint nr_faces = 0;
+   struct st_texture_image *firstImage;
+
+   *needFlush = GL_FALSE;
+
+   /* We know/require this is true by now: 
+    */
+   assert(intelObj->base._Complete);
+
+   /* What levels must the tree include at a minimum?
+    */
+   intel_calculate_first_last_level(intelObj);
+   firstImage =
+      st_texture_image(intelObj->base.Image[0][intelObj->firstLevel]);
+
+   /* Fallback case:
+    */
+   if (firstImage->base.Border) {
+      if (intelObj->mt) {
+         st_miptree_release(pipe, &intelObj->mt);
+      }
+      return GL_FALSE;
+   }
+
+
+   /* If both firstImage and intelObj have a tree which can contain
+    * all active images, favour firstImage.  Note that because of the
+    * completeness requirement, we know that the image dimensions
+    * will match.
+    */
+   if (firstImage->mt &&
+       firstImage->mt != intelObj->mt &&
+       firstImage->mt->first_level <= intelObj->firstLevel &&
+       firstImage->mt->last_level >= intelObj->lastLevel) {
+
+      if (intelObj->mt)
+         st_miptree_release(pipe, &intelObj->mt);
+
+      st_miptree_reference(&intelObj->mt, firstImage->mt);
+   }
+
+   if (firstImage->base.IsCompressed) {
+      comp_byte = intel_compressed_num_bytes(firstImage->base.TexFormat->MesaFormat);
+      cpp = comp_byte;
+   }
+   else cpp = firstImage->base.TexFormat->TexelBytes;
+
+   /* Check tree can hold all active levels.  Check tree matches
+    * target, imageFormat, etc.
+    * 
+    * XXX: For some layouts (eg i945?), the test might have to be
+    * first_level == firstLevel, as the tree isn't valid except at the
+    * original start level.  Hope to get around this by
+    * programming minLod, maxLod, baseLevel into the hardware and
+    * leaving the tree alone.
+    */
+   if (intelObj->mt &&
+       (intelObj->mt->target != intelObj->base.Target ||
+       intelObj->mt->internal_format != firstImage->base.InternalFormat ||
+       intelObj->mt->first_level != intelObj->firstLevel ||
+       intelObj->mt->last_level != intelObj->lastLevel ||
+       intelObj->mt->width0 != firstImage->base.Width ||
+       intelObj->mt->height0 != firstImage->base.Height ||
+       intelObj->mt->depth0 != firstImage->base.Depth ||
+       intelObj->mt->cpp != cpp ||
+       intelObj->mt->compressed != firstImage->base.IsCompressed)) {
+      st_miptree_release(pipe, &intelObj->mt);
+   }
+
+
+   /* May need to create a new tree:
+    */
+   if (!intelObj->mt) {
+      intelObj->mt = st_miptree_create(pipe,
+                                          intelObj->base.Target,
+                                          firstImage->base.InternalFormat,
+                                          intelObj->firstLevel,
+                                          intelObj->lastLevel,
+                                          firstImage->base.Width,
+                                          firstImage->base.Height,
+                                          firstImage->base.Depth,
+                                          cpp,
+                                          comp_byte);
+   }
+
+   /* Pull in any images not in the object's tree:
+    */
+   nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+   for (face = 0; face < nr_faces; face++) {
+      for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
+         struct st_texture_image *stImage =
+            st_texture_image(intelObj->base.Image[face][i]);
+
+         /* Need to import images in main memory or held in other trees.
+          */
+         if (intelObj->mt != stImage->mt) {
+            copy_image_data_to_tree(pipe, intelObj, stImage);
+           *needFlush = GL_TRUE;
+         }
+      }
+   }
+
+   /**
+   if (need_flush)
+      intel_batchbuffer_flush(intel->batch);
+   **/
+
+   return GL_TRUE;
+}
+
+
+#if 0 /* unused? */
+void
+st_tex_map_images(struct pipe_context *pipe,
+                  struct st_texture_object *intelObj)
+{
+   GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+   GLuint face, i;
+
+   DBG("%s\n", __FUNCTION__);
+
+   for (face = 0; face < nr_faces; face++) {
+      for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
+         struct st_texture_image *stImage =
+            st_texture_image(intelObj->base.Image[face][i]);
+
+         if (stImage->mt) {
+            stImage->base.Data =
+               st_miptree_image_map(pipe,
+                                       stImage->mt,
+                                       stImage->face,
+                                       stImage->level,
+                                       &stImage->base.RowStride,
+                                       stImage->base.ImageOffsets);
+            /* convert stride to texels, not bytes */
+            stImage->base.RowStride /= stImage->mt->cpp;
+/*             stImage->base.ImageStride /= stImage->mt->cpp; */
+         }
+      }
+   }
+}
+
+
+
+void
+st_tex_unmap_images(struct pipe_context *pipe,
+                    struct st_texture_object *intelObj)
+{
+   GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+   GLuint face, i;
+
+   for (face = 0; face < nr_faces; face++) {
+      for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
+         struct st_texture_image *stImage =
+            st_texture_image(intelObj->base.Image[face][i]);
+
+         if (stImage->mt) {
+            st_miptree_image_unmap(pipe, stImage->mt);
+            stImage->base.Data = NULL;
+         }
+      }
+   }
+}
+#endif
+
+
+
+
+void st_init_cb_texture( struct st_context *st )
+{
+   struct dd_function_table *functions = &st->ctx->Driver;
+
+   functions->ChooseTextureFormat = st_ChooseTextureFormat;
+   functions->TexImage1D = st_TexImage1D;
+   functions->TexImage2D = st_TexImage2D;
+   functions->TexImage3D = st_TexImage3D;
+   functions->TexSubImage1D = st_TexSubImage1D;
+   functions->TexSubImage2D = st_TexSubImage2D;
+   functions->TexSubImage3D = st_TexSubImage3D;
+   functions->CopyTexImage1D = st_CopyTexImage1D;
+   functions->CopyTexImage2D = st_CopyTexImage2D;
+   functions->CopyTexSubImage1D = st_CopyTexSubImage1D;
+   functions->CopyTexSubImage2D = st_CopyTexSubImage2D;
+   functions->GetTexImage = st_GetTexImage;
+
+   /* compressed texture functions */
+   functions->CompressedTexImage2D = st_CompressedTexImage2D;
+   functions->GetCompressedTexImage = st_GetCompressedTexImage;
+
+   functions->NewTextureObject = st_NewTextureObject;
+   functions->NewTextureImage = st_NewTextureImage;
+   functions->DeleteTexture = st_DeleteTextureObject;
+   functions->FreeTexImageData = st_FreeTextureImageData;
+   functions->UpdateTexturePalette = 0;
+   functions->IsTextureResident = st_IsTextureResident;
+
+   functions->TextureMemCpy = do_memcpy;
+}
+
+
+void st_destroy_cb_texture( struct st_context *st )
+{
+}
diff --git a/src/mesa/state_tracker/st_cb_texture.h b/src/mesa/state_tracker/st_cb_texture.h
new file mode 100644 (file)
index 0000000..c474d16
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef ST_CB_TEXTURE_H
+#define ST_CB_TEXTURE_H
+
+
+extern GLuint
+st_finalize_mipmap_tree(GLcontext *ctx,
+                        struct pipe_context *pipe, GLuint unit,
+                        GLboolean *needFlush);
+
+
+extern void
+st_init_cb_texture( struct st_context *st );
+
+
+extern void
+st_destroy_cb_texture( struct st_context *st );
+
+
+#endif /* ST_CB_TEXTURE_H */