From fbbbf7529c3d99a0b2f569495033283877df8b60 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 10 Jun 2014 16:11:00 +0100 Subject: [PATCH] mesa/main: Add generic bits of ARB_clear_texture implementation This adds the driver entry point for glClearTexSubImage and fills in the _mesa_ClearTexImage and _mesa_ClearTexSubImage functions that call it. v2: Don't clear some of the images if only one of them makes an error Reviewed-by: Jason Ekstrand --- src/mesa/main/dd.h | 14 +++ src/mesa/main/teximage.c | 246 ++++++++++++++++++++++++++++++++++++++- src/mesa/main/teximage.h | 12 ++ 3 files changed, 271 insertions(+), 1 deletion(-) diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 633ea2c3a2e..89765351e14 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -238,6 +238,20 @@ struct dd_function_table { GLenum format, GLenum type, GLvoid *pixels, 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(). * diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index b972cc187ad..fb2dee7d85f 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" /** @@ -3835,20 +3836,264 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, x, y, width, height); } +static bool +check_clear_tex_image(struct gl_context *ctx, + const char *function, + struct gl_texture_image *texImage, + GLenum format, GLenum type, + const void *data, + GLubyte *clearValue) +{ + struct gl_texture_object *texObj = texImage->TexObject; + static const GLubyte zeroData[MAX_PIXEL_BYTES]; + 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 */ + &clearValue, + 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; + } + + 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]; + GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES]; + int i, numImages; + int minDepth, maxDepth; + + 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) { + if (check_clear_tex_image(ctx, "glClearTexSubImage", + texImages[0], + format, type, data, clearValue[0])) { + ctx->Driver.ClearTexSubImage(ctx, + texImages[0], + xoffset, yoffset, zoffset, + width, height, depth, + data ? clearValue[0] : NULL); + } + } else { + for (i = zoffset; i < zoffset + depth; i++) { + if (!check_clear_tex_image(ctx, "glClearTexSubImage", + texImages[i], + format, type, data, clearValue[i])) + goto out; + } + for (i = zoffset; i < zoffset + depth; i++) { + ctx->Driver.ClearTexSubImage(ctx, + texImages[i], + xoffset, yoffset, 0, + width, height, 1, + data ? clearValue[i] : NULL); + } + } + + 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]; + GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES]; + int i, numImages; + + 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++) { + if (!check_clear_tex_image(ctx, "glClearTexImage", + texImages[i], + format, type, data, + clearValue[i])) + goto out; + } + + for (i = 0; i < numImages; i++) { + ctx->Driver.ClearTexSubImage(ctx, texImages[i], + -(GLint) texImages[i]->Border, /* xoffset */ + -(GLint) texImages[i]->Border, /* yoffset */ + -(GLint) texImages[i]->Border, /* zoffset */ + texImages[i]->Width, + texImages[i]->Height, + texImages[i]->Depth, + data ? clearValue[i] : NULL); + } + +out: + _mesa_unlock_texture(ctx, texObj); } @@ -4611,7 +4856,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 42305f44f0b..984321c2100 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, -- 2.30.2