[Mesa-dev] [PATCH 09/14] mesa: overhaul the glGetCompressedTexImage code
Ilia Mirkin
imirkin at alum.mit.edu
Fri Jul 17 18:11:47 PDT 2015
On Wed, Jul 15, 2015 at 7:40 PM, Brian Paul <brianp at vmware.com> wrote:
> Same idea as the previous patch.
> ---
> src/mesa/main/texgetimage.c | 345 ++++++++++++++++++++++++++------------------
> 1 file changed, 203 insertions(+), 142 deletions(-)
>
> diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c
> index 49239e7..6ac1779 100644
> --- a/src/mesa/main/texgetimage.c
> +++ b/src/mesa/main/texgetimage.c
> @@ -1438,224 +1438,285 @@ _mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type,
>
>
> /**
> - * Do error checking for a glGetCompressedTexImage() call.
> - * \return GL_TRUE if any error, GL_FALSE if no errors.
> + * Compute the number of bytes which will be written when retrieving
> + * a sub-region of a compressed texture.
> */
> -static GLboolean
> +static GLsizei
> +packed_compressed_size(GLuint dimensions, mesa_format format,
> + GLsizei width, GLsizei height, GLsizei depth,
> + const struct gl_pixelstore_attrib *packing)
> +{
> + struct compressed_pixelstore st;
> + GLsizei totalBytes;
> +
> + _mesa_compute_compressed_pixelstore(dimensions, format,
> + width, height, depth,
> + packing, &st);
> + totalBytes =
> + (st.CopySlices - 1) * st.TotalRowsPerSlice * st.TotalBytesPerRow +
> + st.SkipBytes +
> + (st.CopyRowsPerSlice - 1) * st.TotalBytesPerRow +
> + st.CopyBytesPerRow;
> +
> + return totalBytes;
> +}
> +
> +
> +/**
> + * Do error checking for getting compressed texture images.
> + * \return true if any error, false if no errors.
> + */
> +static bool
> getcompressedteximage_error_check(struct gl_context *ctx,
> - struct gl_texture_image *texImage,
> - GLenum target,
> - GLint level, GLsizei clientMemSize,
> - GLvoid *img, bool dsa)
> + struct gl_texture_object *texObj,
> + GLenum target, GLint level,
> + GLint xoffset, GLint yoffset, GLint zoffset,
> + GLsizei width, GLsizei height, GLsizei depth,
> + GLsizei bufSize, GLvoid *pixels,
> + const char *caller)
> {
> - const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
> - GLuint compressedSize, dimensions;
> - const char *suffix = dsa ? "ture" : "";
> + struct gl_texture_image *texImage;
> + GLint maxLevels;
> + GLsizei totalBytes;
> + GLuint dimensions;
>
> - assert(texImage);
> + assert(texObj);
>
> - if (!legal_getteximage_target(ctx, target, dsa)) {
> - _mesa_error(ctx, GL_INVALID_ENUM,
> - "glGetCompressedTex%sImage(target=%s)", suffix,
> - _mesa_lookup_enum_by_nr(target));
> - return GL_TRUE;
> + if (texObj->Target == 0) {
> + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller);
> + return true;
> }
>
> - assert(maxLevels != 0);
> + maxLevels = _mesa_max_texture_levels(ctx, target);
> if (level < 0 || level >= maxLevels) {
> _mesa_error(ctx, GL_INVALID_VALUE,
> - "glGetCompressedTex%sImage(bad level = %d)", suffix, level);
> - return GL_TRUE;
> + "%s(bad level = %d)", caller, level);
> + return true;
> }
>
> + if (dimensions_error_check(ctx, texObj, target, level,
> + xoffset, yoffset, zoffset,
> + width, height, depth, caller)) {
> + return true;
> + }
> +
> + texImage = select_tex_image(texObj, target, level, zoffset);
> + assert(texImage);
> +
> if (!_mesa_is_format_compressed(texImage->TexFormat)) {
> _mesa_error(ctx, GL_INVALID_OPERATION,
> - "glGetCompressedTex%sImage(texture is not compressed)",
> - suffix);
> - return GL_TRUE;
> + "%s(texture is not compressed)", caller);
> + return true;
> }
>
> - compressedSize = _mesa_format_image_size(texImage->TexFormat,
> - texImage->Width,
> - texImage->Height,
> - texImage->Depth);
> -
> /* Check for invalid pixel storage modes */
> - dimensions = _mesa_get_texture_dimensions(texImage->TexObject->Target);
> + dimensions = _mesa_get_texture_dimensions(texObj->Target);
> if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions,
> - &ctx->Pack, dsa ?
> - "glGetCompressedTextureImage":
> - "glGetCompressedTexImage")) {
> - return GL_TRUE;
> + &ctx->Pack,
> + caller)) {
> + return true;
> }
>
> - if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
> - /* do bounds checking on writing to client memory */
> - if (clientMemSize < (GLsizei) compressedSize) {
> - _mesa_error(ctx, GL_INVALID_OPERATION,
> - "%s(out of bounds access: bufSize (%d) is too small)",
> - dsa ? "glGetCompressedTextureImage" :
> - "glGetnCompressedTexImageARB", clientMemSize);
> - return GL_TRUE;
> - }
> - } else {
> + /* Compute number of bytes that may be touched in the dest buffer */
> + totalBytes = packed_compressed_size(dimensions, texImage->TexFormat,
> + width, height, depth,
> + &ctx->Pack);
> +
> + /* Do dest buffer bounds checking */
> + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
> /* do bounds checking on PBO write */
> - if ((const GLubyte *) img + compressedSize >
> - (const GLubyte *) ctx->Pack.BufferObj->Size) {
> + if ((GLubyte *) pixels + totalBytes >
> + (GLubyte *) ctx->Pack.BufferObj->Size) {
> _mesa_error(ctx, GL_INVALID_OPERATION,
> - "glGetCompressedTex%sImage(out of bounds PBO access)",
> - suffix);
> - return GL_TRUE;
> + "%s(out of bounds PBO access)", caller);
> + return true;
> }
>
> /* make sure PBO is not mapped */
> if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
> + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller);
> + return true;
> + }
> + }
> + else {
> + /* do bounds checking on writing to client memory */
> + if (totalBytes > bufSize) {
> _mesa_error(ctx, GL_INVALID_OPERATION,
> - "glGetCompressedTex%sImage(PBO is mapped)", suffix);
> - return GL_TRUE;
> + "%s(out of bounds access: bufSize (%d) is too small)",
> + caller, bufSize);
> + return true;
> }
> }
>
> - return GL_FALSE;
> + if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
> + /* not an error, but do nothing */
> + return true;
> + }
> +
> + return false;
> }
>
> -/** Implements glGetnCompressedTexImageARB, glGetCompressedTexImage, and
> - * glGetCompressedTextureImage.
> - *
> - * texImage must be passed in because glGetCompressedTexImage must handle the
> - * target GL_TEXTURE_CUBE_MAP.
> +
> +/**
> + * Common helper for all glGetCompressed-teximage functions.
> */
> -void
> -_mesa_get_compressed_texture_image(struct gl_context *ctx,
> - struct gl_texture_object *texObj,
> - struct gl_texture_image *texImage,
> - GLenum target, GLint level,
> - GLsizei bufSize, GLvoid *pixels,
> - bool dsa)
> +static void
> +get_compressed_texture_image(struct gl_context *ctx,
> + struct gl_texture_object *texObj,
> + GLenum target, GLint level,
> + GLint xoffset, GLint yoffset, GLint zoffset,
> + GLsizei width, GLsizei height, GLint depth,
> + GLsizei bufSize, GLvoid *pixels,
> + const char *caller)
> {
> - assert(texObj);
> - assert(texImage);
> + struct gl_texture_image *texImage;
> + unsigned firstFace, numFaces, i, imageStride;
>
> FLUSH_VERTICES(ctx, 0);
>
> - if (getcompressedteximage_error_check(ctx, texImage, target, level,
> - bufSize, pixels, dsa)) {
> - return;
> - }
> -
> - if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
> - /* not an error, do nothing */
> - return;
> - }
> + texImage = _mesa_select_tex_image(texObj, target, level);
> + assert(texImage); /* should have been error checked already */
>
> if (_mesa_is_zero_size_texture(texImage))
> return;
>
> if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
> _mesa_debug(ctx,
> - "glGetCompressedTex%sImage(tex %u) format = %s, w=%d, h=%d\n",
> - dsa ? "ture" : "", texObj->Name,
> + "%s(tex %u) format = %s, w=%d, h=%d\n",
> + caller, texObj->Name,
> _mesa_get_format_name(texImage->TexFormat),
> texImage->Width, texImage->Height);
> }
>
> + if (target == 0) {
> + target = texObj->Target;
> + }
In the non-compressed patch you fixed this up differently. Can you not
do the same thing here?
> +
> + if (target == GL_TEXTURE_CUBE_MAP) {
> + struct compressed_pixelstore store;
> +
> + /* Compute image stride between cube faces */
> + _mesa_compute_compressed_pixelstore(2, texImage->TexFormat,
> + width, height, depth,
> + &ctx->Pack, &store);
> + imageStride = store.TotalBytesPerRow * store.TotalRowsPerSlice;
> +
> + firstFace = zoffset;
> + numFaces = depth;
> + zoffset = 0;
> + depth = 1;
> + }
> + else {
> + imageStride = 0;
> + firstFace = _mesa_tex_target_to_face(target);
> + numFaces = 1;
> + }
> +
> _mesa_lock_texture(ctx, texObj);
> - {
> +
> + for (i = 0; i < numFaces; i++) {
> + texImage = texObj->Image[firstFace + i][level];
> + assert(texImage);
> +
> ctx->Driver.GetCompressedTexSubImage(ctx, texImage,
> - 0, 0, 0,
> - texImage->Width, texImage->Height,
> - texImage->Depth, pixels);
> + xoffset, yoffset, zoffset,
> + width, height, depth, pixels);
> +
> + /* next cube face */
> + pixels = (GLubyte *) pixels + imageStride;
> + bufSize -= imageStride;
bufSize is unused.
> }
> +
> _mesa_unlock_texture(ctx, texObj);
> }
>
> +
> void GLAPIENTRY
> _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
> - GLvoid *img)
> + GLvoid *pixels)
> {
> - struct gl_texture_object *texObj;
> - struct gl_texture_image *texImage;
> GET_CURRENT_CONTEXT(ctx);
> + static const char *caller = "glGetnCompressedTexImageARB";
> + GLsizei width, height, depth;
> + struct gl_texture_object *texObj;
>
> - texObj = _mesa_get_current_tex_object(ctx, target);
> - if (!texObj)
> + if (!legal_getteximage_target(ctx, target, false)) {
> + _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
> return;
> + }
>
> - texImage = _mesa_select_tex_image(texObj, target, level);
> - if (!texImage)
> + texObj = _mesa_get_current_tex_object(ctx, target);
> + assert(texObj);
> +
> + get_texture_image_dims(texObj, target, level, &width, &height, &depth);
> +
> + if (getcompressedteximage_error_check(ctx, texObj, target, level,
> + 0, 0, 0, width, height, depth,
> + INT_MAX, pixels, caller)) {
> return;
> + }
>
> - _mesa_get_compressed_texture_image(ctx, texObj, texImage, target, level,
> - bufSize, img, false);
> + get_compressed_texture_image(ctx, texObj, target, level,
> + 0, 0, 0, width, height, depth,
> + bufSize, pixels, caller);
> }
>
> -void GLAPIENTRY
> -_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img)
> -{
> - _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
> -}
>
> -/**
> - * Get compressed texture image.
> - *
> - * \param texture texture name.
> - * \param level image level.
> - * \param bufSize size of the pixels data buffer.
> - * \param pixels returned pixel data.
> - */
> void GLAPIENTRY
> -_mesa_GetCompressedTextureImage(GLuint texture, GLint level,
> - GLsizei bufSize, GLvoid *pixels)
> +_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *pixels)
> {
> - struct gl_texture_object *texObj;
> - struct gl_texture_image *texImage;
> - int i;
> - GLint image_stride;
> GET_CURRENT_CONTEXT(ctx);
> + static const char *caller = "glGetCompressedTexImage";
> + GLsizei width, height, depth;
> + struct gl_texture_object *texObj;
>
> - texObj = _mesa_lookup_texture_err(ctx, texture,
> - "glGetCompressedTextureImage");
> - if (!texObj)
> + if (!legal_getteximage_target(ctx, target, false)) {
> + _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
> return;
> + }
>
> - /* Must handle special case GL_TEXTURE_CUBE_MAP. */
> - if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
> + texObj = _mesa_get_current_tex_object(ctx, target);
> + assert(texObj);
>
> - /* Make sure the texture object is a proper cube.
> - * (See texturesubimage in teximage.c for details on why this check is
> - * performed.)
> - */
> - if (!_mesa_cube_level_complete(texObj, level)) {
> - _mesa_error(ctx, GL_INVALID_OPERATION,
> - "glGetCompressedTextureImage(cube map incomplete)");
> - return;
> - }
> + get_texture_image_dims(texObj, texObj->Target, level,
> + &width, &height, &depth);
> +
> + if (getcompressedteximage_error_check(ctx, texObj, target, level,
> + 0, 0, 0, width, height, depth,
> + INT_MAX, pixels, caller)) {
> + return;
> + }
>
> - /* Copy each face. */
> - for (i = 0; i < 6; ++i) {
> - texImage = texObj->Image[i][level];
> - assert(texImage);
> + get_compressed_texture_image(ctx, texObj, target, level,
> + 0, 0, 0, width, height, depth,
> + INT_MAX, pixels, caller);
> +}
>
> - _mesa_get_compressed_texture_image(ctx, texObj, texImage,
> - texObj->Target, level,
> - bufSize, pixels, true);
>
> - /* Compressed images don't have a client format */
> - image_stride = _mesa_format_image_size(texImage->TexFormat,
> - texImage->Width,
> - texImage->Height, 1);
> +void GLAPIENTRY
> +_mesa_GetCompressedTextureImage(GLuint texture, GLint level,
> + GLsizei bufSize, GLvoid *pixels)
> +{
> + GET_CURRENT_CONTEXT(ctx);
> + static const char *caller = "glGetCompressedTextureImage";
> + GLsizei width, height, depth;
> + struct gl_texture_object *texObj =
> + _mesa_lookup_texture_err(ctx, texture, caller);
>
> - pixels = (GLubyte *) pixels + image_stride;
> - bufSize -= image_stride;
> - }
> + if (!texObj) {
> + return;
> }
> - else {
> - texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
> - if (!texImage)
> - return;
>
> - _mesa_get_compressed_texture_image(ctx, texObj, texImage,
> - texObj->Target, level, bufSize,
> - pixels, true);
> + get_texture_image_dims(texObj, texObj->Target, level,
> + &width, &height, &depth);
> +
> + if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
> + 0, 0, 0, width, height, depth,
> + bufSize, pixels, caller)) {
> + return;
> }
> +
> + get_compressed_texture_image(ctx, texObj, 0, level,
This should just use texObj->Target right?
> + 0, 0, 0, width, height, depth,
> + bufSize, pixels, caller);
> }
With those fixed up, this patch is
Reviewed-by: Ilia Mirkin <imirkin at alum.mit.edu>
More information about the mesa-dev
mailing list