[CG] Have Canvas use the IOSurfacePool
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Mar 2015 01:24:14 +0000 (01:24 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Mar 2015 01:24:14 +0000 (01:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142417
<rdar://problem/20044440>

Reviewed by Darin Adler.

PerformanceTests:

Lower the number of different canvas sizes from 1000 to 100 so that
the test does not require such a huge cache size. With 100, we now
get over 90% cache hit rate with the default IOSurfacePool size.

* Canvas/reuse.html:

Source/WebCore:

Have ImageBufferDataCG use the IOSurfacePool so that Canvas can
benefit from it. I see a ~75% progression on Canvas/reuse.html
performance test on my Macbook Pro with 1000 different canvas
sizes and ~110% progression with 100 different canvas sizes.

I also see a ~65% cache hit rate on the mobile version of
cnn.com.

Note that ImageData calls CGContextClearRect() after calling
IOSurface::create() so recycling IOSurfaces in this case should
be safe.

Performance test: Canvas/reuse.html

* platform/graphics/ImageBuffer.h:
(WebCore::ImageBuffer::baseTransform):
* platform/graphics/cg/ImageBufferCG.cpp:
(WebCore::ImageBuffer::ImageBuffer):
(WebCore::ImageBuffer::context):
(WebCore::ImageBuffer::copyImage):
(WebCore::ImageBuffer::copyNativeImage):
(WebCore::ImageBuffer::draw):
(WebCore::ImageBuffer::clip):
(WebCore::ImageBuffer::putByteArray):
(WebCore::ImageBuffer::toDataURL):
* platform/graphics/cg/ImageBufferDataCG.cpp:
(WebCore::ImageBufferData::~ImageBufferData):
(WebCore::ImageBufferData::getData):
(WebCore::ImageBufferData::putData):
(WebCore::ImageBufferData::ImageBufferData): Deleted.
* platform/graphics/cg/ImageBufferDataCG.h:
* platform/graphics/cocoa/IOSurface.h:
* platform/graphics/cocoa/IOSurface.mm:
(IOSurface::surfaceFromPool):
(IOSurface::create):
(IOSurface::createFromSendRight):
(IOSurface::createFromImage):
(IOSurface::setContextSize):

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

PerformanceTests/Canvas/reuse.html
PerformanceTests/ChangeLog
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/ImageBuffer.h
Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp
Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h
Source/WebCore/platform/graphics/cocoa/IOSurface.h
Source/WebCore/platform/graphics/cocoa/IOSurface.mm

index a5de2d1..f206ce4 100644 (file)
@@ -4,7 +4,7 @@
 <script src="../resources/runner.js"></script>
 <script>
 
-var numCreated = 1000;
+var numCreated = 100;
 
 function testCreation() {
     (function() {
index d0808cc..8615dd4 100644 (file)
@@ -1,3 +1,17 @@
+2015-03-09  Chris Dumez  <cdumez@apple.com>
+
+        [CG] Have Canvas use the IOSurfacePool
+        https://bugs.webkit.org/show_bug.cgi?id=142417
+        <rdar://problem/20044440>
+
+        Reviewed by Darin Adler.
+
+        Lower the number of different canvas sizes from 1000 to 100 so that
+        the test does not require such a huge cache size. With 100, we now
+        get over 90% cache hit rate with the default IOSurfacePool size.
+
+        * Canvas/reuse.html:
+
 2015-01-28  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         Poor performance on IE's Chalkboard benchmark.
index a1c92c2..823ee8e 100644 (file)
@@ -1,3 +1,50 @@
+2015-03-09  Chris Dumez  <cdumez@apple.com>
+
+        [CG] Have Canvas use the IOSurfacePool
+        https://bugs.webkit.org/show_bug.cgi?id=142417
+        <rdar://problem/20044440>
+
+        Reviewed by Darin Adler.
+
+        Have ImageBufferDataCG use the IOSurfacePool so that Canvas can
+        benefit from it. I see a ~75% progression on Canvas/reuse.html
+        performance test on my Macbook Pro with 1000 different canvas
+        sizes and ~110% progression with 100 different canvas sizes.
+
+        I also see a ~65% cache hit rate on the mobile version of
+        cnn.com.
+
+        Note that ImageData calls CGContextClearRect() after calling
+        IOSurface::create() so recycling IOSurfaces in this case should
+        be safe.
+
+        Performance test: Canvas/reuse.html
+
+        * platform/graphics/ImageBuffer.h:
+        (WebCore::ImageBuffer::baseTransform):
+        * platform/graphics/cg/ImageBufferCG.cpp:
+        (WebCore::ImageBuffer::ImageBuffer):
+        (WebCore::ImageBuffer::context):
+        (WebCore::ImageBuffer::copyImage):
+        (WebCore::ImageBuffer::copyNativeImage):
+        (WebCore::ImageBuffer::draw):
+        (WebCore::ImageBuffer::clip):
+        (WebCore::ImageBuffer::putByteArray):
+        (WebCore::ImageBuffer::toDataURL):
+        * platform/graphics/cg/ImageBufferDataCG.cpp:
+        (WebCore::ImageBufferData::~ImageBufferData):
+        (WebCore::ImageBufferData::getData):
+        (WebCore::ImageBufferData::putData):
+        (WebCore::ImageBufferData::ImageBufferData): Deleted.
+        * platform/graphics/cg/ImageBufferDataCG.h:
+        * platform/graphics/cocoa/IOSurface.h:
+        * platform/graphics/cocoa/IOSurface.mm:
+        (IOSurface::surfaceFromPool):
+        (IOSurface::create):
+        (IOSurface::createFromSendRight):
+        (IOSurface::createFromImage):
+        (IOSurface::setContextSize):
+
 2015-03-09  Brent Fulgham  <bfulgham@apple.com>
 
         Assertion in ScrollController::processWheelEventForScrollSnapOnAxis when scrolling with mechanical wheel mouse
index 08ead67..aa48a5f 100644 (file)
@@ -114,7 +114,7 @@ public:
     void transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace);
     void platformTransformColorSpace(const Vector<int>&);
 #else
-    AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, m_data.m_backingStoreSize.height()); }
+    AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, m_data.backingStoreSize.height()); }
 #endif
     PlatformLayer* platformLayer() const;
 
index d9536e8..cd92899 100644 (file)
@@ -81,7 +81,7 @@ ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpac
         return;
 
     m_size = IntSize(scaledWidth, scaledHeight);
-    m_data.m_backingStoreSize = m_size;
+    m_data.backingStoreSize = m_size;
 
     success = false;  // Make early return mean failure.
     bool accelerateRendering = renderingMode == Accelerated;
@@ -94,8 +94,8 @@ ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpac
 #endif
 
     // Prevent integer overflows
-    m_data.m_bytesPerRow = 4 * Checked<unsigned, RecordOverflow>(m_data.m_backingStoreSize.width());
-    Checked<size_t, RecordOverflow> numBytes = Checked<unsigned, RecordOverflow>(m_data.m_backingStoreSize.height()) * m_data.m_bytesPerRow;
+    m_data.bytesPerRow = 4 * Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.width());
+    Checked<size_t, RecordOverflow> numBytes = Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.height()) * m_data.bytesPerRow;
     if (numBytes.hasOverflowed())
         return;
 
@@ -107,14 +107,14 @@ ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpac
     ASSERT(renderingMode == Unaccelerated);
 #endif
 
-    m_data.m_colorSpace = cachedCGColorSpace(imageColorSpace);
+    m_data.colorSpace = cachedCGColorSpace(imageColorSpace);
 
     RetainPtr<CGContextRef> cgContext;
     if (accelerateRendering) {
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
-        FloatSize userBounds = scaleSizeToUserSpace(FloatSize(width.unsafeGet(), height.unsafeGet()), m_data.m_backingStoreSize, m_size);
-        m_data.m_surface = IOSurface::create(m_data.m_backingStoreSize, IntSize(userBounds), imageColorSpace);
-        cgContext = m_data.m_surface->ensurePlatformContext();
+        FloatSize userBounds = scaleSizeToUserSpace(FloatSize(width.unsafeGet(), height.unsafeGet()), m_data.backingStoreSize, m_size);
+        m_data.surface = IOSurface::create(m_data.backingStoreSize, IntSize(userBounds), imageColorSpace);
+        cgContext = m_data.surface->ensurePlatformContext();
         if (cgContext)
             CGContextClearRect(cgContext.get(), FloatRect(FloatPoint(), userBounds));
 #endif
@@ -124,27 +124,27 @@ ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpac
     }
 
     if (!accelerateRendering) {
-        if (!tryFastCalloc(m_data.m_backingStoreSize.height(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data))
+        if (!tryFastCalloc(m_data.backingStoreSize.height(), m_data.bytesPerRow.unsafeGet()).getValue(m_data.data))
             return;
-        ASSERT(!(reinterpret_cast<intptr_t>(m_data.m_data) & 3));
+        ASSERT(!(reinterpret_cast<intptr_t>(m_data.data) & 3));
 
 #if USE_ARGB32
-        m_data.m_bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+        m_data.bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
 #else
-        m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast;
+        m_data.bitmapInfo = kCGImageAlphaPremultipliedLast;
 #endif
-        cgContext = adoptCF(CGBitmapContextCreate(m_data.m_data, m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo));
+        cgContext = adoptCF(CGBitmapContextCreate(m_data.data, m_data.backingStoreSize.width(), m_data.backingStoreSize.height(), 8, m_data.bytesPerRow.unsafeGet(), m_data.colorSpace, m_data.bitmapInfo));
         // Create a live image that wraps the data.
-        m_data.m_dataProvider = adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, numBytes.unsafeGet(), releaseImageData));
+        m_data.dataProvider = adoptCF(CGDataProviderCreateWithData(0, m_data.data, numBytes.unsafeGet(), releaseImageData));
 
         if (!cgContext)
             return;
 
-        m_data.m_context = adoptPtr(new GraphicsContext(cgContext.get()));
+        m_data.context = adoptPtr(new GraphicsContext(cgContext.get()));
     }
 
     context()->scale(FloatSize(1, -1));
-    context()->translate(0, -m_data.m_backingStoreSize.height());
+    context()->translate(0, -m_data.backingStoreSize.height());
     context()->applyDeviceScaleFactor(m_resolutionScale);
 
     success = true;
@@ -157,10 +157,10 @@ ImageBuffer::~ImageBuffer()
 GraphicsContext* ImageBuffer::context() const
 {
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
-    if (m_data.m_surface)
-        return &m_data.m_surface->ensureGraphicsContext();
+    if (m_data.surface)
+        return &m_data.surface->ensureGraphicsContext();
 #endif
-    return m_data.m_context.get();
+    return m_data.context.get();
 }
 
 void ImageBuffer::flushContext() const
@@ -188,7 +188,7 @@ PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBeh
         RetainPtr<CGContextRef> context = adoptCF(CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast));
         CGContextSetBlendMode(context.get(), kCGBlendModeCopy);
         CGContextClipToRect(context.get(), FloatRect(FloatPoint::zero(), logicalSize()));
-        FloatSize imageSizeInUserSpace = scaleSizeToUserSpace(logicalSize(), m_data.m_backingStoreSize, internalSize());
+        FloatSize imageSizeInUserSpace = scaleSizeToUserSpace(logicalSize(), m_data.backingStoreSize, internalSize());
         CGContextDrawImage(context.get(), FloatRect(FloatPoint::zero(), imageSizeInUserSpace), image.get());
         image = adoptCF(CGBitmapContextCreateImage(context.get()));
     }
@@ -213,7 +213,7 @@ RetainPtr<CGImageRef> ImageBuffer::copyNativeImage(BackingStoreCopy copyBehavior
     if (!context()->isAcceleratedContext()) {
         switch (copyBehavior) {
         case DontCopyBackingStore:
-            image = adoptCF(CGImageCreate(m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height(), 8, 32, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo, m_data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault));
+            image = adoptCF(CGImageCreate(m_data.backingStoreSize.width(), m_data.backingStoreSize.height(), 8, 32, m_data.bytesPerRow.unsafeGet(), m_data.colorSpace, m_data.bitmapInfo, m_data.dataProvider.get(), 0, true, kCGRenderingIntentDefault));
             break;
         case CopyBackingStore:
             image = adoptCF(CGBitmapContextCreateImage(context()->platformContext()));
@@ -225,7 +225,7 @@ RetainPtr<CGImageRef> ImageBuffer::copyNativeImage(BackingStoreCopy copyBehavior
     }
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
     else
-        image = m_data.m_surface->createImage();
+        image = m_data.surface->createImage();
 #endif
 
     return image;
@@ -244,7 +244,7 @@ void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace,
 
     FloatRect adjustedSrcRect = srcRect;
     adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
-    destContext->drawNativeImage(image.get(), m_data.m_backingStoreSize, colorSpace, destRect, adjustedSrcRect, op, blendMode);
+    destContext->drawNativeImage(image.get(), m_data.backingStoreSize, colorSpace, destRect, adjustedSrcRect, op, blendMode);
 }
 
 void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode)
@@ -268,7 +268,7 @@ void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& src
 
 void ImageBuffer::clip(GraphicsContext* contextToClip, const FloatRect& rect) const
 {
-    FloatSize backingStoreSizeInUserSpace = scaleSizeToUserSpace(rect.size(), m_data.m_backingStoreSize, internalSize());
+    FloatSize backingStoreSizeInUserSpace = scaleSizeToUserSpace(rect.size(), m_data.backingStoreSize, internalSize());
 
     CGContextRef platformContextToClip = contextToClip->platformContext();
     // FIXME: This image needs to be grayscale to be used as an alpha mask here.
@@ -342,7 +342,7 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c
     CGContextSetShadowWithColor(destContext, CGSizeZero, 0, 0);
 
     // Draw the image in CG coordinate space
-    FloatSize scaledDestSize = scaleSizeToUserSpace(coordinateSystem == LogicalCoordinateSystem ? logicalSize() : internalSize(), m_data.m_backingStoreSize, internalSize());
+    FloatSize scaledDestSize = scaleSizeToUserSpace(coordinateSystem == LogicalCoordinateSystem ? logicalSize() : internalSize(), m_data.backingStoreSize, internalSize());
     IntPoint destPointInCGCoords(destPoint.x() + sourceRect.x(), scaledDestSize.height() - (destPoint.y() + sourceRect.y()) - sourceRect.height());
     IntRect destRectInCGCoords(destPointInCGCoords, sourceCopySize);
     CGContextClipToRect(destContext, destRectInCGCoords);
@@ -461,7 +461,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality, Coo
         RetainPtr<CGContextRef> context = adoptCF(CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast));
         CGContextSetBlendMode(context.get(), kCGBlendModeCopy);
         CGContextClipToRect(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()));
-        FloatSize imageSizeInUserSpace = scaleSizeToUserSpace(logicalSize(), m_data.m_backingStoreSize, internalSize());
+        FloatSize imageSizeInUserSpace = scaleSizeToUserSpace(logicalSize(), m_data.backingStoreSize, internalSize());
         CGContextDrawImage(context.get(), CGRectMake(0, 0, imageSizeInUserSpace.width(), imageSizeInUserSpace.height()), image.get());
         image = adoptCF(CGBitmapContextCreateImage(context.get()));
     }
index 537cdb6..8a9d21c 100644 (file)
@@ -37,6 +37,7 @@
 
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
 #include "IOSurface.h"
+#include "IOSurfacePool.h"
 #include "IOSurfaceSPI.h"
 #include <dispatch/dispatch.h>
 #endif
@@ -56,12 +57,12 @@ struct ScanlineData {
 
 namespace WebCore {
 
-ImageBufferData::ImageBufferData()
-    : m_data(nullptr)
+ImageBufferData::~ImageBufferData()
+{
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
-    , m_surface(nullptr)
+    if (surface)
+        IOSurfacePool::sharedPool().addSurface(WTF::move(surface));
 #endif
-{
 }
 
 #if USE(ACCELERATE)
@@ -117,7 +118,7 @@ PassRefPtr<Uint8ClampedArray> ImageBufferData::getData(const IntRect& rect, cons
         return 0;
 
     RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(area.unsafeGet());
-    unsigned char* data = result->data();
+    unsigned char* resultData = result->data();
     
     Checked<int> endx = rect.maxX();
     endx *= ceilf(resolutionScale);
@@ -158,14 +159,14 @@ PassRefPtr<Uint8ClampedArray> ImageBufferData::getData(const IntRect& rect, cons
         return result.release();
     
     unsigned destBytesPerRow = 4 * rect.width();
-    unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
+    unsigned char* destRows = resultData + desty * destBytesPerRow + destx * 4;
     
     unsigned srcBytesPerRow;
     unsigned char* srcRows;
     
     if (!accelerateRendering) {
-        srcBytesPerRow = m_bytesPerRow.unsafeGet();
-        srcRows = reinterpret_cast<unsigned char*>(m_data) + originy * srcBytesPerRow + originx * 4;
+        srcBytesPerRow = bytesPerRow.unsafeGet();
+        srcRows = reinterpret_cast<unsigned char*>(data) + originy * srcBytesPerRow + originx * 4;
         
 #if USE(ACCELERATE)
         if (unmultiplied) {
@@ -205,9 +206,9 @@ PassRefPtr<Uint8ClampedArray> ImageBufferData::getData(const IntRect& rect, cons
         }
 #endif
         if (resolutionScale != 1) {
-            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get()));
-            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
             CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
             if (!unmultiplied)
@@ -272,10 +273,10 @@ PassRefPtr<Uint8ClampedArray> ImageBufferData::getData(const IntRect& rect, cons
     } else {
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
         // FIXME: WebCore::IOSurface should have a locking RAII object and base-address getter.
-        IOSurfaceRef surface = m_surface->surface();
-        IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0);
-        srcBytesPerRow = IOSurfaceGetBytesPerRow(surface);
-        srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4;
+        IOSurfaceRef surfaceRef = surface->surface();
+        IOSurfaceLock(surfaceRef, kIOSurfaceLockReadOnly, nullptr);
+        srcBytesPerRow = IOSurfaceGetBytesPerRow(surfaceRef);
+        srcRows = static_cast<unsigned char*>(IOSurfaceGetBaseAddress(surfaceRef)) + originy * srcBytesPerRow + originx * 4;
 
 #if USE(ACCELERATE)
         vImage_Buffer src;
@@ -320,9 +321,9 @@ PassRefPtr<Uint8ClampedArray> ImageBufferData::getData(const IntRect& rect, cons
         }
 #else
         if (resolutionScale != 1) {
-            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get()));
-            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
             CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
 
@@ -371,7 +372,7 @@ PassRefPtr<Uint8ClampedArray> ImageBufferData::getData(const IntRect& rect, cons
             }
         }
 #endif // USE(ACCELERATE)
-        IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0);
+        IOSurfaceUnlock(surfaceRef, kIOSurfaceLockReadOnly, nullptr);
 #else
         ASSERT_NOT_REACHED();
 #endif // USE(IOSURFACE_CANVAS_BACKING_STORE)
@@ -428,8 +429,8 @@ void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceS
     unsigned char* destRows;
     
     if (!accelerateRendering) {
-        destBytesPerRow = m_bytesPerRow.unsafeGet();
-        destRows = reinterpret_cast<unsigned char*>(m_data) + (desty * destBytesPerRow + destx * 4).unsafeGet();
+        destBytesPerRow = bytesPerRow.unsafeGet();
+        destRows = reinterpret_cast<unsigned char*>(data) + (desty * destBytesPerRow + destx * 4).unsafeGet();
         
 #if  USE(ACCELERATE)
         if (unmultiplied) {
@@ -470,9 +471,9 @@ void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceS
         }
 #endif
         if (resolutionScale != 1) {
-            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get()));
-            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
             CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
             if (!unmultiplied)
@@ -516,10 +517,10 @@ void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceS
         }
     } else {
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
-        IOSurfaceRef surface = m_surface->surface();
-        IOSurfaceLock(surface, 0, 0);
-        destBytesPerRow = IOSurfaceGetBytesPerRow(surface);
-        destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + (desty * destBytesPerRow + destx * 4).unsafeGet();
+        IOSurfaceRef surfaceRef = surface->surface();
+        IOSurfaceLock(surfaceRef, 0, nullptr);
+        destBytesPerRow = IOSurfaceGetBytesPerRow(surfaceRef);
+        destRows = static_cast<unsigned char*>(IOSurfaceGetBaseAddress(surfaceRef)) + (desty * destBytesPerRow + destx * 4).unsafeGet();
 
 #if USE(ACCELERATE)
         vImage_Buffer src;
@@ -564,9 +565,9 @@ void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceS
         }
 #else
         if (resolutionScale != 1) {
-            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get()));
-            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
+            RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast));
             CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
             CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
 
@@ -598,7 +599,7 @@ void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceS
         }
 #endif // USE(ACCELERATE)
 
-        IOSurfaceUnlock(surface, 0, 0);
+        IOSurfaceUnlock(surfaceRef, 0, nullptr);
 #else
         ASSERT_NOT_REACHED();
 #endif // USE(IOSURFACE_CANVAS_BACKING_STORE)
index 4babf7a..3b6c291 100644 (file)
@@ -46,23 +46,22 @@ namespace WebCore {
 class IOSurface;
 class IntSize;
 
-class ImageBufferData {
-public:
-    ImageBufferData();
+struct ImageBufferData {
+    ~ImageBufferData();
 
-    IntSize m_backingStoreSize;
-    Checked<unsigned, RecordOverflow> m_bytesPerRow;
-    CGColorSpaceRef m_colorSpace;
+    IntSize backingStoreSize;
+    Checked<unsigned, RecordOverflow> bytesPerRow;
+    CGColorSpaceRef colorSpace;
 
     // Only for Software ImageBuffers.
-    void* m_data;
-    RetainPtr<CGDataProviderRef> m_dataProvider;
-    CGBitmapInfo m_bitmapInfo;
-    OwnPtr<GraphicsContext> m_context;
+    void* data { nullptr };
+    RetainPtr<CGDataProviderRef> dataProvider;
+    CGBitmapInfo bitmapInfo;
+    OwnPtr<GraphicsContext> context;
 
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
     // Only for Accelerated ImageBuffers.
-    std::unique_ptr<IOSurface> m_surface;
+    std::unique_ptr<IOSurface> surface;
 #endif
 
     PassRefPtr<Uint8ClampedArray> getData(const IntRect&, const IntSize&, bool accelerateRendering, bool unmultiplied, float resolutionScale) const;
index e752a26..ff635ba 100644 (file)
@@ -85,6 +85,10 @@ private:
     IOSurface(IntSize, IntSize contextSize, ColorSpace);
     IOSurface(IOSurfaceRef, ColorSpace);
 
+    static std::unique_ptr<IOSurface> surfaceFromPool(IntSize, IntSize contextSize, ColorSpace);
+    IntSize contextSize() const { return m_contextSize; }
+    void setContextSize(IntSize);
+
     ColorSpace m_colorSpace;
     IntSize m_size;
     IntSize m_contextSize;
index 287c74d..a8f1190 100644 (file)
@@ -41,22 +41,33 @@ CGImageRef CGIOSurfaceContextCreateImage(CGContextRef);
 
 using namespace WebCore;
 
+inline std::unique_ptr<IOSurface> IOSurface::surfaceFromPool(IntSize size, IntSize contextSize, ColorSpace colorSpace)
+{
+    auto cachedSurface = IOSurfacePool::sharedPool().takeSurface(size, colorSpace);
+    if (!cachedSurface)
+        return nullptr;
+
+    cachedSurface->setContextSize(contextSize);
+    return cachedSurface;
+}
+
 std::unique_ptr<IOSurface> IOSurface::create(IntSize size, ColorSpace colorSpace)
 {
-    if (std::unique_ptr<IOSurface> cachedSurface = IOSurfacePool::sharedPool().takeSurface(size, colorSpace))
+    if (auto cachedSurface = surfaceFromPool(size, size, colorSpace))
         return cachedSurface;
     return std::unique_ptr<IOSurface>(new IOSurface(size, colorSpace));
 }
 
 std::unique_ptr<IOSurface> IOSurface::create(IntSize size, IntSize contextSize, ColorSpace colorSpace)
 {
-    // FIXME: We should be able to pull surfaces out of the IOSurfacePool and adjust their contextSize.
+    if (auto cachedSurface = surfaceFromPool(size, contextSize, colorSpace))
+        return cachedSurface;
     return std::unique_ptr<IOSurface>(new IOSurface(size, contextSize, colorSpace));
 }
 
 std::unique_ptr<IOSurface> IOSurface::createFromSendRight(const MachSendRight& sendRight, ColorSpace colorSpace)
 {
-    RetainPtr<IOSurfaceRef> surface = adoptCF(IOSurfaceLookupFromMachPort(sendRight.sendRight()));
+    auto surface = adoptCF(IOSurfaceLookupFromMachPort(sendRight.sendRight()));
     return IOSurface::createFromSurface(surface.get(), colorSpace);
 }
 
@@ -73,7 +84,7 @@ std::unique_ptr<IOSurface> IOSurface::createFromImage(CGImageRef image)
     size_t width = CGImageGetWidth(image);
     size_t height = CGImageGetHeight(image);
 
-    std::unique_ptr<IOSurface> surface = IOSurface::create(IntSize(width, height), ColorSpaceDeviceRGB);
+    auto surface = IOSurface::create(IntSize(width, height), ColorSpaceDeviceRGB);
     auto surfaceContext = surface->ensurePlatformContext();
     CGContextDrawImage(surfaceContext, CGRectMake(0, 0, width, height), image);
     CGContextFlush(surfaceContext);
@@ -143,6 +154,17 @@ RetainPtr<CGImageRef> IOSurface::createImage()
     return adoptCF(CGIOSurfaceContextCreateImage(ensurePlatformContext()));
 }
 
+void IOSurface::setContextSize(IntSize contextSize)
+{
+    if (contextSize == m_contextSize)
+        return;
+
+    // Release the graphics context and update the context size. Next time the graphics context is
+    // accessed, we will construct it again with the right size.
+    releaseGraphicsContext();
+    m_contextSize = contextSize;
+}
+
 CGContextRef IOSurface::ensurePlatformContext()
 {
     if (m_cgContext)