[Chromium] Incremental texture updates are not atomic.
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / cc / CCLayerTreeHost.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "cc/CCLayerTreeHost.h"
28
29 #include "LayerChromium.h"
30 #include "LayerPainterChromium.h"
31 #include "LayerRendererChromium.h"
32 #include "TraceEvent.h"
33 #include "TreeSynchronizer.h"
34 #include "cc/CCLayerIterator.h"
35 #include "cc/CCLayerTreeHostCommon.h"
36 #include "cc/CCLayerTreeHostImpl.h"
37 #include "cc/CCSingleThreadProxy.h"
38 #include "cc/CCThread.h"
39 #include "cc/CCThreadProxy.h"
40
41 namespace {
42 static int numLayerTreeInstances;
43 }
44
45 namespace WebCore {
46
47 bool CCLayerTreeHost::anyLayerTreeHostInstanceExists()
48 {
49     return numLayerTreeInstances > 0;
50 }
51
52 PassRefPtr<CCLayerTreeHost> CCLayerTreeHost::create(CCLayerTreeHostClient* client, const CCSettings& settings)
53 {
54     RefPtr<CCLayerTreeHost> layerTreeHost = adoptRef(new CCLayerTreeHost(client, settings));
55     if (!layerTreeHost->initialize())
56         return 0;
57     return layerTreeHost;
58 }
59
60 CCLayerTreeHost::CCLayerTreeHost(CCLayerTreeHostClient* client, const CCSettings& settings)
61     : m_compositorIdentifier(-1)
62     , m_animating(false)
63     , m_client(client)
64     , m_frameNumber(0)
65     , m_settings(settings)
66     , m_visible(true)
67     , m_haveWheelEventHandlers(false)
68     , m_pageScale(1)
69     , m_minPageScale(1)
70     , m_maxPageScale(1)
71     , m_triggerIdlePaints(true)
72 {
73     ASSERT(CCProxy::isMainThread());
74     numLayerTreeInstances++;
75 }
76
77 bool CCLayerTreeHost::initialize()
78 {
79     TRACE_EVENT("CCLayerTreeHost::initialize", this, 0);
80     if (CCProxy::hasImplThread()) {
81         // The HUD does not work in threaded mode. Turn it off.
82         m_settings.showFPSCounter = false;
83         m_settings.showPlatformLayerTree = false;
84
85         m_proxy = CCThreadProxy::create(this);
86     } else
87         m_proxy = CCSingleThreadProxy::create(this);
88     m_proxy->start();
89
90     if (!m_proxy->initializeLayerRenderer())
91         return false;
92
93     m_compositorIdentifier = m_proxy->compositorIdentifier();
94
95     // Update m_settings based on capabilities that we got back from the renderer.
96     m_settings.acceleratePainting = m_proxy->layerRendererCapabilities().usingAcceleratedPainting;
97
98     // Update m_settings based on partial update capability.
99     m_settings.partialTextureUpdates = m_settings.partialTextureUpdates && m_proxy->partialTextureUpdateCapability();
100
101     m_contentsTextureManager = TextureManager::create(TextureManager::highLimitBytes(viewportSize()),
102                                                       TextureManager::reclaimLimitBytes(viewportSize()),
103                                                       m_proxy->layerRendererCapabilities().maxTextureSize);
104     return true;
105 }
106
107 CCLayerTreeHost::~CCLayerTreeHost()
108 {
109     ASSERT(CCProxy::isMainThread());
110     TRACE_EVENT("CCLayerTreeHost::~CCLayerTreeHost", this, 0);
111     ASSERT(m_proxy);
112     m_proxy->stop();
113     m_proxy.clear();
114     clearPendingUpdate();
115     numLayerTreeInstances--;
116 }
117
118 void CCLayerTreeHost::deleteContentsTexturesOnImplThread(TextureAllocator* allocator)
119 {
120     ASSERT(CCProxy::isImplThread());
121     if (m_contentsTextureManager)
122         m_contentsTextureManager->evictAndDeleteAllTextures(allocator);
123 }
124
125 void CCLayerTreeHost::updateAnimations(double frameBeginTime)
126 {
127     m_animating = true;
128     m_client->updateAnimations(frameBeginTime);
129     m_animating = false;
130 }
131
132 void CCLayerTreeHost::layout()
133 {
134     m_client->layout();
135 }
136
137 void CCLayerTreeHost::beginCommitOnImplThread(CCLayerTreeHostImpl* hostImpl)
138 {
139     ASSERT(CCProxy::isImplThread());
140     TRACE_EVENT("CCLayerTreeHost::commitTo", this, 0);
141
142     contentsTextureManager()->reduceMemoryToLimit(TextureManager::reclaimLimitBytes(viewportSize()));
143     contentsTextureManager()->deleteEvictedTextures(hostImpl->contentsTextureAllocator());
144 }
145
146 // This function commits the CCLayerTreeHost to an impl tree. When modifying
147 // this function, keep in mind that the function *runs* on the impl thread! Any
148 // code that is logically a main thread operation, e.g. deletion of a LayerChromium,
149 // should be delayed until the CCLayerTreeHost::commitComplete, which will run
150 // after the commit, but on the main thread.
151 void CCLayerTreeHost::finishCommitOnImplThread(CCLayerTreeHostImpl* hostImpl)
152 {
153     ASSERT(CCProxy::isImplThread());
154
155     // Synchronize trees, if one exists at all...
156     if (rootLayer())
157         hostImpl->setRootLayer(TreeSynchronizer::synchronizeTrees(rootLayer(), hostImpl->rootLayer()));
158     else
159         hostImpl->setRootLayer(0);
160
161     hostImpl->setSourceFrameNumber(frameNumber());
162     hostImpl->setHaveWheelEventHandlers(m_haveWheelEventHandlers);
163     hostImpl->setViewportSize(viewportSize());
164     hostImpl->setPageScaleFactorAndLimits(pageScale(), m_minPageScale, m_maxPageScale);
165
166     m_frameNumber++;
167 }
168
169 void CCLayerTreeHost::commitComplete()
170 {
171     m_deleteTextureAfterCommitList.clear();
172     clearPendingUpdate();
173     m_contentsTextureManager->unprotectAllTextures();
174 }
175
176 PassRefPtr<GraphicsContext3D> CCLayerTreeHost::createLayerTreeHostContext3D()
177 {
178     return m_client->createLayerTreeHostContext3D();
179 }
180
181 PassOwnPtr<CCLayerTreeHostImpl> CCLayerTreeHost::createLayerTreeHostImpl(CCLayerTreeHostImplClient* client)
182 {
183     return CCLayerTreeHostImpl::create(m_settings, client);
184 }
185
186 void CCLayerTreeHost::didRecreateGraphicsContext(bool success)
187 {
188     if (m_rootLayer) {
189         m_rootLayer->setLayerTreeHost(0);
190         m_rootLayer->setLayerTreeHost(this);
191     }
192     m_client->didRecreateGraphicsContext(success);
193 }
194
195 // Temporary hack until WebViewImpl context creation gets simplified
196 GraphicsContext3D* CCLayerTreeHost::context()
197 {
198     ASSERT(!CCProxy::hasImplThread());
199     return m_proxy->context();
200 }
201
202 bool CCLayerTreeHost::compositeAndReadback(void *pixels, const IntRect& rect)
203 {
204     m_triggerIdlePaints = false;
205     bool ret = m_proxy->compositeAndReadback(pixels, rect);
206     m_triggerIdlePaints = true;
207     return ret;
208 }
209
210 void CCLayerTreeHost::finishAllRendering()
211 {
212     m_proxy->finishAllRendering();
213 }
214
215 const LayerRendererCapabilities& CCLayerTreeHost::layerRendererCapabilities() const
216 {
217     return m_proxy->layerRendererCapabilities();
218 }
219
220 void CCLayerTreeHost::setNeedsAnimate()
221 {
222     ASSERT(CCProxy::hasImplThread());
223     m_proxy->setNeedsAnimate();
224 }
225
226 void CCLayerTreeHost::setNeedsCommit()
227 {
228     if (CCThreadProxy::implThread())
229         m_proxy->setNeedsCommit();
230     else
231         m_client->scheduleComposite();
232 }
233
234 void CCLayerTreeHost::setNeedsRedraw()
235 {
236     if (CCThreadProxy::implThread())
237         m_proxy->setNeedsRedraw();
238     else
239         m_client->scheduleComposite();
240 }
241
242 void CCLayerTreeHost::setRootLayer(PassRefPtr<LayerChromium> rootLayer)
243 {
244     if (m_rootLayer == rootLayer)
245         return;
246
247     if (m_rootLayer)
248         m_rootLayer->setLayerTreeHost(0);
249     m_rootLayer = rootLayer;
250     if (m_rootLayer)
251         m_rootLayer->setLayerTreeHost(this);
252     setNeedsCommit();
253 }
254
255 void CCLayerTreeHost::setViewportSize(const IntSize& viewportSize)
256 {
257     if (viewportSize == m_viewportSize)
258         return;
259
260     contentsTextureManager()->setMaxMemoryLimitBytes(TextureManager::highLimitBytes(viewportSize));
261     contentsTextureManager()->setPreferredMemoryLimitBytes(TextureManager::reclaimLimitBytes(viewportSize));
262     m_viewportSize = viewportSize;
263     setNeedsCommit();
264 }
265
266 void CCLayerTreeHost::setPageScale(float pageScale)
267 {
268     if (pageScale == m_pageScale)
269         return;
270
271     m_pageScale = pageScale;
272     setNeedsCommit();
273 }
274
275 void CCLayerTreeHost::setPageScaleFactorLimits(float minScale, float maxScale)
276 {
277     if (minScale == m_minPageScale && maxScale == m_maxPageScale)
278         return;
279
280     m_minPageScale = minScale;
281     m_maxPageScale = maxScale;
282     setNeedsCommit();
283 }
284
285 void CCLayerTreeHost::setVisible(bool visible)
286 {
287     if (m_visible == visible)
288         return;
289
290     m_visible = visible;
291     if (!visible) {
292         m_contentsTextureManager->reduceMemoryToLimit(TextureManager::lowLimitBytes(viewportSize()));
293         m_contentsTextureManager->unprotectAllTextures();
294     }
295
296     // Tells the proxy that visibility state has changed. This will in turn call
297     // CCLayerTreeHost::didBecomeInvisibleOnImplThread on the appropriate thread, for
298     // the case where !visible.
299     m_proxy->setVisible(visible);
300 }
301
302 void CCLayerTreeHost::didBecomeInvisibleOnImplThread(CCLayerTreeHostImpl* hostImpl)
303 {
304     ASSERT(CCProxy::isImplThread());
305     if (m_proxy->layerRendererCapabilities().contextHasCachedFrontBuffer)
306         contentsTextureManager()->evictAndDeleteAllTextures(hostImpl->contentsTextureAllocator());
307     else {
308         contentsTextureManager()->reduceMemoryToLimit(TextureManager::reclaimLimitBytes(viewportSize()));
309         contentsTextureManager()->deleteEvictedTextures(hostImpl->contentsTextureAllocator());
310     }
311
312     // Ensure that the dropped tiles are propagated to the impl tree.
313     // If the frontbuffer is cached, then clobber the impl tree. Otherwise,
314     // push over the tree changes.
315     if (m_proxy->layerRendererCapabilities().contextHasCachedFrontBuffer) {
316         hostImpl->setRootLayer(0);
317         return;
318     }
319     if (rootLayer())
320         hostImpl->setRootLayer(TreeSynchronizer::synchronizeTrees(rootLayer(), hostImpl->rootLayer()));
321     else
322         hostImpl->setRootLayer(0);
323 }
324
325 void CCLayerTreeHost::setHaveWheelEventHandlers(bool haveWheelEventHandlers)
326 {
327     if (m_haveWheelEventHandlers == haveWheelEventHandlers)
328         return;
329     m_haveWheelEventHandlers = haveWheelEventHandlers;
330     m_proxy->setNeedsCommit();
331 }
332
333
334 void CCLayerTreeHost::loseCompositorContext(int numTimes)
335 {
336     m_proxy->loseCompositorContext(numTimes);
337 }
338
339 TextureManager* CCLayerTreeHost::contentsTextureManager() const
340 {
341     return m_contentsTextureManager.get();
342 }
343
344 void CCLayerTreeHost::composite()
345 {
346     ASSERT(!CCThreadProxy::implThread());
347     static_cast<CCSingleThreadProxy*>(m_proxy.get())->compositeImmediately();
348 }
349
350 void CCLayerTreeHost::updateLayers()
351 {
352     if (!rootLayer())
353         return;
354
355     if (viewportSize().isEmpty())
356         return;
357
358     updateLayers(rootLayer());
359 }
360
361 void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer)
362 {
363     TRACE_EVENT("CCLayerTreeHost::updateLayers", this, 0);
364
365     if (!rootLayer->renderSurface())
366         rootLayer->createRenderSurface();
367     rootLayer->renderSurface()->setContentRect(IntRect(IntPoint(0, 0), viewportSize()));
368
369     IntRect rootClipRect(IntPoint(), viewportSize());
370     rootLayer->setClipRect(rootClipRect);
371
372     // This assert fires if updateCompositorResources wasn't called after
373     // updateLayers. Only one update can be pending at any given time.
374     ASSERT(!m_updateList.size());
375     m_updateList.append(rootLayer);
376
377     RenderSurfaceChromium* rootRenderSurface = rootLayer->renderSurface();
378     rootRenderSurface->clearLayerList();
379
380     TransformationMatrix identityMatrix;
381     {
382         TRACE_EVENT("CCLayerTreeHost::updateLayers::calcDrawEtc", this, 0);
383         CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer, rootLayer, identityMatrix, identityMatrix, m_updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize);
384     }
385
386     paintLayerContents(m_updateList, PaintVisible);
387     if (!m_triggerIdlePaints)
388         return;
389
390     size_t preferredLimitBytes = TextureManager::reclaimLimitBytes(m_viewportSize);
391     size_t maxLimitBytes = TextureManager::highLimitBytes(m_viewportSize);
392     contentsTextureManager()->reduceMemoryToLimit(preferredLimitBytes);
393     if (contentsTextureManager()->currentMemoryUseBytes() >= preferredLimitBytes)
394         return;
395
396     // Idle painting should fail when we hit the preferred memory limit,
397     // otherwise it will always push us towards the maximum limit.
398     m_contentsTextureManager->setMaxMemoryLimitBytes(preferredLimitBytes);
399     // The second (idle) paint will be a no-op in layers where painting already occured above.
400     paintLayerContents(m_updateList, PaintIdle);
401     m_contentsTextureManager->setMaxMemoryLimitBytes(maxLimitBytes);
402 }
403
404 // static
405 void CCLayerTreeHost::paintContentsIfDirty(LayerChromium* layer, PaintType paintType)
406 {
407     ASSERT(layer);
408     ASSERT(PaintVisible == paintType || PaintIdle == paintType);
409     if (PaintVisible == paintType)
410         layer->paintContentsIfDirty();
411     else
412         layer->idlePaintContentsIfDirty();
413 }
414
415 void CCLayerTreeHost::paintMaskAndReplicaForRenderSurface(LayerChromium* renderSurfaceLayer, PaintType paintType)
416 {
417     // Note: Masks and replicas only exist for layers that own render surfaces. If we reach this point
418     // in code, we already know that at least something will be drawn into this render surface, so the
419     // mask and replica should be painted.
420
421     if (renderSurfaceLayer->maskLayer()) {
422         renderSurfaceLayer->maskLayer()->setVisibleLayerRect(IntRect(IntPoint(), renderSurfaceLayer->contentBounds()));
423         paintContentsIfDirty(renderSurfaceLayer->maskLayer(), paintType);
424     }
425
426     LayerChromium* replicaLayer = renderSurfaceLayer->replicaLayer();
427     if (replicaLayer) {
428         paintContentsIfDirty(replicaLayer, paintType);
429
430         if (replicaLayer->maskLayer()) {
431             replicaLayer->maskLayer()->setVisibleLayerRect(IntRect(IntPoint(), replicaLayer->maskLayer()->contentBounds()));
432             paintContentsIfDirty(replicaLayer->maskLayer(), paintType);
433         }
434     }
435 }
436
437 void CCLayerTreeHost::paintLayerContents(const LayerList& renderSurfaceLayerList, PaintType paintType)
438 {
439     // Use FrontToBack to allow for testing occlusion and performing culling during the tree walk.
440     typedef CCLayerIterator<LayerChromium, RenderSurfaceChromium, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType;
441
442     CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
443     for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
444         if (it.representsTargetRenderSurface()) {
445             ASSERT(it->renderSurface()->drawOpacity());
446             paintMaskAndReplicaForRenderSurface(*it, paintType);
447         } else if (it.representsItself()) {
448             ASSERT(!it->bounds().isEmpty());
449             paintContentsIfDirty(*it, paintType);
450         }
451     }
452 }
453
454 void CCLayerTreeHost::updateCompositorResources(GraphicsContext3D* context, CCTextureUpdater& updater)
455 {
456     // Use BackToFront since it's cheap and this isn't order-dependent.
457     typedef CCLayerIterator<LayerChromium, RenderSurfaceChromium, CCLayerIteratorActions::BackToFront> CCLayerIteratorType;
458
459     CCLayerIteratorType end = CCLayerIteratorType::end(&m_updateList);
460     for (CCLayerIteratorType it = CCLayerIteratorType::begin(&m_updateList); it != end; ++it) {
461         if (it.representsTargetRenderSurface()) {
462             ASSERT(it->renderSurface()->drawOpacity());
463             if (it->maskLayer())
464                 it->maskLayer()->updateCompositorResources(context, updater);
465
466             if (it->replicaLayer()) {
467                 it->replicaLayer()->updateCompositorResources(context, updater);
468                 if (it->replicaLayer()->maskLayer())
469                     it->replicaLayer()->maskLayer()->updateCompositorResources(context, updater);
470             }
471         } else if (it.representsItself())
472             it->updateCompositorResources(context, updater);
473     }
474 }
475
476 void CCLayerTreeHost::clearPendingUpdate()
477 {
478     for (size_t surfaceIndex = 0; surfaceIndex < m_updateList.size(); ++surfaceIndex) {
479         LayerChromium* layer = m_updateList[surfaceIndex].get();
480         ASSERT(layer->renderSurface());
481         layer->clearRenderSurface();
482     }
483     m_updateList.clear();
484 }
485
486 void CCLayerTreeHost::applyScrollAndScale(const CCScrollAndScaleSet& info)
487 {
488     // FIXME: pushing scroll offsets to non-root layers not implemented
489     if (!info.scrolls.size())
490         return;
491
492     ASSERT(info.scrolls.size() == 1);
493     IntSize scrollDelta = info.scrolls[0].scrollDelta;
494     m_client->applyScrollAndScale(scrollDelta, info.pageScaleDelta);
495 }
496
497 void CCLayerTreeHost::startRateLimiter(GraphicsContext3D* context)
498 {
499     if (m_animating)
500         return;
501     ASSERT(context);
502     RateLimiterMap::iterator it = m_rateLimiters.find(context);
503     if (it != m_rateLimiters.end())
504         it->second->start();
505     else {
506         RefPtr<RateLimiter> rateLimiter = RateLimiter::create(context);
507         m_rateLimiters.set(context, rateLimiter);
508         rateLimiter->start();
509     }
510 }
511
512 void CCLayerTreeHost::stopRateLimiter(GraphicsContext3D* context)
513 {
514     RateLimiterMap::iterator it = m_rateLimiters.find(context);
515     if (it != m_rateLimiters.end()) {
516         it->second->stop();
517         m_rateLimiters.remove(it);
518     }
519 }
520
521 void CCLayerTreeHost::deleteTextureAfterCommit(PassOwnPtr<ManagedTexture> texture)
522 {
523     m_deleteTextureAfterCommitList.append(texture);
524 }
525
526 }