Bug 1268638 - Update WebGL creation to allow non-blacklisted native-gl. - r=jrmuizel
☠☠ backed out by ead1598b347f ☠ ☠
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 20 Jun 2016 20:28:57 -0700
changeset 302240 8b0db9b0f87cb1ef75491bdd5927c631aca7fafd
parent 302239 5d1285d0c22151079e8e3424a9c6429b3642471d
child 302241 002f87a61edf488c359b6ecee10b3ada554d7036
push id78659
push userjgilbert@mozilla.com
push dateTue, 21 Jun 2016 21:10:32 +0000
treeherdermozilla-inbound@1a2db6efc575 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1268638
milestone50.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 1268638 - Update WebGL creation to allow non-blacklisted native-gl. - r=jrmuizel Also support accumulating a list of WebGL failure reasons. MozReview-Commit-ID: I9p0BBrBJ5V
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -430,22 +430,25 @@ WebGLContext::GetHeight() const
  *
  * That is, try to create headless contexts based on the platform API.
  * Next, create dummy-sized backbuffers for the contexts with the right
  * caps. Finally, resize the backbuffer to an acceptable size given the
  * requested size.
  */
 
 static bool
-IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature, nsACString* const out_failureId)
+IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature,
+                     nsCString* const out_blacklistId)
 {
     int32_t status;
     if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature,
-                                                           *out_failureId, &status)))
+                                                           *out_blacklistId, &status)))
+    {
         return false;
+    }
 
     return status != nsIGfxInfo::FEATURE_STATUS_OK;
 }
 
 static bool
 HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
 {
     int32_t status;
@@ -558,186 +561,191 @@ BaseCaps(const WebGLContextOptions& opti
             break;
 
         baseCaps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
     } while (false);
 #endif
 
     // Done with baseCaps construction.
 
-    bool forceAllowAA = gfxPrefs::WebGLForceMSAA();
-    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
-    nsCString discardFailureId;
-    if (!forceAllowAA &&
-        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &discardFailureId))
-    {
-        webgl->GenerateWarning("Disallowing antialiased backbuffers due"
-                               " to blacklisting.");
-        baseCaps.antialias = false;
+    if (!gfxPrefs::WebGLForceMSAA()) {
+        const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+
+        nsCString blocklistId;
+        if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &blocklistId)) {
+            webgl->GenerateWarning("Disallowing antialiased backbuffers due"
+                                   " to blacklisting.");
+            baseCaps.antialias = false;
+        }
     }
 
     return baseCaps;
 }
 
 ////////////////////////////////////////
 
 static already_AddRefed<gl::GLContext>
 CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
-                WebGLContext* webgl, nsACString* const out_failReason,
-                nsACString* const out_failureId)
+                WebGLContext* webgl, std::vector<FailureReason>* const out_failReasons)
 {
     const gfx::IntSize dummySize(16, 16);
     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
                                                                      flags, out_failureId);
     if (gl && gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
-        if (out_failReason->Length()) {
-            out_failReason->AppendLiteral("\n");
-        }
-        out_failReason->AppendLiteral("Error during EGL OpenGL init.");
-        if (out_failureId->IsEmpty()) {
-            *out_failureId = "FEATURE_FAILURE_WEBGL_EGL_INIT";
-        }
+        out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_EGL_INIT",
+                                     "Error during EGL OpenGL init." });
         return nullptr;
     }
 
     return gl.forget();
 }
 
 static already_AddRefed<GLContext>
 CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
-                  WebGLContext* webgl, nsACString* const out_failReason,
-                  nsACString* const out_failureId)
+                  WebGLContext* webgl, std::vector<FailureReason>* const out_failReasons)
 {
     const gfx::IntSize dummySize(16, 16);
     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
                                                                      flags, out_failureId);
     if (gl && !gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
-        if (out_failReason->Length()) {
-            out_failReason->AppendLiteral("\n");
-        }
-        out_failReason->AppendLiteral("Error during ANGLE OpenGL init.");
-        if (out_failureId->IsEmpty()) {
-            *out_failureId = "FEATURE_FAILURE_WEBGL_ANGLE_INIT";
-        }
+        out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_ANGLE_INIT",
+                                     "Error during ANGLE OpenGL init." });
         return nullptr;
     }
 
     return gl.forget();
 }
 
 static already_AddRefed<gl::GLContext>
 CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
-                    WebGLContext* webgl, nsACString* const out_failReason,
-                    nsACString* const out_failureId)
+                    WebGLContext* webgl,
+                    std::vector<FailureReason>* const out_failReasons)
 {
-    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
-
-    if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) &&
-        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL, out_failureId))
-    {
-        if (out_failReason->Length()) {
-            out_failReason->AppendASCII("\n");
-        }
-        out_failReason->AppendASCII("Refused to create native OpenGL context because of"
-                                    " blacklisting.");
-        return nullptr;
-    }
-
     const gfx::IntSize dummySize(16, 16);
     RefPtr<GLContext> gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps,
                                                                   flags, out_failureId);
 
     if (gl && gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
-        if (out_failReason->Length()) {
-            out_failReason->AppendASCII("\n");
-        }
-        out_failReason->AppendASCII("Error during native OpenGL init.");
-        if (out_failureId->IsEmpty()) {
-            *out_failureId = "FEATURE_FAILURE_WEBGL_DEFAULT_INIT";
-        }
+        out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_DEFAULT_INIT",
+                                     "Error during native OpenGL init." });
         return nullptr;
     }
 
     return gl.forget();
 }
 
 ////////////////////////////////////////
 
 bool
 WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
                                   const gl::SurfaceCaps& baseCaps,
                                   gl::CreateContextFlags flags,
-                                  nsACString* const out_failReason,
-                                  nsACString* const out_failureId)
+                                  std::vector<FailureReason>* const out_failReasons)
 {
     std::queue<gl::SurfaceCaps> fallbackCaps;
     PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
 
     MOZ_RELEASE_ASSERT(!gl, "GFX: Already have a context.");
     gl = nullptr;
     while (!fallbackCaps.empty()) {
-        gl::SurfaceCaps& caps = fallbackCaps.front();
-
-        gl = fnCreateGL(caps, flags, this, out_failReason, out_failureId);
+        const gl::SurfaceCaps& caps = fallbackCaps.front();
+        gl = fnCreateGL(caps, flags, this, out_failReasons);
         if (gl)
             break;
 
         fallbackCaps.pop();
     }
     if (!gl)
         return false;
 
-    if (!InitAndValidateGL(out_failReason, out_failureId)) {
+    FailureReason reason;
+    if (!InitAndValidateGL(&reason.info, &reason.key)) {
         // The fail reason here should be specific enough for now.
         gl = nullptr;
+        out_failReasons->push_back(reason);
         return false;
     }
 
     return true;
 }
 
 bool
-WebGLContext::CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason, nsACString* const out_failureId)
+WebGLContext::CreateAndInitGL(bool forceEnabled,
+                              std::vector<FailureReason>* const out_failReasons)
 {
-    const bool useEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
+    bool blacklistOpenGL = false;
+    if (!forceEnabled) {
+        const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
 
-    bool useANGLE = false;
-#ifdef XP_WIN
-    const bool disableANGLE = (gfxPrefs::WebGLDisableANGLE() ||
-                               PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"));
-    useANGLE = !disableANGLE;
-#endif
+        FailureReason reason;
+        if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL,
+                                 &reason.key))
+        {
+            blacklistOpenGL = true;
+
+            reason.info = "Refused to create native OpenGL context because of blacklist"
+                          " entry: ";
+            reason.info.Append(blacklistId);
+
+            out_failReasons->push_back(reason);
+
+            GenerateWarning(text.BeginReading());
+        }
+    }
+
+    //////
 
     gl::CreateContextFlags flags = gl::CreateContextFlags::NO_VALIDATION;
 
     if (forceEnabled) flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE;
     if (!IsWebGL2())  flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
     if (IsWebGL2())   flags |= gl::CreateContextFlags::PREFER_ES3;
 
     const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
 
-    if (useEGL)
-        return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReason, out_failureId);
+    //////
+
+    if (!blacklistOpenGL) {
+        const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL");
+
+        if (useEGL)
+            return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReasons);
+
+        if (CreateAndInitGLWith(CreateGLWithNative, baseCaps, flags, out_failReasons))
+            return true;
+    }
+
+    //////
+
+    bool useANGLE = false;
+#ifdef XP_WIN
+    const bool disableANGLE = (gfxPrefs::WebGLDisableANGLE() ||
+                               PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"));
+    useANGLE = !disableANGLE;
+#endif
 
     if (useANGLE)
-        return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReason, out_failureId);
+        return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReasons);
 
-    return CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags, out_failReason, out_failureId);
+    //////
+
+    out_failReasons->push_back(nsLiteralCString("Exhausted GL driver options."));
+    return false;
 }
 
 // Fallback for resizes:
 bool
 WebGLContext::ResizeBackbuffer(uint32_t requestedWidth,
                                uint32_t requestedHeight)
 {
     uint32_t width = requestedWidth;
@@ -925,22 +933,25 @@ WebGLContext::SetDimensions(int32_t sign
         }
     }
 
     // Alright, now let's start trying.
     bool forceEnabled = gfxPrefs::WebGLForceEnabled();
     ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
 
     MOZ_ASSERT(!gl);
-    nsCString failReason;
-    nsCString failureId;
-    if (!CreateAndInitGL(forceEnabled, &failReason, &failureId)) {
-        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, failureId);
-        const nsPrintfCString text("WebGL creation failed: %s",
-                                   failReason.BeginReading());
+    std::vector<FailureReason> failReasons;
+    if (!CreateAndInitGL(forceEnabled, &failReasons)) {
+        nsCString text("WebGL creation failed: ");
+        for (const auto& cur : failReasons) {
+            Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key);
+
+            text.AppendASCII("\n* ");
+            text.Append(cur.info);
+        }
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
     MOZ_ASSERT(gl);
     MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha);
 
     if (mOptions.failIfMajorPerformanceCaveat) {
         if (gl->IsWARP()) {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1199,29 +1199,34 @@ protected:
     // -------------------------------------------------------------------------
     // WebGL 2 specifics (implemented in WebGL2Context.cpp)
 public:
     virtual bool IsWebGL2() const = 0;
 
 protected:
     bool InitWebGL2(nsACString* const out_failReason, nsACString* const out_failureId);
 
-    bool CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason, nsACString* const out_failureId);
+    struct FailureReason {
+        nsCString key; // For reporting.
+        nsCString info;
+    };
+    bool CreateAndInitGL(bool forceEnabled,
+                         std::vector<FailureReason>* const out_failReasons);
+
     bool ResizeBackbuffer(uint32_t width, uint32_t height);
 
     typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps,
                                                          gl::CreateContextFlags flags,
                                                          WebGLContext* webgl,
-                                                         nsACString* const out_failReason,
-                                                         nsACString* const out_failureId);
+                                                         std::vector<FailureReason>* const out_failReasons);
 
     bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps,
                              gl::CreateContextFlags flags,
-                             nsACString* const out_failReason,
-                             nsACString* const out_failureId);
+                             std::vector<FailureReason>* const out_failReasons);
+
     void ThrowEvent_WebGLContextCreationError(const nsACString& text);
 
     // -------------------------------------------------------------------------
     // Validation functions (implemented in WebGLContextValidate.cpp)
     bool InitAndValidateGL(nsACString* const out_failReason, nsACString* const out_failureId);
     bool ValidateBlendEquationEnum(GLenum cap, const char* info);
     bool ValidateBlendFuncDstEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);