[Mesa-dev] [PATCH 07/11] mesa: implement glGetCompressedTextureSubImage()
Brian Paul
brianp at vmware.com
Sat Dec 13 06:42:50 PST 2014
---
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
More information about the mesa-dev
mailing list