[chromium] Add overdraw metrics for texture uploads
[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 "TraceEvent.h"
39 #include "cc/CCLayerImpl.h"
40 #include "cc/CCTextureUpdater.h"
41 #include "cc/CCTiledLayerImpl.h"
42 #include <wtf/CurrentTime.h>
43
44 // Start tiling when the width and height of a layer are larger than this size.
45 static int maxUntiledSize = 512;
46
47 // When tiling is enabled, use tiles of this dimension squared.
48 static int defaultTileSize = 256;
49
50 using namespace std;
51
52 namespace WebCore {
53
54 class UpdatableTile : public CCLayerTilingData::Tile {
55     WTF_MAKE_NONCOPYABLE(UpdatableTile);
56 public:
57     static PassOwnPtr<UpdatableTile> create(PassOwnPtr<LayerTextureUpdater::Texture> texture)
58     {
59         return adoptPtr(new UpdatableTile(texture));
60     }
61
62     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
63     ManagedTexture* managedTexture() { return m_texture->texture(); }
64
65     bool isDirty() const { return !m_dirtyRect.isEmpty(); }
66     // Returns whether the layer was dirty and not updated in the current frame. For tiles that were not culled, the
67     // updateRect holds the area of the tile that was updated. Otherwise, the area that would have been updated.
68     bool isDirtyForCurrentFrame() { return !m_dirtyRect.isEmpty() && (m_updateRect.isEmpty() || m_updateCulled); }
69
70     IntRect m_dirtyRect;
71     IntRect m_updateRect;
72     bool m_partialUpdate;
73     bool m_updateCulled;
74 private:
75     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
76         : m_partialUpdate(false)
77         , m_updateCulled(false)
78         , m_texture(texture)
79     {
80     }
81
82     OwnPtr<LayerTextureUpdater::Texture> m_texture;
83 };
84
85 TiledLayerChromium::TiledLayerChromium()
86     : LayerChromium()
87     , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
88     , m_skipsDraw(false)
89     , m_skipsIdlePaint(false)
90     , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
91     , m_tilingOption(AutoTile)
92 {
93     m_tiler = CCLayerTilingData::create(IntSize(defaultTileSize, defaultTileSize), CCLayerTilingData::HasBorderTexels);
94 }
95
96 TiledLayerChromium::~TiledLayerChromium()
97 {
98 }
99
100 PassOwnPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
101 {
102     return CCTiledLayerImpl::create(id());
103 }
104
105 void TiledLayerChromium::updateTileSizeAndTilingOption()
106 {
107     const IntSize tileSize(min(defaultTileSize, contentBounds().width()), min(defaultTileSize, contentBounds().height()));
108
109     // Tile if both dimensions large, or any one dimension large and the other
110     // extends into a second tile. This heuristic allows for long skinny layers
111     // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space.
112     const bool anyDimensionLarge = contentBounds().width() > maxUntiledSize || contentBounds().height() > maxUntiledSize;
113     const bool anyDimensionOneTile = contentBounds().width() <= defaultTileSize || contentBounds().height() <= defaultTileSize;
114     const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile;
115
116     bool isTiled;
117     if (m_tilingOption == AlwaysTile)
118         isTiled = true;
119     else if (m_tilingOption == NeverTile)
120         isTiled = false;
121     else
122         isTiled = autoTiled;
123
124     IntSize requestedSize = isTiled ? tileSize : contentBounds();
125     const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize;
126     IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize));
127     setTileSize(clampedSize);
128 }
129
130 void TiledLayerChromium::updateBounds()
131 {
132     IntSize oldBounds = m_tiler->bounds();
133     IntSize newBounds = contentBounds();
134     if (oldBounds == newBounds)
135         return;
136     m_tiler->setBounds(newBounds);
137
138     // Invalidate any areas that the new bounds exposes.
139     Region oldRegion(IntRect(IntPoint(), oldBounds));
140     Region newRegion(IntRect(IntPoint(), newBounds));
141     newRegion.subtract(oldRegion);
142     Vector<IntRect> rects = newRegion.rects();
143     for (size_t i = 0; i < rects.size(); ++i)
144         invalidateRect(rects[i]);
145 }
146
147 void TiledLayerChromium::setTileSize(const IntSize& size)
148 {
149     m_tiler->setTileSize(size);
150 }
151
152 void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOption borderTexelOption)
153 {
154     m_tiler->setBorderTexelOption(borderTexelOption);
155 }
156
157 bool TiledLayerChromium::drawsContent() const
158 {
159     if (!LayerChromium::drawsContent())
160         return false;
161
162     if (m_tilingOption == NeverTile && m_tiler->numTiles() > 1)
163         return false;
164
165     return true;
166 }
167
168 bool TiledLayerChromium::needsContentsScale() const
169 {
170     return true;
171 }
172
173 IntSize TiledLayerChromium::contentBounds() const
174 {
175     return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale()));
176 }
177
178 void TiledLayerChromium::updateCompositorResources(GraphicsContext3D*, CCTextureUpdater& updater)
179 {
180     // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update.
181     if (m_skipsDraw || m_requestedUpdateTilesRect.isEmpty() || m_tiler->isEmpty())
182         return;
183
184     int left = m_requestedUpdateTilesRect.x();
185     int top = m_requestedUpdateTilesRect.y();
186     int right = m_requestedUpdateTilesRect.maxX() - 1;
187     int bottom = m_requestedUpdateTilesRect.maxY() - 1;
188     for (int j = top; j <= bottom; ++j) {
189         for (int i = left; i <= right; ++i) {
190             UpdatableTile* tile = tileAt(i, j);
191
192             // Required tiles are created in prepareToUpdate(). A tile should
193             // never be removed between the call to prepareToUpdate() and the
194             // call to updateCompositorResources().
195             if (!tile)
196                 CRASH();
197
198             if (tile->m_updateCulled)
199                 continue;
200
201             IntRect sourceRect = tile->m_updateRect;
202             if (tile->m_updateRect.isEmpty())
203                 continue;
204
205             ASSERT(tile->managedTexture()->isReserved());
206             const IntPoint anchor = m_tiler->tileRect(tile).location();
207
208             // Calculate tile-space rectangle to upload into.
209             IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
210             if (destRect.x() < 0)
211                 CRASH();
212             if (destRect.y() < 0)
213                 CRASH();
214
215             // Offset from paint rectangle to this tile's dirty rectangle.
216             IntPoint paintOffset(sourceRect.x() - m_paintRect.x(), sourceRect.y() - m_paintRect.y());
217             if (paintOffset.x() < 0)
218                 CRASH();
219             if (paintOffset.y() < 0)
220                 CRASH();
221             if (paintOffset.x() + destRect.width() > m_paintRect.width())
222                 CRASH();
223             if (paintOffset.y() + destRect.height() > m_paintRect.height())
224                 CRASH();
225
226             if (tile->m_partialUpdate)
227                 updater.appendPartial(tile->texture(), sourceRect, destRect);
228             else
229                 updater.append(tile->texture(), sourceRect, destRect);
230         }
231     }
232
233     // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space.
234     m_updateRect = FloatRect(m_paintRect);
235     float widthScale = bounds().width() / static_cast<float>(contentBounds().width());
236     float heightScale = bounds().height() / static_cast<float>(contentBounds().height());
237     m_updateRect.scale(widthScale, heightScale);
238 }
239
240 void TiledLayerChromium::setTilingOption(TilingOption tilingOption)
241 {
242     m_tilingOption = tilingOption;
243 }
244
245 void TiledLayerChromium::setIsMask(bool isMask)
246 {
247     setTilingOption(isMask ? NeverTile : AutoTile);
248 }
249
250 void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
251 {
252     LayerChromium::pushPropertiesTo(layer);
253
254     CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer);
255
256     tiledLayer->setSkipsDraw(m_skipsDraw);
257     tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater::SampledTexelFormatRGBA);
258     tiledLayer->setTilingData(*m_tiler);
259     Vector<UpdatableTile*> invalidTiles;
260
261     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
262         int i = iter->first.first;
263         int j = iter->first.second;
264         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
265         if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) {
266             invalidTiles.append(tile);
267             continue;
268         }
269         if (tile->isDirtyForCurrentFrame())
270             continue;
271
272         tiledLayer->pushTileProperties(i, j, tile->managedTexture()->textureId(), tile->opaqueRect());
273     }
274     for (Vector<UpdatableTile*>::const_iterator iter = invalidTiles.begin(); iter != invalidTiles.end(); ++iter)
275         m_tiler->takeTile((*iter)->i(), (*iter)->j());
276 }
277
278 TextureManager* TiledLayerChromium::textureManager() const
279 {
280     if (!layerTreeHost())
281         return 0;
282     return layerTreeHost()->contentsTextureManager();
283 }
284
285 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
286 {
287     if (host && host != layerTreeHost()) {
288         for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
289             UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
290             tile->managedTexture()->setTextureManager(host->contentsTextureManager());
291         }
292     }
293     LayerChromium::setLayerTreeHost(host);
294 }
295
296 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
297 {
298     return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
299 }
300
301 UpdatableTile* TiledLayerChromium::createTile(int i, int j)
302 {
303     OwnPtr<UpdatableTile> tile(UpdatableTile::create(textureUpdater()->createTexture(textureManager())));
304     UpdatableTile* addedTile = tile.get();
305     m_tiler->addTile(tile.release(), i, j);
306
307     addedTile->m_dirtyRect = m_tiler->tileRect(addedTile);
308     return addedTile;
309 }
310
311 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
312 {
313     FloatRect scaledDirtyRect(dirtyRect);
314     scaledDirtyRect.scale(contentsScale());
315     IntRect dirty = enclosingIntRect(scaledDirtyRect);
316     invalidateRect(dirty);
317     LayerChromium::setNeedsDisplayRect(dirtyRect);
318 }
319
320 void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
321 {
322     LayerChromium::setIsNonCompositedContent(isNonCompositedContent);
323
324     CCLayerTilingData::BorderTexelOption borderTexelOption;
325 #if OS(ANDROID)
326     // Always want border texels and GL_LINEAR due to pinch zoom.
327     borderTexelOption = CCLayerTilingData::HasBorderTexels;
328 #else
329     borderTexelOption = isNonCompositedContent ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
330 #endif
331     setBorderTexelOption(borderTexelOption);
332 }
333
334 void TiledLayerChromium::invalidateRect(const IntRect& layerRect)
335 {
336     updateBounds();
337     if (m_tiler->isEmpty() || layerRect.isEmpty() || m_skipsDraw)
338         return;
339
340     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
341         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
342         ASSERT(tile);
343         IntRect bound = m_tiler->tileRect(tile);
344         bound.intersect(layerRect);
345         tile->m_dirtyRect.unite(bound);
346     }
347 }
348
349 void TiledLayerChromium::protectVisibleTileTextures()
350 {
351     protectTileTextures(visibleLayerRect());
352 }
353
354 void TiledLayerChromium::protectTileTextures(const IntRect& layerRect)
355 {
356     if (m_tiler->isEmpty() || layerRect.isEmpty())
357         return;
358
359     int left, top, right, bottom;
360     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
361
362     for (int j = top; j <= bottom; ++j) {
363         for (int i = left; i <= right; ++i) {
364             UpdatableTile* tile = tileAt(i, j);
365             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
366                 continue;
367
368             tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat);
369         }
370     }
371 }
372
373 // Returns true if tile is dirty and only part of it needs to be updated.
374 bool TiledLayerChromium::tileOnlyNeedsPartialUpdate(UpdatableTile* tile)
375 {
376     if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
377         return false;
378
379     if (!tile->isDirty())
380         return false;
381
382     return !tile->m_dirtyRect.contains(m_tiler->tileRect(tile));
383 }
384
385 // Dirty tiles with valid textures needs buffered update to guarantee that
386 // we don't modify textures currently used for drawing by the impl thread.
387 bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile)
388 {
389     // No impl thread?.
390     if (!CCProxy::hasImplThread())
391         return false;
392
393     if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
394         return false;
395
396     if (!tile->isDirty())
397         return false;
398
399     return true;
400 }
401
402 void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom, const CCOcclusionTracker* occlusion)
403 {
404     createTextureUpdaterIfNeeded();
405
406     // Create tiles as needed, expanding a dirty rect to contain all
407     // the dirty regions currently being drawn. All dirty tiles that are to be painted
408     // get their m_updateRect set to m_dirtyRect and m_dirtyRect cleared. This way if
409     // invalidateRect is invoked during prepareToUpdate we don't lose the request.
410     IntRect dirtyLayerRect;
411     for (int j = top; j <= bottom; ++j) {
412         for (int i = left; i <= right; ++i) {
413             UpdatableTile* tile = tileAt(i, j);
414             if (!tile)
415                 tile = createTile(i, j);
416
417             // Save the dirty rect since WebKit can change the tile's dirty rect during painting.
418             tile->m_updateRect = tile->m_dirtyRect;
419
420             // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or update the tile.
421             // If any part of the tile is visible, then we need to update it so the tile is pushed to the impl thread.
422             if (!idle && occlusion) {
423                 IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleLayerRect());
424                 if (occlusion->occluded(this, visibleTileRect)) {
425                     tile->m_updateCulled = true;
426                     continue;
427                 }
428             }
429
430             // FIXME: Decide if partial update should be allowed based on cost
431             // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
432             if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost() && layerTreeHost()->requestPartialTextureUpdate())
433                 tile->m_partialUpdate = true;
434             else if (tileNeedsBufferedUpdate(tile) && layerTreeHost())
435                 layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal());
436
437             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) {
438                 // Sets the dirty rect to a full-sized tile with border texels.
439                 tile->m_dirtyRect = m_tiler->tileRect(tile);
440             }
441
442             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) {
443                 m_skipsIdlePaint = true;
444                 if (!idle) {
445                     // If the background covers the viewport, always draw this
446                     // layer so that checkerboarded tiles will still draw.
447                     if (!backgroundCoversViewport())
448                         m_skipsDraw = true;
449                     m_tiler->reset();
450                     m_paintRect = IntRect();
451                     m_requestedUpdateTilesRect = IntRect();
452                 }
453                 return;
454             }
455
456             dirtyLayerRect.unite(tile->m_dirtyRect);
457             // Clear the dirty rect.
458             tile->m_dirtyRect = IntRect();
459         }
460     }
461
462     m_paintRect = dirtyLayerRect;
463     if (dirtyLayerRect.isEmpty())
464         return;
465
466     // Due to borders, when the paint rect is extended to tile boundaries, it
467     // may end up overlapping more tiles than the original content rect. Record
468     // the original tiles so we don't upload more tiles than necessary.
469     if (!m_paintRect.isEmpty())
470         m_requestedUpdateTilesRect = IntRect(left, top, right - left + 1, bottom - top + 1);
471
472     // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
473     // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
474     // However, we can't free the memory backing the GraphicsContext until the paint finishes,
475     // so we grab a local reference here to hold the updater alive until the paint completes.
476     RefPtr<LayerTextureUpdater> protector(textureUpdater());
477     IntRect paintedOpaqueRect;
478     textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &paintedOpaqueRect);
479     for (int j = top; j <= bottom; ++j) {
480         for (int i = left; i <= right; ++i) {
481             UpdatableTile* tile = tileAt(i, j);
482
483             // Tiles are created before prepareToUpdate() is called.
484             if (!tile)
485                 CRASH();
486
487             IntRect tileRect = m_tiler->tileBounds(i, j);
488
489             // Use m_updateRect as the above loop copied the dirty rect for this frame to m_updateRect.
490             const IntRect& dirtyRect = tile->m_updateRect;
491             if (dirtyRect.isEmpty())
492                 continue;
493
494             // sourceRect starts as a full-sized tile with border texels included.
495             IntRect sourceRect = m_tiler->tileRect(tile);
496             sourceRect.intersect(dirtyRect);
497             // Paint rect not guaranteed to line up on tile boundaries, so
498             // make sure that sourceRect doesn't extend outside of it.
499             sourceRect.intersect(m_paintRect);
500
501             if (tile->m_updateCulled && occlusion) {
502                 occlusion->overdrawMetrics().didCull(TransformationMatrix(), sourceRect, IntRect());
503                 continue;
504             }
505
506             // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some
507             // other part of the tile opaque.
508             IntRect tilePaintedRect = intersection(tileRect, m_paintRect);
509             IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect);
510             if (!tilePaintedRect.isEmpty()) {
511                 IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRect(), tilePaintedRect);
512                 bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.contains(paintInsideTileOpaqueRect);
513                 bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect);
514
515                 if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect)
516                     tile->setOpaqueRect(tilePaintedOpaqueRect);
517             }
518
519             tile->m_updateRect = sourceRect;
520             if (sourceRect.isEmpty())
521                 continue;
522
523             tile->texture()->prepareRect(sourceRect);
524             if (occlusion)
525                 occlusion->overdrawMetrics().didDraw(TransformationMatrix(), sourceRect, tile->opaqueRect());
526         }
527     }
528 }
529
530 void TiledLayerChromium::reserveTextures()
531 {
532     updateBounds();
533
534     const IntRect& layerRect = visibleLayerRect();
535     if (layerRect.isEmpty() || !m_tiler->numTiles())
536         return;
537
538     int left, top, right, bottom;
539     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
540
541     createTextureUpdaterIfNeeded();
542     for (int j = top; j <= bottom; ++j) {
543         for (int i = left; i <= right; ++i) {
544             UpdatableTile* tile = tileAt(i, j);
545             if (!tile)
546                 tile = createTile(i, j);
547
548             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
549                 tile->m_dirtyRect = m_tiler->tileRect(tile);
550
551             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat))
552                 return;
553         }
554     }
555 }
556
557 Region TiledLayerChromium::opaqueContentsRegion() const
558 {
559     if (m_skipsDraw)
560         return Region();
561
562     return m_tiler->opaqueRegionInLayerRect(visibleLayerRect());
563 }
564
565 void TiledLayerChromium::resetUpdateState()
566 {
567     // Reset m_updateRect for all tiles.
568     CCLayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end();
569     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != end; ++iter) {
570         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
571         tile->m_updateRect = IntRect();
572         tile->m_partialUpdate = false;
573         tile->m_updateCulled = false;
574     }
575 }
576
577 void TiledLayerChromium::prepareToUpdate(const IntRect& layerRect, const CCOcclusionTracker* occlusion)
578 {
579     m_skipsDraw = false;
580     m_skipsIdlePaint = false;
581     m_requestedUpdateTilesRect = IntRect();
582     m_paintRect = IntRect();
583
584     updateBounds();
585
586     resetUpdateState();
587
588     if (layerRect.isEmpty() || !m_tiler->numTiles())
589         return;
590
591     int left, top, right, bottom;
592     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
593
594     prepareToUpdateTiles(false, left, top, right, bottom, occlusion);
595 }
596
597 void TiledLayerChromium::prepareToUpdateIdle(const IntRect& layerRect, const CCOcclusionTracker* occlusion)
598 {
599     // Abort if we have already prepared a paint or run out of memory.
600     if (m_skipsIdlePaint || !m_paintRect.isEmpty())
601         return;
602
603     ASSERT(m_tiler);
604
605     updateBounds();
606
607     if (m_tiler->isEmpty())
608         return;
609
610     // Protect any textures in the pre-paint area so we don't end up just
611     // reclaiming them below.
612     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
613     protectTileTextures(idlePaintLayerRect);
614
615     int left, top, right, bottom;
616     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
617
618     // Prepaint anything that was occluded but inside the layer's visible region.
619     prepareToUpdateTiles(true, left, top, right, bottom, 0);
620     if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
621         return;
622
623     // Expand outwards until we find a dirty row or column to update.
624     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
625     m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
626     while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
627         if (bottom < prepaintBottom) {
628             ++bottom;
629             prepareToUpdateTiles(true, left, bottom, right, bottom, 0);
630             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
631                 break;
632         }
633         if (top > prepaintTop) {
634             --top;
635             prepareToUpdateTiles(true, left, top, right, top, 0);
636             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
637                 break;
638         }
639         if (left > prepaintLeft) {
640             --left;
641             prepareToUpdateTiles(true, left, top, left, bottom, 0);
642             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
643                 break;
644         }
645         if (right < prepaintRight) {
646             ++right;
647             prepareToUpdateTiles(true, right, top, right, bottom, 0);
648             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
649                 break;
650         }
651     }
652 }
653
654 bool TiledLayerChromium::needsIdlePaint(const IntRect& layerRect)
655 {
656     if (m_skipsIdlePaint)
657         return false;
658
659     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
660
661     int left, top, right, bottom;
662     m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom);
663     for (int j = top; j <= bottom; ++j) {
664         for (int i = left; i <= right; ++i) {
665             if (m_requestedUpdateTilesRect.contains(IntPoint(i, j)))
666                 continue;
667             UpdatableTile* tile = tileAt(i, j);
668             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat) || tile->isDirty())
669                 return true;
670         }
671     }
672     return false;
673 }
674
675 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
676 {
677     IntRect prepaintRect = visibleLayerRect;
678     // FIXME: This can be made a lot larger if we can:
679     // - reserve memory at a lower priority than for visible content
680     // - only reserve idle paint tiles up to a memory reclaim threshold and
681     // - insure we play nicely with other layers
682     prepaintRect.inflateX(m_tiler->tileSize().width());
683     prepaintRect.inflateY(m_tiler->tileSize().height());
684     prepaintRect.intersect(IntRect(IntPoint::zero(), contentBounds()));
685     return prepaintRect;
686 }
687
688 }
689 #endif // USE(ACCELERATED_COMPOSITING)