Add intro to any Chrome app API with no overview docs.
[chromium-blink-merge.git] / cc / thread_proxy.cc
blobbff066bfa221171a3b29da11c1d6cac1796c4d6e
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"
7 #include "base/bind.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;
22 namespace {
24 // Measured in seconds.
25 const double contextRecreationTickRate = 0.03;
27 } // namespace
29 namespace cc {
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)
43 , m_started(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());
65 DCHECK(!m_started);
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");
77 return false;
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;
94 request.rect = rect;
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();
111 return;
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));
141 completion.wait();
144 bool ThreadProxy::isStarted() const
146 DCHECK(Proxy::isMainThread());
147 return m_started;
150 bool ThreadProxy::initializeContext()
152 TRACE_EVENT0("cc", "ThreadProxy::initializeContext");
153 scoped_ptr<GraphicsContext> context = m_layerTreeHost->createContext();
154 if (!context.get())
155 return false;
157 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::initializeContextOnImplThread, base::Unretained(this), base::Passed(context.Pass())));
158 return true;
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));
179 completion.wait();
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),
201 &completion,
202 &initializeSucceeded,
203 &capabilities));
204 completion.wait();
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();
220 if (!context.get())
221 return false;
222 if (m_layerTreeHost->needsSharedContext())
223 if (!WebSharedGraphicsContext3D::createCompositorThreadContext())
224 return false;
226 // Make a blocking call to recreateContextOnImplThread. The results of that
227 // call are pushed into the recreateSucceeded and capabilities local
228 // variables.
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),
235 &completion,
236 base::Passed(context.Pass()),
237 &recreateSucceeded,
238 &capabilities));
239 completion.wait();
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;
257 completion.wait();
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)
275 return;
277 TRACE_EVENT0("cc", "ThreadProxy::setNeedsAnimate");
278 m_animateRequested = true;
280 if (m_commitRequestSentToImplThread)
281 return;
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)
290 return;
291 TRACE_EVENT0("cc", "ThreadProxy::setNeedsCommit");
292 m_commitRequested = true;
294 if (m_commitRequestSentToImplThread)
295 return;
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)
339 return;
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())
371 return false;
373 bool reduceResult = m_layerTreeHost->contentsTextureManager()->reduceMemoryOnImplThread(limitBytes, priorityCutoff, m_layerTreeHostImpl->resourceProvider());
374 if (!reduceResult)
375 return false;
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();
381 return true;
384 void ThreadProxy::sendManagedMemoryStats()
386 DCHECK(isImplThread());
387 if (!m_layerTreeHostImpl.get())
388 return;
389 if (!m_layerTreeHostImpl->renderer())
390 return;
391 if (!m_layerTreeHost->contentsTextureManager())
392 return;
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;
414 if (m_deferCommits)
415 TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::setDeferCommits", this);
416 else
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()));
445 completion.wait();
447 m_started = true;
450 void ThreadProxy::stop()
452 TRACE_EVENT0("cc", "ThreadProxy::stop");
453 DCHECK(isMainThread());
454 DCHECK(m_started);
456 // Synchronously deletes the impl.
458 DebugScopedSetMainThreadBlocked mainThreadBlocked(this);
460 CompletionEvent completion;
461 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::layerTreeHostClosedOnImplThread, base::Unretained(this), &completion));
462 completion.wait();
465 m_mainThreadProxy->shutdown(); // Stop running tasks posted to us.
467 DCHECK(!m_layerTreeHostImpl.get()); // verify that the impl deleted.
468 m_layerTreeHost = 0;
469 m_started = false;
472 void ThreadProxy::forceSerializeOnSwapBuffers()
474 DebugScopedSetMainThreadBlocked mainThreadBlocked(this);
475 CompletionEvent completion;
476 Proxy::implThread()->postTask(base::Bind(&ThreadProxy::forceSerializeOnSwapBuffersOnImplThread, base::Unretained(this), &completion));
477 completion.wait();
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();
504 return;
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)
532 return;
534 if (m_deferCommits) {
535 m_pendingDeferredCommit = beginFrameState.Pass();
536 m_layerTreeHost->didDeferCommit();
537 TRACE_EVENT0("cc", "EarlyOut_DeferCommits");
538 return;
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)));
568 return;
571 m_layerTreeHost->willBeginFrame();
573 if (beginFrameState)
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
585 // updateLayers.
586 m_commitRequested = false;
587 m_commitRequestSentToImplThread = false;
589 if (!m_layerTreeHost->initializeRendererIfNeeded()) {
590 TRACE_EVENT0("cc", "EarlyOut_InitializeFailed");
591 return;
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
606 // the impl thread.
607 if (m_animateRequested) {
608 // Forces setNeedsAnimate to consider posting a commit task.
609 m_animateRequested = false;
610 setNeedsAnimate();
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()));
625 completion.wait();
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();
649 return;
652 if (m_layerTreeHost->contentsTextureManager()->linkedEvictedBackingsExist()) {
653 // Clear any uploads we were making to textures linked to evicted
654 // resources
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())
730 return result;
732 DCHECK(m_layerTreeHostImpl->renderer());
733 if (!m_layerTreeHostImpl->renderer())
734 return result;
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);
755 if (drawFrame) {
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;
764 if (drawFrame) {
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)));
779 return result;
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)
792 return;
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)
832 return;
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)
847 return;
848 m_layerTreeHost->didCommitAndDrawFrame();
851 void ThreadProxy::didCompleteSwapBuffers()
853 DCHECK(isMainThread());
854 if (!m_layerTreeHost)
855 return;
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)
864 return;
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())));
897 else
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()
982 } // namespace cc