[WPE] Implement GStreamer based holepunch
[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, float opacity, const FloatRect& clipRect, const Color& backgroundColor, bool drawsBackground, 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 (drawsBackground) {
82         RGBA32 rgba = makeRGBA32FromFloats(backgroundColor.red(),
83             backgroundColor.green(), backgroundColor.blue(),
84             backgroundColor.alpha() * opacity);
85         m_textureMapper->drawSolidColor(clipRect, TransformationMatrix(), Color(rgba), true);
86     } else
87         m_textureMapper->clearColor(m_viewBackgroundColor);
88
89     if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != matrix) {
90         currentRootLayer->setOpacity(opacity);
91         currentRootLayer->setTransform(matrix);
92     }
93
94     currentRootLayer->paint();
95     m_fpsCounter.updateFPSAndDisplay(*m_textureMapper, clipRect.location(), matrix);
96     m_textureMapper->endClip();
97     m_textureMapper->endPainting();
98
99     if (sceneHasRunningAnimations)
100         updateViewport();
101 }
102
103 void CoordinatedGraphicsScene::updateViewport()
104 {
105     if (m_client)
106         m_client->updateViewport();
107 }
108
109 #if USE(COORDINATED_GRAPHICS_THREADED)
110 void CoordinatedGraphicsScene::onNewBufferAvailable()
111 {
112     updateViewport();
113 }
114 #endif
115
116 Nicosia::CompositionLayerTextureMapperImpl& compositionLayerImpl(Nicosia::CompositionLayer& compositionLayer)
117 {
118     return downcast<Nicosia::CompositionLayerTextureMapperImpl>(compositionLayer.impl());
119 }
120
121 Nicosia::ContentLayerTextureMapperImpl& contentLayerImpl(Nicosia::ContentLayer& contentLayer)
122 {
123     return downcast<Nicosia::ContentLayerTextureMapperImpl>(contentLayer.impl());
124 }
125
126 Nicosia::BackingStoreTextureMapperImpl& backingStoreImpl(Nicosia::BackingStore& backingStore)
127 {
128     return downcast<Nicosia::BackingStoreTextureMapperImpl>(backingStore.impl());
129 }
130
131 Nicosia::ImageBackingTextureMapperImpl& imageBackingImpl(Nicosia::ImageBacking& imageBacking)
132 {
133     return downcast<Nicosia::ImageBackingTextureMapperImpl>(imageBacking.impl());
134 }
135
136 TextureMapperLayer& texmapLayer(Nicosia::CompositionLayer& compositionLayer)
137 {
138     auto& compositionState = compositionLayerImpl(compositionLayer).compositionState();
139     if (!compositionState.layer) {
140         compositionState.layer = std::make_unique<TextureMapperLayer>();
141         compositionState.layer->setID(compositionLayer.id());
142     }
143     return *compositionState.layer;
144 }
145
146 void updateBackingStore(TextureMapperLayer& layer,
147     Nicosia::BackingStoreTextureMapperImpl::CompositionState& compositionState,
148     const Nicosia::BackingStoreTextureMapperImpl::TileUpdate& update)
149 {
150     if (!layerShouldHaveBackingStore(&layer)) {
151         layer.setBackingStore(nullptr);
152         compositionState.backingStore = nullptr;
153         return;
154     }
155
156     if (!compositionState.backingStore)
157         compositionState.backingStore = CoordinatedBackingStore::create();
158     auto& backingStore = *compositionState.backingStore;
159
160     layer.setBackingStore(&backingStore);
161     backingStore.setSize(layer.size());
162
163     for (auto& tile : update.tilesToCreate)
164         backingStore.createTile(tile.tileID, tile.scale);
165     for (auto& tile : update.tilesToRemove)
166         backingStore.removeTile(tile.tileID);
167     for (auto& tile : update.tilesToUpdate) {
168         backingStore.updateTile(tile.tileID, tile.updateInfo.updateRect,
169             tile.tileRect, tile.updateInfo.buffer.copyRef(), { 0, 0 });
170     }
171 }
172
173 void updateImageBacking(TextureMapperLayer& layer,
174     Nicosia::ImageBackingTextureMapperImpl::CompositionState& compositionState,
175     Nicosia::ImageBackingTextureMapperImpl::Update& update)
176 {
177     if (!update.isVisible) {
178         layer.setBackingStore(nullptr);
179         return;
180     }
181
182     if (!compositionState.backingStore)
183         compositionState.backingStore = CoordinatedBackingStore::create();
184     auto& backingStore = *compositionState.backingStore;
185     layer.setContentsLayer(&backingStore);
186
187     if (!update.buffer)
188         return;
189
190     backingStore.createTile(1, 1.0);
191     WebCore::IntRect rect { { }, update.buffer->size() };
192     ASSERT(2000 >= std::max(rect.width(), rect.height()));
193     backingStore.setSize(rect.size());
194     backingStore.updateTile(1, rect, rect, WTFMove(update.buffer), rect.location());
195 }
196
197 void removeLayer(Nicosia::CompositionLayer& layer)
198 {
199     layer.accessCommitted(
200         [](const Nicosia::CompositionLayer::LayerState& committed)
201         {
202             if (committed.backingStore) {
203                 auto& compositionState = backingStoreImpl(*committed.backingStore).compositionState();
204                 compositionState.backingStore = nullptr;
205             }
206
207             if (committed.contentLayer)
208                 contentLayerImpl(*committed.contentLayer).proxy().invalidate();
209
210             if (committed.imageBacking) {
211                 auto& compositionState = imageBackingImpl(*committed.imageBacking).compositionState();
212                 compositionState.backingStore = nullptr;
213             }
214         });
215
216     auto& compositionState = compositionLayerImpl(layer).compositionState();
217     compositionState.layer = nullptr;
218 }
219
220 void CoordinatedGraphicsScene::commitSceneState(const CoordinatedGraphicsState::NicosiaState& state)
221 {
222     if (!m_client)
223         return;
224
225     m_nicosia.scene = state.scene;
226 }
227
228 void CoordinatedGraphicsScene::updateSceneState()
229 {
230     if (!m_nicosia.scene)
231         return;
232
233     // Store layer and impl references along with the corresponding update
234     // for each type of possible layer backing.
235     struct {
236         struct BackingStore {
237             std::reference_wrapper<TextureMapperLayer> layer;
238             std::reference_wrapper<Nicosia::BackingStoreTextureMapperImpl> backingStore;
239             Nicosia::BackingStoreTextureMapperImpl::TileUpdate update;
240         };
241         Vector<BackingStore> backingStore;
242
243         struct ContentLayer {
244             std::reference_wrapper<TextureMapperLayer> layer;
245             std::reference_wrapper<TextureMapperPlatformLayerProxy> proxy;
246             bool needsActivation { false };
247         };
248         Vector<ContentLayer> contentLayer;
249
250         struct ImageBacking {
251             std::reference_wrapper<TextureMapperLayer> layer;
252             std::reference_wrapper<Nicosia::ImageBackingTextureMapperImpl> imageBacking;
253             Nicosia::ImageBackingTextureMapperImpl::Update update;
254         };
255         Vector<ImageBacking> imageBacking;
256     } layersByBacking;
257
258     // Access the scene state and perform state update for each layer.
259     m_nicosia.scene->accessState(
260         [this, &layersByBacking](Nicosia::Scene::State& state)
261         {
262             // FIXME: try to minimize the amount of work in case the Scene::State object
263             // didn't change (i.e. no layer flush was done), but don't forget to properly
264             // gather and update proxy objects for content layers.
265
266             // Handle the root layer, adding it to the TextureMapperLayer tree
267             // on the first update. No such change is expected later.
268             {
269                 auto& rootLayer = texmapLayer(*state.rootLayer);
270                 if (rootLayer.id() != m_rootLayerID) {
271                     m_rootLayerID = rootLayer.id();
272                     RELEASE_ASSERT(m_rootLayer->children().isEmpty());
273                     m_rootLayer->addChild(&rootLayer);
274                 }
275             }
276
277             // Gather all the to-be-removed layers so that composition-side state
278             // can be properly purged after the current state's set of layers is adopted.
279             HashSet<RefPtr<Nicosia::CompositionLayer>> removedLayers;
280             for (auto& layer : m_nicosia.state.layers) {
281                 if (!state.layers.contains(layer))
282                     removedLayers.add(layer);
283             }
284
285             m_nicosia.state = state;
286
287             for (auto& layer : removedLayers)
288                 removeLayer(*layer);
289             removedLayers = { };
290
291             // Iterate the current state's set of layers, updating state values according to
292             // the incoming state changes. Layer backings are stored so that the updates
293             // (possibly time-consuming) can be done outside of this scene update.
294             for (auto& compositionLayer : m_nicosia.state.layers) {
295                 auto& layer = texmapLayer(*compositionLayer);
296                 compositionLayer->commitState(
297                     [this, &layer, &compositionLayer, &layersByBacking]
298                     (const Nicosia::CompositionLayer::LayerState& layerState)
299                     {
300                         if (layerState.delta.positionChanged)
301                             layer.setPosition(layerState.position);
302                         if (layerState.delta.anchorPointChanged)
303                             layer.setAnchorPoint(layerState.anchorPoint);
304                         if (layerState.delta.sizeChanged)
305                             layer.setSize(layerState.size);
306
307                         if (layerState.delta.transformChanged)
308                             layer.setTransform(layerState.transform);
309                         if (layerState.delta.childrenTransformChanged)
310                             layer.setChildrenTransform(layerState.childrenTransform);
311
312                         if (layerState.delta.contentsRectChanged)
313                             layer.setContentsRect(layerState.contentsRect);
314                         if (layerState.delta.contentsTilingChanged) {
315                             layer.setContentsTilePhase(layerState.contentsTilePhase);
316                             layer.setContentsTileSize(layerState.contentsTileSize);
317                         }
318
319                         if (layerState.delta.opacityChanged)
320                             layer.setOpacity(layerState.opacity);
321                         if (layerState.delta.solidColorChanged)
322                             layer.setSolidColor(layerState.solidColor);
323
324                         if (layerState.delta.filtersChanged)
325                             layer.setFilters(layerState.filters);
326                         if (layerState.delta.animationsChanged)
327                             layer.setAnimations(layerState.animations);
328
329                         if (layerState.delta.childrenChanged) {
330                             layer.setChildren(WTF::map(layerState.children,
331                                 [](auto& child) { return &texmapLayer(*child); }));
332                         }
333
334                         if (layerState.delta.maskChanged)
335                             layer.setMaskLayer(layerState.mask ? &texmapLayer(*layerState.mask) : nullptr);
336                         if (layerState.delta.replicaChanged)
337                             layer.setReplicaLayer(layerState.replica ? &texmapLayer(*layerState.replica) : nullptr);
338
339                         if (layerState.delta.flagsChanged) {
340                             layer.setContentsOpaque(layerState.flags.contentsOpaque);
341                             layer.setDrawsContent(layerState.flags.drawsContent);
342                             layer.setContentsVisible(layerState.flags.contentsVisible);
343                             layer.setBackfaceVisibility(layerState.flags.backfaceVisible);
344                             layer.setMasksToBounds(layerState.flags.masksToBounds);
345                             layer.setPreserves3D(layerState.flags.preserves3D);
346                         }
347
348                         if (layerState.delta.repaintCounterChanged)
349                             layer.setRepaintCounter(layerState.repaintCounter.visible, layerState.repaintCounter.count);
350
351                         if (layerState.delta.debugBorderChanged)
352                             layer.setDebugVisuals(layerState.debugBorder.visible, layerState.debugBorder.color, layerState.debugBorder.width);
353
354                         if (layerState.backingStore) {
355                             auto& impl = backingStoreImpl(*layerState.backingStore);
356                             layersByBacking.backingStore.append(
357                                 { std::ref(layer), std::ref(impl), impl.takeUpdate() });
358                         } else
359                             layer.setBackingStore(nullptr);
360
361                         if (layerState.contentLayer) {
362                             auto& impl = contentLayerImpl(*layerState.contentLayer);
363                             layersByBacking.contentLayer.append(
364                                 { std::ref(layer), std::ref(impl.proxy()), layerState.delta.contentLayerChanged });
365                         } else if (layerState.imageBacking) {
366                             auto& impl = imageBackingImpl(*layerState.imageBacking);
367                             layersByBacking.imageBacking.append(
368                                 { std::ref(layer), std::ref(impl), impl.takeUpdate() });
369                         } else
370                             layer.setContentsLayer(nullptr);
371                     });
372             }
373         });
374
375     // Iterate through each backing type of layers and gather backing store
376     // or proxy objects that need an update.
377     // FIXME: HashSet<std::reference_wrapper<>> would be ideal, but doesn't work (yet).
378     HashSet<Ref<WebCore::CoordinatedBackingStore>> backingStoresWithPendingBuffers;
379     HashSet<Ref<WebCore::TextureMapperPlatformLayerProxy>> proxiesForSwapping;
380
381     {
382         for (auto& entry : layersByBacking.backingStore) {
383             auto& compositionState = entry.backingStore.get().compositionState();
384             updateBackingStore(entry.layer.get(), compositionState, entry.update);
385
386             if (compositionState.backingStore)
387                 backingStoresWithPendingBuffers.add(makeRef(*compositionState.backingStore));
388         }
389
390         layersByBacking.backingStore = { };
391     }
392
393     {
394         for (auto& entry : layersByBacking.contentLayer) {
395             auto& proxy = entry.proxy.get();
396             if (entry.needsActivation)
397                 proxy.activateOnCompositingThread(this, &entry.layer.get());
398             proxiesForSwapping.add(makeRef(proxy));
399         }
400
401         layersByBacking.contentLayer = { };
402     }
403
404     {
405         for (auto& entry : layersByBacking.imageBacking) {
406             auto& compositionState = entry.imageBacking.get().compositionState();
407             updateImageBacking(entry.layer.get(), compositionState, entry.update);
408
409             if (compositionState.backingStore)
410                 backingStoresWithPendingBuffers.add(makeRef(*compositionState.backingStore));
411         }
412
413         layersByBacking.imageBacking = { };
414     }
415
416     for (auto& backingStore : backingStoresWithPendingBuffers)
417         backingStore->commitTileOperations(*m_textureMapper);
418
419     for (auto& proxy : proxiesForSwapping)
420         proxy->swapBuffer();
421 }
422
423 void CoordinatedGraphicsScene::ensureRootLayer()
424 {
425     if (m_rootLayer)
426         return;
427
428     m_rootLayer = std::make_unique<TextureMapperLayer>();
429     m_rootLayer->setMasksToBounds(false);
430     m_rootLayer->setDrawsContent(false);
431     m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
432
433     // The root layer should not have zero size, or it would be optimized out.
434     m_rootLayer->setSize(FloatSize(1.0, 1.0));
435
436     ASSERT(m_textureMapper);
437     m_rootLayer->setTextureMapper(m_textureMapper.get());
438 }
439
440 void CoordinatedGraphicsScene::purgeGLResources()
441 {
442     ASSERT(!m_client);
443
444     if (m_nicosia.scene) {
445         m_nicosia.scene->accessState(
446             [this](const Nicosia::Scene::State& state)
447             {
448                 ASSERT(state.id == m_nicosia.state.id);
449                 for (auto& layer : m_nicosia.state.layers)
450                     removeLayer(*layer);
451                 m_nicosia.state.layers = { };
452                 m_nicosia.state.rootLayer = nullptr;
453             });
454         m_nicosia.scene = nullptr;
455     }
456
457     m_rootLayer = nullptr;
458     m_rootLayerID = 0;
459     m_textureMapper = nullptr;
460 }
461
462 void CoordinatedGraphicsScene::detach()
463 {
464     ASSERT(RunLoop::isMain());
465     m_isActive = false;
466     m_client = nullptr;
467 }
468
469 } // namespace WebKit
470
471 #endif // USE(COORDINATED_GRAPHICS)