+2011-09-26 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-26 Adam Klein <adamk@chromium.org>
[MutationObservers] implement MutationRecord
namespace WebCore {
+ class IntRect;
class KURL;
class ResourceError;
class ResourceRequest;
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;
LayerRendererChromium::~LayerRendererChromium()
{
+ ASSERT(CCProxy::isImplThread
+());
m_headsUpDisplay.clear(); // Explicitly destroy the HUD before the TextureManager dies.
cleanupSharedObjects();
}
bool CCHeadsUpDisplay::enabled() const
{
+ // FIXME: HUD does not work in compositor thread mode.
+ if (settings().enableCompositorThread)
+ return false;
return settings().showPlatformLayerTree || settings().showFPSCounter;
}
, m_debugBorderColor(0, 0, 0, 0)
, m_debugBorderWidth(0)
{
+ ASSERT(CCProxy::isImplThread());
}
CCLayerImpl::~CCLayerImpl()
{
+ ASSERT(CCProxy::isImplThread());
}
void CCLayerImpl::addChild(PassRefPtr<CCLayerImpl> child)
, m_settings(settings)
, m_visible(true)
{
+ ASSERT(CCProxy::isMainThread());
}
bool CCLayerTreeHost::initialize()
if (m_settings.enableCompositorThread) {
// Accelerated Painting is not supported in threaded mode. Turn it off.
m_settings.acceleratePainting = false;
+ // The HUD does not work in threaded mode. Turn it off.
+ m_settings.showFPSCounter = false;
+ m_settings.showPlatformLayerTree = false;
+
m_proxy = CCThreadProxy::create(this);
} else
m_proxy = CCSingleThreadProxy::create(this);
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());
contentsTextureManager()->deleteEvictedTextures(hostImpl->context());
updateCompositorResources(m_updateList, hostImpl->context());
- clearPendingUpdate();
hostImpl->setVisible(m_visible);
hostImpl->setZoomAnimatorTransform(m_zoomAnimatorTransform);
hostImpl->setViewport(viewportSize());
hostImpl->layerRenderer()->setContentsTextureMemoryUseBytes(m_contentsTextureManager->currentMemoryUseBytes());
- m_contentsTextureManager->unprotectAllTextures();
// Synchronize trees, if one exists at all...
if (rootLayer())
m_frameNumber++;
}
+void CCLayerTreeHost::commitComplete()
+{
+ clearPendingUpdate();
+ m_contentsTextureManager->unprotectAllTextures();
+}
+
PassOwnPtr<CCThread> CCLayerTreeHost::createCompositorThread()
{
return m_client->createCompositorThread();
void CCLayerTreeHost::setNeedsRedraw()
{
#if USE(THREADED_COMPOSITING)
- TRACE_EVENT("CCLayerTreeHost::setNeedsRedraw", this, 0);
m_proxy->setNeedsRedraw();
#else
m_client->scheduleComposite();
// CCLayerTreeHost interface to CCProxy.
void animateAndLayout(double frameBeginTime);
+ void commitComplete();
void commitTo(CCLayerTreeHostImpl*);
PassOwnPtr<CCThread> createCompositorThread();
PassRefPtr<GraphicsContext3D> createLayerTreeHostContext3D();
, 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();
namespace WebCore {
#ifndef NDEBUG
-bool CCProxy::isMainThread()
-{
- return ::isMainThread();
-}
namespace {
bool fakeImplThread = false;
static WTF::ThreadIdentifier implThreadID;
}
+bool CCProxy::isMainThread()
+{
+ return ::isMainThread() && !fakeImplThread;
+}
+
bool CCProxy::isImplThread()
{
return fakeImplThread || currentThread() == implThreadID;
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;
};
}
ScopedSetImplThread()
{
#ifndef NDEBUG
+ ASSERT(CCProxy::isMainThread());
CCProxy::setImplThread(true);
#endif
}
, m_timesRecreateShouldFail(0)
{
TRACE_EVENT("CCSingleThreadProxy::CCSingleThreadProxy", this, 0);
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
}
void CCSingleThreadProxy::start()
CCSingleThreadProxy::~CCSingleThreadProxy()
{
TRACE_EVENT("CCSingleThreadProxy::~CCSingleThreadProxy", this, 0);
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
ASSERT(!m_layerTreeHostImpl && !m_layerTreeHost); // make sure stop() got called.
}
bool CCSingleThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect)
{
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
if (!recreateContextIfNeeded())
return false;
GraphicsContext3D* CCSingleThreadProxy::context()
{
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
ScopedSetImplThread impl;
return m_layerTreeHostImpl->context();
}
void CCSingleThreadProxy::finishAllRendering()
{
- ASSERT(isMainThread());
- ScopedSetImplThread impl;
- m_layerTreeHostImpl->finishAllRendering();
+ ASSERT(CCProxy::isMainThread());
+ {
+ ScopedSetImplThread impl;
+ m_layerTreeHostImpl->finishAllRendering();
+ }
}
bool CCSingleThreadProxy::isStarted() const
{
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
return m_layerTreeHostImpl;
}
bool CCSingleThreadProxy::initializeLayerRenderer()
{
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
RefPtr<GraphicsContext3D> context = m_layerTreeHost->createLayerTreeHostContext3D();
if (!context)
return false;
{
ScopedSetImplThread impl;
- return m_layerTreeHostImpl->initializeLayerRenderer(context);
+ bool ok = m_layerTreeHostImpl->initializeLayerRenderer(context);
+ if (ok)
+ m_layerRendererCapabilitiesForMainThread = m_layerTreeHostImpl->layerRendererCapabilities();
+ return ok;
}
}
const LayerRendererCapabilities& CCSingleThreadProxy::layerRendererCapabilities() const
{
- ScopedSetImplThread impl;
- return m_layerTreeHostImpl->layerRendererCapabilities();
+ // Note: this gets called during the commit by the "impl" thread
+ return m_layerRendererCapabilitiesForMainThread;
}
void CCSingleThreadProxy::loseCompositorContext(int numTimes)
void CCSingleThreadProxy::setNeedsCommit()
{
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
// Commit immediately
{
ScopedSetImplThread impl;
m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
m_layerTreeHostImpl->commitComplete();
}
+ m_layerTreeHost->commitComplete();
}
void CCSingleThreadProxy::setNeedsCommitAndRedraw()
{
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
#if !USE(THREADED_COMPOSITING)
m_layerTreeHost->scheduleComposite();
#else
void CCSingleThreadProxy::stop()
{
TRACE_EVENT("CCSingleThreadProxy::stop", this, 0);
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
{
ScopedSetImplThread impl;
m_layerTreeHost->deleteContentsTextures(m_layerTreeHostImpl->context());
bool CCSingleThreadProxy::recreateContextIfNeeded()
{
- ASSERT(isMainThread());
+ ASSERT(CCProxy::isMainThread());
if (!m_graphicsContextLost)
return true;
RefPtr<GraphicsContext3D> context;
if (context) {
ASSERT(context->hasOneRef());
- if (m_layerTreeHostImpl->initializeLayerRenderer(context)) {
+ bool ok;
+ {
+ ScopedSetImplThread impl;
+ ok = m_layerTreeHostImpl->initializeLayerRenderer(context);
+ if (ok)
+ m_layerRendererCapabilitiesForMainThread = m_layerTreeHostImpl->layerRendererCapabilities();
+ }
+ if (ok) {
m_layerTreeHost->didRecreateGraphicsContext(true);
m_graphicsContextLost = false;
return true;
void CCSingleThreadProxy::commitIfNeeded()
{
+ ASSERT(CCProxy::isMainThread());
+
// Update
m_layerTreeHost->updateLayers();
m_layerTreeHost->commitTo(m_layerTreeHostImpl.get());
m_layerTreeHostImpl->commitComplete();
}
+ m_layerTreeHost->commitComplete();
}
bool CCSingleThreadProxy::doComposite()
// Used on the CCThread, but checked on main thread during initialization/shutdown.
OwnPtr<CCLayerTreeHostImpl> m_layerTreeHostImpl;
+ LayerRendererCapabilities m_layerRendererCapabilitiesForMainThread;
int m_numFailedRecreateAttempts;
bool m_graphicsContextLost;
#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_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());
{
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) {
bool CCThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect)
{
- ASSERT_NOT_REACHED();
- return false;
+ ASSERT(isMainThread());
+ ASSERT(m_layerTreeHost);
+
+ // 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::obtainBeginFrameAndCommitTaskFromCCThread, AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&taskPtr)));
+ completion.wait();
+ beginFrameAndCommitTask = adoptPtr(taskPtr);
+ }
+
+ beginFrameAndCommitTask->performTask();
+ }
+
+ // Draw using the new tree and read back the results.
+ 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()
void CCThreadProxy::finishAllRendering()
{
- ASSERT_NOT_REACHED();
+ ASSERT(CCProxy::isMainThread());
+
+ // 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()
// 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)));
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)));
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());
+ ASSERT(!m_beginFrameAndCommitPendingOnCCThread);
+ if (m_redrawRequestedOnCCThread) {
+ drawLayersOnCCThread();
+ m_layerTreeHostImpl->present();
+ m_redrawRequestedOnCCThread = false;
+ }
+ m_layerTreeHostImpl->finishAllRendering();
+ completion->signal();
+}
+
+void CCThreadProxy::obtainBeginFrameAndCommitTaskFromCCThread(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);
ASSERT(isImplThread());
- // TEMP HACK so we can exercise this code in unit tests.
- CCMainThread::postTask(createMainThreadTask(this, &CCThreadProxy::beginFrameAndCommit, 0.0));
+ 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 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(double 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());
+ return;
+ }
+
+ // If no commit is pending, but a redraw is requested, then post a redraw right away
+ if (m_redrawRequestedOnCCThread)
+ scheduleDrawTaskOnCCThread();
}
void CCThreadProxy::initializeImplOnCCThread(CCCompletionEvent* completion)
#include "cc/CCCompletionEvent.h"
#include "cc/CCLayerTreeHostImpl.h"
+#include "cc/CCMainThread.h"
#include "cc/CCProxy.h"
#include <wtf/OwnPtr.h>
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 obtainBeginFrameAndCommitTaskFromCCThread(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;
};
}
+2011-09-26 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-26 Joshua Bell <jsbell@chromium.org>
IndexedDB: Second half of IDBFactory.getDatabaseNames implementation
{
}
+#if !USE(THREADED_COMPOSITING)
+ virtual void scheduleComposite() { }
+#endif
+
private:
explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
: m_beginning(false)
, m_endWhenBeginReturns(false)
, m_running(false)
- , m_timedOut(false) { }
+ , m_timedOut(false)
+ {
+#if USE(THREADED_COMPOSITING)
+ m_settings.enableCompositorThread = true;
+#else
+ m_settings.enableCompositorThread = false;
+#endif
+ }
void doBeginTest();
test->endTest();
}
+ CCSettings m_settings;
OwnPtr<MockLayerTreeHostClient> m_client;
RefPtr<CCLayerTreeHost> m_layerTreeHost;
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, m_settings);
ASSERT(m_layerTreeHost);
m_beginning = true;
};
TEST_F(CCLayerTreeHostTestSetNeedsRedraw, run)
{
+ CCSettings setings;
runTest();
}
} // namespace
-#endif // USE(THREADED_COMPOSITING)
+#endif
#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)
// 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));
// 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);
TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
{
+ ScopedSetImplThread impl;
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0);
layerTreeRoot->addChild(LayerChromium::create(0));
layerTreeRoot->addChild(LayerChromium::create(0));
TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
{
+ ScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
// Set up a tree with this sort of structure:
// 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);
// 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));