mesa: pull in mipmap.c changes from gallium-0.2
authorKeith Whitwell <keith@tungstengraphics.com>
Mon, 22 Sep 2008 03:09:31 +0000 (20:09 -0700)
committerKeith Whitwell <keith@tungstengraphics.com>
Mon, 22 Sep 2008 05:13:54 +0000 (22:13 -0700)
src/mesa/main/mipmap.c

index 8ca912b3a9d19826997c7b34bb2b4944b2b6e95e..09709d17874adb67f3384bffb4d343eef128a08b 100644 (file)
 
 
 
-/**
- * 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)
+static GLint
+bytes_per_pixel(GLenum datatype, GLuint comps)
 {
-   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
-   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
+   GLint b = _mesa_sizeof_packed_type(datatype);
+   assert(b >= 0);
+   return b * comps;
+}
 
-   /* This assertion is no longer valid with non-power-of-2 textures
-   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
-   */
 
+static void
+mesa_format_to_type_and_comps(const struct gl_texture_format *format,
+                              GLenum *datatype, GLuint *comps)
+{
    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;
-         }
-      }
+      *datatype = CHAN_TYPE;
+      *comps = 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;
-         }
-      }
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 3;
       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;
-         }
-      }
+      *datatype = GL_UNSIGNED_SHORT_5_6_5;
+      *comps = 3;
       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;
-         }
-      }
+      *datatype = GL_UNSIGNED_SHORT_4_4_4_4;
+      *comps = 4;
       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;
-         }
-      }
+   case MESA_FORMAT_ARGB1555_REV:
+      *datatype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+      *comps = 3;
       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;
-         }
-      }
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 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;
-         }
-      }
+      *datatype = GL_UNSIGNED_BYTE_3_3_2;
+      *comps = 3;
       return;
+
    case MESA_FORMAT_A8:
    case MESA_FORMAT_L8:
    case MESA_FORMAT_I8:
    case MESA_FORMAT_CI8:
-#if FEATURE_EXT_texture_sRGB
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 1;
+      return;
+
+   case MESA_FORMAT_YCBCR:
+   case MESA_FORMAT_YCBCR_REV:
+      *datatype = GL_UNSIGNED_SHORT;
+      *comps = 2;
+      return;
+
+   case MESA_FORMAT_Z24_S8:
+      *datatype = GL_UNSIGNED_INT;
+      *comps = 1; /* XXX OK? */
+      return;
+
+   case MESA_FORMAT_Z16:
+      *datatype = GL_UNSIGNED_SHORT;
+      *comps = 1;
+      return;
+
+   case MESA_FORMAT_Z32:
+      *datatype = GL_UNSIGNED_INT;
+      *comps = 1;
+      return;
+
+   case MESA_FORMAT_SRGB8:
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 3;
+      return;
+   case MESA_FORMAT_SRGBA8:
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 4;
+      return;
    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;
-         }
-      }
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 1;
+      return;
+   case MESA_FORMAT_SLA8:
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 2;
+      return;
+
+   case MESA_FORMAT_RGB_FXT1:
+   case MESA_FORMAT_RGBA_FXT1:
+   case MESA_FORMAT_RGB_DXT1:
+   case MESA_FORMAT_RGBA_DXT1:
+   case MESA_FORMAT_RGBA_DXT3:
+   case MESA_FORMAT_RGBA_DXT5:
+      /* XXX generate error instead? */
+      *datatype = GL_UNSIGNED_BYTE;
+      *comps = 0;
+      return;
+
+   case MESA_FORMAT_RGBA:
+      *datatype = CHAN_TYPE;
+      *comps = 4;
       return;
+   case MESA_FORMAT_RGB:
+      *datatype = CHAN_TYPE;
+      *comps = 3;
+      return;
+   case MESA_FORMAT_LUMINANCE_ALPHA:
+      *datatype = CHAN_TYPE;
+      *comps = 2;
+      return;
+   case MESA_FORMAT_ALPHA:
+   case MESA_FORMAT_LUMINANCE:
+   case MESA_FORMAT_INTENSITY:
+      *datatype = CHAN_TYPE;
+      *comps = 1;
+      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;
-         }
-      }
+      *datatype = GL_FLOAT;
+      *comps = 4;
       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);
-            }
-         }
-      }
+      *datatype = GL_HALF_FLOAT_ARB;
+      *comps = 4;
       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;
-         }
-      }
+      *datatype = GL_FLOAT;
+      *comps = 3;
       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);
-            }
-         }
-      }
+      *datatype = GL_HALF_FLOAT_ARB;
+      *comps = 3;
       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;
-         }
-      }
+      *datatype = GL_FLOAT;
+      *comps = 2;
       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);
-            }
-         }
-      }
+      *datatype = GL_HALF_FLOAT_ARB;
+      *comps = 2;
       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;
-         }
-      }
+      *datatype = GL_FLOAT;
+      *comps = 1;
       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) {
+      *datatype = GL_HALF_FLOAT_ARB;
+      *comps = 1;
+      return;
+
+   default:
+      _mesa_problem(NULL, "bad texture format in mesa_format_to_type_and_comps");
+      *datatype = 0;
+      *comps = 1;
+   }
+}
+
+
+/**
+ * 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.
+ * \param datatype  GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
+ * \param comps  number of components per pixel (1..4)
+ */
+static void
+do_row(GLenum datatype, GLuint comps, 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;
+
+   ASSERT(comps >= 1);
+   ASSERT(comps <= 4);
+
+   /* This assertion is no longer valid with non-power-of-2 textures
+   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
+   */
+
+   if (datatype == GL_UNSIGNED_BYTE && comps == 4) {
+      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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_BYTE && comps == 3) {
+      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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_BYTE && comps == 2) {
+      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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_BYTE && comps == 1) {
+      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;
+      }
+   }
+
+   else if (datatype == GL_UNSIGNED_SHORT && comps == 4) {
+      GLuint i, j, k;
+      const GLushort(*rowA)[4] = (const GLushort(*)[4]) srcRowA;
+      const GLushort(*rowB)[4] = (const GLushort(*)[4]) srcRowB;
+      GLushort(*dst)[4] = (GLushort(*)[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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_SHORT && comps == 3) {
+      GLuint i, j, k;
+      const GLushort(*rowA)[3] = (const GLushort(*)[3]) srcRowA;
+      const GLushort(*rowB)[3] = (const GLushort(*)[3]) srcRowB;
+      GLushort(*dst)[3] = (GLushort(*)[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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_SHORT && comps == 2) {
+      GLuint i, j, k;
+      const GLushort(*rowA)[2] = (const GLushort(*)[2]) srcRowA;
+      const GLushort(*rowB)[2] = (const GLushort(*)[2]) srcRowB;
+      GLushort(*dst)[2] = (GLushort(*)[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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_SHORT && comps == 1) {
+      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;
+      }
+   }
+
+   else if (datatype == GL_FLOAT && comps == 4) {
+      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;
+      }
+   }
+   else if (datatype == GL_FLOAT && comps == 3) {
+      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;
+      }
+   }
+   else if (datatype == GL_FLOAT && comps == 2) {
+      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;
+      }
+   }
+   else if (datatype == GL_FLOAT && comps == 1) {
+      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;
+      }
+   }
+
+   else if (datatype == GL_HALF_FLOAT_ARB && comps == 4) {
+      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]);
-            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);
+            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;
+   }
+   else if (datatype == GL_HALF_FLOAT_ARB && comps == 3) {
+      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);
+         }
+      }
+   }
+   else if (datatype == GL_HALF_FLOAT_ARB && comps == 2) {
+      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);
+         }
+      }
+   }
+   else if (datatype == GL_HALF_FLOAT_ARB && comps == 1) {
+      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);
+      }
+   }
 
-   default:
+   else if (datatype == GL_UNSIGNED_INT && comps == 1) {
+      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;
+      }
+   }
+
+   else if (datatype == GL_UNSIGNED_SHORT_5_6_5 && comps == 3) {
+      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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_SHORT_4_4_4_4 && comps == 4) {
+      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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_SHORT_1_5_5_5_REV && comps == 4) {
+      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;
+      }
+   }
+   else if (datatype == GL_UNSIGNED_BYTE_3_3_2 && comps == 3) {
+      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;
+      }
+   }
+   else {
       _mesa_problem(NULL, "bad format in do_row()");
    }
 }
@@ -504,11 +585,11 @@ do_row(const struct gl_texture_format *format, GLint srcWidth,
  */
 
 static void
-make_1d_mipmap(const struct gl_texture_format *format, GLint border,
+make_1d_mipmap(GLenum datatype, GLuint comps, GLint border,
                GLint srcWidth, const GLubyte *srcPtr,
                GLint dstWidth, GLubyte *dstPtr)
 {
-   const GLint bpt = format->TexelBytes;
+   const GLint bpt = bytes_per_pixel(datatype, comps);
    const GLubyte *src;
    GLubyte *dst;
 
@@ -517,7 +598,7 @@ make_1d_mipmap(const struct gl_texture_format *format, GLint border,
    dst = dstPtr + border * bpt;
 
    /* we just duplicate the input row, kind of hack, saves code */
-   do_row(format, srcWidth - 2 * border, src, src,
+   do_row(datatype, comps, srcWidth - 2 * border, src, src,
           dstWidth - 2 * border, dst);
 
    if (border) {
@@ -532,13 +613,13 @@ make_1d_mipmap(const struct gl_texture_format *format, GLint border,
 
 
 static void
-make_2d_mipmap(const struct gl_texture_format *format, GLint border,
+make_2d_mipmap(GLenum datatype, GLuint comps, GLint border,
                GLint srcWidth, GLint srcHeight,
               const GLubyte *srcPtr, GLint srcRowStride,
                GLint dstWidth, GLint dstHeight,
               GLubyte *dstPtr, GLint dstRowStride)
 {
-   const GLint bpt = format->TexelBytes;
+   const GLint bpt = bytes_per_pixel(datatype, comps);
    const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
    const GLint dstWidthNB = dstWidth - 2 * border;
    const GLint dstHeightNB = dstHeight - 2 * border;
@@ -557,7 +638,7 @@ make_2d_mipmap(const struct gl_texture_format *format, GLint border,
    dst = dstPtr + border * ((dstWidth + 1) * bpt);
 
    for (row = 0; row < dstHeightNB; row++) {
-      do_row(format, srcWidthNB, srcA, srcB,
+      do_row(datatype, comps, srcWidthNB, srcA, srcB,
              dstWidthNB, dst);
       srcA += 2 * srcRowBytes;
       srcB += 2 * srcRowBytes;
@@ -579,12 +660,12 @@ make_2d_mipmap(const struct gl_texture_format *format, GLint border,
       MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
              srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
       /* lower border */
-      do_row(format, srcWidthNB,
+      do_row(datatype, comps, srcWidthNB,
              srcPtr + bpt,
              srcPtr + bpt,
              dstWidthNB, dstPtr + bpt);
       /* upper border */
-      do_row(format, srcWidthNB,
+      do_row(datatype, comps, srcWidthNB,
              srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
              srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
              dstWidthNB,
@@ -602,11 +683,11 @@ make_2d_mipmap(const struct gl_texture_format *format, GLint border,
       else {
          /* average two src pixels each dest pixel */
          for (row = 0; row < dstHeightNB; row += 2) {
-            do_row(format, 1,
+            do_row(datatype, comps, 1,
                    srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
                    srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
                    1, dstPtr + (dstWidth * row + 1) * bpt);
-            do_row(format, 1,
+            do_row(datatype, comps, 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);
@@ -617,13 +698,13 @@ make_2d_mipmap(const struct gl_texture_format *format, GLint border,
 
 
 static void
-make_3d_mipmap(const struct gl_texture_format *format, GLint border,
+make_3d_mipmap(GLenum datatype, GLuint comps, GLint border,
                GLint srcWidth, GLint srcHeight, GLint srcDepth,
                const GLubyte *srcPtr, GLint srcRowStride,
                GLint dstWidth, GLint dstHeight, GLint dstDepth,
                GLubyte *dstPtr, GLint dstRowStride)
 {
-   const GLint bpt = format->TexelBytes;
+   const GLint bpt = bytes_per_pixel(datatype, comps);
    const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
    const GLint srcDepthNB = srcDepth - 2 * border;
    const GLint dstWidthNB = dstWidth - 2 * border;
@@ -693,13 +774,13 @@ make_3d_mipmap(const struct gl_texture_format *format, GLint border,
 
       for (row = 0; row < dstHeightNB; row++) {
          /* Average together two rows from first src image */
-         do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
+         do_row(datatype, comps, srcWidthNB, srcImgARowA, srcImgARowB,
                 srcWidthNB, tmpRowA);
          /* Average together two rows from second src image */
-         do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
+         do_row(datatype, comps, srcWidthNB, srcImgBRowA, srcImgBRowB,
                 srcWidthNB, tmpRowB);
          /* Average together the temp rows to make the final row */
-         do_row(format, srcWidthNB, tmpRowA, tmpRowB,
+         do_row(datatype, comps, srcWidthNB, tmpRowA, tmpRowB,
                 dstWidthNB, dstImgRow);
          /* advance to next rows */
          srcImgARowA += bytesPerSrcRow + srcRowOffset;
@@ -716,10 +797,10 @@ make_3d_mipmap(const struct gl_texture_format *format, GLint border,
    /* 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, srcRowStride,
+      make_2d_mipmap(datatype, comps, 1, srcWidth, srcHeight, srcPtr, srcRowStride,
                      dstWidth, dstHeight, dstPtr, dstRowStride);
       /* do back border image */
-      make_2d_mipmap(format, 1, srcWidth, srcHeight,
+      make_2d_mipmap(datatype, comps, 1, srcWidth, srcHeight,
                      srcPtr + bytesPerSrcImage * (srcDepth - 1), srcRowStride,
                      dstWidth, dstHeight,
                      dstPtr + bytesPerDstImage * (dstDepth - 1), dstRowStride);
@@ -767,28 +848,28 @@ make_3d_mipmap(const struct gl_texture_format *format, GLint border,
             /* 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_row(datatype, comps, 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_row(datatype, comps, 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_row(datatype, comps, 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);
+            do_row(datatype, comps, 1, src, src + srcImageOffset, 1, dst);
          }
       }
    }
@@ -796,12 +877,12 @@ make_3d_mipmap(const struct gl_texture_format *format, GLint border,
 
 
 static void
-make_1d_stack_mipmap(const struct gl_texture_format *format, GLint border,
+make_1d_stack_mipmap(GLenum datatype, GLuint comps, GLint border,
                      GLint srcWidth, const GLubyte *srcPtr, GLuint srcRowStride,
                      GLint dstWidth, GLint dstHeight,
                     GLubyte *dstPtr, GLuint dstRowStride )
 {
-   const GLint bpt = format->TexelBytes;
+   const GLint bpt = bytes_per_pixel(datatype, comps);
    const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
    const GLint dstWidthNB = dstWidth - 2 * border;
    const GLint dstHeightNB = dstHeight - 2 * border;
@@ -816,7 +897,7 @@ make_1d_stack_mipmap(const struct gl_texture_format *format, GLint border,
    dst = dstPtr + border * ((dstWidth + 1) * bpt);
 
    for (row = 0; row < dstHeightNB; row++) {
-      do_row(format, srcWidthNB, src, src,
+      do_row(datatype, comps, srcWidthNB, src, src,
              dstWidthNB, dst);
       src += srcRowBytes;
       dst += dstRowBytes;
@@ -839,13 +920,13 @@ make_1d_stack_mipmap(const struct gl_texture_format *format, GLint border,
  * and \c make_2d_mipmap.
  */
 static void
-make_2d_stack_mipmap(const struct gl_texture_format *format, GLint border,
+make_2d_stack_mipmap(GLenum datatype, GLuint comps, GLint border,
                      GLint srcWidth, GLint srcHeight,
                     const GLubyte *srcPtr, GLint srcRowStride,
                      GLint dstWidth, GLint dstHeight, GLint dstDepth,
                      GLubyte *dstPtr, GLint dstRowStride)
 {
-   const GLint bpt = format->TexelBytes;
+   const GLint bpt = bytes_per_pixel(datatype, comps);
    const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
    const GLint dstWidthNB = dstWidth - 2 * border;
    const GLint dstHeightNB = dstHeight - 2 * border;
@@ -867,7 +948,7 @@ make_2d_stack_mipmap(const struct gl_texture_format *format, GLint border,
 
    for (layer = 0; layer < dstDepthNB; layer++) {
       for (row = 0; row < dstHeightNB; row++) {
-         do_row(format, srcWidthNB, srcA, srcB,
+         do_row(datatype, comps, srcWidthNB, srcA, srcB,
                 dstWidthNB, dst);
          srcA += 2 * srcRowBytes;
          srcB += 2 * srcRowBytes;
@@ -889,12 +970,12 @@ make_2d_stack_mipmap(const struct gl_texture_format *format, GLint border,
          MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
                 srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
          /* lower border */
-         do_row(format, srcWidthNB,
+         do_row(datatype, comps, srcWidthNB,
                 srcPtr + bpt,
                 srcPtr + bpt,
                 dstWidthNB, dstPtr + bpt);
          /* upper border */
-         do_row(format, srcWidthNB,
+         do_row(datatype, comps, srcWidthNB,
                 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
                 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
                 dstWidthNB,
@@ -912,11 +993,11 @@ make_2d_stack_mipmap(const struct gl_texture_format *format, GLint border,
          else {
             /* average two src pixels each dest pixel */
             for (row = 0; row < dstHeightNB; row += 2) {
-               do_row(format, 1,
+               do_row(datatype, comps, 1,
                       srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
                       srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
                       1, dstPtr + (dstWidth * row + 1) * bpt);
-               do_row(format, 1,
+               do_row(datatype, comps, 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);
@@ -941,6 +1022,8 @@ _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
    const GLubyte *srcData = NULL;
    GLubyte *dstData = NULL;
    GLint level, maxLevels;
+   GLenum datatype;
+   GLuint comps;
 
    ASSERT(texObj);
    /* XXX choose cube map face here??? */
@@ -1004,6 +1087,8 @@ _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
       convertFormat = srcImage->TexFormat;
    }
 
+   mesa_format_to_type_and_comps(convertFormat, &datatype, &comps);
+
    for (level = texObj->BaseLevel; level < texObj->MaxLevel
            && level < maxLevels - 1; level++) {
       /* generate image[level+1] from image[level] */
@@ -1120,7 +1205,7 @@ _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
        */
       switch (target) {
          case GL_TEXTURE_1D:
-            make_1d_mipmap(convertFormat, border,
+            make_1d_mipmap(datatype, comps, border,
                            srcWidth, srcData,
                            dstWidth, dstData);
             break;
@@ -1131,25 +1216,25 @@ _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
          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,
+            make_2d_mipmap(datatype, comps, border,
                            srcWidth, srcHeight, srcData, srcImage->RowStride,
                            dstWidth, dstHeight, dstData, dstImage->RowStride);
             break;
          case GL_TEXTURE_3D:
-            make_3d_mipmap(convertFormat, border,
+            make_3d_mipmap(datatype, comps, border,
                            srcWidth, srcHeight, srcDepth,
                           srcData, srcImage->RowStride,
                            dstWidth, dstHeight, dstDepth,
                           dstData, dstImage->RowStride);
             break;
          case GL_TEXTURE_1D_ARRAY_EXT:
-            make_1d_stack_mipmap(convertFormat, border,
+            make_1d_stack_mipmap(datatype, comps, border,
                                  srcWidth, srcData, srcImage->RowStride,
                                  dstWidth, dstHeight,
                                 dstData, dstImage->RowStride);
             break;
          case GL_TEXTURE_2D_ARRAY_EXT:
-            make_2d_stack_mipmap(convertFormat, border,
+            make_2d_stack_mipmap(datatype, comps, border,
                                  srcWidth, srcHeight,
                                 srcData, srcImage->RowStride,
                                  dstWidth, dstHeight,