Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / main / texgetimage.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.7
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 "bufferobj.h"
34 #include "enums.h"
35 #include "context.h"
36 #include "formats.h"
37 #include "image.h"
38 #include "mfeatures.h"
39 #include "mtypes.h"
40 #include "pack.h"
41 #include "pbo.h"
42 #include "texgetimage.h"
43 #include "texfetch.h"
44 #include "teximage.h"
45
46
47
48 /**
49  * Can the given type represent negative values?
50  */
51 static INLINE GLboolean
52 type_with_negative_values(GLenum type)
53 {
54    switch (type) {
55    case GL_BYTE:
56    case GL_SHORT:
57    case GL_INT:
58    case GL_FLOAT:
59    case GL_HALF_FLOAT_ARB:
60       return GL_TRUE;
61    default:
62       return GL_FALSE;
63    }
64 }
65
66
67 /**
68  * glGetTexImage for color index pixels.
69  */
70 static void
71 get_tex_color_index(struct gl_context *ctx, GLuint dimensions,
72                     GLenum format, GLenum type, GLvoid *pixels,
73                     const struct gl_texture_image *texImage)
74 {
75    const GLint width = texImage->Width;
76    const GLint height = texImage->Height;
77    const GLint depth = texImage->Depth;
78    const GLint rowstride = texImage->RowStride;
79    const GLuint indexBits =
80       _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
81    const GLbitfield transferOps = 0x0;
82    GLint img, row, col;
83
84    for (img = 0; img < depth; img++) {
85       for (row = 0; row < height; row++) {
86          GLuint indexRow[MAX_WIDTH] = { 0 };
87          void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
88                                           width, height, format, type,
89                                           img, row, 0);
90          assert(dest);
91
92          if (indexBits == 8) {
93             const GLubyte *src = (const GLubyte *) texImage->Data;
94             src += rowstride * (img * height + row);
95             for (col = 0; col < width; col++) {
96                indexRow[col] = src[col];
97             }
98          }
99          else if (indexBits == 16) {
100             const GLushort *src = (const GLushort *) texImage->Data;
101             src += rowstride * (img * height + row);
102             for (col = 0; col < width; col++) {
103                indexRow[col] = src[col];
104             }
105          }
106          else {
107             _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage");
108          }
109          _mesa_pack_index_span(ctx, width, type, dest,
110                                indexRow, &ctx->Pack, transferOps);
111       }
112    }
113 }
114
115
116 /**
117  * glGetTexImage for depth/Z pixels.
118  */
119 static void
120 get_tex_depth(struct gl_context *ctx, GLuint dimensions,
121               GLenum format, GLenum type, GLvoid *pixels,
122               const struct gl_texture_image *texImage)
123 {
124    const GLint width = texImage->Width;
125    const GLint height = texImage->Height;
126    const GLint depth = texImage->Depth;
127    GLint img, row, col;
128    GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat));
129
130    if (!depthRow) {
131       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
132       return;
133    }
134
135    for (img = 0; img < depth; img++) {
136       for (row = 0; row < height; row++) {
137          void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
138                                           width, height, format, type,
139                                           img, row, 0);
140          assert(dest);
141
142          for (col = 0; col < width; col++) {
143             texImage->FetchTexelf(texImage, col, row, img, depthRow + col);
144          }
145          _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
146       }
147    }
148
149    free(depthRow);
150 }
151
152
153 /**
154  * glGetTexImage for depth/stencil pixels.
155  */
156 static void
157 get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
158                       GLenum format, GLenum type, GLvoid *pixels,
159                       const struct gl_texture_image *texImage)
160 {
161    const GLint width = texImage->Width;
162    const GLint height = texImage->Height;
163    const GLint depth = texImage->Depth;
164    const GLint rowstride = texImage->RowStride;
165    const GLuint *src = (const GLuint *) texImage->Data;
166    GLint img, row;
167
168    for (img = 0; img < depth; img++) {
169       for (row = 0; row < height; row++) {
170          void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
171                                           width, height, format, type,
172                                           img, row, 0);
173          memcpy(dest, src, width * sizeof(GLuint));
174          if (ctx->Pack.SwapBytes) {
175             _mesa_swap4((GLuint *) dest, width);
176          }
177
178          src += rowstride;
179       }
180    }
181 }
182
183
184 /**
185  * glGetTexImage for YCbCr pixels.
186  */
187 static void
188 get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
189               GLenum format, GLenum type, GLvoid *pixels,
190               const struct gl_texture_image *texImage)
191 {
192    const GLint width = texImage->Width;
193    const GLint height = texImage->Height;
194    const GLint depth = texImage->Depth;
195    const GLint rowstride = texImage->RowStride;
196    const GLushort *src = (const GLushort *) texImage->Data;
197    GLint img, row;
198
199    for (img = 0; img < depth; img++) {
200       for (row = 0; row < height; row++) {
201          void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
202                                           width, height, format, type,
203                                           img, row, 0);
204          memcpy(dest, src, width * sizeof(GLushort));
205
206          /* check for byte swapping */
207          if ((texImage->TexFormat == MESA_FORMAT_YCBCR
208               && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
209              (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
210               && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
211             if (!ctx->Pack.SwapBytes)
212                _mesa_swap2((GLushort *) dest, width);
213          }
214          else if (ctx->Pack.SwapBytes) {
215             _mesa_swap2((GLushort *) dest, width);
216          }
217
218          src += rowstride;
219       }
220    }
221 }
222
223
224 /**
225  * glGetTexImage for (s)RGBA, Luminance, etc. pixels.
226  * This is the slow way since we use texture sampling.
227  */
228 static void
229 get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
230              GLenum format, GLenum type, GLvoid *pixels,
231              struct gl_texture_image *texImage)
232 {
233    const GLint width = texImage->Width;
234    const GLint height = texImage->Height;
235    const GLint depth = texImage->Depth;
236    const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
237    /* Normally, no pixel transfer ops are performed during glGetTexImage.
238     * The only possible exception is component clamping to [0,1].
239     */
240    GLbitfield transferOps = 0x0;
241    GLint img, row;
242    GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
243    const GLboolean is_sampler_srgb_decode =
244        _mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB &&
245        texImage->TexObject->Sampler.sRGBDecode == GL_DECODE_EXT;
246
247    if (!rgba) {
248       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
249       return;
250    }
251
252    /* Clamping does not apply to GetTexImage (final conversion)?
253     * Looks like we need clamp though when going from format
254     * containing negative values to unsigned format.
255     */
256    if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) {
257       transferOps |= IMAGE_CLAMP_BIT;
258    }
259    else if (!type_with_negative_values(type) &&
260             (dataType == GL_FLOAT ||
261              dataType == GL_SIGNED_NORMALIZED)) {
262       transferOps |= IMAGE_CLAMP_BIT;
263    }
264
265    /* glGetTexImage always returns sRGB data for sRGB textures. Make sure the
266     * fetch functions return sRGB data without linearizing it.
267     */
268    if (is_sampler_srgb_decode) {
269       texImage->TexObject->Sampler.sRGBDecode = GL_SKIP_DECODE_EXT;
270       _mesa_set_fetch_functions(texImage, dimensions);
271    }
272
273    for (img = 0; img < depth; img++) {
274       for (row = 0; row < height; row++) {
275          void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
276                                           width, height, format, type,
277                                           img, row, 0);
278          GLint col;
279
280          for (col = 0; col < width; col++) {
281             texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
282             if (texImage->_BaseFormat == GL_ALPHA) {
283                rgba[col][RCOMP] = 0.0F;
284                rgba[col][GCOMP] = 0.0F;
285                rgba[col][BCOMP] = 0.0F;
286             }
287             else if (texImage->_BaseFormat == GL_LUMINANCE) {
288                rgba[col][GCOMP] = 0.0F;
289                rgba[col][BCOMP] = 0.0F;
290                rgba[col][ACOMP] = 1.0F;
291             }
292             else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
293                rgba[col][GCOMP] = 0.0F;
294                rgba[col][BCOMP] = 0.0F;
295             }
296             else if (texImage->_BaseFormat == GL_INTENSITY) {
297                rgba[col][GCOMP] = 0.0F;
298                rgba[col][BCOMP] = 0.0F;
299                rgba[col][ACOMP] = 1.0F;
300             }
301          }
302          _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
303                                     format, type, dest,
304                                     &ctx->Pack, transferOps);
305       }
306    }
307
308    if (is_sampler_srgb_decode) {
309       texImage->TexObject->Sampler.sRGBDecode = GL_DECODE_EXT;
310       _mesa_set_fetch_functions(texImage, dimensions);
311    }
312
313    free(rgba);
314 }
315
316
317 /**
318  * Try to do glGetTexImage() with simple memcpy().
319  * \return GL_TRUE if done, GL_FALSE otherwise
320  */
321 static GLboolean
322 get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels,
323                const struct gl_texture_object *texObj,
324                const struct gl_texture_image *texImage)
325 {
326    GLboolean memCopy = GL_FALSE;
327
328    /* Texture image should have been mapped already */
329    assert(texImage->Data);
330
331    /*
332     * Check if the src/dst formats are compatible.
333     * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
334     * so we don't have to worry about those.
335     * XXX more format combinations could be supported here.
336     */
337    if ((texObj->Target == GL_TEXTURE_1D ||
338         texObj->Target == GL_TEXTURE_2D ||
339         texObj->Target == GL_TEXTURE_RECTANGLE ||
340         (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
341          texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
342       if ((texImage->TexFormat == MESA_FORMAT_ARGB8888 ||
343              texImage->TexFormat == MESA_FORMAT_SARGB8) &&
344           format == GL_BGRA &&
345           (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) &&
346           !ctx->Pack.SwapBytes &&
347           _mesa_little_endian()) {
348          memCopy = GL_TRUE;
349       }
350       else if ((texImage->TexFormat == MESA_FORMAT_AL88 ||
351                   texImage->TexFormat == MESA_FORMAT_SLA8) &&
352                format == GL_LUMINANCE_ALPHA &&
353                type == GL_UNSIGNED_BYTE &&
354                !ctx->Pack.SwapBytes &&
355                _mesa_little_endian()) {
356          memCopy = GL_TRUE;
357       }
358       else if ((texImage->TexFormat == MESA_FORMAT_L8 ||
359                   texImage->TexFormat == MESA_FORMAT_SL8) &&
360                format == GL_LUMINANCE &&
361                type == GL_UNSIGNED_BYTE) {
362          memCopy = GL_TRUE;
363       }
364       else if (texImage->TexFormat == MESA_FORMAT_L16 &&
365                format == GL_LUMINANCE &&
366                type == GL_UNSIGNED_SHORT) {
367          memCopy = GL_TRUE;
368       }
369       else if (texImage->TexFormat == MESA_FORMAT_A8 &&
370                format == GL_ALPHA &&
371                type == GL_UNSIGNED_BYTE) {
372          memCopy = GL_TRUE;
373       }
374       else if (texImage->TexFormat == MESA_FORMAT_A16 &&
375                format == GL_ALPHA &&
376                type == GL_UNSIGNED_SHORT) {
377          memCopy = GL_TRUE;
378       }
379    }
380
381    if (memCopy) {
382       const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
383       const GLuint bytesPerRow = texImage->Width * bpp;
384       GLubyte *dst =
385          _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
386                                texImage->Height, format, type, 0, 0);
387       const GLint dstRowStride =
388          _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
389       const GLubyte *src = texImage->Data;
390       const GLint srcRowStride = texImage->RowStride * bpp;
391       GLuint row;
392
393       if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
394          memcpy(dst, src, bytesPerRow * texImage->Height);
395       }
396       else {
397          for (row = 0; row < texImage->Height; row++) {
398             memcpy(dst, src, bytesPerRow);
399             dst += dstRowStride;
400             src += srcRowStride;
401          }
402       }
403    }
404
405    return memCopy;
406 }
407
408
409 /**
410  * This is the software fallback for Driver.GetTexImage().
411  * All error checking will have been done before this routine is called.
412  * The texture image must be mapped.
413  */
414 void
415 _mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level,
416                    GLenum format, GLenum type, GLvoid *pixels,
417                    struct gl_texture_object *texObj,
418                    struct gl_texture_image *texImage)
419 {
420    GLuint dimensions;
421
422    /* If we get here, the texture image should be mapped */
423    assert(texImage->Data);
424
425    switch (target) {
426    case GL_TEXTURE_1D:
427       dimensions = 1;
428       break;
429    case GL_TEXTURE_3D:
430       dimensions = 3;
431       break;
432    default:
433       dimensions = 2;
434    }
435
436    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
437       /* Packing texture image into a PBO.
438        * Map the (potentially) VRAM-based buffer into our process space so
439        * we can write into it with the code below.
440        * A hardware driver might use a sophisticated blit to move the
441        * texture data to the PBO if the PBO is in VRAM along with the texture.
442        */
443       GLubyte *buf = (GLubyte *)
444          ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
445                                GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
446       if (!buf) {
447          /* out of memory or other unexpected error */
448          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
449          return;
450       }
451       /* <pixels> was an offset into the PBO.
452        * Now make it a real, client-side pointer inside the mapped region.
453        */
454       pixels = ADD_POINTERS(buf, pixels);
455    }
456
457    if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) {
458       /* all done */
459    }
460    else if (format == GL_COLOR_INDEX) {
461       get_tex_color_index(ctx, dimensions, format, type, pixels, texImage);
462    }
463    else if (format == GL_DEPTH_COMPONENT) {
464       get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
465    }
466    else if (format == GL_DEPTH_STENCIL_EXT) {
467       get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
468    }
469    else if (format == GL_YCBCR_MESA) {
470       get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
471    }
472    else {
473       get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
474    }
475
476    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
477       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
478                               ctx->Pack.BufferObj);
479    }
480 }
481
482
483
484 /**
485  * This is the software fallback for Driver.GetCompressedTexImage().
486  * All error checking will have been done before this routine is called.
487  */
488 void
489 _mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level,
490                               GLvoid *img,
491                               struct gl_texture_object *texObj,
492                               struct gl_texture_image *texImage)
493 {
494    const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat,
495                                                      texImage->Width);
496    const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat,
497                                                             texImage->RowStride);
498    GLuint i;
499
500    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
501       /* pack texture image into a PBO */
502       GLubyte *buf = (GLubyte *)
503          ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
504                                GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
505       if (!buf) {
506          /* out of memory or other unexpected error */
507          _mesa_error(ctx, GL_OUT_OF_MEMORY,
508                      "glGetCompresssedTexImage(map PBO failed)");
509          return;
510       }
511       img = ADD_POINTERS(buf, img);
512    }
513
514    /* no pixelstore or pixel transfer, but respect stride */
515
516    if (row_stride == row_stride_stored) {
517       const GLuint size = _mesa_format_image_size(texImage->TexFormat,
518                                                   texImage->Width,
519                                                   texImage->Height,
520                                                   texImage->Depth);
521       memcpy(img, texImage->Data, size);
522    }
523    else {
524       GLuint bw, bh;
525       _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
526       for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
527          memcpy((GLubyte *)img + i * row_stride,
528                 (GLubyte *)texImage->Data + i * row_stride_stored,
529                 row_stride);
530       }
531    }
532
533    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
534       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
535                               ctx->Pack.BufferObj);
536    }
537 }
538
539
540
541 /**
542  * Do error checking for a glGetTexImage() call.
543  * \return GL_TRUE if any error, GL_FALSE if no errors.
544  */
545 static GLboolean
546 getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
547                         GLenum format, GLenum type, GLsizei clientMemSize,
548                         GLvoid *pixels )
549 {
550    struct gl_texture_object *texObj;
551    struct gl_texture_image *texImage;
552    const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
553    const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
554    GLenum baseFormat;
555
556    if (maxLevels == 0) {
557       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
558       return GL_TRUE;
559    }
560
561    if (level < 0 || level >= maxLevels) {
562       _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
563       return GL_TRUE;
564    }
565
566    if (_mesa_sizeof_packed_type(type) <= 0) {
567       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
568       return GL_TRUE;
569    }
570
571    if (_mesa_components_in_format(format) <= 0 ||
572        format == GL_STENCIL_INDEX) {
573       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
574       return GL_TRUE;
575    }
576
577    if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
578       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
579       return GL_TRUE;
580    }
581
582    if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
583       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
584       return GL_TRUE;
585    }
586
587    if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
588       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
589       return GL_TRUE;
590    }
591
592    if (!ctx->Extensions.EXT_packed_depth_stencil
593        && _mesa_is_depthstencil_format(format)) {
594       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
595       return GL_TRUE;
596    }
597
598    if (!ctx->Extensions.ATI_envmap_bumpmap
599        && _mesa_is_dudv_format(format)) {
600       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
601       return GL_TRUE;
602    }
603
604    texObj = _mesa_get_current_tex_object(ctx, target);
605
606    if (!texObj || _mesa_is_proxy_texture(target)) {
607       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
608       return GL_TRUE;
609    }
610
611    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
612    if (!texImage) {
613       /* out of memory */
614       return GL_TRUE;
615    }
616
617    baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
618       
619    /* Make sure the requested image format is compatible with the
620     * texture's format.  Note that a color index texture can be converted
621     * to RGBA so that combo is allowed.
622     */
623    if (_mesa_is_color_format(format)
624        && !_mesa_is_color_format(baseFormat)
625        && !_mesa_is_index_format(baseFormat)) {
626       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
627       return GL_TRUE;
628    }
629    else if (_mesa_is_index_format(format)
630             && !_mesa_is_index_format(baseFormat)) {
631       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
632       return GL_TRUE;
633    }
634    else if (_mesa_is_depth_format(format)
635             && !_mesa_is_depth_format(baseFormat)
636             && !_mesa_is_depthstencil_format(baseFormat)) {
637       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
638       return GL_TRUE;
639    }
640    else if (_mesa_is_ycbcr_format(format)
641             && !_mesa_is_ycbcr_format(baseFormat)) {
642       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
643       return GL_TRUE;
644    }
645    else if (_mesa_is_depthstencil_format(format)
646             && !_mesa_is_depthstencil_format(baseFormat)) {
647       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
648       return GL_TRUE;
649    }
650    else if (_mesa_is_dudv_format(format)
651             && !_mesa_is_dudv_format(baseFormat)) {
652       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
653       return GL_TRUE;
654    }
655
656    if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
657                                   texImage->Height, texImage->Depth,
658                                   format, type, clientMemSize, pixels)) {
659       if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
660          _mesa_error(ctx, GL_INVALID_OPERATION,
661                      "glGetTexImage(out of bounds PBO access)");
662       } else {
663          _mesa_error(ctx, GL_INVALID_OPERATION,
664                      "glGetnTexImageARB(out of bounds access:"
665                      " bufSize (%d) is too small)", clientMemSize);
666       }
667       return GL_TRUE;
668    }
669
670    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
671       /* PBO should not be mapped */
672       if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
673          _mesa_error(ctx, GL_INVALID_OPERATION,
674                      "glGetTexImage(PBO is mapped)");
675          return GL_TRUE;
676       }
677    }
678
679    return GL_FALSE;
680 }
681
682
683
684 /**
685  * Get texture image.  Called by glGetTexImage.
686  *
687  * \param target texture target.
688  * \param level image level.
689  * \param format pixel data format for returned image.
690  * \param type pixel data type for returned image.
691  * \param bufSize size of the pixels data buffer.
692  * \param pixels returned pixel data.
693  */
694 void GLAPIENTRY
695 _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
696                        GLenum type, GLsizei bufSize, GLvoid *pixels )
697 {
698    struct gl_texture_object *texObj;
699    struct gl_texture_image *texImage;
700    GET_CURRENT_CONTEXT(ctx);
701    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
702
703    if (getteximage_error_check(ctx, target, level, format, type,
704                                bufSize, pixels)) {
705       return;
706    }
707
708    if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
709       /* not an error, do nothing */
710       return;
711    }
712
713    texObj = _mesa_get_current_tex_object(ctx, target);
714    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
715
716    if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
717       _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
718                   " dstFmt=0x%x, dstType=0x%x\n",
719                   texObj->Name,
720                   _mesa_get_format_name(texImage->TexFormat),
721                   texImage->Width, texImage->Height,
722                   format, type);
723    }
724
725    _mesa_lock_texture(ctx, texObj);
726    {
727       ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
728                               texObj, texImage);
729    }
730    _mesa_unlock_texture(ctx, texObj);
731 }
732
733
734 void GLAPIENTRY
735 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
736                    GLenum type, GLvoid *pixels )
737 {
738    _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
739 }
740
741
742 /**
743  * Do error checking for a glGetCompressedTexImage() call.
744  * \return GL_TRUE if any error, GL_FALSE if no errors.
745  */
746 static GLboolean
747 getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
748                                   GLint level, GLsizei clientMemSize, GLvoid *img)
749 {
750    struct gl_texture_object *texObj;
751    struct gl_texture_image *texImage;
752    const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
753    GLuint compressedSize;
754
755    if (maxLevels == 0) {
756       _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
757                   target);
758       return GL_TRUE;
759    }
760
761    if (level < 0 || level >= maxLevels) {
762       _mesa_error(ctx, GL_INVALID_VALUE,
763                   "glGetCompressedTexImageARB(bad level = %d)", level);
764       return GL_TRUE;
765    }
766
767    if (_mesa_is_proxy_texture(target)) {
768       _mesa_error(ctx, GL_INVALID_ENUM,
769                   "glGetCompressedTexImageARB(bad target = %s)",
770                   _mesa_lookup_enum_by_nr(target));
771       return GL_TRUE;
772    }
773
774    texObj = _mesa_get_current_tex_object(ctx, target);
775    if (!texObj) {
776       _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
777       return GL_TRUE;
778    }
779
780    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
781
782    if (!texImage) {
783       /* probably invalid mipmap level */
784       _mesa_error(ctx, GL_INVALID_VALUE,
785                   "glGetCompressedTexImageARB(level)");
786       return GL_TRUE;
787    }
788
789    if (!_mesa_is_format_compressed(texImage->TexFormat)) {
790       _mesa_error(ctx, GL_INVALID_OPERATION,
791                   "glGetCompressedTexImageARB(texture is not compressed)");
792       return GL_TRUE;
793    }
794
795    compressedSize = _mesa_format_image_size(texImage->TexFormat,
796                                             texImage->Width,
797                                             texImage->Height,
798                                             texImage->Depth);
799
800    if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
801       /* do bounds checking on writing to client memory */
802       if (clientMemSize < compressedSize) {
803          _mesa_error(ctx, GL_INVALID_OPERATION,
804                      "glGetnCompressedTexImageARB(out of bounds access:"
805                      " bufSize (%d) is too small)", clientMemSize);
806       }
807    } else {
808       /* do bounds checking on PBO write */
809       if ((const GLubyte *) img + compressedSize >
810           (const GLubyte *) ctx->Pack.BufferObj->Size) {
811          _mesa_error(ctx, GL_INVALID_OPERATION,
812                      "glGetCompressedTexImage(out of bounds PBO access)");
813          return GL_TRUE;
814       }
815
816       /* make sure PBO is not mapped */
817       if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
818          _mesa_error(ctx, GL_INVALID_OPERATION,
819                      "glGetCompressedTexImage(PBO is mapped)");
820          return GL_TRUE;
821       }
822    }
823
824    return GL_FALSE;
825 }
826
827
828 void GLAPIENTRY
829 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
830                                 GLvoid *img)
831 {
832    struct gl_texture_object *texObj;
833    struct gl_texture_image *texImage;
834    GET_CURRENT_CONTEXT(ctx);
835    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
836
837    if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
838       return;
839    }
840
841    if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
842       /* not an error, do nothing */
843       return;
844    }
845
846    texObj = _mesa_get_current_tex_object(ctx, target);
847    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
848
849    if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
850       _mesa_debug(ctx,
851                   "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
852                   texObj->Name,
853                   _mesa_get_format_name(texImage->TexFormat),
854                   texImage->Width, texImage->Height);
855    }
856
857    _mesa_lock_texture(ctx, texObj);
858    {
859       ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
860                                         texObj, texImage);
861    }
862    _mesa_unlock_texture(ctx, texObj);
863 }
864
865 void GLAPIENTRY
866 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
867 {
868    _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
869 }