On Sat, Dec 13, 2014 at 6:42 AM, Brian Paul <bri...@vmware.com> wrote: > > --- > 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 > You didn't use the new variable caller in dimensions_error_check.
> 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. > + */ > Again, pass in target, too. > +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; > + } > + > It seems like you could get NULL in a really weird edge case, so maybe you should remove the assert. > + 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 { > Hope this doesn't segfault somewhere else. It might be better if you return here. > + /* 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); > Checking for texObj->Target == 0 here is kind of awkward. It would be better to do that in a legal_texgetimage_target check. > + 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; > + } > + I'd do the legal_tex_target check for consistency. > + target = texObj->Target; > Again, this doesn't allow the user to get more than one face. But it may be easier to do that when it is merged with my DSA GetTextureImage. > + 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 >
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev