Bug 1259541 - Reduce clearing backbuffer in nsBaseWidget::CreateBackBufferDrawTarget() r=mattwoodrow
authorSotaro Ikeda <sotaro.ikeda.g@gmail.com>
Mon, 04 Apr 2016 18:25:04 -0700
changeset 347713 ab1e55d01de8dfc614e7a3d127c3add27beb030c
parent 347712 61c5789a67aee10a69947c83342aa1d5cd24b3a0
child 347714 5d3bd2e9a019c867294bdab5a31817d4de1287f3
push id14653
push userolivier@olivieryiptong.com
push dateTue, 05 Apr 2016 19:21:01 +0000
reviewersmattwoodrow
bugs1259541
milestone48.0a1
Bug 1259541 - Reduce clearing backbuffer in nsBaseWidget::CreateBackBufferDrawTarget() r=mattwoodrow
gfx/layers/Compositor.h
gfx/layers/basic/BasicCompositor.cpp
gfx/layers/basic/BasicCompositor.h
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/d3d11/CompositorD3D11.cpp
gfx/layers/d3d11/CompositorD3D11.h
gfx/layers/d3d9/CompositorD3D9.cpp
gfx/layers/d3d9/CompositorD3D9.h
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -366,17 +366,17 @@ public:
    * is returned empty, composition should be aborted.
    *
    * If aOpaque is true, then all of aInvalidRegion will be drawn to with
    * opaque content.
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect* aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect* aClipRectOut = nullptr,
                           gfx::Rect* aRenderBoundsOut = nullptr) = 0;
 
   /**
    * Flush the current frame to the screen and tidy up.
    */
   virtual void EndFrame() = 0;
 
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -155,43 +155,44 @@ BasicCompositor::CreateRenderTargetFromS
                                               const CompositingRenderTarget *aSource,
                                               const IntPoint &aSourcePoint)
 {
   MOZ_CRASH("GFX: Shouldn't be called!");
   return nullptr;
 }
 
 already_AddRefed<CompositingRenderTarget>
-BasicCompositor::CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect, SurfaceInitMode aInit, BufferMode aBufferMode)
+BasicCompositor::CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect, const LayoutDeviceIntRect& aClearRect, BufferMode aBufferMode)
 {
   MOZ_ASSERT(mDrawTarget);
   MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
 
   if (aRect.width * aRect.height == 0) {
     return nullptr;
   }
 
   RefPtr<BasicCompositingRenderTarget> rt;
   IntRect rect = aRect.ToUnknownRect();
 
   if (aBufferMode != BufferMode::BUFFER_NONE) {
-    RefPtr<DrawTarget> target = mWidget->CreateBackBufferDrawTarget(mDrawTarget, aRect, aInit == INIT_MODE_CLEAR);
+    RefPtr<DrawTarget> target = mWidget->CreateBackBufferDrawTarget(mDrawTarget, aRect, aClearRect);
     if (!target) {
       return nullptr;
     }
     rt = new BasicCompositingRenderTarget(target, rect);
   } else {
     IntRect windowRect = rect;
     // Adjust bounds rect to account for new origin at (0, 0).
     if (windowRect.Size() != mDrawTarget->GetSize()) {
       windowRect.ExpandToEnclose(IntPoint(0, 0));
     }
     rt = new BasicCompositingRenderTarget(mDrawTarget, windowRect);
-    if (aInit == INIT_MODE_CLEAR) {
-      mDrawTarget->ClearRect(Rect(rect - rt->GetOrigin()));
+    if (!aClearRect.IsEmpty()) {
+      IntRect clearRect = aRect.ToUnknownRect();
+      mDrawTarget->ClearRect(Rect(clearRect - rt->GetOrigin()));
     }
   }
 
   return rt.forget();
 }
 
 already_AddRefed<DataTextureSource>
 BasicCompositor::CreateDataTextureSource(TextureFlags aFlags)
@@ -469,17 +470,17 @@ BasicCompositor::ClearRect(const gfx::Re
 {
   mRenderTarget->mDrawTarget->ClearRect(aRect);
 }
 
 void
 BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
                             const gfx::Rect *aClipRectIn,
                             const gfx::Rect& aRenderBounds,
-                            bool aOpaque,
+                            const nsIntRegion& aOpaqueRegion,
                             gfx::Rect *aClipRectOut /* = nullptr */,
                             gfx::Rect *aRenderBoundsOut /* = nullptr */)
 {
   LayoutDeviceIntRect intRect(LayoutDeviceIntPoint(), mWidget->GetClientSize());
   Rect rect = Rect(0, 0, intRect.width, intRect.height);
 
   LayoutDeviceIntRegion invalidRegionSafe;
   if (mDidExternalComposition) {
@@ -517,21 +518,30 @@ BasicCompositor::BeginFrame(const nsIntR
       return;
     }
   }
 
   if (!mDrawTarget || mInvalidRect.IsEmpty()) {
     return;
   }
 
+  LayoutDeviceIntRect clearRect;
+  if (!aOpaqueRegion.IsEmpty()) {
+    LayoutDeviceIntRegion clearRegion = mInvalidRegion;
+    clearRegion.SubOut(LayoutDeviceIntRegion::FromUnknownRegion(aOpaqueRegion));
+    clearRect = clearRegion.GetBounds();
+  } else {
+    clearRect = mInvalidRect;
+  }
+
   // Setup an intermediate render target to buffer all compositing. We will
   // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
   RefPtr<CompositingRenderTarget> target =
     CreateRenderTargetForWindow(mInvalidRect,
-                                aOpaque ? INIT_MODE_NONE : INIT_MODE_CLEAR,
+                                clearRect,
                                 bufferMode);
   if (!target) {
     if (!mTarget) {
       mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
     }
     return;
   }
   SetRenderTarget(target);
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -59,17 +59,17 @@ public:
 
   virtual already_AddRefed<CompositingRenderTarget>
   CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                const CompositingRenderTarget *aSource,
                                const gfx::IntPoint &aSourcePoint) override;
 
   virtual already_AddRefed<CompositingRenderTarget>
   CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect,
-                              SurfaceInitMode aInit,
+                              const LayoutDeviceIntRect& aClearRect,
                               BufferMode aBufferMode);
 
   virtual already_AddRefed<DataTextureSource>
   CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override;
 
   virtual already_AddRefed<DataTextureSource>
   CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) override;
 
@@ -92,17 +92,17 @@ public:
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect) override;
 
   virtual void ClearRect(const gfx::Rect& aRect) override;
 
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
   virtual void EndFrame() override;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
 
   virtual bool SupportsPartialTextureUpdate() override { return true; }
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override { return true; }
   virtual int32_t GetMaxTextureSize() const override;
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -477,17 +477,17 @@ LayerManagerComposite::UpdateAndRender()
   InvalidateDebugOverlay(invalid, mRenderBounds);
 
   if (!didEffectiveTransforms) {
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
   }
 
-  Render(invalid);
+  Render(invalid, opaque);
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   RenderToPresentationSurface();
 #endif
   mGeometryChanged = false;
   mWindowOverlayChanged = false;
 
   // Update cached layer tree information.
   mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
@@ -809,17 +809,17 @@ ClearLayerFlags(Layer* aLayer) {
   }
   for (Layer* child = aLayer->GetFirstChild(); child;
        child = child->GetNextSibling()) {
     ClearLayerFlags(child);
   }
 }
 
 void
-LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
+LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion)
 {
   PROFILER_LABEL("LayerManagerComposite", "Render",
     js::ProfileEntry::Category::GRAPHICS);
 
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
@@ -895,24 +895,23 @@ LayerManagerComposite::Render(const nsIn
 
   ParentLayerIntRect clipRect;
   Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
   Rect actualBounds;
 
   CompositorBench(mCompositor, bounds);
 
   MOZ_ASSERT(mRoot->GetOpacity() == 1);
-  bool opaqueContent = (mRoot->GetContentFlags() & Layer::CONTENT_OPAQUE) != 0;
   if (mRoot->GetClipRect()) {
     clipRect = *mRoot->GetClipRect();
     Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
-    mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, opaqueContent, nullptr, &actualBounds);
+    mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion, nullptr, &actualBounds);
   } else {
     gfx::Rect rect;
-    mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, opaqueContent, &rect, &actualBounds);
+    mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, aOpaqueRegion, &rect, &actualBounds);
     clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
   }
 
   if (actualBounds.IsEmpty()) {
     mCompositor->GetWidget()->PostRender(this);
     return;
   }
 
@@ -1156,19 +1155,17 @@ LayerManagerComposite::RenderToPresentat
   nsIntRegion opaque;
   LayerIntRegion visible;
   PostProcessLayers(mRoot, opaque, visible, Nothing());
 
   nsIntRegion invalid;
   Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight);
   Rect rect, actualBounds;
   MOZ_ASSERT(mRoot->GetOpacity() == 1);
-  bool opaqueContent = (mRoot->GetContentFlags() & Layer::CONTENT_OPAQUE) != 0;
-
-  mCompositor->BeginFrame(invalid, nullptr, bounds, opaqueContent, &rect, &actualBounds);
+  mCompositor->BeginFrame(invalid, nullptr, bounds, nsIntRegion(), &rect, &actualBounds);
 
   // The Java side of Fennec sets a scissor rect that accounts for
   // chrome such as the URL bar. Override that so that the entire frame buffer
   // is cleared.
   ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight);
   egl->fClearColor(0.0, 0.0, 0.0, 0.0);
   egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -334,17 +334,17 @@ private:
   /**
    * Update the invalid region and render it.
    */
   void UpdateAndRender();
 
   /**
    * Render the current layer tree to the active target.
    */
-  void Render(const nsIntRegion& aInvalidRegion);
+  void Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion);
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   void RenderToPresentationSurface();
 #endif
 
   /**
    * We need to know our invalid region before we're ready to render.
    */
   void InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const gfx::IntRect& aBounds);
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1114,17 +1114,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
     mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
   }
 }
 
 void
 CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
                             const Rect* aClipRectIn,
                             const Rect& aRenderBounds,
-                            bool aOpaque,
+                            const nsIntRegion& aOpaqueRegion,
                             Rect* aClipRectOut,
                             Rect* aRenderBoundsOut)
 {
   // Don't composite if we are minimised. Other than for the sake of efficency,
   // this is important because resizing our buffers when mimised will fail and
   // cause a crash when we're restored.
   NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
   if (::IsIconic(mHwnd) || mDevice->GetDeviceRemovedReason() != S_OK) {
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -106,17 +106,17 @@ public:
 
   /**
    * Start a new frame. If aClipRectIn is null, sets *aClipRectOut to the
    * screen dimensions. 
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
 
   /**
    * Flush the current frame to the screen.
    */
   virtual void EndFrame() override;
 
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -675,17 +675,17 @@ CompositorD3D9::FailedToResetDevice() {
     gfxWarning() << "[D3D9] Unable to get a working D3D9 Compositor";
   }
 }
 
 void
 CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
                            const Rect *aClipRectIn,
                            const Rect& aRenderBounds,
-                           bool aOpaque,
+                           const nsIntRegion& aOpaqueRegion,
                            Rect *aClipRectOut,
                            Rect *aRenderBoundsOut)
 {
   MOZ_ASSERT(mDeviceManager && mSwapChain);
 
   mDeviceManager->SetupRenderState();
 
   EnsureSize();
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -59,17 +59,17 @@ public:
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect) override;
 
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
 
   virtual void EndFrame() override;
 
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override {}
 
   virtual void PrepareViewport(const gfx::IntSize& aSize);
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -626,17 +626,17 @@ CompositorOGL::ClearRect(const gfx::Rect
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 }
 
 void
 CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
                           const Rect *aClipRectIn,
                           const Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           Rect *aClipRectOut,
                           Rect *aRenderBoundsOut)
 {
   PROFILER_LABEL("CompositorOGL", "BeginFrame",
     js::ProfileEntry::Category::GRAPHICS);
 
   MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
 
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -397,17 +397,17 @@ private:
   virtual void ClearRect(const gfx::Rect& aRect) override;
 
   /* Start a new frame. If aClipRectIn is null and aClipRectOut is non-null,
    * sets *aClipRectOut to the screen dimensions.
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
 
   ShaderConfigOGL GetShaderConfigFor(Effect *aEffect,
                                      MaskType aMask = MaskType::MaskNone,
                                      gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER,
                                      bool aColorMatrix = false,
                                      bool aDEAAEnabled = false) const;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1365,34 +1365,35 @@ void
 nsBaseWidget::CleanupRemoteDrawing()
 {
   mLastBackBuffer = nullptr;
 }
 
 already_AddRefed<mozilla::gfx::DrawTarget>
 nsBaseWidget::CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget,
                                          const LayoutDeviceIntRect& aRect,
-                                         const bool aInitModeClear)
+                                         const LayoutDeviceIntRect& aClearRect)
 {
   MOZ_ASSERT(aScreenTarget);
   gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
   gfx::IntSize size = aRect.ToUnknownRect().Size();
   gfx::IntSize clientSize(GetClientSize().ToUnknownSize());
 
   RefPtr<gfx::DrawTarget> target;
   // Re-use back buffer if possible
   if (mLastBackBuffer &&
       mLastBackBuffer->GetBackendType() == aScreenTarget->GetBackendType() &&
       mLastBackBuffer->GetFormat() == format &&
       size <= mLastBackBuffer->GetSize() &&
       mLastBackBuffer->GetSize() <= clientSize) {
     target = mLastBackBuffer;
     target->SetTransform(gfx::Matrix());
-    if (aInitModeClear) {
-      target->ClearRect(gfx::Rect(0, 0, size.width, size.height));
+    if (!aClearRect.IsEmpty()) {
+      gfx::IntRect clearRect = aClearRect.ToUnknownRect() - aRect.ToUnknownRect().TopLeft();
+      target->ClearRect(gfx::Rect(clearRect.x, clearRect.y, clearRect.width, clearRect.height));
     }
   } else {
     target = aScreenTarget->CreateSimilarDrawTarget(size, format);
     mLastBackBuffer = target;
   }
   return target.forget();
 }
 
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -174,17 +174,17 @@ public:
   virtual void            PostRender(LayerManagerComposite* aManager) override {}
   virtual void            DrawWindowUnderlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {}
   virtual void            DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {}
   virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() override;
   virtual void            EndRemoteDrawing() override { };
   virtual void            CleanupRemoteDrawing() override;
   virtual already_AddRefed<mozilla::gfx::DrawTarget> CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget,
                                                                                 const LayoutDeviceIntRect& aRect,
-                                                                                const bool aInitModeClear) override;
+                                                                                const LayoutDeviceIntRect& aClearRect) override;
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override {}
   NS_IMETHOD              SetModal(bool aModal) override;
   virtual uint32_t        GetMaxTouchPoints() const override;
   NS_IMETHOD              SetWindowClass(const nsAString& xulWinType) override;
   virtual nsresult        SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects, bool aIntersectWithExisting) override;
   // Return whether this widget interprets parameters to Move and Resize APIs
   // as "desktop pixels" rather than "device pixels", and therefore
   // applies its GetDefaultScale() value to them before using them as mBounds
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1320,17 +1320,17 @@ class nsIWidget : public nsISupports {
      */
     virtual void CleanupRemoteDrawing() = 0;
 
     /**
      * Create DrawTarget used as BackBuffer of the screen
      */
     virtual already_AddRefed<mozilla::gfx::DrawTarget> CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget,
                                                                                   const LayoutDeviceIntRect& aRect,
-                                                                                  const bool aInitModeClear) = 0;
+                                                                                  const LayoutDeviceIntRect& aClearRect) = 0;
 
     /**
      * A hook for the widget to prepare a Compositor, during the latter's initialization.
      *
      * If this method returns true, it means that the widget will be able to
      * present frames from the compoositor.
      * Returning false will cause the compositor's initialization to fail, and
      * a different compositor backend will be used (if any).