Bug 1268638 - r?jrmuizel - Update WebGL creation to allow draft
authorJeff Gilbert <jdashg@gmail.com>
Thu, 19 May 2016 15:14:36 -0700
changeset 369927 9ab211ad19ab56c9a65f2456e8f3d67541e24c58
parent 368911 1806d405c8715949b39fa3a4fc142d14a60df590
child 369928 38568116e0ee30d5e43b711558b2053e3c4319e7
push id18953
push userjgilbert@mozilla.com
push dateTue, 24 May 2016 00:19:59 +0000
reviewersjrmuizel
bugs1268638
milestone49.0a1
Bug 1268638 - r?jrmuizel - Update WebGL creation to allow From 9f464312dbf5e8b8d6f529e4ff205494ede5c85a Mon Sep 17 00:00:00 2001 non-blacklisted native-gl. --- dom/canvas/WebGLContext.cpp | 125 ++++++++++++++++++++++++++------------------ dom/canvas/WebGLContext.h | 7 +-- 2 files changed, 77 insertions(+), 55 deletions(-) MozReview-Commit-ID: 5JVxz8usGaJ
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -426,23 +426,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)
+IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature,
+                     nsCString* const out_blacklistId)
 {
     int32_t status;
-    nsCString discardFailureId;
     if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature,
-                                                           discardFailureId, &status)))
+                                                           *out_blacklistId, &status)))
+    {
         return false;
+    }
 
     return status != nsIGfxInfo::FEATURE_STATUS_OK;
 }
 
 static bool
 HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
 {
     int32_t status;
@@ -557,167 +559,183 @@ BaseCaps(const WebGLContextOptions& opti
         baseCaps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
     } while (false);
 #endif
 
     // Done with baseCaps construction.
 
     bool forceAllowAA = gfxPrefs::WebGLForceMSAA();
     nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+    nsCString unused_BlocklistId;
     if (!forceAllowAA &&
-        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA))
+        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA,
+                             &unused_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)
+                WebGLContext* webgl, std::vector<nsCString>* const out_failReasons)
 {
     const gfx::IntSize dummySize(16, 16);
     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
                                                                      flags);
     if (gl && gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
-        if (out_failReason->Length()) {
-            out_failReason->AppendLiteral("\n");
-        }
-        out_failReason->AppendLiteral("Error during EGL OpenGL init.");
+        out_failReasons->push_back(nsLiteralCString("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)
+                  WebGLContext* webgl, std::vector<nsCString>* const out_failReasons)
 {
     const gfx::IntSize dummySize(16, 16);
     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
                                                                      flags);
     if (gl && !gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
-        if (out_failReason->Length()) {
-            out_failReason->AppendLiteral("\n");
-        }
-        out_failReason->AppendLiteral("Error during ANGLE OpenGL init.");
+        out_failReasons->push_back(nsLiteralCString("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)
+CreateGLWithNative(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
+                   WebGLContext* webgl, std::vector<nsCString>* const out_failReasons)
 {
-    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
-
-    if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) &&
-        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
-    {
-        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);
 
     if (gl && gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
-        if (out_failReason->Length()) {
-            out_failReason->AppendASCII("\n");
-        }
-        out_failReason->AppendASCII("Error during native OpenGL init.");
+        out_failReasons->push_back(nsLiteralCString("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)
+                                  std::vector<nsCString>* const out_failReasons)
 {
     std::queue<gl::SurfaceCaps> fallbackCaps;
     PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
 
     MOZ_RELEASE_ASSERT(!gl);
     gl = nullptr;
     while (!fallbackCaps.empty()) {
         gl::SurfaceCaps& caps = fallbackCaps.front();
 
-        gl = fnCreateGL(caps, flags, this, out_failReason);
+        gl = fnCreateGL(caps, flags, this, out_failReasons);
         if (gl)
             break;
 
         fallbackCaps.pop();
     }
     if (!gl)
         return false;
 
-    if (!InitAndValidateGL(out_failReason)) {
+    nsCString failReason;
+    if (!InitAndValidateGL(&failReason)) {
         gl = nullptr;
+        out_failReasons->push_back(failReason);
         return false;
     }
 
     return true;
 }
 
 bool
-WebGLContext::CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason)
+WebGLContext::CreateAndInitGL(bool forceEnabled,
+                              std::vector<nsCString>* const out_failReasons)
 {
-    const bool useEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
+    bool blacklistOpenGL = false;
+    if (!forceEnabled) {
+        const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+
+        nsCString blacklistId;
+        if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL,
+                                 &blacklistId))
+        {
+            blacklistOpenGL = true;
+
+            nsCString text("Refused to create native OpenGL context because of blacklist"
+                           " entry: ");
+            text.Append(blacklistId);
+            out_failReasons->push_back(text);
+
+            GenerateWarning(text.BeginReading());
+        }
+    }
+
+    //////
+
+    gl::CreateContextFlags flags = gl::CreateContextFlags::NONE;
+    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 (!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
 
-    gl::CreateContextFlags flags = gl::CreateContextFlags::NONE;
-    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 (useANGLE)
+        return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReasons);
 
-    if (useEGL)
-        return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReason);
+    //////
 
-    if (useANGLE)
-        return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReason);
-
-    return CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags, out_failReason);
+    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;
@@ -899,20 +917,23 @@ WebGLContext::SetDimensions(int32_t sign
         }
     }
 
     // Alright, now let's start trying.
     bool forceEnabled = gfxPrefs::WebGLForceEnabled();
     ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
 
     MOZ_ASSERT(!gl);
-    nsCString failReason;
-    if (!CreateAndInitGL(forceEnabled, &failReason)) {
-        const nsPrintfCString text("WebGL creation failed: %s",
-                                   failReason.BeginReading());
+    std::vector<nsCString> failReasons;
+    if (!CreateAndInitGL(forceEnabled, &failReasons)) {
+        nsCString text("WebGL creation failed: ");
+        for (const auto& cur : failReasons) {
+            text.AppendASCII("\n* ");
+            text.Append(cur);
+        }
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
     MOZ_ASSERT(gl);
 
     MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha);
 
     if (!ResizeBackbuffer(width, height)) {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1198,27 +1198,28 @@ protected:
     // -------------------------------------------------------------------------
     // WebGL 2 specifics (implemented in WebGL2Context.cpp)
 public:
     virtual bool IsWebGL2() const = 0;
 
 protected:
     bool InitWebGL2(nsACString* const out_failReason);
 
-    bool CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason);
+    bool CreateAndInitGL(bool forceEnabled,
+                         std::vector<nsCString>* 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);
+                                                         std::vector<nsCString>* const out_failReasons);
 
     bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps,
                              gl::CreateContextFlags flags,
-                             nsACString* const out_failReason);
+                             std::vector<nsCString>* const out_failReasons);
     void ThrowEvent_WebGLContextCreationError(const nsACString& text);
 
     // -------------------------------------------------------------------------
     // Validation functions (implemented in WebGLContextValidate.cpp)
     bool InitAndValidateGL(nsACString* const out_failReason);
     bool ValidateBlendEquationEnum(GLenum cap, const char* info);
     bool ValidateBlendFuncDstEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);