Bug 975824 - Fix compressed texture checks. - r=jgilbert
authorDan Glastonbury <dglastonbury@mozilla.com>
Wed, 26 Feb 2014 16:32:17 -0800
changeset 171192 41a6b1af2d90356e02827c430737cf5b02c26cfa
parent 171191 e0284b21846cd062351064208957c822f4641cea
child 171193 e0ef930a64cbd2e5e1836d275da2f7da56dd1149
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersjgilbert
bugs975824
milestone30.0a1
Bug 975824 - Fix compressed texture checks. - r=jgilbert
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextValidate.cpp
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3337,16 +3337,22 @@ WebGLContext::CompressedTexImage2D(GLenu
         return;
     }
 
     uint32_t byteLength = view.Length();
     if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) {
         return;
     }
 
+    if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0,
+                                  width, height, width, height, func))
+    {
+        return;
+    }
+
     MakeContextCurrent();
     gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
     WebGLTexture* tex = activeBoundTextureForTarget(target);
     MOZ_ASSERT(tex);
     tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
                       WebGLImageDataStatus::InitializedImageData);
 
     ReattachTextureToAnyFramebufferToWorkAroundBugs(tex, level);
@@ -3371,29 +3377,29 @@ WebGLContext::CompressedTexSubImage2D(GL
     {
         return;
     }
 
     WebGLTexture *tex = activeBoundTextureForTarget(target);
     MOZ_ASSERT(tex);
     WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
 
+    uint32_t byteLength = view.Length();
+    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
+        return;
+
     if (!ValidateCompTexImageSize(target, level, format,
                                   xoffset, yoffset,
                                   width, height,
                                   levelInfo.Width(), levelInfo.Height(),
                                   func))
     {
         return;
     }
 
-    uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
-        return;
-
     if (levelInfo.HasUninitializedImageData())
         tex->DoDeferredImageInitialization(target, level);
 
     MakeContextCurrent();
     gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
 }
 
 JS::Value
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -771,36 +771,64 @@ WebGLContext::ValidateCompTexImageSize(G
         if (yoffset % blockHeight != 0) {
             ErrorInvalidOperation("%s: yoffset must be multiple of %d",
                                   InfoFrom(func), blockHeight);
             return false;
         }
 
         /* The size must be a multiple of blockWidth and blockHeight,
          * or must be using offset+size that exactly hits the edge.
-         * Important for small mipmap levels. (s3tc extension appears
-         * to have changed and old code that checks 1x1, 2x2 doesn't
-         * appear necessary anymore)
+         * Important for small mipmap levels.
+         */
+        /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+         * "When level equals zero width and height must be a multiple of 4. When
+         *  level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
+         *  If they are not an INVALID_OPERATION error is generated."
          */
-        if ((width % blockWidth != 0) &&
-            (xoffset + width != (GLint) levelWidth))
-        {
-            ErrorInvalidOperation("%s: width must be multiple of %d or "
-                                  "xoffset + width must be %d",
-                                  InfoFrom(func), blockWidth, levelWidth);
-            return false;
+        if (level == 0) {
+            if (width % blockWidth != 0) {
+                ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
+                                      InfoFrom(func), blockWidth);
+                return false;
+            }
+
+            if (height % blockHeight != 0) {
+                ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
+                                      InfoFrom(func), blockHeight);
+                return false;
+            }
+        }
+        else if (level > 0) {
+            if (width % blockWidth != 0 && width > 2) {
+                ErrorInvalidOperation("%s: width of level %d must be multiple"
+                                      " of %d or 0, 1, 2",
+                                      InfoFrom(func), level, blockWidth);
+                return false;
+            }
+
+            if (height % blockHeight != 0 && height > 2) {
+                ErrorInvalidOperation("%s: height of level %d must be multiple"
+                                      " of %d or 0, 1, 2",
+                                      InfoFrom(func), level, blockHeight);
+                return false;
+            }
         }
 
-        if ((height % blockHeight != 0) &&
-            (yoffset + height != (GLint) levelHeight))
-        {
-            ErrorInvalidOperation("%s: height must be multiple of %d or "
-                                  "yoffset + height must be %d",
-                                  InfoFrom(func), blockHeight, levelHeight);
-            return false;
+        if (IsSubFunc(func)) {
+            if ((xoffset % blockWidth) != 0) {
+                ErrorInvalidOperation("%s: xoffset must be multiple of %d",
+                                      InfoFrom(func), blockWidth);
+                return false;
+            }
+
+            if (yoffset % blockHeight != 0) {
+                ErrorInvalidOperation("%s: yoffset must be multiple of %d",
+                                      InfoFrom(func), blockHeight);
+                return false;
+            }
         }
     }
 
     switch (format) {
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
@@ -1148,20 +1176,36 @@ WebGLContext::ValidateTexImageFormatAndT
         validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
                       type == LOCAL_GL_UNSIGNED_INT);
         break;
 
     case LOCAL_GL_DEPTH_STENCIL:
         validCombo = (type == LOCAL_GL_UNSIGNED_INT_24_8);
         break;
 
+    case LOCAL_GL_ATC_RGB:
+    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
+    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
+    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        validCombo = (type == LOCAL_GL_UNSIGNED_BYTE);
+        break;
+
     default:
         // Only valid formats should be passed to the switch stmt.
-        MOZ_ASSERT("Invalid format");
-        return false;
+        MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
+        validCombo = false;
+        // Fall through to return an InvalidOperations. This will alert us to the
+        // unexpected case that needs fixing in builds without asserts.
     }
 
     if (!validCombo)
         ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
                               InfoFrom(func), NameFrom(format), NameFrom(type));
 
     return validCombo;
 }