+static struct gl_texture_image *
+select_tex_image(const struct gl_texture_object *texObj, GLenum target,
+ GLint level, GLint zoffset)
+{
+ assert(level >= 0);
+ assert(level < MAX_TEXTURE_LEVELS);
+ if (target == GL_TEXTURE_CUBE_MAP) {
+ assert(zoffset >= 0);
+ assert(zoffset < 6);
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset;
+ }
+ return _mesa_select_tex_image(texObj, target, level);
+}
+
+
+/**
+ * Error-check the offset and size arguments to
+ * glGet[Compressed]TextureSubImage(). Also checks if the specified
+ * texture image is missing.
+ * \return true if error, false if no error.
+ */
+static bool
+dimensions_error_check(struct gl_context *ctx,
+ struct gl_texture_object *texObj,
+ GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ const char *caller)
+{
+ const struct gl_texture_image *texImage;
+ int i;
+
+ if (xoffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset = %d)", caller, xoffset);
+ return true;
+ }
+
+ if (yoffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset = %d)", caller, yoffset);
+ return true;
+ }
+
+ if (zoffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset = %d)", caller, zoffset);
+ return true;
+ }
+
+ if (width < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(width = %d)", caller, width);
+ return true;
+ }
+
+ if (height < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(height = %d)", caller, height);
+ return true;
+ }
+
+ if (depth < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(depth = %d)", caller, depth);
+ return true;
+ }
+
+ /* do special per-target checks */
+ switch (target) {
+ case GL_TEXTURE_1D:
+ if (yoffset != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(1D, yoffset = %d)", caller, yoffset);
+ return true;
+ }
+ if (height > 1) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(1D, height = %d)", caller, 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,
+ "%s(zoffset = %d)", caller, zoffset);
+ return true;
+ }
+ if (depth > 1) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(depth = %d)", caller, depth);
+ return true;
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ /* Non-array cube maps are special because we have a gl_texture_image
+ * per face.
+ */
+ if (zoffset + depth > 6) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(zoffset + depth = %d)", caller, zoffset + depth);
+ return true;
+ }
+ /* check that the range of faces exist */
+ for (i = 0; i < depth; i++) {
+ GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset + i;
+ if (!_mesa_select_tex_image(texObj, face, level)) {
+ /* non-existant face */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(missing cube face)", caller);
+ return true;
+ }
+ }
+ break;
+ default:
+ ; /* nothing */
+ }
+
+ texImage = select_tex_image(texObj, target, level, zoffset);
+ if (!texImage) {
+ /* missing texture image */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(missing image)", caller);
+ return true;
+ }
+
+ if (xoffset + width > texImage->Width) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(xoffset %d + width %d > %u)",
+ caller, xoffset, width, texImage->Width);
+ return true;
+ }
+
+ if (yoffset + height > texImage->Height) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(yoffset %d + height %d > %u)",
+ caller, yoffset, height, texImage->Height);
+ return true;
+ }
+
+ if (target != GL_TEXTURE_CUBE_MAP) {
+ /* Cube map error checking was done above */
+ if (zoffset + depth > texImage->Depth) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(zoffset %d + depth %d > %u)",
+ caller, zoffset, depth, texImage->Depth);
+ return true;
+ }
+ }
+
+ /* Extra checks for compressed textures */
+ {
+ GLuint bw, bh, bd;
+ _mesa_get_format_block_size_3d(texImage->TexFormat, &bw, &bh, &bd);
+ if (bw > 1 || bh > 1 || bd > 1) {
+ /* offset must be multiple of block size */
+ if (xoffset % bw != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(xoffset = %d)", caller, xoffset);
+ return true;
+ }
+ if (target != GL_TEXTURE_1D && target != GL_TEXTURE_1D_ARRAY) {
+ if (yoffset % bh != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(yoffset = %d)", caller, yoffset);
+ return true;
+ }
+ }
+
+ if (zoffset % bd != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(zoffset = %d)", caller, zoffset);
+ return true;
+ }
+
+ /* The size must be a multiple of bw x bh x bd, 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_VALUE,
+ "%s(width = %d)", caller, width);
+ return true;
+ }
+
+ if ((height % bh != 0) &&
+ (yoffset + height != (GLint) texImage->Height)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(height = %d)", caller, height);
+ return true;
+ }
+
+ if ((depth % bd != 0) &&
+ (zoffset + depth != (GLint) texImage->Depth)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(depth = %d)", caller, depth);
+ 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;
+}
+
+
+/**
+ * Do PBO-related error checking for getting uncompressed images.
+ * \return true if there was an error (or the GetTexImage is to be a no-op)
+ */
+static bool
+pbo_error_check(struct gl_context *ctx, GLenum target,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, GLsizei clientMemSize,
+ GLvoid *pixels,
+ const char *caller)