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
44namespace WebCore {
45
46CompositingCoordinator::~CompositingCoordinator()
47{
48    purgeBackingStores();
49
50    for (auto& registeredLayer : m_registeredLayers.values())
51        registeredLayer->setCoordinator(0);
52}
53
54CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinator::Client* client)
55    : m_page(page)
56    , m_client(client)
57    , m_rootCompositingLayer(0)
58    , m_isPurging(false)
59    , m_isFlushingLayerChanges(false)
60    , m_shouldSyncFrame(false)
61    , m_didInitializeRootCompositingLayer(false)
62    , m_releaseInactiveAtlasesTimer(this, &CompositingCoordinator::releaseInactiveAtlasesTimerFired)
63#if ENABLE(REQUEST_ANIMATION_FRAME)
64    , m_lastAnimationServiceTime(0)
65#endif
66{
67    m_page->settings().setApplyDeviceScaleFactorInCompositor(true);
68
69    // This is a temporary way to enable this only in the GL case, until TextureMapperImageBuffer is removed.
70    // See https://bugs.webkit.org/show_bug.cgi?id=114869
71    CoordinatedGraphicsLayer::setShouldSupportContentsTiling(true);
72}
73
74void CompositingCoordinator::setRootCompositingLayer(GraphicsLayer* compositingLayer, GraphicsLayer* overlayLayer)
75{
76    if (m_rootCompositingLayer)
77        m_rootCompositingLayer->removeFromParent();
78
79    m_rootCompositingLayer = compositingLayer;
80    if (m_rootCompositingLayer)
81        m_rootLayer->addChildAtIndex(m_rootCompositingLayer, 0);
82
83    if (overlayLayer)
84        m_rootLayer->addChild(overlayLayer);
85}
86
87void CompositingCoordinator::sizeDidChange(const IntSize& newSize)
88{
89    m_rootLayer->setSize(newSize);
90    notifyFlushRequired(m_rootLayer.get());
91}
92
93bool CompositingCoordinator::flushPendingLayerChanges()
94{
95    TemporaryChange<bool> protector(m_isFlushingLayerChanges, true);
96
97    initializeRootCompositingLayerIfNeeded();
98
99    m_rootLayer->flushCompositingStateForThisLayerOnly();
100    m_client->didFlushRootLayer(m_visibleContentsRect);
101
102    bool didSync = m_page->mainFrame().view()->flushCompositingStateIncludingSubframes();
103
104    toCoordinatedGraphicsLayer(m_rootLayer.get())->updateContentBuffersIncludingSubLayers();
105    toCoordinatedGraphicsLayer(m_rootLayer.get())->syncPendingStateChangesIncludingSubLayers();
106
107    flushPendingImageBackingChanges();
108
109    if (m_shouldSyncFrame) {
110        didSync = true;
111
112        if (m_rootCompositingLayer) {
113            m_state.contentsSize = roundedIntSize(m_rootCompositingLayer->size());
114            if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
115                m_state.coveredRect = contentsLayer->coverRect();
116        }
117        m_state.scrollPosition = m_visibleContentsRect.location();
118
119        m_client->commitSceneState(m_state);
120
121        clearPendingStateChanges();
122        m_shouldSyncFrame = false;
123    }
124
125    return didSync;
126}
127
128void CompositingCoordinator::syncDisplayState()
129{
130#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
131    // Make sure that any previously registered animation callbacks are being executed before we flush the layers.
132    m_lastAnimationServiceTime = WTF::monotonicallyIncreasingTime();
133    m_page->mainFrame().view()->serviceScriptedAnimations(m_lastAnimationServiceTime);
134#endif
135    m_page->mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
136}
137
138#if ENABLE(REQUEST_ANIMATION_FRAME)
139double CompositingCoordinator::nextAnimationServiceTime() const
140{
141    // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS.
142    static const double MinimalTimeoutForAnimations = 1. / 60.;
143    return std::max<double>(0., MinimalTimeoutForAnimations - WTF::monotonicallyIncreasingTime() + m_lastAnimationServiceTime);
144}
145#endif
146
147void CompositingCoordinator::clearPendingStateChanges()
148{
149    m_state.layersToCreate.clear();
150    m_state.layersToUpdate.clear();
151    m_state.layersToRemove.clear();
152
153    m_state.imagesToCreate.clear();
154    m_state.imagesToRemove.clear();
155    m_state.imagesToUpdate.clear();
156    m_state.imagesToClear.clear();
157
158    m_state.updateAtlasesToCreate.clear();
159    m_state.updateAtlasesToRemove.clear();
160}
161
162void CompositingCoordinator::initializeRootCompositingLayerIfNeeded()
163{
164    if (m_didInitializeRootCompositingLayer)
165        return;
166
167    m_state.rootCompositingLayer = toCoordinatedGraphicsLayer(m_rootLayer.get())->id();
168    m_didInitializeRootCompositingLayer = true;
169    m_shouldSyncFrame = true;
170}
171
172void CompositingCoordinator::createRootLayer(const IntSize& size)
173{
174    ASSERT(!m_rootLayer);
175    // Create a root layer.
176    m_rootLayer = GraphicsLayer::create(this, *this);
177#ifndef NDEBUG
178    m_rootLayer->setName("CompositingCoordinator root layer");
179#endif
180    m_rootLayer->setDrawsContent(false);
181    m_rootLayer->setSize(size);
182}
183
184void CompositingCoordinator::syncLayerState(CoordinatedLayerID id, CoordinatedGraphicsLayerState& state)
185{
186    m_shouldSyncFrame = true;
187    m_state.layersToUpdate.append(std::make_pair(id, state));
188}
189
190PassRefPtr<CoordinatedImageBacking> CompositingCoordinator::createImageBackingIfNeeded(Image* image)
191{
192    CoordinatedImageBackingID imageID = CoordinatedImageBacking::getCoordinatedImageBackingID(image);
193    ImageBackingMap::iterator it = m_imageBackings.find(imageID);
194    RefPtr<CoordinatedImageBacking> imageBacking;
195    if (it == m_imageBackings.end()) {
196        imageBacking = CoordinatedImageBacking::create(this, image);
197        m_imageBackings.add(imageID, imageBacking);
198    } else
199        imageBacking = it->value;
200
201    return imageBacking;
202}
203
204void CompositingCoordinator::createImageBacking(CoordinatedImageBackingID imageID)
205{
206    m_state.imagesToCreate.append(imageID);
207}
208
209void CompositingCoordinator::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
210{
211    m_shouldSyncFrame = true;
212    m_state.imagesToUpdate.append(std::make_pair(imageID, coordinatedSurface));
213}
214
215void CompositingCoordinator::clearImageBackingContents(CoordinatedImageBackingID imageID)
216{
217    m_shouldSyncFrame = true;
218    m_state.imagesToClear.append(imageID);
219}
220
221void CompositingCoordinator::removeImageBacking(CoordinatedImageBackingID imageID)
222{
223    if (m_isPurging)
224        return;
225
226    ASSERT(m_imageBackings.contains(imageID));
227    m_imageBackings.remove(imageID);
228
229    m_state.imagesToRemove.append(imageID);
230
231    size_t imageIDPosition = m_state.imagesToClear.find(imageID);
232    if (imageIDPosition != notFound)
233        m_state.imagesToClear.remove(imageIDPosition);
234}
235
236void CompositingCoordinator::flushPendingImageBackingChanges()
237{
238    for (auto& imageBacking : m_imageBackings.values())
239        imageBacking->update();
240}
241
242void CompositingCoordinator::notifyAnimationStarted(const GraphicsLayer*, double /* time */)
243{
244}
245
246void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*)
247{
248    if (!isFlushingLayerChanges())
249        m_client->notifyFlushRequired();
250}
251
252
253void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect)
254{
255    m_client->paintLayerContents(graphicsLayer, graphicsContext, enclosingIntRect(clipRect));
256}
257
258std::unique_ptr<GraphicsLayer> CompositingCoordinator::createGraphicsLayer(GraphicsLayerClient& client)
259{
260    CoordinatedGraphicsLayer* layer = new CoordinatedGraphicsLayer(client);
261    layer->setCoordinator(this);
262    m_registeredLayers.add(layer->id(), layer);
263    m_state.layersToCreate.append(layer->id());
264    layer->setNeedsVisibleRectAdjustment();
265    notifyFlushRequired(layer);
266    return std::unique_ptr<GraphicsLayer>(layer);
267}
268
269float CompositingCoordinator::deviceScaleFactor() const
270{
271    return m_page->deviceScaleFactor();
272}
273
274float CompositingCoordinator::pageScaleFactor() const
275{
276    return m_page->pageScaleFactor();
277}
278
279void CompositingCoordinator::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
280{
281    m_state.updateAtlasesToCreate.append(std::make_pair(atlasID, coordinatedSurface));
282}
283
284void CompositingCoordinator::removeUpdateAtlas(uint32_t atlasID)
285{
286    if (m_isPurging)
287        return;
288    m_state.updateAtlasesToRemove.append(atlasID);
289}
290
291FloatRect CompositingCoordinator::visibleContentsRect() const
292{
293    return m_visibleContentsRect;
294}
295
296CoordinatedGraphicsLayer* CompositingCoordinator::mainContentsLayer()
297{
298    if (!m_rootCompositingLayer)
299        return 0;
300
301    return toCoordinatedGraphicsLayer(m_rootCompositingLayer)->findFirstDescendantWithContentsRecursively();
302}
303
304void CompositingCoordinator::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector)
305{
306    // A zero trajectoryVector indicates that tiles all around the viewport are requested.
307    if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
308        contentsLayer->setVisibleContentRectTrajectoryVector(trajectoryVector);
309
310    bool contentsRectDidChange = rect != m_visibleContentsRect;
311    if (contentsRectDidChange) {
312        m_visibleContentsRect = rect;
313
314        for (auto& registeredLayer : m_registeredLayers.values())
315            registeredLayer->setNeedsVisibleRectAdjustment();
316    }
317
318    FrameView* view = m_page->mainFrame().view();
319    if (view->useFixedLayout()) {
320        // Round the rect instead of enclosing it to make sure that its size stays
321        // the same while panning. This can have nasty effects on layout.
322        view->setFixedVisibleContentRect(roundedIntRect(rect));
323    }
324}
325
326void CompositingCoordinator::deviceOrPageScaleFactorChanged()
327{
328    m_rootLayer->deviceOrPageScaleFactorChanged();
329}
330
331void CompositingCoordinator::detachLayer(CoordinatedGraphicsLayer* layer)
332{
333    if (m_isPurging)
334        return;
335
336    m_registeredLayers.remove(layer->id());
337
338    size_t index = m_state.layersToCreate.find(layer->id());
339    if (index != notFound) {
340        m_state.layersToCreate.remove(index);
341        return;
342    }
343
344    m_state.layersToRemove.append(layer->id());
345    notifyFlushRequired(layer);
346}
347
348void CompositingCoordinator::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset)
349{
350    LayerMap::iterator i = m_registeredLayers.find(layerID);
351    if (i == m_registeredLayers.end())
352        return;
353
354    i->value->commitScrollOffset(offset);
355}
356
357void CompositingCoordinator::renderNextFrame()
358{
359    for (unsigned i = 0; i < m_updateAtlases.size(); ++i)
360        m_updateAtlases[i]->didSwapBuffers();
361}
362
363void CompositingCoordinator::purgeBackingStores()
364{
365    TemporaryChange<bool> purgingToggle(m_isPurging, true);
366
367    for (auto& registeredLayer : m_registeredLayers.values())
368        registeredLayer->purgeBackingStores();
369
370    m_imageBackings.clear();
371    m_updateAtlases.clear();
372}
373
374bool CompositingCoordinator::paintToSurface(const IntSize& size, CoordinatedSurface::Flags flags, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client* client)
375{
376    for (unsigned i = 0; i < m_updateAtlases.size(); ++i) {
377        UpdateAtlas* atlas = m_updateAtlases[i].get();
378        if (atlas->supportsAlpha() == (flags & CoordinatedSurface::SupportsAlpha)) {
379            // This will be false if there is no available buffer space.
380            if (atlas->paintOnAvailableBuffer(size, atlasID, offset, client))
381                return true;
382        }
383    }
384
385    static const int ScratchBufferDimension = 1024; // Should be a power of two.
386    m_updateAtlases.append(std::make_unique<UpdateAtlas>(this, ScratchBufferDimension, flags));
387    scheduleReleaseInactiveAtlases();
388    return m_updateAtlases.last()->paintOnAvailableBuffer(size, atlasID, offset, client);
389}
390
391const double ReleaseInactiveAtlasesTimerInterval = 0.5;
392
393void CompositingCoordinator::scheduleReleaseInactiveAtlases()
394{
395    if (!m_releaseInactiveAtlasesTimer.isActive())
396        m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval);
397}
398
399void CompositingCoordinator::releaseInactiveAtlasesTimerFired(Timer<CompositingCoordinator>*)
400{
401    // We always want to keep one atlas for root contents layer.
402    std::unique_ptr<UpdateAtlas> atlasToKeepAnyway;
403    bool foundActiveAtlasForRootContentsLayer = false;
404    for (int i = m_updateAtlases.size() - 1;  i >= 0; --i) {
405        UpdateAtlas* atlas = m_updateAtlases[i].get();
406        if (!atlas->isInUse())
407            atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval);
408        bool usableForRootContentsLayer = !atlas->supportsAlpha();
409        if (atlas->isInactive()) {
410            if (!foundActiveAtlasForRootContentsLayer && !atlasToKeepAnyway && usableForRootContentsLayer)
411                atlasToKeepAnyway = WTF::move(m_updateAtlases[i]);
412            m_updateAtlases.remove(i);
413        } else if (usableForRootContentsLayer)
414            foundActiveAtlasForRootContentsLayer = true;
415    }
416
417    if (!foundActiveAtlasForRootContentsLayer && atlasToKeepAnyway)
418        m_updateAtlases.append(atlasToKeepAnyway.release());
419
420    if (m_updateAtlases.size() <= 1)
421        m_releaseInactiveAtlasesTimer.stop();
422}
423
424} // namespace WebCore
425
426#endif // USE(COORDINATED_GRAPHICS)
427