ddeb0c32e2c6375c1e6776ece313f7a9c8915bd3
[WebKit-https.git] / Source / WebCore / platform / graphics / texmap / coordinated / CompositingCoordinator.cpp
1 /*
2  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
3  * Copyright (C) 2013 Company 100, Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if USE(COORDINATED_GRAPHICS)
30
31 #include "CompositingCoordinator.h"
32
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "InspectorController.h"
36 #include "MainFrame.h"
37 #include "Page.h"
38 #include "Settings.h"
39 #include <wtf/CurrentTime.h>
40 #include <wtf/TemporaryChange.h>
41
42 // FIXME: Having this in the platform directory is a layering violation. This does not belong here.
43
44 namespace WebCore {
45
46 CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinator::Client* client)
47     : m_page(page)
48     , m_client(client)
49     , m_rootCompositingLayer(nullptr)
50     , m_overlayCompositingLayer(nullptr)
51     , m_isDestructing(false)
52     , m_isPurging(false)
53     , m_isFlushingLayerChanges(false)
54     , m_shouldSyncFrame(false)
55     , m_didInitializeRootCompositingLayer(false)
56     , m_releaseInactiveAtlasesTimer(*this, &CompositingCoordinator::releaseInactiveAtlasesTimerFired)
57 #if ENABLE(REQUEST_ANIMATION_FRAME)
58     , m_lastAnimationServiceTime(0)
59 #endif
60 {
61 }
62
63 CompositingCoordinator::~CompositingCoordinator()
64 {
65     m_isDestructing = true;
66
67     purgeBackingStores();
68
69     for (auto& registeredLayer : m_registeredLayers.values())
70         registeredLayer->setCoordinator(nullptr);
71 }
72
73 void CompositingCoordinator::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
74 {
75     if (m_rootCompositingLayer == graphicsLayer)
76         return;
77
78     if (m_rootCompositingLayer)
79         m_rootCompositingLayer->removeFromParent();
80
81     m_rootCompositingLayer = graphicsLayer;
82     if (m_rootCompositingLayer)
83         m_rootLayer->addChildAtIndex(m_rootCompositingLayer, 0);
84 }
85
86 void CompositingCoordinator::setViewOverlayRootLayer(GraphicsLayer* graphicsLayer)
87 {
88     if (m_overlayCompositingLayer == graphicsLayer)
89         return;
90
91     if (m_overlayCompositingLayer)
92         m_overlayCompositingLayer->removeFromParent();
93
94     m_overlayCompositingLayer = graphicsLayer;
95     if (m_overlayCompositingLayer)
96         m_rootLayer->addChild(m_overlayCompositingLayer);
97 }
98
99 void CompositingCoordinator::sizeDidChange(const IntSize& newSize)
100 {
101     m_rootLayer->setSize(newSize);
102     notifyFlushRequired(m_rootLayer.get());
103 }
104
105 bool CompositingCoordinator::flushPendingLayerChanges()
106 {
107     TemporaryChange<bool> protector(m_isFlushingLayerChanges, true);
108
109     initializeRootCompositingLayerIfNeeded();
110
111     bool viewportIsStable = m_page->mainFrame().view()->viewportIsStable();
112     m_rootLayer->flushCompositingStateForThisLayerOnly(viewportIsStable);
113     m_client->didFlushRootLayer(m_visibleContentsRect);
114
115     if (m_overlayCompositingLayer)
116         m_overlayCompositingLayer->flushCompositingState(FloatRect(FloatPoint(), m_rootLayer->size()), viewportIsStable);
117
118     bool didSync = m_page->mainFrame().view()->flushCompositingStateIncludingSubframes();
119
120     toCoordinatedGraphicsLayer(m_rootLayer.get())->updateContentBuffersIncludingSubLayers();
121     toCoordinatedGraphicsLayer(m_rootLayer.get())->syncPendingStateChangesIncludingSubLayers();
122
123     flushPendingImageBackingChanges();
124
125     if (m_shouldSyncFrame) {
126         didSync = true;
127
128         if (m_rootCompositingLayer) {
129             m_state.contentsSize = roundedIntSize(m_rootCompositingLayer->size());
130             if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
131                 m_state.coveredRect = contentsLayer->coverRect();
132         }
133         m_state.scrollPosition = m_visibleContentsRect.location();
134
135         m_client->commitSceneState(m_state);
136
137         clearPendingStateChanges();
138         m_shouldSyncFrame = false;
139     }
140
141     return didSync;
142 }
143
144 void CompositingCoordinator::syncDisplayState()
145 {
146 #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
147     // Make sure that any previously registered animation callbacks are being executed before we flush the layers.
148     m_lastAnimationServiceTime = WTF::monotonicallyIncreasingTime();
149     m_page->mainFrame().view()->serviceScriptedAnimations(m_lastAnimationServiceTime);
150 #endif
151     m_page->mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
152 }
153
154 #if ENABLE(REQUEST_ANIMATION_FRAME)
155 double CompositingCoordinator::nextAnimationServiceTime() const
156 {
157     // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS.
158     static const double MinimalTimeoutForAnimations = 1. / 60.;
159     return std::max<double>(0., MinimalTimeoutForAnimations - WTF::monotonicallyIncreasingTime() + m_lastAnimationServiceTime);
160 }
161 #endif
162
163 void CompositingCoordinator::clearPendingStateChanges()
164 {
165     m_state.layersToCreate.clear();
166     m_state.layersToUpdate.clear();
167     m_state.layersToRemove.clear();
168
169     m_state.imagesToCreate.clear();
170     m_state.imagesToRemove.clear();
171     m_state.imagesToUpdate.clear();
172     m_state.imagesToClear.clear();
173
174     m_state.updateAtlasesToCreate.clear();
175     m_state.updateAtlasesToRemove.clear();
176 }
177
178 void CompositingCoordinator::initializeRootCompositingLayerIfNeeded()
179 {
180     if (m_didInitializeRootCompositingLayer)
181         return;
182
183     m_state.rootCompositingLayer = toCoordinatedGraphicsLayer(m_rootLayer.get())->id();
184     m_didInitializeRootCompositingLayer = true;
185     m_shouldSyncFrame = true;
186 }
187
188 void CompositingCoordinator::createRootLayer(const IntSize& size)
189 {
190     ASSERT(!m_rootLayer);
191     // Create a root layer.
192     m_rootLayer = GraphicsLayer::create(this, *this);
193 #ifndef NDEBUG
194     m_rootLayer->setName("CompositingCoordinator root layer");
195 #endif
196     m_rootLayer->setDrawsContent(false);
197     m_rootLayer->setSize(size);
198 }
199
200 void CompositingCoordinator::syncLayerState(CoordinatedLayerID id, CoordinatedGraphicsLayerState& state)
201 {
202     m_shouldSyncFrame = true;
203     m_state.layersToUpdate.append(std::make_pair(id, state));
204 }
205
206 PassRefPtr<CoordinatedImageBacking> CompositingCoordinator::createImageBackingIfNeeded(Image* image)
207 {
208     CoordinatedImageBackingID imageID = CoordinatedImageBacking::getCoordinatedImageBackingID(image);
209     ImageBackingMap::iterator it = m_imageBackings.find(imageID);
210     RefPtr<CoordinatedImageBacking> imageBacking;
211     if (it == m_imageBackings.end()) {
212         imageBacking = CoordinatedImageBacking::create(this, image);
213         m_imageBackings.add(imageID, imageBacking);
214     } else
215         imageBacking = it->value;
216
217     return imageBacking;
218 }
219
220 void CompositingCoordinator::createImageBacking(CoordinatedImageBackingID imageID)
221 {
222     m_state.imagesToCreate.append(imageID);
223 }
224
225 void CompositingCoordinator::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
226 {
227     m_shouldSyncFrame = true;
228     m_state.imagesToUpdate.append(std::make_pair(imageID, coordinatedSurface));
229 }
230
231 void CompositingCoordinator::clearImageBackingContents(CoordinatedImageBackingID imageID)
232 {
233     m_shouldSyncFrame = true;
234     m_state.imagesToClear.append(imageID);
235 }
236
237 void CompositingCoordinator::removeImageBacking(CoordinatedImageBackingID imageID)
238 {
239     if (m_isPurging)
240         return;
241
242     ASSERT(m_imageBackings.contains(imageID));
243     m_imageBackings.remove(imageID);
244
245     m_state.imagesToRemove.append(imageID);
246
247     size_t imageIDPosition = m_state.imagesToClear.find(imageID);
248     if (imageIDPosition != notFound)
249         m_state.imagesToClear.remove(imageIDPosition);
250 }
251
252 void CompositingCoordinator::flushPendingImageBackingChanges()
253 {
254     for (auto& imageBacking : m_imageBackings.values())
255         imageBacking->update();
256 }
257
258 void CompositingCoordinator::notifyAnimationStarted(const GraphicsLayer*, const String&, double /* time */)
259 {
260 }
261
262 void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*)
263 {
264     if (!m_isDestructing && !isFlushingLayerChanges())
265         m_client->notifyFlushRequired();
266 }
267
268 void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect)
269 {
270     m_client->paintLayerContents(graphicsLayer, graphicsContext, enclosingIntRect(clipRect));
271 }
272
273 std::unique_ptr<GraphicsLayer> CompositingCoordinator::createGraphicsLayer(GraphicsLayer::Type layerType, GraphicsLayerClient& client)
274 {
275     CoordinatedGraphicsLayer* layer = new CoordinatedGraphicsLayer(layerType, client);
276     layer->setCoordinator(this);
277     m_registeredLayers.add(layer->id(), layer);
278     m_state.layersToCreate.append(layer->id());
279     layer->setNeedsVisibleRectAdjustment();
280     notifyFlushRequired(layer);
281     return std::unique_ptr<GraphicsLayer>(layer);
282 }
283
284 float CompositingCoordinator::deviceScaleFactor() const
285 {
286     return m_page->deviceScaleFactor();
287 }
288
289 float CompositingCoordinator::pageScaleFactor() const
290 {
291     return m_page->pageScaleFactor();
292 }
293
294 void CompositingCoordinator::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
295 {
296     m_state.updateAtlasesToCreate.append(std::make_pair(atlasID, coordinatedSurface));
297 }
298
299 void CompositingCoordinator::removeUpdateAtlas(uint32_t atlasID)
300 {
301     if (m_isPurging)
302         return;
303     m_state.updateAtlasesToRemove.append(atlasID);
304 }
305
306 FloatRect CompositingCoordinator::visibleContentsRect() const
307 {
308     return m_visibleContentsRect;
309 }
310
311 CoordinatedGraphicsLayer* CompositingCoordinator::mainContentsLayer()
312 {
313     if (!m_rootCompositingLayer)
314         return 0;
315
316     return toCoordinatedGraphicsLayer(m_rootCompositingLayer)->findFirstDescendantWithContentsRecursively();
317 }
318
319 void CompositingCoordinator::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector)
320 {
321     // A zero trajectoryVector indicates that tiles all around the viewport are requested.
322     if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
323         contentsLayer->setVisibleContentRectTrajectoryVector(trajectoryVector);
324
325     bool contentsRectDidChange = rect != m_visibleContentsRect;
326     if (contentsRectDidChange) {
327         m_visibleContentsRect = rect;
328
329         for (auto& registeredLayer : m_registeredLayers.values())
330             registeredLayer->setNeedsVisibleRectAdjustment();
331     }
332
333     FrameView* view = m_page->mainFrame().view();
334     if (view->useFixedLayout() && contentsRectDidChange) {
335         // Round the rect instead of enclosing it to make sure that its size stays
336         // the same while panning. This can have nasty effects on layout.
337         view->setFixedVisibleContentRect(roundedIntRect(rect));
338     }
339 }
340
341 void CompositingCoordinator::deviceOrPageScaleFactorChanged()
342 {
343     m_rootLayer->deviceOrPageScaleFactorChanged();
344 }
345
346 void CompositingCoordinator::detachLayer(CoordinatedGraphicsLayer* layer)
347 {
348     if (m_isPurging)
349         return;
350
351     m_registeredLayers.remove(layer->id());
352
353     size_t index = m_state.layersToCreate.find(layer->id());
354     if (index != notFound) {
355         m_state.layersToCreate.remove(index);
356         return;
357     }
358
359     m_state.layersToRemove.append(layer->id());
360     notifyFlushRequired(layer);
361 }
362
363 void CompositingCoordinator::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset)
364 {
365     LayerMap::iterator i = m_registeredLayers.find(layerID);
366     if (i == m_registeredLayers.end())
367         return;
368
369     i->value->commitScrollOffset(offset);
370 }
371
372 void CompositingCoordinator::renderNextFrame()
373 {
374     for (auto& atlas : m_updateAtlases)
375         atlas->didSwapBuffers();
376 }
377
378 void CompositingCoordinator::purgeBackingStores()
379 {
380     TemporaryChange<bool> purgingToggle(m_isPurging, true);
381
382     for (auto& registeredLayer : m_registeredLayers.values())
383         registeredLayer->purgeBackingStores();
384
385     m_imageBackings.clear();
386     m_updateAtlases.clear();
387 }
388
389 bool CompositingCoordinator::paintToSurface(const IntSize& size, CoordinatedSurface::Flags flags, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client* client)
390 {
391     for (auto& updateAtlas : m_updateAtlases) {
392         UpdateAtlas* atlas = updateAtlas.get();
393         if (atlas->supportsAlpha() == (flags & CoordinatedSurface::SupportsAlpha)) {
394             // This will be false if there is no available buffer space.
395             if (atlas->paintOnAvailableBuffer(size, atlasID, offset, client))
396                 return true;
397         }
398     }
399
400     static const int ScratchBufferDimension = 1024; // Should be a power of two.
401     m_updateAtlases.append(std::make_unique<UpdateAtlas>(this, ScratchBufferDimension, flags));
402     scheduleReleaseInactiveAtlases();
403     return m_updateAtlases.last()->paintOnAvailableBuffer(size, atlasID, offset, client);
404 }
405
406 const double ReleaseInactiveAtlasesTimerInterval = 0.5;
407
408 void CompositingCoordinator::scheduleReleaseInactiveAtlases()
409 {
410     if (!m_releaseInactiveAtlasesTimer.isActive())
411         m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval);
412 }
413
414 void CompositingCoordinator::releaseInactiveAtlasesTimerFired()
415 {
416     // We always want to keep one atlas for root contents layer.
417     std::unique_ptr<UpdateAtlas> atlasToKeepAnyway;
418     bool foundActiveAtlasForRootContentsLayer = false;
419     for (int i = m_updateAtlases.size() - 1;  i >= 0; --i) {
420         UpdateAtlas* atlas = m_updateAtlases[i].get();
421         if (!atlas->isInUse())
422             atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval);
423         bool usableForRootContentsLayer = !atlas->supportsAlpha();
424         if (atlas->isInactive()) {
425             if (!foundActiveAtlasForRootContentsLayer && !atlasToKeepAnyway && usableForRootContentsLayer)
426                 atlasToKeepAnyway = WTFMove(m_updateAtlases[i]);
427             m_updateAtlases.remove(i);
428         } else if (usableForRootContentsLayer)
429             foundActiveAtlasForRootContentsLayer = true;
430     }
431
432     if (!foundActiveAtlasForRootContentsLayer && atlasToKeepAnyway)
433         m_updateAtlases.append(atlasToKeepAnyway.release());
434
435     m_updateAtlases.shrinkToFit();
436
437     if (m_updateAtlases.size() <= 1)
438         m_releaseInactiveAtlasesTimer.stop();
439 }
440
441 } // namespace WebCore
442
443 #endif // USE(COORDINATED_GRAPHICS)