<p dir="ltr"><br>
On Mar 7, 2015 10:57 AM, "Sean Burke" <<a href="mailto:leftmostcat@gmail.com">leftmostcat@gmail.com</a>> wrote:<br>
><br>
> The memory layout of compatible internal formats may differ in bytes per<br>
> block, so TexFormat is not a reliable measure of compatibility. Additionally,<br>
> the current check allows compressed textures of the same block size to be used,<br>
> which is in violation of the spec.</p>
<p dir="ltr">Could you please be more specific about exactly when the old code fails.</p>
<p dir="ltr">> v2: Use a switch instead of array iteration for block class and show the<br>
>     correct GL error when internal formats are mismatched.<br>
> ---<br>
>  src/mesa/main/copyimage.c | 112 +++++++++++++++++++++++++++++++++++++---------<br>
>  1 file changed, 91 insertions(+), 21 deletions(-)<br>
><br>
> diff --git a/src/mesa/main/copyimage.c b/src/mesa/main/copyimage.c<br>
> index 455929d..eaedaa6 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,85 @@ 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 different compressed formats are never compatible. */<br>
> +   if (_mesa_is_compressed_format(ctx, otherFormat)) {<br>
> +      return false;<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>
> +}</p>
<p dir="ltr">For compressed formats this should be the same as doing a bits-per-block check.  Why do we need all this?</p>
<p dir="ltr">> +static bool<br>
> +copy_format_compatible(struct gl_context *ctx,<br>
> +                                GLenum srcFormat, GLenum dstFormat)<br>
> +{<br>
> +   if (srcFormat == dstFormat) {<br>
> +      return true;<br>
> +   }<br>
> +   else if (_mesa_is_compressed_format(ctx, srcFormat)) {<br>
> +      return compressed_format_compatible(ctx, srcFormat, dstFormat);<br>
> +   }<br>
> +   else if (_mesa_is_compressed_format(ctx, dstFormat)) {<br>
> +      return compressed_format_compatible(ctx, dstFormat, srcFormat);<br>
> +   }<br>
> +   else {<br>
> +      return _mesa_texture_view_compatible_format(ctx,<br>
> +                                                  srcFormat,<br>
> +                                                  dstFormat);<br>
> +   }<br>
> +}<br>
> +<br>
>  void GLAPIENTRY<br>
>  _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,<br>
>                         GLint srcX, GLint srcY, GLint srcZ,<br>
> @@ -265,7 +350,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 +391,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 +400,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>
> _______________________________________________<br>
> mesa-dev mailing list<br>
> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</p>