[Mesa-dev] [PATCH 09/13] mesa: overhaul the glGetCompressedTexImage code
Brian Paul
brianp at vmware.com
Mon Jul 13 18:21:09 PDT 2015
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
More information about the mesa-dev
mailing list