[Mesa-dev] [PATCH 2/5] mesa/main: Add generic bits of ARB_clear_texture implementation
Ian Romanick
idr at freedesktop.org
Mon Jun 30 15:50:59 PDT 2014
On 06/13/2014 05:59 PM, Neil Roberts wrote:
> This adds the driver entry point for glClearTexSubImage and fills in the
> _mesa_ClearTexImage and _mesa_ClearTexSubImage functions that call it.
> ---
> src/mesa/main/dd.h | 14 +++
> src/mesa/main/teximage.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++-
> src/mesa/main/teximage.h | 12 +++
> 3 files changed, 266 insertions(+), 1 deletion(-)
>
> 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/teximage.c b/src/mesa/main/teximage.c
> index a893c70..d5baac8 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"
>
>
> /**
> @@ -3848,20 +3849,259 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
> x, y, width, height);
> }
>
> +static bool
> +clear_tex_image(struct gl_context *ctx,
> + const char *function,
> + 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;
> + GLenum internalFormat = texImage->InternalFormat;
> + GLenum err;
> +
> + if (texObj->Target == GL_TEXTURE_BUFFER) {
> + _mesa_error(ctx, GL_INVALID_OPERATION,
> + "%s(buffer texture)", function);
> + return false;
> + }
> +
> + if (_mesa_is_compressed_format(ctx, internalFormat)) {
> + _mesa_error(ctx, GL_INVALID_OPERATION,
> + "%s(compressed texture)", function);
> + return false;
> + }
> +
> + err = _mesa_error_check_format_and_type(ctx, format, type);
> + if (err != GL_NO_ERROR) {
> + _mesa_error(ctx, err,
> + "%s(incompatible format = %s, type = %s)",
> + function,
> + _mesa_lookup_enum_by_nr(format),
> + _mesa_lookup_enum_by_nr(type));
> + return false;
> + }
> +
> + /* make sure internal format and format basically agree */
> + if (!texture_formats_agree(internalFormat, format)) {
> + _mesa_error(ctx, GL_INVALID_OPERATION,
> + "%s(incompatible internalFormat = %s, format = %s)",
> + function,
> + _mesa_lookup_enum_by_nr(internalFormat),
> + _mesa_lookup_enum_by_nr(format));
> + return false;
> + }
> +
> + 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,
> + "%s(integer/non-integer format mismatch)",
> + function);
> + return false;
> + }
> + }
> +
> + 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, "%s(invalid format)", function);
> + return false;
> + }
> +
> + ctx->Driver.ClearTexSubImage(ctx,
> + texImage,
> + xoffset, yoffset, zoffset,
> + width, height, depth,
> + data ? clearValue : NULL);
> +
> + return true;
> +}
> +
> +static struct gl_texture_object *
> +get_tex_obj_for_clear(struct gl_context *ctx,
> + const char *function,
> + GLuint texture)
> +{
> + struct gl_texture_object *texObj;
> +
> + if (texture == 0) {
> + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function);
> + return NULL;
> + }
> +
> + texObj = _mesa_lookup_texture(ctx, texture);
> +
> + if (texObj == NULL) {
> + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function);
> + return NULL;
> + }
> +
> + if (texObj->Target == 0) {
> + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function);
> + return NULL;
> + }
> +
> + return texObj;
> +}
> +
> +static int
> +get_tex_images_for_clear(struct gl_context *ctx,
> + const char *function,
> + 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, "%s(invalid level)", function);
> + 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,
> + "%s(invalid level)", function);
> + 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, "%s(invalid level)", function);
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> 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;
> + bool res;
>
> + texObj = get_tex_obj_for_clear(ctx, "glClearTexSubImage", texture);
> +
> + if (texObj == NULL)
> + return;
> +
> + _mesa_lock_texture(ctx, texObj);
> +
> + numImages = get_tex_images_for_clear(ctx, "glClearTexSubImage",
> + texObj, level, texImages);
> + if (numImages == 0)
> + goto out;
> +
> + if (numImages == 1) {
> + minDepth = -(int) texImages[0]->Border;
> + maxDepth = texImages[0]->Depth;
> + } else {
> + minDepth = 0;
> + maxDepth = numImages;
> + }
> +
> + if (xoffset < -(GLint) texImages[0]->Border ||
> + yoffset < -(GLint) 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, "glClearTexSubImage",
> + texImages[0], level,
> + xoffset, yoffset, zoffset,
> + width, height, depth,
> + format, type, data);
> + } else {
> + for (i = zoffset; i < zoffset + depth; i++) {
> + res = clear_tex_image(ctx, "glClearTexSubImage",
> + texImages[i], level,
> + xoffset, yoffset, 0,
> + width, height, 1,
> + format, type, data);
Are there potentially cases where the first clear_tex_image could
succeed but the second fail? If so, then this is no good. If a GL call
generates an error (other than GL_NO_MEMORY), it is supposed to be as
though nothing happened.
There are a few places in Mesa where things separated into
"check_something" and "something" functions for exactly this reason. Do
all the checks, then do all the work. That may or may not be necessary
here.
> + if (!res)
> + break;
> + }
> + }
> +
> + out:
> + _mesa_unlock_texture(ctx, texObj);
> }
>
> 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;
> + bool res;
> +
> + texObj = get_tex_obj_for_clear(ctx, "glClearTexImage", texture);
>
> + if (texObj == NULL)
> + return;
> +
> + _mesa_lock_texture(ctx, texObj);
> +
> + numImages = get_tex_images_for_clear(ctx, "glClearTexImage",
> + texObj, level, texImages);
> +
> + for (i = 0; i < numImages; i++) {
> + res = clear_tex_image(ctx, "glClearTexImage",
> + texImages[i], level,
> + -(GLint) texImages[i]->Border, /* xoffset */
> + -(GLint) texImages[i]->Border, /* yoffset */
> + -(GLint) texImages[i]->Border, /* zoffset */
> + texImages[i]->Width,
> + texImages[i]->Height,
> + texImages[i]->Depth,
> + format, type, data);
> + if (!res)
> + break;
> + }
> +
> + _mesa_unlock_texture(ctx, texObj);
> }
>
>
> @@ -4624,7 +4864,6 @@ _mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
> "glTexStorage2DMultisample");
> }
>
> -
> void GLAPIENTRY
> _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
> GLenum internalformat, GLsizei width,
> diff --git a/src/mesa/main/teximage.h b/src/mesa/main/teximage.h
> index 42305f4..984321c 100644
> --- a/src/mesa/main/teximage.h
> +++ b/src/mesa/main/teximage.h
> @@ -336,6 +336,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);
> +
> bool
> _mesa_compressed_texture_pixel_storage_error_check(struct gl_context *ctx,
> GLint dimensions,
>
More information about the mesa-dev
mailing list