Bug 1469496 - Handle video memory purge with WebRender. r=sotaro
authorNicolas Silva <nsilva@mozilla.com>
Fri, 10 Aug 2018 17:14:57 +0200
changeset 431010 402e309359419e325967c42a51beeb97eb0971b9
parent 431009 0386ff1e9956566b5ca1b5674af24ac40f4298ed
child 431011 287b6b052c20c5a0d38f9e6a99ac6c386ac88e93
push id34419
push userbtara@mozilla.com
push dateSat, 11 Aug 2018 03:43:33 +0000
treeherdermozilla-central@7ed5ed3d4814 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1469496
milestone63.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 1469496 - Handle video memory purge with WebRender. r=sotaro
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/webrender_bindings/RendererOGL.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi_generated.h
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -2349,16 +2349,24 @@ CompositorBridgeParent::IsSameProcess() 
 
 void
 CompositorBridgeParent::NotifyWebRenderError(wr::WebRenderError aError)
 {
   MOZ_ASSERT(CompositorLoop() == MessageLoop::current());
   Unused << SendNotifyWebRenderError(aError);
 }
 
+void
+CompositorBridgeParent::NotifyWebRenderContextPurge()
+{
+  MOZ_ASSERT(CompositorLoop() == MessageLoop::current());
+  RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
+  api->ClearAllCaches();
+}
+
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 //#define PLUGINS_LOG(...) printf_stderr("CP [%s]: ", __FUNCTION__);
 //                         printf_stderr(__VA_ARGS__);
 //                         printf_stderr("\n");
 #define PLUGINS_LOG(...)
 
 bool
 CompositorBridgeParent::UpdatePluginWindowState(LayersId aId)
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -269,16 +269,17 @@ public:
                                       const LayersId& aId,
                                       const uint64_t& aSerial,
                                       const wr::MaybeExternalImageId& aExternalImageId) override;
   bool DeallocPTextureParent(PTextureParent* actor) override;
 
   bool IsSameProcess() const override;
 
   void NotifyWebRenderError(wr::WebRenderError aError);
+  void NotifyWebRenderContextPurge();
   void NotifyPipelineRendered(const wr::PipelineId& aPipelineId,
                               const wr::Epoch& aEpoch,
                               TimeStamp& aCompositeStart,
                               TimeStamp& aCompositeEnd);
   RefPtr<AsyncImagePipelineManager> GetAsyncImagePipelineManager() const;
 
   PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override;
   bool DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor) override;
--- a/gfx/webrender_bindings/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -90,16 +90,22 @@ RendererOGL::Update()
     wr_renderer_set_debug_flags(mRenderer, mDebugFlags);
   }
 
   if (gl()->MakeCurrent()) {
     wr_renderer_update(mRenderer);
   }
 }
 
+static void
+DoNotifyWebRenderContextPurge(layers::CompositorBridgeParent* aBridge)
+{
+  aBridge->NotifyWebRenderContextPurge();
+}
+
 bool
 RendererOGL::UpdateAndRender(bool aReadback)
 {
   uint32_t flags = gfx::gfxVars::WebRenderDebugFlags();
   // Disable debug flags during readback
   if (aReadback) {
     flags = 0;
   }
@@ -145,16 +151,28 @@ RendererOGL::UpdateAndRender(bool aReadb
   if (mFrameStartTime) {
     uint32_t latencyMs = round((TimeStamp::Now() - mFrameStartTime).ToMilliseconds());
     printf_stderr("generate frame latencyMs latencyMs %d\n", latencyMs);
   }
   // Clear frame start time
   mFrameStartTime = TimeStamp();
 #endif
 
+  gl::GLContext* gl = mCompositor->gl();
+  if (gl->IsSupported(gl::GLFeature::robustness)) {
+    GLenum resetStatus = gl->fGetGraphicsResetStatus();
+    if (resetStatus == LOCAL_GL_PURGED_CONTEXT_RESET_NV) {
+      layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
+        "DoNotifyWebRenderContextPurgeRunnable",
+        &DoNotifyWebRenderContextPurge,
+        mBridge
+      ));
+    }
+  }
+
   // TODO: Flush pending actions such as texture deletions/unlocks and
   //       textureHosts recycling.
 
   return true;
 }
 
 void
 RendererOGL::Pause()
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -418,16 +418,22 @@ WebRenderAPI::Readback(const TimeStamp& 
     // read-back event. Then, we could make sure this read-back event gets the
     // latest result.
     RunOnRenderThread(std::move(event));
 
     task.Wait();
 }
 
 void
+WebRenderAPI::ClearAllCaches()
+{
+  wr_api_clear_all_caches(mDocHandle);
+}
+
+void
 WebRenderAPI::Pause()
 {
     class PauseEvent : public RendererEvent
     {
         public:
             explicit PauseEvent(layers::SynchronousTask* aTask)
                 : mTask(aTask)
             {
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -193,16 +193,18 @@ public:
   void SendTransaction(TransactionBuilder& aTxn);
 
   void SetFrameStartTime(const TimeStamp& aTime);
 
   void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
 
   void Readback(const TimeStamp& aStartTime, gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);
 
+  void ClearAllCaches();
+
   void Pause();
   bool Resume();
 
   void WakeSceneBuilder();
   void FlushSceneBuilder();
 
   wr::WrIdNamespace GetNamespace();
   uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1024,16 +1024,22 @@ pub unsafe extern "C" fn wr_api_delete(d
 }
 
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
 pub unsafe extern "C" fn wr_api_shut_down(dh: &mut DocumentHandle) {
     dh.api.shut_down();
 }
 
+/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
+#[no_mangle]
+pub unsafe extern "C" fn wr_api_clear_all_caches(dh: &mut DocumentHandle) {
+    dh.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all()));
+}
+
 fn make_transaction(do_async: bool) -> Transaction {
     let mut transaction = Transaction::new();
     // Ensure that we either use async scene building or not based on the
     // gecko pref, regardless of what the default is. We can remove this once
     // the scene builder thread is enabled everywhere and working well.
     if do_async {
         transaction.use_scene_builder_thread();
     } else {
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -1046,16 +1046,20 @@ WR_FUNC;
 
 WR_INLINE
 void wr_api_capture(DocumentHandle *aDh,
                     const char *aPath,
                     uint32_t aBitsRaw)
 WR_FUNC;
 
 WR_INLINE
+void wr_api_clear_all_caches(DocumentHandle *aDh)
+WR_DESTRUCTOR_SAFE_FUNC;
+
+WR_INLINE
 void wr_api_clone(DocumentHandle *aDh,
                   DocumentHandle **aOutHandle)
 WR_FUNC;
 
 WR_INLINE
 void wr_api_create_document(DocumentHandle *aRootDh,
                             DocumentHandle **aOutHandle,
                             DeviceUintSize aDocSize,