Fix resize jank on Linux with OMTC (bug 926618, r=mattwoodrow).
authorDavid Anderson <danderson@mozilla.com>
Mon, 21 Oct 2013 13:14:47 -0700
changeset 166370 110171f903b1fce098a2fb45ac5fbda1ed108e0d
parent 166369 3f03e8b077ca29eef3b7dbdf2fddfbd794cb88b7
child 166371 b1ce503713893db81a58156546d3d06b3e29066b
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs926618
milestone27.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
Fix resize jank on Linux with OMTC (bug 926618, r=mattwoodrow).
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientLayerManager.h
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
widget/gtk/nsWindow.cpp
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -38,16 +38,17 @@ namespace layers {
 ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
   : mPhase(PHASE_NONE)
   , mWidget(aWidget) 
   , mTargetRotation(ROTATION_0)
   , mRepeatTransaction(false)
   , mIsRepeatTransaction(false)
   , mTransactionIncomplete(false)
   , mCompositorMightResample(false)
+  , mNeedsComposite(false)
 {
   MOZ_COUNT_CTOR(ClientLayerManager);
 }
 
 ClientLayerManager::~ClientLayerManager()
 {
   mRoot = nullptr;
 
@@ -294,18 +295,19 @@ ClientLayerManager::FlushRendering()
 }
 
 void
 ClientLayerManager::ForwardTransaction()
 {
   mPhase = PHASE_FORWARD;
 
   // forward this transaction's changeset to our LayerManagerComposite
+  bool sent;
   AutoInfallibleTArray<EditReply, 10> replies;
-  if (HasShadowManager() && ShadowLayerForwarder::EndTransaction(&replies)) {
+  if (HasShadowManager() && ShadowLayerForwarder::EndTransaction(&replies, &sent)) {
     for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
       const EditReply& reply = replies[i];
 
       switch (reply.type()) {
       case EditReply::TOpContentBufferSwap: {
         MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
 
         const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
@@ -344,16 +346,20 @@ ClientLayerManager::ForwardTransaction()
         compositable->OnReplyTextureRemoved(rep.textureId());
         break;
       }
 
       default:
         NS_RUNTIMEABORT("not reached");
       }
     }
+
+    if (sent) {
+      mNeedsComposite = false;
+    }
   } else if (HasShadowManager()) {
     NS_WARNING("failed to forward Layers transaction");
   }
 
   mPhase = PHASE_NONE;
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -137,16 +137,22 @@ public:
 
 #ifdef DEBUG
   bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
   bool InDrawing() { return mPhase == PHASE_DRAWING; }
   bool InForward() { return mPhase == PHASE_FORWARD; }
 #endif
   bool InTransaction() { return mPhase != PHASE_NONE; }
 
+  void SetNeedsComposite(bool aNeedsComposite)
+  {
+    mNeedsComposite = aNeedsComposite;
+  }
+  bool NeedsComposite() const { return mNeedsComposite; }
+
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 
 private:
   /**
@@ -195,16 +201,17 @@ private:
   ScreenRotation mTargetRotation;
 
   // Used to repeat the transaction right away (to avoid rebuilding
   // a display list) to support progressive drawing.
   bool mRepeatTransaction;
   bool mIsRepeatTransaction;
   bool mTransactionIncomplete;
   bool mCompositorMightResample;
+  bool mNeedsComposite;
 };
 
 class ClientLayer : public ShadowableLayer
 {
 public:
   ClientLayer()
   {
     MOZ_COUNT_CTOR(ClientLayer);
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -462,18 +462,20 @@ void
 ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
                                  TextureClient* aTexture)
 {
   mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
                              aTexture->GetID()));
 }
 
 bool
-ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
+ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies, bool* aSent)
 {
+  *aSent = false;
+
   PROFILER_LABEL("ShadowLayerForwarder", "EndTranscation");
   RenderTraceScope rendertrace("Foward Transaction", "000091");
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
   NS_ABORT_IF_FALSE(!mTxn->Finished(), "forgot BeginTransaction?");
 
   DiagnosticTypes diagnostics = gfxPlatform::GetPlatform()->GetLayerDiagnosticTypes();
   if (mDiagnosticTypes != diagnostics) {
     mDiagnosticTypes = diagnostics;
@@ -577,16 +579,17 @@ ShadowLayerForwarder::EndTransaction(Inf
     MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
     RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
     if (!mShadowManager->SendUpdateNoSwap(cset, targetConfig, mIsFirstPaint)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
     }
   }
 
+  *aSent = true;
   mIsFirstPaint = false;
   MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
   return true;
 }
 
 bool
 ShadowLayerForwarder::AllocShmem(size_t aSize,
                                  ipc::SharedMemory::SharedMemoryType aType,
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -329,17 +329,17 @@ public:
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) MOZ_OVERRIDE;
 
   /**
    * End the current transaction and forward it to LayerManagerComposite.
    * |aReplies| are directions from the LayerManagerComposite to the
    * caller of EndTransaction().
    */
-  bool EndTransaction(InfallibleTArray<EditReply>* aReplies);
+  bool EndTransaction(InfallibleTArray<EditReply>* aReplies, bool* aSent);
 
   /**
    * Set an actor through which layer updates will be pushed.
    */
   void SetShadowManager(PLayerTransactionChild* aShadowManager)
   {
     mShadowManager = aShadowManager;
   }
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1975,20 +1975,27 @@ nsWindow::OnExposeEvent(cairo_t *cr)
     if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
         return FALSE;
 
     nsIWidgetListener *listener =
         mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
     if (!listener)
         return FALSE;
 
-    // Do an early async composite so that we at least have something on screen
-    // in the right place, even if the content is out of date.
-    if (GetLayerManager()->GetBackendType() == LAYERS_CLIENT && mCompositorParent) {
-        mCompositorParent->ScheduleRenderOnCompositorThread();
+    ClientLayerManager *clientLayers =
+        (GetLayerManager()->GetBackendType() == LAYERS_CLIENT)
+        ? static_cast<ClientLayerManager*>(GetLayerManager())
+        : nullptr;
+
+    if (clientLayers && mCompositorParent &&
+        !gdk_screen_is_composited(gdk_window_get_screen(mGdkWindow)))
+    {
+        // We need to paint to the screen even if nothing changed, since if we
+        // don't have a compositing window manager, our pixels could be stale.
+        clientLayers->SetNeedsComposite(true);
     }
 
     // Dispatch WillPaintWindow notification to allow scripts etc. to run
     // before we paint
     {
         listener->WillPaintWindow(this);
 
         // If the window has been destroyed during the will paint notification,
@@ -1999,16 +2006,21 @@ nsWindow::OnExposeEvent(cairo_t *cr)
         // Re-get the listener since the will paint notification might have
         // killed it.
         listener =
             mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
         if (!listener)
             return FALSE;
     }
 
+    if (clientLayers && mCompositorParent && clientLayers->NeedsComposite()) {
+        mCompositorParent->ScheduleRenderOnCompositorThread();
+        clientLayers->SetNeedsComposite(false);
+    }
+
 #if (MOZ_WIDGET_GTK == 2)
     GdkRectangle *rects;
     gint nrects;
     gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
     if (MOZ_UNLIKELY(!rects)) // OOM
         return FALSE;
 #else
 #ifdef cairo_copy_clip_rectangle_list