Same idea as the previous patch. --- src/mesa/main/texgetimage.c | 345 +++++++++++++++++++++++++------------------- 1 file changed, 196 insertions(+), 149 deletions(-)
diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c index b74517a..bcdcfe8 100644 --- a/src/mesa/main/texgetimage.c +++ b/src/mesa/main/texgetimage.c @@ -1369,109 +1369,161 @@ _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. + * Do error checking for getting compressed texture images. + * \return true if any error, false if no errors. */ -static GLboolean +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, + GLsizei clientMemSize, GLvoid *img, + 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; + const bool dsa = (target == 0); - assert(texImage); + if (!texObj || texObj->Target == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller); + return true; + } + + if (dsa) { + target = texObj->Target; + } 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; + _mesa_error(ctx, GL_INVALID_ENUM, "%s(target=%s)", caller, + _mesa_lookup_enum_by_nr(texObj->Target)); + return true; } + maxLevels = _mesa_max_texture_levels(ctx, target); assert(maxLevels != 0); 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; + } + + texImage = _mesa_select_tex_image(texObj, target, level); + if (!texImage) { + /* non-existant texture image */ + _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", caller); + return true; } 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; + } + + return false; +} + + +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; +} + + +/** + * Common helper for all glGetCompressed-teximage functions. + */ +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) +{ + struct gl_texture_image *texImage; + unsigned firstFace, numFaces, i, imageStride; + GLsizei totalBytes; + GLuint dimensions; + + FLUSH_VERTICES(ctx, 0); + + if (getcompressedteximage_error_check(ctx, texObj, target, level, + bufSize, pixels, caller)) { + return; + } + + texImage = _mesa_select_tex_image(texObj, target, level); + assert(texImage); /* should have been error checked already */ + + /* check sub-image dimensions */ + if (width == WHOLE_WIDTH && height == WHOLE_HEIGHT && depth == WHOLE_DEPTH) { + /* getting whole image */ + width = texImage->Width; + height = texImage->Height; + depth = texImage->Depth; + } + else { + /* getting sub image */ + if (dimensions_error_check(ctx, texImage, xoffset, yoffset, zoffset, + width, height, depth, caller)) { + return; + } } - compressedSize = _mesa_format_image_size(texImage->TexFormat, - texImage->Width, - texImage->Height, - texImage->Depth); + dimensions = _mesa_get_texture_dimensions(texObj->Target); /* 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, dsa ? - "glGetCompressedTextureImage": - "glGetCompressedTexImage")) { - return GL_TRUE; + &ctx->Pack, + caller)) { + return; } - 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; } /* make sure PBO is not mapped */ if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetCompressedTex%sImage(PBO is mapped)", suffix); - return GL_TRUE; + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller); + return; } } - - return GL_FALSE; -} - -/** Implements glGetnCompressedTexImageARB, glGetCompressedTexImage, and - * glGetCompressedTextureImage. - * - * texImage must be passed in because glGetCompressedTexImage must handle the - * target GL_TEXTURE_CUBE_MAP. - */ -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) -{ - assert(texObj); - assert(texImage); - - FLUSH_VERTICES(ctx, 0); - - if (getcompressedteximage_error_check(ctx, texImage, target, level, - bufSize, pixels, dsa)) { - return; + else { + /* do bounds checking on writing to client memory */ + if (totalBytes > bufSize) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds access: bufSize (%d) is too small)", + caller, bufSize); + return; + } } if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { @@ -1484,109 +1536,104 @@ _mesa_get_compressed_texture_image(struct gl_context *ctx, 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; + } + + if (target == GL_TEXTURE_CUBE_MAP) { + struct compressed_pixelstore store; + + /* 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, + "glGetTextureImage(cube map incomplete)"); + return; + } + + /* Compute image stride between cube faces */ + _mesa_compute_compressed_pixelstore(dimensions, 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; } + _mesa_unlock_texture(ctx, texObj); } + 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); + struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target); - texObj = _mesa_get_current_tex_object(ctx, target); - if (!texObj) - return; - - texImage = _mesa_select_tex_image(texObj, target, level); - if (!texImage) - 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, + WHOLE_WIDTH, WHOLE_HEIGHT, WHOLE_DEPTH, + bufSize, img, + "glGetnCompressedTexImageARB"); } + void GLAPIENTRY _mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img) { - _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target); + + get_compressed_texture_image(ctx, texObj, target, level, + 0, 0, 0, + WHOLE_WIDTH, WHOLE_HEIGHT, WHOLE_DEPTH, + INT_MAX, img, + "glGetCompressedTexImage"); } -/** - * 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) { - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - int i; - GLint image_stride; GET_CURRENT_CONTEXT(ctx); + struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture); - texObj = _mesa_lookup_texture_err(ctx, texture, - "glGetCompressedTextureImage"); - if (!texObj) - return; - - /* Must handle special case GL_TEXTURE_CUBE_MAP. */ - if (texObj->Target == GL_TEXTURE_CUBE_MAP) { - - /* 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; - } - - /* Copy each face. */ - for (i = 0; i < 6; ++i) { - texImage = texObj->Image[i][level]; - assert(texImage); - - _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); - - pixels = (GLubyte *) pixels + image_stride; - bufSize -= image_stride; - } - } - 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_compressed_texture_image(ctx, texObj, 0, level, + 0, 0, 0, + WHOLE_WIDTH, WHOLE_HEIGHT, WHOLE_DEPTH, + bufSize, pixels, + "glGetCompressedTextureImage"); } -- 1.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev