--- src/mesa/main/texgetimage.c | 440 +++++++++++++++++++++++++++++--------------- src/mesa/main/texgetimage.h | 7 + 2 files changed, 297 insertions(+), 150 deletions(-)
diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c index ced6a34..ac0be35 100644 --- a/src/mesa/main/texgetimage.c +++ b/src/mesa/main/texgetimage.c @@ -25,7 +25,8 @@ /** - * Code for glGetTexImage() and glGetCompressedTexImage(). + * Code for glGetTexImage(), glGetCompressedTexImage(), + * glGetTextureSubImage() and glGetCompressedTextureSubImage(), */ @@ -717,10 +718,8 @@ _mesa_get_compressed_texsubimage(struct gl_context *ctx, GLubyte *dest; _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat, - texImage->Width, texImage->Height, - texImage->Depth, - &ctx->Pack, - &store); + width, height, depth, + &ctx->Pack, &store); if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* pack texture image into a PBO */ @@ -731,7 +730,7 @@ _mesa_get_compressed_texsubimage(struct gl_context *ctx, if (!dest) { /* out of memory or other unexpected error */ _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glGetCompresssedTexImage(map PBO failed)"); + "glGetCompresssedTexImage/TextureSubImage(map PBO failed)"); return; } dest = ADD_POINTERS(dest, img); @@ -746,25 +745,27 @@ _mesa_get_compressed_texsubimage(struct gl_context *ctx, GLubyte *src; /* map src texture buffer */ - ctx->Driver.MapTextureImage(ctx, texImage, 0, - 0, 0, texImage->Width, texImage->Height, + ctx->Driver.MapTextureImage(ctx, texImage, zoffset + slice, + xoffset, yoffset, width, height, GL_MAP_READ_BIT, &src, &srcRowStride); if (src) { - + /* Copy a row of blocks */ for (i = 0; i < store.CopyRowsPerSlice; i++) { memcpy(dest, src, store.CopyBytesPerRow); dest += store.TotalBytesPerRow; src += srcRowStride; } - ctx->Driver.UnmapTextureImage(ctx, texImage, 0); + ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + slice); /* Advance to next slice */ dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice - store.CopyRowsPerSlice); } else { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glGetCompresssedTexImage/TextureSubImage"); + break; /* don't try the remaining slices */ } } @@ -821,6 +822,12 @@ getteximage_error_check(struct gl_context *ctx, const GLint maxLevels = _mesa_max_texture_levels(ctx, target); GLenum baseFormat, err; + if (maxLevels == 0) { + /* invalid texture (gen'd but never defined) */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller); + return GL_TRUE; + } + assert(maxLevels != 0); if (level < 0 || level >= maxLevels) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", caller); @@ -888,7 +895,9 @@ getteximage_error_check(struct gl_context *ctx, /** - * Do error checking related to the PBO and image size. + * Do error checking related to the PBO and image size (for returning + * uncompressed images only). + * \return true if error is found, false otherwise. */ static bool pbo_error_check(struct gl_context *ctx, GLenum target, @@ -1006,145 +1015,36 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, /** - * Do error checking for a glGetCompressedTexImage() call. - * \return GL_TRUE if any error, GL_FALSE if no errors. + * Compute the number of bytes that will be read/written from/to a buffer + * when packing/unpacking a compressed image. This observes the given GL + * pixel store state which may specify non-default GL_SKIP_PIXEL, + * GL_ROW_LENGTH, etc. values for compressed images. + * Basically, if the value we compute here is larger than the dest/src buffer + * size, we'll have to raise an GL_INVALID_OPERATION (out of bounds) error. + * + * \return number of bytes which will be read/written. */ -static GLboolean -getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, - GLint level, GLsizei clientMemSize, GLvoid *img) +static GLsizei +packed_compressed_size(GLuint dimensions, mesa_format format, + GLsizei width, GLsizei height, GLsizei depth, + const struct gl_pixelstore_attrib *packing) { - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - const GLint maxLevels = _mesa_max_texture_levels(ctx, target); - GLuint compressedSize, dimensions; - - if (!legal_getteximage_target(ctx, target)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", - target); - return GL_TRUE; - } - - assert(maxLevels != 0); - if (level < 0 || level >= maxLevels) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetCompressedTexImageARB(bad level = %d)", level); - return GL_TRUE; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - if (!texObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); - return GL_TRUE; - } - - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - if (!texImage) { - /* probably invalid mipmap level */ - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetCompressedTexImageARB(level)"); - return GL_TRUE; - } - - if (!_mesa_is_format_compressed(texImage->TexFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetCompressedTexImageARB(texture is not compressed)"); - return GL_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); - if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions, - &ctx->Pack, - "glGetCompressedTexImageARB")) { - return GL_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, - "glGetnCompressedTexImageARB(out of bounds access:" - " bufSize (%d) is too small)", clientMemSize); - return GL_TRUE; - } - } else { - /* do bounds checking on PBO write */ - if ((const GLubyte *) img + compressedSize > - (const GLubyte *) ctx->Pack.BufferObj->Size) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetCompressedTexImage(out of bounds PBO access)"); - return GL_TRUE; - } - - /* make sure PBO is not mapped */ - if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetCompressedTexImage(PBO is mapped)"); - return GL_TRUE; - } - } - - return GL_FALSE; + 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; } -void GLAPIENTRY -_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, - GLvoid *img) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GET_CURRENT_CONTEXT(ctx); - - FLUSH_VERTICES(ctx, 0); - - if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) { - return; - } - - if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { - /* not an error, do nothing */ - return; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - if (_mesa_is_zero_size_texture(texImage)) - return; - - if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { - _mesa_debug(ctx, - "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", - texObj->Name, - _mesa_get_format_name(texImage->TexFormat), - texImage->Width, texImage->Height); - } - - _mesa_lock_texture(ctx, texObj); - { - ctx->Driver.GetCompressedTexSubImage(ctx, texImage, - 0, 0, 0, - texImage->Width, texImage->Height, - texImage->Depth, img); - } - _mesa_unlock_texture(ctx, texObj); -} - -void GLAPIENTRY -_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img) -{ - _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); -} - - - /** * Error-check the offset and size arguments to * glGet[Compressed]TextureSubImage(). @@ -1154,7 +1054,8 @@ static bool dimensions_error_check(struct gl_context *ctx, struct gl_texture_image *texImage, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth) + GLsizei width, GLsizei height, GLsizei depth, + const char *caller) { const GLenum target = texImage->TexObject->Target; @@ -1277,6 +1178,169 @@ dimensions_error_check(struct gl_context *ctx, } +/** + * Do error checking for glGetCompressedTexImage() and + * glGetCompressedTextureSubImage(). + * \return true if any error, false if no errors. + */ +static bool +getcompressedteximage_error_check(struct gl_context *ctx, + struct gl_texture_object *texObj, + GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLint height, GLint depth, + GLsizei clientMemSize, GLvoid *img, + const char *caller) +{ + GLenum target = texObj->Target; + struct gl_texture_image *texImage; + const GLint maxLevels = _mesa_max_texture_levels(ctx, target); + const GLuint dimensions = _mesa_get_texture_dimensions(texObj->Target); + GLsizei totalBytes; + + assert(maxLevels != 0); + if (level < 0 || level >= maxLevels) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(bad level = %d)", caller, level); + return true; + } + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (!texImage) { + /* probably invalid mipmap level */ + _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", caller); + return true; + } + + if (!_mesa_is_format_compressed(texImage->TexFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(texture is not compressed)", caller); + return true; + } + + /* check offset, size against texture and block size */ + if (dimensions_error_check(ctx, texImage, xoffset, yoffset, zoffset, + width, height, depth, caller)) { + return true; + } + + /* Check for invalid pixel storage modes */ + if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions, + &ctx->Pack, + caller)) { + return true; + } + + /* 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 ((GLubyte *) img + totalBytes > + (GLubyte *) ctx->Pack.BufferObj->Size) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%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 > clientMemSize) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds access: bufSize (%d) is too small)", + caller, clientMemSize); + return true; + } + } + + return false; +} + + +void GLAPIENTRY +_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, + GLvoid *img) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GLsizei width, height, depth; + GET_CURRENT_CONTEXT(ctx); + + FLUSH_VERTICES(ctx, 0); + + if (!legal_getteximage_target(ctx, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", + target); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + assert(texObj); + if (!texObj) { + return; /* should never happen */ + } + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (texImage) { + width = texImage->Width; + height = texImage->Height; + depth = texImage->Depth; + } + else { + /* some error, we'll find it later */ + width = height = depth = 0; + } + + if (getcompressedteximage_error_check(ctx, texObj, level, + 0, 0, 0, width, height, depth, + bufSize, img, + "glGet[n]CompressedTexImage")) { + return; + } + + if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { + /* not an error, do nothing */ + return; + } + + if (_mesa_is_zero_size_texture(texImage)) + return; + + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { + _mesa_debug(ctx, + "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", + texObj->Name, + _mesa_get_format_name(texImage->TexFormat), + texImage->Width, texImage->Height); + } + + _mesa_lock_texture(ctx, texObj); + { + ctx->Driver.GetCompressedTexSubImage(ctx, texImage, + 0, 0, 0, + texImage->Width, texImage->Height, + texImage->Depth, img); + } + _mesa_unlock_texture(ctx, texObj); +} + +void GLAPIENTRY +_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img) +{ + _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); +} + + void GLAPIENTRY _mesa_GetTextureSubImage(GLuint texture, GLint level, @@ -1293,8 +1357,8 @@ _mesa_GetTextureSubImage(GLuint texture, GLint level, texObj = _mesa_lookup_texture(ctx, texture); if (!texObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetTextureSubImage(invalid texture ID %u\n", texture); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureSubImage(invalid texture ID %u)\n", texture); return; } @@ -1324,7 +1388,7 @@ _mesa_GetTextureSubImage(GLuint texture, GLint level, /* check dimensions */ if (dimensions_error_check(ctx, texImage, xoffset, yoffset, zoffset, - width, height, depth)) { + width, height, depth, "glGetTextureSubImage")) { return; } @@ -1349,3 +1413,79 @@ _mesa_GetTextureSubImage(GLuint texture, GLint level, } _mesa_unlock_texture(ctx, texObj); } + + +void APIENTRY +_mesa_GetCompressedTextureSubImage(GLuint texture, GLint level, + GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, + GLsizei bufSize, void *pixels) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GLenum target; + + GET_CURRENT_CONTEXT(ctx); + + texObj = _mesa_lookup_texture(ctx, texture); + if (!texObj || texObj->Target == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTextureSubImage(invalid texture ID %u)\n", + texture); + return; + } + + /* common error checking */ + if (getcompressedteximage_error_check(ctx, texObj, level, + xoffset, yoffset, zoffset, + width, height, depth, + bufSize, pixels, + "glGetCompressedTextureSubImage")) { + return; + } + + target = texObj->Target; + if (target == GL_TEXTURE_CUBE_MAP) { + /* convert z to face/target */ + if (zoffset >= 6) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetCompressedTextureSubImage(cube, zoffset = %d\n", + zoffset); + return; + } + if (depth != 1) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetCompressedTextureSubImage(cube, depth = %d\n", + depth); + return; + } + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset; + } + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + /* check dimensions */ + if (dimensions_error_check(ctx, texImage, xoffset, yoffset, zoffset, + width, height, depth, + "glGetCompressedTextureSubImage")) { + return; + } + + if (_mesa_is_zero_size_texture(texImage)) { + return; /* nothing to get */ + } + + if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && pixels == NULL) { + return; /* not an error, do nothing */ + } + + _mesa_lock_texture(ctx, texObj); + { + ctx->Driver.GetCompressedTexSubImage(ctx, texImage, + xoffset, yoffset, zoffset, + width, height, depth, + pixels); + } + _mesa_unlock_texture(ctx, texObj); +} diff --git a/src/mesa/main/texgetimage.h b/src/mesa/main/texgetimage.h index 593d5b0..65a1ed2 100644 --- a/src/mesa/main/texgetimage.h +++ b/src/mesa/main/texgetimage.h @@ -75,5 +75,12 @@ _mesa_GetTextureSubImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +extern void APIENTRY +_mesa_GetCompressedTextureSubImage(GLuint texture, GLint level, + GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, + GLsizei bufSize, void *pixels); + #endif /* TEXGETIMAGE_H */ -- 1.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev