<p dir="ltr">LGTM.</p>
<div class="gmail_quote">On Mar 7, 2015 8:34 PM, "Sean Burke" <<a href="mailto:leftmostcat@gmail.com">leftmostcat@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The memory layout of compatible internal formats may differ in bytes per<br>
block, so TexFormat is not a reliable measure of compatibility. For example,<br>
GL_RGB8 and GL_RGB8UI are compatible formats, but GL_RGB8 may be laid out in<br>
memory as B8G8R8X8. If GL_RGB8UI has a 3 byte-per-block memory layout, the<br>
existing compatibility check will fail.<br>
<br>
Additionally, the current check allows any two compressed textures which share<br>
block size to be used, whereas the spec gives an explicit table of compatible<br>
formats.<br>
<br>
v2: Use a switch instead of array iteration for block class and show the<br>
  Â  correct GL error when internal formats are mismatched.<br>
v3: Include spec citations for new compatibility checks, rearrange check<br>
  Â  order to ensure that compressed, view-compatible formats return the<br>
  Â  correct result, and make style fixes. Original commit message amended<br>
  Â  for clarity.<br>
v4: Reformatted spec citations.<br>
<br>
Reviewed-by: Jason Ekstrand <<a href="mailto:jason.ekstrand@intel.com">jason.ekstrand@intel.com</a>><br>
---<br>
 src/mesa/main/copyimage.c | 151 +++++++++++++++++++++++++++++++++++++++-------<br>
 1 file changed, 130 insertions(+), 21 deletions(-)<br>
<br>
diff --git a/src/mesa/main/copyimage.c b/src/mesa/main/copyimage.c<br>
index 455929d..fd22f28 100644<br>
--- a/src/mesa/main/copyimage.c<br>
+++ b/src/mesa/main/copyimage.c<br>
@@ -33,6 +33,12 @@<br>
 #include "texobj.h"<br>
 #include "fbobject.h"<br>
 #include "textureview.h"<br>
+#include "glformats.h"<br>
+<br>
+enum mesa_block_class {<br>
+  Â BLOCK_CLASS_128_BITS,<br>
+  Â BLOCK_CLASS_64_BITS<br>
+};<br>
<br>
 static bool<br>
 prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level,<br>
@@ -253,6 +259,124 @@ check_region_bounds(struct gl_context *ctx,<br>
struct gl_texture_image *tex_image,<br>
  Â  return true;<br>
 }<br>
<br>
+static bool<br>
+compressed_format_compatible(struct gl_context *ctx,<br>
+  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â GLenum compressedFormat, GLenum otherFormat)<br>
+{<br>
+  Â enum mesa_block_class compressedClass, otherClass;<br>
+<br>
+  Â /* Two view-incompatible compressed formats are never compatible. */<br>
+  Â if (_mesa_is_compressed_format(ctx, otherFormat)) {<br>
+  Â  Â  return false;<br>
+  Â }<br>
+<br>
+  Â /*<br>
+  Â  * From ARB_copy_image spec:<br>
+  Â  *  Â  Table 4.X.1 (Compatible internal formats for copying between<br>
+  Â  *  Â  Â  Â  Â  Â  Â  Â  Â compressed and uncompressed internal formats)<br>
+  Â  *  Â  ---------------------------------------------------------------------<br>
+  Â  *  Â  | Texel / | Uncompressed  Â  Â  |  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â |<br>
+  Â  *  Â  | Block  Â | internal format  Â | Compressed internal format  Â  Â  Â  Â  |<br>
+  Â  *  Â  | size  Â  |  Â  Â  Â  Â  Â  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â |<br>
+  Â  *  Â  ---------------------------------------------------------------------<br>
+  Â  *  Â  | 128-bit | RGBA32UI,  Â  Â  Â  Â | COMPRESSED_RGBA_S3TC_DXT3_EXT,  Â  Â  |<br>
+  Â  *  Â  |  Â  Â  Â  Â | RGBA32I,  Â  Â  Â  Â  | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|<br>
+  Â  *  Â  |  Â  Â  Â  Â | RGBA32F  Â  Â  Â  Â  Â | COMPRESSED_RGBA_S3TC_DXT5_EXT,  Â  Â  |<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_RG_RGTC2,  Â  Â  Â  Â  Â  Â  Â  |<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_SIGNED_RG_RGTC2,  Â  Â  Â  Â |<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_RGBA_BPTC_UNORM,  Â  Â  Â  Â |<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_SRGB_ALPHA_BPTC_UNORM,  Â |<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_RGB_BPTC_SIGNED_FLOAT,  Â |<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT  |<br>
+  Â  *  Â  ---------------------------------------------------------------------<br>
+  Â  *  Â  | 64-bit  | RGBA16F, RG32F,  Â | COMPRESSED_RGB_S3TC_DXT1_EXT,  Â  Â  Â |<br>
+  Â  *  Â  |  Â  Â  Â  Â | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT,  Â  Â  |<br>
+  Â  *  Â  |  Â  Â  Â  Â | RGBA16I, RG32I,  Â | COMPRESSED_RGBA_S3TC_DXT1_EXT,  Â  Â  |<br>
+  Â  *  Â  |  Â  Â  Â  Â | RGBA16,  Â  Â  Â  Â  Â | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|<br>
+  Â  *  Â  |  Â  Â  Â  Â | RGBA16_SNORM  Â  Â  | COMPRESSED_RED_RGTC1,  Â  Â  Â  Â  Â  Â  Â |<br>
+  Â  *  Â  |  Â  Â  Â  Â |  Â  Â  Â  Â  Â  Â  Â  Â  Â | COMPRESSED_SIGNED_RED_RGTC1  Â  Â  Â  Â |<br>
+  Â  *  Â  ---------------------------------------------------------------------<br>
+  Â  */<br>
+<br>
+  Â switch (compressedFormat) {<br>
+  Â  Â  case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:<br>
+  Â  Â  case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:<br>
+  Â  Â  case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:<br>
+  Â  Â  case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:<br>
+  Â  Â  case GL_COMPRESSED_RG_RGTC2:<br>
+  Â  Â  case GL_COMPRESSED_SIGNED_RG_RGTC2:<br>
+  Â  Â  case GL_COMPRESSED_RGBA_BPTC_UNORM:<br>
+  Â  Â  case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:<br>
+  Â  Â  case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:<br>
+  Â  Â  case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:<br>
+  Â  Â  Â  Â compressedClass = BLOCK_CLASS_128_BITS;<br>
+  Â  Â  Â  Â break;<br>
+  Â  Â  case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:<br>
+  Â  Â  case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:<br>
+  Â  Â  case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:<br>
+  Â  Â  case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:<br>
+  Â  Â  case GL_COMPRESSED_RED_RGTC1:<br>
+  Â  Â  case GL_COMPRESSED_SIGNED_RED_RGTC1:<br>
+  Â  Â  Â  Â compressedClass = BLOCK_CLASS_64_BITS;<br>
+  Â  Â  Â  Â break;<br>
+  Â  Â  default:<br>
+  Â  Â  Â  Â return false;<br>
+  Â }<br>
+<br>
+  Â switch (otherFormat) {<br>
+  Â  Â  case GL_RGBA32UI:<br>
+  Â  Â  case GL_RGBA32I:<br>
+  Â  Â  case GL_RGBA32F:<br>
+  Â  Â  Â  Â otherClass = BLOCK_CLASS_128_BITS;<br>
+  Â  Â  Â  Â break;<br>
+  Â  Â  case GL_RGBA16F:<br>
+  Â  Â  case GL_RG32F:<br>
+  Â  Â  case GL_RGBA16UI:<br>
+  Â  Â  case GL_RG32UI:<br>
+  Â  Â  case GL_RGBA16I:<br>
+  Â  Â  case GL_RG32I:<br>
+  Â  Â  case GL_RGBA16:<br>
+  Â  Â  case GL_RGBA16_SNORM:<br>
+  Â  Â  Â  Â otherClass = BLOCK_CLASS_64_BITS;<br>
+  Â  Â  Â  Â break;<br>
+  Â  Â  default:<br>
+  Â  Â  Â  Â return false;<br>
+  Â }<br>
+<br>
+  Â return compressedClass == otherClass;<br>
+}<br>
+<br>
+static bool<br>
+copy_format_compatible(struct gl_context *ctx,<br>
+  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  GLenum srcFormat, GLenum dstFormat)<br>
+{<br>
+  Â /*<br>
+  Â  * From ARB_copy_image spec:<br>
+  Â  *  Â  For the purposes of CopyImageSubData, two internal formats<br>
+  Â  *  Â  are considered compatible if any of the following conditions are<br>
+  Â  *  Â  met:<br>
+  Â  *  Â  * the formats are the same,<br>
+  Â  *  Â  * the formats are considered compatible according to the<br>
+  Â  *  Â  Â  compatibility rules used for texture views as defined in<br>
+  Â  *  Â  Â  section 3.9.X. In particular, if both internal formats are listed<br>
+  Â  *  Â  Â  in the same entry of Table 3.X.2, they are considered compatible, or<br>
+  Â  *  Â  * one format is compressed and the other is uncompressed and<br>
+  Â  *  Â  Â  Table 4.X.1 lists the two formats in the same row.<br>
+  Â  */<br>
+<br>
+  Â if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {<br>
+  Â  Â  /* Also checks if formats are equal. */<br>
+  Â  Â  return true;<br>
+  Â } else if (_mesa_is_compressed_format(ctx, srcFormat)) {<br>
+  Â  Â  return compressed_format_compatible(ctx, srcFormat, dstFormat);<br>
+  Â } else if (_mesa_is_compressed_format(ctx, dstFormat)) {<br>
+  Â  Â  return compressed_format_compatible(ctx, dstFormat, srcFormat);<br>
+  Â }<br>
+<br>
+  Â return false;<br>
+}<br>
+<br>
 void GLAPIENTRY<br>
 _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  GLint srcX, GLint srcY, GLint srcZ,<br>
@@ -265,7 +389,7 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum<br>
srcTarget, GLint srcLevel,<br>
  Â  struct gl_texture_object *srcTexObj, *dstTexObj;<br>
  Â  struct gl_texture_image *srcTexImage, *dstTexImage;<br>
  Â  GLuint src_bw, src_bh, dst_bw, dst_bh;<br>
-  Â int i, srcNewZ, dstNewZ, Bpt;<br>
+  Â int i, srcNewZ, dstNewZ;<br>
<br>
  Â  if (MESA_VERBOSE & VERBOSE_API)<br>
  Â  Â  Â _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "<br>
@@ -306,15 +430,6 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum<br>
srcTarget, GLint srcLevel,<br>
  Â  Â  Â goto cleanup;<br>
  Â  }<br>
<br>
-  Â /* Very simple sanity check.  This is sufficient if one of the textures<br>
-  Â  * is compressed. */<br>
-  Â Bpt = _mesa_get_format_bytes(srcTexImage->TexFormat);<br>
-  Â if (_mesa_get_format_bytes(dstTexImage->TexFormat) != Bpt) {<br>
-  Â  Â  _mesa_error(ctx, GL_INVALID_VALUE,<br>
-  Â  Â  Â  Â  Â  Â  Â  Â  "glCopyImageSubData(internalFormat mismatch)");<br>
-  Â  Â  goto cleanup;<br>
-  Â }<br>
-<br>
  Â  if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â srcWidth, srcHeight, srcDepth, "src"))<br>
  Â  Â  Â goto cleanup;<br>
@@ -324,17 +439,11 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum<br>
srcTarget, GLint srcLevel,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â (srcHeight / src_bh) * dst_bh, srcDepth, "dst"))<br>
  Â  Â  Â goto cleanup;<br>
<br>
-  Â if (_mesa_is_format_compressed(srcTexImage->TexFormat)) {<br>
-  Â  Â  /* XXX: Technically, we should probaby do some more specific checking<br>
-  Â  Â  Â * here.  However, this should be sufficient for all compressed<br>
-  Â  Â  Â * formats that mesa supports since it is a direct memory copy.<br>
-  Â  Â  Â */<br>
-  Â } else if (_mesa_is_format_compressed(dstTexImage->TexFormat)) {<br>
-  Â } else if (_mesa_texture_view_compatible_format(ctx,<br>
-  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â srcTexImage->InternalFormat,<br>
-<br>
dstTexImage->InternalFormat)) {<br>
-  Â } else {<br>
-  Â  Â  return; /* Error logged by _mesa_texture_view_compatible_format */<br>
+  Â if (!copy_format_compatible(ctx, srcTexImage->InternalFormat,<br>
+  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â dstTexImage->InternalFormat)) {<br>
+  Â  Â  _mesa_error(ctx, GL_INVALID_OPERATION,<br>
+  Â  Â  Â  Â  Â  Â  Â  Â  "glCopyImageSubData(internalFormat mismatch)");<br>
+  Â  Â  goto cleanup;<br>
  Â  }<br>
<br>
  Â  for (i = 0; i < srcDepth; ++i) {<br>
--<br>
2.1.0<br>
</blockquote></div>