Remote Layer Tree: Double-buffering and minimization of repaints
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Oct 2013 00:51:07 +0000 (00:51 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Oct 2013 00:51:07 +0000 (00:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123043

Reviewed by Simon Fraser.

No new tests, not yet testable.

* WebProcess/WebPage/mac/PlatformCALayerRemote.cpp:
(PlatformCALayerRemote::ensureBackingStore):
Don't worry about isOpaque with RemoteLayerBackingStore; this is a
optimization that is causing trouble; we can re-add it later.

(PlatformCALayerRemote::setBounds):
Make sure that we will repaint if our bounds change.

* WebProcess/WebPage/mac/RemoteLayerBackingStore.h:
(WebKit::RemoteLayerBackingStore::bitmap):
Keep a front and back buffer; return the front buffer when being asked for the bitmap.
Keep a Region of repaint areas.

* WebProcess/WebPage/mac/RemoteLayerBackingStore.mm:
(RemoteLayerBackingStore::RemoteLayerBackingStore):
(RemoteLayerBackingStore::encode):
(RemoteLayerBackingStore::decode):
Serialize only the front buffer, since the UI process only needs that.

(RemoteLayerBackingStore::setNeedsDisplay):
Store repaint rects instead of always setting the whole layer to be dirty.

(RemoteLayerBackingStore::display):
Paint into the back buffer (copying valid parts over from the front buffer),
then swap it to the front buffer. Use drawLayerContents so we get repaint counters, etc.

* WebCore.exp.in:
Export one version of drawLayerContents and Region::contains.

* WebCore.xcodeproj/project.pbxproj:
Expose WebLayer.h as a private header.

* platform/graphics/mac/WebLayer.h:
Clean up this header, and add a new drawLayerContents that can operate without a CALayer.

* platform/graphics/mac/WebLayer.mm:
(WebCore::drawLayerContents):
Split drawLayerContents into one method that acquires properties CALayer,
and one that just does the painting.

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

Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/mac/WebLayer.h
Source/WebCore/platform/graphics/mac/WebLayer.mm
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/WebPage/mac/PlatformCALayerRemote.cpp
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerBackingStore.h
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerBackingStore.mm

index f68e059c4f0b982d8e037b6feda429493220f074..a0808f62f381abb83e37c58492b1d63d8563d2cf 100644 (file)
@@ -1,3 +1,26 @@
+2013-10-18  Tim Horton  <timothy_horton@apple.com>
+
+        Remote Layer Tree: Double-buffering and minimization of repaints
+        https://bugs.webkit.org/show_bug.cgi?id=123043
+
+        Reviewed by Simon Fraser.
+
+        No new tests, not yet testable.
+
+        * WebCore.exp.in:
+        Export one version of drawLayerContents and Region::contains.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        Expose WebLayer.h as a private header.
+
+        * platform/graphics/mac/WebLayer.h:
+        Clean up this header, and add a new drawLayerContents that can operate without a CALayer.
+
+        * platform/graphics/mac/WebLayer.mm:
+        (WebCore::drawLayerContents):
+        Split drawLayerContents into one method that acquires properties CALayer,
+        and one that just does the painting.
+
 2013-10-18  Anders Carlsson  <andersca@apple.com>
 
         Try to fix the Lion build.
index c900e9a5e2c67d9d92990df5016b73d40d0ad762..13b86ef43500b46b3146a73d15a60f062a3fdc60 100644 (file)
@@ -676,6 +676,7 @@ __ZN7WebCore17SQLiteTransactionC1ERNS_14SQLiteDatabaseEb
 __ZN7WebCore17SQLiteTransactionD1Ev
 __ZN7WebCore17SubresourceLoader6createEPNS_5FrameEPNS_14CachedResourceERKNS_15ResourceRequestERKNS_21ResourceLoaderOptionsE
 __ZN7WebCore17cacheDOMStructureEPNS_17JSDOMGlobalObjectEPN3JSC9StructureEPKNS2_9ClassInfoE
+__ZN7WebCore17drawLayerContentsEP9CGContextPNS_15PlatformCALayerENS_9FloatRectEN3WTF6VectorIS4_Lm5ENS5_15CrashOnOverflowEEEb
 __ZN7WebCore17languageDidChangeEv
 __ZN7WebCore17openTemporaryFileERKN3WTF6StringERi
 __ZN7WebCore17setCookiesFromDOMERKNS_21NetworkStorageSessionERKNS_3URLES5_RKN3WTF6StringE
@@ -1708,6 +1709,8 @@ __ZNK7WebCore6Editor8canPasteEv
 __ZNK7WebCore6Editor9canDeleteEv
 __ZNK7WebCore6Length22decrementCalculatedRefEv
 __ZNK7WebCore6Region5rectsEv
+__ZNK7WebCore6Region8containsERKS0_
+__ZNK7WebCore6Region9totalAreaEv
 __ZNK7WebCore6Widget14platformWidgetEv
 __ZNK7WebCore6Widget23convertToContainingViewERKNS_7IntRectE
 __ZNK7WebCore6Widget23convertToContainingViewERKNS_8IntPointE
index d0a94fe4ff52e663a01d49ddc0ee5646126e7c58..03b6e110a88ce375216224ef3ae2df29dd25adff 100644 (file)
                0FCF332C0F2B9A25004B6795 /* WebTiledLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FCF33280F2B9A25004B6795 /* WebTiledLayer.mm */; };
                0FCF332D0F2B9A25004B6795 /* WebTiledLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCF33290F2B9A25004B6795 /* WebTiledLayer.h */; };
                0FCF332E0F2B9A25004B6795 /* WebLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FCF332A0F2B9A25004B6795 /* WebLayer.mm */; };
-               0FCF332F0F2B9A25004B6795 /* WebLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCF332B0F2B9A25004B6795 /* WebLayer.h */; };
+               0FCF332F0F2B9A25004B6795 /* WebLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCF332B0F2B9A25004B6795 /* WebLayer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FD3080E117CF7E700A791F7 /* RenderFrameBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD3080C117CF7E700A791F7 /* RenderFrameBase.cpp */; };
                0FD3080F117CF7E700A791F7 /* RenderFrameBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD3080D117CF7E700A791F7 /* RenderFrameBase.h */; };
                0FD308D5117D168500A791F7 /* RenderIFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD308D3117D168400A791F7 /* RenderIFrame.cpp */; };
index 65569ce5a88cd33278b94712a692f6659b4749a3..4e8a3ec158c7b835fb17cd08398f95b04849cf9e 100644 (file)
 #if USE(ACCELERATED_COMPOSITING)
 
 #import <QuartzCore/QuartzCore.h>
+#import <WebCore/FloatRect.h>
+#import <wtf/Vector.h>
 
-namespace WebCore {
-    class GraphicsLayer;
-    class PlatformCALayer;
-    class PlatformCALayerClient;
-}
+const unsigned webLayerMaxRectsToPaint = 5;
+const float webLayerWastedSpaceThreshold = 0.75f;
 
-@interface WebLayer : CALayer 
-{
-}
+@interface WebLayer : CALayer
 @end
 
+namespace WebCore {
+class GraphicsLayer;
+class PlatformCALayer;
+class PlatformCALayerClient;
+
 // Functions allows us to share implementation across WebTiledLayer and WebLayer
 void drawLayerContents(CGContextRef, CALayer *, WebCore::PlatformCALayer*);
+void drawLayerContents(CGContextRef, WebCore::PlatformCALayer*, WebCore::FloatRect layerBounds, Vector<WebCore::FloatRect, webLayerMaxRectsToPaint> dirtyRects, bool isTiledLayer);
+}
 
 #endif // USE(ACCELERATED_COMPOSITING)
 
index 065a8f7e97ddbbd3dd971b8efbf444f0872d00bc..0d6b1fa34d27bb74dc9446213349a166749a5b25 100644 (file)
 
 using namespace WebCore;
 
-@implementation WebLayer
+namespace WebCore {
 
 void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCALayer* platformLayer)
+{
+    CGRect layerBounds = [layer bounds];
+
+    __block double totalRectArea = 0;
+    __block unsigned rectCount = 0;
+    __block Vector<FloatRect, webLayerMaxRectsToPaint> dirtyRects;
+
+    wkCALayerEnumerateRectsBeingDrawnWithBlock(layer, context, ^(CGRect rect) {
+        if (++rectCount > webLayerMaxRectsToPaint)
+            return;
+
+        totalRectArea += rect.size.width * rect.size.height;
+        dirtyRects.append(rect);
+    });
+
+    FloatRect clipBounds = CGContextGetClipBoundingBox(context);
+    double clipArea = clipBounds.width() * clipBounds.height();
+
+    if (rectCount >= webLayerMaxRectsToPaint || totalRectArea >= clipArea * webLayerWastedSpaceThreshold)
+        dirtyRects.clear();
+
+    bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
+    drawLayerContents(context, platformLayer, layerBounds, dirtyRects, isTiledLayer);
+}
+
+void drawLayerContents(CGContextRef context, WebCore::PlatformCALayer* platformLayer, FloatRect layerBounds, Vector<FloatRect, webLayerMaxRectsToPaint> dirtyRects, bool isTiledLayer)
 {
     WebCore::PlatformCALayerClient* layerContents = platformLayer->owner();
     if (!layerContents)
@@ -53,10 +79,9 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCA
 
     CGContextSaveGState(context);
 
-    CGRect layerBounds = [layer bounds];
     if (layerContents->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp) {
         CGContextScaleCTM(context, 1, -1);
-        CGContextTranslateCTM(context, 0, -layerBounds.size.height);
+        CGContextTranslateCTM(context, 0, -layerBounds.height());
     }
 
     [NSGraphicsContext saveGraphicsState];
@@ -87,24 +112,13 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCA
 #endif
     ThemeMac::setFocusRingClipRect(focusRingClipRect);
 
-    const float wastedSpaceThreshold = 0.75f;
-    const unsigned maxRectsToPaint = 5;
-
-    double clipArea = clipBounds.width() * clipBounds.height();
-    __block double totalRectArea = 0;
-    __block unsigned rectCount = 0;
-    __block Vector<FloatRect, maxRectsToPaint> dirtyRects;
-    
-    wkCALayerEnumerateRectsBeingDrawnWithBlock(layer, context, ^(CGRect rect) {
-        if (++rectCount > maxRectsToPaint)
-            return;
-
-        totalRectArea += rect.size.width * rect.size.height;
-        dirtyRects.append(rect);
-    });
-
-    if (rectCount < maxRectsToPaint && totalRectArea < clipArea * wastedSpaceThreshold) {
-        for (unsigned i = 0; i < rectCount; ++i) {
+    // If we have no dirty rects, repaint the whole layer.
+    if (dirtyRects.isEmpty()) {
+        // CGContextGetClipBoundingBox() gives us the bounds of the dirty region, so clipBounds
+        // encompasses all the dirty rects.
+        layerContents->platformCALayerPaintContents(graphicsContext, enclosingIntRect(clipBounds));
+    } else {
+        for (unsigned i = 0; i < dirtyRects.size(); ++i) {
             const FloatRect& currentRect = dirtyRects[i];
             
             GraphicsContextStateSaver stateSaver(graphicsContext);
@@ -112,10 +126,6 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCA
             
             layerContents->platformCALayerPaintContents(graphicsContext, enclosingIntRect(currentRect));
         }
-    } else {
-        // CGContextGetClipBoundingBox() gives us the bounds of the dirty region, so clipBounds
-        // encompasses all the dirty rects.
-        layerContents->platformCALayerPaintContents(graphicsContext, enclosingIntRect(clipBounds));
     }
 
     ThemeMac::setFocusRingClipRect(FloatRect());
@@ -128,13 +138,11 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCA
 
     CGContextRestoreGState(context);
 
-    // Always update the repain count so that it's accurate even if the count itself is not shown. This will be useful
+    // Always update the repaint count so that it's accurate even if the count itself is not shown. This will be useful
     // for the Web Inspector feeding this information through the LayerTreeAgent. 
     int repaintCount = layerContents->platformCALayerIncrementRepaintCount();
 
     if (!platformLayer->usesTiledBackingLayer() && layerContents && layerContents->platformCALayerShowRepaintCounter(platformLayer)) {
-        bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
-
         char text[16]; // that's a lot of repaints
         snprintf(text, sizeof(text), "%d", repaintCount);
 
@@ -170,6 +178,9 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCA
     }
 }
 
+}
+
+@implementation WebLayer
 
 - (id<CAAction>)actionForKey:(NSString *)key
 {
index 489f2a20fc1c8938143d5f9dec1e1ec2be5ff9e6..ef240bd649ee17b2e20ac40cc1ff6425ada38f74 100644 (file)
@@ -1,3 +1,36 @@
+2013-10-18  Tim Horton  <timothy_horton@apple.com>
+
+        Remote Layer Tree: Double-buffering and minimization of repaints
+        https://bugs.webkit.org/show_bug.cgi?id=123043
+
+        Reviewed by Simon Fraser.
+
+        * WebProcess/WebPage/mac/PlatformCALayerRemote.cpp:
+        (PlatformCALayerRemote::ensureBackingStore):
+        Don't worry about isOpaque with RemoteLayerBackingStore; this is a
+        optimization that is causing trouble; we can re-add it later.
+
+        (PlatformCALayerRemote::setBounds):
+        Make sure that we will repaint if our bounds change.
+
+        * WebProcess/WebPage/mac/RemoteLayerBackingStore.h:
+        (WebKit::RemoteLayerBackingStore::bitmap):
+        Keep a front and back buffer; return the front buffer when being asked for the bitmap.
+        Keep a Region of repaint areas.
+
+        * WebProcess/WebPage/mac/RemoteLayerBackingStore.mm:
+        (RemoteLayerBackingStore::RemoteLayerBackingStore):
+        (RemoteLayerBackingStore::encode):
+        (RemoteLayerBackingStore::decode):
+        Serialize only the front buffer, since the UI process only needs that.
+
+        (RemoteLayerBackingStore::setNeedsDisplay):
+        Store repaint rects instead of always setting the whole layer to be dirty.
+
+        (RemoteLayerBackingStore::display):
+        Paint into the back buffer (copying valid parts over from the front buffer),
+        then swap it to the front buffer. Use drawLayerContents so we get repaint counters, etc.
+
 2013-10-18  Anders Carlsson  <andersca@apple.com>
 
         Try to fix the Lion build.
index 40e7f4a15a8cdc03a876a90ac343cd3ed7b924e2..5f110520344fc4e1f69d38efb2022e910bfd4773 100644 (file)
@@ -101,11 +101,10 @@ void PlatformCALayerRemote::animationStarted(CFTimeInterval beginTime)
 void PlatformCALayerRemote::ensureBackingStore()
 {
     if (m_properties.backingStore.layer() == this
-        && m_properties.backingStore.size() == m_properties.size
-        && m_properties.backingStore.isOpaque() == m_properties.opaque)
+        && m_properties.backingStore.size() == m_properties.size)
         return;
 
-    m_properties.backingStore = RemoteLayerBackingStore(this, expandedIntSize(m_properties.size), m_properties.opaque);
+    m_properties.backingStore = RemoteLayerBackingStore(this, expandedIntSize(m_properties.size));
 }
 
 void PlatformCALayerRemote::setNeedsDisplay(const FloatRect* dirtyRect)
@@ -218,6 +217,8 @@ void PlatformCALayerRemote::setBounds(const FloatRect& value)
 {
     m_properties.size = value.size();
     m_properties.notePropertiesChanged(RemoteLayerTreeTransaction::SizeChanged);
+
+    ensureBackingStore();
 }
 
 FloatPoint3D PlatformCALayerRemote::position() const
index f39123f0b1998b882a72e466c2e871adb20509e1..80444c4e772a996e3de4699ff1512e5ce96b33ad 100644 (file)
@@ -29,7 +29,8 @@
 #if USE(ACCELERATED_COMPOSITING)
 
 #include "ShareableBitmap.h"
-#include <WebCore/IntRect.h>
+#include <WebCore/FloatRect.h>
+#include <WebCore/Region.h>
 
 namespace WebKit {
 
@@ -38,16 +39,15 @@ class PlatformCALayerRemote;
 class RemoteLayerBackingStore {
 public:
     RemoteLayerBackingStore();
-    RemoteLayerBackingStore(PlatformCALayerRemote*, WebCore::IntSize, bool isOpaque);
+    RemoteLayerBackingStore(PlatformCALayerRemote*, WebCore::IntSize);
 
     void setNeedsDisplay(WebCore::IntRect);
     void setNeedsDisplay();
 
     bool display();
 
-    ShareableBitmap* bitmap() const { return m_bitmap.get(); }
+    ShareableBitmap* bitmap() const { return m_frontBuffer.get(); }
     WebCore::IntSize size() const { return m_size; }
-    bool isOpaque() const { return m_isOpaque; }
 
     PlatformCALayerRemote* layer() const { return m_layer; }
 
@@ -58,11 +58,11 @@ private:
     PlatformCALayerRemote* m_layer;
 
     WebCore::IntSize m_size;
-    bool m_isOpaque;
 
-    bool m_needsFullRepaint;
+    WebCore::Region m_dirtyRegion;
 
-    RefPtr<ShareableBitmap> m_bitmap;
+    RefPtr<ShareableBitmap> m_frontBuffer;
+    RefPtr<ShareableBitmap> m_backBuffer;
 };
 
 } // namespace WebKit
index 5ac069448cdc64291af3aafa6d7ef983f7352b22..cb5d7edae903cb79f9b5d5a5a90145bbf97a046a 100644 (file)
 #import "ArgumentCoders.h"
 #import "ShareableBitmap.h"
 #import "WebCoreArgumentCoders.h"
+#import <WebCore/WebLayer.h>
 
 using namespace WebCore;
 using namespace WebKit;
 
-RemoteLayerBackingStore::RemoteLayerBackingStore(PlatformCALayerRemote* layer, IntSize size, bool isOpaque)
+RemoteLayerBackingStore::RemoteLayerBackingStore(PlatformCALayerRemote* layer, IntSize size)
     : m_layer(layer)
     , m_size(size)
-    , m_isOpaque(isOpaque)
-    , m_needsFullRepaint(true)
 {
     ASSERT(layer);
 }
@@ -53,7 +52,7 @@ RemoteLayerBackingStore::RemoteLayerBackingStore()
 void RemoteLayerBackingStore::encode(CoreIPC::ArgumentEncoder& encoder) const
 {
     ShareableBitmap::Handle handle;
-    m_bitmap->createHandle(handle);
+    m_frontBuffer->createHandle(handle);
 
     encoder << handle;
     encoder << m_size;
@@ -64,7 +63,7 @@ bool RemoteLayerBackingStore::decode(CoreIPC::ArgumentDecoder& decoder, RemoteLa
     ShareableBitmap::Handle handle;
     if (!decoder.decode(handle))
         return false;
-    result.m_bitmap = ShareableBitmap::create(handle);
+    result.m_frontBuffer = ShareableBitmap::create(handle);
 
     if (!decoder.decode(result.m_size))
         return false;
@@ -74,13 +73,12 @@ bool RemoteLayerBackingStore::decode(CoreIPC::ArgumentDecoder& decoder, RemoteLa
 
 void RemoteLayerBackingStore::setNeedsDisplay(IntRect rect)
 {
-    // FIXME: Only repaint dirty regions.
-    setNeedsDisplay();
+    m_dirtyRegion.unite(rect);
 }
 
 void RemoteLayerBackingStore::setNeedsDisplay()
 {
-    m_needsFullRepaint = true;
+    setNeedsDisplay(IntRect(IntPoint(), m_size));
 }
 
 bool RemoteLayerBackingStore::display()
@@ -88,28 +86,56 @@ bool RemoteLayerBackingStore::display()
     if (!m_layer)
         return false;
 
-    if (!m_layer->owner()->platformCALayerDrawsContent()) {
-        // If we previously were drawsContent=YES, and now are not, we need
-        // to note that our backing store has changed (by being cleared).
-        if (m_bitmap) {
-            m_bitmap = nullptr;
-            return true;
-        }
+    // If we previously were drawsContent=YES, and now are not, we need
+    // to note that our backing store has been cleared.
+    if (!m_layer->owner()->platformCALayerDrawsContent())
+        return m_frontBuffer;
+
+    if (m_dirtyRegion.isEmpty())
         return false;
+
+    m_backBuffer = ShareableBitmap::createShareable(m_size, ShareableBitmap::SupportsAlpha);
+    if (!m_frontBuffer)
+        m_dirtyRegion.unite(IntRect(IntPoint(), m_size));
+
+    IntRect layerBounds(IntPoint(), m_size);
+
+    if (m_layer->owner()->platformCALayerShowRepaintCounter(m_layer)) {
+        IntRect indicatorRect = IntRect(0, 0, 52, 27);
+        if (m_layer->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp)
+            indicatorRect.setY(layerBounds.height() - indicatorRect.y() - indicatorRect.height());
+
+        m_dirtyRegion.unite(indicatorRect);
     }
 
-    if (m_bitmap && !m_needsFullRepaint)
-        return false;
+    std::unique_ptr<GraphicsContext> context = m_backBuffer->createGraphicsContext();
+
+    Vector<IntRect> dirtyRects = m_dirtyRegion.rects();
+
+    // If we have less than webLayerMaxRectsToPaint rects to paint and they cover less
+    // than webLayerWastedSpaceThreshold of the area, we'll do a partial repaint.
+    Vector<FloatRect, webLayerMaxRectsToPaint> rectsToPaint;
+    if (dirtyRects.size() <= webLayerMaxRectsToPaint && m_dirtyRegion.totalArea() <= webLayerWastedSpaceThreshold * layerBounds.width() * layerBounds.height()) {
+        // Copy over the parts of the front buffer that we're not going to repaint.
+        if (m_frontBuffer) {
+            Region cleanRegion(layerBounds);
+            cleanRegion.subtract(m_dirtyRegion);
+
+            RetainPtr<CGImageRef> frontImage = m_frontBuffer->makeCGImage();
+
+            for (const auto& rect : cleanRegion.rects())
+                context->drawNativeImage(frontImage.get(), m_frontBuffer->size(), ColorSpaceDeviceRGB, rect, rect);
+        }
 
-    if (!m_bitmap) {
-        m_bitmap = ShareableBitmap::createShareable(m_size, m_isOpaque ? ShareableBitmap::NoFlags : ShareableBitmap::SupportsAlpha);
-        m_needsFullRepaint = true;
+        for (const auto& rect : dirtyRects)
+            rectsToPaint.append(rect);
     }
 
-    std::unique_ptr<GraphicsContext> context = m_bitmap->createGraphicsContext();
-    m_layer->owner()->platformCALayerPaintContents(*context.get(), IntRect(IntPoint(), m_size));
+    drawLayerContents(context->platformContext(), m_layer, layerBounds, rectsToPaint, false);
+    m_dirtyRegion = Region();
 
-    m_needsFullRepaint = false;
+    m_frontBuffer = m_backBuffer;
+    m_backBuffer = nullptr;
 
     return true;
 }