Bug 738126 - Enforce spec for webgl.generateMipmap, and zero is not PoT - r=bjacob
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 03 Apr 2012 16:42:06 -0700
changeset 90940 162a102274e763228d20dce9337b0a49a60b2b61
parent 90939 3b8a666e351e1121ac71accf157c44d0b4c93957
child 90941 74c085edb4ec38934d9e6be909811c718d820fdb
push id22401
push usermak77@bonardo.net
push dateWed, 04 Apr 2012 11:37:12 +0000
treeherdermozilla-central@638769f8ec54 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs738126
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 738126 - Enforce spec for webgl.generateMipmap, and zero is not PoT - r=bjacob
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextUtils.cpp
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -122,19 +122,20 @@ struct WebGLTexelFormat {
 };
 
 struct WebGLTexelPremultiplicationOp {
     enum { Generic, None, Premultiply, Unmultiply };
 };
 
 int GetWebGLTexelFormat(GLenum format, GLenum type);
 
+// Zero is not an integer power of two.
 inline bool is_pot_assuming_nonnegative(WebGLsizei x)
 {
-    return (x & (x-1)) == 0;
+    return x && (x & (x-1)) == 0;
 }
 
 /* Each WebGL object class WebGLFoo wants to:
  *  - inherit WebGLRefCountedObject<WebGLFoo>
  *  - implement a Delete() method
  *  - have its destructor call DeleteOnce()
  * 
  * This base class provides two features to WebGL object types:
@@ -580,16 +581,17 @@ public:
     nsresult ErrorInvalidValue(const char *fmt = 0, ...);
     nsresult ErrorInvalidFramebufferOperation(const char *fmt = 0, ...);
     nsresult ErrorInvalidEnumInfo(const char *info, PRUint32 enumvalue) {
         return ErrorInvalidEnum("%s: invalid enum value 0x%x", info, enumvalue);
     }
     nsresult ErrorOutOfMemory(const char *fmt = 0, ...);
 
     const char *ErrorName(GLenum error);
+    bool IsTextureFormatCompressed(GLenum format);
 
     nsresult DummyFramebufferOperation(const char *info);
 
     WebGLTexture *activeBoundTextureForTarget(WebGLenum target) {
         return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
                                              : mBoundCubeMapTextures[mActiveTexture];
     }
 
@@ -1242,24 +1244,36 @@ protected:
 
     // we store information about the various images that are part of
     // this texture (cubemap faces, mipmap levels)
 
 public:
 
     class ImageInfo : public WebGLRectangleObject {
     public:
-        ImageInfo() : mFormat(0), mType(0), mIsDefined(false) {}
+        ImageInfo()
+            : mFormat(0)
+            , mType(0)
+            , mIsDefined(false)
+        {}
+
         ImageInfo(WebGLsizei width, WebGLsizei height,
                   WebGLenum format, WebGLenum type)
-            : WebGLRectangleObject(width, height), mFormat(format), mType(type), mIsDefined(true) {}
+            : WebGLRectangleObject(width, height)
+            , mFormat(format)
+            , mType(type)
+            , mIsDefined(true)
+        {}
 
         bool operator==(const ImageInfo& a) const {
-            return mWidth == a.mWidth && mHeight == a.mHeight &&
-                   mFormat == a.mFormat && mType == a.mType;
+            return mIsDefined == a.mIsDefined &&
+                   mWidth     == a.mWidth &&
+                   mHeight    == a.mHeight &&
+                   mFormat    == a.mFormat &&
+                   mType      == a.mType;
         }
         bool operator!=(const ImageInfo& a) const {
             return !(*this == a);
         }
         bool IsSquare() const {
             return mWidth == mHeight;
         }
         bool IsPositive() const {
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -1906,25 +1906,30 @@ WebGLContext::GenerateMipmap(WebGLenum t
         return NS_OK;
 
     if (!ValidateTextureTargetEnum(target, "generateMipmap"))
         return NS_OK;
 
     WebGLTexture *tex = activeBoundTextureForTarget(target);
 
     if (!tex)
-        return ErrorInvalidOperation("generateMipmap: no texture is bound to this target");
-
-    if (!tex->IsFirstImagePowerOfTwo()) {
-        return ErrorInvalidOperation("generateMipmap: the width or height of this texture is not a power of two");
-    }
-
-    if (!tex->AreAllLevel0ImageInfosEqual()) {
-        return ErrorInvalidOperation("generateMipmap: the six faces of this cube map have different dimensions, format, or type.");
-    }
+        return ErrorInvalidOperation("generateMipmap: No texture is bound to this target.");
+
+    if (!tex->HasImageInfoAt(0, 0))
+        return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
+
+    if (!tex->IsFirstImagePowerOfTwo())
+        return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
+
+    GLenum format = tex->ImageInfoAt(0, 0).Format();
+    if (IsTextureFormatCompressed(format))
+        return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
+
+    if (!tex->AreAllLevel0ImageInfosEqual())
+        return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
 
     tex->SetGeneratedMipmap();
 
     MakeContextCurrent();
     gl->fGenerateMipmap(target);
     return NS_OK;
 }
 
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -234,9 +234,32 @@ WebGLContext::ErrorName(GLenum error)
         case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION:
             return "INVALID_FRAMEBUFFER_OPERATION";
         case LOCAL_GL_NO_ERROR:
             return "NO_ERROR";
         default:
             NS_ABORT();
             return "[unknown WebGL error!]";
     }
-};
+}
+
+bool
+WebGLContext::IsTextureFormatCompressed(GLenum format)
+{
+    switch(format) {
+        case LOCAL_GL_RGB:
+        case LOCAL_GL_RGBA:
+        case LOCAL_GL_ALPHA:
+        case LOCAL_GL_LUMINANCE:
+        case LOCAL_GL_LUMINANCE_ALPHA:
+            return false;
+
+        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:
+            return true;
+    }
+
+    NS_NOTREACHED("Invalid WebGL texture format?");
+    NS_ABORT();
+    return false;
+}