#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, including:
+ * - Error checking
+ * - Creating texture wrappers for renderbuffers
+ * \param name the texture or renderbuffer name
+ * \param target GL_TEXTURE target or GL_RENDERBUFFER. For the later, will
+ * be changed to a compatible GL_TEXTURE target.
+ * \param level mipmap level
+ * \param tex_obj returns a pointer to a texture object
+ * \param tex_image returns a pointer to a texture image
+ * \param tmp_tex returns temporary texture object name
+ * \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,
const char *dbg_prefix)
{
- struct gl_renderbuffer *rb;
-
if (name == 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sName = %d)", dbg_prefix, name);
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);
+ struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
if (!rb) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sName = %u)", dbg_prefix, name);
if ((*tex_obj)->Target != *target) {
_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);
+ *tex_image = _mesa_select_tex_image(*tex_obj, *target, level);
if (!*tex_image) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
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,
+ const struct gl_texture_image *tex_image,
int x, int y, int z, int width, int height, int depth,
const char *dbg_prefix)
{
return false;
}
+ /* Check X direction */
if (x + width > tex_image->Width) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
return false;
}
+ /* Check Y direction */
switch (tex_image->TexObject->Target) {
case GL_TEXTURE_1D:
case GL_TEXTURE_1D_ARRAY:
break;
}
+ /* Check Z direction */
switch (tex_image->TexObject->Target) {
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
return true;
}
-void
+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;
+ default:
+ return false;
+ }
+
+ 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,
GLuint dstName, GLenum dstTarget, GLint dstLevel,
struct gl_texture_object *srcTexObj, *dstTexObj;
struct gl_texture_image *srcTexImage, *dstTexImage;
GLuint src_bw, src_bh, dst_bw, dst_bh;
- int i, srcNewZ, dstNewZ, Bpt;
+ 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 (!ctx->Extensions.ARB_copy_image) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyImageSubData(extension not available)");
+ return;
+ }
+
if (!prepare_target(ctx, srcName, &srcTarget, srcLevel,
&srcTexObj, &srcTexImage, &tmpTexNames[0], "src"))
goto cleanup;
goto cleanup;
}
- /* 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,
- "glCopyImageSubData(internalFormat mismatch)");
- goto cleanup;
- }
-
if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ,
srcWidth, srcHeight, srcDepth, "src"))
goto cleanup;
(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 (!copy_format_compatible(ctx, srcTexImage->InternalFormat,
+ dstTexImage->InternalFormat)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyImageSubData(internalFormat mismatch)");
+ goto cleanup;
}
for (i = 0; i < srcDepth; ++i) {
+ int srcNewZ, dstNewZ;
+
if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) {
srcTexImage = srcTexObj->Image[i + srcZ][srcLevel];
srcNewZ = 0;