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

Ilia Mirkin imirkin at alum.mit.edu
Wed Jun 4 11:46:24 PDT 2014


On Wed, Jun 4, 2014 at 2: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.

You might want to check out the impl I did a few months ago --
https://github.com/imirkin/mesa/commits/clear_texture . It went a few
rounds of review, but died at the "there are no piglit tests" stage.
I'm pretty sure your impl handles a bunch of cases that mine doesn't,
so just go with that. I'm just pointing it out in case you want to
compare and look for cases you might have missed.

I believe the usual thing is to split this sort of thing up into a few
patches, roughly how I had it.

I think you're still missing some api-errors and try-all-the-formats
formats piglit tests. Especially non-renderable formats and MS ones.

There are a few more comments inline:

> ---
>  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)");

I was told to pass the name of the function in and reproduce it with %s.

> +      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)) {

I had used _mesa_is_enum_format_integer_or_type() here. Also, is it
possible to have a ctx->Version >= 30 && !EXT_texture_integer?

FWIW I also had explicit checks making sure that various depth/stencil
stuff weren't mixed together improperly (i.e. passing a
GL_DEPTH_COMPONENT format for a tex image with a diff base format,
etc). Perhaps this checking is handled somewhere else in your code and
I didn't see it though.

> +         _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);

Wait, you go to all the trouble of computing the "zeroData" but then
don't use it?

> +}
> +
> +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);

Basically every implementation is going to do this... why not just
pass it in? Seems safer to explicitly say how many bytes of the
pointer are legal to read. Could be seen as redundant wrt the
TexFormat though... up to you.

> +
> +   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