+/**
+ * Implement all the glTexSubImage1/2/3D() functions.
+ * Must split this out this way because of GL_TEXTURE_CUBE_MAP.
+ */
+static void
+texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, const GLvoid *pixels)
+{
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+
+ texObj = _mesa_get_current_tex_object(ctx, target);
+ if (!texObj)
+ return;
+
+ if (texsubimage_error_check(ctx, dims, texObj, target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth, format, type, false)) {
+ return; /* error was detected */
+ }
+
+ texImage = _mesa_select_tex_image(texObj, target, level);
+ /* texsubimage_error_check ensures that texImage is not NULL */
+
+ if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+ _mesa_debug(ctx, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n",
+ dims,
+ _mesa_lookup_enum_by_nr(target), level,
+ xoffset, yoffset, zoffset, width, height, depth,
+ _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(type), pixels);
+
+ _mesa_texture_sub_image(ctx, dims, texObj, texImage, target, level,
+ xoffset, yoffset, zoffset, width, height, depth,
+ format, type, pixels, false);
+}
+
+
+/**
+ * Implement all the glTextureSubImage1/2/3D() functions.
+ * Must split this out this way because of GL_TEXTURE_CUBE_MAP.
+ */
+static void
+texturesubimage(struct gl_context *ctx, GLuint dims,
+ GLuint texture, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, const GLvoid *pixels)
+{
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+ int i;
+
+ if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+ _mesa_debug(ctx,
+ "glTextureSubImage%uD %d %d %d %d %d %d %d %d %s %s %p\n",
+ dims, texture, level,
+ xoffset, yoffset, zoffset, width, height, depth,
+ _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(type), pixels);
+
+ /* Get the texture object by Name. */
+ texObj = _mesa_lookup_texture(ctx, texture);
+ if (!texObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureSubImage%uD(texture)",
+ dims);
+ return;
+ }
+
+ if (texsubimage_error_check(ctx, dims, texObj, texObj->Target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth, format, type, true)) {
+ return; /* error was detected */
+ }
+
+
+ /* Must handle special case GL_TEXTURE_CUBE_MAP. */
+ if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+ GLint rowStride;
+
+ /* Error checking */
+ if (texObj->NumLayers < 6) {
+ /* Not enough image planes for a cube map. The spec does not say
+ * what should happen in this case because the user has always
+ * specified each cube face separately (using
+ * GL_TEXTURE_CUBE_MAP_POSITIVE_X+i) in previous GL versions.
+ * This is addressed in Khronos Bug 13223.
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glTextureSubImage%uD(insufficient cube map storage)",
+ dims);
+ return;
+ }
+
+ /*
+ * What do we do if the user created a texture with the following code
+ * and then called this function with its handle?
+ *
+ * GLuint tex;
+ * glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &tex);
+ * glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
+ * glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, ...);
+ * glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, ...);
+ * glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, ...);
+ * // Note: GL_TEXTURE_CUBE_MAP_NEGATIVE_Y not set, or given the
+ * // wrong format, or given the wrong size, etc.
+ * glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, ...);
+ * glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, ...);
+ *
+ * A bug has been filed against the spec for this case. In the
+ * meantime, we will check for cube completeness.
+ *
+ * According to Section 8.17 Texture Completeness in the OpenGL 4.5
+ * Core Profile spec (30.10.2014):
+ * "[A] cube map texture is cube complete if the
+ * following conditions all hold true: The [base level] texture
+ * images of each of the six cube map faces have identical, positive,
+ * and square dimensions. The [base level] images were each specified
+ * with the same internal format."
+ *
+ * It seems reasonable to check for cube completeness of an arbitrary
+ * level here so that the image data has a consistent format and size.
+ */
+ if (!_mesa_cube_level_complete(texObj, level)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glTextureSubImage%uD(cube map incomplete)",
+ dims);
+ return;
+ }
+
+ rowStride = _mesa_image_image_stride(&ctx->Unpack, width, height,
+ format, type);
+ /* Copy in each face. */
+ for (i = 0; i < 6; ++i) {
+ texImage = texObj->Image[i][level];
+ _mesa_texture_sub_image(ctx, 3, texObj, texImage, texObj->Target,
+ level, xoffset, yoffset, zoffset,
+ width, height, 1, format,
+ type, pixels, true);
+ pixels = (GLubyte *) pixels + rowStride;
+ }
+ }
+ else {
+ texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
+ if (!texImage)
+ return;
+
+ _mesa_texture_sub_image(ctx, dims, texObj, texImage, texObj->Target,
+ level, xoffset, yoffset, zoffset,
+ width, height, depth, format,
+ type, pixels, true);
+ }
+}
+