[Mesa-dev] [PATCH 05/11] mesa: implement _mesa_GetTextureSubImage()
Brian Paul
brianp at vmware.com
Sat Dec 13 06:42:48 PST 2014
One of the two new functions in GL_ARB_get_texture_sub_image.
---
src/mesa/main/texgetimage.c | 305 ++++++++++++++++++++++++++++++++++++++------
src/mesa/main/texgetimage.h | 8 ++
2 files changed, 277 insertions(+), 36 deletions(-)
diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c
index 71c25bb..e1f238b 100644
--- a/src/mesa/main/texgetimage.c
+++ b/src/mesa/main/texgetimage.c
@@ -44,6 +44,7 @@
#include "texcompress.h"
#include "texgetimage.h"
#include "teximage.h"
+#include "texobj.h"
#include "texstore.h"
@@ -803,41 +804,36 @@ legal_getteximage_target(struct gl_context *ctx, GLenum target)
/**
- * Do error checking for a glGetTexImage() call.
+ * Do error checking for a glGetTexImage() or glGetTextureSubImage() call.
* \return GL_TRUE if any error, GL_FALSE if no errors.
*/
static GLboolean
-getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
+getteximage_error_check(struct gl_context *ctx,
+ struct gl_texture_object *texObj, GLint level,
GLenum format, GLenum type, GLsizei clientMemSize,
- GLvoid *pixels )
+ GLvoid *pixels, const char *caller)
{
- struct gl_texture_object *texObj;
+ GLenum target = texObj->Target;
struct gl_texture_image *texImage;
const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
- const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
GLenum baseFormat, err;
- if (!legal_getteximage_target(ctx, target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
- return GL_TRUE;
- }
-
assert(maxLevels != 0);
if (level < 0 || level >= maxLevels) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", caller);
return GL_TRUE;
}
err = _mesa_error_check_format_and_type(ctx, format, type);
if (err != GL_NO_ERROR) {
- _mesa_error(ctx, err, "glGetTexImage(format/type)");
+ _mesa_error(ctx, err, "%s(format/type)", caller);
return GL_TRUE;
}
texObj = _mesa_get_current_tex_object(ctx, target);
if (!texObj) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
return GL_TRUE;
}
@@ -854,64 +850,79 @@ getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
*/
if (_mesa_is_color_format(format)
&& !_mesa_is_color_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)", caller);
return GL_TRUE;
}
else if (_mesa_is_depth_format(format)
&& !_mesa_is_depth_format(baseFormat)
&& !_mesa_is_depthstencil_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)", caller);
return GL_TRUE;
}
else if (_mesa_is_stencil_format(format)
&& !ctx->Extensions.ARB_texture_stencil8) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format=GL_STENCIL_INDEX)");
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(format=GL_STENCIL_INDEX)", caller);
return GL_TRUE;
}
else if (_mesa_is_ycbcr_format(format)
&& !_mesa_is_ycbcr_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)", caller);
return GL_TRUE;
}
else if (_mesa_is_depthstencil_format(format)
&& !_mesa_is_depthstencil_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)", caller);
return GL_TRUE;
}
else if (_mesa_is_enum_format_integer(format) !=
_mesa_is_format_integer(texImage->TexFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)", caller);
return GL_TRUE;
}
- if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
- texImage->Height, texImage->Depth,
- format, type, clientMemSize, pixels)) {
+ return GL_FALSE;
+}
+
+
+/**
+ * Do error checking related to the PBO and image size.
+ */
+static bool
+pbo_error_check(struct gl_context *ctx, GLenum target,
+ GLenum format, GLenum type,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLsizei bufferSize, void *pixels,
+ const char *caller)
+{
+ const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
+
+ if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack,
+ width, height, depth,
+ format, type, bufferSize, pixels)) {
if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetTexImage(out of bounds PBO access)");
+ "%s(out of bounds PBO access)", caller);
} else {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetnTexImageARB(out of bounds access:"
- " bufSize (%d) is too small)", clientMemSize);
+ "%s(out of bounds access: bufSize (%d) is too small)",
+ caller, bufferSize);
}
- return GL_TRUE;
+ return true;
}
if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
/* PBO should not be mapped */
if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetTexImage(PBO is mapped)");
- return GL_TRUE;
+ "%s(PBO is mapped)", caller);
+ return true;
}
}
- return GL_FALSE;
+ return false;
}
-
/**
* Get texture image. Called by glGetTexImage.
*
@@ -932,21 +943,36 @@ _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
FLUSH_VERTICES(ctx, 0);
- if (getteximage_error_check(ctx, target, level, format, type,
- bufSize, pixels)) {
+ if (!legal_getteximage_target(ctx, target)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
return;
}
- if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
- /* not an error, do nothing */
+ texObj = _mesa_get_current_tex_object(ctx, target);
+
+ if (getteximage_error_check(ctx, texObj, level, format, type,
+ bufSize, pixels, "glGet[n]TexImage")) {
return;
}
- texObj = _mesa_get_current_tex_object(ctx, target);
texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+ if (!texImage) {
+ return; /* no texture image */
+ }
- if (_mesa_is_zero_size_texture(texImage))
+ if (pbo_error_check(ctx, target, format, type,
+ texImage->Width, texImage->Height, texImage->Depth,
+ bufSize, pixels, "glGet[n]TexImage")) {
return;
+ }
+
+ if (_mesa_is_zero_size_texture(texImage)) {
+ return; /* nothing to get */
+ }
+
+ if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
+ return; /* not an error, do nothing */
+ }
if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
_mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
@@ -1110,3 +1136,210 @@ _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().
+ * \return true if error, false if no error.
+ */
+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)
+{
+ const GLenum target = texImage->TexObject->Target;
+
+ switch (target) {
+ case GL_TEXTURE_1D:
+ if (yoffset != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(1D, yoffset = %d)\n", yoffset);
+ return true;
+ }
+ if (height != 1) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(1D, height = %d)\n", height);
+ return true;
+ }
+ /* fall-through */
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_RECTANGLE:
+ if (zoffset != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(zoffset = %d)\n", zoffset);
+ return true;
+ }
+ if (depth != 1) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(depth = %d)\n", depth);
+ return true;
+ }
+ break;
+ default:
+ ; /* nothing */
+ }
+
+ if (xoffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(xoffset = %d)\n", xoffset);
+ return true;
+ }
+
+ if (yoffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(yoffset = %d)\n", yoffset);
+ return true;
+ }
+
+ if (zoffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(zoffset = %d)\n", zoffset);
+ return true;
+ }
+
+ if (xoffset + width > texImage->Width) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(xoffset %d + width %d > %u)\n",
+ xoffset, width, texImage->Width);
+ return true;
+ }
+
+ if (yoffset + height > texImage->Height) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(yoffset %d + height %d > %u)\n",
+ yoffset, height, texImage->Height);
+ return true;
+ }
+
+ if (zoffset + depth > texImage->Depth) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(zoffset %d + depth %d > %u)\n",
+ zoffset, depth, texImage->Depth);
+ return true;
+ }
+
+ /* Extra checks for compressed textures */
+ {
+ GLuint bw, bh;
+ _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
+ if (bw > 1 || bh > 1) {
+ /* offset must be multiple of block size */
+ if (xoffset % bw != 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetTextureSubImage(xoffset = %d)", xoffset);
+ return true;
+ }
+ if (target != GL_TEXTURE_1D && target != GL_TEXTURE_1D_ARRAY) {
+ if (yoffset % bw != 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetTextureSubImage(yoffset = %d)", yoffset);
+ return true;
+ }
+ }
+
+ /* The size must be a multiple of bw x bh, or we must be using a
+ * offset+size that exactly hits the edge of the image.
+ */
+ if ((width % bw != 0) &&
+ (xoffset + width != (GLint) texImage->Width)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetTextureSubImage(width = %d)", width);
+ return true;
+ }
+
+ if ((height % bh != 0) &&
+ (yoffset + height != (GLint) texImage->Height)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetTextureSubImage(height = %d)", height);
+ return true;
+ }
+ }
+ }
+
+ if (width == 0 || height == 0 || depth == 0) {
+ /* Not an error, but nothing to do. Return 'true' so that the
+ * caller simply returns.
+ */
+ return true;
+ }
+
+ return false;
+}
+
+
+
+void GLAPIENTRY
+_mesa_GetTextureSubImage(GLuint texture, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, 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) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(invalid texture ID %u\n", texture);
+ return;
+ }
+
+ /* common error checking */
+ if (getteximage_error_check(ctx, texObj, level, format, type, bufSize,
+ pixels, "glGetTextureSubImage")) {
+ return;
+ }
+
+ target = texObj->Target;
+ if (target == GL_TEXTURE_CUBE_MAP) {
+ /* convert z to face/target */
+ if (zoffset >= 6) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(cube, zoffset = %d\n", zoffset);
+ return;
+ }
+ if (depth != 1) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTextureSubImage(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)) {
+ return;
+ }
+
+ if (pbo_error_check(ctx, target, format, type,
+ width, height, depth,
+ bufSize, pixels, "glGetTextureSubImage")) {
+ 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.GetTexSubImage(ctx, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, pixels, texImage);
+ }
+ _mesa_unlock_texture(ctx, texObj);
+}
diff --git a/src/mesa/main/texgetimage.h b/src/mesa/main/texgetimage.h
index c9af5b9..40f152c 100644
--- a/src/mesa/main/texgetimage.h
+++ b/src/mesa/main/texgetimage.h
@@ -65,4 +65,12 @@ extern void GLAPIENTRY
_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
GLvoid *img);
+extern void GLAPIENTRY
+_mesa_GetTextureSubImage(GLuint texture, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, GLsizei bufSize,
+ void *pixels);
+
+
#endif /* TEXGETIMAGE_H */
--
1.9.1
More information about the mesa-dev
mailing list