Bug 1451183 - Add GLLibraryEGL::Shutdown() r=jgilbert
authorsotaro <sotaro.ikeda.g@gmail.com>
Mon, 04 Jun 2018 11:09:52 +0900
changeset 469225 886f2a6dc76dc0f1613fc30f2a3c566fbadcbf87
parent 469224 db10936e9f8dc579e104cc6ca8e718e7e8dd4499
child 469226 841c624e3dafeb64654b869f59797d462eb7aa80
push id187
push userfmarier@mozilla.com
push dateMon, 04 Jun 2018 22:28:11 +0000
reviewersjgilbert
bugs1451183
milestone62.0a1
Bug 1451183 - Add GLLibraryEGL::Shutdown() r=jgilbert
gfx/gl/GLContextEGL.h
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLLibraryEGL.cpp
gfx/gl/GLLibraryEGL.h
gfx/ipc/GPUParent.cpp
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -98,29 +98,32 @@ public:
     EGLDisplay GetEGLDisplay() const {
         return GLLibraryEGL::Get()->Display();
     }
 
     bool BindTex2DOffscreen(GLContext* aOffscreen);
     void UnbindTex2DOffscreen(GLContext* aOffscreen);
     void BindOffscreenFramebuffer();
 
+    void Destroy();
+
     static already_AddRefed<GLContextEGL>
     CreateEGLPBufferOffscreenContext(CreateContextFlags flags,
                                      const gfx::IntSize& size,
                                      const SurfaceCaps& minCaps,
                                      nsACString* const out_FailureId);
 
 protected:
     friend class GLContextProviderEGL;
     friend class GLContextEGLFactory;
 
 public:
     const EGLConfig mConfig;
 protected:
+    const RefPtr<GLLibraryEGL> mEgl;
     EGLSurface mSurface;
     const EGLSurface mFallbackSurface;
 public:
     const EGLContext mContext;
 protected:
     EGLSurface mSurfaceOverride;
     RefPtr<gfxASurface> mThebesSurface;
     bool mBound;
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -291,16 +291,17 @@ GLContextEGLFactory::Create(EGLNativeWin
     return gl.forget();
 }
 
 GLContextEGL::GLContextEGL(CreateContextFlags flags, const SurfaceCaps& caps,
                            bool isOffscreen, EGLConfig config, EGLSurface surface,
                            EGLContext context)
     : GLContext(flags, caps, nullptr, isOffscreen, false)
     , mConfig(config)
+    , mEgl(gl::GLLibraryEGL::Get())
     , mSurface(surface)
     , mFallbackSurface(CreateFallbackSurface(config))
     , mContext(context)
     , mSurfaceOverride(EGL_NO_SURFACE)
     , mThebesSurface(nullptr)
     , mBound(false)
     , mIsPBuffer(false)
     , mIsDoubleBuffered(false)
@@ -321,19 +322,17 @@ GLContextEGL::~GLContextEGL()
     if (!mOwnsContext) {
         return;
     }
 
 #ifdef DEBUG
     printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 
-    auto* egl = gl::GLLibraryEGL::Get();
-
-    egl->fDestroyContext(EGL_DISPLAY(), mContext);
+    mEgl->fDestroyContext(EGL_DISPLAY(), mContext);
 
     mozilla::gl::DestroySurface(mSurface);
     mozilla::gl::DestroySurface(mFallbackSurface);
 }
 
 bool
 GLContextEGL::Init()
 {
@@ -360,37 +359,33 @@ GLContextEGL::Init()
         gfx::LogFailure(NS_LITERAL_CSTRING(
             "Couldn't get device attachments for device."));
         return false;
     }
 
     static_assert(sizeof(GLint) >= sizeof(int32_t), "GLint is smaller than int32_t");
     mMaxTextureImageSize = INT32_MAX;
 
-    auto* egl = gl::GLLibraryEGL::Get();
-
-    mShareWithEGLImage = egl->HasKHRImageBase() &&
-                         egl->HasKHRImageTexture2D() &&
+    mShareWithEGLImage = mEgl->HasKHRImageBase() &&
+                         mEgl->HasKHRImageTexture2D() &&
                          IsExtensionSupported(OES_EGL_image);
 
     return true;
 }
 
 bool
 GLContextEGL::BindTexImage()
 {
     if (!mSurface)
         return false;
 
     if (mBound && !ReleaseTexImage())
         return false;
 
-    auto* egl = gl::GLLibraryEGL::Get();
-
-    EGLBoolean success = egl->fBindTexImage(EGL_DISPLAY(),
+    EGLBoolean success = mEgl->fBindTexImage(EGL_DISPLAY(),
         (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
     if (success == LOCAL_EGL_FALSE)
         return false;
 
     mBound = true;
     return true;
 }
 
@@ -398,22 +393,20 @@ bool
 GLContextEGL::ReleaseTexImage()
 {
     if (!mBound)
         return true;
 
     if (!mSurface)
         return false;
 
-    auto* egl = gl::GLLibraryEGL::Get();
-
     EGLBoolean success;
-    success = egl->fReleaseTexImage(EGL_DISPLAY(),
-                                    (EGLSurface)mSurface,
-                                    LOCAL_EGL_BACK_BUFFER);
+    success = mEgl->fReleaseTexImage(EGL_DISPLAY(),
+                                     (EGLSurface)mSurface,
+                                     LOCAL_EGL_BACK_BUFFER);
     if (success == LOCAL_EGL_FALSE)
         return false;
 
     mBound = false;
     return true;
 }
 
 void
@@ -436,22 +429,20 @@ bool
 GLContextEGL::MakeCurrentImpl() const
 {
     EGLSurface surface = (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride
                                                               : mSurface;
     if (!surface) {
         surface = mFallbackSurface;
     }
 
-    auto* egl = gl::GLLibraryEGL::Get();
-
-    const bool succeeded = egl->fMakeCurrent(EGL_DISPLAY(), surface, surface,
-                                             mContext);
+    const bool succeeded = mEgl->fMakeCurrent(EGL_DISPLAY(), surface, surface,
+                                              mContext);
     if (!succeeded) {
-        const auto eglError = egl->fGetError();
+        const auto eglError = mEgl->fGetError();
         if (eglError == LOCAL_EGL_CONTEXT_LOST) {
             mContextLost = true;
             NS_WARNING("EGL context has been lost.");
         } else {
             NS_WARNING("Failed to make GL context current!");
 #ifdef DEBUG
             printf_stderr("EGL Error: 0x%04x\n", eglError);
 #endif
@@ -459,18 +450,17 @@ GLContextEGL::MakeCurrentImpl() const
     }
 
     return succeeded;
 }
 
 bool
 GLContextEGL::IsCurrentImpl() const
 {
-    auto* egl = gl::GLLibraryEGL::Get();
-    return egl->fGetCurrentContext() == mContext;
+    return mEgl->fGetCurrentContext() == mContext;
 }
 
 bool
 GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
     if (!mOwnsContext) {
         return false;
     }
     // unconditionally release the surface and create a new one. Don't try to optimize this away.
@@ -499,53 +489,48 @@ GLContextEGL::ReleaseSurface() {
         mSurfaceOverride = EGL_NO_SURFACE;
     }
     mSurface = EGL_NO_SURFACE;
 }
 
 bool
 GLContextEGL::SetupLookupFunction()
 {
-    auto* egl = gl::GLLibraryEGL::Get();
-
-    mLookupFunc = egl->GetLookupFunction();
+    mLookupFunc = mEgl->GetLookupFunction();
     return true;
 }
 
 bool
 GLContextEGL::SwapBuffers()
 {
-    auto* egl = gl::GLLibraryEGL::Get();
     EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
                           ? mSurfaceOverride
                           : mSurface;
     if (surface) {
-        return egl->fSwapBuffers(EGL_DISPLAY(), surface);
+        return mEgl->fSwapBuffers(EGL_DISPLAY(), surface);
     } else {
         return false;
     }
 }
 
 void
 GLContextEGL::GetWSIInfo(nsCString* const out) const
 {
-    auto* egl = gl::GLLibraryEGL::Get();
-
     out->AppendLiteral("EGL_VENDOR: ");
-    out->Append((const char*)egl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VENDOR));
+    out->Append((const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VENDOR));
 
     out->AppendLiteral("\nEGL_VERSION: ");
-    out->Append((const char*)egl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VERSION));
+    out->Append((const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VERSION));
 
     out->AppendLiteral("\nEGL_EXTENSIONS: ");
-    out->Append((const char*)egl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_EXTENSIONS));
+    out->Append((const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_EXTENSIONS));
 
 #ifndef ANDROID // This query will crash some old android.
     out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): ");
-    out->Append((const char*)egl->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS));
+    out->Append((const char*)mEgl->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS));
 #endif
 }
 
 // hold a reference to the given surface
 // for the lifetime of this context.
 void
 GLContextEGL::HoldSurface(gfxASurface* aSurf) {
     mThebesSurface = aSurf;
@@ -1206,14 +1191,18 @@ GLContextProviderEGL::CreateOffscreen(co
 GLContextProviderEGL::GetGlobalContext()
 {
     return nullptr;
 }
 
 /*static*/ void
 GLContextProviderEGL::Shutdown()
 {
+    const RefPtr<GLLibraryEGL> egl = GLLibraryEGL::Get();
+    if (egl) {
+        egl->Shutdown();
+    }
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
 
 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -371,16 +371,22 @@ GLLibraryEGL::EnsureInitialized(bool for
         sEGLLibrary = new GLLibraryEGL();
     }
     return sEGLLibrary->DoEnsureInitialized(forceAccel, out_failureId);
 }
 
 bool
 GLLibraryEGL::DoEnsureInitialized(bool forceAccel, nsACString* const out_failureId)
 {
+    if (mInitialized && !mSymbols.fTerminate) {
+        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_DESTROYED");
+        MOZ_ASSERT(false);
+        return false;
+    }
+
     if (mInitialized) {
         return true;
     }
 
     mozilla::ScopedGfxFeatureReporter reporter("EGL");
 
 #ifdef XP_WIN
     if (!mEGLLibrary) {
@@ -675,16 +681,30 @@ GLLibraryEGL::DoEnsureInitialized(bool f
     mInitialized = true;
     reporter.SetSuccessful();
     return true;
 }
 
 #undef SYMBOL
 #undef END_OF_SYMBOLS
 
+void
+GLLibraryEGL::Shutdown()
+{
+    if (this != sEGLLibrary) {
+        return;
+    }
+    if (mEGLDisplay) {
+        fTerminate(mEGLDisplay);
+        mEGLDisplay = EGL_NO_DISPLAY;
+    }
+    mSymbols = {};
+    sEGLLibrary = nullptr;
+}
+
 EGLDisplay
 GLLibraryEGL::CreateDisplay(bool forceAccel, const nsCOMPtr<nsIGfxInfo>& gfxInfo, nsACString* const out_failureId)
 {
     MOZ_ASSERT(!mInitialized);
 
     EGLDisplay chosenDisplay = nullptr;
 
     if (IsExtensionSupported(ANGLE_platform_angle_d3d)) {
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -372,16 +372,18 @@ public:
     bool ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface);
 
     inline static GLLibraryEGL* Get() {
         return sEGLLibrary;
     }
 
     static bool EnsureInitialized(bool forceAccel, nsACString* const out_failureId);
 
+    void Shutdown();
+
     void DumpEGLConfig(EGLConfig cfg);
     void DumpEGLConfigs();
 
 private:
     struct {
         EGLCastToRelevantPtr (GLAPIENTRY * fGetProcAddress)(const char* procname);
         EGLDisplay (GLAPIENTRY * fGetDisplay)(void* display_id);
         EGLDisplay (GLAPIENTRY * fGetPlatformDisplayEXT)(EGLenum platform,
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -6,16 +6,17 @@
 #ifdef XP_WIN
 #include "WMF.h"
 #endif
 #include "GPUParent.h"
 #include "gfxConfig.h"
 #include "gfxCrashReporterUtils.h"
 #include "gfxPlatform.h"
 #include "gfxPrefs.h"
+#include "GLContextProvider.h"
 #include "GPUProcessHost.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/MemoryReportRequest.h"
 #include "mozilla/dom/VideoDecoderManagerChild.h"
 #include "mozilla/dom/VideoDecoderManagerParent.h"
 #include "mozilla/gfx/2D.h"
@@ -493,16 +494,30 @@ GPUParent::ActorDestroy(ActorDestroyReas
   dom::VideoDecoderManagerParent::ShutdownVideoBridge();
   CompositorThreadHolder::Shutdown();
   VRListenerThreadHolder::Shutdown();
   // There is a case that RenderThread exists when gfxVars::UseWebRender() is false.
   // This could happen when WebRender was fallbacked to compositor.
   if (wr::RenderThread::Get()) {
     wr::RenderThread::ShutDown();
   }
+
+  // Shut down the default GL context provider.
+  gl::GLContextProvider::Shutdown();
+
+#if defined(XP_WIN)
+  // The above shutdown calls operate on the available context providers on
+  // most platforms.  Windows is a "special snowflake", though, and has three
+  // context providers available, so we have to shut all of them down.
+  // We should only support the default GL provider on Windows; then, this
+  // could go away. Unfortunately, we currently support WGL (the default) for
+  // WebGL on Optimus.
+  gl::GLContextProviderEGL::Shutdown();
+#endif
+
   Factory::ShutDown();
 #if defined(XP_WIN)
   DeviceManagerDx::Shutdown();
 #endif
   LayerTreeOwnerTracker::Shutdown();
   gfxVars::Shutdown();
   gfxConfig::Shutdown();
   gfxPrefs::DestroySingleton();