8663ec0ac2cdf36b2472281cffaea1940225a23c
[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     m_contentsTextureManager = TextureManager::create(TextureManager::highLimitBytes(viewportSize()),
99                                                       TextureManager::reclaimLimitBytes(viewportSize()),
100                                                       m_proxy->layerRendererCapabilities().maxTextureSize);
101     return true;
102 }
103
104 CCLayerTreeHost::~CCLayerTreeHost()
105 {
106     ASSERT(CCProxy::isMainThread());
107     TRACE_EVENT("CCLayerTreeHost::~CCLayerTreeHost", this, 0);
108     ASSERT(m_proxy);
109     m_proxy->stop();
110     m_proxy.clear();
111     clearPendingUpdate();
112     numLayerTreeInstances--;
113 }
114
115 void CCLayerTreeHost::deleteContentsTexturesOnImplThread(TextureAllocator* allocator)
116 {
117     ASSERT(CCProxy::isImplThread());
118     if (m_contentsTextureManager)
119         m_contentsTextureManager->evictAndDeleteAllTextures(allocator);
120 }
121
122 void CCLayerTreeHost::updateAnimations(double frameBeginTime)
123 {
124     m_animating = true;
125     m_client->updateAnimations(frameBeginTime);
126     m_animating = false;
127 }
128
129 void CCLayerTreeHost::layout()
130 {
131     m_client->layout();
132 }
133
134 void CCLayerTreeHost::beginCommitOnImplThread(CCLayerTreeHostImpl* hostImpl)
135 {
136     ASSERT(CCProxy::isImplThread());
137     TRACE_EVENT("CCLayerTreeHost::commitTo", this, 0);
138
139     contentsTextureManager()->reduceMemoryToLimit(TextureManager::reclaimLimitBytes(viewportSize()));
140     contentsTextureManager()->deleteEvictedTextures(hostImpl->contentsTextureAllocator());
141 }
142
143 // This function commits the CCLayerTreeHost to an impl tree. When modifying
144 // this function, keep in mind that the function *runs* on the impl thread! Any
145 // code that is logically a main thread operation, e.g. deletion of a LayerChromium,
146 // should be delayed until the CCLayerTreeHost::commitComplete, which will run
147 // after the commit, but on the main thread.
148 void CCLayerTreeHost::finishCommitOnImplThread(CCLayerTreeHostImpl* hostImpl)
149 {
150     ASSERT(CCProxy::isImplThread());
151
152     // Synchronize trees, if one exists at all...
153     if (rootLayer())
154         hostImpl->setRootLayer(TreeSynchronizer::synchronizeTrees(rootLayer(), hostImpl->rootLayer()));
155     else
156         hostImpl->setRootLayer(0);
157
158     hostImpl->setSourceFrameNumber(frameNumber());
159     hostImpl->setHaveWheelEventHandlers(m_haveWheelEventHandlers);
160     hostImpl->setViewportSize(viewportSize());
161     hostImpl->setPageScaleFactorAndLimits(pageScale(), m_minPageScale, m_maxPageScale);
162
163     m_frameNumber++;
164 }
165
166 void CCLayerTreeHost::commitComplete()
167 {
168     clearPendingUpdate();
169     m_contentsTextureManager->unprotectAllTextures();
170 }
171
172 PassRefPtr<GraphicsContext3D> CCLayerTreeHost::createLayerTreeHostContext3D()
173 {
174     return m_client->createLayerTreeHostContext3D();
175 }
176
177 PassOwnPtr<CCLayerTreeHostImpl> CCLayerTreeHost::createLayerTreeHostImpl(CCLayerTreeHostImplClient* client)
178 {
179     return CCLayerTreeHostImpl::create(m_settings, client);
180 }
181
182 void CCLayerTreeHost::didRecreateGraphicsContext(bool success)
183 {
184     if (m_rootLayer) {
185         m_rootLayer->setLayerTreeHost(0);
186         m_rootLayer->setLayerTreeHost(this);
187     }
188     m_client->didRecreateGraphicsContext(success);
189 }
190
191 // Temporary hack until WebViewImpl context creation gets simplified
192 GraphicsContext3D* CCLayerTreeHost::context()
193 {
194     ASSERT(!CCProxy::hasImplThread());
195     return m_proxy->context();
196 }
197
198 bool CCLayerTreeHost::compositeAndReadback(void *pixels, const IntRect& rect)
199 {
200     m_triggerIdlePaints = false;
201     bool ret = m_proxy->compositeAndReadback(pixels, rect);
202     m_triggerIdlePaints = true;
203     return ret;
204 }
205
206 void CCLayerTreeHost::finishAllRendering()
207 {
208     m_proxy->finishAllRendering();
209 }
210
211 const LayerRendererCapabilities& CCLayerTreeHost::layerRendererCapabilities() const
212 {
213     return m_proxy->layerRendererCapabilities();
214 }
215
216 void CCLayerTreeHost::setNeedsAnimate()
217 {
218     ASSERT(CCProxy::hasImplThread());
219     m_proxy->setNeedsAnimate();
220 }
221
222 void CCLayerTreeHost::setNeedsCommit()
223 {
224     if (CCThreadProxy::implThread())
225         m_proxy->setNeedsCommit();
226     else
227         m_client->scheduleComposite();
228 }
229
230 void CCLayerTreeHost::setNeedsRedraw()
231 {
232     if (CCThreadProxy::implThread())
233         m_proxy->setNeedsRedraw();
234     else
235         m_client->scheduleComposite();
236 }
237
238 void CCLayerTreeHost::setRootLayer(PassRefPtr<LayerChromium> rootLayer)
239 {
240     if (m_rootLayer == rootLayer)
241         return;
242
243     if (m_rootLayer)
244         m_rootLayer->setLayerTreeHost(0);
245     m_rootLayer = rootLayer;
246     if (m_rootLayer)
247         m_rootLayer->setLayerTreeHost(this);
248     setNeedsCommit();
249 }
250
251 void CCLayerTreeHost::setViewportSize(const IntSize& viewportSize)
252 {
253     if (viewportSize == m_viewportSize)
254         return;
255
256     contentsTextureManager()->setMaxMemoryLimitBytes(TextureManager::highLimitBytes(viewportSize));
257     contentsTextureManager()->setPreferredMemoryLimitBytes(TextureManager::reclaimLimitBytes(viewportSize));
258     m_viewportSize = viewportSize;
259     setNeedsCommit();
260 }
261
262 void CCLayerTreeHost::setPageScale(float pageScale)
263 {
264     if (pageScale == m_pageScale)
265         return;
266
267     m_pageScale = pageScale;
268     setNeedsCommit();
269 }
270
271 void CCLayerTreeHost::setPageScaleFactorLimits(float minScale, float maxScale)
272 {
273     if (minScale == m_minPageScale && maxScale == m_maxPageScale)
274         return;
275
276     m_minPageScale = minScale;
277     m_maxPageScale = maxScale;
278     setNeedsCommit();
279 }
280
281 void CCLayerTreeHost::setVisible(bool visible)
282 {
283     if (m_visible == visible)
284         return;
285
286     m_visible = visible;
287     if (!visible) {
288         m_contentsTextureManager->reduceMemoryToLimit(TextureManager::lowLimitBytes(viewportSize()));
289         m_contentsTextureManager->unprotectAllTextures();
290     }
291
292     // Tells the proxy that visibility state has changed. This will in turn call
293     // CCLayerTreeHost::didBecomeInvisibleOnImplThread on the appropriate thread, for
294     // the case where !visible.
295     m_proxy->setVisible(visible);
296 }
297
298 void CCLayerTreeHost::didBecomeInvisibleOnImplThread(CCLayerTreeHostImpl* hostImpl)
299 {
300     ASSERT(CCProxy::isImplThread());
301     if (m_proxy->layerRendererCapabilities().contextHasCachedFrontBuffer)
302         contentsTextureManager()->evictAndDeleteAllTextures(hostImpl->contentsTextureAllocator());
303     else {
304         contentsTextureManager()->reduceMemoryToLimit(TextureManager::reclaimLimitBytes(viewportSize()));
305         contentsTextureManager()->deleteEvictedTextures(hostImpl->contentsTextureAllocator());
306     }
307
308     // Ensure that the dropped tiles are propagated to the impl tree.
309     // If the frontbuffer is cached, then clobber the impl tree. Otherwise,
310     // push over the tree changes.
311     if (m_proxy->layerRendererCapabilities().contextHasCachedFrontBuffer) {
312         hostImpl->setRootLayer(0);
313         return;
314     }
315     if (rootLayer())
316         hostImpl->setRootLayer(TreeSynchronizer::synchronizeTrees(rootLayer(), hostImpl->rootLayer()));
317     else
318         hostImpl->setRootLayer(0);
319 }
320
321 void CCLayerTreeHost::setHaveWheelEventHandlers(bool haveWheelEventHandlers)
322 {
323     if (m_haveWheelEventHandlers == haveWheelEventHandlers)
324         return;
325     m_haveWheelEventHandlers = haveWheelEventHandlers;
326     m_proxy->setNeedsCommit();
327 }
328
329
330 void CCLayerTreeHost::loseCompositorContext(int numTimes)
331 {
332     m_proxy->loseCompositorContext(numTimes);
333 }
334
335 TextureManager* CCLayerTreeHost::contentsTextureManager() const
336 {
337     return m_contentsTextureManager.get();
338 }
339
340 void CCLayerTreeHost::composite()
341 {
342     ASSERT(!CCThreadProxy::implThread());
343     static_cast<CCSingleThreadProxy*>(m_proxy.get())->compositeImmediately();
344 }
345
346 void CCLayerTreeHost::updateLayers()
347 {
348     if (!rootLayer())
349         return;
350
351     if (viewportSize().isEmpty())
352         return;
353
354     updateLayers(rootLayer());
355 }
356
357 void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer)
358 {
359     TRACE_EVENT("CCLayerTreeHost::updateLayers", this, 0);
360
361     if (!rootLayer->renderSurface())
362         rootLayer->createRenderSurface();
363     rootLayer->renderSurface()->setContentRect(IntRect(IntPoint(0, 0), viewportSize()));
364
365     IntRect rootClipRect(IntPoint(), viewportSize());
366     rootLayer->setClipRect(rootClipRect);
367
368     // This assert fires if updateCompositorResources wasn't called after
369     // updateLayers. Only one update can be pending at any given time.
370     ASSERT(!m_updateList.size());
371     m_updateList.append(rootLayer);
372
373     RenderSurfaceChromium* rootRenderSurface = rootLayer->renderSurface();
374     rootRenderSurface->clearLayerList();
375
376     TransformationMatrix identityMatrix;
377     {
378         TRACE_EVENT("CCLayerTreeHost::updateLayers::calcDrawEtc", this, 0);
379         CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer, rootLayer, identityMatrix, identityMatrix, m_updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize);
380     }
381
382     paintLayerContents(m_updateList, PaintVisible);
383     if (!m_triggerIdlePaints)
384         return;
385
386     size_t preferredLimitBytes = TextureManager::reclaimLimitBytes(m_viewportSize);
387     size_t maxLimitBytes = TextureManager::highLimitBytes(m_viewportSize);
388     contentsTextureManager()->reduceMemoryToLimit(preferredLimitBytes);
389     if (contentsTextureManager()->currentMemoryUseBytes() >= preferredLimitBytes)
390         return;
391
392     // Idle painting should fail when we hit the preferred memory limit,
393     // otherwise it will always push us towards the maximum limit.
394     m_contentsTextureManager->setMaxMemoryLimitBytes(preferredLimitBytes);
395     // The second (idle) paint will be a no-op in layers where painting already occured above.
396     paintLayerContents(m_updateList, PaintIdle);
397     m_contentsTextureManager->setMaxMemoryLimitBytes(maxLimitBytes);
398 }
399
400 // static
401 void CCLayerTreeHost::paintContentsIfDirty(LayerChromium* layer, PaintType paintType)
402 {
403     ASSERT(layer);
404     ASSERT(PaintVisible == paintType || PaintIdle == paintType);
405     if (PaintVisible == paintType)
406         layer->paintContentsIfDirty();
407     else
408         layer->idlePaintContentsIfDirty();
409 }
410
411 void CCLayerTreeHost::paintMaskAndReplicaForRenderSurface(LayerChromium* renderSurfaceLayer, PaintType paintType)
412 {
413     // Note: Masks and replicas only exist for layers that own render surfaces. If we reach this point
414     // in code, we already know that at least something will be drawn into this render surface, so the
415     // mask and replica should be painted.
416
417     if (renderSurfaceLayer->maskLayer()) {
418         renderSurfaceLayer->maskLayer()->setVisibleLayerRect(IntRect(IntPoint(), renderSurfaceLayer->contentBounds()));
419         paintContentsIfDirty(renderSurfaceLayer->maskLayer(), paintType);
420     }
421
422     LayerChromium* replicaLayer = renderSurfaceLayer->replicaLayer();
423     if (replicaLayer) {
424         paintContentsIfDirty(replicaLayer, paintType);
425
426         if (replicaLayer->maskLayer()) {
427             replicaLayer->maskLayer()->setVisibleLayerRect(IntRect(IntPoint(), replicaLayer->maskLayer()->contentBounds()));
428             paintContentsIfDirty(replicaLayer->maskLayer(), paintType);
429         }
430     }
431 }
432
433 void CCLayerTreeHost::paintLayerContents(const LayerList& renderSurfaceLayerList, PaintType paintType)
434 {
435     // Use FrontToBack to allow for testing occlusion and performing culling during the tree walk.
436     typedef CCLayerIterator<LayerChromium, RenderSurfaceChromium, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType;
437
438     CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
439     for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
440         if (it.representsTargetRenderSurface()) {
441             ASSERT(it->renderSurface()->drawOpacity());
442             paintMaskAndReplicaForRenderSurface(*it, paintType);
443         } else if (it.representsItself()) {
444             ASSERT(!it->bounds().isEmpty());
445             paintContentsIfDirty(*it, paintType);
446         }
447     }
448 }
449
450 void CCLayerTreeHost::updateCompositorResources(GraphicsContext3D* context, CCTextureUpdater& updater)
451 {
452     // Use BackToFront since it's cheap and this isn't order-dependent.
453     typedef CCLayerIterator<LayerChromium, RenderSurfaceChromium, CCLayerIteratorActions::BackToFront> CCLayerIteratorType;
454
455     CCLayerIteratorType end = CCLayerIteratorType::end(&m_updateList);
456     for (CCLayerIteratorType it = CCLayerIteratorType::begin(&m_updateList); it != end; ++it) {
457         if (it.representsTargetRenderSurface()) {
458             ASSERT(it->renderSurface()->drawOpacity());
459             if (it->maskLayer())
460                 it->maskLayer()->updateCompositorResources(context, updater);
461
462             if (it->replicaLayer()) {
463                 it->replicaLayer()->updateCompositorResources(context, updater);
464                 if (it->replicaLayer()->maskLayer())
465                     it->replicaLayer()->maskLayer()->updateCompositorResources(context, updater);
466             }
467         } else if (it.representsItself())
468             it->updateCompositorResources(context, updater);
469     }
470 }
471
472 void CCLayerTreeHost::clearPendingUpdate()
473 {
474     for (size_t surfaceIndex = 0; surfaceIndex < m_updateList.size(); ++surfaceIndex) {
475         LayerChromium* layer = m_updateList[surfaceIndex].get();
476         ASSERT(layer->renderSurface());
477         layer->clearRenderSurface();
478     }
479     m_updateList.clear();
480 }
481
482 void CCLayerTreeHost::applyScrollAndScale(const CCScrollAndScaleSet& info)
483 {
484     // FIXME: pushing scroll offsets to non-root layers not implemented
485     if (!info.scrolls.size())
486         return;
487
488     ASSERT(info.scrolls.size() == 1);
489     IntSize scrollDelta = info.scrolls[0].scrollDelta;
490     m_client->applyScrollAndScale(scrollDelta, info.pageScaleDelta);
491 }
492
493 void CCLayerTreeHost::startRateLimiter(GraphicsContext3D* context)
494 {
495     if (m_animating)
496         return;
497     ASSERT(context);
498     RateLimiterMap::iterator it = m_rateLimiters.find(context);
499     if (it != m_rateLimiters.end())
500         it->second->start();
501     else {
502         RefPtr<RateLimiter> rateLimiter = RateLimiter::create(context);
503         m_rateLimiters.set(context, rateLimiter);
504         rateLimiter->start();
505     }
506 }
507
508 void CCLayerTreeHost::stopRateLimiter(GraphicsContext3D* context)
509 {
510     RateLimiterMap::iterator it = m_rateLimiters.find(context);
511     if (it != m_rateLimiters.end()) {
512         it->second->stop();
513         m_rateLimiters.remove(it);
514     }
515 }
516
517 }