Changeset 112049 in webkit


Ignore:
Timestamp:
Mar 25, 2012 11:02:56 PM (12 years ago)
Author:
commit-queue@webkit.org
Message:

[chromium] Layers with animating transforms should prepaint even if they are not visible yet
https://bugs.webkit.org/show_bug.cgi?id=82117

Patch by Dana Jansens <danakj@chromium.org> on 2012-03-25
Reviewed by Adrienne Walker.

Source/WebCore:

For animating transforms, instead of early-outing when the layer's
visible rect is empty, let it prepaint regardless.

For now, we just only paint the outermost tiles, and only for small
layers, with at most 9 tiles.

This changes the behaviour of ContentLayerChromium's
idlePaintContentsIfDirty() so I've guarded the behaviour of the two
prepainting functions that it calls to ensure the old behaviour holds
without animations, and the new behaviour works with them.

Unit test: TiledLayerChromiumTest.idlePaintZeroSizedLayer

TiledLayerChromiumTest.idlePaintZeroSizedAnimatingLayer
TiledLayerChromiumTest.idlePaintNonVisibleLayers
TiledLayerChromiumTest.idlePaintNonVisibleAnimatingLayers

  • platform/graphics/chromium/ContentLayerChromium.cpp:

(WebCore::ContentLayerChromium::idlePaintContentsIfDirty):

  • platform/graphics/chromium/TiledLayerChromium.cpp:

(WebCore::TiledLayerChromium::prepareToUpdateIdle):
(WebCore::TiledLayerChromium::needsIdlePaint):
(WebCore::TiledLayerChromium::idlePaintRect):

  • platform/graphics/chromium/TiledLayerChromium.h:

(WebCore::TiledLayerChromium::numPaintedTiles):
(TiledLayerChromium):

Source/WebKit/chromium:

  • tests/TiledLayerChromiumTest.cpp:

(WTF::FakeTiledLayerChromium::FakeTiledLayerChromium):
(WTF::FakeTiledLayerChromium::tileSize):
(FakeTiledLayerChromium):
(WTF::TEST):
(WTF):
(WTF::idlePaintRepeat):
(WTF::testHaveOuterTiles):

Location:
trunk/Source
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r112037 r112049  
     12012-03-25  Dana Jansens  <danakj@chromium.org>
     2
     3        [chromium] Layers with animating transforms should prepaint even if they are not visible yet
     4        https://bugs.webkit.org/show_bug.cgi?id=82117
     5
     6        Reviewed by Adrienne Walker.
     7
     8        For animating transforms, instead of early-outing when the layer's
     9        visible rect is empty, let it prepaint regardless.
     10
     11        For now, we just only paint the outermost tiles, and only for small
     12        layers, with at most 9 tiles.
     13
     14        This changes the behaviour of ContentLayerChromium's
     15        idlePaintContentsIfDirty() so I've guarded the behaviour of the two
     16        prepainting functions that it calls to ensure the old behaviour holds
     17        without animations, and the new behaviour works with them.
     18
     19        Unit test: TiledLayerChromiumTest.idlePaintZeroSizedLayer
     20                   TiledLayerChromiumTest.idlePaintZeroSizedAnimatingLayer
     21                   TiledLayerChromiumTest.idlePaintNonVisibleLayers
     22                   TiledLayerChromiumTest.idlePaintNonVisibleAnimatingLayers
     23
     24        * platform/graphics/chromium/ContentLayerChromium.cpp:
     25        (WebCore::ContentLayerChromium::idlePaintContentsIfDirty):
     26        * platform/graphics/chromium/TiledLayerChromium.cpp:
     27        (WebCore::TiledLayerChromium::prepareToUpdateIdle):
     28        (WebCore::TiledLayerChromium::needsIdlePaint):
     29        (WebCore::TiledLayerChromium::idlePaintRect):
     30        * platform/graphics/chromium/TiledLayerChromium.h:
     31        (WebCore::TiledLayerChromium::numPaintedTiles):
     32        (TiledLayerChromium):
     33
    1342012-03-25  Antti Koivisto  <antti@apple.com>
    235
  • trunk/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp

    r110945 r112049  
    115115        return;
    116116
    117     const IntRect& layerRect = visibleLayerRect();
    118     if (layerRect.isEmpty())
    119         return;
    120 
     117    const IntRect layerRect = visibleLayerRect();
    121118    prepareToUpdateIdle(layerRect, occlusion);
    122119    if (needsIdlePaint(layerRect))
  • trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp

    r111978 r112049  
    629629    updateBounds();
    630630
    631     if (m_tiler->isEmpty())
    632         return;
    633 
    634     // Protect any textures in the pre-paint area so we don't end up just
    635     // reclaiming them below.
     631    if (!m_tiler->numTiles())
     632        return;
     633
    636634    IntRect idlePaintLayerRect = idlePaintRect(layerRect);
     635    if (idlePaintLayerRect.isEmpty())
     636        return;
     637
     638    // Protect any textures in the pre-paint area, as we would steal them from other layers
     639    // over time anyhow. This ensures we don't lose tiles in the first rounds of idle painting
     640    // that we have already painted.
    637641    protectTileTextures(idlePaintLayerRect);
     642
     643    int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
     644    m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
     645
     646    // If the layer is not visible, we have nothing to expand from, so instead we prepaint the outer-most set of tiles.
     647    if (layerRect.isEmpty()) {
     648        prepareToUpdateTiles(true, prepaintLeft, prepaintTop, prepaintRight, prepaintTop, 0);
     649        if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
     650            return;
     651        prepareToUpdateTiles(true, prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, 0);
     652        if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
     653            return;
     654        prepareToUpdateTiles(true, prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, 0);
     655        if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
     656            return;
     657        prepareToUpdateTiles(true, prepaintRight, prepaintTop, prepaintRight, prepaintBottom, 0);
     658
     659        return;
     660    }
    638661
    639662    int left, top, right, bottom;
    640663    m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
    641664
    642     // Prepaint anything that was occluded but inside the layer's visible region.
     665    // Otherwise, prepaint anything that was occluded but inside the layer's visible region.
    643666    prepareToUpdateTiles(true, left, top, right, bottom, 0);
    644667    if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
    645668        return;
    646669
    647     // Expand outwards until we find a dirty row or column to update.
    648     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
    649     m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
     670    // Then expand outwards from the visible area until we find a dirty row or column to update.
    650671    while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
    651672        if (bottom < prepaintBottom) {
     
    681702        return false;
    682703
     704    if (!m_tiler->numTiles())
     705        return false;
     706
    683707    IntRect idlePaintLayerRect = idlePaintRect(layerRect);
     708    if (idlePaintLayerRect.isEmpty())
     709        return false;
    684710
    685711    int left, top, right, bottom;
     
    687713    for (int j = top; j <= bottom; ++j) {
    688714        for (int i = left; i <= right; ++i) {
     715            // If the layerRect is empty, then we are painting the outer-most set of tiles only.
     716            if (layerRect.isEmpty() && i != left && i != right && j != top && j != bottom)
     717                continue;
    689718            if (m_requestedUpdateTilesRect.contains(IntPoint(i, j)))
    690719                continue;
     
    699728IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
    700729{
     730    // For layers that are animating transforms but not visible at all, we don't know what part
     731    // of them is going to become visible. For small layers we return the entire layer, for larger
     732    // ones we avoid prepainting the layer at all.
     733    if (visibleLayerRect.isEmpty()) {
     734        if ((drawTransformIsAnimating() || screenSpaceTransformIsAnimating()) && m_tiler->numTiles() <= 9)
     735            return IntRect(IntPoint(), contentBounds());
     736        return IntRect();
     737    }
     738
    701739    IntRect prepaintRect = visibleLayerRect;
    702740    // FIXME: This can be made a lot larger if we can:
  • trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h

    r110945 r112049  
    7878    void setBorderTexelOption(CCLayerTilingData::BorderTexelOption);
    7979    void setSampledTexelFormat(LayerTextureUpdater::SampledTexelFormat sampledTexelFormat) { m_sampledTexelFormat = sampledTexelFormat; }
     80    size_t numPaintedTiles() { return m_tiler->tiles().size(); }
    8081
    8182    virtual LayerTextureUpdater* textureUpdater() const = 0;
     
    9798    bool needsIdlePaint(const IntRect& layerRect);
    9899
     100    IntRect idlePaintRect(const IntRect& visibleLayerRect);
     101
    99102    bool skipsDraw() const { return m_skipsDraw; }
    100103
     
    113116
    114117    void prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom, const CCOcclusionTracker*);
    115     IntRect idlePaintRect(const IntRect& visibleLayerRect);
    116118
    117119    UpdatableTile* tileAt(int, int) const;
  • trunk/Source/WebKit/chromium/ChangeLog

    r112024 r112049  
     12012-03-25  Dana Jansens  <danakj@chromium.org>
     2
     3        [chromium] Layers with animating transforms should prepaint even if they are not visible yet
     4        https://bugs.webkit.org/show_bug.cgi?id=82117
     5
     6        Reviewed by Adrienne Walker.
     7
     8        * tests/TiledLayerChromiumTest.cpp:
     9        (WTF::FakeTiledLayerChromium::FakeTiledLayerChromium):
     10        (WTF::FakeTiledLayerChromium::tileSize):
     11        (FakeTiledLayerChromium):
     12        (WTF::TEST):
     13        (WTF):
     14        (WTF::idlePaintRepeat):
     15        (WTF::testHaveOuterTiles):
     16
    1172012-03-24  Nat Duca  <nduca@chromium.org>
    218
  • trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp

    r111978 r112049  
    2727#include "TiledLayerChromium.h"
    2828
     29#include "CCAnimationTestCommon.h"
    2930#include "CCLayerTreeTestCommon.h"
    3031#include "FakeCCLayerTreeHostClient.h"
     
    3940
    4041using namespace WebCore;
     42using namespace WebKitTests;
    4143using namespace WTF;
    4244
     
    161163        , m_textureManager(textureManager)
    162164    {
    163         setTileSize(IntSize(100, 100));
     165        setTileSize(tileSize());
    164166        setTextureFormat(GraphicsContext3D::RGBA);
    165167        setBorderTexelOption(CCLayerTilingData::NoBorderTexels);
     
    168170    virtual ~FakeTiledLayerChromium() { }
    169171
    170     void invalidateRect(const IntRect& rect)
    171     {
    172         TiledLayerChromium::invalidateRect(rect);
    173     }
    174 
    175     void prepareToUpdate(const IntRect& rect, const CCOcclusionTracker* occlusion)
    176     {
    177         TiledLayerChromium::prepareToUpdate(rect, occlusion);
    178     }
    179 
    180     void prepareToUpdateIdle(const IntRect& rect, const CCOcclusionTracker* occlusion)
    181     {
    182         TiledLayerChromium::prepareToUpdateIdle(rect, occlusion);
    183     }
    184 
    185     bool needsIdlePaint(const IntRect& rect)
    186     {
    187         return TiledLayerChromium::needsIdlePaint(rect);
    188     }
    189 
    190     bool skipsDraw() const
    191     {
    192         return TiledLayerChromium::skipsDraw();
    193     }
     172    static IntSize tileSize() { return IntSize(100, 100); }
     173
     174    using TiledLayerChromium::invalidateRect;
     175    using TiledLayerChromium::prepareToUpdate;
     176    using TiledLayerChromium::prepareToUpdateIdle;
     177    using TiledLayerChromium::needsIdlePaint;
     178    using TiledLayerChromium::skipsDraw;
     179    using TiledLayerChromium::numPaintedTiles;
     180    using TiledLayerChromium::idlePaintRect;
    194181
    195182    virtual void setNeedsDisplayRect(const FloatRect& rect)
     
    686673    layer->updateCompositorResources(0, updater);
    687674    layer->pushPropertiesTo(layerImpl.get());
     675}
     676
     677TEST(TiledLayerChromiumTest, idlePaintZeroSizedLayer)
     678{
     679    OwnPtr<TextureManager> textureManager = TextureManager::create(20000, 10000, 1024);
     680    RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
     681    DebugScopedSetImplThread implThread;
     682    OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
     683
     684    FakeTextureAllocator textureAllocator;
     685    CCTextureUpdater updater(&textureAllocator);
     686
     687    // The layer's bounds are empty.
     688    IntRect contentRect;
     689
     690    layer->setBounds(contentRect.size());
     691    layer->setVisibleLayerRect(contentRect);
     692    layer->invalidateRect(contentRect);
     693    layer->prepareToUpdate(contentRect, 0);
     694
     695    // Empty layers don't have tiles.
     696    EXPECT_EQ(0u, layer->numPaintedTiles());
     697
     698    // Empty layers don't need prepaint.
     699    EXPECT_FALSE(layer->needsIdlePaint(contentRect));
     700
     701    layer->updateCompositorResources(0, updater);
     702    layer->pushPropertiesTo(layerImpl.get());
     703
     704    // Empty layers don't have tiles.
     705    EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
     706
     707    // Non-visible layers don't idle paint.
     708    layer->prepareToUpdateIdle(contentRect, 0);
     709
     710    // Empty layers don't have tiles.
     711    EXPECT_EQ(0u, layer->numPaintedTiles());
     712
     713    layer->updateCompositorResources(0, updater);
     714    layer->pushPropertiesTo(layerImpl.get());
     715
     716    // Empty layers don't have tiles.
     717    EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
     718}
     719
     720TEST(TiledLayerChromiumTest, idlePaintZeroSizedAnimatingLayer)
     721{
     722    OwnPtr<TextureManager> textureManager = TextureManager::create(20000, 10000, 1024);
     723    RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
     724    DebugScopedSetImplThread implThread;
     725    OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
     726
     727    FakeTextureAllocator textureAllocator;
     728    CCTextureUpdater updater(&textureAllocator);
     729
     730    // Pretend the layer is animating.
     731    layer->setDrawTransformIsAnimating(true);
     732
     733    // The layer's bounds are empty.
     734    IntRect contentRect;
     735
     736    layer->setBounds(contentRect.size());
     737    layer->setVisibleLayerRect(contentRect);
     738    layer->invalidateRect(contentRect);
     739    layer->prepareToUpdate(contentRect, 0);
     740
     741    // Empty layers don't have tiles.
     742    EXPECT_EQ(0u, layer->numPaintedTiles());
     743
     744    // Empty layers don't need prepaint.
     745    EXPECT_FALSE(layer->needsIdlePaint(contentRect));
     746
     747    layer->updateCompositorResources(0, updater);
     748    layer->pushPropertiesTo(layerImpl.get());
     749
     750    // Empty layers don't have tiles.
     751    EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
     752
     753    // Non-visible layers don't idle paint.
     754    layer->prepareToUpdateIdle(contentRect, 0);
     755
     756    // Empty layers don't have tiles.
     757    EXPECT_EQ(0u, layer->numPaintedTiles());
     758
     759    layer->updateCompositorResources(0, updater);
     760    layer->pushPropertiesTo(layerImpl.get());
     761
     762    // Empty layers don't have tiles.
     763    EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
     764}
     765
     766TEST(TiledLayerChromiumTest, idlePaintNonVisibleLayers)
     767{
     768    IntSize contentBounds(100, 100);
     769    IntRect contentRect(IntPoint::zero(), contentBounds);
     770
     771    OwnPtr<TextureManager> textureManager = TextureManager::create(20000, 10000, 1024);
     772    RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
     773    DebugScopedSetImplThread implThread;
     774    OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
     775
     776    FakeTextureAllocator textureAllocator;
     777    CCTextureUpdater updater(&textureAllocator);
     778
     779    // Invalidate the layer but make none of it visible, so nothing paints.
     780    IntRect visibleRect;
     781
     782    layer->setBounds(contentBounds);
     783    layer->setVisibleLayerRect(visibleRect);
     784    layer->invalidateRect(contentRect);
     785    layer->prepareToUpdate(visibleRect, 0);
     786
     787    // Non-visible layers don't need idle paint.
     788    EXPECT_FALSE(layer->needsIdlePaint(visibleRect));
     789
     790    layer->updateCompositorResources(0, updater);
     791    layer->pushPropertiesTo(layerImpl.get());
     792
     793    // We should not have any tiles pushed since the layer is not visible.
     794    EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
     795
     796    // Non-visible layers don't idle paint.
     797    layer->prepareToUpdateIdle(visibleRect, 0);
     798
     799    layer->updateCompositorResources(0, updater);
     800    layer->pushPropertiesTo(layerImpl.get());
     801
     802    // We should not have any tiles pushed since the layer is not visible.
     803    EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
     804}
     805
     806static void idlePaintRepeat(int repeatTimes, FakeTiledLayerChromium* layer, FakeCCTiledLayerImpl* layerImpl, CCTextureUpdater& updater, const IntRect& visibleRect)
     807{
     808    for (int i = 0; i < repeatTimes; ++i) {
     809        layer->prepareToUpdate(visibleRect, 0);
     810        layer->prepareToUpdateIdle(visibleRect, 0);
     811        layer->updateCompositorResources(0, updater);
     812        layer->pushPropertiesTo(layerImpl);
     813    }
     814}
     815
     816static void testHaveOuterTiles(FakeCCTiledLayerImpl* layerImpl, int width, int height, int have)
     817{
     818    for (int i = 0; i < width; ++i) {
     819        for (int j = 0; j < height; ++j) {
     820            bool hasTile = i < have || j < have || i >= width - have || j >= height - have;
     821            EXPECT_EQ(hasTile, layerImpl->hasTileAt(i, j));
     822        }
     823    }
     824}
     825
     826TEST(TiledLayerChromiumTest, idlePaintNonVisibleAnimatingLayers)
     827{
     828    OwnPtr<TextureManager> textureManager = TextureManager::create(8000*8000*8, 8000*8000*4, 1024);
     829    DebugScopedSetImplThread implThread;
     830
     831    FakeTextureAllocator textureAllocator;
     832    CCTextureUpdater updater(&textureAllocator);
     833
     834    int tileWidth = FakeTiledLayerChromium::tileSize().width();
     835    int tileHeight = FakeTiledLayerChromium::tileSize().height();
     836    int width[] = { 1, 2, 3, 4, 9, 10, 0 };
     837    int height[] = { 1, 2, 3, 4, 9, 10, 0 };
     838
     839    for (int j = 0; height[j]; ++j) {
     840        for (int i = 0; width[i]; ++i) {
     841            RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
     842            OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
     843
     844            // Pretend the layer is animating.
     845            layer->setDrawTransformIsAnimating(true);
     846
     847            IntSize contentBounds(width[i] * tileWidth, height[j] * tileHeight);
     848            IntRect contentRect(IntPoint::zero(), contentBounds);
     849            IntRect visibleRect;
     850
     851            layer->setBounds(contentBounds);
     852            layer->setVisibleLayerRect(visibleRect);
     853            layer->invalidateRect(contentRect);
     854
     855            // If idlePaintRect gives back a non-empty result then we should paint it. Otherwise,
     856            // we shoud paint nothing.
     857            bool shouldPrepaint = !layer->idlePaintRect(visibleRect).isEmpty();
     858
     859            // This paints the layer but there's nothing visible so it's a no-op.
     860            layer->prepareToUpdate(visibleRect, 0);
     861            layer->updateCompositorResources(0, updater);
     862            layer->pushPropertiesTo(layerImpl.get());
     863
     864            // We should not have any tiles pushed yet since the layer is not visible and we've not prepainted.
     865            testHaveOuterTiles(layerImpl.get(), width[i], height[j], 0);
     866
     867            // Normally we don't allow non-visible layers to pre-paint, but if they are animating then we should.
     868            EXPECT_EQ(shouldPrepaint, layer->needsIdlePaint(visibleRect));
     869
     870            // If the layer is to be prepainted at all, then after four updates we should have the outer row/columns painted.
     871            idlePaintRepeat(4, layer.get(), layerImpl.get(), updater, visibleRect);
     872            testHaveOuterTiles(layerImpl.get(), width[i], height[j], shouldPrepaint ? 1 : 0);
     873
     874            // We don't currently idle paint past the outermost tiles.
     875            EXPECT_FALSE(layer->needsIdlePaint(visibleRect));
     876            idlePaintRepeat(4, layer.get(), layerImpl.get(), updater, visibleRect);
     877            testHaveOuterTiles(layerImpl.get(), width[i], height[j], shouldPrepaint ? 1 : 0);
     878        }
     879    }
    688880}
    689881
Note: See TracChangeset for help on using the changeset viewer.