texgetimage.c revision 63396ce4c0fe067f69d1b53d0408627a421c4678
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 tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat);
310   GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat);
311
312   /* Allocate buffer for one row of texels */
313   rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
314   rgba_uint = (GLuint (*)[4]) rgba;
315   if (!rgba) {
316      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
317      return;
318   }
319
320   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
321      depth = height;
322      height = 1;
323   }
324
325   if (texImage->_BaseFormat == GL_LUMINANCE ||
326       texImage->_BaseFormat == GL_INTENSITY ||
327       texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
328      /* If a luminance (or intensity) texture is read back as RGB(A), the
329       * returned value should be (L,0,0,1), not (L,L,L,1).  Set rebaseFormat
330       * here to get G=B=0.
331       */
332      rebaseFormat = texImage->_BaseFormat;
333   }
334   else if ((texImage->_BaseFormat == GL_RGBA ||
335             texImage->_BaseFormat == GL_RGB) &&
336            (destBaseFormat == GL_LUMINANCE ||
337             destBaseFormat == GL_LUMINANCE_ALPHA ||
338             destBaseFormat == GL_LUMINANCE_INTEGER_EXT ||
339             destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) {
340      /* If we're reading back an RGB(A) texture as luminance then we need
341       * to return L=tex(R).  Note, that's different from glReadPixels which
342       * returns L=R+G+B.
343       */
344      rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */
345   }
346
347   for (img = 0; img < depth; img++) {
348      GLubyte *srcMap;
349      GLint rowstride;
350
351      /* map src texture buffer */
352      ctx->Driver.MapTextureImage(ctx, texImage, img,
353                                  0, 0, width, height, GL_MAP_READ_BIT,
354                                  &srcMap, &rowstride);
355      if (srcMap) {
356         for (row = 0; row < height; row++) {
357            const GLubyte *src = srcMap + row * rowstride;
358            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
359                                             width, height, format, type,
360                                             img, row, 0);
361
362	    if (tex_is_integer) {
363	       _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint);
364               if (rebaseFormat)
365                  _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat);
366               if (tex_is_uint) {
367                  _mesa_pack_rgba_span_from_uints(ctx, width,
368                                                  (GLuint (*)[4]) rgba_uint,
369                                                  format, type, dest);
370               } else {
371                  _mesa_pack_rgba_span_from_ints(ctx, width,
372                                                 (GLint (*)[4]) rgba_uint,
373                                                 format, type, dest);
374               }
375	    } else {
376	       _mesa_unpack_rgba_row(texFormat, width, src, rgba);
377               if (rebaseFormat)
378                  _mesa_rebase_rgba_float(width, rgba, rebaseFormat);
379	       _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
380					  format, type, dest,
381					  &ctx->Pack, transferOps);
382	    }
383	 }
384
385         /* Unmap the src texture buffer */
386         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
387      }
388      else {
389         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
390         break;
391      }
392   }
393
394   free(rgba);
395}
396
397
398/**
399 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
400 * Compressed textures are handled here as well.
401 */
402static void
403get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
404             GLenum format, GLenum type, GLvoid *pixels,
405             struct gl_texture_image *texImage)
406{
407   const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
408   GLbitfield transferOps = 0x0;
409
410   /* In general, clamping does not apply to glGetTexImage, except when
411    * the returned type of the image can't hold negative values.
412    */
413   if (type_needs_clamping(type)) {
414      /* the returned image type can't have negative values */
415      if (dataType == GL_FLOAT ||
416          dataType == GL_SIGNED_NORMALIZED ||
417          format == GL_LUMINANCE ||
418          format == GL_LUMINANCE_ALPHA) {
419         transferOps |= IMAGE_CLAMP_BIT;
420      }
421   }
422   /* This applies to RGB, RGBA textures. if the format is either LUMINANCE
423    * or LUMINANCE ALPHA, luminance (L) is computed as L=R+G+B .we need to
424    * clamp the sum to [0,1].
425    */
426   else if ((format == GL_LUMINANCE ||
427            format == GL_LUMINANCE_ALPHA) &&
428            dataType == GL_UNSIGNED_NORMALIZED) {
429      transferOps |= IMAGE_CLAMP_BIT;
430   }
431
432   if (_mesa_is_format_compressed(texImage->TexFormat)) {
433      get_tex_rgba_compressed(ctx, dimensions, format, type,
434                              pixels, texImage, transferOps);
435   }
436   else {
437      get_tex_rgba_uncompressed(ctx, dimensions, format, type,
438                                pixels, texImage, transferOps);
439   }
440}
441
442
443/**
444 * Try to do glGetTexImage() with simple memcpy().
445 * \return GL_TRUE if done, GL_FALSE otherwise
446 */
447static GLboolean
448get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type,
449               GLvoid *pixels,
450               struct gl_texture_image *texImage)
451{
452   const GLenum target = texImage->TexObject->Target;
453   GLboolean memCopy = GL_FALSE;
454
455   /*
456    * Check if we can use memcpy to copy from the hardware texture
457    * format to the user's format/type.
458    * Note that GL's pixel transfer ops don't apply to glGetTexImage()
459    */
460   if (target == GL_TEXTURE_1D ||
461       target == GL_TEXTURE_2D ||
462       target == GL_TEXTURE_RECTANGLE ||
463       _mesa_is_cube_face(target)) {
464      memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat,
465                                                     format, type,
466                                                     ctx->Pack.SwapBytes);
467   }
468
469   if (memCopy) {
470      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
471      const GLuint bytesPerRow = texImage->Width * bpp;
472      GLubyte *dst =
473         _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
474                               texImage->Height, format, type, 0, 0);
475      const GLint dstRowStride =
476         _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
477      GLubyte *src;
478      GLint srcRowStride;
479
480      /* map src texture buffer */
481      ctx->Driver.MapTextureImage(ctx, texImage, 0,
482                                  0, 0, texImage->Width, texImage->Height,
483                                  GL_MAP_READ_BIT, &src, &srcRowStride);
484
485      if (src) {
486         if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
487            memcpy(dst, src, bytesPerRow * texImage->Height);
488         }
489         else {
490            GLuint row;
491            for (row = 0; row < texImage->Height; row++) {
492               memcpy(dst, src, bytesPerRow);
493               dst += dstRowStride;
494               src += srcRowStride;
495            }
496         }
497
498         /* unmap src texture buffer */
499         ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
500      }
501      else {
502         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
503      }
504   }
505
506   return memCopy;
507}
508
509
510/**
511 * This is the software fallback for Driver.GetTexImage().
512 * All error checking will have been done before this routine is called.
513 * We'll call ctx->Driver.MapTextureImage() to access the data, then
514 * unmap with ctx->Driver.UnmapTextureImage().
515 */
516void
517_mesa_get_teximage(struct gl_context *ctx,
518                   GLenum format, GLenum type, GLvoid *pixels,
519                   struct gl_texture_image *texImage)
520{
521   GLuint dimensions;
522
523   switch (texImage->TexObject->Target) {
524   case GL_TEXTURE_1D:
525      dimensions = 1;
526      break;
527   case GL_TEXTURE_3D:
528      dimensions = 3;
529      break;
530   default:
531      dimensions = 2;
532   }
533
534   /* map dest buffer, if PBO */
535   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
536      /* Packing texture image into a PBO.
537       * Map the (potentially) VRAM-based buffer into our process space so
538       * we can write into it with the code below.
539       * A hardware driver might use a sophisticated blit to move the
540       * texture data to the PBO if the PBO is in VRAM along with the texture.
541       */
542      GLubyte *buf = (GLubyte *)
543         ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
544				    GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
545      if (!buf) {
546         /* out of memory or other unexpected error */
547         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
548         return;
549      }
550      /* <pixels> was an offset into the PBO.
551       * Now make it a real, client-side pointer inside the mapped region.
552       */
553      pixels = ADD_POINTERS(buf, pixels);
554   }
555
556   if (get_tex_memcpy(ctx, format, type, pixels, texImage)) {
557      /* all done */
558   }
559   else if (format == GL_DEPTH_COMPONENT) {
560      get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
561   }
562   else if (format == GL_DEPTH_STENCIL_EXT) {
563      get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
564   }
565   else if (format == GL_YCBCR_MESA) {
566      get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
567   }
568   else {
569      get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
570   }
571
572   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
573      ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
574   }
575}
576
577
578
579/**
580 * This is the software fallback for Driver.GetCompressedTexImage().
581 * All error checking will have been done before this routine is called.
582 */
583void
584_mesa_get_compressed_teximage(struct gl_context *ctx,
585                              struct gl_texture_image *texImage,
586                              GLvoid *img)
587{
588   const GLuint row_stride =
589      _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
590   GLuint i;
591   GLubyte *src;
592   GLint srcRowStride;
593
594   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
595      /* pack texture image into a PBO */
596      GLubyte *buf = (GLubyte *)
597         ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
598				    GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
599      if (!buf) {
600         /* out of memory or other unexpected error */
601         _mesa_error(ctx, GL_OUT_OF_MEMORY,
602                     "glGetCompresssedTexImage(map PBO failed)");
603         return;
604      }
605      img = ADD_POINTERS(buf, img);
606   }
607
608   /* map src texture buffer */
609   ctx->Driver.MapTextureImage(ctx, texImage, 0,
610                               0, 0, texImage->Width, texImage->Height,
611                               GL_MAP_READ_BIT, &src, &srcRowStride);
612
613   if (src) {
614      /* no pixelstore or pixel transfer, but respect stride */
615
616      if (row_stride == srcRowStride) {
617         const GLuint size = _mesa_format_image_size(texImage->TexFormat,
618                                                     texImage->Width,
619                                                     texImage->Height,
620                                                     texImage->Depth);
621         memcpy(img, src, size);
622      }
623      else {
624         GLuint bw, bh;
625         _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
626         for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
627            memcpy((GLubyte *)img + i * row_stride,
628                   (GLubyte *)src + i * srcRowStride,
629                   row_stride);
630         }
631      }
632
633      ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
634   }
635   else {
636      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
637   }
638
639   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
640      ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
641   }
642}
643
644
645/**
646 * Validate the texture target enum supplied to glTexImage or
647 * glCompressedTexImage.
648 */
649static GLboolean
650legal_getteximage_target(struct gl_context *ctx, GLenum target)
651{
652   switch (target) {
653   case GL_TEXTURE_1D:
654   case GL_TEXTURE_2D:
655   case GL_TEXTURE_3D:
656      return GL_TRUE;
657   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
658   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
659   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
660   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
661   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
662   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
663      return ctx->Extensions.ARB_texture_cube_map;
664   case GL_TEXTURE_RECTANGLE_NV:
665      return ctx->Extensions.NV_texture_rectangle;
666   case GL_TEXTURE_1D_ARRAY_EXT:
667   case GL_TEXTURE_2D_ARRAY_EXT:
668      return (ctx->Extensions.MESA_texture_array ||
669              ctx->Extensions.EXT_texture_array);
670   default:
671      return GL_FALSE;
672   }
673}
674
675
676/**
677 * Do error checking for a glGetTexImage() call.
678 * \return GL_TRUE if any error, GL_FALSE if no errors.
679 */
680static GLboolean
681getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
682                        GLenum format, GLenum type, GLsizei clientMemSize,
683                        GLvoid *pixels )
684{
685   struct gl_texture_object *texObj;
686   struct gl_texture_image *texImage;
687   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
688   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
689   GLenum baseFormat, err;
690
691   if (!legal_getteximage_target(ctx, target)) {
692      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
693      return GL_TRUE;
694   }
695
696   assert(maxLevels != 0);
697   if (level < 0 || level >= maxLevels) {
698      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
699      return GL_TRUE;
700   }
701
702   err = _mesa_error_check_format_and_type(ctx, format, type);
703   if (err != GL_NO_ERROR) {
704      _mesa_error(ctx, err, "glGetTexImage(format/type)");
705      return GL_TRUE;
706   }
707
708   texObj = _mesa_get_current_tex_object(ctx, target);
709
710   if (!texObj) {
711      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
712      return GL_TRUE;
713   }
714
715   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
716   if (!texImage) {
717      /* non-existant texture image */
718      return GL_TRUE;
719   }
720
721   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
722
723   /* Make sure the requested image format is compatible with the
724    * texture's format.
725    */
726   if (_mesa_is_color_format(format)
727       && !_mesa_is_color_format(baseFormat)) {
728      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
729      return GL_TRUE;
730   }
731   else if (_mesa_is_depth_format(format)
732            && !_mesa_is_depth_format(baseFormat)
733            && !_mesa_is_depthstencil_format(baseFormat)) {
734      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
735      return GL_TRUE;
736   }
737   else if (_mesa_is_ycbcr_format(format)
738            && !_mesa_is_ycbcr_format(baseFormat)) {
739      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
740      return GL_TRUE;
741   }
742   else if (_mesa_is_depthstencil_format(format)
743            && !_mesa_is_depthstencil_format(baseFormat)) {
744      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
745      return GL_TRUE;
746   }
747   else if (_mesa_is_dudv_format(format)
748            && !_mesa_is_dudv_format(baseFormat)) {
749      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
750      return GL_TRUE;
751   }
752
753   if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
754                                  texImage->Height, texImage->Depth,
755                                  format, type, clientMemSize, pixels)) {
756      if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
757         _mesa_error(ctx, GL_INVALID_OPERATION,
758                     "glGetTexImage(out of bounds PBO access)");
759      } else {
760         _mesa_error(ctx, GL_INVALID_OPERATION,
761                     "glGetnTexImageARB(out of bounds access:"
762                     " bufSize (%d) is too small)", clientMemSize);
763      }
764      return GL_TRUE;
765   }
766
767   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
768      /* PBO should not be mapped */
769      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
770         _mesa_error(ctx, GL_INVALID_OPERATION,
771                     "glGetTexImage(PBO is mapped)");
772         return GL_TRUE;
773      }
774   }
775
776   return GL_FALSE;
777}
778
779
780
781/**
782 * Get texture image.  Called by glGetTexImage.
783 *
784 * \param target texture target.
785 * \param level image level.
786 * \param format pixel data format for returned image.
787 * \param type pixel data type for returned image.
788 * \param bufSize size of the pixels data buffer.
789 * \param pixels returned pixel data.
790 */
791void GLAPIENTRY
792_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
793                       GLenum type, GLsizei bufSize, GLvoid *pixels )
794{
795   struct gl_texture_object *texObj;
796   struct gl_texture_image *texImage;
797   GET_CURRENT_CONTEXT(ctx);
798   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
799
800   if (getteximage_error_check(ctx, target, level, format, type,
801                               bufSize, pixels)) {
802      return;
803   }
804
805   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
806      /* not an error, do nothing */
807      return;
808   }
809
810   texObj = _mesa_get_current_tex_object(ctx, target);
811   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
812
813   if (_mesa_is_zero_size_texture(texImage))
814      return;
815
816   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
817      _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
818                  " dstFmt=0x%x, dstType=0x%x\n",
819                  texObj->Name,
820                  _mesa_get_format_name(texImage->TexFormat),
821                  texImage->Width, texImage->Height,
822                  format, type);
823   }
824
825   _mesa_lock_texture(ctx, texObj);
826   {
827      ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
828   }
829   _mesa_unlock_texture(ctx, texObj);
830}
831
832
833void GLAPIENTRY
834_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
835                   GLenum type, GLvoid *pixels )
836{
837   _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
838}
839
840
841/**
842 * Do error checking for a glGetCompressedTexImage() call.
843 * \return GL_TRUE if any error, GL_FALSE if no errors.
844 */
845static GLboolean
846getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
847                                  GLint level, GLsizei clientMemSize, GLvoid *img)
848{
849   struct gl_texture_object *texObj;
850   struct gl_texture_image *texImage;
851   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
852   GLuint compressedSize;
853
854   if (!legal_getteximage_target(ctx, target)) {
855      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
856                  target);
857      return GL_TRUE;
858   }
859
860   assert(maxLevels != 0);
861   if (level < 0 || level >= maxLevels) {
862      _mesa_error(ctx, GL_INVALID_VALUE,
863                  "glGetCompressedTexImageARB(bad level = %d)", level);
864      return GL_TRUE;
865   }
866
867   texObj = _mesa_get_current_tex_object(ctx, target);
868   if (!texObj) {
869      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
870      return GL_TRUE;
871   }
872
873   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
874
875   if (!texImage) {
876      /* probably invalid mipmap level */
877      _mesa_error(ctx, GL_INVALID_VALUE,
878                  "glGetCompressedTexImageARB(level)");
879      return GL_TRUE;
880   }
881
882   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
883      _mesa_error(ctx, GL_INVALID_OPERATION,
884                  "glGetCompressedTexImageARB(texture is not compressed)");
885      return GL_TRUE;
886   }
887
888   compressedSize = _mesa_format_image_size(texImage->TexFormat,
889                                            texImage->Width,
890                                            texImage->Height,
891                                            texImage->Depth);
892
893   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
894      /* do bounds checking on writing to client memory */
895      if (clientMemSize < compressedSize) {
896         _mesa_error(ctx, GL_INVALID_OPERATION,
897                     "glGetnCompressedTexImageARB(out of bounds access:"
898                     " bufSize (%d) is too small)", clientMemSize);
899         return GL_TRUE;
900      }
901   } else {
902      /* do bounds checking on PBO write */
903      if ((const GLubyte *) img + compressedSize >
904          (const GLubyte *) ctx->Pack.BufferObj->Size) {
905         _mesa_error(ctx, GL_INVALID_OPERATION,
906                     "glGetCompressedTexImage(out of bounds PBO access)");
907         return GL_TRUE;
908      }
909
910      /* make sure PBO is not mapped */
911      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
912         _mesa_error(ctx, GL_INVALID_OPERATION,
913                     "glGetCompressedTexImage(PBO is mapped)");
914         return GL_TRUE;
915      }
916   }
917
918   return GL_FALSE;
919}
920
921
922void GLAPIENTRY
923_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
924                                GLvoid *img)
925{
926   struct gl_texture_object *texObj;
927   struct gl_texture_image *texImage;
928   GET_CURRENT_CONTEXT(ctx);
929   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
930
931   if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
932      return;
933   }
934
935   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
936      /* not an error, do nothing */
937      return;
938   }
939
940   texObj = _mesa_get_current_tex_object(ctx, target);
941   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
942
943   if (_mesa_is_zero_size_texture(texImage))
944      return;
945
946   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
947      _mesa_debug(ctx,
948                  "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
949                  texObj->Name,
950                  _mesa_get_format_name(texImage->TexFormat),
951                  texImage->Width, texImage->Height);
952   }
953
954   _mesa_lock_texture(ctx, texObj);
955   {
956      ctx->Driver.GetCompressedTexImage(ctx, texImage, img);
957   }
958   _mesa_unlock_texture(ctx, texObj);
959}
960
961void GLAPIENTRY
962_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
963{
964   _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
965}
966