[chromium] Set the CCLayerTreeHost pointer on LayerChromium instances eagerly
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / TiledLayerChromium.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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if USE(ACCELERATED_COMPOSITING)
29
30 #include "TiledLayerChromium.h"
31
32 #include "GraphicsContext3D.h"
33 #include "LayerRendererChromium.h"
34 #include "ManagedTexture.h"
35 #include "MathExtras.h"
36 #include "TextStream.h"
37 #include "cc/CCLayerImpl.h"
38 #include "cc/CCTextureUpdater.h"
39 #include "cc/CCTiledLayerImpl.h"
40 #include <wtf/CurrentTime.h>
41
42 // Start tiling when the width and height of a layer are larger than this size.
43 static int maxUntiledSize = 512;
44
45 // When tiling is enabled, use tiles of this dimension squared.
46 static int defaultTileSize = 256;
47
48 using namespace std;
49
50 namespace WebCore {
51
52 class UpdatableTile : public CCLayerTilingData::Tile {
53     WTF_MAKE_NONCOPYABLE(UpdatableTile);
54 public:
55     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture) : m_texture(texture) { }
56
57     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
58     ManagedTexture* managedTexture() { return m_texture->texture(); }
59
60     bool isDirty() const { return !m_dirtyLayerRect.isEmpty(); }
61     void clearDirty() { m_dirtyLayerRect = IntRect(); }
62
63     // Layer-space dirty rectangle that needs to be repainted.
64     IntRect m_dirtyLayerRect;
65     // Content-space rectangle that needs to be updated.
66     IntRect m_updateRect;
67 private:
68     OwnPtr<LayerTextureUpdater::Texture> m_texture;
69 };
70
71 TiledLayerChromium::TiledLayerChromium(CCLayerDelegate* delegate)
72     : LayerChromium(delegate)
73     , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
74     , m_skipsDraw(false)
75     , m_skipsIdlePaint(false)
76     , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
77     , m_tilingOption(AutoTile)
78 {
79 }
80
81 TiledLayerChromium::~TiledLayerChromium()
82 {
83 }
84
85 PassRefPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
86 {
87     return CCTiledLayerImpl::create(id());
88 }
89
90 void TiledLayerChromium::cleanupResources()
91 {
92     LayerChromium::cleanupResources();
93
94     m_tiler.clear();
95     m_paintRect = IntRect();
96     m_requestedUpdateTilesRect = IntRect();
97 }
98
99 void TiledLayerChromium::updateTileSizeAndTilingOption()
100 {
101     const IntSize tileSize(min(defaultTileSize, contentBounds().width()), min(defaultTileSize, contentBounds().height()));
102
103     // Tile if both dimensions large, or any one dimension large and the other
104     // extends into a second tile. This heuristic allows for long skinny layers
105     // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space.
106     const bool anyDimensionLarge = contentBounds().width() > maxUntiledSize || contentBounds().height() > maxUntiledSize;
107     const bool anyDimensionOneTile = contentBounds().width() <= defaultTileSize || contentBounds().height() <= defaultTileSize;
108     const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile;
109
110     bool isTiled;
111     if (m_tilingOption == AlwaysTile)
112         isTiled = true;
113     else if (m_tilingOption == NeverTile)
114         isTiled = false;
115     else
116         isTiled = autoTiled;
117
118     IntSize requestedSize = isTiled ? tileSize : contentBounds();
119     const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize;
120     IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize));
121     setTileSize(clampedSize);
122 }
123
124 void TiledLayerChromium::setTileSize(const IntSize& size)
125 {
126     if (m_tiler && m_tileSize == size)
127         return;
128     m_tileSize = size;
129     m_tiler.clear(); // Changing the tile size invalidates all tiles, so we just throw away the tiling data.
130 }
131
132 bool TiledLayerChromium::drawsContent() const
133 {
134     if (!m_delegate)
135         return false;
136
137     if (!m_tiler)
138         return true;
139
140     if (m_tilingOption == NeverTile && m_tiler->numTiles() > 1)
141         return false;
142
143     return !m_skipsDraw;
144 }
145
146 bool TiledLayerChromium::needsContentsScale() const
147 {
148     return true;
149 }
150
151 IntSize TiledLayerChromium::contentBounds() const
152 {
153     return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale()));
154 }
155
156 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
157 {
158     if (host == layerTreeHost())
159         return;
160
161     if (layerTreeHost())
162         cleanupResources();
163
164     LayerChromium::setLayerTreeHost(host);
165
166     if (!host)
167         return;
168
169     createTextureUpdater(host);
170     setTextureFormat(host->layerRendererCapabilities().bestTextureFormat);
171     m_sampledTexelFormat = textureUpdater()->sampledTexelFormat(m_textureFormat);
172 }
173
174 void TiledLayerChromium::createTiler(CCLayerTilingData::BorderTexelOption borderTexelOption)
175 {
176     m_tiler = CCLayerTilingData::create(m_tileSize, borderTexelOption);
177 }
178
179 void TiledLayerChromium::updateCompositorResources(GraphicsContext3D*, CCTextureUpdater& updater)
180 {
181     // If this assert is hit, it means that paintContentsIfDirty hasn't been
182     // called on this layer. Any layer that is updated should be painted first.
183     ASSERT(m_skipsDraw || m_tiler);
184
185     // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update.
186     if (m_skipsDraw || m_requestedUpdateTilesRect.isEmpty() || !m_tiler || !m_tiler->numTiles())
187         return;
188
189     int left = m_requestedUpdateTilesRect.x();
190     int top = m_requestedUpdateTilesRect.y();
191     int right = m_requestedUpdateTilesRect.maxX() - 1;
192     int bottom = m_requestedUpdateTilesRect.maxY() - 1;
193     for (int j = top; j <= bottom; ++j) {
194         for (int i = left; i <= right; ++i) {
195             UpdatableTile* tile = tileAt(i, j);
196
197             // Required tiles are created in prepareToUpdate(). A tile should
198             // never be removed between the call to prepareToUpdate() and the
199             // call to updateCompositorResources().
200             if (!tile)
201                 CRASH();
202
203             IntRect sourceRect = tile->m_updateRect;
204             if (tile->m_updateRect.isEmpty())
205                 continue;
206
207             ASSERT(tile->managedTexture()->isReserved());
208             const IntPoint anchor = m_tiler->tileContentRect(tile).location();
209
210             // Calculate tile-space rectangle to upload into.
211             IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
212             if (destRect.x() < 0)
213                 CRASH();
214             if (destRect.y() < 0)
215                 CRASH();
216
217             // Offset from paint rectangle to this tile's dirty rectangle.
218             IntPoint paintOffset(sourceRect.x() - m_paintRect.x(), sourceRect.y() - m_paintRect.y());
219             if (paintOffset.x() < 0)
220                 CRASH();
221             if (paintOffset.y() < 0)
222                 CRASH();
223             if (paintOffset.x() + destRect.width() > m_paintRect.width())
224                 CRASH();
225             if (paintOffset.y() + destRect.height() > m_paintRect.height())
226                 CRASH();
227
228             updater.append(tile->texture(), sourceRect, destRect);
229         }
230     }
231
232     m_updateRect = FloatRect(m_tiler->contentRectToLayerRect(m_paintRect));
233 }
234
235 void TiledLayerChromium::setTilingOption(TilingOption tilingOption)
236 {
237     if (m_tiler && m_tilingOption == tilingOption)
238         return;
239     m_tilingOption = tilingOption;
240     m_tiler.clear(); // Changing the tiling option invalidates all tiles, so we just throw away the tiling data.
241 }
242
243 void TiledLayerChromium::setIsMask(bool isMask)
244 {
245     setTilingOption(isMask ? NeverTile : AutoTile);
246 }
247
248 void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
249 {
250     LayerChromium::pushPropertiesTo(layer);
251
252     CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer);
253     if (!m_tiler) {
254         tiledLayer->setSkipsDraw(true);
255         return;
256     }
257
258     tiledLayer->setSkipsDraw(m_skipsDraw);
259     tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater::SampledTexelFormatRGBA);
260     tiledLayer->setTilingData(*m_tiler);
261
262     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
263         int i = iter->first.first;
264         int j = iter->first.second;
265         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
266         if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
267             continue;
268         if (tile->isDirty())
269             continue;
270
271         tiledLayer->syncTextureId(i, j, tile->managedTexture()->textureId());
272     }
273 }
274
275 TextureManager* TiledLayerChromium::textureManager() const
276 {
277     if (!layerTreeHost())
278         return 0;
279     return layerTreeHost()->contentsTextureManager();
280 }
281
282 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
283 {
284     return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
285 }
286
287 UpdatableTile* TiledLayerChromium::createTile(int i, int j)
288 {
289     RefPtr<UpdatableTile> tile = adoptRef(new UpdatableTile(textureUpdater()->createTexture(textureManager())));
290     m_tiler->addTile(tile, i, j);
291     tile->m_dirtyLayerRect = m_tiler->tileLayerRect(tile.get());
292
293     return tile.get();
294 }
295
296 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
297 {
298     IntRect dirty = enclosingIntRect(dirtyRect);
299     invalidateRect(dirty);
300     LayerChromium::setNeedsDisplayRect(dirtyRect);
301 }
302
303 void TiledLayerChromium::invalidateRect(const IntRect& contentRect)
304 {
305     if (!m_tiler || contentRect.isEmpty() || m_skipsDraw)
306         return;
307
308     // Dirty rects are always in layer space, as the layer could be repositioned
309     // after invalidation.
310     const IntRect layerRect = m_tiler->contentRectToLayerRect(contentRect);
311
312     int left, top, right, bottom;
313     m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
314     for (int j = top; j <= bottom; ++j) {
315         for (int i = left; i <= right; ++i) {
316             UpdatableTile* tile = tileAt(i, j);
317             if (!tile)
318                 continue;
319             IntRect bound = m_tiler->tileLayerRect(tile);
320             bound.intersect(layerRect);
321             tile->m_dirtyLayerRect.unite(bound);
322         }
323     }
324 }
325
326 void TiledLayerChromium::protectVisibleTileTextures()
327 {
328     protectTileTextures(IntRect(IntPoint::zero(), contentBounds()));
329 }
330
331 void TiledLayerChromium::protectTileTextures(const IntRect& contentRect)
332 {
333     if (!m_tiler || contentRect.isEmpty())
334         return;
335
336     int left, top, right, bottom;
337     m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
338
339     for (int j = top; j <= bottom; ++j) {
340         for (int i = left; i <= right; ++i) {
341             UpdatableTile* tile = tileAt(i, j);
342             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
343                 continue;
344
345             tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat);
346         }
347     }
348 }
349
350 void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom)
351 {
352     // Reset m_updateRect for all tiles.
353     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
354         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
355         tile->m_updateRect = IntRect();
356     }
357
358     // Create tiles as needed, expanding a dirty rect to contain all
359     // the dirty regions currently being drawn.
360     IntRect dirtyLayerRect;
361     for (int j = top; j <= bottom; ++j) {
362         for (int i = left; i <= right; ++i) {
363             UpdatableTile* tile = tileAt(i, j);
364             if (!tile)
365                 tile = createTile(i, j);
366
367             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
368                 tile->m_dirtyLayerRect = m_tiler->tileLayerRect(tile);
369
370             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) {
371                 m_skipsIdlePaint = true;
372                 if (!idle) {
373                     m_skipsDraw = true;
374                     cleanupResources();
375                 }
376                 return;
377             }
378
379             dirtyLayerRect.unite(tile->m_dirtyLayerRect);
380         }
381     }
382
383     m_paintRect = m_tiler->layerRectToContentRect(dirtyLayerRect);
384     if (dirtyLayerRect.isEmpty())
385         return;
386
387     // Due to borders, when the paint rect is extended to tile boundaries, it
388     // may end up overlapping more tiles than the original content rect. Record
389     // the original tiles so we don't upload more tiles than necessary.
390     if (!m_paintRect.isEmpty())
391         m_requestedUpdateTilesRect = IntRect(left, top, right - left + 1, bottom - top + 1);
392
393     // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
394     // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
395     // However, we can't free the memory backing the GraphicsContext until the paint finishes,
396     // so we grab a local reference here to hold the updater alive until the paint completes.
397     RefPtr<LayerTextureUpdater> protector(textureUpdater());
398     textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale());
399     for (int j = top; j <= bottom; ++j) {
400         for (int i = left; i <= right; ++i) {
401             UpdatableTile* tile = tileAt(i, j);
402
403             // Tiles are created before prepareToUpdate() is called.
404             if (!tile)
405                 CRASH();
406
407             if (!tile->isDirty())
408                 continue;
409
410             // Calculate content-space rectangle to copy from.
411             IntRect sourceRect = m_tiler->tileContentRect(tile);
412             sourceRect.intersect(m_tiler->layerRectToContentRect(tile->m_dirtyLayerRect));
413             // Paint rect not guaranteed to line up on tile boundaries, so
414             // make sure that sourceRect doesn't extend outside of it.
415             sourceRect.intersect(m_paintRect);
416
417             // updateCompositorResources() uses m_updateRect to determine
418             // the tiles to update so we can clear the dirty rectangle here.
419             tile->clearDirty();
420
421             tile->m_updateRect = sourceRect;
422             if (sourceRect.isEmpty())
423                 continue;
424
425             tile->texture()->prepareRect(sourceRect);
426         }
427     }
428 }
429
430
431 void TiledLayerChromium::prepareToUpdate(const IntRect& contentRect)
432 {
433     if (!m_tiler)
434         createTiler(isNonCompositedContent() ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels);
435
436     ASSERT(m_tiler);
437
438     m_skipsDraw = false;
439     m_skipsIdlePaint = false;
440     m_requestedUpdateTilesRect = IntRect();
441     m_paintRect = IntRect();
442
443     m_tiler->growLayerToContain(IntRect(IntPoint::zero(), contentBounds()));
444
445     if (contentRect.isEmpty() || !m_tiler->numTiles())
446         return;
447
448     int left, top, right, bottom;
449     m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
450
451     prepareToUpdateTiles(false, left, top, right, bottom);
452 }
453
454 void TiledLayerChromium::prepareToUpdateIdle(const IntRect& contentRect)
455 {
456     // Abort if we have already prepared a paint or run out of memory.
457     if (m_skipsIdlePaint || !m_paintRect.isEmpty())
458         return;
459
460     ASSERT(m_tiler);
461
462     m_tiler->growLayerToContain(IntRect(IntPoint::zero(), contentBounds()));
463
464     if (!m_tiler->numTiles())
465         return;
466
467     // Protect any textures in the pre-paint area so we don't end up just
468     // reclaiming them below.
469     IntRect idlePaintContentRect = idlePaintRect(contentRect);
470     protectTileTextures(idlePaintContentRect);
471
472     // Expand outwards until we find a dirty row or column to update.
473     int left, top, right, bottom;
474     m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
475     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
476     m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
477     while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
478         if (bottom < prepaintBottom) {
479             ++bottom;
480             prepareToUpdateTiles(true, left, bottom, right, bottom);
481             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
482                 break;
483         }
484         if (top > prepaintTop) {
485             --top;
486             prepareToUpdateTiles(true, left, top, right, top);
487             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
488                 break;
489         }
490         if (left > prepaintLeft) {
491             --left;
492             prepareToUpdateTiles(true, left, top, left, bottom);
493             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
494                 break;
495         }
496         if (right < prepaintRight) {
497             ++right;
498             prepareToUpdateTiles(true, right, top, right, bottom);
499             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
500                 break;
501         }
502     }
503 }
504
505 bool TiledLayerChromium::needsIdlePaint(const IntRect& contentRect)
506 {
507     if (m_skipsIdlePaint)
508         return false;
509
510     ASSERT(m_tiler);
511
512     IntRect idlePaintContentRect = idlePaintRect(contentRect);
513
514     int left, top, right, bottom;
515     m_tiler->contentRectToTileIndices(idlePaintContentRect, left, top, right, bottom);
516     for (int j = top; j <= bottom; ++j) {
517         for (int i = left; i <= right; ++i) {
518             if (m_requestedUpdateTilesRect.contains(IntPoint(i, j)))
519                 continue;
520             UpdatableTile* tile = tileAt(i, j);
521             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat) || tile->isDirty())
522                 return true;
523         }
524     }
525     return false;
526 }
527
528 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleContentRect)
529 {
530     ASSERT(m_tiler);
531     IntRect prepaintRect = visibleContentRect;
532     // FIXME: This can be made a lot larger if we can:
533     // - reserve memory at a lower priority than for visible content
534     // - only reserve idle paint tiles up to a memory reclaim threshold and
535     // - insure we play nicely with other layers
536     prepaintRect.inflateX(m_tiler->tileSize().width());
537     prepaintRect.inflateY(m_tiler->tileSize().height());
538     prepaintRect.intersect(IntRect(IntPoint::zero(), contentBounds()));
539     return prepaintRect;
540 }
541
542 }
543 #endif // USE(ACCELERATED_COMPOSITING)