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