OSDN Git Service

mesa: Use appropriate float/integer types.
[android-x86/external-mesa.git] / src / mesa / main / texgetimage.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.5
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  * Copyright (c) 2009 VMware, Inc.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26
27 /**
28  * Code for glGetTexImage() and glGetCompressedTexImage().
29  */
30
31
32 #include "glheader.h"
33 #include "context.h"
34 #include "image.h"
35 #include "texcompress.h"
36 #include "texformat.h"
37 #include "texgetimage.h"
38
39
40
41 #if FEATURE_EXT_texture_sRGB
42
43 /**
44  * Test if given texture image is an sRGB format.
45  */
46 static GLboolean
47 is_srgb_teximage(const struct gl_texture_image *texImage)
48 {
49    switch (texImage->TexFormat->MesaFormat) {
50    case MESA_FORMAT_SRGB8:
51    case MESA_FORMAT_SRGBA8:
52    case MESA_FORMAT_SARGB8:
53    case MESA_FORMAT_SL8:
54    case MESA_FORMAT_SLA8:
55    case MESA_FORMAT_SRGB_DXT1:
56    case MESA_FORMAT_SRGBA_DXT1:
57    case MESA_FORMAT_SRGBA_DXT3:
58    case MESA_FORMAT_SRGBA_DXT5:
59       return GL_TRUE;
60    default:
61       return GL_FALSE;
62    }
63 }
64
65
66 /**
67  * Convert a float value from linear space to a
68  * non-linear sRGB value in [0, 255].
69  * Not terribly efficient.
70  */
71 static INLINE GLfloat
72 linear_to_nonlinear(GLfloat cl)
73 {
74    /* can't have values outside [0, 1] */
75    GLfloat cs;
76    if (cl < 0.0031308f) {
77       cs = 12.92f * cl;
78    }
79    else {
80       cs = (GLfloat)(1.055 * _mesa_pow(cl, 0.41666) - 0.055);
81    }
82    return cs;
83 }
84
85 #endif /* FEATURE_EXT_texture_sRGB */
86
87
88 /**
89  * Can the given type represent negative values?
90  */
91 static INLINE GLboolean
92 type_with_negative_values(GLenum type)
93 {
94    switch (type) {
95    case GL_BYTE:
96    case GL_SHORT:
97    case GL_INT:
98    case GL_FLOAT:
99    case GL_HALF_FLOAT_ARB:
100       return GL_TRUE;
101    default:
102       return GL_FALSE;
103    }
104 }
105
106
107 /**
108  * This is the software fallback for Driver.GetTexImage().
109  * All error checking will have been done before this routine is called.
110  */
111 void
112 _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
113                    GLenum format, GLenum type, GLvoid *pixels,
114                    struct gl_texture_object *texObj,
115                    struct gl_texture_image *texImage)
116 {
117    const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
118
119    if (ctx->Pack.BufferObj->Name) {
120       /* Packing texture image into a PBO.
121        * Map the (potentially) VRAM-based buffer into our process space so
122        * we can write into it with the code below.
123        * A hardware driver might use a sophisticated blit to move the
124        * texture data to the PBO if the PBO is in VRAM along with the texture.
125        */
126       GLubyte *buf = (GLubyte *)
127          ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
128                                GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
129       if (!buf) {
130          /* buffer is already mapped - that's an error */
131          _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)");
132          return;
133       }
134       /* <pixels> was an offset into the PBO.
135        * Now make it a real, client-side pointer inside the mapped region.
136        */
137       pixels = ADD_POINTERS(buf, pixels);
138    }
139    else if (!pixels) {
140       /* not an error */
141       return;
142    }
143
144    {
145       const GLint width = texImage->Width;
146       const GLint height = texImage->Height;
147       const GLint depth = texImage->Depth;
148       GLint img, row;
149       for (img = 0; img < depth; img++) {
150          for (row = 0; row < height; row++) {
151             /* compute destination address in client memory */
152             GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels,
153                                                 width, height, format, type,
154                                                 img, row, 0);
155             assert(dest);
156
157             if (format == GL_COLOR_INDEX) {
158                GLuint indexRow[MAX_WIDTH];
159                GLint col;
160                /* Can't use FetchTexel here because that returns RGBA */
161                if (texImage->TexFormat->IndexBits == 8) {
162                   const GLubyte *src = (const GLubyte *) texImage->Data;
163                   src += width * (img * texImage->Height + row);
164                   for (col = 0; col < width; col++) {
165                      indexRow[col] = src[col];
166                   }
167                }
168                else if (texImage->TexFormat->IndexBits == 16) {
169                   const GLushort *src = (const GLushort *) texImage->Data;
170                   src += width * (img * texImage->Height + row);
171                   for (col = 0; col < width; col++) {
172                      indexRow[col] = src[col];
173                   }
174                }
175                else {
176                   _mesa_problem(ctx,
177                                 "Color index problem in _mesa_GetTexImage");
178                }
179                _mesa_pack_index_span(ctx, width, type, dest,
180                                      indexRow, &ctx->Pack,
181                                      0 /* no image transfer */);
182             }
183             else if (format == GL_DEPTH_COMPONENT) {
184                GLfloat depthRow[MAX_WIDTH];
185                GLint col;
186                for (col = 0; col < width; col++) {
187                   (*texImage->FetchTexelf)(texImage, col, row, img,
188                                            depthRow + col);
189                }
190                _mesa_pack_depth_span(ctx, width, dest, type,
191                                      depthRow, &ctx->Pack);
192             }
193             else if (format == GL_DEPTH_STENCIL_EXT) {
194                /* XXX Note: we're bypassing texImage->FetchTexel()! */
195                const GLuint *src = (const GLuint *) texImage->Data;
196                src += width * row + width * height * img;
197                _mesa_memcpy(dest, src, width * sizeof(GLuint));
198                if (ctx->Pack.SwapBytes) {
199                   _mesa_swap4((GLuint *) dest, width);
200                }
201             }
202             else if (format == GL_YCBCR_MESA) {
203                /* No pixel transfer */
204                const GLint rowstride = texImage->RowStride;
205                MEMCPY(dest,
206                       (const GLushort *) texImage->Data + row * rowstride,
207                       width * sizeof(GLushort));
208                /* check for byte swapping */
209                if ((texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR
210                     && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
211                    (texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV
212                     && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
213                   if (!ctx->Pack.SwapBytes)
214                      _mesa_swap2((GLushort *) dest, width);
215                }
216                else if (ctx->Pack.SwapBytes) {
217                   _mesa_swap2((GLushort *) dest, width);
218                }
219             }
220 #if FEATURE_EXT_texture_sRGB
221             else if (is_srgb_teximage(texImage)) {
222                /* special case this since need to backconvert values */
223                /* convert row to RGBA format */
224                GLfloat rgba[MAX_WIDTH][4];
225                GLint col;
226                GLbitfield transferOps = 0x0;
227
228                for (col = 0; col < width; col++) {
229                   (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]);
230                   if (texImage->_BaseFormat == GL_LUMINANCE) {
231                      rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
232                      rgba[col][GCOMP] = 0.0;
233                      rgba[col][BCOMP] = 0.0;
234                   }
235                   else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
236                      rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
237                      rgba[col][GCOMP] = 0.0;
238                      rgba[col][BCOMP] = 0.0;
239                   }
240                   else if (texImage->_BaseFormat == GL_RGB ||
241                      texImage->_BaseFormat == GL_RGBA) {
242                      rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
243                      rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
244                      rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
245                   }
246                }
247                _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
248                                           format, type, dest,
249                                           &ctx->Pack, transferOps);
250             }
251 #endif /* FEATURE_EXT_texture_sRGB */
252             else {
253                /* general case:  convert row to RGBA format */
254                GLfloat rgba[MAX_WIDTH][4];
255                GLint col;
256                GLbitfield transferOps = 0x0;
257
258                /* clamp does not apply to GetTexImage (final conversion)?
259                 * Looks like we need clamp though when going from format
260                 * containing negative values to unsigned format.
261                 */
262                if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA)
263                   transferOps |= IMAGE_CLAMP_BIT;
264                else if (!type_with_negative_values(type) &&
265                         (texImage->TexFormat->DataType == GL_FLOAT ||
266                          texImage->TexFormat->DataType == GL_SIGNED_NORMALIZED))
267                   transferOps |= IMAGE_CLAMP_BIT;
268
269                for (col = 0; col < width; col++) {
270                   (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]);
271                   if (texImage->_BaseFormat == GL_ALPHA) {
272                      rgba[col][RCOMP] = 0.0;
273                      rgba[col][GCOMP] = 0.0;
274                      rgba[col][BCOMP] = 0.0;
275                   }
276                   else if (texImage->_BaseFormat == GL_LUMINANCE) {
277                      rgba[col][GCOMP] = 0.0;
278                      rgba[col][BCOMP] = 0.0;
279                      rgba[col][ACOMP] = 1.0;
280                   }
281                   else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
282                      rgba[col][GCOMP] = 0.0;
283                      rgba[col][BCOMP] = 0.0;
284                   }
285                   else if (texImage->_BaseFormat == GL_INTENSITY) {
286                      rgba[col][GCOMP] = 0.0;
287                      rgba[col][BCOMP] = 0.0;
288                      rgba[col][ACOMP] = 1.0;
289                   }
290                }
291                _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
292                                           format, type, dest,
293                                           &ctx->Pack, transferOps);
294             } /* format */
295          } /* row */
296       } /* img */
297    }
298
299    if (ctx->Pack.BufferObj->Name) {
300       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
301                               ctx->Pack.BufferObj);
302    }
303 }
304
305
306
307 /**
308  * This is the software fallback for Driver.GetCompressedTexImage().
309  * All error checking will have been done before this routine is called.
310  */
311 void
312 _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
313                               GLvoid *img,
314                               struct gl_texture_object *texObj,
315                               struct gl_texture_image *texImage)
316 {
317    GLuint size;
318
319    if (ctx->Pack.BufferObj->Name) {
320       /* pack texture image into a PBO */
321       GLubyte *buf;
322       if ((const GLubyte *) img + texImage->CompressedSize >
323           (const GLubyte *) ctx->Pack.BufferObj->Size) {
324          _mesa_error(ctx, GL_INVALID_OPERATION,
325                      "glGetCompressedTexImage(invalid PBO access)");
326          return;
327       }
328       buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
329                                               GL_WRITE_ONLY_ARB,
330                                               ctx->Pack.BufferObj);
331       if (!buf) {
332          /* buffer is already mapped - that's an error */
333          _mesa_error(ctx, GL_INVALID_OPERATION,
334                      "glGetCompressedTexImage(PBO is mapped)");
335          return;
336       }
337       img = ADD_POINTERS(buf, img);
338    }
339    else if (!img) {
340       /* not an error */
341       return;
342    }
343
344    /* don't use texImage->CompressedSize since that may be padded out */
345    size = _mesa_compressed_texture_size(ctx, texImage->Width, texImage->Height,
346                                         texImage->Depth,
347                                         texImage->TexFormat->MesaFormat);
348
349    /* just memcpy, no pixelstore or pixel transfer */
350    _mesa_memcpy(img, texImage->Data, size);
351
352    if (ctx->Pack.BufferObj->Name) {
353       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
354                               ctx->Pack.BufferObj);
355    }
356 }