61af2c08af680f4122573c2f4fcaa7f7a8e3869e
[WebKit.git] / Source / WebKit / Shared / CoordinatedGraphics / CoordinatedGraphicsScene.cpp
1 /*
2     Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3     Copyright (C) 2012 Company 100, Inc.
4     Copyright (C) 2017 Sony Interactive Entertainment Inc.
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20 */
21
22 #include "config.h"
23 #include "CoordinatedGraphicsScene.h"
24
25 #if USE(COORDINATED_GRAPHICS)
26
27 #include <WebCore/CoordinatedBackingStore.h>
28 #include <WebCore/NicosiaBackingStoreTextureMapperImpl.h>
29 #include <WebCore/NicosiaBuffer.h>
30 #include <WebCore/NicosiaCompositionLayerTextureMapperImpl.h>
31 #include <WebCore/NicosiaContentLayerTextureMapperImpl.h>
32 #include <WebCore/NicosiaImageBackingTextureMapperImpl.h>
33 #include <WebCore/NicosiaScene.h>
34 #include <WebCore/TextureMapper.h>
35 #include <WebCore/TextureMapperBackingStore.h>
36 #include <WebCore/TextureMapperGL.h>
37 #include <WebCore/TextureMapperLayer.h>
38 #include <wtf/Atomics.h>
39
40 namespace WebKit {
41 using namespace WebCore;
42
43 static bool layerShouldHaveBackingStore(TextureMapperLayer* layer)
44 {
45     return layer->drawsContent() && layer->contentsAreVisible() && !layer->size().isEmpty();
46 }
47
48 CoordinatedGraphicsScene::CoordinatedGraphicsScene(CoordinatedGraphicsSceneClient* client)
49     : m_client(client)
50 {
51 }
52
53 CoordinatedGraphicsScene::~CoordinatedGraphicsScene() = default;
54
55 void CoordinatedGraphicsScene::applyStateChanges(const Vector<CoordinatedGraphicsState>& states)
56 {
57     if (!m_textureMapper) {
58         m_textureMapper = TextureMapper::create();
59         static_cast<TextureMapperGL*>(m_textureMapper.get())->setEnableEdgeDistanceAntialiasing(true);
60     }
61
62     ensureRootLayer();
63
64     for (auto& state : states)
65         commitSceneState(state.nicosia);
66 }
67
68 void CoordinatedGraphicsScene::paintToCurrentGLContext(const TransformationMatrix& matrix, const FloatRect& clipRect, TextureMapper::PaintFlags PaintFlags)
69 {
70     updateSceneState();
71
72     TextureMapperLayer* currentRootLayer = rootLayer();
73     if (!currentRootLayer)
74         return;
75
76     currentRootLayer->setTextureMapper(m_textureMapper.get());
77     bool sceneHasRunningAnimations = currentRootLayer->applyAnimationsRecursively(MonotonicTime::now());
78     m_textureMapper->beginPainting(PaintFlags);
79     m_textureMapper->beginClip(TransformationMatrix(), clipRect);
80
81     if (currentRootLayer->transform() != matrix)
82         currentRootLayer->setTransform(matrix);
83
84     currentRootLayer->paint();
85     m_fpsCounter.updateFPSAndDisplay(*m_textureMapper, clipRect.location(), matrix);
86     m_textureMapper->endClip();
87     m_textureMapper->endPainting();
88
89     if (sceneHasRunningAnimations)
90         updateViewport();
91 }
92
93 void CoordinatedGraphicsScene::updateViewport()
94 {
95     if (m_client)
96         m_client->updateViewport();
97 }
98
99 void CoordinatedGraphicsScene::onNewBufferAvailable()
100 {
101     updateViewport();
102 }
103
104 Nicosia::CompositionLayerTextureMapperImpl& compositionLayerImpl(Nicosia::CompositionLayer& compositionLayer)
105 {
106     return downcast<Nicosia::CompositionLayerTextureMapperImpl>(compositionLayer.impl());
107 }
108
109 Nicosia::ContentLayerTextureMapperImpl& contentLayerImpl(Nicosia::ContentLayer& contentLayer)
110 {
111     return downcast<Nicosia::ContentLayerTextureMapperImpl>(contentLayer.impl());
112 }
113
114 Nicosia::BackingStoreTextureMapperImpl& backingStoreImpl(Nicosia::BackingStore& backingStore)
115 {
116     return downcast<Nicosia::BackingStoreTextureMapperImpl>(backingStore.impl());
117 }
118
119 Nicosia::ImageBackingTextureMapperImpl& imageBackingImpl(Nicosia::ImageBacking& imageBacking)
120 {
121     return downcast<Nicosia::ImageBackingTextureMapperImpl>(imageBacking.impl());
122 }
123
124 TextureMapperLayer& texmapLayer(Nicosia::CompositionLayer& compositionLayer)
125 {
126     auto& compositionState = compositionLayerImpl(compositionLayer).compositionState();
127     if (!compositionState.layer) {
128         compositionState.layer = makeUnique<TextureMapperLayer>();
129         compositionState.layer->setID(compositionLayer.id());
130     }
131     return *compositionState.layer;
132 }
133
134 void updateBackingStore(TextureMapperLayer& layer,
135     Nicosia::BackingStoreTextureMapperImpl::CompositionState& compositionState,
136     const Nicosia::BackingStoreTextureMapperImpl::TileUpdate& update)
137 {
138     if (!layerShouldHaveBackingStore(&layer)) {
139         layer.setBackingStore(nullptr);
140         compositionState.backingStore = nullptr;
141         return;
142     }
143
144     if (!compositionState.backingStore)
145         compositionState.backingStore = CoordinatedBackingStore::create();
146     auto& backingStore = *compositionState.backingStore;
147
148     layer.setBackingStore(&backingStore);
149     backingStore.setSize(layer.size());
150
151     for (auto& tile : update.tilesToCreate)
152         backingStore.createTile(tile.tileID, tile.scale);
153     for (auto& tile : update.tilesToRemove)
154         backingStore.removeTile(tile.tileID);
155     for (auto& tile : update.tilesToUpdate) {
156         backingStore.updateTile(tile.tileID, tile.updateInfo.updateRect,
157             tile.tileRect, tile.updateInfo.buffer.copyRef(), { 0, 0 });
158     }
159 }
160
161 void updateImageBacking(TextureMapperLayer& layer,
162     Nicosia::ImageBackingTextureMapperImpl::CompositionState& compositionState,
163     Nicosia::ImageBackingTextureMapperImpl::Update& update)
164 {
165     if (!update.isVisible) {
166         layer.setBackingStore(nullptr);
167         return;
168     }
169
170     if (!compositionState.backingStore)
171         compositionState.backingStore = CoordinatedBackingStore::create();
172     auto& backingStore = *compositionState.backingStore;
173     layer.setContentsLayer(&backingStore);
174
175     if (!update.buffer)
176         return;
177
178     backingStore.createTile(1, 1.0);
179     WebCore::IntRect rect { { }, update.buffer->size() };
180     ASSERT(2000 >= std::max(rect.width(), rect.height()));
181     backingStore.setSize(rect.size());
182     backingStore.updateTile(1, rect, rect, WTFMove(update.buffer), rect.location());
183 }
184
185 void removeLayer(Nicosia::CompositionLayer& layer)
186 {
187     layer.accessCommitted(
188         [](const Nicosia::CompositionLayer::LayerState& committed)
189         {
190             if (committed.backingStore) {
191                 auto& compositionState = backingStoreImpl(*committed.backingStore).compositionState();
192                 compositionState.backingStore = nullptr;
193             }
194
195             if (committed.contentLayer)
196                 contentLayerImpl(*committed.contentLayer).proxy().invalidate();
197
198             if (committed.imageBacking) {
199                 auto& compositionState = imageBackingImpl(*committed.imageBacking).compositionState();
200                 compositionState.backingStore = nullptr;
201             }
202         });
203
204     auto& compositionState = compositionLayerImpl(layer).compositionState();
205     compositionState.layer = nullptr;
206 }
207
208 void CoordinatedGraphicsScene::commitSceneState(const CoordinatedGraphicsState::NicosiaState& state)
209 {
210     if (!m_client)
211         return;
212
213     m_nicosia.scene = state.scene;
214 }
215
216 void CoordinatedGraphicsScene::updateSceneState()
217 {
218     if (!m_nicosia.scene)
219         return;
220
221     // Store layer and impl references along with the corresponding update
222     // for each type of possible layer backing.
223     struct {
224         struct BackingStore {
225             std::reference_wrapper<TextureMapperLayer> layer;
226             std::reference_wrapper<Nicosia::BackingStoreTextureMapperImpl> backingStore;
227             Nicosia::BackingStoreTextureMapperImpl::TileUpdate update;
228         };
229         Vector<BackingStore> backingStore;
230
231         struct ContentLayer {
232             std::reference_wrapper<TextureMapperLayer> layer;
233             std::reference_wrapper<TextureMapperPlatformLayerProxy> proxy;
234             bool needsActivation { false };
235         };
236         Vector<ContentLayer> contentLayer;
237
238         struct ImageBacking {
239             std::reference_wrapper<TextureMapperLayer> layer;
240             std::reference_wrapper<Nicosia::ImageBackingTextureMapperImpl> imageBacking;
241             Nicosia::ImageBackingTextureMapperImpl::Update update;
242         };
243         Vector<ImageBacking> imageBacking;
244     } layersByBacking;
245
246     // Access the scene state and perform state update for each layer.
247     m_nicosia.scene->accessState(
248         [this, &layersByBacking](Nicosia::Scene::State& state)
249         {
250             // FIXME: try to minimize the amount of work in case the Scene::State object
251             // didn't change (i.e. no layer flush was done), but don't forget to properly
252             // gather and update proxy objects for content layers.
253
254             // Handle the root layer, adding it to the TextureMapperLayer tree
255             // on the first update. No such change is expected later.
256             {
257                 auto& rootLayer = texmapLayer(*state.rootLayer);
258                 if (rootLayer.id() != m_rootLayerID) {
259                     m_rootLayerID = rootLayer.id();
260                     RELEASE_ASSERT(m_rootLayer->children().isEmpty());
261                     m_rootLayer->addChild(&rootLayer);
262                 }
263             }
264
265             // Gather all the to-be-removed layers so that composition-side state
266             // can be properly purged after the current state's set of layers is adopted.
267             HashSet<RefPtr<Nicosia::CompositionLayer>> removedLayers;
268             for (auto& layer : m_nicosia.state.layers) {
269                 if (!state.layers.contains(layer))
270                     removedLayers.add(layer);
271             }
272
273             m_nicosia.state = state;
274
275             for (auto& layer : removedLayers)
276                 removeLayer(*layer);
277             removedLayers = { };
278
279             // Iterate the current state's set of layers, updating state values according to
280             // the incoming state changes. Layer backings are stored so that the updates
281             // (possibly time-consuming) can be done outside of this scene update.
282             for (auto& compositionLayer : m_nicosia.state.layers) {
283                 auto& layer = texmapLayer(*compositionLayer);
284                 compositionLayer->commitState(
285                     [this, &layer, &compositionLayer, &layersByBacking]
286                     (const Nicosia::CompositionLayer::LayerState& layerState)
287                     {
288                         if (layerState.delta.positionChanged)
289                             layer.setPosition(layerState.position);
290                         if (layerState.delta.anchorPointChanged)
291                             layer.setAnchorPoint(layerState.anchorPoint);
292                         if (layerState.delta.sizeChanged)
293                             layer.setSize(layerState.size);
294                         if (layerState.delta.boundsOriginChanged)
295                             layer.setBoundsOrigin(layerState.boundsOrigin);
296
297                         if (layerState.delta.transformChanged)
298                             layer.setTransform(layerState.transform);
299                         if (layerState.delta.childrenTransformChanged)
300                             layer.setChildrenTransform(layerState.childrenTransform);
301
302                         if (layerState.delta.contentsRectChanged)
303                             layer.setContentsRect(layerState.contentsRect);
304                         if (layerState.delta.contentsTilingChanged) {
305                             layer.setContentsTilePhase(layerState.contentsTilePhase);
306                             layer.setContentsTileSize(layerState.contentsTileSize);
307                         }
308
309                         if (layerState.delta.opacityChanged)
310                             layer.setOpacity(layerState.opacity);
311                         if (layerState.delta.solidColorChanged)
312                             layer.setSolidColor(layerState.solidColor);
313
314                         if (layerState.delta.filtersChanged)
315                             layer.setFilters(layerState.filters);
316                         if (layerState.delta.animationsChanged)
317                             layer.setAnimations(layerState.animations);
318
319                         if (layerState.delta.childrenChanged) {
320                             layer.setChildren(WTF::map(layerState.children,
321                                 [](auto& child) { return &texmapLayer(*child); }));
322                         }
323
324                         if (layerState.delta.maskChanged)
325                             layer.setMaskLayer(layerState.mask ? &texmapLayer(*layerState.mask) : nullptr);
326                         if (layerState.delta.replicaChanged)
327                             layer.setReplicaLayer(layerState.replica ? &texmapLayer(*layerState.replica) : nullptr);
328
329                         if (layerState.delta.flagsChanged) {
330                             layer.setContentsOpaque(layerState.flags.contentsOpaque);
331                             layer.setDrawsContent(layerState.flags.drawsContent);
332                             layer.setContentsVisible(layerState.flags.contentsVisible);
333                             layer.setBackfaceVisibility(layerState.flags.backfaceVisible);
334                             layer.setMasksToBounds(layerState.flags.masksToBounds);
335                             layer.setPreserves3D(layerState.flags.preserves3D);
336                         }
337
338                         if (layerState.delta.repaintCounterChanged)
339                             layer.setRepaintCounter(layerState.repaintCounter.visible, layerState.repaintCounter.count);
340
341                         if (layerState.delta.debugBorderChanged)
342                             layer.setDebugVisuals(layerState.debugBorder.visible, layerState.debugBorder.color, layerState.debugBorder.width);
343
344                         if (layerState.backingStore) {
345                             auto& impl = backingStoreImpl(*layerState.backingStore);
346                             layersByBacking.backingStore.append(
347                                 { std::ref(layer), std::ref(impl), impl.takeUpdate() });
348                         } else
349                             layer.setBackingStore(nullptr);
350
351                         if (layerState.contentLayer) {
352                             auto& impl = contentLayerImpl(*layerState.contentLayer);
353                             layersByBacking.contentLayer.append(
354                                 { std::ref(layer), std::ref(impl.proxy()), layerState.delta.contentLayerChanged });
355                         } else if (layerState.imageBacking) {
356                             auto& impl = imageBackingImpl(*layerState.imageBacking);
357                             layersByBacking.imageBacking.append(
358                                 { std::ref(layer), std::ref(impl), impl.takeUpdate() });
359                         } else
360                             layer.setContentsLayer(nullptr);
361
362                         if (layerState.animatedBackingStoreClient)
363                             layer.setAnimatedBackingStoreClient(layerState.animatedBackingStoreClient.get());
364                         else
365                             layer.setAnimatedBackingStoreClient(nullptr);
366                     });
367             }
368         });
369
370     // Iterate through each backing type of layers and gather backing store
371     // or proxy objects that need an update.
372     // FIXME: HashSet<std::reference_wrapper<>> would be ideal, but doesn't work (yet).
373     HashSet<Ref<WebCore::CoordinatedBackingStore>> backingStoresWithPendingBuffers;
374     HashSet<Ref<WebCore::TextureMapperPlatformLayerProxy>> proxiesForSwapping;
375
376     {
377         for (auto& entry : layersByBacking.backingStore) {
378             auto& compositionState = entry.backingStore.get().compositionState();
379             updateBackingStore(entry.layer.get(), compositionState, entry.update);
380
381             if (compositionState.backingStore)
382                 backingStoresWithPendingBuffers.add(makeRef(*compositionState.backingStore));
383         }
384
385         layersByBacking.backingStore = { };
386     }
387
388     {
389         for (auto& entry : layersByBacking.contentLayer) {
390             auto& proxy = entry.proxy.get();
391             if (entry.needsActivation)
392                 proxy.activateOnCompositingThread(this, &entry.layer.get());
393             proxiesForSwapping.add(makeRef(proxy));
394         }
395
396         layersByBacking.contentLayer = { };
397     }
398
399     {
400         for (auto& entry : layersByBacking.imageBacking) {
401             auto& compositionState = entry.imageBacking.get().compositionState();
402             updateImageBacking(entry.layer.get(), compositionState, entry.update);
403
404             if (compositionState.backingStore)
405                 backingStoresWithPendingBuffers.add(makeRef(*compositionState.backingStore));
406         }
407
408         layersByBacking.imageBacking = { };
409     }
410
411     for (auto& backingStore : backingStoresWithPendingBuffers)
412         backingStore->commitTileOperations(*m_textureMapper);
413
414     for (auto& proxy : proxiesForSwapping)
415         proxy->swapBuffer();
416 }
417
418 void CoordinatedGraphicsScene::ensureRootLayer()
419 {
420     if (m_rootLayer)
421         return;
422
423     m_rootLayer = makeUnique<TextureMapperLayer>();
424     m_rootLayer->setMasksToBounds(false);
425     m_rootLayer->setDrawsContent(false);
426     m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
427
428     // The root layer should not have zero size, or it would be optimized out.
429     m_rootLayer->setSize(FloatSize(1.0, 1.0));
430
431     ASSERT(m_textureMapper);
432     m_rootLayer->setTextureMapper(m_textureMapper.get());
433 }
434
435 void CoordinatedGraphicsScene::purgeGLResources()
436 {
437     ASSERT(!m_client);
438
439     if (m_nicosia.scene) {
440         m_nicosia.scene->accessState(
441             [](Nicosia::Scene::State& state)
442             {
443                 for (auto& layer : state.layers)
444                     removeLayer(*layer);
445                 state.layers = { };
446                 state.rootLayer = nullptr;
447             });
448         m_nicosia.scene = nullptr;
449     }
450
451     m_rootLayer = nullptr;
452     m_rootLayerID = 0;
453     m_textureMapper = nullptr;
454 }
455
456 void CoordinatedGraphicsScene::detach()
457 {
458     ASSERT(RunLoop::isMain());
459     m_isActive = false;
460     m_client = nullptr;
461 }
462
463 } // namespace WebKit
464
465 #endif // USE(COORDINATED_GRAPHICS)