[iOS WebKit2] Flush RemoteLayerBackingStore contexts on a secondary queue
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 May 2014 20:56:37 +0000 (20:56 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 May 2014 20:56:37 +0000 (20:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=132667
<rdar://problem/15349483>

Reviewed by Darin Adler.

* Shared/mac/RemoteLayerBackingStore.h:
* Shared/mac/RemoteLayerBackingStore.mm:
(WebKit::RemoteLayerBackingStore::takeFrontContextPendingFlush):
(WebKit::RemoteLayerBackingStore::flush): Deleted.
Add takeFrontContextPendingFlush, which returns the painted-but-not-yet-flushed front context,
and drops our reference to it. This needs to be called on all backing store between paints.

* WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h:
(WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::hasFlushed):
* WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm:
(WebKit::RemoteLayerTreeDrawingArea::RemoteLayerTreeDrawingArea):
(WebKit::RemoteLayerTreeDrawingArea::~RemoteLayerTreeDrawingArea):
(WebKit::RemoteLayerTreeDrawingArea::flushLayers):
(WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::create):
(WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::BackingStoreFlusher):
(WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush):
(WebKit::flushBackingStoreChangesInTransaction): Deleted.
Flush backing store and send the layer tree commit to the UI process from a dispatch queue.
We will only ever have a single commit in flight at a time, and there's a new
RELEASE_ASSERT to ensure that is the case.
We package up the commit on the main thread; the queue calls CGContextFlush
on all of the newly painted contexts and then tosses the commit over to the UI process.
This is a win in many cases because the Web process main thread can go ahead
and do other non-painting tasks while the queue is blocked on painting.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@168493 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/Shared/mac/RemoteLayerBackingStore.h
Source/WebKit2/Shared/mac/RemoteLayerBackingStore.mm
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm

index a74cb234fbbfe685c6cc0fda6a453dccc125a49f..2f9989557fe244cd43f7c90f8a2ff46418021106 100644 (file)
@@ -1,3 +1,36 @@
+2014-05-08  Tim Horton  <timothy_horton@apple.com>
+
+        [iOS WebKit2] Flush RemoteLayerBackingStore contexts on a secondary queue
+        https://bugs.webkit.org/show_bug.cgi?id=132667
+        <rdar://problem/15349483>
+
+        Reviewed by Darin Adler.
+
+        * Shared/mac/RemoteLayerBackingStore.h:
+        * Shared/mac/RemoteLayerBackingStore.mm:
+        (WebKit::RemoteLayerBackingStore::takeFrontContextPendingFlush):
+        (WebKit::RemoteLayerBackingStore::flush): Deleted.
+        Add takeFrontContextPendingFlush, which returns the painted-but-not-yet-flushed front context,
+        and drops our reference to it. This needs to be called on all backing store between paints.
+
+        * WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h:
+        (WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::hasFlushed):
+        * WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm:
+        (WebKit::RemoteLayerTreeDrawingArea::RemoteLayerTreeDrawingArea):
+        (WebKit::RemoteLayerTreeDrawingArea::~RemoteLayerTreeDrawingArea):
+        (WebKit::RemoteLayerTreeDrawingArea::flushLayers):
+        (WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::create):
+        (WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::BackingStoreFlusher):
+        (WebKit::RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush):
+        (WebKit::flushBackingStoreChangesInTransaction): Deleted.
+        Flush backing store and send the layer tree commit to the UI process from a dispatch queue.
+        We will only ever have a single commit in flight at a time, and there's a new
+        RELEASE_ASSERT to ensure that is the case.
+        We package up the commit on the main thread; the queue calls CGContextFlush
+        on all of the newly painted contexts and then tosses the commit over to the UI process.
+        This is a win in many cases because the Web process main thread can go ahead
+        and do other non-painting tasks while the queue is blocked on painting.
+
 2014-05-08  Tim Horton  <timothy_horton@apple.com>
 
         [wk2] Don't use the XPC-based plugin process for Adobe Reader
index c0ada89a189a336b7eb1f3e42bb30b18b4ca49ce..39c91722b5fd79371483562f5c40def3ad655127 100644 (file)
@@ -81,7 +81,7 @@ public:
         return !!m_frontBuffer;
     }
 
-    void flush();
+    RetainPtr<CGContextRef> takeFrontContextPendingFlush();
 
     enum class Volatility {
         NonVolatile,
index 489eaf623303ef6f88e6005c9a49f94a91661b1f..9d8f0d5da9993ea0d88e2459922f51261097120a 100644 (file)
@@ -354,12 +354,9 @@ void RemoteLayerBackingStore::applyBackingStoreToLayer(CALayer *layer)
     layer.contents = (id)m_frontBuffer->makeCGImageCopy().get();
 }
 
-void RemoteLayerBackingStore::flush()
+RetainPtr<CGContextRef> RemoteLayerBackingStore::takeFrontContextPendingFlush()
 {
-    if (m_frontContextPendingFlush) {
-        CGContextFlush(m_frontContextPendingFlush.get());
-        m_frontContextPendingFlush = nullptr;
-    }
+    return std::move(m_frontContextPendingFlush);
 }
 
 #if USE(IOSURFACE)
index 141340d2877759e8924555407f7535f16a16b254..dcb6885665272a3dab2998de46b3fc27016dcc32 100644 (file)
 #include "GraphicsLayerCARemote.h"
 #include <WebCore/GraphicsLayerClient.h>
 #include <WebCore/Timer.h>
+#include <atomic>
+#include <dispatch/dispatch.h>
 #include <wtf/HashMap.h>
 
 namespace WebCore {
 class PlatformCALayer;
 }
 
+namespace IPC {
+class MessageEncoder;
+}
+
 namespace WebKit {
 
 class RemoteLayerTreeContext;
@@ -96,6 +102,23 @@ private:
 
     WebCore::TiledBacking* mainFrameTiledBacking() const;
 
+    class BackingStoreFlusher : public ThreadSafeRefCounted<BackingStoreFlusher> {
+    public:
+        static PassRefPtr<BackingStoreFlusher> create(IPC::Connection*, std::unique_ptr<IPC::MessageEncoder>, Vector<RetainPtr<CGContextRef>>);
+
+        void flush();
+        bool hasFlushed() const { return m_hasFlushed; }
+
+    private:
+        BackingStoreFlusher(IPC::Connection*, std::unique_ptr<IPC::MessageEncoder>, Vector<RetainPtr<CGContextRef>>);
+
+        RefPtr<IPC::Connection> m_connection;
+        std::unique_ptr<IPC::MessageEncoder> m_commitEncoder;
+        Vector<RetainPtr<CGContextRef>> m_contextsToFlush;
+
+        std::atomic<bool> m_hasFlushed;
+    };
+
     std::unique_ptr<RemoteLayerTreeContext> m_remoteLayerTreeContext;
     std::unique_ptr<WebCore::GraphicsLayer> m_rootLayer;
 
@@ -110,6 +133,9 @@ private:
 
     bool m_waitingForBackingStoreSwap;
     bool m_hadFlushDeferredWhileWaitingForBackingStoreSwap;
+
+    dispatch_queue_t m_commitQueue;
+    RefPtr<BackingStoreFlusher> m_pendingBackingStoreFlusher;
 };
 
 DRAWING_AREA_TYPE_CASTS(RemoteLayerTreeDrawingArea, type() == DrawingAreaTypeRemoteLayerTree);
index 98dc9b0e46942851006b600ed31eb8d36f8aa272..614966095c80502cc2244a0d9c51c3d6b15e9e28 100644 (file)
@@ -35,6 +35,7 @@
 #import "RemoteScrollingCoordinator.h"
 #import "RemoteScrollingCoordinatorTransaction.h"
 #import "WebPage.h"
+#import "WebProcess.h"
 #import <WebCore/Frame.h>
 #import <WebCore/FrameView.h>
 #import <WebCore/MainFrame.h>
@@ -64,10 +65,13 @@ RemoteLayerTreeDrawingArea::RemoteLayerTreeDrawingArea(WebPage* webPage, const W
 #if PLATFORM(IOS)
     webPage->corePage()->settings().setDelegatesPageScaling(true);
 #endif
+
+    m_commitQueue = dispatch_queue_create("com.apple.WebKit.WebContent.RemoteLayerTreeDrawingArea.CommitQueue", nullptr);
 }
 
 RemoteLayerTreeDrawingArea::~RemoteLayerTreeDrawingArea()
 {
+    dispatch_release(m_commitQueue);
 }
 
 void RemoteLayerTreeDrawingArea::setNeedsDisplay()
@@ -223,17 +227,6 @@ void RemoteLayerTreeDrawingArea::layerFlushTimerFired(WebCore::Timer<RemoteLayer
     flushLayers();
 }
 
-static void flushBackingStoreChangesInTransaction(RemoteLayerTreeTransaction& transaction)
-{
-    for (RefPtr<PlatformCALayerRemote> layer : transaction.changedLayers()) {
-        if (!layer->properties().changedProperties & RemoteLayerTreeTransaction::BackingStoreChanged)
-            return;
-
-        if (RemoteLayerBackingStore* backingStore = layer->properties().backingStore.get())
-            backingStore->flush();
-    }
-}
-
 void RemoteLayerTreeDrawingArea::flushLayers()
 {
     if (!m_rootLayer)
@@ -249,6 +242,8 @@ void RemoteLayerTreeDrawingArea::flushLayers()
         return;
     }
 
+    RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
+
     m_webPage->layoutIfNeeded();
 
     FloatRect visibleRect(FloatPoint(), m_viewSize);
@@ -268,21 +263,33 @@ void RemoteLayerTreeDrawingArea::flushLayers()
         toRemoteScrollingCoordinator(m_webPage->scrollingCoordinator())->buildTransaction(scrollingTransaction);
 #endif
 
-    // FIXME: Move flushing backing store and sending CommitLayerTree onto a background thread.
-    flushBackingStoreChangesInTransaction(layerTransaction);
-
     m_waitingForBackingStoreSwap = true;
-    m_webPage->send(Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree(layerTransaction, scrollingTransaction));
+
+    Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree message(layerTransaction, scrollingTransaction);
+    auto commitEncoder = std::make_unique<IPC::MessageEncoder>(Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::receiverName(), Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::name(), m_webPage->pageID());
+    commitEncoder->encode(message.arguments());
 
     bool hadAnyChangedBackingStore = false;
+    Vector<RetainPtr<CGContextRef>> contextsToFlush;
     for (auto& layer : layerTransaction.changedLayers()) {
-        if (layer->properties().changedProperties & RemoteLayerTreeTransaction::LayerChanges::BackingStoreChanged)
+        if (layer->properties().changedProperties & RemoteLayerTreeTransaction::LayerChanges::BackingStoreChanged) {
             hadAnyChangedBackingStore = true;
+            if (auto contextPendingFlush = layer->properties().backingStore->takeFrontContextPendingFlush())
+                contextsToFlush.append(contextPendingFlush);
+        }
+
         layer->didCommit();
     }
 
     if (hadAnyChangedBackingStore)
         m_remoteLayerTreeContext->backingStoreCollection().schedulePurgeabilityTimer();
+
+    RefPtr<BackingStoreFlusher> backingStoreFlusher = BackingStoreFlusher::create(WebProcess::shared().parentProcessConnection(), std::move(commitEncoder), std::move(contextsToFlush));
+    m_pendingBackingStoreFlusher = backingStoreFlusher;
+
+    dispatch_async(m_commitQueue, [backingStoreFlusher]{
+        backingStoreFlusher->flush();
+    });
 }
 
 void RemoteLayerTreeDrawingArea::didUpdate()
@@ -308,4 +315,28 @@ void RemoteLayerTreeDrawingArea::mainFrameContentSizeChanged(const IntSize& cont
     m_webPage->pageOverlayController().didChangeDocumentSize();
 }
 
+PassRefPtr<RemoteLayerTreeDrawingArea::BackingStoreFlusher> RemoteLayerTreeDrawingArea::BackingStoreFlusher::create(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
+{
+    return adoptRef(new RemoteLayerTreeDrawingArea::BackingStoreFlusher(connection, std::move(encoder), contextsToFlush));
+}
+
+RemoteLayerTreeDrawingArea::BackingStoreFlusher::BackingStoreFlusher(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
+    : m_connection(connection)
+    , m_commitEncoder(std::move(encoder))
+    , m_contextsToFlush(std::move(contextsToFlush))
+    , m_hasFlushed(false)
+{
+}
+
+void RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush()
+{
+    ASSERT(!m_hasFlushed);
+
+    for (auto& context : m_contextsToFlush)
+        CGContextFlush(context.get());
+
+    m_connection->sendMessage(std::move(m_commitEncoder));
+    m_hasFlushed = true;
+}
+
 } // namespace WebKit