texgetimage.c revision 3464ebd5
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"
383464ebd5Sriastradh#include "mfeatures.h"
393464ebd5Sriastradh#include "mtypes.h"
403464ebd5Sriastradh#include "pack.h"
413464ebd5Sriastradh#include "pbo.h"
424a49301eSmrg#include "texgetimage.h"
433464ebd5Sriastradh#include "texfetch.h"
444a49301eSmrg#include "teximage.h"
454a49301eSmrg
464a49301eSmrg
474a49301eSmrg
484a49301eSmrg/**
494a49301eSmrg * Can the given type represent negative values?
504a49301eSmrg */
514a49301eSmrgstatic INLINE GLboolean
524a49301eSmrgtype_with_negative_values(GLenum type)
534a49301eSmrg{
544a49301eSmrg   switch (type) {
554a49301eSmrg   case GL_BYTE:
564a49301eSmrg   case GL_SHORT:
574a49301eSmrg   case GL_INT:
584a49301eSmrg   case GL_FLOAT:
594a49301eSmrg   case GL_HALF_FLOAT_ARB:
604a49301eSmrg      return GL_TRUE;
614a49301eSmrg   default:
624a49301eSmrg      return GL_FALSE;
634a49301eSmrg   }
644a49301eSmrg}
654a49301eSmrg
664a49301eSmrg
674a49301eSmrg/**
684a49301eSmrg * glGetTexImage for color index pixels.
694a49301eSmrg */
704a49301eSmrgstatic void
713464ebd5Sriastradhget_tex_color_index(struct gl_context *ctx, GLuint dimensions,
724a49301eSmrg                    GLenum format, GLenum type, GLvoid *pixels,
734a49301eSmrg                    const struct gl_texture_image *texImage)
744a49301eSmrg{
754a49301eSmrg   const GLint width = texImage->Width;
764a49301eSmrg   const GLint height = texImage->Height;
774a49301eSmrg   const GLint depth = texImage->Depth;
783464ebd5Sriastradh   const GLint rowstride = texImage->RowStride;
794a49301eSmrg   const GLuint indexBits =
804a49301eSmrg      _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
814a49301eSmrg   const GLbitfield transferOps = 0x0;
824a49301eSmrg   GLint img, row, col;
834a49301eSmrg
844a49301eSmrg   for (img = 0; img < depth; img++) {
854a49301eSmrg      for (row = 0; row < height; row++) {
864a49301eSmrg         GLuint indexRow[MAX_WIDTH] = { 0 };
874a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
884a49301eSmrg                                          width, height, format, type,
894a49301eSmrg                                          img, row, 0);
904a49301eSmrg         assert(dest);
914a49301eSmrg
924a49301eSmrg         if (indexBits == 8) {
934a49301eSmrg            const GLubyte *src = (const GLubyte *) texImage->Data;
943464ebd5Sriastradh            src += rowstride * (img * height + row);
954a49301eSmrg            for (col = 0; col < width; col++) {
964a49301eSmrg               indexRow[col] = src[col];
974a49301eSmrg            }
984a49301eSmrg         }
994a49301eSmrg         else if (indexBits == 16) {
1004a49301eSmrg            const GLushort *src = (const GLushort *) texImage->Data;
1013464ebd5Sriastradh            src += rowstride * (img * height + row);
1024a49301eSmrg            for (col = 0; col < width; col++) {
1034a49301eSmrg               indexRow[col] = src[col];
1044a49301eSmrg            }
1054a49301eSmrg         }
1064a49301eSmrg         else {
1074a49301eSmrg            _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage");
1084a49301eSmrg         }
1094a49301eSmrg         _mesa_pack_index_span(ctx, width, type, dest,
1104a49301eSmrg                               indexRow, &ctx->Pack, transferOps);
1114a49301eSmrg      }
1124a49301eSmrg   }
1134a49301eSmrg}
1144a49301eSmrg
1154a49301eSmrg
1164a49301eSmrg/**
1174a49301eSmrg * glGetTexImage for depth/Z pixels.
1184a49301eSmrg */
1194a49301eSmrgstatic void
1203464ebd5Sriastradhget_tex_depth(struct gl_context *ctx, GLuint dimensions,
1214a49301eSmrg              GLenum format, GLenum type, GLvoid *pixels,
1224a49301eSmrg              const struct gl_texture_image *texImage)
1234a49301eSmrg{
1244a49301eSmrg   const GLint width = texImage->Width;
1254a49301eSmrg   const GLint height = texImage->Height;
1264a49301eSmrg   const GLint depth = texImage->Depth;
1274a49301eSmrg   GLint img, row, col;
1283464ebd5Sriastradh   GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat));
1293464ebd5Sriastradh
1303464ebd5Sriastradh   if (!depthRow) {
1313464ebd5Sriastradh      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
1323464ebd5Sriastradh      return;
1333464ebd5Sriastradh   }
1344a49301eSmrg
1354a49301eSmrg   for (img = 0; img < depth; img++) {
1364a49301eSmrg      for (row = 0; row < height; row++) {
1374a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
1384a49301eSmrg                                          width, height, format, type,
1394a49301eSmrg                                          img, row, 0);
1404a49301eSmrg         assert(dest);
1414a49301eSmrg
1424a49301eSmrg         for (col = 0; col < width; col++) {
1434a49301eSmrg            texImage->FetchTexelf(texImage, col, row, img, depthRow + col);
1444a49301eSmrg         }
1454a49301eSmrg         _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
1464a49301eSmrg      }
1474a49301eSmrg   }
1483464ebd5Sriastradh
1493464ebd5Sriastradh   free(depthRow);
1504a49301eSmrg}
1514a49301eSmrg
1524a49301eSmrg
1534a49301eSmrg/**
1544a49301eSmrg * glGetTexImage for depth/stencil pixels.
1554a49301eSmrg */
1564a49301eSmrgstatic void
1573464ebd5Sriastradhget_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
1584a49301eSmrg                      GLenum format, GLenum type, GLvoid *pixels,
1594a49301eSmrg                      const struct gl_texture_image *texImage)
1604a49301eSmrg{
1614a49301eSmrg   const GLint width = texImage->Width;
1624a49301eSmrg   const GLint height = texImage->Height;
1634a49301eSmrg   const GLint depth = texImage->Depth;
1643464ebd5Sriastradh   const GLint rowstride = texImage->RowStride;
1654a49301eSmrg   const GLuint *src = (const GLuint *) texImage->Data;
1664a49301eSmrg   GLint img, row;
1674a49301eSmrg
1684a49301eSmrg   for (img = 0; img < depth; img++) {
1694a49301eSmrg      for (row = 0; row < height; row++) {
1704a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
1714a49301eSmrg                                          width, height, format, type,
1724a49301eSmrg                                          img, row, 0);
173cdc920a0Smrg         memcpy(dest, src, width * sizeof(GLuint));
1744a49301eSmrg         if (ctx->Pack.SwapBytes) {
1754a49301eSmrg            _mesa_swap4((GLuint *) dest, width);
1764a49301eSmrg         }
1774a49301eSmrg
1783464ebd5Sriastradh         src += rowstride;
1794a49301eSmrg      }
1804a49301eSmrg   }
1814a49301eSmrg}
1824a49301eSmrg
1834a49301eSmrg
1844a49301eSmrg/**
1854a49301eSmrg * glGetTexImage for YCbCr pixels.
1864a49301eSmrg */
1874a49301eSmrgstatic void
1883464ebd5Sriastradhget_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
1894a49301eSmrg              GLenum format, GLenum type, GLvoid *pixels,
1904a49301eSmrg              const struct gl_texture_image *texImage)
1914a49301eSmrg{
1924a49301eSmrg   const GLint width = texImage->Width;
1934a49301eSmrg   const GLint height = texImage->Height;
1944a49301eSmrg   const GLint depth = texImage->Depth;
1954a49301eSmrg   const GLint rowstride = texImage->RowStride;
1964a49301eSmrg   const GLushort *src = (const GLushort *) texImage->Data;
1974a49301eSmrg   GLint img, row;
1984a49301eSmrg
1994a49301eSmrg   for (img = 0; img < depth; img++) {
2004a49301eSmrg      for (row = 0; row < height; row++) {
2014a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
2024a49301eSmrg                                          width, height, format, type,
2034a49301eSmrg                                          img, row, 0);
204cdc920a0Smrg         memcpy(dest, src, width * sizeof(GLushort));
2054a49301eSmrg
2064a49301eSmrg         /* check for byte swapping */
2074a49301eSmrg         if ((texImage->TexFormat == MESA_FORMAT_YCBCR
2084a49301eSmrg              && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
2094a49301eSmrg             (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
2104a49301eSmrg              && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
2114a49301eSmrg            if (!ctx->Pack.SwapBytes)
2124a49301eSmrg               _mesa_swap2((GLushort *) dest, width);
2134a49301eSmrg         }
2144a49301eSmrg         else if (ctx->Pack.SwapBytes) {
2154a49301eSmrg            _mesa_swap2((GLushort *) dest, width);
2164a49301eSmrg         }
2174a49301eSmrg
2184a49301eSmrg         src += rowstride;
2194a49301eSmrg      }
2204a49301eSmrg   }
2214a49301eSmrg}
2224a49301eSmrg
2234a49301eSmrg
2244a49301eSmrg/**
2253464ebd5Sriastradh * glGetTexImage for (s)RGBA, Luminance, etc. pixels.
2264a49301eSmrg * This is the slow way since we use texture sampling.
2274a49301eSmrg */
2284a49301eSmrgstatic void
2293464ebd5Sriastradhget_tex_rgba(struct gl_context *ctx, GLuint dimensions,
2304a49301eSmrg             GLenum format, GLenum type, GLvoid *pixels,
2313464ebd5Sriastradh             struct gl_texture_image *texImage)
2324a49301eSmrg{
2334a49301eSmrg   const GLint width = texImage->Width;
2344a49301eSmrg   const GLint height = texImage->Height;
2354a49301eSmrg   const GLint depth = texImage->Depth;
2363464ebd5Sriastradh   const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
2374a49301eSmrg   /* Normally, no pixel transfer ops are performed during glGetTexImage.
2384a49301eSmrg    * The only possible exception is component clamping to [0,1].
2394a49301eSmrg    */
2404a49301eSmrg   GLbitfield transferOps = 0x0;
2414a49301eSmrg   GLint img, row;
2423464ebd5Sriastradh   GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
2433464ebd5Sriastradh   const GLboolean is_sampler_srgb_decode =
2443464ebd5Sriastradh       _mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB &&
2453464ebd5Sriastradh       texImage->TexObject->Sampler.sRGBDecode == GL_DECODE_EXT;
2463464ebd5Sriastradh
2473464ebd5Sriastradh   if (!rgba) {
2483464ebd5Sriastradh      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
2493464ebd5Sriastradh      return;
2503464ebd5Sriastradh   }
2513464ebd5Sriastradh
2523464ebd5Sriastradh   /* Clamping does not apply to GetTexImage (final conversion)?
2533464ebd5Sriastradh    * Looks like we need clamp though when going from format
2543464ebd5Sriastradh    * containing negative values to unsigned format.
2553464ebd5Sriastradh    */
2563464ebd5Sriastradh   if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) {
2573464ebd5Sriastradh      transferOps |= IMAGE_CLAMP_BIT;
2583464ebd5Sriastradh   }
2593464ebd5Sriastradh   else if (!type_with_negative_values(type) &&
2603464ebd5Sriastradh            (dataType == GL_FLOAT ||
2613464ebd5Sriastradh             dataType == GL_SIGNED_NORMALIZED)) {
2623464ebd5Sriastradh      transferOps |= IMAGE_CLAMP_BIT;
2633464ebd5Sriastradh   }
2643464ebd5Sriastradh
2653464ebd5Sriastradh   /* glGetTexImage always returns sRGB data for sRGB textures. Make sure the
2663464ebd5Sriastradh    * fetch functions return sRGB data without linearizing it.
2673464ebd5Sriastradh    */
2683464ebd5Sriastradh   if (is_sampler_srgb_decode) {
2693464ebd5Sriastradh      texImage->TexObject->Sampler.sRGBDecode = GL_SKIP_DECODE_EXT;
2703464ebd5Sriastradh      _mesa_set_fetch_functions(texImage, dimensions);
2713464ebd5Sriastradh   }
2724a49301eSmrg
2734a49301eSmrg   for (img = 0; img < depth; img++) {
2744a49301eSmrg      for (row = 0; row < height; row++) {
2754a49301eSmrg         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
2764a49301eSmrg                                          width, height, format, type,
2774a49301eSmrg                                          img, row, 0);
2784a49301eSmrg         GLint col;
2794a49301eSmrg
2804a49301eSmrg         for (col = 0; col < width; col++) {
2814a49301eSmrg            texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
2824a49301eSmrg            if (texImage->_BaseFormat == GL_ALPHA) {
2834a49301eSmrg               rgba[col][RCOMP] = 0.0F;
2844a49301eSmrg               rgba[col][GCOMP] = 0.0F;
2854a49301eSmrg               rgba[col][BCOMP] = 0.0F;
2864a49301eSmrg            }
2874a49301eSmrg            else if (texImage->_BaseFormat == GL_LUMINANCE) {
2884a49301eSmrg               rgba[col][GCOMP] = 0.0F;
2894a49301eSmrg               rgba[col][BCOMP] = 0.0F;
2904a49301eSmrg               rgba[col][ACOMP] = 1.0F;
2914a49301eSmrg            }
2924a49301eSmrg            else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
2934a49301eSmrg               rgba[col][GCOMP] = 0.0F;
2944a49301eSmrg               rgba[col][BCOMP] = 0.0F;
2954a49301eSmrg            }
2964a49301eSmrg            else if (texImage->_BaseFormat == GL_INTENSITY) {
2974a49301eSmrg               rgba[col][GCOMP] = 0.0F;
2984a49301eSmrg               rgba[col][BCOMP] = 0.0F;
2994a49301eSmrg               rgba[col][ACOMP] = 1.0F;
3004a49301eSmrg            }
3014a49301eSmrg         }
3024a49301eSmrg         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
3034a49301eSmrg                                    format, type, dest,
3044a49301eSmrg                                    &ctx->Pack, transferOps);
3054a49301eSmrg      }
3064a49301eSmrg   }
3073464ebd5Sriastradh
3083464ebd5Sriastradh   if (is_sampler_srgb_decode) {
3093464ebd5Sriastradh      texImage->TexObject->Sampler.sRGBDecode = GL_DECODE_EXT;
3103464ebd5Sriastradh      _mesa_set_fetch_functions(texImage, dimensions);
3113464ebd5Sriastradh   }
3123464ebd5Sriastradh
3133464ebd5Sriastradh   free(rgba);
3144a49301eSmrg}
3154a49301eSmrg
3164a49301eSmrg
3174a49301eSmrg/**
3184a49301eSmrg * Try to do glGetTexImage() with simple memcpy().
3194a49301eSmrg * \return GL_TRUE if done, GL_FALSE otherwise
3204a49301eSmrg */
3214a49301eSmrgstatic GLboolean
3223464ebd5Sriastradhget_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels,
3234a49301eSmrg               const struct gl_texture_object *texObj,
3244a49301eSmrg               const struct gl_texture_image *texImage)
3254a49301eSmrg{
3264a49301eSmrg   GLboolean memCopy = GL_FALSE;
3274a49301eSmrg
3284a49301eSmrg   /* Texture image should have been mapped already */
3294a49301eSmrg   assert(texImage->Data);
3304a49301eSmrg
3314a49301eSmrg   /*
3324a49301eSmrg    * Check if the src/dst formats are compatible.
3334a49301eSmrg    * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
3344a49301eSmrg    * so we don't have to worry about those.
3354a49301eSmrg    * XXX more format combinations could be supported here.
3364a49301eSmrg    */
3374a49301eSmrg   if ((texObj->Target == GL_TEXTURE_1D ||
3384a49301eSmrg        texObj->Target == GL_TEXTURE_2D ||
3394a49301eSmrg        texObj->Target == GL_TEXTURE_RECTANGLE ||
3404a49301eSmrg        (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
3414a49301eSmrg         texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
3423464ebd5Sriastradh      if ((texImage->TexFormat == MESA_FORMAT_ARGB8888 ||
3433464ebd5Sriastradh             texImage->TexFormat == MESA_FORMAT_SARGB8) &&
3444a49301eSmrg          format == GL_BGRA &&
3453464ebd5Sriastradh          (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) &&
3464a49301eSmrg          !ctx->Pack.SwapBytes &&
3474a49301eSmrg          _mesa_little_endian()) {
3484a49301eSmrg         memCopy = GL_TRUE;
3494a49301eSmrg      }
3503464ebd5Sriastradh      else if ((texImage->TexFormat == MESA_FORMAT_AL88 ||
3513464ebd5Sriastradh                  texImage->TexFormat == MESA_FORMAT_SLA8) &&
3524a49301eSmrg               format == GL_LUMINANCE_ALPHA &&
3534a49301eSmrg               type == GL_UNSIGNED_BYTE &&
3544a49301eSmrg               !ctx->Pack.SwapBytes &&
3554a49301eSmrg               _mesa_little_endian()) {
3564a49301eSmrg         memCopy = GL_TRUE;
3574a49301eSmrg      }
3583464ebd5Sriastradh      else if ((texImage->TexFormat == MESA_FORMAT_L8 ||
3593464ebd5Sriastradh                  texImage->TexFormat == MESA_FORMAT_SL8) &&
3604a49301eSmrg               format == GL_LUMINANCE &&
3614a49301eSmrg               type == GL_UNSIGNED_BYTE) {
3624a49301eSmrg         memCopy = GL_TRUE;
3634a49301eSmrg      }
3643464ebd5Sriastradh      else if (texImage->TexFormat == MESA_FORMAT_L16 &&
3653464ebd5Sriastradh               format == GL_LUMINANCE &&
3663464ebd5Sriastradh               type == GL_UNSIGNED_SHORT) {
3673464ebd5Sriastradh         memCopy = GL_TRUE;
3683464ebd5Sriastradh      }
3694a49301eSmrg      else if (texImage->TexFormat == MESA_FORMAT_A8 &&
3704a49301eSmrg               format == GL_ALPHA &&
3714a49301eSmrg               type == GL_UNSIGNED_BYTE) {
3724a49301eSmrg         memCopy = GL_TRUE;
3734a49301eSmrg      }
3743464ebd5Sriastradh      else if (texImage->TexFormat == MESA_FORMAT_A16 &&
3753464ebd5Sriastradh               format == GL_ALPHA &&
3763464ebd5Sriastradh               type == GL_UNSIGNED_SHORT) {
3773464ebd5Sriastradh         memCopy = GL_TRUE;
3783464ebd5Sriastradh      }
3794a49301eSmrg   }
3804a49301eSmrg
3814a49301eSmrg   if (memCopy) {
3824a49301eSmrg      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
3834a49301eSmrg      const GLuint bytesPerRow = texImage->Width * bpp;
3844a49301eSmrg      GLubyte *dst =
3854a49301eSmrg         _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
3864a49301eSmrg                               texImage->Height, format, type, 0, 0);
3874a49301eSmrg      const GLint dstRowStride =
3884a49301eSmrg         _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
3894a49301eSmrg      const GLubyte *src = texImage->Data;
3904a49301eSmrg      const GLint srcRowStride = texImage->RowStride * bpp;
3914a49301eSmrg      GLuint row;
3924a49301eSmrg
3934a49301eSmrg      if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
3944a49301eSmrg         memcpy(dst, src, bytesPerRow * texImage->Height);
3954a49301eSmrg      }
3964a49301eSmrg      else {
3974a49301eSmrg         for (row = 0; row < texImage->Height; row++) {
3984a49301eSmrg            memcpy(dst, src, bytesPerRow);
3994a49301eSmrg            dst += dstRowStride;
4004a49301eSmrg            src += srcRowStride;
4014a49301eSmrg         }
4024a49301eSmrg      }
4034a49301eSmrg   }
4044a49301eSmrg
4054a49301eSmrg   return memCopy;
4064a49301eSmrg}
4074a49301eSmrg
4084a49301eSmrg
4094a49301eSmrg/**
4104a49301eSmrg * This is the software fallback for Driver.GetTexImage().
4114a49301eSmrg * All error checking will have been done before this routine is called.
4124a49301eSmrg * The texture image must be mapped.
4134a49301eSmrg */
4144a49301eSmrgvoid
4153464ebd5Sriastradh_mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level,
4164a49301eSmrg                   GLenum format, GLenum type, GLvoid *pixels,
4174a49301eSmrg                   struct gl_texture_object *texObj,
4184a49301eSmrg                   struct gl_texture_image *texImage)
4194a49301eSmrg{
4204a49301eSmrg   GLuint dimensions;
4214a49301eSmrg
4224a49301eSmrg   /* If we get here, the texture image should be mapped */
4234a49301eSmrg   assert(texImage->Data);
4244a49301eSmrg
4254a49301eSmrg   switch (target) {
4264a49301eSmrg   case GL_TEXTURE_1D:
4274a49301eSmrg      dimensions = 1;
4284a49301eSmrg      break;
4294a49301eSmrg   case GL_TEXTURE_3D:
4304a49301eSmrg      dimensions = 3;
4314a49301eSmrg      break;
4324a49301eSmrg   default:
4334a49301eSmrg      dimensions = 2;
4344a49301eSmrg   }
4354a49301eSmrg
4364a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
4374a49301eSmrg      /* Packing texture image into a PBO.
4384a49301eSmrg       * Map the (potentially) VRAM-based buffer into our process space so
4394a49301eSmrg       * we can write into it with the code below.
4404a49301eSmrg       * A hardware driver might use a sophisticated blit to move the
4414a49301eSmrg       * texture data to the PBO if the PBO is in VRAM along with the texture.
4424a49301eSmrg       */
4434a49301eSmrg      GLubyte *buf = (GLubyte *)
4444a49301eSmrg         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
4454a49301eSmrg                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
4464a49301eSmrg      if (!buf) {
4474a49301eSmrg         /* out of memory or other unexpected error */
4484a49301eSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
4494a49301eSmrg         return;
4504a49301eSmrg      }
4514a49301eSmrg      /* <pixels> was an offset into the PBO.
4524a49301eSmrg       * Now make it a real, client-side pointer inside the mapped region.
4534a49301eSmrg       */
4544a49301eSmrg      pixels = ADD_POINTERS(buf, pixels);
4554a49301eSmrg   }
4564a49301eSmrg
4574a49301eSmrg   if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) {
4584a49301eSmrg      /* all done */
4594a49301eSmrg   }
4604a49301eSmrg   else if (format == GL_COLOR_INDEX) {
4614a49301eSmrg      get_tex_color_index(ctx, dimensions, format, type, pixels, texImage);
4624a49301eSmrg   }
4634a49301eSmrg   else if (format == GL_DEPTH_COMPONENT) {
4644a49301eSmrg      get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
4654a49301eSmrg   }
4664a49301eSmrg   else if (format == GL_DEPTH_STENCIL_EXT) {
4674a49301eSmrg      get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
4684a49301eSmrg   }
4694a49301eSmrg   else if (format == GL_YCBCR_MESA) {
4704a49301eSmrg      get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
4714a49301eSmrg   }
4724a49301eSmrg   else {
4734a49301eSmrg      get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
4744a49301eSmrg   }
4754a49301eSmrg
4764a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
4774a49301eSmrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
4784a49301eSmrg                              ctx->Pack.BufferObj);
4794a49301eSmrg   }
4804a49301eSmrg}
4814a49301eSmrg
4824a49301eSmrg
4834a49301eSmrg
4844a49301eSmrg/**
4854a49301eSmrg * This is the software fallback for Driver.GetCompressedTexImage().
4864a49301eSmrg * All error checking will have been done before this routine is called.
4874a49301eSmrg */
4884a49301eSmrgvoid
4893464ebd5Sriastradh_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level,
4904a49301eSmrg                              GLvoid *img,
4914a49301eSmrg                              struct gl_texture_object *texObj,
4924a49301eSmrg                              struct gl_texture_image *texImage)
4934a49301eSmrg{
4944a49301eSmrg   const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat,
4954a49301eSmrg                                                     texImage->Width);
4964a49301eSmrg   const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat,
4974a49301eSmrg                                                            texImage->RowStride);
4984a49301eSmrg   GLuint i;
4994a49301eSmrg
5004a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
5014a49301eSmrg      /* pack texture image into a PBO */
5024a49301eSmrg      GLubyte *buf = (GLubyte *)
5034a49301eSmrg         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
5044a49301eSmrg                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
5054a49301eSmrg      if (!buf) {
5064a49301eSmrg         /* out of memory or other unexpected error */
5074a49301eSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY,
5084a49301eSmrg                     "glGetCompresssedTexImage(map PBO failed)");
5094a49301eSmrg         return;
5104a49301eSmrg      }
5114a49301eSmrg      img = ADD_POINTERS(buf, img);
5124a49301eSmrg   }
5134a49301eSmrg
5144a49301eSmrg   /* no pixelstore or pixel transfer, but respect stride */
5154a49301eSmrg
5164a49301eSmrg   if (row_stride == row_stride_stored) {
5174a49301eSmrg      const GLuint size = _mesa_format_image_size(texImage->TexFormat,
5184a49301eSmrg                                                  texImage->Width,
5194a49301eSmrg                                                  texImage->Height,
5204a49301eSmrg                                                  texImage->Depth);
521cdc920a0Smrg      memcpy(img, texImage->Data, size);
5224a49301eSmrg   }
5234a49301eSmrg   else {
5244a49301eSmrg      GLuint bw, bh;
5254a49301eSmrg      _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
5264a49301eSmrg      for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
5274a49301eSmrg         memcpy((GLubyte *)img + i * row_stride,
528cdc920a0Smrg                (GLubyte *)texImage->Data + i * row_stride_stored,
529cdc920a0Smrg                row_stride);
5304a49301eSmrg      }
5314a49301eSmrg   }
5324a49301eSmrg
5334a49301eSmrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
5344a49301eSmrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
5354a49301eSmrg                              ctx->Pack.BufferObj);
5364a49301eSmrg   }
5374a49301eSmrg}
5384a49301eSmrg
5394a49301eSmrg
5404a49301eSmrg
5414a49301eSmrg/**
5424a49301eSmrg * Do error checking for a glGetTexImage() call.
5434a49301eSmrg * \return GL_TRUE if any error, GL_FALSE if no errors.
5444a49301eSmrg */
5454a49301eSmrgstatic GLboolean
5463464ebd5Sriastradhgetteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
5473464ebd5Sriastradh                        GLenum format, GLenum type, GLsizei clientMemSize,
5483464ebd5Sriastradh                        GLvoid *pixels )
5494a49301eSmrg{
5504a49301eSmrg   struct gl_texture_object *texObj;
5514a49301eSmrg   struct gl_texture_image *texImage;
552cdc920a0Smrg   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
5533464ebd5Sriastradh   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
5544a49301eSmrg   GLenum baseFormat;
5554a49301eSmrg
5564a49301eSmrg   if (maxLevels == 0) {
5574a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
5584a49301eSmrg      return GL_TRUE;
5594a49301eSmrg   }
5604a49301eSmrg
5614a49301eSmrg   if (level < 0 || level >= maxLevels) {
5624a49301eSmrg      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
5634a49301eSmrg      return GL_TRUE;
5644a49301eSmrg   }
5654a49301eSmrg
5664a49301eSmrg   if (_mesa_sizeof_packed_type(type) <= 0) {
5674a49301eSmrg      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
5684a49301eSmrg      return GL_TRUE;
5694a49301eSmrg   }
5704a49301eSmrg
5714a49301eSmrg   if (_mesa_components_in_format(format) <= 0 ||
5724a49301eSmrg       format == GL_STENCIL_INDEX) {
5734a49301eSmrg      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
5744a49301eSmrg      return GL_TRUE;
5754a49301eSmrg   }
5764a49301eSmrg
5774a49301eSmrg   if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
5784a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
5794a49301eSmrg      return GL_TRUE;
5804a49301eSmrg   }
5814a49301eSmrg
5824a49301eSmrg   if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
5834a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
5844a49301eSmrg      return GL_TRUE;
5854a49301eSmrg   }
5864a49301eSmrg
5874a49301eSmrg   if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
5884a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
5894a49301eSmrg      return GL_TRUE;
5904a49301eSmrg   }
5914a49301eSmrg
5924a49301eSmrg   if (!ctx->Extensions.EXT_packed_depth_stencil
5934a49301eSmrg       && _mesa_is_depthstencil_format(format)) {
5944a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
5954a49301eSmrg      return GL_TRUE;
5964a49301eSmrg   }
5974a49301eSmrg
5984a49301eSmrg   if (!ctx->Extensions.ATI_envmap_bumpmap
5994a49301eSmrg       && _mesa_is_dudv_format(format)) {
6004a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
6014a49301eSmrg      return GL_TRUE;
6024a49301eSmrg   }
6034a49301eSmrg
6044a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
6054a49301eSmrg
6064a49301eSmrg   if (!texObj || _mesa_is_proxy_texture(target)) {
6074a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
6084a49301eSmrg      return GL_TRUE;
6094a49301eSmrg   }
6104a49301eSmrg
6114a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
6124a49301eSmrg   if (!texImage) {
6134a49301eSmrg      /* out of memory */
6144a49301eSmrg      return GL_TRUE;
6154a49301eSmrg   }
6164a49301eSmrg
6174a49301eSmrg   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
6184a49301eSmrg
6194a49301eSmrg   /* Make sure the requested image format is compatible with the
6204a49301eSmrg    * texture's format.  Note that a color index texture can be converted
6214a49301eSmrg    * to RGBA so that combo is allowed.
6224a49301eSmrg    */
6234a49301eSmrg   if (_mesa_is_color_format(format)
6244a49301eSmrg       && !_mesa_is_color_format(baseFormat)
6254a49301eSmrg       && !_mesa_is_index_format(baseFormat)) {
6264a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6274a49301eSmrg      return GL_TRUE;
6284a49301eSmrg   }
6294a49301eSmrg   else if (_mesa_is_index_format(format)
6304a49301eSmrg            && !_mesa_is_index_format(baseFormat)) {
6314a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6324a49301eSmrg      return GL_TRUE;
6334a49301eSmrg   }
6344a49301eSmrg   else if (_mesa_is_depth_format(format)
6354a49301eSmrg            && !_mesa_is_depth_format(baseFormat)
6364a49301eSmrg            && !_mesa_is_depthstencil_format(baseFormat)) {
6374a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6384a49301eSmrg      return GL_TRUE;
6394a49301eSmrg   }
6404a49301eSmrg   else if (_mesa_is_ycbcr_format(format)
6414a49301eSmrg            && !_mesa_is_ycbcr_format(baseFormat)) {
6424a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6434a49301eSmrg      return GL_TRUE;
6444a49301eSmrg   }
6454a49301eSmrg   else if (_mesa_is_depthstencil_format(format)
6464a49301eSmrg            && !_mesa_is_depthstencil_format(baseFormat)) {
6474a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6484a49301eSmrg      return GL_TRUE;
6494a49301eSmrg   }
6504a49301eSmrg   else if (_mesa_is_dudv_format(format)
6514a49301eSmrg            && !_mesa_is_dudv_format(baseFormat)) {
6524a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
6534a49301eSmrg      return GL_TRUE;
6544a49301eSmrg   }
6554a49301eSmrg
6563464ebd5Sriastradh   if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
6573464ebd5Sriastradh                                  texImage->Height, texImage->Depth,
6583464ebd5Sriastradh                                  format, type, clientMemSize, pixels)) {
6593464ebd5Sriastradh      if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
6604a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
6613464ebd5Sriastradh                     "glGetTexImage(out of bounds PBO access)");
6623464ebd5Sriastradh      } else {
6633464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
6643464ebd5Sriastradh                     "glGetnTexImageARB(out of bounds access:"
6653464ebd5Sriastradh                     " bufSize (%d) is too small)", clientMemSize);
6664a49301eSmrg      }
6673464ebd5Sriastradh      return GL_TRUE;
6683464ebd5Sriastradh   }
6694a49301eSmrg
6703464ebd5Sriastradh   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
6714a49301eSmrg      /* PBO should not be mapped */
6724a49301eSmrg      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
6734a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
6744a49301eSmrg                     "glGetTexImage(PBO is mapped)");
6754a49301eSmrg         return GL_TRUE;
6764a49301eSmrg      }
6774a49301eSmrg   }
6784a49301eSmrg
6794a49301eSmrg   return GL_FALSE;
6804a49301eSmrg}
6814a49301eSmrg
6824a49301eSmrg
6834a49301eSmrg
6844a49301eSmrg/**
6854a49301eSmrg * Get texture image.  Called by glGetTexImage.
6864a49301eSmrg *
6874a49301eSmrg * \param target texture target.
6884a49301eSmrg * \param level image level.
6894a49301eSmrg * \param format pixel data format for returned image.
6904a49301eSmrg * \param type pixel data type for returned image.
6913464ebd5Sriastradh * \param bufSize size of the pixels data buffer.
6924a49301eSmrg * \param pixels returned pixel data.
6934a49301eSmrg */
6944a49301eSmrgvoid GLAPIENTRY
6953464ebd5Sriastradh_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
6963464ebd5Sriastradh                       GLenum type, GLsizei bufSize, GLvoid *pixels )
6974a49301eSmrg{
6984a49301eSmrg   struct gl_texture_object *texObj;
6994a49301eSmrg   struct gl_texture_image *texImage;
7004a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
7014a49301eSmrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
7024a49301eSmrg
7033464ebd5Sriastradh   if (getteximage_error_check(ctx, target, level, format, type,
7043464ebd5Sriastradh                               bufSize, pixels)) {
7054a49301eSmrg      return;
7064a49301eSmrg   }
7074a49301eSmrg
7084a49301eSmrg   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
7094a49301eSmrg      /* not an error, do nothing */
7104a49301eSmrg      return;
7114a49301eSmrg   }
7124a49301eSmrg
7134a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
7144a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
7154a49301eSmrg
7164a49301eSmrg   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
7174a49301eSmrg      _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
7184a49301eSmrg                  " dstFmt=0x%x, dstType=0x%x\n",
7194a49301eSmrg                  texObj->Name,
7204a49301eSmrg                  _mesa_get_format_name(texImage->TexFormat),
7214a49301eSmrg                  texImage->Width, texImage->Height,
7224a49301eSmrg                  format, type);
7234a49301eSmrg   }
7244a49301eSmrg
7254a49301eSmrg   _mesa_lock_texture(ctx, texObj);
7264a49301eSmrg   {
7274a49301eSmrg      ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
7284a49301eSmrg                              texObj, texImage);
7294a49301eSmrg   }
7304a49301eSmrg   _mesa_unlock_texture(ctx, texObj);
7314a49301eSmrg}
7324a49301eSmrg
7334a49301eSmrg
7343464ebd5Sriastradhvoid GLAPIENTRY
7353464ebd5Sriastradh_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
7363464ebd5Sriastradh                   GLenum type, GLvoid *pixels )
7373464ebd5Sriastradh{
7383464ebd5Sriastradh   _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
7393464ebd5Sriastradh}
7403464ebd5Sriastradh
7414a49301eSmrg
7424a49301eSmrg/**
7434a49301eSmrg * Do error checking for a glGetCompressedTexImage() call.
7444a49301eSmrg * \return GL_TRUE if any error, GL_FALSE if no errors.
7454a49301eSmrg */
7464a49301eSmrgstatic GLboolean
7473464ebd5Sriastradhgetcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
7483464ebd5Sriastradh                                  GLint level, GLsizei clientMemSize, GLvoid *img)
7494a49301eSmrg{
7504a49301eSmrg   struct gl_texture_object *texObj;
7514a49301eSmrg   struct gl_texture_image *texImage;
752cdc920a0Smrg   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
7533464ebd5Sriastradh   GLuint compressedSize;
7544a49301eSmrg
7554a49301eSmrg   if (maxLevels == 0) {
7564a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
7574a49301eSmrg                  target);
7584a49301eSmrg      return GL_TRUE;
7594a49301eSmrg   }
7604a49301eSmrg
7614a49301eSmrg   if (level < 0 || level >= maxLevels) {
7624a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
7634a49301eSmrg                  "glGetCompressedTexImageARB(bad level = %d)", level);
7644a49301eSmrg      return GL_TRUE;
7654a49301eSmrg   }
7664a49301eSmrg
7674a49301eSmrg   if (_mesa_is_proxy_texture(target)) {
7684a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
7694a49301eSmrg                  "glGetCompressedTexImageARB(bad target = %s)",
7704a49301eSmrg                  _mesa_lookup_enum_by_nr(target));
7714a49301eSmrg      return GL_TRUE;
7724a49301eSmrg   }
7734a49301eSmrg
7744a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
7754a49301eSmrg   if (!texObj) {
7764a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
7774a49301eSmrg      return GL_TRUE;
7784a49301eSmrg   }
7794a49301eSmrg
7804a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
7814a49301eSmrg
7824a49301eSmrg   if (!texImage) {
7834a49301eSmrg      /* probably invalid mipmap level */
7844a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
7854a49301eSmrg                  "glGetCompressedTexImageARB(level)");
7864a49301eSmrg      return GL_TRUE;
7874a49301eSmrg   }
7884a49301eSmrg
7894a49301eSmrg   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
7904a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
7914a49301eSmrg                  "glGetCompressedTexImageARB(texture is not compressed)");
7924a49301eSmrg      return GL_TRUE;
7934a49301eSmrg   }
7944a49301eSmrg
7953464ebd5Sriastradh   compressedSize = _mesa_format_image_size(texImage->TexFormat,
7963464ebd5Sriastradh                                            texImage->Width,
7973464ebd5Sriastradh                                            texImage->Height,
7983464ebd5Sriastradh                                            texImage->Depth);
7994a49301eSmrg
8003464ebd5Sriastradh   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
8013464ebd5Sriastradh      /* do bounds checking on writing to client memory */
8023464ebd5Sriastradh      if (clientMemSize < compressedSize) {
8034a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
8043464ebd5Sriastradh                     "glGetnCompressedTexImageARB(out of bounds access:"
8053464ebd5Sriastradh                     " bufSize (%d) is too small)", clientMemSize);
8064a49301eSmrg      }
8073464ebd5Sriastradh   } else {
8084a49301eSmrg      /* do bounds checking on PBO write */
8094a49301eSmrg      if ((const GLubyte *) img + compressedSize >
8104a49301eSmrg          (const GLubyte *) ctx->Pack.BufferObj->Size) {
8114a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
8123464ebd5Sriastradh                     "glGetCompressedTexImage(out of bounds PBO access)");
8133464ebd5Sriastradh         return GL_TRUE;
8143464ebd5Sriastradh      }
8153464ebd5Sriastradh
8163464ebd5Sriastradh      /* make sure PBO is not mapped */
8173464ebd5Sriastradh      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
8183464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
8193464ebd5Sriastradh                     "glGetCompressedTexImage(PBO is mapped)");
8204a49301eSmrg         return GL_TRUE;
8214a49301eSmrg      }
8224a49301eSmrg   }
8234a49301eSmrg
8244a49301eSmrg   return GL_FALSE;
8254a49301eSmrg}
8264a49301eSmrg
8274a49301eSmrg
8284a49301eSmrgvoid GLAPIENTRY
8293464ebd5Sriastradh_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
8303464ebd5Sriastradh                                GLvoid *img)
8314a49301eSmrg{
8324a49301eSmrg   struct gl_texture_object *texObj;
8334a49301eSmrg   struct gl_texture_image *texImage;
8344a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
8354a49301eSmrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
8364a49301eSmrg
8373464ebd5Sriastradh   if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
8384a49301eSmrg      return;
8394a49301eSmrg   }
8404a49301eSmrg
8413464ebd5Sriastradh   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
8424a49301eSmrg      /* not an error, do nothing */
8434a49301eSmrg      return;
8444a49301eSmrg   }
8454a49301eSmrg
8464a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
8474a49301eSmrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
8484a49301eSmrg
8494a49301eSmrg   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
8504a49301eSmrg      _mesa_debug(ctx,
8514a49301eSmrg                  "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
8524a49301eSmrg                  texObj->Name,
8534a49301eSmrg                  _mesa_get_format_name(texImage->TexFormat),
8544a49301eSmrg                  texImage->Width, texImage->Height);
8554a49301eSmrg   }
8564a49301eSmrg
8574a49301eSmrg   _mesa_lock_texture(ctx, texObj);
8584a49301eSmrg   {
8594a49301eSmrg      ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
8604a49301eSmrg                                        texObj, texImage);
8614a49301eSmrg   }
8624a49301eSmrg   _mesa_unlock_texture(ctx, texObj);
8634a49301eSmrg}
8643464ebd5Sriastradh
8653464ebd5Sriastradhvoid GLAPIENTRY
8663464ebd5Sriastradh_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
8673464ebd5Sriastradh{
8683464ebd5Sriastradh   _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
8693464ebd5Sriastradh}
870