texgetimage.c revision cdc920a0
14a49301eSmrg/*
24a49301eSmrg * Mesa 3-D graphics library
34a49301eSmrg * Version:  7.7
44a49301eSmrg *
54a49301eSmrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
64a49301eSmrg * Copyright (c) 2009 VMware, Inc.
74a49301eSmrg *
84a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
94a49301eSmrg * copy of this software and associated documentation files (the "Software"),
104a49301eSmrg * to deal in the Software without restriction, including without limitation
114a49301eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
124a49301eSmrg * and/or sell copies of the Software, and to permit persons to whom the
134a49301eSmrg * Software is furnished to do so, subject to the following conditions:
144a49301eSmrg *
154a49301eSmrg * The above copyright notice and this permission notice shall be included
164a49301eSmrg * in all copies or substantial portions of the Software.
174a49301eSmrg *
184a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
194a49301eSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
204a49301eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
214a49301eSmrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
224a49301eSmrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
234a49301eSmrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
244a49301eSmrg */
254a49301eSmrg
264a49301eSmrg
274a49301eSmrg/**
284a49301eSmrg * Code for glGetTexImage() and glGetCompressedTexImage().
294a49301eSmrg */
304a49301eSmrg
314a49301eSmrg
324a49301eSmrg#include "glheader.h"
334a49301eSmrg#include "bufferobj.h"
344a49301eSmrg#include "enums.h"
354a49301eSmrg#include "context.h"
364a49301eSmrg#include "formats.h"
374a49301eSmrg#include "image.h"
384a49301eSmrg#include "texgetimage.h"
394a49301eSmrg#include "teximage.h"
404a49301eSmrg
414a49301eSmrg
424a49301eSmrg
434a49301eSmrg/**
444a49301eSmrg * Can the given type represent negative values?
454a49301eSmrg */
464a49301eSmrgstatic INLINE GLboolean
474a49301eSmrgtype_with_negative_values(GLenum type)
484a49301eSmrg{
494a49301eSmrg   switch (type) {
504a49301eSmrg   case GL_BYTE:
514a49301eSmrg   case GL_SHORT:
524a49301eSmrg   case GL_INT:
534a49301eSmrg   case GL_FLOAT:
544a49301eSmrg   case GL_HALF_FLOAT_ARB:
554a49301eSmrg      return GL_TRUE;
564a49301eSmrg   default:
574a49301eSmrg      return GL_FALSE;
584a49301eSmrg   }
594a49301eSmrg}
604a49301eSmrg
614a49301eSmrg
624a49301eSmrg/**
634a49301eSmrg * glGetTexImage for color index pixels.
644a49301eSmrg */
654a49301eSmrgstatic void
664a49301eSmrgget_tex_color_index(GLcontext *ctx, GLuint dimensions,
674a49301eSmrg                    GLenum format, GLenum type, GLvoid *pixels,
684a49301eSmrg                    const struct gl_texture_image *texImage)
694a49301eSmrg{
704a49301eSmrg   const GLint width = texImage->Width;
714a49301eSmrg   const GLint height = texImage->Height;
724a49301eSmrg   const GLint depth = texImage->Depth;
734a49301eSmrg   const GLuint indexBits =
744a49301eSmrg      _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
754a49301eSmrg   const GLbitfield transferOps = 0x0;
764a49301eSmrg   GLint img, row, col;
774a49301eSmrg
784a49301eSmrg   for (img = 0; img < depth; img++) {
794a49301eSmrg      for (row = 0; row < height; row++) {
804a49301eSmrg         GLuint indexRow[MAX_WIDTH] = { 0 };
814a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
824a49301eSmrg                                          width, height, format, type,
834a49301eSmrg                                          img, row, 0);
844a49301eSmrg         assert(dest);
854a49301eSmrg
864a49301eSmrg         if (indexBits == 8) {
874a49301eSmrg            const GLubyte *src = (const GLubyte *) texImage->Data;
884a49301eSmrg            src += width * (img * texImage->Height + row);
894a49301eSmrg            for (col = 0; col < width; col++) {
904a49301eSmrg               indexRow[col] = src[col];
914a49301eSmrg            }
924a49301eSmrg         }
934a49301eSmrg         else if (indexBits == 16) {
944a49301eSmrg            const GLushort *src = (const GLushort *) texImage->Data;
954a49301eSmrg            src += width * (img * texImage->Height + row);
964a49301eSmrg            for (col = 0; col < width; col++) {
974a49301eSmrg               indexRow[col] = src[col];
984a49301eSmrg            }
994a49301eSmrg         }
1004a49301eSmrg         else {
1014a49301eSmrg            _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage");
1024a49301eSmrg         }
1034a49301eSmrg         _mesa_pack_index_span(ctx, width, type, dest,
1044a49301eSmrg                               indexRow, &ctx->Pack, transferOps);
1054a49301eSmrg      }
1064a49301eSmrg   }
1074a49301eSmrg}
1084a49301eSmrg
1094a49301eSmrg
1104a49301eSmrg/**
1114a49301eSmrg * glGetTexImage for depth/Z pixels.
1124a49301eSmrg */
1134a49301eSmrgstatic void
1144a49301eSmrgget_tex_depth(GLcontext *ctx, GLuint dimensions,
1154a49301eSmrg              GLenum format, GLenum type, GLvoid *pixels,
1164a49301eSmrg              const struct gl_texture_image *texImage)
1174a49301eSmrg{
1184a49301eSmrg   const GLint width = texImage->Width;
1194a49301eSmrg   const GLint height = texImage->Height;
1204a49301eSmrg   const GLint depth = texImage->Depth;
1214a49301eSmrg   GLint img, row, col;
1224a49301eSmrg
1234a49301eSmrg   for (img = 0; img < depth; img++) {
1244a49301eSmrg      for (row = 0; row < height; row++) {
1254a49301eSmrg         GLfloat depthRow[MAX_WIDTH];
1264a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
1274a49301eSmrg                                          width, height, format, type,
1284a49301eSmrg                                          img, row, 0);
1294a49301eSmrg         assert(dest);
1304a49301eSmrg
1314a49301eSmrg         for (col = 0; col < width; col++) {
1324a49301eSmrg            texImage->FetchTexelf(texImage, col, row, img, depthRow + col);
1334a49301eSmrg         }
1344a49301eSmrg         _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
1354a49301eSmrg      }
1364a49301eSmrg   }
1374a49301eSmrg}
1384a49301eSmrg
1394a49301eSmrg
1404a49301eSmrg/**
1414a49301eSmrg * glGetTexImage for depth/stencil pixels.
1424a49301eSmrg */
1434a49301eSmrgstatic void
1444a49301eSmrgget_tex_depth_stencil(GLcontext *ctx, GLuint dimensions,
1454a49301eSmrg                      GLenum format, GLenum type, GLvoid *pixels,
1464a49301eSmrg                      const struct gl_texture_image *texImage)
1474a49301eSmrg{
1484a49301eSmrg   const GLint width = texImage->Width;
1494a49301eSmrg   const GLint height = texImage->Height;
1504a49301eSmrg   const GLint depth = texImage->Depth;
1514a49301eSmrg   const GLuint *src = (const GLuint *) texImage->Data;
1524a49301eSmrg   GLint img, row;
1534a49301eSmrg
1544a49301eSmrg   for (img = 0; img < depth; img++) {
1554a49301eSmrg      for (row = 0; row < height; row++) {
1564a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
1574a49301eSmrg                                          width, height, format, type,
1584a49301eSmrg                                          img, row, 0);
159cdc920a0Smrg         memcpy(dest, src, width * sizeof(GLuint));
1604a49301eSmrg         if (ctx->Pack.SwapBytes) {
1614a49301eSmrg            _mesa_swap4((GLuint *) dest, width);
1624a49301eSmrg         }
1634a49301eSmrg
1644a49301eSmrg         src += width * row + width * height * img;
1654a49301eSmrg      }
1664a49301eSmrg   }
1674a49301eSmrg}
1684a49301eSmrg
1694a49301eSmrg
1704a49301eSmrg/**
1714a49301eSmrg * glGetTexImage for YCbCr pixels.
1724a49301eSmrg */
1734a49301eSmrgstatic void
1744a49301eSmrgget_tex_ycbcr(GLcontext *ctx, GLuint dimensions,
1754a49301eSmrg              GLenum format, GLenum type, GLvoid *pixels,
1764a49301eSmrg              const struct gl_texture_image *texImage)
1774a49301eSmrg{
1784a49301eSmrg   const GLint width = texImage->Width;
1794a49301eSmrg   const GLint height = texImage->Height;
1804a49301eSmrg   const GLint depth = texImage->Depth;
1814a49301eSmrg   const GLint rowstride = texImage->RowStride;
1824a49301eSmrg   const GLushort *src = (const GLushort *) texImage->Data;
1834a49301eSmrg   GLint img, row;
1844a49301eSmrg
1854a49301eSmrg   for (img = 0; img < depth; img++) {
1864a49301eSmrg      for (row = 0; row < height; row++) {
1874a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
1884a49301eSmrg                                          width, height, format, type,
1894a49301eSmrg                                          img, row, 0);
190cdc920a0Smrg         memcpy(dest, src, width * sizeof(GLushort));
1914a49301eSmrg
1924a49301eSmrg         /* check for byte swapping */
1934a49301eSmrg         if ((texImage->TexFormat == MESA_FORMAT_YCBCR
1944a49301eSmrg              && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
1954a49301eSmrg             (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
1964a49301eSmrg              && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
1974a49301eSmrg            if (!ctx->Pack.SwapBytes)
1984a49301eSmrg               _mesa_swap2((GLushort *) dest, width);
1994a49301eSmrg         }
2004a49301eSmrg         else if (ctx->Pack.SwapBytes) {
2014a49301eSmrg            _mesa_swap2((GLushort *) dest, width);
2024a49301eSmrg         }
2034a49301eSmrg
2044a49301eSmrg         src += rowstride;
2054a49301eSmrg      }
2064a49301eSmrg   }
2074a49301eSmrg}
2084a49301eSmrg
2094a49301eSmrg
210cdc920a0Smrg#if FEATURE_EXT_texture_sRGB
211cdc920a0Smrg
212cdc920a0Smrg
213cdc920a0Smrg/**
214cdc920a0Smrg * Convert a float value from linear space to a
215cdc920a0Smrg * non-linear sRGB value in [0, 255].
216cdc920a0Smrg * Not terribly efficient.
217cdc920a0Smrg */
218cdc920a0Smrgstatic INLINE GLfloat
219cdc920a0Smrglinear_to_nonlinear(GLfloat cl)
220cdc920a0Smrg{
221cdc920a0Smrg   /* can't have values outside [0, 1] */
222cdc920a0Smrg   GLfloat cs;
223cdc920a0Smrg   if (cl < 0.0031308f) {
224cdc920a0Smrg      cs = 12.92f * cl;
225cdc920a0Smrg   }
226cdc920a0Smrg   else {
227cdc920a0Smrg      cs = (GLfloat)(1.055 * _mesa_pow(cl, 0.41666) - 0.055);
228cdc920a0Smrg   }
229cdc920a0Smrg   return cs;
230cdc920a0Smrg}
231cdc920a0Smrg
232cdc920a0Smrg
2334a49301eSmrg/**
2344a49301eSmrg * glGetTexImagefor sRGB pixels;
2354a49301eSmrg */
2364a49301eSmrgstatic void
2374a49301eSmrgget_tex_srgb(GLcontext *ctx, GLuint dimensions,
2384a49301eSmrg             GLenum format, GLenum type, GLvoid *pixels,
2394a49301eSmrg             const struct gl_texture_image *texImage)
2404a49301eSmrg{
2414a49301eSmrg   const GLint width = texImage->Width;
2424a49301eSmrg   const GLint height = texImage->Height;
2434a49301eSmrg   const GLint depth = texImage->Depth;
2444a49301eSmrg   const GLbitfield transferOps = 0x0;
2454a49301eSmrg   GLint img, row;
2464a49301eSmrg
2474a49301eSmrg   for (img = 0; img < depth; img++) {
2484a49301eSmrg      for (row = 0; row < height; row++) {
2494a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
2504a49301eSmrg                                          width, height, format, type,
2514a49301eSmrg                                          img, row, 0);
2524a49301eSmrg
2534a49301eSmrg         GLfloat rgba[MAX_WIDTH][4];
2544a49301eSmrg         GLint col;
2554a49301eSmrg
2564a49301eSmrg         /* convert row to RGBA format */
2574a49301eSmrg         for (col = 0; col < width; col++) {
2584a49301eSmrg            texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
2594a49301eSmrg            if (texImage->_BaseFormat == GL_LUMINANCE) {
2604a49301eSmrg               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
2614a49301eSmrg               rgba[col][GCOMP] = 0.0;
2624a49301eSmrg               rgba[col][BCOMP] = 0.0;
2634a49301eSmrg            }
2644a49301eSmrg            else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
2654a49301eSmrg               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
2664a49301eSmrg               rgba[col][GCOMP] = 0.0;
2674a49301eSmrg               rgba[col][BCOMP] = 0.0;
2684a49301eSmrg            }
2694a49301eSmrg            else if (texImage->_BaseFormat == GL_RGB ||
2704a49301eSmrg                     texImage->_BaseFormat == GL_RGBA) {
2714a49301eSmrg               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
2724a49301eSmrg               rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
2734a49301eSmrg               rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
2744a49301eSmrg            }
2754a49301eSmrg         }
2764a49301eSmrg         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
2774a49301eSmrg                                    format, type, dest,
2784a49301eSmrg                                    &ctx->Pack, transferOps);
2794a49301eSmrg      }
2804a49301eSmrg   }
2814a49301eSmrg}
2824a49301eSmrg
2834a49301eSmrg
284cdc920a0Smrg#else /* FEATURE_EXT_texture_sRGB */
285cdc920a0Smrg
286cdc920a0Smrg
287cdc920a0Smrgstatic INLINE void
288cdc920a0Smrgget_tex_srgb(GLcontext *ctx, GLuint dimensions,
289cdc920a0Smrg             GLenum format, GLenum type, GLvoid *pixels,
290cdc920a0Smrg             const struct gl_texture_image *texImage)
291cdc920a0Smrg{
292cdc920a0Smrg   ASSERT_NO_FEATURE();
293cdc920a0Smrg}
294cdc920a0Smrg
295cdc920a0Smrg
296cdc920a0Smrg#endif /* FEATURE_EXT_texture_sRGB */
297cdc920a0Smrg
298cdc920a0Smrg
2994a49301eSmrg/**
3004a49301eSmrg * glGetTexImagefor RGBA, Luminance, etc. pixels.
3014a49301eSmrg * This is the slow way since we use texture sampling.
3024a49301eSmrg */
3034a49301eSmrgstatic void
3044a49301eSmrgget_tex_rgba(GLcontext *ctx, GLuint dimensions,
3054a49301eSmrg             GLenum format, GLenum type, GLvoid *pixels,
3064a49301eSmrg             const struct gl_texture_image *texImage)
3074a49301eSmrg{
3084a49301eSmrg   const GLint width = texImage->Width;
3094a49301eSmrg   const GLint height = texImage->Height;
3104a49301eSmrg   const GLint depth = texImage->Depth;
3114a49301eSmrg   /* Normally, no pixel transfer ops are performed during glGetTexImage.
3124a49301eSmrg    * The only possible exception is component clamping to [0,1].
3134a49301eSmrg    */
3144a49301eSmrg   GLbitfield transferOps = 0x0;
3154a49301eSmrg   GLint img, row;
3164a49301eSmrg
3174a49301eSmrg   for (img = 0; img < depth; img++) {
3184a49301eSmrg      for (row = 0; row < height; row++) {
3194a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
3204a49301eSmrg                                          width, height, format, type,
3214a49301eSmrg                                          img, row, 0);
3224a49301eSmrg         GLfloat rgba[MAX_WIDTH][4];
3234a49301eSmrg         GLint col;
3244a49301eSmrg         GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
3254a49301eSmrg
3264a49301eSmrg         /* clamp does not apply to GetTexImage (final conversion)?
3274a49301eSmrg          * Looks like we need clamp though when going from format
3284a49301eSmrg          * containing negative values to unsigned format.
3294a49301eSmrg          */
3304a49301eSmrg         if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) {
3314a49301eSmrg            transferOps |= IMAGE_CLAMP_BIT;
3324a49301eSmrg         }
3334a49301eSmrg         else if (!type_with_negative_values(type) &&
3344a49301eSmrg                  (dataType == GL_FLOAT ||
3354a49301eSmrg                   dataType == GL_SIGNED_NORMALIZED)) {
3364a49301eSmrg            transferOps |= IMAGE_CLAMP_BIT;
3374a49301eSmrg         }
3384a49301eSmrg
3394a49301eSmrg         for (col = 0; col < width; col++) {
3404a49301eSmrg            texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
3414a49301eSmrg            if (texImage->_BaseFormat == GL_ALPHA) {
3424a49301eSmrg               rgba[col][RCOMP] = 0.0F;
3434a49301eSmrg               rgba[col][GCOMP] = 0.0F;
3444a49301eSmrg               rgba[col][BCOMP] = 0.0F;
3454a49301eSmrg            }
3464a49301eSmrg            else if (texImage->_BaseFormat == GL_LUMINANCE) {
3474a49301eSmrg               rgba[col][GCOMP] = 0.0F;
3484a49301eSmrg               rgba[col][BCOMP] = 0.0F;
3494a49301eSmrg               rgba[col][ACOMP] = 1.0F;
3504a49301eSmrg            }
3514a49301eSmrg            else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
3524a49301eSmrg               rgba[col][GCOMP] = 0.0F;
3534a49301eSmrg               rgba[col][BCOMP] = 0.0F;
3544a49301eSmrg            }
3554a49301eSmrg            else if (texImage->_BaseFormat == GL_INTENSITY) {
3564a49301eSmrg               rgba[col][GCOMP] = 0.0F;
3574a49301eSmrg               rgba[col][BCOMP] = 0.0F;
3584a49301eSmrg               rgba[col][ACOMP] = 1.0F;
3594a49301eSmrg            }
3604a49301eSmrg         }
3614a49301eSmrg         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
3624a49301eSmrg                                    format, type, dest,
3634a49301eSmrg                                    &ctx->Pack, transferOps);
3644a49301eSmrg      }
3654a49301eSmrg   }
3664a49301eSmrg}
3674a49301eSmrg
3684a49301eSmrg
3694a49301eSmrg/**
3704a49301eSmrg * Try to do glGetTexImage() with simple memcpy().
3714a49301eSmrg * \return GL_TRUE if done, GL_FALSE otherwise
3724a49301eSmrg */
3734a49301eSmrgstatic GLboolean
3744a49301eSmrgget_tex_memcpy(GLcontext *ctx, GLenum format, GLenum type, GLvoid *pixels,
3754a49301eSmrg               const struct gl_texture_object *texObj,
3764a49301eSmrg               const struct gl_texture_image *texImage)
3774a49301eSmrg{
3784a49301eSmrg   GLboolean memCopy = GL_FALSE;
3794a49301eSmrg
3804a49301eSmrg   /* Texture image should have been mapped already */
3814a49301eSmrg   assert(texImage->Data);
3824a49301eSmrg
3834a49301eSmrg   /*
3844a49301eSmrg    * Check if the src/dst formats are compatible.
3854a49301eSmrg    * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
3864a49301eSmrg    * so we don't have to worry about those.
3874a49301eSmrg    * XXX more format combinations could be supported here.
3884a49301eSmrg    */
3894a49301eSmrg   if ((texObj->Target == GL_TEXTURE_1D ||
3904a49301eSmrg        texObj->Target == GL_TEXTURE_2D ||
3914a49301eSmrg        texObj->Target == GL_TEXTURE_RECTANGLE ||
3924a49301eSmrg        (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
3934a49301eSmrg         texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
3944a49301eSmrg      if (texImage->TexFormat == MESA_FORMAT_ARGB8888 &&
3954a49301eSmrg          format == GL_BGRA &&
3964a49301eSmrg          type == GL_UNSIGNED_BYTE &&
3974a49301eSmrg          !ctx->Pack.SwapBytes &&
3984a49301eSmrg          _mesa_little_endian()) {
3994a49301eSmrg         memCopy = GL_TRUE;
4004a49301eSmrg      }
4014a49301eSmrg      else if (texImage->TexFormat == MESA_FORMAT_AL88 &&
4024a49301eSmrg               format == GL_LUMINANCE_ALPHA &&
4034a49301eSmrg               type == GL_UNSIGNED_BYTE &&
4044a49301eSmrg               !ctx->Pack.SwapBytes &&
4054a49301eSmrg               _mesa_little_endian()) {
4064a49301eSmrg         memCopy = GL_TRUE;
4074a49301eSmrg      }
4084a49301eSmrg      else if (texImage->TexFormat == MESA_FORMAT_L8 &&
4094a49301eSmrg               format == GL_LUMINANCE &&
4104a49301eSmrg               type == GL_UNSIGNED_BYTE) {
4114a49301eSmrg         memCopy = GL_TRUE;
4124a49301eSmrg      }
4134a49301eSmrg      else if (texImage->TexFormat == MESA_FORMAT_A8 &&
4144a49301eSmrg               format == GL_ALPHA &&
4154a49301eSmrg               type == GL_UNSIGNED_BYTE) {
4164a49301eSmrg         memCopy = GL_TRUE;
4174a49301eSmrg      }
4184a49301eSmrg   }
4194a49301eSmrg
4204a49301eSmrg   if (memCopy) {
4214a49301eSmrg      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
4224a49301eSmrg      const GLuint bytesPerRow = texImage->Width * bpp;
4234a49301eSmrg      GLubyte *dst =
4244a49301eSmrg         _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
4254a49301eSmrg                               texImage->Height, format, type, 0, 0);
4264a49301eSmrg      const GLint dstRowStride =
4274a49301eSmrg         _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
4284a49301eSmrg      const GLubyte *src = texImage->Data;
4294a49301eSmrg      const GLint srcRowStride = texImage->RowStride * bpp;
4304a49301eSmrg      GLuint row;
4314a49301eSmrg
4324a49301eSmrg      if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
4334a49301eSmrg         memcpy(dst, src, bytesPerRow * texImage->Height);
4344a49301eSmrg      }
4354a49301eSmrg      else {
4364a49301eSmrg         for (row = 0; row < texImage->Height; row++) {
4374a49301eSmrg            memcpy(dst, src, bytesPerRow);
4384a49301eSmrg            dst += dstRowStride;
4394a49301eSmrg            src += srcRowStride;
4404a49301eSmrg         }
4414a49301eSmrg      }
4424a49301eSmrg   }
4434a49301eSmrg
4444a49301eSmrg   return memCopy;
4454a49301eSmrg}
4464a49301eSmrg
4474a49301eSmrg
4484a49301eSmrg/**
4494a49301eSmrg * This is the software fallback for Driver.GetTexImage().
4504a49301eSmrg * All error checking will have been done before this routine is called.
4514a49301eSmrg * The texture image must be mapped.
4524a49301eSmrg */
4534a49301eSmrgvoid
4544a49301eSmrg_mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
4554a49301eSmrg                   GLenum format, GLenum type, GLvoid *pixels,
4564a49301eSmrg                   struct gl_texture_object *texObj,
4574a49301eSmrg                   struct gl_texture_image *texImage)
4584a49301eSmrg{
4594a49301eSmrg   GLuint dimensions;
4604a49301eSmrg
4614a49301eSmrg   /* If we get here, the texture image should be mapped */
4624a49301eSmrg   assert(texImage->Data);
4634a49301eSmrg
4644a49301eSmrg   switch (target) {
4654a49301eSmrg   case GL_TEXTURE_1D:
4664a49301eSmrg      dimensions = 1;
4674a49301eSmrg      break;
4684a49301eSmrg   case GL_TEXTURE_3D:
4694a49301eSmrg      dimensions = 3;
4704a49301eSmrg      break;
4714a49301eSmrg   default:
4724a49301eSmrg      dimensions = 2;
4734a49301eSmrg   }
4744a49301eSmrg
4754a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
4764a49301eSmrg      /* Packing texture image into a PBO.
4774a49301eSmrg       * Map the (potentially) VRAM-based buffer into our process space so
4784a49301eSmrg       * we can write into it with the code below.
4794a49301eSmrg       * A hardware driver might use a sophisticated blit to move the
4804a49301eSmrg       * texture data to the PBO if the PBO is in VRAM along with the texture.
4814a49301eSmrg       */
4824a49301eSmrg      GLubyte *buf = (GLubyte *)
4834a49301eSmrg         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
4844a49301eSmrg                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
4854a49301eSmrg      if (!buf) {
4864a49301eSmrg         /* out of memory or other unexpected error */
4874a49301eSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
4884a49301eSmrg         return;
4894a49301eSmrg      }
4904a49301eSmrg      /* <pixels> was an offset into the PBO.
4914a49301eSmrg       * Now make it a real, client-side pointer inside the mapped region.
4924a49301eSmrg       */
4934a49301eSmrg      pixels = ADD_POINTERS(buf, pixels);
4944a49301eSmrg   }
4954a49301eSmrg
4964a49301eSmrg   if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) {
4974a49301eSmrg      /* all done */
4984a49301eSmrg   }
4994a49301eSmrg   else if (format == GL_COLOR_INDEX) {
5004a49301eSmrg      get_tex_color_index(ctx, dimensions, format, type, pixels, texImage);
5014a49301eSmrg   }
5024a49301eSmrg   else if (format == GL_DEPTH_COMPONENT) {
5034a49301eSmrg      get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
5044a49301eSmrg   }
5054a49301eSmrg   else if (format == GL_DEPTH_STENCIL_EXT) {
5064a49301eSmrg      get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
5074a49301eSmrg   }
5084a49301eSmrg   else if (format == GL_YCBCR_MESA) {
5094a49301eSmrg      get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
5104a49301eSmrg   }
5114a49301eSmrg   else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) {
5124a49301eSmrg      get_tex_srgb(ctx, dimensions, format, type, pixels, texImage);
5134a49301eSmrg   }
5144a49301eSmrg   else {
5154a49301eSmrg      get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
5164a49301eSmrg   }
5174a49301eSmrg
5184a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
5194a49301eSmrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
5204a49301eSmrg                              ctx->Pack.BufferObj);
5214a49301eSmrg   }
5224a49301eSmrg}
5234a49301eSmrg
5244a49301eSmrg
5254a49301eSmrg
5264a49301eSmrg/**
5274a49301eSmrg * This is the software fallback for Driver.GetCompressedTexImage().
5284a49301eSmrg * All error checking will have been done before this routine is called.
5294a49301eSmrg */
5304a49301eSmrgvoid
5314a49301eSmrg_mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
5324a49301eSmrg                              GLvoid *img,
5334a49301eSmrg                              struct gl_texture_object *texObj,
5344a49301eSmrg                              struct gl_texture_image *texImage)
5354a49301eSmrg{
5364a49301eSmrg   const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat,
5374a49301eSmrg                                                     texImage->Width);
5384a49301eSmrg   const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat,
5394a49301eSmrg                                                            texImage->RowStride);
5404a49301eSmrg   GLuint i;
5414a49301eSmrg
5424a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
5434a49301eSmrg      /* pack texture image into a PBO */
5444a49301eSmrg      GLubyte *buf = (GLubyte *)
5454a49301eSmrg         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
5464a49301eSmrg                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
5474a49301eSmrg      if (!buf) {
5484a49301eSmrg         /* out of memory or other unexpected error */
5494a49301eSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY,
5504a49301eSmrg                     "glGetCompresssedTexImage(map PBO failed)");
5514a49301eSmrg         return;
5524a49301eSmrg      }
5534a49301eSmrg      img = ADD_POINTERS(buf, img);
5544a49301eSmrg   }
5554a49301eSmrg
5564a49301eSmrg   /* no pixelstore or pixel transfer, but respect stride */
5574a49301eSmrg
5584a49301eSmrg   if (row_stride == row_stride_stored) {
5594a49301eSmrg      const GLuint size = _mesa_format_image_size(texImage->TexFormat,
5604a49301eSmrg                                                  texImage->Width,
5614a49301eSmrg                                                  texImage->Height,
5624a49301eSmrg                                                  texImage->Depth);
563cdc920a0Smrg      memcpy(img, texImage->Data, size);
5644a49301eSmrg   }
5654a49301eSmrg   else {
5664a49301eSmrg      GLuint bw, bh;
5674a49301eSmrg      _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
5684a49301eSmrg      for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
5694a49301eSmrg         memcpy((GLubyte *)img + i * row_stride,
570cdc920a0Smrg                (GLubyte *)texImage->Data + i * row_stride_stored,
571cdc920a0Smrg                row_stride);
5724a49301eSmrg      }
5734a49301eSmrg   }
5744a49301eSmrg
5754a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
5764a49301eSmrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
5774a49301eSmrg                              ctx->Pack.BufferObj);
5784a49301eSmrg   }
5794a49301eSmrg}
5804a49301eSmrg
5814a49301eSmrg
5824a49301eSmrg
5834a49301eSmrg/**
5844a49301eSmrg * Do error checking for a glGetTexImage() call.
5854a49301eSmrg * \return GL_TRUE if any error, GL_FALSE if no errors.
5864a49301eSmrg */
5874a49301eSmrgstatic GLboolean
5884a49301eSmrggetteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
5894a49301eSmrg                        GLenum format, GLenum type, GLvoid *pixels )
5904a49301eSmrg{
5914a49301eSmrg   struct gl_texture_object *texObj;
5924a49301eSmrg   struct gl_texture_image *texImage;
593cdc920a0Smrg   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
5944a49301eSmrg   GLenum baseFormat;
5954a49301eSmrg
5964a49301eSmrg   if (maxLevels == 0) {
5974a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
5984a49301eSmrg      return GL_TRUE;
5994a49301eSmrg   }
6004a49301eSmrg
6014a49301eSmrg   if (level < 0 || level >= maxLevels) {
6024a49301eSmrg      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
6034a49301eSmrg      return GL_TRUE;
6044a49301eSmrg   }
6054a49301eSmrg
6064a49301eSmrg   if (_mesa_sizeof_packed_type(type) <= 0) {
6074a49301eSmrg      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
6084a49301eSmrg      return GL_TRUE;
6094a49301eSmrg   }
6104a49301eSmrg
6114a49301eSmrg   if (_mesa_components_in_format(format) <= 0 ||
6124a49301eSmrg       format == GL_STENCIL_INDEX) {
6134a49301eSmrg      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
6144a49301eSmrg      return GL_TRUE;
6154a49301eSmrg   }
6164a49301eSmrg
6174a49301eSmrg   if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
6184a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
6194a49301eSmrg      return GL_TRUE;
6204a49301eSmrg   }
6214a49301eSmrg
6224a49301eSmrg   if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
6234a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
6244a49301eSmrg      return GL_TRUE;
6254a49301eSmrg   }
6264a49301eSmrg
6274a49301eSmrg   if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
6284a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
6294a49301eSmrg      return GL_TRUE;
6304a49301eSmrg   }
6314a49301eSmrg
6324a49301eSmrg   if (!ctx->Extensions.EXT_packed_depth_stencil
6334a49301eSmrg       && _mesa_is_depthstencil_format(format)) {
6344a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
6354a49301eSmrg      return GL_TRUE;
6364a49301eSmrg   }
6374a49301eSmrg
6384a49301eSmrg   if (!ctx->Extensions.ATI_envmap_bumpmap
6394a49301eSmrg       && _mesa_is_dudv_format(format)) {
6404a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
6414a49301eSmrg      return GL_TRUE;
6424a49301eSmrg   }
6434a49301eSmrg
6444a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
6454a49301eSmrg
6464a49301eSmrg   if (!texObj || _mesa_is_proxy_texture(target)) {
6474a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
6484a49301eSmrg      return GL_TRUE;
6494a49301eSmrg   }
6504a49301eSmrg
6514a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
6524a49301eSmrg   if (!texImage) {
6534a49301eSmrg      /* out of memory */
6544a49301eSmrg      return GL_TRUE;
6554a49301eSmrg   }
6564a49301eSmrg
6574a49301eSmrg   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
6584a49301eSmrg
6594a49301eSmrg   /* Make sure the requested image format is compatible with the
6604a49301eSmrg    * texture's format.  Note that a color index texture can be converted
6614a49301eSmrg    * to RGBA so that combo is allowed.
6624a49301eSmrg    */
6634a49301eSmrg   if (_mesa_is_color_format(format)
6644a49301eSmrg       && !_mesa_is_color_format(baseFormat)
6654a49301eSmrg       && !_mesa_is_index_format(baseFormat)) {
6664a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6674a49301eSmrg      return GL_TRUE;
6684a49301eSmrg   }
6694a49301eSmrg   else if (_mesa_is_index_format(format)
6704a49301eSmrg            && !_mesa_is_index_format(baseFormat)) {
6714a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6724a49301eSmrg      return GL_TRUE;
6734a49301eSmrg   }
6744a49301eSmrg   else if (_mesa_is_depth_format(format)
6754a49301eSmrg            && !_mesa_is_depth_format(baseFormat)
6764a49301eSmrg            && !_mesa_is_depthstencil_format(baseFormat)) {
6774a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6784a49301eSmrg      return GL_TRUE;
6794a49301eSmrg   }
6804a49301eSmrg   else if (_mesa_is_ycbcr_format(format)
6814a49301eSmrg            && !_mesa_is_ycbcr_format(baseFormat)) {
6824a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6834a49301eSmrg      return GL_TRUE;
6844a49301eSmrg   }
6854a49301eSmrg   else if (_mesa_is_depthstencil_format(format)
6864a49301eSmrg            && !_mesa_is_depthstencil_format(baseFormat)) {
6874a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6884a49301eSmrg      return GL_TRUE;
6894a49301eSmrg   }
6904a49301eSmrg   else if (_mesa_is_dudv_format(format)
6914a49301eSmrg            && !_mesa_is_dudv_format(baseFormat)) {
6924a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6934a49301eSmrg      return GL_TRUE;
6944a49301eSmrg   }
6954a49301eSmrg
6964a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
6974a49301eSmrg      /* packing texture image into a PBO */
6984a49301eSmrg      const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
6994a49301eSmrg      if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
7004a49301eSmrg                                     texImage->Height, texImage->Depth,
7014a49301eSmrg                                     format, type, pixels)) {
7024a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
7034a49301eSmrg                     "glGetTexImage(out of bounds PBO write)");
7044a49301eSmrg         return GL_TRUE;
7054a49301eSmrg      }
7064a49301eSmrg
7074a49301eSmrg      /* PBO should not be mapped */
7084a49301eSmrg      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
7094a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
7104a49301eSmrg                     "glGetTexImage(PBO is mapped)");
7114a49301eSmrg         return GL_TRUE;
7124a49301eSmrg      }
7134a49301eSmrg   }
7144a49301eSmrg
7154a49301eSmrg   return GL_FALSE;
7164a49301eSmrg}
7174a49301eSmrg
7184a49301eSmrg
7194a49301eSmrg
7204a49301eSmrg/**
7214a49301eSmrg * Get texture image.  Called by glGetTexImage.
7224a49301eSmrg *
7234a49301eSmrg * \param target texture target.
7244a49301eSmrg * \param level image level.
7254a49301eSmrg * \param format pixel data format for returned image.
7264a49301eSmrg * \param type pixel data type for returned image.
7274a49301eSmrg * \param pixels returned pixel data.
7284a49301eSmrg */
7294a49301eSmrgvoid GLAPIENTRY
7304a49301eSmrg_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
7314a49301eSmrg                   GLenum type, GLvoid *pixels )
7324a49301eSmrg{
7334a49301eSmrg   struct gl_texture_object *texObj;
7344a49301eSmrg   struct gl_texture_image *texImage;
7354a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
7364a49301eSmrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
7374a49301eSmrg
7384a49301eSmrg   if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
7394a49301eSmrg      return;
7404a49301eSmrg   }
7414a49301eSmrg
7424a49301eSmrg   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
7434a49301eSmrg      /* not an error, do nothing */
7444a49301eSmrg      return;
7454a49301eSmrg   }
7464a49301eSmrg
7474a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
7484a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
7494a49301eSmrg
7504a49301eSmrg   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
7514a49301eSmrg      _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
7524a49301eSmrg                  " dstFmt=0x%x, dstType=0x%x\n",
7534a49301eSmrg                  texObj->Name,
7544a49301eSmrg                  _mesa_get_format_name(texImage->TexFormat),
7554a49301eSmrg                  texImage->Width, texImage->Height,
7564a49301eSmrg                  format, type);
7574a49301eSmrg   }
7584a49301eSmrg
7594a49301eSmrg   _mesa_lock_texture(ctx, texObj);
7604a49301eSmrg   {
7614a49301eSmrg      ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
7624a49301eSmrg                              texObj, texImage);
7634a49301eSmrg   }
7644a49301eSmrg   _mesa_unlock_texture(ctx, texObj);
7654a49301eSmrg}
7664a49301eSmrg
7674a49301eSmrg
7684a49301eSmrg
7694a49301eSmrg/**
7704a49301eSmrg * Do error checking for a glGetCompressedTexImage() call.
7714a49301eSmrg * \return GL_TRUE if any error, GL_FALSE if no errors.
7724a49301eSmrg */
7734a49301eSmrgstatic GLboolean
7744a49301eSmrggetcompressedteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
7754a49301eSmrg                                  GLvoid *img)
7764a49301eSmrg{
7774a49301eSmrg   struct gl_texture_object *texObj;
7784a49301eSmrg   struct gl_texture_image *texImage;
779cdc920a0Smrg   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
7804a49301eSmrg
7814a49301eSmrg   if (maxLevels == 0) {
7824a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
7834a49301eSmrg                  target);
7844a49301eSmrg      return GL_TRUE;
7854a49301eSmrg   }
7864a49301eSmrg
7874a49301eSmrg   if (level < 0 || level >= maxLevels) {
7884a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
7894a49301eSmrg                  "glGetCompressedTexImageARB(bad level = %d)", level);
7904a49301eSmrg      return GL_TRUE;
7914a49301eSmrg   }
7924a49301eSmrg
7934a49301eSmrg   if (_mesa_is_proxy_texture(target)) {
7944a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
7954a49301eSmrg                  "glGetCompressedTexImageARB(bad target = %s)",
7964a49301eSmrg                  _mesa_lookup_enum_by_nr(target));
7974a49301eSmrg      return GL_TRUE;
7984a49301eSmrg   }
7994a49301eSmrg
8004a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
8014a49301eSmrg   if (!texObj) {
8024a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
8034a49301eSmrg      return GL_TRUE;
8044a49301eSmrg   }
8054a49301eSmrg
8064a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
8074a49301eSmrg
8084a49301eSmrg   if (!texImage) {
8094a49301eSmrg      /* probably invalid mipmap level */
8104a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
8114a49301eSmrg                  "glGetCompressedTexImageARB(level)");
8124a49301eSmrg      return GL_TRUE;
8134a49301eSmrg   }
8144a49301eSmrg
8154a49301eSmrg   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
8164a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
8174a49301eSmrg                  "glGetCompressedTexImageARB(texture is not compressed)");
8184a49301eSmrg      return GL_TRUE;
8194a49301eSmrg   }
8204a49301eSmrg
8214a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
8224a49301eSmrg      GLuint compressedSize;
8234a49301eSmrg
8244a49301eSmrg      /* make sure PBO is not mapped */
8254a49301eSmrg      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
8264a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
8274a49301eSmrg                     "glGetCompressedTexImage(PBO is mapped)");
8284a49301eSmrg         return GL_TRUE;
8294a49301eSmrg      }
8304a49301eSmrg
8314a49301eSmrg      compressedSize = _mesa_format_image_size(texImage->TexFormat,
8324a49301eSmrg                                               texImage->Width,
8334a49301eSmrg                                               texImage->Height,
8344a49301eSmrg                                               texImage->Depth);
8354a49301eSmrg
8364a49301eSmrg      /* do bounds checking on PBO write */
8374a49301eSmrg      if ((const GLubyte *) img + compressedSize >
8384a49301eSmrg          (const GLubyte *) ctx->Pack.BufferObj->Size) {
8394a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
8404a49301eSmrg                     "glGetCompressedTexImage(out of bounds PBO write)");
8414a49301eSmrg         return GL_TRUE;
8424a49301eSmrg      }
8434a49301eSmrg   }
8444a49301eSmrg
8454a49301eSmrg   return GL_FALSE;
8464a49301eSmrg}
8474a49301eSmrg
8484a49301eSmrg
8494a49301eSmrgvoid GLAPIENTRY
8504a49301eSmrg_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
8514a49301eSmrg{
8524a49301eSmrg   struct gl_texture_object *texObj;
8534a49301eSmrg   struct gl_texture_image *texImage;
8544a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
8554a49301eSmrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
8564a49301eSmrg
8574a49301eSmrg   if (getcompressedteximage_error_check(ctx, target, level, img)) {
8584a49301eSmrg      return;
8594a49301eSmrg   }
8604a49301eSmrg
8614a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
8624a49301eSmrg      /* not an error, do nothing */
8634a49301eSmrg      return;
8644a49301eSmrg   }
8654a49301eSmrg
8664a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
8674a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
8684a49301eSmrg
8694a49301eSmrg   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
8704a49301eSmrg      _mesa_debug(ctx,
8714a49301eSmrg                  "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
8724a49301eSmrg                  texObj->Name,
8734a49301eSmrg                  _mesa_get_format_name(texImage->TexFormat),
8744a49301eSmrg                  texImage->Width, texImage->Height);
8754a49301eSmrg   }
8764a49301eSmrg
8774a49301eSmrg   _mesa_lock_texture(ctx, texObj);
8784a49301eSmrg   {
8794a49301eSmrg      ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
8804a49301eSmrg                                        texObj, texImage);
8814a49301eSmrg   }
8824a49301eSmrg   _mesa_unlock_texture(ctx, texObj);
8834a49301eSmrg}
884