1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg/**
27848b8605Smrg * \file mipmap.c  mipmap generation and teximage resizing functions.
28848b8605Smrg */
29848b8605Smrg
30b8e80941Smrg#include "errors.h"
31848b8605Smrg#include "imports.h"
32848b8605Smrg#include "formats.h"
33848b8605Smrg#include "glformats.h"
34848b8605Smrg#include "mipmap.h"
35848b8605Smrg#include "mtypes.h"
36848b8605Smrg#include "teximage.h"
37848b8605Smrg#include "texobj.h"
38848b8605Smrg#include "texstore.h"
39848b8605Smrg#include "image.h"
40848b8605Smrg#include "macros.h"
41b8e80941Smrg#include "util/half_float.h"
42b8e80941Smrg#include "util/format_rgb9e5.h"
43b8e80941Smrg#include "util/format_r11g11b10f.h"
44848b8605Smrg
45848b8605Smrg
46b8e80941Smrg/**
47b8e80941Smrg * Compute the expected number of mipmap levels in the texture given
48b8e80941Smrg * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
49b8e80941Smrg * GL_TEXTURE_MAX_LEVEL settings.  This will tell us how many mipmap
50b8e80941Smrg * levels should be generated.
51b8e80941Smrg */
52b8e80941Smrgunsigned
53b8e80941Smrg_mesa_compute_num_levels(struct gl_context *ctx,
54b8e80941Smrg                         struct gl_texture_object *texObj,
55b8e80941Smrg                         GLenum target)
56b8e80941Smrg{
57b8e80941Smrg   const struct gl_texture_image *baseImage;
58b8e80941Smrg   GLuint numLevels;
59b8e80941Smrg
60b8e80941Smrg   baseImage = _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel);
61b8e80941Smrg
62b8e80941Smrg   numLevels = texObj->BaseLevel + baseImage->MaxNumLevels;
63b8e80941Smrg   numLevels = MIN2(numLevels, (GLuint) texObj->MaxLevel + 1);
64b8e80941Smrg   if (texObj->Immutable)
65b8e80941Smrg      numLevels = MIN2(numLevels, texObj->NumLevels);
66b8e80941Smrg   assert(numLevels >= 1);
67b8e80941Smrg
68b8e80941Smrg   return numLevels;
69b8e80941Smrg}
70848b8605Smrg
71848b8605Smrgstatic GLint
72848b8605Smrgbytes_per_pixel(GLenum datatype, GLuint comps)
73848b8605Smrg{
74848b8605Smrg   GLint b;
75848b8605Smrg
76848b8605Smrg   if (datatype == GL_UNSIGNED_INT_8_24_REV_MESA ||
77848b8605Smrg       datatype == GL_UNSIGNED_INT_24_8_MESA)
78848b8605Smrg      return 4;
79848b8605Smrg
80848b8605Smrg   b = _mesa_sizeof_packed_type(datatype);
81848b8605Smrg   assert(b >= 0);
82848b8605Smrg
83848b8605Smrg   if (_mesa_type_is_packed(datatype))
84848b8605Smrg      return b;
85848b8605Smrg   else
86848b8605Smrg      return b * comps;
87848b8605Smrg}
88848b8605Smrg
89848b8605Smrg
90848b8605Smrg/**
91848b8605Smrg * \name Support macros for do_row and do_row_3d
92848b8605Smrg *
93848b8605Smrg * The macro madness is here for two reasons.  First, it compacts the code
94848b8605Smrg * slightly.  Second, it makes it much easier to adjust the specifics of the
95848b8605Smrg * filter to tune the rounding characteristics.
96848b8605Smrg */
97848b8605Smrg/*@{*/
98848b8605Smrg#define DECLARE_ROW_POINTERS(t, e) \
99848b8605Smrg      const t(*rowA)[e] = (const t(*)[e]) srcRowA; \
100848b8605Smrg      const t(*rowB)[e] = (const t(*)[e]) srcRowB; \
101848b8605Smrg      const t(*rowC)[e] = (const t(*)[e]) srcRowC; \
102848b8605Smrg      const t(*rowD)[e] = (const t(*)[e]) srcRowD; \
103848b8605Smrg      t(*dst)[e] = (t(*)[e]) dstRow
104848b8605Smrg
105848b8605Smrg#define DECLARE_ROW_POINTERS0(t) \
106848b8605Smrg      const t *rowA = (const t *) srcRowA; \
107848b8605Smrg      const t *rowB = (const t *) srcRowB; \
108848b8605Smrg      const t *rowC = (const t *) srcRowC; \
109848b8605Smrg      const t *rowD = (const t *) srcRowD; \
110848b8605Smrg      t *dst = (t *) dstRow
111848b8605Smrg
112848b8605Smrg#define FILTER_SUM_3D(Aj, Ak, Bj, Bk, Cj, Ck, Dj, Dk) \
113848b8605Smrg   ((unsigned) Aj + (unsigned) Ak \
114848b8605Smrg    + (unsigned) Bj + (unsigned) Bk \
115848b8605Smrg    + (unsigned) Cj + (unsigned) Ck \
116848b8605Smrg    + (unsigned) Dj + (unsigned) Dk \
117848b8605Smrg    + 4) >> 3
118848b8605Smrg
119848b8605Smrg#define FILTER_3D(e) \
120848b8605Smrg   do { \
121848b8605Smrg      dst[i][e] = FILTER_SUM_3D(rowA[j][e], rowA[k][e], \
122848b8605Smrg                                rowB[j][e], rowB[k][e], \
123848b8605Smrg                                rowC[j][e], rowC[k][e], \
124848b8605Smrg                                rowD[j][e], rowD[k][e]); \
125848b8605Smrg   } while(0)
126848b8605Smrg
127848b8605Smrg#define FILTER_SUM_3D_SIGNED(Aj, Ak, Bj, Bk, Cj, Ck, Dj, Dk) \
128848b8605Smrg   (Aj + Ak \
129848b8605Smrg    + Bj + Bk \
130848b8605Smrg    + Cj + Ck \
131848b8605Smrg    + Dj + Dk \
132848b8605Smrg    + 4) / 8
133848b8605Smrg
134848b8605Smrg#define FILTER_3D_SIGNED(e) \
135848b8605Smrg   do { \
136848b8605Smrg      dst[i][e] = FILTER_SUM_3D_SIGNED(rowA[j][e], rowA[k][e], \
137848b8605Smrg                                       rowB[j][e], rowB[k][e], \
138848b8605Smrg                                       rowC[j][e], rowC[k][e], \
139848b8605Smrg                                       rowD[j][e], rowD[k][e]); \
140848b8605Smrg   } while(0)
141848b8605Smrg
142848b8605Smrg#define FILTER_F_3D(e) \
143848b8605Smrg   do { \
144848b8605Smrg      dst[i][e] = (rowA[j][e] + rowA[k][e] \
145848b8605Smrg                   + rowB[j][e] + rowB[k][e] \
146848b8605Smrg                   + rowC[j][e] + rowC[k][e] \
147848b8605Smrg                   + rowD[j][e] + rowD[k][e]) * 0.125F; \
148848b8605Smrg   } while(0)
149848b8605Smrg
150848b8605Smrg#define FILTER_HF_3D(e) \
151848b8605Smrg   do { \
152848b8605Smrg      const GLfloat aj = _mesa_half_to_float(rowA[j][e]); \
153848b8605Smrg      const GLfloat ak = _mesa_half_to_float(rowA[k][e]); \
154848b8605Smrg      const GLfloat bj = _mesa_half_to_float(rowB[j][e]); \
155848b8605Smrg      const GLfloat bk = _mesa_half_to_float(rowB[k][e]); \
156848b8605Smrg      const GLfloat cj = _mesa_half_to_float(rowC[j][e]); \
157848b8605Smrg      const GLfloat ck = _mesa_half_to_float(rowC[k][e]); \
158848b8605Smrg      const GLfloat dj = _mesa_half_to_float(rowD[j][e]); \
159848b8605Smrg      const GLfloat dk = _mesa_half_to_float(rowD[k][e]); \
160848b8605Smrg      dst[i][e] = _mesa_float_to_half((aj + ak + bj + bk + cj + ck + dj + dk) \
161848b8605Smrg                                      * 0.125F); \
162848b8605Smrg   } while(0)
163848b8605Smrg/*@}*/
164848b8605Smrg
165848b8605Smrg
166848b8605Smrg/**
167848b8605Smrg * Average together two rows of a source image to produce a single new
168848b8605Smrg * row in the dest image.  It's legal for the two source rows to point
169848b8605Smrg * to the same data.  The source width must be equal to either the
170848b8605Smrg * dest width or two times the dest width.
171848b8605Smrg * \param datatype  GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
172848b8605Smrg * \param comps  number of components per pixel (1..4)
173848b8605Smrg */
174848b8605Smrgstatic void
175848b8605Smrgdo_row(GLenum datatype, GLuint comps, GLint srcWidth,
176848b8605Smrg       const GLvoid *srcRowA, const GLvoid *srcRowB,
177848b8605Smrg       GLint dstWidth, GLvoid *dstRow)
178848b8605Smrg{
179848b8605Smrg   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
180848b8605Smrg   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
181848b8605Smrg
182b8e80941Smrg   assert(comps >= 1);
183b8e80941Smrg   assert(comps <= 4);
184848b8605Smrg
185848b8605Smrg   /* This assertion is no longer valid with non-power-of-2 textures
186848b8605Smrg   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
187848b8605Smrg   */
188848b8605Smrg
189848b8605Smrg   if (datatype == GL_UNSIGNED_BYTE && comps == 4) {
190848b8605Smrg      GLuint i, j, k;
191848b8605Smrg      const GLubyte(*rowA)[4] = (const GLubyte(*)[4]) srcRowA;
192848b8605Smrg      const GLubyte(*rowB)[4] = (const GLubyte(*)[4]) srcRowB;
193848b8605Smrg      GLubyte(*dst)[4] = (GLubyte(*)[4]) dstRow;
194848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
195848b8605Smrg           i++, j += colStride, k += colStride) {
196848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
197848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
198848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
199848b8605Smrg         dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
200848b8605Smrg      }
201848b8605Smrg   }
202848b8605Smrg   else if (datatype == GL_UNSIGNED_BYTE && comps == 3) {
203848b8605Smrg      GLuint i, j, k;
204848b8605Smrg      const GLubyte(*rowA)[3] = (const GLubyte(*)[3]) srcRowA;
205848b8605Smrg      const GLubyte(*rowB)[3] = (const GLubyte(*)[3]) srcRowB;
206848b8605Smrg      GLubyte(*dst)[3] = (GLubyte(*)[3]) dstRow;
207848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
208848b8605Smrg           i++, j += colStride, k += colStride) {
209848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
210848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
211848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
212848b8605Smrg      }
213848b8605Smrg   }
214848b8605Smrg   else if (datatype == GL_UNSIGNED_BYTE && comps == 2) {
215848b8605Smrg      GLuint i, j, k;
216848b8605Smrg      const GLubyte(*rowA)[2] = (const GLubyte(*)[2]) srcRowA;
217848b8605Smrg      const GLubyte(*rowB)[2] = (const GLubyte(*)[2]) srcRowB;
218848b8605Smrg      GLubyte(*dst)[2] = (GLubyte(*)[2]) dstRow;
219848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
220848b8605Smrg           i++, j += colStride, k += colStride) {
221848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) >> 2;
222848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) >> 2;
223848b8605Smrg      }
224848b8605Smrg   }
225848b8605Smrg   else if (datatype == GL_UNSIGNED_BYTE && comps == 1) {
226848b8605Smrg      GLuint i, j, k;
227848b8605Smrg      const GLubyte *rowA = (const GLubyte *) srcRowA;
228848b8605Smrg      const GLubyte *rowB = (const GLubyte *) srcRowB;
229848b8605Smrg      GLubyte *dst = (GLubyte *) dstRow;
230848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
231848b8605Smrg           i++, j += colStride, k += colStride) {
232848b8605Smrg         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
233848b8605Smrg      }
234848b8605Smrg   }
235848b8605Smrg
236848b8605Smrg   else if (datatype == GL_BYTE && comps == 4) {
237848b8605Smrg      GLuint i, j, k;
238848b8605Smrg      const GLbyte(*rowA)[4] = (const GLbyte(*)[4]) srcRowA;
239848b8605Smrg      const GLbyte(*rowB)[4] = (const GLbyte(*)[4]) srcRowB;
240848b8605Smrg      GLbyte(*dst)[4] = (GLbyte(*)[4]) dstRow;
241848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
242848b8605Smrg           i++, j += colStride, k += colStride) {
243848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
244848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
245848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
246848b8605Smrg         dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
247848b8605Smrg      }
248848b8605Smrg   }
249848b8605Smrg   else if (datatype == GL_BYTE && comps == 3) {
250848b8605Smrg      GLuint i, j, k;
251848b8605Smrg      const GLbyte(*rowA)[3] = (const GLbyte(*)[3]) srcRowA;
252848b8605Smrg      const GLbyte(*rowB)[3] = (const GLbyte(*)[3]) srcRowB;
253848b8605Smrg      GLbyte(*dst)[3] = (GLbyte(*)[3]) dstRow;
254848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
255848b8605Smrg           i++, j += colStride, k += colStride) {
256848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
257848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
258848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
259848b8605Smrg      }
260848b8605Smrg   }
261848b8605Smrg   else if (datatype == GL_BYTE && comps == 2) {
262848b8605Smrg      GLuint i, j, k;
263848b8605Smrg      const GLbyte(*rowA)[2] = (const GLbyte(*)[2]) srcRowA;
264848b8605Smrg      const GLbyte(*rowB)[2] = (const GLbyte(*)[2]) srcRowB;
265848b8605Smrg      GLbyte(*dst)[2] = (GLbyte(*)[2]) dstRow;
266848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
267848b8605Smrg           i++, j += colStride, k += colStride) {
268848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
269848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
270848b8605Smrg      }
271848b8605Smrg   }
272848b8605Smrg   else if (datatype == GL_BYTE && comps == 1) {
273848b8605Smrg      GLuint i, j, k;
274848b8605Smrg      const GLbyte *rowA = (const GLbyte *) srcRowA;
275848b8605Smrg      const GLbyte *rowB = (const GLbyte *) srcRowB;
276848b8605Smrg      GLbyte *dst = (GLbyte *) dstRow;
277848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
278848b8605Smrg           i++, j += colStride, k += colStride) {
279848b8605Smrg         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
280848b8605Smrg      }
281848b8605Smrg   }
282848b8605Smrg
283848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT && comps == 4) {
284848b8605Smrg      GLuint i, j, k;
285848b8605Smrg      const GLushort(*rowA)[4] = (const GLushort(*)[4]) srcRowA;
286848b8605Smrg      const GLushort(*rowB)[4] = (const GLushort(*)[4]) srcRowB;
287848b8605Smrg      GLushort(*dst)[4] = (GLushort(*)[4]) dstRow;
288848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
289848b8605Smrg           i++, j += colStride, k += colStride) {
290848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
291848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
292848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
293848b8605Smrg         dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
294848b8605Smrg      }
295848b8605Smrg   }
296848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT && comps == 3) {
297848b8605Smrg      GLuint i, j, k;
298848b8605Smrg      const GLushort(*rowA)[3] = (const GLushort(*)[3]) srcRowA;
299848b8605Smrg      const GLushort(*rowB)[3] = (const GLushort(*)[3]) srcRowB;
300848b8605Smrg      GLushort(*dst)[3] = (GLushort(*)[3]) dstRow;
301848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
302848b8605Smrg           i++, j += colStride, k += colStride) {
303848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
304848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
305848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
306848b8605Smrg      }
307848b8605Smrg   }
308848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT && comps == 2) {
309848b8605Smrg      GLuint i, j, k;
310848b8605Smrg      const GLushort(*rowA)[2] = (const GLushort(*)[2]) srcRowA;
311848b8605Smrg      const GLushort(*rowB)[2] = (const GLushort(*)[2]) srcRowB;
312848b8605Smrg      GLushort(*dst)[2] = (GLushort(*)[2]) dstRow;
313848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
314848b8605Smrg           i++, j += colStride, k += colStride) {
315848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
316848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
317848b8605Smrg      }
318848b8605Smrg   }
319848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT && comps == 1) {
320848b8605Smrg      GLuint i, j, k;
321848b8605Smrg      const GLushort *rowA = (const GLushort *) srcRowA;
322848b8605Smrg      const GLushort *rowB = (const GLushort *) srcRowB;
323848b8605Smrg      GLushort *dst = (GLushort *) dstRow;
324848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
325848b8605Smrg           i++, j += colStride, k += colStride) {
326848b8605Smrg         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
327848b8605Smrg      }
328848b8605Smrg   }
329848b8605Smrg
330848b8605Smrg   else if (datatype == GL_SHORT && comps == 4) {
331848b8605Smrg      GLuint i, j, k;
332848b8605Smrg      const GLshort(*rowA)[4] = (const GLshort(*)[4]) srcRowA;
333848b8605Smrg      const GLshort(*rowB)[4] = (const GLshort(*)[4]) srcRowB;
334848b8605Smrg      GLshort(*dst)[4] = (GLshort(*)[4]) dstRow;
335848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
336848b8605Smrg           i++, j += colStride, k += colStride) {
337848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
338848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
339848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
340848b8605Smrg         dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
341848b8605Smrg      }
342848b8605Smrg   }
343848b8605Smrg   else if (datatype == GL_SHORT && comps == 3) {
344848b8605Smrg      GLuint i, j, k;
345848b8605Smrg      const GLshort(*rowA)[3] = (const GLshort(*)[3]) srcRowA;
346848b8605Smrg      const GLshort(*rowB)[3] = (const GLshort(*)[3]) srcRowB;
347848b8605Smrg      GLshort(*dst)[3] = (GLshort(*)[3]) dstRow;
348848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
349848b8605Smrg           i++, j += colStride, k += colStride) {
350848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
351848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
352848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
353848b8605Smrg      }
354848b8605Smrg   }
355848b8605Smrg   else if (datatype == GL_SHORT && comps == 2) {
356848b8605Smrg      GLuint i, j, k;
357848b8605Smrg      const GLshort(*rowA)[2] = (const GLshort(*)[2]) srcRowA;
358848b8605Smrg      const GLshort(*rowB)[2] = (const GLshort(*)[2]) srcRowB;
359848b8605Smrg      GLshort(*dst)[2] = (GLshort(*)[2]) dstRow;
360848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
361848b8605Smrg           i++, j += colStride, k += colStride) {
362848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
363848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
364848b8605Smrg      }
365848b8605Smrg   }
366848b8605Smrg   else if (datatype == GL_SHORT && comps == 1) {
367848b8605Smrg      GLuint i, j, k;
368848b8605Smrg      const GLshort *rowA = (const GLshort *) srcRowA;
369848b8605Smrg      const GLshort *rowB = (const GLshort *) srcRowB;
370848b8605Smrg      GLshort *dst = (GLshort *) dstRow;
371848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
372848b8605Smrg           i++, j += colStride, k += colStride) {
373848b8605Smrg         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
374848b8605Smrg      }
375848b8605Smrg   }
376848b8605Smrg
377848b8605Smrg   else if (datatype == GL_FLOAT && comps == 4) {
378848b8605Smrg      GLuint i, j, k;
379848b8605Smrg      const GLfloat(*rowA)[4] = (const GLfloat(*)[4]) srcRowA;
380848b8605Smrg      const GLfloat(*rowB)[4] = (const GLfloat(*)[4]) srcRowB;
381848b8605Smrg      GLfloat(*dst)[4] = (GLfloat(*)[4]) dstRow;
382848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
383848b8605Smrg           i++, j += colStride, k += colStride) {
384848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] +
385848b8605Smrg                      rowB[j][0] + rowB[k][0]) * 0.25F;
386848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] +
387848b8605Smrg                      rowB[j][1] + rowB[k][1]) * 0.25F;
388848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] +
389848b8605Smrg                      rowB[j][2] + rowB[k][2]) * 0.25F;
390848b8605Smrg         dst[i][3] = (rowA[j][3] + rowA[k][3] +
391848b8605Smrg                      rowB[j][3] + rowB[k][3]) * 0.25F;
392848b8605Smrg      }
393848b8605Smrg   }
394848b8605Smrg   else if (datatype == GL_FLOAT && comps == 3) {
395848b8605Smrg      GLuint i, j, k;
396848b8605Smrg      const GLfloat(*rowA)[3] = (const GLfloat(*)[3]) srcRowA;
397848b8605Smrg      const GLfloat(*rowB)[3] = (const GLfloat(*)[3]) srcRowB;
398848b8605Smrg      GLfloat(*dst)[3] = (GLfloat(*)[3]) dstRow;
399848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
400848b8605Smrg           i++, j += colStride, k += colStride) {
401848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] +
402848b8605Smrg                      rowB[j][0] + rowB[k][0]) * 0.25F;
403848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] +
404848b8605Smrg                      rowB[j][1] + rowB[k][1]) * 0.25F;
405848b8605Smrg         dst[i][2] = (rowA[j][2] + rowA[k][2] +
406848b8605Smrg                      rowB[j][2] + rowB[k][2]) * 0.25F;
407848b8605Smrg      }
408848b8605Smrg   }
409848b8605Smrg   else if (datatype == GL_FLOAT && comps == 2) {
410848b8605Smrg      GLuint i, j, k;
411848b8605Smrg      const GLfloat(*rowA)[2] = (const GLfloat(*)[2]) srcRowA;
412848b8605Smrg      const GLfloat(*rowB)[2] = (const GLfloat(*)[2]) srcRowB;
413848b8605Smrg      GLfloat(*dst)[2] = (GLfloat(*)[2]) dstRow;
414848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
415848b8605Smrg           i++, j += colStride, k += colStride) {
416848b8605Smrg         dst[i][0] = (rowA[j][0] + rowA[k][0] +
417848b8605Smrg                      rowB[j][0] + rowB[k][0]) * 0.25F;
418848b8605Smrg         dst[i][1] = (rowA[j][1] + rowA[k][1] +
419848b8605Smrg                      rowB[j][1] + rowB[k][1]) * 0.25F;
420848b8605Smrg      }
421848b8605Smrg   }
422848b8605Smrg   else if (datatype == GL_FLOAT && comps == 1) {
423848b8605Smrg      GLuint i, j, k;
424848b8605Smrg      const GLfloat *rowA = (const GLfloat *) srcRowA;
425848b8605Smrg      const GLfloat *rowB = (const GLfloat *) srcRowB;
426848b8605Smrg      GLfloat *dst = (GLfloat *) dstRow;
427848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
428848b8605Smrg           i++, j += colStride, k += colStride) {
429848b8605Smrg         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
430848b8605Smrg      }
431848b8605Smrg   }
432848b8605Smrg
433848b8605Smrg   else if (datatype == GL_HALF_FLOAT_ARB && comps == 4) {
434848b8605Smrg      GLuint i, j, k, comp;
435848b8605Smrg      const GLhalfARB(*rowA)[4] = (const GLhalfARB(*)[4]) srcRowA;
436848b8605Smrg      const GLhalfARB(*rowB)[4] = (const GLhalfARB(*)[4]) srcRowB;
437848b8605Smrg      GLhalfARB(*dst)[4] = (GLhalfARB(*)[4]) dstRow;
438848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
439848b8605Smrg           i++, j += colStride, k += colStride) {
440848b8605Smrg         for (comp = 0; comp < 4; comp++) {
441848b8605Smrg            GLfloat aj, ak, bj, bk;
442848b8605Smrg            aj = _mesa_half_to_float(rowA[j][comp]);
443848b8605Smrg            ak = _mesa_half_to_float(rowA[k][comp]);
444848b8605Smrg            bj = _mesa_half_to_float(rowB[j][comp]);
445848b8605Smrg            bk = _mesa_half_to_float(rowB[k][comp]);
446848b8605Smrg            dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
447848b8605Smrg         }
448848b8605Smrg      }
449848b8605Smrg   }
450848b8605Smrg   else if (datatype == GL_HALF_FLOAT_ARB && comps == 3) {
451848b8605Smrg      GLuint i, j, k, comp;
452848b8605Smrg      const GLhalfARB(*rowA)[3] = (const GLhalfARB(*)[3]) srcRowA;
453848b8605Smrg      const GLhalfARB(*rowB)[3] = (const GLhalfARB(*)[3]) srcRowB;
454848b8605Smrg      GLhalfARB(*dst)[3] = (GLhalfARB(*)[3]) dstRow;
455848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
456848b8605Smrg           i++, j += colStride, k += colStride) {
457848b8605Smrg         for (comp = 0; comp < 3; comp++) {
458848b8605Smrg            GLfloat aj, ak, bj, bk;
459848b8605Smrg            aj = _mesa_half_to_float(rowA[j][comp]);
460848b8605Smrg            ak = _mesa_half_to_float(rowA[k][comp]);
461848b8605Smrg            bj = _mesa_half_to_float(rowB[j][comp]);
462848b8605Smrg            bk = _mesa_half_to_float(rowB[k][comp]);
463848b8605Smrg            dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
464848b8605Smrg         }
465848b8605Smrg      }
466848b8605Smrg   }
467848b8605Smrg   else if (datatype == GL_HALF_FLOAT_ARB && comps == 2) {
468848b8605Smrg      GLuint i, j, k, comp;
469848b8605Smrg      const GLhalfARB(*rowA)[2] = (const GLhalfARB(*)[2]) srcRowA;
470848b8605Smrg      const GLhalfARB(*rowB)[2] = (const GLhalfARB(*)[2]) srcRowB;
471848b8605Smrg      GLhalfARB(*dst)[2] = (GLhalfARB(*)[2]) dstRow;
472848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
473848b8605Smrg           i++, j += colStride, k += colStride) {
474848b8605Smrg         for (comp = 0; comp < 2; comp++) {
475848b8605Smrg            GLfloat aj, ak, bj, bk;
476848b8605Smrg            aj = _mesa_half_to_float(rowA[j][comp]);
477848b8605Smrg            ak = _mesa_half_to_float(rowA[k][comp]);
478848b8605Smrg            bj = _mesa_half_to_float(rowB[j][comp]);
479848b8605Smrg            bk = _mesa_half_to_float(rowB[k][comp]);
480848b8605Smrg            dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
481848b8605Smrg         }
482848b8605Smrg      }
483848b8605Smrg   }
484848b8605Smrg   else if (datatype == GL_HALF_FLOAT_ARB && comps == 1) {
485848b8605Smrg      GLuint i, j, k;
486848b8605Smrg      const GLhalfARB *rowA = (const GLhalfARB *) srcRowA;
487848b8605Smrg      const GLhalfARB *rowB = (const GLhalfARB *) srcRowB;
488848b8605Smrg      GLhalfARB *dst = (GLhalfARB *) dstRow;
489848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
490848b8605Smrg           i++, j += colStride, k += colStride) {
491848b8605Smrg         GLfloat aj, ak, bj, bk;
492848b8605Smrg         aj = _mesa_half_to_float(rowA[j]);
493848b8605Smrg         ak = _mesa_half_to_float(rowA[k]);
494848b8605Smrg         bj = _mesa_half_to_float(rowB[j]);
495848b8605Smrg         bk = _mesa_half_to_float(rowB[k]);
496848b8605Smrg         dst[i] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
497848b8605Smrg      }
498848b8605Smrg   }
499848b8605Smrg
500848b8605Smrg   else if (datatype == GL_UNSIGNED_INT && comps == 1) {
501848b8605Smrg      GLuint i, j, k;
502848b8605Smrg      const GLuint *rowA = (const GLuint *) srcRowA;
503848b8605Smrg      const GLuint *rowB = (const GLuint *) srcRowB;
504848b8605Smrg      GLuint *dst = (GLuint *) dstRow;
505848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
506848b8605Smrg           i++, j += colStride, k += colStride) {
507848b8605Smrg         dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
508848b8605Smrg      }
509848b8605Smrg   }
510848b8605Smrg
511848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT_5_6_5 && comps == 3) {
512848b8605Smrg      GLuint i, j, k;
513848b8605Smrg      const GLushort *rowA = (const GLushort *) srcRowA;
514848b8605Smrg      const GLushort *rowB = (const GLushort *) srcRowB;
515848b8605Smrg      GLushort *dst = (GLushort *) dstRow;
516848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
517848b8605Smrg           i++, j += colStride, k += colStride) {
518848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x1f;
519848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x1f;
520848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x1f;
521848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x1f;
522848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
523848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
524848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
525848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
526848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
527848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
528848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
529848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
530848b8605Smrg         const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
531848b8605Smrg         const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
532848b8605Smrg         const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
533848b8605Smrg         dst[i] = (blue << 11) | (green << 5) | red;
534848b8605Smrg      }
535848b8605Smrg   }
536848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT_4_4_4_4 && comps == 4) {
537848b8605Smrg      GLuint i, j, k;
538848b8605Smrg      const GLushort *rowA = (const GLushort *) srcRowA;
539848b8605Smrg      const GLushort *rowB = (const GLushort *) srcRowB;
540848b8605Smrg      GLushort *dst = (GLushort *) dstRow;
541848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
542848b8605Smrg           i++, j += colStride, k += colStride) {
543848b8605Smrg         const GLint rowAr0 = rowA[j] & 0xf;
544848b8605Smrg         const GLint rowAr1 = rowA[k] & 0xf;
545848b8605Smrg         const GLint rowBr0 = rowB[j] & 0xf;
546848b8605Smrg         const GLint rowBr1 = rowB[k] & 0xf;
547848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
548848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
549848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
550848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
551848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
552848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
553848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
554848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
555848b8605Smrg         const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
556848b8605Smrg         const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
557848b8605Smrg         const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
558848b8605Smrg         const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
559848b8605Smrg         const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
560848b8605Smrg         const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
561848b8605Smrg         const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
562848b8605Smrg         const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
563848b8605Smrg         dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
564848b8605Smrg      }
565848b8605Smrg   }
566848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT_1_5_5_5_REV && comps == 4) {
567848b8605Smrg      GLuint i, j, k;
568848b8605Smrg      const GLushort *rowA = (const GLushort *) srcRowA;
569848b8605Smrg      const GLushort *rowB = (const GLushort *) srcRowB;
570848b8605Smrg      GLushort *dst = (GLushort *) dstRow;
571848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
572848b8605Smrg           i++, j += colStride, k += colStride) {
573848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x1f;
574848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x1f;
575848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x1f;
576848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x1f;
577848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
578848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
579848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
580848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
581848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
582848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
583848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
584848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
585848b8605Smrg         const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
586848b8605Smrg         const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
587848b8605Smrg         const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
588848b8605Smrg         const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
589848b8605Smrg         const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
590848b8605Smrg         const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
591848b8605Smrg         const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
592848b8605Smrg         const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
593848b8605Smrg         dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
594848b8605Smrg      }
595848b8605Smrg   }
596848b8605Smrg   else if (datatype == GL_UNSIGNED_SHORT_5_5_5_1 && comps == 4) {
597848b8605Smrg      GLuint i, j, k;
598848b8605Smrg      const GLushort *rowA = (const GLushort *) srcRowA;
599848b8605Smrg      const GLushort *rowB = (const GLushort *) srcRowB;
600848b8605Smrg      GLushort *dst = (GLushort *) dstRow;
601848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
602848b8605Smrg           i++, j += colStride, k += colStride) {
603848b8605Smrg         const GLint rowAr0 = (rowA[j] >> 11) & 0x1f;
604848b8605Smrg         const GLint rowAr1 = (rowA[k] >> 11) & 0x1f;
605848b8605Smrg         const GLint rowBr0 = (rowB[j] >> 11) & 0x1f;
606848b8605Smrg         const GLint rowBr1 = (rowB[k] >> 11) & 0x1f;
607848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 6) & 0x1f;
608848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 6) & 0x1f;
609848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 6) & 0x1f;
610848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 6) & 0x1f;
611848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 1) & 0x1f;
612848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 1) & 0x1f;
613848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 1) & 0x1f;
614848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 1) & 0x1f;
615848b8605Smrg         const GLint rowAa0 = (rowA[j] & 0x1);
616848b8605Smrg         const GLint rowAa1 = (rowA[k] & 0x1);
617848b8605Smrg         const GLint rowBa0 = (rowB[j] & 0x1);
618848b8605Smrg         const GLint rowBa1 = (rowB[k] & 0x1);
619848b8605Smrg         const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
620848b8605Smrg         const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
621848b8605Smrg         const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
622848b8605Smrg         const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
623848b8605Smrg         dst[i] = (red << 11) | (green << 6) | (blue << 1) | alpha;
624848b8605Smrg      }
625848b8605Smrg   }
626848b8605Smrg
627848b8605Smrg   else if (datatype == GL_UNSIGNED_BYTE_3_3_2 && comps == 3) {
628848b8605Smrg      GLuint i, j, k;
629848b8605Smrg      const GLubyte *rowA = (const GLubyte *) srcRowA;
630848b8605Smrg      const GLubyte *rowB = (const GLubyte *) srcRowB;
631848b8605Smrg      GLubyte *dst = (GLubyte *) dstRow;
632848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
633848b8605Smrg           i++, j += colStride, k += colStride) {
634848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x3;
635848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x3;
636848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x3;
637848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x3;
638848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
639848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
640848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
641848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
642848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
643848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
644848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
645848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
646848b8605Smrg         const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
647848b8605Smrg         const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
648848b8605Smrg         const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
649848b8605Smrg         dst[i] = (blue << 5) | (green << 2) | red;
650848b8605Smrg      }
651848b8605Smrg   }
652848b8605Smrg
653848b8605Smrg   else if (datatype == MESA_UNSIGNED_BYTE_4_4 && comps == 2) {
654848b8605Smrg      GLuint i, j, k;
655848b8605Smrg      const GLubyte *rowA = (const GLubyte *) srcRowA;
656848b8605Smrg      const GLubyte *rowB = (const GLubyte *) srcRowB;
657848b8605Smrg      GLubyte *dst = (GLubyte *) dstRow;
658848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
659848b8605Smrg           i++, j += colStride, k += colStride) {
660848b8605Smrg         const GLint rowAr0 = rowA[j] & 0xf;
661848b8605Smrg         const GLint rowAr1 = rowA[k] & 0xf;
662848b8605Smrg         const GLint rowBr0 = rowB[j] & 0xf;
663848b8605Smrg         const GLint rowBr1 = rowB[k] & 0xf;
664848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
665848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
666848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
667848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
668848b8605Smrg         const GLint r = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
669848b8605Smrg         const GLint g = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
670848b8605Smrg         dst[i] = (g << 4) | r;
671848b8605Smrg      }
672848b8605Smrg   }
673848b8605Smrg
674848b8605Smrg   else if (datatype == GL_UNSIGNED_INT_2_10_10_10_REV && comps == 4) {
675848b8605Smrg      GLuint i, j, k;
676848b8605Smrg      const GLuint *rowA = (const GLuint *) srcRowA;
677848b8605Smrg      const GLuint *rowB = (const GLuint *) srcRowB;
678848b8605Smrg      GLuint *dst = (GLuint *) dstRow;
679848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
680848b8605Smrg           i++, j += colStride, k += colStride) {
681848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x3ff;
682848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x3ff;
683848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x3ff;
684848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x3ff;
685848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 10) & 0x3ff;
686848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 10) & 0x3ff;
687848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 10) & 0x3ff;
688848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 10) & 0x3ff;
689848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 20) & 0x3ff;
690848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 20) & 0x3ff;
691848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 20) & 0x3ff;
692848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 20) & 0x3ff;
693848b8605Smrg         const GLint rowAa0 = (rowA[j] >> 30) & 0x3;
694848b8605Smrg         const GLint rowAa1 = (rowA[k] >> 30) & 0x3;
695848b8605Smrg         const GLint rowBa0 = (rowB[j] >> 30) & 0x3;
696848b8605Smrg         const GLint rowBa1 = (rowB[k] >> 30) & 0x3;
697848b8605Smrg         const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
698848b8605Smrg         const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
699848b8605Smrg         const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
700848b8605Smrg         const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
701848b8605Smrg         dst[i] = (alpha << 30) | (blue << 20) | (green << 10) | red;
702848b8605Smrg      }
703848b8605Smrg   }
704848b8605Smrg
705848b8605Smrg   else if (datatype == GL_UNSIGNED_INT_5_9_9_9_REV && comps == 3) {
706848b8605Smrg      GLuint i, j, k;
707848b8605Smrg      const GLuint *rowA = (const GLuint*) srcRowA;
708848b8605Smrg      const GLuint *rowB = (const GLuint*) srcRowB;
709848b8605Smrg      GLuint *dst = (GLuint*)dstRow;
710848b8605Smrg      GLfloat res[3], rowAj[3], rowBj[3], rowAk[3], rowBk[3];
711848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
712848b8605Smrg           i++, j += colStride, k += colStride) {
713848b8605Smrg         rgb9e5_to_float3(rowA[j], rowAj);
714848b8605Smrg         rgb9e5_to_float3(rowB[j], rowBj);
715848b8605Smrg         rgb9e5_to_float3(rowA[k], rowAk);
716848b8605Smrg         rgb9e5_to_float3(rowB[k], rowBk);
717848b8605Smrg         res[0] = (rowAj[0] + rowAk[0] + rowBj[0] + rowBk[0]) * 0.25F;
718848b8605Smrg         res[1] = (rowAj[1] + rowAk[1] + rowBj[1] + rowBk[1]) * 0.25F;
719848b8605Smrg         res[2] = (rowAj[2] + rowAk[2] + rowBj[2] + rowBk[2]) * 0.25F;
720848b8605Smrg         dst[i] = float3_to_rgb9e5(res);
721848b8605Smrg      }
722848b8605Smrg   }
723848b8605Smrg
724848b8605Smrg   else if (datatype == GL_UNSIGNED_INT_10F_11F_11F_REV && comps == 3) {
725848b8605Smrg      GLuint i, j, k;
726848b8605Smrg      const GLuint *rowA = (const GLuint*) srcRowA;
727848b8605Smrg      const GLuint *rowB = (const GLuint*) srcRowB;
728848b8605Smrg      GLuint *dst = (GLuint*)dstRow;
729848b8605Smrg      GLfloat res[3], rowAj[3], rowBj[3], rowAk[3], rowBk[3];
730848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
731848b8605Smrg           i++, j += colStride, k += colStride) {
732848b8605Smrg         r11g11b10f_to_float3(rowA[j], rowAj);
733848b8605Smrg         r11g11b10f_to_float3(rowB[j], rowBj);
734848b8605Smrg         r11g11b10f_to_float3(rowA[k], rowAk);
735848b8605Smrg         r11g11b10f_to_float3(rowB[k], rowBk);
736848b8605Smrg         res[0] = (rowAj[0] + rowAk[0] + rowBj[0] + rowBk[0]) * 0.25F;
737848b8605Smrg         res[1] = (rowAj[1] + rowAk[1] + rowBj[1] + rowBk[1]) * 0.25F;
738848b8605Smrg         res[2] = (rowAj[2] + rowAk[2] + rowBj[2] + rowBk[2]) * 0.25F;
739848b8605Smrg         dst[i] = float3_to_r11g11b10f(res);
740848b8605Smrg      }
741848b8605Smrg   }
742848b8605Smrg
743848b8605Smrg   else if (datatype == GL_FLOAT_32_UNSIGNED_INT_24_8_REV && comps == 1) {
744848b8605Smrg      GLuint i, j, k;
745848b8605Smrg      const GLfloat *rowA = (const GLfloat *) srcRowA;
746848b8605Smrg      const GLfloat *rowB = (const GLfloat *) srcRowB;
747848b8605Smrg      GLfloat *dst = (GLfloat *) dstRow;
748848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
749848b8605Smrg           i++, j += colStride, k += colStride) {
750848b8605Smrg         dst[i*2] = (rowA[j*2] + rowA[k*2] + rowB[j*2] + rowB[k*2]) * 0.25F;
751848b8605Smrg      }
752848b8605Smrg   }
753848b8605Smrg
754848b8605Smrg   else if (datatype == GL_UNSIGNED_INT_24_8_MESA && comps == 2) {
755848b8605Smrg      GLuint i, j, k;
756848b8605Smrg      const GLuint *rowA = (const GLuint *) srcRowA;
757848b8605Smrg      const GLuint *rowB = (const GLuint *) srcRowB;
758848b8605Smrg      GLuint *dst = (GLuint *) dstRow;
759848b8605Smrg      /* note: averaging stencil values seems weird, but what else? */
760848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
761848b8605Smrg           i++, j += colStride, k += colStride) {
762848b8605Smrg         GLuint z = (((rowA[j] >> 8) + (rowA[k] >> 8) +
763848b8605Smrg                      (rowB[j] >> 8) + (rowB[k] >> 8)) / 4) << 8;
764848b8605Smrg         GLuint s = ((rowA[j] & 0xff) + (rowA[k] & 0xff) +
765848b8605Smrg                     (rowB[j] & 0xff) + (rowB[k] & 0xff)) / 4;
766848b8605Smrg         dst[i] = z | s;
767848b8605Smrg      }
768848b8605Smrg   }
769848b8605Smrg   else if (datatype == GL_UNSIGNED_INT_8_24_REV_MESA && comps == 2) {
770848b8605Smrg      GLuint i, j, k;
771848b8605Smrg      const GLuint *rowA = (const GLuint *) srcRowA;
772848b8605Smrg      const GLuint *rowB = (const GLuint *) srcRowB;
773848b8605Smrg      GLuint *dst = (GLuint *) dstRow;
774848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
775848b8605Smrg           i++, j += colStride, k += colStride) {
776848b8605Smrg         GLuint z = ((rowA[j] & 0xffffff) + (rowA[k] & 0xffffff) +
777848b8605Smrg                     (rowB[j] & 0xffffff) + (rowB[k] & 0xffffff)) / 4;
778848b8605Smrg         GLuint s = (((rowA[j] >> 24) + (rowA[k] >> 24) +
779848b8605Smrg                      (rowB[j] >> 24) + (rowB[k] >> 24)) / 4) << 24;
780848b8605Smrg         dst[i] = z | s;
781848b8605Smrg      }
782848b8605Smrg   }
783848b8605Smrg
784848b8605Smrg   else {
785b8e80941Smrg      unreachable("bad format in do_row()");
786848b8605Smrg   }
787848b8605Smrg}
788848b8605Smrg
789848b8605Smrg
790848b8605Smrg/**
791848b8605Smrg * Average together four rows of a source image to produce a single new
792848b8605Smrg * row in the dest image.  It's legal for the two source rows to point
793848b8605Smrg * to the same data.  The source width must be equal to either the
794848b8605Smrg * dest width or two times the dest width.
795848b8605Smrg *
796848b8605Smrg * \param datatype  GL pixel type \c GL_UNSIGNED_BYTE, \c GL_UNSIGNED_SHORT,
797848b8605Smrg *                  \c GL_FLOAT, etc.
798848b8605Smrg * \param comps     number of components per pixel (1..4)
799848b8605Smrg * \param srcWidth  Width of a row in the source data
800848b8605Smrg * \param srcRowA   Pointer to one of the rows of source data
801848b8605Smrg * \param srcRowB   Pointer to one of the rows of source data
802848b8605Smrg * \param srcRowC   Pointer to one of the rows of source data
803848b8605Smrg * \param srcRowD   Pointer to one of the rows of source data
804848b8605Smrg * \param dstWidth  Width of a row in the destination data
805848b8605Smrg * \param srcRowA   Pointer to the row of destination data
806848b8605Smrg */
807848b8605Smrgstatic void
808848b8605Smrgdo_row_3D(GLenum datatype, GLuint comps, GLint srcWidth,
809848b8605Smrg          const GLvoid *srcRowA, const GLvoid *srcRowB,
810848b8605Smrg          const GLvoid *srcRowC, const GLvoid *srcRowD,
811848b8605Smrg          GLint dstWidth, GLvoid *dstRow)
812848b8605Smrg{
813848b8605Smrg   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
814848b8605Smrg   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
815848b8605Smrg   GLuint i, j, k;
816848b8605Smrg
817b8e80941Smrg   assert(comps >= 1);
818b8e80941Smrg   assert(comps <= 4);
819848b8605Smrg
820848b8605Smrg   if ((datatype == GL_UNSIGNED_BYTE) && (comps == 4)) {
821848b8605Smrg      DECLARE_ROW_POINTERS(GLubyte, 4);
822848b8605Smrg
823848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
824848b8605Smrg           i++, j += colStride, k += colStride) {
825848b8605Smrg         FILTER_3D(0);
826848b8605Smrg         FILTER_3D(1);
827848b8605Smrg         FILTER_3D(2);
828848b8605Smrg         FILTER_3D(3);
829848b8605Smrg      }
830848b8605Smrg   }
831848b8605Smrg   else if ((datatype == GL_UNSIGNED_BYTE) && (comps == 3)) {
832848b8605Smrg      DECLARE_ROW_POINTERS(GLubyte, 3);
833848b8605Smrg
834848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
835848b8605Smrg           i++, j += colStride, k += colStride) {
836848b8605Smrg         FILTER_3D(0);
837848b8605Smrg         FILTER_3D(1);
838848b8605Smrg         FILTER_3D(2);
839848b8605Smrg      }
840848b8605Smrg   }
841848b8605Smrg   else if ((datatype == GL_UNSIGNED_BYTE) && (comps == 2)) {
842848b8605Smrg      DECLARE_ROW_POINTERS(GLubyte, 2);
843848b8605Smrg
844848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
845848b8605Smrg           i++, j += colStride, k += colStride) {
846848b8605Smrg         FILTER_3D(0);
847848b8605Smrg         FILTER_3D(1);
848848b8605Smrg      }
849848b8605Smrg   }
850848b8605Smrg   else if ((datatype == GL_UNSIGNED_BYTE) && (comps == 1)) {
851848b8605Smrg      DECLARE_ROW_POINTERS(GLubyte, 1);
852848b8605Smrg
853848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
854848b8605Smrg           i++, j += colStride, k += colStride) {
855848b8605Smrg         FILTER_3D(0);
856848b8605Smrg      }
857848b8605Smrg   }
858848b8605Smrg   else if ((datatype == GL_BYTE) && (comps == 4)) {
859848b8605Smrg      DECLARE_ROW_POINTERS(GLbyte, 4);
860848b8605Smrg
861848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
862848b8605Smrg           i++, j += colStride, k += colStride) {
863848b8605Smrg         FILTER_3D_SIGNED(0);
864848b8605Smrg         FILTER_3D_SIGNED(1);
865848b8605Smrg         FILTER_3D_SIGNED(2);
866848b8605Smrg         FILTER_3D_SIGNED(3);
867848b8605Smrg      }
868848b8605Smrg   }
869848b8605Smrg   else if ((datatype == GL_BYTE) && (comps == 3)) {
870848b8605Smrg      DECLARE_ROW_POINTERS(GLbyte, 3);
871848b8605Smrg
872848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
873848b8605Smrg           i++, j += colStride, k += colStride) {
874848b8605Smrg         FILTER_3D_SIGNED(0);
875848b8605Smrg         FILTER_3D_SIGNED(1);
876848b8605Smrg         FILTER_3D_SIGNED(2);
877848b8605Smrg      }
878848b8605Smrg   }
879848b8605Smrg   else if ((datatype == GL_BYTE) && (comps == 2)) {
880848b8605Smrg      DECLARE_ROW_POINTERS(GLbyte, 2);
881848b8605Smrg
882848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
883848b8605Smrg           i++, j += colStride, k += colStride) {
884848b8605Smrg         FILTER_3D_SIGNED(0);
885848b8605Smrg         FILTER_3D_SIGNED(1);
886848b8605Smrg       }
887848b8605Smrg   }
888848b8605Smrg   else if ((datatype == GL_BYTE) && (comps == 1)) {
889848b8605Smrg      DECLARE_ROW_POINTERS(GLbyte, 1);
890848b8605Smrg
891848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
892848b8605Smrg           i++, j += colStride, k += colStride) {
893848b8605Smrg         FILTER_3D_SIGNED(0);
894848b8605Smrg      }
895848b8605Smrg   }
896848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT) && (comps == 4)) {
897848b8605Smrg      DECLARE_ROW_POINTERS(GLushort, 4);
898848b8605Smrg
899848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
900848b8605Smrg           i++, j += colStride, k += colStride) {
901848b8605Smrg         FILTER_3D(0);
902848b8605Smrg         FILTER_3D(1);
903848b8605Smrg         FILTER_3D(2);
904848b8605Smrg         FILTER_3D(3);
905848b8605Smrg      }
906848b8605Smrg   }
907848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT) && (comps == 3)) {
908848b8605Smrg      DECLARE_ROW_POINTERS(GLushort, 3);
909848b8605Smrg
910848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
911848b8605Smrg           i++, j += colStride, k += colStride) {
912848b8605Smrg         FILTER_3D(0);
913848b8605Smrg         FILTER_3D(1);
914848b8605Smrg         FILTER_3D(2);
915848b8605Smrg      }
916848b8605Smrg   }
917848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT) && (comps == 2)) {
918848b8605Smrg      DECLARE_ROW_POINTERS(GLushort, 2);
919848b8605Smrg
920848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
921848b8605Smrg           i++, j += colStride, k += colStride) {
922848b8605Smrg         FILTER_3D(0);
923848b8605Smrg         FILTER_3D(1);
924848b8605Smrg      }
925848b8605Smrg   }
926848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT) && (comps == 1)) {
927848b8605Smrg      DECLARE_ROW_POINTERS(GLushort, 1);
928848b8605Smrg
929848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
930848b8605Smrg           i++, j += colStride, k += colStride) {
931848b8605Smrg         FILTER_3D(0);
932848b8605Smrg      }
933848b8605Smrg   }
934848b8605Smrg   else if ((datatype == GL_SHORT) && (comps == 4)) {
935848b8605Smrg      DECLARE_ROW_POINTERS(GLshort, 4);
936848b8605Smrg
937848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
938848b8605Smrg           i++, j += colStride, k += colStride) {
939848b8605Smrg         FILTER_3D(0);
940848b8605Smrg         FILTER_3D(1);
941848b8605Smrg         FILTER_3D(2);
942848b8605Smrg         FILTER_3D(3);
943848b8605Smrg      }
944848b8605Smrg   }
945848b8605Smrg   else if ((datatype == GL_SHORT) && (comps == 3)) {
946848b8605Smrg      DECLARE_ROW_POINTERS(GLshort, 3);
947848b8605Smrg
948848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
949848b8605Smrg           i++, j += colStride, k += colStride) {
950848b8605Smrg         FILTER_3D(0);
951848b8605Smrg         FILTER_3D(1);
952848b8605Smrg         FILTER_3D(2);
953848b8605Smrg      }
954848b8605Smrg   }
955848b8605Smrg   else if ((datatype == GL_SHORT) && (comps == 2)) {
956848b8605Smrg      DECLARE_ROW_POINTERS(GLshort, 2);
957848b8605Smrg
958848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
959848b8605Smrg           i++, j += colStride, k += colStride) {
960848b8605Smrg         FILTER_3D(0);
961848b8605Smrg         FILTER_3D(1);
962848b8605Smrg      }
963848b8605Smrg   }
964848b8605Smrg   else if ((datatype == GL_SHORT) && (comps == 1)) {
965848b8605Smrg      DECLARE_ROW_POINTERS(GLshort, 1);
966848b8605Smrg
967848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
968848b8605Smrg           i++, j += colStride, k += colStride) {
969848b8605Smrg         FILTER_3D(0);
970848b8605Smrg      }
971848b8605Smrg   }
972848b8605Smrg   else if ((datatype == GL_FLOAT) && (comps == 4)) {
973848b8605Smrg      DECLARE_ROW_POINTERS(GLfloat, 4);
974848b8605Smrg
975848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
976848b8605Smrg           i++, j += colStride, k += colStride) {
977848b8605Smrg         FILTER_F_3D(0);
978848b8605Smrg         FILTER_F_3D(1);
979848b8605Smrg         FILTER_F_3D(2);
980848b8605Smrg         FILTER_F_3D(3);
981848b8605Smrg      }
982848b8605Smrg   }
983848b8605Smrg   else if ((datatype == GL_FLOAT) && (comps == 3)) {
984848b8605Smrg      DECLARE_ROW_POINTERS(GLfloat, 3);
985848b8605Smrg
986848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
987848b8605Smrg           i++, j += colStride, k += colStride) {
988848b8605Smrg         FILTER_F_3D(0);
989848b8605Smrg         FILTER_F_3D(1);
990848b8605Smrg         FILTER_F_3D(2);
991848b8605Smrg      }
992848b8605Smrg   }
993848b8605Smrg   else if ((datatype == GL_FLOAT) && (comps == 2)) {
994848b8605Smrg      DECLARE_ROW_POINTERS(GLfloat, 2);
995848b8605Smrg
996848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
997848b8605Smrg           i++, j += colStride, k += colStride) {
998848b8605Smrg         FILTER_F_3D(0);
999848b8605Smrg         FILTER_F_3D(1);
1000848b8605Smrg      }
1001848b8605Smrg   }
1002848b8605Smrg   else if ((datatype == GL_FLOAT) && (comps == 1)) {
1003848b8605Smrg      DECLARE_ROW_POINTERS(GLfloat, 1);
1004848b8605Smrg
1005848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1006848b8605Smrg           i++, j += colStride, k += colStride) {
1007848b8605Smrg         FILTER_F_3D(0);
1008848b8605Smrg      }
1009848b8605Smrg   }
1010848b8605Smrg   else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 4)) {
1011848b8605Smrg      DECLARE_ROW_POINTERS(GLhalfARB, 4);
1012848b8605Smrg
1013848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1014848b8605Smrg           i++, j += colStride, k += colStride) {
1015848b8605Smrg         FILTER_HF_3D(0);
1016848b8605Smrg         FILTER_HF_3D(1);
1017848b8605Smrg         FILTER_HF_3D(2);
1018848b8605Smrg         FILTER_HF_3D(3);
1019848b8605Smrg      }
1020848b8605Smrg   }
1021848b8605Smrg   else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 3)) {
1022848b8605Smrg      DECLARE_ROW_POINTERS(GLhalfARB, 3);
1023848b8605Smrg
1024848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1025848b8605Smrg           i++, j += colStride, k += colStride) {
1026848b8605Smrg         FILTER_HF_3D(0);
1027848b8605Smrg         FILTER_HF_3D(1);
1028848b8605Smrg         FILTER_HF_3D(2);
1029848b8605Smrg      }
1030848b8605Smrg   }
1031848b8605Smrg   else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 2)) {
1032848b8605Smrg      DECLARE_ROW_POINTERS(GLhalfARB, 2);
1033848b8605Smrg
1034848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1035848b8605Smrg           i++, j += colStride, k += colStride) {
1036848b8605Smrg         FILTER_HF_3D(0);
1037848b8605Smrg         FILTER_HF_3D(1);
1038848b8605Smrg      }
1039848b8605Smrg   }
1040848b8605Smrg   else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 1)) {
1041848b8605Smrg      DECLARE_ROW_POINTERS(GLhalfARB, 1);
1042848b8605Smrg
1043848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1044848b8605Smrg           i++, j += colStride, k += colStride) {
1045848b8605Smrg         FILTER_HF_3D(0);
1046848b8605Smrg      }
1047848b8605Smrg   }
1048848b8605Smrg   else if ((datatype == GL_UNSIGNED_INT) && (comps == 1)) {
1049848b8605Smrg      const GLuint *rowA = (const GLuint *) srcRowA;
1050848b8605Smrg      const GLuint *rowB = (const GLuint *) srcRowB;
1051848b8605Smrg      const GLuint *rowC = (const GLuint *) srcRowC;
1052848b8605Smrg      const GLuint *rowD = (const GLuint *) srcRowD;
1053848b8605Smrg      GLfloat *dst = (GLfloat *) dstRow;
1054848b8605Smrg
1055848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1056848b8605Smrg           i++, j += colStride, k += colStride) {
1057848b8605Smrg         const uint64_t tmp = (((uint64_t) rowA[j] + (uint64_t) rowA[k])
1058848b8605Smrg                               + ((uint64_t) rowB[j] + (uint64_t) rowB[k])
1059848b8605Smrg                               + ((uint64_t) rowC[j] + (uint64_t) rowC[k])
1060848b8605Smrg                               + ((uint64_t) rowD[j] + (uint64_t) rowD[k]));
1061848b8605Smrg         dst[i] = (GLfloat)((double) tmp * 0.125);
1062848b8605Smrg      }
1063848b8605Smrg   }
1064848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT_5_6_5) && (comps == 3)) {
1065848b8605Smrg      DECLARE_ROW_POINTERS0(GLushort);
1066848b8605Smrg
1067848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1068848b8605Smrg           i++, j += colStride, k += colStride) {
1069848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x1f;
1070848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x1f;
1071848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x1f;
1072848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x1f;
1073848b8605Smrg         const GLint rowCr0 = rowC[j] & 0x1f;
1074848b8605Smrg         const GLint rowCr1 = rowC[k] & 0x1f;
1075848b8605Smrg         const GLint rowDr0 = rowD[j] & 0x1f;
1076848b8605Smrg         const GLint rowDr1 = rowD[k] & 0x1f;
1077848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
1078848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
1079848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
1080848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
1081848b8605Smrg         const GLint rowCg0 = (rowC[j] >> 5) & 0x3f;
1082848b8605Smrg         const GLint rowCg1 = (rowC[k] >> 5) & 0x3f;
1083848b8605Smrg         const GLint rowDg0 = (rowD[j] >> 5) & 0x3f;
1084848b8605Smrg         const GLint rowDg1 = (rowD[k] >> 5) & 0x3f;
1085848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
1086848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
1087848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
1088848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
1089848b8605Smrg         const GLint rowCb0 = (rowC[j] >> 11) & 0x1f;
1090848b8605Smrg         const GLint rowCb1 = (rowC[k] >> 11) & 0x1f;
1091848b8605Smrg         const GLint rowDb0 = (rowD[j] >> 11) & 0x1f;
1092848b8605Smrg         const GLint rowDb1 = (rowD[k] >> 11) & 0x1f;
1093848b8605Smrg         const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
1094848b8605Smrg                                       rowCr0, rowCr1, rowDr0, rowDr1);
1095848b8605Smrg         const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
1096848b8605Smrg                                       rowCg0, rowCg1, rowDg0, rowDg1);
1097848b8605Smrg         const GLint b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
1098848b8605Smrg                                       rowCb0, rowCb1, rowDb0, rowDb1);
1099848b8605Smrg         dst[i] = (b << 11) | (g << 5) | r;
1100848b8605Smrg      }
1101848b8605Smrg   }
1102848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT_4_4_4_4) && (comps == 4)) {
1103848b8605Smrg      DECLARE_ROW_POINTERS0(GLushort);
1104848b8605Smrg
1105848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1106848b8605Smrg           i++, j += colStride, k += colStride) {
1107848b8605Smrg         const GLint rowAr0 = rowA[j] & 0xf;
1108848b8605Smrg         const GLint rowAr1 = rowA[k] & 0xf;
1109848b8605Smrg         const GLint rowBr0 = rowB[j] & 0xf;
1110848b8605Smrg         const GLint rowBr1 = rowB[k] & 0xf;
1111848b8605Smrg         const GLint rowCr0 = rowC[j] & 0xf;
1112848b8605Smrg         const GLint rowCr1 = rowC[k] & 0xf;
1113848b8605Smrg         const GLint rowDr0 = rowD[j] & 0xf;
1114848b8605Smrg         const GLint rowDr1 = rowD[k] & 0xf;
1115848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
1116848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
1117848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
1118848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
1119848b8605Smrg         const GLint rowCg0 = (rowC[j] >> 4) & 0xf;
1120848b8605Smrg         const GLint rowCg1 = (rowC[k] >> 4) & 0xf;
1121848b8605Smrg         const GLint rowDg0 = (rowD[j] >> 4) & 0xf;
1122848b8605Smrg         const GLint rowDg1 = (rowD[k] >> 4) & 0xf;
1123848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
1124848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
1125848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
1126848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
1127848b8605Smrg         const GLint rowCb0 = (rowC[j] >> 8) & 0xf;
1128848b8605Smrg         const GLint rowCb1 = (rowC[k] >> 8) & 0xf;
1129848b8605Smrg         const GLint rowDb0 = (rowD[j] >> 8) & 0xf;
1130848b8605Smrg         const GLint rowDb1 = (rowD[k] >> 8) & 0xf;
1131848b8605Smrg         const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
1132848b8605Smrg         const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
1133848b8605Smrg         const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
1134848b8605Smrg         const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
1135848b8605Smrg         const GLint rowCa0 = (rowC[j] >> 12) & 0xf;
1136848b8605Smrg         const GLint rowCa1 = (rowC[k] >> 12) & 0xf;
1137848b8605Smrg         const GLint rowDa0 = (rowD[j] >> 12) & 0xf;
1138848b8605Smrg         const GLint rowDa1 = (rowD[k] >> 12) & 0xf;
1139848b8605Smrg         const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
1140848b8605Smrg                                       rowCr0, rowCr1, rowDr0, rowDr1);
1141848b8605Smrg         const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
1142848b8605Smrg                                       rowCg0, rowCg1, rowDg0, rowDg1);
1143848b8605Smrg         const GLint b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
1144848b8605Smrg                                       rowCb0, rowCb1, rowDb0, rowDb1);
1145848b8605Smrg         const GLint a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
1146848b8605Smrg                                       rowCa0, rowCa1, rowDa0, rowDa1);
1147848b8605Smrg
1148848b8605Smrg         dst[i] = (a << 12) | (b << 8) | (g << 4) | r;
1149848b8605Smrg      }
1150848b8605Smrg   }
1151848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT_1_5_5_5_REV) && (comps == 4)) {
1152848b8605Smrg      DECLARE_ROW_POINTERS0(GLushort);
1153848b8605Smrg
1154848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1155848b8605Smrg           i++, j += colStride, k += colStride) {
1156848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x1f;
1157848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x1f;
1158848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x1f;
1159848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x1f;
1160848b8605Smrg         const GLint rowCr0 = rowC[j] & 0x1f;
1161848b8605Smrg         const GLint rowCr1 = rowC[k] & 0x1f;
1162848b8605Smrg         const GLint rowDr0 = rowD[j] & 0x1f;
1163848b8605Smrg         const GLint rowDr1 = rowD[k] & 0x1f;
1164848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
1165848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
1166848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
1167848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
1168848b8605Smrg         const GLint rowCg0 = (rowC[j] >> 5) & 0x1f;
1169848b8605Smrg         const GLint rowCg1 = (rowC[k] >> 5) & 0x1f;
1170848b8605Smrg         const GLint rowDg0 = (rowD[j] >> 5) & 0x1f;
1171848b8605Smrg         const GLint rowDg1 = (rowD[k] >> 5) & 0x1f;
1172848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
1173848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
1174848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
1175848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
1176848b8605Smrg         const GLint rowCb0 = (rowC[j] >> 10) & 0x1f;
1177848b8605Smrg         const GLint rowCb1 = (rowC[k] >> 10) & 0x1f;
1178848b8605Smrg         const GLint rowDb0 = (rowD[j] >> 10) & 0x1f;
1179848b8605Smrg         const GLint rowDb1 = (rowD[k] >> 10) & 0x1f;
1180848b8605Smrg         const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
1181848b8605Smrg         const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
1182848b8605Smrg         const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
1183848b8605Smrg         const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
1184848b8605Smrg         const GLint rowCa0 = (rowC[j] >> 15) & 0x1;
1185848b8605Smrg         const GLint rowCa1 = (rowC[k] >> 15) & 0x1;
1186848b8605Smrg         const GLint rowDa0 = (rowD[j] >> 15) & 0x1;
1187848b8605Smrg         const GLint rowDa1 = (rowD[k] >> 15) & 0x1;
1188848b8605Smrg         const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
1189848b8605Smrg                                       rowCr0, rowCr1, rowDr0, rowDr1);
1190848b8605Smrg         const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
1191848b8605Smrg                                       rowCg0, rowCg1, rowDg0, rowDg1);
1192848b8605Smrg         const GLint b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
1193848b8605Smrg                                       rowCb0, rowCb1, rowDb0, rowDb1);
1194848b8605Smrg         const GLint a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
1195848b8605Smrg                                       rowCa0, rowCa1, rowDa0, rowDa1);
1196848b8605Smrg
1197848b8605Smrg         dst[i] = (a << 15) | (b << 10) | (g << 5) | r;
1198848b8605Smrg      }
1199848b8605Smrg   }
1200848b8605Smrg   else if ((datatype == GL_UNSIGNED_SHORT_5_5_5_1) && (comps == 4)) {
1201848b8605Smrg      DECLARE_ROW_POINTERS0(GLushort);
1202848b8605Smrg
1203848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1204848b8605Smrg           i++, j += colStride, k += colStride) {
1205848b8605Smrg         const GLint rowAr0 = (rowA[j] >> 11) & 0x1f;
1206848b8605Smrg         const GLint rowAr1 = (rowA[k] >> 11) & 0x1f;
1207848b8605Smrg         const GLint rowBr0 = (rowB[j] >> 11) & 0x1f;
1208848b8605Smrg         const GLint rowBr1 = (rowB[k] >> 11) & 0x1f;
1209848b8605Smrg         const GLint rowCr0 = (rowC[j] >> 11) & 0x1f;
1210848b8605Smrg         const GLint rowCr1 = (rowC[k] >> 11) & 0x1f;
1211848b8605Smrg         const GLint rowDr0 = (rowD[j] >> 11) & 0x1f;
1212848b8605Smrg         const GLint rowDr1 = (rowD[k] >> 11) & 0x1f;
1213848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 6) & 0x1f;
1214848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 6) & 0x1f;
1215848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 6) & 0x1f;
1216848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 6) & 0x1f;
1217848b8605Smrg         const GLint rowCg0 = (rowC[j] >> 6) & 0x1f;
1218848b8605Smrg         const GLint rowCg1 = (rowC[k] >> 6) & 0x1f;
1219848b8605Smrg         const GLint rowDg0 = (rowD[j] >> 6) & 0x1f;
1220848b8605Smrg         const GLint rowDg1 = (rowD[k] >> 6) & 0x1f;
1221848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 1) & 0x1f;
1222848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 1) & 0x1f;
1223848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 1) & 0x1f;
1224848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 1) & 0x1f;
1225848b8605Smrg         const GLint rowCb0 = (rowC[j] >> 1) & 0x1f;
1226848b8605Smrg         const GLint rowCb1 = (rowC[k] >> 1) & 0x1f;
1227848b8605Smrg         const GLint rowDb0 = (rowD[j] >> 1) & 0x1f;
1228848b8605Smrg         const GLint rowDb1 = (rowD[k] >> 1) & 0x1f;
1229848b8605Smrg         const GLint rowAa0 = (rowA[j] & 0x1);
1230848b8605Smrg         const GLint rowAa1 = (rowA[k] & 0x1);
1231848b8605Smrg         const GLint rowBa0 = (rowB[j] & 0x1);
1232848b8605Smrg         const GLint rowBa1 = (rowB[k] & 0x1);
1233848b8605Smrg         const GLint rowCa0 = (rowC[j] & 0x1);
1234848b8605Smrg         const GLint rowCa1 = (rowC[k] & 0x1);
1235848b8605Smrg         const GLint rowDa0 = (rowD[j] & 0x1);
1236848b8605Smrg         const GLint rowDa1 = (rowD[k] & 0x1);
1237848b8605Smrg         const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
1238848b8605Smrg                                       rowCr0, rowCr1, rowDr0, rowDr1);
1239848b8605Smrg         const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
1240848b8605Smrg                                       rowCg0, rowCg1, rowDg0, rowDg1);
1241848b8605Smrg         const GLint b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
1242848b8605Smrg                                       rowCb0, rowCb1, rowDb0, rowDb1);
1243848b8605Smrg         const GLint a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
1244848b8605Smrg                                       rowCa0, rowCa1, rowDa0, rowDa1);
1245848b8605Smrg
1246848b8605Smrg         dst[i] = (r << 11) | (g << 6) | (b << 1) | a;
1247848b8605Smrg      }
1248848b8605Smrg   }
1249848b8605Smrg   else if ((datatype == GL_UNSIGNED_BYTE_3_3_2) && (comps == 3)) {
1250848b8605Smrg      DECLARE_ROW_POINTERS0(GLubyte);
1251848b8605Smrg
1252848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1253848b8605Smrg           i++, j += colStride, k += colStride) {
1254848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x3;
1255848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x3;
1256848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x3;
1257848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x3;
1258848b8605Smrg         const GLint rowCr0 = rowC[j] & 0x3;
1259848b8605Smrg         const GLint rowCr1 = rowC[k] & 0x3;
1260848b8605Smrg         const GLint rowDr0 = rowD[j] & 0x3;
1261848b8605Smrg         const GLint rowDr1 = rowD[k] & 0x3;
1262848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
1263848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
1264848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
1265848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
1266848b8605Smrg         const GLint rowCg0 = (rowC[j] >> 2) & 0x7;
1267848b8605Smrg         const GLint rowCg1 = (rowC[k] >> 2) & 0x7;
1268848b8605Smrg         const GLint rowDg0 = (rowD[j] >> 2) & 0x7;
1269848b8605Smrg         const GLint rowDg1 = (rowD[k] >> 2) & 0x7;
1270848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
1271848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
1272848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
1273848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
1274848b8605Smrg         const GLint rowCb0 = (rowC[j] >> 5) & 0x7;
1275848b8605Smrg         const GLint rowCb1 = (rowC[k] >> 5) & 0x7;
1276848b8605Smrg         const GLint rowDb0 = (rowD[j] >> 5) & 0x7;
1277848b8605Smrg         const GLint rowDb1 = (rowD[k] >> 5) & 0x7;
1278848b8605Smrg         const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
1279848b8605Smrg                                       rowCr0, rowCr1, rowDr0, rowDr1);
1280848b8605Smrg         const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
1281848b8605Smrg                                       rowCg0, rowCg1, rowDg0, rowDg1);
1282848b8605Smrg         const GLint b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
1283848b8605Smrg                                       rowCb0, rowCb1, rowDb0, rowDb1);
1284848b8605Smrg         dst[i] = (b << 5) | (g << 2) | r;
1285848b8605Smrg      }
1286848b8605Smrg   }
1287848b8605Smrg   else if (datatype == MESA_UNSIGNED_BYTE_4_4 && comps == 2) {
1288848b8605Smrg      DECLARE_ROW_POINTERS0(GLubyte);
1289848b8605Smrg
1290848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1291848b8605Smrg           i++, j += colStride, k += colStride) {
1292848b8605Smrg         const GLint rowAr0 = rowA[j] & 0xf;
1293848b8605Smrg         const GLint rowAr1 = rowA[k] & 0xf;
1294848b8605Smrg         const GLint rowBr0 = rowB[j] & 0xf;
1295848b8605Smrg         const GLint rowBr1 = rowB[k] & 0xf;
1296848b8605Smrg         const GLint rowCr0 = rowC[j] & 0xf;
1297848b8605Smrg         const GLint rowCr1 = rowC[k] & 0xf;
1298848b8605Smrg         const GLint rowDr0 = rowD[j] & 0xf;
1299848b8605Smrg         const GLint rowDr1 = rowD[k] & 0xf;
1300848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
1301848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
1302848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
1303848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
1304848b8605Smrg         const GLint rowCg0 = (rowC[j] >> 4) & 0xf;
1305848b8605Smrg         const GLint rowCg1 = (rowC[k] >> 4) & 0xf;
1306848b8605Smrg         const GLint rowDg0 = (rowD[j] >> 4) & 0xf;
1307848b8605Smrg         const GLint rowDg1 = (rowD[k] >> 4) & 0xf;
1308848b8605Smrg         const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
1309848b8605Smrg                                       rowCr0, rowCr1, rowDr0, rowDr1);
1310848b8605Smrg         const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
1311848b8605Smrg                                       rowCg0, rowCg1, rowDg0, rowDg1);
1312848b8605Smrg         dst[i] = (g << 4) | r;
1313848b8605Smrg      }
1314848b8605Smrg   }
1315848b8605Smrg   else if ((datatype == GL_UNSIGNED_INT_2_10_10_10_REV) && (comps == 4)) {
1316848b8605Smrg      DECLARE_ROW_POINTERS0(GLuint);
1317848b8605Smrg
1318848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1319848b8605Smrg           i++, j += colStride, k += colStride) {
1320848b8605Smrg         const GLint rowAr0 = rowA[j] & 0x3ff;
1321848b8605Smrg         const GLint rowAr1 = rowA[k] & 0x3ff;
1322848b8605Smrg         const GLint rowBr0 = rowB[j] & 0x3ff;
1323848b8605Smrg         const GLint rowBr1 = rowB[k] & 0x3ff;
1324848b8605Smrg         const GLint rowCr0 = rowC[j] & 0x3ff;
1325848b8605Smrg         const GLint rowCr1 = rowC[k] & 0x3ff;
1326848b8605Smrg         const GLint rowDr0 = rowD[j] & 0x3ff;
1327848b8605Smrg         const GLint rowDr1 = rowD[k] & 0x3ff;
1328848b8605Smrg         const GLint rowAg0 = (rowA[j] >> 10) & 0x3ff;
1329848b8605Smrg         const GLint rowAg1 = (rowA[k] >> 10) & 0x3ff;
1330848b8605Smrg         const GLint rowBg0 = (rowB[j] >> 10) & 0x3ff;
1331848b8605Smrg         const GLint rowBg1 = (rowB[k] >> 10) & 0x3ff;
1332848b8605Smrg         const GLint rowCg0 = (rowC[j] >> 10) & 0x3ff;
1333848b8605Smrg         const GLint rowCg1 = (rowC[k] >> 10) & 0x3ff;
1334848b8605Smrg         const GLint rowDg0 = (rowD[j] >> 10) & 0x3ff;
1335848b8605Smrg         const GLint rowDg1 = (rowD[k] >> 10) & 0x3ff;
1336848b8605Smrg         const GLint rowAb0 = (rowA[j] >> 20) & 0x3ff;
1337848b8605Smrg         const GLint rowAb1 = (rowA[k] >> 20) & 0x3ff;
1338848b8605Smrg         const GLint rowBb0 = (rowB[j] >> 20) & 0x3ff;
1339848b8605Smrg         const GLint rowBb1 = (rowB[k] >> 20) & 0x3ff;
1340848b8605Smrg         const GLint rowCb0 = (rowC[j] >> 20) & 0x3ff;
1341848b8605Smrg         const GLint rowCb1 = (rowC[k] >> 20) & 0x3ff;
1342848b8605Smrg         const GLint rowDb0 = (rowD[j] >> 20) & 0x3ff;
1343848b8605Smrg         const GLint rowDb1 = (rowD[k] >> 20) & 0x3ff;
1344848b8605Smrg         const GLint rowAa0 = (rowA[j] >> 30) & 0x3;
1345848b8605Smrg         const GLint rowAa1 = (rowA[k] >> 30) & 0x3;
1346848b8605Smrg         const GLint rowBa0 = (rowB[j] >> 30) & 0x3;
1347848b8605Smrg         const GLint rowBa1 = (rowB[k] >> 30) & 0x3;
1348848b8605Smrg         const GLint rowCa0 = (rowC[j] >> 30) & 0x3;
1349848b8605Smrg         const GLint rowCa1 = (rowC[k] >> 30) & 0x3;
1350848b8605Smrg         const GLint rowDa0 = (rowD[j] >> 30) & 0x3;
1351848b8605Smrg         const GLint rowDa1 = (rowD[k] >> 30) & 0x3;
1352848b8605Smrg         const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
1353848b8605Smrg                                       rowCr0, rowCr1, rowDr0, rowDr1);
1354848b8605Smrg         const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
1355848b8605Smrg                                       rowCg0, rowCg1, rowDg0, rowDg1);
1356848b8605Smrg         const GLint b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
1357848b8605Smrg                                       rowCb0, rowCb1, rowDb0, rowDb1);
1358848b8605Smrg         const GLint a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
1359848b8605Smrg                                       rowCa0, rowCa1, rowDa0, rowDa1);
1360848b8605Smrg
1361848b8605Smrg         dst[i] = (a << 30) | (b << 20) | (g << 10) | r;
1362848b8605Smrg      }
1363848b8605Smrg   }
1364848b8605Smrg
1365848b8605Smrg   else if (datatype == GL_UNSIGNED_INT_5_9_9_9_REV && comps == 3) {
1366848b8605Smrg      DECLARE_ROW_POINTERS0(GLuint);
1367848b8605Smrg
1368848b8605Smrg      GLfloat res[3];
1369848b8605Smrg      GLfloat rowAj[3], rowBj[3], rowCj[3], rowDj[3];
1370848b8605Smrg      GLfloat rowAk[3], rowBk[3], rowCk[3], rowDk[3];
1371848b8605Smrg
1372848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1373848b8605Smrg           i++, j += colStride, k += colStride) {
1374848b8605Smrg         rgb9e5_to_float3(rowA[j], rowAj);
1375848b8605Smrg         rgb9e5_to_float3(rowB[j], rowBj);
1376848b8605Smrg         rgb9e5_to_float3(rowC[j], rowCj);
1377848b8605Smrg         rgb9e5_to_float3(rowD[j], rowDj);
1378848b8605Smrg         rgb9e5_to_float3(rowA[k], rowAk);
1379848b8605Smrg         rgb9e5_to_float3(rowB[k], rowBk);
1380848b8605Smrg         rgb9e5_to_float3(rowC[k], rowCk);
1381848b8605Smrg         rgb9e5_to_float3(rowD[k], rowDk);
1382848b8605Smrg         res[0] = (rowAj[0] + rowAk[0] + rowBj[0] + rowBk[0] +
1383848b8605Smrg                   rowCj[0] + rowCk[0] + rowDj[0] + rowDk[0]) * 0.125F;
1384848b8605Smrg         res[1] = (rowAj[1] + rowAk[1] + rowBj[1] + rowBk[1] +
1385848b8605Smrg                   rowCj[1] + rowCk[1] + rowDj[1] + rowDk[1]) * 0.125F;
1386848b8605Smrg         res[2] = (rowAj[2] + rowAk[2] + rowBj[2] + rowBk[2] +
1387848b8605Smrg                   rowCj[2] + rowCk[2] + rowDj[2] + rowDk[2]) * 0.125F;
1388848b8605Smrg         dst[i] = float3_to_rgb9e5(res);
1389848b8605Smrg      }
1390848b8605Smrg   }
1391848b8605Smrg
1392848b8605Smrg   else if (datatype == GL_UNSIGNED_INT_10F_11F_11F_REV && comps == 3) {
1393848b8605Smrg      DECLARE_ROW_POINTERS0(GLuint);
1394848b8605Smrg
1395848b8605Smrg      GLfloat res[3];
1396848b8605Smrg      GLfloat rowAj[3], rowBj[3], rowCj[3], rowDj[3];
1397848b8605Smrg      GLfloat rowAk[3], rowBk[3], rowCk[3], rowDk[3];
1398848b8605Smrg
1399848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1400848b8605Smrg           i++, j += colStride, k += colStride) {
1401848b8605Smrg         r11g11b10f_to_float3(rowA[j], rowAj);
1402848b8605Smrg         r11g11b10f_to_float3(rowB[j], rowBj);
1403848b8605Smrg         r11g11b10f_to_float3(rowC[j], rowCj);
1404848b8605Smrg         r11g11b10f_to_float3(rowD[j], rowDj);
1405848b8605Smrg         r11g11b10f_to_float3(rowA[k], rowAk);
1406848b8605Smrg         r11g11b10f_to_float3(rowB[k], rowBk);
1407848b8605Smrg         r11g11b10f_to_float3(rowC[k], rowCk);
1408848b8605Smrg         r11g11b10f_to_float3(rowD[k], rowDk);
1409848b8605Smrg         res[0] = (rowAj[0] + rowAk[0] + rowBj[0] + rowBk[0] +
1410848b8605Smrg                   rowCj[0] + rowCk[0] + rowDj[0] + rowDk[0]) * 0.125F;
1411848b8605Smrg         res[1] = (rowAj[1] + rowAk[1] + rowBj[1] + rowBk[1] +
1412848b8605Smrg                   rowCj[1] + rowCk[1] + rowDj[1] + rowDk[1]) * 0.125F;
1413848b8605Smrg         res[2] = (rowAj[2] + rowAk[2] + rowBj[2] + rowBk[2] +
1414848b8605Smrg                   rowCj[2] + rowCk[2] + rowDj[2] + rowDk[2]) * 0.125F;
1415848b8605Smrg         dst[i] = float3_to_r11g11b10f(res);
1416848b8605Smrg      }
1417848b8605Smrg   }
1418848b8605Smrg
1419848b8605Smrg   else if (datatype == GL_FLOAT_32_UNSIGNED_INT_24_8_REV && comps == 1) {
1420848b8605Smrg      DECLARE_ROW_POINTERS(GLfloat, 2);
1421848b8605Smrg
1422848b8605Smrg      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1423848b8605Smrg           i++, j += colStride, k += colStride) {
1424848b8605Smrg         FILTER_F_3D(0);
1425848b8605Smrg      }
1426848b8605Smrg   }
1427848b8605Smrg
1428848b8605Smrg   else {
1429b8e80941Smrg      unreachable("bad format in do_row()");
1430848b8605Smrg   }
1431848b8605Smrg}
1432848b8605Smrg
1433848b8605Smrg
1434848b8605Smrg/*
1435848b8605Smrg * These functions generate a 1/2-size mipmap image from a source image.
1436848b8605Smrg * Texture borders are handled by copying or averaging the source image's
1437848b8605Smrg * border texels, depending on the scale-down factor.
1438848b8605Smrg */
1439848b8605Smrg
1440848b8605Smrgstatic void
1441848b8605Smrgmake_1d_mipmap(GLenum datatype, GLuint comps, GLint border,
1442848b8605Smrg               GLint srcWidth, const GLubyte *srcPtr,
1443848b8605Smrg               GLint dstWidth, GLubyte *dstPtr)
1444848b8605Smrg{
1445848b8605Smrg   const GLint bpt = bytes_per_pixel(datatype, comps);
1446848b8605Smrg   const GLubyte *src;
1447848b8605Smrg   GLubyte *dst;
1448848b8605Smrg
1449848b8605Smrg   /* skip the border pixel, if any */
1450848b8605Smrg   src = srcPtr + border * bpt;
1451848b8605Smrg   dst = dstPtr + border * bpt;
1452848b8605Smrg
1453848b8605Smrg   /* we just duplicate the input row, kind of hack, saves code */
1454848b8605Smrg   do_row(datatype, comps, srcWidth - 2 * border, src, src,
1455848b8605Smrg          dstWidth - 2 * border, dst);
1456848b8605Smrg
1457848b8605Smrg   if (border) {
1458848b8605Smrg      /* copy left-most pixel from source */
1459848b8605Smrg      assert(dstPtr);
1460848b8605Smrg      assert(srcPtr);
1461848b8605Smrg      memcpy(dstPtr, srcPtr, bpt);
1462848b8605Smrg      /* copy right-most pixel from source */
1463848b8605Smrg      memcpy(dstPtr + (dstWidth - 1) * bpt,
1464848b8605Smrg             srcPtr + (srcWidth - 1) * bpt,
1465848b8605Smrg             bpt);
1466848b8605Smrg   }
1467848b8605Smrg}
1468848b8605Smrg
1469848b8605Smrg
1470848b8605Smrgstatic void
1471848b8605Smrgmake_2d_mipmap(GLenum datatype, GLuint comps, GLint border,
1472848b8605Smrg               GLint srcWidth, GLint srcHeight,
1473b8e80941Smrg               const GLubyte *srcPtr, GLint srcRowStride,
1474848b8605Smrg               GLint dstWidth, GLint dstHeight,
1475b8e80941Smrg               GLubyte *dstPtr, GLint dstRowStride)
1476848b8605Smrg{
1477848b8605Smrg   const GLint bpt = bytes_per_pixel(datatype, comps);
1478848b8605Smrg   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
1479848b8605Smrg   const GLint dstWidthNB = dstWidth - 2 * border;
1480848b8605Smrg   const GLint dstHeightNB = dstHeight - 2 * border;
1481848b8605Smrg   const GLubyte *srcA, *srcB;
1482848b8605Smrg   GLubyte *dst;
1483848b8605Smrg   GLint row, srcRowStep;
1484848b8605Smrg
1485848b8605Smrg   /* Compute src and dst pointers, skipping any border */
1486848b8605Smrg   srcA = srcPtr + border * ((srcWidth + 1) * bpt);
1487848b8605Smrg   if (srcHeight > 1 && srcHeight > dstHeight) {
1488848b8605Smrg      /* sample from two source rows */
1489848b8605Smrg      srcB = srcA + srcRowStride;
1490848b8605Smrg      srcRowStep = 2;
1491848b8605Smrg   }
1492848b8605Smrg   else {
1493848b8605Smrg      /* sample from one source row */
1494848b8605Smrg      srcB = srcA;
1495848b8605Smrg      srcRowStep = 1;
1496848b8605Smrg   }
1497848b8605Smrg
1498848b8605Smrg   dst = dstPtr + border * ((dstWidth + 1) * bpt);
1499848b8605Smrg
1500848b8605Smrg   for (row = 0; row < dstHeightNB; row++) {
1501848b8605Smrg      do_row(datatype, comps, srcWidthNB, srcA, srcB,
1502848b8605Smrg             dstWidthNB, dst);
1503848b8605Smrg      srcA += srcRowStep * srcRowStride;
1504848b8605Smrg      srcB += srcRowStep * srcRowStride;
1505848b8605Smrg      dst += dstRowStride;
1506848b8605Smrg   }
1507848b8605Smrg
1508848b8605Smrg   /* This is ugly but probably won't be used much */
1509848b8605Smrg   if (border > 0) {
1510848b8605Smrg      /* fill in dest border */
1511848b8605Smrg      /* lower-left border pixel */
1512848b8605Smrg      assert(dstPtr);
1513848b8605Smrg      assert(srcPtr);
1514848b8605Smrg      memcpy(dstPtr, srcPtr, bpt);
1515848b8605Smrg      /* lower-right border pixel */
1516848b8605Smrg      memcpy(dstPtr + (dstWidth - 1) * bpt,
1517848b8605Smrg             srcPtr + (srcWidth - 1) * bpt, bpt);
1518848b8605Smrg      /* upper-left border pixel */
1519848b8605Smrg      memcpy(dstPtr + dstWidth * (dstHeight - 1) * bpt,
1520848b8605Smrg             srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
1521848b8605Smrg      /* upper-right border pixel */
1522848b8605Smrg      memcpy(dstPtr + (dstWidth * dstHeight - 1) * bpt,
1523848b8605Smrg             srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
1524848b8605Smrg      /* lower border */
1525848b8605Smrg      do_row(datatype, comps, srcWidthNB,
1526848b8605Smrg             srcPtr + bpt,
1527848b8605Smrg             srcPtr + bpt,
1528848b8605Smrg             dstWidthNB, dstPtr + bpt);
1529848b8605Smrg      /* upper border */
1530848b8605Smrg      do_row(datatype, comps, srcWidthNB,
1531848b8605Smrg             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1532848b8605Smrg             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1533848b8605Smrg             dstWidthNB,
1534848b8605Smrg             dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
1535848b8605Smrg      /* left and right borders */
1536848b8605Smrg      if (srcHeight == dstHeight) {
1537848b8605Smrg         /* copy border pixel from src to dst */
1538848b8605Smrg         for (row = 1; row < srcHeight; row++) {
1539848b8605Smrg            memcpy(dstPtr + dstWidth * row * bpt,
1540848b8605Smrg                   srcPtr + srcWidth * row * bpt, bpt);
1541848b8605Smrg            memcpy(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
1542848b8605Smrg                   srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
1543848b8605Smrg         }
1544848b8605Smrg      }
1545848b8605Smrg      else {
1546848b8605Smrg         /* average two src pixels each dest pixel */
1547848b8605Smrg         for (row = 0; row < dstHeightNB; row += 2) {
1548848b8605Smrg            do_row(datatype, comps, 1,
1549848b8605Smrg                   srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
1550848b8605Smrg                   srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
1551848b8605Smrg                   1, dstPtr + (dstWidth * row + 1) * bpt);
1552848b8605Smrg            do_row(datatype, comps, 1,
1553848b8605Smrg                   srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
1554848b8605Smrg                   srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
1555848b8605Smrg                   1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
1556848b8605Smrg         }
1557848b8605Smrg      }
1558848b8605Smrg   }
1559848b8605Smrg}
1560848b8605Smrg
1561848b8605Smrg
1562848b8605Smrgstatic void
1563848b8605Smrgmake_3d_mipmap(GLenum datatype, GLuint comps, GLint border,
1564848b8605Smrg               GLint srcWidth, GLint srcHeight, GLint srcDepth,
1565848b8605Smrg               const GLubyte **srcPtr, GLint srcRowStride,
1566848b8605Smrg               GLint dstWidth, GLint dstHeight, GLint dstDepth,
1567848b8605Smrg               GLubyte **dstPtr, GLint dstRowStride)
1568848b8605Smrg{
1569848b8605Smrg   const GLint bpt = bytes_per_pixel(datatype, comps);
1570848b8605Smrg   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
1571848b8605Smrg   const GLint srcDepthNB = srcDepth - 2 * border;
1572848b8605Smrg   const GLint dstWidthNB = dstWidth - 2 * border;
1573848b8605Smrg   const GLint dstHeightNB = dstHeight - 2 * border;
1574848b8605Smrg   const GLint dstDepthNB = dstDepth - 2 * border;
1575848b8605Smrg   GLint img, row;
1576848b8605Smrg   GLint bytesPerSrcImage, bytesPerDstImage;
1577848b8605Smrg   GLint srcImageOffset, srcRowOffset;
1578848b8605Smrg
1579848b8605Smrg   (void) srcDepthNB; /* silence warnings */
1580848b8605Smrg
1581848b8605Smrg   bytesPerSrcImage = srcRowStride * srcHeight * bpt;
1582848b8605Smrg   bytesPerDstImage = dstRowStride * dstHeight * bpt;
1583848b8605Smrg
1584848b8605Smrg   /* Offset between adjacent src images to be averaged together */
1585848b8605Smrg   srcImageOffset = (srcDepth == dstDepth) ? 0 : 1;
1586848b8605Smrg
1587848b8605Smrg   /* Offset between adjacent src rows to be averaged together */
1588848b8605Smrg   srcRowOffset = (srcHeight == dstHeight) ? 0 : srcRowStride;
1589848b8605Smrg
1590848b8605Smrg   /*
1591848b8605Smrg    * Need to average together up to 8 src pixels for each dest pixel.
1592848b8605Smrg    * Break that down into 3 operations:
1593848b8605Smrg    *   1. take two rows from source image and average them together.
1594848b8605Smrg    *   2. take two rows from next source image and average them together.
1595848b8605Smrg    *   3. take the two averaged rows and average them for the final dst row.
1596848b8605Smrg    */
1597848b8605Smrg
1598848b8605Smrg   /*
1599848b8605Smrg   printf("mip3d %d x %d x %d  ->  %d x %d x %d\n",
1600848b8605Smrg          srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
1601848b8605Smrg   */
1602848b8605Smrg
1603848b8605Smrg   for (img = 0; img < dstDepthNB; img++) {
1604848b8605Smrg      /* first source image pointer, skipping border */
1605848b8605Smrg      const GLubyte *imgSrcA = srcPtr[img * 2 + border]
1606848b8605Smrg         + srcRowStride * border + bpt * border;
1607848b8605Smrg      /* second source image pointer, skipping border */
1608848b8605Smrg      const GLubyte *imgSrcB = srcPtr[img * 2 + srcImageOffset + border]
1609848b8605Smrg         + srcRowStride * border + bpt * border;
1610848b8605Smrg
1611848b8605Smrg      /* address of the dest image, skipping border */
1612848b8605Smrg      GLubyte *imgDst = dstPtr[img + border]
1613848b8605Smrg         + dstRowStride * border + bpt * border;
1614848b8605Smrg
1615848b8605Smrg      /* setup the four source row pointers and the dest row pointer */
1616848b8605Smrg      const GLubyte *srcImgARowA = imgSrcA;
1617848b8605Smrg      const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
1618848b8605Smrg      const GLubyte *srcImgBRowA = imgSrcB;
1619848b8605Smrg      const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
1620848b8605Smrg      GLubyte *dstImgRow = imgDst;
1621848b8605Smrg
1622848b8605Smrg      for (row = 0; row < dstHeightNB; row++) {
1623848b8605Smrg         do_row_3D(datatype, comps, srcWidthNB,
1624848b8605Smrg                   srcImgARowA, srcImgARowB,
1625848b8605Smrg                   srcImgBRowA, srcImgBRowB,
1626848b8605Smrg                   dstWidthNB, dstImgRow);
1627848b8605Smrg
1628848b8605Smrg         /* advance to next rows */
1629848b8605Smrg         srcImgARowA += srcRowStride + srcRowOffset;
1630848b8605Smrg         srcImgARowB += srcRowStride + srcRowOffset;
1631848b8605Smrg         srcImgBRowA += srcRowStride + srcRowOffset;
1632848b8605Smrg         srcImgBRowB += srcRowStride + srcRowOffset;
1633848b8605Smrg         dstImgRow += dstRowStride;
1634848b8605Smrg      }
1635848b8605Smrg   }
1636848b8605Smrg
1637848b8605Smrg
1638848b8605Smrg   /* Luckily we can leverage the make_2d_mipmap() function here! */
1639848b8605Smrg   if (border > 0) {
1640848b8605Smrg      /* do front border image */
1641848b8605Smrg      make_2d_mipmap(datatype, comps, 1,
1642848b8605Smrg                     srcWidth, srcHeight, srcPtr[0], srcRowStride,
1643848b8605Smrg                     dstWidth, dstHeight, dstPtr[0], dstRowStride);
1644848b8605Smrg      /* do back border image */
1645848b8605Smrg      make_2d_mipmap(datatype, comps, 1,
1646848b8605Smrg                     srcWidth, srcHeight, srcPtr[srcDepth - 1], srcRowStride,
1647848b8605Smrg                     dstWidth, dstHeight, dstPtr[dstDepth - 1], dstRowStride);
1648848b8605Smrg
1649848b8605Smrg      /* do four remaining border edges that span the image slices */
1650848b8605Smrg      if (srcDepth == dstDepth) {
1651848b8605Smrg         /* just copy border pixels from src to dst */
1652848b8605Smrg         for (img = 0; img < dstDepthNB; img++) {
1653848b8605Smrg            const GLubyte *src;
1654848b8605Smrg            GLubyte *dst;
1655848b8605Smrg
1656848b8605Smrg            /* do border along [img][row=0][col=0] */
1657848b8605Smrg            src = srcPtr[img * 2];
1658848b8605Smrg            dst = dstPtr[img];
1659848b8605Smrg            memcpy(dst, src, bpt);
1660848b8605Smrg
1661848b8605Smrg            /* do border along [img][row=dstHeight-1][col=0] */
1662848b8605Smrg            src = srcPtr[img * 2] + (srcHeight - 1) * srcRowStride;
1663848b8605Smrg            dst = dstPtr[img] + (dstHeight - 1) * dstRowStride;
1664848b8605Smrg            memcpy(dst, src, bpt);
1665848b8605Smrg
1666848b8605Smrg            /* do border along [img][row=0][col=dstWidth-1] */
1667848b8605Smrg            src = srcPtr[img * 2] + (srcWidth - 1) * bpt;
1668848b8605Smrg            dst = dstPtr[img] + (dstWidth - 1) * bpt;
1669848b8605Smrg            memcpy(dst, src, bpt);
1670848b8605Smrg
1671848b8605Smrg            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1672848b8605Smrg            src = srcPtr[img * 2] + (bytesPerSrcImage - bpt);
1673848b8605Smrg            dst = dstPtr[img] + (bytesPerDstImage - bpt);
1674848b8605Smrg            memcpy(dst, src, bpt);
1675848b8605Smrg         }
1676848b8605Smrg      }
1677848b8605Smrg      else {
1678848b8605Smrg         /* average border pixels from adjacent src image pairs */
1679b8e80941Smrg         assert(srcDepthNB == 2 * dstDepthNB);
1680848b8605Smrg         for (img = 0; img < dstDepthNB; img++) {
1681848b8605Smrg            const GLubyte *srcA, *srcB;
1682848b8605Smrg            GLubyte *dst;
1683848b8605Smrg
1684848b8605Smrg            /* do border along [img][row=0][col=0] */
1685848b8605Smrg            srcA = srcPtr[img * 2 + 0];
1686848b8605Smrg            srcB = srcPtr[img * 2 + srcImageOffset];
1687848b8605Smrg            dst = dstPtr[img];
1688848b8605Smrg            do_row(datatype, comps, 1, srcA, srcB, 1, dst);
1689848b8605Smrg
1690848b8605Smrg            /* do border along [img][row=dstHeight-1][col=0] */
1691848b8605Smrg            srcA = srcPtr[img * 2 + 0]
1692848b8605Smrg               + (srcHeight - 1) * srcRowStride;
1693848b8605Smrg            srcB = srcPtr[img * 2 + srcImageOffset]
1694848b8605Smrg               + (srcHeight - 1) * srcRowStride;
1695848b8605Smrg            dst = dstPtr[img] + (dstHeight - 1) * dstRowStride;
1696848b8605Smrg            do_row(datatype, comps, 1, srcA, srcB, 1, dst);
1697848b8605Smrg
1698848b8605Smrg            /* do border along [img][row=0][col=dstWidth-1] */
1699848b8605Smrg            srcA = srcPtr[img * 2 + 0] + (srcWidth - 1) * bpt;
1700848b8605Smrg            srcB = srcPtr[img * 2 + srcImageOffset] + (srcWidth - 1) * bpt;
1701848b8605Smrg            dst = dstPtr[img] + (dstWidth - 1) * bpt;
1702848b8605Smrg            do_row(datatype, comps, 1, srcA, srcB, 1, dst);
1703848b8605Smrg
1704848b8605Smrg            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1705848b8605Smrg            srcA = srcPtr[img * 2 + 0] + (bytesPerSrcImage - bpt);
1706848b8605Smrg            srcB = srcPtr[img * 2 + srcImageOffset] + (bytesPerSrcImage - bpt);
1707848b8605Smrg            dst = dstPtr[img] + (bytesPerDstImage - bpt);
1708848b8605Smrg            do_row(datatype, comps, 1, srcA, srcB, 1, dst);
1709848b8605Smrg         }
1710848b8605Smrg      }
1711848b8605Smrg   }
1712848b8605Smrg}
1713848b8605Smrg
1714848b8605Smrg
1715848b8605Smrg/**
1716848b8605Smrg * Down-sample a texture image to produce the next lower mipmap level.
1717848b8605Smrg * \param comps  components per texel (1, 2, 3 or 4)
1718848b8605Smrg * \param srcData  array[slice] of pointers to source image slices
1719848b8605Smrg * \param dstData  array[slice] of pointers to dest image slices
1720848b8605Smrg * \param srcRowStride  stride between source rows, in bytes
1721848b8605Smrg * \param dstRowStride  stride between destination rows, in bytes
1722848b8605Smrg */
1723848b8605Smrgvoid
1724848b8605Smrg_mesa_generate_mipmap_level(GLenum target,
1725848b8605Smrg                            GLenum datatype, GLuint comps,
1726848b8605Smrg                            GLint border,
1727848b8605Smrg                            GLint srcWidth, GLint srcHeight, GLint srcDepth,
1728848b8605Smrg                            const GLubyte **srcData,
1729848b8605Smrg                            GLint srcRowStride,
1730848b8605Smrg                            GLint dstWidth, GLint dstHeight, GLint dstDepth,
1731848b8605Smrg                            GLubyte **dstData,
1732848b8605Smrg                            GLint dstRowStride)
1733848b8605Smrg{
1734848b8605Smrg   int i;
1735848b8605Smrg
1736848b8605Smrg   switch (target) {
1737848b8605Smrg   case GL_TEXTURE_1D:
1738848b8605Smrg      make_1d_mipmap(datatype, comps, border,
1739848b8605Smrg                     srcWidth, srcData[0],
1740848b8605Smrg                     dstWidth, dstData[0]);
1741848b8605Smrg      break;
1742848b8605Smrg   case GL_TEXTURE_2D:
1743b8e80941Smrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1744b8e80941Smrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1745b8e80941Smrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1746b8e80941Smrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1747b8e80941Smrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1748b8e80941Smrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1749848b8605Smrg      make_2d_mipmap(datatype, comps, border,
1750848b8605Smrg                     srcWidth, srcHeight, srcData[0], srcRowStride,
1751848b8605Smrg                     dstWidth, dstHeight, dstData[0], dstRowStride);
1752848b8605Smrg      break;
1753848b8605Smrg   case GL_TEXTURE_3D:
1754848b8605Smrg      make_3d_mipmap(datatype, comps, border,
1755848b8605Smrg                     srcWidth, srcHeight, srcDepth,
1756848b8605Smrg                     srcData, srcRowStride,
1757848b8605Smrg                     dstWidth, dstHeight, dstDepth,
1758848b8605Smrg                     dstData, dstRowStride);
1759848b8605Smrg      break;
1760848b8605Smrg   case GL_TEXTURE_1D_ARRAY_EXT:
1761848b8605Smrg      assert(srcHeight == 1);
1762848b8605Smrg      assert(dstHeight == 1);
1763848b8605Smrg      for (i = 0; i < dstDepth; i++) {
1764b8e80941Smrg         make_1d_mipmap(datatype, comps, border,
1765b8e80941Smrg                        srcWidth, srcData[i],
1766b8e80941Smrg                        dstWidth, dstData[i]);
1767848b8605Smrg      }
1768848b8605Smrg      break;
1769848b8605Smrg   case GL_TEXTURE_2D_ARRAY_EXT:
1770848b8605Smrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
1771848b8605Smrg      for (i = 0; i < dstDepth; i++) {
1772b8e80941Smrg         make_2d_mipmap(datatype, comps, border,
1773b8e80941Smrg                        srcWidth, srcHeight, srcData[i], srcRowStride,
1774b8e80941Smrg                        dstWidth, dstHeight, dstData[i], dstRowStride);
1775848b8605Smrg      }
1776848b8605Smrg      break;
1777848b8605Smrg   case GL_TEXTURE_RECTANGLE_NV:
1778848b8605Smrg   case GL_TEXTURE_EXTERNAL_OES:
1779848b8605Smrg      /* no mipmaps, do nothing */
1780848b8605Smrg      break;
1781848b8605Smrg   default:
1782b8e80941Smrg      unreachable("bad tex target in _mesa_generate_mipmaps");
1783848b8605Smrg   }
1784848b8605Smrg}
1785848b8605Smrg
1786848b8605Smrg
1787848b8605Smrg/**
1788848b8605Smrg * compute next (level+1) image size
1789848b8605Smrg * \return GL_FALSE if no smaller size can be generated (eg. src is 1x1x1 size)
1790848b8605Smrg */
1791848b8605SmrgGLboolean
1792848b8605Smrg_mesa_next_mipmap_level_size(GLenum target, GLint border,
1793848b8605Smrg                       GLint srcWidth, GLint srcHeight, GLint srcDepth,
1794848b8605Smrg                       GLint *dstWidth, GLint *dstHeight, GLint *dstDepth)
1795848b8605Smrg{
1796848b8605Smrg   if (srcWidth - 2 * border > 1) {
1797848b8605Smrg      *dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1798848b8605Smrg   }
1799848b8605Smrg   else {
1800848b8605Smrg      *dstWidth = srcWidth; /* can't go smaller */
1801848b8605Smrg   }
1802848b8605Smrg
1803b8e80941Smrg   if ((srcHeight - 2 * border > 1) &&
1804b8e80941Smrg       target != GL_TEXTURE_1D_ARRAY_EXT &&
1805b8e80941Smrg       target != GL_PROXY_TEXTURE_1D_ARRAY_EXT) {
1806848b8605Smrg      *dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1807848b8605Smrg   }
1808848b8605Smrg   else {
1809848b8605Smrg      *dstHeight = srcHeight; /* can't go smaller */
1810848b8605Smrg   }
1811848b8605Smrg
1812848b8605Smrg   if ((srcDepth - 2 * border > 1) &&
1813b8e80941Smrg       target != GL_TEXTURE_2D_ARRAY_EXT &&
1814b8e80941Smrg       target != GL_PROXY_TEXTURE_2D_ARRAY_EXT &&
1815b8e80941Smrg       target != GL_TEXTURE_CUBE_MAP_ARRAY &&
1816b8e80941Smrg       target != GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) {
1817848b8605Smrg      *dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1818848b8605Smrg   }
1819848b8605Smrg   else {
1820848b8605Smrg      *dstDepth = srcDepth; /* can't go smaller */
1821848b8605Smrg   }
1822848b8605Smrg
1823848b8605Smrg   if (*dstWidth == srcWidth &&
1824848b8605Smrg       *dstHeight == srcHeight &&
1825848b8605Smrg       *dstDepth == srcDepth) {
1826848b8605Smrg      return GL_FALSE;
1827848b8605Smrg   }
1828848b8605Smrg   else {
1829848b8605Smrg      return GL_TRUE;
1830848b8605Smrg   }
1831848b8605Smrg}
1832848b8605Smrg
1833848b8605Smrg
1834848b8605Smrg/**
1835848b8605Smrg * Helper function for mipmap generation.
1836848b8605Smrg * Make sure the specified destination mipmap level is the right size/format
1837848b8605Smrg * for mipmap generation.  If not, (re) allocate it.
1838848b8605Smrg * \return GL_TRUE if successful, GL_FALSE if mipmap generation should stop
1839848b8605Smrg */
1840b8e80941Smrgstatic GLboolean
1841b8e80941Smrgprepare_mipmap_level(struct gl_context *ctx,
1842b8e80941Smrg                     struct gl_texture_object *texObj, GLuint level,
1843b8e80941Smrg                     GLsizei width, GLsizei height, GLsizei depth,
1844b8e80941Smrg                     GLsizei border, GLenum intFormat, mesa_format format)
1845848b8605Smrg{
1846848b8605Smrg   const GLuint numFaces = _mesa_num_tex_faces(texObj->Target);
1847848b8605Smrg   GLuint face;
1848848b8605Smrg
1849848b8605Smrg   if (texObj->Immutable) {
1850848b8605Smrg      /* The texture was created with glTexStorage() so the number/size of
1851848b8605Smrg       * mipmap levels is fixed and the storage for all images is already
1852848b8605Smrg       * allocated.
1853848b8605Smrg       */
1854848b8605Smrg      if (!texObj->Image[0][level]) {
1855848b8605Smrg         /* No more levels to create - we're done */
1856848b8605Smrg         return GL_FALSE;
1857848b8605Smrg      }
1858848b8605Smrg      else {
1859848b8605Smrg         /* Nothing to do - the texture memory must have already been
1860848b8605Smrg          * allocated to the right size so we're all set.
1861848b8605Smrg          */
1862848b8605Smrg         return GL_TRUE;
1863848b8605Smrg      }
1864848b8605Smrg   }
1865848b8605Smrg
1866848b8605Smrg   for (face = 0; face < numFaces; face++) {
1867848b8605Smrg      struct gl_texture_image *dstImage;
1868b8e80941Smrg      const GLenum target = _mesa_cube_face_target(texObj->Target, face);
1869848b8605Smrg
1870848b8605Smrg      dstImage = _mesa_get_tex_image(ctx, texObj, target, level);
1871848b8605Smrg      if (!dstImage) {
1872848b8605Smrg         /* out of memory */
1873848b8605Smrg         return GL_FALSE;
1874848b8605Smrg      }
1875848b8605Smrg
1876848b8605Smrg      if (dstImage->Width != width ||
1877848b8605Smrg          dstImage->Height != height ||
1878848b8605Smrg          dstImage->Depth != depth ||
1879848b8605Smrg          dstImage->Border != border ||
1880848b8605Smrg          dstImage->InternalFormat != intFormat ||
1881848b8605Smrg          dstImage->TexFormat != format) {
1882848b8605Smrg         /* need to (re)allocate image */
1883848b8605Smrg         ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
1884848b8605Smrg
1885848b8605Smrg         _mesa_init_teximage_fields(ctx, dstImage,
1886848b8605Smrg                                    width, height, depth,
1887848b8605Smrg                                    border, intFormat, format);
1888848b8605Smrg
1889848b8605Smrg         ctx->Driver.AllocTextureImageBuffer(ctx, dstImage);
1890848b8605Smrg
1891848b8605Smrg         /* in case the mipmap level is part of an FBO: */
1892848b8605Smrg         _mesa_update_fbo_texture(ctx, texObj, face, level);
1893848b8605Smrg
1894b8e80941Smrg         ctx->NewState |= _NEW_TEXTURE_OBJECT;
1895848b8605Smrg      }
1896848b8605Smrg   }
1897848b8605Smrg
1898848b8605Smrg   return GL_TRUE;
1899848b8605Smrg}
1900848b8605Smrg
1901848b8605Smrg
1902b8e80941Smrg/**
1903b8e80941Smrg * Prepare all mipmap levels beyond 'baseLevel' for mipmap generation.
1904b8e80941Smrg * When finished, all the gl_texture_image structures for the smaller
1905b8e80941Smrg * mipmap levels will be consistent with the base level (in terms of
1906b8e80941Smrg * dimensions, format, etc).
1907b8e80941Smrg */
1908b8e80941Smrgvoid
1909b8e80941Smrg_mesa_prepare_mipmap_levels(struct gl_context *ctx,
1910b8e80941Smrg                            struct gl_texture_object *texObj,
1911b8e80941Smrg                            unsigned baseLevel, unsigned maxLevel)
1912b8e80941Smrg{
1913b8e80941Smrg   const struct gl_texture_image *baseImage =
1914b8e80941Smrg      _mesa_select_tex_image(texObj, texObj->Target, baseLevel);
1915b8e80941Smrg   const GLint border = 0;
1916b8e80941Smrg   GLint width = baseImage->Width;
1917b8e80941Smrg   GLint height = baseImage->Height;
1918b8e80941Smrg   GLint depth = baseImage->Depth;
1919b8e80941Smrg   const GLenum intFormat = baseImage->InternalFormat;
1920b8e80941Smrg   const mesa_format texFormat = baseImage->TexFormat;
1921b8e80941Smrg   GLint newWidth, newHeight, newDepth;
1922b8e80941Smrg
1923b8e80941Smrg   /* Prepare baseLevel + 1, baseLevel + 2, ... */
1924b8e80941Smrg   for (unsigned level = baseLevel + 1; level <= maxLevel; level++) {
1925b8e80941Smrg      if (!_mesa_next_mipmap_level_size(texObj->Target, border,
1926b8e80941Smrg                                        width, height, depth,
1927b8e80941Smrg                                        &newWidth, &newHeight, &newDepth)) {
1928b8e80941Smrg         /* all done */
1929b8e80941Smrg         break;
1930b8e80941Smrg      }
1931b8e80941Smrg
1932b8e80941Smrg      if (!prepare_mipmap_level(ctx, texObj, level,
1933b8e80941Smrg                                newWidth, newHeight, newDepth,
1934b8e80941Smrg                                border, intFormat, texFormat)) {
1935b8e80941Smrg         break;
1936b8e80941Smrg      }
1937b8e80941Smrg
1938b8e80941Smrg      width = newWidth;
1939b8e80941Smrg      height = newHeight;
1940b8e80941Smrg      depth = newDepth;
1941b8e80941Smrg   }
1942b8e80941Smrg}
1943b8e80941Smrg
1944b8e80941Smrg
1945848b8605Smrgstatic void
1946848b8605Smrggenerate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
1947b8e80941Smrg                             struct gl_texture_object *texObj,
1948b8e80941Smrg                             const struct gl_texture_image *srcImage,
1949b8e80941Smrg                             GLuint maxLevel)
1950848b8605Smrg{
1951848b8605Smrg   GLuint level;
1952848b8605Smrg   GLenum datatype;
1953848b8605Smrg   GLuint comps;
1954848b8605Smrg
1955b8e80941Smrg   _mesa_uncompressed_format_to_type_and_comps(srcImage->TexFormat, &datatype, &comps);
1956848b8605Smrg
1957848b8605Smrg   for (level = texObj->BaseLevel; level < maxLevel; level++) {
1958848b8605Smrg      /* generate image[level+1] from image[level] */
1959848b8605Smrg      struct gl_texture_image *srcImage, *dstImage;
1960848b8605Smrg      GLint srcRowStride, dstRowStride;
1961848b8605Smrg      GLint srcWidth, srcHeight, srcDepth;
1962848b8605Smrg      GLint dstWidth, dstHeight, dstDepth;
1963848b8605Smrg      GLint border;
1964848b8605Smrg      GLint slice;
1965848b8605Smrg      GLubyte **srcMaps, **dstMaps;
1966848b8605Smrg      GLboolean success = GL_TRUE;
1967848b8605Smrg
1968848b8605Smrg      /* get src image parameters */
1969b8e80941Smrg      srcImage = _mesa_select_tex_image(texObj, target, level);
1970b8e80941Smrg      assert(srcImage);
1971848b8605Smrg      srcWidth = srcImage->Width;
1972848b8605Smrg      srcHeight = srcImage->Height;
1973848b8605Smrg      srcDepth = srcImage->Depth;
1974848b8605Smrg      border = srcImage->Border;
1975848b8605Smrg
1976848b8605Smrg      /* get dest gl_texture_image */
1977b8e80941Smrg      dstImage = _mesa_select_tex_image(texObj, target, level + 1);
1978848b8605Smrg      if (!dstImage) {
1979b8e80941Smrg         break;
1980848b8605Smrg      }
1981b8e80941Smrg      dstWidth = dstImage->Width;
1982b8e80941Smrg      dstHeight = dstImage->Height;
1983b8e80941Smrg      dstDepth = dstImage->Depth;
1984848b8605Smrg
1985848b8605Smrg      if (target == GL_TEXTURE_1D_ARRAY) {
1986b8e80941Smrg         srcDepth = srcHeight;
1987b8e80941Smrg         dstDepth = dstHeight;
1988b8e80941Smrg         srcHeight = 1;
1989b8e80941Smrg         dstHeight = 1;
1990848b8605Smrg      }
1991848b8605Smrg
1992848b8605Smrg      /* Map src texture image slices */
1993848b8605Smrg      srcMaps = calloc(srcDepth, sizeof(GLubyte *));
1994848b8605Smrg      if (srcMaps) {
1995848b8605Smrg         for (slice = 0; slice < srcDepth; slice++) {
1996848b8605Smrg            ctx->Driver.MapTextureImage(ctx, srcImage, slice,
1997848b8605Smrg                                        0, 0, srcWidth, srcHeight,
1998848b8605Smrg                                        GL_MAP_READ_BIT,
1999848b8605Smrg                                        &srcMaps[slice], &srcRowStride);
2000848b8605Smrg            if (!srcMaps[slice]) {
2001848b8605Smrg               success = GL_FALSE;
2002848b8605Smrg               break;
2003848b8605Smrg            }
2004848b8605Smrg         }
2005848b8605Smrg      }
2006848b8605Smrg      else {
2007848b8605Smrg         success = GL_FALSE;
2008848b8605Smrg      }
2009848b8605Smrg
2010848b8605Smrg      /* Map dst texture image slices */
2011848b8605Smrg      dstMaps = calloc(dstDepth, sizeof(GLubyte *));
2012848b8605Smrg      if (dstMaps) {
2013848b8605Smrg         for (slice = 0; slice < dstDepth; slice++) {
2014848b8605Smrg            ctx->Driver.MapTextureImage(ctx, dstImage, slice,
2015848b8605Smrg                                        0, 0, dstWidth, dstHeight,
2016848b8605Smrg                                        GL_MAP_WRITE_BIT,
2017848b8605Smrg                                        &dstMaps[slice], &dstRowStride);
2018848b8605Smrg            if (!dstMaps[slice]) {
2019848b8605Smrg               success = GL_FALSE;
2020848b8605Smrg               break;
2021848b8605Smrg            }
2022848b8605Smrg         }
2023848b8605Smrg      }
2024848b8605Smrg      else {
2025848b8605Smrg         success = GL_FALSE;
2026848b8605Smrg      }
2027848b8605Smrg
2028848b8605Smrg      if (success) {
2029848b8605Smrg         /* generate one mipmap level (for 1D/2D/3D/array/etc texture) */
2030848b8605Smrg         _mesa_generate_mipmap_level(target, datatype, comps, border,
2031848b8605Smrg                                     srcWidth, srcHeight, srcDepth,
2032848b8605Smrg                                     (const GLubyte **) srcMaps, srcRowStride,
2033848b8605Smrg                                     dstWidth, dstHeight, dstDepth,
2034848b8605Smrg                                     dstMaps, dstRowStride);
2035848b8605Smrg      }
2036848b8605Smrg
2037848b8605Smrg      /* Unmap src image slices */
2038848b8605Smrg      if (srcMaps) {
2039848b8605Smrg         for (slice = 0; slice < srcDepth; slice++) {
2040848b8605Smrg            if (srcMaps[slice]) {
2041848b8605Smrg               ctx->Driver.UnmapTextureImage(ctx, srcImage, slice);
2042848b8605Smrg            }
2043848b8605Smrg         }
2044848b8605Smrg         free(srcMaps);
2045848b8605Smrg      }
2046848b8605Smrg
2047848b8605Smrg      /* Unmap dst image slices */
2048848b8605Smrg      if (dstMaps) {
2049848b8605Smrg         for (slice = 0; slice < dstDepth; slice++) {
2050848b8605Smrg            if (dstMaps[slice]) {
2051848b8605Smrg               ctx->Driver.UnmapTextureImage(ctx, dstImage, slice);
2052848b8605Smrg            }
2053848b8605Smrg         }
2054848b8605Smrg         free(dstMaps);
2055848b8605Smrg      }
2056848b8605Smrg
2057848b8605Smrg      if (!success) {
2058848b8605Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "mipmap generation");
2059848b8605Smrg         break;
2060848b8605Smrg      }
2061848b8605Smrg   } /* loop over mipmap levels */
2062848b8605Smrg}
2063848b8605Smrg
2064848b8605Smrg
2065848b8605Smrgstatic void
2066848b8605Smrggenerate_mipmap_compressed(struct gl_context *ctx, GLenum target,
2067b8e80941Smrg                           struct gl_texture_object *texObj,
2068b8e80941Smrg                           struct gl_texture_image *srcImage,
2069b8e80941Smrg                           GLuint maxLevel)
2070848b8605Smrg{
2071848b8605Smrg   GLuint level;
2072848b8605Smrg   mesa_format temp_format;
2073848b8605Smrg   GLint components;
2074848b8605Smrg   GLuint temp_src_row_stride, temp_src_img_stride; /* in bytes */
2075848b8605Smrg   GLubyte *temp_src = NULL, *temp_dst = NULL;
2076848b8605Smrg   GLenum temp_datatype;
2077848b8605Smrg   GLenum temp_base_format;
2078848b8605Smrg   GLubyte **temp_src_slices = NULL, **temp_dst_slices = NULL;
2079848b8605Smrg
2080848b8605Smrg   /* only two types of compressed textures at this time */
2081848b8605Smrg   assert(texObj->Target == GL_TEXTURE_2D ||
2082b8e80941Smrg          texObj->Target == GL_TEXTURE_2D_ARRAY ||
2083b8e80941Smrg          texObj->Target == GL_TEXTURE_CUBE_MAP ||
2084848b8605Smrg          texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY);
2085848b8605Smrg
2086848b8605Smrg   /*
2087848b8605Smrg    * Choose a format for the temporary, uncompressed base image.
2088848b8605Smrg    * Then, get number of components, choose temporary image datatype,
2089848b8605Smrg    * and get base format.
2090848b8605Smrg    */
2091848b8605Smrg   temp_format = _mesa_get_uncompressed_format(srcImage->TexFormat);
2092848b8605Smrg
2093848b8605Smrg   components = _mesa_format_num_components(temp_format);
2094848b8605Smrg
2095848b8605Smrg   switch (_mesa_get_format_datatype(srcImage->TexFormat)) {
2096848b8605Smrg   case GL_FLOAT:
2097848b8605Smrg      temp_datatype = GL_FLOAT;
2098848b8605Smrg      break;
2099848b8605Smrg   case GL_SIGNED_NORMALIZED:
2100848b8605Smrg      /* Revisit this if we get compressed formats with >8 bits per component */
2101848b8605Smrg      temp_datatype = GL_BYTE;
2102848b8605Smrg      break;
2103848b8605Smrg   default:
2104848b8605Smrg      temp_datatype = GL_UNSIGNED_BYTE;
2105848b8605Smrg   }
2106848b8605Smrg
2107848b8605Smrg   temp_base_format = _mesa_get_format_base_format(temp_format);
2108848b8605Smrg
2109848b8605Smrg
2110848b8605Smrg   /* allocate storage for the temporary, uncompressed image */
2111848b8605Smrg   temp_src_row_stride = _mesa_format_row_stride(temp_format, srcImage->Width);
2112848b8605Smrg   temp_src_img_stride = _mesa_format_image_size(temp_format, srcImage->Width,
2113848b8605Smrg                                                 srcImage->Height, 1);
2114848b8605Smrg   temp_src = malloc(temp_src_img_stride * srcImage->Depth);
2115848b8605Smrg
2116848b8605Smrg   /* Allocate storage for arrays of slice pointers */
2117848b8605Smrg   temp_src_slices = malloc(srcImage->Depth * sizeof(GLubyte *));
2118848b8605Smrg   temp_dst_slices = malloc(srcImage->Depth * sizeof(GLubyte *));
2119848b8605Smrg
2120848b8605Smrg   if (!temp_src || !temp_src_slices || !temp_dst_slices) {
2121848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
2122848b8605Smrg      goto end;
2123848b8605Smrg   }
2124848b8605Smrg
2125848b8605Smrg   /* decompress base image to the temporary src buffer */
2126848b8605Smrg   {
2127848b8605Smrg      /* save pixel packing mode */
2128848b8605Smrg      struct gl_pixelstore_attrib save = ctx->Pack;
2129848b8605Smrg      /* use default/tight packing parameters */
2130848b8605Smrg      ctx->Pack = ctx->DefaultPacking;
2131848b8605Smrg
2132848b8605Smrg      /* Get the uncompressed image */
2133848b8605Smrg      assert(srcImage->Level == texObj->BaseLevel);
2134b8e80941Smrg      ctx->Driver.GetTexSubImage(ctx,
2135b8e80941Smrg                                 0, 0, 0,
2136b8e80941Smrg                                 srcImage->Width, srcImage->Height,
2137b8e80941Smrg                                 srcImage->Depth,
2138b8e80941Smrg                                 temp_base_format, temp_datatype,
2139b8e80941Smrg                                 temp_src, srcImage);
2140848b8605Smrg      /* restore packing mode */
2141848b8605Smrg      ctx->Pack = save;
2142848b8605Smrg   }
2143848b8605Smrg
2144848b8605Smrg   for (level = texObj->BaseLevel; level < maxLevel; level++) {
2145848b8605Smrg      /* generate image[level+1] from image[level] */
2146848b8605Smrg      const struct gl_texture_image *srcImage;
2147848b8605Smrg      struct gl_texture_image *dstImage;
2148848b8605Smrg      GLint srcWidth, srcHeight, srcDepth;
2149848b8605Smrg      GLint dstWidth, dstHeight, dstDepth;
2150848b8605Smrg      GLint border;
2151848b8605Smrg      GLuint temp_dst_row_stride, temp_dst_img_stride; /* in bytes */
2152b8e80941Smrg      GLint i;
2153848b8605Smrg
2154848b8605Smrg      /* get src image parameters */
2155b8e80941Smrg      srcImage = _mesa_select_tex_image(texObj, target, level);
2156b8e80941Smrg      assert(srcImage);
2157848b8605Smrg      srcWidth = srcImage->Width;
2158848b8605Smrg      srcHeight = srcImage->Height;
2159848b8605Smrg      srcDepth = srcImage->Depth;
2160848b8605Smrg      border = srcImage->Border;
2161848b8605Smrg
2162b8e80941Smrg      /* get dest gl_texture_image */
2163b8e80941Smrg      dstImage = _mesa_select_tex_image(texObj, target, level + 1);
2164b8e80941Smrg      if (!dstImage) {
2165b8e80941Smrg         break;
2166b8e80941Smrg      }
2167b8e80941Smrg      dstWidth = dstImage->Width;
2168b8e80941Smrg      dstHeight = dstImage->Height;
2169b8e80941Smrg      dstDepth = dstImage->Depth;
2170848b8605Smrg
2171848b8605Smrg      /* Compute dst image strides and alloc memory on first iteration */
2172848b8605Smrg      temp_dst_row_stride = _mesa_format_row_stride(temp_format, dstWidth);
2173848b8605Smrg      temp_dst_img_stride = _mesa_format_image_size(temp_format, dstWidth,
2174848b8605Smrg                                                    dstHeight, 1);
2175848b8605Smrg      if (!temp_dst) {
2176b8e80941Smrg         temp_dst = malloc(temp_dst_img_stride * dstDepth);
2177b8e80941Smrg         if (!temp_dst) {
2178b8e80941Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
2179848b8605Smrg            goto end;
2180b8e80941Smrg         }
2181848b8605Smrg      }
2182848b8605Smrg
2183848b8605Smrg      /* for 2D arrays, setup array[depth] of slice pointers */
2184848b8605Smrg      for (i = 0; i < srcDepth; i++) {
2185848b8605Smrg         temp_src_slices[i] = temp_src + temp_src_img_stride * i;
2186848b8605Smrg      }
2187848b8605Smrg      for (i = 0; i < dstDepth; i++) {
2188848b8605Smrg         temp_dst_slices[i] = temp_dst + temp_dst_img_stride * i;
2189848b8605Smrg      }
2190848b8605Smrg
2191848b8605Smrg      /* Rescale src image to dest image.
2192848b8605Smrg       * This will loop over the slices of a 2D array.
2193848b8605Smrg       */
2194848b8605Smrg      _mesa_generate_mipmap_level(target, temp_datatype, components, border,
2195848b8605Smrg                                  srcWidth, srcHeight, srcDepth,
2196848b8605Smrg                                  (const GLubyte **) temp_src_slices,
2197848b8605Smrg                                  temp_src_row_stride,
2198848b8605Smrg                                  dstWidth, dstHeight, dstDepth,
2199848b8605Smrg                                  temp_dst_slices, temp_dst_row_stride);
2200848b8605Smrg
2201848b8605Smrg      /* The image space was allocated above so use glTexSubImage now */
2202848b8605Smrg      ctx->Driver.TexSubImage(ctx, 2, dstImage,
2203848b8605Smrg                              0, 0, 0, dstWidth, dstHeight, dstDepth,
2204848b8605Smrg                              temp_base_format, temp_datatype,
2205848b8605Smrg                              temp_dst, &ctx->DefaultPacking);
2206848b8605Smrg
2207848b8605Smrg      /* swap src and dest pointers */
2208848b8605Smrg      {
2209b8e80941Smrg         GLubyte *temp = temp_src;
2210b8e80941Smrg         temp_src = temp_dst;
2211b8e80941Smrg         temp_dst = temp;
2212848b8605Smrg         temp_src_row_stride = temp_dst_row_stride;
2213848b8605Smrg         temp_src_img_stride = temp_dst_img_stride;
2214848b8605Smrg      }
2215848b8605Smrg   } /* loop over mipmap levels */
2216848b8605Smrg
2217848b8605Smrgend:
2218848b8605Smrg   free(temp_src);
2219848b8605Smrg   free(temp_dst);
2220848b8605Smrg   free(temp_src_slices);
2221848b8605Smrg   free(temp_dst_slices);
2222848b8605Smrg}
2223848b8605Smrg
2224848b8605Smrg/**
2225848b8605Smrg * Automatic mipmap generation.
2226848b8605Smrg * This is the fallback/default function for ctx->Driver.GenerateMipmap().
2227848b8605Smrg * Generate a complete set of mipmaps from texObj's BaseLevel image.
2228848b8605Smrg * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
2229848b8605Smrg * For cube maps, target will be one of
2230848b8605Smrg * GL_TEXTURE_CUBE_MAP_POSITIVE/NEGATIVE_X/Y/Z; never GL_TEXTURE_CUBE_MAP.
2231848b8605Smrg */
2232848b8605Smrgvoid
2233848b8605Smrg_mesa_generate_mipmap(struct gl_context *ctx, GLenum target,
2234848b8605Smrg                      struct gl_texture_object *texObj)
2235848b8605Smrg{
2236848b8605Smrg   struct gl_texture_image *srcImage;
2237848b8605Smrg   GLint maxLevel;
2238848b8605Smrg
2239b8e80941Smrg   assert(texObj);
2240b8e80941Smrg   srcImage = _mesa_select_tex_image(texObj, target, texObj->BaseLevel);
2241b8e80941Smrg   assert(srcImage);
2242848b8605Smrg
2243848b8605Smrg   maxLevel = _mesa_max_texture_levels(ctx, texObj->Target) - 1;
2244b8e80941Smrg   assert(maxLevel >= 0);  /* bad target */
2245848b8605Smrg
2246848b8605Smrg   maxLevel = MIN2(maxLevel, texObj->MaxLevel);
2247848b8605Smrg
2248b8e80941Smrg   _mesa_prepare_mipmap_levels(ctx, texObj, texObj->BaseLevel, maxLevel);
2249b8e80941Smrg
2250848b8605Smrg   if (_mesa_is_format_compressed(srcImage->TexFormat)) {
2251848b8605Smrg      generate_mipmap_compressed(ctx, target, texObj, srcImage, maxLevel);
2252848b8605Smrg   } else {
2253848b8605Smrg      generate_mipmap_uncompressed(ctx, target, texObj, srcImage, maxLevel);
2254848b8605Smrg   }
2255848b8605Smrg}
2256