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