[Mesa-dev] [PATCH] Implement the ARB_clear_texture extension

Marek Olšák maraeo at gmail.com
Thu Jun 5 03:23:16 PDT 2014


Hi Neil,

I'd like to have full hardware acceleration for Gallium drivers before
advertising the extension for them. I wouldn't like to have extensions
which are only implemented in software where hardware support is
preferable. Therefore, not advertising the extension is the way to go
if you are not interested in Gallium.

Thanks,

Marek


On Wed, Jun 4, 2014 at 8:12 PM, Neil Roberts <neil at linux.intel.com> wrote:
> The clear texture extension is used to clear a texture to a given value
> without having to provide a buffer for the whole texture and without having to
> create an FBO. This patch provides a generic implementation that works with
> any driver. There are two approaches, the first being in meta.c which tries to
> create a GL framebuffer to the texture and calls glClear. This can fail
> if the FBO extension is not supported or if the texture can't be used as a
> render target. In that case it will fall back to an implementation in
> texstore.c which maps a region of the texture and just directly writes in the
> values.
>
> A small problem with this patch is that the fallback approach that maps the
> texture doesn't seem to work with depth-stencil textures. However I think this
> may be a general bug with mapping depth-stencil textures because I seem to get
> the same issue if I try to update the texture using glTexSubImage2D as well.
> You can replicate this if you run the Piglit test
> arb_clear_texture-depth-stencil and set MESA_EXTENSION_OVERRIDE to
> -GL_ARB_framebuffer_object.
> ---
>  src/mapi/glapi/gen/ARB_clear_texture.xml |  32 ++++
>  src/mapi/glapi/gen/gl_API.xml            |   6 +-
>  src/mesa/drivers/common/driverfuncs.c    |   1 +
>  src/mesa/drivers/common/meta.c           | 143 ++++++++++++++++++
>  src/mesa/drivers/common/meta.h           |  14 ++
>  src/mesa/main/dd.h                       |  14 ++
>  src/mesa/main/extensions.c               |   1 +
>  src/mesa/main/teximage.c                 | 251 ++++++++++++++++++++++++++++++-
>  src/mesa/main/teximage.h                 |  12 ++
>  src/mesa/main/texstore.c                 |  70 +++++++++
>  src/mesa/main/texstore.h                 |   7 +
>  11 files changed, 549 insertions(+), 2 deletions(-)
>  create mode 100644 src/mapi/glapi/gen/ARB_clear_texture.xml
>
> diff --git a/src/mapi/glapi/gen/ARB_clear_texture.xml b/src/mapi/glapi/gen/ARB_clear_texture.xml
> new file mode 100644
> index 0000000..9bb400a
> --- /dev/null
> +++ b/src/mapi/glapi/gen/ARB_clear_texture.xml
> @@ -0,0 +1,32 @@
> +<?xml version="1.0"?>
> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
> +
> +<OpenGLAPI>
> +
> +<category name="GL_ARB_clear_texture" number="145">
> +
> +    <function name ="ClearTexImage" offset="assign">
> +        <param name="texture" type="GLuint"/>
> +        <param name="level" type="GLint"/>
> +        <param name="format" type="GLenum"/>
> +        <param name="type" type="GLenum"/>
> +        <param name="data" type="const GLvoid *"/>
> +    </function>
> +
> +    <function name ="ClearTexSubImage" offset="assign">
> +        <param name="texture" type="GLuint"/>
> +        <param name="level" type="GLint"/>
> +        <param name="xoffset" type="GLint"/>
> +        <param name="yoffset" type="GLint"/>
> +        <param name="zoffset" type="GLint"/>
> +        <param name="width" type="GLsizei"/>
> +        <param name="height" type="GLsizei"/>
> +        <param name="depth" type="GLsizei"/>
> +        <param name="format" type="GLenum"/>
> +        <param name="type" type="GLenum"/>
> +        <param name="data" type="const GLvoid *"/>
> +    </function>
> +
> +</category>
> +
> +</OpenGLAPI>
> diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml
> index 0791bfc..181263a 100644
> --- a/src/mapi/glapi/gen/gl_API.xml
> +++ b/src/mapi/glapi/gen/gl_API.xml
> @@ -8344,7 +8344,11 @@
>      </function>
>  </category>
>
> -<!-- ARB extensions #145...#146 -->
> +<!-- ARB extension #145 -->
> +
> +<xi:include href="ARB_clear_texture.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
> +
> +<!-- ARB extension #147 -->
>
>  <xi:include href="ARB_multi_bind.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
>
> diff --git a/src/mesa/drivers/common/driverfuncs.c b/src/mesa/drivers/common/driverfuncs.c
> index 6ece5d8..4f0f7a6 100644
> --- a/src/mesa/drivers/common/driverfuncs.c
> +++ b/src/mesa/drivers/common/driverfuncs.c
> @@ -95,6 +95,7 @@ _mesa_init_driver_functions(struct dd_function_table *driver)
>     driver->TexImage = _mesa_store_teximage;
>     driver->TexSubImage = _mesa_store_texsubimage;
>     driver->GetTexImage = _mesa_meta_GetTexImage;
> +   driver->ClearTexSubImage = _mesa_meta_ClearTexSubImage;
>     driver->CopyTexSubImage = _mesa_meta_CopyTexSubImage;
>     driver->GenerateMipmap = _mesa_meta_GenerateMipmap;
>     driver->TestProxyTexImage = _mesa_test_proxy_teximage;
> diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
> index fec0d2b..e4aa8b2 100644
> --- a/src/mesa/drivers/common/meta.c
> +++ b/src/mesa/drivers/common/meta.c
> @@ -40,6 +40,7 @@
>  #include "main/blit.h"
>  #include "main/bufferobj.h"
>  #include "main/buffers.h"
> +#include "main/clear.h"
>  #include "main/colortab.h"
>  #include "main/condrender.h"
>  #include "main/depth.h"
> @@ -47,6 +48,7 @@
>  #include "main/fbobject.h"
>  #include "main/feedback.h"
>  #include "main/formats.h"
> +#include "main/format_unpack.h"
>  #include "main/glformats.h"
>  #include "main/image.h"
>  #include "main/macros.h"
> @@ -71,6 +73,7 @@
>  #include "main/teximage.h"
>  #include "main/texparam.h"
>  #include "main/texstate.h"
> +#include "main/texstore.h"
>  #include "main/transformfeedback.h"
>  #include "main/uniforms.h"
>  #include "main/varray.h"
> @@ -3359,3 +3362,143 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
>
>     _mesa_meta_end(ctx);
>  }
> +
> +static bool
> +cleartexsubimage_using_fbo_for_zoffset(struct gl_context *ctx,
> +                                       struct gl_texture_image *texImage,
> +                                       GLint xoffset, GLint yoffset,
> +                                       GLint zoffset,
> +                                       GLsizei width, GLsizei height,
> +                                       const GLvoid *clearValue)
> +{
> +   GLuint fbo;
> +   bool success = false;
> +   GLbitfield mask;
> +   GLenum status;
> +   GLuint depthStencilValue[2];
> +   GLfloat depthValue;
> +
> +   _mesa_GenFramebuffers(1, &fbo);
> +   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
> +
> +   if (texImage->_BaseFormat == GL_DEPTH_STENCIL ||
> +       texImage->_BaseFormat == GL_DEPTH_COMPONENT) {
> +      _mesa_meta_bind_fbo_image(GL_DEPTH_ATTACHMENT, texImage, zoffset);
> +      mask = GL_DEPTH_BUFFER_BIT;
> +
> +      if (clearValue)
> +         _mesa_unpack_float_32_uint_24_8_depth_stencil_row(texImage->TexFormat,
> +                                                           1, /* n */
> +                                                           clearValue,
> +                                                           depthStencilValue);
> +      else
> +         memset(depthStencilValue, 0, sizeof depthStencilValue);
> +
> +      memcpy(&depthValue, depthStencilValue, sizeof depthValue);
> +      ctx->Depth.Clear = depthValue;
> +
> +      if (texImage->_BaseFormat == GL_DEPTH_STENCIL) {
> +         _mesa_meta_bind_fbo_image(GL_STENCIL_ATTACHMENT, texImage, zoffset);
> +         mask |= GL_STENCIL_BUFFER_BIT;
> +         ctx->Stencil.Clear = depthStencilValue[1] & 0xff;
> +      }
> +      _mesa_DrawBuffer(GL_NONE);
> +   } else {
> +      _mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, texImage, zoffset);
> +      _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
> +      mask = GL_COLOR_BUFFER_BIT;
> +
> +      if (clearValue)
> +         _mesa_unpack_rgba_row(texImage->TexFormat, 1, clearValue,
> +                               (GLfloat (*)[4]) ctx->Color.ClearColor.f);
> +      else
> +         memset(ctx->Color.ClearColor.f, 0, sizeof ctx->Color.ClearColor.f);
> +   }
> +
> +   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
> +   if (status != GL_FRAMEBUFFER_COMPLETE)
> +      goto out;
> +
> +   _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE);
> +   _mesa_Scissor(xoffset, yoffset, width, height);
> +   _mesa_Clear(mask);
> +
> +   success = true;
> +
> + out:
> +   _mesa_DeleteFramebuffers(1, &fbo);
> +   return success;
> +}
> +
> +static bool
> +cleartexsubimage_using_fbo(struct gl_context *ctx,
> +                           struct gl_texture_image *texImage,
> +                           GLint xoffset, GLint yoffset, GLint zoffset,
> +                           GLsizei width, GLsizei height, GLsizei depth,
> +                           const GLvoid *clearValue)
> +{
> +   union gl_color_union saveColorValue;
> +   bool success = false;
> +
> +   if (!ctx->Extensions.ARB_framebuffer_object)
> +      return false;
> +
> +   /* This probably won't work with images that have a border */
> +   if (texImage->Border != 0)
> +      return false;
> +
> +   _mesa_meta_begin(ctx,
> +                    MESA_META_SCISSOR |
> +                    MESA_META_COLOR_MASK |
> +                    MESA_META_DEPTH_TEST |
> +                    MESA_META_STENCIL_TEST);
> +
> +   /* _mesa_meta_begin doesn't seem to save this */
> +   saveColorValue = ctx->Color.ClearColor;
> +
> +   while (depth-- > 0) {
> +      if (!cleartexsubimage_using_fbo_for_zoffset(ctx, texImage,
> +                                                  xoffset, yoffset, zoffset++,
> +                                                  width, height,
> +                                                  clearValue))
> +         goto out;
> +   }
> +
> +   success = true;
> +
> + out:
> +   ctx->Color.ClearColor = saveColorValue;
> +   _mesa_meta_end(ctx);
> +   return success;
> +}
> +
> +extern void
> +_mesa_meta_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)
> +{
> +   bool res;
> +
> +   _mesa_unlock_texture(ctx, texImage->TexObject);
> +
> +   res = cleartexsubimage_using_fbo(ctx, texImage,
> +                                    xoffset, yoffset, zoffset,
> +                                    width, height, depth,
> +                                    clearValue);
> +
> +   _mesa_lock_texture(ctx, texImage->TexObject);
> +
> +   if (res)
> +      return;
> +
> +   _mesa_warning(ctx,
> +                 "Falling back to mapping the texture in "
> +                 "glClearTexSubImage\n");
> +
> +   _mesa_store_ClearTexSubImage(ctx, texImage,
> +                                xoffset, yoffset, zoffset,
> +                                width, height, depth,
> +                                clearValue);
> +}
> diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h
> index 765f8df..456412b 100644
> --- a/src/mesa/drivers/common/meta.h
> +++ b/src/mesa/drivers/common/meta.h
> @@ -473,6 +473,13 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
>                             GLsizei width, GLsizei height);
>
>  extern void
> +_mesa_meta_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);
> +
> +extern void
>  _mesa_meta_GetTexImage(struct gl_context *ctx,
>                         GLenum format, GLenum type, GLvoid *pixels,
>                         struct gl_texture_image *texImage);
> @@ -481,6 +488,13 @@ extern void
>  _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
>                     GLfloat width, GLfloat height);
>
> +extern void
> +_mesa_store_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);
> +
>  /* meta-internal functions */
>  GLuint
>  _mesa_meta_compile_shader_with_debug(struct gl_context *ctx, GLenum target,
> 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/extensions.c b/src/mesa/main/extensions.c
> index c2ff7e3..bf7ef13 100644
> --- a/src/mesa/main/extensions.c
> +++ b/src/mesa/main/extensions.c
> @@ -85,6 +85,7 @@ static const struct extension extension_table[] = {
>     { "GL_ARB_blend_func_extended",                 o(ARB_blend_func_extended),                 GL,             2009 },
>     { "GL_ARB_buffer_storage",                      o(ARB_buffer_storage),                      GL,             2013 },
>     { "GL_ARB_clear_buffer_object",                 o(dummy_true),                              GL,             2012 },
> +   { "GL_ARB_clear_texture",                       o(dummy_true),                              GL,             2013 },
>     { "GL_ARB_color_buffer_float",                  o(ARB_color_buffer_float),                  GL,             2004 },
>     { "GL_ARB_compute_shader",                      o(ARB_compute_shader),                      GL,             2012 },
>     { "GL_ARB_copy_buffer",                         o(dummy_true),                              GL,             2008 },
> diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c
> index 845ba80..43c5889 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"
>
>
>  /**
> @@ -4544,7 +4545,6 @@ _mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
>                         "glTexStorage2DMultisample");
>  }
>
> -
>  void GLAPIENTRY
>  _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
>                                GLenum internalformat, GLsizei width,
> @@ -4555,3 +4555,252 @@ _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
>                         width, height, depth, fixedsamplelocations, GL_TRUE,
>                         "glTexStorage3DMultisample");
>  }
> +
> +static void
> +clear_tex_image(struct gl_context *ctx,
> +                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;
> +   GLint dimensions;
> +   GLenum err;
> +
> +   dimensions = _mesa_get_texture_dimensions(texObj->Target);
> +
> +   if (texObj->Target == GL_TEXTURE_BUFFER) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glClear*TexImage(buffer texture)");
> +      return;
> +   }
> +
> +   if (_mesa_is_compressed_format(ctx, texImage->InternalFormat)) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glClear*TexImage(compressed texture)");
> +      return;
> +   }
> +
> +   /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
> +    * combinations of format and type that can be used.  Formats and types
> +    * that require additional extensions (e.g., GL_FLOAT requires
> +    * GL_OES_texture_float) are filtered elsewhere.
> +    */
> +   if (_mesa_is_gles(ctx) && !_mesa_is_gles3(ctx)) {
> +      err = _mesa_es_error_check_format_and_type(format, type, dimensions);
> +      if (err != GL_NO_ERROR) {
> +         _mesa_error(ctx, err,
> +                     "glClearTex*Image(format = %s, type = %s)",
> +                     _mesa_lookup_enum_by_nr(format),
> +                     _mesa_lookup_enum_by_nr(type));
> +         return;
> +      }
> +   }
> +
> +   err = _mesa_error_check_format_and_type(ctx, format, type);
> +   if (err != GL_NO_ERROR) {
> +      _mesa_error(ctx, err,
> +                  "glClearTex*Image(incompatible format = %s, type = %s)",
> +                  _mesa_lookup_enum_by_nr(format),
> +                  _mesa_lookup_enum_by_nr(type));
> +      return;
> +   }
> +
> +   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,
> +                     "glClearTex*Image(integer/non-integer format mismatch)");
> +         return;
> +      }
> +   }
> +
> +   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, "glClearTex*Image");
> +      return;
> +   }
> +
> +   ctx->Driver.ClearTexSubImage(ctx,
> +                                texImage,
> +                                xoffset, yoffset, zoffset,
> +                                width, height, depth,
> +                                data ? clearValue : NULL);
> +}
> +
> +static struct gl_texture_object *
> +get_tex_obj_for_clear(struct gl_context *ctx,
> +                      GLuint texture)
> +{
> +   struct gl_texture_object *texObj;
> +
> +   if (texture == 0) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "glClear*TexImage(zero texture)");
> +      return NULL;
> +   }
> +
> +   texObj = _mesa_lookup_texture(ctx, texture);
> +
> +   if (texObj == NULL) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "glClear*TexImage(non-gen name)");
> +      return NULL;
> +   }
> +
> +   if (texObj->Target == 0) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "glClear*TexImage(unbound tex)");
> +      return NULL;
> +   }
> +
> +   return texObj;
> +}
> +
> +static int
> +get_tex_images_for_clear(struct gl_context *ctx,
> +                         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, "glClear*TexImage(invalid level)");
> +      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,
> +                        "glClear*TexImage(invalid level)");
> +            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, "glClear*TexImage(invalid level)");
> +      return 0;
> +   }
> +
> +   return 1;
> +}
> +
> +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;
> +
> +   texObj = get_tex_obj_for_clear(ctx, texture);
> +
> +   if (texObj == NULL)
> +      return;
> +
> +   _mesa_lock_texture(ctx, texObj);
> +
> +   numImages = get_tex_images_for_clear(ctx, texObj, level, texImages);
> +   if (numImages == 0)
> +      goto out;
> +
> +   for (i = 0; i < numImages; i++) {
> +      clear_tex_image(ctx, texImages[i], level,
> +                      -texImages[i]->Border, /* xoffset */
> +                      -texImages[i]->Border, /* yoffset */
> +                      -texImages[i]->Border, /* zoffset */
> +                      texImages[i]->Width,
> +                      texImages[i]->Height,
> +                      texImages[i]->Depth,
> +                      format, type, data);
> +   }
> +
> + out:
> +   _mesa_unlock_texture(ctx, texObj);
> +}
> +
> +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;
> +
> +   texObj = get_tex_obj_for_clear(ctx, texture);
> +
> +   if (texObj == NULL)
> +      return;
> +
> +   _mesa_lock_texture(ctx, texObj);
> +
> +   numImages = get_tex_images_for_clear(ctx, texObj, level, texImages);
> +   if (numImages == 0)
> +      goto out;
> +
> +   if (numImages == 1) {
> +      minDepth = -texImages[0]->Border;
> +      maxDepth = texImages[0]->Depth;
> +   } else {
> +      minDepth = 0;
> +      maxDepth = numImages;
> +   }
> +
> +   if (xoffset < -texImages[0]->Border ||
> +       yoffset < -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, texImages[0], level,
> +                      xoffset, yoffset, zoffset,
> +                      width, height, depth,
> +                      format, type, data);
> +   } else {
> +      for (i = zoffset; i < zoffset + depth; i++)
> +         clear_tex_image(ctx, texImages[i], level,
> +                         xoffset, yoffset, 0,
> +                         width, height, 1,
> +                         format, type, data);
> +   }
> +
> + out:
> +   _mesa_unlock_texture(ctx, texObj);
> +}
> diff --git a/src/mesa/main/teximage.h b/src/mesa/main/teximage.h
> index 51d94d1..68c568a 100644
> --- a/src/mesa/main/teximage.h
> +++ b/src/mesa/main/teximage.h
> @@ -326,6 +326,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);
> +
>  /*@}*/
>
>  #ifdef __cplusplus
> diff --git a/src/mesa/main/texstore.c b/src/mesa/main/texstore.c
> index 7642146..6b94b89 100644
> --- a/src/mesa/main/texstore.c
> +++ b/src/mesa/main/texstore.c
> @@ -4157,6 +4157,76 @@ _mesa_store_texsubimage(struct gl_context *ctx, GLuint dims,
>                       format, type, pixels, packing, "glTexSubImage");
>  }
>
> +static void
> +clear_image_to_zero(GLubyte *dstMap, GLint dstRowStride,
> +                    GLsizei width, GLsizei height,
> +                    GLsizei clearValueSize)
> +{
> +   while (height-- > 0) {
> +      memset(dstMap, 0, clearValueSize * width);
> +      dstMap += dstRowStride;
> +   }
> +}
> +
> +static void
> +clear_image_to_value(GLubyte *dstMap, GLint dstRowStride,
> +                     GLsizei width, GLsizei height,
> +                     const GLvoid *clearValue,
> +                     GLsizei clearValueSize)
> +{
> +   GLsizei x;
> +
> +   while (height-- > 0) {
> +      for (x = 0; x < width; x++) {
> +         memcpy(dstMap, clearValue, clearValueSize);
> +         dstMap += clearValueSize;
> +      }
> +      dstMap += dstRowStride - clearValueSize * width;
> +   }
> +}
> +
> +/*
> + * Fallback for Driver.ClearTexSubImage().
> + */
> +void
> +_mesa_store_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)
> +{
> +   GLubyte *dstMap;
> +   GLint dstRowStride;
> +   GLsizeiptr clearValueSize;
> +   GLsizei z;
> +
> +   clearValueSize = _mesa_get_format_bytes(texImage->TexFormat);
> +
> +   for (z = 0; z < depth; z++) {
> +      ctx->Driver.MapTextureImage(ctx, texImage,
> +                                  z + zoffset, xoffset, yoffset,
> +                                  width, height,
> +                                  GL_MAP_WRITE_BIT,
> +                                  &dstMap, &dstRowStride);
> +      if (dstMap == NULL) {
> +         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearTex*Image");
> +         return;
> +      }
> +
> +      if (clearValue) {
> +         clear_image_to_value(dstMap, dstRowStride,
> +                              width, height,
> +                              clearValue,
> +                              clearValueSize);
> +      } else {
> +         clear_image_to_zero(dstMap, dstRowStride,
> +                             width, height,
> +                             clearValueSize);
> +      }
> +
> +      ctx->Driver.UnmapTextureImage(ctx, texImage, z + zoffset);
> +   }
> +}
>
>  /**
>   * Fallback for Driver.CompressedTexImage()
> diff --git a/src/mesa/main/texstore.h b/src/mesa/main/texstore.h
> index 490f9f5..91db152 100644
> --- a/src/mesa/main/texstore.h
> +++ b/src/mesa/main/texstore.h
> @@ -118,6 +118,13 @@ _mesa_store_texsubimage(struct gl_context *ctx, GLuint dims,
>
>
>  extern void
> +_mesa_store_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);
> +
> +extern void
>  _mesa_store_compressed_teximage(struct gl_context *ctx, GLuint dims,
>                                  struct gl_texture_image *texImage,
>                                  GLsizei imageSize, const GLvoid *data);
> --
> 1.9.0
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list