On 06/04/2014 11:12 AM, Neil Roberts 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.
GL_EXT_framebuffer_object is always supported, so that shouldn't be a concern. > 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 + Also need changes to src/mesa/main/tests/dispatch_sanity.cpp. I guess you didn't 'make check'. :) Below I've deleted any files where I didn't have comments... otherwise I think my comments may have gotten lost. That's part of the reason more small patches is better than a signle large patch. > 11 files changed, 549 insertions(+), 2 deletions(-) > create mode 100644 src/mapi/glapi/gen/ARB_clear_texture.xml > > 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. > + */ This extension doesn't exist in ES, so I don't think any of these ES checks are useful. > + 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); Gallium drivers don't use meta at all, so ctx->Driver.ClearTexSubImage will be NULL in all Gallium drivers. Until there is a Gallium implementation (Ilia may have done one already...), I don't think we can enable this extension by default. > +} > + > +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; Is this actually necessary / better? With the loop condition below, this seems like extra code... > + > + 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); > +} _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev