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