[Chromium] Avoid unnecessary full tile updates without breaking atomicity of commits.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Feb 2012 05:26:00 +0000 (05:26 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Feb 2012 05:26:00 +0000 (05:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=76740

Patch by David Reveman <reveman@chromium.org> on 2012-02-08
Reviewed by James Robinson.

Source/WebCore:

Allow the final batch of texture uploads to be performed without
allocating new textures and re-painting complete tiles.

This patch is tested by the following unit test:
- CCLayerTreeHostTestAtomicCommitWithPartialUpdate.runMultiThread
- TiledLayerChromiumTest.partialUpdates

* platform/graphics/chromium/TiledLayerChromium.cpp:
(WebCore::UpdatableTile::UpdatableTile):
(UpdatableTile):
(WebCore::TiledLayerChromium::updateCompositorResources):
(WebCore):
(WebCore::TiledLayerChromium::tileOnlyNeedsPartialUpdate):
(WebCore::TiledLayerChromium::tileNeedsBufferedUpdate):
(WebCore::TiledLayerChromium::prepareToUpdateTiles):
* platform/graphics/chromium/TiledLayerChromium.h:
(TiledLayerChromium):
* platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
(WebCore::CCLayerTreeHost::CCLayerTreeHost):
(WebCore::CCLayerTreeHost::initializeLayerRenderer):
(WebCore::CCLayerTreeHost::updateLayers):
(WebCore::CCLayerTreeHost::requestPartialTextureUpdate):
(WebCore):
* platform/graphics/chromium/cc/CCLayerTreeHost.h:
(WebCore::CCSettings::CCSettings):
(CCSettings):
(CCLayerTreeHost):
* platform/graphics/chromium/cc/CCProxy.h:
(CCProxy):
* platform/graphics/chromium/cc/CCSingleThreadProxy.cpp:
(WebCore::CCSingleThreadProxy::doCommit):
* platform/graphics/chromium/cc/CCSingleThreadProxy.h:
(WebCore::CCSingleThreadProxy::maxPartialTextureUpdates):
* platform/graphics/chromium/cc/CCTextureUpdater.cpp:
(WebCore::CCTextureUpdater::append):
(WebCore):
(WebCore::CCTextureUpdater::appendPartial):
(WebCore::CCTextureUpdater::hasMoreUpdates):
(WebCore::CCTextureUpdater::update):
(WebCore::CCTextureUpdater::clear):
* platform/graphics/chromium/cc/CCTextureUpdater.h:
(CCTextureUpdater):
* platform/graphics/chromium/cc/CCThreadProxy.cpp:
(WTF):
(WebCore::CCThreadProxy::scheduledActionUpdateMoreResources):
(WebCore::CCThreadProxy::maxPartialTextureUpdates):
* platform/graphics/chromium/cc/CCThreadProxy.h:
(CCThreadProxy):

Source/WebKit/chromium:

Add CCLayerTreeHostTestAtomicCommitWithPartialUpdate and
TiledLayerChromiumTest.partialUpdates tests that verifies
atomicity of commits with partial updates.

* tests/CCLayerTreeHostTest.cpp:
(WTF::CCLayerTreeHostTestAtomicCommit::CCLayerTreeHostTestAtomicCommit):
(WTF::CCLayerTreeHostTestAtomicCommit::beginTest):
(WTF::CCLayerTreeHostTestAtomicCommit::commitCompleteOnCCThread):
(WTF::CCLayerTreeHostTestAtomicCommit::layout):
(CCLayerTreeHostTestAtomicCommit):
(CCLayerTreeHostTestAtomicCommitWithPartialUpdate):
(WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::CCLayerTreeHostTestAtomicCommitWithPartialUpdate):
(WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::beginTest):
(WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::commitCompleteOnCCThread):
(WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::drawLayersOnCCThread):
(WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::layout):
(WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::afterTest):
(WTF):
(WTF::TEST_F):
* tests/TiledLayerChromiumTest.cpp:
(WTF::FakeLayerTextureUpdater::Texture::Texture):
(WTF::FakeLayerTextureUpdater::Texture::updateRect):
(Texture):
(WTF::FakeLayerTextureUpdater::FakeLayerTextureUpdater):
(FakeLayerTextureUpdater):
(WTF::FakeLayerTextureUpdater::updateCount):
(WTF::FakeLayerTextureUpdater::clearUpdateCount):
(WTF::FakeLayerTextureUpdater::updateRect):
(WTF::FakeLayerTextureUpdater::createTexture):
(FakeTiledLayerChromium):
(WTF::TEST):
(WTF):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@107177 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp
Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h
Source/WebCore/platform/graphics/chromium/cc/CCProxy.h
Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.cpp
Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h
Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.cpp
Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.h
Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp
Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp
Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp

index 33f8368..27af7c8 100644 (file)
@@ -1,3 +1,59 @@
+2012-02-08  David Reveman  <reveman@chromium.org>
+
+        [Chromium] Avoid unnecessary full tile updates without breaking atomicity of commits.
+        https://bugs.webkit.org/show_bug.cgi?id=76740
+
+        Reviewed by James Robinson.
+
+        Allow the final batch of texture uploads to be performed without
+        allocating new textures and re-painting complete tiles.
+
+        This patch is tested by the following unit test:
+        - CCLayerTreeHostTestAtomicCommitWithPartialUpdate.runMultiThread
+        - TiledLayerChromiumTest.partialUpdates
+
+        * platform/graphics/chromium/TiledLayerChromium.cpp:
+        (WebCore::UpdatableTile::UpdatableTile):
+        (UpdatableTile):
+        (WebCore::TiledLayerChromium::updateCompositorResources):
+        (WebCore):
+        (WebCore::TiledLayerChromium::tileOnlyNeedsPartialUpdate):
+        (WebCore::TiledLayerChromium::tileNeedsBufferedUpdate):
+        (WebCore::TiledLayerChromium::prepareToUpdateTiles):
+        * platform/graphics/chromium/TiledLayerChromium.h:
+        (TiledLayerChromium):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
+        (WebCore::CCLayerTreeHost::CCLayerTreeHost):
+        (WebCore::CCLayerTreeHost::initializeLayerRenderer):
+        (WebCore::CCLayerTreeHost::updateLayers):
+        (WebCore::CCLayerTreeHost::requestPartialTextureUpdate):
+        (WebCore):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.h:
+        (WebCore::CCSettings::CCSettings):
+        (CCSettings):
+        (CCLayerTreeHost):
+        * platform/graphics/chromium/cc/CCProxy.h:
+        (CCProxy):
+        * platform/graphics/chromium/cc/CCSingleThreadProxy.cpp:
+        (WebCore::CCSingleThreadProxy::doCommit):
+        * platform/graphics/chromium/cc/CCSingleThreadProxy.h:
+        (WebCore::CCSingleThreadProxy::maxPartialTextureUpdates):
+        * platform/graphics/chromium/cc/CCTextureUpdater.cpp:
+        (WebCore::CCTextureUpdater::append):
+        (WebCore):
+        (WebCore::CCTextureUpdater::appendPartial):
+        (WebCore::CCTextureUpdater::hasMoreUpdates):
+        (WebCore::CCTextureUpdater::update):
+        (WebCore::CCTextureUpdater::clear):
+        * platform/graphics/chromium/cc/CCTextureUpdater.h:
+        (CCTextureUpdater):
+        * platform/graphics/chromium/cc/CCThreadProxy.cpp:
+        (WTF):
+        (WebCore::CCThreadProxy::scheduledActionUpdateMoreResources):
+        (WebCore::CCThreadProxy::maxPartialTextureUpdates):
+        * platform/graphics/chromium/cc/CCThreadProxy.h:
+        (CCThreadProxy):
+
 2012-02-07  MORITA Hajime  <morrita@google.com>
 
         Replacement text should be available from the marker.
index c91dd5d..d9e2487 100644 (file)
@@ -53,7 +53,11 @@ namespace WebCore {
 class UpdatableTile : public CCLayerTilingData::Tile {
     WTF_MAKE_NONCOPYABLE(UpdatableTile);
 public:
-    explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture) : m_texture(texture) { }
+    explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
+        : m_partialUpdate(false)
+        , m_texture(texture)
+    {
+    }
 
     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
     ManagedTexture* managedTexture() { return m_texture->texture(); }
@@ -68,6 +72,7 @@ public:
     IntRect m_dirtyRect;
     IntRect m_updateRect;
     IntRect m_opaqueRect;
+    bool m_partialUpdate;
 private:
     OwnPtr<LayerTextureUpdater::Texture> m_texture;
 };
@@ -210,7 +215,10 @@ void TiledLayerChromium::updateCompositorResources(GraphicsContext3D*, CCTexture
             if (paintOffset.y() + destRect.height() > m_paintRect.height())
                 CRASH();
 
-            updater.append(tile->texture(), sourceRect, destRect);
+            if (tile->m_partialUpdate)
+                updater.appendPartial(tile->texture(), sourceRect, destRect);
+            else
+                updater.append(tile->texture(), sourceRect, destRect);
         }
     }
 
@@ -351,12 +359,42 @@ void TiledLayerChromium::protectTileTextures(const IntRect& layerRect)
     }
 }
 
+// Returns true if tile is dirty and only part of it needs to be updated.
+bool TiledLayerChromium::tileOnlyNeedsPartialUpdate(UpdatableTile* tile)
+{
+    if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
+        return false;
+
+    if (!tile->isDirty())
+        return false;
+
+    return !tile->m_dirtyRect.contains(m_tiler->tileRect(tile));
+}
+
+// Dirty tiles with valid textures needs buffered update to guarantee that
+// we don't modify textures currently used for drawing by the impl thread.
+bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile)
+{
+    // No impl thread?.
+    if (!CCProxy::hasImplThread())
+        return false;
+
+    if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
+        return false;
+
+    if (!tile->isDirty())
+        return false;
+
+    return true;
+}
+
 void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom)
 {
     // Reset m_updateRect for all tiles.
     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
         tile->m_updateRect = IntRect();
+        tile->m_partialUpdate = false;
     }
 
     createTextureUpdaterIfNeeded();
@@ -372,9 +410,11 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int
             if (!tile)
                 tile = createTile(i, j);
 
-            // Do post commit deletion of current texture when partial texture
-            // updates are not used.
-            if (tile->isDirty() && layerTreeHost() && !layerTreeHost()->settings().partialTextureUpdates)
+            // FIXME: Decide if partial update should be allowed based on cost
+            // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
+            if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost() && layerTreeHost()->requestPartialTextureUpdate())
+                tile->m_partialUpdate = true;
+            else if (tileNeedsBufferedUpdate(tile) && layerTreeHost())
                 layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal());
 
             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
index 46192fe..2d99953 100644 (file)
@@ -107,6 +107,9 @@ private:
     void createTilerIfNeeded();
     void setTilingOption(TilingOption);
 
+    bool tileOnlyNeedsPartialUpdate(UpdatableTile*);
+    bool tileNeedsBufferedUpdate(UpdatableTile*);
+
     void prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom);
     IntRect idlePaintRect(const IntRect& visibleLayerRect);
 
index 70c9c82..15a3074 100644 (file)
@@ -39,6 +39,8 @@
 #include "cc/CCThread.h"
 #include "cc/CCThreadProxy.h"
 
+using namespace std;
+
 namespace {
 static int numLayerTreeInstances;
 }
@@ -71,6 +73,7 @@ CCLayerTreeHost::CCLayerTreeHost(CCLayerTreeHostClient* client, const CCSettings
     , m_minPageScale(1)
     , m_maxPageScale(1)
     , m_triggerIdlePaints(true)
+    , m_partialTextureUpdateRequests(0)
 {
     ASSERT(CCProxy::isMainThread());
     numLayerTreeInstances++;
@@ -120,7 +123,7 @@ void CCLayerTreeHost::initializeLayerRenderer()
     m_settings.acceleratePainting = m_proxy->layerRendererCapabilities().usingAcceleratedPainting;
 
     // Update m_settings based on partial update capability.
-    m_settings.partialTextureUpdates = m_settings.partialTextureUpdates && m_proxy->partialTextureUpdateCapability();
+    m_settings.maxPartialTextureUpdates = min(m_settings.maxPartialTextureUpdates, m_proxy->maxPartialTextureUpdates());
 
     m_contentsTextureManager = TextureManager::create(TextureManager::highLimitBytes(viewportSize()),
                                                       TextureManager::reclaimLimitBytes(viewportSize()),
@@ -415,6 +418,9 @@ void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer)
         CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer, rootLayer, identityMatrix, identityMatrix, m_updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize);
     }
 
+    // Reset partial texture update requests.
+    m_partialTextureUpdateRequests = 0;
+
     reserveTextures();
 
     paintLayerContents(m_updateList, PaintVisible);
@@ -623,6 +629,15 @@ void CCLayerTreeHost::stopRateLimiter(GraphicsContext3D* context)
     }
 }
 
+bool CCLayerTreeHost::requestPartialTextureUpdate()
+{
+    if (m_partialTextureUpdateRequests >= m_settings.maxPartialTextureUpdates)
+        return false;
+
+    m_partialTextureUpdateRequests++;
+    return true;
+}
+
 void CCLayerTreeHost::deleteTextureAfterCommit(PassOwnPtr<ManagedTexture> texture)
 {
     m_deleteTextureAfterCommitList.append(texture);
index c3810ab..e82f298 100644 (file)
@@ -33,6 +33,7 @@
 #include "cc/CCLayerTreeHostCommon.h"
 #include "cc/CCProxy.h"
 
+#include <limits>
 #include <wtf/HashMap.h>
 #include <wtf/PassOwnPtr.h>
 #include <wtf/PassRefPtr.h>
@@ -74,7 +75,7 @@ struct CCSettings {
             , refreshRate(0)
             , perTilePainting(false)
             , partialSwapEnabled(false)
-            , partialTextureUpdates(true) { }
+            , maxPartialTextureUpdates(std::numeric_limits<size_t>::max()) { }
 
     bool acceleratePainting;
     bool compositeOffscreen;
@@ -83,7 +84,7 @@ struct CCSettings {
     double refreshRate;
     bool perTilePainting;
     bool partialSwapEnabled;
-    bool partialTextureUpdates;
+    size_t maxPartialTextureUpdates;
 };
 
 // Provides information on an Impl's rendering capabilities back to the CCLayerTreeHost
@@ -192,6 +193,7 @@ public:
     void startRateLimiter(GraphicsContext3D*);
     void stopRateLimiter(GraphicsContext3D*);
 
+    bool requestPartialTextureUpdate();
     void deleteTextureAfterCommit(PassOwnPtr<ManagedTexture>);
 
 protected:
@@ -243,6 +245,7 @@ private:
     bool m_triggerIdlePaints;
 
     TextureList m_deleteTextureAfterCommitList;
+    size_t m_partialTextureUpdateRequests;
 };
 
 }
index a3aa716..44aacce 100644 (file)
@@ -80,9 +80,8 @@ public:
     virtual void start() = 0; // Must be called before using the proxy.
     virtual void stop() = 0; // Must be called before deleting the proxy.
 
-    // Whether sub-regions of textures can be updated or if complete texture
-    // updates are required.
-    virtual bool partialTextureUpdateCapability() const = 0;
+    // Maximum number of sub-region texture updates supported for each commit.
+    virtual size_t maxPartialTextureUpdates() const = 0;
 
     // Debug hooks
 #ifndef NDEBUG
index b7fc612..2e48e10 100644 (file)
@@ -33,6 +33,7 @@
 #include "cc/CCTextureUpdater.h"
 #include <wtf/CurrentTime.h>
 
+using namespace std;
 using namespace WTF;
 
 namespace WebCore {
@@ -172,7 +173,8 @@ void CCSingleThreadProxy::doCommit()
         m_layerTreeHost->beginCommitOnImplThread(m_layerTreeHostImpl.get());
         CCTextureUpdater updater(m_layerTreeHostImpl->contentsTextureAllocator());
         m_layerTreeHost->updateCompositorResources(m_layerTreeHostImpl->context(), updater);
-        while (updater.update(m_layerTreeHostImpl->context(), 1)) { }
+        updater.update(m_layerTreeHostImpl->context(), numeric_limits<size_t>::max());
+        ASSERT(!updater.hasMoreUpdates());
         m_layerTreeHostImpl->setVisible(m_layerTreeHost->visible());
         m_layerTreeHost->finishCommitOnImplThread(m_layerTreeHostImpl.get());
 
index da1fe46..a94405f 100644 (file)
@@ -28,6 +28,7 @@
 #include "cc/CCCompletionEvent.h"
 #include "cc/CCLayerTreeHostImpl.h"
 #include "cc/CCProxy.h"
+#include <limits>
 #include <wtf/OwnPtr.h>
 
 namespace WebCore {
@@ -55,7 +56,7 @@ public:
     virtual void setVisible(bool);
     virtual void start();
     virtual void stop();
-    virtual bool partialTextureUpdateCapability() const { return true; }
+    virtual size_t maxPartialTextureUpdates() const { return std::numeric_limits<size_t>::max(); }
 
     // CCLayerTreeHostImplClient implementation
     virtual void onSwapBuffersCompleteOnImplThread() { ASSERT_NOT_REACHED(); }
index 8745c4e..66e08c8 100644 (file)
@@ -48,7 +48,7 @@ CCTextureUpdater::~CCTextureUpdater()
 {
 }
 
-void CCTextureUpdater::append(LayerTextureUpdater::Texture* texture, const IntRect& sourceRect, const IntRect& destRect)
+void CCTextureUpdater::append(LayerTextureUpdater::Texture* texture, const IntRect& sourceRect, const IntRect& destRect, Vector<UpdateEntry>& entries)
 {
     ASSERT(texture);
 
@@ -56,24 +56,50 @@ void CCTextureUpdater::append(LayerTextureUpdater::Texture* texture, const IntRe
     entry.m_texture = texture;
     entry.m_sourceRect = sourceRect;
     entry.m_destRect = destRect;
-    m_entries.append(entry);
+    entries.append(entry);
+}
+
+void CCTextureUpdater::append(LayerTextureUpdater::Texture* texture, const IntRect& sourceRect, const IntRect& destRect)
+{
+    append(texture, sourceRect, destRect, m_entries);
+}
+
+void CCTextureUpdater::appendPartial(LayerTextureUpdater::Texture* texture, const IntRect& sourceRect, const IntRect& destRect)
+{
+    append(texture, sourceRect, destRect, m_partialEntries);
 }
 
 bool CCTextureUpdater::hasMoreUpdates() const
 {
-    return m_entries.size();
+    return m_entries.size() || m_partialEntries.size();
 }
 
 bool CCTextureUpdater::update(GraphicsContext3D* context, size_t count)
 {
+    size_t index;
     size_t maxIndex = min(m_entryIndex + count, m_entries.size());
-    for (; m_entryIndex < maxIndex; ++m_entryIndex) {
-        UpdateEntry& entry = m_entries[m_entryIndex];
+    for (index = m_entryIndex; index < maxIndex; ++index) {
+        UpdateEntry& entry = m_entries[index];
         entry.m_texture->updateRect(context, m_allocator, entry.m_sourceRect, entry.m_destRect);
     }
 
-    if (maxIndex < m_entries.size())
+    bool moreUpdates = maxIndex < m_entries.size();
+
+    ASSERT(m_partialEntries.size() <= count);
+    // Make sure the number of updates including partial updates are not more
+    // than |count|.
+    if ((count - (index - m_entryIndex)) < m_partialEntries.size())
+        moreUpdates = true;
+
+    if (moreUpdates) {
+        m_entryIndex = index;
         return true;
+    }
+
+    for (index = 0; index < m_partialEntries.size(); ++index) {
+        UpdateEntry& entry = m_partialEntries[index];
+        entry.m_texture->updateRect(context, m_allocator, entry.m_sourceRect, entry.m_destRect);
+    }
 
     // If no entries left to process, auto-clear.
     clear();
@@ -84,6 +110,7 @@ void CCTextureUpdater::clear()
 {
     m_entryIndex = 0;
     m_entries.clear();
+    m_partialEntries.clear();
 }
 
 }
index bf79ac9..dbb52c9 100644 (file)
@@ -41,6 +41,7 @@ public:
     ~CCTextureUpdater();
 
     void append(LayerTextureUpdater::Texture*, const IntRect& sourceRect, const IntRect& destRect);
+    void appendPartial(LayerTextureUpdater::Texture*, const IntRect& sourceRect, const IntRect& destRect);
 
     bool hasMoreUpdates() const;
 
@@ -58,9 +59,12 @@ private:
         IntRect m_destRect;
     };
 
+    static void append(LayerTextureUpdater::Texture*, const IntRect& sourceRect, const IntRect& destRect, Vector<UpdateEntry>&);
+
     TextureAllocator* m_allocator;
     size_t m_entryIndex;
     Vector<UpdateEntry> m_entries;
+    Vector<UpdateEntry> m_partialEntries;
 };
 
 }
index fd63bd5..8ca852d 100644 (file)
@@ -43,7 +43,9 @@ using namespace WTF;
 
 namespace {
 
-static const size_t textureUpdatesPerFrame = 0;
+// Number of textures to update with each call to
+// scheduledActionUpdateMoreResources().
+static const size_t textureUpdatesPerFrame = 5;
 
 } // anonymous namespace
 
@@ -462,7 +464,7 @@ void CCThreadProxy::scheduledActionUpdateMoreResources()
 {
     TRACE_EVENT("CCThreadProxy::scheduledActionUpdateMoreResources", this, 0);
     ASSERT(m_currentTextureUpdaterOnImplThread);
-    m_currentTextureUpdaterOnImplThread->update(m_layerTreeHostImpl->context(), textureUpdatesPerFrame > 0 ? textureUpdatesPerFrame : 99999);
+    m_currentTextureUpdaterOnImplThread->update(m_layerTreeHostImpl->context(), textureUpdatesPerFrame);
 }
 
 void CCThreadProxy::scheduledActionCommit()
@@ -595,9 +597,9 @@ void CCThreadProxy::layerTreeHostClosedOnImplThread(CCCompletionEvent* completio
     completion->signal();
 }
 
-bool CCThreadProxy::partialTextureUpdateCapability() const
+size_t CCThreadProxy::maxPartialTextureUpdates() const
 {
-    return !textureUpdatesPerFrame;
+    return textureUpdatesPerFrame;
 }
 
 } // namespace WebCore
index b65a6c6..d304acd 100644 (file)
@@ -63,7 +63,7 @@ public:
     virtual void setVisible(bool);
     virtual void start();
     virtual void stop();
-    virtual bool partialTextureUpdateCapability() const;
+    virtual size_t maxPartialTextureUpdates() const;
 
     // CCLayerTreeHostImplClient implementation
     virtual void onSwapBuffersCompleteOnImplThread();
index a764b88..bb70608 100644 (file)
@@ -1,3 +1,43 @@
+2012-02-08  David Reveman  <reveman@chromium.org>
+
+        [Chromium] Avoid unnecessary full tile updates without breaking atomicity of commits.
+        https://bugs.webkit.org/show_bug.cgi?id=76740
+
+        Reviewed by James Robinson.
+
+        Add CCLayerTreeHostTestAtomicCommitWithPartialUpdate and
+        TiledLayerChromiumTest.partialUpdates tests that verifies
+        atomicity of commits with partial updates.
+
+        * tests/CCLayerTreeHostTest.cpp:
+        (WTF::CCLayerTreeHostTestAtomicCommit::CCLayerTreeHostTestAtomicCommit):
+        (WTF::CCLayerTreeHostTestAtomicCommit::beginTest):
+        (WTF::CCLayerTreeHostTestAtomicCommit::commitCompleteOnCCThread):
+        (WTF::CCLayerTreeHostTestAtomicCommit::layout):
+        (CCLayerTreeHostTestAtomicCommit):
+        (CCLayerTreeHostTestAtomicCommitWithPartialUpdate):
+        (WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::CCLayerTreeHostTestAtomicCommitWithPartialUpdate):
+        (WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::beginTest):
+        (WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::commitCompleteOnCCThread):
+        (WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::drawLayersOnCCThread):
+        (WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::layout):
+        (WTF::CCLayerTreeHostTestAtomicCommitWithPartialUpdate::afterTest):
+        (WTF):
+        (WTF::TEST_F):
+        * tests/TiledLayerChromiumTest.cpp:
+        (WTF::FakeLayerTextureUpdater::Texture::Texture):
+        (WTF::FakeLayerTextureUpdater::Texture::updateRect):
+        (Texture):
+        (WTF::FakeLayerTextureUpdater::FakeLayerTextureUpdater):
+        (FakeLayerTextureUpdater):
+        (WTF::FakeLayerTextureUpdater::updateCount):
+        (WTF::FakeLayerTextureUpdater::clearUpdateCount):
+        (WTF::FakeLayerTextureUpdater::updateRect):
+        (WTF::FakeLayerTextureUpdater::createTexture):
+        (FakeTiledLayerChromium):
+        (WTF::TEST):
+        (WTF):
+
 2012-02-07  MORITA Hajime  <morrita@google.com>
 
         Replacement text should be available from the marker.
index edcc0b5..fc414f7 100644 (file)
@@ -1147,16 +1147,15 @@ public:
 class CCLayerTreeHostTestAtomicCommit : public CCLayerTreeHostTest {
 public:
     CCLayerTreeHostTestAtomicCommit()
-        : m_updateCheckLayer(ContentLayerChromiumWithUpdateTracking::create(&m_delegate))
-        , m_numCommits(0)
+        : m_layer(ContentLayerChromiumWithUpdateTracking::create(&m_delegate))
     {
         // Make sure partial texture updates are turned off.
-        m_settings.partialTextureUpdates = false;
+        m_settings.maxPartialTextureUpdates = 0;
     }
 
     virtual void beginTest()
     {
-        m_layerTreeHost->setRootLayer(m_updateCheckLayer);
+        m_layerTreeHost->setRootLayer(m_layer);
         m_layerTreeHost->setViewportSize(IntSize(10, 10));
 
         postSetNeedsCommitToMainThread();
@@ -1173,7 +1172,7 @@ public:
             EXPECT_EQ(1, context->numTextures());
             // Number of textures used for commit should be one.
             EXPECT_EQ(1, context->numUsedTextures());
-            // Verify used texture is correct.
+            // Verify that used texture is correct.
             EXPECT_TRUE(context->usedTexture(context->texture(0)));
 
             context->resetUsedTextures();
@@ -1214,7 +1213,7 @@ public:
 
     virtual void layout()
     {
-        m_updateCheckLayer->setNeedsDisplay();
+        m_layer->setNeedsDisplay();
     }
 
     virtual void afterTest()
@@ -1223,8 +1222,7 @@ public:
 
 private:
     MockContentLayerDelegate m_delegate;
-    RefPtr<ContentLayerChromiumWithUpdateTracking> m_updateCheckLayer;
-    int m_numCommits;
+    RefPtr<ContentLayerChromiumWithUpdateTracking> m_layer;
 };
 
 TEST_F(CCLayerTreeHostTestAtomicCommit, runMultiThread)
@@ -1232,6 +1230,132 @@ TEST_F(CCLayerTreeHostTestAtomicCommit, runMultiThread)
     runTest(true);
 }
 
+class CCLayerTreeHostTestAtomicCommitWithPartialUpdate : public CCLayerTreeHostTest {
+public:
+    CCLayerTreeHostTestAtomicCommitWithPartialUpdate()
+        : m_parent(ContentLayerChromiumWithUpdateTracking::create(&m_delegate))
+        , m_child(ContentLayerChromiumWithUpdateTracking::create(&m_delegate))
+        , m_numCommits(0)
+    {
+        // Allow one partial texture update.
+        m_settings.maxPartialTextureUpdates = 1;
+    }
+
+    virtual void beginTest()
+    {
+        m_layerTreeHost->setRootLayer(m_parent);
+        m_layerTreeHost->setViewportSize(IntSize(10, 10));
+        m_parent->addChild(m_child);
+        m_child->setOpacity(0.5);
+        m_child->setBounds(IntSize(20, 20));
+
+        postSetNeedsCommitToMainThread();
+        postSetNeedsRedrawToMainThread();
+    }
+
+    virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl)
+    {
+        CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()));
+
+        switch (impl->frameNumber()) {
+        case 0:
+            // Number of textures should be two.
+            EXPECT_EQ(2, context->numTextures());
+            // Number of textures used for commit should be two.
+            EXPECT_EQ(2, context->numUsedTextures());
+            // Verify that used textures are correct.
+            EXPECT_TRUE(context->usedTexture(context->texture(0)));
+            EXPECT_TRUE(context->usedTexture(context->texture(1)));
+
+            context->resetUsedTextures();
+            break;
+        case 1:
+            // Number of textures should be four as the first two
+            // textures are used by the impl thread.
+            EXPECT_EQ(4, context->numTextures());
+            // Number of textures used for commit should still be two.
+            EXPECT_EQ(2, context->numUsedTextures());
+            // First two textures should not have been used.
+            EXPECT_FALSE(context->usedTexture(context->texture(0)));
+            EXPECT_FALSE(context->usedTexture(context->texture(1)));
+            // New textures should have been used.
+            EXPECT_TRUE(context->usedTexture(context->texture(2)));
+            EXPECT_TRUE(context->usedTexture(context->texture(3)));
+
+            context->resetUsedTextures();
+            break;
+        case 2:
+            // Number of textures should be three as we allow one
+            // partial update and the first two textures are used by
+            // the impl thread.
+            EXPECT_EQ(3, context->numTextures());
+            // Number of textures used for commit should still be two.
+            EXPECT_EQ(2, context->numUsedTextures());
+            // First texture should not have been used.
+            EXPECT_FALSE(context->usedTexture(context->texture(0)));
+            // Second texture should have been used.
+            EXPECT_TRUE(context->usedTexture(context->texture(1)));
+            // New textures should have been used.
+            EXPECT_TRUE(context->usedTexture(context->texture(2)));
+
+            context->resetUsedTextures();
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+
+    virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
+    {
+        CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()));
+
+        // Number of textures used for drawing should always be two.
+        EXPECT_EQ(2, context->numUsedTextures());
+
+        if (impl->frameNumber() < 3) {
+            context->resetUsedTextures();
+            postSetNeedsAnimateAndCommitToMainThread();
+            postSetNeedsRedrawToMainThread();
+        } else
+            endTest();
+    }
+
+    virtual void layout()
+    {
+        switch (m_numCommits++) {
+        case 0:
+        case 1:
+            m_parent->setNeedsDisplay();
+            m_child->setNeedsDisplay();
+            break;
+        case 2:
+            // Damage part of layers.
+            m_parent->setNeedsDisplayRect(FloatRect(0, 0, 5, 5));
+            m_child->setNeedsDisplayRect(FloatRect(0, 0, 5, 5));
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+
+    virtual void afterTest()
+    {
+    }
+
+private:
+    MockContentLayerDelegate m_delegate;
+    RefPtr<ContentLayerChromiumWithUpdateTracking> m_parent;
+    RefPtr<ContentLayerChromiumWithUpdateTracking> m_child;
+    int m_numCommits;
+};
+
+TEST_F(CCLayerTreeHostTestAtomicCommitWithPartialUpdate, runMultiThread)
+{
+    runTest(true);
+}
+
 #define EXPECT_EQ_RECT(a, b) \
     EXPECT_EQ(a.x(), b.x()); \
     EXPECT_EQ(a.y(), b.y()); \
index 6069fd1..fcd3878 100644 (file)
@@ -60,13 +60,24 @@ class FakeLayerTextureUpdater : public LayerTextureUpdater {
 public:
     class Texture : public LayerTextureUpdater::Texture {
     public:
-        Texture(PassOwnPtr<ManagedTexture> texture) : LayerTextureUpdater::Texture(texture) { }
+        Texture(FakeLayerTextureUpdater* layer, PassOwnPtr<ManagedTexture> texture)
+            : LayerTextureUpdater::Texture(texture)
+            , m_layer(layer)
+        {
+        }
         virtual ~Texture() { }
 
-        virtual void updateRect(GraphicsContext3D*, TextureAllocator*, const IntRect&, const IntRect&) { }
+        virtual void updateRect(GraphicsContext3D*, TextureAllocator*, const IntRect&, const IntRect&) { m_layer->updateRect(); }
+
+    private:
+        FakeLayerTextureUpdater* m_layer;
     };
 
-    FakeLayerTextureUpdater() : m_prepareCount(0) { }
+    FakeLayerTextureUpdater()
+        : m_prepareCount(0)
+        , m_updateCount(0)
+    {
+    }
     virtual ~FakeLayerTextureUpdater() { }
 
     // Sets the rect to invalidate during the next call to prepareToUpdate(). After the next
@@ -77,17 +88,23 @@ public:
     int prepareCount() const { return m_prepareCount; }
     void clearPrepareCount() { m_prepareCount = 0; }
 
+    // Number of times updateRect has been invoked.
+    int updateCount() const { return m_updateCount; }
+    void clearUpdateCount() { m_updateCount = 0; }
+    void updateRect() { m_updateCount++; }
+
     void setOpaquePaintRect(const IntRect& opaquePaintRect) { m_opaquePaintRect = opaquePaintRect; }
 
     // Last rect passed to prepareToUpdate().
     const IntRect& lastUpdateRect()  const { return m_lastUpdateRect; }
 
-    virtual PassOwnPtr<LayerTextureUpdater::Texture> createTexture(TextureManager* manager) { return adoptPtr(new Texture(ManagedTexture::create(manager))); }
+    virtual PassOwnPtr<LayerTextureUpdater::Texture> createTexture(TextureManager* manager) { return adoptPtr(new Texture(this, ManagedTexture::create(manager))); }
     virtual SampledTexelFormat sampledTexelFormat(GC3Denum) { return SampledTexelFormatRGBA; }
     virtual void prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect* resultingOpaqueRect);
 
 private:
     int m_prepareCount;
+    int m_updateCount;
     IntRect m_rectToInvalidate;
     IntRect m_lastUpdateRect;
     IntRect m_opaquePaintRect;
@@ -155,8 +172,6 @@ public:
     }
 
 private:
-    virtual void createTextureUpdater(const CCLayerTreeHost*) { }
-
     virtual LayerTextureUpdater* textureUpdater() const
     {
         return m_fakeTextureUpdater.get();
@@ -579,4 +594,75 @@ TEST(TiledLayerChromiumTest, resizeToSmaller)
     layer->invalidateRect(IntRect(0, 0, 200, 200));
 }
 
+TEST(TiledLayerChromiumTest, partialUpdates)
+{
+    CCSettings settings;
+    settings.maxPartialTextureUpdates = 4;
+    // Initialize without threading support.
+    WebKit::WebCompositor::initialize(0);
+    FakeCCLayerTreeHostClient fakeCCLayerTreeHostClient;
+    RefPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, settings);
+
+    // Create one 500 x 300 tiled layer.
+    IntSize contentBounds(300, 200);
+    IntRect contentRect(IntPoint::zero(), contentBounds);
+
+    OwnPtr<TextureManager> textureManager = TextureManager::create(60*1024*1024, 60*1024*1024, 1024);
+    RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
+    layer->setBounds(contentBounds);
+    layer->setPosition(FloatPoint(150, 150));
+    layer->invalidateRect(contentRect);
+
+    FakeTextureAllocator textureAllocator;
+    CCTextureUpdater updater(&textureAllocator);
+
+    ccLayerTreeHost->setRootLayer(layer);
+    ccLayerTreeHost->setViewportSize(IntSize(300, 200));
+
+    // Full update of all 6 tiles.
+    ccLayerTreeHost->updateLayers();
+    ccLayerTreeHost->updateCompositorResources(ccLayerTreeHost->context(), updater);
+    updater.update(0, 4);
+    EXPECT_EQ(4, layer->fakeLayerTextureUpdater()->updateCount());
+    EXPECT_TRUE(updater.hasMoreUpdates());
+    layer->fakeLayerTextureUpdater()->clearUpdateCount();
+    updater.update(0, 4);
+    EXPECT_EQ(2, layer->fakeLayerTextureUpdater()->updateCount());
+    EXPECT_FALSE(updater.hasMoreUpdates());
+    layer->fakeLayerTextureUpdater()->clearUpdateCount();
+    ccLayerTreeHost->commitComplete();
+
+    // Full update of 3 tiles and partial update of 3 tiles.
+    layer->invalidateRect(IntRect(0, 0, 300, 150));
+    ccLayerTreeHost->updateLayers();
+    ccLayerTreeHost->updateCompositorResources(ccLayerTreeHost->context(), updater);
+    updater.update(0, 4);
+    EXPECT_EQ(3, layer->fakeLayerTextureUpdater()->updateCount());
+    EXPECT_TRUE(updater.hasMoreUpdates());
+    layer->fakeLayerTextureUpdater()->clearUpdateCount();
+    updater.update(0, 4);
+    EXPECT_EQ(3, layer->fakeLayerTextureUpdater()->updateCount());
+    EXPECT_FALSE(updater.hasMoreUpdates());
+    layer->fakeLayerTextureUpdater()->clearUpdateCount();
+    ccLayerTreeHost->commitComplete();
+
+    // Partial update of 6 tiles.
+    layer->invalidateRect(IntRect(50, 50, 200, 100));
+    ccLayerTreeHost->updateLayers();
+    ccLayerTreeHost->updateCompositorResources(ccLayerTreeHost->context(), updater);
+    updater.update(0, 4);
+    EXPECT_EQ(2, layer->fakeLayerTextureUpdater()->updateCount());
+    EXPECT_TRUE(updater.hasMoreUpdates());
+    layer->fakeLayerTextureUpdater()->clearUpdateCount();
+    updater.update(0, 4);
+    EXPECT_EQ(4, layer->fakeLayerTextureUpdater()->updateCount());
+    EXPECT_FALSE(updater.hasMoreUpdates());
+    layer->fakeLayerTextureUpdater()->clearUpdateCount();
+    ccLayerTreeHost->commitComplete();
+
+    ccLayerTreeHost->setRootLayer(0);
+    ccLayerTreeHost.clear();
+    WebKit::WebCompositor::shutdown();
+}
+
 } // namespace