* Jason Ekstrand <jason.ekstrand@intel.com>
*/
+#include "context.h"
#include "glheader.h"
#include "errors.h"
#include "enums.h"
#include "texobj.h"
#include "fbobject.h"
#include "textureview.h"
-
+#include "glformats.h"
+
+enum mesa_block_class {
+ BLOCK_CLASS_128_BITS,
+ BLOCK_CLASS_64_BITS
+};
+
+/**
+ * Prepare the source or destination resource. This involves error
+ * checking and returning the relevant gl_texture_image or gl_renderbuffer.
+ * Note that one of the resulting tex_image or renderbuffer pointers will be
+ * NULL and the other will be non-null.
+ *
+ * \param name the texture or renderbuffer name
+ * \param target One of GL_TEXTURE_x target or GL_RENDERBUFFER
+ * \param level mipmap level
+ * \param z src or dest Z
+ * \param depth number of slices/faces/layers to copy
+ * \param tex_image returns a pointer to a texture image
+ * \param renderbuffer returns a pointer to a renderbuffer
+ * \return true if success, false if error
+ */
static bool
-prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level,
- struct gl_texture_object **tex_obj,
- struct gl_texture_image **tex_image, GLuint *tmp_tex,
+prepare_target(struct gl_context *ctx, GLuint name, GLenum target,
+ int level, int z, int depth,
+ struct gl_texture_image **tex_image,
+ struct gl_renderbuffer **renderbuffer,
+ mesa_format *format,
+ GLenum *internalFormat,
+ GLuint *width,
+ GLuint *height,
+ GLuint *num_samples,
const char *dbg_prefix)
{
- struct gl_renderbuffer *rb;
-
if (name == 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sName = %d)", dbg_prefix, name);
* - is TEXTURE_BUFFER, or
* - is one of the cubemap face selectors described in table 3.17,
*/
- switch (*target) {
+ switch (target) {
case GL_RENDERBUFFER:
/* Not a texture target, but valid */
case GL_TEXTURE_1D:
default:
_mesa_error(ctx, GL_INVALID_ENUM,
"glCopyImageSubData(%sTarget = %s)", dbg_prefix,
- _mesa_lookup_enum_by_nr(*target));
+ _mesa_enum_to_string(target));
return false;
}
- if (*target == GL_RENDERBUFFER) {
- rb = _mesa_lookup_renderbuffer(ctx, name);
+ if (target == GL_RENDERBUFFER) {
+ struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
+
if (!rb) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sName = %u)", dbg_prefix, name);
return false;
}
- if (rb->NumSamples > 1)
- *target = GL_TEXTURE_2D_MULTISAMPLE;
- else
- *target = GL_TEXTURE_2D;
-
- *tmp_tex = 0;
- _mesa_GenTextures(1, tmp_tex);
- if (*tmp_tex == 0)
- return false; /* Error already set by GenTextures */
-
- _mesa_BindTexture(*target, *tmp_tex);
- *tex_obj = _mesa_lookup_texture(ctx, *tmp_tex);
- *tex_image = _mesa_get_tex_image(ctx, *tex_obj, *target, 0);
-
- if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, *tex_image)) {
- _mesa_problem(ctx, "Failed to create texture from renderbuffer");
- return false;
- }
-
- if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
- rb->NeedsFinishRenderTexture = true;
- ctx->Driver.FinishRenderTexture(ctx, rb);
- }
+ *renderbuffer = rb;
+ *format = rb->Format;
+ *internalFormat = rb->InternalFormat;
+ *width = rb->Width;
+ *height = rb->Height;
+ *num_samples = rb->NumSamples;
+ *tex_image = NULL;
} else {
- *tex_obj = _mesa_lookup_texture(ctx, name);
- if (!*tex_obj) {
+ struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
+
+ if (!texObj) {
+ /*
+ * From GL_ARB_copy_image specification:
+ * "INVALID_VALUE is generated if either <srcName> or <dstName> does
+ * not correspond to a valid renderbuffer or texture object according
+ * to the corresponding target parameter."
+ */
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sName = %u)", dbg_prefix, name);
return false;
}
- _mesa_test_texobj_completeness(ctx, *tex_obj);
- if (!(*tex_obj)->_BaseComplete ||
- (level != 0 && !(*tex_obj)->_MipmapComplete)) {
+ _mesa_test_texobj_completeness(ctx, texObj);
+ if (!texObj->_BaseComplete ||
+ (level != 0 && !texObj->_MipmapComplete)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glCopyImageSubData(%sName incomplete)", dbg_prefix);
return false;
}
- if ((*tex_obj)->Target != *target) {
+ /* Note that target will not be a cube face name */
+ if (texObj->Target != target) {
+ /*
+ * From GL_ARB_copy_image_specification:
+ * "INVALID_ENUM is generated if the target does not match the type
+ * of the object."
+ */
_mesa_error(ctx, GL_INVALID_ENUM,
"glCopyImageSubData(%sTarget = %s)", dbg_prefix,
- _mesa_lookup_enum_by_nr(*target));
+ _mesa_enum_to_string(target));
return false;
}
return false;
}
- *tex_image = _mesa_select_tex_image(ctx, *tex_obj, *target, level);
+ if (target == GL_TEXTURE_CUBE_MAP) {
+ int i;
+
+ assert(z < MAX_FACES); /* should have been caught earlier */
+
+ /* make sure all the cube faces are present */
+ for (i = 0; i < depth; i++) {
+ if (!texObj->Image[z+i][level]) {
+ /* missing cube face */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyImageSubData(missing cube face)");
+ return false;
+ }
+ }
+
+ *tex_image = texObj->Image[z][level];
+ }
+ else {
+ *tex_image = _mesa_select_tex_image(texObj, target, level);
+ }
+
if (!*tex_image) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
return false;
}
+
+ *renderbuffer = NULL;
+ *format = (*tex_image)->TexFormat;
+ *internalFormat = (*tex_image)->InternalFormat;
+ *width = (*tex_image)->Width;
+ *height = (*tex_image)->Height;
+ *num_samples = (*tex_image)->NumSamples;
}
return true;
}
+
+/**
+ * Check that the x,y,z,width,height,region is within the texture image
+ * dimensions.
+ * \return true if bounds OK, false if regions is out of bounds
+ */
static bool
-check_region_bounds(struct gl_context *ctx, struct gl_texture_image *tex_image,
+check_region_bounds(struct gl_context *ctx,
+ GLenum target,
+ const struct gl_texture_image *tex_image,
+ const struct gl_renderbuffer *renderbuffer,
int x, int y, int z, int width, int height, int depth,
const char *dbg_prefix)
{
+ int surfWidth, surfHeight, surfDepth;
+
if (width < 0 || height < 0 || depth < 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
return false;
}
- if (x + width > tex_image->Width) {
+ /* Check X direction */
+ if (target == GL_RENDERBUFFER) {
+ surfWidth = renderbuffer->Width;
+ }
+ else {
+ surfWidth = tex_image->Width;
+ }
+
+ if (x + width > surfWidth) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
dbg_prefix, dbg_prefix);
return false;
}
- switch (tex_image->TexObject->Target) {
+ /* Check Y direction */
+ switch (target) {
+ case GL_RENDERBUFFER:
+ surfHeight = renderbuffer->Height;
+ break;
case GL_TEXTURE_1D:
case GL_TEXTURE_1D_ARRAY:
- if (y != 0 || height != 1) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
- dbg_prefix, dbg_prefix);
- return false;
- }
+ surfHeight = 1;
break;
default:
- if (y + height > tex_image->Height) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
- dbg_prefix, dbg_prefix);
- return false;
- }
- break;
+ surfHeight = tex_image->Height;
+ }
+
+ if (y + height > surfHeight) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
+ dbg_prefix, dbg_prefix);
+ return false;
}
- switch (tex_image->TexObject->Target) {
+ /* Check Z direction */
+ switch (target) {
+ case GL_RENDERBUFFER:
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
case GL_TEXTURE_2D_MULTISAMPLE:
case GL_TEXTURE_RECTANGLE:
- if (z != 0 || depth != 1) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
- dbg_prefix, dbg_prefix);
- return false;
- }
+ surfDepth = 1;
break;
case GL_TEXTURE_CUBE_MAP:
- if (z < 0 || z + depth > 6) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
- dbg_prefix, dbg_prefix);
- return false;
- }
+ surfDepth = 6;
break;
case GL_TEXTURE_1D_ARRAY:
- if (z < 0 || z + depth > tex_image->Height) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
- dbg_prefix, dbg_prefix);
- return false;
- }
- break;
- case GL_TEXTURE_CUBE_MAP_ARRAY:
- case GL_TEXTURE_2D_ARRAY:
- case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
- case GL_TEXTURE_3D:
- if (z < 0 || z + depth > tex_image->Depth) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
- dbg_prefix, dbg_prefix);
- return false;
- }
+ surfDepth = tex_image->Height;
break;
+ default:
+ surfDepth = tex_image->Depth;
+ }
+
+ if (z < 0 || z + depth > surfDepth) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
+ dbg_prefix, dbg_prefix);
+ return false;
}
return true;
}
+static bool
+compressed_format_compatible(const struct gl_context *ctx,
+ GLenum compressedFormat, GLenum otherFormat)
+{
+ enum mesa_block_class compressedClass, otherClass;
+
+ /* Two view-incompatible compressed formats are never compatible. */
+ if (_mesa_is_compressed_format(ctx, otherFormat)) {
+ return false;
+ }
+
+ /*
+ * From ARB_copy_image spec:
+ * Table 4.X.1 (Compatible internal formats for copying between
+ * compressed and uncompressed internal formats)
+ * ---------------------------------------------------------------------
+ * | Texel / | Uncompressed | |
+ * | Block | internal format | Compressed internal format |
+ * | size | | |
+ * ---------------------------------------------------------------------
+ * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
+ * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
+ * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
+ * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
+ * | | | COMPRESSED_RG_RGTC2, |
+ * | | | COMPRESSED_SIGNED_RG_RGTC2, |
+ * | | | COMPRESSED_RGBA_BPTC_UNORM, |
+ * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
+ * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
+ * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
+ * ---------------------------------------------------------------------
+ * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
+ * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
+ * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
+ * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
+ * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
+ * | | | COMPRESSED_SIGNED_RED_RGTC1 |
+ * ---------------------------------------------------------------------
+ */
+
+ switch (compressedFormat) {
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ case GL_COMPRESSED_RG_RGTC2:
+ case GL_COMPRESSED_SIGNED_RG_RGTC2:
+ case GL_COMPRESSED_RGBA_BPTC_UNORM:
+ case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
+ case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
+ case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
+ compressedClass = BLOCK_CLASS_128_BITS;
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RED_RGTC1:
+ case GL_COMPRESSED_SIGNED_RED_RGTC1:
+ compressedClass = BLOCK_CLASS_64_BITS;
+ break;
+ case GL_COMPRESSED_RGBA8_ETC2_EAC:
+ case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+ case GL_COMPRESSED_RG11_EAC:
+ case GL_COMPRESSED_SIGNED_RG11_EAC:
+ if (_mesa_is_gles(ctx))
+ compressedClass = BLOCK_CLASS_128_BITS;
+ else
+ return false;
+ break;
+ case GL_COMPRESSED_RGB8_ETC2:
+ case GL_COMPRESSED_SRGB8_ETC2:
+ case GL_COMPRESSED_R11_EAC:
+ case GL_COMPRESSED_SIGNED_R11_EAC:
+ case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ if (_mesa_is_gles(ctx))
+ compressedClass = BLOCK_CLASS_64_BITS;
+ else
+ return false;
+ break;
+ default:
+ if (_mesa_is_gles(ctx) && _mesa_is_astc_format(compressedFormat))
+ compressedClass = BLOCK_CLASS_128_BITS;
+ else
+ return false;
+ break;
+ }
+
+ switch (otherFormat) {
+ case GL_RGBA32UI:
+ case GL_RGBA32I:
+ case GL_RGBA32F:
+ otherClass = BLOCK_CLASS_128_BITS;
+ break;
+ case GL_RGBA16F:
+ case GL_RG32F:
+ case GL_RGBA16UI:
+ case GL_RG32UI:
+ case GL_RGBA16I:
+ case GL_RG32I:
+ case GL_RGBA16:
+ case GL_RGBA16_SNORM:
+ otherClass = BLOCK_CLASS_64_BITS;
+ break;
+ default:
+ return false;
+ }
+
+ return compressedClass == otherClass;
+}
+
+static bool
+copy_format_compatible(const struct gl_context *ctx,
+ GLenum srcFormat, GLenum dstFormat)
+{
+ /*
+ * From ARB_copy_image spec:
+ * For the purposes of CopyImageSubData, two internal formats
+ * are considered compatible if any of the following conditions are
+ * met:
+ * * the formats are the same,
+ * * the formats are considered compatible according to the
+ * compatibility rules used for texture views as defined in
+ * section 3.9.X. In particular, if both internal formats are listed
+ * in the same entry of Table 3.X.2, they are considered compatible, or
+ * * one format is compressed and the other is uncompressed and
+ * Table 4.X.1 lists the two formats in the same row.
+ */
+
+ if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
+ /* Also checks if formats are equal. */
+ return true;
+ } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
+ return compressed_format_compatible(ctx, srcFormat, dstFormat);
+ } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
+ return compressed_format_compatible(ctx, dstFormat, srcFormat);
+ }
+
+ return false;
+}
+
void GLAPIENTRY
_mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
GLint srcX, GLint srcY, GLint srcZ,
GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
{
GET_CURRENT_CONTEXT(ctx);
- GLuint tmpTexNames[2] = { 0, 0 };
- struct gl_texture_object *srcTexObj, *dstTexObj;
struct gl_texture_image *srcTexImage, *dstTexImage;
+ struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
+ mesa_format srcFormat, dstFormat;
+ GLenum srcIntFormat, dstIntFormat;
+ GLuint src_w, src_h, dst_w, dst_h;
GLuint src_bw, src_bh, dst_bw, dst_bh;
- int i, srcNewZ, dstNewZ, Bpt;
+ GLuint src_num_samples, dst_num_samples;
+ int dstWidth, dstHeight, dstDepth;
+ int i;
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
"%u, %s, %d, %d, %d, %d, "
"%d, %d, %d)\n",
- srcName, _mesa_lookup_enum_by_nr(srcTarget), srcLevel,
+ srcName, _mesa_enum_to_string(srcTarget), srcLevel,
srcX, srcY, srcZ,
- dstName, _mesa_lookup_enum_by_nr(dstTarget), dstLevel,
+ dstName, _mesa_enum_to_string(dstTarget), dstLevel,
dstX, dstY, dstZ,
- srcWidth, srcHeight, srcWidth);
-
- if (!prepare_target(ctx, srcName, &srcTarget, srcLevel,
- &srcTexObj, &srcTexImage, &tmpTexNames[0], "src"))
- goto cleanup;
+ srcWidth, srcHeight, srcDepth);
- if (!prepare_target(ctx, dstName, &dstTarget, dstLevel,
- &dstTexObj, &dstTexImage, &tmpTexNames[1], "dst"))
- goto cleanup;
+ if (!ctx->Extensions.ARB_copy_image) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyImageSubData(extension not available)");
+ return;
+ }
- _mesa_get_format_block_size(srcTexImage->TexFormat, &src_bw, &src_bh);
+ if (!prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth,
+ &srcTexImage, &srcRenderbuffer, &srcFormat,
+ &srcIntFormat, &src_w, &src_h, &src_num_samples, "src"))
+ return;
+
+ if (!prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth,
+ &dstTexImage, &dstRenderbuffer, &dstFormat,
+ &dstIntFormat, &dst_w, &dst_h, &dst_num_samples, "dst"))
+ return;
+
+ _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh);
+
+ /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
+ * spec says:
+ *
+ * An INVALID_VALUE error is generated if the dimensions of either
+ * subregion exceeds the boundaries of the corresponding image object,
+ * or if the image format is compressed and the dimensions of the
+ * subregion fail to meet the alignment constraints of the format.
+ *
+ * and Section 8.7 (Compressed Texture Images) says:
+ *
+ * An INVALID_OPERATION error is generated if any of the following
+ * conditions occurs:
+ *
+ * * width is not a multiple of four, and width + xoffset is not
+ * equal to the value of TEXTURE_WIDTH.
+ * * height is not a multiple of four, and height + yoffset is not
+ * equal to the value of TEXTURE_HEIGHT.
+ *
+ * so we take that to mean that you can copy the "last" block of a
+ * compressed texture image even if it's smaller than the minimum block
+ * dimensions.
+ */
if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
- (srcWidth % src_bw != 0) || (srcHeight % src_bh != 0)) {
+ (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) ||
+ (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(unaligned src rectangle)");
- goto cleanup;
+ return;
}
- _mesa_get_format_block_size(dstTexImage->TexFormat, &dst_bw, &dst_bh);
+ _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh);
if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(unaligned dst rectangle)");
- goto cleanup;
+ return;
}
- /* Very simple sanity check. This is sufficient if one of the textures
- * is compressed. */
- Bpt = _mesa_get_format_bytes(srcTexImage->TexFormat);
- if (_mesa_get_format_bytes(dstTexImage->TexFormat) != Bpt) {
- _mesa_error(ctx, GL_INVALID_VALUE,
+ /* From the GL_ARB_copy_image spec:
+ *
+ * "The dimensions are always specified in texels, even for compressed
+ * texture formats. But it should be noted that if only one of the
+ * source and destination textures is compressed then the number of
+ * texels touched in the compressed image will be a factor of the
+ * block size larger than in the uncompressed image."
+ *
+ * So, if copying from compressed to uncompressed, the dest region is
+ * shrunk by the src block size factor. If copying from uncompressed
+ * to compressed, the dest region is grown by the dest block size factor.
+ * Note that we're passed the _source_ width, height, depth and those
+ * dimensions are never changed.
+ */
+ dstWidth = srcWidth * dst_bw / src_bw;
+ dstHeight = srcHeight * dst_bh / src_bh;
+ dstDepth = srcDepth;
+
+ if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer,
+ srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
+ "src"))
+ return;
+
+ if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer,
+ dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth,
+ "dst"))
+ return;
+
+ /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
+ * spec says:
+ *
+ * An INVALID_OPERATION error is generated if either object is a texture
+ * and the texture is not complete, if the source and destination internal
+ * formats are not compatible, or if the number of samples do not match.
+ */
+ if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
"glCopyImageSubData(internalFormat mismatch)");
- goto cleanup;
+ return;
}
- if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ,
- srcWidth, srcHeight, srcDepth, "src"))
- goto cleanup;
-
- if (!check_region_bounds(ctx, dstTexImage, dstX, dstY, dstZ,
- (srcWidth / src_bw) * dst_bw,
- (srcHeight / src_bh) * dst_bh, srcDepth, "dst"))
- goto cleanup;
-
- if (_mesa_is_format_compressed(srcTexImage->TexFormat)) {
- /* XXX: Technically, we should probaby do some more specific checking
- * here. However, this should be sufficient for all compressed
- * formats that mesa supports since it is a direct memory copy.
- */
- } else if (_mesa_is_format_compressed(dstTexImage->TexFormat)) {
- } else if (_mesa_texture_view_compatible_format(ctx,
- srcTexImage->InternalFormat,
- dstTexImage->InternalFormat)) {
- } else {
- return; /* Error loged by _mesa_texture_view_compatible_format */
+ if (src_num_samples != dst_num_samples) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyImageSubData(number of samples mismatch)");
+ return;
}
+ /* loop over 2D slices/faces/layers */
for (i = 0; i < srcDepth; ++i) {
- if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) {
- srcTexImage = srcTexObj->Image[i + srcZ][srcLevel];
- srcNewZ = 0;
- } else {
- srcNewZ = srcZ + i;
+ int newSrcZ = srcZ + i;
+ int newDstZ = dstZ + i;
+
+ if (srcTexImage &&
+ srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
+ /* need to update srcTexImage pointer for the cube face */
+ assert(srcZ + i < MAX_FACES);
+ srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel];
+ assert(srcTexImage);
+ newSrcZ = 0;
}
- if (dstTexObj->Target == GL_TEXTURE_CUBE_MAP) {
- dstTexImage = dstTexObj->Image[i + dstZ][dstLevel];
- dstNewZ = 0;
- } else {
- dstNewZ = dstZ + i;
+ if (dstTexImage &&
+ dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
+ /* need to update dstTexImage pointer for the cube face */
+ assert(dstZ + i < MAX_FACES);
+ dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel];
+ assert(dstTexImage);
+ newDstZ = 0;
}
- ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcX, srcY, srcNewZ,
- dstTexImage, dstX, dstY, dstNewZ,
+ ctx->Driver.CopyImageSubData(ctx,
+ srcTexImage, srcRenderbuffer,
+ srcX, srcY, newSrcZ,
+ dstTexImage, dstRenderbuffer,
+ dstX, dstY, newDstZ,
srcWidth, srcHeight);
}
-
-cleanup:
- _mesa_DeleteTextures(2, tmpTexNames);
}