Bug 1494763 - Use a single shared GLContext in RenderThread when we support it. r=sotaro
authorDan Glastonbury <dan.glastonbury@gmail.com>
Thu, 04 Oct 2018 02:54:50 +0000
changeset 487892 9c9d32068acf37740896df161189fb413ac169a2
parent 487891 e682824ac09e11bc6e3778f2e1aeb89dea4043bd
child 487893 2735d9fa61d7b0623b2a9c63cc68ff6b5ba83f7d
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewerssotaro
bugs1494763
milestone64.0a1
Bug 1494763 - Use a single shared GLContext in RenderThread when we support it. r=sotaro Differential Revision: https://phabricator.services.mozilla.com/D7382
gfx/webrender_bindings/RenderCompositor.cpp
gfx/webrender_bindings/RenderCompositor.h
gfx/webrender_bindings/RenderCompositorANGLE.cpp
gfx/webrender_bindings/RenderCompositorANGLE.h
gfx/webrender_bindings/RenderThread.cpp
gfx/webrender_bindings/RenderThread.h
gfx/webrender_bindings/RendererOGL.cpp
--- a/gfx/webrender_bindings/RenderCompositor.cpp
+++ b/gfx/webrender_bindings/RenderCompositor.cpp
@@ -34,10 +34,16 @@ RenderCompositor::RenderCompositor(RefPt
   : mWidget(aWidget)
 {
 }
 
 RenderCompositor::~RenderCompositor()
 {
 }
 
+bool
+RenderCompositor::MakeCurrent()
+{
+  return gl()->MakeCurrent();
+}
+
 } // namespace wr
 } // namespace mozilla
--- a/gfx/webrender_bindings/RenderCompositor.h
+++ b/gfx/webrender_bindings/RenderCompositor.h
@@ -37,16 +37,18 @@ public:
 
   virtual bool BeginFrame() = 0;
   virtual void EndFrame() = 0;
   virtual void Pause() = 0;
   virtual bool Resume() = 0;
 
   virtual gl::GLContext* gl() const { return nullptr; }
 
+  virtual bool MakeCurrent();
+
   virtual bool UseANGLE() const { return false; }
 
   virtual bool UseDComp() const { return false; }
 
   virtual LayoutDeviceIntSize GetBufferSize() = 0;
 
   widget::CompositorWidget* GetWidget() const { return mWidget; }
 
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
@@ -88,16 +88,17 @@ RenderCompositorANGLE::SutdownEGLLibrary
   // since EGLDisplay uses DeviceManagerDx::mCompositorDevice on ANGLE WebRender use case.
   // EGLDisplay could be updated when Renderer count becomes 0.
   // It is ensured by GPUProcessManager during handling DeviceReset.
   // GPUChild::RecvNotifyDeviceReset() destroys all CompositorSessions before
   // re-creating them.
   if (device.get() != GetDeviceOfEGLDisplay() &&
       RenderThread::Get()->RendererCount() == 0) {
     // Shutdown GLLibraryEGL for updating EGLDisplay.
+    RenderThread::Get()->ClearSharedGL();
     egl->Shutdown();
   }
   return true;
 }
 
 bool
 RenderCompositorANGLE::Initialize()
 {
@@ -105,22 +106,17 @@ RenderCompositorANGLE::Initialize()
     gfxCriticalNote << "Waiting for handling device reset";
     return false;
   }
 
   // Update device if necessary.
   if (!SutdownEGLLibraryIfNecessary()) {
     return false;
   }
-
-  nsCString discardFailureId;
-  if (!gl::GLLibraryEGL::EnsureInitialized(/* forceAccel */ true, &discardFailureId)) {
-    gfxCriticalNote << "Failed to load EGL library: " << discardFailureId.get();
-    return false;
-  }
+  RenderThread::Get()->SharedGL();
 
   mDevice = GetDeviceOfEGLDisplay();
 
   if (!mDevice) {
     gfxCriticalNote << "[WR] failed to get compositor device.";
     return false;
   }
 
@@ -208,31 +204,16 @@ RenderCompositorANGLE::Initialize()
 
   mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(mDevice);
   if (!mSyncObject->Init()) {
     // Some errors occur. Clear the mSyncObject here.
     // Then, there will be no texture synchronization.
     return false;
   }
 
-  const auto flags = gl::CreateContextFlags::PREFER_ES3;
-
-  // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
-  // Instread we override it with EGLSurface of SwapChain's back buffer.
-  mGL = gl::GLContextProviderEGL::CreateHeadless(flags, &discardFailureId);
-  if (!mGL || !mGL->IsANGLE()) {
-    gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(mGL.get());
-    return false;
-  }
-
-  if (!mGL->MakeCurrent()) {
-    gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(mGL.get());
-    return false;
-  }
-
   // Force enable alpha channel to make sure ANGLE use correct framebuffer formart
   if (!gl::CreateConfig(&mEGLConfig, /* bpp */ 32, /* enableDepthBuffer */ true)) {
     gfxCriticalNote << "Failed to create EGLConfig for WebRender";
   }
   MOZ_ASSERT(mEGLConfig);
 
   if (!ResizeBufferIfNeeded()) {
     return false;
@@ -319,17 +300,17 @@ RenderCompositorANGLE::BeginFrame()
   }
 
   mWidget->AsWindows()->UpdateCompositorWndSizeIfNecessary();
 
   if (!ResizeBufferIfNeeded()) {
     return false;
   }
 
-  if (!mGL->MakeCurrent()) {
+  if (!MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current, can't draw.";
     return false;
   }
 
   if (mSyncObject) {
     if (!mSyncObject->Synchronize()) {
       // It's timeout or other error. Handle the device-reset here.
       RenderThread::Get()->HandleDeviceReset("SyncObject", /* aNotify */ true);
@@ -429,48 +410,53 @@ RenderCompositorANGLE::ResizeBufferIfNee
     pbuffer_attribs);
 
   EGLint err = egl->fGetError();
   if (err != LOCAL_EGL_SUCCESS) {
     gfxCriticalError() << "Failed to create Pbuffer of back buffer error: " << gfx::hexa(err) << " Size : " << size;
     return false;
   }
 
-  gl::GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(surface);
-
   mEGLSurface = surface;
   mBufferSize = Some(size);
 
   return true;
 }
 
 void
 RenderCompositorANGLE::DestroyEGLSurface()
 {
   auto* egl = gl::GLLibraryEGL::Get();
 
   // Release EGLSurface of back buffer before calling ResizeBuffers().
   if (mEGLSurface) {
-    gl::GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(EGL_NO_SURFACE);
+    gl::GLContextEGL::Cast(gl())->SetEGLSurfaceOverride(EGL_NO_SURFACE);
     egl->fDestroySurface(egl->Display(), mEGLSurface);
     mEGLSurface = nullptr;
   }
 }
 
 void
 RenderCompositorANGLE::Pause()
 {
 }
 
 bool
 RenderCompositorANGLE::Resume()
 {
   return true;
 }
 
+bool
+RenderCompositorANGLE::MakeCurrent()
+{
+  gl::GLContextEGL::Cast(gl())->SetEGLSurfaceOverride(mEGLSurface);
+  return gl()->MakeCurrent();
+}
+
 LayoutDeviceIntSize
 RenderCompositorANGLE::GetBufferSize()
 {
   MOZ_ASSERT(mBufferSize.isSome());
   if (mBufferSize.isNothing()) {
     return LayoutDeviceIntSize();
   }
   return mBufferSize.ref();
--- a/gfx/webrender_bindings/RenderCompositorANGLE.h
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
 #define MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
 
 #include "GLTypes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/webrender/RenderCompositor.h"
+#include "mozilla/webrender/RenderThread.h"
 
 struct ID3D11DeviceContext;
 struct ID3D11Device;
 struct ID3D11Query;
 struct IDCompositionDevice;
 struct IDCompositionTarget;
 struct IDCompositionVisual;
 struct IDXGIFactory2;
@@ -33,34 +34,35 @@ public:
   virtual ~RenderCompositorANGLE();
   bool Initialize();
 
   bool BeginFrame() override;
   void EndFrame() override;
   void Pause() override;
   bool Resume() override;
 
-  gl::GLContext* gl() const override { return mGL; }
+  gl::GLContext* gl() const override { return RenderThread::Get()->SharedGL(); }
+
+  bool MakeCurrent() override;
 
   bool UseANGLE() const override { return true; }
 
   bool UseDComp() const override { return !!mCompositionDevice; }
 
   LayoutDeviceIntSize GetBufferSize() override;
 
 protected:
   void InsertPresentWaitQuery();
   void WaitForPreviousPresentQuery();
   bool ResizeBufferIfNeeded();
   void DestroyEGLSurface();
   ID3D11Device* GetDeviceOfEGLDisplay();
   void CreateSwapChainForDCompIfPossible(IDXGIFactory2* aDXGIFactory2);
   bool SutdownEGLLibraryIfNecessary();
 
-  RefPtr<gl::GLContext> mGL;
   EGLConfig mEGLConfig;
   EGLSurface mEGLSurface;
 
   RefPtr<ID3D11Device> mDevice;
   RefPtr<ID3D11DeviceContext> mCtx;
   RefPtr<IDXGISwapChain> mSwapChain;
 
   RefPtr<IDCompositionDevice> mCompositionDevice;
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -17,19 +17,24 @@
 #include "mozilla/layers/SharedSurfacesParent.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/webrender/RendererOGL.h"
 #include "mozilla/webrender/RenderTextureHost.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 #ifdef XP_WIN
+#include "GLLibraryEGL.h"
 #include "mozilla/widget/WinCompositorWindowThread.h"
 #endif
 
+using namespace mozilla;
+
+static already_AddRefed<gl::GLContext> CreateGLContext();
+
 namespace mozilla {
 namespace wr {
 
 static StaticRefPtr<RenderThread> sRenderThread;
 
 RenderThread::RenderThread(base::Thread* aThread)
   : mThread(aThread)
   , mFrameCountMapLock("RenderThread.mFrameCountMapLock")
@@ -71,16 +76,21 @@ RenderThread::Start()
   }
 
   sRenderThread = new RenderThread(thread);
 #ifdef XP_WIN
   widget::WinCompositorWindowThread::Start();
 #endif
   layers::SharedSurfacesParent::Initialize();
 
+  RefPtr<Runnable> runnable = WrapRunnable(
+    RefPtr<RenderThread>(sRenderThread.get()),
+    &RenderThread::InitSharedGLContext);
+  sRenderThread->Loop()->PostTask(runnable.forget());
+
   if (XRE_IsGPUProcess() &&
       gfx::gfxVars::UseWebRenderProgramBinary()) {
     MOZ_ASSERT(gfx::gfxVars::UseWebRender());
     // Initialize program cache if necessary
     RefPtr<Runnable> runnable = WrapRunnable(
       RefPtr<RenderThread>(sRenderThread.get()),
       &RenderThread::ProgramCacheTask);
     sRenderThread->Loop()->PostTask(runnable.forget());
@@ -121,16 +131,17 @@ RenderThread::ShutDownTask(layers::Synch
   layers::AutoCompleteTask complete(aTask);
   MOZ_ASSERT(IsInRenderThread());
 
   // Releasing on the render thread will allow us to avoid dispatching to remove
   // remaining textures from the texture map.
   layers::SharedSurfacesParent::Shutdown();
 
   ClearAllBlobImageResources();
+  ClearSharedGL();
 }
 
 // static
 MessageLoop*
 RenderThread::Loop()
 {
   return sRenderThread ? sRenderThread->mThread->message_loop() : nullptr;
 }
@@ -716,16 +727,43 @@ RenderThread::ProgramCache()
   MOZ_ASSERT(IsInRenderThread());
 
   if (!mProgramCache) {
     mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
   }
   return mProgramCache.get();
 }
 
+void
+RenderThread::InitSharedGLContext()
+{
+  MOZ_ASSERT(IsInRenderThread());
+
+  if (!mSharedGL) {
+    mSharedGL = CreateGLContext();
+  }
+}
+
+gl::GLContext*
+RenderThread::SharedGL()
+{
+  MOZ_ASSERT(IsInRenderThread());
+  InitSharedGLContext();
+
+  return mSharedGL.get();
+}
+
+void
+RenderThread::ClearSharedGL()
+{
+  MOZ_ASSERT(IsInRenderThread());
+  mSharedGL = nullptr;
+}
+
+
 WebRenderThreadPool::WebRenderThreadPool()
 {
   mThreadPool = wr_thread_pool_new();
 }
 
 WebRenderThreadPool::~WebRenderThreadPool()
 {
   wr_thread_pool_delete(mThreadPool);
@@ -746,16 +784,59 @@ WebRenderProgramCache::WebRenderProgramC
 WebRenderProgramCache::~WebRenderProgramCache()
 {
   wr_program_cache_delete(mProgramCache);
 }
 
 } // namespace wr
 } // namespace mozilla
 
+#ifdef XP_WIN
+static already_AddRefed<gl::GLContext>
+CreateGLContextANGLE()
+{
+  nsCString discardFailureId;
+  if (!gl::GLLibraryEGL::EnsureInitialized(/* forceAccel */ true, &discardFailureId)) {
+    gfxCriticalNote << "Failed to load EGL library: " << discardFailureId.get();
+    return nullptr;
+  }
+
+  auto* egl = gl::GLLibraryEGL::Get();
+  auto flags = gl::CreateContextFlags::PREFER_ES3;
+
+  // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
+  // Instread we override it with EGLSurface of SwapChain's back buffer.
+  RefPtr<gl::GLContext> gl = gl::GLContextProviderEGL::CreateHeadless(flags, &discardFailureId);
+  if (!gl || !gl->IsANGLE()) {
+    gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(gl.get());
+    return nullptr;
+  }
+
+  if (!gl->MakeCurrent()) {
+    gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(gl.get());
+    return nullptr;
+  }
+
+  return gl.forget();
+}
+#endif
+
+static already_AddRefed<gl::GLContext>
+CreateGLContext()
+{
+#ifdef XP_WIN
+  if (gfx::gfxVars::UseWebRenderANGLE()) {
+    return CreateGLContextANGLE();
+  }
+#endif
+  // We currently only support a shared GLContext
+  // with ANGLE.
+  return nullptr;
+}
+
 extern "C" {
 
 static void HandleFrame(mozilla::wr::WrWindowId aWindowId, bool aRender)
 {
   mozilla::wr::RenderThread::Get()->IncRenderingFrameCount(aWindowId);
   mozilla::wr::RenderThread::Get()->HandleFrame(aWindowId, aRender);
 }
 
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -14,16 +14,17 @@
 #include "nsISupportsImpl.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/layers/SynchronousTask.h"
+#include "GLContext.h"
 
 #include <list>
 #include <queue>
 #include <unordered_map>
 
 namespace mozilla {
 namespace wr {
 
@@ -175,16 +176,23 @@ public:
 
   /// Can be called from any thread.
   WebRenderThreadPool& ThreadPool() { return mThreadPool; }
 
   /// Can only be called from the render thread.
   WebRenderProgramCache* ProgramCache();
 
   /// Can only be called from the render thread.
+  void InitSharedGLContext();
+  /// Can only be called from the render thread.
+  gl::GLContext* SharedGL();
+
+  void ClearSharedGL();
+
+  /// Can only be called from the render thread.
   void HandleDeviceReset(const char* aWhere, bool aNotify);
   /// Can only be called from the render thread.
   bool IsHandlingDeviceReset();
   /// Can be called from any thread.
   void SimulateDeviceReset();
 
   size_t RendererCount();
 
@@ -199,16 +207,20 @@ private:
 
   ~RenderThread();
 
   base::Thread* const mThread;
 
   WebRenderThreadPool mThreadPool;
   UniquePtr<WebRenderProgramCache> mProgramCache;
 
+  // An optional shared GLContext to be used for all
+  // windows.
+  RefPtr<gl::GLContext> mSharedGL;
+
   std::map<wr::WindowId, UniquePtr<RendererOGL>> mRenderers;
 
   struct WindowInfo {
     bool mIsDestroyed = false;
     int64_t mPendingCount = 0;
     int64_t mRenderingCount = 0;
     // One entry in this queue for each pending frame, so the length
     // should always equal mPendingCount
--- a/gfx/webrender_bindings/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -62,17 +62,17 @@ RendererOGL::RendererOGL(RefPtr<RenderTh
   MOZ_ASSERT(mRenderer);
   MOZ_ASSERT(mBridge);
   MOZ_COUNT_CTOR(RendererOGL);
 }
 
 RendererOGL::~RendererOGL()
 {
   MOZ_COUNT_DTOR(RendererOGL);
-  if (!mCompositor->gl()->MakeCurrent()) {
+  if (!mCompositor->MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current during destroying.";
     // Leak resources!
     return;
   }
   wr_renderer_delete(mRenderer);
 }
 
 wr::WrExternalImageHandler
@@ -89,17 +89,17 @@ void
 RendererOGL::Update()
 {
   uint32_t flags = gfx::gfxVars::WebRenderDebugFlags();
   if (mDebugFlags.mBits != flags) {
     mDebugFlags.mBits = flags;
     wr_renderer_set_debug_flags(mRenderer, mDebugFlags);
   }
 
-  if (gl()->MakeCurrent()) {
+  if (mCompositor->MakeCurrent()) {
     wr_renderer_update(mRenderer);
   }
 }
 
 static void
 DoNotifyWebRenderContextPurge(layers::CompositorBridgeParent* aBridge)
 {
   aBridge->NotifyWebRenderContextPurge();