Bug 1437886 - Prevent shared surfaces from being used without WebRender. r=nical
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 16 Feb 2018 09:50:40 -0500
changeset 404219 fa3b9f40e77b970992686c064a1a8c368eb8b5d5
parent 404218 45b2ae093db8ad9cf5186292b58dca1b5443b286
child 404220 c69ec6a80fa2eaa31ad6d69526a9371d7d576c70
push id33457
push userrgurzau@mozilla.com
push dateFri, 16 Feb 2018 22:09:48 +0000
treeherdermozilla-central@c4d818c13868 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1437886
milestone60.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 1437886 - Prevent shared surfaces from being used without WebRender. r=nical Move the initialization of SharedSurfacesParent from the compositor thread creation to mirror the other WebRender-specific components, such as the render thread creation. Now it will only be created if WebRender is in use. Also prevent shared surfaces from being used by the image frame allocator, even if image.mem.shared is set -- there is no purpose in allowing this at present. It was causing startup crashes for users who requested image.mem.shared and/or WebRender via gfx.webrender.all but did not actually get WebRender at all. Surfaces would get allocated in the shared memory, try to register themselves with the WR render thread, and then crash since that thread was never created.
gfx/config/gfxVars.h
gfx/ipc/GPUParent.cpp
gfx/layers/ipc/CompositorThread.cpp
gfx/layers/ipc/SharedSurfacesChild.cpp
gfx/thebes/gfxPlatform.cpp
image/VectorImage.cpp
image/imgFrame.cpp
--- a/gfx/config/gfxVars.h
+++ b/gfx/config/gfxVars.h
@@ -132,16 +132,22 @@ private:                                
   static DataType Get##CxxName##Default() {                     \
     return DefaultValue;                                        \
   }                                                             \
   VarImpl<DataType, Get##CxxName##Default> mVar##CxxName;       \
 public:                                                         \
   static const DataType& CxxName() {                            \
     return sInstance->mVar##CxxName.Get();                      \
   }                                                             \
+  static DataType Get##CxxName##OrDefault() {                   \
+    if (!sInstance) {                                           \
+      return DefaultValue;                                      \
+    }                                                           \
+    return sInstance->mVar##CxxName.Get();                      \
+  }                                                             \
   static void Set##CxxName(const DataType& aValue) {            \
     if (sInstance->mVar##CxxName.Set(aValue)) {                 \
       sInstance->NotifyReceivers(&sInstance->mVar##CxxName);    \
     }                                                           \
   }
 
   GFX_VARS_LIST(GFX_VAR_DECL)
 #undef GFX_VAR_DECL
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorManagerParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
 #include "mozilla/layers/UiCompositorControllerParent.h"
 #include "mozilla/layers/MemoryReportingMLGPU.h"
+#include "mozilla/layers/SharedSurfacesParent.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/HangDetails.h"
 #include "nsDebugImpl.h"
 #include "nsIGfxInfo.h"
 #include "nsThreadManager.h"
 #include "prenv.h"
 #include "ProcessUtils.h"
@@ -229,16 +230,17 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett
   }
 #endif
 
   // Make sure to do this *after* we update gfxVars above.
   if (gfxVars::UseWebRender()) {
     wr::WebRenderAPI::InitExternalLogHandler();
 
     wr::RenderThread::Start();
+    SharedSurfacesParent::Initialize();
   }
 
   VRManager::ManagerInit();
   // Send a message to the UI process that we're done.
   GPUDeviceData data;
   RecvGetDeviceStatus(&data);
   Unused << SendInitComplete(data);
 
@@ -460,16 +462,17 @@ GPUParent::ActorDestroy(ActorDestroyReas
     mVsyncBridge = nullptr;
   }
   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()) {
+    SharedSurfacesParent::Shutdown();
     wr::RenderThread::ShutDown();
 
     wr::WebRenderAPI::ShutdownExternalLogHandler();
   }
   Factory::ShutDown();
 #if defined(XP_WIN)
   DeviceManagerDx::Shutdown();
 #endif
--- a/gfx/layers/ipc/CompositorThread.cpp
+++ b/gfx/layers/ipc/CompositorThread.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "CompositorThread.h"
 #include "MainThreadUtils.h"
 #include "nsThreadUtils.h"
 #include "CompositorBridgeParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
-#include "mozilla/layers/SharedSurfacesParent.h"
 #include "mozilla/media/MediaSystemResourceService.h"
 
 namespace mozilla {
 
 namespace gfx {
 // See VRManagerChild.cpp
 void ReleaseVRManagerParentSingleton();
 } // namespace gfx
@@ -65,17 +64,16 @@ CompositorThreadHolder::~CompositorThrea
 /* static */ void
 CompositorThreadHolder::DestroyCompositorThread(base::Thread* aCompositorThread)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
 
   CompositorBridgeParent::Shutdown();
-  SharedSurfacesParent::Shutdown();
   delete aCompositorThread;
   sFinishedCompositorShutDown = true;
 }
 
 /* static */ base::Thread*
 CompositorThreadHolder::CreateCompositorThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -100,17 +98,16 @@ CompositorThreadHolder::CreateCompositor
   options.message_loop_type = MessageLoop::TYPE_UI;
 #endif
 
   if (!compositorThread->StartWithOptions(options)) {
     delete compositorThread;
     return nullptr;
   }
 
-  SharedSurfacesParent::Initialize();
   CompositorBridgeParent::Setup();
   ImageBridgeParent::Setup();
 
   return compositorThread;
 }
 
 void
 CompositorThreadHolder::Start()
--- a/gfx/layers/ipc/SharedSurfacesChild.cpp
+++ b/gfx/layers/ipc/SharedSurfacesChild.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SharedSurfacesChild.h"
 #include "SharedSurfacesParent.h"
 #include "CompositorManagerChild.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/SourceSurfaceSharedData.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/SystemGroup.h"        // for SystemGroup
 
 namespace mozilla {
 namespace layers {
@@ -187,17 +188,17 @@ SharedSurfacesChild::DestroySharedUserDa
 SharedSurfacesChild::ShareInternal(SourceSurfaceSharedData* aSurface,
                                    SharedUserData** aUserData)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aSurface);
   MOZ_ASSERT(aUserData);
 
   CompositorManagerChild* manager = CompositorManagerChild::GetInstance();
-  if (NS_WARN_IF(!manager || !manager->CanSend())) {
+  if (NS_WARN_IF(!manager || !manager->CanSend() || !gfxVars::UseWebRender())) {
     // We cannot try to share the surface, most likely because the GPU process
     // crashed. Ideally, we would retry when it is ready, but the handles may be
     // a scarce resource, which can cause much more serious problems if we run
     // out. Better to copy into a fresh buffer later.
     aSurface->FinishedSharing();
     return NS_ERROR_NOT_INITIALIZED;
   }
 
@@ -386,19 +387,23 @@ SharedSurfacesChild::Unshare(const wr::E
 
   CompositorManagerChild* manager = CompositorManagerChild::GetInstance();
   if (MOZ_UNLIKELY(!manager || !manager->CanSend())) {
     return;
   }
 
   if (manager->OtherPid() == base::GetCurrentProcId()) {
     // We are in the combined UI/GPU process. Call directly to it to remove its
-    // wrapper surface to free the underlying buffer.
-    MOZ_ASSERT(manager->OwnsExternalImageId(aId));
-    SharedSurfacesParent::RemoveSameProcess(aId);
+    // wrapper surface to free the underlying buffer, but only if the external
+    // image ID is owned by the manager. It can be different if the surface was
+    // last shared with the GPU process, which crashed several times, and its
+    // job was moved into the parent process.
+    if (manager->OwnsExternalImageId(aId)) {
+      SharedSurfacesParent::RemoveSameProcess(aId);
+    }
   } else if (manager->OwnsExternalImageId(aId)) {
     // Only attempt to release current mappings in the GPU process. It is
     // possible we had a surface that was previously shared, the GPU process
     // crashed / was restarted, and then we freed the surface. In that case
     // we know the mapping has already been freed.
     manager->SendRemoveSharedSurface(aId);
   }
 }
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/CompositorManagerChild.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/ISurfaceAllocator.h"     // for GfxMemoryImageReporter
+#include "mozilla/layers/SharedSurfacesParent.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/layers/PaintThread.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/gfx/GraphicsMessages.h"
 #include "mozilla/ClearOnShutdown.h"
@@ -1014,16 +1015,17 @@ gfxPlatform::InitLayersIPC()
 
   if (XRE_IsContentProcess()) {
     if (gfxVars::UseOMTP()) {
       layers::PaintThread::Start();
     }
   } else if (XRE_IsParentProcess()) {
     if (gfxVars::UseWebRender()) {
       wr::RenderThread::Start();
+      layers::SharedSurfacesParent::Initialize();
     }
 
     layers::CompositorThreadHolder::Start();
     gfx::VRListenerThreadHolder::Start();
   }
 }
 
 /* static */ void
@@ -1050,16 +1052,17 @@ gfxPlatform::ShutdownLayersIPC()
         layers::CompositorManagerChild::Shutdown();
         layers::ImageBridgeChild::ShutDown();
         // This has to happen after shutting down the child protocols.
         layers::CompositorThreadHolder::Shutdown();
         gfx::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()) {
+          layers::SharedSurfacesParent::Shutdown();
           wr::RenderThread::ShutDown();
 
           Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF);
         }
 
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -871,17 +871,17 @@ VectorImage::GetImageContainer(LayerMana
 
 //******************************************************************************
 NS_IMETHODIMP_(bool)
 VectorImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
                                              const IntSize& aSize,
                                              uint32_t aFlags)
 {
   if (mError || !mIsFullyLoaded || aSize.IsEmpty() ||
-      mHaveAnimations || !gfxVars::UseWebRender()) {
+      mHaveAnimations || !gfxVars::GetUseWebRenderOrDefault()) {
     return false;
   }
 
   int32_t maxTextureSize = aManager->GetMaxTextureSize();
   return aSize.width <= maxTextureSize &&
          aSize.height <= maxTextureSize;
 }
 
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -96,17 +96,18 @@ AllocateBufferForImage(const IntSize& si
     // use the heap. On the other platforms we do not have the file handle
     // problem, and additionally we may avoid a superfluous memset since the
     // volatile memory starts out as zero-filled.
     return Factory::CreateDataSourceSurfaceWithStride(size, format,
                                                       stride, false);
   }
 #endif
 
-  if (!aIsAnimated && gfxPrefs::ImageMemShared()) {
+  if (!aIsAnimated && gfxVars::GetUseWebRenderOrDefault()
+                   && gfxPrefs::ImageMemShared()) {
     RefPtr<SourceSurfaceSharedData> newSurf = new SourceSurfaceSharedData();
     if (newSurf->Init(size, stride, format)) {
       return newSurf.forget();
     }
   } else {
     RefPtr<SourceSurfaceVolatileData> newSurf= new SourceSurfaceVolatileData();
     if (newSurf->Init(size, stride, format)) {
       return newSurf.forget();