[Mesa-dev] [PATCH 09/14] mesa: overhaul the glGetCompressedTexImage code

Ilia Mirkin imirkin at alum.mit.edu
Fri Jul 17 18:11:47 PDT 2015


On Wed, Jul 15, 2015 at 7:40 PM, Brian Paul <brianp at vmware.com> wrote:
> Same idea as the previous patch.
> ---
>  src/mesa/main/texgetimage.c | 345 ++++++++++++++++++++++++++------------------
>  1 file changed, 203 insertions(+), 142 deletions(-)
>
> diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c
> index 49239e7..6ac1779 100644
> --- a/src/mesa/main/texgetimage.c
> +++ b/src/mesa/main/texgetimage.c
> @@ -1438,224 +1438,285 @@ _mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type,
>
>
>  /**
> - * Do error checking for a glGetCompressedTexImage() call.
> - * \return GL_TRUE if any error, GL_FALSE if no errors.
> + * Compute the number of bytes which will be written when retrieving
> + * a sub-region of a compressed texture.
>   */
> -static GLboolean
> +static GLsizei
> +packed_compressed_size(GLuint dimensions, mesa_format format,
> +                       GLsizei width, GLsizei height, GLsizei depth,
> +                       const struct gl_pixelstore_attrib *packing)
> +{
> +   struct compressed_pixelstore st;
> +   GLsizei totalBytes;
> +
> +   _mesa_compute_compressed_pixelstore(dimensions, format,
> +                                       width, height, depth,
> +                                       packing, &st);
> +   totalBytes =
> +      (st.CopySlices - 1) * st.TotalRowsPerSlice * st.TotalBytesPerRow +
> +      st.SkipBytes +
> +      (st.CopyRowsPerSlice - 1) * st.TotalBytesPerRow +
> +      st.CopyBytesPerRow;
> +
> +   return totalBytes;
> +}
> +
> +
> +/**
> + * Do error checking for getting compressed texture images.
> + * \return true if any error, false if no errors.
> + */
> +static bool
>  getcompressedteximage_error_check(struct gl_context *ctx,
> -                                  struct gl_texture_image *texImage,
> -                                  GLenum target,
> -                                  GLint level, GLsizei clientMemSize,
> -                                  GLvoid *img, bool dsa)
> +                                  struct gl_texture_object *texObj,
> +                                  GLenum target, GLint level,
> +                                  GLint xoffset, GLint yoffset, GLint zoffset,
> +                                  GLsizei width, GLsizei height, GLsizei depth,
> +                                  GLsizei bufSize, GLvoid *pixels,
> +                                  const char *caller)
>  {
> -   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
> -   GLuint compressedSize, dimensions;
> -   const char *suffix = dsa ? "ture" : "";
> +   struct gl_texture_image *texImage;
> +   GLint maxLevels;
> +   GLsizei totalBytes;
> +   GLuint dimensions;
>
> -   assert(texImage);
> +   assert(texObj);
>
> -   if (!legal_getteximage_target(ctx, target, dsa)) {
> -      _mesa_error(ctx, GL_INVALID_ENUM,
> -                  "glGetCompressedTex%sImage(target=%s)", suffix,
> -                  _mesa_lookup_enum_by_nr(target));
> -      return GL_TRUE;
> +   if (texObj->Target == 0) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller);
> +      return true;
>     }
>
> -   assert(maxLevels != 0);
> +   maxLevels = _mesa_max_texture_levels(ctx, target);
>     if (level < 0 || level >= maxLevels) {
>        _mesa_error(ctx, GL_INVALID_VALUE,
> -                  "glGetCompressedTex%sImage(bad level = %d)", suffix, level);
> -      return GL_TRUE;
> +                  "%s(bad level = %d)", caller, level);
> +      return true;
>     }
>
> +   if (dimensions_error_check(ctx, texObj, target, level,
> +                              xoffset, yoffset, zoffset,
> +                              width, height, depth, caller)) {
> +      return true;
> +   }
> +
> +   texImage = select_tex_image(texObj, target, level, zoffset);
> +   assert(texImage);
> +
>     if (!_mesa_is_format_compressed(texImage->TexFormat)) {
>        _mesa_error(ctx, GL_INVALID_OPERATION,
> -                  "glGetCompressedTex%sImage(texture is not compressed)",
> -                  suffix);
> -      return GL_TRUE;
> +                  "%s(texture is not compressed)", caller);
> +      return true;
>     }
>
> -   compressedSize = _mesa_format_image_size(texImage->TexFormat,
> -                                            texImage->Width,
> -                                            texImage->Height,
> -                                            texImage->Depth);
> -
>     /* Check for invalid pixel storage modes */
> -   dimensions = _mesa_get_texture_dimensions(texImage->TexObject->Target);
> +   dimensions = _mesa_get_texture_dimensions(texObj->Target);
>     if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions,
> -                                              &ctx->Pack, dsa ?
> -                                              "glGetCompressedTextureImage":
> -                                              "glGetCompressedTexImage")) {
> -      return GL_TRUE;
> +                                                   &ctx->Pack,
> +                                                   caller)) {
> +      return true;
>     }
>
> -   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
> -      /* do bounds checking on writing to client memory */
> -      if (clientMemSize < (GLsizei) compressedSize) {
> -         _mesa_error(ctx, GL_INVALID_OPERATION,
> -                     "%s(out of bounds access: bufSize (%d) is too small)",
> -                     dsa ? "glGetCompressedTextureImage" :
> -                     "glGetnCompressedTexImageARB", clientMemSize);
> -         return GL_TRUE;
> -      }
> -   } else {
> +   /* Compute number of bytes that may be touched in the dest buffer */
> +   totalBytes = packed_compressed_size(dimensions, texImage->TexFormat,
> +                                       width, height, depth,
> +                                       &ctx->Pack);
> +
> +   /* Do dest buffer bounds checking */
> +   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
>        /* do bounds checking on PBO write */
> -      if ((const GLubyte *) img + compressedSize >
> -          (const GLubyte *) ctx->Pack.BufferObj->Size) {
> +      if ((GLubyte *) pixels + totalBytes >
> +          (GLubyte *) ctx->Pack.BufferObj->Size) {
>           _mesa_error(ctx, GL_INVALID_OPERATION,
> -                     "glGetCompressedTex%sImage(out of bounds PBO access)",
> -                     suffix);
> -         return GL_TRUE;
> +                     "%s(out of bounds PBO access)", caller);
> +         return true;
>        }
>
>        /* make sure PBO is not mapped */
>        if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
> +         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller);
> +         return true;
> +      }
> +   }
> +   else {
> +      /* do bounds checking on writing to client memory */
> +      if (totalBytes > bufSize) {
>           _mesa_error(ctx, GL_INVALID_OPERATION,
> -                     "glGetCompressedTex%sImage(PBO is mapped)", suffix);
> -         return GL_TRUE;
> +                     "%s(out of bounds access: bufSize (%d) is too small)",
> +                     caller, bufSize);
> +         return true;
>        }
>     }
>
> -   return GL_FALSE;
> +   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
> +      /* not an error, but do nothing */
> +      return true;
> +   }
> +
> +   return false;
>  }
>
> -/** Implements glGetnCompressedTexImageARB, glGetCompressedTexImage, and
> - * glGetCompressedTextureImage.
> - *
> - * texImage must be passed in because glGetCompressedTexImage must handle the
> - * target GL_TEXTURE_CUBE_MAP.
> +
> +/**
> + * Common helper for all glGetCompressed-teximage functions.
>   */
> -void
> -_mesa_get_compressed_texture_image(struct gl_context *ctx,
> -                                   struct gl_texture_object *texObj,
> -                                   struct gl_texture_image *texImage,
> -                                   GLenum target, GLint level,
> -                                   GLsizei bufSize, GLvoid *pixels,
> -                                   bool dsa)
> +static void
> +get_compressed_texture_image(struct gl_context *ctx,
> +                             struct gl_texture_object *texObj,
> +                             GLenum target, GLint level,
> +                             GLint xoffset, GLint yoffset, GLint zoffset,
> +                             GLsizei width, GLsizei height, GLint depth,
> +                             GLsizei bufSize, GLvoid *pixels,
> +                             const char *caller)
>  {
> -   assert(texObj);
> -   assert(texImage);
> +   struct gl_texture_image *texImage;
> +   unsigned firstFace, numFaces, i, imageStride;
>
>     FLUSH_VERTICES(ctx, 0);
>
> -   if (getcompressedteximage_error_check(ctx, texImage, target, level,
> -                                         bufSize, pixels, dsa)) {
> -      return;
> -   }
> -
> -   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
> -      /* not an error, do nothing */
> -      return;
> -   }
> +   texImage = _mesa_select_tex_image(texObj, target, level);
> +   assert(texImage);  /* should have been error checked already */
>
>     if (_mesa_is_zero_size_texture(texImage))
>        return;
>
>     if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
>        _mesa_debug(ctx,
> -                  "glGetCompressedTex%sImage(tex %u) format = %s, w=%d, h=%d\n",
> -                  dsa ? "ture" : "", texObj->Name,
> +                  "%s(tex %u) format = %s, w=%d, h=%d\n",
> +                  caller, texObj->Name,
>                    _mesa_get_format_name(texImage->TexFormat),
>                    texImage->Width, texImage->Height);
>     }
>
> +   if (target == 0) {
> +      target = texObj->Target;
> +   }

In the non-compressed patch you fixed this up differently. Can you not
do the same thing here?

> +
> +   if (target == GL_TEXTURE_CUBE_MAP) {
> +      struct compressed_pixelstore store;
> +
> +      /* Compute image stride between cube faces */
> +      _mesa_compute_compressed_pixelstore(2, texImage->TexFormat,
> +                                          width, height, depth,
> +                                          &ctx->Pack, &store);
> +      imageStride = store.TotalBytesPerRow * store.TotalRowsPerSlice;
> +
> +      firstFace = zoffset;
> +      numFaces = depth;
> +      zoffset = 0;
> +      depth = 1;
> +   }
> +   else {
> +      imageStride = 0;
> +      firstFace = _mesa_tex_target_to_face(target);
> +      numFaces = 1;
> +   }
> +
>     _mesa_lock_texture(ctx, texObj);
> -   {
> +
> +   for (i = 0; i < numFaces; i++) {
> +      texImage = texObj->Image[firstFace + i][level];
> +      assert(texImage);
> +
>        ctx->Driver.GetCompressedTexSubImage(ctx, texImage,
> -                                           0, 0, 0,
> -                                           texImage->Width, texImage->Height,
> -                                           texImage->Depth, pixels);
> +                                           xoffset, yoffset, zoffset,
> +                                           width, height, depth, pixels);
> +
> +      /* next cube face */
> +      pixels = (GLubyte *) pixels + imageStride;
> +      bufSize -= imageStride;

bufSize is unused.

>     }
> +
>     _mesa_unlock_texture(ctx, texObj);
>  }
>
> +
>  void GLAPIENTRY
>  _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
> -                                GLvoid *img)
> +                                GLvoid *pixels)
>  {
> -   struct gl_texture_object *texObj;
> -   struct gl_texture_image *texImage;
>     GET_CURRENT_CONTEXT(ctx);
> +   static const char *caller = "glGetnCompressedTexImageARB";
> +   GLsizei width, height, depth;
> +   struct gl_texture_object *texObj;
>
> -   texObj = _mesa_get_current_tex_object(ctx, target);
> -   if (!texObj)
> +   if (!legal_getteximage_target(ctx, target, false)) {
> +      _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
>        return;
> +   }
>
> -   texImage = _mesa_select_tex_image(texObj, target, level);
> -   if (!texImage)
> +   texObj = _mesa_get_current_tex_object(ctx, target);
> +   assert(texObj);
> +
> +   get_texture_image_dims(texObj, target, level, &width, &height, &depth);
> +
> +   if (getcompressedteximage_error_check(ctx, texObj, target, level,
> +                                         0, 0, 0, width, height, depth,
> +                                         INT_MAX, pixels, caller)) {
>        return;
> +   }
>
> -   _mesa_get_compressed_texture_image(ctx, texObj, texImage, target, level,
> -                                      bufSize, img, false);
> +   get_compressed_texture_image(ctx, texObj, target, level,
> +                                0, 0, 0, width, height, depth,
> +                                bufSize, pixels, caller);
>  }
>
> -void GLAPIENTRY
> -_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img)
> -{
> -   _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
> -}
>
> -/**
> - * Get compressed texture image.
> - *
> - * \param texture texture name.
> - * \param level image level.
> - * \param bufSize size of the pixels data buffer.
> - * \param pixels returned pixel data.
> - */
>  void GLAPIENTRY
> -_mesa_GetCompressedTextureImage(GLuint texture, GLint level,
> -                                GLsizei bufSize, GLvoid *pixels)
> +_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *pixels)
>  {
> -   struct gl_texture_object *texObj;
> -   struct gl_texture_image *texImage;
> -   int i;
> -   GLint image_stride;
>     GET_CURRENT_CONTEXT(ctx);
> +   static const char *caller = "glGetCompressedTexImage";
> +   GLsizei width, height, depth;
> +   struct gl_texture_object *texObj;
>
> -   texObj = _mesa_lookup_texture_err(ctx, texture,
> -                                     "glGetCompressedTextureImage");
> -   if (!texObj)
> +   if (!legal_getteximage_target(ctx, target, false)) {
> +      _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
>        return;
> +   }
>
> -   /* Must handle special case GL_TEXTURE_CUBE_MAP. */
> -   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
> +   texObj = _mesa_get_current_tex_object(ctx, target);
> +   assert(texObj);
>
> -      /* Make sure the texture object is a proper cube.
> -       * (See texturesubimage in teximage.c for details on why this check is
> -       * performed.)
> -       */
> -      if (!_mesa_cube_level_complete(texObj, level)) {
> -         _mesa_error(ctx, GL_INVALID_OPERATION,
> -                     "glGetCompressedTextureImage(cube map incomplete)");
> -         return;
> -      }
> +   get_texture_image_dims(texObj, texObj->Target, level,
> +                          &width, &height, &depth);
> +
> +   if (getcompressedteximage_error_check(ctx, texObj, target, level,
> +                                         0, 0, 0, width, height, depth,
> +                                         INT_MAX, pixels, caller)) {
> +      return;
> +   }
>
> -      /* Copy each face. */
> -      for (i = 0; i < 6; ++i) {
> -         texImage = texObj->Image[i][level];
> -         assert(texImage);
> +   get_compressed_texture_image(ctx, texObj, target, level,
> +                                0, 0, 0, width, height, depth,
> +                                INT_MAX, pixels, caller);
> +}
>
> -         _mesa_get_compressed_texture_image(ctx, texObj, texImage,
> -                                            texObj->Target, level,
> -                                            bufSize, pixels, true);
>
> -         /* Compressed images don't have a client format */
> -         image_stride = _mesa_format_image_size(texImage->TexFormat,
> -                                                texImage->Width,
> -                                                texImage->Height, 1);
> +void GLAPIENTRY
> +_mesa_GetCompressedTextureImage(GLuint texture, GLint level,
> +                                GLsizei bufSize, GLvoid *pixels)
> +{
> +   GET_CURRENT_CONTEXT(ctx);
> +   static const char *caller = "glGetCompressedTextureImage";
> +   GLsizei width, height, depth;
> +   struct gl_texture_object *texObj =
> +      _mesa_lookup_texture_err(ctx, texture, caller);
>
> -         pixels = (GLubyte *) pixels + image_stride;
> -         bufSize -= image_stride;
> -      }
> +   if (!texObj) {
> +      return;
>     }
> -   else {
> -      texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
> -      if (!texImage)
> -         return;
>
> -      _mesa_get_compressed_texture_image(ctx, texObj, texImage,
> -                                         texObj->Target, level, bufSize,
> -                                         pixels, true);
> +   get_texture_image_dims(texObj, texObj->Target, level,
> +                          &width, &height, &depth);
> +
> +   if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
> +                                         0, 0, 0, width, height, depth,
> +                                         bufSize, pixels, caller)) {
> +      return;
>     }
> +
> +   get_compressed_texture_image(ctx, texObj, 0, level,

This should just use texObj->Target right?

> +                                0, 0, 0, width, height, depth,
> +                                bufSize, pixels, caller);
>  }

With those fixed up, this patch is

Reviewed-by: Ilia Mirkin <imirkin at alum.mit.edu>


More information about the mesa-dev mailing list