Bug 1008310 - WebGL warning for using element array with different types. r=jgilbert
authorWalter Litwinczyk <wlitwinczyk@mozilla.com>
Mon, 02 Jun 2014 16:30:00 -0400
changeset 207165 f323624f89a765ce4f7b5f8f2cc987cdfd612645
parent 207164 5203fa15941366fa8ef557a0065915735d273a5d
child 207166 5ac4b3ef5e0ec165818b83043a8658572eae1f1c
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1008310
milestone32.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 1008310 - WebGL warning for using element array with different types. r=jgilbert
content/canvas/src/WebGLBuffer.cpp
content/canvas/src/WebGLBuffer.h
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextDraw.cpp
content/canvas/src/WebGLContextUtils.cpp
content/canvas/src/WebGLContextValidate.cpp
content/canvas/src/WebGLElementArrayCache.cpp
content/canvas/src/WebGLElementArrayCache.h
--- a/content/canvas/src/WebGLBuffer.cpp
+++ b/content/canvas/src/WebGLBuffer.cpp
@@ -67,16 +67,21 @@ WebGLBuffer::SizeOfIncludingThis(mozilla
 bool
 WebGLBuffer::Validate(GLenum type, uint32_t max_allowed,
                       size_t first, size_t count,
                       uint32_t* out_upperBound)
 {
     return mCache->Validate(type, max_allowed, first, count, out_upperBound);
 }
 
+bool
+WebGLBuffer::IsElementArrayUsedWithMultipleTypes() const
+{
+    return mCache->BeenUsedWithMultipleTypes();
+}
 
 JSObject*
 WebGLBuffer::WrapObject(JSContext *cx) {
     return dom::WebGLBufferBinding::Wrap(cx, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLBuffer)
 
--- a/content/canvas/src/WebGLBuffer.h
+++ b/content/canvas/src/WebGLBuffer.h
@@ -44,16 +44,18 @@ public:
 
     bool ElementArrayCacheBufferData(const void* ptr, size_t buffer_size_in_bytes);
 
     void ElementArrayCacheBufferSubData(size_t pos, const void* ptr, size_t update_size_in_bytes);
 
     bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
                   uint32_t* out_upperBound);
 
+    bool IsElementArrayUsedWithMultipleTypes() const;
+
     WebGLContext *GetParentObject() const {
         return Context();
     }
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -208,16 +208,24 @@ public:
     void ErrorInvalidEnum(const char *fmt = 0, ...);
     void ErrorInvalidOperation(const char *fmt = 0, ...);
     void ErrorInvalidValue(const char *fmt = 0, ...);
     void ErrorInvalidFramebufferOperation(const char *fmt = 0, ...);
     void ErrorInvalidEnumInfo(const char *info, GLenum enumvalue);
     void ErrorOutOfMemory(const char *fmt = 0, ...);
 
     const char *ErrorName(GLenum error);
+
+    /**
+     * Return displayable name for GLenum.
+     * This version is like gl::GLenumToStr but with out the GL_ prefix to
+     * keep consistency with how errors are reported from WebGL.
+     */
+    static const char *EnumName(GLenum glenum);
+
     bool IsTextureFormatCompressed(GLenum format);
 
     void DummyFramebufferOperation(const char *info);
 
     WebGLTexture* activeBoundTextureForTarget(GLenum target) const {
         MOZ_ASSERT(!IsTextureBinding(target));
         return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
                                              : mBoundCubeMapTextures[mActiveTexture];
--- a/content/canvas/src/WebGLContextDraw.cpp
+++ b/content/canvas/src/WebGLContextDraw.cpp
@@ -255,16 +255,24 @@ WebGLContext::DrawElements_check(GLsizei
         return false;
     }
 
     if (uint32_t(primcount) > mMaxFetchedInstances) {
         ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
         return false;
     }
 
+    // Bug 1008310 - Check if buffer has been used with a different previous type
+    if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
+        GenerateWarning("%s: bound element array buffer previously used with a type other than "
+                        "%s, this will affect performance.",
+                        info,
+                        WebGLContext::EnumName(type));
+    }
+
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
             ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
             return false;
         }
     } else {
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -357,16 +357,74 @@ WebGLContext::ErrorName(GLenum error)
         case LOCAL_GL_NO_ERROR:
             return "NO_ERROR";
         default:
             MOZ_ASSERT(false);
             return "[unknown WebGL error!]";
     }
 }
 
+const char*
+WebGLContext::EnumName(GLenum glenum)
+{
+    switch (glenum) {
+#define XX(x) case LOCAL_GL_##x: return #x
+        XX(ALPHA);
+        XX(ATC_RGB);
+        XX(ATC_RGBA_EXPLICIT_ALPHA);
+        XX(ATC_RGBA_INTERPOLATED_ALPHA);
+        XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
+        XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
+        XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
+        XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
+        XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
+        XX(COMPRESSED_RGB_PVRTC_2BPPV1);
+        XX(COMPRESSED_RGB_PVRTC_4BPPV1);
+        XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
+        XX(DEPTH_COMPONENT);
+        XX(DEPTH_COMPONENT16);
+        XX(DEPTH_COMPONENT32);
+        XX(DEPTH_STENCIL);
+        XX(DEPTH24_STENCIL8);
+        XX(ETC1_RGB8_OES);
+        XX(FLOAT);
+        XX(HALF_FLOAT);
+        XX(LUMINANCE);
+        XX(LUMINANCE_ALPHA);
+        XX(RGB);
+        XX(RGB16F);
+        XX(RGB32F);
+        XX(RGBA);
+        XX(RGBA16F);
+        XX(RGBA32F);
+        XX(SRGB);
+        XX(SRGB_ALPHA);
+        XX(TEXTURE_2D);
+        XX(TEXTURE_3D);
+        XX(TEXTURE_CUBE_MAP);
+        XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
+        XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
+        XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
+        XX(TEXTURE_CUBE_MAP_POSITIVE_X);
+        XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
+        XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
+        XX(UNSIGNED_BYTE);
+        XX(UNSIGNED_INT);
+        XX(UNSIGNED_INT_24_8);
+        XX(UNSIGNED_SHORT);
+        XX(UNSIGNED_SHORT_4_4_4_4);
+        XX(UNSIGNED_SHORT_5_5_5_1);
+        XX(UNSIGNED_SHORT_5_6_5);
+#undef XX
+    }
+
+    return "[Unknown enum name]";
+}
+
+
 bool
 WebGLContext::IsTextureFormatCompressed(GLenum format)
 {
     switch (format) {
         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:
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -77,85 +77,23 @@ InfoFrom(WebGLTexImageFunc func)
     case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
     default:
         MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
         return "(error)";
     }
 }
 
 /**
- * Return displayable name for GLenum.
- * This version is like gl::GLenumToStr but with out the GL_ prefix to
- * keep consistency with how errors are reported from WebGL.
- */
-static const char*
-NameFrom(GLenum glenum)
-{
-    switch (glenum) {
-#define XX(x) case LOCAL_GL_##x: return #x
-        XX(ALPHA);
-        XX(ATC_RGB);
-        XX(ATC_RGBA_EXPLICIT_ALPHA);
-        XX(ATC_RGBA_INTERPOLATED_ALPHA);
-        XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
-        XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
-        XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
-        XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
-        XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
-        XX(COMPRESSED_RGB_PVRTC_2BPPV1);
-        XX(COMPRESSED_RGB_PVRTC_4BPPV1);
-        XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
-        XX(DEPTH_COMPONENT);
-        XX(DEPTH_COMPONENT16);
-        XX(DEPTH_COMPONENT32);
-        XX(DEPTH_STENCIL);
-        XX(DEPTH24_STENCIL8);
-        XX(ETC1_RGB8_OES);
-        XX(FLOAT);
-        XX(HALF_FLOAT);
-        XX(LUMINANCE);
-        XX(LUMINANCE_ALPHA);
-        XX(RGB);
-        XX(RGB16F);
-        XX(RGB32F);
-        XX(RGBA);
-        XX(RGBA16F);
-        XX(RGBA32F);
-        XX(SRGB);
-        XX(SRGB_ALPHA);
-        XX(TEXTURE_2D);
-        XX(TEXTURE_3D);
-        XX(TEXTURE_CUBE_MAP);
-        XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
-        XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
-        XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
-        XX(TEXTURE_CUBE_MAP_POSITIVE_X);
-        XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
-        XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
-        XX(UNSIGNED_BYTE);
-        XX(UNSIGNED_INT);
-        XX(UNSIGNED_INT_24_8);
-        XX(UNSIGNED_SHORT);
-        XX(UNSIGNED_SHORT_4_4_4_4);
-        XX(UNSIGNED_SHORT_5_5_5_1);
-        XX(UNSIGNED_SHORT_5_6_5);
-#undef XX
-    }
-
-    return nullptr;
-}
-
-/**
- * Same as ErrorInvalidEnum but uses NameFrom to print displayable
+ * Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
  * name for \a glenum.
  */
 static void
 ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
 {
-    const char* name = NameFrom(glenum);
+    const char* name = WebGLContext::EnumName(glenum);
     if (name)
         ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
     else
         ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
 }
 
 /**
  * Return true if the format is valid for source calls.
@@ -599,75 +537,75 @@ WebGLContext::ValidateTexImageFormat(GLe
 
     /* WEBGL_depth_texture added formats */
     if (format == LOCAL_GL_DEPTH_COMPONENT ||
         format == LOCAL_GL_DEPTH_STENCIL)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     /* EXT_sRGB added formats */
     if (format == LOCAL_GL_SRGB ||
         format == LOCAL_GL_SRGB_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     /* WEBGL_compressed_texture_atc added formats */
     if (format == LOCAL_GL_ATC_RGB ||
         format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
         format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     // WEBGL_compressed_texture_etc1
     if (format == LOCAL_GL_ETC1_RGB8_OES) {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     ErrorInvalidEnumWithName(this, "invalid format", format, func);
 
     return false;
 }
 
@@ -711,38 +649,38 @@ WebGLContext::ValidateTexImageType(GLenu
         return true;
     }
 
     /* OES_texture_float added types */
     if (type == LOCAL_GL_FLOAT) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
-                             InfoFrom(func), NameFrom(type));
+                             InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* OES_texture_half_float add types */
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
-                             InfoFrom(func), NameFrom(type));
+                             InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* WEBGL_depth_texture added types */
     if (type == LOCAL_GL_UNSIGNED_SHORT ||
         type == LOCAL_GL_UNSIGNED_INT ||
         type == LOCAL_GL_UNSIGNED_INT_24_8)
     {
         bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), NameFrom(type));
+                             InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     ErrorInvalidEnumWithName(this, "invalid type", type, func);
     return false;
 }
 
 /**
@@ -1239,17 +1177,17 @@ WebGLContext::ValidateTexImageFormatAndT
         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));
+                              InfoFrom(func), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
 
     return validCombo;
 }
 
 /**
  * Return true if format, type and jsArrayType are a valid combination.
  * Also returns the size for texel of format and type (in bytes) via
  * \a texelSize.
@@ -1361,24 +1299,24 @@ WebGLContext::ValidateTexImage(GLuint di
     /* 5.14.8 Texture objects - WebGL Spec.
      *   "If an attempt is made to call these functions with no
      *    WebGLTexture bound (see above), an INVALID_OPERATION error
      *    is generated."
      */
     WebGLTexture* tex = activeBoundTextureForTarget(target);
     if (!tex) {
         ErrorInvalidOperation("%s: no texture is bound to target %s",
-                              info, NameFrom(target));
+                              info, WebGLContext::EnumName(target));
         return false;
     }
 
     if (IsSubFunc(func)) {
         if (!tex->HasImageInfoAt(target, level)) {
             ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
-                                  info, NameFrom(target), level);
+                                  info, WebGLContext::EnumName(target), level);
             return false;
         }
 
         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
         if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
                                      width, height, depth,
                                      imageInfo.Width(), imageInfo.Height(), 0,
                                      func))
@@ -1399,24 +1337,24 @@ WebGLContext::ValidateTexImage(GLuint di
     }
 
     /* Additional checks for depth textures */
     if (target != LOCAL_GL_TEXTURE_2D &&
         (format == LOCAL_GL_DEPTH_COMPONENT ||
          format == LOCAL_GL_DEPTH_STENCIL))
     {
         ErrorInvalidOperation("%s: with format of %s target must be TEXTURE_2D",
-                              info, NameFrom(format));
+                              info, WebGLContext::EnumName(format));
         return false;
     }
 
     /* Additional checks for compressed textures */
     if (!IsAllowedFromSource(format, func)) {
         ErrorInvalidOperation("%s: Invalid format %s for this operation",
-                              info, NameFrom(format));
+                              info, WebGLContext::EnumName(format));
         return false;
     }
 
     /* Parameters are OK */
     return true;
 }
 
 bool
--- a/content/canvas/src/WebGLElementArrayCache.cpp
+++ b/content/canvas/src/WebGLElementArrayCache.cpp
@@ -599,9 +599,21 @@ WebGLElementArrayCache::SizeOfIncludingT
   size_t uint32TreeSize = mUint32Tree ? mUint32Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
   return aMallocSizeOf(this) +
           mBytes.SizeOfExcludingThis(aMallocSizeOf) +
           uint8TreeSize +
           uint16TreeSize +
           uint32TreeSize;
 }
 
+bool
+WebGLElementArrayCache::BeenUsedWithMultipleTypes() const
+{
+  // C++ Standard ($4.7)
+  // "If the source type is bool, the value false is converted to zero and
+  //  the value true is converted to one."
+  const int num_types_used = (mUint8Tree  != nullptr) +
+                             (mUint16Tree != nullptr) +
+                             (mUint32Tree != nullptr);
+  return num_types_used > 1;
+}
+
 } // end namespace mozilla
--- a/content/canvas/src/WebGLElementArrayCache.h
+++ b/content/canvas/src/WebGLElementArrayCache.h
@@ -42,16 +42,18 @@ public:
   T Element(size_t i) const { return Elements<T>()[i]; }
 
   WebGLElementArrayCache();
 
   ~WebGLElementArrayCache();
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
+  bool BeenUsedWithMultipleTypes() const;
+
 private:
 
   template<typename T>
   bool Validate(uint32_t maxAllowed, size_t first, size_t count,
                 uint32_t* out_upperBound);
 
   template<typename T>
   const T* Elements() const { return reinterpret_cast<const T*>(mBytes.Elements()); }