[chromium] Make CCThreadProxy draw
authorjamesr@google.com <jamesr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Sep 2011 07:22:10 +0000 (07:22 +0000)
committerjamesr@google.com <jamesr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Sep 2011 07:22:10 +0000 (07:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=67417

Source/WebCore:

Update the CCThreadProxy to correctly implement the CCProxy
interface, do all the right committing and updating steps, and
draw a picture on the screen.

Patch by Nat Duca <nduca@chromium.org> on 2011-09-22
Reviewed by James Robinson.

* platform/graphics/IntRect.h:
* platform/graphics/chromium/LayerRendererChromium.cpp:
(WebCore::LayerRendererChromium::~LayerRendererChromium):
* platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp:
(WebCore::CCHeadsUpDisplay::enabled):
* platform/graphics/chromium/cc/CCLayerImpl.cpp:
(WebCore::CCLayerImpl::CCLayerImpl):
(WebCore::CCLayerImpl::~CCLayerImpl):
* platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
(WebCore::CCLayerTreeHost::CCLayerTreeHost):
(WebCore::CCLayerTreeHost::commitTo):
(WebCore::CCLayerTreeHost::commitComplete):
(WebCore::CCLayerTreeHost::setNeedsRedraw):
* platform/graphics/chromium/cc/CCLayerTreeHost.h:
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
(WebCore::CCLayerTreeHostImpl::CCLayerTreeHostImpl):
(WebCore::CCLayerTreeHostImpl::~CCLayerTreeHostImpl):
* platform/graphics/chromium/cc/CCSingleThreadProxy.cpp:
(WebCore::CCSingleThreadProxy::finishAllRendering):
(WebCore::CCSingleThreadProxy::setNeedsCommit):
(WebCore::CCSingleThreadProxy::commitIfNeeded):
* platform/graphics/chromium/cc/CCThreadProxy.cpp:
(WebCore::CCThreadProxy::CCThreadProxy):
(WebCore::CCThreadProxy::~CCThreadProxy):
(WebCore::CCThreadProxy::compositeAndReadback):
(WebCore::CCThreadProxy::drawLayersAndReadbackOnCCThread):
(WebCore::CCThreadProxy::finishAllRendering):
(WebCore::CCThreadProxy::isStarted):
(WebCore::CCThreadProxy::setNeedsCommit):
(WebCore::CCThreadProxy::setNeedsCommitAndRedraw):
(WebCore::CCThreadProxy::setNeedsRedraw):
(WebCore::CCThreadProxy::start):
(WebCore::CCThreadProxy::stop):
(WebCore::CCThreadProxy::finishAllRenderingOnCCThread):
(WebCore::CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread):
(WebCore::CCThreadProxy::beginFrameAndCommit):
(WebCore::CCThreadProxy::commitOnCCThread):
(WebCore::CCThreadProxy::scheduleDrawTaskOnCCThread):
(WebCore::CCThreadProxy::drawLayersAndPresentOnCCThread):
(WebCore::CCThreadProxy::drawLayersOnCCThread):
(WebCore::CCThreadProxy::updateSchedulerStateOnCCThread):
* platform/graphics/chromium/cc/CCThreadProxy.h:

Source/WebKit/chromium:

Disable CCLayerTreeHostTest temporarily. Will re-enable
with https://bugs.webkit.org/show_bug.cgi?id=67418

Patch by Nat Duca <nduca@chromium.org> on 2011-09-22
Reviewed by James Robinson.

* tests/CCLayerTreeHostTest.cpp:

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

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/CrossThreadCopier.h
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCProxy.h
Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.cpp
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/TreeSynchronizerTest.cpp

index bb42501..9210646 100644 (file)
@@ -1,3 +1,57 @@
+2011-09-22  Nat Duca  <nduca@chromium.org>
+
+        [chromium] Make CCThreadProxy draw
+        https://bugs.webkit.org/show_bug.cgi?id=67417
+
+        Update the CCThreadProxy to correctly implement the CCProxy
+        interface, do all the right committing and updating steps, and
+        draw a picture on the screen.
+
+        Reviewed by James Robinson.
+
+        * platform/graphics/IntRect.h:
+        * platform/graphics/chromium/LayerRendererChromium.cpp:
+        (WebCore::LayerRendererChromium::~LayerRendererChromium):
+        * platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp:
+        (WebCore::CCHeadsUpDisplay::enabled):
+        * platform/graphics/chromium/cc/CCLayerImpl.cpp:
+        (WebCore::CCLayerImpl::CCLayerImpl):
+        (WebCore::CCLayerImpl::~CCLayerImpl):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
+        (WebCore::CCLayerTreeHost::CCLayerTreeHost):
+        (WebCore::CCLayerTreeHost::commitTo):
+        (WebCore::CCLayerTreeHost::commitComplete):
+        (WebCore::CCLayerTreeHost::setNeedsRedraw):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.h:
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
+        (WebCore::CCLayerTreeHostImpl::CCLayerTreeHostImpl):
+        (WebCore::CCLayerTreeHostImpl::~CCLayerTreeHostImpl):
+        * platform/graphics/chromium/cc/CCSingleThreadProxy.cpp:
+        (WebCore::CCSingleThreadProxy::finishAllRendering):
+        (WebCore::CCSingleThreadProxy::setNeedsCommit):
+        (WebCore::CCSingleThreadProxy::commitIfNeeded):
+        * platform/graphics/chromium/cc/CCThreadProxy.cpp:
+        (WebCore::CCThreadProxy::CCThreadProxy):
+        (WebCore::CCThreadProxy::~CCThreadProxy):
+        (WebCore::CCThreadProxy::compositeAndReadback):
+        (WebCore::CCThreadProxy::drawLayersAndReadbackOnCCThread):
+        (WebCore::CCThreadProxy::finishAllRendering):
+        (WebCore::CCThreadProxy::isStarted):
+        (WebCore::CCThreadProxy::setNeedsCommit):
+        (WebCore::CCThreadProxy::setNeedsCommitAndRedraw):
+        (WebCore::CCThreadProxy::setNeedsRedraw):
+        (WebCore::CCThreadProxy::start):
+        (WebCore::CCThreadProxy::stop):
+        (WebCore::CCThreadProxy::finishAllRenderingOnCCThread):
+        (WebCore::CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread):
+        (WebCore::CCThreadProxy::beginFrameAndCommit):
+        (WebCore::CCThreadProxy::commitOnCCThread):
+        (WebCore::CCThreadProxy::scheduleDrawTaskOnCCThread):
+        (WebCore::CCThreadProxy::drawLayersAndPresentOnCCThread):
+        (WebCore::CCThreadProxy::drawLayersOnCCThread):
+        (WebCore::CCThreadProxy::updateSchedulerStateOnCCThread):
+        * platform/graphics/chromium/cc/CCThreadProxy.h:
+
 2011-09-21  Beth Dakin  <bdakin@apple.com>
 
         https://bugs.webkit.org/show_bug.cgi?id=67415
index 7ce7f98..39d11b5 100644 (file)
@@ -41,6 +41,7 @@
 
 namespace WebCore {
 
+    class IntRect;
     class KURL;
     class ResourceError;
     class ResourceRequest;
@@ -63,9 +64,14 @@ namespace WebCore {
     template<typename T> struct CrossThreadCopierBase<true, false, T> : public CrossThreadCopierPassThrough<T> {
     };
 
+    // To allow a type to be passed across threads using its copy constructor, add a forward declaration of the type and
+    // a CopyThreadCopierBase<false, false, TypeName> : public CrossThreadCopierPassThrough<TypeName> { }; to this file.
     template<> struct CrossThreadCopierBase<false, false, ThreadableLoaderOptions> : public CrossThreadCopierPassThrough<ThreadableLoaderOptions> {
     };
 
+    template<> struct CrossThreadCopierBase<false, false, IntRect> : public CrossThreadCopierPassThrough<IntRect> {
+    };
+
     // Custom copy methods.
     template<typename T> struct CrossThreadCopierBase<false, true, T> {
         typedef typename WTF::RemoveTemplate<T, RefPtr>::Type TypeWithoutRefPtr;
index 4dae613..1946a96 100644 (file)
@@ -182,6 +182,7 @@ bool LayerRendererChromium::initialize()
 
 LayerRendererChromium::~LayerRendererChromium()
 {
+    ASSERT(CCProxy::isMainThread());
     m_headsUpDisplay.clear(); // Explicitly destroy the HUD before the TextureManager dies.
     cleanupSharedObjects();
 }
index 30aa82c..dc27148 100644 (file)
@@ -89,6 +89,9 @@ void CCHeadsUpDisplay::onPresent()
 
 bool CCHeadsUpDisplay::enabled() const
 {
+    // FIXME: HUD does not work in compositor thread mode.
+    if (settings().enableCompositorThread)
+        return false;
     return settings().showPlatformLayerTree || settings().showFPSCounter;
 }
 
index c986591..64168c2 100644 (file)
@@ -55,10 +55,12 @@ CCLayerImpl::CCLayerImpl(int id)
     , m_debugBorderColor(0, 0, 0, 0)
     , m_debugBorderWidth(0)
 {
+    ASSERT(CCProxy::isImplThread());
 }
 
 CCLayerImpl::~CCLayerImpl()
 {
+    ASSERT(CCProxy::isImplThread());
 }
 
 void CCLayerImpl::addChild(PassRefPtr<CCLayerImpl> child)
index a257b41..bda6004 100644 (file)
@@ -56,6 +56,7 @@ CCLayerTreeHost::CCLayerTreeHost(CCLayerTreeHostClient* client, PassRefPtr<Layer
     , m_zoomAnimatorScale(1)
     , m_visible(true)
 {
+    ASSERT(CCProxy::isMainThread());
 }
 
 bool CCLayerTreeHost::initialize()
@@ -106,6 +107,11 @@ void CCLayerTreeHost::animateAndLayout(double frameBeginTime)
     m_animating = false;
 }
 
+// This function commits the CCLayerTreeHost to an impl tree. When modifying
+// this function, keep in mind that the function *runs* on the impl thread! Any
+// code that is logically a main thread operation, e.g. deletion of a LayerChromium,
+// should be delayed until the CCLayerTreeHost::commitComplete, which will run
+// after the commit, but on the main thread.
 void CCLayerTreeHost::commitTo(CCLayerTreeHostImpl* hostImpl)
 {
     ASSERT(CCProxy::isImplThread());
@@ -120,14 +126,12 @@ void CCLayerTreeHost::commitTo(CCLayerTreeHostImpl* hostImpl)
     contentsTextureManager()->deleteEvictedTextures(hostImpl->context());
 
     updateCompositorResources(m_updateList, hostImpl->context());
-    clearPendingUpdate();
 
     hostImpl->setVisible(m_visible);
     hostImpl->setZoomAnimatorScale(m_zoomAnimatorScale);
     hostImpl->setViewport(viewportSize());
 
     hostImpl->layerRenderer()->setContentsTextureMemoryUseBytes(m_contentsTextureManager->currentMemoryUseBytes());
-    m_contentsTextureManager->unprotectAllTextures();
 
     // Synchronize trees, if one exists at all...
     if (rootLayer())
@@ -138,6 +142,12 @@ void CCLayerTreeHost::commitTo(CCLayerTreeHostImpl* hostImpl)
     m_frameNumber++;
 }
 
+void CCLayerTreeHost::commitComplete()
+{
+    clearPendingUpdate();
+    m_contentsTextureManager->unprotectAllTextures();
+}
+
 PassOwnPtr<CCThread> CCLayerTreeHost::createCompositorThread()
 {
     return m_client->createCompositorThread();
@@ -214,7 +224,6 @@ void CCLayerTreeHost::setNeedsCommitAndRedraw()
 void CCLayerTreeHost::setNeedsRedraw()
 {
 #if USE(THREADED_COMPOSITING)
-    TRACE_EVENT("CCLayerTreeHost::setNeedsRedraw", this, 0);
     m_proxy->setNeedsRedraw();
 #else
     m_client->scheduleComposite();
index fee2956..b7b9048 100644 (file)
@@ -67,6 +67,12 @@ struct CCSettings {
             , enableCompositorThread(false)
             , showFPSCounter(false)
             , showPlatformLayerTree(false) { }
+    CCSettings(bool acceleratePainting, bool compositeOffscreen, bool enableCompositorThread, bool showFPSCounter, bool showPlatformLayerTree)
+            : acceleratePainting(acceleratePainting)
+            , compositeOffscreen(compositeOffscreen)
+            , enableCompositorThread(enableCompositorThread)
+            , showFPSCounter(showFPSCounter)
+            , showPlatformLayerTree(showPlatformLayerTree) { }
 
     bool acceleratePainting;
     bool compositeOffscreen;
@@ -96,6 +102,7 @@ public:
 
     // CCLayerTreeHost interface to CCProxy.
     void animateAndLayout(double frameBeginTime);
+    void commitComplete();
     void commitTo(CCLayerTreeHostImpl*);
     PassOwnPtr<CCThread> createCompositorThread();
     PassRefPtr<GraphicsContext3D> createLayerTreeHostContext3D();
index b304836..4a1c39d 100644 (file)
@@ -48,10 +48,12 @@ CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCSettings& settings)
     , m_frameNumber(0)
     , m_settings(settings)
 {
+    ASSERT(CCProxy::isImplThread());
 }
 
 CCLayerTreeHostImpl::~CCLayerTreeHostImpl()
 {
+    ASSERT(CCProxy::isImplThread());
     TRACE_EVENT("CCLayerTreeHostImpl::~CCLayerTreeHostImpl()", this, 0);
     if (m_layerRenderer)
         m_layerRenderer->close();
index f5e418b..b222b99 100644 (file)
@@ -75,19 +75,20 @@ public:
     static bool isImplThread();
 #endif
 
-    // Testing hooks
-    virtual void loseCompositorContext(int numTimes) = 0;
-
     // Temporary hack while render_widget still does scheduling for CCLayerTreeHostMainThreadI
     virtual GraphicsContext3D* context() = 0;
 
-protected:
-    CCProxy() { }
-    friend class ScopedSetImplThread;
+    // Testing hooks
+    virtual void loseCompositorContext(int numTimes) = 0;
+
 #ifndef NDEBUG
     static void setImplThread(bool);
     static void setImplThread(WTF::ThreadIdentifier);
 #endif
+
+protected:
+    CCProxy() { }
+    friend class ScopedSetImplThread;
 };
 
 }
index 2d27d72..002a4ab 100644 (file)
@@ -111,8 +111,15 @@ GraphicsContext3D* CCSingleThreadProxy::context()
 void CCSingleThreadProxy::finishAllRendering()
 {
     ASSERT(isMainThread());
-    ScopedSetImplThread impl;
-    m_layerTreeHostImpl->finishAllRendering();
+    if (!recreateContextIfNeeded())
+        return;
+
+    commitIfNeeded();
+
+    {
+        ScopedSetImplThread impl;
+        m_layerTreeHostImpl->finishAllRendering();
+    }
 }
 
 bool CCSingleThreadProxy::isStarted() const
@@ -157,6 +164,7 @@ void CCSingleThreadProxy::setNeedsCommit()
         m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
         m_layerTreeHostImpl->commitComplete();
     }
+    m_layerTreeHost->commitComplete();
 }
 
 void CCSingleThreadProxy::setNeedsCommitAndRedraw()
@@ -250,6 +258,7 @@ void CCSingleThreadProxy::commitIfNeeded()
         m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
         m_layerTreeHostImpl->commitComplete();
     }
+    m_layerTreeHost->commitComplete();
 }
 
 bool CCSingleThreadProxy::doComposite()
index 9a84da6..3d4ed5e 100644 (file)
@@ -31,6 +31,7 @@
 #include "cc/CCLayerTreeHost.h"
 #include "cc/CCMainThreadTask.h"
 #include "cc/CCThreadTask.h"
+#include <wtf/CurrentTime.h>
 #include <wtf/MainThread.h>
 
 using namespace WTF;
@@ -48,8 +49,14 @@ PassOwnPtr<CCProxy> CCThreadProxy::create(CCLayerTreeHost* layerTreeHost)
 }
 
 CCThreadProxy::CCThreadProxy(CCLayerTreeHost* layerTreeHost)
-    : m_commitPending(false)
+    : m_commitRequested(false)
     , m_layerTreeHost(layerTreeHost)
+    , m_started(false)
+    , m_lastExecutedBeginFrameAndCommitSequenceNumber(-1)
+    , m_numBeginFrameAndCommitsIssuedOnCCThread(0)
+    , m_beginFrameAndCommitPendingOnCCThread(false)
+    , m_drawTaskPostedOnCCThread(false)
+    , m_redrawRequestedOnCCThread(false)
 {
     TRACE_EVENT("CCThreadProxy::CCThreadProxy", this, 0);
     ASSERT(isMainThread());
@@ -66,8 +73,7 @@ CCThreadProxy::~CCThreadProxy()
 {
     TRACE_EVENT("CCThreadProxy::~CCThreadProxy", this, 0);
     ASSERT(isMainThread());
-    ASSERT(!m_layerTreeHostImpl); // Make sure stop() got called.
-    ASSERT(!m_layerTreeHost); // Make sure stop() got called.
+    ASSERT(!m_started);
 
     numProxies--;
     if (!numProxies) {
@@ -78,8 +84,29 @@ CCThreadProxy::~CCThreadProxy()
 
 bool CCThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect)
 {
-    ASSERT_NOT_REACHED();
-    return false;
+    ASSERT(isMainThread());
+    ASSERT(m_layerTreeHost);
+
+    finishAllRendering();
+    bool success = false;
+    CCCompletionEvent completion;
+    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::drawLayersAndReadbackOnCCThread, AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&success), AllowCrossThreadAccess(pixels), rect));
+    completion.wait();
+    return success;
+}
+
+void CCThreadProxy::drawLayersAndReadbackOnCCThread(CCCompletionEvent* completion, bool* success, void* pixels, const IntRect& rect)
+{
+    ASSERT(CCProxy::isImplThread());
+    if (!m_layerTreeHostImpl) {
+        *success = false;
+        completion->signal();
+        return;
+    }
+    drawLayersOnCCThread();
+    m_layerTreeHostImpl->readback(pixels, rect);
+    *success = m_layerTreeHostImpl->isContextLost();
+    completion->signal();
 }
 
 GraphicsContext3D* CCThreadProxy::context()
@@ -89,12 +116,34 @@ GraphicsContext3D* CCThreadProxy::context()
 
 void CCThreadProxy::finishAllRendering()
 {
-    ASSERT_NOT_REACHED();
+    ASSERT(CCProxy::isMainThread());
+    // If a commit is pending, perform the commit first.
+    if (m_commitRequested)  {
+        // This bit of code is uglier than it should be because returning
+        // pointers via the CCThread task model is really messy. Effectively, we
+        // are making a blocking call to createBeginFrameAndCommitTaskOnCCThread,
+        // and trying to get the CCMainThread::Task it returns so we can run it.
+        OwnPtr<CCMainThread::Task> beginFrameAndCommitTask;
+        {
+            CCMainThread::Task* taskPtr = 0;
+            CCCompletionEvent completion;
+            ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread, AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&taskPtr)));
+            completion.wait();
+            beginFrameAndCommitTask = adoptPtr(taskPtr);
+        }
+
+        beginFrameAndCommitTask->performTask();
+    }
+    // Make sure all GL drawing is finished on the impl thread.
+    CCCompletionEvent completion;
+    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::finishAllRenderingOnCCThread, AllowCrossThreadAccess(&completion)));
+    completion.wait();
 }
 
 bool CCThreadProxy::isStarted() const
 {
-    return m_layerTreeHostImpl;
+    ASSERT(CCProxy::isMainThread());
+    return m_started;
 }
 
 bool CCThreadProxy::initializeLayerRenderer()
@@ -111,7 +160,7 @@ bool CCThreadProxy::initializeLayerRenderer()
     // Make a blocking call to initializeLayerRendererOnCCThread. The results of that call
     // are pushed into the initializeSucceeded and capabilities local variables.
     CCCompletionEvent completion;
-    bool initializeSucceeded;
+    bool initializeSucceeded = false;
     LayerRendererCapabilities capabilities;
     ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::initializeLayerRendererOnCCThread,
                                           AllowCrossThreadAccess(contextPtr), AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&initializeSucceeded), AllowCrossThreadAccess(&capabilities)));
@@ -135,43 +184,57 @@ void CCThreadProxy::loseCompositorContext(int numTimes)
 void CCThreadProxy::setNeedsCommit()
 {
     ASSERT(isMainThread());
-    if (m_commitPending)
+    if (m_commitRequested)
         return;
 
     TRACE_EVENT("CCThreadProxy::setNeedsCommit", this, 0);
-    m_commitPending = true;
-    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitOnCCThread));
+    m_commitRequested = true;
+    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::updateSchedulerStateOnCCThread, m_commitRequested, true));
 }
 
 void CCThreadProxy::setNeedsCommitAndRedraw()
 {
     ASSERT(isMainThread());
-    if (m_commitPending)
+    if (m_commitRequested)
         return;
+    m_commitRequested = true;
 
     TRACE_EVENT("CCThreadProxy::setNeedsCommitAndRedraw", this, 0);
-    m_commitPending = true;
-    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitAndRedrawOnCCThread));
+    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::updateSchedulerStateOnCCThread, m_commitRequested, true));
 }
 
 void CCThreadProxy::setNeedsRedraw()
 {
     ASSERT(isMainThread());
-    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsRedrawOnCCThread));
+    if (m_commitRequested) // Implies that a commit is in flight.
+        return;
+    // Unlike setNeedsCommit that tracks whether a commit message has been sent,
+    // setNeedsRedraw always sends a message to the compositor thread. This is
+    // because the compositor thread can draw without telling the main
+    // thread. This should not be much of a problem because calls to
+    // setNeedsRedraw messages are uncommon (only triggered by WM_PAINT/etc),
+    // compared to setNeedsCommitAndRedraw messages.
+    TRACE_EVENT("CCThreadProxy::setNeedsRedraw", this, 0);
+    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::updateSchedulerStateOnCCThread, false, true));
 }
 
 void CCThreadProxy::start()
 {
+    ASSERT(isMainThread());
     // Create LayerTreeHostImpl.
     CCCompletionEvent completion;
     ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::initializeImplOnCCThread, AllowCrossThreadAccess(&completion)));
     completion.wait();
+
+    m_started = true;
 }
 
 void CCThreadProxy::stop()
 {
     TRACE_EVENT("CCThreadProxy::stop", this, 0);
     ASSERT(isMainThread());
+    ASSERT(m_started);
+
     // Synchronously deletes the impl.
     CCCompletionEvent completion;
     ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::layerTreeHostClosedOnCCThread, AllowCrossThreadAccess(&completion)));
@@ -179,82 +242,166 @@ void CCThreadProxy::stop()
 
     ASSERT(!m_layerTreeHostImpl); // verify that the impl deleted.
     m_layerTreeHost = 0;
+    m_started = false;
 }
 
-void CCThreadProxy::beginFrameAndCommitOnCCThread()
+void CCThreadProxy::finishAllRenderingOnCCThread(CCCompletionEvent* completion)
 {
-    TRACE_EVENT("CCThreadProxy::beginFrameAndCommitOnCCThread", this, 0);
+    TRACE_EVENT("CCThreadProxy::finishAllRenderingOnCCThread", this, 0);
     ASSERT(isImplThread());
-    // TEMP HACK so we can exercise this code in unit tests.
-    CCMainThread::postTask(createMainThreadTask(this, &CCThreadProxy::beginFrameAndCommit, 0.0));
+    ASSERT(!m_beginFrameAndCommitPendingOnCCThread);
+    if (m_redrawRequestedOnCCThread) {
+        drawLayersOnCCThread();
+        m_layerTreeHostImpl->present();
+        m_redrawRequestedOnCCThread = false;
+    }
+    m_layerTreeHostImpl->finishAllRendering();
+    completion->signal();
+}
+
+void CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread(CCCompletionEvent* completion, CCMainThread::Task** taskPtr)
+{
+    OwnPtr<CCMainThread::Task> task = createBeginFrameAndCommitTaskOnCCThread();
+    *taskPtr = task.leakPtr();
+    completion->signal();
 }
 
-void CCThreadProxy::beginFrameAndCommit(double frameBeginTime)
+PassOwnPtr<CCMainThread::Task> CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread()
 {
+    TRACE_EVENT("CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread", this, 0);
+    ASSERT(isImplThread());
+    double frameBeginTime = currentTime();
+    m_beginFrameAndCommitPendingOnCCThread = true;
+
+    // NOTE, it is possible to receieve a request for a
+    // beginFrameAndCommitOnCCThread from finishAllRendering while a
+    // beginFrameAndCommitOnCCThread is enqueued. Since it CCMainThread doesn't
+    // provide a threadsafe way to cancel tasks, it is important that
+    // beginFrameAndCommit be structured to understand that it may get called at
+    // a point that it shouldn't. We do this by assigning a sequence number to
+    // every new beginFrameAndCommit task. Then, beginFrameAndCommit tracks the
+    // last executed sequence number, dropping beginFrameAndCommit with sequence
+    // numbers below the last executed one.
+    int thisTaskSequenceNumber = m_numBeginFrameAndCommitsIssuedOnCCThread;
+    m_numBeginFrameAndCommitsIssuedOnCCThread++;
+    return createMainThreadTask(this, &CCThreadProxy::beginFrameAndCommit, thisTaskSequenceNumber, frameBeginTime);
+}
+
+void CCThreadProxy::beginFrameAndCommit(int sequenceNumber, double frameBeginTime)
+{
+    TRACE_EVENT("CCThreadProxy::beginFrameAndCommit", this, 0);
     ASSERT(isMainThread());
     if (!m_layerTreeHost)
         return;
 
-    TRACE_EVENT("CCThreadProxy::requestFrameAndCommit", this, 0);
+    // Drop beginFrameAndCommit calls that occur out of sequence. See createBeginFrameAndCommitTaskOnCCThread for
+    // an explanation of how out-of-sequence beginFrameAndCommit tasks can occur.
+    if (sequenceNumber < m_lastExecutedBeginFrameAndCommitSequenceNumber) {
+        TRACE_EVENT("EarlyOut_StaleBeginFrameAndCommit", this, 0);
+        return;
+    }
+    m_lastExecutedBeginFrameAndCommitSequenceNumber = sequenceNumber;
+
+    ASSERT(m_commitRequested);
+
+    // FIXME: recreate the context if it was requested by the impl thread
     {
         TRACE_EVENT("CCLayerTreeHost::animateAndLayout", this, 0);
         m_layerTreeHost->animateAndLayout(frameBeginTime);
     }
 
-    m_commitPending = false;
+    ASSERT(m_lastExecutedBeginFrameAndCommitSequenceNumber == sequenceNumber);
 
-    // Blocking call to CCThreadProxy::performCommit
-    CCCompletionEvent completion;
-    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::commitOnCCThread, AllowCrossThreadAccess(&completion)));
-    completion.wait();
+    // Clear the commit flag after animateAndLayout here --- objects that only
+    // layout when painted will trigger another setNeedsCommit inside
+    // updateLayers.
+    m_commitRequested = false;
+
+    m_layerTreeHost->updateLayers();
+
+    {
+        // Blocking call to CCThreadProxy::commitOnCCThread
+        TRACE_EVENT("commit", this, 0);
+        CCCompletionEvent completion;
+        ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::commitOnCCThread, AllowCrossThreadAccess(&completion)));
+        completion.wait();
+    }
+
+    m_layerTreeHost->commitComplete();
+
+    ASSERT(m_lastExecutedBeginFrameAndCommitSequenceNumber == sequenceNumber);
 }
 
 void CCThreadProxy::commitOnCCThread(CCCompletionEvent* completion)
 {
+    TRACE_EVENT("CCThreadProxy::beginFrameAndCommitOnCCThread", this, 0);
     ASSERT(isImplThread());
-    TRACE_EVENT("CCThreadProxy::commitOnCCThread", this, 0);
-    m_layerTreeHostImpl->beginCommit();
-    {
-        TRACE_EVENT("CCLayerTreeHost::commit", this, 0);
-        m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
+    ASSERT(m_beginFrameAndCommitPendingOnCCThread);
+    m_beginFrameAndCommitPendingOnCCThread = false;
+    if (!m_layerTreeHostImpl) {
+        completion->signal();
+        return;
     }
+    m_layerTreeHostImpl->beginCommit();
+    m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
+    m_layerTreeHostImpl->commitComplete();
+
     completion->signal();
 
-    m_layerTreeHostImpl->commitComplete();
-    setNeedsRedrawOnCCThread();
+    if (m_redrawRequestedOnCCThread)
+        scheduleDrawTaskOnCCThread();
 }
 
-void CCThreadProxy::drawLayersOnCCThread()
+void CCThreadProxy::scheduleDrawTaskOnCCThread()
 {
-    TRACE_EVENT("CCThreadProxy::drawLayersOnCCThread", this, 0);
     ASSERT(isImplThread());
-    if (m_layerTreeHostImpl)
-        m_layerTreeHostImpl->drawLayers();
+    if (m_drawTaskPostedOnCCThread)
+        return;
+    TRACE_EVENT("CCThreadProxy::scheduleDrawTaskOnCCThread", this, 0);
+    ASSERT(m_layerTreeHostImpl);
+    m_drawTaskPostedOnCCThread = true;
+    ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::drawLayersAndPresentOnCCThread));
 }
 
-void CCThreadProxy::setNeedsCommitOnCCThread()
+void CCThreadProxy::drawLayersAndPresentOnCCThread()
 {
-    TRACE_EVENT("CCThreadProxy::setNeedsCommitOnCCThread", this, 0);
+    TRACE_EVENT("CCThreadProxy::drawLayersOnCCThread", this, 0);
     ASSERT(isImplThread());
-    ASSERT(m_layerTreeHostImpl);
-    // FIXME: Not yet implemented, see https://bugs.webkit.org/show_bug.cgi?id=67417
-    ASSERT_NOT_REACHED();
+    if (!m_layerTreeHostImpl)
+        return;
+
+    drawLayersOnCCThread();
+    m_layerTreeHostImpl->present();
+    m_redrawRequestedOnCCThread = false;
+    m_drawTaskPostedOnCCThread = false;
 }
 
-void CCThreadProxy::setNeedsCommitAndRedrawOnCCThread()
+void CCThreadProxy::drawLayersOnCCThread()
 {
-    TRACE_EVENT("CCThreadProxy::setNeedsCommitAndRedrawOnCCThread", this, 0);
+    TRACE_EVENT("CCThreadProxy::drawLayersOnCCThread", this, 0);
     ASSERT(isImplThread());
     ASSERT(m_layerTreeHostImpl);
-    // TEMP HACK so we can exercise this code in unit tests.
-    CCMainThread::postTask(createMainThreadTask(this, &CCThreadProxy::beginFrameAndCommit, 0.0));
+
+    m_layerTreeHostImpl->drawLayers();
+    ASSERT(!m_layerTreeHostImpl->isContextLost());
 }
 
-void CCThreadProxy::setNeedsRedrawOnCCThread()
+void CCThreadProxy::updateSchedulerStateOnCCThread(bool commitRequested, bool redrawRequested)
 {
-    TRACE_EVENT("CCThreadProxy::setNeedsRedrawOnCCThread", this, 0);
-    // TEMP HACK so we can exercise this code in unit tests.
-    drawLayersOnCCThread();
+    TRACE_EVENT("CCThreadProxy::updateSchedulerStateOnCCThread", this, 0);
+    ASSERT(isImplThread());
+    ASSERT(m_layerTreeHostImpl);
+
+    // FIXME: use CCScheduler to decide when to manage the conversion of this
+    // commit request into an actual createBeginFrameAndCommitTaskOnCCThread call.
+    m_redrawRequestedOnCCThread |= redrawRequested;
+    if (!m_beginFrameAndCommitPendingOnCCThread)
+        CCMainThread::postTask(createBeginFrameAndCommitTaskOnCCThread());
+
+    // If no commit is pending, but a redraw is requested, then post a redraw right away
+    if (!m_beginFrameAndCommitPendingOnCCThread && m_redrawRequestedOnCCThread)
+        scheduleDrawTaskOnCCThread();
+
 }
 
 void CCThreadProxy::initializeImplOnCCThread(CCCompletionEvent* completion)
index 2467724..5a0ea67 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "cc/CCCompletionEvent.h"
 #include "cc/CCLayerTreeHostImpl.h"
+#include "cc/CCMainThread.h"
 #include "cc/CCProxy.h"
 #include <wtf/OwnPtr.h>
 
@@ -58,28 +59,36 @@ private:
     explicit CCThreadProxy(CCLayerTreeHost*);
 
     // Called on CCMainThread
-    void beginFrameAndCommit(double frameBeginTime);
+    void beginFrameAndCommit(int sequenceNumber, double frameBeginTime);
 
     // Called on CCThread
-    void beginFrameAndCommitOnCCThread();
+    PassOwnPtr<CCMainThread::Task> createBeginFrameAndCommitTaskOnCCThread();
+    void createBeginFrameAndCommitTaskOnCCThread(CCCompletionEvent*, CCMainThread::Task**);
     void commitOnCCThread(CCCompletionEvent*);
+    void drawLayersAndPresentOnCCThread();
     void drawLayersOnCCThread();
+    void drawLayersAndReadbackOnCCThread(CCCompletionEvent*, bool* success, void* pixels, const IntRect&);
+    void finishAllRenderingOnCCThread(CCCompletionEvent*);
     void initializeImplOnCCThread(CCCompletionEvent*);
     void initializeLayerRendererOnCCThread(GraphicsContext3D*, CCCompletionEvent*, bool* initializeSucceeded, LayerRendererCapabilities*);
     void setNeedsCommitOnCCThread();
-    void setNeedsCommitAndRedrawOnCCThread();
-    void setNeedsRedrawOnCCThread();
+    void updateSchedulerStateOnCCThread(bool commitRequested, bool redrawRequested);
     void layerTreeHostClosedOnCCThread(CCCompletionEvent*);
-
-    // Used on main-thread only.
-    bool m_commitPending;
+    void scheduleDrawTaskOnCCThread();
 
     // Accessed on main thread only.
+    bool m_commitRequested;
     CCLayerTreeHost* m_layerTreeHost;
     LayerRendererCapabilities m_layerRendererCapabilitiesMainThreadCopy;
+    bool m_started;
+    int m_lastExecutedBeginFrameAndCommitSequenceNumber;
 
-    // Used on the CCThread, but checked on main thread during initialization/shutdown.
+    // Used on the CCThread only
     OwnPtr<CCLayerTreeHostImpl> m_layerTreeHostImpl;
+    int m_numBeginFrameAndCommitsIssuedOnCCThread;
+    bool m_beginFrameAndCommitPendingOnCCThread;
+    bool m_drawTaskPostedOnCCThread;
+    bool m_redrawRequestedOnCCThread;
 };
 
 }
index 7bb8c96..d34db66 100644 (file)
@@ -1,3 +1,15 @@
+2011-09-22  Nat Duca  <nduca@chromium.org>
+
+        [chromium] Make CCThreadProxy draw
+        https://bugs.webkit.org/show_bug.cgi?id=67417
+
+        Disable CCLayerTreeHostTest temporarily. Will re-enable
+        with https://bugs.webkit.org/show_bug.cgi?id=67418
+
+        Reviewed by James Robinson.
+
+        * tests/CCLayerTreeHostTest.cpp:
+
 2011-09-21  Joshua Bell  <jsbell@chromium.org>
 
         Implement WebKit side of IDBFactory::getDatabaseNames
index ff4ffbe..64c2161 100644 (file)
@@ -170,6 +170,10 @@ public:
     {
     }
 
+#if !USE(THREADED_COMPOSITING)
+    virtual void scheduleComposite() { }
+#endif
+
 private:
     explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
 
@@ -186,8 +190,11 @@ private:
 //
 // The test continues until someone calls endTest. endTest can be called on any thread, but be aware that
 // ending the test is an asynchronous process.
-class CCLayerTreeHostTest : public testing::Test, TestHooks {
+class CCLayerTreeHostTest : public testing::TestWithParam<CCSettings>, TestHooks {
 public:
+    virtual void SetUp()
+    {
+    }
     virtual void afterTest() = 0;
     virtual void beginTest() = 0;
 
@@ -287,10 +294,8 @@ void CCLayerTreeHostTest::doBeginTest()
     m_running = true;
     m_client = MockLayerTreeHostClient::create(this);
 
-    CCSettings settings;
-    settings.enableCompositorThread = true;
     RefPtr<LayerChromium> rootLayer;
-    m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, settings);
+    m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, GetParam());
     ASSERT(m_layerTreeHost);
 
     m_beginning = true;
@@ -299,6 +304,11 @@ void CCLayerTreeHostTest::doBeginTest()
     if (m_endWhenBeginReturns)
         onEndTest(static_cast<void*>(this));
 }
+INSTANTIATE_TEST_CASE_P(
+    ProxyTests, CCLayerTreeHostTest,
+    testing::Values(
+        CCSettings(false, false, false, false, false),
+        CCSettings(false, false, true, false, false)));
 
 void CCLayerTreeHostTest::endTest()
 {
@@ -545,9 +555,10 @@ private:
 };
 TEST_F(CCLayerTreeHostTestSetNeedsRedraw, run)
 {
+    CCSettings setings;
     runTest();
 }
 
 } // namespace
 
-#endif // USE(THREADED_COMPOSITING)
+#endif
index 8adf476..c37de73 100644 (file)
 
 #include "LayerChromium.h"
 #include "cc/CCLayerImpl.h"
+#include "cc/CCProxy.h"
 #include <gtest/gtest.h>
 
 using namespace WebCore;
 
 namespace {
 
+class ScopedSetImplThread {
+public:
+    ScopedSetImplThread()
+    {
+#ifndef NDEBUG
+        CCProxy::setImplThread(true);
+#endif
+    }
+    ~ScopedSetImplThread()
+    {
+#ifndef NDEBUG
+        CCProxy::setImplThread(false);
+#endif
+    }
+};
+
 class MockCCLayerImpl : public CCLayerImpl {
 public:
     static PassRefPtr<MockCCLayerImpl> create(int layerId)
@@ -116,6 +133,7 @@ void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer)
 // Constructs a very simple tree and synchronizes it without trying to reuse any preexisting layers.
 TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty)
 {
+    ScopedSetImplThread impl;
     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
     layerTreeRoot->addChild(LayerChromium::create(0));
     layerTreeRoot->addChild(LayerChromium::create(0));
@@ -128,6 +146,7 @@ TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty)
 // Constructs a very simple tree and synchronizes it attempting to reuse some layers
 TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
 {
+    ScopedSetImplThread impl;
     Vector<int> ccLayerDestructionList;
 
     RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
@@ -153,6 +172,7 @@ TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
 
 TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
 {
+    ScopedSetImplThread impl;
     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
     layerTreeRoot->addChild(LayerChromium::create(0));
     layerTreeRoot->addChild(LayerChromium::create(0));
@@ -184,6 +204,7 @@ TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
 
 TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
 {
+    ScopedSetImplThread impl;
     Vector<int> ccLayerDestructionList;
 
     // Set up a tree with this sort of structure:
@@ -230,6 +251,7 @@ TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
 // Constructs a very simple tree, synchronizes it, then synchronizes to a totally new tree. All layers from the old tree should be deleted.
 TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
 {
+    ScopedSetImplThread impl;
     Vector<int> ccLayerDestructionList;
 
     RefPtr<LayerChromium> oldLayerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
@@ -260,6 +282,7 @@ TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
 // Constructs+syncs a tree with mask, replica, and replica mask layers.
 TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers)
 {
+    ScopedSetImplThread impl;
     RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
     layerTreeRoot->addChild(LayerChromium::create(0));
     layerTreeRoot->addChild(LayerChromium::create(0));