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