Unreviewed, rolling out r180203 and r180210.
[WebKit-https.git] / Source / WebKit2 / Shared / mac / RemoteLayerBackingStore.mm
1  /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "RemoteLayerBackingStore.h"
28
29 #import "ArgumentCoders.h"
30 #import "MachPort.h"
31 #import "PlatformCALayerRemote.h"
32 #import "RemoteLayerBackingStoreCollection.h"
33 #import "RemoteLayerTreeContext.h"
34 #import "ShareableBitmap.h"
35 #import "WebCoreArgumentCoders.h"
36 #import <QuartzCore/QuartzCore.h>
37 #import <WebCore/GraphicsContextCG.h>
38 #import <WebCore/IOSurface.h>
39 #import <WebCore/IOSurfacePool.h>
40 #import <WebCore/MachSendRight.h>
41 #import <WebCore/QuartzCoreSPI.h>
42 #import <WebCore/WebLayer.h>
43
44 #if USE(IOSURFACE)
45 #import <mach/mach_port.h>
46 #endif
47
48 using namespace WebCore;
49
50 namespace WebKit {
51
52 RemoteLayerBackingStore::RemoteLayerBackingStore(PlatformCALayerRemote* layer)
53     : m_layer(layer)
54     , m_isOpaque(false)
55     , m_lastDisplayTime(std::chrono::steady_clock::time_point::min())
56 {
57     if (!m_layer)
58         return;
59     if (RemoteLayerTreeContext* context = m_layer->context())
60         context->backingStoreWasCreated(*this);
61 }
62
63 RemoteLayerBackingStore::~RemoteLayerBackingStore()
64 {
65     clearBackingStore();
66
67     if (!m_layer)
68         return;
69     if (RemoteLayerTreeContext* context = m_layer->context())
70         context->backingStoreWillBeDestroyed(*this);
71 }
72
73 void RemoteLayerBackingStore::ensureBackingStore(FloatSize size, float scale, bool acceleratesDrawing, bool isOpaque)
74 {
75     if (m_size == size && m_scale == scale && m_acceleratesDrawing == acceleratesDrawing && m_isOpaque == isOpaque)
76         return;
77
78     m_size = size;
79     m_scale = scale;
80     m_acceleratesDrawing = acceleratesDrawing;
81     m_isOpaque = isOpaque;
82
83     if (m_frontBuffer) {
84         // If we have a valid backing store, we need to ensure that it gets completely
85         // repainted the next time display() is called.
86         setNeedsDisplay();
87     }
88
89     clearBackingStore();
90 }
91
92 void RemoteLayerBackingStore::clearBackingStore()
93 {
94     m_frontBuffer.discard();
95     m_backBuffer.discard();
96 #if USE(IOSURFACE)
97     m_secondaryBackBuffer.discard();
98 #endif
99 }
100
101 void RemoteLayerBackingStore::encode(IPC::ArgumentEncoder& encoder) const
102 {
103     encoder << m_size;
104     encoder << m_scale;
105     encoder << m_acceleratesDrawing;
106     encoder << m_isOpaque;
107
108 #if USE(IOSURFACE)
109     if (m_acceleratesDrawing) {
110         encoder << m_frontBuffer.surface->createSendRight();
111         return;
112     }
113 #endif
114
115     ASSERT(!m_acceleratesDrawing);
116
117     ShareableBitmap::Handle handle;
118     m_frontBuffer.bitmap->createHandle(handle);
119     encoder << handle;
120 }
121
122 bool RemoteLayerBackingStore::decode(IPC::ArgumentDecoder& decoder, RemoteLayerBackingStore& result)
123 {
124     if (!decoder.decode(result.m_size))
125         return false;
126
127     if (!decoder.decode(result.m_scale))
128         return false;
129
130     if (!decoder.decode(result.m_acceleratesDrawing))
131         return false;
132
133     if (!decoder.decode(result.m_isOpaque))
134         return false;
135
136 #if USE(IOSURFACE)
137     if (result.m_acceleratesDrawing) {
138         MachSendRight sendRight;
139         if (!decoder.decode(sendRight))
140             return false;
141         result.m_frontBuffer.surface = IOSurface::createFromSendRight(sendRight, ColorSpaceDeviceRGB);
142         return true;
143     }
144 #endif
145
146     ASSERT(!result.m_acceleratesDrawing);
147
148     ShareableBitmap::Handle handle;
149     if (!decoder.decode(handle))
150         return false;
151     result.m_frontBuffer.bitmap = ShareableBitmap::create(handle);
152
153     return true;
154 }
155
156 void RemoteLayerBackingStore::setNeedsDisplay(const IntRect rect)
157 {
158     m_dirtyRegion.unite(rect);
159 }
160
161 void RemoteLayerBackingStore::setNeedsDisplay()
162 {
163     setNeedsDisplay(IntRect(IntPoint(), expandedIntSize(m_size)));
164 }
165
166 IntSize RemoteLayerBackingStore::backingStoreSize() const
167 {
168     FloatSize scaledSize = m_size;
169     scaledSize.scale(m_scale);
170     return roundedIntSize(scaledSize);
171 }
172
173 void RemoteLayerBackingStore::swapToValidFrontBuffer()
174 {
175     IntSize expandedScaledSize = backingStoreSize();
176
177 #if USE(IOSURFACE)
178     if (m_acceleratesDrawing) {
179         if (!m_backBuffer.surface || m_backBuffer.surface->isInUse()) {
180             std::swap(m_backBuffer, m_secondaryBackBuffer);
181             if (m_backBuffer.surface && m_backBuffer.surface->isInUse())
182                 m_backBuffer.discard();
183         }
184
185         std::swap(m_frontBuffer, m_backBuffer);
186
187         if (!m_frontBuffer.surface)
188             m_frontBuffer.surface = IOSurface::create(expandedScaledSize, ColorSpaceDeviceRGB);
189
190         setBufferVolatility(BufferType::Front, false);
191
192         return;
193     }
194 #endif
195
196     ASSERT(!m_acceleratesDrawing);
197     std::swap(m_frontBuffer, m_backBuffer);
198
199     if (!m_frontBuffer.bitmap)
200         m_frontBuffer.bitmap = ShareableBitmap::createShareable(expandedScaledSize, m_isOpaque ? ShareableBitmap::NoFlags : ShareableBitmap::SupportsAlpha);
201 }
202
203 bool RemoteLayerBackingStore::display()
204 {
205     ASSERT(!m_frontContextPendingFlush);
206
207     m_lastDisplayTime = std::chrono::steady_clock::now();
208
209     if (RemoteLayerTreeContext* context = m_layer->context())
210         context->backingStoreWillBeDisplayed(*this);
211
212     // Make the previous front buffer non-volatile early, so that we can dirty the whole layer if it comes back empty.
213     setBufferVolatility(BufferType::Front, false);
214
215     IntSize expandedScaledSize = backingStoreSize();
216
217     if (m_dirtyRegion.isEmpty() || expandedScaledSize.isEmpty())
218         return false;
219
220     IntRect layerBounds(IntPoint(), expandedIntSize(m_size));
221     if (!hasFrontBuffer())
222         m_dirtyRegion.unite(layerBounds);
223
224     if (m_layer->owner()->platformCALayerShowRepaintCounter(m_layer)) {
225         IntRect indicatorRect(0, 0, 52, 27);
226         m_dirtyRegion.unite(indicatorRect);
227     }
228
229     IntRect expandedScaledLayerBounds(IntPoint(), expandedScaledSize);
230     bool willPaintEntireBackingStore = m_dirtyRegion.contains(layerBounds);
231
232     swapToValidFrontBuffer();
233
234 #if USE(IOSURFACE)
235     if (m_acceleratesDrawing) {
236         RetainPtr<CGImageRef> backImage;
237         if (m_backBuffer.surface && !willPaintEntireBackingStore)
238             backImage = m_backBuffer.surface->createImage();
239
240         GraphicsContext& context = m_frontBuffer.surface->ensureGraphicsContext();
241
242         context.scale(FloatSize(1, -1));
243         context.translate(0, -expandedScaledSize.height());
244         drawInContext(context, backImage.get());
245
246         m_frontBuffer.surface->releaseGraphicsContext();
247     } else
248 #endif
249     {
250         ASSERT(!m_acceleratesDrawing);
251         std::unique_ptr<GraphicsContext> context = m_frontBuffer.bitmap->createGraphicsContext();
252
253         RetainPtr<CGImageRef> backImage;
254         if (m_backBuffer.bitmap && !willPaintEntireBackingStore)
255             backImage = m_backBuffer.bitmap->makeCGImage();
256
257         drawInContext(*context, backImage.get());
258     }
259     
260     m_layer->owner()->platformCALayerLayerDidDisplay(m_layer);
261     
262     return true;
263 }
264
265 void RemoteLayerBackingStore::drawInContext(GraphicsContext& context, CGImageRef backImage)
266 {
267     FloatSize scaledSize = m_size;
268     scaledSize.scale(m_scale);
269     IntRect scaledLayerBounds(IntPoint(), roundedIntSize(scaledSize));
270
271     if (!m_isOpaque)
272         context.clearRect(scaledLayerBounds);
273
274 #ifndef NDEBUG
275     if (m_isOpaque)
276         context.fillRect(scaledLayerBounds, Color(255, 0, 0), ColorSpaceDeviceRGB);
277 #endif
278
279     CGContextRef cgContext = context.platformContext();
280
281     // If we have less than webLayerMaxRectsToPaint rects to paint and they cover less
282     // than webLayerWastedSpaceThreshold of the total dirty area, we'll repaint each rect separately.
283     // Otherwise, repaint the entire bounding box of the dirty region.
284     IntRect dirtyBounds = m_dirtyRegion.bounds();
285
286     Vector<IntRect> dirtyRects = m_dirtyRegion.rects();
287     if (dirtyRects.size() > PlatformCALayer::webLayerMaxRectsToPaint || m_dirtyRegion.totalArea() > PlatformCALayer::webLayerWastedSpaceThreshold * dirtyBounds.width() * dirtyBounds.height()) {
288         dirtyRects.clear();
289         dirtyRects.append(dirtyBounds);
290     }
291
292     // FIXME: find a consistent way to scale and snap dirty and CG clip rects.
293     for (const auto& rect : dirtyRects) {
294         FloatRect scaledRect(rect);
295         scaledRect.scale(m_scale);
296         scaledRect = enclosingIntRect(scaledRect);
297         scaledRect.scale(1 / m_scale);
298         m_paintingRects.append(scaledRect);
299     }
300
301     CGRect cgPaintingRects[PlatformCALayer::webLayerMaxRectsToPaint];
302     for (size_t i = 0, dirtyRectCount = m_paintingRects.size(); i < dirtyRectCount; ++i) {
303         FloatRect scaledPaintingRect = m_paintingRects[i];
304         scaledPaintingRect.scale(m_scale);
305         cgPaintingRects[i] = scaledPaintingRect;
306     }
307
308     if (backImage) {
309         CGContextSaveGState(cgContext);
310         CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
311
312         CGContextAddRect(cgContext, CGRectInfinite);
313         CGContextAddRects(cgContext, cgPaintingRects, m_paintingRects.size());
314         CGContextEOClip(cgContext);
315
316         CGContextTranslateCTM(cgContext, 0, scaledLayerBounds.height());
317         CGContextScaleCTM(cgContext, 1, -1);
318         CGContextDrawImage(cgContext, scaledLayerBounds, backImage);
319         CGContextRestoreGState(cgContext);
320     }
321
322     CGContextClipToRects(cgContext, cgPaintingRects, m_paintingRects.size());
323
324     context.scale(FloatSize(m_scale, m_scale));
325
326     // FIXME: This should be moved to PlatformCALayerRemote for better layering.
327     switch (m_layer->layerType()) {
328     case PlatformCALayer::LayerTypeSimpleLayer:
329     case PlatformCALayer::LayerTypeTiledBackingTileLayer:
330         m_layer->owner()->platformCALayerPaintContents(m_layer, context, dirtyBounds);
331         break;
332     case PlatformCALayer::LayerTypeWebLayer:
333         PlatformCALayer::drawLayerContents(cgContext, m_layer, m_paintingRects);
334         break;
335     case PlatformCALayer::LayerTypeLayer:
336     case PlatformCALayer::LayerTypeTransformLayer:
337     case PlatformCALayer::LayerTypeWebTiledLayer:
338     case PlatformCALayer::LayerTypeTiledBackingLayer:
339     case PlatformCALayer::LayerTypePageTiledBackingLayer:
340     case PlatformCALayer::LayerTypeRootLayer:
341     case PlatformCALayer::LayerTypeAVPlayerLayer:
342     case PlatformCALayer::LayerTypeWebGLLayer:
343     case PlatformCALayer::LayerTypeBackdropLayer:
344     case PlatformCALayer::LayerTypeShapeLayer:
345     case PlatformCALayer::LayerTypeScrollingLayer:
346     case PlatformCALayer::LayerTypeCustom:
347         ASSERT_NOT_REACHED();
348         break;
349     };
350
351     m_dirtyRegion = Region();
352     m_paintingRects.clear();
353
354     m_frontContextPendingFlush = context.platformContext();
355 }
356
357 void RemoteLayerBackingStore::enumerateRectsBeingDrawn(CGContextRef context, void (^block)(CGRect))
358 {
359     CGAffineTransform inverseTransform = CGAffineTransformInvert(CGContextGetCTM(context));
360
361     // We don't want to un-apply the flipping or contentsScale,
362     // because they're not applied to repaint rects.
363     inverseTransform = CGAffineTransformScale(inverseTransform, m_scale, -m_scale);
364     inverseTransform = CGAffineTransformTranslate(inverseTransform, 0, -m_size.height());
365
366     for (const auto& rect : m_paintingRects) {
367         CGRect rectToDraw = CGRectApplyAffineTransform(rect, inverseTransform);
368         block(rectToDraw);
369     }
370 }
371
372 void RemoteLayerBackingStore::applyBackingStoreToLayer(CALayer *layer)
373 {
374     layer.contentsOpaque = m_isOpaque;
375
376 #if USE(IOSURFACE)
377     if (acceleratesDrawing()) {
378         layer.contents = (id)m_frontBuffer.surface->surface();
379         return;
380     }
381 #endif
382
383     ASSERT(!acceleratesDrawing());
384     layer.contents = (id)m_frontBuffer.bitmap->makeCGImageCopy().get();
385 }
386
387 RetainPtr<CGContextRef> RemoteLayerBackingStore::takeFrontContextPendingFlush()
388 {
389     return WTF::move(m_frontContextPendingFlush);
390 }
391
392 #if USE(IOSURFACE)
393 bool RemoteLayerBackingStore::setBufferVolatility(BufferType type, bool isVolatile)
394 {
395     switch(type) {
396     case BufferType::Front:
397         if (m_frontBuffer.surface && m_frontBuffer.isVolatile != isVolatile) {
398             if (isVolatile)
399                 m_frontBuffer.surface->releaseGraphicsContext();
400             if (!isVolatile || !m_frontBuffer.surface->isInUse()) {
401                 IOSurface::SurfaceState previousState = m_frontBuffer.surface->setIsVolatile(isVolatile);
402                 m_frontBuffer.isVolatile = isVolatile;
403
404                 // Becoming non-volatile and the front buffer was purged, so we need to repaint.
405                 if (!isVolatile && (previousState == IOSurface::SurfaceState::Empty))
406                     setNeedsDisplay();
407             } else
408                 return false;
409         }
410         break;
411     case BufferType::Back:
412         if (m_backBuffer.surface && m_backBuffer.isVolatile != isVolatile) {
413             if (isVolatile)
414                 m_backBuffer.surface->releaseGraphicsContext();
415             if (!isVolatile || !m_backBuffer.surface->isInUse()) {
416                 m_backBuffer.surface->setIsVolatile(isVolatile);
417                 m_backBuffer.isVolatile = isVolatile;
418             } else
419                 return false;
420         }
421         break;
422     case BufferType::SecondaryBack:
423         if (m_secondaryBackBuffer.surface && m_secondaryBackBuffer.isVolatile != isVolatile) {
424             if (isVolatile)
425                 m_secondaryBackBuffer.surface->releaseGraphicsContext();
426             if (!isVolatile || !m_secondaryBackBuffer.surface->isInUse()) {
427                 m_secondaryBackBuffer.surface->setIsVolatile(isVolatile);
428                 m_secondaryBackBuffer.isVolatile = isVolatile;
429             } else
430                 return false;
431         }
432         break;
433     }
434     return true;
435 }
436 #else
437 bool RemoteLayerBackingStore::setBufferVolatility(BufferType, bool)
438 {
439     return true;
440 }
441 #endif
442
443 void RemoteLayerBackingStore::Buffer::discard()
444 {
445 #if USE(IOSURFACE)
446     if (surface)
447         IOSurfacePool::sharedPool().addSurface(WTF::move(surface));
448     isVolatile = false;
449 #endif
450     bitmap = nullptr;
451 }
452
453 } // namespace WebKit