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