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 439511 9c9d32068acf37740896df161189fb413ac169a2
parent 439510 e682824ac09e11bc6e3778f2e1aeb89dea4043bd
child 439512 2735d9fa61d7b0623b2a9c63cc68ff6b5ba83f7d
push id34777
push usernbeleuzu@mozilla.com
push dateThu, 04 Oct 2018 09:26:06 +0000
treeherdermozilla-central@f87eeba88f1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1494763
milestone64.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 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();