Bug 1535809 - Add warning on use of implicitly enabled extensions r=jgilbert
authorGreyson Gilbert <greyson.gilbert.oss@gmail.com>
Tue, 09 Jul 2019 05:21:30 +0000
changeset 545578 5d8406bfe056b2aee644c856d38b49d682cfdb0a
parent 545577 a6f3fd30a0a712f426a36bdb01bb40c56b6d8334
child 545579 012d470fdcd530913edb27cc062e9d7511ba31aa
push id2165
push userffxbld-merge
push dateMon, 14 Oct 2019 16:30:58 +0000
treeherdermozilla-release@0eae18af659f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1535809
milestone70.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 1535809 - Add warning on use of implicitly enabled extensions r=jgilbert Differential Revision: https://phabricator.services.mozilla.com/D36431
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextDraw.cpp
dom/canvas/WebGLContextExtensions.cpp
dom/canvas/WebGLContextFramebufferOperations.cpp
dom/canvas/WebGLExtensionColorBufferFloat.cpp
dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
dom/canvas/WebGLExtensions.cpp
dom/canvas/WebGLExtensions.h
dom/canvas/WebGLFormats.cpp
dom/canvas/WebGLFormats.h
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLTexture.cpp
dom/canvas/WebGLTextureUpload.cpp
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1689,24 +1689,29 @@ class WebGLContext : public nsICanvasRen
 
   ExtensionsArrayType mExtensions;
 
   // enable an extension. the extension should not be enabled before.
   void EnableExtension(WebGLExtensionID ext);
 
   // Enable an extension if it's supported. Return the extension on success.
   WebGLExtensionBase* EnableSupportedExtension(dom::CallerType callerType,
-                                               WebGLExtensionID ext);
+                                               WebGLExtensionID ext,
+                                               bool explict = true);
 
  public:
   // returns true if the extension has been enabled by calling getExtension.
   bool IsExtensionEnabled(const WebGLExtensionID ext) const {
     return mExtensions[ext];
   }
 
+  bool IsExtensionExplicit(const WebGLExtensionID ext) const;
+
+  void WarnIfImplicit(const WebGLExtensionID ext);
+
  protected:
   // returns true if the extension is supported for this caller type (this
   // decides what getSupportedExtensions exposes)
   bool IsExtensionSupported(dom::CallerType callerType,
                             WebGLExtensionID ext) const;
   bool IsExtensionSupported(WebGLExtensionID ext) const;
 
   static const char* GetExtensionString(WebGLExtensionID ext);
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -328,23 +328,25 @@ static bool DoSetsIntersect(const std::s
 }
 
 const webgl::CachedDrawFetchLimits* ValidateDraw(WebGLContext* const webgl,
                                                  const GLenum mode,
                                                  const uint32_t instanceCount) {
   if (!webgl->BindCurFBForDraw()) return nullptr;
 
   const auto& fb = webgl->mBoundDrawFramebuffer;
-  if (fb && !webgl->IsExtensionEnabled(WebGLExtensionID::EXT_float_blend) &&
-      webgl->mBlendEnabled) {
+  if (fb && webgl->mBlendEnabled) {
     const auto& info = *fb->GetCompletenessInfo();
     if (info.hasFloat32) {
-      webgl->ErrorInvalidOperation(
-          "Float32 blending requires EXT_float_blend.");
-      return nullptr;
+      if (!webgl->IsExtensionEnabled(WebGLExtensionID::EXT_float_blend)) {
+        webgl->ErrorInvalidOperation(
+            "Float32 blending requires EXT_float_blend.");
+        return nullptr;
+      }
+      webgl->WarnIfImplicit(WebGLExtensionID::EXT_float_blend);
     }
   }
 
   switch (mode) {
     case LOCAL_GL_TRIANGLES:
     case LOCAL_GL_TRIANGLE_STRIP:
     case LOCAL_GL_TRIANGLE_FAN:
     case LOCAL_GL_POINTS:
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -230,30 +230,54 @@ bool WebGLContext::IsExtensionSupported(
     case WebGLExtensionID::MOZ_debug:
     case WebGLExtensionID::Max:
       return false;
   }
 
   return false;
 }
 
+bool WebGLContext::IsExtensionExplicit(const WebGLExtensionID ext) const {
+  MOZ_ASSERT(ext < WebGLExtensionID::Max);
+  return mExtensions[ext] && mExtensions[ext]->IsExplicit();
+}
+
+void WebGLContext::WarnIfImplicit(const WebGLExtensionID ext) {
+  MOZ_ASSERT(ext < WebGLExtensionID::Max);
+  const auto& extension = mExtensions[ext];
+  if (!extension || extension->IsExplicit()) return;
+
+  GenerateWarning(
+      "Using format enabled by implicitly enabled extension: %s. "
+      "For maximal portability enable it explicitly.",
+      GetExtensionString(ext));
+  // Don't spam warnings
+  extension->SetExplicit();
+}
+
 static bool CompareWebGLExtensionName(const nsACString& name,
                                       const char* other) {
   return name.Equals(other, nsCaseInsensitiveCStringComparator());
 }
 
 WebGLExtensionBase* WebGLContext::EnableSupportedExtension(
-    dom::CallerType callerType, WebGLExtensionID ext) {
+    dom::CallerType callerType, WebGLExtensionID ext, bool explict) {
   if (!IsExtensionEnabled(ext)) {
     if (!IsExtensionSupported(callerType, ext)) return nullptr;
 
     EnableExtension(ext);
   }
 
-  return mExtensions[ext];
+  const auto extension = mExtensions[ext];
+  MOZ_ASSERT(extension);
+  if (explict && !extension->IsExplicit()) {
+    extension->SetExplicit();
+  }
+
+  return extension;
 }
 
 void WebGLContext::GetExtension(JSContext* cx, const nsAString& wideName,
                                 JS::MutableHandle<JSObject*> retval,
                                 dom::CallerType callerType, ErrorResult& rv) {
   retval.set(nullptr);
   const FuncScope funcScope(*this, "getExtension");
   if (IsContextLost()) return;
@@ -280,32 +304,35 @@ void WebGLContext::GetExtension(JSContex
   // step 3: if the extension hadn't been previously been created, create it
   // now, thus enabling it
   WebGLExtensionBase* extObj = EnableSupportedExtension(callerType, ext);
   if (!extObj) return;
 
   // Step 4: Enable any implied extensions.
   switch (ext) {
     case WebGLExtensionID::EXT_color_buffer_float:
-      EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend);
+      EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend,
+                               false);
       break;
 
     case WebGLExtensionID::OES_texture_float:
-      EnableSupportedExtension(callerType,
-                               WebGLExtensionID::WEBGL_color_buffer_float);
-      EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend);
+      EnableSupportedExtension(
+          callerType, WebGLExtensionID::WEBGL_color_buffer_float, false);
+      EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend,
+                               false);
       break;
 
     case WebGLExtensionID::OES_texture_half_float:
-      EnableSupportedExtension(callerType,
-                               WebGLExtensionID::EXT_color_buffer_half_float);
+      EnableSupportedExtension(
+          callerType, WebGLExtensionID::EXT_color_buffer_half_float, false);
       break;
 
     case WebGLExtensionID::WEBGL_color_buffer_float:
-      EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend);
+      EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend,
+                               false);
       break;
 
     default:
       break;
   }
 
   retval.set(WebGLObjectAsJSObject(cx, extObj, rv));
 }
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -67,21 +67,37 @@ static GLfloat GLClampFloat(GLfloat val)
 
   return val;
 }
 
 void WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
   const FuncScope funcScope(*this, "clearColor");
   if (IsContextLost()) return;
 
-  const bool supportsFloatColorBuffers =
-      (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_float) ||
-       IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
-       IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float));
-  if (!supportsFloatColorBuffers) {
+  if (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_float)) {
+    MOZ_ASSERT(IsExtensionExplicit(WebGLExtensionID::EXT_color_buffer_float));
+
+  } else if (IsExtensionEnabled(
+                 WebGLExtensionID::EXT_color_buffer_half_float) ||
+             IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float)) {
+    const bool explict =
+        (IsExtensionExplicit(WebGLExtensionID::EXT_color_buffer_half_float) ||
+         IsExtensionExplicit(WebGLExtensionID::WEBGL_color_buffer_float));
+    const bool wouldHaveClamped =
+        (r != GLClampFloat(r) || g != GLClampFloat(g) || b != GLClampFloat(b) ||
+         a != GLClampFloat(a));
+    if (!explict && wouldHaveClamped) {
+      if (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float)) {
+        WarnIfImplicit(WebGLExtensionID::EXT_color_buffer_half_float);
+      } else if (IsExtensionEnabled(
+                     WebGLExtensionID::WEBGL_color_buffer_float)) {
+        WarnIfImplicit(WebGLExtensionID::WEBGL_color_buffer_float);
+      }
+    }
+  } else {
     r = GLClampFloat(r);
     g = GLClampFloat(g);
     b = GLClampFloat(b);
     a = GLClampFloat(a);
   }
 
   gl->fClearColor(r, g, b, a);
 
--- a/dom/canvas/WebGLExtensionColorBufferFloat.cpp
+++ b/dom/canvas/WebGLExtensionColorBufferFloat.cpp
@@ -10,34 +10,43 @@
 #include "WebGLFormats.h"
 
 namespace mozilla {
 
 WebGLExtensionColorBufferFloat::WebGLExtensionColorBufferFloat(
     WebGLContext* webgl)
     : WebGLExtensionBase(webgl) {
   MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
-
-  auto& fua = webgl->mFormatUsage;
+  SetRenderable(webgl::FormatRenderableState::Implicit(
+      WebGLExtensionID::WEBGL_color_buffer_float));
+}
 
-  auto fnUpdateUsage = [&fua](GLenum sizedFormat,
-                              webgl::EffectiveFormat effFormat) {
+void WebGLExtensionColorBufferFloat::SetRenderable(
+    const webgl::FormatRenderableState state) {
+  auto& fua = mContext->mFormatUsage;
+
+  auto fnUpdateUsage = [&](GLenum sizedFormat,
+                           webgl::EffectiveFormat effFormat) {
     auto usage = fua->EditUsage(effFormat);
-    usage->SetRenderable();
+    usage->SetRenderable(state);
     fua->AllowRBFormat(sizedFormat, usage);
   };
 
 #define FOO(x) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x)
 
   // The extension doesn't actually add RGB32F; only RGBA32F.
   FOO(RGBA32F);
 
 #undef FOO
 }
 
+void WebGLExtensionColorBufferFloat::OnSetExplicit() {
+  SetRenderable(webgl::FormatRenderableState::Explicit());
+}
+
 WebGLExtensionColorBufferFloat::~WebGLExtensionColorBufferFloat() {}
 
 bool WebGLExtensionColorBufferFloat::IsSupported(const WebGLContext* webgl) {
   if (webgl->IsWebGL2()) return false;
 
   const auto& gl = webgl->gl;
   return gl->IsSupported(gl::GLFeature::renderbuffer_color_float) &&
          gl->IsSupported(gl::GLFeature::frag_color_float);
--- a/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
+++ b/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
@@ -10,38 +10,46 @@
 #include "WebGLFormats.h"
 
 namespace mozilla {
 
 WebGLExtensionColorBufferHalfFloat::WebGLExtensionColorBufferHalfFloat(
     WebGLContext* webgl)
     : WebGLExtensionBase(webgl) {
   MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
-
-  auto& fua = webgl->mFormatUsage;
+  SetRenderable(webgl::FormatRenderableState::Implicit(
+      WebGLExtensionID::EXT_color_buffer_half_float));
+}
 
-  auto fnUpdateUsage = [&fua](GLenum sizedFormat,
-                              webgl::EffectiveFormat effFormat,
-                              const bool renderable) {
+void WebGLExtensionColorBufferHalfFloat::SetRenderable(
+    const webgl::FormatRenderableState state) {
+  auto& fua = mContext->mFormatUsage;
+
+  auto fnUpdateUsage = [&](GLenum sizedFormat, webgl::EffectiveFormat effFormat,
+                           const bool renderable) {
     auto usage = fua->EditUsage(effFormat);
     if (renderable) {
-      usage->SetRenderable();
+      usage->SetRenderable(state);
     }
     fua->AllowRBFormat(sizedFormat, usage, renderable);
   };
 
 #define FOO(x, y) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x, y)
 
   FOO(RGBA16F, true);
   FOO(RGB16F, false);  // It's not required, thus not portable. (Also there's a
                        // wicked driver bug on Mac+Intel)
 
 #undef FOO
 }
 
+void WebGLExtensionColorBufferHalfFloat::OnSetExplicit() {
+  SetRenderable(webgl::FormatRenderableState::Explicit());
+}
+
 WebGLExtensionColorBufferHalfFloat::~WebGLExtensionColorBufferHalfFloat() {}
 
 bool WebGLExtensionColorBufferHalfFloat::IsSupported(
     const WebGLContext* webgl) {
   if (webgl->IsWebGL2()) return false;
 
   const auto& gl = webgl->gl;
   return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) &&
--- a/dom/canvas/WebGLExtensions.cpp
+++ b/dom/canvas/WebGLExtensions.cpp
@@ -7,18 +7,18 @@
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "mozilla/StaticPrefs.h"
 #include "WebGLContext.h"
 
 namespace mozilla {
 
-WebGLExtensionBase::WebGLExtensionBase(WebGLContext* context)
-    : WebGLContextBoundObject(context), mIsLost(false) {}
+WebGLExtensionBase::WebGLExtensionBase(WebGLContext* webgl)
+    : WebGLContextBoundObject(webgl), mIsLost(false), mIsExplicit(false) {}
 
 WebGLExtensionBase::~WebGLExtensionBase() {}
 
 void WebGLExtensionBase::MarkLost() {
   mIsLost = true;
 
   OnMarkLost();
 }
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -7,16 +7,17 @@
 #define WEBGL_EXTENSIONS_H_
 
 #include "mozilla/AlreadyAddRefed.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "WebGLObjectModel.h"
 #include "WebGLTypes.h"
+#include "WebGLFormats.h"
 
 namespace mozilla {
 class ErrorResult;
 
 namespace dom {
 template <typename>
 struct Nullable;
 template <typename>
@@ -37,25 +38,36 @@ class WebGLExtensionBase : public nsWrap
                            public WebGLContextBoundObject {
  public:
   explicit WebGLExtensionBase(WebGLContext* webgl);
 
   WebGLContext* GetParentObject() const { return mContext; }
 
   void MarkLost();
 
+  void SetExplicit() {
+    mIsExplicit = true;
+    OnSetExplicit();
+  }
+
+  bool IsExplicit() { return mIsExplicit; }
+
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLExtensionBase)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLExtensionBase)
 
  protected:
   virtual ~WebGLExtensionBase();
 
   virtual void OnMarkLost() {}
 
   bool mIsLost;
+
+  virtual void OnSetExplicit() {}
+
+  bool mIsExplicit;
 };
 
 #define DECL_WEBGL_EXTENSION_GOOP             \
   virtual JSObject* WrapObject(JSContext* cx, \
                                JS::Handle<JSObject*> givenProto) override;
 
 #define IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionType, WebGLBindingType)        \
   JSObject* WebGLExtensionType::WrapObject(JSContext* cx,                      \
@@ -316,26 +328,34 @@ class WebGLExtensionTextureHalfFloatLine
 
 class WebGLExtensionColorBufferFloat : public WebGLExtensionBase {
  public:
   explicit WebGLExtensionColorBufferFloat(WebGLContext*);
   virtual ~WebGLExtensionColorBufferFloat();
 
   static bool IsSupported(const WebGLContext*);
 
+  void SetRenderable(const webgl::FormatRenderableState);
+
+  void OnSetExplicit() override;
+
   DECL_WEBGL_EXTENSION_GOOP
 };
 
 class WebGLExtensionColorBufferHalfFloat : public WebGLExtensionBase {
  public:
   explicit WebGLExtensionColorBufferHalfFloat(WebGLContext*);
   virtual ~WebGLExtensionColorBufferHalfFloat();
 
   static bool IsSupported(const WebGLContext*);
 
+  void SetRenderable(const webgl::FormatRenderableState);
+
+  void OnSetExplicit() override;
+
   DECL_WEBGL_EXTENSION_GOOP
 };
 
 class WebGLExtensionDrawBuffers : public WebGLExtensionBase {
  public:
   explicit WebGLExtensionDrawBuffers(WebGLContext*);
   virtual ~WebGLExtensionDrawBuffers();
 
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -760,18 +760,20 @@ static bool AddUnsizedFormats(FormatUsag
     AddSimpleUnsized(fua, LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5  , EffectiveFormat::RGB565 );
 
     // L, A, LA
     return AddLegacyFormats_LA8(fua, gl);
 
   // clang-format on
 }
 
-void FormatUsageInfo::SetRenderable() {
-  this->isRenderable = true;
+void FormatUsageInfo::SetRenderable(const FormatRenderableState& state) {
+  if (!renderableState.IsExplicit()) {
+    renderableState = state;
+  }
 
 #ifdef DEBUG
   const auto format = this->format;
   if (format->IsColorFormat()) {
     const auto& map = format->copyDecayFormats;
     const auto itr = map.find(format->unsizedFormat);
     MOZ_ASSERT(itr != map.end(),
                "Renderable formats must be in copyDecayFormats.");
@@ -1120,16 +1122,21 @@ bool FormatUsageAuthority::AreUnpackEnum
 
 void FormatUsageAuthority::AllowRBFormat(GLenum sizedFormat,
                                          const FormatUsageInfo* usage,
                                          const bool expectRenderable) {
   MOZ_ASSERT(!usage->format->compression);
   MOZ_ASSERT(usage->format->sizedFormat);
   MOZ_ASSERT(usage->IsRenderable() || !expectRenderable);
 
+  const auto& found = mRBFormatMap.find(sizedFormat);
+  if (found != mRBFormatMap.end()) {
+    MOZ_ASSERT(found->second == usage);
+    return;
+  }
   AlwaysInsert(mRBFormatMap, sizedFormat, usage);
 }
 
 void FormatUsageAuthority::AllowSizedTexFormat(GLenum sizedFormat,
                                                const FormatUsageInfo* usage) {
   if (usage->format->compression) {
     MOZ_ASSERT(usage->isFilterable, "Compressed formats should be filterable.");
   } else {
--- a/dom/canvas/WebGLFormats.h
+++ b/dom/canvas/WebGLFormats.h
@@ -304,21 +304,45 @@ const FormatInfo* GetFormat(EffectiveFor
 uint8_t BytesPerPixel(const PackingInfo& packing);
 bool GetBytesPerPixel(const PackingInfo& packing, uint8_t* const out_bytes);
 /*
 GLint ComponentSize(const FormatInfo* format, GLenum component);
 GLenum ComponentType(const FormatInfo* format);
 */
 ////////////////////////////////////////
 
+struct FormatRenderableState final {
+ private:
+  enum class RenderableState {
+    Disabled,
+    Implicit,
+    Explicit,
+  };
+
+ public:
+  RenderableState state = RenderableState::Disabled;
+  WebGLExtensionID extid = WebGLExtensionID::Max;
+
+  static FormatRenderableState Explicit() {
+    return {RenderableState::Explicit};
+  }
+
+  static FormatRenderableState Implicit(WebGLExtensionID extid) {
+    return {RenderableState::Implicit, extid};
+  }
+
+  bool IsRenderable() const { return state != RenderableState::Disabled; }
+  bool IsExplicit() const { return state == RenderableState::Explicit; }
+};
+
 struct FormatUsageInfo {
   const FormatInfo* const format;
 
  private:
-  bool isRenderable = false;
+  FormatRenderableState renderableState;
 
  public:
   bool isFilterable = false;
 
   std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
   const DriverUnpackInfo* idealUnpack = nullptr;
 
   const GLint* textureSwizzleRGBA = nullptr;
@@ -333,18 +357,24 @@ struct FormatUsageInfo {
   static const GLint kLumAlphaSwizzleRGBA[4];
 
   explicit FormatUsageInfo(const FormatInfo* const _format) : format(_format) {
     if (format->IsColorFormat() && format->baseType != TextureBaseType::Float) {
       maxSamplesKnown = true;
     }
   }
 
-  bool IsRenderable() const { return isRenderable; }
-  void SetRenderable();
+  bool IsRenderable() const { return renderableState.IsRenderable(); }
+  void SetRenderable(
+      const FormatRenderableState& state = FormatRenderableState::Explicit());
+  bool IsExplicitlyRenderable() const { return renderableState.IsExplicit(); }
+  WebGLExtensionID GetExtensionID() const {
+    MOZ_ASSERT(renderableState.extid != WebGLExtensionID::Max);
+    return renderableState.extid;
+  }
 
   bool IsUnpackValid(const PackingInfo& key,
                      const DriverUnpackInfo** const out_value) const;
 
  private:
   void ResolveMaxSamples(gl::GLContext& gl) const;
 
  public:
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -138,16 +138,19 @@ bool WebGLFBAttachPoint::IsComplete(WebG
   if (!formatUsage->IsRenderable()) {
     const auto info = nsPrintfCString(
         "Attachment has an effective format of %s,"
         " which is not renderable.",
         formatUsage->format->name);
     fnWriteErrorInfo(info.BeginReading());
     return false;
   }
+  if (!formatUsage->IsExplicitlyRenderable()) {
+    webgl->WarnIfImplicit(formatUsage->GetExtensionID());
+  }
 
   const auto format = formatUsage->format;
 
   bool hasRequiredBits;
 
   switch (mAttachmentPoint) {
     case LOCAL_GL_DEPTH_ATTACHMENT:
       hasRequiredBits = format->d;
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -770,16 +770,20 @@ void WebGLTexture::GenerateMipmap() {
   if (!canGenerateMipmap) {
     mContext->ErrorInvalidOperation(
         "Texture at base level is not unsized"
         " internal format or is not"
         " color-renderable or texture-filterable.");
     return;
   }
 
+  if (usage->IsRenderable() && !usage->IsExplicitlyRenderable()) {
+    mContext->WarnIfImplicit(usage->GetExtensionID());
+  }
+
   // Done with validation. Do the operation.
 
   gl::GLContext* gl = mContext->gl;
 
   if (gl->WorkAroundDriverBugs()) {
     // bug 696495 - to work around failures in the texture-mips.html test on
     // various drivers, we set the minification filter before calling
     // glGenerateMipmap. This should not carry a significant performance
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1665,22 +1665,24 @@ ScopedCopyTexImageSource::ScopedCopyTexI
     case webgl::ComponentType::NormUInt:
       sizedFormat = LOCAL_GL_RGBA8;
       break;
 
     case webgl::ComponentType::Float:
       if (webgl->IsExtensionEnabled(
               WebGLExtensionID::WEBGL_color_buffer_float)) {
         sizedFormat = LOCAL_GL_RGBA32F;
+        webgl->WarnIfImplicit(WebGLExtensionID::WEBGL_color_buffer_float);
         break;
       }
 
       if (webgl->IsExtensionEnabled(
               WebGLExtensionID::EXT_color_buffer_half_float)) {
         sizedFormat = LOCAL_GL_RGBA16F;
+        webgl->WarnIfImplicit(WebGLExtensionID::EXT_color_buffer_half_float);
         break;
       }
       MOZ_CRASH("GFX: Should be able to request CopyTexImage from Float.");
 
     default:
       MOZ_CRASH("GFX: Should be able to request CopyTexImage from this type.");
   }