1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/thread_proxy.h"
8 #include "base/debug/trace_event.h"
9 #include "cc/delay_based_time_source.h"
10 #include "cc/draw_quad.h"
11 #include "cc/frame_rate_controller.h"
12 #include "cc/graphics_context.h"
13 #include "cc/input_handler.h"
14 #include "cc/layer_tree_host.h"
15 #include "cc/scheduler.h"
16 #include "cc/scoped_thread_proxy.h"
17 #include "cc/thread.h"
18 #include <public/WebSharedGraphicsContext3D.h>
20 using WebKit::WebSharedGraphicsContext3D
;
24 // Measured in seconds.
25 const double contextRecreationTickRate
= 0.03;
31 scoped_ptr
<Proxy
> ThreadProxy::create(LayerTreeHost
* layerTreeHost
, scoped_ptr
<Thread
> implThread
)
33 return make_scoped_ptr(new ThreadProxy(layerTreeHost
, implThread
.Pass())).PassAs
<Proxy
>();
36 ThreadProxy::ThreadProxy(LayerTreeHost
* layerTreeHost
, scoped_ptr
<Thread
> implThread
)
37 : Proxy(implThread
.Pass())
38 , m_animateRequested(false)
39 , m_commitRequested(false)
40 , m_commitRequestSentToImplThread(false)
41 , m_layerTreeHost(layerTreeHost
)
42 , m_rendererInitialized(false)
44 , m_texturesAcquired(true)
45 , m_inCompositeAndReadback(false)
46 , m_manageTilesPending(false)
47 , m_mainThreadProxy(ScopedThreadProxy::create(Proxy::mainThread()))
48 , m_beginFrameCompletionEventOnImplThread(0)
49 , m_readbackRequestOnImplThread(0)
50 , m_commitCompletionEventOnImplThread(0)
51 , m_textureAcquisitionCompletionEventOnImplThread(0)
52 , m_nextFrameIsNewlyCommittedFrameOnImplThread(false)
53 , m_renderVSyncEnabled(layerTreeHost
->settings().renderVSyncEnabled
)
54 , m_totalCommitCount(0)
55 , m_deferCommits(false)
57 TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
58 DCHECK(isMainThread());
61 ThreadProxy::~ThreadProxy()
63 TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy");
64 DCHECK(isMainThread());
68 bool ThreadProxy::compositeAndReadback(void *pixels
, const gfx::Rect
& rect
)
70 TRACE_EVENT0("cc", "ThreadProxy::compositeAndReadback");
71 DCHECK(isMainThread());
72 DCHECK(m_layerTreeHost
);
73 DCHECK(!m_deferCommits
);
75 if (!m_layerTreeHost
->initializeRendererIfNeeded()) {
76 TRACE_EVENT0("cc", "compositeAndReadback_EarlyOut_LR_Uninitialized");
81 // Perform a synchronous commit.
83 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
84 CompletionEvent beginFrameCompletion
;
85 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::forceBeginFrameOnImplThread
, base::Unretained(this), &beginFrameCompletion
));
86 beginFrameCompletion
.wait();
88 m_inCompositeAndReadback
= true;
89 beginFrame(scoped_ptr
<BeginFrameAndCommitState
>());
90 m_inCompositeAndReadback
= false;
92 // Perform a synchronous readback.
93 ReadbackRequest request
;
95 request
.pixels
= pixels
;
97 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
98 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::requestReadbackOnImplThread
, base::Unretained(this), &request
));
99 request
.completion
.wait();
101 return request
.success
;
104 void ThreadProxy::requestReadbackOnImplThread(ReadbackRequest
* request
)
106 DCHECK(Proxy::isImplThread());
107 DCHECK(!m_readbackRequestOnImplThread
);
108 if (!m_layerTreeHostImpl
.get()) {
109 request
->success
= false;
110 request
->completion
.signal();
114 m_readbackRequestOnImplThread
= request
;
115 m_schedulerOnImplThread
->setNeedsRedraw();
116 m_schedulerOnImplThread
->setNeedsForcedRedraw();
119 void ThreadProxy::startPageScaleAnimation(gfx::Vector2d targetOffset
, bool useAnchor
, float scale
, base::TimeDelta duration
)
121 DCHECK(Proxy::isMainThread());
122 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::requestStartPageScaleAnimationOnImplThread
, base::Unretained(this), targetOffset
, useAnchor
, scale
, duration
));
125 void ThreadProxy::requestStartPageScaleAnimationOnImplThread(gfx::Vector2d targetOffset
, bool useAnchor
, float scale
, base::TimeDelta duration
)
127 DCHECK(Proxy::isImplThread());
128 if (m_layerTreeHostImpl
.get())
129 m_layerTreeHostImpl
->startPageScaleAnimation(targetOffset
, useAnchor
, scale
, base::TimeTicks::Now(), duration
);
132 void ThreadProxy::finishAllRendering()
134 DCHECK(Proxy::isMainThread());
135 DCHECK(!m_deferCommits
);
137 // Make sure all GL drawing is finished on the impl thread.
138 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
139 CompletionEvent completion
;
140 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::finishAllRenderingOnImplThread
, base::Unretained(this), &completion
));
144 bool ThreadProxy::isStarted() const
146 DCHECK(Proxy::isMainThread());
150 bool ThreadProxy::initializeContext()
152 TRACE_EVENT0("cc", "ThreadProxy::initializeContext");
153 scoped_ptr
<GraphicsContext
> context
= m_layerTreeHost
->createContext();
157 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::initializeContextOnImplThread
, base::Unretained(this), base::Passed(context
.Pass())));
161 void ThreadProxy::setSurfaceReady()
163 TRACE_EVENT0("cc", "ThreadProxy::setSurfaceReady");
164 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::setSurfaceReadyOnImplThread
, base::Unretained(this)));
167 void ThreadProxy::setSurfaceReadyOnImplThread()
169 TRACE_EVENT0("cc", "ThreadProxy::setSurfaceReadyOnImplThread");
170 m_schedulerOnImplThread
->setCanBeginFrame(true);
173 void ThreadProxy::setVisible(bool visible
)
175 TRACE_EVENT0("cc", "ThreadProxy::setVisible");
176 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
177 CompletionEvent completion
;
178 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::setVisibleOnImplThread
, base::Unretained(this), &completion
, visible
));
182 void ThreadProxy::setVisibleOnImplThread(CompletionEvent
* completion
, bool visible
)
184 TRACE_EVENT0("cc", "ThreadProxy::setVisibleOnImplThread");
185 m_layerTreeHostImpl
->setVisible(visible
);
186 m_schedulerOnImplThread
->setVisible(visible
);
187 completion
->signal();
190 bool ThreadProxy::initializeRenderer()
192 TRACE_EVENT0("cc", "ThreadProxy::initializeRenderer");
193 // Make a blocking call to initializeRendererOnImplThread. The results of that call
194 // are pushed into the initializeSucceeded and capabilities local variables.
195 CompletionEvent completion
;
196 bool initializeSucceeded
= false;
197 RendererCapabilities capabilities
;
198 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
199 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::initializeRendererOnImplThread
,
200 base::Unretained(this),
202 &initializeSucceeded
,
206 if (initializeSucceeded
) {
207 m_rendererInitialized
= true;
208 m_RendererCapabilitiesMainThreadCopy
= capabilities
;
210 return initializeSucceeded
;
213 bool ThreadProxy::recreateContext()
215 TRACE_EVENT0("cc", "ThreadProxy::recreateContext");
216 DCHECK(isMainThread());
218 // Try to create the context.
219 scoped_ptr
<GraphicsContext
> context
= m_layerTreeHost
->createContext();
222 if (m_layerTreeHost
->needsSharedContext())
223 if (!WebSharedGraphicsContext3D::createCompositorThreadContext())
226 // Make a blocking call to recreateContextOnImplThread. The results of that
227 // call are pushed into the recreateSucceeded and capabilities local
229 CompletionEvent completion
;
230 bool recreateSucceeded
= false;
231 RendererCapabilities capabilities
;
232 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
233 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::recreateContextOnImplThread
,
234 base::Unretained(this),
236 base::Passed(context
.Pass()),
241 if (recreateSucceeded
)
242 m_RendererCapabilitiesMainThreadCopy
= capabilities
;
243 return recreateSucceeded
;
246 void ThreadProxy::renderingStats(RenderingStats
* stats
)
248 DCHECK(isMainThread());
250 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
251 CompletionEvent completion
;
252 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::renderingStatsOnImplThread
,
253 base::Unretained(this), &completion
, stats
));
254 stats
->totalCommitTimeInSeconds
= m_totalCommitTime
.InSecondsF();
255 stats
->totalCommitCount
= m_totalCommitCount
;
260 const RendererCapabilities
& ThreadProxy::rendererCapabilities() const
262 DCHECK(m_rendererInitialized
);
263 return m_RendererCapabilitiesMainThreadCopy
;
266 void ThreadProxy::loseContext()
268 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::didLoseContextOnImplThread
, base::Unretained(this)));
271 void ThreadProxy::setNeedsAnimate()
273 DCHECK(isMainThread());
274 if (m_animateRequested
)
277 TRACE_EVENT0("cc", "ThreadProxy::setNeedsAnimate");
278 m_animateRequested
= true;
280 if (m_commitRequestSentToImplThread
)
282 m_commitRequestSentToImplThread
= true;
283 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::setNeedsCommitOnImplThread
, base::Unretained(this)));
286 void ThreadProxy::setNeedsCommit()
288 DCHECK(isMainThread());
289 if (m_commitRequested
)
291 TRACE_EVENT0("cc", "ThreadProxy::setNeedsCommit");
292 m_commitRequested
= true;
294 if (m_commitRequestSentToImplThread
)
296 m_commitRequestSentToImplThread
= true;
297 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::setNeedsCommitOnImplThread
, base::Unretained(this)));
300 void ThreadProxy::didLoseContextOnImplThread()
302 DCHECK(isImplThread());
303 TRACE_EVENT0("cc", "ThreadProxy::didLoseContextOnImplThread");
304 m_schedulerOnImplThread
->didLoseContext();
307 void ThreadProxy::onSwapBuffersCompleteOnImplThread()
309 DCHECK(isImplThread());
310 TRACE_EVENT0("cc", "ThreadProxy::onSwapBuffersCompleteOnImplThread");
311 m_schedulerOnImplThread
->didSwapBuffersComplete();
312 m_mainThreadProxy
->postTask(FROM_HERE
, base::Bind(&ThreadProxy::didCompleteSwapBuffers
, base::Unretained(this)));
315 void ThreadProxy::onVSyncParametersChanged(base::TimeTicks timebase
, base::TimeDelta interval
)
317 DCHECK(isImplThread());
318 TRACE_EVENT2("cc", "ThreadProxy::onVSyncParametersChanged", "timebase", (timebase
- base::TimeTicks()).InMilliseconds(), "interval", interval
.InMilliseconds());
319 m_schedulerOnImplThread
->setTimebaseAndInterval(timebase
, interval
);
322 void ThreadProxy::onCanDrawStateChanged(bool canDraw
)
324 DCHECK(isImplThread());
325 TRACE_EVENT1("cc", "ThreadProxy::onCanDrawStateChanged", "canDraw", canDraw
);
326 m_schedulerOnImplThread
->setCanDraw(canDraw
);
329 void ThreadProxy::setNeedsCommitOnImplThread()
331 DCHECK(isImplThread());
332 TRACE_EVENT0("cc", "ThreadProxy::setNeedsCommitOnImplThread");
333 m_schedulerOnImplThread
->setNeedsCommit();
336 void ThreadProxy::setNeedsManageTilesOnImplThread()
338 if (m_manageTilesPending
)
340 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::manageTilesOnImplThread
, base::Unretained(this)));
341 m_manageTilesPending
= true;
344 void ThreadProxy::manageTilesOnImplThread()
346 // TODO(nduca): If needed, move this into CCSchedulerStateMachine.
347 m_manageTilesPending
= false;
348 if (m_layerTreeHostImpl
)
349 m_layerTreeHostImpl
->manageTiles();
352 void ThreadProxy::setNeedsForcedCommitOnImplThread()
354 DCHECK(isImplThread());
355 TRACE_EVENT0("cc", "ThreadProxy::setNeedsForcedCommitOnImplThread");
356 m_schedulerOnImplThread
->setNeedsForcedCommit();
359 void ThreadProxy::postAnimationEventsToMainThreadOnImplThread(scoped_ptr
<AnimationEventsVector
> events
, base::Time wallClockTime
)
361 DCHECK(isImplThread());
362 TRACE_EVENT0("cc", "ThreadProxy::postAnimationEventsToMainThreadOnImplThread");
363 m_mainThreadProxy
->postTask(FROM_HERE
, base::Bind(&ThreadProxy::setAnimationEvents
, base::Unretained(this), base::Passed(events
.Pass()), wallClockTime
));
366 bool ThreadProxy::reduceContentsTextureMemoryOnImplThread(size_t limitBytes
, int priorityCutoff
)
368 DCHECK(isImplThread());
370 if (!m_layerTreeHost
->contentsTextureManager())
373 bool reduceResult
= m_layerTreeHost
->contentsTextureManager()->reduceMemoryOnImplThread(limitBytes
, priorityCutoff
, m_layerTreeHostImpl
->resourceProvider());
377 // The texture upload queue may reference textures that were just purged, clear
378 // them from the queue.
379 if (m_currentResourceUpdateControllerOnImplThread
.get())
380 m_currentResourceUpdateControllerOnImplThread
->discardUploadsToEvictedResources();
384 void ThreadProxy::sendManagedMemoryStats()
386 DCHECK(isImplThread());
387 if (!m_layerTreeHostImpl
.get())
389 if (!m_layerTreeHostImpl
->renderer())
391 if (!m_layerTreeHost
->contentsTextureManager())
394 m_layerTreeHostImpl
->renderer()->sendManagedMemoryStats(
395 m_layerTreeHost
->contentsTextureManager()->memoryVisibleBytes(),
396 m_layerTreeHost
->contentsTextureManager()->memoryVisibleAndNearbyBytes(),
397 m_layerTreeHost
->contentsTextureManager()->memoryUseBytes());
400 void ThreadProxy::setNeedsRedraw()
402 DCHECK(isMainThread());
403 TRACE_EVENT0("cc", "ThreadProxy::setNeedsRedraw");
404 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::setFullRootLayerDamageOnImplThread
, base::Unretained(this)));
405 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::setNeedsRedrawOnImplThread
, base::Unretained(this)));
408 void ThreadProxy::setDeferCommits(bool deferCommits
)
410 DCHECK(isMainThread());
411 DCHECK_NE(m_deferCommits
, deferCommits
);
412 m_deferCommits
= deferCommits
;
415 TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::setDeferCommits", this);
417 TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::setDeferCommits", this);
419 if (!m_deferCommits
&& m_pendingDeferredCommit
)
420 m_mainThreadProxy
->postTask(FROM_HERE
, base::Bind(&ThreadProxy::beginFrame
, base::Unretained(this), base::Passed(m_pendingDeferredCommit
.Pass())));
423 bool ThreadProxy::commitRequested() const
425 DCHECK(isMainThread());
426 return m_commitRequested
;
429 void ThreadProxy::setNeedsRedrawOnImplThread()
431 DCHECK(isImplThread());
432 TRACE_EVENT0("cc", "ThreadProxy::setNeedsRedrawOnImplThread");
433 m_schedulerOnImplThread
->setNeedsRedraw();
436 void ThreadProxy::start()
438 DCHECK(isMainThread());
439 DCHECK(Proxy::implThread());
440 // Create LayerTreeHostImpl.
441 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
442 CompletionEvent completion
;
443 scoped_ptr
<InputHandler
> handler
= m_layerTreeHost
->createInputHandler();
444 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::initializeImplOnImplThread
, base::Unretained(this), &completion
, handler
.release()));
450 void ThreadProxy::stop()
452 TRACE_EVENT0("cc", "ThreadProxy::stop");
453 DCHECK(isMainThread());
456 // Synchronously deletes the impl.
458 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
460 CompletionEvent completion
;
461 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::layerTreeHostClosedOnImplThread
, base::Unretained(this), &completion
));
465 m_mainThreadProxy
->shutdown(); // Stop running tasks posted to us.
467 DCHECK(!m_layerTreeHostImpl
.get()); // verify that the impl deleted.
472 void ThreadProxy::forceSerializeOnSwapBuffers()
474 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
475 CompletionEvent completion
;
476 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::forceSerializeOnSwapBuffersOnImplThread
, base::Unretained(this), &completion
));
480 void ThreadProxy::forceSerializeOnSwapBuffersOnImplThread(CompletionEvent
* completion
)
482 if (m_rendererInitialized
)
483 m_layerTreeHostImpl
->renderer()->doNoOp();
484 completion
->signal();
488 void ThreadProxy::finishAllRenderingOnImplThread(CompletionEvent
* completion
)
490 TRACE_EVENT0("cc", "ThreadProxy::finishAllRenderingOnImplThread");
491 DCHECK(isImplThread());
492 m_layerTreeHostImpl
->finishAllRendering();
493 completion
->signal();
496 void ThreadProxy::forceBeginFrameOnImplThread(CompletionEvent
* completion
)
498 TRACE_EVENT0("cc", "ThreadProxy::forceBeginFrameOnImplThread");
499 DCHECK(!m_beginFrameCompletionEventOnImplThread
);
501 setNeedsForcedCommitOnImplThread();
502 if (m_schedulerOnImplThread
->commitPending()) {
503 completion
->signal();
507 m_beginFrameCompletionEventOnImplThread
= completion
;
510 void ThreadProxy::scheduledActionBeginFrame()
512 TRACE_EVENT0("cc", "ThreadProxy::scheduledActionBeginFrame");
513 scoped_ptr
<BeginFrameAndCommitState
> beginFrameState(new BeginFrameAndCommitState
);
514 beginFrameState
->monotonicFrameBeginTime
= base::TimeTicks::Now();
515 beginFrameState
->scrollInfo
= m_layerTreeHostImpl
->processScrollDeltas();
516 beginFrameState
->implTransform
= m_layerTreeHostImpl
->implTransform();
517 DCHECK_GT(m_layerTreeHostImpl
->memoryAllocationLimitBytes(), 0u);
518 beginFrameState
->memoryAllocationLimitBytes
= m_layerTreeHostImpl
->memoryAllocationLimitBytes();
519 m_mainThreadProxy
->postTask(FROM_HERE
, base::Bind(&ThreadProxy::beginFrame
, base::Unretained(this), base::Passed(beginFrameState
.Pass())));
521 if (m_beginFrameCompletionEventOnImplThread
) {
522 m_beginFrameCompletionEventOnImplThread
->signal();
523 m_beginFrameCompletionEventOnImplThread
= 0;
527 void ThreadProxy::beginFrame(scoped_ptr
<BeginFrameAndCommitState
> beginFrameState
)
529 TRACE_EVENT0("cc", "ThreadProxy::beginFrame");
530 DCHECK(isMainThread());
531 if (!m_layerTreeHost
)
534 if (m_deferCommits
) {
535 m_pendingDeferredCommit
= beginFrameState
.Pass();
536 m_layerTreeHost
->didDeferCommit();
537 TRACE_EVENT0("cc", "EarlyOut_DeferCommits");
541 if (m_layerTreeHost
->needsSharedContext() && !WebSharedGraphicsContext3D::haveCompositorThreadContext())
542 WebSharedGraphicsContext3D::createCompositorThreadContext();
544 // Do not notify the impl thread of commit requests that occur during
545 // the apply/animate/layout part of the beginFrameAndCommit process since
546 // those commit requests will get painted immediately. Once we have done
547 // the paint, m_commitRequested will be set to false to allow new commit
548 // requests to be scheduled.
549 m_commitRequested
= true;
550 m_commitRequestSentToImplThread
= true;
552 // On the other hand, the animationRequested flag needs to be cleared
553 // here so that any animation requests generated by the apply or animate
554 // callbacks will trigger another frame.
555 m_animateRequested
= false;
557 if (beginFrameState
) {
558 m_layerTreeHost
->applyScrollAndScale(*beginFrameState
->scrollInfo
);
559 m_layerTreeHost
->setImplTransform(beginFrameState
->implTransform
);
562 if (!m_inCompositeAndReadback
&& !m_layerTreeHost
->visible()) {
563 m_commitRequested
= false;
564 m_commitRequestSentToImplThread
= false;
566 TRACE_EVENT0("cc", "EarlyOut_NotVisible");
567 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::beginFrameAbortedOnImplThread
, base::Unretained(this)));
571 m_layerTreeHost
->willBeginFrame();
574 m_layerTreeHost
->updateAnimations(beginFrameState
->monotonicFrameBeginTime
);
576 // Unlink any backings that the impl thread has evicted, so that we know to re-paint
577 // them in updateLayers.
578 if (m_layerTreeHost
->contentsTextureManager())
579 m_layerTreeHost
->contentsTextureManager()->unlinkAndClearEvictedBackings();
581 m_layerTreeHost
->layout();
583 // Clear the commit flag after updating animations and layout here --- objects that only
584 // layout when painted will trigger another setNeedsCommit inside
586 m_commitRequested
= false;
587 m_commitRequestSentToImplThread
= false;
589 if (!m_layerTreeHost
->initializeRendererIfNeeded()) {
590 TRACE_EVENT0("cc", "EarlyOut_InitializeFailed");
594 scoped_ptr
<ResourceUpdateQueue
> queue
= make_scoped_ptr(new ResourceUpdateQueue
);
595 m_layerTreeHost
->updateLayers(*(queue
.get()), beginFrameState
? beginFrameState
->memoryAllocationLimitBytes
: 0);
597 // Once single buffered layers are committed, they cannot be modified until
598 // they are drawn by the impl thread.
599 m_texturesAcquired
= false;
601 m_layerTreeHost
->willCommit();
602 // Before applying scrolls and calling animate, we set m_animateRequested to
603 // false. If it is true now, it means setNeedAnimate was called again, but
604 // during a state when m_commitRequestSentToImplThread = true. We need to
605 // force that call to happen again now so that the commit request is sent to
607 if (m_animateRequested
) {
608 // Forces setNeedsAnimate to consider posting a commit task.
609 m_animateRequested
= false;
613 // Notify the impl thread that the beginFrame has completed. This will
614 // begin the commit process, which is blocking from the main thread's
615 // point of view, but asynchronously performed on the impl thread,
616 // coordinated by the Scheduler.
618 TRACE_EVENT0("cc", "commit");
620 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
622 base::TimeTicks startTime
= base::TimeTicks::HighResNow();
623 CompletionEvent completion
;
624 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::beginFrameCompleteOnImplThread
, base::Unretained(this), &completion
, queue
.release()));
626 base::TimeTicks endTime
= base::TimeTicks::HighResNow();
628 m_totalCommitTime
+= endTime
- startTime
;
629 m_totalCommitCount
++;
632 m_layerTreeHost
->commitComplete();
633 m_layerTreeHost
->didBeginFrame();
636 void ThreadProxy::beginFrameCompleteOnImplThread(CompletionEvent
* completion
, ResourceUpdateQueue
* rawQueue
)
638 scoped_ptr
<ResourceUpdateQueue
> queue(rawQueue
);
640 TRACE_EVENT0("cc", "ThreadProxy::beginFrameCompleteOnImplThread");
641 DCHECK(!m_commitCompletionEventOnImplThread
);
642 DCHECK(isImplThread() && isMainThreadBlocked());
643 DCHECK(m_schedulerOnImplThread
);
644 DCHECK(m_schedulerOnImplThread
->commitPending());
646 if (!m_layerTreeHostImpl
.get()) {
647 TRACE_EVENT0("cc", "EarlyOut_NoLayerTree");
648 completion
->signal();
652 if (m_layerTreeHost
->contentsTextureManager()->linkedEvictedBackingsExist()) {
653 // Clear any uploads we were making to textures linked to evicted
655 queue
->clearUploadsToEvictedResources();
656 // Some textures in the layer tree are invalid. Kick off another commit
657 // to fill them again.
658 setNeedsCommitOnImplThread();
661 m_layerTreeHost
->contentsTextureManager()->pushTexturePrioritiesToBackings();
663 m_currentResourceUpdateControllerOnImplThread
= ResourceUpdateController::create(this, Proxy::implThread(), queue
.Pass(), m_layerTreeHostImpl
->resourceProvider(), hasImplThread());
664 m_currentResourceUpdateControllerOnImplThread
->performMoreUpdates(
665 m_schedulerOnImplThread
->anticipatedDrawTime());
667 m_commitCompletionEventOnImplThread
= completion
;
670 void ThreadProxy::beginFrameAbortedOnImplThread()
672 TRACE_EVENT0("cc", "ThreadProxy::beginFrameAbortedOnImplThread");
673 DCHECK(isImplThread());
674 DCHECK(m_schedulerOnImplThread
);
675 DCHECK(m_schedulerOnImplThread
->commitPending());
677 m_schedulerOnImplThread
->beginFrameAborted();
680 void ThreadProxy::scheduledActionCommit()
682 TRACE_EVENT0("cc", "ThreadProxy::scheduledActionCommit");
683 DCHECK(isImplThread());
684 DCHECK(m_commitCompletionEventOnImplThread
);
685 DCHECK(m_currentResourceUpdateControllerOnImplThread
);
687 // Complete all remaining texture updates.
688 m_currentResourceUpdateControllerOnImplThread
->finalize();
689 m_currentResourceUpdateControllerOnImplThread
.reset();
691 // If there are linked evicted backings, these backings' resources may be put into the
692 // impl tree, so we can't draw yet. Determine this before clearing all evicted backings.
693 bool newImplTreeHasNoEvictedResources
= !m_layerTreeHost
->contentsTextureManager()->linkedEvictedBackingsExist();
695 m_layerTreeHostImpl
->beginCommit();
696 m_layerTreeHost
->beginCommitOnImplThread(m_layerTreeHostImpl
.get());
697 m_layerTreeHost
->finishCommitOnImplThread(m_layerTreeHostImpl
.get());
699 if (newImplTreeHasNoEvictedResources
) {
700 if (m_layerTreeHostImpl
->contentsTexturesPurged())
701 m_layerTreeHostImpl
->resetContentsTexturesPurged();
704 m_layerTreeHostImpl
->commitComplete();
706 m_nextFrameIsNewlyCommittedFrameOnImplThread
= true;
708 m_commitCompletionEventOnImplThread
->signal();
709 m_commitCompletionEventOnImplThread
= 0;
711 // SetVisible kicks off the next scheduler action, so this must be last.
712 m_schedulerOnImplThread
->setVisible(m_layerTreeHostImpl
->visible());
715 void ThreadProxy::scheduledActionBeginContextRecreation()
717 DCHECK(isImplThread());
718 m_mainThreadProxy
->postTask(FROM_HERE
, base::Bind(&ThreadProxy::beginContextRecreation
, base::Unretained(this)));
721 ScheduledActionDrawAndSwapResult
ThreadProxy::scheduledActionDrawAndSwapInternal(bool forcedDraw
)
723 TRACE_EVENT0("cc", "ThreadProxy::scheduledActionDrawAndSwap");
724 ScheduledActionDrawAndSwapResult result
;
725 result
.didDraw
= false;
726 result
.didSwap
= false;
727 DCHECK(isImplThread());
728 DCHECK(m_layerTreeHostImpl
.get());
729 if (!m_layerTreeHostImpl
.get())
732 DCHECK(m_layerTreeHostImpl
->renderer());
733 if (!m_layerTreeHostImpl
->renderer())
736 // FIXME: compute the frame display time more intelligently
737 base::TimeTicks monotonicTime
= base::TimeTicks::Now();
738 base::Time wallClockTime
= base::Time::Now();
740 if (m_inputHandlerOnImplThread
.get())
741 m_inputHandlerOnImplThread
->animate(monotonicTime
);
742 m_layerTreeHostImpl
->animate(monotonicTime
, wallClockTime
);
744 // This method is called on a forced draw, regardless of whether we are able to produce a frame,
745 // as the calling site on main thread is blocked until its request completes, and we signal
746 // completion here. If canDraw() is false, we will indicate success=false to the caller, but we
747 // must still signal completion to avoid deadlock.
749 // We guard prepareToDraw() with canDraw() because it always returns a valid frame, so can only
750 // be used when such a frame is possible. Since drawLayers() depends on the result of
751 // prepareToDraw(), it is guarded on canDraw() as well.
753 LayerTreeHostImpl::FrameData frame
;
754 bool drawFrame
= m_layerTreeHostImpl
->canDraw() && (m_layerTreeHostImpl
->prepareToDraw(frame
) || forcedDraw
);
756 m_layerTreeHostImpl
->drawLayers(frame
);
757 result
.didDraw
= true;
759 m_layerTreeHostImpl
->didDrawAllLayers(frame
);
761 // Check for a pending compositeAndReadback.
762 if (m_readbackRequestOnImplThread
) {
763 m_readbackRequestOnImplThread
->success
= false;
765 m_layerTreeHostImpl
->readback(m_readbackRequestOnImplThread
->pixels
, m_readbackRequestOnImplThread
->rect
);
766 m_readbackRequestOnImplThread
->success
= !m_layerTreeHostImpl
->isContextLost();
768 m_readbackRequestOnImplThread
->completion
.signal();
769 m_readbackRequestOnImplThread
= 0;
770 } else if (drawFrame
)
771 result
.didSwap
= m_layerTreeHostImpl
->swapBuffers();
773 // Tell the main thread that the the newly-commited frame was drawn.
774 if (m_nextFrameIsNewlyCommittedFrameOnImplThread
) {
775 m_nextFrameIsNewlyCommittedFrameOnImplThread
= false;
776 m_mainThreadProxy
->postTask(FROM_HERE
, base::Bind(&ThreadProxy::didCommitAndDrawFrame
, base::Unretained(this)));
782 void ThreadProxy::acquireLayerTextures()
784 // Called when the main thread needs to modify a layer texture that is used
785 // directly by the compositor.
786 // This method will block until the next compositor draw if there is a
787 // previously committed frame that is still undrawn. This is necessary to
788 // ensure that the main thread does not monopolize access to the textures.
789 DCHECK(isMainThread());
791 if (m_texturesAcquired
)
794 TRACE_EVENT0("cc", "ThreadProxy::acquireLayerTextures");
795 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
796 CompletionEvent completion
;
797 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::acquireLayerTexturesForMainThreadOnImplThread
, base::Unretained(this), &completion
));
798 completion
.wait(); // Block until it is safe to write to layer textures from the main thread.
800 m_texturesAcquired
= true;
803 void ThreadProxy::acquireLayerTexturesForMainThreadOnImplThread(CompletionEvent
* completion
)
805 DCHECK(isImplThread());
806 DCHECK(!m_textureAcquisitionCompletionEventOnImplThread
);
808 m_textureAcquisitionCompletionEventOnImplThread
= completion
;
809 m_schedulerOnImplThread
->setMainThreadNeedsLayerTextures();
812 void ThreadProxy::scheduledActionAcquireLayerTexturesForMainThread()
814 DCHECK(m_textureAcquisitionCompletionEventOnImplThread
);
815 m_textureAcquisitionCompletionEventOnImplThread
->signal();
816 m_textureAcquisitionCompletionEventOnImplThread
= 0;
819 ScheduledActionDrawAndSwapResult
ThreadProxy::scheduledActionDrawAndSwapIfPossible()
821 return scheduledActionDrawAndSwapInternal(false);
824 ScheduledActionDrawAndSwapResult
ThreadProxy::scheduledActionDrawAndSwapForced()
826 return scheduledActionDrawAndSwapInternal(true);
829 void ThreadProxy::didAnticipatedDrawTimeChange(base::TimeTicks time
)
831 if (!m_currentResourceUpdateControllerOnImplThread
)
834 m_currentResourceUpdateControllerOnImplThread
->performMoreUpdates(time
);
837 void ThreadProxy::readyToFinalizeTextureUpdates()
839 DCHECK(isImplThread());
840 m_schedulerOnImplThread
->beginFrameComplete();
843 void ThreadProxy::didCommitAndDrawFrame()
845 DCHECK(isMainThread());
846 if (!m_layerTreeHost
)
848 m_layerTreeHost
->didCommitAndDrawFrame();
851 void ThreadProxy::didCompleteSwapBuffers()
853 DCHECK(isMainThread());
854 if (!m_layerTreeHost
)
856 m_layerTreeHost
->didCompleteSwapBuffers();
859 void ThreadProxy::setAnimationEvents(scoped_ptr
<AnimationEventsVector
> events
, base::Time wallClockTime
)
861 TRACE_EVENT0("cc", "ThreadProxy::setAnimationEvents");
862 DCHECK(isMainThread());
863 if (!m_layerTreeHost
)
865 m_layerTreeHost
->setAnimationEvents(events
.Pass(), wallClockTime
);
868 void ThreadProxy::beginContextRecreation()
870 TRACE_EVENT0("cc", "ThreadProxy::beginContextRecreation");
871 DCHECK(isMainThread());
872 m_layerTreeHost
->didLoseContext();
873 m_contextRecreationCallback
.Reset(base::Bind(&ThreadProxy::tryToRecreateContext
, base::Unretained(this)));
874 Proxy::mainThread()->postTask(m_contextRecreationCallback
.callback());
877 void ThreadProxy::tryToRecreateContext()
879 DCHECK(isMainThread());
880 DCHECK(m_layerTreeHost
);
881 LayerTreeHost::RecreateResult result
= m_layerTreeHost
->recreateContext();
882 if (result
== LayerTreeHost::RecreateFailedButTryAgain
)
883 Proxy::mainThread()->postTask(m_contextRecreationCallback
.callback());
884 else if (result
== LayerTreeHost::RecreateSucceeded
)
885 m_contextRecreationCallback
.Cancel();
888 void ThreadProxy::initializeImplOnImplThread(CompletionEvent
* completion
, InputHandler
* handler
)
890 TRACE_EVENT0("cc", "ThreadProxy::initializeImplOnImplThread");
891 DCHECK(isImplThread());
892 m_layerTreeHostImpl
= m_layerTreeHost
->createLayerTreeHostImpl(this);
893 const base::TimeDelta displayRefreshInterval
= base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond
/ 60);
894 scoped_ptr
<FrameRateController
> frameRateController
;
895 if (m_renderVSyncEnabled
)
896 frameRateController
.reset(new FrameRateController(DelayBasedTimeSource::create(displayRefreshInterval
, Proxy::implThread())));
898 frameRateController
.reset(new FrameRateController(Proxy::implThread()));
899 m_schedulerOnImplThread
= Scheduler::create(this, frameRateController
.Pass());
900 m_schedulerOnImplThread
->setVisible(m_layerTreeHostImpl
->visible());
902 m_inputHandlerOnImplThread
= scoped_ptr
<InputHandler
>(handler
);
903 if (m_inputHandlerOnImplThread
.get())
904 m_inputHandlerOnImplThread
->bindToClient(m_layerTreeHostImpl
.get());
906 completion
->signal();
909 void ThreadProxy::initializeContextOnImplThread(scoped_ptr
<GraphicsContext
> context
)
911 TRACE_EVENT0("cc", "ThreadProxy::initializeContextOnImplThread");
912 DCHECK(isImplThread());
913 m_contextBeforeInitializationOnImplThread
= context
.Pass();
916 void ThreadProxy::initializeRendererOnImplThread(CompletionEvent
* completion
, bool* initializeSucceeded
, RendererCapabilities
* capabilities
)
918 TRACE_EVENT0("cc", "ThreadProxy::initializeRendererOnImplThread");
919 DCHECK(isImplThread());
920 DCHECK(m_contextBeforeInitializationOnImplThread
.get());
921 *initializeSucceeded
= m_layerTreeHostImpl
->initializeRenderer(m_contextBeforeInitializationOnImplThread
.Pass());
922 if (*initializeSucceeded
) {
923 *capabilities
= m_layerTreeHostImpl
->rendererCapabilities();
924 m_schedulerOnImplThread
->setSwapBuffersCompleteSupported(
925 capabilities
->usingSwapCompleteCallback
);
928 completion
->signal();
931 void ThreadProxy::layerTreeHostClosedOnImplThread(CompletionEvent
* completion
)
933 TRACE_EVENT0("cc", "ThreadProxy::layerTreeHostClosedOnImplThread");
934 DCHECK(isImplThread());
935 m_layerTreeHost
->deleteContentsTexturesOnImplThread(m_layerTreeHostImpl
->resourceProvider());
936 m_inputHandlerOnImplThread
.reset();
937 m_layerTreeHostImpl
.reset();
938 m_schedulerOnImplThread
.reset();
939 completion
->signal();
942 void ThreadProxy::setFullRootLayerDamageOnImplThread()
944 DCHECK(isImplThread());
945 m_layerTreeHostImpl
->setFullRootLayerDamage();
948 size_t ThreadProxy::maxPartialTextureUpdates() const
950 return ResourceUpdateController::maxPartialTextureUpdates();
953 void ThreadProxy::recreateContextOnImplThread(CompletionEvent
* completion
, scoped_ptr
<GraphicsContext
> context
, bool* recreateSucceeded
, RendererCapabilities
* capabilities
)
955 TRACE_EVENT0("cc", "ThreadProxy::recreateContextOnImplThread");
956 DCHECK(isImplThread());
957 m_layerTreeHost
->deleteContentsTexturesOnImplThread(m_layerTreeHostImpl
->resourceProvider());
958 *recreateSucceeded
= m_layerTreeHostImpl
->initializeRenderer(context
.Pass());
959 if (*recreateSucceeded
) {
960 *capabilities
= m_layerTreeHostImpl
->rendererCapabilities();
961 m_schedulerOnImplThread
->didRecreateContext();
963 completion
->signal();
966 void ThreadProxy::renderingStatsOnImplThread(CompletionEvent
* completion
, RenderingStats
* stats
)
968 DCHECK(isImplThread());
969 m_layerTreeHostImpl
->renderingStats(stats
);
970 completion
->signal();
973 ThreadProxy::BeginFrameAndCommitState::BeginFrameAndCommitState()
974 : memoryAllocationLimitBytes(0)
978 ThreadProxy::BeginFrameAndCommitState::~BeginFrameAndCommitState()