[Qt] Race condition in LayerTreeHost/Proxy can cause blank rendering
[qtwebkit:qt5-module.git] / Source / WebKit2 / UIProcess / WebLayerTreeRenderer.cpp
1 /*
2     Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #if USE(UI_SIDE_COMPOSITING)
23
24 #include "WebLayerTreeRenderer.h"
25
26 #include "GraphicsLayerTextureMapper.h"
27 #include "LayerBackingStore.h"
28 #include "LayerTreeHostProxy.h"
29 #include "MessageID.h"
30 #include "ShareableBitmap.h"
31 #include "TextureMapper.h"
32 #include "TextureMapperBackingStore.h"
33 #include "TextureMapperLayer.h"
34 #include "UpdateInfo.h"
35 #include <OpenGLShims.h>
36 #include <wtf/Atomics.h>
37 #include <wtf/MainThread.h>
38
39 namespace WebKit {
40
41 using namespace WebCore;
42
43 template<class T> class MainThreadGuardedInvoker {
44 public:
45     static void call(PassRefPtr<T> objectToGuard, const Function<void()>& function)
46     {
47         MainThreadGuardedInvoker<T>* invoker = new MainThreadGuardedInvoker<T>(objectToGuard, function);
48         callOnMainThread(invoke, invoker);
49     }
50
51 private:
52     MainThreadGuardedInvoker(PassRefPtr<T> object, const Function<void()>& newFunction)
53         : objectToGuard(object)
54         , function(newFunction)
55     {
56     }
57
58     RefPtr<T> objectToGuard;
59     Function<void()> function;
60     static void invoke(void* data)
61     {
62         MainThreadGuardedInvoker<T>* invoker = static_cast<MainThreadGuardedInvoker<T>*>(data);
63         invoker->function();
64         delete invoker;
65     }
66 };
67
68 void WebLayerTreeRenderer::callOnMainTread(const Function<void()>& function)
69 {
70     if (isMainThread())
71         function();
72     else
73         MainThreadGuardedInvoker<WebLayerTreeRenderer>::call(this, function);
74 }
75
76 static IntPoint boundedScrollPosition(const IntPoint& scrollPosition, const IntRect& visibleContentRect, const FloatSize& contentSize)
77 {
78     IntSize size(contentSize.width(), contentSize.height());
79     int scrollPositionX = std::max(scrollPosition.x(), 0);
80     scrollPositionX = std::min(scrollPositionX, size.width() - visibleContentRect.width());
81
82     int scrollPositionY = std::max(scrollPosition.y(), 0);
83     scrollPositionY = std::min(scrollPositionY, size.height() - visibleContentRect.height());
84     return IntPoint(scrollPositionX, scrollPositionY);
85 }
86
87 WebLayerTreeRenderer::WebLayerTreeRenderer(LayerTreeHostProxy* layerTreeHostProxy)
88     : m_layerTreeHostProxy(layerTreeHostProxy)
89     , m_rootLayerID(InvalidWebLayerID)
90     , m_isActive(false)
91 {
92 }
93
94 WebLayerTreeRenderer::~WebLayerTreeRenderer()
95 {
96 }
97
98 PassOwnPtr<GraphicsLayer> WebLayerTreeRenderer::createLayer(WebLayerID layerID)
99 {
100     GraphicsLayer* newLayer = new GraphicsLayerTextureMapper(this);
101     TextureMapperLayer* layer = toTextureMapperLayer(newLayer);
102     layer->setShouldUpdateBackingStoreFromLayer(false);
103     return adoptPtr(newLayer);
104 }
105
106 void WebLayerTreeRenderer::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity, const FloatRect& clipRect, TextureMapper::PaintFlags PaintFlags)
107 {
108     if (!m_textureMapper)
109         m_textureMapper = TextureMapper::create(TextureMapper::OpenGLMode);
110     ASSERT(m_textureMapper->accelerationMode() == TextureMapper::OpenGLMode);
111
112     // We need to compensate for the rounding error that happens due to m_visibleContentsRect being
113     // int and not float. We do that by moving the TransformationMatrix by the delta between the
114     // position of m_visibleContentsRect and the position it would have if it wasn't rounded.
115  
116     TransformationMatrix newMatrix = matrix;
117     newMatrix.translate(m_accurateVisibleContentsPosition.x() / m_contentsScale - m_visibleContentsRect.x(), m_accurateVisibleContentsPosition.y() / m_contentsScale - m_visibleContentsRect.y());
118     adjustPositionForFixedLayers();
119     GraphicsLayer* currentRootLayer = rootLayer();
120     if (!currentRootLayer)
121         return;
122
123     TextureMapperLayer* layer = toTextureMapperLayer(currentRootLayer);
124
125     if (!layer)
126         return;
127
128     layer->setTextureMapper(m_textureMapper.get());
129     m_textureMapper->beginPainting(PaintFlags);
130     m_textureMapper->beginClip(TransformationMatrix(), clipRect);
131
132     if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != newMatrix) {
133         currentRootLayer->setOpacity(opacity);
134         currentRootLayer->setTransform(newMatrix);
135         currentRootLayer->syncCompositingStateForThisLayerOnly();
136     }
137
138     layer->paint();
139     m_textureMapper->endClip();
140     m_textureMapper->endPainting();
141 }
142
143 void WebLayerTreeRenderer::paintToGraphicsContext(QPainter* painter)
144 {
145     if (!m_textureMapper)
146         m_textureMapper = TextureMapper::create();
147     ASSERT(m_textureMapper->accelerationMode() == TextureMapper::SoftwareMode);
148     syncRemoteContent();
149     TextureMapperLayer* layer = toTextureMapperLayer(rootLayer());
150
151     if (!layer)
152         return;
153
154     GraphicsContext graphicsContext(painter);
155     m_textureMapper->setGraphicsContext(&graphicsContext);
156     m_textureMapper->beginPainting();
157     layer->paint();
158     m_textureMapper->endPainting();
159     m_textureMapper->setGraphicsContext(0);
160 }
161
162 void WebLayerTreeRenderer::setContentsSize(const WebCore::FloatSize& contentsSize)
163 {
164     m_contentsSize = contentsSize;
165 }
166
167 void WebLayerTreeRenderer::setVisibleContentsRect(const IntRect& rect, float scale, const WebCore::FloatPoint& accurateVisibleContentsPosition)
168 {
169     m_visibleContentsRect = rect;
170     m_contentsScale = scale;
171     m_accurateVisibleContentsPosition = accurateVisibleContentsPosition;
172 }
173
174 void WebLayerTreeRenderer::updateViewport()
175 {
176     if (m_layerTreeHostProxy)
177         m_layerTreeHostProxy->updateViewport();
178 }
179
180 void WebLayerTreeRenderer::adjustPositionForFixedLayers()
181 {
182     if (m_fixedLayers.isEmpty())
183         return;
184
185     IntPoint scrollPosition = boundedScrollPosition(m_visibleContentsRect.location(), m_visibleContentsRect, m_contentsSize);
186
187     LayerMap::iterator end = m_fixedLayers.end();
188     for (LayerMap::iterator it = m_fixedLayers.begin(); it != end; ++it)
189         toTextureMapperLayer(it->second)->setScrollPositionDeltaIfNeeded(IntPoint(scrollPosition.x() - m_renderedContentsScrollPosition.x(), scrollPosition.y() - m_renderedContentsScrollPosition.y()));
190 }
191
192 void WebLayerTreeRenderer::didChangeScrollPosition(const IntPoint& position)
193 {
194     m_pendingRenderedContentsScrollPosition = boundedScrollPosition(position, m_visibleContentsRect, m_contentsSize);
195 }
196
197 void WebLayerTreeRenderer::setLayerChildren(WebLayerID id, const Vector<WebLayerID>& childIDs)
198 {
199     ensureLayer(id);
200     LayerMap::iterator it = m_layers.find(id);
201     GraphicsLayer* layer = it->second;
202     Vector<GraphicsLayer*> children;
203
204     for (size_t i = 0; i < childIDs.size(); ++i) {
205         WebLayerID childID = childIDs[i];
206         GraphicsLayer* child = layerByID(childID);
207         if (!child) {
208             child = createLayer(childID).leakPtr();
209             m_layers.add(childID, child);
210         }
211         children.append(child);
212     }
213     layer->setChildren(children);
214 }
215
216 #if ENABLE(CSS_FILTERS)
217 void WebLayerTreeRenderer::setLayerFilters(WebLayerID id, const FilterOperations& filters)
218 {
219     ensureLayer(id);
220     LayerMap::iterator it = m_layers.find(id);
221     ASSERT(it != m_layers.end());
222
223     GraphicsLayer* layer = it->second;
224     layer->setFilters(filters);
225 }
226 #endif
227
228 void WebLayerTreeRenderer::setLayerState(WebLayerID id, const WebLayerInfo& layerInfo)
229 {
230     ensureLayer(id);
231     LayerMap::iterator it = m_layers.find(id);
232     ASSERT(it != m_layers.end());
233
234     GraphicsLayer* layer = it->second;
235
236     layer->setReplicatedByLayer(layerByID(layerInfo.replica));
237     layer->setMaskLayer(layerByID(layerInfo.mask));
238
239     layer->setPosition(layerInfo.pos);
240     layer->setSize(layerInfo.size);
241     layer->setTransform(layerInfo.transform);
242     layer->setAnchorPoint(layerInfo.anchorPoint);
243     layer->setChildrenTransform(layerInfo.childrenTransform);
244     layer->setBackfaceVisibility(layerInfo.backfaceVisible);
245     layer->setContentsOpaque(layerInfo.contentsOpaque);
246     layer->setContentsRect(layerInfo.contentsRect);
247     layer->setDrawsContent(layerInfo.drawsContent);
248     toGraphicsLayerTextureMapper(layer)->setFixedToViewport(layerInfo.fixedToViewport);
249
250     if (layerInfo.fixedToViewport)
251         m_fixedLayers.add(id, layer);
252     else
253         m_fixedLayers.remove(id);
254
255     assignImageToLayer(layer, layerInfo.imageBackingStoreID);
256
257     // Never make the root layer clip.
258     layer->setMasksToBounds(layerInfo.isRootLayer ? false : layerInfo.masksToBounds);
259     layer->setOpacity(layerInfo.opacity);
260     layer->setPreserves3D(layerInfo.preserves3D);
261     if (layerInfo.isRootLayer && m_rootLayerID != id)
262         setRootLayerID(id);
263 }
264
265 void WebLayerTreeRenderer::deleteLayer(WebLayerID layerID)
266 {
267     GraphicsLayer* layer = layerByID(layerID);
268     if (!layer)
269         return;
270
271     layer->removeFromParent();
272     m_layers.remove(layerID);
273     m_fixedLayers.remove(layerID);
274     delete layer;
275 }
276
277
278 void WebLayerTreeRenderer::ensureLayer(WebLayerID id)
279 {
280     // We have to leak the new layer's pointer and manage it ourselves,
281     // because OwnPtr is not copyable.
282     if (m_layers.find(id) == m_layers.end())
283         m_layers.add(id, createLayer(id).leakPtr());
284 }
285
286 void WebLayerTreeRenderer::setRootLayerID(WebLayerID layerID)
287 {
288     if (layerID == m_rootLayerID)
289         return;
290
291     m_rootLayerID = layerID;
292
293     m_rootLayer->removeAllChildren();
294
295     if (!layerID)
296         return;
297
298     GraphicsLayer* layer = layerByID(layerID);
299     if (!layer)
300         return;
301
302     m_rootLayer->addChild(layer);
303 }
304
305 PassRefPtr<LayerBackingStore> WebLayerTreeRenderer::getBackingStore(WebLayerID id)
306 {
307     TextureMapperLayer* layer = toTextureMapperLayer(layerByID(id));
308     ASSERT(layer);
309     RefPtr<LayerBackingStore> backingStore = static_cast<LayerBackingStore*>(layer->backingStore().get());
310     if (!backingStore) {
311         backingStore = LayerBackingStore::create();
312         layer->setBackingStore(backingStore.get());
313     }
314     ASSERT(backingStore);
315     return backingStore;
316 }
317
318 void WebLayerTreeRenderer::createTile(WebLayerID layerID, int tileID, float scale)
319 {
320     getBackingStore(layerID)->createTile(tileID, scale);
321 }
322
323 void WebLayerTreeRenderer::removeTile(WebLayerID layerID, int tileID)
324 {
325     getBackingStore(layerID)->removeTile(tileID);
326 }
327
328 void WebLayerTreeRenderer::updateTile(WebLayerID layerID, int tileID, const TileUpdate& update)
329 {
330     RefPtr<LayerBackingStore> backingStore = getBackingStore(layerID);
331     backingStore->updateTile(tileID, update.sourceRect, update.targetRect, update.surface, update.offset);
332     m_backingStoresWithPendingBuffers.add(backingStore);
333 }
334
335 void WebLayerTreeRenderer::createImage(int64_t imageID, PassRefPtr<ShareableBitmap> weakBitmap)
336 {
337     RefPtr<ShareableBitmap> bitmap = weakBitmap;
338     RefPtr<TextureMapperTiledBackingStore> backingStore = TextureMapperTiledBackingStore::create();
339     m_directlyCompositedImages.set(imageID, backingStore);
340     backingStore->updateContents(m_textureMapper.get(), bitmap->createImage().get());
341 }
342
343 void WebLayerTreeRenderer::destroyImage(int64_t imageID)
344 {
345     m_directlyCompositedImages.remove(imageID);
346 }
347
348 void WebLayerTreeRenderer::assignImageToLayer(GraphicsLayer* layer, int64_t imageID)
349 {
350     if (!imageID) {
351         layer->setContentsToMedia(0);
352         return;
353     }
354
355     HashMap<int64_t, RefPtr<TextureMapperBackingStore> >::iterator it = m_directlyCompositedImages.find(imageID);
356     ASSERT(it != m_directlyCompositedImages.end());
357     layer->setContentsToMedia(it->second.get());
358 }
359
360 void WebLayerTreeRenderer::commitTileOperations()
361 {
362     HashSet<RefPtr<LayerBackingStore> >::iterator end = m_backingStoresWithPendingBuffers.end();
363     for (HashSet<RefPtr<LayerBackingStore> >::iterator it = m_backingStoresWithPendingBuffers.begin(); it != end; ++it)
364         (*it)->commitTileOperations(m_textureMapper.get());
365
366     m_backingStoresWithPendingBuffers.clear();
367 }
368
369 void WebLayerTreeRenderer::flushLayerChanges()
370 {
371     m_renderedContentsScrollPosition = m_pendingRenderedContentsScrollPosition;
372
373     m_rootLayer->syncCompositingState(FloatRect());
374     commitTileOperations();
375
376     // The pending tiles state is on its way for the screen, tell the web process to render the next one.
377     callOnMainThread(bind(&WebLayerTreeRenderer::renderNextFrame, this));
378 }
379
380 void WebLayerTreeRenderer::renderNextFrame()
381 {
382     if (m_layerTreeHostProxy)
383         m_layerTreeHostProxy->renderNextFrame();
384 }
385
386 void WebLayerTreeRenderer::ensureRootLayer()
387 {
388     if (m_rootLayer)
389         return;
390     if (!m_textureMapper)
391         m_textureMapper = TextureMapper::create(TextureMapper::OpenGLMode);
392
393     m_rootLayer = createLayer(InvalidWebLayerID);
394     m_rootLayer->setMasksToBounds(false);
395     m_rootLayer->setDrawsContent(false);
396     m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
397
398     // The root layer should not have zero size, or it would be optimized out.
399     m_rootLayer->setSize(FloatSize(1.0, 1.0));
400     toTextureMapperLayer(m_rootLayer.get())->setTextureMapper(m_textureMapper.get());
401 }
402
403 void WebLayerTreeRenderer::syncRemoteContent()
404 {
405     // We enqueue messages and execute them during paint, as they require an active GL context.
406     ensureRootLayer();
407
408     for (size_t i = 0; i < m_renderQueue.size(); ++i)
409         m_renderQueue[i]();
410
411     m_renderQueue.clear();
412 }
413
414 void WebLayerTreeRenderer::purgeGLResources()
415 {
416     TextureMapperLayer* layer = toTextureMapperLayer(rootLayer());
417
418     if (layer)
419         layer->clearBackingStoresRecursive();
420
421     m_directlyCompositedImages.clear();
422
423     m_rootLayer->removeAllChildren();
424     m_rootLayer.clear();
425     m_rootLayerID = InvalidWebLayerID;
426     m_layers.clear();
427     m_fixedLayers.clear();
428     m_textureMapper.clear();
429     m_backingStoresWithPendingBuffers.clear();
430
431     callOnMainThread(bind(&WebLayerTreeRenderer::purgeBackingStores, this));
432 }
433
434 void WebLayerTreeRenderer::purgeBackingStores()
435 {
436     if (m_layerTreeHostProxy)
437         m_layerTreeHostProxy->purgeBackingStores();
438 }
439
440 void WebLayerTreeRenderer::detach()
441 {
442     m_layerTreeHostProxy = 0;
443 }
444
445 void WebLayerTreeRenderer::appendUpdate(const Function<void()>& function)
446 {
447     if (!m_isActive)
448         return;
449
450     m_renderQueue.append(function);
451 }
452
453 void WebLayerTreeRenderer::setActive(bool active)
454 {
455     if (m_isActive == active)
456         return;
457
458     // Have to clear render queue in both cases.
459     // If there are some updates in queue during activation then those updates are from previous instance of paint node
460     // and cannot be applied to the newly created instance.
461     m_renderQueue.clear();
462     m_isActive = active;
463     if (m_isActive)
464         renderNextFrame();
465 }
466
467 } // namespace WebKit
468
469 #endif // USE(UI_SIDE_COMPOSITING)