[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