[Mesa-dev] [PATCH 2/5] mesa/main: Add generic bits of ARB_clear_texture implementation

Ian Romanick idr at freedesktop.org
Mon Jun 30 15:50:59 PDT 2014


On 06/13/2014 05:59 PM, Neil Roberts wrote:
> This adds the driver entry point for glClearTexSubImage and fills in the
> _mesa_ClearTexImage and _mesa_ClearTexSubImage functions that call it.
> ---
>  src/mesa/main/dd.h       |  14 +++
>  src/mesa/main/teximage.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++-
>  src/mesa/main/teximage.h |  12 +++
>  3 files changed, 266 insertions(+), 1 deletion(-)
> 
> diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
> index 633ea2c..8976535 100644
> --- a/src/mesa/main/dd.h
> +++ b/src/mesa/main/dd.h
> @@ -239,6 +239,20 @@ struct dd_function_table {
>                          struct gl_texture_image *texImage );
>  
>     /**
> +    * Called by glClearTex[Sub]Image
> +    *
> +    * Clears a rectangular region of the image to a given value. The
> +    * clearValue argument is either NULL or points to a single texel to use as
> +    * the clear value in the same internal format as the texture image. If it
> +    * is NULL then the texture should be cleared to zeroes.
> +    */
> +   void (*ClearTexSubImage)(struct gl_context *ctx,
> +                            struct gl_texture_image *texImage,
> +                            GLint xoffset, GLint yoffset, GLint zoffset,
> +                            GLsizei width, GLsizei height, GLsizei depth,
> +                            const GLvoid *clearValue);
> +
> +   /**
>      * Called by glCopyTex[Sub]Image[123]D().
>      *
>      * This function should copy a rectangular region in the rb to a single
> diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c
> index a893c70..d5baac8 100644
> --- a/src/mesa/main/teximage.c
> +++ b/src/mesa/main/teximage.c
> @@ -51,6 +51,7 @@
>  #include "textureview.h"
>  #include "mtypes.h"
>  #include "glformats.h"
> +#include "texstore.h"
>  
>  
>  /**
> @@ -3848,20 +3849,259 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
>                     x, y, width, height);
>  }
>  
> +static bool
> +clear_tex_image(struct gl_context *ctx,
> +                const char *function,
> +                struct gl_texture_image *texImage, GLint level,
> +                GLint xoffset, GLint yoffset, GLint zoffset,
> +                GLsizei width, GLsizei height, GLsizei depth,
> +                GLenum format, GLenum type,
> +                const void *data)
> +{
> +   struct gl_texture_object *texObj = texImage->TexObject;
> +   static const GLubyte zeroData[MAX_PIXEL_BYTES];
> +   GLubyte clearValue[MAX_PIXEL_BYTES];
> +   GLubyte *clearValuePtr = clearValue;
> +   GLenum internalFormat = texImage->InternalFormat;
> +   GLenum err;
> +
> +   if (texObj->Target == GL_TEXTURE_BUFFER) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "%s(buffer texture)", function);
> +      return false;
> +   }
> +
> +   if (_mesa_is_compressed_format(ctx, internalFormat)) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "%s(compressed texture)", function);
> +      return false;
> +   }
> +
> +   err = _mesa_error_check_format_and_type(ctx, format, type);
> +   if (err != GL_NO_ERROR) {
> +      _mesa_error(ctx, err,
> +                  "%s(incompatible format = %s, type = %s)",
> +                  function,
> +                  _mesa_lookup_enum_by_nr(format),
> +                  _mesa_lookup_enum_by_nr(type));
> +      return false;
> +   }
> +
> +   /* make sure internal format and format basically agree */
> +   if (!texture_formats_agree(internalFormat, format)) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "%s(incompatible internalFormat = %s, format = %s)",
> +                  function,
> +                  _mesa_lookup_enum_by_nr(internalFormat),
> +                  _mesa_lookup_enum_by_nr(format));
> +      return false;
> +   }
> +
> +   if (ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) {
> +      /* both source and dest must be integer-valued, or neither */
> +      if (_mesa_is_format_integer_color(texImage->TexFormat) !=
> +          _mesa_is_enum_format_integer(format)) {
> +         _mesa_error(ctx, GL_INVALID_OPERATION,
> +                     "%s(integer/non-integer format mismatch)",
> +                     function);
> +         return false;
> +      }
> +   }
> +
> +   if (!_mesa_texstore(ctx,
> +                       1, /* dims */
> +                       texImage->_BaseFormat,
> +                       texImage->TexFormat,
> +                       0, /* dstRowStride */
> +                       &clearValuePtr,
> +                       1, 1, 1, /* srcWidth/Height/Depth */
> +                       format, type,
> +                       data ? data : zeroData,
> +                       &ctx->DefaultPacking)) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid format)", function);
> +      return false;
> +   }
> +
> +   ctx->Driver.ClearTexSubImage(ctx,
> +                                texImage,
> +                                xoffset, yoffset, zoffset,
> +                                width, height, depth,
> +                                data ? clearValue : NULL);
> +
> +   return true;
> +}
> +
> +static struct gl_texture_object *
> +get_tex_obj_for_clear(struct gl_context *ctx,
> +                      const char *function,
> +                      GLuint texture)
> +{
> +   struct gl_texture_object *texObj;
> +
> +   if (texture == 0) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function);
> +      return NULL;
> +   }
> +
> +   texObj = _mesa_lookup_texture(ctx, texture);
> +
> +   if (texObj == NULL) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function);
> +      return NULL;
> +   }
> +
> +   if (texObj->Target == 0) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function);
> +      return NULL;
> +   }
> +
> +   return texObj;
> +}
> +
> +static int
> +get_tex_images_for_clear(struct gl_context *ctx,
> +                         const char *function,
> +                         struct gl_texture_object *texObj,
> +                         GLint level,
> +                         struct gl_texture_image **texImages)
> +{
> +   GLenum target;
> +   int i;
> +
> +   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
> +      return 0;
> +   }
> +
> +   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
> +      for (i = 0; i < MAX_FACES; i++) {
> +         target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
> +
> +         texImages[i] = _mesa_select_tex_image(ctx, texObj, target, level);
> +         if (texImages[i] == NULL) {
> +            _mesa_error(ctx, GL_INVALID_OPERATION,
> +                        "%s(invalid level)", function);
> +            return 0;
> +         }
> +      }
> +
> +      return MAX_FACES;
> +   }
> +
> +   texImages[0] = _mesa_select_tex_image(ctx, texObj, texObj->Target, level);
> +
> +   if (texImages[0] == NULL) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
> +      return 0;
> +   }
> +
> +   return 1;
> +}
> +
>  void GLAPIENTRY
>  _mesa_ClearTexSubImage( GLuint texture, GLint level,
>                          GLint xoffset, GLint yoffset, GLint zoffset,
>                          GLsizei width, GLsizei height, GLsizei depth,
>                          GLenum format, GLenum type, const void *data )
>  {
> +   GET_CURRENT_CONTEXT(ctx);
> +   struct gl_texture_object *texObj;
> +   struct gl_texture_image *texImages[MAX_FACES];
> +   int i, numImages;
> +   int minDepth, maxDepth;
> +   bool res;
>  
> +   texObj = get_tex_obj_for_clear(ctx, "glClearTexSubImage", texture);
> +
> +   if (texObj == NULL)
> +      return;
> +
> +   _mesa_lock_texture(ctx, texObj);
> +
> +   numImages = get_tex_images_for_clear(ctx, "glClearTexSubImage",
> +                                        texObj, level, texImages);
> +   if (numImages == 0)
> +      goto out;
> +
> +   if (numImages == 1) {
> +      minDepth = -(int) texImages[0]->Border;
> +      maxDepth = texImages[0]->Depth;
> +   } else {
> +      minDepth = 0;
> +      maxDepth = numImages;
> +   }
> +
> +   if (xoffset < -(GLint) texImages[0]->Border ||
> +       yoffset < -(GLint) texImages[0]->Border ||
> +       zoffset < minDepth ||
> +       width < 0 ||
> +       height < 0 ||
> +       depth < 0 ||
> +       xoffset + width > texImages[0]->Width ||
> +       yoffset + height > texImages[0]->Height ||
> +       zoffset + depth > maxDepth) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glClearSubTexImage(invalid dimensions)");
> +      goto out;
> +   }
> +
> +   if (numImages == 1) {
> +      clear_tex_image(ctx, "glClearTexSubImage",
> +                      texImages[0], level,
> +                      xoffset, yoffset, zoffset,
> +                      width, height, depth,
> +                      format, type, data);
> +   } else {
> +      for (i = zoffset; i < zoffset + depth; i++) {
> +         res = clear_tex_image(ctx, "glClearTexSubImage",
> +                               texImages[i], level,
> +                               xoffset, yoffset, 0,
> +                               width, height, 1,
> +                               format, type, data);

Are there potentially cases where the first clear_tex_image could
succeed but the second fail?  If so, then this is no good.  If a GL call
generates an error (other than GL_NO_MEMORY), it is supposed to be as
though nothing happened.

There are a few places in Mesa where things separated into
"check_something" and "something" functions for exactly this reason.  Do
all the checks, then do all the work.  That may or may not be necessary
here.

> +         if (!res)
> +            break;
> +      }
> +   }
> +
> + out:
> +   _mesa_unlock_texture(ctx, texObj);
>  }
>  
>  void GLAPIENTRY
>  _mesa_ClearTexImage( GLuint texture, GLint level,
>                       GLenum format, GLenum type, const void *data )
>  {
> +   GET_CURRENT_CONTEXT(ctx);
> +   struct gl_texture_object *texObj;
> +   struct gl_texture_image *texImages[MAX_FACES];
> +   int i, numImages;
> +   bool res;
> +
> +   texObj = get_tex_obj_for_clear(ctx, "glClearTexImage", texture);
>  
> +   if (texObj == NULL)
> +      return;
> +
> +   _mesa_lock_texture(ctx, texObj);
> +
> +   numImages = get_tex_images_for_clear(ctx, "glClearTexImage",
> +                                        texObj, level, texImages);
> +
> +   for (i = 0; i < numImages; i++) {
> +      res = clear_tex_image(ctx, "glClearTexImage",
> +                            texImages[i], level,
> +                            -(GLint) texImages[i]->Border, /* xoffset */
> +                            -(GLint) texImages[i]->Border, /* yoffset */
> +                            -(GLint) texImages[i]->Border, /* zoffset */
> +                            texImages[i]->Width,
> +                            texImages[i]->Height,
> +                            texImages[i]->Depth,
> +                            format, type, data);
> +      if (!res)
> +         break;
> +   }
> +
> +   _mesa_unlock_texture(ctx, texObj);
>  }
>  
>  
> @@ -4624,7 +4864,6 @@ _mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
>                         "glTexStorage2DMultisample");
>  }
>  
> -
>  void GLAPIENTRY
>  _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
>                                GLenum internalformat, GLsizei width,
> diff --git a/src/mesa/main/teximage.h b/src/mesa/main/teximage.h
> index 42305f4..984321c 100644
> --- a/src/mesa/main/teximage.h
> +++ b/src/mesa/main/teximage.h
> @@ -336,6 +336,18 @@ _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
>                                GLsizei height, GLsizei depth,
>                                GLboolean fixedsamplelocations);
>  
> +extern void GLAPIENTRY
> +_mesa_ClearTexImage(GLuint texture, GLint level,
> +                    GLenum format, GLenum type,
> +                    const void *data);
> +
> +extern void GLAPIENTRY
> +_mesa_ClearTexSubImage(GLuint texture, GLint level,
> +                       GLint xoffset, GLint yoffset, GLint zoffset,
> +                       GLsizei width, GLsizei height, GLsizei depth,
> +                       GLenum format, GLenum type,
> +                       const void *data);
> +
>  bool
>  _mesa_compressed_texture_pixel_storage_error_check(struct gl_context *ctx,
>                                               GLint dimensions,
> 



More information about the mesa-dev mailing list