[chromium] Don't ever skip drawing the non-composited content layer
[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 "Region.h"
37 #include "TextStream.h"
38 #include "cc/CCLayerImpl.h"
39 #include "cc/CCTextureUpdater.h"
40 #include "cc/CCTiledLayerImpl.h"
41 #include <wtf/CurrentTime.h>
42
43 // Start tiling when the width and height of a layer are larger than this size.
44 static int maxUntiledSize = 512;
45
46 // When tiling is enabled, use tiles of this dimension squared.
47 static int defaultTileSize = 256;
48
49 using namespace std;
50
51 namespace WebCore {
52
53 class UpdatableTile : public CCLayerTilingData::Tile {
54     WTF_MAKE_NONCOPYABLE(UpdatableTile);
55 public:
56     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture) : m_texture(texture) { }
57
58     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
59     ManagedTexture* managedTexture() { return m_texture->texture(); }
60
61     bool isDirty() const { return !m_dirtyRect.isEmpty(); }
62     void copyAndClearDirty()
63     {
64         m_updateRect = m_dirtyRect;
65         m_dirtyRect = IntRect();
66     }
67
68     IntRect m_dirtyRect;
69     IntRect m_updateRect;
70 private:
71     OwnPtr<LayerTextureUpdater::Texture> m_texture;
72 };
73
74 TiledLayerChromium::TiledLayerChromium()
75     : LayerChromium()
76     , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
77     , m_skipsDraw(false)
78     , m_skipsIdlePaint(false)
79     , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
80     , m_tilingOption(AutoTile)
81 {
82     m_tiler = CCLayerTilingData::create(IntSize(defaultTileSize, defaultTileSize), CCLayerTilingData::HasBorderTexels);
83 }
84
85 TiledLayerChromium::~TiledLayerChromium()
86 {
87 }
88
89 PassRefPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
90 {
91     return CCTiledLayerImpl::create(id());
92 }
93
94 void TiledLayerChromium::cleanupResources()
95 {
96     LayerChromium::cleanupResources();
97
98     m_tiler->reset();
99     m_paintRect = IntRect();
100     m_requestedUpdateTilesRect = IntRect();
101 }
102
103 void TiledLayerChromium::updateTileSizeAndTilingOption()
104 {
105     const IntSize tileSize(min(defaultTileSize, contentBounds().width()), min(defaultTileSize, contentBounds().height()));
106
107     // Tile if both dimensions large, or any one dimension large and the other
108     // extends into a second tile. This heuristic allows for long skinny layers
109     // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space.
110     const bool anyDimensionLarge = contentBounds().width() > maxUntiledSize || contentBounds().height() > maxUntiledSize;
111     const bool anyDimensionOneTile = contentBounds().width() <= defaultTileSize || contentBounds().height() <= defaultTileSize;
112     const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile;
113
114     bool isTiled;
115     if (m_tilingOption == AlwaysTile)
116         isTiled = true;
117     else if (m_tilingOption == NeverTile)
118         isTiled = false;
119     else
120         isTiled = autoTiled;
121
122     IntSize requestedSize = isTiled ? tileSize : contentBounds();
123     const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize;
124     IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize));
125     setTileSize(clampedSize);
126 }
127
128 void TiledLayerChromium::updateBounds()
129 {
130     IntSize oldBounds = m_tiler->bounds();
131     IntSize newBounds = contentBounds();
132     if (oldBounds == newBounds)
133         return;
134     m_tiler->setBounds(newBounds);
135
136     // Invalidate any areas that the new bounds exposes.
137     Region oldRegion(IntRect(IntPoint(), oldBounds));
138     Region newRegion(IntRect(IntPoint(), newBounds));
139     newRegion.subtract(oldRegion);
140     Vector<IntRect> rects = newRegion.rects();
141     for (size_t i = 0; i < rects.size(); ++i)
142         invalidateRect(rects[i]);
143 }
144
145 void TiledLayerChromium::setTileSize(const IntSize& size)
146 {
147     m_tiler->setTileSize(size);
148 }
149
150 void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOption borderTexelOption)
151 {
152     m_tiler->setBorderTexelOption(borderTexelOption);
153 }
154
155 bool TiledLayerChromium::drawsContent() const
156 {
157     if (!LayerChromium::drawsContent())
158         return false;
159
160     if (m_tilingOption == NeverTile && m_tiler->numTiles() > 1)
161         return false;
162
163     return true;
164 }
165
166 bool TiledLayerChromium::needsContentsScale() const
167 {
168     return true;
169 }
170
171 IntSize TiledLayerChromium::contentBounds() const
172 {
173     return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale()));
174 }
175
176 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
177 {
178     if (host == layerTreeHost())
179         return;
180
181     LayerChromium::setLayerTreeHost(host);
182
183     if (!host)
184         return;
185
186     createTextureUpdater(host);
187     setTextureFormat(host->layerRendererCapabilities().bestTextureFormat);
188     m_sampledTexelFormat = textureUpdater()->sampledTexelFormat(m_textureFormat);
189 }
190
191 void TiledLayerChromium::updateCompositorResources(GraphicsContext3D*, CCTextureUpdater& updater)
192 {
193     // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update.
194     if (m_skipsDraw || m_requestedUpdateTilesRect.isEmpty() || m_tiler->isEmpty())
195         return;
196
197     int left = m_requestedUpdateTilesRect.x();
198     int top = m_requestedUpdateTilesRect.y();
199     int right = m_requestedUpdateTilesRect.maxX() - 1;
200     int bottom = m_requestedUpdateTilesRect.maxY() - 1;
201     for (int j = top; j <= bottom; ++j) {
202         for (int i = left; i <= right; ++i) {
203             UpdatableTile* tile = tileAt(i, j);
204
205             // Required tiles are created in prepareToUpdate(). A tile should
206             // never be removed between the call to prepareToUpdate() and the
207             // call to updateCompositorResources().
208             if (!tile)
209                 CRASH();
210
211             IntRect sourceRect = tile->m_updateRect;
212             if (tile->m_updateRect.isEmpty())
213                 continue;
214
215             ASSERT(tile->managedTexture()->isReserved());
216             const IntPoint anchor = m_tiler->tileRect(tile).location();
217
218             // Calculate tile-space rectangle to upload into.
219             IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
220             if (destRect.x() < 0)
221                 CRASH();
222             if (destRect.y() < 0)
223                 CRASH();
224
225             // Offset from paint rectangle to this tile's dirty rectangle.
226             IntPoint paintOffset(sourceRect.x() - m_paintRect.x(), sourceRect.y() - m_paintRect.y());
227             if (paintOffset.x() < 0)
228                 CRASH();
229             if (paintOffset.y() < 0)
230                 CRASH();
231             if (paintOffset.x() + destRect.width() > m_paintRect.width())
232                 CRASH();
233             if (paintOffset.y() + destRect.height() > m_paintRect.height())
234                 CRASH();
235
236             updater.append(tile->texture(), sourceRect, destRect);
237         }
238     }
239
240     // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space.
241     m_updateRect = FloatRect(m_paintRect);
242     float widthScale = bounds().width() / static_cast<float>(contentBounds().width());
243     float heightScale = bounds().height() / static_cast<float>(contentBounds().height());
244     m_updateRect.scale(widthScale, heightScale);
245 }
246
247 void TiledLayerChromium::setTilingOption(TilingOption tilingOption)
248 {
249     m_tilingOption = tilingOption;
250 }
251
252 void TiledLayerChromium::setIsMask(bool isMask)
253 {
254     setTilingOption(isMask ? NeverTile : AutoTile);
255 }
256
257 void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
258 {
259     LayerChromium::pushPropertiesTo(layer);
260
261     CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer);
262
263     tiledLayer->setSkipsDraw(m_skipsDraw);
264     tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater::SampledTexelFormatRGBA);
265     tiledLayer->setTilingData(*m_tiler);
266
267     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
268         int i = iter->first.first;
269         int j = iter->first.second;
270         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
271         if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
272             continue;
273         if (tile->isDirty())
274             continue;
275
276         tiledLayer->syncTextureId(i, j, tile->managedTexture()->textureId());
277     }
278 }
279
280 TextureManager* TiledLayerChromium::textureManager() const
281 {
282     if (!layerTreeHost())
283         return 0;
284     return layerTreeHost()->contentsTextureManager();
285 }
286
287 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
288 {
289     return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
290 }
291
292 UpdatableTile* TiledLayerChromium::createTile(int i, int j)
293 {
294     RefPtr<UpdatableTile> tile = adoptRef(new UpdatableTile(textureUpdater()->createTexture(textureManager())));
295     m_tiler->addTile(tile, i, j);
296     tile->m_dirtyRect = m_tiler->tileRect(tile.get());
297
298     return tile.get();
299 }
300
301 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
302 {
303     IntRect dirty = enclosingIntRect(dirtyRect);
304     invalidateRect(dirty);
305     LayerChromium::setNeedsDisplayRect(dirtyRect);
306 }
307
308 void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
309 {
310     LayerChromium::setIsNonCompositedContent(isNonCompositedContent);
311
312     CCLayerTilingData::BorderTexelOption borderTexelOption;
313 #if OS(ANDROID)
314     // Always want border texels and GL_LINEAR due to pinch zoom.
315     borderTexelOption = CCLayerTilingData::HasBorderTexels;
316 #else
317     borderTexelOption = isNonCompositedContent ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
318 #endif
319     setBorderTexelOption(borderTexelOption);
320 }
321
322 void TiledLayerChromium::invalidateRect(const IntRect& layerRect)
323 {
324     if (m_tiler->isEmpty() || layerRect.isEmpty() || m_skipsDraw)
325         return;
326
327     int left, top, right, bottom;
328     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
329     for (int j = top; j <= bottom; ++j) {
330         for (int i = left; i <= right; ++i) {
331             UpdatableTile* tile = tileAt(i, j);
332             if (!tile)
333                 continue;
334             IntRect bound = m_tiler->tileRect(tile);
335             bound.intersect(layerRect);
336             tile->m_dirtyRect.unite(bound);
337         }
338     }
339 }
340
341 void TiledLayerChromium::protectVisibleTileTextures()
342 {
343     protectTileTextures(IntRect(IntPoint::zero(), contentBounds()));
344 }
345
346 void TiledLayerChromium::protectTileTextures(const IntRect& layerRect)
347 {
348     if (m_tiler->isEmpty() || layerRect.isEmpty())
349         return;
350
351     int left, top, right, bottom;
352     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
353
354     for (int j = top; j <= bottom; ++j) {
355         for (int i = left; i <= right; ++i) {
356             UpdatableTile* tile = tileAt(i, j);
357             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
358                 continue;
359
360             tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat);
361         }
362     }
363 }
364
365 void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom)
366 {
367     // Reset m_updateRect for all tiles.
368     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
369         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
370         tile->m_updateRect = IntRect();
371     }
372
373     // Create tiles as needed, expanding a dirty rect to contain all
374     // the dirty regions currently being drawn. All dirty tiles that are to be painted
375     // get their m_updateRect set to m_dirtyRect and m_dirtyRect cleared. This way if
376     // invalidateRect is invoked during prepareToUpdate we don't lose the request.
377     IntRect dirtyLayerRect;
378     for (int j = top; j <= bottom; ++j) {
379         for (int i = left; i <= right; ++i) {
380             UpdatableTile* tile = tileAt(i, j);
381             if (!tile)
382                 tile = createTile(i, j);
383
384             // Do post commit deletion of current texture when partial texture
385             // updates are not used.
386             if (tile->isDirty() && layerTreeHost() && !layerTreeHost()->settings().partialTextureUpdates)
387                 layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal());
388
389             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
390                 tile->m_dirtyRect = m_tiler->tileRect(tile);
391
392             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) {
393                 m_skipsIdlePaint = true;
394                 if (!idle) {
395                     // If the background covers the viewport, always draw this
396                     // layer so that checkerboarded tiles will still draw.
397                     if (!backgroundCoversViewport())
398                         m_skipsDraw = true;
399                     cleanupResources();
400                 }
401                 return;
402             }
403
404             dirtyLayerRect.unite(tile->m_dirtyRect);
405             tile->copyAndClearDirty();
406         }
407     }
408
409     m_paintRect = dirtyLayerRect;
410     if (dirtyLayerRect.isEmpty())
411         return;
412
413     // Due to borders, when the paint rect is extended to tile boundaries, it
414     // may end up overlapping more tiles than the original content rect. Record
415     // the original tiles so we don't upload more tiles than necessary.
416     if (!m_paintRect.isEmpty())
417         m_requestedUpdateTilesRect = IntRect(left, top, right - left + 1, bottom - top + 1);
418
419     // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
420     // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
421     // However, we can't free the memory backing the GraphicsContext until the paint finishes,
422     // so we grab a local reference here to hold the updater alive until the paint completes.
423     RefPtr<LayerTextureUpdater> protector(textureUpdater());
424     IntRect opaqueRect; // FIXME: unused. remove this and store in the layer to pass to impl for draw culling
425     textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &opaqueRect);
426     for (int j = top; j <= bottom; ++j) {
427         for (int i = left; i <= right; ++i) {
428             UpdatableTile* tile = tileAt(i, j);
429
430             // Tiles are created before prepareToUpdate() is called.
431             if (!tile)
432                 CRASH();
433
434             // Use m_updateRect as copyAndClearDirty above moved the existing dirty rect to m_updateRect.
435             const IntRect& dirtyRect = tile->m_updateRect;
436             if (dirtyRect.isEmpty())
437                 continue;
438
439             IntRect sourceRect = m_tiler->tileRect(tile);
440             sourceRect.intersect(dirtyRect);
441             // Paint rect not guaranteed to line up on tile boundaries, so
442             // make sure that sourceRect doesn't extend outside of it.
443             sourceRect.intersect(m_paintRect);
444
445             tile->m_updateRect = sourceRect;
446             if (sourceRect.isEmpty())
447                 continue;
448
449             tile->texture()->prepareRect(sourceRect);
450         }
451     }
452 }
453
454
455 void TiledLayerChromium::prepareToUpdate(const IntRect& layerRect)
456 {
457     m_skipsDraw = false;
458     m_skipsIdlePaint = false;
459     m_requestedUpdateTilesRect = IntRect();
460     m_paintRect = IntRect();
461
462     updateBounds();
463
464     if (layerRect.isEmpty() || !m_tiler->numTiles())
465         return;
466
467     int left, top, right, bottom;
468     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
469
470     prepareToUpdateTiles(false, left, top, right, bottom);
471 }
472
473 void TiledLayerChromium::prepareToUpdateIdle(const IntRect& layerRect)
474 {
475     // Abort if we have already prepared a paint or run out of memory.
476     if (m_skipsIdlePaint || !m_paintRect.isEmpty())
477         return;
478
479     ASSERT(m_tiler);
480
481     updateBounds();
482
483     if (m_tiler->isEmpty())
484         return;
485
486     // Protect any textures in the pre-paint area so we don't end up just
487     // reclaiming them below.
488     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
489     protectTileTextures(idlePaintLayerRect);
490
491     // Expand outwards until we find a dirty row or column to update.
492     int left, top, right, bottom;
493     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
494     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
495     m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
496     while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
497         if (bottom < prepaintBottom) {
498             ++bottom;
499             prepareToUpdateTiles(true, left, bottom, right, bottom);
500             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
501                 break;
502         }
503         if (top > prepaintTop) {
504             --top;
505             prepareToUpdateTiles(true, left, top, right, top);
506             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
507                 break;
508         }
509         if (left > prepaintLeft) {
510             --left;
511             prepareToUpdateTiles(true, left, top, left, bottom);
512             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
513                 break;
514         }
515         if (right < prepaintRight) {
516             ++right;
517             prepareToUpdateTiles(true, right, top, right, bottom);
518             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
519                 break;
520         }
521     }
522 }
523
524 bool TiledLayerChromium::needsIdlePaint(const IntRect& layerRect)
525 {
526     if (m_skipsIdlePaint)
527         return false;
528
529     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
530
531     int left, top, right, bottom;
532     m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom);
533     for (int j = top; j <= bottom; ++j) {
534         for (int i = left; i <= right; ++i) {
535             if (m_requestedUpdateTilesRect.contains(IntPoint(i, j)))
536                 continue;
537             UpdatableTile* tile = tileAt(i, j);
538             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat) || tile->isDirty())
539                 return true;
540         }
541     }
542     return false;
543 }
544
545 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
546 {
547     IntRect prepaintRect = visibleLayerRect;
548     // FIXME: This can be made a lot larger if we can:
549     // - reserve memory at a lower priority than for visible content
550     // - only reserve idle paint tiles up to a memory reclaim threshold and
551     // - insure we play nicely with other layers
552     prepaintRect.inflateX(m_tiler->tileSize().width());
553     prepaintRect.inflateY(m_tiler->tileSize().height());
554     prepaintRect.intersect(IntRect(IntPoint::zero(), contentBounds()));
555     return prepaintRect;
556 }
557
558 }
559 #endif // USE(ACCELERATED_COMPOSITING)