#include "cc/CCLayerTreeHost.h"
#include "cc/CCMainThreadTask.h"
#include "cc/CCThreadTask.h"
-#include <wtf/CurrentTime.h>
#include <wtf/MainThread.h>
using namespace WTF;
}
CCThreadProxy::CCThreadProxy(CCLayerTreeHost* layerTreeHost)
- : m_commitRequested(false)
+ : m_commitPending(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());
{
TRACE_EVENT("CCThreadProxy::~CCThreadProxy", this, 0);
ASSERT(isMainThread());
- ASSERT(!m_started);
+ ASSERT(!m_layerTreeHostImpl); // Make sure stop() got called.
+ ASSERT(!m_layerTreeHost); // Make sure stop() got called.
numProxies--;
if (!numProxies) {
bool CCThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect)
{
- 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();
+ ASSERT_NOT_REACHED();
+ return false;
}
GraphicsContext3D* CCThreadProxy::context()
void CCThreadProxy::finishAllRendering()
{
- 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();
+ ASSERT_NOT_REACHED();
}
bool CCThreadProxy::isStarted() const
{
- ASSERT(CCProxy::isMainThread());
- return m_started;
+ return m_layerTreeHostImpl;
}
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 = false;
+ bool initializeSucceeded;
LayerRendererCapabilities capabilities;
ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::initializeLayerRendererOnCCThread,
AllowCrossThreadAccess(contextPtr), AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&initializeSucceeded), AllowCrossThreadAccess(&capabilities)));
void CCThreadProxy::setNeedsCommit()
{
ASSERT(isMainThread());
- if (m_commitRequested)
+ if (m_commitPending)
return;
TRACE_EVENT("CCThreadProxy::setNeedsCommit", this, 0);
- m_commitRequested = true;
- ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::updateSchedulerStateOnCCThread, m_commitRequested, true));
+ m_commitPending = true;
+ ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitOnCCThread));
}
void CCThreadProxy::setNeedsCommitAndRedraw()
{
ASSERT(isMainThread());
- if (m_commitRequested)
+ if (m_commitPending)
return;
- m_commitRequested = true;
TRACE_EVENT("CCThreadProxy::setNeedsCommitAndRedraw", this, 0);
- ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::updateSchedulerStateOnCCThread, m_commitRequested, true));
+ m_commitPending = true;
+ ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitAndRedrawOnCCThread));
}
void CCThreadProxy::setNeedsRedraw()
{
ASSERT(isMainThread());
- 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));
+ ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsRedrawOnCCThread));
}
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)));
ASSERT(!m_layerTreeHostImpl); // verify that the impl deleted.
m_layerTreeHost = 0;
- m_started = false;
}
-void CCThreadProxy::finishAllRenderingOnCCThread(CCCompletionEvent* completion)
+void CCThreadProxy::beginFrameAndCommitOnCCThread()
{
- TRACE_EVENT("CCThreadProxy::finishAllRenderingOnCCThread", this, 0);
- ASSERT(isImplThread());
- 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();
-}
-
-PassOwnPtr<CCMainThread::Task> CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread()
-{
- TRACE_EVENT("CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread", this, 0);
+ TRACE_EVENT("CCThreadProxy::beginFrameAndCommitOnCCThread", 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);
+ // TEMP HACK so we can exercise this code in unit tests.
+ CCMainThread::postTask(createMainThreadTask(this, &CCThreadProxy::beginFrameAndCommit, 0.0));
}
-void CCThreadProxy::beginFrameAndCommit(int sequenceNumber, double frameBeginTime)
+void CCThreadProxy::beginFrameAndCommit(double frameBeginTime)
{
- TRACE_EVENT("CCThreadProxy::beginFrameAndCommit", this, 0);
ASSERT(isMainThread());
if (!m_layerTreeHost)
return;
- // 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("CCThreadProxy::requestFrameAndCommit", this, 0);
{
TRACE_EVENT("CCLayerTreeHost::animateAndLayout", this, 0);
m_layerTreeHost->animateAndLayout(frameBeginTime);
}
- ASSERT(m_lastExecutedBeginFrameAndCommitSequenceNumber == sequenceNumber);
+ m_commitPending = false;
- // 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);
+ // Blocking call to CCThreadProxy::performCommit
+ CCCompletionEvent completion;
+ ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::commitOnCCThread, AllowCrossThreadAccess(&completion)));
+ completion.wait();
}
void CCThreadProxy::commitOnCCThread(CCCompletionEvent* completion)
{
- TRACE_EVENT("CCThreadProxy::beginFrameAndCommitOnCCThread", this, 0);
ASSERT(isImplThread());
- ASSERT(m_beginFrameAndCommitPendingOnCCThread);
- m_beginFrameAndCommitPendingOnCCThread = false;
- if (!m_layerTreeHostImpl) {
- completion->signal();
- return;
- }
+ TRACE_EVENT("CCThreadProxy::commitOnCCThread", this, 0);
m_layerTreeHostImpl->beginCommit();
- m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
- m_layerTreeHostImpl->commitComplete();
-
+ {
+ TRACE_EVENT("CCLayerTreeHost::commit", this, 0);
+ m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
+ }
completion->signal();
- if (m_redrawRequestedOnCCThread)
- scheduleDrawTaskOnCCThread();
-}
-
-void CCThreadProxy::scheduleDrawTaskOnCCThread()
-{
- ASSERT(isImplThread());
- if (m_drawTaskPostedOnCCThread)
- return;
- TRACE_EVENT("CCThreadProxy::scheduleDrawTaskOnCCThread", this, 0);
- ASSERT(m_layerTreeHostImpl);
- m_drawTaskPostedOnCCThread = true;
- ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::drawLayersAndPresentOnCCThread));
+ m_layerTreeHostImpl->commitComplete();
+ setNeedsRedrawOnCCThread();
}
-void CCThreadProxy::drawLayersAndPresentOnCCThread()
+void CCThreadProxy::drawLayersOnCCThread()
{
TRACE_EVENT("CCThreadProxy::drawLayersOnCCThread", this, 0);
ASSERT(isImplThread());
- if (!m_layerTreeHostImpl)
- return;
-
- drawLayersOnCCThread();
- m_layerTreeHostImpl->present();
- m_redrawRequestedOnCCThread = false;
- m_drawTaskPostedOnCCThread = false;
+ if (m_layerTreeHostImpl)
+ m_layerTreeHostImpl->drawLayers();
}
-void CCThreadProxy::drawLayersOnCCThread()
+void CCThreadProxy::setNeedsCommitOnCCThread()
{
- TRACE_EVENT("CCThreadProxy::drawLayersOnCCThread", this, 0);
+ TRACE_EVENT("CCThreadProxy::setNeedsCommitOnCCThread", this, 0);
ASSERT(isImplThread());
ASSERT(m_layerTreeHostImpl);
-
- m_layerTreeHostImpl->drawLayers();
- ASSERT(!m_layerTreeHostImpl->isContextLost());
+ // FIXME: Not yet implemented, see https://bugs.webkit.org/show_bug.cgi?id=67417
+ ASSERT_NOT_REACHED();
}
-void CCThreadProxy::updateSchedulerStateOnCCThread(bool commitRequested, bool redrawRequested)
+void CCThreadProxy::setNeedsCommitAndRedrawOnCCThread()
{
- TRACE_EVENT("CCThreadProxy::updateSchedulerStateOnCCThread", this, 0);
+ TRACE_EVENT("CCThreadProxy::setNeedsCommitAndRedrawOnCCThread", 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));
+}
- // 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::setNeedsRedrawOnCCThread()
+{
+ TRACE_EVENT("CCThreadProxy::setNeedsRedrawOnCCThread", this, 0);
+ // TEMP HACK so we can exercise this code in unit tests.
+ drawLayersOnCCThread();
}
void CCThreadProxy::initializeImplOnCCThread(CCCompletionEvent* completion)