From 3769bf8b35532523a502e223988aa772c800a7dd Mon Sep 17 00:00:00 2001 From: "commit-queue@webkit.org" Date: Thu, 9 Feb 2012 05:26:00 +0000 Subject: [PATCH] [Chromium] Avoid unnecessary full tile updates without breaking atomicity of commits. https://bugs.webkit.org/show_bug.cgi?id=76740 Patch by David Reveman 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 --- Source/WebCore/ChangeLog | 56 +++++++++ .../graphics/chromium/TiledLayerChromium.cpp | 50 +++++++- .../graphics/chromium/TiledLayerChromium.h | 3 + .../graphics/chromium/cc/CCLayerTreeHost.cpp | 17 ++- .../graphics/chromium/cc/CCLayerTreeHost.h | 7 +- .../platform/graphics/chromium/cc/CCProxy.h | 5 +- .../graphics/chromium/cc/CCSingleThreadProxy.cpp | 4 +- .../graphics/chromium/cc/CCSingleThreadProxy.h | 3 +- .../graphics/chromium/cc/CCTextureUpdater.cpp | 39 +++++- .../graphics/chromium/cc/CCTextureUpdater.h | 4 + .../graphics/chromium/cc/CCThreadProxy.cpp | 10 +- .../platform/graphics/chromium/cc/CCThreadProxy.h | 2 +- Source/WebKit/chromium/ChangeLog | 40 ++++++ .../WebKit/chromium/tests/CCLayerTreeHostTest.cpp | 140 +++++++++++++++++++-- .../chromium/tests/TiledLayerChromiumTest.cpp | 98 ++++++++++++++- 15 files changed, 440 insertions(+), 38 deletions(-) diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index 33f8368..27af7c8 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,59 @@ +2012-02-08 David Reveman + + [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 Replacement text should be available from the marker. diff --git a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp index c91dd5d..d9e2487 100644 --- a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp @@ -53,7 +53,11 @@ namespace WebCore { class UpdatableTile : public CCLayerTilingData::Tile { WTF_MAKE_NONCOPYABLE(UpdatableTile); public: - explicit UpdatableTile(PassOwnPtr texture) : m_texture(texture) { } + explicit UpdatableTile(PassOwnPtr 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 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(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)) diff --git a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h index 46192fe..2d99953 100644 --- a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h @@ -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); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp index 70c9c82..15a3074 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp @@ -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 texture) { m_deleteTextureAfterCommitList.append(texture); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h index c3810ab..e82f298 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h @@ -33,6 +33,7 @@ #include "cc/CCLayerTreeHostCommon.h" #include "cc/CCProxy.h" +#include #include #include #include @@ -74,7 +75,7 @@ struct CCSettings { , refreshRate(0) , perTilePainting(false) , partialSwapEnabled(false) - , partialTextureUpdates(true) { } + , maxPartialTextureUpdates(std::numeric_limits::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); protected: @@ -243,6 +245,7 @@ private: bool m_triggerIdlePaints; TextureList m_deleteTextureAfterCommitList; + size_t m_partialTextureUpdateRequests; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h b/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h index a3aa716..44aacce 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h @@ -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 diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.cpp index b7fc612..2e48e10 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.cpp @@ -33,6 +33,7 @@ #include "cc/CCTextureUpdater.h" #include +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::max()); + ASSERT(!updater.hasMoreUpdates()); m_layerTreeHostImpl->setVisible(m_layerTreeHost->visible()); m_layerTreeHost->finishCommitOnImplThread(m_layerTreeHostImpl.get()); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h b/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h index da1fe46..a94405f 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h @@ -28,6 +28,7 @@ #include "cc/CCCompletionEvent.h" #include "cc/CCLayerTreeHostImpl.h" #include "cc/CCProxy.h" +#include #include 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::max(); } // CCLayerTreeHostImplClient implementation virtual void onSwapBuffersCompleteOnImplThread() { ASSERT_NOT_REACHED(); } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.cpp index 8745c4e..66e08c8 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.cpp @@ -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& 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(); } } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.h b/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.h index bf79ac9..dbb52c9 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdater.h @@ -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&); + TextureAllocator* m_allocator; size_t m_entryIndex; Vector m_entries; + Vector m_partialEntries; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp index fd63bd5..8ca852d 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp @@ -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 diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h index b65a6c6..d304acd 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h @@ -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(); diff --git a/Source/WebKit/chromium/ChangeLog b/Source/WebKit/chromium/ChangeLog index a764b88..bb70608 100644 --- a/Source/WebKit/chromium/ChangeLog +++ b/Source/WebKit/chromium/ChangeLog @@ -1,3 +1,43 @@ +2012-02-08 David Reveman + + [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 Replacement text should be available from the marker. diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp index edcc0b5..fc414f7 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp @@ -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 m_updateCheckLayer; - int m_numCommits; + RefPtr 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(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(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 m_parent; + RefPtr 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()); \ diff --git a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp index 6069fd1..fcd3878 100644 --- a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp @@ -60,13 +60,24 @@ class FakeLayerTextureUpdater : public LayerTextureUpdater { public: class Texture : public LayerTextureUpdater::Texture { public: - Texture(PassOwnPtr texture) : LayerTextureUpdater::Texture(texture) { } + Texture(FakeLayerTextureUpdater* layer, PassOwnPtr 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 createTexture(TextureManager* manager) { return adoptPtr(new Texture(ManagedTexture::create(manager))); } + virtual PassOwnPtr 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::create(&fakeCCLayerTreeHostClient, settings); + + // Create one 500 x 300 tiled layer. + IntSize contentBounds(300, 200); + IntRect contentRect(IntPoint::zero(), contentBounds); + + OwnPtr textureManager = TextureManager::create(60*1024*1024, 60*1024*1024, 1024); + RefPtr 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 -- 2.7.4