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

Neil Roberts neil at linux.intel.com
Wed Jun 4 11:12:24 PDT 2014


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



More information about the mesa-dev mailing list