Move mipmap generation functions, texture scaling functions into new
authorBrian Paul <brian.paul@tungstengraphics.com>
Fri, 29 Sep 2006 01:24:26 +0000 (01:24 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Fri, 29 Sep 2006 01:24:26 +0000 (01:24 +0000)
mipmap.c file.

13 files changed:
src/mesa/drivers/dri/tdfx/tdfx_tex.c
src/mesa/drivers/dri/unichrome/via_tex.c
src/mesa/main/descrip.mms
src/mesa/main/fbobject.c
src/mesa/main/mipmap.c [new file with mode: 0644]
src/mesa/main/mipmap.h [new file with mode: 0644]
src/mesa/main/texcompress.c
src/mesa/main/texstore.c
src/mesa/main/texstore.h
src/mesa/sources
src/mesa/swrast/s_texstore.c
windows/VC6/mesa/mesa/mesa.dsp
windows/VC7/mesa/mesa/mesa.vcproj

index 862c7dacf1ffc5c806a620220a56b950737e571f..f67934587206aaefb1823dc61f2c05e0a1c979e1 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "enums.h"
 #include "image.h"
+#include "mipmap.h"
 #include "texcompress.h"
 #include "texformat.h"
 #include "teximage.h"
index b344c00931874c019b1e7cd8ca02d41ed7f414f8..939422ce2f93cb619eef2890bce469dd75e57246 100644 (file)
@@ -33,6 +33,7 @@
 #include "colortab.h"
 #include "convolve.h"
 #include "context.h"
+#include "mipmap.h"
 #include "simple_list.h"
 #include "texcompress.h"
 #include "texformat.h"
index 5790e6b796c1637fddd4cfb1753d2f9b01fa0a22..d09c57b3212857f726a628808ad68ff0ce77579f 100644 (file)
@@ -56,6 +56,7 @@ SOURCES =accum.c \
        light.c \
        lines.c \
        matrix.c \
+       mipmap.c \
        mm.c \
        occlude.c \
        pixel.c \
@@ -118,6 +119,7 @@ imports.obj,\
 light.obj,\
 lines.obj,\
 matrix.obj,\
+mipmap.obj,\
 mm.obj,\
 occlude.obj,\
 pixel.obj,\
@@ -193,6 +195,7 @@ imports.obj : imports.c vsnprintf.c
 light.obj : light.c
 lines.obj : lines.c
 matrix.obj : matrix.c
+mipmap.obj : mipmap.c
 mm.obj : mm.c
 occlude.obj : occlude.c
 pixel.obj : pixel.c
index f00b37fc9f62899f51d3b1e90226cb168d705464..2ca10146313f90833698251a06306410a0fdf9bc 100644 (file)
@@ -33,6 +33,7 @@
 #include "fbobject.h"
 #include "framebuffer.h"
 #include "hash.h"
+#include "mipmap.h"
 #include "renderbuffer.h"
 #include "state.h"
 #include "teximage.h"
diff --git a/src/mesa/main/mipmap.c b/src/mesa/main/mipmap.c
new file mode 100644 (file)
index 0000000..604dea3
--- /dev/null
@@ -0,0 +1,1147 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5.2
+ *
+ * Copyright (C) 1999-2006  Brian Paul   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, sublicense,
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+
+/**
+ * \file mipmap.c  mipmap generation and teximage resizing functions.
+ */
+
+#include "imports.h"
+#include "mipmap.h"
+#include "texcompress.h"
+#include "texformat.h"
+#include "teximage.h"
+#include "image.h"
+
+
+
+/**
+ * Average together two rows of a source image to produce a single new
+ * row in the dest image.  It's legal for the two source rows to point
+ * to the same data.  The source width must be equal to either the
+ * dest width or two times the dest width.
+ */
+static void
+do_row(const struct gl_texture_format *format, GLint srcWidth,
+       const GLvoid *srcRowA, const GLvoid *srcRowB,
+       GLint dstWidth, GLvoid *dstRow)
+{
+   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
+   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
+
+   /* This assertion is no longer valid with non-power-of-2 textures
+   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
+   */
+
+   switch (format->MesaFormat) {
+   case MESA_FORMAT_RGBA:
+      {
+         GLuint i, j, k;
+         const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
+         const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
+         GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) / 4;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) / 4;
+            dst[i][2] = (rowA[j][2] + rowA[k][2] +
+                         rowB[j][2] + rowB[k][2]) / 4;
+            dst[i][3] = (rowA[j][3] + rowA[k][3] +
+                         rowB[j][3] + rowB[k][3]) / 4;
+         }
+      }
+      return;
+   case MESA_FORMAT_RGB:
+      {
+         GLuint i, j, k;
+         const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
+         const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
+         GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) / 4;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) / 4;
+            dst[i][2] = (rowA[j][2] + rowA[k][2] +
+                         rowB[j][2] + rowB[k][2]) / 4;
+         }
+      }
+      return;
+   case MESA_FORMAT_ALPHA:
+   case MESA_FORMAT_LUMINANCE:
+   case MESA_FORMAT_INTENSITY:
+      {
+         GLuint i, j, k;
+         const GLchan *rowA = (const GLchan *) srcRowA;
+         const GLchan *rowB = (const GLchan *) srcRowB;
+         GLchan *dst = (GLchan *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
+         }
+      }
+      return;
+   case MESA_FORMAT_LUMINANCE_ALPHA:
+      {
+         GLuint i, j, k;
+         const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
+         const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
+         GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) / 4;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) / 4;
+         }
+      }
+      return;
+   case MESA_FORMAT_Z32:
+      {
+         GLuint i, j, k;
+         const GLuint *rowA = (const GLuint *) srcRowA;
+         const GLuint *rowB = (const GLuint *) srcRowB;
+         GLfloat *dst = (GLfloat *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
+         }
+      }
+      return;
+   case MESA_FORMAT_Z16:
+      {
+         GLuint i, j, k;
+         const GLushort *rowA = (const GLushort *) srcRowA;
+         const GLushort *rowB = (const GLushort *) srcRowB;
+         GLushort *dst = (GLushort *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
+         }
+      }
+      return;
+   /* Begin hardware formats */
+   case MESA_FORMAT_RGBA8888:
+   case MESA_FORMAT_RGBA8888_REV:
+   case MESA_FORMAT_ARGB8888:
+   case MESA_FORMAT_ARGB8888_REV:
+#if FEATURE_EXT_texture_sRGB
+   case MESA_FORMAT_SRGBA8:
+#endif
+      {
+         GLuint i, j, k;
+         const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
+         const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
+         GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) / 4;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) / 4;
+            dst[i][2] = (rowA[j][2] + rowA[k][2] +
+                         rowB[j][2] + rowB[k][2]) / 4;
+            dst[i][3] = (rowA[j][3] + rowA[k][3] +
+                         rowB[j][3] + rowB[k][3]) / 4;
+         }
+      }
+      return;
+   case MESA_FORMAT_RGB888:
+   case MESA_FORMAT_BGR888:
+#if FEATURE_EXT_texture_sRGB
+   case MESA_FORMAT_SRGB8:
+#endif
+      {
+         GLuint i, j, k;
+         const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
+         const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
+         GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) / 4;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) / 4;
+            dst[i][2] = (rowA[j][2] + rowA[k][2] +
+                         rowB[j][2] + rowB[k][2]) / 4;
+         }
+      }
+      return;
+   case MESA_FORMAT_RGB565:
+   case MESA_FORMAT_RGB565_REV:
+      {
+         GLuint i, j, k;
+         const GLushort *rowA = (const GLushort *) srcRowA;
+         const GLushort *rowB = (const GLushort *) srcRowB;
+         GLushort *dst = (GLushort *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            const GLint rowAr0 = rowA[j] & 0x1f;
+            const GLint rowAr1 = rowA[k] & 0x1f;
+            const GLint rowBr0 = rowB[j] & 0x1f;
+            const GLint rowBr1 = rowB[k] & 0x1f;
+            const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
+            const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
+            const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
+            const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
+            const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
+            const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
+            const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
+            const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
+            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
+            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
+            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
+            dst[i] = (blue << 11) | (green << 5) | red;
+         }
+      }
+      return;
+   case MESA_FORMAT_ARGB4444:
+   case MESA_FORMAT_ARGB4444_REV:
+      {
+         GLuint i, j, k;
+         const GLushort *rowA = (const GLushort *) srcRowA;
+         const GLushort *rowB = (const GLushort *) srcRowB;
+         GLushort *dst = (GLushort *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            const GLint rowAr0 = rowA[j] & 0xf;
+            const GLint rowAr1 = rowA[k] & 0xf;
+            const GLint rowBr0 = rowB[j] & 0xf;
+            const GLint rowBr1 = rowB[k] & 0xf;
+            const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
+            const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
+            const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
+            const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
+            const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
+            const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
+            const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
+            const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
+            const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
+            const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
+            const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
+            const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
+            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
+            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
+            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
+            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
+            dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
+         }
+      }
+      return;
+   case MESA_FORMAT_ARGB1555:
+   case MESA_FORMAT_ARGB1555_REV: /* XXX broken? */
+      {
+         GLuint i, j, k;
+         const GLushort *rowA = (const GLushort *) srcRowA;
+         const GLushort *rowB = (const GLushort *) srcRowB;
+         GLushort *dst = (GLushort *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            const GLint rowAr0 = rowA[j] & 0x1f;
+            const GLint rowAr1 = rowA[k] & 0x1f;
+            const GLint rowBr0 = rowB[j] & 0x1f;
+            const GLint rowBr1 = rowB[k] & 0xf;
+            const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
+            const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
+            const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
+            const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
+            const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
+            const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
+            const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
+            const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
+            const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
+            const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
+            const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
+            const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
+            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
+            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
+            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
+            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
+            dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
+         }
+      }
+      return;
+   case MESA_FORMAT_AL88:
+   case MESA_FORMAT_AL88_REV:
+#if FEATURE_EXT_texture_sRGB
+   case MESA_FORMAT_SLA8:
+#endif
+      {
+         GLuint i, j, k;
+         const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
+         const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
+         GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) >> 2;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) >> 2;
+         }
+      }
+      return;
+   case MESA_FORMAT_RGB332:
+      {
+         GLuint i, j, k;
+         const GLubyte *rowA = (const GLubyte *) srcRowA;
+         const GLubyte *rowB = (const GLubyte *) srcRowB;
+         GLubyte *dst = (GLubyte *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            const GLint rowAr0 = rowA[j] & 0x3;
+            const GLint rowAr1 = rowA[k] & 0x3;
+            const GLint rowBr0 = rowB[j] & 0x3;
+            const GLint rowBr1 = rowB[k] & 0x3;
+            const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
+            const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
+            const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
+            const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
+            const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
+            const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
+            const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
+            const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
+            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
+            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
+            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
+            dst[i] = (blue << 5) | (green << 2) | red;
+         }
+      }
+      return;
+   case MESA_FORMAT_A8:
+   case MESA_FORMAT_L8:
+   case MESA_FORMAT_I8:
+   case MESA_FORMAT_CI8:
+#if FEATURE_EXT_texture_sRGB
+   case MESA_FORMAT_SL8:
+#endif
+      {
+         GLuint i, j, k;
+         const GLubyte *rowA = (const GLubyte *) srcRowA;
+         const GLubyte *rowB = (const GLubyte *) srcRowB;
+         GLubyte *dst = (GLubyte *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
+         }
+      }
+      return;
+   case MESA_FORMAT_RGBA_FLOAT32:
+      {
+         GLuint i, j, k;
+         const GLfloat (*rowA)[4] = (const GLfloat (*)[4]) srcRowA;
+         const GLfloat (*rowB)[4] = (const GLfloat (*)[4]) srcRowB;
+         GLfloat (*dst)[4] = (GLfloat (*)[4]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) * 0.25F;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) * 0.25F;
+            dst[i][2] = (rowA[j][2] + rowA[k][2] +
+                         rowB[j][2] + rowB[k][2]) * 0.25F;
+            dst[i][3] = (rowA[j][3] + rowA[k][3] +
+                         rowB[j][3] + rowB[k][3]) * 0.25F;
+         }
+      }
+      return;
+   case MESA_FORMAT_RGBA_FLOAT16:
+      {
+         GLuint i, j, k, comp;
+         const GLhalfARB (*rowA)[4] = (const GLhalfARB (*)[4]) srcRowA;
+         const GLhalfARB (*rowB)[4] = (const GLhalfARB (*)[4]) srcRowB;
+         GLhalfARB (*dst)[4] = (GLhalfARB (*)[4]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            for (comp = 0; comp < 4; comp++) {
+               GLfloat aj, ak, bj, bk;
+               aj = _mesa_half_to_float(rowA[j][comp]);
+               ak = _mesa_half_to_float(rowA[k][comp]);
+               bj = _mesa_half_to_float(rowB[j][comp]);
+               bk = _mesa_half_to_float(rowB[k][comp]);
+               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
+            }
+         }
+      }
+      return;
+   case MESA_FORMAT_RGB_FLOAT32:
+      {
+         GLuint i, j, k;
+         const GLfloat (*rowA)[3] = (const GLfloat (*)[3]) srcRowA;
+         const GLfloat (*rowB)[3] = (const GLfloat (*)[3]) srcRowB;
+         GLfloat (*dst)[3] = (GLfloat (*)[3]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) * 0.25F;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) * 0.25F;
+            dst[i][2] = (rowA[j][2] + rowA[k][2] +
+                         rowB[j][2] + rowB[k][2]) * 0.25F;
+         }
+      }
+      return;
+   case MESA_FORMAT_RGB_FLOAT16:
+      {
+         GLuint i, j, k, comp;
+         const GLhalfARB (*rowA)[3] = (const GLhalfARB (*)[3]) srcRowA;
+         const GLhalfARB (*rowB)[3] = (const GLhalfARB (*)[3]) srcRowB;
+         GLhalfARB (*dst)[3] = (GLhalfARB (*)[3]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            for (comp = 0; comp < 3; comp++) {
+               GLfloat aj, ak, bj, bk;
+               aj = _mesa_half_to_float(rowA[j][comp]);
+               ak = _mesa_half_to_float(rowA[k][comp]);
+               bj = _mesa_half_to_float(rowB[j][comp]);
+               bk = _mesa_half_to_float(rowB[k][comp]);
+               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
+            }
+         }
+      }
+      return;
+   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32:
+      {
+         GLuint i, j, k;
+         const GLfloat (*rowA)[2] = (const GLfloat (*)[2]) srcRowA;
+         const GLfloat (*rowB)[2] = (const GLfloat (*)[2]) srcRowB;
+         GLfloat (*dst)[2] = (GLfloat (*)[2]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i][0] = (rowA[j][0] + rowA[k][0] +
+                         rowB[j][0] + rowB[k][0]) * 0.25F;
+            dst[i][1] = (rowA[j][1] + rowA[k][1] +
+                         rowB[j][1] + rowB[k][1]) * 0.25F;
+         }
+      }
+      return;
+   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16:
+      {
+         GLuint i, j, k, comp;
+         const GLhalfARB (*rowA)[2] = (const GLhalfARB (*)[2]) srcRowA;
+         const GLhalfARB (*rowB)[2] = (const GLhalfARB (*)[2]) srcRowB;
+         GLhalfARB (*dst)[2] = (GLhalfARB (*)[2]) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            for (comp = 0; comp < 2; comp++) {
+               GLfloat aj, ak, bj, bk;
+               aj = _mesa_half_to_float(rowA[j][comp]);
+               ak = _mesa_half_to_float(rowA[k][comp]);
+               bj = _mesa_half_to_float(rowB[j][comp]);
+               bk = _mesa_half_to_float(rowB[k][comp]);
+               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
+            }
+         }
+      }
+      return;
+   case MESA_FORMAT_ALPHA_FLOAT32:
+   case MESA_FORMAT_LUMINANCE_FLOAT32:
+   case MESA_FORMAT_INTENSITY_FLOAT32:
+      {
+         GLuint i, j, k;
+         const GLfloat *rowA = (const GLfloat *) srcRowA;
+         const GLfloat *rowB = (const GLfloat *) srcRowB;
+         GLfloat *dst = (GLfloat *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
+         }
+      }
+      return;
+   case MESA_FORMAT_ALPHA_FLOAT16:
+   case MESA_FORMAT_LUMINANCE_FLOAT16:
+   case MESA_FORMAT_INTENSITY_FLOAT16:
+      {
+         GLuint i, j, k;
+         const GLhalfARB *rowA = (const GLhalfARB *) srcRowA;
+         const GLhalfARB *rowB = (const GLhalfARB *) srcRowB;
+         GLhalfARB *dst = (GLhalfARB *) dstRow;
+         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+              i++, j += colStride, k += colStride) {
+            GLfloat aj, ak, bj, bk;
+            aj = _mesa_half_to_float(rowA[j]);
+            ak = _mesa_half_to_float(rowA[k]);
+            bj = _mesa_half_to_float(rowB[j]);
+            bk = _mesa_half_to_float(rowB[k]);
+            dst[i] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
+         }
+      }
+      return;
+
+   default:
+      _mesa_problem(NULL, "bad format in do_row()");
+   }
+}
+
+
+/*
+ * These functions generate a 1/2-size mipmap image from a source image.
+ * Texture borders are handled by copying or averaging the source image's
+ * border texels, depending on the scale-down factor.
+ */
+
+static void
+make_1d_mipmap(const struct gl_texture_format *format, GLint border,
+               GLint srcWidth, const GLubyte *srcPtr,
+               GLint dstWidth, GLubyte *dstPtr)
+{
+   const GLint bpt = format->TexelBytes;
+   const GLubyte *src;
+   GLubyte *dst;
+
+   /* skip the border pixel, if any */
+   src = srcPtr + border * bpt;
+   dst = dstPtr + border * bpt;
+
+   /* we just duplicate the input row, kind of hack, saves code */
+   do_row(format, srcWidth - 2 * border, src, src,
+          dstWidth - 2 * border, dst);
+
+   if (border) {
+      /* copy left-most pixel from source */
+      MEMCPY(dstPtr, srcPtr, bpt);
+      /* copy right-most pixel from source */
+      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
+             srcPtr + (srcWidth - 1) * bpt,
+             bpt);
+   }
+}
+
+
+/**
+ * XXX need to use the tex image's row stride!
+ */
+static void
+make_2d_mipmap(const struct gl_texture_format *format, GLint border,
+               GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
+               GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
+{
+   const GLint bpt = format->TexelBytes;
+   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
+   const GLint dstWidthNB = dstWidth - 2 * border;
+   const GLint dstHeightNB = dstHeight - 2 * border;
+   const GLint srcRowStride = bpt * srcWidth;
+   const GLint dstRowStride = bpt * dstWidth;
+   const GLubyte *srcA, *srcB;
+   GLubyte *dst;
+   GLint row;
+
+   /* Compute src and dst pointers, skipping any border */
+   srcA = srcPtr + border * ((srcWidth + 1) * bpt);
+   if (srcHeight > 1)
+      srcB = srcA + srcRowStride;
+   else
+      srcB = srcA;
+   dst = dstPtr + border * ((dstWidth + 1) * bpt);
+
+   for (row = 0; row < dstHeightNB; row++) {
+      do_row(format, srcWidthNB, srcA, srcB,
+             dstWidthNB, dst);
+      srcA += 2 * srcRowStride;
+      srcB += 2 * srcRowStride;
+      dst += dstRowStride;
+   }
+
+   /* This is ugly but probably won't be used much */
+   if (border > 0) {
+      /* fill in dest border */
+      /* lower-left border pixel */
+      MEMCPY(dstPtr, srcPtr, bpt);
+      /* lower-right border pixel */
+      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
+             srcPtr + (srcWidth - 1) * bpt, bpt);
+      /* upper-left border pixel */
+      MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
+             srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
+      /* upper-right border pixel */
+      MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
+             srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
+      /* lower border */
+      do_row(format, srcWidthNB,
+             srcPtr + bpt,
+             srcPtr + bpt,
+             dstWidthNB, dstPtr + bpt);
+      /* upper border */
+      do_row(format, srcWidthNB,
+             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
+             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
+             dstWidthNB,
+             dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
+      /* left and right borders */
+      if (srcHeight == dstHeight) {
+         /* copy border pixel from src to dst */
+         for (row = 1; row < srcHeight; row++) {
+            MEMCPY(dstPtr + dstWidth * row * bpt,
+                   srcPtr + srcWidth * row * bpt, bpt);
+            MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
+                   srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
+         }
+      }
+      else {
+         /* average two src pixels each dest pixel */
+         for (row = 0; row < dstHeightNB; row += 2) {
+            do_row(format, 1,
+                   srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
+                   srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
+                   1, dstPtr + (dstWidth * row + 1) * bpt);
+            do_row(format, 1,
+                   srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
+                   srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
+                   1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
+         }
+      }
+   }
+}
+
+
+static void
+make_3d_mipmap(const struct gl_texture_format *format, GLint border,
+               GLint srcWidth, GLint srcHeight, GLint srcDepth,
+               const GLubyte *srcPtr,
+               GLint dstWidth, GLint dstHeight, GLint dstDepth,
+               GLubyte *dstPtr)
+{
+   const GLint bpt = format->TexelBytes;
+   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
+   const GLint srcDepthNB = srcDepth - 2 * border;
+   const GLint dstWidthNB = dstWidth - 2 * border;
+   const GLint dstHeightNB = dstHeight - 2 * border;
+   const GLint dstDepthNB = dstDepth - 2 * border;
+   GLvoid *tmpRowA, *tmpRowB;
+   GLint img, row;
+   GLint bytesPerSrcImage, bytesPerDstImage;
+   GLint bytesPerSrcRow, bytesPerDstRow;
+   GLint srcImageOffset, srcRowOffset;
+
+   (void) srcDepthNB; /* silence warnings */
+
+   /* Need two temporary row buffers */
+   tmpRowA = _mesa_malloc(srcWidth * bpt);
+   if (!tmpRowA)
+      return;
+   tmpRowB = _mesa_malloc(srcWidth * bpt);
+   if (!tmpRowB) {
+      _mesa_free(tmpRowA);
+      return;
+   }
+
+   bytesPerSrcImage = srcWidth * srcHeight * bpt;
+   bytesPerDstImage = dstWidth * dstHeight * bpt;
+
+   bytesPerSrcRow = srcWidth * bpt;
+   bytesPerDstRow = dstWidth * bpt;
+
+   /* Offset between adjacent src images to be averaged together */
+   srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
+
+   /* Offset between adjacent src rows to be averaged together */
+   srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
+
+   /*
+    * Need to average together up to 8 src pixels for each dest pixel.
+    * Break that down into 3 operations:
+    *   1. take two rows from source image and average them together.
+    *   2. take two rows from next source image and average them together.
+    *   3. take the two averaged rows and average them for the final dst row.
+    */
+
+   /*
+   _mesa_printf("mip3d %d x %d x %d  ->  %d x %d x %d\n",
+          srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
+   */
+
+   for (img = 0; img < dstDepthNB; img++) {
+      /* first source image pointer, skipping border */
+      const GLubyte *imgSrcA = srcPtr
+         + (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
+         + img * (bytesPerSrcImage + srcImageOffset);
+      /* second source image pointer, skipping border */
+      const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
+      /* address of the dest image, skipping border */
+      GLubyte *imgDst = dstPtr
+         + (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
+         + img * bytesPerDstImage;
+
+      /* setup the four source row pointers and the dest row pointer */
+      const GLubyte *srcImgARowA = imgSrcA;
+      const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
+      const GLubyte *srcImgBRowA = imgSrcB;
+      const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
+      GLubyte *dstImgRow = imgDst;
+
+      for (row = 0; row < dstHeightNB; row++) {
+         /* Average together two rows from first src image */
+         do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
+                srcWidthNB, tmpRowA);
+         /* Average together two rows from second src image */
+         do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
+                srcWidthNB, tmpRowB);
+         /* Average together the temp rows to make the final row */
+         do_row(format, srcWidthNB, tmpRowA, tmpRowB,
+                dstWidthNB, dstImgRow);
+         /* advance to next rows */
+         srcImgARowA += bytesPerSrcRow + srcRowOffset;
+         srcImgARowB += bytesPerSrcRow + srcRowOffset;
+         srcImgBRowA += bytesPerSrcRow + srcRowOffset;
+         srcImgBRowB += bytesPerSrcRow + srcRowOffset;
+         dstImgRow += bytesPerDstRow;
+      }
+   }
+
+   _mesa_free(tmpRowA);
+   _mesa_free(tmpRowB);
+
+   /* Luckily we can leverage the make_2d_mipmap() function here! */
+   if (border > 0) {
+      /* do front border image */
+      make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
+                     dstWidth, dstHeight, dstPtr);
+      /* do back border image */
+      make_2d_mipmap(format, 1, srcWidth, srcHeight,
+                     srcPtr + bytesPerSrcImage * (srcDepth - 1),
+                     dstWidth, dstHeight,
+                     dstPtr + bytesPerDstImage * (dstDepth - 1));
+      /* do four remaining border edges that span the image slices */
+      if (srcDepth == dstDepth) {
+         /* just copy border pixels from src to dst */
+         for (img = 0; img < dstDepthNB; img++) {
+            const GLubyte *src;
+            GLubyte *dst;
+
+            /* do border along [img][row=0][col=0] */
+            src = srcPtr + (img + 1) * bytesPerSrcImage;
+            dst = dstPtr + (img + 1) * bytesPerDstImage;
+            MEMCPY(dst, src, bpt);
+
+            /* do border along [img][row=dstHeight-1][col=0] */
+            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+                         + (srcHeight - 1) * bytesPerSrcRow;
+            dst = dstPtr + (img + 1) * bytesPerDstImage
+                         + (dstHeight - 1) * bytesPerDstRow;
+            MEMCPY(dst, src, bpt);
+
+            /* do border along [img][row=0][col=dstWidth-1] */
+            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+                         + (srcWidth - 1) * bpt;
+            dst = dstPtr + (img + 1) * bytesPerDstImage
+                         + (dstWidth - 1) * bpt;
+            MEMCPY(dst, src, bpt);
+
+            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
+            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+                         + (bytesPerSrcImage - bpt);
+            dst = dstPtr + (img + 1) * bytesPerDstImage
+                         + (bytesPerDstImage - bpt);
+            MEMCPY(dst, src, bpt);
+         }
+      }
+      else {
+         /* average border pixels from adjacent src image pairs */
+         ASSERT(srcDepthNB == 2 * dstDepthNB);
+         for (img = 0; img < dstDepthNB; img++) {
+            const GLubyte *src;
+            GLubyte *dst;
+
+            /* do border along [img][row=0][col=0] */
+            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
+            dst = dstPtr + (img + 1) * bytesPerDstImage;
+            do_row(format, 1, src, src + srcImageOffset, 1, dst);
+
+            /* do border along [img][row=dstHeight-1][col=0] */
+            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+                         + (srcHeight - 1) * bytesPerSrcRow;
+            dst = dstPtr + (img + 1) * bytesPerDstImage
+                         + (dstHeight - 1) * bytesPerDstRow;
+            do_row(format, 1, src, src + srcImageOffset, 1, dst);
+
+            /* do border along [img][row=0][col=dstWidth-1] */
+            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+                         + (srcWidth - 1) * bpt;
+            dst = dstPtr + (img + 1) * bytesPerDstImage
+                         + (dstWidth - 1) * bpt;
+            do_row(format, 1, src, src + srcImageOffset, 1, dst);
+
+            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
+            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
+                         + (bytesPerSrcImage - bpt);
+            dst = dstPtr + (img + 1) * bytesPerDstImage
+                         + (bytesPerDstImage - bpt);
+            do_row(format, 1, src, src + srcImageOffset, 1, dst);
+         }
+      }
+   }
+}
+
+
+/**
+ * For GL_SGIX_generate_mipmap:
+ * Generate a complete set of mipmaps from texObj's base-level image.
+ * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
+ */
+void
+_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
+                      const struct gl_texture_unit *texUnit,
+                      struct gl_texture_object *texObj)
+{
+   const struct gl_texture_image *srcImage;
+   const struct gl_texture_format *convertFormat;
+   const GLubyte *srcData = NULL;
+   GLubyte *dstData = NULL;
+   GLint level, maxLevels;
+
+   ASSERT(texObj);
+   /* XXX choose cube map face here??? */
+   srcImage = texObj->Image[0][texObj->BaseLevel];
+   ASSERT(srcImage);
+
+   maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
+   ASSERT(maxLevels > 0);  /* bad target */
+
+   /* Find convertFormat - the format that do_row() will process */
+   if (srcImage->IsCompressed) {
+      /* setup for compressed textures */
+      GLuint row;
+      GLint  components, size;
+      GLchan *dst;
+
+      assert(texObj->Target == GL_TEXTURE_2D);
+
+      if (srcImage->_BaseFormat == GL_RGB) {
+         convertFormat = &_mesa_texformat_rgb;
+         components = 3;
+      }
+      else if (srcImage->_BaseFormat == GL_RGBA) {
+         convertFormat = &_mesa_texformat_rgba;
+         components = 4;
+      }
+      else {
+         _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
+         return;
+      }
+
+      /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
+      size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE)
+         * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
+      /* 20 extra bytes, just be safe when calling last FetchTexel */
+      srcData = (GLubyte *) _mesa_malloc(size);
+      if (!srcData) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
+         return;
+      }
+      dstData = (GLubyte *) _mesa_malloc(size / 2);  /* 1/4 would probably be OK */
+      if (!dstData) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
+         _mesa_free((void *) srcData);
+         return;
+      }
+
+      /* decompress base image here */
+      dst = (GLchan *) srcData;
+      for (row = 0; row < srcImage->Height; row++) {
+         GLuint col;
+         for (col = 0; col < srcImage->Width; col++) {
+            srcImage->FetchTexelc(srcImage, col, row, 0, dst);
+            dst += components;
+         }
+      }
+   }
+   else {
+      /* uncompressed */
+      convertFormat = srcImage->TexFormat;
+   }
+
+   for (level = texObj->BaseLevel; level < texObj->MaxLevel
+           && level < maxLevels - 1; level++) {
+      /* generate image[level+1] from image[level] */
+      const struct gl_texture_image *srcImage;
+      struct gl_texture_image *dstImage;
+      GLint srcWidth, srcHeight, srcDepth;
+      GLint dstWidth, dstHeight, dstDepth;
+      GLint border, bytesPerTexel;
+
+      /* get src image parameters */
+      srcImage = _mesa_select_tex_image(ctx, texUnit, target, level);
+      ASSERT(srcImage);
+      srcWidth = srcImage->Width;
+      srcHeight = srcImage->Height;
+      srcDepth = srcImage->Depth;
+      border = srcImage->Border;
+
+      /* compute next (level+1) image size */
+      if (srcWidth - 2 * border > 1) {
+         dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
+      }
+      else {
+         dstWidth = srcWidth; /* can't go smaller */
+      }
+      if (srcHeight - 2 * border > 1) {
+         dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
+      }
+      else {
+         dstHeight = srcHeight; /* can't go smaller */
+      }
+      if (srcDepth - 2 * border > 1) {
+         dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
+      }
+      else {
+         dstDepth = srcDepth; /* can't go smaller */
+      }
+
+      if (dstWidth == srcWidth &&
+          dstHeight == srcHeight &&
+          dstDepth == srcDepth) {
+         /* all done */
+         if (srcImage->IsCompressed) {
+            _mesa_free((void *) srcData);
+            _mesa_free(dstData);
+         }
+         return;
+      }
+
+      /* get dest gl_texture_image */
+      dstImage = _mesa_get_tex_image(ctx, texUnit, target, level + 1);
+      if (!dstImage) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+         return;
+      }
+
+      /* Free old image data */
+      if (dstImage->Data)
+         ctx->Driver.FreeTexImageData(ctx, dstImage);
+
+      /* initialize new image */
+      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
+                                 dstDepth, border, srcImage->InternalFormat);
+      dstImage->DriverData = NULL;
+      dstImage->TexFormat = srcImage->TexFormat;
+      dstImage->FetchTexelc = srcImage->FetchTexelc;
+      dstImage->FetchTexelf = srcImage->FetchTexelf;
+      dstImage->IsCompressed = srcImage->IsCompressed;
+      if (dstImage->IsCompressed) {
+         dstImage->CompressedSize
+            = ctx->Driver.CompressedTextureSize(ctx, dstImage->Width,
+                                              dstImage->Height,
+                                              dstImage->Depth,
+                                              dstImage->TexFormat->MesaFormat);
+         ASSERT(dstImage->CompressedSize > 0);
+      }
+
+      ASSERT(dstImage->TexFormat);
+      ASSERT(dstImage->FetchTexelc);
+      ASSERT(dstImage->FetchTexelf);
+
+      /* Alloc new teximage data buffer.
+       * Setup src and dest data pointers.
+       */
+      if (dstImage->IsCompressed) {
+         dstImage->Data = _mesa_alloc_texmemory(dstImage->CompressedSize);
+         if (!dstImage->Data) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+            return;
+         }
+         /* srcData and dstData are already set */
+         ASSERT(srcData);
+         ASSERT(dstData);
+      }
+      else {
+         bytesPerTexel = dstImage->TexFormat->TexelBytes;
+         ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
+         dstImage->Data = _mesa_alloc_texmemory(dstWidth * dstHeight
+                                                * dstDepth * bytesPerTexel);
+         if (!dstImage->Data) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+            return;
+         }
+         srcData = (const GLubyte *) srcImage->Data;
+         dstData = (GLubyte *) dstImage->Data;
+      }
+
+      /*
+       * We use simple 2x2 averaging to compute the next mipmap level.
+       */
+      switch (target) {
+         case GL_TEXTURE_1D:
+            make_1d_mipmap(convertFormat, border,
+                           srcWidth, srcData,
+                           dstWidth, dstData);
+            break;
+         case GL_TEXTURE_2D:
+         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:
+            make_2d_mipmap(convertFormat, border,
+                           srcWidth, srcHeight, srcData,
+                           dstWidth, dstHeight, dstData);
+            break;
+         case GL_TEXTURE_3D:
+            make_3d_mipmap(convertFormat, border,
+                           srcWidth, srcHeight, srcDepth, srcData,
+                           dstWidth, dstHeight, dstDepth, dstData);
+            break;
+         case GL_TEXTURE_RECTANGLE_NV:
+            /* no mipmaps, do nothing */
+            break;
+         default:
+            _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
+            return;
+      }
+
+      if (dstImage->IsCompressed) {
+         GLubyte *temp;
+         /* compress image from dstData into dstImage->Data */
+         const GLenum srcFormat = convertFormat->BaseFormat;
+         GLint dstRowStride
+            = _mesa_compressed_row_stride(dstImage->TexFormat->MesaFormat, dstWidth);
+         ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
+         dstImage->TexFormat->StoreImage(ctx, 2, dstImage->_BaseFormat,
+                                         dstImage->TexFormat,
+                                         dstImage->Data,
+                                         0, 0, 0, /* dstX/Y/Zoffset */
+                                         dstRowStride, 0, /* strides */
+                                         dstWidth, dstHeight, 1, /* size */
+                                         srcFormat, CHAN_TYPE,
+                                         dstData, /* src data, actually */
+                                         &ctx->DefaultPacking);
+         /* swap src and dest pointers */
+         temp = (GLubyte *) srcData;
+         srcData = dstData;
+         dstData = temp;
+      }
+
+   } /* loop over mipmap levels */
+}
+
+
+/**
+ * Helper function for drivers which need to rescale texture images to
+ * certain aspect ratios.
+ * Nearest filtering only (for broken hardware that can't support
+ * all aspect ratios).  This can be made a lot faster, but I don't
+ * really care enough...
+ */
+void
+_mesa_rescale_teximage2d(GLuint bytesPerPixel,
+                        GLuint srcStrideInPixels,
+                        GLuint dstRowStride,
+                        GLint srcWidth, GLint srcHeight,
+                        GLint dstWidth, GLint dstHeight,
+                        const GLvoid *srcImage, GLvoid *dstImage)
+{
+   GLint row, col;
+
+#define INNER_LOOP( TYPE, HOP, WOP )                                   \
+   for ( row = 0 ; row < dstHeight ; row++ ) {                         \
+      GLint srcRow = row HOP hScale;                                   \
+      for ( col = 0 ; col < dstWidth ; col++ ) {                       \
+        GLint srcCol = col WOP wScale;                                 \
+        dst[col] = src[srcRow * srcStrideInPixels + srcCol];           \
+      }                                                                        \
+      dst = (TYPE *) ((GLubyte *) dst + dstRowStride);                 \
+   }                                                                   \
+
+#define RESCALE_IMAGE( TYPE )                                          \
+do {                                                                   \
+   const TYPE *src = (const TYPE *)srcImage;                           \
+   TYPE *dst = (TYPE *)dstImage;                                       \
+                                                                       \
+   if ( srcHeight < dstHeight ) {                                      \
+      const GLint hScale = dstHeight / srcHeight;                      \
+      if ( srcWidth < dstWidth ) {                                     \
+        const GLint wScale = dstWidth / srcWidth;                      \
+        INNER_LOOP( TYPE, /, / );                                      \
+      }                                                                        \
+      else {                                                           \
+        const GLint wScale = srcWidth / dstWidth;                      \
+        INNER_LOOP( TYPE, /, * );                                      \
+      }                                                                        \
+   }                                                                   \
+   else {                                                              \
+      const GLint hScale = srcHeight / dstHeight;                      \
+      if ( srcWidth < dstWidth ) {                                     \
+        const GLint wScale = dstWidth / srcWidth;                      \
+        INNER_LOOP( TYPE, *, / );                                      \
+      }                                                                        \
+      else {                                                           \
+        const GLint wScale = srcWidth / dstWidth;                      \
+        INNER_LOOP( TYPE, *, * );                                      \
+      }                                                                        \
+   }                                                                   \
+} while (0)
+
+   switch ( bytesPerPixel ) {
+   case 4:
+      RESCALE_IMAGE( GLuint );
+      break;
+
+   case 2:
+      RESCALE_IMAGE( GLushort );
+      break;
+
+   case 1:
+      RESCALE_IMAGE( GLubyte );
+      break;
+   default:
+      _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
+   }
+}
+
+
+/**
+ * Upscale an image by replication, not (typical) stretching.
+ * We use this when the image width or height is less than a
+ * certain size (4, 8) and we need to upscale an image.
+ */
+void
+_mesa_upscale_teximage2d(GLsizei inWidth, GLsizei inHeight,
+                         GLsizei outWidth, GLsizei outHeight,
+                         GLint comps, const GLchan *src, GLint srcRowStride,
+                         GLchan *dest )
+{
+   GLint i, j, k;
+
+   ASSERT(outWidth >= inWidth);
+   ASSERT(outHeight >= inHeight);
+#if 0
+   ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
+   ASSERT((outWidth & 3) == 0);
+   ASSERT((outHeight & 3) == 0);
+#endif
+
+   for (i = 0; i < outHeight; i++) {
+      const GLint ii = i % inHeight;
+      for (j = 0; j < outWidth; j++) {
+         const GLint jj = j % inWidth;
+         for (k = 0; k < comps; k++) {
+            dest[(i * outWidth + j) * comps + k]
+               = src[ii * srcRowStride + jj * comps + k];
+         }
+      }
+   }
+}
+
diff --git a/src/mesa/main/mipmap.h b/src/mesa/main/mipmap.h
new file mode 100644 (file)
index 0000000..df78603
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5.2
+ *
+ * Copyright (C) 1999-2006  Brian Paul   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, sublicense,
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+
+#ifndef MIPMAP_H
+#define MIPMAP_H
+
+#include "mtypes.h"
+
+extern void
+_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
+                      const struct gl_texture_unit *texUnit,
+                      struct gl_texture_object *texObj);
+
+
+extern void
+_mesa_rescale_teximage2d(GLuint bytesPerPixel,
+                         GLuint srcStrideInPixels,
+                         GLuint dstRowStride,
+                         GLint srcWidth, GLint srcHeight,
+                         GLint dstWidth, GLint dstHeight,
+                         const GLvoid *srcImage, GLvoid *dstImage);
+
+extern void
+_mesa_upscale_teximage2d(GLsizei inWidth, GLsizei inHeight,
+                         GLsizei outWidth, GLsizei outHeight,
+                         GLint comps, const GLchan *src, GLint srcRowStride,
+                         GLchan *dest);
+
+
+#endif /* MIPMAP_H */
index d594308024530331eb21b6a8859fb0fed28acef7..c44d594d68333306a14b96fbc3a6bedeec555a40 100644 (file)
@@ -34,6 +34,7 @@
 #include "colormac.h"
 #include "context.h"
 #include "image.h"
+#include "mipmap.h"
 #include "texcompress.h"
 #include "texformat.h"
 #include "texstore.h"
index 9c63b7e4ba264fb7de8eef71009813bd903522d3..72ff73ef05445f4c68c1214fb8c1eb29c34c5121 100644 (file)
@@ -58,6 +58,7 @@
 #include "convolve.h"
 #include "image.h"
 #include "macros.h"
+#include "mipmap.h"
 #include "imports.h"
 #include "texcompress.h"
 #include "texformat.h"
@@ -2719,8 +2720,8 @@ _mesa_unmap_teximage_pbo(GLcontext *ctx,
  * Adaptor for fetching a GLchan texel from a float-valued texture.
  */
 static void
-FetchTexelFloatToChan( const struct gl_texture_image *texImage,
-                       GLint i, GLint j, GLint k, GLchan *texelOut )
+fetch_texel_float_to_chan(const struct gl_texture_image *texImage,
+                          GLint i, GLint j, GLint k, GLchan *texelOut)
 {
    GLfloat temp[4];
    ASSERT(texImage->FetchTexelf);
@@ -2744,8 +2745,8 @@ FetchTexelFloatToChan( const struct gl_texture_image *texImage,
  * Adaptor for fetching a float texel from a GLchan-valued texture.
  */
 static void
-FetchTexelChanToFloat( const struct gl_texture_image *texImage,
-                       GLint i, GLint j, GLint k, GLfloat *texelOut )
+fetch_texel_chan_to_float(const struct gl_texture_image *texImage,
+                          GLint i, GLint j, GLint k, GLfloat *texelOut)
 {
    GLchan temp[4];
    ASSERT(texImage->FetchTexelc);
@@ -2793,10 +2794,10 @@ set_fetch_functions(struct gl_texture_image *texImage, GLuint dims)
 
    /* now check if we need to use a float/chan adaptor */
    if (!texImage->FetchTexelc) {
-      texImage->FetchTexelc = FetchTexelFloatToChan;
+      texImage->FetchTexelc = fetch_texel_float_to_chan;
    }
    else if (!texImage->FetchTexelf) {
-      texImage->FetchTexelf = FetchTexelChanToFloat;
+      texImage->FetchTexelf = fetch_texel_chan_to_float;
    }
 
 
@@ -3452,1114 +3453,6 @@ _mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target,
 }
 
 
-/*
- * Average together two rows of a source image to produce a single new
- * row in the dest image.  It's legal for the two source rows to point
- * to the same data.  The source width must be equal to either the
- * dest width or two times the dest width.
- */
-static void
-do_row(const struct gl_texture_format *format, GLint srcWidth,
-       const GLvoid *srcRowA, const GLvoid *srcRowB,
-       GLint dstWidth, GLvoid *dstRow)
-{
-   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
-   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
-
-   /* This assertion is no longer valid with non-power-of-2 textures
-   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
-   */
-
-   switch (format->MesaFormat) {
-   case MESA_FORMAT_RGBA:
-      {
-         GLuint i, j, k;
-         const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
-         const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
-         GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) / 4;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) / 4;
-            dst[i][2] = (rowA[j][2] + rowA[k][2] +
-                         rowB[j][2] + rowB[k][2]) / 4;
-            dst[i][3] = (rowA[j][3] + rowA[k][3] +
-                         rowB[j][3] + rowB[k][3]) / 4;
-         }
-      }
-      return;
-   case MESA_FORMAT_RGB:
-      {
-         GLuint i, j, k;
-         const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
-         const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
-         GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) / 4;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) / 4;
-            dst[i][2] = (rowA[j][2] + rowA[k][2] +
-                         rowB[j][2] + rowB[k][2]) / 4;
-         }
-      }
-      return;
-   case MESA_FORMAT_ALPHA:
-   case MESA_FORMAT_LUMINANCE:
-   case MESA_FORMAT_INTENSITY:
-      {
-         GLuint i, j, k;
-         const GLchan *rowA = (const GLchan *) srcRowA;
-         const GLchan *rowB = (const GLchan *) srcRowB;
-         GLchan *dst = (GLchan *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
-         }
-      }
-      return;
-   case MESA_FORMAT_LUMINANCE_ALPHA:
-      {
-         GLuint i, j, k;
-         const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
-         const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
-         GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) / 4;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) / 4;
-         }
-      }
-      return;
-   case MESA_FORMAT_Z32:
-      {
-         GLuint i, j, k;
-         const GLuint *rowA = (const GLuint *) srcRowA;
-         const GLuint *rowB = (const GLuint *) srcRowB;
-         GLfloat *dst = (GLfloat *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
-         }
-      }
-      return;
-   case MESA_FORMAT_Z16:
-      {
-         GLuint i, j, k;
-         const GLushort *rowA = (const GLushort *) srcRowA;
-         const GLushort *rowB = (const GLushort *) srcRowB;
-         GLushort *dst = (GLushort *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
-         }
-      }
-      return;
-   /* Begin hardware formats */
-   case MESA_FORMAT_RGBA8888:
-   case MESA_FORMAT_RGBA8888_REV:
-   case MESA_FORMAT_ARGB8888:
-   case MESA_FORMAT_ARGB8888_REV:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SRGBA8:
-#endif
-      {
-         GLuint i, j, k;
-         const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
-         const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
-         GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) / 4;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) / 4;
-            dst[i][2] = (rowA[j][2] + rowA[k][2] +
-                         rowB[j][2] + rowB[k][2]) / 4;
-            dst[i][3] = (rowA[j][3] + rowA[k][3] +
-                         rowB[j][3] + rowB[k][3]) / 4;
-         }
-      }
-      return;
-   case MESA_FORMAT_RGB888:
-   case MESA_FORMAT_BGR888:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SRGB8:
-#endif
-      {
-         GLuint i, j, k;
-         const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
-         const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
-         GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) / 4;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) / 4;
-            dst[i][2] = (rowA[j][2] + rowA[k][2] +
-                         rowB[j][2] + rowB[k][2]) / 4;
-         }
-      }
-      return;
-   case MESA_FORMAT_RGB565:
-   case MESA_FORMAT_RGB565_REV:
-      {
-         GLuint i, j, k;
-         const GLushort *rowA = (const GLushort *) srcRowA;
-         const GLushort *rowB = (const GLushort *) srcRowB;
-         GLushort *dst = (GLushort *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            const GLint rowAr0 = rowA[j] & 0x1f;
-            const GLint rowAr1 = rowA[k] & 0x1f;
-            const GLint rowBr0 = rowB[j] & 0x1f;
-            const GLint rowBr1 = rowB[k] & 0x1f;
-            const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
-            const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
-            const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
-            const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
-            const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
-            const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
-            const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
-            const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
-            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
-            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
-            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
-            dst[i] = (blue << 11) | (green << 5) | red;
-         }
-      }
-      return;
-   case MESA_FORMAT_ARGB4444:
-   case MESA_FORMAT_ARGB4444_REV:
-      {
-         GLuint i, j, k;
-         const GLushort *rowA = (const GLushort *) srcRowA;
-         const GLushort *rowB = (const GLushort *) srcRowB;
-         GLushort *dst = (GLushort *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            const GLint rowAr0 = rowA[j] & 0xf;
-            const GLint rowAr1 = rowA[k] & 0xf;
-            const GLint rowBr0 = rowB[j] & 0xf;
-            const GLint rowBr1 = rowB[k] & 0xf;
-            const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
-            const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
-            const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
-            const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
-            const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
-            const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
-            const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
-            const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
-            const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
-            const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
-            const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
-            const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
-            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
-            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
-            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
-            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
-            dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
-         }
-      }
-      return;
-   case MESA_FORMAT_ARGB1555:
-   case MESA_FORMAT_ARGB1555_REV: /* XXX broken? */
-      {
-         GLuint i, j, k;
-         const GLushort *rowA = (const GLushort *) srcRowA;
-         const GLushort *rowB = (const GLushort *) srcRowB;
-         GLushort *dst = (GLushort *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            const GLint rowAr0 = rowA[j] & 0x1f;
-            const GLint rowAr1 = rowA[k] & 0x1f;
-            const GLint rowBr0 = rowB[j] & 0x1f;
-            const GLint rowBr1 = rowB[k] & 0xf;
-            const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
-            const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
-            const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
-            const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
-            const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
-            const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
-            const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
-            const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
-            const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
-            const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
-            const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
-            const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
-            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
-            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
-            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
-            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
-            dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
-         }
-      }
-      return;
-   case MESA_FORMAT_AL88:
-   case MESA_FORMAT_AL88_REV:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SLA8:
-#endif
-      {
-         GLuint i, j, k;
-         const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
-         const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
-         GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) >> 2;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) >> 2;
-         }
-      }
-      return;
-   case MESA_FORMAT_RGB332:
-      {
-         GLuint i, j, k;
-         const GLubyte *rowA = (const GLubyte *) srcRowA;
-         const GLubyte *rowB = (const GLubyte *) srcRowB;
-         GLubyte *dst = (GLubyte *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            const GLint rowAr0 = rowA[j] & 0x3;
-            const GLint rowAr1 = rowA[k] & 0x3;
-            const GLint rowBr0 = rowB[j] & 0x3;
-            const GLint rowBr1 = rowB[k] & 0x3;
-            const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
-            const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
-            const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
-            const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
-            const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
-            const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
-            const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
-            const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
-            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
-            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
-            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
-            dst[i] = (blue << 5) | (green << 2) | red;
-         }
-      }
-      return;
-   case MESA_FORMAT_A8:
-   case MESA_FORMAT_L8:
-   case MESA_FORMAT_I8:
-   case MESA_FORMAT_CI8:
-#if FEATURE_EXT_texture_sRGB
-   case MESA_FORMAT_SL8:
-#endif
-      {
-         GLuint i, j, k;
-         const GLubyte *rowA = (const GLubyte *) srcRowA;
-         const GLubyte *rowB = (const GLubyte *) srcRowB;
-         GLubyte *dst = (GLubyte *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
-         }
-      }
-      return;
-   case MESA_FORMAT_RGBA_FLOAT32:
-      {
-         GLuint i, j, k;
-         const GLfloat (*rowA)[4] = (const GLfloat (*)[4]) srcRowA;
-         const GLfloat (*rowB)[4] = (const GLfloat (*)[4]) srcRowB;
-         GLfloat (*dst)[4] = (GLfloat (*)[4]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) * 0.25F;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) * 0.25F;
-            dst[i][2] = (rowA[j][2] + rowA[k][2] +
-                         rowB[j][2] + rowB[k][2]) * 0.25F;
-            dst[i][3] = (rowA[j][3] + rowA[k][3] +
-                         rowB[j][3] + rowB[k][3]) * 0.25F;
-         }
-      }
-      return;
-   case MESA_FORMAT_RGBA_FLOAT16:
-      {
-         GLuint i, j, k, comp;
-         const GLhalfARB (*rowA)[4] = (const GLhalfARB (*)[4]) srcRowA;
-         const GLhalfARB (*rowB)[4] = (const GLhalfARB (*)[4]) srcRowB;
-         GLhalfARB (*dst)[4] = (GLhalfARB (*)[4]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            for (comp = 0; comp < 4; comp++) {
-               GLfloat aj, ak, bj, bk;
-               aj = _mesa_half_to_float(rowA[j][comp]);
-               ak = _mesa_half_to_float(rowA[k][comp]);
-               bj = _mesa_half_to_float(rowB[j][comp]);
-               bk = _mesa_half_to_float(rowB[k][comp]);
-               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
-            }
-         }
-      }
-      return;
-   case MESA_FORMAT_RGB_FLOAT32:
-      {
-         GLuint i, j, k;
-         const GLfloat (*rowA)[3] = (const GLfloat (*)[3]) srcRowA;
-         const GLfloat (*rowB)[3] = (const GLfloat (*)[3]) srcRowB;
-         GLfloat (*dst)[3] = (GLfloat (*)[3]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) * 0.25F;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) * 0.25F;
-            dst[i][2] = (rowA[j][2] + rowA[k][2] +
-                         rowB[j][2] + rowB[k][2]) * 0.25F;
-         }
-      }
-      return;
-   case MESA_FORMAT_RGB_FLOAT16:
-      {
-         GLuint i, j, k, comp;
-         const GLhalfARB (*rowA)[3] = (const GLhalfARB (*)[3]) srcRowA;
-         const GLhalfARB (*rowB)[3] = (const GLhalfARB (*)[3]) srcRowB;
-         GLhalfARB (*dst)[3] = (GLhalfARB (*)[3]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            for (comp = 0; comp < 3; comp++) {
-               GLfloat aj, ak, bj, bk;
-               aj = _mesa_half_to_float(rowA[j][comp]);
-               ak = _mesa_half_to_float(rowA[k][comp]);
-               bj = _mesa_half_to_float(rowB[j][comp]);
-               bk = _mesa_half_to_float(rowB[k][comp]);
-               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
-            }
-         }
-      }
-      return;
-   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32:
-      {
-         GLuint i, j, k;
-         const GLfloat (*rowA)[2] = (const GLfloat (*)[2]) srcRowA;
-         const GLfloat (*rowB)[2] = (const GLfloat (*)[2]) srcRowB;
-         GLfloat (*dst)[2] = (GLfloat (*)[2]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i][0] = (rowA[j][0] + rowA[k][0] +
-                         rowB[j][0] + rowB[k][0]) * 0.25F;
-            dst[i][1] = (rowA[j][1] + rowA[k][1] +
-                         rowB[j][1] + rowB[k][1]) * 0.25F;
-         }
-      }
-      return;
-   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16:
-      {
-         GLuint i, j, k, comp;
-         const GLhalfARB (*rowA)[2] = (const GLhalfARB (*)[2]) srcRowA;
-         const GLhalfARB (*rowB)[2] = (const GLhalfARB (*)[2]) srcRowB;
-         GLhalfARB (*dst)[2] = (GLhalfARB (*)[2]) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            for (comp = 0; comp < 2; comp++) {
-               GLfloat aj, ak, bj, bk;
-               aj = _mesa_half_to_float(rowA[j][comp]);
-               ak = _mesa_half_to_float(rowA[k][comp]);
-               bj = _mesa_half_to_float(rowB[j][comp]);
-               bk = _mesa_half_to_float(rowB[k][comp]);
-               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
-            }
-         }
-      }
-      return;
-   case MESA_FORMAT_ALPHA_FLOAT32:
-   case MESA_FORMAT_LUMINANCE_FLOAT32:
-   case MESA_FORMAT_INTENSITY_FLOAT32:
-      {
-         GLuint i, j, k;
-         const GLfloat *rowA = (const GLfloat *) srcRowA;
-         const GLfloat *rowB = (const GLfloat *) srcRowB;
-         GLfloat *dst = (GLfloat *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
-         }
-      }
-      return;
-   case MESA_FORMAT_ALPHA_FLOAT16:
-   case MESA_FORMAT_LUMINANCE_FLOAT16:
-   case MESA_FORMAT_INTENSITY_FLOAT16:
-      {
-         GLuint i, j, k;
-         const GLhalfARB *rowA = (const GLhalfARB *) srcRowA;
-         const GLhalfARB *rowB = (const GLhalfARB *) srcRowB;
-         GLhalfARB *dst = (GLhalfARB *) dstRow;
-         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
-              i++, j += colStride, k += colStride) {
-            GLfloat aj, ak, bj, bk;
-            aj = _mesa_half_to_float(rowA[j]);
-            ak = _mesa_half_to_float(rowA[k]);
-            bj = _mesa_half_to_float(rowB[j]);
-            bk = _mesa_half_to_float(rowB[k]);
-            dst[i] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
-         }
-      }
-      return;
-
-   default:
-      _mesa_problem(NULL, "bad format in do_row()");
-   }
-}
-
-
-/*
- * These functions generate a 1/2-size mipmap image from a source image.
- * Texture borders are handled by copying or averaging the source image's
- * border texels, depending on the scale-down factor.
- */
-
-static void
-make_1d_mipmap(const struct gl_texture_format *format, GLint border,
-               GLint srcWidth, const GLubyte *srcPtr,
-               GLint dstWidth, GLubyte *dstPtr)
-{
-   const GLint bpt = format->TexelBytes;
-   const GLubyte *src;
-   GLubyte *dst;
-
-   /* skip the border pixel, if any */
-   src = srcPtr + border * bpt;
-   dst = dstPtr + border * bpt;
-
-   /* we just duplicate the input row, kind of hack, saves code */
-   do_row(format, srcWidth - 2 * border, src, src,
-          dstWidth - 2 * border, dst);
-
-   if (border) {
-      /* copy left-most pixel from source */
-      MEMCPY(dstPtr, srcPtr, bpt);
-      /* copy right-most pixel from source */
-      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
-             srcPtr + (srcWidth - 1) * bpt,
-             bpt);
-   }
-}
-
-
-/**
- * XXX need to use the tex image's row stride!
- */
-static void
-make_2d_mipmap(const struct gl_texture_format *format, GLint border,
-               GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
-               GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
-{
-   const GLint bpt = format->TexelBytes;
-   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
-   const GLint dstWidthNB = dstWidth - 2 * border;
-   const GLint dstHeightNB = dstHeight - 2 * border;
-   const GLint srcRowStride = bpt * srcWidth;
-   const GLint dstRowStride = bpt * dstWidth;
-   const GLubyte *srcA, *srcB;
-   GLubyte *dst;
-   GLint row;
-
-   /* Compute src and dst pointers, skipping any border */
-   srcA = srcPtr + border * ((srcWidth + 1) * bpt);
-   if (srcHeight > 1)
-      srcB = srcA + srcRowStride;
-   else
-      srcB = srcA;
-   dst = dstPtr + border * ((dstWidth + 1) * bpt);
-
-   for (row = 0; row < dstHeightNB; row++) {
-      do_row(format, srcWidthNB, srcA, srcB,
-             dstWidthNB, dst);
-      srcA += 2 * srcRowStride;
-      srcB += 2 * srcRowStride;
-      dst += dstRowStride;
-   }
-
-   /* This is ugly but probably won't be used much */
-   if (border > 0) {
-      /* fill in dest border */
-      /* lower-left border pixel */
-      MEMCPY(dstPtr, srcPtr, bpt);
-      /* lower-right border pixel */
-      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
-             srcPtr + (srcWidth - 1) * bpt, bpt);
-      /* upper-left border pixel */
-      MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
-             srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
-      /* upper-right border pixel */
-      MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
-             srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
-      /* lower border */
-      do_row(format, srcWidthNB,
-             srcPtr + bpt,
-             srcPtr + bpt,
-             dstWidthNB, dstPtr + bpt);
-      /* upper border */
-      do_row(format, srcWidthNB,
-             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
-             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
-             dstWidthNB,
-             dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
-      /* left and right borders */
-      if (srcHeight == dstHeight) {
-         /* copy border pixel from src to dst */
-         for (row = 1; row < srcHeight; row++) {
-            MEMCPY(dstPtr + dstWidth * row * bpt,
-                   srcPtr + srcWidth * row * bpt, bpt);
-            MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
-                   srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
-         }
-      }
-      else {
-         /* average two src pixels each dest pixel */
-         for (row = 0; row < dstHeightNB; row += 2) {
-            do_row(format, 1,
-                   srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
-                   srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
-                   1, dstPtr + (dstWidth * row + 1) * bpt);
-            do_row(format, 1,
-                   srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
-                   srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
-                   1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
-         }
-      }
-   }
-}
-
-
-static void
-make_3d_mipmap(const struct gl_texture_format *format, GLint border,
-               GLint srcWidth, GLint srcHeight, GLint srcDepth,
-               const GLubyte *srcPtr,
-               GLint dstWidth, GLint dstHeight, GLint dstDepth,
-               GLubyte *dstPtr)
-{
-   const GLint bpt = format->TexelBytes;
-   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
-   const GLint srcDepthNB = srcDepth - 2 * border;
-   const GLint dstWidthNB = dstWidth - 2 * border;
-   const GLint dstHeightNB = dstHeight - 2 * border;
-   const GLint dstDepthNB = dstDepth - 2 * border;
-   GLvoid *tmpRowA, *tmpRowB;
-   GLint img, row;
-   GLint bytesPerSrcImage, bytesPerDstImage;
-   GLint bytesPerSrcRow, bytesPerDstRow;
-   GLint srcImageOffset, srcRowOffset;
-
-   (void) srcDepthNB; /* silence warnings */
-
-   /* Need two temporary row buffers */
-   tmpRowA = _mesa_malloc(srcWidth * bpt);
-   if (!tmpRowA)
-      return;
-   tmpRowB = _mesa_malloc(srcWidth * bpt);
-   if (!tmpRowB) {
-      _mesa_free(tmpRowA);
-      return;
-   }
-
-   bytesPerSrcImage = srcWidth * srcHeight * bpt;
-   bytesPerDstImage = dstWidth * dstHeight * bpt;
-
-   bytesPerSrcRow = srcWidth * bpt;
-   bytesPerDstRow = dstWidth * bpt;
-
-   /* Offset between adjacent src images to be averaged together */
-   srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
-
-   /* Offset between adjacent src rows to be averaged together */
-   srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
-
-   /*
-    * Need to average together up to 8 src pixels for each dest pixel.
-    * Break that down into 3 operations:
-    *   1. take two rows from source image and average them together.
-    *   2. take two rows from next source image and average them together.
-    *   3. take the two averaged rows and average them for the final dst row.
-    */
-
-   /*
-   _mesa_printf("mip3d %d x %d x %d  ->  %d x %d x %d\n",
-          srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
-   */
-
-   for (img = 0; img < dstDepthNB; img++) {
-      /* first source image pointer, skipping border */
-      const GLubyte *imgSrcA = srcPtr
-         + (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
-         + img * (bytesPerSrcImage + srcImageOffset);
-      /* second source image pointer, skipping border */
-      const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
-      /* address of the dest image, skipping border */
-      GLubyte *imgDst = dstPtr
-         + (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
-         + img * bytesPerDstImage;
-
-      /* setup the four source row pointers and the dest row pointer */
-      const GLubyte *srcImgARowA = imgSrcA;
-      const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
-      const GLubyte *srcImgBRowA = imgSrcB;
-      const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
-      GLubyte *dstImgRow = imgDst;
-
-      for (row = 0; row < dstHeightNB; row++) {
-         /* Average together two rows from first src image */
-         do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
-                srcWidthNB, tmpRowA);
-         /* Average together two rows from second src image */
-         do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
-                srcWidthNB, tmpRowB);
-         /* Average together the temp rows to make the final row */
-         do_row(format, srcWidthNB, tmpRowA, tmpRowB,
-                dstWidthNB, dstImgRow);
-         /* advance to next rows */
-         srcImgARowA += bytesPerSrcRow + srcRowOffset;
-         srcImgARowB += bytesPerSrcRow + srcRowOffset;
-         srcImgBRowA += bytesPerSrcRow + srcRowOffset;
-         srcImgBRowB += bytesPerSrcRow + srcRowOffset;
-         dstImgRow += bytesPerDstRow;
-      }
-   }
-
-   _mesa_free(tmpRowA);
-   _mesa_free(tmpRowB);
-
-   /* Luckily we can leverage the make_2d_mipmap() function here! */
-   if (border > 0) {
-      /* do front border image */
-      make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
-                     dstWidth, dstHeight, dstPtr);
-      /* do back border image */
-      make_2d_mipmap(format, 1, srcWidth, srcHeight,
-                     srcPtr + bytesPerSrcImage * (srcDepth - 1),
-                     dstWidth, dstHeight,
-                     dstPtr + bytesPerDstImage * (dstDepth - 1));
-      /* do four remaining border edges that span the image slices */
-      if (srcDepth == dstDepth) {
-         /* just copy border pixels from src to dst */
-         for (img = 0; img < dstDepthNB; img++) {
-            const GLubyte *src;
-            GLubyte *dst;
-
-            /* do border along [img][row=0][col=0] */
-            src = srcPtr + (img + 1) * bytesPerSrcImage;
-            dst = dstPtr + (img + 1) * bytesPerDstImage;
-            MEMCPY(dst, src, bpt);
-
-            /* do border along [img][row=dstHeight-1][col=0] */
-            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
-                         + (srcHeight - 1) * bytesPerSrcRow;
-            dst = dstPtr + (img + 1) * bytesPerDstImage
-                         + (dstHeight - 1) * bytesPerDstRow;
-            MEMCPY(dst, src, bpt);
-
-            /* do border along [img][row=0][col=dstWidth-1] */
-            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
-                         + (srcWidth - 1) * bpt;
-            dst = dstPtr + (img + 1) * bytesPerDstImage
-                         + (dstWidth - 1) * bpt;
-            MEMCPY(dst, src, bpt);
-
-            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
-            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
-                         + (bytesPerSrcImage - bpt);
-            dst = dstPtr + (img + 1) * bytesPerDstImage
-                         + (bytesPerDstImage - bpt);
-            MEMCPY(dst, src, bpt);
-         }
-      }
-      else {
-         /* average border pixels from adjacent src image pairs */
-         ASSERT(srcDepthNB == 2 * dstDepthNB);
-         for (img = 0; img < dstDepthNB; img++) {
-            const GLubyte *src;
-            GLubyte *dst;
-
-            /* do border along [img][row=0][col=0] */
-            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
-            dst = dstPtr + (img + 1) * bytesPerDstImage;
-            do_row(format, 1, src, src + srcImageOffset, 1, dst);
-
-            /* do border along [img][row=dstHeight-1][col=0] */
-            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
-                         + (srcHeight - 1) * bytesPerSrcRow;
-            dst = dstPtr + (img + 1) * bytesPerDstImage
-                         + (dstHeight - 1) * bytesPerDstRow;
-            do_row(format, 1, src, src + srcImageOffset, 1, dst);
-
-            /* do border along [img][row=0][col=dstWidth-1] */
-            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
-                         + (srcWidth - 1) * bpt;
-            dst = dstPtr + (img + 1) * bytesPerDstImage
-                         + (dstWidth - 1) * bpt;
-            do_row(format, 1, src, src + srcImageOffset, 1, dst);
-
-            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
-            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
-                         + (bytesPerSrcImage - bpt);
-            dst = dstPtr + (img + 1) * bytesPerDstImage
-                         + (bytesPerDstImage - bpt);
-            do_row(format, 1, src, src + srcImageOffset, 1, dst);
-         }
-      }
-   }
-}
-
-
-/**
- * For GL_SGIX_generate_mipmap:
- * Generate a complete set of mipmaps from texObj's base-level image.
- * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
- */
-void
-_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
-                      const struct gl_texture_unit *texUnit,
-                      struct gl_texture_object *texObj)
-{
-   const struct gl_texture_image *srcImage;
-   const struct gl_texture_format *convertFormat;
-   const GLubyte *srcData = NULL;
-   GLubyte *dstData = NULL;
-   GLint level, maxLevels;
-
-   ASSERT(texObj);
-   /* XXX choose cube map face here??? */
-   srcImage = texObj->Image[0][texObj->BaseLevel];
-   ASSERT(srcImage);
-
-   maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
-   ASSERT(maxLevels > 0);  /* bad target */
-
-   /* Find convertFormat - the format that do_row() will process */
-   if (srcImage->IsCompressed) {
-      /* setup for compressed textures */
-      GLuint row;
-      GLint  components, size;
-      GLchan *dst;
-
-      assert(texObj->Target == GL_TEXTURE_2D);
-
-      if (srcImage->_BaseFormat == GL_RGB) {
-         convertFormat = &_mesa_texformat_rgb;
-         components = 3;
-      }
-      else if (srcImage->_BaseFormat == GL_RGBA) {
-         convertFormat = &_mesa_texformat_rgba;
-         components = 4;
-      }
-      else {
-         _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
-         return;
-      }
-
-      /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
-      size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE)
-         * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
-      /* 20 extra bytes, just be safe when calling last FetchTexel */
-      srcData = (GLubyte *) _mesa_malloc(size);
-      if (!srcData) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
-         return;
-      }
-      dstData = (GLubyte *) _mesa_malloc(size / 2);  /* 1/4 would probably be OK */
-      if (!dstData) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
-         _mesa_free((void *) srcData);
-         return;
-      }
-
-      /* decompress base image here */
-      dst = (GLchan *) srcData;
-      for (row = 0; row < srcImage->Height; row++) {
-         GLuint col;
-         for (col = 0; col < srcImage->Width; col++) {
-            srcImage->FetchTexelc(srcImage, col, row, 0, dst);
-            dst += components;
-         }
-      }
-   }
-   else {
-      /* uncompressed */
-      convertFormat = srcImage->TexFormat;
-   }
-
-   for (level = texObj->BaseLevel; level < texObj->MaxLevel
-           && level < maxLevels - 1; level++) {
-      /* generate image[level+1] from image[level] */
-      const struct gl_texture_image *srcImage;
-      struct gl_texture_image *dstImage;
-      GLint srcWidth, srcHeight, srcDepth;
-      GLint dstWidth, dstHeight, dstDepth;
-      GLint border, bytesPerTexel;
-
-      /* get src image parameters */
-      srcImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-      ASSERT(srcImage);
-      srcWidth = srcImage->Width;
-      srcHeight = srcImage->Height;
-      srcDepth = srcImage->Depth;
-      border = srcImage->Border;
-
-      /* compute next (level+1) image size */
-      if (srcWidth - 2 * border > 1) {
-         dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
-      }
-      else {
-         dstWidth = srcWidth; /* can't go smaller */
-      }
-      if (srcHeight - 2 * border > 1) {
-         dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
-      }
-      else {
-         dstHeight = srcHeight; /* can't go smaller */
-      }
-      if (srcDepth - 2 * border > 1) {
-         dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
-      }
-      else {
-         dstDepth = srcDepth; /* can't go smaller */
-      }
-
-      if (dstWidth == srcWidth &&
-          dstHeight == srcHeight &&
-          dstDepth == srcDepth) {
-         /* all done */
-         if (srcImage->IsCompressed) {
-            _mesa_free((void *) srcData);
-            _mesa_free(dstData);
-         }
-         return;
-      }
-
-      /* get dest gl_texture_image */
-      dstImage = _mesa_get_tex_image(ctx, texUnit, target, level + 1);
-      if (!dstImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
-         return;
-      }
-
-      /* Free old image data */
-      if (dstImage->Data)
-         ctx->Driver.FreeTexImageData(ctx, dstImage);
-
-      /* initialize new image */
-      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
-                                 dstDepth, border, srcImage->InternalFormat);
-      dstImage->DriverData = NULL;
-      dstImage->TexFormat = srcImage->TexFormat;
-      dstImage->FetchTexelc = srcImage->FetchTexelc;
-      dstImage->FetchTexelf = srcImage->FetchTexelf;
-      dstImage->IsCompressed = srcImage->IsCompressed;
-      if (dstImage->IsCompressed) {
-         dstImage->CompressedSize
-            = ctx->Driver.CompressedTextureSize(ctx, dstImage->Width,
-                                              dstImage->Height,
-                                              dstImage->Depth,
-                                              dstImage->TexFormat->MesaFormat);
-         ASSERT(dstImage->CompressedSize > 0);
-      }
-
-      ASSERT(dstImage->TexFormat);
-      ASSERT(dstImage->FetchTexelc);
-      ASSERT(dstImage->FetchTexelf);
-
-      /* Alloc new teximage data buffer.
-       * Setup src and dest data pointers.
-       */
-      if (dstImage->IsCompressed) {
-         dstImage->Data = _mesa_alloc_texmemory(dstImage->CompressedSize);
-         if (!dstImage->Data) {
-            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
-            return;
-         }
-         /* srcData and dstData are already set */
-         ASSERT(srcData);
-         ASSERT(dstData);
-      }
-      else {
-         bytesPerTexel = dstImage->TexFormat->TexelBytes;
-         ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
-         dstImage->Data = _mesa_alloc_texmemory(dstWidth * dstHeight
-                                                * dstDepth * bytesPerTexel);
-         if (!dstImage->Data) {
-            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
-            return;
-         }
-         srcData = (const GLubyte *) srcImage->Data;
-         dstData = (GLubyte *) dstImage->Data;
-      }
-
-      /*
-       * We use simple 2x2 averaging to compute the next mipmap level.
-       */
-      switch (target) {
-         case GL_TEXTURE_1D:
-            make_1d_mipmap(convertFormat, border,
-                           srcWidth, srcData,
-                           dstWidth, dstData);
-            break;
-         case GL_TEXTURE_2D:
-         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:
-            make_2d_mipmap(convertFormat, border,
-                           srcWidth, srcHeight, srcData,
-                           dstWidth, dstHeight, dstData);
-            break;
-         case GL_TEXTURE_3D:
-            make_3d_mipmap(convertFormat, border,
-                           srcWidth, srcHeight, srcDepth, srcData,
-                           dstWidth, dstHeight, dstDepth, dstData);
-            break;
-         case GL_TEXTURE_RECTANGLE_NV:
-            /* no mipmaps, do nothing */
-            break;
-         default:
-            _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
-            return;
-      }
-
-      if (dstImage->IsCompressed) {
-         GLubyte *temp;
-         /* compress image from dstData into dstImage->Data */
-         const GLenum srcFormat = convertFormat->BaseFormat;
-         GLint dstRowStride
-            = _mesa_compressed_row_stride(dstImage->TexFormat->MesaFormat, dstWidth);
-         ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
-         dstImage->TexFormat->StoreImage(ctx, 2, dstImage->_BaseFormat,
-                                         dstImage->TexFormat,
-                                         dstImage->Data,
-                                         0, 0, 0, /* dstX/Y/Zoffset */
-                                         dstRowStride, 0, /* strides */
-                                         dstWidth, dstHeight, 1, /* size */
-                                         srcFormat, CHAN_TYPE,
-                                         dstData, /* src data, actually */
-                                         &ctx->DefaultPacking);
-         /* swap src and dest pointers */
-         temp = (GLubyte *) srcData;
-         srcData = dstData;
-         dstData = temp;
-      }
-
-   } /* loop over mipmap levels */
-}
-
-
-/**
- * Helper function for drivers which need to rescale texture images to
- * certain aspect ratios.
- * Nearest filtering only (for broken hardware that can't support
- * all aspect ratios).  This can be made a lot faster, but I don't
- * really care enough...
- */
-void
-_mesa_rescale_teximage2d (GLuint bytesPerPixel,
-                         GLuint srcStrideInPixels,
-                         GLuint dstRowStride,
-                         GLint srcWidth, GLint srcHeight,
-                         GLint dstWidth, GLint dstHeight,
-                         const GLvoid *srcImage, GLvoid *dstImage)
-{
-   GLint row, col;
-
-#define INNER_LOOP( TYPE, HOP, WOP )                                   \
-   for ( row = 0 ; row < dstHeight ; row++ ) {                         \
-      GLint srcRow = row HOP hScale;                                   \
-      for ( col = 0 ; col < dstWidth ; col++ ) {                       \
-        GLint srcCol = col WOP wScale;                                 \
-        dst[col] = src[srcRow * srcStrideInPixels + srcCol];           \
-      }                                                                        \
-      dst = (TYPE *) ((GLubyte *) dst + dstRowStride);                 \
-   }                                                                   \
-
-#define RESCALE_IMAGE( TYPE )                                          \
-do {                                                                   \
-   const TYPE *src = (const TYPE *)srcImage;                           \
-   TYPE *dst = (TYPE *)dstImage;                                       \
-                                                                       \
-   if ( srcHeight < dstHeight ) {                                      \
-      const GLint hScale = dstHeight / srcHeight;                      \
-      if ( srcWidth < dstWidth ) {                                     \
-        const GLint wScale = dstWidth / srcWidth;                      \
-        INNER_LOOP( TYPE, /, / );                                      \
-      }                                                                        \
-      else {                                                           \
-        const GLint wScale = srcWidth / dstWidth;                      \
-        INNER_LOOP( TYPE, /, * );                                      \
-      }                                                                        \
-   }                                                                   \
-   else {                                                              \
-      const GLint hScale = srcHeight / dstHeight;                      \
-      if ( srcWidth < dstWidth ) {                                     \
-        const GLint wScale = dstWidth / srcWidth;                      \
-        INNER_LOOP( TYPE, *, / );                                      \
-      }                                                                        \
-      else {                                                           \
-        const GLint wScale = srcWidth / dstWidth;                      \
-        INNER_LOOP( TYPE, *, * );                                      \
-      }                                                                        \
-   }                                                                   \
-} while (0)
-
-   switch ( bytesPerPixel ) {
-   case 4:
-      RESCALE_IMAGE( GLuint );
-      break;
-
-   case 2:
-      RESCALE_IMAGE( GLushort );
-      break;
-
-   case 1:
-      RESCALE_IMAGE( GLubyte );
-      break;
-   default:
-      _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
-   }
-}
-
-
-/**
- * Upscale an image by replication, not (typical) stretching.
- * We use this when the image width or height is less than a
- * certain size (4, 8) and we need to upscale an image.
- */
-void
-_mesa_upscale_teximage2d (GLsizei inWidth, GLsizei inHeight,
-                          GLsizei outWidth, GLsizei outHeight,
-                          GLint comps, const GLchan *src, GLint srcRowStride,
-                          GLchan *dest )
-{
-   GLint i, j, k;
-
-   ASSERT(outWidth >= inWidth);
-   ASSERT(outHeight >= inHeight);
-#if 0
-   ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
-   ASSERT((outWidth & 3) == 0);
-   ASSERT((outHeight & 3) == 0);
-#endif
-
-   for (i = 0; i < outHeight; i++) {
-      const GLint ii = i % inHeight;
-      for (j = 0; j < outWidth; j++) {
-         const GLint jj = j % inWidth;
-         for (k = 0; k < comps; k++) {
-            dest[(i * outWidth + j) * comps + k]
-               = src[ii * srcRowStride + jj * comps + k];
-         }
-      }
-   }
-}
 
 
 #if FEATURE_EXT_texture_sRGB
index 7dc82a51c895019f5c09f4ff73e490cf9e507730..f67defc503fcb7e62d05361fbfb2b22307ffeb7e 100644 (file)
@@ -200,27 +200,6 @@ _mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target,
                                 struct gl_texture_image *texImage);
 
 
-extern void
-_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
-                      const struct gl_texture_unit *texUnit,
-                      struct gl_texture_object *texObj);
-
-
-extern void
-_mesa_rescale_teximage2d(GLuint bytesPerPixel,
-                         GLuint srcStrideInPixels,
-                         GLuint dstRowStride,
-                         GLint srcWidth, GLint srcHeight,
-                         GLint dstWidth, GLint dstHeight,
-                         const GLvoid *srcImage, GLvoid *dstImage);
-
-extern void
-_mesa_upscale_teximage2d(GLsizei inWidth, GLsizei inHeight,
-                         GLsizei outWidth, GLsizei outHeight,
-                         GLint comps, const GLchan *src, GLint srcRowStride,
-                         GLchan *dest);
-
-
 extern void
 _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
                    GLenum format, GLenum type, GLvoid *pixels,
index 8a13010c27b496860d19aa7807554db26b51bfa9..5d9f2d3c05ae02faab3cfd21864d8aff7b1fe151 100644 (file)
@@ -39,6 +39,7 @@ MAIN_SOURCES = \
        main/light.c \
        main/lines.c \
        main/matrix.c \
+       main/mipmap.c \
        main/mm.c \
        main/occlude.c \
        main/pixel.c \
index e9f4faeed00500822daa24df5ef75fe3cdc42ab7..b018c5a4a63e6960999e60a92062e4053b9a62c6 100644 (file)
@@ -43,6 +43,7 @@
 #include "convolve.h"
 #include "image.h"
 #include "macros.h"
+#include "mipmap.h"
 #include "texformat.h"
 #include "teximage.h"
 #include "texstore.h"
index 60ff915a32e66239aef6d4b55bd6722fbcca3190..a2f2f2dff4fe55ab5d1a52fcb27127ac340cd47a 100644 (file)
@@ -393,6 +393,10 @@ SOURCE=..\..\..\..\src\mesa\main\matrix.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\..\..\..\src\mesa\main\mipmap.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\..\..\..\src\mesa\main\mm.c\r
 # End Source File\r
 # Begin Source File\r
index c6da5b0cffbc9baaffae313d27caada3ea4ed3a2..b63312c88625a65a03ef7ee5b317535ab3abbae0 100644 (file)
                        <File\r
                                RelativePath="..\..\..\..\src\mesa\main\matrix.c">\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\..\..\..\src\mesa\main\mipmap.c">\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\..\src\mesa\main\mm.c">\r
                        </File>\r