[chromium] race between CCLayerTreeHostImpl::releaseContentsTextures and CCThreadProx...
authorpiman@chromium.org <piman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Aug 2012 17:25:55 +0000 (17:25 +0000)
committerpiman@chromium.org <piman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Aug 2012 17:25:55 +0000 (17:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=93684

Reviewed by James Robinson.

This keeps track of whether we're between the beginFrame post and the
commit when releaseContentsTextures comes, and if that is the case, we
prune the texture uploads, keep the "textures purged" flag on and kick a
new commit.

Added CCLayerTreeHostTestEvictTextures test.

* platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
(WebCore::CCLayerTreeHostImpl::CCLayerTreeHostImpl):
(WebCore::CCLayerTreeHostImpl::beginFramePosted):
(WebCore):
(WebCore::CCLayerTreeHostImpl::commitComplete):
(WebCore::CCLayerTreeHostImpl::canDraw):
(WebCore::CCLayerTreeHostImpl::releaseContentsTextures):
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
(CCLayerTreeHostImpl):
(WebCore::CCLayerTreeHostImpl::contentsTexturesPurged):
(WebCore::CCLayerTreeHostImpl::contentsTexturesWerePurgedSinceLastBeginFrame):
* platform/graphics/chromium/cc/CCSingleThreadProxy.cpp:
(WebCore::CCSingleThreadProxy::stop):
(WebCore::CCSingleThreadProxy::commitAndComposite):
* platform/graphics/chromium/cc/CCTextureUpdateController.h:
(CCTextureUpdateController):
* platform/graphics/chromium/cc/CCTextureUpdateQueue.cpp:
(WebCore::CCTextureUpdateQueue::clearUploads):
(WebCore):
* platform/graphics/chromium/cc/CCTextureUpdateQueue.h:
(CCTextureUpdateQueue):
* platform/graphics/chromium/cc/CCThreadProxy.cpp:
(WebCore::CCThreadProxy::scheduledActionBeginFrame):
(WebCore::CCThreadProxy::beginFrameCompleteOnImplThread):
(WebCore::CCThreadProxy::layerTreeHostClosedOnImplThread):

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.cpp
Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdateController.h
Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdateQueue.cpp
Source/WebCore/platform/graphics/chromium/cc/CCTextureUpdateQueue.h
Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp
Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h
Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp
Source/WebKit/chromium/tests/CCThreadedTest.h

index 943a030..8ec1a50 100644 (file)
@@ -1,3 +1,43 @@
+2012-08-14  Antoine Labour  <piman@chromium.org>
+
+        [chromium] race between CCLayerTreeHostImpl::releaseContentsTextures and CCThreadProxy::beginFrameCompleteOnImplThread
+        https://bugs.webkit.org/show_bug.cgi?id=93684
+
+        Reviewed by James Robinson.
+
+        This keeps track of whether we're between the beginFrame post and the
+        commit when releaseContentsTextures comes, and if that is the case, we
+        prune the texture uploads, keep the "textures purged" flag on and kick a
+        new commit.
+
+        Added CCLayerTreeHostTestEvictTextures test.
+
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
+        (WebCore::CCLayerTreeHostImpl::CCLayerTreeHostImpl):
+        (WebCore::CCLayerTreeHostImpl::beginFramePosted):
+        (WebCore):
+        (WebCore::CCLayerTreeHostImpl::commitComplete):
+        (WebCore::CCLayerTreeHostImpl::canDraw):
+        (WebCore::CCLayerTreeHostImpl::releaseContentsTextures):
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
+        (CCLayerTreeHostImpl):
+        (WebCore::CCLayerTreeHostImpl::contentsTexturesPurged):
+        (WebCore::CCLayerTreeHostImpl::contentsTexturesWerePurgedSinceLastBeginFrame):
+        * platform/graphics/chromium/cc/CCSingleThreadProxy.cpp:
+        (WebCore::CCSingleThreadProxy::stop):
+        (WebCore::CCSingleThreadProxy::commitAndComposite):
+        * platform/graphics/chromium/cc/CCTextureUpdateController.h:
+        (CCTextureUpdateController):
+        * platform/graphics/chromium/cc/CCTextureUpdateQueue.cpp:
+        (WebCore::CCTextureUpdateQueue::clearUploads):
+        (WebCore):
+        * platform/graphics/chromium/cc/CCTextureUpdateQueue.h:
+        (CCTextureUpdateQueue):
+        * platform/graphics/chromium/cc/CCThreadProxy.cpp:
+        (WebCore::CCThreadProxy::scheduledActionBeginFrame):
+        (WebCore::CCThreadProxy::beginFrameCompleteOnImplThread):
+        (WebCore::CCThreadProxy::layerTreeHostClosedOnImplThread):
+
 2012-08-14  Yong Li  <yoli@rim.com>
 
         [BlackBerry] Pass URL String's 8-bit buffer directly to platform layer when possible
index b4f808e..166772a 100644 (file)
@@ -122,7 +122,7 @@ CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCLayerTreeSettings& settings, CC
     , m_settings(settings)
     , m_deviceScaleFactor(1)
     , m_visible(true)
-    , m_contentsTexturesWerePurgedSinceLastCommit(false)
+    , m_contentsTexturesPurged(false)
     , m_memoryAllocationLimitBytes(CCPrioritizedTextureManager::defaultMemoryAllocationLimit())
     , m_pageScale(1)
     , m_pageScaleDelta(1)
@@ -159,7 +159,6 @@ void CCLayerTreeHostImpl::commitComplete()
     // Recompute max scroll position; must be after layer content bounds are
     // updated.
     updateMaxScrollPosition();
-    m_contentsTexturesWerePurgedSinceLastCommit = false;
 }
 
 bool CCLayerTreeHostImpl::canDraw()
@@ -176,7 +175,7 @@ bool CCLayerTreeHostImpl::canDraw()
         TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no layerRenderer");
         return false;
     }
-    if (m_contentsTexturesWerePurgedSinceLastCommit) {
+    if (m_contentsTexturesPurged) {
         TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw contents textures purged");
         return false;
     }
@@ -512,8 +511,10 @@ bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame)
 
 void CCLayerTreeHostImpl::releaseContentsTextures()
 {
+    if (m_contentsTexturesPurged)
+        return;
     m_resourceProvider->deleteOwnedResources(CCRenderer::ContentPool);
-    m_contentsTexturesWerePurgedSinceLastCommit = true;
+    m_contentsTexturesPurged = true;
     m_client->setNeedsCommitOnImplThread();
 }
 
index 6ca0cd6..c600b5d 100644 (file)
@@ -152,7 +152,8 @@ public:
     int sourceFrameNumber() const { return m_sourceFrameNumber; }
     void setSourceFrameNumber(int frameNumber) { m_sourceFrameNumber = frameNumber; }
 
-    bool contentsTexturesWerePurgedSinceLastCommit() const { return m_contentsTexturesWerePurgedSinceLastCommit; }
+    bool contentsTexturesPurged() const { return m_contentsTexturesPurged; }
+    void resetContentsTexturesPurged() { m_contentsTexturesPurged = false; }
     size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes; }
 
     void setViewportSize(const IntSize& layoutViewportSize, const IntSize& deviceViewportSize);
@@ -272,7 +273,7 @@ private:
     IntSize m_deviceViewportSize;
     float m_deviceScaleFactor;
     bool m_visible;
-    bool m_contentsTexturesWerePurgedSinceLastCommit;
+    bool m_contentsTexturesPurged;
     size_t m_memoryAllocationLimitBytes;
 
     float m_pageScale;
index 9fe505f..361b515 100644 (file)
@@ -260,7 +260,7 @@ void CCSingleThreadProxy::stop()
         DebugScopedSetMainThreadBlocked mainThreadBlocked;
         DebugScopedSetImplThread impl;
 
-        if (!m_layerTreeHostImpl->contentsTexturesWerePurgedSinceLastCommit())
+        if (!m_layerTreeHostImpl->contentsTexturesPurged())
             m_layerTreeHost->deleteContentsTexturesOnImplThread(m_layerTreeHostImpl->resourceProvider());
         m_layerTreeHostImpl.clear();
     }
@@ -300,11 +300,12 @@ bool CCSingleThreadProxy::commitAndComposite()
     if (!m_layerTreeHost->initializeLayerRendererIfNeeded())
         return false;
 
-    if (m_layerTreeHostImpl->contentsTexturesWerePurgedSinceLastCommit())
+    if (m_layerTreeHostImpl->contentsTexturesPurged())
         m_layerTreeHost->evictAllContentTextures();
 
     CCTextureUpdateQueue queue;
     m_layerTreeHost->updateLayers(queue, m_layerTreeHostImpl->memoryAllocationLimitBytes());
+    m_layerTreeHostImpl->resetContentsTexturesPurged();
 
     m_layerTreeHost->willCommit();
     doCommit(queue);
index bd2c7bc..d6cda59 100644 (file)
@@ -57,6 +57,7 @@ protected:
     CCTextureUpdateController(PassOwnPtr<CCTextureUpdateQueue>, CCResourceProvider*, TextureCopier*, TextureUploader*);
 
     OwnPtr<CCTextureUpdateQueue> m_queue;
+    bool m_contentsTexturesPurged;
     CCResourceProvider* m_resourceProvider;
     TextureCopier* m_copier;
     TextureUploader* m_uploader;
index ae9ab97..6c650f9 100644 (file)
@@ -54,6 +54,12 @@ void CCTextureUpdateQueue::appendCopy(TextureCopier::Parameters copy)
     m_copyEntries.append(copy);
 }
 
+void CCTextureUpdateQueue::clearUploads()
+{
+    m_fullEntries.clear();
+    m_partialEntries.clear();
+}
+
 TextureUploader::Parameters CCTextureUpdateQueue::takeFirstFullUpload()
 {
     return m_fullEntries.takeFirst();
index 7bb5cbc..de63738 100644 (file)
@@ -43,6 +43,8 @@ public:
     void appendPartialUpload(TextureUploader::Parameters);
     void appendCopy(TextureCopier::Parameters);
 
+    void clearUploads();
+
     TextureUploader::Parameters takeFirstFullUpload();
     TextureUploader::Parameters takeFirstPartialUpload();
     TextureCopier::Parameters takeFirstCopy();
index 31d3571..7d5d4b6 100644 (file)
@@ -80,6 +80,7 @@ CCThreadProxy::CCThreadProxy(CCLayerTreeHost* layerTreeHost)
     , m_readbackRequestOnImplThread(0)
     , m_commitCompletionEventOnImplThread(0)
     , m_textureAcquisitionCompletionEventOnImplThread(0)
+    , m_resetContentsTexturesPurgedAfterCommitOnImplThread(false)
     , m_nextFrameIsNewlyCommittedFrameOnImplThread(false)
     , m_renderVSyncEnabled(layerTreeHost->settings().renderVSyncEnabled)
 {
@@ -452,7 +453,7 @@ void CCThreadProxy::scheduledActionBeginFrame()
     m_pendingBeginFrameRequest = adoptPtr(new BeginFrameAndCommitState());
     m_pendingBeginFrameRequest->monotonicFrameBeginTime = monotonicallyIncreasingTime();
     m_pendingBeginFrameRequest->scrollInfo = m_layerTreeHostImpl->processScrollDeltas();
-    m_pendingBeginFrameRequest->contentsTexturesWereDeleted = m_layerTreeHostImpl->contentsTexturesWerePurgedSinceLastCommit();
+    m_pendingBeginFrameRequest->contentsTexturesWereDeleted = m_layerTreeHostImpl->contentsTexturesPurged();
     m_pendingBeginFrameRequest->memoryAllocationLimitBytes = m_layerTreeHostImpl->memoryAllocationLimitBytes();
 
     m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::beginFrame));
@@ -545,7 +546,7 @@ void CCThreadProxy::beginFrame()
         DebugScopedSetMainThreadBlocked mainThreadBlocked;
 
         CCCompletionEvent completion;
-        CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::beginFrameCompleteOnImplThread, &completion, queue.release()));
+        CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::beginFrameCompleteOnImplThread, &completion, queue.release(), request->contentsTexturesWereDeleted));
         completion.wait();
     }
 
@@ -553,7 +554,7 @@ void CCThreadProxy::beginFrame()
     m_layerTreeHost->didBeginFrame();
 }
 
-void CCThreadProxy::beginFrameCompleteOnImplThread(CCCompletionEvent* completion, PassOwnPtr<CCTextureUpdateQueue> queue)
+void CCThreadProxy::beginFrameCompleteOnImplThread(CCCompletionEvent* completion, PassOwnPtr<CCTextureUpdateQueue> queue, bool contentsTexturesWereDeleted)
 {
     TRACE_EVENT0("cc", "CCThreadProxy::beginFrameCompleteOnImplThread");
     ASSERT(!m_commitCompletionEventOnImplThread);
@@ -566,6 +567,16 @@ void CCThreadProxy::beginFrameCompleteOnImplThread(CCCompletionEvent* completion
         return;
     }
 
+    if (!contentsTexturesWereDeleted && m_layerTreeHostImpl->contentsTexturesPurged()) {
+        // We purged the content textures on the impl thread between the time we
+        // posted the beginFrame task and now, meaning we have a bunch of
+        // uploads that are now invalid. Clear the uploads (they all go to
+        // content textures), and kick another commit to fill them again.
+        queue->clearUploads();
+        setNeedsCommitOnImplThread();
+    } else
+        m_resetContentsTexturesPurgedAfterCommitOnImplThread = true;
+
     m_currentTextureUpdateControllerOnImplThread = CCTextureUpdateController::create(queue, m_layerTreeHostImpl->resourceProvider(), m_layerTreeHostImpl->layerRenderer()->textureCopier(), m_layerTreeHostImpl->layerRenderer()->textureUploader());
     m_commitCompletionEventOnImplThread = completion;
 
@@ -619,6 +630,11 @@ void CCThreadProxy::scheduledActionCommit()
     m_layerTreeHost->beginCommitOnImplThread(m_layerTreeHostImpl.get());
     m_layerTreeHost->finishCommitOnImplThread(m_layerTreeHostImpl.get());
 
+    if (m_resetContentsTexturesPurgedAfterCommitOnImplThread) {
+        m_resetContentsTexturesPurgedAfterCommitOnImplThread = false;
+        m_layerTreeHostImpl->resetContentsTexturesPurged();
+    }
+
     m_layerTreeHostImpl->commitComplete();
 
     m_nextFrameIsNewlyCommittedFrameOnImplThread = true;
@@ -853,7 +869,7 @@ void CCThreadProxy::layerTreeHostClosedOnImplThread(CCCompletionEvent* completio
 {
     TRACE_EVENT0("cc", "CCThreadProxy::layerTreeHostClosedOnImplThread");
     ASSERT(isImplThread());
-    if (!m_layerTreeHostImpl->contentsTexturesWerePurgedSinceLastCommit())
+    if (!m_layerTreeHostImpl->contentsTexturesPurged())
         m_layerTreeHost->deleteContentsTexturesOnImplThread(m_layerTreeHostImpl->resourceProvider());
     m_inputHandlerOnImplThread.clear();
     m_layerTreeHostImpl.clear();
index 34360d5..ddb4d90 100644 (file)
@@ -127,7 +127,7 @@ private:
         IntRect rect;
     };
     void forceBeginFrameOnImplThread(CCCompletionEvent*);
-    void beginFrameCompleteOnImplThread(CCCompletionEvent*, PassOwnPtr<CCTextureUpdateQueue>);
+    void beginFrameCompleteOnImplThread(CCCompletionEvent*, PassOwnPtr<CCTextureUpdateQueue>, bool contentsTexturesWereDeleted);
     void beginFrameAbortedOnImplThread();
     void requestReadbackOnImplThread(ReadbackRequest*);
     void requestStartPageScaleAnimationOnImplThread(IntSize targetPosition, bool useAnchor, float scale, double durationSec);
@@ -185,6 +185,10 @@ private:
 
     OwnPtr<CCTextureUpdateController> m_currentTextureUpdateControllerOnImplThread;
 
+    // Set when we need to reset the contentsTexturesPurged flag after the
+    // commit.
+    bool m_resetContentsTexturesPurgedAfterCommitOnImplThread;
+
     // Set when the next draw should post didCommitAndDrawFrame to the main thread.
     bool m_nextFrameIsNewlyCommittedFrameOnImplThread;
 
index 137e624..4aa1afd 100644 (file)
@@ -2347,4 +2347,251 @@ private:
 
 SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit)
 
+
+class EvictionTrackingTexture : public LayerTextureUpdater::Texture {
+public:
+    static PassOwnPtr<EvictionTrackingTexture> create(PassOwnPtr<CCPrioritizedTexture> texture) { return adoptPtr(new EvictionTrackingTexture(texture)); }
+    virtual ~EvictionTrackingTexture() { }
+
+    virtual void updateRect(CCResourceProvider* resourceProvider, const IntRect&, const IntRect&) OVERRIDE
+    {
+        ASSERT_TRUE(!texture()->haveBackingTexture() || resourceProvider->numResources() > 0);
+        texture()->acquireBackingTexture(resourceProvider);
+        m_updated = true;
+    }
+    void resetUpdated() { m_updated = false; }
+    bool updated() const { return m_updated; }
+
+private:
+    explicit EvictionTrackingTexture(PassOwnPtr<CCPrioritizedTexture> texture)
+        : LayerTextureUpdater::Texture(texture)
+        , m_updated(false)
+    { }
+    bool m_updated;
+};
+
+class EvictionTestLayer : public LayerChromium {
+public:
+    static PassRefPtr<EvictionTestLayer> create() { return adoptRef(new EvictionTestLayer()); }
+
+    virtual void update(CCTextureUpdateQueue&, const CCOcclusionTracker*, CCRenderingStats&) OVERRIDE;
+    virtual bool drawsContent() const OVERRIDE { return true; }
+
+    virtual PassOwnPtr<CCLayerImpl> createCCLayerImpl() OVERRIDE;
+    virtual void pushPropertiesTo(CCLayerImpl*) OVERRIDE;
+    virtual void setTexturePriorities(const CCPriorityCalculator&) OVERRIDE;
+
+    void resetUpdated()
+    {
+        if (m_texture.get())
+            m_texture->resetUpdated();
+    }
+    bool updated() const { return m_texture.get() ? m_texture->updated() : false; }
+
+private:
+    EvictionTestLayer() : LayerChromium() { }
+
+    void createTextureIfNeeded()
+    {
+        if (m_texture.get())
+            return;
+        m_texture = EvictionTrackingTexture::create(CCPrioritizedTexture::create(layerTreeHost()->contentsTextureManager()));
+        m_texture->texture()->setDimensions(WebCore::IntSize(10, 10), WebCore::GraphicsContext3D::RGBA);
+    }
+
+    OwnPtr<EvictionTrackingTexture> m_texture;
+};
+
+class EvictionTestLayerImpl : public CCLayerImpl {
+public:
+    static PassOwnPtr<EvictionTestLayerImpl> create(int id)
+    {
+        return adoptPtr(new EvictionTestLayerImpl(id));
+    }
+    virtual ~EvictionTestLayerImpl() { }
+    virtual void appendQuads(CCQuadSink&, const CCSharedQuadState*, bool& hadMissingTiles)
+    {
+        ASSERT_TRUE(m_hasTexture);
+        ASSERT_NE(0u, layerTreeHostImpl()->resourceProvider()->numResources());
+    }
+    void setHasTexture(bool hasTexture) { m_hasTexture = hasTexture; }
+
+private:
+    explicit EvictionTestLayerImpl(int id)
+        : CCLayerImpl(id)
+        , m_hasTexture(false) { }
+
+    bool m_hasTexture;
+};
+
+void EvictionTestLayer::setTexturePriorities(const CCPriorityCalculator&)
+{
+    createTextureIfNeeded();
+    if (!m_texture.get())
+        return;
+    m_texture->texture()->setRequestPriority(CCPriorityCalculator::uiPriority(true));
+}
+
+void EvictionTestLayer::update(CCTextureUpdateQueue& queue, const CCOcclusionTracker*, CCRenderingStats&)
+{
+    createTextureIfNeeded();
+    if (!m_texture.get())
+        return;
+    IntRect fullRect(0, 0, 10, 10);
+    TextureUploader::Parameters parameters = { m_texture.get(), fullRect, fullRect };
+    queue.appendFullUpload(parameters);
+}
+
+PassOwnPtr<CCLayerImpl> EvictionTestLayer::createCCLayerImpl()
+{
+    return EvictionTestLayerImpl::create(m_layerId);
+}
+
+void EvictionTestLayer::pushPropertiesTo(CCLayerImpl* layerImpl)
+{
+    LayerChromium::pushPropertiesTo(layerImpl);
+
+    EvictionTestLayerImpl* testLayerImpl = static_cast<EvictionTestLayerImpl*>(layerImpl);
+    testLayerImpl->setHasTexture(m_texture->texture()->haveBackingTexture());
+}
+
+class CCLayerTreeHostTestEvictTextures : public CCLayerTreeHostTest {
+public:
+    CCLayerTreeHostTestEvictTextures()
+        : m_layer(EvictionTestLayer::create())
+        , m_implForEvictTextures(0)
+        , m_numCommits(0)
+    {
+    }
+
+    virtual void beginTest()
+    {
+        m_layerTreeHost->setRootLayer(m_layer);
+        m_layerTreeHost->setViewportSize(IntSize(10, 20), IntSize(10, 20));
+
+        WebTransformationMatrix identityMatrix;
+        setLayerPropertiesForTesting(m_layer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(10, 20), true);
+    }
+
+    class EvictTexturesTask : public WebKit::WebThread::Task {
+    public:
+        EvictTexturesTask(CCLayerTreeHostTestEvictTextures* test) : m_test(test) { }
+        virtual ~EvictTexturesTask() { }
+        virtual void run()
+        {
+            ASSERT(m_test->m_implForEvictTextures);
+            m_test->m_implForEvictTextures->releaseContentsTextures();
+        }
+
+    private:
+        CCLayerTreeHostTestEvictTextures* m_test;
+    };
+
+    void postEvictTextures()
+    {
+        ASSERT(webThread());
+        webThread()->postTask(new EvictTexturesTask(this));
+    }
+
+    // Commit 1: Just commit and draw normally, then post an eviction at the end
+    // that will trigger a commit.
+    // Commit 2: Triggered by the eviction, let it go through and then set
+    // needsCommit.
+    // Commit 3: Triggered by the setNeedsCommit. In layout(), post an eviction
+    // task, which will be handled before the commit. Don't set needsCommit, it
+    // should have been posted. A frame should not be drawn (note,
+    // didCommitAndDrawFrame may be called anyway).
+    // Commit 4: Triggered by the eviction, let it go through and then set
+    // needsCommit.
+    // Commit 5: Triggered by the setNeedsCommit, post an eviction task in
+    // layout(), a frame should not be drawn but a commit will be posted.
+    // Commit 6: Triggered by the eviction, post an eviction task in
+    // layout(), which will be a noop, letting the commit (which recreates the
+    // textures) go through and draw a frame, then end the test.
+    //
+    // Commits 1+2 test the eviction recovery path where eviction happens outside
+    // of the beginFrame/commit pair.
+    // Commits 3+4 test the eviction recovery path where eviction happens inside
+    // the beginFrame/commit pair.
+    // Commits 5+6 test the path where an eviction happens during the eviction
+    // recovery path.
+    virtual void didCommitAndDrawFrame()
+    {
+        switch (m_numCommits) {
+        case 1:
+            EXPECT_TRUE(m_layer->updated());
+            postEvictTextures();
+            break;
+        case 2:
+            EXPECT_TRUE(m_layer->updated());
+            m_layerTreeHost->setNeedsCommit();
+            break;
+        case 3:
+            break;
+        case 4:
+            EXPECT_TRUE(m_layer->updated());
+            m_layerTreeHost->setNeedsCommit();
+            break;
+        case 5:
+            break;
+        case 6:
+            EXPECT_TRUE(m_layer->updated());
+            endTest();
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+
+    virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl)
+    {
+        m_implForEvictTextures = impl;
+    }
+
+    virtual void layout()
+    {
+        ++m_numCommits;
+        switch (m_numCommits) {
+        case 1:
+        case 2:
+            break;
+        case 3:
+            postEvictTextures();
+            break;
+        case 4:
+            // We couldn't check in didCommitAndDrawFrame on commit 3, so check here.
+            EXPECT_FALSE(m_layer->updated());
+            break;
+        case 5:
+            postEvictTextures();
+            break;
+        case 6:
+            // We couldn't check in didCommitAndDrawFrame on commit 5, so check here.
+            EXPECT_FALSE(m_layer->updated());
+            postEvictTextures();
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+        m_layer->resetUpdated();
+    }
+
+    virtual void afterTest()
+    {
+    }
+
+private:
+    MockContentLayerDelegate m_delegate;
+    RefPtr<EvictionTestLayer> m_layer;
+    CCLayerTreeHostImpl* m_implForEvictTextures;
+    int m_numCommits;
+};
+
+TEST_F(CCLayerTreeHostTestEvictTextures, runMultiThread)
+{
+    runTest(true);
+}
+
 } // namespace
index 946b65f..0ad6f3d 100644 (file)
@@ -134,6 +134,7 @@ protected:
     static void dispatchDidAddAnimation(void* self);
 
     virtual void runTest(bool threaded);
+    WebKit::WebThread* webThread() const { return m_webThread.get(); }
 
     WebCore::CCLayerTreeSettings m_settings;
     OwnPtr<MockCCLayerTreeHostClient> m_client;