diff options
Diffstat (limited to 'src/mesa/main/texgetimage.c')
| -rw-r--r-- | src/mesa/main/texgetimage.c | 789 | 
1 files changed, 531 insertions, 258 deletions
| diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c index 14d6fc7659..2f88718933 100644 --- a/src/mesa/main/texgetimage.c +++ b/src/mesa/main/texgetimage.c @@ -1,6 +1,6 @@  /*   * Mesa 3-D graphics library - * Version:  7.5 + * Version:  7.7   *   * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.   * Copyright (c) 2009 VMware, Inc. @@ -31,10 +31,11 @@  #include "glheader.h"  #include "bufferobj.h" +#include "enums.h"  #include "context.h" +#include "formats.h"  #include "image.h"  #include "texcompress.h" -#include "texformat.h"  #include "texgetimage.h"  #include "teximage.h"  #include "texstate.h" @@ -44,29 +45,6 @@  #if FEATURE_EXT_texture_sRGB  /** - * Test if given texture image is an sRGB format. - */ -static GLboolean -is_srgb_teximage(const struct gl_texture_image *texImage) -{ -   switch (texImage->TexFormat->MesaFormat) { -   case MESA_FORMAT_SRGB8: -   case MESA_FORMAT_SRGBA8: -   case MESA_FORMAT_SARGB8: -   case MESA_FORMAT_SL8: -   case MESA_FORMAT_SLA8: -   case MESA_FORMAT_SRGB_DXT1: -   case MESA_FORMAT_SRGBA_DXT1: -   case MESA_FORMAT_SRGBA_DXT3: -   case MESA_FORMAT_SRGBA_DXT5: -      return GL_TRUE; -   default: -      return GL_FALSE; -   } -} - - -/**   * Convert a float value from linear space to a   * non-linear sRGB value in [0, 255].   * Not terribly efficient. @@ -108,8 +86,357 @@ type_with_negative_values(GLenum type)  /** + * glGetTexImage for color index pixels. + */ +static void +get_tex_color_index(GLcontext *ctx, GLuint dimensions, +                    GLenum format, GLenum type, GLvoid *pixels, +                    const struct gl_texture_image *texImage) +{ +   const GLint width = texImage->Width; +   const GLint height = texImage->Height; +   const GLint depth = texImage->Depth; +   const GLuint indexBits = +      _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT); +   const GLbitfield transferOps = 0x0; +   GLint img, row, col; + +   for (img = 0; img < depth; img++) { +      for (row = 0; row < height; row++) { +         GLuint indexRow[MAX_WIDTH]; +         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, +                                          width, height, format, type, +                                          img, row, 0); +         assert(dest); + +         if (indexBits == 8) { +            const GLubyte *src = (const GLubyte *) texImage->Data; +            src += width * (img * texImage->Height + row); +            for (col = 0; col < width; col++) { +               indexRow[col] = src[col]; +            } +         } +         else if (indexBits == 16) { +            const GLushort *src = (const GLushort *) texImage->Data; +            src += width * (img * texImage->Height + row); +            for (col = 0; col < width; col++) { +               indexRow[col] = src[col]; +            } +         } +         else { +            _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); +         } +         _mesa_pack_index_span(ctx, width, type, dest, +                               indexRow, &ctx->Pack, transferOps); +      } +   } +} + + +/** + * glGetTexImage for depth/Z pixels. + */ +static void +get_tex_depth(GLcontext *ctx, GLuint dimensions, +              GLenum format, GLenum type, GLvoid *pixels, +              const struct gl_texture_image *texImage) +{ +   const GLint width = texImage->Width; +   const GLint height = texImage->Height; +   const GLint depth = texImage->Depth; +   GLint img, row, col; + +   for (img = 0; img < depth; img++) { +      for (row = 0; row < height; row++) { +         GLfloat depthRow[MAX_WIDTH]; +         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, +                                          width, height, format, type, +                                          img, row, 0); +         assert(dest); + +         for (col = 0; col < width; col++) { +            texImage->FetchTexelf(texImage, col, row, img, depthRow + col); +         } +         _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); +      } +   } +} + + +/** + * glGetTexImage for depth/stencil pixels. + */ +static void +get_tex_depth_stencil(GLcontext *ctx, GLuint dimensions, +                      GLenum format, GLenum type, GLvoid *pixels, +                      const struct gl_texture_image *texImage) +{ +   const GLint width = texImage->Width; +   const GLint height = texImage->Height; +   const GLint depth = texImage->Depth; +   const GLuint *src = (const GLuint *) texImage->Data; +   GLint img, row; + +   for (img = 0; img < depth; img++) { +      for (row = 0; row < height; row++) { +         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, +                                          width, height, format, type, +                                          img, row, 0); +         _mesa_memcpy(dest, src, width * sizeof(GLuint)); +         if (ctx->Pack.SwapBytes) { +            _mesa_swap4((GLuint *) dest, width); +         } + +         src += width * row + width * height * img; +      } +   } +} + + +/** + * glGetTexImage for YCbCr pixels. + */ +static void +get_tex_ycbcr(GLcontext *ctx, GLuint dimensions, +              GLenum format, GLenum type, GLvoid *pixels, +              const struct gl_texture_image *texImage) +{ +   const GLint width = texImage->Width; +   const GLint height = texImage->Height; +   const GLint depth = texImage->Depth; +   const GLint rowstride = texImage->RowStride; +   const GLushort *src = (const GLushort *) texImage->Data; +   GLint img, row; + +   for (img = 0; img < depth; img++) { +      for (row = 0; row < height; row++) { +         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, +                                          width, height, format, type, +                                          img, row, 0); +         _mesa_memcpy(dest, src, width * sizeof(GLushort)); + +         /* check for byte swapping */ +         if ((texImage->TexFormat == MESA_FORMAT_YCBCR +              && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || +             (texImage->TexFormat == MESA_FORMAT_YCBCR_REV +              && type == GL_UNSIGNED_SHORT_8_8_MESA)) { +            if (!ctx->Pack.SwapBytes) +               _mesa_swap2((GLushort *) dest, width); +         } +         else if (ctx->Pack.SwapBytes) { +            _mesa_swap2((GLushort *) dest, width); +         } + +         src += rowstride; +      } +   } +} + + +/** + * glGetTexImagefor sRGB pixels; + */ +static void +get_tex_srgb(GLcontext *ctx, GLuint dimensions, +             GLenum format, GLenum type, GLvoid *pixels, +             const struct gl_texture_image *texImage) +{ +   const GLint width = texImage->Width; +   const GLint height = texImage->Height; +   const GLint depth = texImage->Depth; +   const GLbitfield transferOps = 0x0; +   GLint img, row; + +   for (img = 0; img < depth; img++) { +      for (row = 0; row < height; row++) { +         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, +                                          width, height, format, type, +                                          img, row, 0); + +         GLfloat rgba[MAX_WIDTH][4]; +         GLint col; + +         /* convert row to RGBA format */ +         for (col = 0; col < width; col++) { +            texImage->FetchTexelf(texImage, col, row, img, rgba[col]); +            if (texImage->_BaseFormat == GL_LUMINANCE) { +               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); +               rgba[col][GCOMP] = 0.0; +               rgba[col][BCOMP] = 0.0; +            } +            else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { +               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); +               rgba[col][GCOMP] = 0.0; +               rgba[col][BCOMP] = 0.0; +            } +            else if (texImage->_BaseFormat == GL_RGB || +                     texImage->_BaseFormat == GL_RGBA) { +               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); +               rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); +               rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); +            } +         } +         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, +                                    format, type, dest, +                                    &ctx->Pack, transferOps); +      } +   } +} + + +/** + * glGetTexImagefor RGBA, Luminance, etc. pixels. + * This is the slow way since we use texture sampling. + */ +static void +get_tex_rgba(GLcontext *ctx, GLuint dimensions, +             GLenum format, GLenum type, GLvoid *pixels, +             const struct gl_texture_image *texImage) +{ +   const GLint width = texImage->Width; +   const GLint height = texImage->Height; +   const GLint depth = texImage->Depth; +   /* Normally, no pixel transfer ops are performed during glGetTexImage. +    * The only possible exception is component clamping to [0,1]. +    */ +   GLbitfield transferOps = 0x0; +   GLint img, row; + +   for (img = 0; img < depth; img++) { +      for (row = 0; row < height; row++) { +         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, +                                          width, height, format, type, +                                          img, row, 0); +         GLfloat rgba[MAX_WIDTH][4]; +         GLint col; +         GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); + +         /* clamp does not apply to GetTexImage (final conversion)? +          * Looks like we need clamp though when going from format +          * containing negative values to unsigned format. +          */ +         if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { +            transferOps |= IMAGE_CLAMP_BIT; +         } +         else if (!type_with_negative_values(type) && +                  (dataType == GL_FLOAT || +                   dataType == GL_SIGNED_NORMALIZED)) { +            transferOps |= IMAGE_CLAMP_BIT; +         } + +         for (col = 0; col < width; col++) { +            texImage->FetchTexelf(texImage, col, row, img, rgba[col]); +            if (texImage->_BaseFormat == GL_ALPHA) { +               rgba[col][RCOMP] = 0.0F; +               rgba[col][GCOMP] = 0.0F; +               rgba[col][BCOMP] = 0.0F; +            } +            else if (texImage->_BaseFormat == GL_LUMINANCE) { +               rgba[col][GCOMP] = 0.0F; +               rgba[col][BCOMP] = 0.0F; +               rgba[col][ACOMP] = 1.0F; +            } +            else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { +               rgba[col][GCOMP] = 0.0F; +               rgba[col][BCOMP] = 0.0F; +            } +            else if (texImage->_BaseFormat == GL_INTENSITY) { +               rgba[col][GCOMP] = 0.0F; +               rgba[col][BCOMP] = 0.0F; +               rgba[col][ACOMP] = 1.0F; +            } +         } +         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, +                                    format, type, dest, +                                    &ctx->Pack, transferOps); +      } +   } +} + + +/** + * Try to do glGetTexImage() with simple memcpy(). + * \return GL_TRUE if done, GL_FALSE otherwise + */ +static GLboolean +get_tex_memcpy(GLcontext *ctx, GLenum format, GLenum type, GLvoid *pixels, +               const struct gl_texture_object *texObj, +               const struct gl_texture_image *texImage) +{ +   GLboolean memCopy = GL_FALSE; + +   /* Texture image should have been mapped already */ +   assert(texImage->Data); + +   /* +    * Check if the src/dst formats are compatible. +    * Also note that GL's pixel transfer ops don't apply to glGetTexImage() +    * so we don't have to worry about those. +    * XXX more format combinations could be supported here. +    */ +   if ((texObj->Target == GL_TEXTURE_1D || +        texObj->Target == GL_TEXTURE_2D || +        texObj->Target == GL_TEXTURE_RECTANGLE || +        (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && +         texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { +      if (texImage->TexFormat == MESA_FORMAT_ARGB8888 && +          format == GL_BGRA && +          type == GL_UNSIGNED_BYTE && +          !ctx->Pack.SwapBytes && +          _mesa_little_endian()) { +         memCopy = GL_TRUE; +      } +      else if (texImage->TexFormat == MESA_FORMAT_AL88 && +               format == GL_LUMINANCE_ALPHA && +               type == GL_UNSIGNED_BYTE && +               !ctx->Pack.SwapBytes && +               _mesa_little_endian()) { +         memCopy = GL_TRUE; +      } +      else if (texImage->TexFormat == MESA_FORMAT_L8 && +               format == GL_LUMINANCE && +               type == GL_UNSIGNED_BYTE) { +         memCopy = GL_TRUE; +      } +      else if (texImage->TexFormat == MESA_FORMAT_A8 && +               format == GL_ALPHA && +               type == GL_UNSIGNED_BYTE) { +         memCopy = GL_TRUE; +      } +   } + +   if (memCopy) { +      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); +      const GLuint bytesPerRow = texImage->Width * bpp; +      GLubyte *dst = +         _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, +                               texImage->Height, format, type, 0, 0); +      const GLint dstRowStride = +         _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); +      const GLubyte *src = texImage->Data; +      const GLint srcRowStride = texImage->RowStride * bpp; +      GLuint row; + +      if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { +         memcpy(dst, src, bytesPerRow * texImage->Height); +      } +      else { +         for (row = 0; row < texImage->Height; row++) { +            memcpy(dst, src, bytesPerRow); +            dst += dstRowStride; +            src += srcRowStride; +         } +      } +   } + +   return memCopy; +} + + +/**   * This is the software fallback for Driver.GetTexImage().   * All error checking will have been done before this routine is called. + * The texture image must be mapped.   */  void  _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level, @@ -117,7 +444,21 @@ _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,                     struct gl_texture_object *texObj,                     struct gl_texture_image *texImage)  { -   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; +   GLuint dimensions; + +   /* If we get here, the texture image should be mapped */ +   assert(texImage->Data); + +   switch (target) { +   case GL_TEXTURE_1D: +      dimensions = 1; +      break; +   case GL_TEXTURE_3D: +      dimensions = 3; +      break; +   default: +      dimensions = 2; +   }     if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {        /* Packing texture image into a PBO. @@ -130,8 +471,8 @@ _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,           ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,                                 GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);        if (!buf) { -         /* buffer is already mapped - that's an error */ -         _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)"); +         /* out of memory or other unexpected error */ +         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");           return;        }        /* <pixels> was an offset into the PBO. @@ -139,164 +480,27 @@ _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,         */        pixels = ADD_POINTERS(buf, pixels);     } -   else if (!pixels) { -      /* not an error */ -      return; -   } - -   { -      const GLint width = texImage->Width; -      const GLint height = texImage->Height; -      const GLint depth = texImage->Depth; -      GLint img, row; -      for (img = 0; img < depth; img++) { -         for (row = 0; row < height; row++) { -            /* compute destination address in client memory */ -            GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels, -                                                width, height, format, type, -                                                img, row, 0); -            assert(dest); - -            if (format == GL_COLOR_INDEX) { -               GLuint indexRow[MAX_WIDTH]; -               GLint col; -               /* Can't use FetchTexel here because that returns RGBA */ -               if (texImage->TexFormat->IndexBits == 8) { -                  const GLubyte *src = (const GLubyte *) texImage->Data; -                  src += width * (img * texImage->Height + row); -                  for (col = 0; col < width; col++) { -                     indexRow[col] = src[col]; -                  } -               } -               else if (texImage->TexFormat->IndexBits == 16) { -                  const GLushort *src = (const GLushort *) texImage->Data; -                  src += width * (img * texImage->Height + row); -                  for (col = 0; col < width; col++) { -                     indexRow[col] = src[col]; -                  } -               } -               else { -                  _mesa_problem(ctx, -                                "Color index problem in _mesa_GetTexImage"); -               } -               _mesa_pack_index_span(ctx, width, type, dest, -                                     indexRow, &ctx->Pack, -                                     0 /* no image transfer */); -            } -            else if (format == GL_DEPTH_COMPONENT) { -               GLfloat depthRow[MAX_WIDTH]; -               GLint col; -               for (col = 0; col < width; col++) { -                  (*texImage->FetchTexelf)(texImage, col, row, img, -                                           depthRow + col); -               } -               _mesa_pack_depth_span(ctx, width, dest, type, -                                     depthRow, &ctx->Pack); -            } -            else if (format == GL_DEPTH_STENCIL_EXT) { -               /* XXX Note: we're bypassing texImage->FetchTexel()! */ -               const GLuint *src = (const GLuint *) texImage->Data; -               src += width * row + width * height * img; -               _mesa_memcpy(dest, src, width * sizeof(GLuint)); -               if (ctx->Pack.SwapBytes) { -                  _mesa_swap4((GLuint *) dest, width); -               } -            } -            else if (format == GL_YCBCR_MESA) { -               /* No pixel transfer */ -               const GLint rowstride = texImage->RowStride; -               MEMCPY(dest, -                      (const GLushort *) texImage->Data + row * rowstride, -                      width * sizeof(GLushort)); -               /* check for byte swapping */ -               if ((texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR -                    && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || -                   (texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV -                    && type == GL_UNSIGNED_SHORT_8_8_MESA)) { -                  if (!ctx->Pack.SwapBytes) -                     _mesa_swap2((GLushort *) dest, width); -               } -               else if (ctx->Pack.SwapBytes) { -                  _mesa_swap2((GLushort *) dest, width); -               } -            } -#if FEATURE_EXT_texture_sRGB -            else if (is_srgb_teximage(texImage)) { -               /* special case this since need to backconvert values */ -               /* convert row to RGBA format */ -               GLfloat rgba[MAX_WIDTH][4]; -               GLint col; -               GLbitfield transferOps = 0x0; - -               for (col = 0; col < width; col++) { -                  (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); -                  if (texImage->_BaseFormat == GL_LUMINANCE) { -                     rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); -                     rgba[col][GCOMP] = 0.0; -                     rgba[col][BCOMP] = 0.0; -                  } -                  else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { -                     rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); -                     rgba[col][GCOMP] = 0.0; -                     rgba[col][BCOMP] = 0.0; -                  } -                  else if (texImage->_BaseFormat == GL_RGB || -                     texImage->_BaseFormat == GL_RGBA) { -                     rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); -                     rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); -                     rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); -                  } -               } -               _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, -                                          format, type, dest, -                                          &ctx->Pack, transferOps); -            } -#endif /* FEATURE_EXT_texture_sRGB */ -            else { -               /* general case:  convert row to RGBA format */ -               GLfloat rgba[MAX_WIDTH][4]; -               GLint col; -               GLbitfield transferOps = 0x0; - -               /* clamp does not apply to GetTexImage (final conversion)? -                * Looks like we need clamp though when going from format -                * containing negative values to unsigned format. -                */ -               if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) -                  transferOps |= IMAGE_CLAMP_BIT; -               else if (!type_with_negative_values(type) && -                        (texImage->TexFormat->DataType == GL_FLOAT || -                         texImage->TexFormat->DataType == GL_SIGNED_NORMALIZED)) -                  transferOps |= IMAGE_CLAMP_BIT; -               for (col = 0; col < width; col++) { -                  (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); -                  if (texImage->_BaseFormat == GL_ALPHA) { -                     rgba[col][RCOMP] = 0.0; -                     rgba[col][GCOMP] = 0.0; -                     rgba[col][BCOMP] = 0.0; -                  } -                  else if (texImage->_BaseFormat == GL_LUMINANCE) { -                     rgba[col][GCOMP] = 0.0; -                     rgba[col][BCOMP] = 0.0; -                     rgba[col][ACOMP] = 1.0; -                  } -                  else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { -                     rgba[col][GCOMP] = 0.0; -                     rgba[col][BCOMP] = 0.0; -                  } -                  else if (texImage->_BaseFormat == GL_INTENSITY) { -                     rgba[col][GCOMP] = 0.0; -                     rgba[col][BCOMP] = 0.0; -                     rgba[col][ACOMP] = 1.0; -                  } -               } -               _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, -                                          format, type, dest, -                                          &ctx->Pack, transferOps); -            } /* format */ -         } /* row */ -      } /* img */ +   if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) { +      /* all done */ +   } +   else if (format == GL_COLOR_INDEX) { +      get_tex_color_index(ctx, dimensions, format, type, pixels, texImage); +   } +   else if (format == GL_DEPTH_COMPONENT) { +      get_tex_depth(ctx, dimensions, format, type, pixels, texImage); +   } +   else if (format == GL_DEPTH_STENCIL_EXT) { +      get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); +   } +   else if (format == GL_YCBCR_MESA) { +      get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); +   } +   else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) { +      get_tex_srgb(ctx, dimensions, format, type, pixels, texImage); +   } +   else { +      get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);     }     if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { @@ -317,37 +521,24 @@ _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,                                struct gl_texture_object *texObj,                                struct gl_texture_image *texImage)  { -   GLuint size; +   const GLuint size = _mesa_format_image_size(texImage->TexFormat, +                                               texImage->Width, +                                               texImage->Height, +                                               texImage->Depth);     if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {        /* pack texture image into a PBO */ -      GLubyte *buf; -      if ((const GLubyte *) img + texImage->CompressedSize > -          (const GLubyte *) ctx->Pack.BufferObj->Size) { -         _mesa_error(ctx, GL_INVALID_OPERATION, -                     "glGetCompressedTexImage(invalid PBO access)"); -         return; -      } -      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, -                                              GL_WRITE_ONLY_ARB, -                                              ctx->Pack.BufferObj); +      GLubyte *buf = (GLubyte *) +         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, +                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);        if (!buf) { -         /* buffer is already mapped - that's an error */ -         _mesa_error(ctx, GL_INVALID_OPERATION, -                     "glGetCompressedTexImage(PBO is mapped)"); +         /* out of memory or other unexpected error */ +         _mesa_error(ctx, GL_OUT_OF_MEMORY, +                     "glGetCompresssedTexImage(map PBO failed)");           return;        }        img = ADD_POINTERS(buf, img);     } -   else if (!img) { -      /* not an error */ -      return; -   } - -   /* don't use texImage->CompressedSize since that may be padded out */ -   size = _mesa_compressed_texture_size(ctx, texImage->Width, texImage->Height, -                                        texImage->Depth, -                                        texImage->TexFormat->MesaFormat);     /* just memcpy, no pixelstore or pixel transfer */     _mesa_memcpy(img, texImage->Data, size); @@ -368,10 +559,10 @@ static GLboolean  getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,                          GLenum format, GLenum type, GLvoid *pixels )  { -   const struct gl_texture_unit *texUnit;     struct gl_texture_object *texObj;     struct gl_texture_image *texImage;     const GLuint maxLevels = _mesa_max_texture_levels(ctx, target); +   GLenum baseFormat;     if (maxLevels == 0) {        _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); @@ -421,8 +612,7 @@ getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,        return GL_TRUE;     } -   texUnit = _mesa_get_current_tex_unit(ctx); -   texObj = _mesa_select_tex_object(ctx, texUnit, target); +   texObj = _mesa_get_current_tex_object(ctx, target);     if (!texObj || _mesa_is_proxy_texture(target)) {        _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); @@ -434,40 +624,42 @@ getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,        /* out of memory */        return GL_TRUE;     } + +   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);     /* Make sure the requested image format is compatible with the      * texture's format.  Note that a color index texture can be converted      * to RGBA so that combo is allowed.      */     if (_mesa_is_color_format(format) -       && !_mesa_is_color_format(texImage->TexFormat->BaseFormat) -       && !_mesa_is_index_format(texImage->TexFormat->BaseFormat)) { +       && !_mesa_is_color_format(baseFormat) +       && !_mesa_is_index_format(baseFormat)) {        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");        return GL_TRUE;     }     else if (_mesa_is_index_format(format) -            && !_mesa_is_index_format(texImage->TexFormat->BaseFormat)) { +            && !_mesa_is_index_format(baseFormat)) {        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");        return GL_TRUE;     }     else if (_mesa_is_depth_format(format) -            && !_mesa_is_depth_format(texImage->TexFormat->BaseFormat) -            && !_mesa_is_depthstencil_format(texImage->TexFormat->BaseFormat)) { +            && !_mesa_is_depth_format(baseFormat) +            && !_mesa_is_depthstencil_format(baseFormat)) {        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");        return GL_TRUE;     }     else if (_mesa_is_ycbcr_format(format) -            && !_mesa_is_ycbcr_format(texImage->TexFormat->BaseFormat)) { +            && !_mesa_is_ycbcr_format(baseFormat)) {        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");        return GL_TRUE;     }     else if (_mesa_is_depthstencil_format(format) -            && !_mesa_is_depthstencil_format(texImage->TexFormat->BaseFormat)) { +            && !_mesa_is_depthstencil_format(baseFormat)) {        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");        return GL_TRUE;     }     else if (_mesa_is_dudv_format(format) -            && !_mesa_is_dudv_format(texImage->TexFormat->BaseFormat)) { +            && !_mesa_is_dudv_format(baseFormat)) {        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");        return GL_TRUE;     } @@ -479,7 +671,14 @@ getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,                                       texImage->Height, texImage->Depth,                                       format, type, pixels)) {           _mesa_error(ctx, GL_INVALID_OPERATION, -                     "glGetTexImage(invalid PBO access)"); +                     "glGetTexImage(out of bounds PBO write)"); +         return GL_TRUE; +      } + +      /* PBO should not be mapped */ +      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { +         _mesa_error(ctx, GL_INVALID_OPERATION, +                     "glGetTexImage(PBO is mapped)");           return GL_TRUE;        }     } @@ -502,8 +701,8 @@ void GLAPIENTRY  _mesa_GetTexImage( GLenum target, GLint level, GLenum format,                     GLenum type, GLvoid *pixels )  { -   const struct gl_texture_unit *texUnit;     struct gl_texture_object *texObj; +   struct gl_texture_image *texImage;     GET_CURRENT_CONTEXT(ctx);     ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -511,15 +710,25 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,        return;     } -   texUnit = _mesa_get_current_tex_unit(ctx); -   texObj = _mesa_select_tex_object(ctx, texUnit, target); +   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { +      /* not an error, do nothing */ +      return; +   } + +   texObj = _mesa_get_current_tex_object(ctx, target); +   texImage = _mesa_select_tex_image(ctx, texObj, target, level); + +   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { +      _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," +                  " dstFmt=0x%x, dstType=0x%x\n", +                  texObj->Name, +                  _mesa_get_format_name(texImage->TexFormat), +                  texImage->Width, texImage->Height, +                  format, type); +   }     _mesa_lock_texture(ctx, texObj);     { -      struct gl_texture_image *texImage = -         _mesa_select_tex_image(ctx, texObj, target, level); - -      /* typically, this will call _mesa_get_teximage() */        ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,                                texObj, texImage);     } @@ -527,55 +736,119 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,  } + +/** + * Do error checking for a glGetCompressedTexImage() call. + * \return GL_TRUE if any error, GL_FALSE if no errors. + */ +static GLboolean +getcompressedteximage_error_check(GLcontext *ctx, GLenum target, GLint level, +                                  GLvoid *img) +{ +   struct gl_texture_object *texObj; +   struct gl_texture_image *texImage; +   const GLuint maxLevels = _mesa_max_texture_levels(ctx, target); + +   if (maxLevels == 0) { +      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", +                  target); +      return GL_TRUE; +   } + +   if (level < 0 || level >= maxLevels) { +      _mesa_error(ctx, GL_INVALID_VALUE, +                  "glGetCompressedTexImageARB(bad level = %d)", level); +      return GL_TRUE; +   } + +   if (_mesa_is_proxy_texture(target)) { +      _mesa_error(ctx, GL_INVALID_ENUM, +                  "glGetCompressedTexImageARB(bad target = %s)", +                  _mesa_lookup_enum_by_nr(target)); +      return GL_TRUE; +   } + +   texObj = _mesa_get_current_tex_object(ctx, target); +   if (!texObj) { +      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); +      return GL_TRUE; +   } + +   texImage = _mesa_select_tex_image(ctx, texObj, target, level); + +   if (!texImage) { +      /* probably invalid mipmap level */ +      _mesa_error(ctx, GL_INVALID_VALUE, +                  "glGetCompressedTexImageARB(level)"); +      return GL_TRUE; +   } + +   if (!_mesa_is_format_compressed(texImage->TexFormat)) { +      _mesa_error(ctx, GL_INVALID_OPERATION, +                  "glGetCompressedTexImageARB(texture is not compressed)"); +      return GL_TRUE; +   } + +   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { +      GLuint compressedSize; + +      /* make sure PBO is not mapped */ +      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { +         _mesa_error(ctx, GL_INVALID_OPERATION, +                     "glGetCompressedTexImage(PBO is mapped)"); +         return GL_TRUE; +      } + +      compressedSize = _mesa_format_image_size(texImage->TexFormat, +                                               texImage->Width, +                                               texImage->Height, +                                               texImage->Depth); + +      /* do bounds checking on PBO write */ +      if ((const GLubyte *) img + compressedSize > +          (const GLubyte *) ctx->Pack.BufferObj->Size) { +         _mesa_error(ctx, GL_INVALID_OPERATION, +                     "glGetCompressedTexImage(out of bounds PBO write)"); +         return GL_TRUE; +      } +   } + +   return GL_FALSE; +} + +  void GLAPIENTRY  _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)  { -   const struct gl_texture_unit *texUnit;     struct gl_texture_object *texObj;     struct gl_texture_image *texImage; -   GLint maxLevels;     GET_CURRENT_CONTEXT(ctx);     ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); -   texUnit = _mesa_get_current_tex_unit(ctx); -   texObj = _mesa_select_tex_object(ctx, texUnit, target); -   if (!texObj) { -      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB"); +   if (getcompressedteximage_error_check(ctx, target, level, img)) {        return;     } -   maxLevels = _mesa_max_texture_levels(ctx, target); -   ASSERT(maxLevels > 0); /* 0 indicates bad target, caught above */ - -   if (level < 0 || level >= maxLevels) { -      _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)"); +   if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { +      /* not an error, do nothing */        return;     } -   if (_mesa_is_proxy_texture(target)) { -      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); -      return; +   texObj = _mesa_get_current_tex_object(ctx, target); +   texImage = _mesa_select_tex_image(ctx, texObj, target, level); + +   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { +      _mesa_debug(ctx, +                  "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", +                  texObj->Name, +                  _mesa_get_format_name(texImage->TexFormat), +                  texImage->Width, texImage->Height);     }     _mesa_lock_texture(ctx, texObj);     { -      texImage = _mesa_select_tex_image(ctx, texObj, target, level); -      if (texImage) { -         if (texImage->IsCompressed) { -            /* this typically calls _mesa_get_compressed_teximage() */ -            ctx->Driver.GetCompressedTexImage(ctx, target, level, img, -                                              texObj, texImage); -         } -         else { -            _mesa_error(ctx, GL_INVALID_OPERATION, -                        "glGetCompressedTexImageARB"); -         } -      } -      else { -         /* probably invalid mipmap level */ -         _mesa_error(ctx, GL_INVALID_VALUE, -                     "glGetCompressedTexImageARB(level)"); -      } +      ctx->Driver.GetCompressedTexImage(ctx, target, level, img, +                                        texObj, texImage);     }     _mesa_unlock_texture(ctx, texObj);  } | 
